]> git.ipfire.org Git - thirdparty/glibc.git/blame - elf/sprof.c
x86_64: Fix missing wcsncat function definition without multiarch (x86-64-v4)
[thirdparty/glibc.git] / elf / sprof.c
CommitLineData
ae828bc6 1/* Read and display shared object profiling data.
dff8da6b 2 Copyright (C) 1997-2024 Free Software Foundation, Inc.
ae828bc6 3 This file is part of the GNU C Library.
ae828bc6
UD
4
5 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
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.
ae828bc6
UD
9
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
41bdb6e2 13 Lesser General Public License for more details.
ae828bc6 14
41bdb6e2 15 You should have received a copy of the GNU Lesser General Public
59ba27a6 16 License along with the GNU C Library; if not, see
5a82c748 17 <https://www.gnu.org/licenses/>. */
ae828bc6
UD
18
19#include <argp.h>
20#include <dlfcn.h>
21#include <elf.h>
ae828bc6
UD
22#include <error.h>
23#include <fcntl.h>
24#include <inttypes.h>
25#include <libintl.h>
ae828bc6
UD
26#include <locale.h>
27#include <obstack.h>
28#include <search.h>
b8b9340e 29#include <stdbool.h>
ae828bc6
UD
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <unistd.h>
e054f494 34#include <stdint.h>
a42195db 35#include <ldsodefs.h>
ae828bc6
UD
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>
41
ae828bc6
UD
42/* Get libc version number. */
43#include "../version.h"
44
45#define PACKAGE _libc_intl_domainname
46
47
48#include <endian.h>
49#if BYTE_ORDER == BIG_ENDIAN
fcf5e998
UD
50# define byteorder ELFDATA2MSB
51# define byteorder_name "big-endian"
ae828bc6 52#elif BYTE_ORDER == LITTLE_ENDIAN
fcf5e998
UD
53# define byteorder ELFDATA2LSB
54# define byteorder_name "little-endian"
ae828bc6 55#else
fcf5e998
UD
56# error "Unknown BYTE_ORDER " BYTE_ORDER
57# define byteorder ELFDATANONE
58#endif
59
60#ifndef PATH_MAX
61# define PATH_MAX 1024
ae828bc6
UD
62#endif
63
64
d8cf93f4 65extern int __profile_frequency (void);
ae828bc6
UD
66
67/* Name and version of program. */
68static void print_version (FILE *stream, struct argp_state *state);
69void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
70
c0fb8a56 71#define OPT_TEST 1
ae828bc6
UD
72
73/* Definitions of arguments for argp functions. */
74static const struct argp_option options[] =
75{
76 { NULL, 0, NULL, 0, N_("Output selection:") },
ccd17b32
UD
77 { "call-pairs", 'c', NULL, 0,
78 N_("print list of count paths and their number of use") },
c0fb8a56
UD
79 { "flat-profile", 'p', NULL, 0,
80 N_("generate flat profile with counts and ticks") },
31f7410f 81 { "graph", 'q', NULL, 0, N_("generate call graph") },
c0fb8a56 82
ae828bc6
UD
83 { "test", OPT_TEST, NULL, OPTION_HIDDEN, NULL },
84 { NULL, 0, NULL, 0, NULL }
85};
86
87/* Short description of program. */
cbbcaf23 88static const char doc[] = N_("Read and display shared object profiling data.");
a99e59d7 89//For bug reporting instructions, please see:\n
5a82c748 90//<https://www.gnu.org/software/libc/bugs.html>.\n");
ae828bc6
UD
91
92/* Strings for arguments in help texts. */
93static const char args_doc[] = N_("SHOBJ [PROFDATA]");
94
95/* Prototype for option handler. */
96static error_t parse_opt (int key, char *arg, struct argp_state *state);
97
cbbcaf23
UD
98/* Function to print some extra text in the help message. */
99static char *more_help (int key, const char *text, void *input);
100
ae828bc6
UD
101/* Data structure to communicate with argp functions. */
102static struct argp argp =
103{
cbbcaf23 104 options, parse_opt, args_doc, doc, NULL, more_help
ae828bc6
UD
105};
106
107
108/* Operation modes. */
109static enum
110{
111 NONE = 0,
c0fb8a56 112 FLAT_MODE = 1 << 0,
31f7410f 113 CALL_GRAPH_MODE = 1 << 1,
ccd17b32 114 CALL_PAIRS = 1 << 2,
c0fb8a56 115
31f7410f 116 DEFAULT_MODE = FLAT_MODE | CALL_GRAPH_MODE
ae828bc6
UD
117} mode;
118
ae828bc6 119/* Nozero for testing. */
fcf5e998 120static int do_test;
ae828bc6 121
630da022 122/* Structure describing calls. */
ae828bc6 123struct here_fromstruct
31f7410f
UD
124{
125 struct here_cg_arc_record volatile *here;
126 uint16_t link;
127};
ae828bc6
UD
128
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. */
132struct here_cg_arc_record
31f7410f
UD
133{
134 uintptr_t from_pc;
135 uintptr_t self_pc;
136 uint32_t count;
137} __attribute__ ((packed));
138
139
140struct known_symbol;
141struct arc_list
142{
143 size_t idx;
144 uintmax_t count;
145
146 struct arc_list *next;
147};
148
149static struct obstack ob_list;
ae828bc6 150
ae828bc6
UD
151
152struct known_symbol
153{
154 const char *name;
155 uintptr_t addr;
156 size_t size;
b8b9340e
UD
157 bool weak;
158 bool hidden;
8fb3e007
UD
159
160 uintmax_t ticks;
c0fb8a56 161 uintmax_t calls;
31f7410f
UD
162
163 struct arc_list *froms;
164 struct arc_list *tos;
ae828bc6
UD
165};
166
167
168struct shobj
169{
170 const char *name; /* User-provided name. */
171
172 struct link_map *map;
19212f87 173 const char *dynstrtab; /* Dynamic string table of shared object. */
ae828bc6
UD
174 const char *soname; /* Soname of shared object. */
175
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;
185
19212f87
UD
186 void *symbol_map;
187 size_t symbol_mapsize;
188 const ElfW(Sym) *symtab;
189 size_t symtab_size;
190 const char *strtab;
ae828bc6
UD
191
192 struct obstack ob_str;
193 struct obstack ob_sym;
194};
195
196
1ac03a1e
UD
197struct real_gmon_hist_hdr
198{
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;
205};
206
207
ae828bc6
UD
208struct profdata
209{
210 void *addr;
211 off_t size;
212
213 char *hist;
1ac03a1e 214 struct real_gmon_hist_hdr *hist_hdr;
ae828bc6
UD
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;
220};
221
222/* Search tree for symbols. */
fcf5e998 223static void *symroot;
8fb3e007 224static struct known_symbol **sortsym;
ae828bc6 225static size_t symidx;
8fb3e007 226static uintmax_t total_ticks;
ae828bc6
UD
227
228/* Prototypes for local functions. */
229static struct shobj *load_shobj (const char *name);
230static void unload_shobj (struct shobj *shobj);
231static struct profdata *load_profdata (const char *name, struct shobj *shobj);
232static void unload_profdata (struct profdata *profdata);
233static void count_total_ticks (struct shobj *shobj, struct profdata *profdata);
c0fb8a56 234static void count_calls (struct shobj *shobj, struct profdata *profdata);
ae828bc6 235static void read_symbols (struct shobj *shobj);
31f7410f 236static void add_arcs (struct profdata *profdata);
c0fb8a56 237static void generate_flat_profile (struct profdata *profdata);
31f7410f 238static void generate_call_graph (struct profdata *profdata);
ccd17b32 239static void generate_call_pair_list (struct profdata *profdata);
ae828bc6
UD
240
241
242int
243main (int argc, char *argv[])
244{
245 const char *shobj;
246 const char *profdata;
247 struct shobj *shobj_handle;
248 struct profdata *profdata_handle;
249 int remaining;
250
251 setlocale (LC_ALL, "");
252
253 /* Initialize the message catalog. */
254 textdomain (_libc_intl_domainname);
255
256 /* Parse and process arguments. */
257 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
258
259 if (argc - remaining == 0 || argc - remaining > 2)
260 {
261 /* We need exactly two non-option parameter. */
262 argp_help (&argp, stdout, ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR,
561470e0 263 program_invocation_short_name);
ae828bc6
UD
264 exit (1);
265 }
266
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;
275
276 /* First see whether we can load the shared object. */
277 shobj_handle = load_shobj (shobj);
278 if (shobj_handle == NULL)
279 exit (1);
280
281 /* We can now determine the filename for the profiling data, if
282 nececessary. */
283 if (profdata == NULL)
284 {
285 char *newp;
9d0881aa
UD
286 const char *soname;
287 size_t soname_len;
ae828bc6 288
9d0881aa
UD
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");
ae828bc6
UD
293 profdata = newp;
294 }
295
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)
299 {
300 unload_shobj (shobj_handle);
301
302 exit (1);
303 }
304
305 read_symbols (shobj_handle);
306
c0fb8a56
UD
307 /* Count the ticks. */
308 count_total_ticks (shobj_handle, profdata_handle);
309
310 /* Count the calls. */
311 count_calls (shobj_handle, profdata_handle);
312
31f7410f
UD
313 /* Add the arc information. */
314 add_arcs (profdata_handle);
315
c0fb8a56
UD
316 /* If no mode is specified fall back to the default mode. */
317 if (mode == NONE)
318 mode = DEFAULT_MODE;
319
ae828bc6 320 /* Do some work. */
c0fb8a56
UD
321 if (mode & FLAT_MODE)
322 generate_flat_profile (profdata_handle);
ae828bc6 323
31f7410f
UD
324 if (mode & CALL_GRAPH_MODE)
325 generate_call_graph (profdata_handle);
326
ccd17b32
UD
327 if (mode & CALL_PAIRS)
328 generate_call_pair_list (profdata_handle);
329
ae828bc6
UD
330 /* Free the resources. */
331 unload_shobj (shobj_handle);
332 unload_profdata (profdata_handle);
333
334 return 0;
335}
336
337
338/* Handle program arguments. */
339static error_t
340parse_opt (int key, char *arg, struct argp_state *state)
341{
342 switch (key)
343 {
ccd17b32
UD
344 case 'c':
345 mode |= CALL_PAIRS;
346 break;
31f7410f
UD
347 case 'p':
348 mode |= FLAT_MODE;
349 break;
350 case 'q':
351 mode |= CALL_GRAPH_MODE;
352 break;
ae828bc6
UD
353 case OPT_TEST:
354 do_test = 1;
355 break;
356 default:
357 return ARGP_ERR_UNKNOWN;
358 }
359 return 0;
360}
361
362
cbbcaf23
UD
363static char *
364more_help (int key, const char *text, void *input)
365{
8b748aed 366 char *tp = NULL;
cbbcaf23
UD
367 switch (key)
368 {
369 case ARGP_KEY_HELP_EXTRA:
370 /* We print some extra information. */
8b748aed 371 if (asprintf (&tp, gettext ("\
cbbcaf23 372For bug reporting instructions, please see:\n\
8b748aed
JM
373%s.\n"), REPORT_BUGS_TO) < 0)
374 return NULL;
375 return tp;
cbbcaf23
UD
376 default:
377 break;
378 }
379 return (char *) text;
380}
381
382
ae828bc6
UD
383/* Print the version information. */
384static void
385print_version (FILE *stream, struct argp_state *state)
386{
8b748aed 387 fprintf (stream, "sprof %s%s\n", PKGVERSION, VERSION);
ae828bc6
UD
388 fprintf (stream, gettext ("\
389Copyright (C) %s Free Software Foundation, Inc.\n\
390This is free software; see the source for copying conditions. There is NO\n\
391warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
392"),
1059defe 393 "2024");
ae828bc6
UD
394 fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
395}
396
397
398/* Note that we must not use `dlopen' etc. The shobj object must not
399 be loaded for use. */
400static struct shobj *
401load_shobj (const char *name)
402{
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;
ae828bc6
UD
409 ElfW(Ehdr) *ehdr;
410 int fd;
411 ElfW(Shdr) *shdr;
ae828bc6 412 size_t pagesize = getpagesize ();
ae828bc6
UD
413
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
630da022 416 in the current directory and the user specifies foo.so on the command
ae828bc6
UD
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)
421 {
422 char *load_name = (char *) alloca (strlen (name) + 3);
423 stpcpy (stpcpy (load_name, "./"), name);
424
9d0881aa 425 map = (struct link_map *) dlopen (load_name, RTLD_LAZY | __RTLD_SPROF);
ae828bc6
UD
426 }
427 if (map == NULL)
428 {
9d0881aa 429 map = (struct link_map *) dlopen (name, RTLD_LAZY | __RTLD_SPROF);
ae828bc6
UD
430 if (map == NULL)
431 {
432 error (0, errno, _("failed to load shared object `%s'"), name);
433 return NULL;
434 }
435 }
436
437 /* Prepare the result. */
438 result = (struct shobj *) calloc (1, sizeof (struct shobj));
439 if (result == NULL)
440 {
9be1052b 441 error (0, errno, _("cannot create internal descriptor"));
ae828bc6
UD
442 dlclose (map);
443 return NULL;
444 }
445 result->name = name;
446 result->map = map;
447
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))
452 {
19212f87
UD
453 ElfW(Addr) start = (ph->p_vaddr & ~(pagesize - 1));
454 ElfW(Addr) end = ((ph->p_vaddr + ph->p_memsz + pagesize - 1)
455 & ~(pagesize - 1));
ae828bc6
UD
456
457 if (start < mapstart)
458 mapstart = start;
459 if (end > mapend)
460 mapend = end;
461 }
462
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);
474
475 textsize = result->highpc - result->lowpc;
476 result->kcountsize = textsize / HISTFRACTION;
477 result->hashfraction = HASHFRACTION;
ae828bc6 478 if (do_test)
de477abc 479 printf ("hashfraction = %d\ndivider = %zu\n",
ae828bc6
UD
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);
489
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)));
496
497 if (do_test)
de477abc 498 printf ("expected size: %zd\n", result->expected_size);
ae828bc6 499
8fb3e007 500#define SCALE_1_TO_1 0x10000L
ae828bc6 501
8fb3e007
UD
502 if (result->kcountsize < result->highpc - result->lowpc)
503 {
504 size_t range = result->highpc - result->lowpc;
505 size_t quot = range / result->kcountsize;
506
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)));
ae828bc6 514 else
8fb3e007
UD
515 result->s_scale = ((SCALE_1_TO_1 * 256)
516 / ((range * 256) / result->kcountsize));
ae828bc6 517 }
8fb3e007
UD
518 else
519 result->s_scale = SCALE_1_TO_1;
520
521 if (do_test)
522 printf ("s_scale: %d\n", result->s_scale);
ae828bc6 523
19212f87 524 /* Determine the dynamic string table. */
ae828bc6 525 if (map->l_info[DT_STRTAB] == NULL)
19212f87 526 result->dynstrtab = NULL;
ae828bc6 527 else
ea97f90c 528 result->dynstrtab = (const char *) D_PTR (map, l_info[DT_STRTAB]);
ae828bc6 529 if (do_test)
19212f87 530 printf ("string table: %p\n", result->dynstrtab);
ae828bc6
UD
531
532 /* Determine the soname. */
533 if (map->l_info[DT_SONAME] == NULL)
534 result->soname = NULL;
535 else
19212f87 536 result->soname = result->dynstrtab + map->l_info[DT_SONAME]->d_un.d_val;
ea97f90c 537 if (do_test && result->soname != NULL)
ae828bc6
UD
538 printf ("soname: %s\n", result->soname);
539
19212f87 540 /* Now we have to load the symbol table.
ae828bc6
UD
541
542 First load the section header table. */
9a267ae2 543 ehdr = (ElfW(Ehdr) *) map->l_map_start;
ae828bc6
UD
544
545 /* Make sure we are on the right party. */
546 if (ehdr->e_shentsize != sizeof (ElfW(Shdr)))
547 abort ();
548
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. */
dbbbaf53
UD
553 error (EXIT_FAILURE, errno, _("Reopening shared object `%s' failed"),
554 map->l_name);
ae828bc6 555
fcf5e998
UD
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"));
ae828bc6
UD
561
562 /* Get the section header string table. */
fcf5e998
UD
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)
ae828bc6 567 error (EXIT_FAILURE, errno,
fcf5e998 568 _("reading of section header string table failed"));
ae828bc6 569
19212f87 570 /* Search for the ".symtab" section. */
fcf5e998
UD
571 ElfW(Shdr) *symtab_entry = NULL;
572 ElfW(Shdr) *debuglink_entry = NULL;
573 for (int idx = 0; idx < ehdr->e_shnum; ++idx)
19212f87
UD
574 if (shdr[idx].sh_type == SHT_SYMTAB
575 && strcmp (shstrtab + shdr[idx].sh_name, ".symtab") == 0)
ae828bc6 576 {
19212f87
UD
577 symtab_entry = &shdr[idx];
578 break;
ae828bc6 579 }
fcf5e998
UD
580 else if (shdr[idx].sh_type == SHT_PROGBITS
581 && strcmp (shstrtab + shdr[idx].sh_name, ".gnu_debuglink") == 0)
582 debuglink_entry = &shdr[idx];
583
584 /* Get the file name of the debuginfo file if necessary. */
585 int symfd = fd;
586 if (symtab_entry == NULL && debuglink_entry != NULL)
587 {
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)
593 {
594 fprintf (stderr, _("*** Cannot read debuginfo file name: %m\n"));
595 goto no_debuginfo;
596 }
ae828bc6 597
fcf5e998
UD
598 static const char procpath[] = "/proc/self/fd/%d";
599 char origprocname[sizeof (procpath) + sizeof (int) * 3];
600 snprintf (origprocname, sizeof (origprocname), procpath, fd);
c9aaface 601 char *origlink = (char *) alloca (PATH_MAX);
10fb0bfa 602 ssize_t n = readlink (origprocname, origlink, PATH_MAX - 1);
c9aaface 603 if (n == -1)
fcf5e998 604 goto no_debuginfo;
c9aaface 605 origlink[n] = '\0';
fcf5e998
UD
606
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
611 */
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"));
616
617 /* Leave the last slash in place. */
618 *++cp = '\0';
619
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);
626
627 int fd2 = open (workbuf, O_RDONLY);
628 if (fd2 == -1)
629 {
630 strcpy (stpcpy (stpcpy (workbuf, realname), ".debug/"),
631 debuginfo_fname);
632 fd2 = open (workbuf, O_RDONLY);
633 if (fd2 == -1)
634 {
635 strcpy (stpcpy (stpcpy (workbuf, usrlibdebug), realname),
636 debuginfo_fname);
637 fd2 = open (workbuf, O_RDONLY);
638 }
639 }
ae828bc6 640
fcf5e998
UD
641 if (fd2 != -1)
642 {
643 ElfW(Ehdr) ehdr2;
644
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"));
649
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"));
656
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"));
664
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)
669 {
670 symtab_entry = &shdr2[idx];
671 shdr = shdr2;
672 symfd = fd2;
673 break;
674 }
675
676 if (fd2 != symfd)
677 close (fd2);
678 }
679 }
680
681 no_debuginfo:
19212f87 682 if (symtab_entry == NULL)
ae828bc6
UD
683 {
684 fprintf (stderr, _("\
685*** The file `%s' is stripped: no detailed analysis possible\n"),
686 name);
19212f87
UD
687 result->symtab = NULL;
688 result->strtab = NULL;
ae828bc6
UD
689 }
690 else
691 {
19212f87
UD
692 ElfW(Off) min_offset, max_offset;
693 ElfW(Shdr) *strtab_entry;
694
695 strtab_entry = &shdr[symtab_entry->sh_link];
696
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)
700 {
701 min_offset = symtab_entry->sh_offset & ~(pagesize - 1);
702 max_offset = strtab_entry->sh_offset + strtab_entry->sh_size;
703 }
704 else
705 {
706 min_offset = strtab_entry->sh_offset & ~(pagesize - 1);
707 max_offset = symtab_entry->sh_offset + symtab_entry->sh_size;
708 }
709
710 result->symbol_map = mmap (NULL, max_offset - min_offset,
fcf5e998 711 PROT_READ, MAP_SHARED|MAP_FILE, symfd,
19212f87 712 min_offset);
fcf5e998 713 if (result->symbol_map == MAP_FAILED)
19212f87
UD
714 error (EXIT_FAILURE, errno, _("failed to load symbol data"));
715
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;
ae828bc6
UD
723 }
724
ae828bc6
UD
725 /* Free the descriptor for the shared object. */
726 close (fd);
fcf5e998
UD
727 if (symfd != fd)
728 close (symfd);
ae828bc6
UD
729
730 return result;
731}
732
733
734static void
735unload_shobj (struct shobj *shobj)
736{
19212f87 737 munmap (shobj->symbol_map, shobj->symbol_mapsize);
ae828bc6
UD
738 dlclose (shobj->map);
739}
740
741
742static struct profdata *
743load_profdata (const char *name, struct shobj *shobj)
744{
745 struct profdata *result;
746 int fd;
4c0fe6fe 747 struct stat64 st;
ae828bc6 748 void *addr;
ae828bc6
UD
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;
756
757 fd = open (name, O_RDONLY);
758 if (fd == -1)
759 {
760 char *ext_name;
761
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;
767
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;
774
775 fd = open (ext_name, O_RDONLY);
776 if (fd == -1)
777 {
778 /* Even this file does not exist. */
779 error (0, errno, _("cannot load profiling data"));
780 return NULL;
781 }
782 }
783
784 /* We have found the file, now make sure it is the right one for the
785 data file. */
4c0fe6fe 786 if (fstat64 (fd, &st) < 0)
ae828bc6
UD
787 {
788 error (0, errno, _("while stat'ing profiling data file"));
789 close (fd);
790 return NULL;
791 }
792
6dd67bd5 793 if ((size_t) st.st_size != shobj->expected_size)
ae828bc6 794 {
cc9b1d46
UD
795 error (0, 0,
796 _("profiling data file `%s' does not match shared object `%s'"),
ae828bc6
UD
797 name, shobj->name);
798 close (fd);
799 return NULL;
800 }
801
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)
806 {
807 error (0, errno, _("failed to mmap the profiling data file"));
808 close (fd);
809 return NULL;
810 }
811
630da022 812 /* We don't need the file descriptor anymore. */
ae828bc6
UD
813 if (close (fd) < 0)
814 {
815 error (0, errno, _("error while closing the profiling data file"));
816 munmap (addr, st.st_size);
817 return NULL;
818 }
819
820 /* Prepare the result. */
821 result = (struct profdata *) calloc (1, sizeof (struct profdata));
822 if (result == NULL)
823 {
824 error (0, errno, _("cannot create internal descriptor"));
825 munmap (addr, st.st_size);
826 return NULL;
827 }
828
829 /* Store the address and size so that we can later free the resources. */
830 result->addr = addr;
831 result->size = st.st_size;
832
833 /* Pointer to data after the header. */
834 result->hist = (char *) ((struct gmon_hdr *) addr + 1);
1ac03a1e
UD
835 result->hist_hdr = (struct real_gmon_hist_hdr *) ((char *) result->hist
836 + sizeof (uint32_t));
ae828bc6 837 result->kcount = (uint16_t *) ((char *) result->hist + sizeof (uint32_t)
1ac03a1e 838 + sizeof (struct real_gmon_hist_hdr));
ae828bc6
UD
839
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));
846
847 /* Create the gmon_hdr we expect or write. */
1ac03a1e
UD
848 struct real_gmon_hdr
849 {
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 ();
860
ae828bc6 861 memcpy (&gmon_hdr.cookie[0], GMON_MAGIC, sizeof (gmon_hdr.cookie));
1ac03a1e
UD
862 gmon_hdr.version = GMON_SHOBJ_VERSION;
863 memset (gmon_hdr.spare, '\0', sizeof (gmon_hdr.spare));
ae828bc6
UD
864
865 /* Create the hist_hdr we expect or write. */
1ac03a1e
UD
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 ();
881
882 hist_hdr.low_pc = (char *) shobj->lowpc - shobj->map->l_addr;
883 hist_hdr.high_pc = (char *) shobj->highpc - shobj->map->l_addr;
ae828bc6 884 if (do_test)
1ac03a1e
UD
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 ();
ae828bc6
UD
888 strncpy (hist_hdr.dimen, "seconds", sizeof (hist_hdr.dimen));
889 hist_hdr.dimen_abbrev = 's';
890
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
c0fb8a56 894 || memcmp (result->hist_hdr, &hist_hdr,
ae828bc6
UD
895 sizeof (struct gmon_hist_hdr)) != 0
896 || narcsp[-1] != GMON_TAG_CG_ARC)
897 {
ae828bc6
UD
898 error (0, 0, _("`%s' is no correct profile data file for `%s'"),
899 name, shobj->name);
7fec4f2f
UD
900 if (do_test)
901 {
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");
911 }
912 free (result);
ae828bc6
UD
913 munmap (addr, st.st_size);
914 return NULL;
915 }
916
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)
921 {
922 error (0, errno, _("cannot create internal descriptor"));
923 munmap (addr, st.st_size);
924 free (result);
925 return NULL;
926 }
927
928 result->froms = (struct here_fromstruct *) ((char *) result->tos
929 + shobj->tossize);
930 fromidx = 0;
931
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)
938 {
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;
946 }
947
948 return result;
949}
950
951
952static void
953unload_profdata (struct profdata *profdata)
954{
955 free (profdata->tos);
956 munmap (profdata->addr, profdata->size);
957 free (profdata);
958}
959
960
961static void
962count_total_ticks (struct shobj *shobj, struct profdata *profdata)
963{
964 volatile uint16_t *kcount = profdata->kcount;
8fb3e007 965 size_t maxkidx = shobj->kcountsize;
ae828bc6 966 size_t factor = 2 * (65536 / shobj->s_scale);
8fb3e007
UD
967 size_t kidx = 0;
968 size_t sidx = 0;
ae828bc6 969
8fb3e007 970 while (sidx < symidx)
ae828bc6 971 {
8fb3e007
UD
972 uintptr_t start = sortsym[sidx]->addr;
973 uintptr_t end = start + sortsym[sidx]->size;
974
975 while (kidx < maxkidx && factor * kidx < start)
976 ++kidx;
977 if (kidx == maxkidx)
978 break;
ae828bc6 979
8fb3e007
UD
980 while (kidx < maxkidx && factor * kidx < end)
981 sortsym[sidx]->ticks += kcount[kidx++];
982 if (kidx == maxkidx)
983 break;
984
985 total_ticks += sortsym[sidx++]->ticks;
986 }
ae828bc6
UD
987}
988
989
31f7410f 990static size_t
c0fb8a56
UD
991find_symbol (uintptr_t addr)
992{
993 size_t sidx = 0;
994
995 while (sidx < symidx)
996 {
997 uintptr_t start = sortsym[sidx]->addr;
998 uintptr_t end = start + sortsym[sidx]->size;
999
1000 if (addr >= start && addr < end)
31f7410f 1001 return sidx;
c0fb8a56
UD
1002
1003 if (addr < start)
1004 break;
1005
1006 ++sidx;
1007 }
1008
31f7410f 1009 return (size_t) -1l;
c0fb8a56
UD
1010}
1011
1012
1013static void
1014count_calls (struct shobj *shobj, struct profdata *profdata)
1015{
1016 struct here_cg_arc_record *data = profdata->data;
1017 uint32_t narcs = profdata->narcs;
1018 uint32_t cnt;
1019
1020 for (cnt = 0; cnt < narcs; ++cnt)
1021 {
1022 uintptr_t here = data[cnt].self_pc;
31f7410f 1023 size_t symbol_idx;
c0fb8a56
UD
1024
1025 /* Find the symbol for this address. */
31f7410f
UD
1026 symbol_idx = find_symbol (here);
1027 if (symbol_idx != (size_t) -1l)
1028 sortsym[symbol_idx]->calls += data[cnt].count;
c0fb8a56
UD
1029 }
1030}
1031
1032
ae828bc6
UD
1033static int
1034symorder (const void *o1, const void *o2)
1035{
31f7410f
UD
1036 const struct known_symbol *p1 = (const struct known_symbol *) o1;
1037 const struct known_symbol *p2 = (const struct known_symbol *) o2;
ae828bc6
UD
1038
1039 return p1->addr - p2->addr;
1040}
1041
1042
1043static void
1044printsym (const void *node, VISIT value, int level)
1045{
1046 if (value == leaf || value == postorder)
19212f87 1047 sortsym[symidx++] = *(struct known_symbol **) node;
ae828bc6
UD
1048}
1049
1050
1051static void
1052read_symbols (struct shobj *shobj)
1053{
ae828bc6 1054 int n = 0;
ae828bc6
UD
1055
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);
31f7410f 1061 obstack_init (&ob_list);
ae828bc6 1062
19212f87 1063 /* Process the symbols. */
8d88a164 1064 if (shobj->symtab != NULL)
19212f87
UD
1065 {
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)
ae828bc6 1073 {
c0fb8a56 1074 struct known_symbol **existp;
19212f87
UD
1075 struct known_symbol *newsym
1076 = (struct known_symbol *) obstack_alloc (&shobj->ob_sym,
ae828bc6 1077 sizeof (*newsym));
19212f87 1078 if (newsym == NULL)
ae828bc6
UD
1079 error (EXIT_FAILURE, errno, _("cannot allocate symbol data"));
1080
19212f87
UD
1081 newsym->name = &shobj->strtab[sym->st_name];
1082 newsym->addr = sym->st_value;
1083 newsym->size = sym->st_size;
eba19d2b 1084 newsym->weak = ELFW(ST_BIND) (sym->st_info) == STB_WEAK;
b8b9340e
UD
1085 newsym->hidden = (ELFW(ST_VISIBILITY) (sym->st_other)
1086 != STV_DEFAULT);
8fb3e007 1087 newsym->ticks = 0;
c0fb8a56
UD
1088 newsym->calls = 0;
1089
1090 existp = tfind (newsym, &symroot, symorder);
1091 if (existp == NULL)
1092 {
1093 /* New function. */
1094 tsearch (newsym, &symroot, symorder);
1095 ++n;
1096 }
1097 else
1098 {
1099 /* The function is already defined. See whether we have
1100 a better name here. */
b8b9340e
UD
1101 if (((*existp)->hidden && !newsym->hidden)
1102 || ((*existp)->name[0] == '_' && newsym->name[0] != '_')
eba19d2b 1103 || ((*existp)->name[0] != '_' && newsym->name[0] != '_'
b8b9340e 1104 && ((*existp)->weak && !newsym->weak)))
c0fb8a56
UD
1105 *existp = newsym;
1106 else
1107 /* We don't need the allocated memory. */
1108 obstack_free (&shobj->ob_sym, newsym);
1109 }
ae828bc6 1110 }
19212f87
UD
1111 }
1112 else
ae828bc6
UD
1113 {
1114 /* Blarg, the binary is stripped. We have to rely on the
1115 information contained in the dynamic section of the object. */
ea97f90c
UD
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]);
ae828bc6
UD
1120
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
8d88a164 1123 dynamic symbol table without looking at the section headers. */
ae828bc6
UD
1124 while ((void *) symtab < (void *) strtab)
1125 {
c0fb8a56
UD
1126 if ((ELFW(ST_TYPE)(symtab->st_info) == STT_FUNC
1127 || ELFW(ST_TYPE)(symtab->st_info) == STT_NOTYPE)
1128 && symtab->st_size != 0)
ae828bc6
UD
1129 {
1130 struct known_symbol *newsym;
c0fb8a56 1131 struct known_symbol **existp;
ae828bc6
UD
1132
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"));
1138
1139 newsym->name = &strtab[symtab->st_name];
1140 newsym->addr = symtab->st_value;
1141 newsym->size = symtab->st_size;
eba19d2b 1142 newsym->weak = ELFW(ST_BIND) (symtab->st_info) == STB_WEAK;
b8b9340e
UD
1143 newsym->hidden = (ELFW(ST_VISIBILITY) (symtab->st_other)
1144 != STV_DEFAULT);
8fb3e007 1145 newsym->ticks = 0;
31f7410f
UD
1146 newsym->froms = NULL;
1147 newsym->tos = NULL;
ae828bc6 1148
c0fb8a56
UD
1149 existp = tfind (newsym, &symroot, symorder);
1150 if (existp == NULL)
1151 {
1152 /* New function. */
1153 tsearch (newsym, &symroot, symorder);
1154 ++n;
1155 }
1156 else
1157 {
1158 /* The function is already defined. See whether we have
1159 a better name here. */
b8b9340e
UD
1160 if (((*existp)->hidden && !newsym->hidden)
1161 || ((*existp)->name[0] == '_' && newsym->name[0] != '_')
eba19d2b 1162 || ((*existp)->name[0] != '_' && newsym->name[0] != '_'
b8b9340e 1163 && ((*existp)->weak && !newsym->weak)))
c0fb8a56
UD
1164 *existp = newsym;
1165 else
1166 /* We don't need the allocated memory. */
1167 obstack_free (&shobj->ob_sym, newsym);
1168 }
ae828bc6 1169 }
ae828bc6 1170
8d88a164
UD
1171 ++symtab;
1172 }
ae828bc6
UD
1173 }
1174
1175 sortsym = malloc (n * sizeof (struct known_symbol *));
1176 if (sortsym == NULL)
1177 abort ();
1178
1179 twalk (symroot, printsym);
1180}
c0fb8a56
UD
1181
1182
31f7410f
UD
1183static void
1184add_arcs (struct profdata *profdata)
1185{
1186 uint32_t narcs = profdata->narcs;
1187 struct here_cg_arc_record *data = profdata->data;
1188 uint32_t cnt;
1189
1190 for (cnt = 0; cnt < narcs; ++cnt)
1191 {
1192 /* First add the incoming arc. */
1193 size_t sym_idx = find_symbol (data[cnt].self_pc);
1194
1195 if (sym_idx != (size_t) -1l)
1196 {
1197 struct known_symbol *sym = sortsym[sym_idx];
1198 struct arc_list *runp = sym->froms;
1199
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;
1209
1210 if (runp == NULL)
1211 {
1212 /* We need a new entry. */
1213 struct arc_list *newp = (struct arc_list *)
1214 obstack_alloc (&ob_list, sizeof (struct arc_list));
1215
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;
1223 }
1224 else
1225 /* Increment the counter for the found entry. */
1226 runp->count += data[cnt].count;
1227 }
1228
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)
1232 {
1233 struct known_symbol *sym = sortsym[sym_idx];
1234 struct arc_list *runp = sym->tos;
1235
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;
1242
1243 if (runp == NULL)
1244 {
1245 /* We need a new entry. */
1246 struct arc_list *newp = (struct arc_list *)
1247 obstack_alloc (&ob_list, sizeof (struct arc_list));
1248
1249 newp->idx = find_symbol (data[cnt].self_pc);
1250 newp->count = data[cnt].count;
1251 newp->next = sym->tos;
1252 sym->tos = newp;
1253 }
1254 else
1255 /* Increment the counter for the found entry. */
1256 runp->count += data[cnt].count;
1257 }
1258 }
1259}
1260
1261
c0fb8a56
UD
1262static int
1263countorder (const void *p1, const void *p2)
1264{
1265 struct known_symbol *s1 = (struct known_symbol *) p1;
1266 struct known_symbol *s2 = (struct known_symbol *) p2;
1267
1268 if (s1->ticks != s2->ticks)
1269 return (int) (s2->ticks - s1->ticks);
1270
1271 if (s1->calls != s2->calls)
1272 return (int) (s2->calls - s1->calls);
1273
1274 return strcmp (s1->name, s2->name);
1275}
1276
1277
1278static double tick_unit;
1279static uintmax_t cumu_ticks;
1280
1281static void
1282printflat (const void *node, VISIT value, int level)
1283{
1284 if (value == leaf || value == postorder)
1285 {
1286 struct known_symbol *s = *(struct known_symbol **) node;
1287
1288 cumu_ticks += s->ticks;
1289
31f7410f 1290 printf ("%6.2f%10.2f%9.2f%9" PRIdMAX "%9.2f %s\n",
c0fb8a56
UD
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,
31f7410f 1296 /* FIXME: don't know about called functions. */
c0fb8a56
UD
1297 s->name);
1298 }
1299}
1300
1301
1302/* ARGUSED */
1303static void
1304freenoop (void *p)
1305{
1306}
1307
1308
1309static void
1310generate_flat_profile (struct profdata *profdata)
1311{
1312 size_t n;
1313 void *data = NULL;
1314
1ac03a1e 1315 tick_unit = 1.0 / profdata->hist_hdr->prof_rate;
c0fb8a56
UD
1316
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);
1323
1324 for (n = 0; n < symidx; ++n)
1325 if (sortsym[n]->calls != 0 || sortsym[n]->ticks != 0)
1326 tsearch (sortsym[n], &data, countorder);
1327
1328 twalk (data, printflat);
1329
1330 tdestroy (data, freenoop);
1331}
31f7410f
UD
1332
1333
1334static void
1335generate_call_graph (struct profdata *profdata)
1336{
1337 size_t cnt;
1338
1339 puts ("\nindex % time self children called name\n");
1340
1341 for (cnt = 0; cnt < symidx; ++cnt)
1342 if (sortsym[cnt]->froms != NULL || sortsym[cnt]->tos != NULL)
1343 {
1344 struct arc_list *runp;
1345 size_t n;
1346
1347 /* First print the from-information. */
1348 runp = sortsym[cnt]->froms;
1349 while (runp != NULL)
1350 {
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),
ccd17b32 1354 0.0, /* FIXME: what's time for the children, recursive */
31f7410f 1355 runp->count, sortsym[cnt]->calls,
34a5a146
JM
1356 (runp->idx != (size_t) -1l
1357 ? sortsym[runp->idx]->name : "<UNKNOWN>"));
31f7410f
UD
1358
1359 if (runp->idx != (size_t) -1l)
de477abc 1360 printf (" [%zd]", runp->idx);
31f7410f
UD
1361 putchar_unlocked ('\n');
1362
1363 runp = runp->next;
1364 }
1365
c0c3f78a 1366 /* Info about the function itself. */
de477abc
AZN
1367 n = printf ("[%zu]", cnt);
1368 printf ("%*s%5.1f%8.2f%8.2f%9" PRIdMAX " %s [%zd]\n",
dbbbaf53 1369 (int) (7 - n), " ",
31f7410f
UD
1370 total_ticks ? (100.0 * sortsym[cnt]->ticks) / total_ticks : 0,
1371 sortsym[cnt]->ticks * tick_unit,
ccd17b32 1372 0.0, /* FIXME: what's time for the children, recursive */
31f7410f
UD
1373 sortsym[cnt]->calls,
1374 sortsym[cnt]->name, cnt);
1375
1376 /* Info about the functions this function calls. */
1377 runp = sortsym[cnt]->tos;
1378 while (runp != NULL)
1379 {
1380 printf (" %8.2f%8.2f%9" PRIdMAX "/",
1381 (runp->idx != (size_t) -1l
1382 ? sortsym[runp->idx]->ticks * tick_unit : 0.0),
ccd17b32 1383 0.0, /* FIXME: what's time for the children, recursive */
31f7410f
UD
1384 runp->count);
1385
1386 if (runp->idx != (size_t) -1l)
de477abc 1387 printf ("%-9" PRIdMAX " %s [%zd]\n",
31f7410f
UD
1388 sortsym[runp->idx]->calls,
1389 sortsym[runp->idx]->name,
1390 runp->idx);
1391 else
1392 fputs ("??? <UNKNOWN>\n\n", stdout);
1393
1394 runp = runp->next;
1395 }
1396
1397 fputs ("-----------------------------------------------\n", stdout);
1398 }
1399}
ccd17b32
UD
1400
1401
1402static void
1403generate_call_pair_list (struct profdata *profdata)
1404{
1405 size_t cnt;
1406
1407 for (cnt = 0; cnt < symidx; ++cnt)
1408 if (sortsym[cnt]->froms != NULL || sortsym[cnt]->tos != NULL)
1409 {
1410 struct arc_list *runp;
1411
1412 /* First print the incoming arcs. */
1413 runp = sortsym[cnt]->froms;
1414 while (runp != NULL)
1415 {
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;
1421 }
1422
1423 /* Next the outgoing arcs. */
1424 runp = sortsym[cnt]->tos;
1425 while (runp != NULL)
1426 {
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;
1433 }
1434 }
1435}