xref: /netbsd-src/external/gpl3/binutils.old/dist/gprofng/libcollector/mmaptrace.c (revision c42dbd0ed2e61fe6eda8590caa852ccf34719964)
1 /* Copyright (C) 2021 Free Software Foundation, Inc.
2    Contributed by Oracle.
3 
4    This file is part of GNU Binutils.
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3, or (at your option)
9    any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, 51 Franklin Street - Fifth Floor, Boston,
19    MA 02110-1301, USA.  */
20 
21 /*
22  * memory map tracking
23  * incorporating former "loadobjects" into more general "map"
24  * (including code and data segments and dynamic functions)
25  */
26 
27 #include "config.h"
28 #include <alloca.h>
29 #include <dlfcn.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <elf.h>
33 #include <sys/mman.h>
34 #include <sys/param.h>
35 #include <stdint.h>
36 
37 #include "gp-defs.h"
38 #include "collector.h"
39 #include "gp-experiment.h"
40 #include "memmgr.h"
41 
42 /*
43  * These are obsolete and unreliable.
44  * They are included here only for historical compatibility.
45  */
46 #define MA_SHARED   0x08 /* changes are shared by mapped object */
47 #define MA_ANON     0x40 /* anonymous memory (e.g. /dev/zero) */
48 #define MA_ISM      0x80 /* intimate shared mem (shared MMU resources) */
49 #define MA_BREAK    0x10 /* grown by brk(2) */
50 #define MA_STACK    0x20 /* grown automatically on stack faults */
51 
52 typedef struct prmap_t
53 {
54   unsigned long pr_vaddr;   /* virtual address of mapping */
55   unsigned long pr_size;    /* size of mapping in bytes */
56   char *pr_mapname;         /* name in /proc/<pid>/object */
57   int pr_mflags;            /* protection and attribute flags (see below) */
58   unsigned long pr_offset;  /* offset into mapped object, if any */
59   unsigned long pr_dev;
60   unsigned long pr_ino;
61   int pr_pagesize;          /* pagesize (bytes) for this mapping */
62 } prmap_t;
63 
64 /* TprintfT(<level>,...) definitions.  Adjust per module as needed */
65 #define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
66 #define DBG_LT1 1 // for configuration details, warnings
67 #define DBG_LT2 2
68 #define DBG_LT3 3
69 #define DBG_LT4 4
70 
71 #define SYS_MMAP_NAME       "mmap"
72 #define SYS_MMAP64_NAME     "mmap64"
73 #define SYS_MUNMAP_NAME     "munmap"
74 #define SYS_DLOPEN_NAME     "dlopen"
75 #define SYS_DLCLOSE_NAME    "dlclose"
76 
77 typedef struct MapInfo
78 {
79   struct MapInfo *next;
80   unsigned long vaddr;
81   unsigned long size;
82   char *mapname;    /* name in /proc/<pid>/object */
83   char *filename;
84   unsigned long offset;
85   int mflags;
86   int pagesize;
87 } MapInfo;
88 
89 typedef struct NameInfo
90 {
91   struct NameInfo *next;
92   char *mapname;
93   char filename[1];     /* dynamic length file name   */
94 } NameInfo;
95 
96 static NameInfo *namemaps = NULL;
97 static MapInfo mmaps;               /* current memory maps */
98 static struct DataHandle *map_hndl = NULL;
99 static char dyntext_fname[MAXPATHLEN];
100 static void *mapcache = NULL;
101 static char *maptext = NULL;
102 static size_t maptext_sz = 4096;    /* initial buffer size */
103 static int mmap_mode = 0;
104 static int mmap_initted = 0;
105 static collector_mutex_t map_lock = COLLECTOR_MUTEX_INITIALIZER;
106 static collector_mutex_t dyntext_lock = COLLECTOR_MUTEX_INITIALIZER;
107 
108 /* a reentrance guard for the interposition functions ensures that updates to
109    the map cache/file are sequential, with the first doing the final update */
110 static int reentrance = 0;
111 #define CHCK_REENTRANCE  (reentrance || mmap_mode <= 0)
112 #define CURR_REENTRANCE  reentrance
113 #define PUSH_REENTRANCE  reentrance++
114 #define POP_REENTRANCE   reentrance--
115 
116 #define CALL_REAL(x)    (__real_##x)
117 #define NULL_PTR(x)     (__real_##x == NULL)
118 
119 /* interposition function handles */
120 static void *(*__real_mmap)(void* start, size_t length, int prot, int flags,
121 			    int fd, off_t offset) = NULL;
122 static void *(*__real_mmap64)(void* start, size_t length, int prot, int flags,
123 			      int fd, off64_t offset) = NULL;
124 static int (*__real_munmap)(void* start, size_t length) = NULL;
125 static void *(*__real_dlopen)(const char* pathname, int mode) = NULL;
126 #if (ARCH(Intel) && WSIZE(32)) || ARCH(SPARC)
127 static void *(*__real_dlopen_2_1)(const char* pathname, int mode) = NULL;
128 static void *(*__real_dlopen_2_0)(const char* pathname, int mode) = NULL;
129 #endif
130 static int (*__real_dlclose)(void* handle) = NULL;
131 static void (*collector_heap_record)(int, size_t, void*) = NULL;
132 
133 /* internal function prototypes */
134 static int init_mmap_intf ();
135 static int init_mmap_files ();
136 static void append_segment_record (char *format, ...);
137 static void update_map_segments (hrtime_t hrt, int resolve);
138 static void resolve_mapname (MapInfo *map, char *name);
139 static void record_segment_map (hrtime_t timestamp, uint64_t loadaddr,
140 				unsigned long msize, int pagesize, int modeflags,
141 				long long offset, unsigned check, char *name);
142 static void record_segment_unmap (hrtime_t timestamp, uint64_t loadaddr);
143 
144 /* Linux needs handling of the vsyscall page to get its data into the map.xml file */
145 static void process_vsyscall_page ();
146 
147 #define MAXVSYSFUNCS 10
148 static int nvsysfuncs = 0;
149 static char *sysfuncname[MAXVSYSFUNCS];
150 static uint64_t sysfuncvaddr[MAXVSYSFUNCS];
151 static unsigned long sysfuncsize[MAXVSYSFUNCS];
152 
153 #define MAXDYN 20
154 static int ndyn = 0;
155 static char *dynname [MAXDYN];
156 static void *dynvaddr [MAXDYN];
157 static unsigned dynsize [MAXDYN];
158 static char *dynfuncname[MAXDYN];
159 
160 /*===================================================================*/
161 
162 /*
163  * void __collector_mmap_init_mutex_locks()
164  *      Iinitialize mmap mutex locks.
165  */
166 void
__collector_mmap_init_mutex_locks()167 __collector_mmap_init_mutex_locks ()
168 {
169   __collector_mutex_init (&map_lock);
170   __collector_mutex_init (&dyntext_lock);
171 }
172 
173 /* __collector_ext_update_map_segments called by the audit agent
174  * Is is also called by dbx/collector when a (possible) map update
175  * is intimated, such as after dlopen/dlclose.
176  * Required when libcollector.so is not preloaded and interpositions inactive.
177  */
178 int
__collector_ext_update_map_segments(void)179 __collector_ext_update_map_segments (void)
180 {
181   if (!mmap_initted)
182     return 0;
183   TprintfT (0, "__collector_ext_update_map_segments(%d)\n", CURR_REENTRANCE);
184   if (CHCK_REENTRANCE)
185     return 0;
186   PUSH_REENTRANCE;
187   update_map_segments (GETRELTIME (), 1);
188   POP_REENTRANCE;
189   return 0;
190 }
191 /*
192  * int __collector_ext_mmap_install()
193  *      Install and initialise mmap tracing.
194  */
195 int
__collector_ext_mmap_install(int record)196 __collector_ext_mmap_install (int record)
197 {
198   TprintfT (0, "__collector_ext_mmap_install(mmap_mode=%d)\n", mmap_mode);
199   if (NULL_PTR (mmap))
200     {
201       if (init_mmap_intf ())
202 	{
203 	  TprintfT (0, "ERROR: collector mmap tracing initialization failed.\n");
204 	  return COL_ERROR_EXPOPEN;
205 	}
206     }
207   else
208     TprintfT (DBG_LT2, "collector mmap tracing: mmap pointer not null\n");
209 
210   /* Initialize side door interface with the heap tracing module */
211   collector_heap_record = (void(*)(int, size_t, void*))dlsym (RTLD_DEFAULT, "__collector_heap_record");
212   if (record)
213     {
214       map_hndl = __collector_create_handle (SP_MAP_FILE);
215       if (map_hndl == NULL)
216 	return COL_ERROR_MAPOPEN;
217       if (init_mmap_files ())
218 	{
219 	  TprintfT (0, "ERROR: collector init_mmap_files() failed.\n");
220 	  return COL_ERROR_EXPOPEN;
221 	}
222     }
223   mmaps.next = NULL;
224   mapcache = NULL;
225   PUSH_REENTRANCE;
226   update_map_segments (GETRELTIME (), 1); // initial map
227   POP_REENTRANCE;
228   mmap_mode = 1;
229   mmap_initted = 1;
230   process_vsyscall_page ();
231   return COL_ERROR_NONE;
232 }
233 
234 /*
235  * int __collector_ext_mmap_deinstall()
236  *	Optionally update final map and stop tracing mmap events.
237  */
238 int
__collector_ext_mmap_deinstall(int update)239 __collector_ext_mmap_deinstall (int update)
240 {
241   if (!mmap_initted)
242     return COL_ERROR_NONE;
243   mmap_mode = 0;
244   if (update)
245     {
246       /* Final map */
247       PUSH_REENTRANCE;
248       update_map_segments (GETRELTIME (), 1);
249       POP_REENTRANCE;
250     }
251   TprintfT (0, "__collector_ext_mmap_deinstall(%d)\n", update);
252   if (map_hndl != NULL)
253     {
254       __collector_delete_handle (map_hndl);
255       map_hndl = NULL;
256     }
257   __collector_mutex_lock (&map_lock); // get lock before resetting
258 
259   /* Free all memory maps */
260   MapInfo *mp;
261   for (mp = mmaps.next; mp;)
262     {
263       MapInfo *next = mp->next;
264       __collector_freeCSize (__collector_heap, mp, sizeof (*mp));
265       mp = next;
266     }
267   mmaps.next = NULL;
268 
269   /* Free all name maps */
270   NameInfo *np;
271   for (np = namemaps; np;)
272     {
273       NameInfo *next = np->next;
274       __collector_freeCSize (__collector_heap, np, sizeof (*np) + __collector_strlen (np->filename));
275       np = next;
276     }
277   namemaps = NULL;
278   mapcache = __collector_reallocVSize (__collector_heap, mapcache, 0);
279   mmaps.next = NULL;
280   mapcache = NULL;
281   __collector_mutex_unlock (&map_lock);
282   TprintfT (0, "__collector_ext_mmap_deinstall done\n");
283   return 0;
284 }
285 
286 /*
287  * void __collector_mmap_fork_child_cleanup()
288  *	Perform all necessary cleanup steps in child process after fork().
289  */
290 void
__collector_mmap_fork_child_cleanup()291 __collector_mmap_fork_child_cleanup ()
292 {
293   /* Initialize all mmap "mutex" locks */
294   __collector_mmap_init_mutex_locks ();
295   if (!mmap_initted)
296     return;
297   mmap_mode = 0;
298   __collector_delete_handle (map_hndl);
299   __collector_mutex_lock (&map_lock); // get lock before resetting
300 
301   /* Free all memory maps */
302   MapInfo *mp;
303   for (mp = mmaps.next; mp;)
304     {
305       MapInfo *next = mp->next;
306       __collector_freeCSize (__collector_heap, mp, sizeof (*mp));
307       mp = next;
308     }
309   mmaps.next = NULL;
310 
311   /* Free all name maps */
312   NameInfo *np;
313   for (np = namemaps; np;)
314     {
315       NameInfo *next = np->next;
316       __collector_freeCSize (__collector_heap, np, sizeof (*np) + __collector_strlen (np->filename));
317       np = next;
318     }
319   namemaps = NULL;
320   mapcache = __collector_reallocVSize (__collector_heap, mapcache, 0);
321   mmap_initted = 0;
322   reentrance = 0;
323   __collector_mutex_unlock (&map_lock);
324 }
325 
326 static int
init_mmap_files()327 init_mmap_files ()
328 {
329   TprintfT (DBG_LT2, "init_mmap_files\n");
330   /* also create the headerless dyntext file (if required) */
331   CALL_UTIL (snprintf)(dyntext_fname, sizeof (dyntext_fname), "%s/%s",
332 		       __collector_exp_dir_name, SP_DYNTEXT_FILE);
333   if (CALL_UTIL (access)(dyntext_fname, F_OK) != 0)
334     {
335       int fd = CALL_UTIL (open)(dyntext_fname, O_RDWR | O_CREAT | O_TRUNC,
336 				S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
337       if (fd == -1)
338 	{
339 	  char errmsg[256];
340 	  TprintfT (0, "ERROR: init_mmap_files: open(%s) failed\n",
341 		    dyntext_fname);
342 	  __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s: %s</event>\n",
343 				 SP_JCMD_CERROR, COL_ERROR_DYNOPEN, errno,
344 				 dyntext_fname, errmsg);
345 	  return COL_ERROR_DYNOPEN;
346 	}
347       else
348 	CALL_UTIL (close)(fd);
349     }
350   return COL_ERROR_NONE;
351 }
352 
353 static void
append_segment_record(char * format,...)354 append_segment_record (char *format, ...)
355 {
356   char buf[1024];
357   char *bufptr = buf;
358   va_list va;
359   va_start (va, format);
360   int sz = __collector_xml_vsnprintf (bufptr, sizeof (buf), format, va);
361   va_end (va);
362 
363   if (__collector_expstate != EXP_OPEN && __collector_expstate != EXP_PAUSED)
364     {
365       TprintfT (0, "append_segment_record: expt neither open nor paused (%d); "
366 		   "not writing to map.xml\n\t%s", __collector_expstate, buf);
367       return;
368     }
369   if (sz >= sizeof (buf))
370     {
371       /* Allocate a new buffer */
372       sz += 1; /* add the terminating null byte */
373       bufptr = (char*) alloca (sz);
374       va_start (va, format);
375       sz = __collector_xml_vsnprintf (bufptr, sz, format, va);
376       va_end (va);
377     }
378   int rc = __collector_write_string (map_hndl, bufptr, sz);
379   if (rc != 0)
380     (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\"></event>\n",
381 				  SP_JCMD_CERROR, COL_ERROR_MAPWRITE);
382 }
383 
384 static void
record_segment_map(hrtime_t timestamp,uint64_t loadaddr,unsigned long msize,int pagesize,int modeflags,long long offset,unsigned check,char * name)385 record_segment_map (hrtime_t timestamp, uint64_t loadaddr, unsigned long msize,
386 		    int pagesize, int modeflags, long long offset,
387 		    unsigned check, char *name)
388 {
389 
390   TprintfT (DBG_LT2, "record_segment_map(%s @ 0x%llx)\n", name, (long long) loadaddr);
391   append_segment_record ("<event kind=\"map\" object=\"segment\" tstamp=\"%u.%09u\" "
392 			 "vaddr=\"0x%016llX\" size=\"%lu\" pagesz=\"%d\" foffset=\"%c0x%08llX\" "
393 			 "modes=\"0x%03X\" chksum=\"0x%0X\" name=\"%s\"/>\n",
394 			 (unsigned) (timestamp / NANOSEC),
395 			 (unsigned) (timestamp % NANOSEC),
396 			 loadaddr, msize, pagesize,
397 			 offset < 0 ? '-' : '+', offset < 0 ? -offset : offset,
398 			 modeflags, check, name);
399 }
400 
401 static void
record_segment_unmap(hrtime_t timestamp,uint64_t loadaddr)402 record_segment_unmap (hrtime_t timestamp, uint64_t loadaddr)
403 {
404   TprintfT (DBG_LT2, "record_segment_unmap(@ 0x%llx)\n", (long long) loadaddr);
405   append_segment_record ("<event kind=\"unmap\" tstamp=\"%u.%09u\" vaddr=\"0x%016llX\"/>\n",
406 			 (unsigned) (timestamp / NANOSEC),
407 			 (unsigned) (timestamp % NANOSEC), loadaddr);
408 }
409 
410 #if WSIZE(64)
411 #define ELF_EHDR    Elf64_Ehdr
412 #define ELF_PHDR    Elf64_Phdr
413 #define ELF_SHDR    Elf64_Shdr
414 #define ELF_DYN     Elf64_Dyn
415 #define ELF_AUX     Elf64_auxv_t
416 #define ELF_SYM     Elf64_Sym
417 #define ELF_ST_BIND ELF64_ST_BIND
418 #define ELF_ST_TYPE ELF64_ST_TYPE
419 #elif WSIZE(32)
420 #define ELF_EHDR    Elf32_Ehdr
421 #define ELF_PHDR    Elf32_Phdr
422 #define ELF_SHDR    Elf32_Shdr
423 #define ELF_DYN     Elf32_Dyn
424 #define ELF_AUX     Elf32_auxv_t
425 #define ELF_SYM     Elf32_Sym
426 #define ELF_ST_BIND ELF32_ST_BIND
427 #define ELF_ST_TYPE ELF32_ST_TYPE
428 #endif
429 
430 static unsigned
checksum_mapname(MapInfo * map)431 checksum_mapname (MapInfo* map)
432 {
433   unsigned checksum = 0;
434   /* only checksum code segments */
435   if ((map->mflags & (PROT_EXEC | PROT_READ)) == 0 ||
436       (map->mflags & PROT_WRITE) != 0)
437     return 0;
438   checksum = (unsigned) - 1;
439   TprintfT (DBG_LT2, "checksum_mapname checksum = 0x%0X\n", checksum);
440   return checksum;
441 }
442 
443 
444 #if (ARCH(Intel) && WSIZE(32)) || ARCH(SPARC)
445 static void*
dlopen_searchpath_symver(void * (real_dlopen)(),void * caller_addr,const char * basename,int mode)446 dlopen_searchpath_symver (void*(real_dlopen) (), void* caller_addr, const char* basename, int mode)
447 #else
448 static void*
449 dlopen_searchpath (void* caller_addr, const char* basename, int mode)
450 #endif
451 {
452   TprintfT (DBG_LT2, "dlopen_searchpath(%p, %s, %d)\n", caller_addr, basename, mode);
453   Dl_info dl_info;
454   if (dladdr (caller_addr, &dl_info) == 0)
455     {
456       TprintfT (0, "ERROR: dladdr(%p): %s\n", caller_addr, dlerror ());
457       return 0;
458     }
459   TprintfT (DBG_LT2, "dladdr(%p): %p fname=%s\n",
460 	    caller_addr, dl_info.dli_fbase, dl_info.dli_fname);
461   int noload = RTLD_BINDING_MASK | RTLD_NOLOAD; //XXXX why RTLD_BINDING_MASK?
462 #define WORKAROUND_RTLD_BUG 1
463 #ifdef WORKAROUND_RTLD_BUG
464   // A dynamic linker dlopen bug can result in corruption/closure of open streams
465   // XXXX workaround should be removed once linker patches are all available
466 #if WSIZE(64)
467 #define MAINBASE 0x400000
468 #elif WSIZE(32)
469 #define MAINBASE 0x08048000
470 #endif
471   const char* tmp_path =
472 	  (dl_info.dli_fbase == (void*) MAINBASE) ? NULL : dl_info.dli_fname;
473   void* caller_hndl = NULL;
474 #if ((ARCH(Intel) && WSIZE(32)) || ARCH(SPARC))
475   caller_hndl = (real_dlopen) (tmp_path, noload);
476 #else
477   caller_hndl = CALL_REAL (dlopen)(tmp_path, noload);
478 #endif
479 
480 #else //XXXX workaround should be removed once linker patches are all available
481 
482   void* caller_hndl = NULL;
483 #if (ARCH(Intel) && WSIZE(32) || ARCH(SPARC)
484   caller_hndl = (real_dlopen) (dl_info.dli_fname, noload);
485 #else
486   caller_hndl = CALL_REAL (dlopen)(dl_info.dli_fname, noload);
487 #endif
488 
489 #endif //XXXX workaround should be removed once linker patches are all available
490 
491   if (!caller_hndl)
492     {
493       TprintfT (0, "ERROR: dlopen(%s,NOLOAD): %s\n", dl_info.dli_fname, dlerror ());
494       return 0;
495     }
496   Dl_serinfo _info, *info = &_info;
497   Dl_serpath *path;
498 
499   /* determine search path count and required buffer size */
500   dlinfo (caller_hndl, RTLD_DI_SERINFOSIZE, (void *) info);
501 
502   /* allocate new buffer and initialize */
503   /*
504       CR# 7191331
505       There is a bug in Linux that causes the first call
506       to dlinfo() to return a small value for the dls_size.
507 
508       The first call to dlinfo() determines the search path
509       count and the required buffer size. The second call to
510       dlinfo() tries to obtain the search path information.
511 
512       However, the size of the buffer that is returned by
513       the first call to the dlinfo() is incorrect (too small).
514       The second call to dlinfo() uses the incorrect size to
515       allocate memory on the stack and internally uses the memcpy()
516       function to copy the search paths to the allocated memory space.
517       The length of the search path is much larger than the buffer
518       that is allocated on the stack. The memcpy() overwrites some
519       of the information that are saved on the stack, specifically,
520       it overwrites the "basename" parameter.
521 
522       collect crashes right after the second call to dlinfo().
523 
524       The search paths are used to locate the shared libraries.
525       dlinfo() creates the search paths based on the paths
526       that are assigned to LD_LIBRARY_PATH environment variable
527       and the standard library paths. The standard library paths
528       consists of the /lib and the /usr/lib paths. The
529       standard library paths are always included to the search
530       paths by dlinfo() even if the LD_LIBRARY_PATH environment
531       variable is not defined. Therefore, at the very least the
532       dls_cnt is assigned to 2 (/lib and /usr/lib) and dlinfo()
533       will never assign dls_cnt to zero. The dls_cnt is the count
534       of the potential paths for searching the shared libraries.
535 
536       So we need to increase the buffer size before the second
537       call to dlinfo(). There are number of ways to increase
538       the buffer size. However, none of them can calculate the
539       buffer size precisely. Some users on the web have suggested
540       to multiply the MAXPATHLEN by dls_cnt for the buffer size.
541       The MAXPATHLEN is assigned to 1024 bytes. In my opinion
542       this is too much. So I have decided to multiply dls_size
543       by dls_cnt for the buffer size since the dls_size is much
544       smaller than 1024 bytes.
545 
546       I have already confirmed with our user that the workaround
547       is working with his real application. Additionally,
548       the dlopen_searchpath() function is called only by the
549       libcorrector init() function when the experiment is started.
550       Therefore, allocating some extra bytes on the stack which
551       is local to this routine is harmless.
552    */
553 
554   info = alloca (_info.dls_size * _info.dls_cnt);
555   info->dls_size = _info.dls_size;
556   info->dls_cnt = _info.dls_cnt;
557 
558   /* obtain search path information */
559   dlinfo (caller_hndl, RTLD_DI_SERINFO, (void *) info);
560   path = &info->dls_serpath[0];
561 
562   char pathname[MAXPATHLEN];
563   for (unsigned int cnt = 1; cnt <= info->dls_cnt; cnt++, path++)
564     {
565       __collector_strlcpy (pathname, path->dls_name, sizeof (pathname));
566       __collector_strlcat (pathname, "/", sizeof (pathname));
567       __collector_strlcat (pathname, basename, sizeof (pathname));
568       void* ret = NULL;
569 #if (ARCH(Intel) && WSIZE(32)) || ARCH(SPARC)
570       ret = (real_dlopen) (pathname, mode);
571 #else
572       ret = CALL_REAL (dlopen)(pathname, mode);
573 #endif
574       TprintfT (DBG_LT2, "try %d/%d: %s = %p\n", cnt, info->dls_cnt, pathname, ret);
575       if (ret)
576 	return ret; // success!
577     }
578   return 0;
579 }
580 
581 static void
resolve_mapname(MapInfo * map,char * name)582 resolve_mapname (MapInfo *map, char *name)
583 {
584   map->filename = "";
585   map->mapname = "";
586   if (name == NULL || *name == '\0')
587     {
588       if (map->mflags & MA_STACK)
589 	map->filename = "<" SP_MAP_STACK ">";
590       else if (map->mflags & MA_BREAK)
591 	map->filename = "<" SP_MAP_HEAP ">";
592       else if (map->mflags & MA_ISM)
593 	map->filename = "<" SP_MAP_SHMEM ">";
594       return;
595     }
596   NameInfo *np;
597   for (np = namemaps; np; np = np->next)
598     if (__collector_strcmp (np->mapname, name) == 0)
599       break;
600 
601   if (np == NULL)
602     {
603       const char *fname;
604       fname = name;
605       /* Create and link a new name map */
606       size_t fnamelen = __collector_strlen (fname) + 1;
607       np = (NameInfo*) __collector_allocCSize (__collector_heap, sizeof (NameInfo) + fnamelen, 1);
608       if (np == NULL)   // We could not get memory
609 	return;
610       np->mapname = np->filename;
611       __collector_strlcpy (np->filename, fname, fnamelen);
612       np->next = namemaps;
613       namemaps = np;
614     }
615   map->mapname = np->mapname;
616   map->filename = np->filename;
617   if (map->filename[0] == (char) 0)
618     map->filename = map->mapname;
619   TprintfT (DBG_LT2, "resolve_mapname: %s resolved to %s\n", map->mapname, map->filename);
620 }
621 
622 static unsigned long
str2ulong(char ** ss)623 str2ulong (char **ss)
624 {
625   char *s = *ss;
626   unsigned long val = 0UL;
627   const int base = 16;
628   for (;;)
629     {
630       char c = *s++;
631       if (c >= '0' && c <= '9')
632 	val = val * base + (c - '0');
633       else if (c >= 'a' && c <= 'f')
634 	val = val * base + (c - 'a') + 10;
635       else if (c >= 'A' && c <= 'F')
636 	val = val * base + (c - 'A') + 10;
637       else
638 	break;
639     }
640   *ss = s - 1;
641   return val;
642 }
643 
644 static void
update_map_segments(hrtime_t hrt,int resolve)645 update_map_segments (hrtime_t hrt, int resolve)
646 {
647   size_t filesz;
648   if (__collector_mutex_trylock (&map_lock))
649     {
650       TprintfT (0, "WARNING: update_map_segments(resolve=%d) BUSY\n", resolve);
651       return;
652     }
653   TprintfT (DBG_LT2, "\n");
654   TprintfT (DBG_LT2, "begin update_map_segments(hrt, %d)\n", resolve);
655 
656   // Note: there is similar code to read /proc/$PID/map[s] in
657   // perfan/er_kernel/src/KSubExp.cc KSubExp::write_subexpt_map()
658   const char* proc_map = "/proc/self/maps";
659   size_t bufsz = maptext_sz;
660   int done = 0;
661   filesz = 0;
662   int map_fd = CALL_UTIL (open)(proc_map, O_RDONLY);
663   while (!done)
664     {
665       bufsz *= 2;
666       maptext = __collector_reallocVSize (__collector_heap, maptext, bufsz);
667       TprintfT (DBG_LT2, "  update_map_segments: Loop for bufsize=%ld\n",
668 		(long) bufsz);
669       for (;;)
670 	{
671 	  int n = CALL_UTIL (read)(map_fd, maptext + filesz, bufsz - filesz);
672 	  TprintfT (DBG_LT2, "    update_map_segments: __collector_read(bufp=%p nbyte=%ld)=%d\n",
673 		    maptext + filesz, (long) ( bufsz - filesz), n);
674 	  if (n < 0)
675 	    {
676 	      TprintfT (0, "ERROR: update_map_segments: read(maps): errno=%d\n", errno);
677 	      (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s</event>\n",
678 					    SP_JCMD_CERROR, COL_ERROR_MAPREAD, errno, proc_map);
679 	      CALL_UTIL (close)(map_fd);
680 	      __collector_mutex_unlock (&map_lock);
681 	      return;
682 	    }
683 	  else if (n == 0)
684 	    {
685 	      done = 1;
686 	      break;
687 	    }
688 	  filesz += n;
689 	  if (filesz >= bufsz) /* Buffer too small */
690 	    break;
691 	}
692     }
693   CALL_UTIL (close)(map_fd);
694   maptext_sz = filesz;
695 
696   int mapcache_entries = 0;
697   char *str, *str1;
698   for (str = maptext;; str = str1)
699     {
700       for (str1 = str; str1 - maptext < filesz; str1++)
701 	{
702 	  if (*str1 == '\n')
703 	    {
704 	      *str1 = (char) 0;
705 	      break;
706 	    }
707 	}
708       if (str1 - maptext >= filesz)
709 	break;
710       str1++;
711       mapcache_entries++;
712       mapcache = __collector_reallocVSize (__collector_heap, mapcache,
713 					   sizeof (prmap_t) * mapcache_entries);
714       prmap_t *map = ((prmap_t *) mapcache) + (mapcache_entries - 1);
715       map->pr_vaddr = str2ulong (&str);
716       str++;
717       unsigned long eaddr = str2ulong (&str);
718       str++;
719       map->pr_size = eaddr - map->pr_vaddr;
720       map->pr_mflags = 0;
721       map->pr_mflags += (*str++ == 'r' ? PROT_READ : 0);
722       map->pr_mflags += (*str++ == 'w' ? PROT_WRITE : 0);
723       map->pr_mflags += (*str++ == 'x' ? PROT_EXEC : 0);
724       map->pr_mflags += (*str++ == 's' ? MA_SHARED : 0);
725       str++;
726       map->pr_offset = str2ulong (&str);
727       str++;
728       map->pr_dev = str2ulong (&str) * 0x100;
729       str++;
730       map->pr_dev += str2ulong (&str);
731       str++;
732       map->pr_ino = str2ulong (&str);
733       if (map->pr_dev == 0)
734 	map->pr_mflags |= MA_ANON;
735       while (*str == ' ')
736 	str++;
737       map->pr_mapname = str;
738       map->pr_pagesize = 4096;
739     }
740 
741   /* Compare two maps and record all differences */
742   unsigned nidx = 0;
743   MapInfo *prev = &mmaps;
744   MapInfo *oldp = mmaps.next;
745   for (;;)
746     {
747       prmap_t *newp = nidx < mapcache_entries ?
748 	      (prmap_t*) mapcache + nidx : NULL;
749       if (oldp == NULL && newp == NULL)
750 	break;
751 
752       /* If two maps are equal proceed to the next pair */
753       if (oldp && newp &&
754 	  oldp->vaddr == newp->pr_vaddr &&
755 	  oldp->size == newp->pr_size &&
756 	  __collector_strcmp (oldp->mapname, newp->pr_mapname) == 0)
757 	{
758 	  prev = oldp;
759 	  oldp = oldp->next;
760 	  nidx++;
761 	  continue;
762 	}
763       /* Check if we need to unload the old map first */
764       if (newp == NULL || (oldp && oldp->vaddr <= newp->pr_vaddr))
765 	{
766 	  if (oldp != NULL)
767 	    {
768 	      /* Don't record MA_ANON maps except MA_STACK and MA_BREAK */
769 	      if ((!(oldp->mflags & MA_ANON) || (oldp->mflags & (MA_STACK | MA_BREAK))))
770 		record_segment_unmap (hrt, oldp->vaddr);
771 	      /* Remove and free map */
772 	      prev->next = oldp->next;
773 	      MapInfo *tmp = oldp;
774 	      oldp = oldp->next;
775 	      __collector_freeCSize (__collector_heap, tmp, sizeof (*tmp));
776 	    }
777 	}
778       else
779 	{
780 	  MapInfo *map = (MapInfo*) __collector_allocCSize (__collector_heap, sizeof (MapInfo), 1);
781 	  if (map == NULL)
782 	    {
783 	      __collector_mutex_unlock (&map_lock);
784 	      return;
785 	    }
786 	  map->vaddr = newp->pr_vaddr;
787 	  map->size = newp->pr_size;
788 	  map->offset = newp->pr_offset;
789 	  map->mflags = newp->pr_mflags;
790 	  map->pagesize = newp->pr_pagesize;
791 	  resolve_mapname (map, newp->pr_mapname);
792 
793 	  /* Insert new map */
794 	  map->next = prev->next;
795 	  prev->next = map;
796 	  prev = map;
797 
798 	  /* Don't record MA_ANON maps except MA_STACK and MA_BREAK */
799 	  if (!(newp->pr_mflags & MA_ANON) || (newp->pr_mflags & (MA_STACK | MA_BREAK)))
800 	    {
801 	      unsigned checksum = checksum_mapname (map);
802 	      record_segment_map (hrt, map->vaddr, map->size,
803 				  map->pagesize, map->mflags,
804 				  map->offset, checksum, map->filename);
805 	    }
806 	  nidx++;
807 	}
808     }
809   TprintfT (DBG_LT2, "update_map_segments: done\n\n");
810   __collector_mutex_unlock (&map_lock);
811 } /* update_map_segments */
812 
813 /*
814  *    Map addr to a segment. Cope with split segments.
815  */
816 int
__collector_check_segment_internal(unsigned long addr,unsigned long * base,unsigned long * end,int maxnretries,int MA_FLAGS)817 __collector_check_segment_internal (unsigned long addr, unsigned long *base,
818 				    unsigned long *end, int maxnretries, int MA_FLAGS)
819 {
820   int number_of_tries = 0;
821 retry:
822   ;
823 
824   unsigned long curbase = 0;
825   unsigned long curfoff = 0;
826   unsigned long cursize = 0;
827 
828   MapInfo *mp;
829   for (mp = mmaps.next; mp; mp = mp->next)
830     {
831 
832       if (curbase + cursize == mp->vaddr &&
833 	  curfoff + cursize == mp->offset &&
834 	  ((mp->mflags & MA_FLAGS) == MA_FLAGS
835 	   || __collector_strncmp (mp->mapname, "[vdso]", 6) == 0
836 	   || __collector_strncmp (mp->mapname, "[vsyscall]", 10) == 0
837 	   ))
838 	cursize = mp->vaddr + mp->size - curbase;
839       else if (addr < mp->vaddr)
840 	break;
841       else if ((mp->mflags & MA_FLAGS) != MA_FLAGS
842 	       && __collector_strncmp (mp->mapname, "[vdso]", 6)
843 	       && __collector_strncmp (mp->mapname, "[vsyscall]", 10))
844 	{
845 	  curbase = 0;
846 	  curfoff = 0;
847 	  cursize = 0;
848 	}
849       else
850 	{
851 	  curbase = mp->vaddr;
852 	  curfoff = mp->offset;
853 	  cursize = mp->size;
854 	}
855     }
856 
857   if (addr >= curbase && addr < curbase + cursize)
858     {
859       *base = curbase;
860       *end = curbase + cursize;
861       return 1;
862     }
863 
864   /*
865    * 21275311 Unwind failure in native stack for java application running on jdk8 on x86
866    *
867    * On JDK8, we've observed cases where Java-compiled methods end up
868    * in virtual address segments that were "dead zones" (mflags&PROT_READ==0) at
869    * the time of the last update_map_segments() but are now "live".  So if we
870    * fail to find a segment, let's call update_map_segments and then retry
871    * before giving up.
872    */
873   if (number_of_tries < maxnretries)
874     {
875       number_of_tries++;
876       __collector_ext_update_map_segments ();
877       goto retry;
878     }
879   *base = 0;
880   *end = 0;
881   return 0;
882 }
883 
884 /**
885  * Check if address belongs to a readable and executable segment
886  * @param addr
887  * @param base
888  * @param end
889  * @param maxnretries
890  * @return 1 - yes, 0 - no
891  */
892 int
__collector_check_segment(unsigned long addr,unsigned long * base,unsigned long * end,int maxnretries)893 __collector_check_segment (unsigned long addr, unsigned long *base,
894 			   unsigned long *end, int maxnretries)
895 {
896   int MA_FLAGS = PROT_READ | PROT_EXEC;
897   int res = __collector_check_segment_internal (addr, base, end, maxnretries, MA_FLAGS);
898   return res;
899 }
900 
901 /**
902  * Check if address belongs to a readable segment
903  * @param addr
904  * @param base
905  * @param end
906  * @param maxnretries
907  * @return 1 - yes, 0 - no
908  */
909 int
__collector_check_readable_segment(unsigned long addr,unsigned long * base,unsigned long * end,int maxnretries)910 __collector_check_readable_segment( unsigned long addr, unsigned long *base, unsigned long *end, int maxnretries )
911 {
912     int MA_FLAGS = PROT_READ;
913     int res = __collector_check_segment_internal(addr, base, end, maxnretries, MA_FLAGS);
914     return res;
915 }
916 
917 static ELF_AUX *auxv = NULL;
918 
919 static void
process_vsyscall_page()920 process_vsyscall_page ()
921 {
922   TprintfT (DBG_LT2, "process_vsyscall_page()\n");
923   if (ndyn != 0)
924     {
925       /* We've done this one in this process, and cached the results */
926       /* use the cached results */
927       for (int i = 0; i < ndyn; i++)
928 	{
929 	  append_segment_record ("<event kind=\"map\" object=\"dynfunc\" name=\"%s\" "
930 				 "vaddr=\"0x%016lX\" size=\"%u\" funcname=\"%s\" />\n",
931 				 dynname[i], dynvaddr[i], dynsize[i], dynfuncname[i]);
932 	  TprintfT (DBG_LT2, "process_vsyscall_page: append_segment_record map dynfunc='%s' vaddr=0x%016lX size=%ld funcname='%s' -- from cache\n",
933 		    dynname[i], (unsigned long) dynvaddr[i],
934 		    (long) dynsize[i], dynfuncname[i]);
935 	}
936     }
937   if (nvsysfuncs != 0)
938     {
939       /* We've done this one in this process, and cached the results */
940       /* use the cached results */
941       hrtime_t hrt = GETRELTIME ();
942       for (int i = 0; i < nvsysfuncs; i++)
943 	{
944 	  append_segment_record ("<event kind=\"map\" object=\"function\" tstamp=\"%u.%09u\" "
945 				 "vaddr=\"0x%016lX\" size=\"%u\" name=\"%s\" />\n",
946 				 (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC),
947 				 (unsigned long) sysfuncvaddr[i], (unsigned) sysfuncsize[i], sysfuncname[i]);
948 	  TprintfT (DBG_LT2, "process_vsyscall_page: append_segment_record map function='%s' vaddr=0x%016lX size=%ld -- from cache\n",
949 		    sysfuncname[i], (unsigned long) sysfuncvaddr[i], (long) sysfuncsize[i]);
950 	}
951     }
952   if (ndyn + nvsysfuncs != 0)
953     return;
954 
955   /* After fork we can't rely on environ as it might have
956    * been moved by putenv(). Use the pointer saved by the parent.
957    */
958   if (auxv == NULL)
959     {
960       char **envp = (char**) environ;
961       if (envp == NULL)
962 	return;
963       while (*envp++ != NULL);
964       auxv = (ELF_AUX*) envp;
965     }
966   TprintfT (DBG_LT2, "process_vsyscall_page, auxv = ox%p\n", auxv);
967 
968   ELF_AUX *ap;
969 #ifdef DEBUG
970   for (ap = auxv; ap->a_type != AT_NULL; ap++)
971     TprintfT (DBG_LT2, "process_vsyscall_page: ELF_AUX: "
972 	      " a_type = 0x%016llx %10lld   "
973 	      " a_un.a_val = 0x%016llx %10lld\n",
974 	      (long long) ap->a_type, (long long) ap->a_type,
975 	      (long long) ap->a_un.a_val, (long long) ap->a_un.a_val);
976 #endif
977 
978   // find the first ELF_AUX of type AT_SYSINFO_EHDR
979   ELF_EHDR *ehdr = NULL;
980   for (ap = auxv; ap->a_type != AT_NULL; ap++)
981     {
982       if (ap->a_type == AT_SYSINFO_EHDR)
983 	{
984 	  // newer Linuxes do not have a_ptr field, they just have a_val
985 	  ehdr = (ELF_EHDR*)(intptr_t) ap->a_un.a_val;
986 	  if (ehdr != NULL)
987 	    break;
988 	}
989     }
990 
991   // If one is found
992   if (ehdr != NULL)
993     {
994       char *mapName = "SYSINFO_EHDR";
995       MapInfo *mp;
996       for (mp = mmaps.next; mp; mp = mp->next)
997 	{
998 	  if ((unsigned long) ehdr == mp->vaddr)
999 	    {
1000 	      mp->mflags |= PROT_EXEC;
1001 	      if (mp->mapname && mp->mapname[0])
1002 		mapName = mp->mapname;
1003 	      break;
1004 	    }
1005 	}
1006 
1007       // Find the dynsym section and record all symbols
1008       char *base = (char*) ehdr;
1009       ELF_SHDR *shdr = (ELF_SHDR*) (base + ehdr->e_shoff);
1010       int i;
1011 
1012 #if 0
1013       TprintfT (DBG_LT2, "process_vsyscall_page: ehdr: EI_CLASS=%lld  EI_DATA=%lld EI_OSABI=%lld e_type=%lld e_machine=%lld e_version=%lld\n"
1014 		"  e_entry   =0x%016llx %10lld  e_phoff     =0x%016llx %10lld\n"
1015 		"  e_shoff   =0x%016llx %10lld  e_flags     =0x%016llx %10lld\n"
1016 		"  e_ehsize  =0x%016llx %10lld  e_phentsize =0x%016llx %10lld\n"
1017 		"  e_phnum   =0x%016llx %10lld  e_shentsize =0x%016llx %10lld\n"
1018 		"  e_shnum   =0x%016llx %10lld  e_shstrndx  =0x%016llx %10lld\n",
1019 		(long long) ehdr->e_ident[EI_CLASS], (long long) ehdr->e_ident[EI_DATA], (long long) ehdr->e_ident[EI_OSABI],
1020 		(long long) ehdr->e_type, (long long) ehdr->e_machine, (long long) ehdr->e_version,
1021 		(long long) ehdr->e_entry, (long long) ehdr->e_entry,
1022 		(long long) ehdr->e_phoff, (long long) ehdr->e_phoff,
1023 		(long long) ehdr->e_shoff, (long long) ehdr->e_shoff,
1024 		(long long) ehdr->e_flags, (long long) ehdr->e_flags,
1025 		(long long) ehdr->e_ehsize, (long long) ehdr->e_ehsize,
1026 		(long long) ehdr->e_phentsize, (long long) ehdr->e_phentsize,
1027 		(long long) ehdr->e_phnum, (long long) ehdr->e_phnum,
1028 		(long long) ehdr->e_shentsize, (long long) ehdr->e_shentsize,
1029 		(long long) ehdr->e_shnum, (long long) ehdr->e_shnum,
1030 		(long long) ehdr->e_shstrndx, (long long) ehdr->e_shstrndx);
1031       for (i = 1; i < ehdr->e_shnum; i++)
1032 	{
1033 	  TprintfT (DBG_LT2, "process_vsyscall_page: SECTION=%d sh_name=%lld '%s'\n"
1034 		    "  sh_type       =0x%016llx %10lld\n"
1035 		    "  sh_flags      =0x%016llx %10lld\n"
1036 		    "  sh_addr       =0x%016llx %10lld\n"
1037 		    "  sh_offset     =0x%016llx %10lld\n"
1038 		    "  sh_size       =0x%016llx %10lld\n"
1039 		    "  sh_link       =0x%016llx %10lld\n"
1040 		    "  sh_info       =0x%016llx %10lld\n"
1041 		    "  sh_addralign  =0x%016llx %10lld\n"
1042 		    "  sh_entsize    =0x%016llx %10lld\n",
1043 		    i, (long long) shdr[i].sh_name, base + shdr[ehdr->e_shstrndx].sh_offset + shdr[i].sh_name,
1044 		    (long long) shdr[i].sh_type, (long long) shdr[i].sh_type,
1045 		    (long long) shdr[i].sh_flags, (long long) shdr[i].sh_flags,
1046 		    (long long) shdr[i].sh_addr, (long long) shdr[i].sh_addr,
1047 		    (long long) shdr[i].sh_offset, (long long) shdr[i].sh_offset,
1048 		    (long long) shdr[i].sh_size, (long long) shdr[i].sh_size,
1049 		    (long long) shdr[i].sh_link, (long long) shdr[i].sh_link,
1050 		    (long long) shdr[i].sh_info, (long long) shdr[i].sh_info,
1051 		    (long long) shdr[i].sh_addralign, (long long) shdr[i].sh_addralign,
1052 		    (long long) shdr[i].sh_entsize, (long long) shdr[i].sh_entsize);
1053 	}
1054 #endif
1055 
1056       int dynSec = -1;
1057       for (i = 1; i < ehdr->e_shnum; i++)
1058 	if (shdr[i].sh_type == SHT_DYNSYM)
1059 	  {
1060 	    dynSec = i;
1061 	    break;
1062 	  }
1063       if (dynSec != -1)
1064 	{
1065 	  char *symbase = base + shdr[shdr[dynSec].sh_link].sh_offset;
1066 	  ELF_SYM *symbols = (ELF_SYM*) (base + shdr[dynSec].sh_offset);
1067 	  int nextSec = 0;
1068 	  int n = shdr[dynSec].sh_size / shdr[dynSec].sh_entsize;
1069 	  for (i = 0; i < n; i++)
1070 	    {
1071 	      ELF_SYM *sym = symbols + i;
1072 	      TprintfT (DBG_LT2, "process_vsyscall_page: symbol=%d st_name=%lld '%s'\n"
1073 			"  st_size     = 0x%016llx %10lld\n"
1074 			"  st_value    = 0x%016llx %10lld\n"
1075 			"  st_shndx    = 0x%016llx %10lld\n"
1076 			"  st_info     = 0x%016llx %10lld\n",
1077 			i, (long long) sym->st_name, symbase + sym->st_name,
1078 			(long long) sym->st_size, (long long) sym->st_size,
1079 			(long long) sym->st_value, (long long) sym->st_value,
1080 			(long long) sym->st_shndx, (long long) sym->st_shndx,
1081 			(long long) sym->st_info, (long long) sym->st_info);
1082 	      if (sym->st_shndx <= 0 || sym->st_size <= 0 ||
1083 		  ELF_ST_BIND (sym->st_info) != STB_GLOBAL || ELF_ST_TYPE (sym->st_info) != STT_FUNC)
1084 		continue;
1085 	      if (nextSec == 0)
1086 		nextSec = sym->st_shndx;
1087 	      else if (nextSec > sym->st_shndx)
1088 		nextSec = sym->st_shndx;
1089 	    }
1090 	  if (nextSec == 0)
1091 	    ehdr = NULL;
1092 
1093 	  while (nextSec != 0)
1094 	    {
1095 	      int curSec = nextSec;
1096 	      char *bgn = base + shdr[curSec].sh_offset;
1097 	      char *end = bgn + shdr[curSec].sh_size;
1098 	      for (i = 0; i < n; i++)
1099 		{
1100 		  ELF_SYM *sym = symbols + i;
1101 		  if (sym->st_shndx <= 0 || sym->st_size <= 0 ||
1102 		      ELF_ST_BIND (sym->st_info) != STB_GLOBAL || ELF_ST_TYPE (sym->st_info) != STT_FUNC)
1103 		    continue;
1104 		  if (sym->st_shndx > curSec)
1105 		    {
1106 		      if (nextSec == curSec)
1107 			nextSec = sym->st_shndx;
1108 		      else if (nextSec > sym->st_shndx)
1109 			nextSec = sym->st_shndx;
1110 		      nextSec = sym->st_shndx;
1111 		      continue;
1112 		    }
1113 		  if (sym->st_shndx != curSec)
1114 		    continue;
1115 		  long long st_delta = (sym->st_value >= shdr[sym->st_shndx].sh_addr) ?
1116 			  (sym->st_value - shdr[sym->st_shndx].sh_addr) : -1;
1117 		  char *st_value = bgn + st_delta;
1118 		  if (st_delta >= 0 && st_value + sym->st_size <= end)
1119 		    {
1120 		      append_segment_record ("<event kind=\"map\" object=\"dynfunc\" name=\"%s\" "
1121 					     "vaddr=\"0x%016lX\" size=\"%u\" funcname=\"%s\" />\n",
1122 					     mapName, (void*) st_value, sym->st_size, symbase + sym->st_name);
1123 
1124 		      TprintfT (DBG_LT2, "process_vsyscall_page: append_segment_record map dynfunc='%s' vaddr=%016lX size=%ld funcname='%s'\n",
1125 				mapName, (unsigned long) st_value,
1126 				(long) sym->st_size, symbase + sym->st_name);
1127 
1128 		      /* now cache this for a subsequent experiment */
1129 		      if (ndyn >= MAXDYN)
1130 			__collector_log_write ("<event kind=\"%s\" id=\"%d\">MAXDYN=%d</event>\n",
1131 					       SP_JCMD_CERROR, COL_ERROR_MAPCACHE, MAXDYN);
1132 		      else
1133 			{
1134 			  dynname [ndyn] = CALL_UTIL (libc_strdup)(mapName);
1135 			  dynvaddr [ndyn] = (void *) st_value;
1136 			  dynsize [ndyn] = (unsigned) sym->st_size;
1137 			  dynfuncname[ndyn] = CALL_UTIL (libc_strdup)(symbase + sym->st_name);
1138 			  TprintfT (DBG_LT2, "process_vsyscall_page: cached entry %d  map function='%s' vaddr=0x%016lX size=%ld '%s'\n",
1139 				    ndyn, dynname[ndyn], (unsigned long) dynvaddr[ndyn],
1140 				    (long) dynsize[ndyn], dynfuncname[ndyn]);
1141 			  ndyn++;
1142 			}
1143 		    }
1144 		}
1145 	      __collector_int_func_load (DFUNC_KERNEL, mapName, NULL,
1146 					 (void*) (base + shdr[curSec].sh_offset), shdr[curSec].sh_size, 0, NULL);
1147 
1148 	      /* now cache this function for a subsequent experiment */
1149 	      if (nvsysfuncs >= MAXVSYSFUNCS)
1150 		__collector_log_write ("<event kind=\"%s\" id=\"%d\">MAXVSYSFUNCS=%d</event>\n",
1151 				       SP_JCMD_CERROR, COL_ERROR_MAPCACHE, MAXVSYSFUNCS);
1152 	      else
1153 		{
1154 		  sysfuncname[nvsysfuncs] = CALL_UTIL (libc_strdup)(mapName);
1155 		  sysfuncvaddr[nvsysfuncs] = (unsigned long) (base + shdr[curSec].sh_offset);
1156 		  sysfuncsize[nvsysfuncs] = (unsigned long) (shdr[curSec].sh_size);
1157 		  TprintfT (DBG_LT2, "process_vsyscall_page: cached entry %d  map function='%s' vaddr=0x%016lX size=%ld\n",
1158 			    nvsysfuncs, sysfuncname[nvsysfuncs],
1159 			    (unsigned long) sysfuncvaddr[nvsysfuncs],
1160 			    (long) sysfuncsize[nvsysfuncs]);
1161 		  nvsysfuncs++;
1162 		}
1163 	      TprintfT (DBG_LT2, "process_vsyscall_page: collector_int_func_load='%s' vaddr=0x%016lX size=%ld\n",
1164 			mapName, (unsigned long) (base + shdr[curSec].sh_offset),
1165 			(long) shdr[curSec].sh_size);
1166 	      if (curSec == nextSec)
1167 		break;
1168 	    }
1169 	}
1170     }
1171 
1172 #if WSIZE(32)
1173   unsigned long vsysaddr = (unsigned long) 0xffffe000;
1174 #elif WSIZE(64)
1175   unsigned long vsysaddr = (unsigned long) 0xffffffffff600000;
1176 #endif
1177   // Make sure the vsyscall map has PROT_EXEC
1178   MapInfo *mp;
1179   for (mp = mmaps.next; mp; mp = mp->next)
1180     {
1181       TprintfT (DBG_LT2, "MapInfo: vaddr=0x%016llx [size=%lld] mflags=0x%llx offset=%lld pagesize=%lld\n"
1182 		"  mapname='%s'   filename='%s'\n",
1183 		(unsigned long long) mp->vaddr, (long long) mp->size,
1184 		(long long) mp->mflags, (long long) mp->offset, (long long) mp->pagesize,
1185 		mp->mapname ? mp->mapname : "NULL",
1186 		mp->filename ? mp->filename : "NULL");
1187       if (vsysaddr == mp->vaddr)
1188 	mp->mflags |= PROT_EXEC;
1189       if ((unsigned long) ehdr == (unsigned long) mp->vaddr)
1190 	continue;
1191       if (__collector_strncmp (mp->mapname, "[vdso]", 6) == 0
1192 	  || __collector_strncmp (mp->mapname, "[vsyscall]", 10) == 0)
1193 	{
1194 	  /*
1195 	   * On rubbia ( 2.6.9-5.ELsmp #1 SMP 32-bit ) access to ehdr causes SEGV.
1196 	   * There doesn't seem to be a way to reliably determine the actual presence
1197 	   * of the page: even when /proc reports it's there it can't be accessed.
1198 	   * We will have to put up with <Unknown> on some Linuxes until this is resolved.
1199 	  __collector_int_func_load(DFUNC_KERNEL, mp->mapname, NULL, (void*) mp->vaddr, mp->size, 0, NULL);
1200 	   */
1201 	  hrtime_t hrt = GETRELTIME ();
1202 	  append_segment_record (
1203 				 "<event kind=\"map\" object=\"function\" tstamp=\"%u.%09u\" "
1204 				 "vaddr=\"0x%016lX\" size=\"%u\" name=\"%s\" />\n",
1205 				 (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC),
1206 				 (unsigned long) mp->vaddr, (unsigned) mp->size, mp->mapname);
1207 	  TprintfT (DBG_LT2, "process_vsyscall_page: append_segment_record map function = %s, vaddr = 0x%016lX, size = %u\n",
1208 		    mp->mapname, (unsigned long) mp->vaddr, (unsigned) mp->size);
1209 
1210 	  /* now cache this function for a subsequent experiment */
1211 	  if (nvsysfuncs >= MAXVSYSFUNCS)
1212 	    __collector_log_write ("<event kind=\"%s\" id=\"%d\">MAXVSYSFUNCS=%d</event>\n",
1213 				   SP_JCMD_CERROR, COL_ERROR_MAPCACHE, MAXVSYSFUNCS);
1214 	  else
1215 	    {
1216 	      sysfuncname[nvsysfuncs] = CALL_UTIL (libc_strdup)(mp->mapname);
1217 	      sysfuncvaddr[nvsysfuncs] = mp->vaddr;
1218 	      sysfuncsize[nvsysfuncs] = (unsigned long) mp->size;
1219 	      TprintfT (DBG_LT2, "process_vsyscall_page: cached entry %d  map function='%s' vaddr=0x%016lX size=%ld\n",
1220 			nvsysfuncs, sysfuncname[nvsysfuncs],
1221 			(unsigned long) sysfuncvaddr[nvsysfuncs],
1222 			(long) sysfuncsize[nvsysfuncs]);
1223 	      nvsysfuncs++;
1224 
1225 	    }
1226 	}
1227     }
1228 }
1229 
1230 /*
1231  * collector API for dynamic functions
1232  */
1233 void collector_func_load () __attribute__ ((weak, alias ("__collector_func_load")));
1234 void
__collector_func_load(char * name,char * alias,char * sourcename,void * vaddr,int size,int lntsize,DT_lineno * lntable)1235 __collector_func_load (char *name, char *alias, char *sourcename,
1236 		       void *vaddr, int size, int lntsize, DT_lineno *lntable)
1237 {
1238   __collector_int_func_load (DFUNC_API, name, sourcename,
1239 			     vaddr, size, lntsize, lntable);
1240 }
1241 
1242 void collector_func_unload () __attribute__ ((weak, alias ("__collector_func_unload")));
1243 void
__collector_func_unload(void * vaddr)1244 __collector_func_unload (void *vaddr)
1245 {
1246   __collector_int_func_unload (DFUNC_API, vaddr);
1247 }
1248 
1249 /* routines for handling dynamic functions */
1250 static void
rwrite(int fd,void * buf,size_t nbyte)1251 rwrite (int fd, void *buf, size_t nbyte)
1252 {
1253   size_t left = nbyte;
1254   size_t res;
1255   char *ptr = (char*) buf;
1256   while (left > 0)
1257     {
1258       res = CALL_UTIL (write)(fd, ptr, left);
1259       if (res == -1)
1260 	{
1261 	  TprintfT (0, "ERROR: rwrite(%s) failed: errno=%d\n", dyntext_fname, errno);
1262 	  (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s</event>\n",
1263 					SP_JCMD_CERROR, COL_ERROR_DYNWRITE, errno, dyntext_fname);
1264 	  return;
1265 	}
1266       left -= res;
1267       ptr += res;
1268     }
1269 }
1270 
1271 void
__collector_int_func_load(dfunc_mode_t mode,char * name,char * sourcename,void * vaddr,int size,int lntsize,DT_lineno * lntable)1272 __collector_int_func_load (dfunc_mode_t mode, char *name, char *sourcename,
1273 			   void *vaddr, int size, int lntsize, DT_lineno *lntable)
1274 {
1275   char name_buf[32];
1276   int slen;
1277   static char pad[16];
1278   int padn;
1279   if (!mmap_initted)
1280     return;
1281   hrtime_t hrt = GETRELTIME ();
1282 
1283   if (name == NULL)
1284     {
1285       /* generate a name based on vaddr */
1286       CALL_UTIL (snprintf)(name_buf, sizeof (name_buf), "0x%lx", (unsigned long) vaddr);
1287       name = name_buf;
1288     }
1289 
1290   switch (mode)
1291     {
1292     case DFUNC_API:
1293     case DFUNC_KERNEL:
1294       append_segment_record ("<event kind=\"map\" object=\"function\" tstamp=\"%u.%09u\" "
1295 			     "vaddr=\"0x%016lX\" size=\"%u\" name=\"%s\" />\n",
1296 			     (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC),
1297 			     (unsigned long) vaddr, (unsigned) size, name);
1298       break;
1299     case DFUNC_JAVA:
1300       append_segment_record ("<event kind=\"map\" object=\"jcm\" tstamp=\"%u.%09u\" "
1301 			     "vaddr=\"0x%016lX\" size=\"%u\" methodId=\"%s\" />\n",
1302 			     (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC),
1303 			     (unsigned long) vaddr, (unsigned) size, name);
1304       break;
1305     default:
1306       return;
1307     }
1308 
1309   /* 21275311 Unwind failure in native stack for java application running on jdk8 on x86
1310    * Check:
1311    *   - function starts in a known segment (base1 != 0)
1312    *   - function ends in the same segment (base1==base2 && end1==end2)
1313    * If not, then call update_map_segments().
1314    */
1315   unsigned long base1, end1, base2, end2;
1316   __collector_check_segment ((unsigned long) vaddr, &base1, &end1, 0);
1317   if (base1)
1318     __collector_check_segment (((unsigned long) vaddr)+((unsigned long) size), &base2, &end2, 0);
1319   if (base1 == 0 || base1 != base2 || end1 != end2)
1320     __collector_ext_update_map_segments ();
1321 
1322   /* Write a copy of actual code to the "dyntext" file */
1323   DT_header dt_hdr;
1324   dt_hdr.type = DT_HEADER;
1325   dt_hdr.size = sizeof (dt_hdr);
1326   dt_hdr.time = hrt;
1327   unsigned long t = (unsigned long) vaddr; /* to suppress a warning from gcc */
1328   dt_hdr.vaddr = (uint64_t) t;
1329 
1330   DT_code dt_code;
1331   dt_code.type = DT_CODE;
1332   void *code = vaddr;
1333   if (vaddr != NULL && size > 0)
1334     {
1335       dt_code.size = sizeof (dt_code) + ((size + 0xf) & ~0xf);
1336       if (mode == DFUNC_KERNEL)
1337 	{
1338 	  /* Some Linuxes don't accept vaddrs from the vsyscall
1339 	   * page in write(). Make a copy.
1340 	   */
1341 	  code = alloca (size);
1342 	  __collector_memcpy (code, vaddr, size);
1343 	}
1344     }
1345   else
1346     dt_code.size = 0;
1347 
1348   DT_srcfile dt_src;
1349   dt_src.type = DT_SRCFILE;
1350   if (sourcename)
1351     {
1352       slen = CALL_UTIL (strlen)(sourcename) + 1;
1353       dt_src.size = slen ? sizeof (dt_src) + ((slen + 0xf) & ~0xf) : 0;
1354     }
1355   else
1356     {
1357       slen = 0;
1358       dt_src.size = 0;
1359     }
1360 
1361   DT_ltable dt_ltbl;
1362   dt_ltbl.type = DT_LTABLE;
1363   if (lntable != NULL && lntsize > 0)
1364     dt_ltbl.size = sizeof (dt_ltbl) + lntsize * sizeof (DT_lineno);
1365   else
1366     dt_ltbl.size = 0;
1367 
1368   int fd = CALL_UTIL (open)(dyntext_fname, O_RDWR | O_APPEND);
1369   if (fd == -1)
1370     {
1371       TprintfT (0, "ERROR: __collector_int_func_load: open(%s) failed: errno=%d\n",
1372 		dyntext_fname, errno);
1373       (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s</event>\n",
1374 				    SP_JCMD_CERROR, COL_ERROR_DYNOPEN, errno, dyntext_fname);
1375       return;
1376     }
1377 
1378   /* Lock the whole file */
1379   __collector_mutex_lock (&dyntext_lock);
1380   rwrite (fd, &dt_hdr, sizeof (dt_hdr));
1381   if (dt_code.size)
1382     {
1383       padn = dt_code.size - sizeof (dt_code) - size;
1384       rwrite (fd, &dt_code, sizeof (dt_code));
1385       rwrite (fd, code, size);
1386       rwrite (fd, &pad, padn);
1387     }
1388   if (dt_src.size)
1389     {
1390       padn = dt_src.size - sizeof (dt_src) - slen;
1391       rwrite (fd, &dt_src, sizeof (dt_src));
1392       rwrite (fd, sourcename, slen);
1393       rwrite (fd, &pad, padn);
1394     }
1395   if (dt_ltbl.size)
1396     {
1397       rwrite (fd, &dt_ltbl, sizeof (dt_ltbl));
1398       rwrite (fd, lntable, dt_ltbl.size - sizeof (dt_ltbl));
1399     }
1400 
1401     /* Unlock the file */
1402     __collector_mutex_unlock( &dyntext_lock );
1403     CALL_UTIL(close( fd ) );
1404 }
1405 
1406 void
__collector_int_func_unload(dfunc_mode_t mode,void * vaddr)1407 __collector_int_func_unload (dfunc_mode_t mode, void *vaddr)
1408 {
1409   if (!mmap_initted)
1410     return;
1411   hrtime_t hrt = GETRELTIME ();
1412   if (mode == DFUNC_API)
1413     append_segment_record ("<event kind=\"unmap\" tstamp=\"%u.%09u\" vaddr=\"0x%016lX\"/>\n",
1414 			   (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC), (unsigned long) vaddr);
1415   else if (mode == DFUNC_JAVA)
1416     /* note that the "vaddr" is really a method id, not an address */
1417     append_segment_record ("<event kind=\"unmap\" tstamp=\"%u.%09u\" methodId=\"0x%016lX\"/>\n",
1418 			   (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC), (unsigned long) vaddr);
1419   else
1420     return;
1421 }
1422 
1423 /*
1424  * int init_mmap_intf()
1425  *      Set up interposition (if not already done).
1426  */
1427 static int
init_mmap_intf()1428 init_mmap_intf ()
1429 {
1430   if (__collector_dlsym_guard)
1431     return 1;
1432   void *dlflag;
1433   __real_mmap = (void*(*)(void* addr, size_t len, int prot, int flags,
1434 			  int fildes, off_t off))dlsym (RTLD_NEXT, SYS_MMAP_NAME);
1435   if (__real_mmap == NULL)
1436     {
1437 
1438       /* We are probably dlopened after libthread/libc,
1439        * try to search in the previously loaded objects
1440        */
1441       __real_mmap = (void*(*)(void* addr, size_t len, int prot, int flags,
1442 			      int fildes, off_t off))dlsym (RTLD_DEFAULT, SYS_MMAP_NAME);
1443       if (__real_mmap == NULL)
1444 	{
1445 	  TprintfT (0, "ERROR: collector real mmap not found\n");
1446 	  return 1;
1447 	}
1448       TprintfT (DBG_LT2, "collector real mmap found with RTLD_DEFAULT\n");
1449       dlflag = RTLD_DEFAULT;
1450     }
1451   else
1452     {
1453       TprintfT (DBG_LT2, "collector real mmap found with RTLD_NEXT\n");
1454       dlflag = RTLD_NEXT;
1455     }
1456 
1457   TprintfT (DBG_LT2, "init_mmap_intf() @%p __real_mmap\n", __real_mmap);
1458   __real_mmap64 = (void*(*)(void *, size_t, int, int, int, off64_t))
1459 	  dlsym (dlflag, SYS_MMAP64_NAME);
1460   TprintfT (DBG_LT2, "init_mmap_intf() @%p __real_mmap64\n", __real_mmap64);
1461   __real_munmap = (int(*)(void *, size_t)) dlsym (dlflag, SYS_MUNMAP_NAME);
1462   TprintfT (DBG_LT2, "init_mmap_intf() @%p __real_munmap\n", __real_munmap);
1463 
1464   // dlopen/dlmopen/dlclose are in libdl.so
1465   __real_dlopen = (void*(*)(const char *, int))
1466 	  dlvsym (dlflag, SYS_DLOPEN_NAME, SYS_DLOPEN_VERSION);
1467   TprintfT (DBG_LT2, "init_mmap_intf() [%s] @%p __real_dlopen\n",
1468 	    SYS_DLOPEN_VERSION, __real_dlopen);
1469 #if (ARCH(Intel) && WSIZE(32)) || ARCH(SPARC)
1470   __real_dlopen_2_1 = __real_dlopen;
1471   __real_dlopen_2_0 = (void*(*)(const char *, int))
1472 	  dlvsym (dlflag, SYS_DLOPEN_NAME, "GLIBC_2.0");
1473 #endif
1474 
1475   __real_dlclose = (int(*)(void* handle))dlsym (dlflag, SYS_DLCLOSE_NAME);
1476   TprintfT (DBG_LT2, "init_mmap_intf() @%p __real_dlclose\n", __real_dlclose);
1477   TprintfT (DBG_LT2, "init_mmap_intf() done\n");
1478 
1479   return 0;
1480 }
1481 
1482 /*------------------------------------------------------------- mmap */
1483 void *
mmap(void * start,size_t length,int prot,int flags,int fd,off_t offset)1484 mmap (void *start, size_t length, int prot, int flags, int fd, off_t offset)
1485 {
1486   int err = 0;
1487   if (NULL_PTR (mmap))
1488     err = init_mmap_intf ();
1489   if (err)
1490     return MAP_FAILED;
1491 
1492   /* hrtime_t hrt = GETRELTIME(); */
1493   void *ret = CALL_REAL (mmap)(start, length, prot, flags, fd, offset);
1494 
1495   if (!CHCK_REENTRANCE && (ret != MAP_FAILED) && collector_heap_record != NULL)
1496     {
1497       PUSH_REENTRANCE;
1498       /* write a separate record for mmap tracing */
1499       collector_heap_record (MMAP_TRACE, length, ret);
1500       POP_REENTRANCE;
1501     }
1502   TprintfT (DBG_LT2, "libcollector.mmap(%p, %ld, %d, %d, %d, 0x%lld) = %p\n",
1503 	    start, (long) length, prot, flags, fd, (long long) offset, ret);
1504   return ret;
1505 }
1506 
1507 /*------------------------------------------------------------- mmap64 */
1508 #if WSIZE(32)       /* mmap64 only defined for non-64-bit */
1509 
1510 void *
mmap64(void * start,size_t length,int prot,int flags,int fd,off64_t offset)1511 mmap64 (void *start, size_t length, int prot, int flags, int fd, off64_t offset)
1512 {
1513   if (NULL_PTR (mmap64))
1514     init_mmap_intf ();
1515 
1516   /* hrtime_t hrt = GETRELTIME(); */
1517   void *ret = CALL_REAL (mmap64)(start, length, prot, flags, fd, offset);
1518   if (!CHCK_REENTRANCE && (ret != MAP_FAILED) && collector_heap_record != NULL)
1519     {
1520       PUSH_REENTRANCE;
1521       /* write a separate record for mmap tracing */
1522       collector_heap_record (MMAP_TRACE, length, ret);
1523       POP_REENTRANCE;
1524     }
1525   TprintfT (DBG_LT2, "libcollector.mmap64(%p, %ld, %d, %d, %d, 0x%lld) = %p\n",
1526 	    start, (long) length, prot, flags, fd, (long long) offset, ret);
1527   return ret;
1528 }
1529 #endif /* WSIZE(32) */
1530 
1531 /*------------------------------------------------------------- munmap */
1532 int
munmap(void * start,size_t length)1533 munmap (void *start, size_t length)
1534 {
1535   if (NULL_PTR (munmap))
1536     init_mmap_intf ();
1537 
1538   /* hrtime_t hrt = GETRELTIME(); */
1539   int rc = CALL_REAL (munmap)(start, length);
1540   if (!CHCK_REENTRANCE && (rc == 0) && collector_heap_record != NULL)
1541     {
1542       PUSH_REENTRANCE;
1543       /* write a separate record for mmap tracing */
1544       collector_heap_record (MUNMAP_TRACE, length, start);
1545       POP_REENTRANCE;
1546     }
1547   TprintfT (DBG_LT2, "libcollector.munmap(%p, %ld) = %d\n", start, (long) length, rc);
1548   return rc;
1549 }
1550 
1551 
1552 /*------------------------------------------------------------- dlopen */
1553 // map interposed symbol versions
1554 #if (ARCH(Intel) && WSIZE(32)) || ARCH(SPARC)
1555 
1556 static void *
1557 __collector_dlopen_symver (void*(real_dlopen) (), void *caller, const char *pathname, int mode);
1558 
1559 SYMVER_ATTRIBUTE (__collector_dlopen_2_1, dlopen@@GLIBC_2.1)
1560 void *
__collector_dlopen_2_1(const char * pathname,int mode)1561 __collector_dlopen_2_1 (const char *pathname, int mode)
1562 {
1563   if (NULL_PTR (dlopen))
1564     init_mmap_intf ();
1565   void *caller = __builtin_return_address (0); // must be called inside dlopen first layer interpostion
1566   return __collector_dlopen_symver (CALL_REAL (dlopen_2_1), caller, pathname, mode);
1567 }
1568 
1569 SYMVER_ATTRIBUTE (__collector_dlopen_2_0, dlopen@GLIBC_2.0)
1570 void *
__collector_dlopen_2_0(const char * pathname,int mode)1571 __collector_dlopen_2_0 (const char *pathname, int mode)
1572 {
1573   if (NULL_PTR (dlopen))
1574     init_mmap_intf ();
1575   void* caller = __builtin_return_address (0); // must be called inside dlopen first layer interpostion
1576   return __collector_dlopen_symver (CALL_REAL (dlopen_2_0), caller, pathname, mode);
1577 }
1578 #endif
1579 
1580 #if (ARCH(Intel) && WSIZE(32)) || ARCH(SPARC)
1581 static void *
__collector_dlopen_symver(void * (real_dlopen)(),void * caller,const char * pathname,int mode)1582 __collector_dlopen_symver (void*(real_dlopen) (), void *caller, const char *pathname, int mode)
1583 #else
1584 void *
1585 dlopen (const char *pathname, int mode)
1586 #endif
1587 {
1588   const char * real_pathname = pathname;
1589   char new_pathname[MAXPATHLEN];
1590   int origin_offset = 0;
1591   TprintfT (DBG_LT2, "dlopen: pathname=%s, mode=%d\n", pathname ? pathname : "NULL", mode);
1592   if (pathname && __collector_strStartWith (pathname, "$ORIGIN/") == 0)
1593     origin_offset = 8;
1594   else if (pathname && __collector_strStartWith (pathname, "${ORIGIN}/") == 0)
1595     origin_offset = 10;
1596   if (origin_offset)
1597     {
1598 #if ! ((ARCH(Intel) && WSIZE(32)) || ARCH(SPARC))
1599       // 'caller' is not passed as an argument
1600       void * caller = __builtin_return_address (0); // must be called inside dlopen first layer interpostion
1601 #endif
1602       Dl_info dl_info;
1603       if (caller && dladdr (caller, &dl_info) != 0)
1604 	{
1605 	  TprintfT (DBG_LT2, "dladdr(%p): %p fname=%s\n",
1606 		    caller, dl_info.dli_fbase, dl_info.dli_fname);
1607 	  new_pathname[0] = '\0';
1608 	  const char *p = __collector_strrchr (dl_info.dli_fname, '/');
1609 	  if (p)
1610 	    __collector_strlcpy (new_pathname, dl_info.dli_fname,
1611 				 (p - dl_info.dli_fname + 2) < MAXPATHLEN ? (p - dl_info.dli_fname + 2) : MAXPATHLEN);
1612 	  __collector_strlcat (new_pathname, pathname + origin_offset, MAXPATHLEN - CALL_UTIL (strlen)(new_pathname));
1613 	  real_pathname = new_pathname;
1614 	}
1615       else
1616 	TprintfT (0, "ERROR: dladdr(%p): %s\n", caller, dlerror ());
1617     }
1618   if (NULL_PTR (dlopen))
1619     init_mmap_intf ();
1620   TprintfT (DBG_LT2, "libcollector.dlopen(%s,%d) interposing\n",
1621 	    pathname ? pathname : "", mode);
1622   void* ret = NULL;
1623 
1624   // set guard for duration of handling dlopen, since want to ensure
1625   // new mappings are resolved after the actual dlopen has occurred
1626   PUSH_REENTRANCE;
1627   hrtime_t hrt = GETRELTIME ();
1628 
1629   if (real_pathname && !__collector_strchr (real_pathname, '/'))
1630     { // got an unqualified name
1631       // get caller and use its searchpath
1632 #if ! ((ARCH(Intel) && WSIZE(32)) || ARCH(SPARC))
1633       void* caller = __builtin_return_address (0); // must be called inside dlopen
1634 #endif
1635       if (caller)
1636 	{
1637 #if (ARCH(Intel) && WSIZE(32)) || ARCH(SPARC)
1638 	  ret = dlopen_searchpath_symver (real_dlopen, caller, real_pathname, mode);
1639 #else
1640 	  ret = dlopen_searchpath (caller, real_pathname, mode);
1641 #endif
1642 	}
1643     }
1644 
1645   if (!ret)
1646     {
1647 #if (ARCH(Intel) && WSIZE(32)) || ARCH(SPARC)
1648       ret = (real_dlopen) (real_pathname, mode);
1649 #else
1650       ret = CALL_REAL (dlopen)(real_pathname, mode);
1651 #endif
1652     }
1653   TprintfT (DBG_LT2, "libcollector -- dlopen(%s) returning %p\n", pathname, ret);
1654 
1655   /* Don't call update if dlopen failed: preserve dlerror() */
1656   if (ret && (mmap_mode > 0) && !(mode & RTLD_NOLOAD))
1657     update_map_segments (hrt, 1);
1658   TprintfT (DBG_LT2, "libcollector -- dlopen(%s) returning %p\n", pathname, ret);
1659   POP_REENTRANCE;
1660   return ret;
1661 }
1662 
1663 /*------------------------------------------------------------- dlclose */
1664 int
dlclose(void * handle)1665 dlclose (void *handle)
1666 {
1667   if (NULL_PTR (dlclose))
1668     init_mmap_intf ();
1669   TprintfT (DBG_LT2, "__collector_dlclose(%p) entered\n", handle);
1670   hrtime_t hrt = GETRELTIME ();
1671   if (!CHCK_REENTRANCE)
1672     {
1673       PUSH_REENTRANCE;
1674       update_map_segments (hrt, 1);
1675       POP_REENTRANCE;
1676       hrt = GETRELTIME ();
1677     }
1678   int ret = CALL_REAL (dlclose)(handle);
1679 
1680   /* Don't call update if dlclose failed: preserve dlerror() */
1681   if (!ret && !CHCK_REENTRANCE)
1682     {
1683       PUSH_REENTRANCE;
1684       update_map_segments (hrt, 1);
1685       POP_REENTRANCE;
1686     }
1687   TprintfT (DBG_LT2, "__collector_dlclose(%p) returning %d\n", handle, ret);
1688   return ret;
1689 }
1690