1 /* Read and display shared object profiling data.
2 Copyright (C) 1997-2002, 2003, 2004, 2005 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
6 The GNU C Library is free software; you can redistribute it and/or
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.
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
14 Lesser General Public License for more details.
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
38 #include <sys/gmon_out.h>
40 #include <sys/param.h>
43 /* Get libc version number. */
44 #include "../version.h"
46 #define PACKAGE _libc_intl_domainname
50 #if BYTE_ORDER == BIG_ENDIAN
51 # define byteorder ELFDATA2MSB
52 # define byteorder_name "big-endian"
53 #elif BYTE_ORDER == LITTLE_ENDIAN
54 # define byteorder ELFDATA2LSB
55 # define byteorder_name "little-endian"
57 # error "Unknown BYTE_ORDER " BYTE_ORDER
58 # define byteorder ELFDATANONE
62 # define PATH_MAX 1024
66 extern int __profile_frequency (void);
68 /* Name and version of program. */
69 static void print_version (FILE *stream
, struct argp_state
*state
);
70 void (*argp_program_version_hook
) (FILE *, struct argp_state
*) = print_version
;
74 /* Definitions of arguments for argp functions. */
75 static const struct argp_option options
[] =
77 { NULL
, 0, NULL
, 0, N_("Output selection:") },
78 { "call-pairs", 'c', NULL
, 0,
79 N_("print list of count paths and their number of use") },
80 { "flat-profile", 'p', NULL
, 0,
81 N_("generate flat profile with counts and ticks") },
82 { "graph", 'q', NULL
, 0, N_("generate call graph") },
84 { "test", OPT_TEST
, NULL
, OPTION_HIDDEN
, NULL
},
85 { NULL
, 0, NULL
, 0, NULL
}
88 /* Short description of program. */
89 static const char doc
[] = N_("Read and display shared object profiling data.\v\
90 For bug reporting instructions, please see:\n\
91 <http://www.gnu.org/software/libc/bugs.html>.\n");
93 /* Strings for arguments in help texts. */
94 static const char args_doc
[] = N_("SHOBJ [PROFDATA]");
96 /* Prototype for option handler. */
97 static error_t
parse_opt (int key
, char *arg
, struct argp_state
*state
);
99 /* Data structure to communicate with argp functions. */
100 static struct argp argp
=
102 options
, parse_opt
, args_doc
, doc
106 /* Operation modes. */
111 CALL_GRAPH_MODE
= 1 << 1,
114 DEFAULT_MODE
= FLAT_MODE
| CALL_GRAPH_MODE
117 /* Nozero for testing. */
120 /* Strcuture describing calls. */
121 struct here_fromstruct
123 struct here_cg_arc_record
volatile *here
;
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. */
130 struct here_cg_arc_record
135 } __attribute__ ((packed
));
144 struct arc_list
*next
;
147 static struct obstack ob_list
;
161 struct arc_list
*froms
;
162 struct arc_list
*tos
;
168 const char *name
; /* User-provided name. */
170 struct link_map
*map
;
171 const char *dynstrtab
; /* Dynamic string table of shared object. */
172 const char *soname
; /* Soname of shared object. */
176 unsigned long int kcountsize
;
177 size_t expected_size
; /* Expected size of profiling file. */
181 unsigned int hashfraction
;
185 size_t symbol_mapsize
;
186 const ElfW(Sym
) *symtab
;
190 struct obstack ob_str
;
191 struct obstack ob_sym
;
201 struct gmon_hist_hdr
*hist_hdr
;
203 uint32_t narcs
; /* Number of arcs in toset. */
204 struct here_cg_arc_record
*data
;
206 struct here_fromstruct
*froms
;
209 /* Search tree for symbols. */
210 static void *symroot
;
211 static struct known_symbol
**sortsym
;
212 static size_t symidx
;
213 static uintmax_t total_ticks
;
215 /* Prototypes for local functions. */
216 static struct shobj
*load_shobj (const char *name
);
217 static void unload_shobj (struct shobj
*shobj
);
218 static struct profdata
*load_profdata (const char *name
, struct shobj
*shobj
);
219 static void unload_profdata (struct profdata
*profdata
);
220 static void count_total_ticks (struct shobj
*shobj
, struct profdata
*profdata
);
221 static void count_calls (struct shobj
*shobj
, struct profdata
*profdata
);
222 static void read_symbols (struct shobj
*shobj
);
223 static void add_arcs (struct profdata
*profdata
);
224 static void generate_flat_profile (struct profdata
*profdata
);
225 static void generate_call_graph (struct profdata
*profdata
);
226 static void generate_call_pair_list (struct profdata
*profdata
);
230 main (int argc
, char *argv
[])
233 const char *profdata
;
234 struct shobj
*shobj_handle
;
235 struct profdata
*profdata_handle
;
238 setlocale (LC_ALL
, "");
240 /* Initialize the message catalog. */
241 textdomain (_libc_intl_domainname
);
243 /* Parse and process arguments. */
244 argp_parse (&argp
, argc
, argv
, 0, &remaining
, NULL
);
246 if (argc
- remaining
== 0 || argc
- remaining
> 2)
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
);
254 /* Get parameters. */
255 shobj
= argv
[remaining
];
256 if (argc
- remaining
== 2)
257 profdata
= argv
[remaining
+ 1];
259 /* No filename for the profiling data given. We will determine it
260 from the soname of the shobj, later. */
263 /* First see whether we can load the shared object. */
264 shobj_handle
= load_shobj (shobj
);
265 if (shobj_handle
== NULL
)
268 /* We can now determine the filename for the profiling data, if
270 if (profdata
== NULL
)
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");
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
)
287 unload_shobj (shobj_handle
);
292 read_symbols (shobj_handle
);
294 /* Count the ticks. */
295 count_total_ticks (shobj_handle
, profdata_handle
);
297 /* Count the calls. */
298 count_calls (shobj_handle
, profdata_handle
);
300 /* Add the arc information. */
301 add_arcs (profdata_handle
);
303 /* If no mode is specified fall back to the default mode. */
308 if (mode
& FLAT_MODE
)
309 generate_flat_profile (profdata_handle
);
311 if (mode
& CALL_GRAPH_MODE
)
312 generate_call_graph (profdata_handle
);
314 if (mode
& CALL_PAIRS
)
315 generate_call_pair_list (profdata_handle
);
317 /* Free the resources. */
318 unload_shobj (shobj_handle
);
319 unload_profdata (profdata_handle
);
325 /* Handle program arguments. */
327 parse_opt (int key
, char *arg
, struct argp_state
*state
)
338 mode
|= CALL_GRAPH_MODE
;
344 return ARGP_ERR_UNKNOWN
;
350 /* Print the version information. */
352 print_version (FILE *stream
, struct argp_state
*state
)
354 fprintf (stream
, "sprof (GNU %s) %s\n", PACKAGE
, VERSION
);
355 fprintf (stream
, gettext ("\
356 Copyright (C) %s Free Software Foundation, Inc.\n\
357 This is free software; see the source for copying conditions. There is NO\n\
358 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
361 fprintf (stream
, gettext ("Written by %s.\n"), "Ulrich Drepper");
365 /* Note that we must not use `dlopen' etc. The shobj object must not
366 be loaded for use. */
367 static struct shobj
*
368 load_shobj (const char *name
)
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
;
376 unsigned int log_hashfraction
;
380 size_t pagesize
= getpagesize ();
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
)
390 char *load_name
= (char *) alloca (strlen (name
) + 3);
391 stpcpy (stpcpy (load_name
, "./"), name
);
393 map
= (struct link_map
*) dlopen (load_name
, RTLD_LAZY
| __RTLD_SPROF
);
397 map
= (struct link_map
*) dlopen (name
, RTLD_LAZY
| __RTLD_SPROF
);
400 error (0, errno
, _("failed to load shared object `%s'"), name
);
405 /* Prepare the result. */
406 result
= (struct shobj
*) calloc (1, sizeof (struct shobj
));
409 error (0, errno
, _("cannot create internal descriptors"));
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
))
421 ElfW(Addr
) start
= (ph
->p_vaddr
& ~(pagesize
- 1));
422 ElfW(Addr
) end
= ((ph
->p_vaddr
+ ph
->p_memsz
+ pagesize
- 1)
425 if (start
< mapstart
)
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
));
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
);
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;
452 log_hashfraction
= -1;
454 printf ("hashfraction = %d\ndivider = %Zu\n",
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
);
465 result
->expected_size
= (sizeof (struct gmon_hdr
)
466 + 4 + sizeof (struct gmon_hist_hdr
)
470 * sizeof (struct here_cg_arc_record
)));
473 printf ("expected size: %Zd\n", result
->expected_size
);
475 #define SCALE_1_TO_1 0x10000L
477 if (result
->kcountsize
< result
->highpc
- result
->lowpc
)
479 size_t range
= result
->highpc
- result
->lowpc
;
480 size_t quot
= range
/ result
->kcountsize
;
482 if (quot
>= SCALE_1_TO_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)));
490 result
->s_scale
= ((SCALE_1_TO_1
* 256)
491 / ((range
* 256) / result
->kcountsize
));
494 result
->s_scale
= SCALE_1_TO_1
;
497 printf ("s_scale: %d\n", result
->s_scale
);
499 /* Determine the dynamic string table. */
500 if (map
->l_info
[DT_STRTAB
] == NULL
)
501 result
->dynstrtab
= NULL
;
503 result
->dynstrtab
= (const char *) D_PTR (map
, l_info
[DT_STRTAB
]);
505 printf ("string table: %p\n", result
->dynstrtab
);
507 /* Determine the soname. */
508 if (map
->l_info
[DT_SONAME
] == NULL
)
509 result
->soname
= NULL
;
511 result
->soname
= result
->dynstrtab
+ map
->l_info
[DT_SONAME
]->d_un
.d_val
;
512 if (do_test
&& result
->soname
!= NULL
)
513 printf ("soname: %s\n", result
->soname
);
515 /* Now we have to load the symbol table.
517 First load the section header table. */
518 ehdr
= (ElfW(Ehdr
) *) map
->l_map_start
;
520 /* Make sure we are on the right party. */
521 if (ehdr
->e_shentsize
!= sizeof (ElfW(Shdr
)))
524 /* And we need the shared object file descriptor again. */
525 fd
= open (map
->l_name
, O_RDONLY
);
527 /* Dooh, this really shouldn't happen. We know the file is available. */
528 error (EXIT_FAILURE
, errno
, _("Reopening shared object `%s' failed"),
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"));
537 /* Get the section header string table. */
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
)
542 error (EXIT_FAILURE
, errno
,
543 _("reading of section header string table failed"));
545 /* Search for the ".symtab" section. */
546 ElfW(Shdr
) *symtab_entry
= NULL
;
547 ElfW(Shdr
) *debuglink_entry
= NULL
;
548 for (int idx
= 0; idx
< ehdr
->e_shnum
; ++idx
)
549 if (shdr
[idx
].sh_type
== SHT_SYMTAB
550 && strcmp (shstrtab
+ shdr
[idx
].sh_name
, ".symtab") == 0)
552 symtab_entry
= &shdr
[idx
];
555 else if (shdr
[idx
].sh_type
== SHT_PROGBITS
556 && strcmp (shstrtab
+ shdr
[idx
].sh_name
, ".gnu_debuglink") == 0)
557 debuglink_entry
= &shdr
[idx
];
559 /* Get the file name of the debuginfo file if necessary. */
561 if (symtab_entry
== NULL
&& debuglink_entry
!= NULL
)
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
)
569 fprintf (stderr
, _("*** Cannot read debuginfo file name: %m\n"));
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)
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
586 char *realname
= canonicalize_file_name (origlink
);
588 if (realname
== NULL
|| (cp
= strrchr (realname
, '/')) == NULL
)
589 error (EXIT_FAILURE
, errno
, _("cannot determine file name"));
591 /* Leave the last slash in place. */
594 /* First add the debuginfo file name only. */
595 static const char usrlibdebug
[]= "/usr/lib/debug/";
596 char *workbuf
= (char *) alloca (sizeof (usrlibdebug
)
598 + strlen (debuginfo_fname
));
599 strcpy (stpcpy (workbuf
, realname
), debuginfo_fname
);
601 int fd2
= open (workbuf
, O_RDONLY
);
604 strcpy (stpcpy (stpcpy (workbuf
, realname
), ".debug/"),
606 fd2
= open (workbuf
, O_RDONLY
);
609 strcpy (stpcpy (stpcpy (workbuf
, usrlibdebug
), realname
),
611 fd2
= open (workbuf
, O_RDONLY
);
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"));
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"));
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"));
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)
644 symtab_entry
= &shdr2
[idx
];
656 if (symtab_entry
== NULL
)
658 fprintf (stderr
, _("\
659 *** The file `%s' is stripped: no detailed analysis possible\n"),
661 result
->symtab
= NULL
;
662 result
->strtab
= NULL
;
666 ElfW(Off
) min_offset
, max_offset
;
667 ElfW(Shdr
) *strtab_entry
;
669 strtab_entry
= &shdr
[symtab_entry
->sh_link
];
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
)
675 min_offset
= symtab_entry
->sh_offset
& ~(pagesize
- 1);
676 max_offset
= strtab_entry
->sh_offset
+ strtab_entry
->sh_size
;
680 min_offset
= strtab_entry
->sh_offset
& ~(pagesize
- 1);
681 max_offset
= symtab_entry
->sh_offset
+ symtab_entry
->sh_size
;
684 result
->symbol_map
= mmap (NULL
, max_offset
- min_offset
,
685 PROT_READ
, MAP_SHARED
|MAP_FILE
, symfd
,
687 if (result
->symbol_map
== MAP_FAILED
)
688 error (EXIT_FAILURE
, errno
, _("failed to load symbol data"));
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
;
699 /* Free the descriptor for the shared object. */
709 unload_shobj (struct shobj
*shobj
)
711 munmap (shobj
->symbol_map
, shobj
->symbol_mapsize
);
712 dlclose (shobj
->map
);
716 static struct profdata
*
717 load_profdata (const char *name
, struct shobj
*shobj
)
719 struct profdata
*result
;
723 struct gmon_hdr gmon_hdr
;
724 struct gmon_hist_hdr hist_hdr
;
727 struct here_cg_arc_record
*data
;
728 struct here_fromstruct
*froms
;
733 fd
= open (name
, O_RDONLY
);
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
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
);
751 fd
= open (ext_name
, O_RDONLY
);
754 /* Even this file does not exist. */
755 error (0, errno
, _("cannot load profiling data"));
760 /* We have found the file, now make sure it is the right one for the
762 if (fstat (fd
, &st
) < 0)
764 error (0, errno
, _("while stat'ing profiling data file"));
769 if ((size_t) st
.st_size
!= shobj
->expected_size
)
772 _("profiling data file `%s' does not match shared object `%s'"),
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
)
783 error (0, errno
, _("failed to mmap the profiling data file"));
788 /* We don't need the file desriptor anymore. */
791 error (0, errno
, _("error while closing the profiling data file"));
792 munmap (addr
, st
.st_size
);
796 /* Prepare the result. */
797 result
= (struct profdata
*) calloc (1, sizeof (struct profdata
));
800 error (0, errno
, _("cannot create internal descriptor"));
801 munmap (addr
, st
.st_size
);
805 /* Store the address and size so that we can later free the resources. */
807 result
->size
= st
.st_size
;
809 /* Pointer to data after the header. */
810 result
->hist
= (char *) ((struct gmon_hdr
*) addr
+ 1);
811 result
->hist_hdr
= (struct gmon_hist_hdr
*) ((char *) result
->hist
812 + sizeof (uint32_t));
813 result
->kcount
= (uint16_t *) ((char *) result
->hist
+ sizeof (uint32_t)
814 + sizeof (struct gmon_hist_hdr
));
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));
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
;
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
;
832 printf ("low_pc = %p\nhigh_pc = %p\n",
833 *(char **) hist_hdr
.low_pc
, *(char **) hist_hdr
.high_pc
);
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';
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
842 || memcmp (result
->hist_hdr
, &hist_hdr
,
843 sizeof (struct gmon_hist_hdr
)) != 0
844 || narcsp
[-1] != GMON_TAG_CG_ARC
)
846 error (0, 0, _("`%s' is no correct profile data file for `%s'"),
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");
861 munmap (addr
, st
.st_size
);
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
)
870 error (0, errno
, _("cannot create internal descriptor"));
871 munmap (addr
, st
.st_size
);
876 result
->froms
= (struct here_fromstruct
*) ((char *) result
->tos
880 /* Now we have to process all the arc count entries. */
881 fromlimit
= shobj
->fromlimit
;
883 froms
= result
->froms
;
885 for (idx
= 0; idx
< MIN (*narcsp
, fromlimit
); ++idx
)
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
;
901 unload_profdata (struct profdata
*profdata
)
903 free (profdata
->tos
);
904 munmap (profdata
->addr
, profdata
->size
);
910 count_total_ticks (struct shobj
*shobj
, struct profdata
*profdata
)
912 volatile uint16_t *kcount
= profdata
->kcount
;
913 size_t maxkidx
= shobj
->kcountsize
;
914 size_t factor
= 2 * (65536 / shobj
->s_scale
);
918 while (sidx
< symidx
)
920 uintptr_t start
= sortsym
[sidx
]->addr
;
921 uintptr_t end
= start
+ sortsym
[sidx
]->size
;
923 while (kidx
< maxkidx
&& factor
* kidx
< start
)
928 while (kidx
< maxkidx
&& factor
* kidx
< end
)
929 sortsym
[sidx
]->ticks
+= kcount
[kidx
++];
933 total_ticks
+= sortsym
[sidx
++]->ticks
;
939 find_symbol (uintptr_t addr
)
943 while (sidx
< symidx
)
945 uintptr_t start
= sortsym
[sidx
]->addr
;
946 uintptr_t end
= start
+ sortsym
[sidx
]->size
;
948 if (addr
>= start
&& addr
< end
)
962 count_calls (struct shobj
*shobj
, struct profdata
*profdata
)
964 struct here_cg_arc_record
*data
= profdata
->data
;
965 uint32_t narcs
= profdata
->narcs
;
968 for (cnt
= 0; cnt
< narcs
; ++cnt
)
970 uintptr_t here
= data
[cnt
].self_pc
;
973 /* Find the symbol for this address. */
974 symbol_idx
= find_symbol (here
);
975 if (symbol_idx
!= (size_t) -1l)
976 sortsym
[symbol_idx
]->calls
+= data
[cnt
].count
;
982 symorder (const void *o1
, const void *o2
)
984 const struct known_symbol
*p1
= (const struct known_symbol
*) o1
;
985 const struct known_symbol
*p2
= (const struct known_symbol
*) o2
;
987 return p1
->addr
- p2
->addr
;
992 printsym (const void *node
, VISIT value
, int level
)
994 if (value
== leaf
|| value
== postorder
)
995 sortsym
[symidx
++] = *(struct known_symbol
**) node
;
1000 read_symbols (struct shobj
*shobj
)
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
);
1009 obstack_init (&ob_list
);
1011 /* Process the symbols. */
1012 if (shobj
->symtab
!= NULL
)
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)
1022 struct known_symbol
**existp
;
1023 struct known_symbol
*newsym
1024 = (struct known_symbol
*) obstack_alloc (&shobj
->ob_sym
,
1027 error (EXIT_FAILURE
, errno
, _("cannot allocate symbol data"));
1029 newsym
->name
= &shobj
->strtab
[sym
->st_name
];
1030 newsym
->addr
= sym
->st_value
;
1031 newsym
->size
= sym
->st_size
;
1032 newsym
->weak
= ELFW(ST_BIND
) (sym
->st_info
) == STB_WEAK
;
1033 newsym
->hidden
= (ELFW(ST_VISIBILITY
) (sym
->st_other
)
1038 existp
= tfind (newsym
, &symroot
, symorder
);
1042 tsearch (newsym
, &symroot
, symorder
);
1047 /* The function is already defined. See whether we have
1048 a better name here. */
1049 if (((*existp
)->hidden
&& !newsym
->hidden
)
1050 || ((*existp
)->name
[0] == '_' && newsym
->name
[0] != '_')
1051 || ((*existp
)->name
[0] != '_' && newsym
->name
[0] != '_'
1052 && ((*existp
)->weak
&& !newsym
->weak
)))
1055 /* We don't need the allocated memory. */
1056 obstack_free (&shobj
->ob_sym
, newsym
);
1062 /* Blarg, the binary is stripped. We have to rely on the
1063 information contained in the dynamic section of the object. */
1064 const ElfW(Sym
) *symtab
= (ElfW(Sym
) *) D_PTR (shobj
->map
,
1066 const char *strtab
= (const char *) D_PTR (shobj
->map
,
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
1071 dynamic symbol table without looking at the section headers. */
1072 while ((void *) symtab
< (void *) strtab
)
1074 if ((ELFW(ST_TYPE
)(symtab
->st_info
) == STT_FUNC
1075 || ELFW(ST_TYPE
)(symtab
->st_info
) == STT_NOTYPE
)
1076 && symtab
->st_size
!= 0)
1078 struct known_symbol
*newsym
;
1079 struct known_symbol
**existp
;
1082 (struct known_symbol
*) obstack_alloc (&shobj
->ob_sym
,
1085 error (EXIT_FAILURE
, errno
, _("cannot allocate symbol data"));
1087 newsym
->name
= &strtab
[symtab
->st_name
];
1088 newsym
->addr
= symtab
->st_value
;
1089 newsym
->size
= symtab
->st_size
;
1090 newsym
->weak
= ELFW(ST_BIND
) (symtab
->st_info
) == STB_WEAK
;
1091 newsym
->hidden
= (ELFW(ST_VISIBILITY
) (symtab
->st_other
)
1094 newsym
->froms
= NULL
;
1097 existp
= tfind (newsym
, &symroot
, symorder
);
1101 tsearch (newsym
, &symroot
, symorder
);
1106 /* The function is already defined. See whether we have
1107 a better name here. */
1108 if (((*existp
)->hidden
&& !newsym
->hidden
)
1109 || ((*existp
)->name
[0] == '_' && newsym
->name
[0] != '_')
1110 || ((*existp
)->name
[0] != '_' && newsym
->name
[0] != '_'
1111 && ((*existp
)->weak
&& !newsym
->weak
)))
1114 /* We don't need the allocated memory. */
1115 obstack_free (&shobj
->ob_sym
, newsym
);
1123 sortsym
= malloc (n
* sizeof (struct known_symbol
*));
1124 if (sortsym
== NULL
)
1127 twalk (symroot
, printsym
);
1132 add_arcs (struct profdata
*profdata
)
1134 uint32_t narcs
= profdata
->narcs
;
1135 struct here_cg_arc_record
*data
= profdata
->data
;
1138 for (cnt
= 0; cnt
< narcs
; ++cnt
)
1140 /* First add the incoming arc. */
1141 size_t sym_idx
= find_symbol (data
[cnt
].self_pc
);
1143 if (sym_idx
!= (size_t) -1l)
1145 struct known_symbol
*sym
= sortsym
[sym_idx
];
1146 struct arc_list
*runp
= sym
->froms
;
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
))))))
1160 /* We need a new entry. */
1161 struct arc_list
*newp
= (struct arc_list
*)
1162 obstack_alloc (&ob_list
, sizeof (struct arc_list
));
1164 if (data
[cnt
].from_pc
== 0)
1165 newp
->idx
= (size_t) -1l;
1167 newp
->idx
= find_symbol (data
[cnt
].from_pc
);
1168 newp
->count
= data
[cnt
].count
;
1169 newp
->next
= sym
->froms
;
1173 /* Increment the counter for the found entry. */
1174 runp
->count
+= data
[cnt
].count
;
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)
1181 struct known_symbol
*sym
= sortsym
[sym_idx
];
1182 struct arc_list
*runp
= sym
->tos
;
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
)))
1193 /* We need a new entry. */
1194 struct arc_list
*newp
= (struct arc_list
*)
1195 obstack_alloc (&ob_list
, sizeof (struct arc_list
));
1197 newp
->idx
= find_symbol (data
[cnt
].self_pc
);
1198 newp
->count
= data
[cnt
].count
;
1199 newp
->next
= sym
->tos
;
1203 /* Increment the counter for the found entry. */
1204 runp
->count
+= data
[cnt
].count
;
1211 countorder (const void *p1
, const void *p2
)
1213 struct known_symbol
*s1
= (struct known_symbol
*) p1
;
1214 struct known_symbol
*s2
= (struct known_symbol
*) p2
;
1216 if (s1
->ticks
!= s2
->ticks
)
1217 return (int) (s2
->ticks
- s1
->ticks
);
1219 if (s1
->calls
!= s2
->calls
)
1220 return (int) (s2
->calls
- s1
->calls
);
1222 return strcmp (s1
->name
, s2
->name
);
1226 static double tick_unit
;
1227 static uintmax_t cumu_ticks
;
1230 printflat (const void *node
, VISIT value
, int level
)
1232 if (value
== leaf
|| value
== postorder
)
1234 struct known_symbol
*s
= *(struct known_symbol
**) node
;
1236 cumu_ticks
+= s
->ticks
;
1238 printf ("%6.2f%10.2f%9.2f%9" PRIdMAX
"%9.2f %s\n",
1239 total_ticks
? (100.0 * s
->ticks
) / total_ticks
: 0.0,
1240 tick_unit
* cumu_ticks
,
1241 tick_unit
* s
->ticks
,
1243 s
->calls
? (s
->ticks
* 1000000) * tick_unit
/ s
->calls
: 0,
1244 /* FIXME: don't know about called functions. */
1258 generate_flat_profile (struct profdata
*profdata
)
1263 tick_unit
= 1.0 / *(uint32_t *) profdata
->hist_hdr
->prof_rate
;
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",
1272 for (n
= 0; n
< symidx
; ++n
)
1273 if (sortsym
[n
]->calls
!= 0 || sortsym
[n
]->ticks
!= 0)
1274 tsearch (sortsym
[n
], &data
, countorder
);
1276 twalk (data
, printflat
);
1278 tdestroy (data
, freenoop
);
1283 generate_call_graph (struct profdata
*profdata
)
1287 puts ("\nindex % time self children called name\n");
1289 for (cnt
= 0; cnt
< symidx
; ++cnt
)
1290 if (sortsym
[cnt
]->froms
!= NULL
|| sortsym
[cnt
]->tos
!= NULL
)
1292 struct arc_list
*runp
;
1295 /* First print the from-information. */
1296 runp
= sortsym
[cnt
]->froms
;
1297 while (runp
!= NULL
)
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),
1302 0.0, /* FIXME: what's time for the children, recursive */
1303 runp
->count
, sortsym
[cnt
]->calls
,
1304 (runp
->idx
!= (size_t) -1l ?
1305 sortsym
[runp
->idx
]->name
: "<UNKNOWN>"));
1307 if (runp
->idx
!= (size_t) -1l)
1308 printf (" [%Zd]", runp
->idx
);
1309 putchar_unlocked ('\n');
1314 /* Info abount the function itself. */
1315 n
= printf ("[%Zu]", cnt
);
1316 printf ("%*s%5.1f%8.2f%8.2f%9" PRIdMAX
" %s [%Zd]\n",
1318 total_ticks
? (100.0 * sortsym
[cnt
]->ticks
) / total_ticks
: 0,
1319 sortsym
[cnt
]->ticks
* tick_unit
,
1320 0.0, /* FIXME: what's time for the children, recursive */
1321 sortsym
[cnt
]->calls
,
1322 sortsym
[cnt
]->name
, cnt
);
1324 /* Info about the functions this function calls. */
1325 runp
= sortsym
[cnt
]->tos
;
1326 while (runp
!= NULL
)
1328 printf (" %8.2f%8.2f%9" PRIdMAX
"/",
1329 (runp
->idx
!= (size_t) -1l
1330 ? sortsym
[runp
->idx
]->ticks
* tick_unit
: 0.0),
1331 0.0, /* FIXME: what's time for the children, recursive */
1334 if (runp
->idx
!= (size_t) -1l)
1335 printf ("%-9" PRIdMAX
" %s [%Zd]\n",
1336 sortsym
[runp
->idx
]->calls
,
1337 sortsym
[runp
->idx
]->name
,
1340 fputs ("??? <UNKNOWN>\n\n", stdout
);
1345 fputs ("-----------------------------------------------\n", stdout
);
1351 generate_call_pair_list (struct profdata
*profdata
)
1355 for (cnt
= 0; cnt
< symidx
; ++cnt
)
1356 if (sortsym
[cnt
]->froms
!= NULL
|| sortsym
[cnt
]->tos
!= NULL
)
1358 struct arc_list
*runp
;
1360 /* First print the incoming arcs. */
1361 runp
= sortsym
[cnt
]->froms
;
1362 while (runp
!= NULL
)
1364 if (runp
->idx
== (size_t) -1l)
1366 <UNKNOWN> %-34s %9" PRIdMAX
"\n",
1367 sortsym
[cnt
]->name
, runp
->count
);
1371 /* Next the outgoing arcs. */
1372 runp
= sortsym
[cnt
]->tos
;
1373 while (runp
!= NULL
)
1375 printf ("%-34s %-34s %9" PRIdMAX
"\n",
1377 (runp
->idx
!= (size_t) -1l
1378 ? sortsym
[runp
->idx
]->name
: "<UNKNOWN>"),