HPCToolkit
uw_recipe_map.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 /*
48  * Maintain a map from address Intervals to unwind intervals.
49  *
50  * Note: the caller need not acquire/release locks as part
51  * of using the map.
52  *
53  * $Id$
54  */
55 
56 //---------------------------------------------------------------------
57 // debugging support
58 //---------------------------------------------------------------------
59 
60 #define UW_RECIPE_MAP_DEBUG 0
61 
62 #define UW_RECIPE_MAP_DEBUG_VERBOSE 0
63 
64 #if UW_RECIPE_MAP_DEBUG_VERBOSE
65 #undef UW_RECIPE_MAP_DEBUG
66 #define UW_RECIPE_MAP_DEBUG 1
67 #endif
68 
69 
70 #if UW_RECIPE_MAP_DEBUG
71 #include <assert.h>
72 #include <stdlib.h>
73 #include <stdio.h>
74 #endif
75 
76 
77 
78 //---------------------------------------------------------------------
79 // local include files
80 //---------------------------------------------------------------------
81 #include <memory/hpcrun-malloc.h>
82 #include <main.h>
83 #include "thread_data.h"
84 #include "uw_recipe_map.h"
85 #include "unwind-interval.h"
88 #include <lib/prof-lean/mcs-lock.h>
90 #include "binarytree_uwi.h"
91 #include "segv_handler.h"
92 #include <messages/messages.h>
93 
94 // libmonitor functions
95 #include <monitor.h>
96 
97 //******************************************************************************
98 // global include files
99 //******************************************************************************
100 
101 #include <stdio.h>
102 #include <stdlib.h>
103 #include <string.h>
104 
105 //---------------------------------------------------------------------
106 // macros
107 //---------------------------------------------------------------------
108 
109 #define SKIPLIST_HEIGHT 8
110 
111 #define NUM_NODES 10
112 
113 //******************************************************************************
114 // type
115 //******************************************************************************
116 
117 typedef struct ilmstat_btuwi_pair_s {
120  _Atomic(tree_stat_t) stat;
121  bitree_uwi_t *btuwi;
123 
124 //******************************************************************************
125 // Comparators
126 //******************************************************************************
127 
128 /*
129  * pre-condition: lhs, rhs are ilmstat_btuwi_pair_t*
130  */
131 static int
132 ilmstat_btuwi_pair_cmp(void *lhs, void *rhs)
133 {
136  return interval_t_cmp(
137  &l->interval,
138  &r->interval);
139 }
140 
141 /*
142  * pre-condition: itp is a ilmstat_btuwi_pair_t*, address is a uintptr_t
143  * return interval_ldmod_pair_inrange(itp->first, address)
144  */
145 static int
146 ilmstat_btuwi_pair_inrange(void *itp, void *address)
147 {
149  return interval_t_inrange(&p->interval, address);
150 }
151 
152 static ilmstat_btuwi_pair_t *GF_ilmstat_btuwi = NULL; // global free list of ilmstat_btuwi_pair_t*
153 static mcs_lock_t GFL_lock; // lock for GF_ilmstat_btuwi
154 static __thread ilmstat_btuwi_pair_t *_lf_ilmstat_btuwi = NULL; // thread local free list of ilmstat_btuwi_pair_t*
155 
156 
157 //******************************************************************************
158 // Constructors
159 //******************************************************************************
160 
161 static inline ilmstat_btuwi_pair_t *
163  tree_stat_t treestat,
164  load_module_t *lm,
165  uintptr_t start,
166  uintptr_t end)
167 {
168  atomic_store_explicit(&node->stat, treestat, memory_order_relaxed);
169  node->lm = lm;
170  node->interval.start = start;
171  node->interval.end = end;
172  node->btuwi = NULL;
173  return node;
174 }
175 
176 static inline ilmstat_btuwi_pair_t*
177 ilmstat_btuwi_pair_build(uintptr_t start, uintptr_t end, load_module_t *lm,
178  tree_stat_t treestat, mem_alloc m_alloc)
179 {
180  ilmstat_btuwi_pair_t* node = m_alloc(sizeof(*node));
181  return ilmstat__btuwi_pair_init(node, treestat, lm, start, end);
182 }
183 
184 static inline void
186 {
187  pair->btuwi = (bitree_uwi_t *)*list;
188  *list = pair;
189 }
190 
191 static inline ilmstat_btuwi_pair_t *
193 {
194  ilmstat_btuwi_pair_t *head = *list;
195  *list = (ilmstat_btuwi_pair_t *)head->btuwi;
196  return head;
197 }
198 
199 static ilmstat_btuwi_pair_t*
201  uintptr_t start,
202  uintptr_t end,
203  load_module_t *lm,
204  tree_stat_t treestat,
205  mem_alloc m_alloc)
206 {
207  if (!_lf_ilmstat_btuwi) {
208  /*
209  * Look for nodes in the global free list.
210  * If the global free list is not empty,
211  * transfer a bunch of nodes to the local free list,
212  * otherwise add a bunch of nodes to the local free list.
213  */
214  mcs_node_t me;
215  bool acquired = mcs_trylock(&GFL_lock, &me);
216  if (acquired) {
217  if (GF_ilmstat_btuwi) {
218  // transfer a bunch of nodes the global free list to the local free list
219  int n = 0;
220  while (GF_ilmstat_btuwi && n < NUM_NODES) {
221  ilmstat_btuwi_pair_t *head = pop_free_pair(&GF_ilmstat_btuwi);
223  n++;
224  }
225  }
226  mcs_unlock(&GFL_lock, &me);
227  }
228  if (!_lf_ilmstat_btuwi) {
229  /* add a bunch of nodes to _lf_ilmstat_btuwi */
230  for (int i = 0; i < NUM_NODES; i++) {
231  ilmstat_btuwi_pair_t *node = m_alloc(sizeof(*node));
233  }
234  }
235  }
236 
237 #if UW_RECIPE_MAP_DEBUG
238  assert (_lf_ilmstat_btuwi);
239 #endif
240 
241 /*
242  * remove the head node of the local free list
243  * set its fields using the appropriate parameters
244  * return the head node.
245  */
247  return ilmstat__btuwi_pair_init(ans, treestat, lm, start, end);
248 }
249 
250 //******************************************************************************
251 // Destructor
252 //******************************************************************************
253 
254 static void
256 {
257  if (!pair) return;
258  bitree_uwi_free(uw, pair->btuwi);
259 
260  // add pair to the front of the global free list of ilmstat_btuwi_pair_t*:
261  mcs_node_t me;
262  mcs_lock(&GFL_lock, &me);
263  push_free_pair(&GF_ilmstat_btuwi, pair);
264  mcs_unlock(&GFL_lock, &me);
265 }
266 
267 //---------------------------------------------------------------------
268 // local data
269 //---------------------------------------------------------------------
270 
271 // The concrete representation of the abstract data type unwind recipe map.
273 
274 // memory allocator for creating addr2recipe_map
275 // and inserting entries into addr2recipe_map:
277 
278 //******************************************************************************
279 // String output
280 //******************************************************************************
281 
282 
283 #define MAX_STAT_STR 14
284 #define LDMOD_NAME_LEN 128
285 #define MAX_ILDMODSTAT_STR MAX_INTERVAL_STR+LDMOD_NAME_LEN+MAX_STAT_STR
286 
287 
288 //---------------------------------------------------------------------
289 // private operations
290 //---------------------------------------------------------------------
291 
292 #if UW_RECIPE_MAP_DEBUG
293 static void
294 uw_recipe_map_report(const char *op, void *start, void *end)
295 {
296  fprintf(stderr, "%s [start=%p, end=%p)\n", op, start, end);
297 }
298 #else
299 #define uw_recipe_map_report(op, start, end)
300 #endif
301 
302 //---------------------------------------------------------------------
303 // debug operations
304 //---------------------------------------------------------------------
305 
306 
307 #if UW_RECIPE_MAP_DEBUG_VERBOSE
308 static void
309 treestat_tostr(tree_stat_t stat, char str[])
310 {
311  switch (stat) {
312  case NEVER: strcpy(str, " NEVER"); break;
313  case DEFERRED: strcpy(str, " DEFERRED"); break;
314  case FORTHCOMING: strcpy(str, "FORTHCOMING"); break;
315  case READY: strcpy(str, " READY"); break;
316  default: strcpy(str, "STAT_ERROR");
317  }
318 }
319 
320 static void
321 load_module_tostr(void* lm, char str[])
322 {
323  load_module_t* ldmod = (load_module_t*)lm;
324  if (ldmod) {
325  snprintf(str, LDMOD_NAME_LEN, "%s%s%d", ldmod->name, " ", ldmod->id);
326  }
327  else {
328  snprintf(str, LDMOD_NAME_LEN, "%s", "nil");
329  }
330 }
331 
332 static void
333 ildmod_stat_tostr(void* ilms, char str[])
334 {
335  ilmstat_btuwi_pair_t *pair = ilms;
336  char intervalstr[MAX_INTERVAL_STR];
337  interval_t_tostr(&pair->interval, intervalstr);
338  char ldmodstr[LDMOD_NAME_LEN];
339  load_module_tostr(pair->lm, ldmodstr);
340  char statstr[MAX_STAT_STR];
341  treestat_tostr(atomic_load_explicit(&pair->stat, memory_order_relaxed), statstr);
342  sprintf(str, "(%s %s %s)", intervalstr, ldmodstr, statstr);
343 }
344 
345 
346 
347 static int
348 max_ilmstat_btuwi_pair_len()
349 {
350  return MAX_ILDMODSTAT_STR + MAX_TREE_STR + 4;
351 }
352 
353 
354 static char
355 ILdMod_Stat_MaxSpaces[] = " ";
356 
357 /*
358  * the max spaces occupied by "([start_address ... end_address), load module xx, status)
359  */
360 static char*
361 ildmod_stat_maxspaces()
362 {
363  return ILdMod_Stat_MaxSpaces;
364 }
365 
366 /*
367  * Compute a string representation of map and store result in str.
368  */
369 /*
370  * pre-condition: *nodeval is an ilmstat_btuwi_pair_t.
371  */
372 
373 static void
374 cskl_ilmstat_btuwi_any_node_tostr(void* nodeval, int node_height, int max_height,
375  char str[], int max_cskl_str_len, unwinder_t uw)
376 {
377  cskl_levels_tostr(node_height, max_height, str, max_cskl_str_len);
378 
379  // build needed indentation to print the binary tree inside the skiplist:
380  char indents[MAX_CSKIPLIST_STR];
381  snprintf(indents, MAX_CSKIPLIST_STR, "%s%s", str, ildmod_stat_maxspaces());
382 
383  // print the binary tree with the proper indentation:
384  char itpairStr[max_ilmstat_btuwi_pair_len()];
385  ilmstat_btuwi_pair_t* it_pair = (ilmstat_btuwi_pair_t*)nodeval;
386  /*
387  * Compute the string representation of ilmstat_btuwi_pair_t with
388  * appropriate indentation of the second component which is a binary
389  * tree.
390  */
391  bitree_uwi_t *tree = it_pair->btuwi;
392  char firststr[MAX_ILDMODSTAT_STR];
393  char secondstr[MAX_TREE_STR];
394  ildmod_stat_tostr(it_pair, firststr);
395  bitree_uwi_tostring_indent(tree, indents, secondstr, uw);
396  snprintf(itpairStr, strlen(firststr) + strlen(secondstr) + 6, "%s%s%s%s%s",
397  "(", firststr, ", ", secondstr, ")");
398 
399  // add new line:
400  cskl_append_node_str(itpairStr, str, max_cskl_str_len);
401 }
402 
403 
404 static void
405 cskl_ilmstat_btuwi_dwarf_node_tostr(void* nodeval, int node_height, int max_height,
406  char str[], int max_cskl_str_len)
407 {
408  cskl_ilmstat_btuwi_any_node_tostr(nodeval, node_height, max_height, str, max_cskl_str_len,
410 }
411 
412 static void
413 cskl_ilmstat_btuwi_native_node_tostr(void* nodeval, int node_height, int max_height,
414  char str[], int max_cskl_str_len)
415 {
416  cskl_ilmstat_btuwi_any_node_tostr(nodeval, node_height, max_height, str, max_cskl_str_len,
418 }
419 
420 static void
421 (*cskl_ilmstat_btuwi_node_tostr[NUM_UNWINDERS])(void* nodeval, int node_height, int max_height,
422  char str[], int max_cskl_str_len) =
423 {
424  [DWARF_UNWINDER] = cskl_ilmstat_btuwi_dwarf_node_tostr,
425  [NATIVE_UNWINDER] = cskl_ilmstat_btuwi_native_node_tostr
426 };
427 
428 static void
429 uw_recipe_map_report_and_dump(const char *op, void *start, void *end)
430 {
431  uw_recipe_map_report(op, start, end);
432  unwinder_t uw;
433  for (uw = 0; uw < NUM_UNWINDERS; uw++) {
434  char buf[MAX_CSKIPLIST_STR];
435  cskl_tostr(addr2recipe_map[uw], cskl_ilmstat_btuwi_node_tostr[uw], buf, MAX_CSKIPLIST_STR);
436  fprintf(stderr, "%s", buf);
437  }
438 }
439 #else
440 #define uw_recipe_map_report_and_dump(op, start, end)
441 #endif
442 
443 static void
444 uw_recipe_map_poison(uintptr_t start, uintptr_t end, unwinder_t uw)
445 {
446  uw_recipe_map_report("uw_recipe_map_poison", (void *) start, (void *) end);
447 
448  ilmstat_btuwi_pair_t* itpair =
450  csklnode_t *node = cskl_insert(addr2recipe_map[uw], itpair, my_alloc);
451  if (itpair != (ilmstat_btuwi_pair_t*)node->val)
452  ilmstat_btuwi_pair_free(itpair, uw);
453 }
454 
455 
456 /*
457  * if the given address, value, is in the range of a node in the cskiplist,
458  * return that node, otherwise return NULL.
459  */
460 static ilmstat_btuwi_pair_t*
462 {
463  return (ilmstat_btuwi_pair_t*)cskl_inrange_find(addr2recipe_map[uw], (void*)addr);
464 }
465 
466 static void
468 {
469 #if CSKL_ILS_BTU
470 // printf("DXN_DBG cskl_ilmstat_btuwi_free(%p)...\n", anode);
471 #endif
472 
473  csklnode_t *node = (csklnode_t*) anode;
474  ilmstat_btuwi_pair_t *ilmstat_btuwi = (ilmstat_btuwi_pair_t*)node->val;
475  ilmstat_btuwi_pair_free(ilmstat_btuwi, uw);
476  node->val = NULL;
477  cskl_free(node);
478 }
479 
480 static void
482 {
483  cskl_ilmstat_btuwi_free_uw(anode, 0);
484 }
485 
486 
487 static void
489 {
490  cskl_ilmstat_btuwi_free_uw(anode, 1);
491 }
492 
493 static void (*cskl_ilmstat_btuwi_free[])(void *anode) =
495 
496 static bool
499  unwinder_t uw)
500 {
501  return cskl_cmp_del_bulk_unsynch(addr2recipe_map[uw], key, key, cskl_ilmstat_btuwi_free[uw]);
502 }
503 
504 static void
505 uw_recipe_map_unpoison(uintptr_t start, uintptr_t end, unwinder_t uw)
506 {
507  ilmstat_btuwi_pair_t* ilmstat_btuwi = uw_recipe_map_inrange_find(start, uw);
508  if (ilmstat_btuwi == NULL)
509  return;
510 
511  uw_recipe_map_report("uw_recipe_map_unpoison", (void *) start, (void *) end);
512 
513 #if UW_RECIPE_MAP_DEBUG
514  assert(ilmstat_btuwi != NULL); // start should be in range of some poisoned interval
515  assert(atomic_load_explicit(&ilmstat_btuwi->stat, memory_order_relaxed) == NEVER); // should be a poisoned node
516 #endif
517 
518  uintptr_t s0 = ilmstat_btuwi->interval.start;
519  uintptr_t e0 = ilmstat_btuwi->interval.end;
520  uw_recipe_map_cmp_del_bulk_unsynch(ilmstat_btuwi, uw);
521  uw_recipe_map_poison(s0, start, uw);
522  uw_recipe_map_poison(end, e0, uw);
523 }
524 
525 
526 static void
527 uw_recipe_map_repoison(uintptr_t start, uintptr_t end, unwinder_t uw)
528 {
529  if (start > 0) {
530  ilmstat_btuwi_pair_t* ileft = uw_recipe_map_inrange_find(start - 1, uw);
531  if (ileft) {
532  if ((ileft->interval.end == start) &&
533  (NEVER == atomic_load_explicit(&ileft->stat, memory_order_acquire))) {
534  // poisoned interval adjacent on the left
535  start = ileft->interval.start;
537  }
538  }
539  }
540  if (end < UINTPTR_MAX) {
542  if (iright) {
543  if ((iright->interval.start == end) &&
544  (NEVER == atomic_load_explicit(&iright->stat, memory_order_acquire))) {
545  // poisoned interval adjacent on the right
546  end = iright->interval.end;
548  }
549  }
550  }
551  uw_recipe_map_poison(start, end, uw);
552 }
553 
554 static void
555 uw_recipe_map_notify_map(void *start, void *end)
556 {
557  uw_recipe_map_report_and_dump("*** map: before unpoisoning", start, end);
558 
559  unwinder_t uw;
560  for (uw = 0; uw < NUM_UNWINDERS; uw++)
561  uw_recipe_map_unpoison((uintptr_t)start, (uintptr_t)end, uw);
562 
563  uw_recipe_map_report_and_dump("*** map: after unpoisoning", start, end);
564 }
565 
566 
567 static void
568 uw_recipe_map_notify_unmap(void *start, void *end)
569 {
570  uw_recipe_map_report_and_dump("*** unmap: before poisoning", start, end);
571 
572  // Remove intervals in the range [start, end) from the unwind interval tree.
573  TMSG(UW_RECIPE_MAP, "uw_recipe_map_delete_range from %p to %p", start, end);
574  unwinder_t uw;
575  for (uw = 0; uw < NUM_UNWINDERS; uw++)
576  cskl_inrange_del_bulk_unsynch(addr2recipe_map[uw], start, ((void*)((char *) end) - 1), cskl_ilmstat_btuwi_free[uw]);
577 
578  // join poisoned intervals here.
579  for (uw = 0; uw < NUM_UNWINDERS; uw++)
580  uw_recipe_map_repoison((uintptr_t)start, (uintptr_t)end, uw);
581 
582  uw_recipe_map_report_and_dump("*** unmap: after poisoning", start, end);
583 }
584 
585 static void
587 {
588  static loadmap_notify_t uw_recipe_map_notifiers;
589 
590  uw_recipe_map_notifiers.map = uw_recipe_map_notify_map;
591  uw_recipe_map_notifiers.unmap = uw_recipe_map_notify_unmap;
592  hpcrun_loadmap_notify_register(&uw_recipe_map_notifiers);
593 }
594 
595 
596 
597 //---------------------------------------------------------------------
598 // interface operations
599 //---------------------------------------------------------------------
600 
601 void
603 {
605 #if UW_RECIPE_MAP_DEBUG
606  fprintf(stderr, "uw_recipe_map_init: call a2r_map_init(my_alloc) ... \n");
607 #endif
608 
609  cskl_init();
610 #if UW_RECIPE_MAP_DEBUG
611  fprintf(stderr, "%s: mcs_init(&GFL_lock), call bitree_uwi_init() \n", __func__);
612 #endif
613  mcs_init(&GFL_lock);
615 
616  TMSG(UW_RECIPE_MAP, "init address-to-recipe map");
617  ilmstat_btuwi_pair_t* lsentinel =
619  ilmstat_btuwi_pair_t* rsentinel =
620  ilmstat_btuwi_pair_build(UINTPTR_MAX, UINTPTR_MAX, NULL, NEVER, my_alloc );
621  unwinder_t uw;
622  for (uw = 0; uw < NUM_UNWINDERS; uw++)
623  addr2recipe_map[uw] =
624  cskl_new(lsentinel, rsentinel, SKIPLIST_HEIGHT,
626 
628 
629  // initialize the map with a POISONED node ({([0, UINTPTR_MAX), NULL), NEVER}, NULL)
630  for (uw = 0; uw < NUM_UNWINDERS; uw++)
631  uw_recipe_map_poison(0, UINTPTR_MAX, uw);
632 }
633 
634 
635 /*
636  *
637  */
638 bool
640 {
641  // fill unwr_info with appropriate values to indicate that the lookup fails and the unwind recipe
642  // information is invalid, in case of failure.
643  // known use case:
644  // hpcrun_generate_backtrace_no_trampoline calls
645  // 1. hpcrun_unw_init_cursor(&cursor, context), which calls
646  // uw_recipe_map_lookup,
647  // 2. hpcrun_unw_step(&cursor), which calls
648  // hpcrun_unw_step_real(cursor), which looks at cursor->unwr_info
649 
650  unwr_info->btuwi = NULL;
651  unwr_info->treestat = NEVER;
652  unwr_info->lm = NULL;
653  unwr_info->interval.start = 0;
654  unwr_info->interval.end = 0;
655 
656  // check if addr is already in the range of an interval key in the map
657  ilmstat_btuwi_pair_t* ilm_btui =
658  uw_recipe_map_inrange_find((uintptr_t)addr, uw);
659 
660  if (!ilm_btui) {
661  load_module_t *lm;
662  void *fcn_start, *fcn_end;
663  if (!fnbounds_enclosing_addr(addr, &fcn_start, &fcn_end, &lm)) {
664  TMSG(UW_RECIPE_MAP, "BAD fnbounds_enclosing_addr failed: addr %p", addr);
665  return false;
666  }
667  if (addr < fcn_start || fcn_end <= addr) {
668  TMSG(UW_RECIPE_MAP, "BAD fnbounds_enclosing_addr failed: addr %p "
669  "not within fcn range %p to %p", addr, fcn_start, fcn_end);
670  return false;
671  }
672 
673  // bounding addresses found; set DEFERRED state and pair it with
674  // (bitree_uwi_t*)NULL and try to insert into map:
675  ilm_btui =
676  ilmstat_btuwi_pair_malloc((uintptr_t)fcn_start, (uintptr_t)fcn_end, lm,
677  DEFERRED, my_alloc);
678 
679 
680  csklnode_t *node = cskl_insert(addr2recipe_map[uw], ilm_btui, my_alloc);
681  if (ilm_btui != (ilmstat_btuwi_pair_t*)node->val) {
682  // interval_ldmod_pair ([fcn_start, fcn_end), lm) is already in the map,
683  // so free the unused copy and use the mapped one
684  ilmstat_btuwi_pair_free(ilm_btui, uw);
685  ilm_btui = (ilmstat_btuwi_pair_t*)node->val;
686  }
687  // ilm_btui is now in the map.
688  }
689 #if UW_RECIPE_MAP_DEBUG
690  assert(ilm_btui != NULL);
691 #endif
692 
693  tree_stat_t oldstat = DEFERRED;
694  if (atomic_compare_exchange_strong_explicit(&ilm_btui->stat, &oldstat, FORTHCOMING,
696  // it is my responsibility to build the tree of intervals for the function
697  void *fcn_start = (void*)ilm_btui->interval.start;
698  void *fcn_end = (void*)ilm_btui->interval.end;
699 
700  // ----------------------------------------------------------
701  // potentially crash in this statement. need to save the state
702  // ----------------------------------------------------------
703 
705  sigjmp_buf_t *oldjmp = td->current_jmp_buf; // store the outer sigjmp
706 
707  td->current_jmp_buf = &(td->bad_interval);
708 
709  int ljmp = sigsetjmp(td->bad_interval.jb, 1);
710  if (ljmp == 0) {
711  btuwi_status_t btuwi_stat = build_intervals(fcn_start, fcn_end - fcn_start, uw);
712  if (btuwi_stat.error != 0) {
713  TMSG(UW_RECIPE_MAP, "build_intervals: fcn range %p to %p: error %d",
714  fcn_start, fcn_end, btuwi_stat.error);
715  }
716  ilm_btui->btuwi = bitree_uwi_rebalance(btuwi_stat.first, btuwi_stat.count);
718 
719  td->current_jmp_buf = oldjmp; // restore the outer sigjmp
720 
721  } else {
722  td->current_jmp_buf = oldjmp; // restore the outer sigjmp
723  EMSG("Fail to get interval %p to %p", fcn_start, fcn_end);
725  return false;
726  }
727  }
728  else {
729  while (FORTHCOMING == oldstat)
730  oldstat = atomic_load_explicit(&ilm_btui->stat, memory_order_acquire);
731  if (oldstat == NEVER) {
732  // addr is in the range of some poisoned load module
733  return false;
734  }
735  }
736 
737  TMSG(UW_RECIPE_MAP_LOOKUP, "found in unwind tree: addr %p", addr);
738 
739  bitree_uwi_t *btuwi = ilm_btui->btuwi;
740  unwr_info->btuwi = bitree_uwi_inrange(btuwi, (uintptr_t)addr);
741  unwr_info->treestat = READY;
742  unwr_info->lm = ilm_btui->lm;
743  unwr_info->interval = ilm_btui->interval;
744 
745  return (unwr_info->btuwi != NULL);
746 }
static void cskl_ilmstat_btuwi_free_uw(void *anode, unwinder_t uw)
bitree_uwi_t * first
#define MAX_INTERVAL_STR
Definition: interval_t.h:20
static ilmstat_btuwi_pair_t * ilmstat__btuwi_pair_init(ilmstat_btuwi_pair_t *node, tree_stat_t treestat, load_module_t *lm, uintptr_t start, uintptr_t end)
void *(* mem_alloc)(size_t size)
Definition: mem_manager.h:17
#define MAX_STAT_STR
static mem_alloc my_alloc
bitree_uwi_t * bitree_uwi_rebalance(bitree_uwi_t *tree, int count)
void mcs_lock(mcs_lock_t *l, mcs_node_t *me)
Definition: mcs-lock.c:77
static void uw_recipe_map_notify_init()
static mcs_lock_t GFL_lock
void cskl_tostr(cskiplist_t *cskl, cskl_node_tostr node_tostr, char csklstr[], int max_cskl_str_len)
Definition: cskiplist.c:706
static __thread ilmstat_btuwi_pair_t * _lf_ilmstat_btuwi
static void(* cskl_ilmstat_btuwi_free[])(void *anode)
static bool uw_recipe_map_cmp_del_bulk_unsynch(ilmstat_btuwi_pair_t *key, unwinder_t uw)
int interval_t_cmp(void *lhs, void *rhs)
Definition: interval_t.c:21
void hpcrun_loadmap_notify_register(loadmap_notify_t *n)
Definition: loadmap.c:74
cskiplist_t * cskl_new(void *lsentinel, void *rsentinel, int max_height, val_cmp compare, val_cmp inrange, mem_alloc m_alloc)
Definition: cskiplist.c:441
#define NUM_NODES
load_module_t * lm
int interval_t_inrange(void *lhs, void *val)
Definition: interval_t.c:31
void cskl_free(void *anode)
Definition: cskiplist.c:422
static void uw_recipe_map_notify_unmap(void *start, void *end)
#define LDMOD_NAME_LEN
#define MAX_TREE_STR
Definition: binarytree.h:83
static void cskl_ilmstat_btuwi_free_0(void *anode)
bool cskl_inrange_del_bulk_unsynch(cskiplist_t *cskl, void *lo, void *hi, mem_free m_free)
Definition: cskiplist.c:672
static ilmstat_btuwi_pair_t * ilmstat_btuwi_pair_build(uintptr_t start, uintptr_t end, load_module_t *lm, tree_stat_t treestat, mem_alloc m_alloc)
static int ilmstat_btuwi_pair_inrange(void *itp, void *address)
#define MAX_CSKIPLIST_STR
Definition: cskiplist.h:78
void * cskl_inrange_find(cskiplist_t *cskl, void *value)
Definition: cskiplist.c:475
uintptr_t end
Definition: interval_t.h:28
Definition: fmt.c:108
cct_node_t * node
Definition: cct.c:128
btuwi_status_t build_intervals(char *ins, unsigned int len, unwinder_t uw)
interval_t interval
Definition: unwindr_info.h:100
bool cskl_cmp_del_bulk_unsynch(cskiplist_t *cskl, void *lo, void *hi, mem_free m_free)
Definition: cskiplist.c:666
bitree_uwi_t * bitree_uwi_inrange(bitree_uwi_t *tree, uintptr_t address)
#define atomic_load_explicit(object, order)
Definition: stdatomic.h:378
bitree_uwi_t * btuwi
Definition: unwindr_info.h:103
static ilmstat_btuwi_pair_t * ilmstat_btuwi_pair_malloc(uintptr_t start, uintptr_t end, load_module_t *lm, tree_stat_t treestat, mem_alloc m_alloc)
bool uw_recipe_map_lookup(void *addr, unwinder_t uw, unwindr_info_t *unwr_info)
#define atomic_store_explicit(object, desired, order)
Definition: stdatomic.h:380
uint16_t id
Definition: loadmap.h:127
tree_stat_t
Definition: unwindr_info.h:95
bool mcs_trylock(mcs_lock_t *l, mcs_node_t *me)
Definition: mcs-lock.c:122
void mcs_unlock(mcs_lock_t *l, mcs_node_t *me)
Definition: mcs-lock.c:146
char * name
Definition: loadmap.h:128
static void uw_recipe_map_poison(uintptr_t start, uintptr_t end, unwinder_t uw)
sigjmp_buf_t bad_interval
Definition: thread_data.h:212
#define MAX_ILDMODSTAT_STR
loadmap_notify_range_t map
Definition: loadmap.h:244
static ilmstat_btuwi_pair_t * uw_recipe_map_inrange_find(uintptr_t addr, unwinder_t uw)
#define atomic_compare_exchange_strong_explicit(object, expected, desired, success, failure)
Definition: stdatomic.h:335
#define EMSG
Definition: messages.h:70
void hpcrun_set_real_siglongjmp(void)
Definition: main.c:1148
static void uw_recipe_map_notify_map(void *start, void *end)
struct bitree_uwi_s bitree_uwi_t
static void cskl_ilmstat_btuwi_free_1(void *anode)
static ilmstat_btuwi_pair_t * GF_ilmstat_btuwi
static void uw_recipe_map_repoison(uintptr_t start, uintptr_t end, unwinder_t uw)
void cskl_init()
Definition: cskiplist.c:409
sigjmp_buf_t * current_jmp_buf
Definition: thread_data.h:211
void * hpcrun_malloc(size_t size)
Definition: mem.c:275
#define uw_recipe_map_report_and_dump(op, start, end)
csklnode_t * cskl_insert(cskiplist_t *cskl, void *value, mem_alloc m_alloc)
Definition: cskiplist.c:483
struct ilmstat_btuwi_pair_s ilmstat_btuwi_pair_t
#define _Atomic(T)
Definition: stdatomic.h:121
void cskl_append_node_str(char nodestr[], char str[], int max_cskl_str_len)
Definition: cskiplist.c:697
void bitree_uwi_init(mem_alloc m_alloc)
void bitree_uwi_free(unwinder_t uw, bitree_uwi_t *tree)
void interval_t_tostr(void *ptrinterval, char result[])
Definition: interval_t.c:49
#define TMSG(f,...)
Definition: messages.h:93
#define SKIPLIST_HEIGHT
#define uw_recipe_map_report(op, start, end)
#define NULL
Definition: ElfHelper.cpp:85
load_module_t * lm
Definition: unwindr_info.h:101
void cskl_levels_tostr(int height, int max_height, char str[], int max_cskl_str_len)
Definition: cskiplist.c:678
enum unwinder_e unwinder_t
uintptr_t start
Definition: interval_t.h:27
static void ilmstat_btuwi_pair_free(ilmstat_btuwi_pair_t *pair, unwinder_t uw)
cct_addr_t * addr
Definition: cct.c:130
tree_stat_t treestat
Definition: unwindr_info.h:102
static void push_free_pair(ilmstat_btuwi_pair_t **list, ilmstat_btuwi_pair_t *pair)
<!-- ********************************************************************--> n<!-- HPCToolkit Experiment DTD --> n<!-- Version 2.1 --> n<!-- ********************************************************************--> n<!ELEMENT HPCToolkitExperiment(Header,(SecCallPathProfile|SecFlatProfile) *)> n<!ATTLIST HPCToolkitExperiment\n version CDATA #REQUIRED > n n<!-- ******************************************************************--> n n<!-- Info/NV:flexible name-value pairs:(n) ame;(t) ype;(v) alue --> n<!ELEMENT Info(NV *)> n<!ATTLIST Info\n n CDATA #IMPLIED > n<!ELEMENT NV EMPTY > n<!ATTLIST NV\n n CDATA #REQUIRED\n t CDATA #IMPLIED\n v CDATA #REQUIRED > n n<!-- ******************************************************************--> n<!-- Header --> n<!-- ******************************************************************--> n<!ELEMENT Header(Info *)> n<!ATTLIST Header\n n CDATA #REQUIRED > n n<!-- ******************************************************************--> n<!-- Section Header --> n<!-- ******************************************************************--> n<!ELEMENT SecHeader(MetricTable?, MetricDBTable?, TraceDBTable?, LoadModuleTable?, FileTable?, ProcedureTable?, Info *)> n n<!-- MetricTable:--> n<!ELEMENT MetricTable(Metric) * > n n<!-- Metric:(i) d;(n) ame --> n<!--(v) alue-type:transient type of values --> n<!--(t) ype:persistent type of metric --> n<!-- fmt:format;show;--> n<!ELEMENT Metric(MetricFormula *, Info?)> n<!ATTLIST Metric\n i CDATA #REQUIRED\n n CDATA #REQUIRED\n es CDATA #IMPLIED\n em CDATA #IMPLIED\n ep CDATA #IMPLIED\n v(raw|final|derived-incr|derived) \"raw\\ t (inclusive|exclusive|nil) \nil\\ partner CDATA #IMPLIED\ fmt CDATA #IMPLIED\ show (1|0) \1\\ show-percent (1|0) \1> n n<!-- MetricFormula represents derived metrics: (t)ype; (frm): formula --> n<!ELEMENT MetricFormula (Info?)> n<!ATTLIST MetricFormula\ t (combine|finalize) \finalize\\ i CDATA #IMPLIED\ frm CDATA #REQUIRED> n n<!-- Metric data, used in sections: (n)ame [from Metric]; (v)alue --> n<!ELEMENT M EMPTY> n<!ATTLIST M\ n CDATA #REQUIRED\ v CDATA #REQUIRED> n n<!-- MetricDBTable: --> n<!ELEMENT MetricDBTable (MetricDB)*> n n<!-- MetricDB: (i)d; (n)ame --> n<!-- (t)ype: persistent type of metric --> n<!-- db-glob: file glob describing files in metric db --> n<!-- db-id: id within metric db --> n<!-- db-num-metrics: number of metrics in db --> n<!-- db-header-sz: size (in bytes) of a db file header --> n<!ELEMENT MetricDB EMPTY> n<!ATTLIST MetricDB\ i CDATA #REQUIRED\ n CDATA #REQUIRED\ t (inclusive|exclusive|nil) \nil\\ partner CDATA #IMPLIED\ db-glob CDATA #IMPLIED\ db-id CDATA #IMPLIED\ db-num-metrics CDATA #IMPLIED\ db-header-sz CDATA #IMPLIED> n n<!-- TraceDBTable: --> n<!ELEMENT TraceDBTable (TraceDB)> n n<!-- TraceDB: (i)d --> n<!-- db-min-time: min beginning time stamp (global) --> n<!-- db-max-time: max ending time stamp (global) --> n<!ELEMENT TraceDB EMPTY> n<!ATTLIST TraceDB\ i CDATA #REQUIRED\ db-glob CDATA #IMPLIED\ db-min-time CDATA #IMPLIED\ db-max-time CDATA #IMPLIED\ db-header-sz CDATA #IMPLIED> n n<!-- LoadModuleTable assigns a short name to a load module --> n<!ELEMENT LoadModuleTable (LoadModule)*> n n<!ELEMENT LoadModule (Info?)> n<!ATTLIST LoadModule\ i CDATA #REQUIRED\ n CDATA #REQUIRED> n n<!-- FileTable assigns a short name to a file --> n<!ELEMENT FileTable (File)*> n n<!ELEMENT File (Info?)> n<!ATTLIST File\ i CDATA #REQUIRED\ n CDATA #REQUIRED> n n<!-- ProcedureTable assigns a short name to a procedure --> n<!ELEMENT ProcedureTable (Procedure)*> n n<!-- Info/NV: flexible name-value pairs: (n)ame; (t)ype; (v)alue --> n<!-- f: family of the procedure (fake, root, ...)--> n<!ELEMENT Procedure (Info?)> n<!ATTLIST Procedure\ i CDATA #REQUIRED\ n CDATA #REQUIRED\ f CDATA #IMPLIED> n n<!-- ****************************************************************** --> n<!-- Section: Call path profile --> n<!-- ****************************************************************** --> n<!ELEMENT SecCallPathProfile (SecHeader, SecCallPathProfileData)> n<!ATTLIST SecCallPathProfile\ i CDATA #REQUIRED\ n CDATA #REQUIRED> n n<!ELEMENT SecCallPathProfileData (PF|M)*> n<!-- Procedure frame --> n<!-- (i)d: unique identifier for cross referencing --> n<!-- (s)tatic scope id --> n<!-- (n)ame: a string or an id in ProcedureTable --> n<!-- (lm) load module: a string or an id in LoadModuleTable --> n<!-- (f)ile name: a string or an id in LoadModuleTable --> n<!-- (l)ine range: \beg-end\ (inclusive range) --> n<!-- (a)lien: whether frame is alien to enclosing P --> n<!-- (str)uct: hpcstruct node id --> n<!-- (t)ype: hpcrun node type: memory access, variable declaration, ... --> n<!-- (v)ma-range-set: \{[beg-end), [beg-end)...}\ --> n<!ELEMENT PF (PF|Pr|L|C|S|M)*> n<!ATTLIST PF\ i CDATA #IMPLIED\ s CDATA #IMPLIED\ n CDATA #REQUIRED\ lm CDATA #IMPLIED\ f CDATA #IMPLIED\ l CDATA #IMPLIED\ str CDATA #IMPLIED\ v CDATA #IMPLIED> n<!-- Procedure (static): GOAL: replace with 'P' --> n<!ELEMENT Pr (Pr|L|C|S|M)*> n<!ATTLIST Pr\ i CDATA #IMPLIED\ s CDATA #IMPLIED\ n CDATA #REQUIRED\ lm CDATA #IMPLIED\ f CDATA #IMPLIED\ l CDATA #IMPLIED\ a (1|0) \0\\ str CDATA #IMPLIED\ v CDATA #IMPLIED> n<!-- Callsite (a special StatementRange) --> n<!ELEMENT C (PF|M)*> n<!ATTLIST C\ i CDATA #IMPLIED\ s CDATA #IMPLIED\ l CDATA #IMPLIED\ str CDATA #IMPLIED\ v CDATA #IMPLIED> n n<!-- ****************************************************************** --> n<!-- Section: Flat profile --> n<!-- ****************************************************************** --> n<!ELEMENT SecFlatProfile (SecHeader, SecFlatProfileData)> n<!ATTLIST SecFlatProfile\ i CDATA #REQUIRED\ n CDATA #REQUIRED> n n<!ELEMENT SecFlatProfileData (LM|M)*> n<!-- Load module: (i)d; (n)ame; (v)ma-range-set --> n<!ELEMENT LM (F|P|M)*> n<!ATTLIST LM\ i CDATA #IMPLIED\ n CDATA #REQUIRED\ v CDATA #IMPLIED> n<!-- File --> n<!ELEMENT F (P|L|S|M)*> n<!ATTLIST F\ i CDATA #IMPLIED\ n CDATA #REQUIRED> n<!-- Procedure (Note 1) --> n<!ELEMENT P (P|A|L|S|C|M)*> n<!ATTLIST P\ i CDATA #IMPLIED\ n CDATA #REQUIRED\ l CDATA #IMPLIED\ str CDATA #IMPLIED\ v CDATA #IMPLIED> n<!-- Alien (Note 1) --> n<!ELEMENT A (A|L|S|C|M)*> n<!ATTLIST A\ i CDATA #IMPLIED\ f CDATA #IMPLIED\ n CDATA #IMPLIED\ l CDATA #IMPLIED\ str CDATA #IMPLIED\ v CDATA #IMPLIED> n<!-- Loop (Note 1,2) --> n<!ELEMENT L (A|Pr|L|S|C|M)*> n<!ATTLIST L\ i CDATA #IMPLIED\ s CDATA #IMPLIED\ l CDATA #IMPLIED\ f CDATA #IMPLIED\ str CDATA #IMPLIED\ v CDATA #IMPLIED> n<!-- Statement (Note 2) --> n<!-- (it): trace record identifier --> n<!ELEMENT S (S|M)*> n<!ATTLIST S\ i CDATA #IMPLIED\ it CDATA #IMPLIED\ s CDATA #IMPLIED\ l CDATA #IMPLIED\ str CDATA #IMPLIED\ v CDATA #IMPLIED> n<!-- Note 1: Contained Cs may not contain PFs --> n<!-- Note 2: The 's' attribute is not used for flat profiles --> n
static void uw_recipe_map_unpoison(uintptr_t start, uintptr_t end, unwinder_t uw)
static void mcs_init(mcs_lock_t *l)
Definition: mcs-lock.h:100
sigjmp_buf jb
Definition: thread_data.h:74
static ilmstat_btuwi_pair_t * pop_free_pair(ilmstat_btuwi_pair_t **list)
bitree_uwi_t * tree
static cskiplist_t * addr2recipe_map[NUM_UNWINDERS]
static int ilmstat_btuwi_pair_cmp(void *lhs, void *rhs)
bool fnbounds_enclosing_addr(void *ip, void **start, void **end, load_module_t **lm)
void bitree_uwi_tostring_indent(bitree_uwi_t *tree, char *indents, char treestr[], unwinder_t uw)
thread_data_t *(* hpcrun_get_thread_data)(void)
Definition: thread_data.c:168
void uw_recipe_map_init(void)
loadmap_notify_range_t unmap
Definition: loadmap.h:245