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