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