elf: Make glibc.rtld.enable_secure ignore alias environment variables
[glibc.git] / elf / sprof.c
blobb19aca329241a41a7fc4294e4d613a51b695b7c1
1 /* Read and display shared object profiling data.
2 Copyright (C) 1997-2024 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
19 #include <argp.h>
20 #include <dlfcn.h>
21 #include <elf.h>
22 #include <error.h>
23 #include <fcntl.h>
24 #include <inttypes.h>
25 #include <libintl.h>
26 #include <locale.h>
27 #include <obstack.h>
28 #include <search.h>
29 #include <stdbool.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <stdint.h>
35 #include <ldsodefs.h>
36 #include <sys/gmon.h>
37 #include <sys/gmon_out.h>
38 #include <sys/mman.h>
39 #include <sys/param.h>
40 #include <sys/stat.h>
42 /* Get libc version number. */
43 #include "../version.h"
45 #define PACKAGE _libc_intl_domainname
48 #include <endian.h>
49 #if BYTE_ORDER == BIG_ENDIAN
50 # define byteorder ELFDATA2MSB
51 # define byteorder_name "big-endian"
52 #elif BYTE_ORDER == LITTLE_ENDIAN
53 # define byteorder ELFDATA2LSB
54 # define byteorder_name "little-endian"
55 #else
56 # error "Unknown BYTE_ORDER " BYTE_ORDER
57 # define byteorder ELFDATANONE
58 #endif
60 #ifndef PATH_MAX
61 # define PATH_MAX 1024
62 #endif
65 extern int __profile_frequency (void);
67 /* Name and version of program. */
68 static void print_version (FILE *stream, struct argp_state *state);
69 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
71 #define OPT_TEST 1
73 /* Definitions of arguments for argp functions. */
74 static const struct argp_option options[] =
76 { NULL, 0, NULL, 0, N_("Output selection:") },
77 { "call-pairs", 'c', NULL, 0,
78 N_("print list of count paths and their number of use") },
79 { "flat-profile", 'p', NULL, 0,
80 N_("generate flat profile with counts and ticks") },
81 { "graph", 'q', NULL, 0, N_("generate call graph") },
83 { "test", OPT_TEST, NULL, OPTION_HIDDEN, NULL },
84 { NULL, 0, NULL, 0, NULL }
87 /* Short description of program. */
88 static const char doc[] = N_("Read and display shared object profiling data.");
89 //For bug reporting instructions, please see:\n
90 //<https://www.gnu.org/software/libc/bugs.html>.\n");
92 /* Strings for arguments in help texts. */
93 static const char args_doc[] = N_("SHOBJ [PROFDATA]");
95 /* Prototype for option handler. */
96 static error_t parse_opt (int key, char *arg, struct argp_state *state);
98 /* Function to print some extra text in the help message. */
99 static char *more_help (int key, const char *text, void *input);
101 /* Data structure to communicate with argp functions. */
102 static struct argp argp =
104 options, parse_opt, args_doc, doc, NULL, more_help
108 /* Operation modes. */
109 static enum
111 NONE = 0,
112 FLAT_MODE = 1 << 0,
113 CALL_GRAPH_MODE = 1 << 1,
114 CALL_PAIRS = 1 << 2,
116 DEFAULT_MODE = FLAT_MODE | CALL_GRAPH_MODE
117 } mode;
119 /* Nozero for testing. */
120 static int do_test;
122 /* Structure describing calls. */
123 struct here_fromstruct
125 struct here_cg_arc_record volatile *here;
126 uint16_t link;
129 /* We define a special type to address the elements of the arc table.
130 This is basically the `gmon_cg_arc_record' format but it includes
131 the room for the tag and it uses real types. */
132 struct here_cg_arc_record
134 uintptr_t from_pc;
135 uintptr_t self_pc;
136 uint32_t count;
137 } __attribute__ ((packed));
140 struct known_symbol;
141 struct arc_list
143 size_t idx;
144 uintmax_t count;
146 struct arc_list *next;
149 static struct obstack ob_list;
152 struct known_symbol
154 const char *name;
155 uintptr_t addr;
156 size_t size;
157 bool weak;
158 bool hidden;
160 uintmax_t ticks;
161 uintmax_t calls;
163 struct arc_list *froms;
164 struct arc_list *tos;
168 struct shobj
170 const char *name; /* User-provided name. */
172 struct link_map *map;
173 const char *dynstrtab; /* Dynamic string table of shared object. */
174 const char *soname; /* Soname of shared object. */
176 uintptr_t lowpc;
177 uintptr_t highpc;
178 unsigned long int kcountsize;
179 size_t expected_size; /* Expected size of profiling file. */
180 size_t tossize;
181 size_t fromssize;
182 size_t fromlimit;
183 unsigned int hashfraction;
184 int s_scale;
186 void *symbol_map;
187 size_t symbol_mapsize;
188 const ElfW(Sym) *symtab;
189 size_t symtab_size;
190 const char *strtab;
192 struct obstack ob_str;
193 struct obstack ob_sym;
197 struct real_gmon_hist_hdr
199 char *low_pc;
200 char *high_pc;
201 int32_t hist_size;
202 int32_t prof_rate;
203 char dimen[15];
204 char dimen_abbrev;
208 struct profdata
210 void *addr;
211 off_t size;
213 char *hist;
214 struct real_gmon_hist_hdr *hist_hdr;
215 uint16_t *kcount;
216 uint32_t narcs; /* Number of arcs in toset. */
217 struct here_cg_arc_record *data;
218 uint16_t *tos;
219 struct here_fromstruct *froms;
222 /* Search tree for symbols. */
223 static void *symroot;
224 static struct known_symbol **sortsym;
225 static size_t symidx;
226 static uintmax_t total_ticks;
228 /* Prototypes for local functions. */
229 static struct shobj *load_shobj (const char *name);
230 static void unload_shobj (struct shobj *shobj);
231 static struct profdata *load_profdata (const char *name, struct shobj *shobj);
232 static void unload_profdata (struct profdata *profdata);
233 static void count_total_ticks (struct shobj *shobj, struct profdata *profdata);
234 static void count_calls (struct shobj *shobj, struct profdata *profdata);
235 static void read_symbols (struct shobj *shobj);
236 static void add_arcs (struct profdata *profdata);
237 static void generate_flat_profile (struct profdata *profdata);
238 static void generate_call_graph (struct profdata *profdata);
239 static void generate_call_pair_list (struct profdata *profdata);
243 main (int argc, char *argv[])
245 const char *shobj;
246 const char *profdata;
247 struct shobj *shobj_handle;
248 struct profdata *profdata_handle;
249 int remaining;
251 setlocale (LC_ALL, "");
253 /* Initialize the message catalog. */
254 textdomain (_libc_intl_domainname);
256 /* Parse and process arguments. */
257 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
259 if (argc - remaining == 0 || argc - remaining > 2)
261 /* We need exactly two non-option parameter. */
262 argp_help (&argp, stdout, ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR,
263 program_invocation_short_name);
264 exit (1);
267 /* Get parameters. */
268 shobj = argv[remaining];
269 if (argc - remaining == 2)
270 profdata = argv[remaining + 1];
271 else
272 /* No filename for the profiling data given. We will determine it
273 from the soname of the shobj, later. */
274 profdata = NULL;
276 /* First see whether we can load the shared object. */
277 shobj_handle = load_shobj (shobj);
278 if (shobj_handle == NULL)
279 exit (1);
281 /* We can now determine the filename for the profiling data, if
282 nececessary. */
283 if (profdata == NULL)
285 char *newp;
286 const char *soname;
287 size_t soname_len;
289 soname = shobj_handle->soname ?: basename (shobj);
290 soname_len = strlen (soname);
291 newp = (char *) alloca (soname_len + sizeof ".profile");
292 stpcpy (mempcpy (newp, soname, soname_len), ".profile");
293 profdata = newp;
296 /* Now see whether the profiling data file matches the given object. */
297 profdata_handle = load_profdata (profdata, shobj_handle);
298 if (profdata_handle == NULL)
300 unload_shobj (shobj_handle);
302 exit (1);
305 read_symbols (shobj_handle);
307 /* Count the ticks. */
308 count_total_ticks (shobj_handle, profdata_handle);
310 /* Count the calls. */
311 count_calls (shobj_handle, profdata_handle);
313 /* Add the arc information. */
314 add_arcs (profdata_handle);
316 /* If no mode is specified fall back to the default mode. */
317 if (mode == NONE)
318 mode = DEFAULT_MODE;
320 /* Do some work. */
321 if (mode & FLAT_MODE)
322 generate_flat_profile (profdata_handle);
324 if (mode & CALL_GRAPH_MODE)
325 generate_call_graph (profdata_handle);
327 if (mode & CALL_PAIRS)
328 generate_call_pair_list (profdata_handle);
330 /* Free the resources. */
331 unload_shobj (shobj_handle);
332 unload_profdata (profdata_handle);
334 return 0;
338 /* Handle program arguments. */
339 static error_t
340 parse_opt (int key, char *arg, struct argp_state *state)
342 switch (key)
344 case 'c':
345 mode |= CALL_PAIRS;
346 break;
347 case 'p':
348 mode |= FLAT_MODE;
349 break;
350 case 'q':
351 mode |= CALL_GRAPH_MODE;
352 break;
353 case OPT_TEST:
354 do_test = 1;
355 break;
356 default:
357 return ARGP_ERR_UNKNOWN;
359 return 0;
363 static char *
364 more_help (int key, const char *text, void *input)
366 char *tp = NULL;
367 switch (key)
369 case ARGP_KEY_HELP_EXTRA:
370 /* We print some extra information. */
371 if (asprintf (&tp, gettext ("\
372 For bug reporting instructions, please see:\n\
373 %s.\n"), REPORT_BUGS_TO) < 0)
374 return NULL;
375 return tp;
376 default:
377 break;
379 return (char *) text;
383 /* Print the version information. */
384 static void
385 print_version (FILE *stream, struct argp_state *state)
387 fprintf (stream, "sprof %s%s\n", PKGVERSION, VERSION);
388 fprintf (stream, gettext ("\
389 Copyright (C) %s Free Software Foundation, Inc.\n\
390 This is free software; see the source for copying conditions. There is NO\n\
391 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
393 "2024");
394 fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
398 /* Note that we must not use `dlopen' etc. The shobj object must not
399 be loaded for use. */
400 static struct shobj *
401 load_shobj (const char *name)
403 struct link_map *map = NULL;
404 struct shobj *result;
405 ElfW(Addr) mapstart = ~((ElfW(Addr)) 0);
406 ElfW(Addr) mapend = 0;
407 const ElfW(Phdr) *ph;
408 size_t textsize;
409 ElfW(Ehdr) *ehdr;
410 int fd;
411 ElfW(Shdr) *shdr;
412 size_t pagesize = getpagesize ();
414 /* Since we use dlopen() we must be prepared to work around the sometimes
415 strange lookup rules for the shared objects. If we have a file foo.so
416 in the current directory and the user specifies foo.so on the command
417 line (without specifying a directory) we should load the file in the
418 current directory even if a normal dlopen() call would read the other
419 file. We do this by adding a directory portion to the name. */
420 if (strchr (name, '/') == NULL)
422 char *load_name = (char *) alloca (strlen (name) + 3);
423 stpcpy (stpcpy (load_name, "./"), name);
425 map = (struct link_map *) dlopen (load_name, RTLD_LAZY | __RTLD_SPROF);
427 if (map == NULL)
429 map = (struct link_map *) dlopen (name, RTLD_LAZY | __RTLD_SPROF);
430 if (map == NULL)
432 error (0, errno, _("failed to load shared object `%s'"), name);
433 return NULL;
437 /* Prepare the result. */
438 result = (struct shobj *) calloc (1, sizeof (struct shobj));
439 if (result == NULL)
441 error (0, errno, _("cannot create internal descriptor"));
442 dlclose (map);
443 return NULL;
445 result->name = name;
446 result->map = map;
448 /* Compute the size of the sections which contain program code.
449 This must match the code in dl-profile.c (_dl_start_profile). */
450 for (ph = map->l_phdr; ph < &map->l_phdr[map->l_phnum]; ++ph)
451 if (ph->p_type == PT_LOAD && (ph->p_flags & PF_X))
453 ElfW(Addr) start = (ph->p_vaddr & ~(pagesize - 1));
454 ElfW(Addr) end = ((ph->p_vaddr + ph->p_memsz + pagesize - 1)
455 & ~(pagesize - 1));
457 if (start < mapstart)
458 mapstart = start;
459 if (end > mapend)
460 mapend = end;
463 result->lowpc = ROUNDDOWN ((uintptr_t) (mapstart + map->l_addr),
464 HISTFRACTION * sizeof (HISTCOUNTER));
465 result->highpc = ROUNDUP ((uintptr_t) (mapend + map->l_addr),
466 HISTFRACTION * sizeof (HISTCOUNTER));
467 if (do_test)
468 printf ("load addr: %0#*" PRIxPTR "\n"
469 "lower bound PC: %0#*" PRIxPTR "\n"
470 "upper bound PC: %0#*" PRIxPTR "\n",
471 __ELF_NATIVE_CLASS == 32 ? 10 : 18, map->l_addr,
472 __ELF_NATIVE_CLASS == 32 ? 10 : 18, result->lowpc,
473 __ELF_NATIVE_CLASS == 32 ? 10 : 18, result->highpc);
475 textsize = result->highpc - result->lowpc;
476 result->kcountsize = textsize / HISTFRACTION;
477 result->hashfraction = HASHFRACTION;
478 if (do_test)
479 printf ("hashfraction = %d\ndivider = %zu\n",
480 result->hashfraction,
481 result->hashfraction * sizeof (struct here_fromstruct));
482 result->tossize = textsize / HASHFRACTION;
483 result->fromlimit = textsize * ARCDENSITY / 100;
484 if (result->fromlimit < MINARCS)
485 result->fromlimit = MINARCS;
486 if (result->fromlimit > MAXARCS)
487 result->fromlimit = MAXARCS;
488 result->fromssize = result->fromlimit * sizeof (struct here_fromstruct);
490 result->expected_size = (sizeof (struct gmon_hdr)
491 + 4 + sizeof (struct gmon_hist_hdr)
492 + result->kcountsize
493 + 4 + 4
494 + (result->fromssize
495 * sizeof (struct here_cg_arc_record)));
497 if (do_test)
498 printf ("expected size: %zd\n", result->expected_size);
500 #define SCALE_1_TO_1 0x10000L
502 if (result->kcountsize < result->highpc - result->lowpc)
504 size_t range = result->highpc - result->lowpc;
505 size_t quot = range / result->kcountsize;
507 if (quot >= SCALE_1_TO_1)
508 result->s_scale = 1;
509 else if (quot >= SCALE_1_TO_1 / 256)
510 result->s_scale = SCALE_1_TO_1 / quot;
511 else if (range > ULONG_MAX / 256)
512 result->s_scale = ((SCALE_1_TO_1 * 256)
513 / (range / (result->kcountsize / 256)));
514 else
515 result->s_scale = ((SCALE_1_TO_1 * 256)
516 / ((range * 256) / result->kcountsize));
518 else
519 result->s_scale = SCALE_1_TO_1;
521 if (do_test)
522 printf ("s_scale: %d\n", result->s_scale);
524 /* Determine the dynamic string table. */
525 if (map->l_info[DT_STRTAB] == NULL)
526 result->dynstrtab = NULL;
527 else
528 result->dynstrtab = (const char *) D_PTR (map, l_info[DT_STRTAB]);
529 if (do_test)
530 printf ("string table: %p\n", result->dynstrtab);
532 /* Determine the soname. */
533 if (map->l_info[DT_SONAME] == NULL)
534 result->soname = NULL;
535 else
536 result->soname = result->dynstrtab + map->l_info[DT_SONAME]->d_un.d_val;
537 if (do_test && result->soname != NULL)
538 printf ("soname: %s\n", result->soname);
540 /* Now we have to load the symbol table.
542 First load the section header table. */
543 ehdr = (ElfW(Ehdr) *) map->l_map_start;
545 /* Make sure we are on the right party. */
546 if (ehdr->e_shentsize != sizeof (ElfW(Shdr)))
547 abort ();
549 /* And we need the shared object file descriptor again. */
550 fd = open (map->l_name, O_RDONLY);
551 if (fd == -1)
552 /* Dooh, this really shouldn't happen. We know the file is available. */
553 error (EXIT_FAILURE, errno, _("Reopening shared object `%s' failed"),
554 map->l_name);
556 /* Map the section header. */
557 size_t size = ehdr->e_shnum * sizeof (ElfW(Shdr));
558 shdr = (ElfW(Shdr) *) alloca (size);
559 if (pread (fd, shdr, size, ehdr->e_shoff) != size)
560 error (EXIT_FAILURE, errno, _("reading of section headers failed"));
562 /* Get the section header string table. */
563 char *shstrtab = (char *) alloca (shdr[ehdr->e_shstrndx].sh_size);
564 if (pread (fd, shstrtab, shdr[ehdr->e_shstrndx].sh_size,
565 shdr[ehdr->e_shstrndx].sh_offset)
566 != shdr[ehdr->e_shstrndx].sh_size)
567 error (EXIT_FAILURE, errno,
568 _("reading of section header string table failed"));
570 /* Search for the ".symtab" section. */
571 ElfW(Shdr) *symtab_entry = NULL;
572 ElfW(Shdr) *debuglink_entry = NULL;
573 for (int idx = 0; idx < ehdr->e_shnum; ++idx)
574 if (shdr[idx].sh_type == SHT_SYMTAB
575 && strcmp (shstrtab + shdr[idx].sh_name, ".symtab") == 0)
577 symtab_entry = &shdr[idx];
578 break;
580 else if (shdr[idx].sh_type == SHT_PROGBITS
581 && strcmp (shstrtab + shdr[idx].sh_name, ".gnu_debuglink") == 0)
582 debuglink_entry = &shdr[idx];
584 /* Get the file name of the debuginfo file if necessary. */
585 int symfd = fd;
586 if (symtab_entry == NULL && debuglink_entry != NULL)
588 size_t size = debuglink_entry->sh_size;
589 char *debuginfo_fname = (char *) alloca (size + 1);
590 debuginfo_fname[size] = '\0';
591 if (pread (fd, debuginfo_fname, size, debuglink_entry->sh_offset)
592 != size)
594 fprintf (stderr, _("*** Cannot read debuginfo file name: %m\n"));
595 goto no_debuginfo;
598 static const char procpath[] = "/proc/self/fd/%d";
599 char origprocname[sizeof (procpath) + sizeof (int) * 3];
600 snprintf (origprocname, sizeof (origprocname), procpath, fd);
601 char *origlink = (char *) alloca (PATH_MAX);
602 ssize_t n = readlink (origprocname, origlink, PATH_MAX - 1);
603 if (n == -1)
604 goto no_debuginfo;
605 origlink[n] = '\0';
607 /* Try to find the actual file. There are three places:
608 1. the same directory the DSO is in
609 2. in a subdir named .debug of the directory the DSO is in
610 3. in /usr/lib/debug/PATH-OF-DSO
612 char *realname = canonicalize_file_name (origlink);
613 char *cp = NULL;
614 if (realname == NULL || (cp = strrchr (realname, '/')) == NULL)
615 error (EXIT_FAILURE, errno, _("cannot determine file name"));
617 /* Leave the last slash in place. */
618 *++cp = '\0';
620 /* First add the debuginfo file name only. */
621 static const char usrlibdebug[]= "/usr/lib/debug/";
622 char *workbuf = (char *) alloca (sizeof (usrlibdebug)
623 + (cp - realname)
624 + strlen (debuginfo_fname));
625 strcpy (stpcpy (workbuf, realname), debuginfo_fname);
627 int fd2 = open (workbuf, O_RDONLY);
628 if (fd2 == -1)
630 strcpy (stpcpy (stpcpy (workbuf, realname), ".debug/"),
631 debuginfo_fname);
632 fd2 = open (workbuf, O_RDONLY);
633 if (fd2 == -1)
635 strcpy (stpcpy (stpcpy (workbuf, usrlibdebug), realname),
636 debuginfo_fname);
637 fd2 = open (workbuf, O_RDONLY);
641 if (fd2 != -1)
643 ElfW(Ehdr) ehdr2;
645 /* Read the ELF header. */
646 if (pread (fd2, &ehdr2, sizeof (ehdr2), 0) != sizeof (ehdr2))
647 error (EXIT_FAILURE, errno,
648 _("reading of ELF header failed"));
650 /* Map the section header. */
651 size_t size = ehdr2.e_shnum * sizeof (ElfW(Shdr));
652 ElfW(Shdr) *shdr2 = (ElfW(Shdr) *) alloca (size);
653 if (pread (fd2, shdr2, size, ehdr2.e_shoff) != size)
654 error (EXIT_FAILURE, errno,
655 _("reading of section headers failed"));
657 /* Get the section header string table. */
658 shstrtab = (char *) alloca (shdr2[ehdr2.e_shstrndx].sh_size);
659 if (pread (fd2, shstrtab, shdr2[ehdr2.e_shstrndx].sh_size,
660 shdr2[ehdr2.e_shstrndx].sh_offset)
661 != shdr2[ehdr2.e_shstrndx].sh_size)
662 error (EXIT_FAILURE, errno,
663 _("reading of section header string table failed"));
665 /* Search for the ".symtab" section. */
666 for (int idx = 0; idx < ehdr2.e_shnum; ++idx)
667 if (shdr2[idx].sh_type == SHT_SYMTAB
668 && strcmp (shstrtab + shdr2[idx].sh_name, ".symtab") == 0)
670 symtab_entry = &shdr2[idx];
671 shdr = shdr2;
672 symfd = fd2;
673 break;
676 if (fd2 != symfd)
677 close (fd2);
681 no_debuginfo:
682 if (symtab_entry == NULL)
684 fprintf (stderr, _("\
685 *** The file `%s' is stripped: no detailed analysis possible\n"),
686 name);
687 result->symtab = NULL;
688 result->strtab = NULL;
690 else
692 ElfW(Off) min_offset, max_offset;
693 ElfW(Shdr) *strtab_entry;
695 strtab_entry = &shdr[symtab_entry->sh_link];
697 /* Find the minimum and maximum offsets that include both the symbol
698 table and the string table. */
699 if (symtab_entry->sh_offset < strtab_entry->sh_offset)
701 min_offset = symtab_entry->sh_offset & ~(pagesize - 1);
702 max_offset = strtab_entry->sh_offset + strtab_entry->sh_size;
704 else
706 min_offset = strtab_entry->sh_offset & ~(pagesize - 1);
707 max_offset = symtab_entry->sh_offset + symtab_entry->sh_size;
710 result->symbol_map = mmap (NULL, max_offset - min_offset,
711 PROT_READ, MAP_SHARED|MAP_FILE, symfd,
712 min_offset);
713 if (result->symbol_map == MAP_FAILED)
714 error (EXIT_FAILURE, errno, _("failed to load symbol data"));
716 result->symtab
717 = (const ElfW(Sym) *) ((const char *) result->symbol_map
718 + (symtab_entry->sh_offset - min_offset));
719 result->symtab_size = symtab_entry->sh_size;
720 result->strtab = ((const char *) result->symbol_map
721 + (strtab_entry->sh_offset - min_offset));
722 result->symbol_mapsize = max_offset - min_offset;
725 /* Free the descriptor for the shared object. */
726 close (fd);
727 if (symfd != fd)
728 close (symfd);
730 return result;
734 static void
735 unload_shobj (struct shobj *shobj)
737 munmap (shobj->symbol_map, shobj->symbol_mapsize);
738 dlclose (shobj->map);
742 static struct profdata *
743 load_profdata (const char *name, struct shobj *shobj)
745 struct profdata *result;
746 int fd;
747 struct stat64 st;
748 void *addr;
749 uint32_t *narcsp;
750 size_t fromlimit;
751 struct here_cg_arc_record *data;
752 struct here_fromstruct *froms;
753 uint16_t *tos;
754 size_t fromidx;
755 size_t idx;
757 fd = open (name, O_RDONLY);
758 if (fd == -1)
760 char *ext_name;
762 if (errno != ENOENT || strchr (name, '/') != NULL)
763 /* The file exists but we are not allowed to read it or the
764 file does not exist and the name includes a path
765 specification.. */
766 return NULL;
768 /* A file with the given name does not exist in the current
769 directory, try it in the default location where the profiling
770 files are created. */
771 ext_name = (char *) alloca (strlen (name) + sizeof "/var/tmp/");
772 stpcpy (stpcpy (ext_name, "/var/tmp/"), name);
773 name = ext_name;
775 fd = open (ext_name, O_RDONLY);
776 if (fd == -1)
778 /* Even this file does not exist. */
779 error (0, errno, _("cannot load profiling data"));
780 return NULL;
784 /* We have found the file, now make sure it is the right one for the
785 data file. */
786 if (fstat64 (fd, &st) < 0)
788 error (0, errno, _("while stat'ing profiling data file"));
789 close (fd);
790 return NULL;
793 if ((size_t) st.st_size != shobj->expected_size)
795 error (0, 0,
796 _("profiling data file `%s' does not match shared object `%s'"),
797 name, shobj->name);
798 close (fd);
799 return NULL;
802 /* The data file is most probably the right one for our shared
803 object. Map it now. */
804 addr = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED|MAP_FILE, fd, 0);
805 if (addr == MAP_FAILED)
807 error (0, errno, _("failed to mmap the profiling data file"));
808 close (fd);
809 return NULL;
812 /* We don't need the file descriptor anymore. */
813 if (close (fd) < 0)
815 error (0, errno, _("error while closing the profiling data file"));
816 munmap (addr, st.st_size);
817 return NULL;
820 /* Prepare the result. */
821 result = (struct profdata *) calloc (1, sizeof (struct profdata));
822 if (result == NULL)
824 error (0, errno, _("cannot create internal descriptor"));
825 munmap (addr, st.st_size);
826 return NULL;
829 /* Store the address and size so that we can later free the resources. */
830 result->addr = addr;
831 result->size = st.st_size;
833 /* Pointer to data after the header. */
834 result->hist = (char *) ((struct gmon_hdr *) addr + 1);
835 result->hist_hdr = (struct real_gmon_hist_hdr *) ((char *) result->hist
836 + sizeof (uint32_t));
837 result->kcount = (uint16_t *) ((char *) result->hist + sizeof (uint32_t)
838 + sizeof (struct real_gmon_hist_hdr));
840 /* Compute pointer to array of the arc information. */
841 narcsp = (uint32_t *) ((char *) result->kcount + shobj->kcountsize
842 + sizeof (uint32_t));
843 result->narcs = *narcsp;
844 result->data = (struct here_cg_arc_record *) ((char *) narcsp
845 + sizeof (uint32_t));
847 /* Create the gmon_hdr we expect or write. */
848 struct real_gmon_hdr
850 char cookie[4];
851 int32_t version;
852 char spare[3 * 4];
853 } gmon_hdr;
854 if (sizeof (gmon_hdr) != sizeof (struct gmon_hdr)
855 || (offsetof (struct real_gmon_hdr, cookie)
856 != offsetof (struct gmon_hdr, cookie))
857 || (offsetof (struct real_gmon_hdr, version)
858 != offsetof (struct gmon_hdr, version)))
859 abort ();
861 memcpy (&gmon_hdr.cookie[0], GMON_MAGIC, sizeof (gmon_hdr.cookie));
862 gmon_hdr.version = GMON_SHOBJ_VERSION;
863 memset (gmon_hdr.spare, '\0', sizeof (gmon_hdr.spare));
865 /* Create the hist_hdr we expect or write. */
866 struct real_gmon_hist_hdr hist_hdr;
867 if (sizeof (hist_hdr) != sizeof (struct gmon_hist_hdr)
868 || (offsetof (struct real_gmon_hist_hdr, low_pc)
869 != offsetof (struct gmon_hist_hdr, low_pc))
870 || (offsetof (struct real_gmon_hist_hdr, high_pc)
871 != offsetof (struct gmon_hist_hdr, high_pc))
872 || (offsetof (struct real_gmon_hist_hdr, hist_size)
873 != offsetof (struct gmon_hist_hdr, hist_size))
874 || (offsetof (struct real_gmon_hist_hdr, prof_rate)
875 != offsetof (struct gmon_hist_hdr, prof_rate))
876 || (offsetof (struct real_gmon_hist_hdr, dimen)
877 != offsetof (struct gmon_hist_hdr, dimen))
878 || (offsetof (struct real_gmon_hist_hdr, dimen_abbrev)
879 != offsetof (struct gmon_hist_hdr, dimen_abbrev)))
880 abort ();
882 hist_hdr.low_pc = (char *) shobj->lowpc - shobj->map->l_addr;
883 hist_hdr.high_pc = (char *) shobj->highpc - shobj->map->l_addr;
884 if (do_test)
885 printf ("low_pc = %p\nhigh_pc = %p\n", hist_hdr.low_pc, hist_hdr.high_pc);
886 hist_hdr.hist_size = shobj->kcountsize / sizeof (HISTCOUNTER);
887 hist_hdr.prof_rate = __profile_frequency ();
888 strncpy (hist_hdr.dimen, "seconds", sizeof (hist_hdr.dimen));
889 hist_hdr.dimen_abbrev = 's';
891 /* Test whether the header of the profiling data is ok. */
892 if (memcmp (addr, &gmon_hdr, sizeof (struct gmon_hdr)) != 0
893 || *(uint32_t *) result->hist != GMON_TAG_TIME_HIST
894 || memcmp (result->hist_hdr, &hist_hdr,
895 sizeof (struct gmon_hist_hdr)) != 0
896 || narcsp[-1] != GMON_TAG_CG_ARC)
898 error (0, 0, _("`%s' is no correct profile data file for `%s'"),
899 name, shobj->name);
900 if (do_test)
902 if (memcmp (addr, &gmon_hdr, sizeof (struct gmon_hdr)) != 0)
903 puts ("gmon_hdr differs");
904 if (*(uint32_t *) result->hist != GMON_TAG_TIME_HIST)
905 puts ("result->hist differs");
906 if (memcmp (result->hist_hdr, &hist_hdr,
907 sizeof (struct gmon_hist_hdr)) != 0)
908 puts ("hist_hdr differs");
909 if (narcsp[-1] != GMON_TAG_CG_ARC)
910 puts ("narcsp[-1] differs");
912 free (result);
913 munmap (addr, st.st_size);
914 return NULL;
917 /* We are pretty sure now that this is a correct input file. Set up
918 the remaining information in the result structure and return. */
919 result->tos = (uint16_t *) calloc (shobj->tossize + shobj->fromssize, 1);
920 if (result->tos == NULL)
922 error (0, errno, _("cannot create internal descriptor"));
923 munmap (addr, st.st_size);
924 free (result);
925 return NULL;
928 result->froms = (struct here_fromstruct *) ((char *) result->tos
929 + shobj->tossize);
930 fromidx = 0;
932 /* Now we have to process all the arc count entries. */
933 fromlimit = shobj->fromlimit;
934 data = result->data;
935 froms = result->froms;
936 tos = result->tos;
937 for (idx = 0; idx < MIN (*narcsp, fromlimit); ++idx)
939 size_t to_index;
940 size_t newfromidx;
941 to_index = (data[idx].self_pc / (shobj->hashfraction * sizeof (*tos)));
942 newfromidx = fromidx++;
943 froms[newfromidx].here = &data[idx];
944 froms[newfromidx].link = tos[to_index];
945 tos[to_index] = newfromidx;
948 return result;
952 static void
953 unload_profdata (struct profdata *profdata)
955 free (profdata->tos);
956 munmap (profdata->addr, profdata->size);
957 free (profdata);
961 static void
962 count_total_ticks (struct shobj *shobj, struct profdata *profdata)
964 volatile uint16_t *kcount = profdata->kcount;
965 size_t maxkidx = shobj->kcountsize;
966 size_t factor = 2 * (65536 / shobj->s_scale);
967 size_t kidx = 0;
968 size_t sidx = 0;
970 while (sidx < symidx)
972 uintptr_t start = sortsym[sidx]->addr;
973 uintptr_t end = start + sortsym[sidx]->size;
975 while (kidx < maxkidx && factor * kidx < start)
976 ++kidx;
977 if (kidx == maxkidx)
978 break;
980 while (kidx < maxkidx && factor * kidx < end)
981 sortsym[sidx]->ticks += kcount[kidx++];
982 if (kidx == maxkidx)
983 break;
985 total_ticks += sortsym[sidx++]->ticks;
990 static size_t
991 find_symbol (uintptr_t addr)
993 size_t sidx = 0;
995 while (sidx < symidx)
997 uintptr_t start = sortsym[sidx]->addr;
998 uintptr_t end = start + sortsym[sidx]->size;
1000 if (addr >= start && addr < end)
1001 return sidx;
1003 if (addr < start)
1004 break;
1006 ++sidx;
1009 return (size_t) -1l;
1013 static void
1014 count_calls (struct shobj *shobj, struct profdata *profdata)
1016 struct here_cg_arc_record *data = profdata->data;
1017 uint32_t narcs = profdata->narcs;
1018 uint32_t cnt;
1020 for (cnt = 0; cnt < narcs; ++cnt)
1022 uintptr_t here = data[cnt].self_pc;
1023 size_t symbol_idx;
1025 /* Find the symbol for this address. */
1026 symbol_idx = find_symbol (here);
1027 if (symbol_idx != (size_t) -1l)
1028 sortsym[symbol_idx]->calls += data[cnt].count;
1033 static int
1034 symorder (const void *o1, const void *o2)
1036 const struct known_symbol *p1 = (const struct known_symbol *) o1;
1037 const struct known_symbol *p2 = (const struct known_symbol *) o2;
1039 return p1->addr - p2->addr;
1043 static void
1044 printsym (const void *node, VISIT value, int level)
1046 if (value == leaf || value == postorder)
1047 sortsym[symidx++] = *(struct known_symbol **) node;
1051 static void
1052 read_symbols (struct shobj *shobj)
1054 int n = 0;
1056 /* Initialize the obstacks. */
1057 #define obstack_chunk_alloc malloc
1058 #define obstack_chunk_free free
1059 obstack_init (&shobj->ob_str);
1060 obstack_init (&shobj->ob_sym);
1061 obstack_init (&ob_list);
1063 /* Process the symbols. */
1064 if (shobj->symtab != NULL)
1066 const ElfW(Sym) *sym = shobj->symtab;
1067 const ElfW(Sym) *sym_end
1068 = (const ElfW(Sym) *) ((const char *) sym + shobj->symtab_size);
1069 for (; sym < sym_end; sym++)
1070 if ((ELFW(ST_TYPE) (sym->st_info) == STT_FUNC
1071 || ELFW(ST_TYPE) (sym->st_info) == STT_NOTYPE)
1072 && sym->st_size != 0)
1074 struct known_symbol **existp;
1075 struct known_symbol *newsym
1076 = (struct known_symbol *) obstack_alloc (&shobj->ob_sym,
1077 sizeof (*newsym));
1078 if (newsym == NULL)
1079 error (EXIT_FAILURE, errno, _("cannot allocate symbol data"));
1081 newsym->name = &shobj->strtab[sym->st_name];
1082 newsym->addr = sym->st_value;
1083 newsym->size = sym->st_size;
1084 newsym->weak = ELFW(ST_BIND) (sym->st_info) == STB_WEAK;
1085 newsym->hidden = (ELFW(ST_VISIBILITY) (sym->st_other)
1086 != STV_DEFAULT);
1087 newsym->ticks = 0;
1088 newsym->calls = 0;
1090 existp = tfind (newsym, &symroot, symorder);
1091 if (existp == NULL)
1093 /* New function. */
1094 tsearch (newsym, &symroot, symorder);
1095 ++n;
1097 else
1099 /* The function is already defined. See whether we have
1100 a better name here. */
1101 if (((*existp)->hidden && !newsym->hidden)
1102 || ((*existp)->name[0] == '_' && newsym->name[0] != '_')
1103 || ((*existp)->name[0] != '_' && newsym->name[0] != '_'
1104 && ((*existp)->weak && !newsym->weak)))
1105 *existp = newsym;
1106 else
1107 /* We don't need the allocated memory. */
1108 obstack_free (&shobj->ob_sym, newsym);
1112 else
1114 /* Blarg, the binary is stripped. We have to rely on the
1115 information contained in the dynamic section of the object. */
1116 const ElfW(Sym) *symtab = (ElfW(Sym) *) D_PTR (shobj->map,
1117 l_info[DT_SYMTAB]);
1118 const char *strtab = (const char *) D_PTR (shobj->map,
1119 l_info[DT_STRTAB]);
1121 /* We assume that the string table follows the symbol table,
1122 because there is no way in ELF to know the size of the
1123 dynamic symbol table without looking at the section headers. */
1124 while ((void *) symtab < (void *) strtab)
1126 if ((ELFW(ST_TYPE)(symtab->st_info) == STT_FUNC
1127 || ELFW(ST_TYPE)(symtab->st_info) == STT_NOTYPE)
1128 && symtab->st_size != 0)
1130 struct known_symbol *newsym;
1131 struct known_symbol **existp;
1133 newsym =
1134 (struct known_symbol *) obstack_alloc (&shobj->ob_sym,
1135 sizeof (*newsym));
1136 if (newsym == NULL)
1137 error (EXIT_FAILURE, errno, _("cannot allocate symbol data"));
1139 newsym->name = &strtab[symtab->st_name];
1140 newsym->addr = symtab->st_value;
1141 newsym->size = symtab->st_size;
1142 newsym->weak = ELFW(ST_BIND) (symtab->st_info) == STB_WEAK;
1143 newsym->hidden = (ELFW(ST_VISIBILITY) (symtab->st_other)
1144 != STV_DEFAULT);
1145 newsym->ticks = 0;
1146 newsym->froms = NULL;
1147 newsym->tos = NULL;
1149 existp = tfind (newsym, &symroot, symorder);
1150 if (existp == NULL)
1152 /* New function. */
1153 tsearch (newsym, &symroot, symorder);
1154 ++n;
1156 else
1158 /* The function is already defined. See whether we have
1159 a better name here. */
1160 if (((*existp)->hidden && !newsym->hidden)
1161 || ((*existp)->name[0] == '_' && newsym->name[0] != '_')
1162 || ((*existp)->name[0] != '_' && newsym->name[0] != '_'
1163 && ((*existp)->weak && !newsym->weak)))
1164 *existp = newsym;
1165 else
1166 /* We don't need the allocated memory. */
1167 obstack_free (&shobj->ob_sym, newsym);
1171 ++symtab;
1175 sortsym = malloc (n * sizeof (struct known_symbol *));
1176 if (sortsym == NULL)
1177 abort ();
1179 twalk (symroot, printsym);
1183 static void
1184 add_arcs (struct profdata *profdata)
1186 uint32_t narcs = profdata->narcs;
1187 struct here_cg_arc_record *data = profdata->data;
1188 uint32_t cnt;
1190 for (cnt = 0; cnt < narcs; ++cnt)
1192 /* First add the incoming arc. */
1193 size_t sym_idx = find_symbol (data[cnt].self_pc);
1195 if (sym_idx != (size_t) -1l)
1197 struct known_symbol *sym = sortsym[sym_idx];
1198 struct arc_list *runp = sym->froms;
1200 while (runp != NULL
1201 && ((data[cnt].from_pc == 0 && runp->idx != (size_t) -1l)
1202 || (data[cnt].from_pc != 0
1203 && (runp->idx == (size_t) -1l
1204 || data[cnt].from_pc < sortsym[runp->idx]->addr
1205 || (data[cnt].from_pc
1206 >= (sortsym[runp->idx]->addr
1207 + sortsym[runp->idx]->size))))))
1208 runp = runp->next;
1210 if (runp == NULL)
1212 /* We need a new entry. */
1213 struct arc_list *newp = (struct arc_list *)
1214 obstack_alloc (&ob_list, sizeof (struct arc_list));
1216 if (data[cnt].from_pc == 0)
1217 newp->idx = (size_t) -1l;
1218 else
1219 newp->idx = find_symbol (data[cnt].from_pc);
1220 newp->count = data[cnt].count;
1221 newp->next = sym->froms;
1222 sym->froms = newp;
1224 else
1225 /* Increment the counter for the found entry. */
1226 runp->count += data[cnt].count;
1229 /* Now add it to the appropriate outgoing list. */
1230 sym_idx = find_symbol (data[cnt].from_pc);
1231 if (sym_idx != (size_t) -1l)
1233 struct known_symbol *sym = sortsym[sym_idx];
1234 struct arc_list *runp = sym->tos;
1236 while (runp != NULL
1237 && (runp->idx == (size_t) -1l
1238 || data[cnt].self_pc < sortsym[runp->idx]->addr
1239 || data[cnt].self_pc >= (sortsym[runp->idx]->addr
1240 + sortsym[runp->idx]->size)))
1241 runp = runp->next;
1243 if (runp == NULL)
1245 /* We need a new entry. */
1246 struct arc_list *newp = (struct arc_list *)
1247 obstack_alloc (&ob_list, sizeof (struct arc_list));
1249 newp->idx = find_symbol (data[cnt].self_pc);
1250 newp->count = data[cnt].count;
1251 newp->next = sym->tos;
1252 sym->tos = newp;
1254 else
1255 /* Increment the counter for the found entry. */
1256 runp->count += data[cnt].count;
1262 static int
1263 countorder (const void *p1, const void *p2)
1265 struct known_symbol *s1 = (struct known_symbol *) p1;
1266 struct known_symbol *s2 = (struct known_symbol *) p2;
1268 if (s1->ticks != s2->ticks)
1269 return (int) (s2->ticks - s1->ticks);
1271 if (s1->calls != s2->calls)
1272 return (int) (s2->calls - s1->calls);
1274 return strcmp (s1->name, s2->name);
1278 static double tick_unit;
1279 static uintmax_t cumu_ticks;
1281 static void
1282 printflat (const void *node, VISIT value, int level)
1284 if (value == leaf || value == postorder)
1286 struct known_symbol *s = *(struct known_symbol **) node;
1288 cumu_ticks += s->ticks;
1290 printf ("%6.2f%10.2f%9.2f%9" PRIdMAX "%9.2f %s\n",
1291 total_ticks ? (100.0 * s->ticks) / total_ticks : 0.0,
1292 tick_unit * cumu_ticks,
1293 tick_unit * s->ticks,
1294 s->calls,
1295 s->calls ? (s->ticks * 1000000) * tick_unit / s->calls : 0,
1296 /* FIXME: don't know about called functions. */
1297 s->name);
1302 /* ARGUSED */
1303 static void
1304 freenoop (void *p)
1309 static void
1310 generate_flat_profile (struct profdata *profdata)
1312 size_t n;
1313 void *data = NULL;
1315 tick_unit = 1.0 / profdata->hist_hdr->prof_rate;
1317 printf ("Flat profile:\n\n"
1318 "Each sample counts as %g %s.\n",
1319 tick_unit, profdata->hist_hdr->dimen);
1320 fputs (" % cumulative self self total\n"
1321 " time seconds seconds calls us/call us/call name\n",
1322 stdout);
1324 for (n = 0; n < symidx; ++n)
1325 if (sortsym[n]->calls != 0 || sortsym[n]->ticks != 0)
1326 tsearch (sortsym[n], &data, countorder);
1328 twalk (data, printflat);
1330 tdestroy (data, freenoop);
1334 static void
1335 generate_call_graph (struct profdata *profdata)
1337 size_t cnt;
1339 puts ("\nindex % time self children called name\n");
1341 for (cnt = 0; cnt < symidx; ++cnt)
1342 if (sortsym[cnt]->froms != NULL || sortsym[cnt]->tos != NULL)
1344 struct arc_list *runp;
1345 size_t n;
1347 /* First print the from-information. */
1348 runp = sortsym[cnt]->froms;
1349 while (runp != NULL)
1351 printf (" %8.2f%8.2f%9" PRIdMAX "/%-9" PRIdMAX " %s",
1352 (runp->idx != (size_t) -1l
1353 ? sortsym[runp->idx]->ticks * tick_unit : 0.0),
1354 0.0, /* FIXME: what's time for the children, recursive */
1355 runp->count, sortsym[cnt]->calls,
1356 (runp->idx != (size_t) -1l
1357 ? sortsym[runp->idx]->name : "<UNKNOWN>"));
1359 if (runp->idx != (size_t) -1l)
1360 printf (" [%zd]", runp->idx);
1361 putchar_unlocked ('\n');
1363 runp = runp->next;
1366 /* Info about the function itself. */
1367 n = printf ("[%zu]", cnt);
1368 printf ("%*s%5.1f%8.2f%8.2f%9" PRIdMAX " %s [%zd]\n",
1369 (int) (7 - n), " ",
1370 total_ticks ? (100.0 * sortsym[cnt]->ticks) / total_ticks : 0,
1371 sortsym[cnt]->ticks * tick_unit,
1372 0.0, /* FIXME: what's time for the children, recursive */
1373 sortsym[cnt]->calls,
1374 sortsym[cnt]->name, cnt);
1376 /* Info about the functions this function calls. */
1377 runp = sortsym[cnt]->tos;
1378 while (runp != NULL)
1380 printf (" %8.2f%8.2f%9" PRIdMAX "/",
1381 (runp->idx != (size_t) -1l
1382 ? sortsym[runp->idx]->ticks * tick_unit : 0.0),
1383 0.0, /* FIXME: what's time for the children, recursive */
1384 runp->count);
1386 if (runp->idx != (size_t) -1l)
1387 printf ("%-9" PRIdMAX " %s [%zd]\n",
1388 sortsym[runp->idx]->calls,
1389 sortsym[runp->idx]->name,
1390 runp->idx);
1391 else
1392 fputs ("??? <UNKNOWN>\n\n", stdout);
1394 runp = runp->next;
1397 fputs ("-----------------------------------------------\n", stdout);
1402 static void
1403 generate_call_pair_list (struct profdata *profdata)
1405 size_t cnt;
1407 for (cnt = 0; cnt < symidx; ++cnt)
1408 if (sortsym[cnt]->froms != NULL || sortsym[cnt]->tos != NULL)
1410 struct arc_list *runp;
1412 /* First print the incoming arcs. */
1413 runp = sortsym[cnt]->froms;
1414 while (runp != NULL)
1416 if (runp->idx == (size_t) -1l)
1417 printf ("\
1418 <UNKNOWN> %-34s %9" PRIdMAX "\n",
1419 sortsym[cnt]->name, runp->count);
1420 runp = runp->next;
1423 /* Next the outgoing arcs. */
1424 runp = sortsym[cnt]->tos;
1425 while (runp != NULL)
1427 printf ("%-34s %-34s %9" PRIdMAX "\n",
1428 sortsym[cnt]->name,
1429 (runp->idx != (size_t) -1l
1430 ? sortsym[runp->idx]->name : "<UNKNOWN>"),
1431 runp->count);
1432 runp = runp->next;