HPCToolkit
libunw_intervals.c
Go to the documentation of this file.
1 // -*-Mode: C++;-*- // technically C99
2 
3 // * BeginRiceCopyright *****************************************************
4 //
5 // $HeadURL$
6 // $Id$
7 //
8 // --------------------------------------------------------------------------
9 // Part of HPCToolkit (hpctoolkit.org)
10 //
11 // Information about sources of support for research and development of
12 // HPCToolkit is at 'hpctoolkit.org' and in 'README.Acknowledgments'.
13 // --------------------------------------------------------------------------
14 //
15 // Copyright ((c)) 2002-2019, Rice University
16 // All rights reserved.
17 //
18 // Redistribution and use in source and binary forms, with or without
19 // modification, are permitted provided that the following conditions are
20 // met:
21 //
22 // * Redistributions of source code must retain the above copyright
23 // notice, this list of conditions and the following disclaimer.
24 //
25 // * Redistributions in binary form must reproduce the above copyright
26 // notice, this list of conditions and the following disclaimer in the
27 // documentation and/or other materials provided with the distribution.
28 //
29 // * Neither the name of Rice University (RICE) nor the names of its
30 // contributors may be used to endorse or promote products derived from
31 // this software without specific prior written permission.
32 //
33 // This software is provided by RICE and contributors "as is" and any
34 // express or implied warranties, including, but not limited to, the
35 // implied warranties of merchantability and fitness for a particular
36 // purpose are disclaimed. In no event shall RICE or contributors be
37 // liable for any direct, indirect, incidental, special, exemplary, or
38 // consequential damages (including, but not limited to, procurement of
39 // substitute goods or services; loss of use, data, or profits; or
40 // business interruption) however caused and on any theory of liability,
41 // whether in contract, strict liability, or tort (including negligence
42 // or otherwise) arising in any way out of the use of this software, even
43 // if advised of the possibility of such damage.
44 //
45 // ******************************************************* EndRiceCopyright *
46 //
47 // This software was produced with support in part from the Defense Advanced
48 // Research Projects Agency (DARPA) through AFRL Contract FA8650-09-C-1915.
49 // Nothing in this work should be construed as reflecting the official policy or
50 // position of the Defense Department, the United States government, or
51 // Rice University.
52 //
53 //***************************************************************************
54 
55 //************************************************
56 // system includes
57 //************************************************
58 
59 #define UNW_LOCAL_ONLY
60 
61 #include <stdlib.h>
62 #include <stddef.h>
63 #include <stdint.h>
64 #include <inttypes.h>
65 #include <stdbool.h>
66 
67 #include <ucontext.h>
68 
69 #include <include/hpctoolkit-config.h>
70 
71 //************************************************
72 // external includes
73 //************************************************
74 
75 #include <monitor.h>
76 
77 //************************************************
78 // local includes
79 //************************************************
80 
82 #include <messages/messages.h>
83 #include <hpcrun/hpcrun_stats.h>
85 #include <unwind/common/unwind.h>
89 
90 
91 
92 //************************************************
93 // macros
94 //************************************************
95 
96 #define DEBUG_LIBUNWIND_INTERFACE 0
97 
98 
99 
100 //************************************************
101 // local data
102 //************************************************
103 
104 #if DEBUG_LIBUNWIND_INTERFACE
105 static int libunwind_debug = 0;
106 #endif
107 
108 
109 
110 //************************************************
111 // debugging public interface
112 //************************************************
113 
114 #if DEBUG_LIBUNWIND_INTERFACE
115 int
116 libunw_debug_on()
117 {
118  libunwind_debug = 1;
119  return libunwind_debug;
120 }
121 
122 
123 int
124 libunwind_debug_off()
125 {
126  libunwind_debug = 0;
127  return libunwind_debug;
128 }
129 #endif
130 
131 
132 
133 //************************************************
134 // debugging private functions
135 //************************************************
136 
137 #if DEBUG_LIBUNWIND_INTERFACE
138 static const char *
139 fence_string(hpcrun_unw_cursor_t* cursor)
140 {
141  switch(cursor->fence) {
142  case FENCE_MAIN: return "FENCE_MAIN";
143  case FENCE_NONE: return "FENCE_NONE";
144  case FENCE_THREAD: return "FENCE_THREAD";
145  case FENCE_BAD: return "FENCE_BAD";
146  case FENCE_TRAMP: return "FENCE_TRAMP";
147  }
148  return NULL;
149 }
150 
151 static const char *
152 step_state_string(step_state state)
153 {
154  switch(state) {
155  case STEP_OK: return "STEP_OK";
156  case STEP_ERROR: return "STEP_ERROR";
157  case STEP_STOP: return "STEP_STOP";
158  case STEP_STOP_WEAK: return "STEP_STOP_WEAK";
159  case STEP_TROLL: return "STEP_TROLL";
160  }
161  return NULL;
162 }
163 
164 static const char *
165 libunw_state_string(enum libunw_state state)
166 {
167  switch(state) {
168  case LIBUNW_READY: return "LIBUNW_READY";
169  case LIBUNW_UNAVAIL: return "LIBUNW_UNAVAIL";
170  }
171  return NULL;
172 }
173 #endif
174 
175 
176 //************************************************
177 // private functions
178 //************************************************
179 
180 static void *
182 {
183  unw_word_t tmp;
184 
185  unw_cursor_t *unw_cursor = &(cursor->uc);
186  unw_get_reg(unw_cursor, UNW_REG_IP, &tmp);
187 
188  return (void *) tmp;
189 }
190 
191 static void
193 {
194  void *func_start_pc = (void*) cursor->unwr_info.interval.start;
195  load_module_t* lm = cursor->unwr_info.lm;
196 
197  cursor->pc_norm = hpcrun_normalize_ip(cursor->pc_unnorm, lm);
198  cursor->the_function = hpcrun_normalize_ip(func_start_pc, lm);
199 
200 #if DEBUG_LIBUNWIND_INTERFACE
201  if (libunwind_debug) {
202  printf("ip = %p (%d, %lx) the_function=%p (%d,%lx) ",
203  cursor->pc_unnorm, cursor->pc_norm.lm_id, cursor->pc_norm.lm_ip,
204  func_start_pc, cursor->the_function.lm_id, cursor->the_function.lm_ip);
205  }
206 #endif
207 }
208 
209 bool
211 {
212  void *pc = libunw_cursor_get_pc(cursor);
213  cursor->pc_unnorm = pc;
214  bool found = uw_recipe_map_lookup(pc, DWARF_UNWINDER, &cursor->unwr_info);
215  compute_normalized_ips(cursor);
216  TMSG(UNW, "unw_step: advance pc: %p\n", pc);
217  cursor->libunw_status = found ? LIBUNW_READY : LIBUNW_UNAVAIL;
218 
219 #if DEBUG_LIBUNWIND_INTERFACE
220  if (libunwind_debug) {
221  printf("libunw_status = %s ", libunw_state_string(cursor->libunw_status));
222  }
223 #endif
224 
225  return found;
226 }
227 
230 {
231  void *pc = libunw_cursor_get_pc(cursor); // pc after step
232 
233  // full unwind: stop at libmonitor fence. this is where we hope the
234  // unwind stops.
235  cursor->fence = (monitor_unwind_process_bottom_frame(pc) ? FENCE_MAIN :
236  monitor_unwind_thread_bottom_frame(pc)? FENCE_THREAD : FENCE_NONE);
237 
238 #if DEBUG_LIBUNWIND_INTERFACE
239  if (libunwind_debug) {
240  printf("fence = %s ", fence_string(cursor));
241  }
242 #endif
243 
244  if (cursor->fence != FENCE_NONE) {
245  TMSG(UNW, "unw_step: stop at monitor fence: %p\n", pc);
246  return STEP_STOP;
247  }
248 
249  bitree_uwi_t* uw = cursor->unwr_info.btuwi;
250  if (!uw) {
251  TMSG(UNW, "libunw_take_step: error: failed at: %p\n", pc);
252  return STEP_ERROR;
253  }
254 
255  uwi_t *uwi = bitree_uwi_rootval(uw);
256  unw_apply_reg_state(&(cursor->uc), uwi->recipe);
257 
258  return STEP_OK;
259 }
260 
261 // Takes a sigaction() context pointer and makes a libunwind
262 // unw_cursor_t. The other fields in hpcrun_unw_cursor_t are unused,
263 // except for pc_norm and pc_unnorm.
264 //
265 void
267 {
268  unw_cursor_t *unw_cursor = &(cursor->uc);
269  unw_context_t *ctx = (unw_context_t *) context;
270 
271  if (ctx != NULL && unw_init_local2(unw_cursor, ctx, UNW_INIT_SIGNAL_FRAME) == 0) {
272  libunw_finalize_cursor(cursor);
273  }
274 }
275 
276 //***************************************************************************
277 // unwind_interval interface
278 //***************************************************************************
279 
280 struct builder
281 {
284  int count;
285 };
286 
287 static int
289  void *rs,
290  size_t size,
291  unw_word_t start_ip, unw_word_t end_ip)
292 {
293  struct builder *b = token;
294  bitree_uwi_t *u = bitree_uwi_malloc(b->uw, size);
295  if (!u)
296  return (-1);
298  uwi_t *uwi = bitree_uwi_rootval(u);
299  uwi->interval.start = (uintptr_t)start_ip;
300  uwi->interval.end = (uintptr_t)end_ip;
301  memcpy(uwi->recipe, rs, size);
302  b->latest = u;
303  b->count++;
305  return 0;
306 }
307 
308 
310 libunw_build_intervals(char *beg_insn, unsigned int len)
311 {
312  unw_context_t uc;
313  (void) unw_getcontext(&uc);
314  unw_cursor_t c;
315  unw_init_local2(&c, &uc, UNW_INIT_SIGNAL_FRAME);
316  unw_set_reg(&c, UNW_REG_IP, (intptr_t)beg_insn);
317  void *space[2] __attribute((aligned (32))); // enough space for any binarytree
318  bitree_uwi_t *dummy = (bitree_uwi_t*)space;
319  struct builder b = {DWARF_UNWINDER, dummy, 0};
320  int status = unw_reg_states_iterate(&c, dwarf_reg_states_callback, &b);
321  /* whatever libutils says about the last address range,
322  * we insist that it extend to the last address of this
323  * function range. but we can't rely on the so-called end of the function
324  * really being all the way to the end.*/
325  if (status == 0 &&
326  bitree_uwi_rootval(b.latest)->interval.end < (uintptr_t)(beg_insn + len))
327  bitree_uwi_rootval(b.latest)->interval.end = (uintptr_t)(beg_insn + len);
329 
330  btuwi_status_t stat;
331  stat.first_undecoded_ins = NULL;
332  stat.count = b.count;
333  stat.error = status;
334  stat.first = bitree_uwi_rightsubtree(dummy);
335 
336  return stat;
337 }
338 
339 // ----------------------------------------------------------
340 // libunw_unw_step:
341 // Given a cursor, step the cursor to the next (less deeply
342 // nested) frame using a recipe found previously, and find
343 // a new recipe for the next call.
344 // ---------------------------------------------------------
345 
348 {
349  step_state result = libunw_take_step(cursor);
350  if (result != STEP_ERROR) {
351  libunw_finalize_cursor(cursor);
352  }
353 
354 #if DEBUG_LIBUNWIND_INTERFACE
355  if (libunwind_debug) {
356  printf("result = %s\n", step_state_string(result));
357  }
358 #endif
359 
360  return result;
361 }
362 
363 void
364 libunw_uw_recipe_tostr(void *uwr, char str[])
365 {
366  snprintf(str, MAX_RECIPE_STR, "*");
367 }
bitree_uwi_t * first
ip_normalized_t hpcrun_normalize_ip(void *unnormalized_ip, load_module_t *lm)
Definition: ip-normalized.c:70
static int dwarf_reg_states_callback(void *token, void *rs, size_t size, unw_word_t start_ip, unw_word_t end_ip)
static char * tmp
Definition: tokenize.c:63
fence_enum_t fence
bitree_uwi_t * bitree_uwi_rightsubtree(bitree_uwi_t *tree)
uwi_t * bitree_uwi_rootval(bitree_uwi_t *tree)
libunw_state
char * first_undecoded_ins
bitree_uwi_t * latest
uintptr_t end
Definition: interval_t.h:28
interval_t interval
Definition: unwindr_info.h:100
enum libunw_state libunw_status
bitree_uwi_t * btuwi
Definition: unwindr_info.h:103
bool uw_recipe_map_lookup(void *addr, unwinder_t uw, unwindr_info_t *unwr_info)
uintptr_t lm_ip
Definition: ip-normalized.h:78
bitree_uwi_t * bitree_uwi_malloc(unwinder_t uw, size_t recipe_size)
interval_t interval
ip_normalized_t pc_norm
static void compute_normalized_ips(hpcrun_unw_cursor_t *cursor)
static void * libunw_cursor_get_pc(hpcrun_unw_cursor_t *cursor)
void hpcrun_stats_num_unwind_intervals_total_inc(void)
Definition: hpcrun_stats.c:239
struct bitree_uwi_s bitree_uwi_t
unwinder_t uw
#define MAX_RECIPE_STR
bool found
Definition: cct.c:129
btuwi_status_t libunw_build_intervals(char *beg_insn, unsigned int len)
#define TMSG(f,...)
Definition: messages.h:93
ip_normalized_t the_function
step_state libunw_take_step(hpcrun_unw_cursor_t *cursor)
char recipe[]
#define NULL
Definition: ElfHelper.cpp:85
load_module_t * lm
Definition: unwindr_info.h:101
enum unwinder_e unwinder_t
unsigned char uc
Definition: amd-xop.c:3
static arm_state_t state
uintptr_t start
Definition: interval_t.h:27
bool libunw_finalize_cursor(hpcrun_unw_cursor_t *cursor)
void libunw_uw_recipe_tostr(void *uwr, char str[])
step_state
Definition: unwind.h:124
void libunw_unw_init_cursor(hpcrun_unw_cursor_t *cursor, void *context)
unwindr_info_t unwr_info
step_state libunw_unw_step(hpcrun_unw_cursor_t *cursor)
void bitree_uwi_set_rightsubtree(bitree_uwi_t *tree, bitree_uwi_t *subtree)