]> git.ipfire.org Git - thirdparty/glibc.git/blame - elf/sprof.c
math: Use wordsize-64 version for isnan
[thirdparty/glibc.git] / elf / sprof.c
CommitLineData
ae828bc6 1/* Read and display shared object profiling data.
04277e02 2 Copyright (C) 1997-2019 Free Software Foundation, Inc.
ae828bc6
UD
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
5
6 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
ae828bc6
UD
10
11 The GNU C Library 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 GNU
41bdb6e2 14 Lesser General Public License for more details.
ae828bc6 15
41bdb6e2 16 You should have received a copy of the GNU Lesser General Public
59ba27a6
PE
17 License along with the GNU C Library; if not, see
18 <http://www.gnu.org/licenses/>. */
ae828bc6
UD
19
20#include <argp.h>
21#include <dlfcn.h>
22#include <elf.h>
ae828bc6
UD
23#include <error.h>
24#include <fcntl.h>
25#include <inttypes.h>
26#include <libintl.h>
ae828bc6
UD
27#include <locale.h>
28#include <obstack.h>
29#include <search.h>
b8b9340e 30#include <stdbool.h>
ae828bc6
UD
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <unistd.h>
e054f494 35#include <stdint.h>
a42195db 36#include <ldsodefs.h>
ae828bc6
UD
37#include <sys/gmon.h>
38#include <sys/gmon_out.h>
39#include <sys/mman.h>
40#include <sys/param.h>
41#include <sys/stat.h>
42
ae828bc6
UD
43/* Get libc version number. */
44#include "../version.h"
45
46#define PACKAGE _libc_intl_domainname
47
48
49#include <endian.h>
50#if BYTE_ORDER == BIG_ENDIAN
fcf5e998
UD
51# define byteorder ELFDATA2MSB
52# define byteorder_name "big-endian"
ae828bc6 53#elif BYTE_ORDER == LITTLE_ENDIAN
fcf5e998
UD
54# define byteorder ELFDATA2LSB
55# define byteorder_name "little-endian"
ae828bc6 56#else
fcf5e998
UD
57# error "Unknown BYTE_ORDER " BYTE_ORDER
58# define byteorder ELFDATANONE
59#endif
60
61#ifndef PATH_MAX
62# define PATH_MAX 1024
ae828bc6
UD
63#endif
64
65
d8cf93f4 66extern int __profile_frequency (void);
ae828bc6
UD
67
68/* Name and version of program. */
69static void print_version (FILE *stream, struct argp_state *state);
70void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
71
c0fb8a56 72#define OPT_TEST 1
ae828bc6
UD
73
74/* Definitions of arguments for argp functions. */
75static const struct argp_option options[] =
76{
77 { NULL, 0, NULL, 0, N_("Output selection:") },
ccd17b32
UD
78 { "call-pairs", 'c', NULL, 0,
79 N_("print list of count paths and their number of use") },
c0fb8a56
UD
80 { "flat-profile", 'p', NULL, 0,
81 N_("generate flat profile with counts and ticks") },
31f7410f 82 { "graph", 'q', NULL, 0, N_("generate call graph") },
c0fb8a56 83
ae828bc6
UD
84 { "test", OPT_TEST, NULL, OPTION_HIDDEN, NULL },
85 { NULL, 0, NULL, 0, NULL }
86};
87
88/* Short description of program. */
cbbcaf23 89static const char doc[] = N_("Read and display shared object profiling data.");
a99e59d7 90//For bug reporting instructions, please see:\n
cbbcaf23 91//<http://www.gnu.org/software/libc/bugs.html>.\n");
ae828bc6
UD
92
93/* Strings for arguments in help texts. */
94static const char args_doc[] = N_("SHOBJ [PROFDATA]");
95
96/* Prototype for option handler. */
97static error_t parse_opt (int key, char *arg, struct argp_state *state);
98
cbbcaf23
UD
99/* Function to print some extra text in the help message. */
100static char *more_help (int key, const char *text, void *input);
101
ae828bc6
UD
102/* Data structure to communicate with argp functions. */
103static struct argp argp =
104{
cbbcaf23 105 options, parse_opt, args_doc, doc, NULL, more_help
ae828bc6
UD
106};
107
108
109/* Operation modes. */
110static enum
111{
112 NONE = 0,
c0fb8a56 113 FLAT_MODE = 1 << 0,
31f7410f 114 CALL_GRAPH_MODE = 1 << 1,
ccd17b32 115 CALL_PAIRS = 1 << 2,
c0fb8a56 116
31f7410f 117 DEFAULT_MODE = FLAT_MODE | CALL_GRAPH_MODE
ae828bc6
UD
118} mode;
119
ae828bc6 120/* Nozero for testing. */
fcf5e998 121static int do_test;
ae828bc6
UD
122
123/* Strcuture describing calls. */
124struct here_fromstruct
31f7410f
UD
125{
126 struct here_cg_arc_record volatile *here;
127 uint16_t link;
128};
ae828bc6
UD
129
130/* We define a special type to address the elements of the arc table.
131 This is basically the `gmon_cg_arc_record' format but it includes
132 the room for the tag and it uses real types. */
133struct here_cg_arc_record
31f7410f
UD
134{
135 uintptr_t from_pc;
136 uintptr_t self_pc;
137 uint32_t count;
138} __attribute__ ((packed));
139
140
141struct known_symbol;
142struct arc_list
143{
144 size_t idx;
145 uintmax_t count;
146
147 struct arc_list *next;
148};
149
150static struct obstack ob_list;
ae828bc6 151
ae828bc6
UD
152
153struct known_symbol
154{
155 const char *name;
156 uintptr_t addr;
157 size_t size;
b8b9340e
UD
158 bool weak;
159 bool hidden;
8fb3e007
UD
160
161 uintmax_t ticks;
c0fb8a56 162 uintmax_t calls;
31f7410f
UD
163
164 struct arc_list *froms;
165 struct arc_list *tos;
ae828bc6
UD
166};
167
168
169struct shobj
170{
171 const char *name; /* User-provided name. */
172
173 struct link_map *map;
19212f87 174 const char *dynstrtab; /* Dynamic string table of shared object. */
ae828bc6
UD
175 const char *soname; /* Soname of shared object. */
176
177 uintptr_t lowpc;
178 uintptr_t highpc;
179 unsigned long int kcountsize;
180 size_t expected_size; /* Expected size of profiling file. */
181 size_t tossize;
182 size_t fromssize;
183 size_t fromlimit;
184 unsigned int hashfraction;
185 int s_scale;
186
19212f87
UD
187 void *symbol_map;
188 size_t symbol_mapsize;
189 const ElfW(Sym) *symtab;
190 size_t symtab_size;
191 const char *strtab;
ae828bc6
UD
192
193 struct obstack ob_str;
194 struct obstack ob_sym;
195};
196
197
1ac03a1e
UD
198struct real_gmon_hist_hdr
199{
200 char *low_pc;
201 char *high_pc;
202 int32_t hist_size;
203 int32_t prof_rate;
204 char dimen[15];
205 char dimen_abbrev;
206};
207
208
ae828bc6
UD
209struct profdata
210{
211 void *addr;
212 off_t size;
213
214 char *hist;
1ac03a1e 215 struct real_gmon_hist_hdr *hist_hdr;
ae828bc6
UD
216 uint16_t *kcount;
217 uint32_t narcs; /* Number of arcs in toset. */
218 struct here_cg_arc_record *data;
219 uint16_t *tos;
220 struct here_fromstruct *froms;
221};
222
223/* Search tree for symbols. */
fcf5e998 224static void *symroot;
8fb3e007 225static struct known_symbol **sortsym;
ae828bc6 226static size_t symidx;
8fb3e007 227static uintmax_t total_ticks;
ae828bc6
UD
228
229/* Prototypes for local functions. */
230static struct shobj *load_shobj (const char *name);
231static void unload_shobj (struct shobj *shobj);
232static struct profdata *load_profdata (const char *name, struct shobj *shobj);
233static void unload_profdata (struct profdata *profdata);
234static void count_total_ticks (struct shobj *shobj, struct profdata *profdata);
c0fb8a56 235static void count_calls (struct shobj *shobj, struct profdata *profdata);
ae828bc6 236static void read_symbols (struct shobj *shobj);
31f7410f 237static void add_arcs (struct profdata *profdata);
c0fb8a56 238static void generate_flat_profile (struct profdata *profdata);
31f7410f 239static void generate_call_graph (struct profdata *profdata);
ccd17b32 240static void generate_call_pair_list (struct profdata *profdata);
ae828bc6
UD
241
242
243int
244main (int argc, char *argv[])
245{
246 const char *shobj;
247 const char *profdata;
248 struct shobj *shobj_handle;
249 struct profdata *profdata_handle;
250 int remaining;
251
252 setlocale (LC_ALL, "");
253
254 /* Initialize the message catalog. */
255 textdomain (_libc_intl_domainname);
256
257 /* Parse and process arguments. */
258 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
259
260 if (argc - remaining == 0 || argc - remaining > 2)
261 {
262 /* We need exactly two non-option parameter. */
263 argp_help (&argp, stdout, ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR,
561470e0 264 program_invocation_short_name);
ae828bc6
UD
265 exit (1);
266 }
267
268 /* Get parameters. */
269 shobj = argv[remaining];
270 if (argc - remaining == 2)
271 profdata = argv[remaining + 1];
272 else
273 /* No filename for the profiling data given. We will determine it
274 from the soname of the shobj, later. */
275 profdata = NULL;
276
277 /* First see whether we can load the shared object. */
278 shobj_handle = load_shobj (shobj);
279 if (shobj_handle == NULL)
280 exit (1);
281
282 /* We can now determine the filename for the profiling data, if
283 nececessary. */
284 if (profdata == NULL)
285 {
286 char *newp;
9d0881aa
UD
287 const char *soname;
288 size_t soname_len;
ae828bc6 289
9d0881aa
UD
290 soname = shobj_handle->soname ?: basename (shobj);
291 soname_len = strlen (soname);
292 newp = (char *) alloca (soname_len + sizeof ".profile");
293 stpcpy (mempcpy (newp, soname, soname_len), ".profile");
ae828bc6
UD
294 profdata = newp;
295 }
296
297 /* Now see whether the profiling data file matches the given object. */
298 profdata_handle = load_profdata (profdata, shobj_handle);
299 if (profdata_handle == NULL)
300 {
301 unload_shobj (shobj_handle);
302
303 exit (1);
304 }
305
306 read_symbols (shobj_handle);
307
c0fb8a56
UD
308 /* Count the ticks. */
309 count_total_ticks (shobj_handle, profdata_handle);
310
311 /* Count the calls. */
312 count_calls (shobj_handle, profdata_handle);
313
31f7410f
UD
314 /* Add the arc information. */
315 add_arcs (profdata_handle);
316
c0fb8a56
UD
317 /* If no mode is specified fall back to the default mode. */
318 if (mode == NONE)
319 mode = DEFAULT_MODE;
320
ae828bc6 321 /* Do some work. */
c0fb8a56
UD
322 if (mode & FLAT_MODE)
323 generate_flat_profile (profdata_handle);
ae828bc6 324
31f7410f
UD
325 if (mode & CALL_GRAPH_MODE)
326 generate_call_graph (profdata_handle);
327
ccd17b32
UD
328 if (mode & CALL_PAIRS)
329 generate_call_pair_list (profdata_handle);
330
ae828bc6
UD
331 /* Free the resources. */
332 unload_shobj (shobj_handle);
333 unload_profdata (profdata_handle);
334
335 return 0;
336}
337
338
339/* Handle program arguments. */
340static error_t
341parse_opt (int key, char *arg, struct argp_state *state)
342{
343 switch (key)
344 {
ccd17b32
UD
345 case 'c':
346 mode |= CALL_PAIRS;
347 break;
31f7410f
UD
348 case 'p':
349 mode |= FLAT_MODE;
350 break;
351 case 'q':
352 mode |= CALL_GRAPH_MODE;
353 break;
ae828bc6
UD
354 case OPT_TEST:
355 do_test = 1;
356 break;
357 default:
358 return ARGP_ERR_UNKNOWN;
359 }
360 return 0;
361}
362
363
cbbcaf23
UD
364static char *
365more_help (int key, const char *text, void *input)
366{
8b748aed 367 char *tp = NULL;
cbbcaf23
UD
368 switch (key)
369 {
370 case ARGP_KEY_HELP_EXTRA:
371 /* We print some extra information. */
8b748aed 372 if (asprintf (&tp, gettext ("\
cbbcaf23 373For bug reporting instructions, please see:\n\
8b748aed
JM
374%s.\n"), REPORT_BUGS_TO) < 0)
375 return NULL;
376 return tp;
cbbcaf23
UD
377 default:
378 break;
379 }
380 return (char *) text;
381}
382
383
ae828bc6
UD
384/* Print the version information. */
385static void
386print_version (FILE *stream, struct argp_state *state)
387{
8b748aed 388 fprintf (stream, "sprof %s%s\n", PKGVERSION, VERSION);
ae828bc6
UD
389 fprintf (stream, gettext ("\
390Copyright (C) %s Free Software Foundation, Inc.\n\
391This is free software; see the source for copying conditions. There is NO\n\
392warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
393"),
c9123888 394 "2019");
ae828bc6
UD
395 fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
396}
397
398
399/* Note that we must not use `dlopen' etc. The shobj object must not
400 be loaded for use. */
401static struct shobj *
402load_shobj (const char *name)
403{
404 struct link_map *map = NULL;
405 struct shobj *result;
406 ElfW(Addr) mapstart = ~((ElfW(Addr)) 0);
407 ElfW(Addr) mapend = 0;
408 const ElfW(Phdr) *ph;
409 size_t textsize;
ae828bc6
UD
410 ElfW(Ehdr) *ehdr;
411 int fd;
412 ElfW(Shdr) *shdr;
ae828bc6 413 size_t pagesize = getpagesize ();
ae828bc6
UD
414
415 /* Since we use dlopen() we must be prepared to work around the sometimes
416 strange lookup rules for the shared objects. If we have a file foo.so
417 in the current directory and the user specfies foo.so on the command
418 line (without specifying a directory) we should load the file in the
419 current directory even if a normal dlopen() call would read the other
420 file. We do this by adding a directory portion to the name. */
421 if (strchr (name, '/') == NULL)
422 {
423 char *load_name = (char *) alloca (strlen (name) + 3);
424 stpcpy (stpcpy (load_name, "./"), name);
425
9d0881aa 426 map = (struct link_map *) dlopen (load_name, RTLD_LAZY | __RTLD_SPROF);
ae828bc6
UD
427 }
428 if (map == NULL)
429 {
9d0881aa 430 map = (struct link_map *) dlopen (name, RTLD_LAZY | __RTLD_SPROF);
ae828bc6
UD
431 if (map == NULL)
432 {
433 error (0, errno, _("failed to load shared object `%s'"), name);
434 return NULL;
435 }
436 }
437
438 /* Prepare the result. */
439 result = (struct shobj *) calloc (1, sizeof (struct shobj));
440 if (result == NULL)
441 {
9be1052b 442 error (0, errno, _("cannot create internal descriptor"));
ae828bc6
UD
443 dlclose (map);
444 return NULL;
445 }
446 result->name = name;
447 result->map = map;
448
449 /* Compute the size of the sections which contain program code.
450 This must match the code in dl-profile.c (_dl_start_profile). */
451 for (ph = map->l_phdr; ph < &map->l_phdr[map->l_phnum]; ++ph)
452 if (ph->p_type == PT_LOAD && (ph->p_flags & PF_X))
453 {
19212f87
UD
454 ElfW(Addr) start = (ph->p_vaddr & ~(pagesize - 1));
455 ElfW(Addr) end = ((ph->p_vaddr + ph->p_memsz + pagesize - 1)
456 & ~(pagesize - 1));
ae828bc6
UD
457
458 if (start < mapstart)
459 mapstart = start;
460 if (end > mapend)
461 mapend = end;
462 }
463
464 result->lowpc = ROUNDDOWN ((uintptr_t) (mapstart + map->l_addr),
465 HISTFRACTION * sizeof (HISTCOUNTER));
466 result->highpc = ROUNDUP ((uintptr_t) (mapend + map->l_addr),
467 HISTFRACTION * sizeof (HISTCOUNTER));
468 if (do_test)
469 printf ("load addr: %0#*" PRIxPTR "\n"
470 "lower bound PC: %0#*" PRIxPTR "\n"
471 "upper bound PC: %0#*" PRIxPTR "\n",
472 __ELF_NATIVE_CLASS == 32 ? 10 : 18, map->l_addr,
473 __ELF_NATIVE_CLASS == 32 ? 10 : 18, result->lowpc,
474 __ELF_NATIVE_CLASS == 32 ? 10 : 18, result->highpc);
475
476 textsize = result->highpc - result->lowpc;
477 result->kcountsize = textsize / HISTFRACTION;
478 result->hashfraction = HASHFRACTION;
ae828bc6 479 if (do_test)
ba9234d9 480 printf ("hashfraction = %d\ndivider = %Zu\n",
ae828bc6
UD
481 result->hashfraction,
482 result->hashfraction * sizeof (struct here_fromstruct));
483 result->tossize = textsize / HASHFRACTION;
484 result->fromlimit = textsize * ARCDENSITY / 100;
485 if (result->fromlimit < MINARCS)
486 result->fromlimit = MINARCS;
487 if (result->fromlimit > MAXARCS)
488 result->fromlimit = MAXARCS;
489 result->fromssize = result->fromlimit * sizeof (struct here_fromstruct);
490
491 result->expected_size = (sizeof (struct gmon_hdr)
492 + 4 + sizeof (struct gmon_hist_hdr)
493 + result->kcountsize
494 + 4 + 4
495 + (result->fromssize
496 * sizeof (struct here_cg_arc_record)));
497
498 if (do_test)
8fb3e007 499 printf ("expected size: %Zd\n", result->expected_size);
ae828bc6 500
8fb3e007 501#define SCALE_1_TO_1 0x10000L
ae828bc6 502
8fb3e007
UD
503 if (result->kcountsize < result->highpc - result->lowpc)
504 {
505 size_t range = result->highpc - result->lowpc;
506 size_t quot = range / result->kcountsize;
507
508 if (quot >= SCALE_1_TO_1)
509 result->s_scale = 1;
510 else if (quot >= SCALE_1_TO_1 / 256)
511 result->s_scale = SCALE_1_TO_1 / quot;
512 else if (range > ULONG_MAX / 256)
513 result->s_scale = ((SCALE_1_TO_1 * 256)
514 / (range / (result->kcountsize / 256)));
ae828bc6 515 else
8fb3e007
UD
516 result->s_scale = ((SCALE_1_TO_1 * 256)
517 / ((range * 256) / result->kcountsize));
ae828bc6 518 }
8fb3e007
UD
519 else
520 result->s_scale = SCALE_1_TO_1;
521
522 if (do_test)
523 printf ("s_scale: %d\n", result->s_scale);
ae828bc6 524
19212f87 525 /* Determine the dynamic string table. */
ae828bc6 526 if (map->l_info[DT_STRTAB] == NULL)
19212f87 527 result->dynstrtab = NULL;
ae828bc6 528 else
ea97f90c 529 result->dynstrtab = (const char *) D_PTR (map, l_info[DT_STRTAB]);
ae828bc6 530 if (do_test)
19212f87 531 printf ("string table: %p\n", result->dynstrtab);
ae828bc6
UD
532
533 /* Determine the soname. */
534 if (map->l_info[DT_SONAME] == NULL)
535 result->soname = NULL;
536 else
19212f87 537 result->soname = result->dynstrtab + map->l_info[DT_SONAME]->d_un.d_val;
ea97f90c 538 if (do_test && result->soname != NULL)
ae828bc6
UD
539 printf ("soname: %s\n", result->soname);
540
19212f87 541 /* Now we have to load the symbol table.
ae828bc6
UD
542
543 First load the section header table. */
9a267ae2 544 ehdr = (ElfW(Ehdr) *) map->l_map_start;
ae828bc6
UD
545
546 /* Make sure we are on the right party. */
547 if (ehdr->e_shentsize != sizeof (ElfW(Shdr)))
548 abort ();
549
550 /* And we need the shared object file descriptor again. */
551 fd = open (map->l_name, O_RDONLY);
552 if (fd == -1)
553 /* Dooh, this really shouldn't happen. We know the file is available. */
dbbbaf53
UD
554 error (EXIT_FAILURE, errno, _("Reopening shared object `%s' failed"),
555 map->l_name);
ae828bc6 556
fcf5e998
UD
557 /* Map the section header. */
558 size_t size = ehdr->e_shnum * sizeof (ElfW(Shdr));
559 shdr = (ElfW(Shdr) *) alloca (size);
560 if (pread (fd, shdr, size, ehdr->e_shoff) != size)
561 error (EXIT_FAILURE, errno, _("reading of section headers failed"));
ae828bc6
UD
562
563 /* Get the section header string table. */
fcf5e998
UD
564 char *shstrtab = (char *) alloca (shdr[ehdr->e_shstrndx].sh_size);
565 if (pread (fd, shstrtab, shdr[ehdr->e_shstrndx].sh_size,
566 shdr[ehdr->e_shstrndx].sh_offset)
567 != shdr[ehdr->e_shstrndx].sh_size)
ae828bc6 568 error (EXIT_FAILURE, errno,
fcf5e998 569 _("reading of section header string table failed"));
ae828bc6 570
19212f87 571 /* Search for the ".symtab" section. */
fcf5e998
UD
572 ElfW(Shdr) *symtab_entry = NULL;
573 ElfW(Shdr) *debuglink_entry = NULL;
574 for (int idx = 0; idx < ehdr->e_shnum; ++idx)
19212f87
UD
575 if (shdr[idx].sh_type == SHT_SYMTAB
576 && strcmp (shstrtab + shdr[idx].sh_name, ".symtab") == 0)
ae828bc6 577 {
19212f87
UD
578 symtab_entry = &shdr[idx];
579 break;
ae828bc6 580 }
fcf5e998
UD
581 else if (shdr[idx].sh_type == SHT_PROGBITS
582 && strcmp (shstrtab + shdr[idx].sh_name, ".gnu_debuglink") == 0)
583 debuglink_entry = &shdr[idx];
584
585 /* Get the file name of the debuginfo file if necessary. */
586 int symfd = fd;
587 if (symtab_entry == NULL && debuglink_entry != NULL)
588 {
589 size_t size = debuglink_entry->sh_size;
590 char *debuginfo_fname = (char *) alloca (size + 1);
591 debuginfo_fname[size] = '\0';
592 if (pread (fd, debuginfo_fname, size, debuglink_entry->sh_offset)
593 != size)
594 {
595 fprintf (stderr, _("*** Cannot read debuginfo file name: %m\n"));
596 goto no_debuginfo;
597 }
ae828bc6 598
fcf5e998
UD
599 static const char procpath[] = "/proc/self/fd/%d";
600 char origprocname[sizeof (procpath) + sizeof (int) * 3];
601 snprintf (origprocname, sizeof (origprocname), procpath, fd);
c9aaface 602 char *origlink = (char *) alloca (PATH_MAX);
10fb0bfa 603 ssize_t n = readlink (origprocname, origlink, PATH_MAX - 1);
c9aaface 604 if (n == -1)
fcf5e998 605 goto no_debuginfo;
c9aaface 606 origlink[n] = '\0';
fcf5e998
UD
607
608 /* Try to find the actual file. There are three places:
609 1. the same directory the DSO is in
610 2. in a subdir named .debug of the directory the DSO is in
611 3. in /usr/lib/debug/PATH-OF-DSO
612 */
613 char *realname = canonicalize_file_name (origlink);
614 char *cp = NULL;
615 if (realname == NULL || (cp = strrchr (realname, '/')) == NULL)
616 error (EXIT_FAILURE, errno, _("cannot determine file name"));
617
618 /* Leave the last slash in place. */
619 *++cp = '\0';
620
621 /* First add the debuginfo file name only. */
622 static const char usrlibdebug[]= "/usr/lib/debug/";
623 char *workbuf = (char *) alloca (sizeof (usrlibdebug)
624 + (cp - realname)
625 + strlen (debuginfo_fname));
626 strcpy (stpcpy (workbuf, realname), debuginfo_fname);
627
628 int fd2 = open (workbuf, O_RDONLY);
629 if (fd2 == -1)
630 {
631 strcpy (stpcpy (stpcpy (workbuf, realname), ".debug/"),
632 debuginfo_fname);
633 fd2 = open (workbuf, O_RDONLY);
634 if (fd2 == -1)
635 {
636 strcpy (stpcpy (stpcpy (workbuf, usrlibdebug), realname),
637 debuginfo_fname);
638 fd2 = open (workbuf, O_RDONLY);
639 }
640 }
ae828bc6 641
fcf5e998
UD
642 if (fd2 != -1)
643 {
644 ElfW(Ehdr) ehdr2;
645
646 /* Read the ELF header. */
647 if (pread (fd2, &ehdr2, sizeof (ehdr2), 0) != sizeof (ehdr2))
648 error (EXIT_FAILURE, errno,
649 _("reading of ELF header failed"));
650
651 /* Map the section header. */
652 size_t size = ehdr2.e_shnum * sizeof (ElfW(Shdr));
653 ElfW(Shdr) *shdr2 = (ElfW(Shdr) *) alloca (size);
654 if (pread (fd2, shdr2, size, ehdr2.e_shoff) != size)
655 error (EXIT_FAILURE, errno,
656 _("reading of section headers failed"));
657
658 /* Get the section header string table. */
659 shstrtab = (char *) alloca (shdr2[ehdr2.e_shstrndx].sh_size);
660 if (pread (fd2, shstrtab, shdr2[ehdr2.e_shstrndx].sh_size,
661 shdr2[ehdr2.e_shstrndx].sh_offset)
662 != shdr2[ehdr2.e_shstrndx].sh_size)
663 error (EXIT_FAILURE, errno,
664 _("reading of section header string table failed"));
665
666 /* Search for the ".symtab" section. */
667 for (int idx = 0; idx < ehdr2.e_shnum; ++idx)
668 if (shdr2[idx].sh_type == SHT_SYMTAB
669 && strcmp (shstrtab + shdr2[idx].sh_name, ".symtab") == 0)
670 {
671 symtab_entry = &shdr2[idx];
672 shdr = shdr2;
673 symfd = fd2;
674 break;
675 }
676
677 if (fd2 != symfd)
678 close (fd2);
679 }
680 }
681
682 no_debuginfo:
19212f87 683 if (symtab_entry == NULL)
ae828bc6
UD
684 {
685 fprintf (stderr, _("\
686*** The file `%s' is stripped: no detailed analysis possible\n"),
687 name);
19212f87
UD
688 result->symtab = NULL;
689 result->strtab = NULL;
ae828bc6
UD
690 }
691 else
692 {
19212f87
UD
693 ElfW(Off) min_offset, max_offset;
694 ElfW(Shdr) *strtab_entry;
695
696 strtab_entry = &shdr[symtab_entry->sh_link];
697
698 /* Find the minimum and maximum offsets that include both the symbol
699 table and the string table. */
700 if (symtab_entry->sh_offset < strtab_entry->sh_offset)
701 {
702 min_offset = symtab_entry->sh_offset & ~(pagesize - 1);
703 max_offset = strtab_entry->sh_offset + strtab_entry->sh_size;
704 }
705 else
706 {
707 min_offset = strtab_entry->sh_offset & ~(pagesize - 1);
708 max_offset = symtab_entry->sh_offset + symtab_entry->sh_size;
709 }
710
711 result->symbol_map = mmap (NULL, max_offset - min_offset,
fcf5e998 712 PROT_READ, MAP_SHARED|MAP_FILE, symfd,
19212f87 713 min_offset);
fcf5e998 714 if (result->symbol_map == MAP_FAILED)
19212f87
UD
715 error (EXIT_FAILURE, errno, _("failed to load symbol data"));
716
717 result->symtab
718 = (const ElfW(Sym) *) ((const char *) result->symbol_map
719 + (symtab_entry->sh_offset - min_offset));
720 result->symtab_size = symtab_entry->sh_size;
721 result->strtab = ((const char *) result->symbol_map
722 + (strtab_entry->sh_offset - min_offset));
723 result->symbol_mapsize = max_offset - min_offset;
ae828bc6
UD
724 }
725
ae828bc6
UD
726 /* Free the descriptor for the shared object. */
727 close (fd);
fcf5e998
UD
728 if (symfd != fd)
729 close (symfd);
ae828bc6
UD
730
731 return result;
732}
733
734
735static void
736unload_shobj (struct shobj *shobj)
737{
19212f87 738 munmap (shobj->symbol_map, shobj->symbol_mapsize);
ae828bc6
UD
739 dlclose (shobj->map);
740}
741
742
743static struct profdata *
744load_profdata (const char *name, struct shobj *shobj)
745{
746 struct profdata *result;
747 int fd;
4c0fe6fe 748 struct stat64 st;
ae828bc6 749 void *addr;
ae828bc6
UD
750 uint32_t *narcsp;
751 size_t fromlimit;
752 struct here_cg_arc_record *data;
753 struct here_fromstruct *froms;
754 uint16_t *tos;
755 size_t fromidx;
756 size_t idx;
757
758 fd = open (name, O_RDONLY);
759 if (fd == -1)
760 {
761 char *ext_name;
762
763 if (errno != ENOENT || strchr (name, '/') != NULL)
764 /* The file exists but we are not allowed to read it or the
765 file does not exist and the name includes a path
766 specification.. */
767 return NULL;
768
769 /* A file with the given name does not exist in the current
770 directory, try it in the default location where the profiling
771 files are created. */
772 ext_name = (char *) alloca (strlen (name) + sizeof "/var/tmp/");
773 stpcpy (stpcpy (ext_name, "/var/tmp/"), name);
774 name = ext_name;
775
776 fd = open (ext_name, O_RDONLY);
777 if (fd == -1)
778 {
779 /* Even this file does not exist. */
780 error (0, errno, _("cannot load profiling data"));
781 return NULL;
782 }
783 }
784
785 /* We have found the file, now make sure it is the right one for the
786 data file. */
4c0fe6fe 787 if (fstat64 (fd, &st) < 0)
ae828bc6
UD
788 {
789 error (0, errno, _("while stat'ing profiling data file"));
790 close (fd);
791 return NULL;
792 }
793
6dd67bd5 794 if ((size_t) st.st_size != shobj->expected_size)
ae828bc6 795 {
cc9b1d46
UD
796 error (0, 0,
797 _("profiling data file `%s' does not match shared object `%s'"),
ae828bc6
UD
798 name, shobj->name);
799 close (fd);
800 return NULL;
801 }
802
803 /* The data file is most probably the right one for our shared
804 object. Map it now. */
805 addr = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED|MAP_FILE, fd, 0);
806 if (addr == MAP_FAILED)
807 {
808 error (0, errno, _("failed to mmap the profiling data file"));
809 close (fd);
810 return NULL;
811 }
812
813 /* We don't need the file desriptor anymore. */
814 if (close (fd) < 0)
815 {
816 error (0, errno, _("error while closing the profiling data file"));
817 munmap (addr, st.st_size);
818 return NULL;
819 }
820
821 /* Prepare the result. */
822 result = (struct profdata *) calloc (1, sizeof (struct profdata));
823 if (result == NULL)
824 {
825 error (0, errno, _("cannot create internal descriptor"));
826 munmap (addr, st.st_size);
827 return NULL;
828 }
829
830 /* Store the address and size so that we can later free the resources. */
831 result->addr = addr;
832 result->size = st.st_size;
833
834 /* Pointer to data after the header. */
835 result->hist = (char *) ((struct gmon_hdr *) addr + 1);
1ac03a1e
UD
836 result->hist_hdr = (struct real_gmon_hist_hdr *) ((char *) result->hist
837 + sizeof (uint32_t));
ae828bc6 838 result->kcount = (uint16_t *) ((char *) result->hist + sizeof (uint32_t)
1ac03a1e 839 + sizeof (struct real_gmon_hist_hdr));
ae828bc6
UD
840
841 /* Compute pointer to array of the arc information. */
842 narcsp = (uint32_t *) ((char *) result->kcount + shobj->kcountsize
843 + sizeof (uint32_t));
844 result->narcs = *narcsp;
845 result->data = (struct here_cg_arc_record *) ((char *) narcsp
846 + sizeof (uint32_t));
847
848 /* Create the gmon_hdr we expect or write. */
1ac03a1e
UD
849 struct real_gmon_hdr
850 {
851 char cookie[4];
852 int32_t version;
853 char spare[3 * 4];
854 } gmon_hdr;
855 if (sizeof (gmon_hdr) != sizeof (struct gmon_hdr)
856 || (offsetof (struct real_gmon_hdr, cookie)
857 != offsetof (struct gmon_hdr, cookie))
858 || (offsetof (struct real_gmon_hdr, version)
859 != offsetof (struct gmon_hdr, version)))
860 abort ();
861
ae828bc6 862 memcpy (&gmon_hdr.cookie[0], GMON_MAGIC, sizeof (gmon_hdr.cookie));
1ac03a1e
UD
863 gmon_hdr.version = GMON_SHOBJ_VERSION;
864 memset (gmon_hdr.spare, '\0', sizeof (gmon_hdr.spare));
ae828bc6
UD
865
866 /* Create the hist_hdr we expect or write. */
1ac03a1e
UD
867 struct real_gmon_hist_hdr hist_hdr;
868 if (sizeof (hist_hdr) != sizeof (struct gmon_hist_hdr)
869 || (offsetof (struct real_gmon_hist_hdr, low_pc)
870 != offsetof (struct gmon_hist_hdr, low_pc))
871 || (offsetof (struct real_gmon_hist_hdr, high_pc)
872 != offsetof (struct gmon_hist_hdr, high_pc))
873 || (offsetof (struct real_gmon_hist_hdr, hist_size)
874 != offsetof (struct gmon_hist_hdr, hist_size))
875 || (offsetof (struct real_gmon_hist_hdr, prof_rate)
876 != offsetof (struct gmon_hist_hdr, prof_rate))
877 || (offsetof (struct real_gmon_hist_hdr, dimen)
878 != offsetof (struct gmon_hist_hdr, dimen))
879 || (offsetof (struct real_gmon_hist_hdr, dimen_abbrev)
880 != offsetof (struct gmon_hist_hdr, dimen_abbrev)))
881 abort ();
882
883 hist_hdr.low_pc = (char *) shobj->lowpc - shobj->map->l_addr;
884 hist_hdr.high_pc = (char *) shobj->highpc - shobj->map->l_addr;
ae828bc6 885 if (do_test)
1ac03a1e
UD
886 printf ("low_pc = %p\nhigh_pc = %p\n", hist_hdr.low_pc, hist_hdr.high_pc);
887 hist_hdr.hist_size = shobj->kcountsize / sizeof (HISTCOUNTER);
888 hist_hdr.prof_rate = __profile_frequency ();
ae828bc6
UD
889 strncpy (hist_hdr.dimen, "seconds", sizeof (hist_hdr.dimen));
890 hist_hdr.dimen_abbrev = 's';
891
892 /* Test whether the header of the profiling data is ok. */
893 if (memcmp (addr, &gmon_hdr, sizeof (struct gmon_hdr)) != 0
894 || *(uint32_t *) result->hist != GMON_TAG_TIME_HIST
c0fb8a56 895 || memcmp (result->hist_hdr, &hist_hdr,
ae828bc6
UD
896 sizeof (struct gmon_hist_hdr)) != 0
897 || narcsp[-1] != GMON_TAG_CG_ARC)
898 {
ae828bc6
UD
899 error (0, 0, _("`%s' is no correct profile data file for `%s'"),
900 name, shobj->name);
7fec4f2f
UD
901 if (do_test)
902 {
903 if (memcmp (addr, &gmon_hdr, sizeof (struct gmon_hdr)) != 0)
904 puts ("gmon_hdr differs");
905 if (*(uint32_t *) result->hist != GMON_TAG_TIME_HIST)
906 puts ("result->hist differs");
907 if (memcmp (result->hist_hdr, &hist_hdr,
908 sizeof (struct gmon_hist_hdr)) != 0)
909 puts ("hist_hdr differs");
910 if (narcsp[-1] != GMON_TAG_CG_ARC)
911 puts ("narcsp[-1] differs");
912 }
913 free (result);
ae828bc6
UD
914 munmap (addr, st.st_size);
915 return NULL;
916 }
917
918 /* We are pretty sure now that this is a correct input file. Set up
919 the remaining information in the result structure and return. */
920 result->tos = (uint16_t *) calloc (shobj->tossize + shobj->fromssize, 1);
921 if (result->tos == NULL)
922 {
923 error (0, errno, _("cannot create internal descriptor"));
924 munmap (addr, st.st_size);
925 free (result);
926 return NULL;
927 }
928
929 result->froms = (struct here_fromstruct *) ((char *) result->tos
930 + shobj->tossize);
931 fromidx = 0;
932
933 /* Now we have to process all the arc count entries. */
934 fromlimit = shobj->fromlimit;
935 data = result->data;
936 froms = result->froms;
937 tos = result->tos;
938 for (idx = 0; idx < MIN (*narcsp, fromlimit); ++idx)
939 {
940 size_t to_index;
941 size_t newfromidx;
942 to_index = (data[idx].self_pc / (shobj->hashfraction * sizeof (*tos)));
943 newfromidx = fromidx++;
944 froms[newfromidx].here = &data[idx];
945 froms[newfromidx].link = tos[to_index];
946 tos[to_index] = newfromidx;
947 }
948
949 return result;
950}
951
952
953static void
954unload_profdata (struct profdata *profdata)
955{
956 free (profdata->tos);
957 munmap (profdata->addr, profdata->size);
958 free (profdata);
959}
960
961
962static void
963count_total_ticks (struct shobj *shobj, struct profdata *profdata)
964{
965 volatile uint16_t *kcount = profdata->kcount;
8fb3e007 966 size_t maxkidx = shobj->kcountsize;
ae828bc6 967 size_t factor = 2 * (65536 / shobj->s_scale);
8fb3e007
UD
968 size_t kidx = 0;
969 size_t sidx = 0;
ae828bc6 970
8fb3e007 971 while (sidx < symidx)
ae828bc6 972 {
8fb3e007
UD
973 uintptr_t start = sortsym[sidx]->addr;
974 uintptr_t end = start + sortsym[sidx]->size;
975
976 while (kidx < maxkidx && factor * kidx < start)
977 ++kidx;
978 if (kidx == maxkidx)
979 break;
ae828bc6 980
8fb3e007
UD
981 while (kidx < maxkidx && factor * kidx < end)
982 sortsym[sidx]->ticks += kcount[kidx++];
983 if (kidx == maxkidx)
984 break;
985
986 total_ticks += sortsym[sidx++]->ticks;
987 }
ae828bc6
UD
988}
989
990
31f7410f 991static size_t
c0fb8a56
UD
992find_symbol (uintptr_t addr)
993{
994 size_t sidx = 0;
995
996 while (sidx < symidx)
997 {
998 uintptr_t start = sortsym[sidx]->addr;
999 uintptr_t end = start + sortsym[sidx]->size;
1000
1001 if (addr >= start && addr < end)
31f7410f 1002 return sidx;
c0fb8a56
UD
1003
1004 if (addr < start)
1005 break;
1006
1007 ++sidx;
1008 }
1009
31f7410f 1010 return (size_t) -1l;
c0fb8a56
UD
1011}
1012
1013
1014static void
1015count_calls (struct shobj *shobj, struct profdata *profdata)
1016{
1017 struct here_cg_arc_record *data = profdata->data;
1018 uint32_t narcs = profdata->narcs;
1019 uint32_t cnt;
1020
1021 for (cnt = 0; cnt < narcs; ++cnt)
1022 {
1023 uintptr_t here = data[cnt].self_pc;
31f7410f 1024 size_t symbol_idx;
c0fb8a56
UD
1025
1026 /* Find the symbol for this address. */
31f7410f
UD
1027 symbol_idx = find_symbol (here);
1028 if (symbol_idx != (size_t) -1l)
1029 sortsym[symbol_idx]->calls += data[cnt].count;
c0fb8a56
UD
1030 }
1031}
1032
1033
ae828bc6
UD
1034static int
1035symorder (const void *o1, const void *o2)
1036{
31f7410f
UD
1037 const struct known_symbol *p1 = (const struct known_symbol *) o1;
1038 const struct known_symbol *p2 = (const struct known_symbol *) o2;
ae828bc6
UD
1039
1040 return p1->addr - p2->addr;
1041}
1042
1043
1044static void
1045printsym (const void *node, VISIT value, int level)
1046{
1047 if (value == leaf || value == postorder)
19212f87 1048 sortsym[symidx++] = *(struct known_symbol **) node;
ae828bc6
UD
1049}
1050
1051
1052static void
1053read_symbols (struct shobj *shobj)
1054{
ae828bc6 1055 int n = 0;
ae828bc6
UD
1056
1057 /* Initialize the obstacks. */
1058#define obstack_chunk_alloc malloc
1059#define obstack_chunk_free free
1060 obstack_init (&shobj->ob_str);
1061 obstack_init (&shobj->ob_sym);
31f7410f 1062 obstack_init (&ob_list);
ae828bc6 1063
19212f87 1064 /* Process the symbols. */
8d88a164 1065 if (shobj->symtab != NULL)
19212f87
UD
1066 {
1067 const ElfW(Sym) *sym = shobj->symtab;
1068 const ElfW(Sym) *sym_end
1069 = (const ElfW(Sym) *) ((const char *) sym + shobj->symtab_size);
1070 for (; sym < sym_end; sym++)
1071 if ((ELFW(ST_TYPE) (sym->st_info) == STT_FUNC
1072 || ELFW(ST_TYPE) (sym->st_info) == STT_NOTYPE)
1073 && sym->st_size != 0)
ae828bc6 1074 {
c0fb8a56 1075 struct known_symbol **existp;
19212f87
UD
1076 struct known_symbol *newsym
1077 = (struct known_symbol *) obstack_alloc (&shobj->ob_sym,
ae828bc6 1078 sizeof (*newsym));
19212f87 1079 if (newsym == NULL)
ae828bc6
UD
1080 error (EXIT_FAILURE, errno, _("cannot allocate symbol data"));
1081
19212f87
UD
1082 newsym->name = &shobj->strtab[sym->st_name];
1083 newsym->addr = sym->st_value;
1084 newsym->size = sym->st_size;
eba19d2b 1085 newsym->weak = ELFW(ST_BIND) (sym->st_info) == STB_WEAK;
b8b9340e
UD
1086 newsym->hidden = (ELFW(ST_VISIBILITY) (sym->st_other)
1087 != STV_DEFAULT);
8fb3e007 1088 newsym->ticks = 0;
c0fb8a56
UD
1089 newsym->calls = 0;
1090
1091 existp = tfind (newsym, &symroot, symorder);
1092 if (existp == NULL)
1093 {
1094 /* New function. */
1095 tsearch (newsym, &symroot, symorder);
1096 ++n;
1097 }
1098 else
1099 {
1100 /* The function is already defined. See whether we have
1101 a better name here. */
b8b9340e
UD
1102 if (((*existp)->hidden && !newsym->hidden)
1103 || ((*existp)->name[0] == '_' && newsym->name[0] != '_')
eba19d2b 1104 || ((*existp)->name[0] != '_' && newsym->name[0] != '_'
b8b9340e 1105 && ((*existp)->weak && !newsym->weak)))
c0fb8a56
UD
1106 *existp = newsym;
1107 else
1108 /* We don't need the allocated memory. */
1109 obstack_free (&shobj->ob_sym, newsym);
1110 }
ae828bc6 1111 }
19212f87
UD
1112 }
1113 else
ae828bc6
UD
1114 {
1115 /* Blarg, the binary is stripped. We have to rely on the
1116 information contained in the dynamic section of the object. */
ea97f90c
UD
1117 const ElfW(Sym) *symtab = (ElfW(Sym) *) D_PTR (shobj->map,
1118 l_info[DT_SYMTAB]);
1119 const char *strtab = (const char *) D_PTR (shobj->map,
1120 l_info[DT_STRTAB]);
ae828bc6
UD
1121
1122 /* We assume that the string table follows the symbol table,
1123 because there is no way in ELF to know the size of the
8d88a164 1124 dynamic symbol table without looking at the section headers. */
ae828bc6
UD
1125 while ((void *) symtab < (void *) strtab)
1126 {
c0fb8a56
UD
1127 if ((ELFW(ST_TYPE)(symtab->st_info) == STT_FUNC
1128 || ELFW(ST_TYPE)(symtab->st_info) == STT_NOTYPE)
1129 && symtab->st_size != 0)
ae828bc6
UD
1130 {
1131 struct known_symbol *newsym;
c0fb8a56 1132 struct known_symbol **existp;
ae828bc6
UD
1133
1134 newsym =
1135 (struct known_symbol *) obstack_alloc (&shobj->ob_sym,
1136 sizeof (*newsym));
1137 if (newsym == NULL)
1138 error (EXIT_FAILURE, errno, _("cannot allocate symbol data"));
1139
1140 newsym->name = &strtab[symtab->st_name];
1141 newsym->addr = symtab->st_value;
1142 newsym->size = symtab->st_size;
eba19d2b 1143 newsym->weak = ELFW(ST_BIND) (symtab->st_info) == STB_WEAK;
b8b9340e
UD
1144 newsym->hidden = (ELFW(ST_VISIBILITY) (symtab->st_other)
1145 != STV_DEFAULT);
8fb3e007 1146 newsym->ticks = 0;
31f7410f
UD
1147 newsym->froms = NULL;
1148 newsym->tos = NULL;
ae828bc6 1149
c0fb8a56
UD
1150 existp = tfind (newsym, &symroot, symorder);
1151 if (existp == NULL)
1152 {
1153 /* New function. */
1154 tsearch (newsym, &symroot, symorder);
1155 ++n;
1156 }
1157 else
1158 {
1159 /* The function is already defined. See whether we have
1160 a better name here. */
b8b9340e
UD
1161 if (((*existp)->hidden && !newsym->hidden)
1162 || ((*existp)->name[0] == '_' && newsym->name[0] != '_')
eba19d2b 1163 || ((*existp)->name[0] != '_' && newsym->name[0] != '_'
b8b9340e 1164 && ((*existp)->weak && !newsym->weak)))
c0fb8a56
UD
1165 *existp = newsym;
1166 else
1167 /* We don't need the allocated memory. */
1168 obstack_free (&shobj->ob_sym, newsym);
1169 }
ae828bc6 1170 }
ae828bc6 1171
8d88a164
UD
1172 ++symtab;
1173 }
ae828bc6
UD
1174 }
1175
1176 sortsym = malloc (n * sizeof (struct known_symbol *));
1177 if (sortsym == NULL)
1178 abort ();
1179
1180 twalk (symroot, printsym);
1181}
c0fb8a56
UD
1182
1183
31f7410f
UD
1184static void
1185add_arcs (struct profdata *profdata)
1186{
1187 uint32_t narcs = profdata->narcs;
1188 struct here_cg_arc_record *data = profdata->data;
1189 uint32_t cnt;
1190
1191 for (cnt = 0; cnt < narcs; ++cnt)
1192 {
1193 /* First add the incoming arc. */
1194 size_t sym_idx = find_symbol (data[cnt].self_pc);
1195
1196 if (sym_idx != (size_t) -1l)
1197 {
1198 struct known_symbol *sym = sortsym[sym_idx];
1199 struct arc_list *runp = sym->froms;
1200
1201 while (runp != NULL
1202 && ((data[cnt].from_pc == 0 && runp->idx != (size_t) -1l)
1203 || (data[cnt].from_pc != 0
1204 && (runp->idx == (size_t) -1l
1205 || data[cnt].from_pc < sortsym[runp->idx]->addr
1206 || (data[cnt].from_pc
1207 >= (sortsym[runp->idx]->addr
1208 + sortsym[runp->idx]->size))))))
1209 runp = runp->next;
1210
1211 if (runp == NULL)
1212 {
1213 /* We need a new entry. */
1214 struct arc_list *newp = (struct arc_list *)
1215 obstack_alloc (&ob_list, sizeof (struct arc_list));
1216
1217 if (data[cnt].from_pc == 0)
1218 newp->idx = (size_t) -1l;
1219 else
1220 newp->idx = find_symbol (data[cnt].from_pc);
1221 newp->count = data[cnt].count;
1222 newp->next = sym->froms;
1223 sym->froms = newp;
1224 }
1225 else
1226 /* Increment the counter for the found entry. */
1227 runp->count += data[cnt].count;
1228 }
1229
1230 /* Now add it to the appropriate outgoing list. */
1231 sym_idx = find_symbol (data[cnt].from_pc);
1232 if (sym_idx != (size_t) -1l)
1233 {
1234 struct known_symbol *sym = sortsym[sym_idx];
1235 struct arc_list *runp = sym->tos;
1236
1237 while (runp != NULL
1238 && (runp->idx == (size_t) -1l
1239 || data[cnt].self_pc < sortsym[runp->idx]->addr
1240 || data[cnt].self_pc >= (sortsym[runp->idx]->addr
1241 + sortsym[runp->idx]->size)))
1242 runp = runp->next;
1243
1244 if (runp == NULL)
1245 {
1246 /* We need a new entry. */
1247 struct arc_list *newp = (struct arc_list *)
1248 obstack_alloc (&ob_list, sizeof (struct arc_list));
1249
1250 newp->idx = find_symbol (data[cnt].self_pc);
1251 newp->count = data[cnt].count;
1252 newp->next = sym->tos;
1253 sym->tos = newp;
1254 }
1255 else
1256 /* Increment the counter for the found entry. */
1257 runp->count += data[cnt].count;
1258 }
1259 }
1260}
1261
1262
c0fb8a56
UD
1263static int
1264countorder (const void *p1, const void *p2)
1265{
1266 struct known_symbol *s1 = (struct known_symbol *) p1;
1267 struct known_symbol *s2 = (struct known_symbol *) p2;
1268
1269 if (s1->ticks != s2->ticks)
1270 return (int) (s2->ticks - s1->ticks);
1271
1272 if (s1->calls != s2->calls)
1273 return (int) (s2->calls - s1->calls);
1274
1275 return strcmp (s1->name, s2->name);
1276}
1277
1278
1279static double tick_unit;
1280static uintmax_t cumu_ticks;
1281
1282static void
1283printflat (const void *node, VISIT value, int level)
1284{
1285 if (value == leaf || value == postorder)
1286 {
1287 struct known_symbol *s = *(struct known_symbol **) node;
1288
1289 cumu_ticks += s->ticks;
1290
31f7410f 1291 printf ("%6.2f%10.2f%9.2f%9" PRIdMAX "%9.2f %s\n",
c0fb8a56
UD
1292 total_ticks ? (100.0 * s->ticks) / total_ticks : 0.0,
1293 tick_unit * cumu_ticks,
1294 tick_unit * s->ticks,
1295 s->calls,
1296 s->calls ? (s->ticks * 1000000) * tick_unit / s->calls : 0,
31f7410f 1297 /* FIXME: don't know about called functions. */
c0fb8a56
UD
1298 s->name);
1299 }
1300}
1301
1302
1303/* ARGUSED */
1304static void
1305freenoop (void *p)
1306{
1307}
1308
1309
1310static void
1311generate_flat_profile (struct profdata *profdata)
1312{
1313 size_t n;
1314 void *data = NULL;
1315
1ac03a1e 1316 tick_unit = 1.0 / profdata->hist_hdr->prof_rate;
c0fb8a56
UD
1317
1318 printf ("Flat profile:\n\n"
1319 "Each sample counts as %g %s.\n",
1320 tick_unit, profdata->hist_hdr->dimen);
1321 fputs (" % cumulative self self total\n"
1322 " time seconds seconds calls us/call us/call name\n",
1323 stdout);
1324
1325 for (n = 0; n < symidx; ++n)
1326 if (sortsym[n]->calls != 0 || sortsym[n]->ticks != 0)
1327 tsearch (sortsym[n], &data, countorder);
1328
1329 twalk (data, printflat);
1330
1331 tdestroy (data, freenoop);
1332}
31f7410f
UD
1333
1334
1335static void
1336generate_call_graph (struct profdata *profdata)
1337{
1338 size_t cnt;
1339
1340 puts ("\nindex % time self children called name\n");
1341
1342 for (cnt = 0; cnt < symidx; ++cnt)
1343 if (sortsym[cnt]->froms != NULL || sortsym[cnt]->tos != NULL)
1344 {
1345 struct arc_list *runp;
1346 size_t n;
1347
1348 /* First print the from-information. */
1349 runp = sortsym[cnt]->froms;
1350 while (runp != NULL)
1351 {
1352 printf (" %8.2f%8.2f%9" PRIdMAX "/%-9" PRIdMAX " %s",
1353 (runp->idx != (size_t) -1l
1354 ? sortsym[runp->idx]->ticks * tick_unit : 0.0),
ccd17b32 1355 0.0, /* FIXME: what's time for the children, recursive */
31f7410f 1356 runp->count, sortsym[cnt]->calls,
34a5a146
JM
1357 (runp->idx != (size_t) -1l
1358 ? sortsym[runp->idx]->name : "<UNKNOWN>"));
31f7410f
UD
1359
1360 if (runp->idx != (size_t) -1l)
1361 printf (" [%Zd]", runp->idx);
1362 putchar_unlocked ('\n');
1363
1364 runp = runp->next;
1365 }
1366
c0c3f78a 1367 /* Info about the function itself. */
ba9234d9 1368 n = printf ("[%Zu]", cnt);
31f7410f 1369 printf ("%*s%5.1f%8.2f%8.2f%9" PRIdMAX " %s [%Zd]\n",
dbbbaf53 1370 (int) (7 - n), " ",
31f7410f
UD
1371 total_ticks ? (100.0 * sortsym[cnt]->ticks) / total_ticks : 0,
1372 sortsym[cnt]->ticks * tick_unit,
ccd17b32 1373 0.0, /* FIXME: what's time for the children, recursive */
31f7410f
UD
1374 sortsym[cnt]->calls,
1375 sortsym[cnt]->name, cnt);
1376
1377 /* Info about the functions this function calls. */
1378 runp = sortsym[cnt]->tos;
1379 while (runp != NULL)
1380 {
1381 printf (" %8.2f%8.2f%9" PRIdMAX "/",
1382 (runp->idx != (size_t) -1l
1383 ? sortsym[runp->idx]->ticks * tick_unit : 0.0),
ccd17b32 1384 0.0, /* FIXME: what's time for the children, recursive */
31f7410f
UD
1385 runp->count);
1386
1387 if (runp->idx != (size_t) -1l)
1388 printf ("%-9" PRIdMAX " %s [%Zd]\n",
1389 sortsym[runp->idx]->calls,
1390 sortsym[runp->idx]->name,
1391 runp->idx);
1392 else
1393 fputs ("??? <UNKNOWN>\n\n", stdout);
1394
1395 runp = runp->next;
1396 }
1397
1398 fputs ("-----------------------------------------------\n", stdout);
1399 }
1400}
ccd17b32
UD
1401
1402
1403static void
1404generate_call_pair_list (struct profdata *profdata)
1405{
1406 size_t cnt;
1407
1408 for (cnt = 0; cnt < symidx; ++cnt)
1409 if (sortsym[cnt]->froms != NULL || sortsym[cnt]->tos != NULL)
1410 {
1411 struct arc_list *runp;
1412
1413 /* First print the incoming arcs. */
1414 runp = sortsym[cnt]->froms;
1415 while (runp != NULL)
1416 {
1417 if (runp->idx == (size_t) -1l)
1418 printf ("\
1419<UNKNOWN> %-34s %9" PRIdMAX "\n",
1420 sortsym[cnt]->name, runp->count);
1421 runp = runp->next;
1422 }
1423
1424 /* Next the outgoing arcs. */
1425 runp = sortsym[cnt]->tos;
1426 while (runp != NULL)
1427 {
1428 printf ("%-34s %-34s %9" PRIdMAX "\n",
1429 sortsym[cnt]->name,
1430 (runp->idx != (size_t) -1l
1431 ? sortsym[runp->idx]->name : "<UNKNOWN>"),
1432 runp->count);
1433 runp = runp->next;
1434 }
1435 }
1436}