HPCToolkit
dylib.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 // system includes
49 //*****************************************************************************
50 
51 #include <stdlib.h>
52 #include <string.h>
53 #include <limits.h>
54 
55 //#define GNU_SOURCE
56 #include <link.h> // dl_iterate_phdr
57 #include <dlfcn.h> // dladdr
58 
59 
60 //*****************************************************************************
61 // local includes
62 //*****************************************************************************
63 
64 #include "dylib.h"
65 #include "fnbounds_interface.h"
66 
67 #include <messages/messages.h>
68 
69 
70 //*****************************************************************************
71 // type declarations
72 //*****************************************************************************
73 
75  void *start;
76  void *end;
77 };
78 
79 struct dylib_fmca_s {
80  void *addr;
81  const char *module_name;
82  struct dylib_seg_bounds_s bounds;
83 };
84 
85 
86 
87 //*****************************************************************************
88 // macro declarations
89 //*****************************************************************************
90 
91 #define SEG_START_ADDR(info, seg) \
92  ((char *) (info)->dlpi_addr + (info)->dlpi_phdr[seg].p_vaddr)
93 
94 #define SEG_SIZE(info, seg) ((info)->dlpi_phdr[seg].p_memsz)
95 
96 #define SEG_IS_EXECUTABLE_CODE(info, seg) \
97  (((info) != NULL) && \
98  ((info)->dlpi_phdr != NULL) && \
99  ((info)->dlpi_phdr[seg].p_type == PT_LOAD) && \
100  ((info)->dlpi_phdr[seg].p_flags & PF_X))
101 
102 
103 //*****************************************************************************
104 // forward declarations
105 //*****************************************************************************
106 
107 static int
108 dylib_map_open_dsos_callback(struct dl_phdr_info *info,
109  size_t size, void *);
110 
111 static int
112 dylib_find_module_containing_addr_callback(struct dl_phdr_info *info,
113  size_t size, void *fargs_v);
114 
115 
116 
117 //*****************************************************************************
118 // interface operations
119 //*****************************************************************************
120 
121 //------------------------------------------------------------------
122 // ensure bounds information computed for all open shared libraries
123 //------------------------------------------------k-----------------
124 void
126 {
127  dl_iterate_phdr(dylib_map_open_dsos_callback, (void *)0);
128 }
129 
130 
131 //------------------------------------------------------------------
132 // ensure bounds information computed for the executable
133 //------------------------------------------------------------------
134 
135 void
137 {
138  const char *executable_name = "/proc/self/exe";
139  fnbounds_ensure_mapped_dso(executable_name, NULL, NULL);
140 }
141 
142 
143 int
145 {
146  struct dylib_fmca_s arg;
147 
148  // initialize arg structure
149  arg.addr = addr;
150  return dl_iterate_phdr(dylib_find_module_containing_addr_callback, &arg);
151 }
152 
153 
154 int
156  char* module_name,
157  void** start,
158  void** end)
159 {
160  int retval = 0; // not found
161  struct dylib_fmca_s arg;
162 
163  // initialize arg structure
164  arg.addr = addr;
165 
166  if (dl_iterate_phdr(dylib_find_module_containing_addr_callback, &arg)) {
167 
168  //-------------------------------------
169  // return callback results into arguments
170  //-------------------------------------
171  strcpy(module_name, arg.module_name);
172  *start = arg.bounds.start;
173  *end = arg.bounds.end;
174  retval = 1;
175  }
176 
177  return retval;
178 }
179 
180 
181 int
182 dylib_find_proc(void* pc, void* *proc_beg, void* *mod_beg)
183 {
184  Dl_info dli;
185  int ret = dladdr(pc, &dli); // cf. glibc's _dl_addr
186  if (ret) {
187  //printf("dylib_find_proc: lm: %s (%p); sym: %s (%p)\n", dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
188  *proc_beg = dli.dli_saddr;
189  *mod_beg = dli.dli_fbase;
190  return 0;
191  }
192  else {
193  *proc_beg = NULL;
194  *mod_beg = NULL;
195  return -1;
196  }
197 }
198 
199 
200 #if defined(__ia64__) && defined(__linux__)
201 bool
202 dylib_isin_start_func(void* pc)
203 {
204  extern int __libc_start_main(void); // start of a process
205  extern int __clone2(int (*fn)(void *), void *child_stack_base,
206  size_t stack_size, int flags, void *arg, ...
207  /* pid_t *pid, struct user_desc *tls, pid_t *ctid */ );
208  void* proc_beg = NULL, *mod_beg = NULL;
209  dylib_find_proc(pc, &proc_beg, &mod_beg);
210 
211  return (proc_beg == __libc_start_main ||
212  proc_beg == __clone2);
213 }
214 #else
215 bool
217 {
218  extern int __libc_start_main(void); // start of a process
219  extern int __clone(void); // start of a thread (extern)
220  extern int clone(void); // start of a thread (weak)
221 
222  void* proc_beg = NULL, *mod_beg = NULL;
223  dylib_find_proc(pc, &proc_beg, &mod_beg);
224  return (proc_beg == __libc_start_main ||
225  proc_beg == clone || proc_beg == __clone);
226 }
227 #endif // __ia64__ && __linux__
228 
229 const char*
230 dylib_find_proc_name(const void* pc)
231 {
232  Dl_info dli;
233  int ret = dladdr(pc, &dli);
234  if (ret) {
235  return (dli.dli_sname) ? dli.dli_sname : dli.dli_fname;
236  }
237  else {
238  return NULL;
239  }
240 }
241 
242 
243 
244 //*****************************************************************************
245 // private operations
246 //*****************************************************************************
247 
248 void
249 dylib_get_segment_bounds(struct dl_phdr_info *info,
250  struct dylib_seg_bounds_s *bounds)
251 {
252  int j;
253  char *start = (char *) -1;
254  char *end = NULL;
255 
256  //------------------------------------------------------------------------
257  // compute start of first & end of last executable chunks in this segment
258  //------------------------------------------------------------------------
259  for (j = 0; j < info->dlpi_phnum; j++) {
260  if (SEG_IS_EXECUTABLE_CODE(info, j)) {
261  char *saddr = SEG_START_ADDR(info, j);
262  long size = SEG_SIZE(info, j);
263  // don't adjust info unless segment has positive size
264  if (size > 0) {
265  char *eaddr = saddr + size;
266  if (saddr < start) start = saddr;
267  if (eaddr >= end) end = eaddr;
268  }
269  }
270  }
271 
272  bounds->start = start;
273  bounds->end = end;
274 }
275 
276 
277 static int
278 dylib_map_open_dsos_callback(struct dl_phdr_info *info, size_t size,
279  void *unused)
280 {
281  if (strcmp(info->dlpi_name,"") != 0) {
282  struct dylib_seg_bounds_s bounds;
283  dylib_get_segment_bounds(info, &bounds);
284  fnbounds_ensure_mapped_dso(info->dlpi_name, bounds.start, bounds.end);
285  }
286 
287  return 0;
288 }
289 
290 
291 static int
293  size_t size, void* fargs_v)
294 {
295  struct dylib_fmca_s* fargs = (struct dylib_fmca_s*) fargs_v;
296  dylib_get_segment_bounds(info, &fargs->bounds);
297 
298  //------------------------------------------------------------------------
299  // if addr is in within the segment bounds
300  //------------------------------------------------------------------------
301  if (fargs->addr >= fargs->bounds.start &&
302  fargs->addr < fargs->bounds.end) {
303  fargs->module_name = info->dlpi_name;
304  return 1;
305  }
306 
307  return 0;
308 }
309 
char * executable_name
#define SEG_START_ADDR(info, seg)
Definition: dylib.c:91
void dylib_map_executable()
Definition: dylib.c:136
static int dylib_find_module_containing_addr_callback(struct dl_phdr_info *info, size_t size, void *fargs_v)
Definition: dylib.c:292
#define SEG_IS_EXECUTABLE_CODE(info, seg)
Definition: dylib.c:96
int dylib_addr_is_mapped(void *addr)
Definition: dylib.c:144
const char * dylib_find_proc_name(const void *pc)
Definition: dylib.c:230
int dylib_find_proc(void *pc, void **proc_beg, void **mod_beg)
Definition: dylib.c:182
bool fnbounds_ensure_mapped_dso(const char *module_name, void *start, void *end)
void dylib_get_segment_bounds(struct dl_phdr_info *info, struct dylib_seg_bounds_s *bounds)
Definition: dylib.c:249
void dylib_map_open_dsos()
Definition: dylib.c:125
const char * module_name
Definition: dylib.c:81
bool dylib_isin_start_func(void *pc)
Definition: dylib.c:216
struct dylib_seg_bounds_s bounds
Definition: dylib.c:82
static int dylib_map_open_dsos_callback(struct dl_phdr_info *info, size_t size, void *)
Definition: dylib.c:278
void * addr
Definition: dylib.c:80
int dylib_find_module_containing_addr(void *addr, char *module_name, void **start, void **end)
Definition: dylib.c:155
#define NULL
Definition: ElfHelper.cpp:85
void * start
Definition: dylib.c:75
cct_addr_t * addr
Definition: cct.c:130
#define SEG_SIZE(info, seg)
Definition: dylib.c:94
void * end
Definition: dylib.c:76