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