HPCToolkit
function-entries.cpp
Go to the documentation of this file.
1 // -*-Mode: C++;-*-
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  * include files
49  *****************************************************************************/
50 
51 #include <stdio.h>
52 #include <unistd.h>
53 #include <string>
54 
55 #include "code-ranges.h"
56 #include "function-entries.h"
57 #include "process-ranges.h"
58 #include "intervals.h"
59 #include "server.h"
60 
61 #define __STDC_FORMAT_MACROS
62 #include <inttypes.h>
63 
64 #include <map>
65 #include <set>
66 
67 using namespace std;
68 
69 
70 /******************************************************************************
71  * types
72  *****************************************************************************/
73 
74 class Function {
75 public:
76  Function(void *_address, string *_comment, bool _isvisible, int _call_count);
77  void AppendComment(const string *c);
78  void *address;
79  string *comment;
80  bool isvisible;
82  int operator<(Function *right);
83 };
84 
85 
86 /******************************************************************************
87  * forward declarations
88  *****************************************************************************/
89 
90 static void new_function_entry(void *addr, string *comment, bool isvisible,
91  int call_count);
92 static void dump_function_entry(void *addr, const char *comment);
93 
94 
95 /******************************************************************************
96  * local variables
97  *****************************************************************************/
98 
99 typedef map<void*,Function*> FunctionSet;
100 typedef set<void*> ExcludedFunctionSet;
101 
104 
106 
107 static long num_entries_total = 0;
108 
109 
110 /******************************************************************************
111  * interface operations
112  *****************************************************************************/
113 
114 // Free the function_entries map, the Function objects in the map, the
115 // excluded_function_entries set and cbranges intervals.
116 //
117 void
119 {
120  FunctionSet::iterator it;
121 
122  for (it = function_entries.begin(); it != function_entries.end(); it++) {
123  Function *f = it->second;
124  delete f->comment;
125  delete f;
126  }
127  function_entries.clear();
129  cbranges.clear();
130  num_entries_total = 0;
131 }
132 
133 
134 void
136 {
137  excluded_function_entries.insert(addr);
138 }
139 
140 
141 void
143 {
144  char buffer[1024];
145  FunctionSet::iterator i = function_entries.begin();
146 
147  for (; i != function_entries.end();) {
148  Function *f = (*i).second;
149  ++i;
150 
151  const char *name;
152  if (!f->isvisible && !(f->call_count > 1) && !is_possible_fn(f->address)) continue;
153  if (f->comment) {
154  name = f->comment->c_str();
155  }
156  else {
157  // inferred functions must be at least 16 bytes long
158  if (i != function_entries.end()) {
159  Function *nextf = (*i).second;
160  if (f->call_count == 0 &&
161  (((unsigned long) nextf->address) -
162  ((unsigned long) f->address)) < 16) {
163  long offset = offset_for_fn(f->address);
164  if (offset == 0) {
165  // if f->address lies within a valid code range, its
166  // offset will be non-zero. if offset is zero, the
167  // address cannot be a valid function start.
168  continue;
169  }
170  if (!range_contains_control_flow((char *) f->address + offset,
171  ((char *) nextf->address +
172  offset)))
173  continue;
174  }
175  }
176  sprintf(buffer,"stripped_%p", f->address);
177  name = buffer;
178  }
179  dump_function_entry(f->address, name);
180  }
181 }
182 
183 
184 void
185 add_stripped_function_entry(void *addr, int call_count)
186 {
187  // only add the function if it hasn't been specifically excluded
188  if (excluded_function_entries.find(addr) ==
190  add_function_entry(addr, NULL, false, call_count);
191  }
192 }
193 
194 
195 bool
197 {
198  FunctionSet::iterator it = function_entries.find(addr);
199 
200  if (it == function_entries.end()) return false;
201  else return true;
202 }
203 
204 
205 void
206 add_function_entry(void *addr, const string *comment, bool isvisible,
207  int call_count)
208 {
209  FunctionSet::iterator it = function_entries.find(addr);
210 
211  if (it == function_entries.end()) {
212  new_function_entry(addr, comment ? new string(*comment) : NULL,
213  isvisible, call_count);
214  } else {
215  Function *f = (*it).second;
216  if (comment) {
217  f->AppendComment(comment);
218  } else if (f->comment) {
219  f->isvisible = true;
220  }
221  f->call_count += call_count;
222  }
223 }
224 
225 
226 void
227 entries_in_range(void *start, void *end, vector<void *> &result)
228 {
229 #ifdef DEBUG_ENTRIES_IN_RANGE
230  printf("function entries for range [%p, %p]\n", start, end);
231 #endif
232  FunctionSet::iterator it = function_entries.find(start);
233  for (; it != function_entries.end(); it++) {
234  void *addr = (*it).first;
235  if (addr > end) return;
236 #ifdef DEBUG_ENTRIES_IN_RANGE
237  printf(" %p\n", addr);
238 #endif
239  result.push_back(addr);
240  }
241 }
242 
243 
244 bool contains_function_entry(void *address)
245 {
246  FunctionSet::iterator it = function_entries.find(address);
247  if (it != function_entries.end()) return true;
248  else return false;
249 }
250 
251 
253 {
254  return (num_entries_total);
255 }
256 
257 
258 /******************************************************************************
259  * private operations
260  *****************************************************************************/
261 
262 //
263 // Write one function entry in one format: server, C or text.
264 //
265 static void
266 dump_function_entry(void *addr, const char *comment)
267 {
269 
270  if (server_mode()) {
271  syserv_add_addr(addr, function_entries.size());
272  return;
273  }
274 
275  if (c_mode()) {
276  if (num_entries_total > 1) {
277  printf(",\n");
278  }
279  printf(" 0x%" PRIxPTR " /* %s */", (uintptr_t) addr, comment);
280  return;
281  }
282 
283  // default is text mode
284  printf("0x%" PRIxPTR " %s\n", (uintptr_t) addr, comment);
285 }
286 
287 
288 static void
289 new_function_entry(void *addr, string *comment, bool isvisible, int call_count)
290 {
291  Function *f = new Function(addr, comment, isvisible, call_count);
292  function_entries.insert(pair<void*, Function*>(addr, f));
293 }
294 
295 
296 int
298 {
299  return (cbranges.contains(addr) == NULL);
300 }
301 
302 
303 // test if an address is within a range rather than at its start
304 int
306 {
307  std::pair<void *const, void *> *interval = cbranges.contains(addr);
308  if (interval != NULL && (addr > interval->first)) return 1;
309  return 0;
310 }
311 
312 
313 //
314 // FIXME? add finer grained segv handling here?
315 //
316 void
317 add_protected_range(void *start, void *end)
318 {
319  if (start < end) {
320  cbranges.insert(start,end);
321  }
322 }
323 
324 
325 Function::Function(void *_address, string *_comment, bool _isvisible,
326  int _call_count)
327 {
328  address = _address;
329  comment = _comment;
330  isvisible = _isvisible;
331  call_count = _call_count;
332 }
333 
334 
335 void
336 Function::AppendComment(const string *c)
337 {
338  *comment = *comment + ", " + *c;
339 }
340 
341 
342 int
344 {
345  return this->address < right->address;
346 }
Function(void *_address, string *_comment, bool _isvisible, int _call_count)
int server_mode(void)
Definition: main.cpp:208
static void dump_function_entry(void *addr, const char *comment)
set< void * > ExcludedFunctionSet
long offset_for_fn(void *addr)
static void new_function_entry(void *addr, string *comment, bool isvisible, int call_count)
void dump_reachable_functions()
static ExcludedFunctionSet excluded_function_entries
bool query_function_entry(void *addr)
static long num_entries_total
int is_possible_fn(void *addr)
static intervals cbranges
int operator<(Function *right)
void add_stripped_function_entry(void *addr, int call_count)
void AppendComment(const string *c)
static FunctionSet function_entries
long num_function_entries(void)
map< void *, Function * > FunctionSet
void add_function_entry(void *addr, const string *comment, bool isvisible, int call_count)
void syserv_add_addr(void *addr, long func_entry_map_size)
Definition: server.cpp:218
void insert(void *start, void *end)
Definition: intervals.cpp:76
int c_mode(void)
Definition: main.cpp:202
void entries_in_range(void *start, void *end, vector< void *> &result)
void exclude_function_entry(void *addr)
int inside_protected_range(void *addr)
string * comment
void clear()
Definition: intervals.cpp:145
bool range_contains_control_flow(void *vstart, void *vend)
#define NULL
Definition: ElfHelper.cpp:85
void function_entries_reinit(void)
cct_addr_t * addr
Definition: cct.c:130
bool operator<(const VMAInterval &x, const VMAInterval &y)
void add_protected_range(void *start, void *end)
bool contains_function_entry(void *address)
std::pair< void *const, void * > * contains(void *i)
Definition: intervals.cpp:128