Blame elf/sprof.c

Packit 6c4009
/* Read and display shared object profiling data.
Packit 6c4009
   Copyright (C) 1997-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <argp.h>
Packit 6c4009
#include <dlfcn.h>
Packit 6c4009
#include <elf.h>
Packit 6c4009
#include <error.h>
Packit 6c4009
#include <fcntl.h>
Packit 6c4009
#include <inttypes.h>
Packit 6c4009
#include <libintl.h>
Packit 6c4009
#include <locale.h>
Packit 6c4009
#include <obstack.h>
Packit 6c4009
#include <search.h>
Packit 6c4009
#include <stdbool.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <stdint.h>
Packit 6c4009
#include <ldsodefs.h>
Packit 6c4009
#include <sys/gmon.h>
Packit 6c4009
#include <sys/gmon_out.h>
Packit 6c4009
#include <sys/mman.h>
Packit 6c4009
#include <sys/param.h>
Packit 6c4009
#include <sys/stat.h>
Packit 6c4009
Packit 6c4009
/* Get libc version number.  */
Packit 6c4009
#include "../version.h"
Packit 6c4009
Packit 6c4009
#define PACKAGE _libc_intl_domainname
Packit 6c4009
Packit 6c4009
Packit 6c4009
#include <endian.h>
Packit 6c4009
#if BYTE_ORDER == BIG_ENDIAN
Packit 6c4009
# define byteorder ELFDATA2MSB
Packit 6c4009
# define byteorder_name "big-endian"
Packit 6c4009
#elif BYTE_ORDER == LITTLE_ENDIAN
Packit 6c4009
# define byteorder ELFDATA2LSB
Packit 6c4009
# define byteorder_name "little-endian"
Packit 6c4009
#else
Packit 6c4009
# error "Unknown BYTE_ORDER " BYTE_ORDER
Packit 6c4009
# define byteorder ELFDATANONE
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifndef PATH_MAX
Packit 6c4009
# define PATH_MAX 1024
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
Packit 6c4009
extern int __profile_frequency (void);
Packit 6c4009
Packit 6c4009
/* Name and version of program.  */
Packit 6c4009
static void print_version (FILE *stream, struct argp_state *state);
Packit 6c4009
void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
Packit 6c4009
Packit 6c4009
#define OPT_TEST	1
Packit 6c4009
Packit 6c4009
/* Definitions of arguments for argp functions.  */
Packit 6c4009
static const struct argp_option options[] =
Packit 6c4009
{
Packit 6c4009
  { NULL, 0, NULL, 0, N_("Output selection:") },
Packit 6c4009
  { "call-pairs", 'c', NULL, 0,
Packit 6c4009
    N_("print list of count paths and their number of use") },
Packit 6c4009
  { "flat-profile", 'p', NULL, 0,
Packit 6c4009
    N_("generate flat profile with counts and ticks") },
Packit 6c4009
  { "graph", 'q', NULL, 0, N_("generate call graph") },
Packit 6c4009
Packit 6c4009
  { "test", OPT_TEST, NULL, OPTION_HIDDEN, NULL },
Packit 6c4009
  { NULL, 0, NULL, 0, NULL }
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
/* Short description of program.  */
Packit 6c4009
static const char doc[] = N_("Read and display shared object profiling data.");
Packit 6c4009
//For bug reporting instructions, please see:\n
Packit 6c4009
//<http://www.gnu.org/software/libc/bugs.html>.\n");
Packit 6c4009
Packit 6c4009
/* Strings for arguments in help texts.  */
Packit 6c4009
static const char args_doc[] = N_("SHOBJ [PROFDATA]");
Packit 6c4009
Packit 6c4009
/* Prototype for option handler.  */
Packit 6c4009
static error_t parse_opt (int key, char *arg, struct argp_state *state);
Packit 6c4009
Packit 6c4009
/* Function to print some extra text in the help message.  */
Packit 6c4009
static char *more_help (int key, const char *text, void *input);
Packit 6c4009
Packit 6c4009
/* Data structure to communicate with argp functions.  */
Packit 6c4009
static struct argp argp =
Packit 6c4009
{
Packit 6c4009
  options, parse_opt, args_doc, doc, NULL, more_help
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Operation modes.  */
Packit 6c4009
static enum
Packit 6c4009
{
Packit 6c4009
  NONE = 0,
Packit 6c4009
  FLAT_MODE = 1 << 0,
Packit 6c4009
  CALL_GRAPH_MODE = 1 << 1,
Packit 6c4009
  CALL_PAIRS = 1 << 2,
Packit 6c4009
Packit 6c4009
  DEFAULT_MODE = FLAT_MODE | CALL_GRAPH_MODE
Packit 6c4009
} mode;
Packit 6c4009
Packit 6c4009
/* Nozero for testing.  */
Packit 6c4009
static int do_test;
Packit 6c4009
Packit 6c4009
/* Strcuture describing calls.  */
Packit 6c4009
struct here_fromstruct
Packit 6c4009
{
Packit 6c4009
  struct here_cg_arc_record volatile *here;
Packit 6c4009
  uint16_t link;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
/* We define a special type to address the elements of the arc table.
Packit 6c4009
   This is basically the `gmon_cg_arc_record' format but it includes
Packit 6c4009
   the room for the tag and it uses real types.  */
Packit 6c4009
struct here_cg_arc_record
Packit 6c4009
{
Packit 6c4009
  uintptr_t from_pc;
Packit 6c4009
  uintptr_t self_pc;
Packit 6c4009
  uint32_t count;
Packit 6c4009
} __attribute__ ((packed));
Packit 6c4009
Packit 6c4009
Packit 6c4009
struct known_symbol;
Packit 6c4009
struct arc_list
Packit 6c4009
{
Packit 6c4009
  size_t idx;
Packit 6c4009
  uintmax_t count;
Packit 6c4009
Packit 6c4009
  struct arc_list *next;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
static struct obstack ob_list;
Packit 6c4009
Packit 6c4009
Packit 6c4009
struct known_symbol
Packit 6c4009
{
Packit 6c4009
  const char *name;
Packit 6c4009
  uintptr_t addr;
Packit 6c4009
  size_t size;
Packit 6c4009
  bool weak;
Packit 6c4009
  bool hidden;
Packit 6c4009
Packit 6c4009
  uintmax_t ticks;
Packit 6c4009
  uintmax_t calls;
Packit 6c4009
Packit 6c4009
  struct arc_list *froms;
Packit 6c4009
  struct arc_list *tos;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
Packit 6c4009
struct shobj
Packit 6c4009
{
Packit 6c4009
  const char *name;		/* User-provided name.  */
Packit 6c4009
Packit 6c4009
  struct link_map *map;
Packit 6c4009
  const char *dynstrtab;	/* Dynamic string table of shared object.  */
Packit 6c4009
  const char *soname;		/* Soname of shared object.  */
Packit 6c4009
Packit 6c4009
  uintptr_t lowpc;
Packit 6c4009
  uintptr_t highpc;
Packit 6c4009
  unsigned long int kcountsize;
Packit 6c4009
  size_t expected_size;		/* Expected size of profiling file.  */
Packit 6c4009
  size_t tossize;
Packit 6c4009
  size_t fromssize;
Packit 6c4009
  size_t fromlimit;
Packit 6c4009
  unsigned int hashfraction;
Packit 6c4009
  int s_scale;
Packit 6c4009
Packit 6c4009
  void *symbol_map;
Packit 6c4009
  size_t symbol_mapsize;
Packit 6c4009
  const ElfW(Sym) *symtab;
Packit 6c4009
  size_t symtab_size;
Packit 6c4009
  const char *strtab;
Packit 6c4009
Packit 6c4009
  struct obstack ob_str;
Packit 6c4009
  struct obstack ob_sym;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
Packit 6c4009
struct real_gmon_hist_hdr
Packit 6c4009
{
Packit 6c4009
  char *low_pc;
Packit 6c4009
  char *high_pc;
Packit 6c4009
  int32_t hist_size;
Packit 6c4009
  int32_t prof_rate;
Packit 6c4009
  char dimen[15];
Packit 6c4009
  char dimen_abbrev;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
Packit 6c4009
struct profdata
Packit 6c4009
{
Packit 6c4009
  void *addr;
Packit 6c4009
  off_t size;
Packit 6c4009
Packit 6c4009
  char *hist;
Packit 6c4009
  struct real_gmon_hist_hdr *hist_hdr;
Packit 6c4009
  uint16_t *kcount;
Packit 6c4009
  uint32_t narcs;		/* Number of arcs in toset.  */
Packit 6c4009
  struct here_cg_arc_record *data;
Packit 6c4009
  uint16_t *tos;
Packit 6c4009
  struct here_fromstruct *froms;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
/* Search tree for symbols.  */
Packit 6c4009
static void *symroot;
Packit 6c4009
static struct known_symbol **sortsym;
Packit 6c4009
static size_t symidx;
Packit 6c4009
static uintmax_t total_ticks;
Packit 6c4009
Packit 6c4009
/* Prototypes for local functions.  */
Packit 6c4009
static struct shobj *load_shobj (const char *name);
Packit 6c4009
static void unload_shobj (struct shobj *shobj);
Packit 6c4009
static struct profdata *load_profdata (const char *name, struct shobj *shobj);
Packit 6c4009
static void unload_profdata (struct profdata *profdata);
Packit 6c4009
static void count_total_ticks (struct shobj *shobj, struct profdata *profdata);
Packit 6c4009
static void count_calls (struct shobj *shobj, struct profdata *profdata);
Packit 6c4009
static void read_symbols (struct shobj *shobj);
Packit 6c4009
static void add_arcs (struct profdata *profdata);
Packit 6c4009
static void generate_flat_profile (struct profdata *profdata);
Packit 6c4009
static void generate_call_graph (struct profdata *profdata);
Packit 6c4009
static void generate_call_pair_list (struct profdata *profdata);
Packit 6c4009
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
main (int argc, char *argv[])
Packit 6c4009
{
Packit 6c4009
  const char *shobj;
Packit 6c4009
  const char *profdata;
Packit 6c4009
  struct shobj *shobj_handle;
Packit 6c4009
  struct profdata *profdata_handle;
Packit 6c4009
  int remaining;
Packit 6c4009
Packit 6c4009
  setlocale (LC_ALL, "");
Packit 6c4009
Packit 6c4009
  /* Initialize the message catalog.  */
Packit 6c4009
  textdomain (_libc_intl_domainname);
Packit 6c4009
Packit 6c4009
  /* Parse and process arguments.  */
Packit 6c4009
  argp_parse (&argp, argc, argv, 0, &remaining, NULL);
Packit 6c4009
Packit 6c4009
  if (argc - remaining == 0 || argc - remaining > 2)
Packit 6c4009
    {
Packit 6c4009
      /* We need exactly two non-option parameter.  */
Packit 6c4009
      argp_help (&argp, stdout, ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR,
Packit 6c4009
		 program_invocation_short_name);
Packit 6c4009
      exit (1);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Get parameters.  */
Packit 6c4009
  shobj = argv[remaining];
Packit 6c4009
  if (argc - remaining == 2)
Packit 6c4009
    profdata = argv[remaining + 1];
Packit 6c4009
  else
Packit 6c4009
    /* No filename for the profiling data given.  We will determine it
Packit 6c4009
       from the soname of the shobj, later.  */
Packit 6c4009
    profdata = NULL;
Packit 6c4009
Packit 6c4009
  /* First see whether we can load the shared object.  */
Packit 6c4009
  shobj_handle = load_shobj (shobj);
Packit 6c4009
  if (shobj_handle == NULL)
Packit 6c4009
    exit (1);
Packit 6c4009
Packit 6c4009
  /* We can now determine the filename for the profiling data, if
Packit 6c4009
     nececessary.  */
Packit 6c4009
  if (profdata == NULL)
Packit 6c4009
    {
Packit 6c4009
      char *newp;
Packit 6c4009
      const char *soname;
Packit 6c4009
      size_t soname_len;
Packit 6c4009
Packit 6c4009
      soname = shobj_handle->soname ?: basename (shobj);
Packit 6c4009
      soname_len = strlen (soname);
Packit 6c4009
      newp = (char *) alloca (soname_len + sizeof ".profile");
Packit 6c4009
      stpcpy (mempcpy (newp, soname, soname_len), ".profile");
Packit 6c4009
      profdata = newp;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Now see whether the profiling data file matches the given object.   */
Packit 6c4009
  profdata_handle = load_profdata (profdata, shobj_handle);
Packit 6c4009
  if (profdata_handle == NULL)
Packit 6c4009
    {
Packit 6c4009
      unload_shobj (shobj_handle);
Packit 6c4009
Packit 6c4009
      exit (1);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  read_symbols (shobj_handle);
Packit 6c4009
Packit 6c4009
  /* Count the ticks.  */
Packit 6c4009
  count_total_ticks (shobj_handle, profdata_handle);
Packit 6c4009
Packit 6c4009
  /* Count the calls.  */
Packit 6c4009
  count_calls (shobj_handle, profdata_handle);
Packit 6c4009
Packit 6c4009
  /* Add the arc information.  */
Packit 6c4009
  add_arcs (profdata_handle);
Packit 6c4009
Packit 6c4009
  /* If no mode is specified fall back to the default mode.  */
Packit 6c4009
  if (mode == NONE)
Packit 6c4009
    mode = DEFAULT_MODE;
Packit 6c4009
Packit 6c4009
  /* Do some work.  */
Packit 6c4009
  if (mode & FLAT_MODE)
Packit 6c4009
    generate_flat_profile (profdata_handle);
Packit 6c4009
Packit 6c4009
  if (mode & CALL_GRAPH_MODE)
Packit 6c4009
    generate_call_graph (profdata_handle);
Packit 6c4009
Packit 6c4009
  if (mode & CALL_PAIRS)
Packit 6c4009
    generate_call_pair_list (profdata_handle);
Packit 6c4009
Packit 6c4009
  /* Free the resources.  */
Packit 6c4009
  unload_shobj (shobj_handle);
Packit 6c4009
  unload_profdata (profdata_handle);
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Handle program arguments.  */
Packit 6c4009
static error_t
Packit 6c4009
parse_opt (int key, char *arg, struct argp_state *state)
Packit 6c4009
{
Packit 6c4009
  switch (key)
Packit 6c4009
    {
Packit 6c4009
    case 'c':
Packit 6c4009
      mode |= CALL_PAIRS;
Packit 6c4009
      break;
Packit 6c4009
    case 'p':
Packit 6c4009
      mode |= FLAT_MODE;
Packit 6c4009
      break;
Packit 6c4009
    case 'q':
Packit 6c4009
      mode |= CALL_GRAPH_MODE;
Packit 6c4009
      break;
Packit 6c4009
    case OPT_TEST:
Packit 6c4009
      do_test = 1;
Packit 6c4009
      break;
Packit 6c4009
    default:
Packit 6c4009
      return ARGP_ERR_UNKNOWN;
Packit 6c4009
    }
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static char *
Packit 6c4009
more_help (int key, const char *text, void *input)
Packit 6c4009
{
Packit 6c4009
  char *tp = NULL;
Packit 6c4009
  switch (key)
Packit 6c4009
    {
Packit 6c4009
    case ARGP_KEY_HELP_EXTRA:
Packit 6c4009
      /* We print some extra information.  */
Packit 6c4009
      if (asprintf (&tp, gettext ("\
Packit 6c4009
For bug reporting instructions, please see:\n\
Packit 6c4009
%s.\n"), REPORT_BUGS_TO) < 0)
Packit 6c4009
	return NULL;
Packit 6c4009
      return tp;
Packit 6c4009
    default:
Packit 6c4009
      break;
Packit 6c4009
    }
Packit 6c4009
  return (char *) text;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Print the version information.  */
Packit 6c4009
static void
Packit 6c4009
print_version (FILE *stream, struct argp_state *state)
Packit 6c4009
{
Packit 6c4009
  fprintf (stream, "sprof %s%s\n", PKGVERSION, VERSION);
Packit 6c4009
  fprintf (stream, gettext ("\
Packit 6c4009
Copyright (C) %s Free Software Foundation, Inc.\n\
Packit 6c4009
This is free software; see the source for copying conditions.  There is NO\n\
Packit 6c4009
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
Packit 6c4009
"),
Packit 6c4009
	   "2018");
Packit 6c4009
  fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Note that we must not use `dlopen' etc.  The shobj object must not
Packit 6c4009
   be loaded for use.  */
Packit 6c4009
static struct shobj *
Packit 6c4009
load_shobj (const char *name)
Packit 6c4009
{
Packit 6c4009
  struct link_map *map = NULL;
Packit 6c4009
  struct shobj *result;
Packit 6c4009
  ElfW(Addr) mapstart = ~((ElfW(Addr)) 0);
Packit 6c4009
  ElfW(Addr) mapend = 0;
Packit 6c4009
  const ElfW(Phdr) *ph;
Packit 6c4009
  size_t textsize;
Packit 6c4009
  ElfW(Ehdr) *ehdr;
Packit 6c4009
  int fd;
Packit 6c4009
  ElfW(Shdr) *shdr;
Packit 6c4009
  size_t pagesize = getpagesize ();
Packit 6c4009
Packit 6c4009
  /* Since we use dlopen() we must be prepared to work around the sometimes
Packit 6c4009
     strange lookup rules for the shared objects.  If we have a file foo.so
Packit 6c4009
     in the current directory and the user specfies foo.so on the command
Packit 6c4009
     line (without specifying a directory) we should load the file in the
Packit 6c4009
     current directory even if a normal dlopen() call would read the other
Packit 6c4009
     file.  We do this by adding a directory portion to the name.  */
Packit 6c4009
  if (strchr (name, '/') == NULL)
Packit 6c4009
    {
Packit 6c4009
      char *load_name = (char *) alloca (strlen (name) + 3);
Packit 6c4009
      stpcpy (stpcpy (load_name, "./"), name);
Packit 6c4009
Packit 6c4009
      map = (struct link_map *) dlopen (load_name, RTLD_LAZY | __RTLD_SPROF);
Packit 6c4009
    }
Packit 6c4009
  if (map == NULL)
Packit 6c4009
    {
Packit 6c4009
      map = (struct link_map *) dlopen (name, RTLD_LAZY | __RTLD_SPROF);
Packit 6c4009
      if (map == NULL)
Packit 6c4009
	{
Packit 6c4009
	  error (0, errno, _("failed to load shared object `%s'"), name);
Packit 6c4009
	  return NULL;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Prepare the result.  */
Packit 6c4009
  result = (struct shobj *) calloc (1, sizeof (struct shobj));
Packit 6c4009
  if (result == NULL)
Packit 6c4009
    {
Packit 6c4009
      error (0, errno, _("cannot create internal descriptor"));
Packit 6c4009
      dlclose (map);
Packit 6c4009
      return NULL;
Packit 6c4009
    }
Packit 6c4009
  result->name = name;
Packit 6c4009
  result->map = map;
Packit 6c4009
Packit 6c4009
  /* Compute the size of the sections which contain program code.
Packit 6c4009
     This must match the code in dl-profile.c (_dl_start_profile).  */
Packit 6c4009
  for (ph = map->l_phdr; ph < &map->l_phdr[map->l_phnum]; ++ph)
Packit 6c4009
    if (ph->p_type == PT_LOAD && (ph->p_flags & PF_X))
Packit 6c4009
      {
Packit 6c4009
	ElfW(Addr) start = (ph->p_vaddr & ~(pagesize - 1));
Packit 6c4009
	ElfW(Addr) end = ((ph->p_vaddr + ph->p_memsz + pagesize - 1)
Packit 6c4009
			  & ~(pagesize - 1));
Packit 6c4009
Packit 6c4009
	if (start < mapstart)
Packit 6c4009
	  mapstart = start;
Packit 6c4009
	if (end > mapend)
Packit 6c4009
	  mapend = end;
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
  result->lowpc = ROUNDDOWN ((uintptr_t) (mapstart + map->l_addr),
Packit 6c4009
			     HISTFRACTION * sizeof (HISTCOUNTER));
Packit 6c4009
  result->highpc = ROUNDUP ((uintptr_t) (mapend + map->l_addr),
Packit 6c4009
			    HISTFRACTION * sizeof (HISTCOUNTER));
Packit 6c4009
  if (do_test)
Packit 6c4009
    printf ("load addr: %0#*" PRIxPTR "\n"
Packit 6c4009
	    "lower bound PC: %0#*" PRIxPTR "\n"
Packit 6c4009
	    "upper bound PC: %0#*" PRIxPTR "\n",
Packit 6c4009
	    __ELF_NATIVE_CLASS == 32 ? 10 : 18, map->l_addr,
Packit 6c4009
	    __ELF_NATIVE_CLASS == 32 ? 10 : 18, result->lowpc,
Packit 6c4009
	    __ELF_NATIVE_CLASS == 32 ? 10 : 18, result->highpc);
Packit 6c4009
Packit 6c4009
  textsize = result->highpc - result->lowpc;
Packit 6c4009
  result->kcountsize = textsize / HISTFRACTION;
Packit 6c4009
  result->hashfraction = HASHFRACTION;
Packit 6c4009
  if (do_test)
Packit 6c4009
    printf ("hashfraction = %d\ndivider = %Zu\n",
Packit 6c4009
	    result->hashfraction,
Packit 6c4009
	    result->hashfraction * sizeof (struct here_fromstruct));
Packit 6c4009
  result->tossize = textsize / HASHFRACTION;
Packit 6c4009
  result->fromlimit = textsize * ARCDENSITY / 100;
Packit 6c4009
  if (result->fromlimit < MINARCS)
Packit 6c4009
    result->fromlimit = MINARCS;
Packit 6c4009
  if (result->fromlimit > MAXARCS)
Packit 6c4009
    result->fromlimit = MAXARCS;
Packit 6c4009
  result->fromssize = result->fromlimit * sizeof (struct here_fromstruct);
Packit 6c4009
Packit 6c4009
  result->expected_size = (sizeof (struct gmon_hdr)
Packit 6c4009
			   + 4 + sizeof (struct gmon_hist_hdr)
Packit 6c4009
			   + result->kcountsize
Packit 6c4009
			   + 4 + 4
Packit 6c4009
			   + (result->fromssize
Packit 6c4009
			      * sizeof (struct here_cg_arc_record)));
Packit 6c4009
Packit 6c4009
  if (do_test)
Packit 6c4009
    printf ("expected size: %Zd\n", result->expected_size);
Packit 6c4009
Packit 6c4009
#define SCALE_1_TO_1	0x10000L
Packit 6c4009
Packit 6c4009
  if (result->kcountsize < result->highpc - result->lowpc)
Packit 6c4009
    {
Packit 6c4009
      size_t range = result->highpc - result->lowpc;
Packit 6c4009
      size_t quot = range / result->kcountsize;
Packit 6c4009
Packit 6c4009
      if (quot >= SCALE_1_TO_1)
Packit 6c4009
	result->s_scale = 1;
Packit 6c4009
      else if (quot >= SCALE_1_TO_1 / 256)
Packit 6c4009
	result->s_scale = SCALE_1_TO_1 / quot;
Packit 6c4009
      else if (range > ULONG_MAX / 256)
Packit 6c4009
	result->s_scale = ((SCALE_1_TO_1 * 256)
Packit 6c4009
			   / (range / (result->kcountsize / 256)));
Packit 6c4009
      else
Packit 6c4009
	result->s_scale = ((SCALE_1_TO_1 * 256)
Packit 6c4009
			   / ((range * 256) / result->kcountsize));
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    result->s_scale = SCALE_1_TO_1;
Packit 6c4009
Packit 6c4009
  if (do_test)
Packit 6c4009
    printf ("s_scale: %d\n", result->s_scale);
Packit 6c4009
Packit 6c4009
  /* Determine the dynamic string table.  */
Packit 6c4009
  if (map->l_info[DT_STRTAB] == NULL)
Packit 6c4009
    result->dynstrtab = NULL;
Packit 6c4009
  else
Packit 6c4009
    result->dynstrtab = (const char *) D_PTR (map, l_info[DT_STRTAB]);
Packit 6c4009
  if (do_test)
Packit 6c4009
    printf ("string table: %p\n", result->dynstrtab);
Packit 6c4009
Packit 6c4009
  /* Determine the soname.  */
Packit 6c4009
  if (map->l_info[DT_SONAME] == NULL)
Packit 6c4009
    result->soname = NULL;
Packit 6c4009
  else
Packit 6c4009
    result->soname = result->dynstrtab + map->l_info[DT_SONAME]->d_un.d_val;
Packit 6c4009
  if (do_test && result->soname != NULL)
Packit 6c4009
    printf ("soname: %s\n", result->soname);
Packit 6c4009
Packit 6c4009
  /* Now we have to load the symbol table.
Packit 6c4009
Packit 6c4009
     First load the section header table.  */
Packit 6c4009
  ehdr = (ElfW(Ehdr) *) map->l_map_start;
Packit 6c4009
Packit 6c4009
  /* Make sure we are on the right party.  */
Packit 6c4009
  if (ehdr->e_shentsize != sizeof (ElfW(Shdr)))
Packit 6c4009
    abort ();
Packit 6c4009
Packit 6c4009
  /* And we need the shared object file descriptor again.  */
Packit 6c4009
  fd = open (map->l_name, O_RDONLY);
Packit 6c4009
  if (fd == -1)
Packit 6c4009
    /* Dooh, this really shouldn't happen.  We know the file is available.  */
Packit 6c4009
    error (EXIT_FAILURE, errno, _("Reopening shared object `%s' failed"),
Packit 6c4009
	   map->l_name);
Packit 6c4009
Packit 6c4009
  /* Map the section header.  */
Packit 6c4009
  size_t size = ehdr->e_shnum * sizeof (ElfW(Shdr));
Packit 6c4009
  shdr = (ElfW(Shdr) *) alloca (size);
Packit 6c4009
  if (pread (fd, shdr, size, ehdr->e_shoff) != size)
Packit 6c4009
    error (EXIT_FAILURE, errno, _("reading of section headers failed"));
Packit 6c4009
Packit 6c4009
  /* Get the section header string table.  */
Packit 6c4009
  char *shstrtab = (char *) alloca (shdr[ehdr->e_shstrndx].sh_size);
Packit 6c4009
  if (pread (fd, shstrtab, shdr[ehdr->e_shstrndx].sh_size,
Packit 6c4009
	     shdr[ehdr->e_shstrndx].sh_offset)
Packit 6c4009
      != shdr[ehdr->e_shstrndx].sh_size)
Packit 6c4009
    error (EXIT_FAILURE, errno,
Packit 6c4009
	   _("reading of section header string table failed"));
Packit 6c4009
Packit 6c4009
  /* Search for the ".symtab" section.  */
Packit 6c4009
  ElfW(Shdr) *symtab_entry = NULL;
Packit 6c4009
  ElfW(Shdr) *debuglink_entry = NULL;
Packit 6c4009
  for (int idx = 0; idx < ehdr->e_shnum; ++idx)
Packit 6c4009
    if (shdr[idx].sh_type == SHT_SYMTAB
Packit 6c4009
	&& strcmp (shstrtab + shdr[idx].sh_name, ".symtab") == 0)
Packit 6c4009
      {
Packit 6c4009
	symtab_entry = &shdr[idx];
Packit 6c4009
	break;
Packit 6c4009
      }
Packit 6c4009
    else if (shdr[idx].sh_type == SHT_PROGBITS
Packit 6c4009
	     && strcmp (shstrtab + shdr[idx].sh_name, ".gnu_debuglink") == 0)
Packit 6c4009
      debuglink_entry = &shdr[idx];
Packit 6c4009
Packit 6c4009
  /* Get the file name of the debuginfo file if necessary.  */
Packit 6c4009
  int symfd = fd;
Packit 6c4009
  if (symtab_entry == NULL && debuglink_entry != NULL)
Packit 6c4009
    {
Packit 6c4009
      size_t size = debuglink_entry->sh_size;
Packit 6c4009
      char *debuginfo_fname = (char *) alloca (size + 1);
Packit 6c4009
      debuginfo_fname[size] = '\0';
Packit 6c4009
      if (pread (fd, debuginfo_fname, size, debuglink_entry->sh_offset)
Packit 6c4009
	  != size)
Packit 6c4009
	{
Packit 6c4009
	  fprintf (stderr, _("*** Cannot read debuginfo file name: %m\n"));
Packit 6c4009
	  goto no_debuginfo;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      static const char procpath[] = "/proc/self/fd/%d";
Packit 6c4009
      char origprocname[sizeof (procpath) + sizeof (int) * 3];
Packit 6c4009
      snprintf (origprocname, sizeof (origprocname), procpath, fd);
Packit 6c4009
      char *origlink = (char *) alloca (PATH_MAX);
Packit 6c4009
      ssize_t n = readlink (origprocname, origlink, PATH_MAX - 1);
Packit 6c4009
      if (n == -1)
Packit 6c4009
	goto no_debuginfo;
Packit 6c4009
      origlink[n] = '\0';
Packit 6c4009
Packit 6c4009
      /* Try to find the actual file.  There are three places:
Packit 6c4009
	 1. the same directory the DSO is in
Packit 6c4009
	 2. in a subdir named .debug of the directory the DSO is in
Packit 6c4009
	 3. in /usr/lib/debug/PATH-OF-DSO
Packit 6c4009
      */
Packit 6c4009
      char *realname = canonicalize_file_name (origlink);
Packit 6c4009
      char *cp = NULL;
Packit 6c4009
      if (realname == NULL || (cp = strrchr (realname, '/')) == NULL)
Packit 6c4009
	error (EXIT_FAILURE, errno, _("cannot determine file name"));
Packit 6c4009
Packit 6c4009
      /* Leave the last slash in place.  */
Packit 6c4009
      *++cp = '\0';
Packit 6c4009
Packit 6c4009
      /* First add the debuginfo file name only.  */
Packit 6c4009
      static const char usrlibdebug[]= "/usr/lib/debug/";
Packit 6c4009
      char *workbuf = (char *) alloca (sizeof (usrlibdebug)
Packit 6c4009
				       + (cp - realname)
Packit 6c4009
				       + strlen (debuginfo_fname));
Packit 6c4009
      strcpy (stpcpy (workbuf, realname), debuginfo_fname);
Packit 6c4009
Packit 6c4009
      int fd2 = open (workbuf, O_RDONLY);
Packit 6c4009
      if (fd2 == -1)
Packit 6c4009
	{
Packit 6c4009
	  strcpy (stpcpy (stpcpy (workbuf, realname), ".debug/"),
Packit 6c4009
		  debuginfo_fname);
Packit 6c4009
	  fd2 = open (workbuf, O_RDONLY);
Packit 6c4009
	  if (fd2 == -1)
Packit 6c4009
	    {
Packit 6c4009
	      strcpy (stpcpy (stpcpy (workbuf, usrlibdebug), realname),
Packit 6c4009
		      debuginfo_fname);
Packit 6c4009
	      fd2 = open (workbuf, O_RDONLY);
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (fd2 != -1)
Packit 6c4009
	{
Packit 6c4009
	  ElfW(Ehdr) ehdr2;
Packit 6c4009
Packit 6c4009
	  /* Read the ELF header.  */
Packit 6c4009
	  if (pread (fd2, &ehdr2, sizeof (ehdr2), 0) != sizeof (ehdr2))
Packit 6c4009
	    error (EXIT_FAILURE, errno,
Packit 6c4009
		   _("reading of ELF header failed"));
Packit 6c4009
Packit 6c4009
	  /* Map the section header.  */
Packit 6c4009
	  size_t size = ehdr2.e_shnum * sizeof (ElfW(Shdr));
Packit 6c4009
	  ElfW(Shdr) *shdr2 = (ElfW(Shdr) *) alloca (size);
Packit 6c4009
	  if (pread (fd2, shdr2, size, ehdr2.e_shoff) != size)
Packit 6c4009
	    error (EXIT_FAILURE, errno,
Packit 6c4009
		   _("reading of section headers failed"));
Packit 6c4009
Packit 6c4009
	  /* Get the section header string table.  */
Packit 6c4009
	  shstrtab = (char *) alloca (shdr2[ehdr2.e_shstrndx].sh_size);
Packit 6c4009
	  if (pread (fd2, shstrtab, shdr2[ehdr2.e_shstrndx].sh_size,
Packit 6c4009
		     shdr2[ehdr2.e_shstrndx].sh_offset)
Packit 6c4009
	      != shdr2[ehdr2.e_shstrndx].sh_size)
Packit 6c4009
	    error (EXIT_FAILURE, errno,
Packit 6c4009
		   _("reading of section header string table failed"));
Packit 6c4009
Packit 6c4009
	  /* Search for the ".symtab" section.  */
Packit 6c4009
	  for (int idx = 0; idx < ehdr2.e_shnum; ++idx)
Packit 6c4009
	    if (shdr2[idx].sh_type == SHT_SYMTAB
Packit 6c4009
		&& strcmp (shstrtab + shdr2[idx].sh_name, ".symtab") == 0)
Packit 6c4009
	      {
Packit 6c4009
		symtab_entry = &shdr2[idx];
Packit 6c4009
		shdr = shdr2;
Packit 6c4009
		symfd = fd2;
Packit 6c4009
		break;
Packit 6c4009
	      }
Packit 6c4009
Packit 6c4009
	  if  (fd2 != symfd)
Packit 6c4009
	    close (fd2);
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
 no_debuginfo:
Packit 6c4009
  if (symtab_entry == NULL)
Packit 6c4009
    {
Packit 6c4009
      fprintf (stderr, _("\
Packit 6c4009
*** The file `%s' is stripped: no detailed analysis possible\n"),
Packit 6c4009
	      name);
Packit 6c4009
      result->symtab = NULL;
Packit 6c4009
      result->strtab = NULL;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      ElfW(Off) min_offset, max_offset;
Packit 6c4009
      ElfW(Shdr) *strtab_entry;
Packit 6c4009
Packit 6c4009
      strtab_entry = &shdr[symtab_entry->sh_link];
Packit 6c4009
Packit 6c4009
      /* Find the minimum and maximum offsets that include both the symbol
Packit 6c4009
	 table and the string table.  */
Packit 6c4009
      if (symtab_entry->sh_offset < strtab_entry->sh_offset)
Packit 6c4009
	{
Packit 6c4009
	  min_offset = symtab_entry->sh_offset & ~(pagesize - 1);
Packit 6c4009
	  max_offset = strtab_entry->sh_offset + strtab_entry->sh_size;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  min_offset = strtab_entry->sh_offset & ~(pagesize - 1);
Packit 6c4009
	  max_offset = symtab_entry->sh_offset + symtab_entry->sh_size;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      result->symbol_map = mmap (NULL, max_offset - min_offset,
Packit 6c4009
				 PROT_READ, MAP_SHARED|MAP_FILE, symfd,
Packit 6c4009
				 min_offset);
Packit 6c4009
      if (result->symbol_map == MAP_FAILED)
Packit 6c4009
	error (EXIT_FAILURE, errno, _("failed to load symbol data"));
Packit 6c4009
Packit 6c4009
      result->symtab
Packit 6c4009
	= (const ElfW(Sym) *) ((const char *) result->symbol_map
Packit 6c4009
			       + (symtab_entry->sh_offset - min_offset));
Packit 6c4009
      result->symtab_size = symtab_entry->sh_size;
Packit 6c4009
      result->strtab = ((const char *) result->symbol_map
Packit 6c4009
			+ (strtab_entry->sh_offset - min_offset));
Packit 6c4009
      result->symbol_mapsize = max_offset - min_offset;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Free the descriptor for the shared object.  */
Packit 6c4009
  close (fd);
Packit 6c4009
  if (symfd != fd)
Packit 6c4009
    close (symfd);
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
unload_shobj (struct shobj *shobj)
Packit 6c4009
{
Packit 6c4009
  munmap (shobj->symbol_map, shobj->symbol_mapsize);
Packit 6c4009
  dlclose (shobj->map);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static struct profdata *
Packit 6c4009
load_profdata (const char *name, struct shobj *shobj)
Packit 6c4009
{
Packit 6c4009
  struct profdata *result;
Packit 6c4009
  int fd;
Packit 6c4009
  struct stat64 st;
Packit 6c4009
  void *addr;
Packit 6c4009
  uint32_t *narcsp;
Packit 6c4009
  size_t fromlimit;
Packit 6c4009
  struct here_cg_arc_record *data;
Packit 6c4009
  struct here_fromstruct *froms;
Packit 6c4009
  uint16_t *tos;
Packit 6c4009
  size_t fromidx;
Packit 6c4009
  size_t idx;
Packit 6c4009
Packit 6c4009
  fd = open (name, O_RDONLY);
Packit 6c4009
  if (fd == -1)
Packit 6c4009
    {
Packit 6c4009
      char *ext_name;
Packit 6c4009
Packit 6c4009
      if (errno != ENOENT || strchr (name, '/') != NULL)
Packit 6c4009
	/* The file exists but we are not allowed to read it or the
Packit 6c4009
	   file does not exist and the name includes a path
Packit 6c4009
	   specification..  */
Packit 6c4009
	return NULL;
Packit 6c4009
Packit 6c4009
      /* A file with the given name does not exist in the current
Packit 6c4009
	 directory, try it in the default location where the profiling
Packit 6c4009
	 files are created.  */
Packit 6c4009
      ext_name = (char *) alloca (strlen (name) + sizeof "/var/tmp/");
Packit 6c4009
      stpcpy (stpcpy (ext_name, "/var/tmp/"), name);
Packit 6c4009
      name = ext_name;
Packit 6c4009
Packit 6c4009
      fd = open (ext_name, O_RDONLY);
Packit 6c4009
      if (fd == -1)
Packit 6c4009
	{
Packit 6c4009
	  /* Even this file does not exist.  */
Packit 6c4009
	  error (0, errno, _("cannot load profiling data"));
Packit 6c4009
	  return NULL;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* We have found the file, now make sure it is the right one for the
Packit 6c4009
     data file.  */
Packit 6c4009
  if (fstat64 (fd, &st) < 0)
Packit 6c4009
    {
Packit 6c4009
      error (0, errno, _("while stat'ing profiling data file"));
Packit 6c4009
      close (fd);
Packit 6c4009
      return NULL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if ((size_t) st.st_size != shobj->expected_size)
Packit 6c4009
    {
Packit 6c4009
      error (0, 0,
Packit 6c4009
	     _("profiling data file `%s' does not match shared object `%s'"),
Packit 6c4009
	     name, shobj->name);
Packit 6c4009
      close (fd);
Packit 6c4009
      return NULL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* The data file is most probably the right one for our shared
Packit 6c4009
     object.  Map it now.  */
Packit 6c4009
  addr = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED|MAP_FILE, fd, 0);
Packit 6c4009
  if (addr == MAP_FAILED)
Packit 6c4009
    {
Packit 6c4009
      error (0, errno, _("failed to mmap the profiling data file"));
Packit 6c4009
      close (fd);
Packit 6c4009
      return NULL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* We don't need the file desriptor anymore.  */
Packit 6c4009
  if (close (fd) < 0)
Packit 6c4009
    {
Packit 6c4009
      error (0, errno, _("error while closing the profiling data file"));
Packit 6c4009
      munmap (addr, st.st_size);
Packit 6c4009
      return NULL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Prepare the result.  */
Packit 6c4009
  result = (struct profdata *) calloc (1, sizeof (struct profdata));
Packit 6c4009
  if (result == NULL)
Packit 6c4009
    {
Packit 6c4009
      error (0, errno, _("cannot create internal descriptor"));
Packit 6c4009
      munmap (addr, st.st_size);
Packit 6c4009
      return NULL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Store the address and size so that we can later free the resources.  */
Packit 6c4009
  result->addr = addr;
Packit 6c4009
  result->size = st.st_size;
Packit 6c4009
Packit 6c4009
  /* Pointer to data after the header.  */
Packit 6c4009
  result->hist = (char *) ((struct gmon_hdr *) addr + 1);
Packit 6c4009
  result->hist_hdr = (struct real_gmon_hist_hdr *) ((char *) result->hist
Packit 6c4009
						    + sizeof (uint32_t));
Packit 6c4009
  result->kcount = (uint16_t *) ((char *) result->hist + sizeof (uint32_t)
Packit 6c4009
				 + sizeof (struct real_gmon_hist_hdr));
Packit 6c4009
Packit 6c4009
  /* Compute pointer to array of the arc information.  */
Packit 6c4009
  narcsp = (uint32_t *) ((char *) result->kcount + shobj->kcountsize
Packit 6c4009
			 + sizeof (uint32_t));
Packit 6c4009
  result->narcs = *narcsp;
Packit 6c4009
  result->data = (struct here_cg_arc_record *) ((char *) narcsp
Packit 6c4009
						+ sizeof (uint32_t));
Packit 6c4009
Packit 6c4009
  /* Create the gmon_hdr we expect or write.  */
Packit 6c4009
  struct real_gmon_hdr
Packit 6c4009
  {
Packit 6c4009
    char cookie[4];
Packit 6c4009
    int32_t version;
Packit 6c4009
    char spare[3 * 4];
Packit 6c4009
  } gmon_hdr;
Packit 6c4009
  if (sizeof (gmon_hdr) != sizeof (struct gmon_hdr)
Packit 6c4009
      || (offsetof (struct real_gmon_hdr, cookie)
Packit 6c4009
	  != offsetof (struct gmon_hdr, cookie))
Packit 6c4009
      || (offsetof (struct real_gmon_hdr, version)
Packit 6c4009
	  != offsetof (struct gmon_hdr, version)))
Packit 6c4009
    abort ();
Packit 6c4009
Packit 6c4009
  memcpy (&gmon_hdr.cookie[0], GMON_MAGIC, sizeof (gmon_hdr.cookie));
Packit 6c4009
  gmon_hdr.version = GMON_SHOBJ_VERSION;
Packit 6c4009
  memset (gmon_hdr.spare, '\0', sizeof (gmon_hdr.spare));
Packit 6c4009
Packit 6c4009
  /* Create the hist_hdr we expect or write.  */
Packit 6c4009
  struct real_gmon_hist_hdr hist_hdr;
Packit 6c4009
  if (sizeof (hist_hdr) != sizeof (struct gmon_hist_hdr)
Packit 6c4009
      || (offsetof (struct real_gmon_hist_hdr, low_pc)
Packit 6c4009
	  != offsetof (struct gmon_hist_hdr, low_pc))
Packit 6c4009
      || (offsetof (struct real_gmon_hist_hdr, high_pc)
Packit 6c4009
	  != offsetof (struct gmon_hist_hdr, high_pc))
Packit 6c4009
      || (offsetof (struct real_gmon_hist_hdr, hist_size)
Packit 6c4009
	  != offsetof (struct gmon_hist_hdr, hist_size))
Packit 6c4009
      || (offsetof (struct real_gmon_hist_hdr, prof_rate)
Packit 6c4009
	  != offsetof (struct gmon_hist_hdr, prof_rate))
Packit 6c4009
      || (offsetof (struct real_gmon_hist_hdr, dimen)
Packit 6c4009
	  != offsetof (struct gmon_hist_hdr, dimen))
Packit 6c4009
      || (offsetof (struct real_gmon_hist_hdr, dimen_abbrev)
Packit 6c4009
	  != offsetof (struct gmon_hist_hdr, dimen_abbrev)))
Packit 6c4009
    abort ();
Packit 6c4009
Packit 6c4009
  hist_hdr.low_pc = (char *) shobj->lowpc - shobj->map->l_addr;
Packit 6c4009
  hist_hdr.high_pc = (char *) shobj->highpc - shobj->map->l_addr;
Packit 6c4009
  if (do_test)
Packit 6c4009
    printf ("low_pc = %p\nhigh_pc = %p\n", hist_hdr.low_pc, hist_hdr.high_pc);
Packit 6c4009
  hist_hdr.hist_size = shobj->kcountsize / sizeof (HISTCOUNTER);
Packit 6c4009
  hist_hdr.prof_rate = __profile_frequency ();
Packit 6c4009
  strncpy (hist_hdr.dimen, "seconds", sizeof (hist_hdr.dimen));
Packit 6c4009
  hist_hdr.dimen_abbrev = 's';
Packit 6c4009
Packit 6c4009
  /* Test whether the header of the profiling data is ok.  */
Packit 6c4009
  if (memcmp (addr, &gmon_hdr, sizeof (struct gmon_hdr)) != 0
Packit 6c4009
      || *(uint32_t *) result->hist != GMON_TAG_TIME_HIST
Packit 6c4009
      || memcmp (result->hist_hdr, &hist_hdr,
Packit 6c4009
		 sizeof (struct gmon_hist_hdr)) != 0
Packit 6c4009
      || narcsp[-1] != GMON_TAG_CG_ARC)
Packit 6c4009
    {
Packit 6c4009
      error (0, 0, _("`%s' is no correct profile data file for `%s'"),
Packit 6c4009
	     name, shobj->name);
Packit 6c4009
      if (do_test)
Packit 6c4009
	{
Packit 6c4009
	  if (memcmp (addr, &gmon_hdr, sizeof (struct gmon_hdr)) != 0)
Packit 6c4009
	    puts ("gmon_hdr differs");
Packit 6c4009
	  if (*(uint32_t *) result->hist != GMON_TAG_TIME_HIST)
Packit 6c4009
	    puts ("result->hist differs");
Packit 6c4009
	  if (memcmp (result->hist_hdr, &hist_hdr,
Packit 6c4009
		      sizeof (struct gmon_hist_hdr)) != 0)
Packit 6c4009
	    puts ("hist_hdr differs");
Packit 6c4009
	  if (narcsp[-1] != GMON_TAG_CG_ARC)
Packit 6c4009
	    puts ("narcsp[-1] differs");
Packit 6c4009
	}
Packit 6c4009
      free (result);
Packit 6c4009
      munmap (addr, st.st_size);
Packit 6c4009
      return NULL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* We are pretty sure now that this is a correct input file.  Set up
Packit 6c4009
     the remaining information in the result structure and return.  */
Packit 6c4009
  result->tos = (uint16_t *) calloc (shobj->tossize + shobj->fromssize, 1);
Packit 6c4009
  if (result->tos == NULL)
Packit 6c4009
    {
Packit 6c4009
      error (0, errno, _("cannot create internal descriptor"));
Packit 6c4009
      munmap (addr, st.st_size);
Packit 6c4009
      free (result);
Packit 6c4009
      return NULL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  result->froms = (struct here_fromstruct *) ((char *) result->tos
Packit 6c4009
					      + shobj->tossize);
Packit 6c4009
  fromidx = 0;
Packit 6c4009
Packit 6c4009
  /* Now we have to process all the arc count entries.  */
Packit 6c4009
  fromlimit = shobj->fromlimit;
Packit 6c4009
  data = result->data;
Packit 6c4009
  froms = result->froms;
Packit 6c4009
  tos = result->tos;
Packit 6c4009
  for (idx = 0; idx < MIN (*narcsp, fromlimit); ++idx)
Packit 6c4009
    {
Packit 6c4009
      size_t to_index;
Packit 6c4009
      size_t newfromidx;
Packit 6c4009
      to_index = (data[idx].self_pc / (shobj->hashfraction * sizeof (*tos)));
Packit 6c4009
      newfromidx = fromidx++;
Packit 6c4009
      froms[newfromidx].here = &data[idx];
Packit 6c4009
      froms[newfromidx].link = tos[to_index];
Packit 6c4009
      tos[to_index] = newfromidx;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
unload_profdata (struct profdata *profdata)
Packit 6c4009
{
Packit 6c4009
  free (profdata->tos);
Packit 6c4009
  munmap (profdata->addr, profdata->size);
Packit 6c4009
  free (profdata);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
count_total_ticks (struct shobj *shobj, struct profdata *profdata)
Packit 6c4009
{
Packit 6c4009
  volatile uint16_t *kcount = profdata->kcount;
Packit 6c4009
  size_t maxkidx = shobj->kcountsize;
Packit 6c4009
  size_t factor = 2 * (65536 / shobj->s_scale);
Packit 6c4009
  size_t kidx = 0;
Packit 6c4009
  size_t sidx = 0;
Packit 6c4009
Packit 6c4009
  while (sidx < symidx)
Packit 6c4009
    {
Packit 6c4009
      uintptr_t start = sortsym[sidx]->addr;
Packit 6c4009
      uintptr_t end = start + sortsym[sidx]->size;
Packit 6c4009
Packit 6c4009
      while (kidx < maxkidx && factor * kidx < start)
Packit 6c4009
	++kidx;
Packit 6c4009
      if (kidx == maxkidx)
Packit 6c4009
	break;
Packit 6c4009
Packit 6c4009
      while (kidx < maxkidx && factor * kidx < end)
Packit 6c4009
	sortsym[sidx]->ticks += kcount[kidx++];
Packit 6c4009
      if (kidx == maxkidx)
Packit 6c4009
	break;
Packit 6c4009
Packit 6c4009
      total_ticks += sortsym[sidx++]->ticks;
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static size_t
Packit 6c4009
find_symbol (uintptr_t addr)
Packit 6c4009
{
Packit 6c4009
  size_t sidx = 0;
Packit 6c4009
Packit 6c4009
  while (sidx < symidx)
Packit 6c4009
    {
Packit 6c4009
      uintptr_t start = sortsym[sidx]->addr;
Packit 6c4009
      uintptr_t end = start + sortsym[sidx]->size;
Packit 6c4009
Packit 6c4009
      if (addr >= start && addr < end)
Packit 6c4009
	return sidx;
Packit 6c4009
Packit 6c4009
      if (addr < start)
Packit 6c4009
	break;
Packit 6c4009
Packit 6c4009
      ++sidx;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return (size_t) -1l;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
count_calls (struct shobj *shobj, struct profdata *profdata)
Packit 6c4009
{
Packit 6c4009
  struct here_cg_arc_record *data = profdata->data;
Packit 6c4009
  uint32_t narcs = profdata->narcs;
Packit 6c4009
  uint32_t cnt;
Packit 6c4009
Packit 6c4009
  for (cnt = 0; cnt < narcs; ++cnt)
Packit 6c4009
    {
Packit 6c4009
      uintptr_t here = data[cnt].self_pc;
Packit 6c4009
      size_t symbol_idx;
Packit 6c4009
Packit 6c4009
      /* Find the symbol for this address.  */
Packit 6c4009
      symbol_idx = find_symbol (here);
Packit 6c4009
      if (symbol_idx != (size_t) -1l)
Packit 6c4009
	sortsym[symbol_idx]->calls += data[cnt].count;
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
symorder (const void *o1, const void *o2)
Packit 6c4009
{
Packit 6c4009
  const struct known_symbol *p1 = (const struct known_symbol *) o1;
Packit 6c4009
  const struct known_symbol *p2 = (const struct known_symbol *) o2;
Packit 6c4009
Packit 6c4009
  return p1->addr - p2->addr;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
printsym (const void *node, VISIT value, int level)
Packit 6c4009
{
Packit 6c4009
  if (value == leaf || value == postorder)
Packit 6c4009
    sortsym[symidx++] = *(struct known_symbol **) node;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
read_symbols (struct shobj *shobj)
Packit 6c4009
{
Packit 6c4009
  int n = 0;
Packit 6c4009
Packit 6c4009
  /* Initialize the obstacks.  */
Packit 6c4009
#define obstack_chunk_alloc malloc
Packit 6c4009
#define obstack_chunk_free free
Packit 6c4009
  obstack_init (&shobj->ob_str);
Packit 6c4009
  obstack_init (&shobj->ob_sym);
Packit 6c4009
  obstack_init (&ob_list);
Packit 6c4009
Packit 6c4009
  /* Process the symbols.  */
Packit 6c4009
  if (shobj->symtab != NULL)
Packit 6c4009
    {
Packit 6c4009
      const ElfW(Sym) *sym = shobj->symtab;
Packit 6c4009
      const ElfW(Sym) *sym_end
Packit 6c4009
	= (const ElfW(Sym) *) ((const char *) sym + shobj->symtab_size);
Packit 6c4009
      for (; sym < sym_end; sym++)
Packit 6c4009
	if ((ELFW(ST_TYPE) (sym->st_info) == STT_FUNC
Packit 6c4009
	     || ELFW(ST_TYPE) (sym->st_info) == STT_NOTYPE)
Packit 6c4009
	    && sym->st_size != 0)
Packit 6c4009
	  {
Packit 6c4009
	    struct known_symbol **existp;
Packit 6c4009
	    struct known_symbol *newsym
Packit 6c4009
	      = (struct known_symbol *) obstack_alloc (&shobj->ob_sym,
Packit 6c4009
						       sizeof (*newsym));
Packit 6c4009
	    if (newsym == NULL)
Packit 6c4009
	      error (EXIT_FAILURE, errno, _("cannot allocate symbol data"));
Packit 6c4009
Packit 6c4009
	    newsym->name = &shobj->strtab[sym->st_name];
Packit 6c4009
	    newsym->addr = sym->st_value;
Packit 6c4009
	    newsym->size = sym->st_size;
Packit 6c4009
	    newsym->weak = ELFW(ST_BIND) (sym->st_info) == STB_WEAK;
Packit 6c4009
	    newsym->hidden = (ELFW(ST_VISIBILITY) (sym->st_other)
Packit 6c4009
			      != STV_DEFAULT);
Packit 6c4009
	    newsym->ticks = 0;
Packit 6c4009
	    newsym->calls = 0;
Packit 6c4009
Packit 6c4009
	    existp = tfind (newsym, &symroot, symorder);
Packit 6c4009
	    if (existp == NULL)
Packit 6c4009
	      {
Packit 6c4009
		/* New function.  */
Packit 6c4009
		tsearch (newsym, &symroot, symorder);
Packit 6c4009
		++n;
Packit 6c4009
	      }
Packit 6c4009
	    else
Packit 6c4009
	      {
Packit 6c4009
		/* The function is already defined.  See whether we have
Packit 6c4009
		   a better name here.  */
Packit 6c4009
		if (((*existp)->hidden && !newsym->hidden)
Packit 6c4009
		    || ((*existp)->name[0] == '_' && newsym->name[0] != '_')
Packit 6c4009
		    || ((*existp)->name[0] != '_' && newsym->name[0] != '_'
Packit 6c4009
			&& ((*existp)->weak && !newsym->weak)))
Packit 6c4009
		  *existp = newsym;
Packit 6c4009
		else
Packit 6c4009
		  /* We don't need the allocated memory.  */
Packit 6c4009
		  obstack_free (&shobj->ob_sym, newsym);
Packit 6c4009
	      }
Packit 6c4009
	  }
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      /* Blarg, the binary is stripped.  We have to rely on the
Packit 6c4009
	 information contained in the dynamic section of the object.  */
Packit 6c4009
      const ElfW(Sym) *symtab = (ElfW(Sym) *) D_PTR (shobj->map,
Packit 6c4009
						     l_info[DT_SYMTAB]);
Packit 6c4009
      const char *strtab = (const char *) D_PTR (shobj->map,
Packit 6c4009
						 l_info[DT_STRTAB]);
Packit 6c4009
Packit 6c4009
      /* We assume that the string table follows the symbol table,
Packit 6c4009
	 because there is no way in ELF to know the size of the
Packit 6c4009
	 dynamic symbol table without looking at the section headers.  */
Packit 6c4009
      while ((void *) symtab < (void *) strtab)
Packit 6c4009
	{
Packit 6c4009
	  if ((ELFW(ST_TYPE)(symtab->st_info) == STT_FUNC
Packit 6c4009
	       || ELFW(ST_TYPE)(symtab->st_info) == STT_NOTYPE)
Packit 6c4009
	      && symtab->st_size != 0)
Packit 6c4009
	    {
Packit 6c4009
	      struct known_symbol *newsym;
Packit 6c4009
	      struct known_symbol **existp;
Packit 6c4009
Packit 6c4009
	      newsym =
Packit 6c4009
		(struct known_symbol *) obstack_alloc (&shobj->ob_sym,
Packit 6c4009
						       sizeof (*newsym));
Packit 6c4009
	      if (newsym == NULL)
Packit 6c4009
		error (EXIT_FAILURE, errno, _("cannot allocate symbol data"));
Packit 6c4009
Packit 6c4009
	      newsym->name = &strtab[symtab->st_name];
Packit 6c4009
	      newsym->addr = symtab->st_value;
Packit 6c4009
	      newsym->size = symtab->st_size;
Packit 6c4009
	      newsym->weak = ELFW(ST_BIND) (symtab->st_info) == STB_WEAK;
Packit 6c4009
	      newsym->hidden = (ELFW(ST_VISIBILITY) (symtab->st_other)
Packit 6c4009
				!= STV_DEFAULT);
Packit 6c4009
	      newsym->ticks = 0;
Packit 6c4009
	      newsym->froms = NULL;
Packit 6c4009
	      newsym->tos = NULL;
Packit 6c4009
Packit 6c4009
	      existp = tfind (newsym, &symroot, symorder);
Packit 6c4009
	      if (existp == NULL)
Packit 6c4009
		{
Packit 6c4009
		  /* New function.  */
Packit 6c4009
		  tsearch (newsym, &symroot, symorder);
Packit 6c4009
		  ++n;
Packit 6c4009
		}
Packit 6c4009
	      else
Packit 6c4009
		{
Packit 6c4009
		  /* The function is already defined.  See whether we have
Packit 6c4009
		     a better name here.  */
Packit 6c4009
		  if (((*existp)->hidden && !newsym->hidden)
Packit 6c4009
		      || ((*existp)->name[0] == '_' && newsym->name[0] != '_')
Packit 6c4009
		      || ((*existp)->name[0] != '_' && newsym->name[0] != '_'
Packit 6c4009
			  && ((*existp)->weak && !newsym->weak)))
Packit 6c4009
		    *existp = newsym;
Packit 6c4009
		  else
Packit 6c4009
		    /* We don't need the allocated memory.  */
Packit 6c4009
		    obstack_free (&shobj->ob_sym, newsym);
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  ++symtab;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  sortsym = malloc (n * sizeof (struct known_symbol *));
Packit 6c4009
  if (sortsym == NULL)
Packit 6c4009
    abort ();
Packit 6c4009
Packit 6c4009
  twalk (symroot, printsym);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
add_arcs (struct profdata *profdata)
Packit 6c4009
{
Packit 6c4009
  uint32_t narcs = profdata->narcs;
Packit 6c4009
  struct here_cg_arc_record *data = profdata->data;
Packit 6c4009
  uint32_t cnt;
Packit 6c4009
Packit 6c4009
  for (cnt = 0; cnt < narcs; ++cnt)
Packit 6c4009
    {
Packit 6c4009
      /* First add the incoming arc.  */
Packit 6c4009
      size_t sym_idx = find_symbol (data[cnt].self_pc);
Packit 6c4009
Packit 6c4009
      if (sym_idx != (size_t) -1l)
Packit 6c4009
	{
Packit 6c4009
	  struct known_symbol *sym = sortsym[sym_idx];
Packit 6c4009
	  struct arc_list *runp = sym->froms;
Packit 6c4009
Packit 6c4009
	  while (runp != NULL
Packit 6c4009
		 && ((data[cnt].from_pc == 0 && runp->idx != (size_t) -1l)
Packit 6c4009
		     || (data[cnt].from_pc != 0
Packit 6c4009
			 && (runp->idx == (size_t) -1l
Packit 6c4009
			     || data[cnt].from_pc < sortsym[runp->idx]->addr
Packit 6c4009
			     || (data[cnt].from_pc
Packit 6c4009
				 >= (sortsym[runp->idx]->addr
Packit 6c4009
				     + sortsym[runp->idx]->size))))))
Packit 6c4009
	    runp = runp->next;
Packit 6c4009
Packit 6c4009
	  if (runp == NULL)
Packit 6c4009
	    {
Packit 6c4009
	      /* We need a new entry.  */
Packit 6c4009
	      struct arc_list *newp = (struct arc_list *)
Packit 6c4009
		obstack_alloc (&ob_list, sizeof (struct arc_list));
Packit 6c4009
Packit 6c4009
	      if (data[cnt].from_pc == 0)
Packit 6c4009
		newp->idx = (size_t) -1l;
Packit 6c4009
	      else
Packit 6c4009
		newp->idx = find_symbol (data[cnt].from_pc);
Packit 6c4009
	      newp->count = data[cnt].count;
Packit 6c4009
	      newp->next = sym->froms;
Packit 6c4009
	      sym->froms = newp;
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    /* Increment the counter for the found entry.  */
Packit 6c4009
	    runp->count += data[cnt].count;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Now add it to the appropriate outgoing list.  */
Packit 6c4009
      sym_idx = find_symbol (data[cnt].from_pc);
Packit 6c4009
      if (sym_idx != (size_t) -1l)
Packit 6c4009
	{
Packit 6c4009
	  struct known_symbol *sym = sortsym[sym_idx];
Packit 6c4009
	  struct arc_list *runp = sym->tos;
Packit 6c4009
Packit 6c4009
	  while (runp != NULL
Packit 6c4009
		 && (runp->idx == (size_t) -1l
Packit 6c4009
		     || data[cnt].self_pc < sortsym[runp->idx]->addr
Packit 6c4009
		     || data[cnt].self_pc >= (sortsym[runp->idx]->addr
Packit 6c4009
					      + sortsym[runp->idx]->size)))
Packit 6c4009
	    runp = runp->next;
Packit 6c4009
Packit 6c4009
	  if (runp == NULL)
Packit 6c4009
	    {
Packit 6c4009
	      /* We need a new entry.  */
Packit 6c4009
	      struct arc_list *newp = (struct arc_list *)
Packit 6c4009
		obstack_alloc (&ob_list, sizeof (struct arc_list));
Packit 6c4009
Packit 6c4009
	      newp->idx = find_symbol (data[cnt].self_pc);
Packit 6c4009
	      newp->count = data[cnt].count;
Packit 6c4009
	      newp->next = sym->tos;
Packit 6c4009
	      sym->tos = newp;
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    /* Increment the counter for the found entry.  */
Packit 6c4009
	    runp->count += data[cnt].count;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
countorder (const void *p1, const void *p2)
Packit 6c4009
{
Packit 6c4009
  struct known_symbol *s1 = (struct known_symbol *) p1;
Packit 6c4009
  struct known_symbol *s2 = (struct known_symbol *) p2;
Packit 6c4009
Packit 6c4009
  if (s1->ticks != s2->ticks)
Packit 6c4009
    return (int) (s2->ticks - s1->ticks);
Packit 6c4009
Packit 6c4009
  if (s1->calls != s2->calls)
Packit 6c4009
    return (int) (s2->calls - s1->calls);
Packit 6c4009
Packit 6c4009
  return strcmp (s1->name, s2->name);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static double tick_unit;
Packit 6c4009
static uintmax_t cumu_ticks;
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
printflat (const void *node, VISIT value, int level)
Packit 6c4009
{
Packit 6c4009
  if (value == leaf || value == postorder)
Packit 6c4009
    {
Packit 6c4009
      struct known_symbol *s = *(struct known_symbol **) node;
Packit 6c4009
Packit 6c4009
      cumu_ticks += s->ticks;
Packit 6c4009
Packit 6c4009
      printf ("%6.2f%10.2f%9.2f%9" PRIdMAX "%9.2f           %s\n",
Packit 6c4009
	      total_ticks ? (100.0 * s->ticks) / total_ticks : 0.0,
Packit 6c4009
	      tick_unit * cumu_ticks,
Packit 6c4009
	      tick_unit * s->ticks,
Packit 6c4009
	      s->calls,
Packit 6c4009
	      s->calls ? (s->ticks * 1000000) * tick_unit / s->calls : 0,
Packit 6c4009
	      /* FIXME: don't know about called functions.  */
Packit 6c4009
	      s->name);
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* ARGUSED */
Packit 6c4009
static void
Packit 6c4009
freenoop (void *p)
Packit 6c4009
{
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
generate_flat_profile (struct profdata *profdata)
Packit 6c4009
{
Packit 6c4009
  size_t n;
Packit 6c4009
  void *data = NULL;
Packit 6c4009
Packit 6c4009
  tick_unit = 1.0 / profdata->hist_hdr->prof_rate;
Packit 6c4009
Packit 6c4009
  printf ("Flat profile:\n\n"
Packit 6c4009
	  "Each sample counts as %g %s.\n",
Packit 6c4009
	  tick_unit, profdata->hist_hdr->dimen);
Packit 6c4009
  fputs ("  %   cumulative   self              self     total\n"
Packit 6c4009
	 " time   seconds   seconds    calls  us/call  us/call  name\n",
Packit 6c4009
	 stdout);
Packit 6c4009
Packit 6c4009
  for (n = 0; n < symidx; ++n)
Packit 6c4009
    if (sortsym[n]->calls != 0 || sortsym[n]->ticks != 0)
Packit 6c4009
      tsearch (sortsym[n], &data, countorder);
Packit 6c4009
Packit 6c4009
  twalk (data, printflat);
Packit 6c4009
Packit 6c4009
  tdestroy (data, freenoop);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
generate_call_graph (struct profdata *profdata)
Packit 6c4009
{
Packit 6c4009
  size_t cnt;
Packit 6c4009
Packit 6c4009
  puts ("\nindex % time    self  children    called     name\n");
Packit 6c4009
Packit 6c4009
  for (cnt = 0; cnt < symidx; ++cnt)
Packit 6c4009
    if (sortsym[cnt]->froms != NULL || sortsym[cnt]->tos != NULL)
Packit 6c4009
      {
Packit 6c4009
	struct arc_list *runp;
Packit 6c4009
	size_t n;
Packit 6c4009
Packit 6c4009
	/* First print the from-information.  */
Packit 6c4009
	runp = sortsym[cnt]->froms;
Packit 6c4009
	while (runp != NULL)
Packit 6c4009
	  {
Packit 6c4009
	    printf ("            %8.2f%8.2f%9" PRIdMAX "/%-9" PRIdMAX "   %s",
Packit 6c4009
		    (runp->idx != (size_t) -1l
Packit 6c4009
		     ? sortsym[runp->idx]->ticks * tick_unit : 0.0),
Packit 6c4009
		    0.0, /* FIXME: what's time for the children, recursive */
Packit 6c4009
		    runp->count, sortsym[cnt]->calls,
Packit 6c4009
		    (runp->idx != (size_t) -1l ?
Packit 6c4009
		     sortsym[runp->idx]->name : "<UNKNOWN>"));
Packit 6c4009
Packit 6c4009
	    if (runp->idx != (size_t) -1l)
Packit 6c4009
	      printf (" [%Zd]", runp->idx);
Packit 6c4009
	    putchar_unlocked ('\n');
Packit 6c4009
Packit 6c4009
	    runp = runp->next;
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
	/* Info about the function itself.  */
Packit 6c4009
	n = printf ("[%Zu]", cnt);
Packit 6c4009
	printf ("%*s%5.1f%8.2f%8.2f%9" PRIdMAX "         %s [%Zd]\n",
Packit 6c4009
		(int) (7 - n), " ",
Packit 6c4009
		total_ticks ? (100.0 * sortsym[cnt]->ticks) / total_ticks : 0,
Packit 6c4009
		sortsym[cnt]->ticks * tick_unit,
Packit 6c4009
		0.0, /* FIXME: what's time for the children, recursive */
Packit 6c4009
		sortsym[cnt]->calls,
Packit 6c4009
		sortsym[cnt]->name, cnt);
Packit 6c4009
Packit 6c4009
	/* Info about the functions this function calls.  */
Packit 6c4009
	runp = sortsym[cnt]->tos;
Packit 6c4009
	while (runp != NULL)
Packit 6c4009
	  {
Packit 6c4009
	    printf ("            %8.2f%8.2f%9" PRIdMAX "/",
Packit 6c4009
		    (runp->idx != (size_t) -1l
Packit 6c4009
		     ? sortsym[runp->idx]->ticks * tick_unit : 0.0),
Packit 6c4009
		    0.0, /* FIXME: what's time for the children, recursive */
Packit 6c4009
		    runp->count);
Packit 6c4009
Packit 6c4009
	    if (runp->idx != (size_t) -1l)
Packit 6c4009
	      printf ("%-9" PRIdMAX "   %s [%Zd]\n",
Packit 6c4009
		      sortsym[runp->idx]->calls,
Packit 6c4009
		      sortsym[runp->idx]->name,
Packit 6c4009
		      runp->idx);
Packit 6c4009
	    else
Packit 6c4009
	      fputs ("???         <UNKNOWN>\n\n", stdout);
Packit 6c4009
Packit 6c4009
	    runp = runp->next;
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
	fputs ("-----------------------------------------------\n", stdout);
Packit 6c4009
      }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
generate_call_pair_list (struct profdata *profdata)
Packit 6c4009
{
Packit 6c4009
  size_t cnt;
Packit 6c4009
Packit 6c4009
  for (cnt = 0; cnt < symidx; ++cnt)
Packit 6c4009
    if (sortsym[cnt]->froms != NULL || sortsym[cnt]->tos != NULL)
Packit 6c4009
      {
Packit 6c4009
	struct arc_list *runp;
Packit 6c4009
Packit 6c4009
	/* First print the incoming arcs.  */
Packit 6c4009
	runp = sortsym[cnt]->froms;
Packit 6c4009
	while (runp != NULL)
Packit 6c4009
	  {
Packit 6c4009
	    if (runp->idx == (size_t) -1l)
Packit 6c4009
	      printf ("\
Packit 6c4009
<UNKNOWN>                          %-34s %9" PRIdMAX "\n",
Packit 6c4009
		      sortsym[cnt]->name, runp->count);
Packit 6c4009
	    runp = runp->next;
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
	/* Next the outgoing arcs.  */
Packit 6c4009
	runp = sortsym[cnt]->tos;
Packit 6c4009
	while (runp != NULL)
Packit 6c4009
	  {
Packit 6c4009
	    printf ("%-34s %-34s %9" PRIdMAX "\n",
Packit 6c4009
		    sortsym[cnt]->name,
Packit 6c4009
		    (runp->idx != (size_t) -1l
Packit 6c4009
		     ? sortsym[runp->idx]->name : "<UNKNOWN>"),
Packit 6c4009
		    runp->count);
Packit 6c4009
	    runp = runp->next;
Packit 6c4009
	  }
Packit 6c4009
      }
Packit 6c4009
}