HPCToolkit
trampoline.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 // File: trampoline.c
49 //
50 // Purpose: architecture independent support for counting returns of sampled
51 // frames using trampolines
52 //
53 // Modification History:
54 // 2009/09/15 - created - Mike Fagan and John Mellor-Crummey
55 //******************************************************************************
56 
57 //******************************************************************************
58 // system includes
59 //******************************************************************************
60 
61 #include <stdbool.h>
62 
63 //******************************************************************************
64 // local includes
65 //******************************************************************************
66 
67 #include "trampoline.h"
68 #include <hpcrun/thread_data.h>
69 #include <cct/cct.h>
70 #include <messages/messages.h>
71 #include <hpcrun/safe-sampling.h>
72 #include <hpcrun/sample_event.h>
73 #include <sample-sources/retcnt.h>
74 #include <monitor.h>
75 
76 
77 //******************************************************************************
78 // interface operations
79 //******************************************************************************
80 
81 void
83 {
85 
86  TMSG(TRAMP, "Num frames cached = %d ?= %d (cached_counter)",
88  for (frame_t* f = td->cached_bt; f < td->cached_bt_end; f++) {
89  TMSG(TRAMP, "ra loc = %p, ra@loc = %p", f->ra_loc, *((void**) f->ra_loc));
90  }
91 }
92 
93 void
95 {
97 
98  TMSG(TRAMP, "INIT called, tramp state zeroed");
99  td->tramp_present = false;
100  td->tramp_retn_addr = NULL;
101  td->tramp_loc = NULL;
102  td->tramp_cct_node = NULL;
103 }
104 
105 
106 // returns true if address is inside the assembly language trampoline code;
107 // returns false if at first address of trampoline code or outside.
108 bool
110 {
111  return ((void*)hpcrun_trampoline < addr
112  && addr <= (void*)hpcrun_trampoline_end);
113 }
114 
115 
116 // returns true iff at first address of trampoline code.
117 bool
119 {
120  return (addr == hpcrun_trampoline);
121 }
122 
123 
124 static bool
125 ok_to_advance(void* target, void* current)
126 {
127  return (target > current) && (target < monitor_stack_bottom());
128 }
129 
130 static cct_node_t*
132 {
135  void* current_frame_sp = td->tramp_frame->ra_loc;
136  if (! td->cached_frame_count ) return NULL;
137 
138  TMSG(TRAMP, "Advance from node %p...", node);
139  cct_node_t* parent = (node) ? hpcrun_cct_parent(node) : NULL;
140  TMSG(TRAMP, " ... to node %p", parent);
141  td->tramp_frame++;
142  TMSG(TRAMP, "cached frame count reduced from %d to %d", td->cached_frame_count,
143  td->cached_frame_count - 1);
144  (td->cached_frame_count)--;
145  if ( ! td->cached_frame_count ) {
146  TMSG(TRAMP, "**cached frame count = 0");
147  }
148  else if (! ok_to_advance (td->tramp_frame->ra_loc, current_frame_sp) ) {
149  EMSG("Encountered bad advance of trampoline ( target > stack_bottom or target < current\n"
150  "%p(target) %p(current) %p(bottom)",
151  td->tramp_frame->ra_loc, current_frame_sp, monitor_stack_bottom());
152  }
153  else if (! parent) {
154  TMSG(TRAMP, "No parent node, trampoline self-removes");
155  }
156  else {
157  TMSG(TRAMP, "... Trampoline advanced to %p", parent);
158  hpcrun_trampoline_insert(parent);
159  return parent;
160  }
161  TMSG(TRAMP,"*** trampoline self-removes ***");
163  return NULL;
164 }
165 
166 void
168 {
169  TMSG(TRAMP, "insert into node %p", node);
171  if (! td->tramp_frame) {
172  TMSG(TRAMP, " **No tramp frame: init tramp info");
174  return;
175  }
176  void* addr = td->tramp_frame->ra_loc;
177  if (! addr) {
178  TMSG(TRAMP, " **Tramp frame ra loc = NULL");
180  return;
181  }
182 
183  TMSG(TRAMP, "Stack addr for retn addr = %p", addr);
184  // save location where trampoline was placed
185  td->tramp_loc = addr;
186 
187  TMSG(TRAMP, "Actual return addr @ %p = %p", addr, *((void**) addr));
188  // save the return address overwritten with trampoline address
189  td->tramp_retn_addr = *((void**) addr);
190 
191  *((void**)addr) = hpcrun_trampoline;
192  td->tramp_cct_node = node;
193  td->tramp_present = true;
194 }
195 
196 void
198 {
200  if (td->tramp_present){
201  TMSG(TRAMP, "removing live trampoline from %p", td->tramp_loc);
202  TMSG(TRAMP, "confirm trampoline @ location: ra@tramp loc = %p == %p (tramp)",
203  *((void**)td->tramp_loc), hpcrun_trampoline);
204  if (*((void**)td->tramp_loc) != hpcrun_trampoline) {
205  EMSG("INTERNAL ERROR: purported trampoline location does NOT have a trampoline:"
206  " loc %p: %p != %p", td->tramp_loc, *((void**)td->tramp_loc), hpcrun_trampoline);
207  }
208  else {
209  *((void**)td->tramp_loc) = td->tramp_retn_addr;
210  }
211  }
213 }
214 
215 void*
217 {
218  // probably not possible to get here from inside our code.
220 
221  TMSG(TRAMP, "Trampoline fired!");
223 
224  // get the address where we need to return
225  void* ra = td->tramp_retn_addr;
226 
227  TMSG(TRAMP, " --real return addr returned to hpcrun_trampoline = %p", ra);
229 
230  TMSG(TRAMP, "About to advance trampoline ...");
231 #if OLD_TRAMP_ADV
233  TMSG(TRAMP, "... Trampoline advanced to %p", n);
234  if (n)
236  else {
237  EMSG("NULL trampoline advance !!, trampoline removed");
239  }
240 #endif
243 
244  return ra; // our assembly code caller will return to ra
245 }
void hpcrun_trampoline_insert(cct_node_t *node)
Definition: trampoline.c:167
size_t cached_frame_count
Definition: thread_data.h:201
void * ra_loc
Definition: frame.h:63
static void hpcrun_safe_exit(void)
void * tramp_loc
Definition: thread_data.h:200
frame_t * cached_bt_end
Definition: thread_data.h:203
void * hpcrun_trampoline_handler(void)
Definition: trampoline.c:216
cct_node_t * node
Definition: cct.c:128
void hpcrun_trampoline(void)
Definition: aarch64-tramp.c:4
void * tramp_retn_addr
Definition: thread_data.h:199
cct_node_t * hpcrun_cct_parent(cct_node_t *x)
Definition: cct.c:357
frame_t * cached_bt
Definition: thread_data.h:202
frame_t * tramp_frame
Definition: thread_data.h:205
void hpcrun_retcnt_inc(cct_node_t *node, int incr)
Definition: retcnt.c:236
#define EMSG
Definition: messages.h:70
bool hpcrun_trampoline_at_entry(void *addr)
Definition: trampoline.c:118
bool tramp_present
Definition: thread_data.h:198
cct_node_t * tramp_cct_node
Definition: thread_data.h:206
void hpcrun_init_trampoline_info(void)
Definition: trampoline.c:94
#define TMSG(f,...)
Definition: messages.h:93
#define NULL
Definition: ElfHelper.cpp:85
Definition: cct.c:96
void hpcrun_trampoline_bt_dump(void)
Definition: trampoline.c:82
static cct_node_t * hpcrun_trampoline_advance(void)
Definition: trampoline.c:131
Definition: frame.h:58
cct_addr_t * addr
Definition: cct.c:130
<!-- ********************************************************************--> 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
void hpcrun_trampoline_remove(void)
Definition: trampoline.c:197
bool hpcrun_trampoline_interior(void *addr)
Definition: trampoline.c:109
static bool ok_to_advance(void *target, void *current)
Definition: trampoline.c:125
static int hpcrun_safe_enter(void)
thread_data_t *(* hpcrun_get_thread_data)(void)
Definition: thread_data.c:168
void hpcrun_trampoline_end(void)
Definition: aarch64-tramp.c:5