[v3] gprof: only process line numbers for intersection of vmas and histograms

Message ID CAMe9rOpriE0Bx1FPw5iq-pVcNJwpNsBm0nWiPCCO_KNYH1Nf9g@mail.gmail.com
State New
Headers
Series [v3] gprof: only process line numbers for intersection of vmas and histograms |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm fail Patch failed to apply
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 fail Patch failed to apply

Commit Message

H.J. Lu March 9, 2025, 3:40 p.m. UTC
  On Sat, Mar 8, 2025 at 7:17 PM Richard Allen <rsaxvc@gmail.com> wrote:
>
> > Here is the patch to delay loading the symbol table until its first use.
> > Does it work for you?
>
> I changed core_create_line_syms() to call get_symtab_direct()
> to fix runaway recursion and stack overflow.

Fixed it and core_create_syms_from.

> I ran gprof with small gmon file against the Linux kernel debug symbols:
>
> Before: 55 minutes.
> After: ~8 seconds.
>
> Also, I'm not sure if it is enough for core_create_line_syms() to check
> only the histograms for symbols. Do you think we'll also need to lookup
> symbols for basic-block and call-graph addresses?

How can we get these symbols?

>

Here is the v3 patch.


--
H.J.
  

Comments

Richard Allen March 10, 2025, 4:08 a.m. UTC | #1
> Here is the v3 patch.

I'm afraid loading the symbols on-demand may add a
dependency on the order of records in the gmon file, so that
[call-graph record, histogram record] may parse differently from
[histogram record, callgraph record].

>> Also, I'm not sure if it is enough for core_create_line_syms() to check
>> only the histograms for symbols. Do you think we'll also need to lookup
>> symbols for basic-block and call-graph addresses?
> How can we get these symbols?

Idea1:
1) For bb_read_rec and cg_read_rec, split the loading apart from the
processing, and perform only the loading first, similar to hist_read_rec.
2) lookup symbols for all three record types, according to the addresses
from each record type parsed.
3) perform processing for all three record types.

Idea2:
Build an expandable cache of address->symbol mappings.
On cache miss, perform BFD lookup and insert in cache.

-Richard
  

Patch

From d57c063eba40a3657f500da590bdbd6cbcc8ec6a Mon Sep 17 00:00:00 2001
From: Richard Allen <rsaxvc@gmail.com>
Date: Sat, 8 Mar 2025 16:44:18 +0800
Subject: [PATCH v3] gprof: only process line numbers for intersection of vmas
 and histograms

Some programs like RTOS firmware may have a large number of symbols.

By loading the histograms before loading symbols, we can look up
only the line numbers that were captured in the histogram file,
which reduces processing time for such a firmware from ~2 minutes
to ~2 seconds.

Add symbol table access function, get_symtab, get_symtab_direct and
set_symtab to delay loading the symbol table until its first use.

Signed-off-by: Richard Allen <rsaxvc@gmail.com>
Co-Authored-By: H.J. Lu <hjl.tools@gmail.com>
---
 gprof/aarch64.c      |   3 +-
 gprof/alpha.c        |   3 +-
 gprof/basic_blocks.c |  20 +++--
 gprof/call_graph.c   |  12 +--
 gprof/cg_arcs.c      |  37 ++++----
 gprof/cg_print.c     |  62 +++++++-------
 gprof/corefile.c     | 197 +++++++++++++++++++++++--------------------
 gprof/gmon_io.c      |   5 +-
 gprof/gprof.c        |  28 +++---
 gprof/gprof.h        |   2 +
 gprof/hist.c         |  31 ++++---
 gprof/i386.c         |   3 +-
 gprof/mips.c         |   3 +-
 gprof/sparc.c        |   3 +-
 gprof/sym_ids.c      |   5 +-
 gprof/symtab.c       |  34 +++++++-
 gprof/symtab.h       |   4 +-
 gprof/vax.c          |   3 +-
 18 files changed, 268 insertions(+), 187 deletions(-)

diff --git a/gprof/aarch64.c b/gprof/aarch64.c
index 3ab6067dbac..0365930961a 100644
--- a/gprof/aarch64.c
+++ b/gprof/aarch64.c
@@ -50,6 +50,7 @@  aarch64_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
   bfd_vma pc, dest_pc, offset;
   unsigned int insn;
   Sym *child;
+  Sym_Table *symtab = get_symtab ();
 
   DBG (CALLDEBUG, printf ("[find_call] %s: 0x%lx to 0x%lx\n",
 			  parent->name, (unsigned long) p_lowpc,
@@ -75,7 +76,7 @@  aarch64_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
 
 	  if (hist_check_address (dest_pc))
 	    {
-	      child = sym_lookup (&symtab, dest_pc);
+	      child = sym_lookup (symtab, dest_pc);
 
 	      if (child)
 		{
diff --git a/gprof/alpha.c b/gprof/alpha.c
index df714be6c81..b7740d8b586 100644
--- a/gprof/alpha.c
+++ b/gprof/alpha.c
@@ -95,6 +95,7 @@  alpha_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
   bfd_vma pc, dest_pc;
   unsigned int insn;
   Sym *child;
+  Sym_Table *symtab = get_symtab ();
 
   if (indirect_child.name == NULL)
     {
@@ -149,7 +150,7 @@  alpha_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
 			       ^ 0x100000) - 0x100000);
 	  if (hist_check_address (dest_pc))
 	    {
-	      child = sym_lookup (&symtab, dest_pc);
+	      child = sym_lookup (symtab, dest_pc);
               if (child)
                 {
 	          DBG (CALLDEBUG,
diff --git a/gprof/basic_blocks.c b/gprof/basic_blocks.c
index 4a4e491495f..d8659382d2c 100644
--- a/gprof/basic_blocks.c
+++ b/gprof/basic_blocks.c
@@ -122,6 +122,7 @@  bb_read_rec (FILE *ifp, const char *filename)
   unsigned int nblocks, b;
   bfd_vma addr, ncalls;
   Sym *sym;
+  Sym_Table *symtab;
 
   if (gmon_io_read_32 (ifp, &nblocks))
     {
@@ -130,6 +131,8 @@  bb_read_rec (FILE *ifp, const char *filename)
       done (1);
     }
 
+  symtab = get_symtab ();
+
   nblocks = bfd_get_32 (core_bfd, (bfd_byte *) & nblocks);
   if (gmon_file_version == 0)
     fskip_string (ifp);
@@ -163,7 +166,7 @@  bb_read_rec (FILE *ifp, const char *filename)
 	 profiling at the line-by-line level:  */
       if (line_granularity)
 	{
-	  sym = sym_lookup (&symtab, addr);
+	  sym = sym_lookup (symtab, addr);
 
 	  if (sym)
 	    {
@@ -210,9 +213,10 @@  bb_write_blocks (FILE *ofp, const char *filename)
   unsigned int nblocks = 0;
   Sym *sym;
   int i;
+  Sym_Table *symtab = get_symtab ();
 
   /* Count how many non-zero blocks with have:  */
-  for (sym = symtab.base; sym < symtab.limit; ++sym)
+  for (sym = symtab->base; sym < symtab->limit; ++sym)
     {
       for (i = 0; i < NBBS && sym->bb_addr[i]; i++)
 	;
@@ -228,7 +232,7 @@  bb_write_blocks (FILE *ofp, const char *filename)
     }
 
   /* Write counts:  */
-  for (sym = symtab.base; sym < symtab.limit; ++sym)
+  for (sym = symtab->base; sym < symtab->limit; ++sym)
     {
       for (i = 0; i < NBBS && sym->bb_addr[i]; i++)
 	{
@@ -252,6 +256,7 @@  print_exec_counts (void)
 {
   Sym **sorted_bbs, *sym;
   unsigned int i, j, len;
+  Sym_Table *symtab = get_symtab ();
 
   if (first_output)
     first_output = false;
@@ -259,10 +264,10 @@  print_exec_counts (void)
     printf ("\f\n");
 
   /* Sort basic-blocks according to function name and line number:  */
-  sorted_bbs = (Sym **) xmalloc (symtab.len * sizeof (sorted_bbs[0]));
+  sorted_bbs = (Sym **) xmalloc (symtab->len * sizeof (sorted_bbs[0]));
   len = 0;
 
-  for (sym = symtab.base; sym < symtab.limit; ++sym)
+  for (sym = symtab->base; sym < symtab->limit; ++sym)
     {
       /* Accept symbol if it's in the INCL_EXEC table
 	 or there is no INCL_EXEC table
@@ -461,10 +466,11 @@  print_annotated_source (void)
   Source_File *sf;
   int i, table_len;
   FILE *ofp;
+  Sym_Table *symtab = get_symtab ();
 
   /* Find maximum line number for each source file that user is
      interested in:  */
-  for (sym = symtab.base; sym < symtab.limit; ++sym)
+  for (sym = symtab->base; sym < symtab->limit; ++sym)
     {
       /* Accept symbol if it's file is known, its line number is
 	 bigger than anything we have seen for that file so far and
@@ -490,7 +496,7 @@  print_annotated_source (void)
     }
 
   /* Count executions per line:  */
-  for (sym = symtab.base; sym < symtab.limit; ++sym)
+  for (sym = symtab->base; sym < symtab->limit; ++sym)
     {
       if (sym->file && sym->file->num_lines
 	  && (sym_lookup (&syms[INCL_ANNO], sym->addr)
diff --git a/gprof/call_graph.c b/gprof/call_graph.c
index 259cbaaef1b..b76a8adde58 100644
--- a/gprof/call_graph.c
+++ b/gprof/call_graph.c
@@ -35,9 +35,10 @@  cg_tally (bfd_vma from_pc, bfd_vma self_pc, unsigned long count)
 {
   Sym *parent;
   Sym *child;
+  Sym_Table *symtab = get_symtab ();
 
-  parent = sym_lookup (&symtab, from_pc);
-  child = sym_lookup (&symtab, self_pc);
+  parent = sym_lookup (symtab, from_pc);
+  child = sym_lookup (symtab, self_pc);
 
   if (child == NULL || parent == NULL)
     return;
@@ -51,10 +52,10 @@  cg_tally (bfd_vma from_pc, bfd_vma self_pc, unsigned long count)
 
      For normal profiling, is_func will be set on all symbols, so this
      code will do nothing.  */
-  while (child >= symtab.base && ! child->is_func)
+  while (child >= symtab->base && ! child->is_func)
     --child;
 
-  if (child < symtab.base)
+  if (child < symtab->base)
     return;
 
   /* Keep arc if it is on INCL_ARCS table or if the INCL_ARCS table
@@ -108,8 +109,9 @@  cg_write_arcs (FILE *ofp, const char *filename)
 {
   Arc *arc;
   Sym *sym;
+  Sym_Table *symtab = get_symtab ();
 
-  for (sym = symtab.base; sym < symtab.limit; sym++)
+  for (sym = symtab->base; sym < symtab->limit; sym++)
     {
       for (arc = sym->cg.children; arc; arc = arc->next_child)
 	{
diff --git a/gprof/cg_arcs.c b/gprof/cg_arcs.c
index cfffb09ff87..a19686b2710 100644
--- a/gprof/cg_arcs.c
+++ b/gprof/cg_arcs.c
@@ -275,11 +275,12 @@  cycle_link (void)
   Sym *sym, *cyc, *member;
   Arc *arc;
   int num;
+  Sym_Table *symtab = get_symtab ();
 
   /* count the number of cycles, and initialize the cycle lists: */
 
   num_cycles = 0;
-  for (sym = symtab.base; sym < symtab.limit; ++sym)
+  for (sym = symtab->base; sym < symtab->limit; ++sym)
     {
       /* this is how you find unattached cycles: */
       if (sym->cg.cyc.head == sym && sym->cg.cyc.next)
@@ -300,7 +301,7 @@  cycle_link (void)
    */
   num = 0;
   cyc = cycle_header;
-  for (sym = symtab.base; sym < symtab.limit; ++sym)
+  for (sym = symtab->base; sym < symtab->limit; ++sym)
     {
       if (!(sym->cg.cyc.head == sym && sym->cg.cyc.next != 0))
 	{
@@ -440,9 +441,10 @@  propagate_flags (Sym **symbols)
 {
   int sym_index;
   Sym *old_head, *child;
+  Sym_Table *symtab = get_symtab ();
 
   old_head = 0;
-  for (sym_index = symtab.len - 1; sym_index >= 0; --sym_index)
+  for (sym_index = symtab->len - 1; sym_index >= 0; --sym_index)
     {
       child = symbols[sym_index];
       /*
@@ -597,12 +599,13 @@  cg_assemble (void)
   Sym *parent, **time_sorted_syms, **top_sorted_syms;
   unsigned int sym_index;
   Arc *arc;
+  Sym_Table *symtab = get_symtab ();
 
   /* Initialize various things:
        Zero out child times.
        Count self-recursive calls.
        Indicate that nothing is on cycles.  */
-  for (parent = symtab.base; parent < symtab.limit; parent++)
+  for (parent = symtab->base; parent < symtab->limit; parent++)
     {
       parent->cg.child_time = 0.0;
       arc = arc_lookup (parent, parent);
@@ -633,7 +636,7 @@  cg_assemble (void)
 
   /* Topologically order things.  If any node is unnumbered, number
      it and any of its descendents.  */
-  for (parent = symtab.base; parent < symtab.limit; parent++)
+  for (parent = symtab->base; parent < symtab->limit; parent++)
     {
       if (parent->cg.top_order == DFN_NAN)
 	cg_dfn (parent);
@@ -643,14 +646,14 @@  cg_assemble (void)
   cycle_link ();
 
   /* Sort the symbol table in reverse topological order.  */
-  top_sorted_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
-  for (sym_index = 0; sym_index < symtab.len; ++sym_index)
-    top_sorted_syms[sym_index] = &symtab.base[sym_index];
+  top_sorted_syms = (Sym **) xmalloc (symtab->len * sizeof (Sym *));
+  for (sym_index = 0; sym_index < symtab->len; ++sym_index)
+    top_sorted_syms[sym_index] = &symtab->base[sym_index];
 
-  qsort (top_sorted_syms, symtab.len, sizeof (Sym *), cmp_topo);
+  qsort (top_sorted_syms, symtab->len, sizeof (Sym *), cmp_topo);
   DBG (DFNDEBUG,
        printf ("[cg_assemble] topological sort listing\n");
-       for (sym_index = 0; sym_index < symtab.len; ++sym_index)
+       for (sym_index = 0; sym_index < symtab->len; ++sym_index)
 	 {
 	   printf ("[cg_assemble] ");
 	   printf ("%d:", top_sorted_syms[sym_index]->cg.top_order);
@@ -668,24 +671,24 @@  cg_assemble (void)
   /* Starting from the topological bottom, propagate children times
      up to parents.  */
   cycle_time ();
-  for (sym_index = 0; sym_index < symtab.len; ++sym_index)
+  for (sym_index = 0; sym_index < symtab->len; ++sym_index)
     propagate_time (top_sorted_syms[sym_index]);
 
   free (top_sorted_syms);
 
   /* Now, sort by CG.PROP.SELF + CG.PROP.CHILD.  Sorting both the regular
      function names and cycle headers.  */
-  time_sorted_syms = (Sym **) xmalloc ((symtab.len + num_cycles) * sizeof (Sym *));
-  for (sym_index = 0; sym_index < symtab.len; sym_index++)
-    time_sorted_syms[sym_index] = &symtab.base[sym_index];
+  time_sorted_syms = (Sym **) xmalloc ((symtab->len + num_cycles) * sizeof (Sym *));
+  for (sym_index = 0; sym_index < symtab->len; sym_index++)
+    time_sorted_syms[sym_index] = &symtab->base[sym_index];
 
   for (sym_index = 1; sym_index <= num_cycles; sym_index++)
-    time_sorted_syms[symtab.len + sym_index - 1] = &cycle_header[sym_index];
+    time_sorted_syms[symtab->len + sym_index - 1] = &cycle_header[sym_index];
 
-  qsort (time_sorted_syms, symtab.len + num_cycles, sizeof (Sym *),
+  qsort (time_sorted_syms, symtab->len + num_cycles, sizeof (Sym *),
 	 cmp_total);
 
-  for (sym_index = 0; sym_index < symtab.len + num_cycles; sym_index++)
+  for (sym_index = 0; sym_index < symtab->len + num_cycles; sym_index++)
     time_sorted_syms[sym_index]->cg.index = sym_index + 1;
 
   return time_sorted_syms;
diff --git a/gprof/cg_print.c b/gprof/cg_print.c
index 1d8e7d6b5b3..c8e80d9d3a5 100644
--- a/gprof/cg_print.c
+++ b/gprof/cg_print.c
@@ -504,13 +504,14 @@  cg_print (Sym ** timesortsym)
 {
   unsigned int sym_index;
   Sym *parent;
+  Sym_Table *symtab = get_symtab ();
 
   if (print_descriptions && bsd_style_output)
     bsd_callg_blurb (stdout);
 
   print_header ();
 
-  for (sym_index = 0; sym_index < symtab.len + num_cycles; ++sym_index)
+  for (sym_index = 0; sym_index < symtab->len + num_cycles; ++sym_index)
     {
       parent = timesortsym[sym_index];
 
@@ -570,18 +571,19 @@  cg_print_index (void)
   const char *filename;
   char buf[20];
   int column_width = (output_width - 1) / 3;	/* Don't write in last col!  */
+  Sym_Table *symtab = get_symtab ();
 
   /* Now, sort regular function name
      alphabetically to create an index.  */
-  name_sorted_syms = (Sym **) xmalloc ((symtab.len + num_cycles) * sizeof (Sym *));
+  name_sorted_syms = (Sym **) xmalloc ((symtab->len + num_cycles) * sizeof (Sym *));
 
-  for (sym_index = 0, nnames = 0; sym_index < symtab.len; sym_index++)
+  for (sym_index = 0, nnames = 0; sym_index < symtab->len; sym_index++)
     {
-      if (ignore_zeros && symtab.base[sym_index].ncalls == 0
-	  && symtab.base[sym_index].hist.time == 0)
+      if (ignore_zeros && symtab->base[sym_index].ncalls == 0
+	  && symtab->base[sym_index].hist.time == 0)
 	continue;
 
-      name_sorted_syms[nnames++] = &symtab.base[sym_index];
+      name_sorted_syms[nnames++] = &symtab->base[sym_index];
     }
 
   qsort (name_sorted_syms, nnames, sizeof (Sym *), cmp_name);
@@ -787,6 +789,7 @@  cg_print_function_ordering (void)
 #endif
   Sym **unused_syms, **used_syms, **scratch_syms;
   Arc **unplaced_arcs, **high_arcs, **scratch_arcs;
+  Sym_Table *symtab = get_symtab ();
 
   sym_index = 0;
   used = 0;
@@ -797,29 +800,29 @@  cg_print_function_ordering (void)
   scratch_arc_count = 0;
 
   /* First group all the unused functions together.  */
-  unused_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
-  used_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
-  scratch_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
+  unused_syms = (Sym **) xmalloc (symtab->len * sizeof (Sym *));
+  used_syms = (Sym **) xmalloc (symtab->len * sizeof (Sym *));
+  scratch_syms = (Sym **) xmalloc (symtab->len * sizeof (Sym *));
   high_arcs = (Arc **) xmalloc (numarcs * sizeof (Arc *));
   scratch_arcs = (Arc **) xmalloc (numarcs * sizeof (Arc *));
   unplaced_arcs = (Arc **) xmalloc (numarcs * sizeof (Arc *));
 
   /* Walk through all the functions; mark those which are never
      called as placed (we'll emit them as a group later).  */
-  for (sym_index = 0, used = 0, unused = 0; sym_index < symtab.len; sym_index++)
+  for (sym_index = 0, used = 0, unused = 0; sym_index < symtab->len; sym_index++)
     {
-      if (symtab.base[sym_index].ncalls == 0)
+      if (symtab->base[sym_index].ncalls == 0)
 	{
-	  unused_syms[unused++] = &symtab.base[sym_index];
-	  symtab.base[sym_index].has_been_placed = 1;
+	  unused_syms[unused++] = &symtab->base[sym_index];
+	  symtab->base[sym_index].has_been_placed = 1;
 	}
       else
 	{
-	  used_syms[used++] = &symtab.base[sym_index];
-	  symtab.base[sym_index].has_been_placed = 0;
-	  symtab.base[sym_index].next = 0;
-	  symtab.base[sym_index].prev = 0;
-	  symtab.base[sym_index].nuses = 0;
+	  used_syms[used++] = &symtab->base[sym_index];
+	  symtab->base[sym_index].has_been_placed = 0;
+	  symtab->base[sym_index].next = 0;
+	  symtab->base[sym_index].prev = 0;
+	  symtab->base[sym_index].nuses = 0;
 	}
     }
 
@@ -961,9 +964,9 @@  cg_print_function_ordering (void)
   for (sym_index = 0; sym_index < unused; sym_index++)
     printf("%s\n", unused_syms[sym_index]->name);
 
-  unused_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
-  used_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
-  scratch_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
+  unused_syms = (Sym **) xmalloc (symtab->len * sizeof (Sym *));
+  used_syms = (Sym **) xmalloc (symtab->len * sizeof (Sym *));
+  scratch_syms = (Sym **) xmalloc (symtab->len * sizeof (Sym *));
   high_arcs = (Arc **) xmalloc (numarcs * sizeof (Arc *));
   scratch_arcs = (Arc **) xmalloc (numarcs * sizeof (Arc *));
   unplaced_arcs = (Arc **) xmalloc (numarcs * sizeof (Arc *));
@@ -1236,6 +1239,7 @@  cg_print_file_ordering (void)
   unsigned long sym_index;
   Arc **scratch_arcs;
   char *last;
+  Sym_Table *symtab = get_symtab ();
 
   scratch_arc_count = 0;
 
@@ -1251,11 +1255,11 @@  cg_print_file_ordering (void)
 				    scratch_arcs, &scratch_arc_count);
 
   /* Output .o's not handled by the main placement algorithm.  */
-  for (sym_index = 0; sym_index < symtab.len; sym_index++)
+  for (sym_index = 0; sym_index < symtab->len; sym_index++)
     {
-      if (symtab.base[sym_index].mapped
-	  && ! symtab.base[sym_index].has_been_placed)
-	printf ("%s\n", symtab.base[sym_index].name);
+      if (symtab->base[sym_index].mapped
+	  && ! symtab->base[sym_index].has_been_placed)
+	printf ("%s\n", symtab->base[sym_index].name);
     }
 
   qsort (symbol_map, symbol_map_count, sizeof (struct function_map), cmp_symbol_map);
@@ -1271,19 +1275,19 @@  cg_print_file_ordering (void)
       if (last && !filename_cmp (last, symbol_map[sym_index].file_name))
 	continue;
 
-      for (index2 = 0; index2 < symtab.len; index2++)
+      for (index2 = 0; index2 < symtab->len; index2++)
 	{
-	  if (! symtab.base[index2].mapped)
+	  if (! symtab->base[index2].mapped)
 	    continue;
 
-	  if (!filename_cmp (symtab.base[index2].name,
+	  if (!filename_cmp (symtab->base[index2].name,
 			     symbol_map[sym_index].file_name))
 	    break;
 	}
 
       /* If we didn't find it in the symbol table, then it must
 	 be a .o with no text symbols.  Output it last.  */
-      if (index2 == symtab.len)
+      if (index2 == symtab->len)
 	printf ("%s\n", symbol_map[sym_index].file_name);
       last = symbol_map[sym_index].file_name;
     }
diff --git a/gprof/corefile.c b/gprof/corefile.c
index bc26bd7883e..d2ece3dc7aa 100644
--- a/gprof/corefile.c
+++ b/gprof/corefile.c
@@ -523,6 +523,7 @@  core_create_syms_from (const char * sym_table_file)
 {
   char type;
   FILE * f;
+  Sym_Table *symtab;
 
   f = fopen (sym_table_file, "r");
   if (!f)
@@ -531,25 +532,27 @@  core_create_syms_from (const char * sym_table_file)
       done (1);
     }
 
+  symtab = get_symtab_direct ();
+
   /* Pass 1 - determine upper bound on number of function names.  */
-  symtab.len = num_of_syms_in (f);
+  symtab->len = num_of_syms_in (f);
 
-  if (symtab.len == 0)
+  if (symtab->len == 0)
     {
       fprintf (stderr, _("%s: file `%s' has no symbols\n"), whoami, sym_table_file);
       done (1);
     }
-  else if (symtab.len == -1U)
+  else if (symtab->len == -1U)
     {
       fprintf (stderr, _("%s: file `%s' has too many symbols\n"),
 	       whoami, sym_table_file);
       done (1);
     }
 
-  symtab.base = (Sym *) xmalloc (symtab.len * sizeof (Sym));
+  symtab->base = (Sym *) xmalloc (symtab->len * sizeof (Sym));
 
   /* Pass 2 - create symbols.  */
-  symtab.limit = symtab.base;
+  symtab->limit = symtab->base;
 
   if (fseek (f, 0, SEEK_SET) != 0)
     {
@@ -564,25 +567,25 @@  core_create_syms_from (const char * sym_table_file)
       if (type != 't' && type != 'T')
 	continue;
 
-      sym_init (symtab.limit);
+      sym_init (symtab->limit);
 
       uint64_t addr;
       sscanf (address, "%" SCNx64, &addr);
-      symtab.limit->addr = addr;
+      symtab->limit->addr = addr;
 
-      symtab.limit->name = (char *) xmalloc (strlen (name) + 1);
-      strcpy ((char *) symtab.limit->name, name);
-      symtab.limit->mapped = 0;
-      symtab.limit->is_func = true;
-      symtab.limit->is_bb_head = true;
-      symtab.limit->is_static = (type == 't');
+      symtab->limit->name = (char *) xmalloc (strlen (name) + 1);
+      strcpy ((char *) symtab->limit->name, name);
+      symtab->limit->mapped = 0;
+      symtab->limit->is_func = true;
+      symtab->limit->is_bb_head = true;
+      symtab->limit->is_static = (type == 't');
 
-      ++symtab.limit;
+      ++symtab->limit;
     }
   fclose (f);
 
-  symtab.len = symtab.limit - symtab.base;
-  symtab_finalize (&symtab);
+  symtab->len = symtab->limit - symtab->base;
+  symtab_finalize (symtab);
 }
 
 static int
@@ -601,6 +604,7 @@  core_create_function_syms (void)
   long i;
   struct function_map * found = NULL;
   int core_has_func_syms = 0;
+  Sym_Table *symtab = get_symtab_direct ();
 
   switch (core_bfd->xvec->flavour)
     {
@@ -615,7 +619,7 @@  core_create_function_syms (void)
     }
 
   /* Pass 1 - determine upper bound on number of function names.  */
-  symtab.len = 0;
+  symtab->len = 0;
 
   for (i = 0; i < core_num_syms; ++i)
     {
@@ -634,19 +638,19 @@  core_create_function_syms (void)
 	     sizeof (struct function_map), search_mapped_symbol);
 	}
       if (found == NULL || found->is_first)
-	++symtab.len;
+	++symtab->len;
     }
 
-  if (symtab.len == 0)
+  if (symtab->len == 0)
     {
       fprintf (stderr, _("%s: file `%s' has no symbols\n"), whoami, a_out_name);
       done (1);
     }
 
-  symtab.base = (Sym *) xmalloc (symtab.len * sizeof (Sym));
+  symtab->base = (Sym *) xmalloc (symtab->len * sizeof (Sym));
 
   /* Pass 2 - create symbols.  */
-  symtab.limit = symtab.base;
+  symtab->limit = symtab->base;
 
   for (i = 0; i < core_num_syms; ++i)
     {
@@ -674,23 +678,23 @@  core_create_function_syms (void)
       if (found && ! found->is_first)
 	continue;
 
-      sym_init (symtab.limit);
+      sym_init (symtab->limit);
 
       /* Symbol offsets are always section-relative.  */
       sym_sec = core_syms[i]->section;
-      symtab.limit->addr = core_syms[i]->value;
+      symtab->limit->addr = core_syms[i]->value;
       if (sym_sec)
-	symtab.limit->addr += bfd_section_vma (sym_sec);
+	symtab->limit->addr += bfd_section_vma (sym_sec);
 
       if (found)
 	{
-	  symtab.limit->name = found->file_name;
-	  symtab.limit->mapped = 1;
+	  symtab->limit->name = found->file_name;
+	  symtab->limit->mapped = 1;
 	}
       else
 	{
-	  symtab.limit->name = core_syms[i]->name;
-	  symtab.limit->mapped = 0;
+	  symtab->limit->name = core_syms[i]->name;
+	  symtab->limit->mapped = 0;
 	}
 
       /* Lookup filename and line number, if we can.  */
@@ -698,10 +702,10 @@  core_create_function_syms (void)
 	const char * filename;
 	const char * func_name;
 
-	if (get_src_info (symtab.limit->addr, & filename, & func_name,
-			  & symtab.limit->line_num))
+	if (get_src_info (symtab->limit->addr, & filename, & func_name,
+			  & symtab->limit->line_num))
 	  {
-	    symtab.limit->file = source_file_lookup_path (filename);
+	    symtab->limit->file = source_file_lookup_path (filename);
 
 	    /* FIXME: Checking __osf__ here does not work with a cross
 	       gprof.  */
@@ -713,36 +717,36 @@  core_create_function_syms (void)
 	       labels do not appear in the symbol table info, so this isn't
 	       necessary.  */
 
-	    if (strcmp (symtab.limit->name, func_name) != 0)
+	    if (strcmp (symtab->limit->name, func_name) != 0)
 	      {
 		/* The symbol's address maps to a different name, so
 		   it can't be a function-entry point.  This happens
 		   for labels, for example.  */
 		DBG (AOUTDEBUG,
 		     printf ("[core_create_function_syms: rej %s (maps to %s)\n",
-			     symtab.limit->name, func_name));
+			     symtab->limit->name, func_name));
 		continue;
 	      }
 #endif
 	  }
       }
 
-      symtab.limit->is_func = (!core_has_func_syms
+      symtab->limit->is_func = (!core_has_func_syms
 			       || (core_syms[i]->flags & BSF_FUNCTION) != 0);
-      symtab.limit->is_bb_head = true;
+      symtab->limit->is_bb_head = true;
 
       if (cxxclass == 't')
-	symtab.limit->is_static = true;
+	symtab->limit->is_static = true;
 
       DBG (AOUTDEBUG, printf ("[core_create_function_syms] %ld %s 0x%lx\n",
-			      (long) (symtab.limit - symtab.base),
-			      symtab.limit->name,
-			      (unsigned long) symtab.limit->addr));
-      ++symtab.limit;
+			      (long) (symtab->limit - symtab->base),
+			      symtab->limit->name,
+			      (unsigned long) symtab->limit->addr));
+      ++symtab->limit;
     }
 
-  symtab.len = symtab.limit - symtab.base;
-  symtab_finalize (&symtab);
+  symtab->len = symtab->limit - symtab->base;
+  symtab_finalize (symtab);
 }
 
 /* Read in symbol table from core.
@@ -755,8 +759,10 @@  core_create_line_syms (void)
   Sym prev, *sym;
   const char *filename;
   Sym_Table ltab;
-  bfd_vma vma_high;
   size_t ltab_reserved;
+  Sym_Table *symtab = get_symtab_direct ();
+  bfd_vma bfd_vma_low = core_text_sect->vma;
+  bfd_vma bfd_vma_high = bfd_vma_low + bfd_section_size (core_text_sect);
 
   /* Create symbols for functions as usual.  This is necessary in
      cases where parts of a program were not compiled with -g.  For
@@ -786,67 +792,72 @@  core_create_line_syms (void)
      lot cleaner now.  */
   memset (&prev, 0, sizeof (prev));
 
-  vma_high = core_text_sect->vma + bfd_section_size (core_text_sect);
-  for (vma = core_text_sect->vma; vma < vma_high; vma += insn_boundary)
+  for (size_t i = 0; i < num_histograms; ++i)
     {
-      if (ltab.len >= ltab_reserved)
+      bfd_vma hist_vma_high = histograms[i].highpc;
+      bfd_vma vma_low = MAX (histograms[i].lowpc, bfd_vma_low);
+      bfd_vma vma_high = MIN (bfd_vma_high, hist_vma_high);
+      for (vma = vma_low; vma < vma_high; vma += insn_boundary)
 	{
-	  /* Reserve more space for line symbols.  */
-	  ltab_reserved *= 2;
-	  ltab.base = (Sym *) xrealloc (ltab.base, ltab_reserved * sizeof (Sym));
-	  ltab.limit = ltab.base + ltab.len;
+	  if (ltab.len >= ltab_reserved)
+	    {
+	      /* Reserve more space for line symbols.  */
+	      ltab_reserved *= 2;
+	      ltab.base = xrealloc (ltab.base, ltab_reserved * sizeof (Sym));
+	      ltab.limit = ltab.base + ltab.len;
+	    }
+	  sym_init (ltab.limit);
+
+	  if (!get_src_info (vma, &filename, &ltab.limit->name, &ltab.limit->line_num)
+	      || (prev.name && prev.line_num == ltab.limit->line_num
+		  && strcmp (prev.name, ltab.limit->name) == 0
+		  && filename_cmp (prev.file->name, filename) == 0))
+	    continue;
+
+	  /* Make name pointer a malloc'ed string.  */
+	  ltab.limit->name = xstrdup (ltab.limit->name);
+	  ltab.limit->file = source_file_lookup_path (filename);
+
+	  ltab.limit->addr = vma;
+
+	  /* Set is_static based on the enclosing function, using either:
+	     1) the previous symbol, if it's from the same function, or
+	     2) a symtab lookup.  */
+	  if (prev.name && ltab.limit->file == prev.file
+	      && strcmp (ltab.limit->name, prev.name) == 0)
+	    {
+	      ltab.limit->is_static = prev.is_static;
+	    }
+	  else
+	    {
+	      sym = sym_lookup (symtab, ltab.limit->addr);
+	      if (sym)
+		ltab.limit->is_static = sym->is_static;
+	    }
+
+	  prev = *ltab.limit;
+
+	  DBG (AOUTDEBUG, printf ("[core_create_line_syms] %lu %s 0x%lx\n",
+				  (unsigned long) (ltab.limit - ltab.base),
+				  ltab.limit->name,
+				  (unsigned long) ltab.limit->addr));
+	  ++ltab.limit;
+	  ++ltab.len;
 	}
-      sym_init (ltab.limit);
-
-      if (!get_src_info (vma, &filename, &ltab.limit->name, &ltab.limit->line_num)
-	  || (prev.name && prev.line_num == ltab.limit->line_num
-	      && strcmp (prev.name, ltab.limit->name) == 0
-	      && filename_cmp (prev.file->name, filename) == 0))
-	continue;
-
-      /* Make name pointer a malloc'ed string.  */
-      ltab.limit->name = xstrdup (ltab.limit->name);
-      ltab.limit->file = source_file_lookup_path (filename);
-
-      ltab.limit->addr = vma;
-
-      /* Set is_static based on the enclosing function, using either:
-	 1) the previous symbol, if it's from the same function, or
-	 2) a symtab lookup.  */
-      if (ltab.limit->file == prev.file
-	  && strcmp (ltab.limit->name, prev.name) == 0)
-	{
-	  ltab.limit->is_static = prev.is_static;
-	}
-      else
-	{
-	  sym = sym_lookup(&symtab, ltab.limit->addr);
-          if (sym)
-	    ltab.limit->is_static = sym->is_static;
-	}
-
-      prev = *ltab.limit;
-
-      DBG (AOUTDEBUG, printf ("[core_create_line_syms] %lu %s 0x%lx\n",
-			      (unsigned long) (ltab.limit - ltab.base),
-			      ltab.limit->name,
-			      (unsigned long) ltab.limit->addr));
-      ++ltab.limit;
-      ++ltab.len;
     }
 
   /* Reserve space for function symbols and/or trim excess space.  */
-  ltab_reserved = ltab.len + symtab.len;
+  ltab_reserved = ltab.len + symtab->len;
   ltab.base = xrealloc (ltab.base, ltab_reserved * sizeof (Sym));
   ltab.limit = ltab.base + ltab.len;
 
   /* Copy in function symbols.  */
-  memcpy (ltab.limit, symtab.base, symtab.len * sizeof (Sym));
-  ltab.limit += symtab.len;
-  ltab.len += symtab.len;
+  memcpy (ltab.limit, symtab->base, symtab->len * sizeof (Sym));
+  ltab.limit += symtab->len;
+  ltab.len += symtab->len;
 
   /* Finalize ltab and make it symbol table.  */
   symtab_finalize (&ltab);
-  free (symtab.base);
-  symtab = ltab;
+  free (symtab->base);
+  set_symtab (&ltab);
 }
diff --git a/gprof/gmon_io.c b/gprof/gmon_io.c
index 9a069504d85..05e5bcce68f 100644
--- a/gprof/gmon_io.c
+++ b/gprof/gmon_io.c
@@ -576,6 +576,7 @@  gmon_out_write (const char *filename)
 {
   FILE *ofp;
   struct gmon_hdr ghdr;
+  Sym_Table *symtab;
 
   ofp = fopen (filename, FOPEN_WB);
   if (!ofp)
@@ -584,6 +585,8 @@  gmon_out_write (const char *filename)
       done (1);
     }
 
+  symtab = get_symtab ();
+
   if (file_format == FF_AUTO || file_format == FF_MAGIC)
     {
       /* Write gmon header.  */
@@ -704,7 +707,7 @@  gmon_out_write (const char *filename)
 	}
 
       /* Dump the normalized raw arc information.  */
-      for (sym = symtab.base; sym < symtab.limit; ++sym)
+      for (sym = symtab->base; sym < symtab->limit; ++sym)
 	{
 	  for (arc = sym->cg.children; arc; arc = arc->next_child)
 	    {
diff --git a/gprof/gprof.c b/gprof/gprof.c
index 9392575f747..cea269bc80f 100644
--- a/gprof/gprof.c
+++ b/gprof/gprof.c
@@ -527,17 +527,6 @@  This program is free software.  This program has absolutely no warranty.\n"));
   if (ignore_direct_calls)
     core_get_text_space (core_bfd);
 
-  /* Create symbols from core image.  */
-  if (external_symbol_table)
-    core_create_syms_from (external_symbol_table);
-  else if (line_granularity)
-    core_create_line_syms ();
-  else
-    core_create_function_syms ();
-
-  /* Translate sym specs into syms.  */
-  sym_id_parse ();
-
   if (file_format == FF_PROF)
     {
       fprintf (stderr,
@@ -644,6 +633,23 @@  This program is free software.  This program has absolutely no warranty.\n"));
   return 0;
 }
 
+/* Initialize the symbol table.  */
+
+void
+symtab_init (void)
+{
+  /* Create symbols from core image.  */
+  if (external_symbol_table)
+    core_create_syms_from (external_symbol_table);
+  else if (line_granularity)
+    core_create_line_syms ();
+  else
+    core_create_function_syms ();
+
+  /* Translate sym specs into syms.  */
+  sym_id_parse ();
+}
+
 void
 done (int status)
 {
diff --git a/gprof/gprof.h b/gprof/gprof.h
index 1d8d8964772..4222731603f 100644
--- a/gprof/gprof.h
+++ b/gprof/gprof.h
@@ -132,4 +132,6 @@  extern bool first_output;		/* no output so far? */
 
 extern void done (int status) ATTRIBUTE_NORETURN;
 
+extern void symtab_init (void);
+
 #endif /* gprof_h */
diff --git a/gprof/hist.c b/gprof/hist.c
index 2d3b0b11ac5..ef4756531c6 100644
--- a/gprof/hist.c
+++ b/gprof/hist.c
@@ -294,8 +294,9 @@  scale_and_align_entries (void)
   Sym *sym;
   bfd_vma bin_of_entry;
   bfd_vma bin_of_code;
+  Sym_Table *symtab = get_symtab ();
 
-  for (sym = symtab.base; sym < symtab.limit; sym++)
+  for (sym = symtab->base; sym < symtab->limit; sym++)
     {
       histogram *r = find_histogram_for_pc (sym->addr);
 
@@ -366,6 +367,7 @@  hist_assign_samples_1 (histogram *r)
   unsigned int bin_count;
   unsigned int i, j, k;
   double count_time, credit;
+  Sym_Table *symtab = get_symtab ();
 
   bfd_vma lowpc = r->lowpc / sizeof (UNIT);
 
@@ -392,10 +394,10 @@  hist_assign_samples_1 (histogram *r)
 
          PR gprof/13325: Make sure that K does not get decremented
 	 and J will never be less than 0.  */
-      for (j = k - 1; j < symtab.len; k = ++j)
+      for (j = k - 1; j < symtab->len; k = ++j)
 	{
-	  sym_low_pc = symtab.base[j].hist.scaled_addr;
-	  sym_high_pc = symtab.base[j + 1].hist.scaled_addr;
+	  sym_low_pc = symtab->base[j].hist.scaled_addr;
+	  sym_high_pc = symtab->base[j + 1].hist.scaled_addr;
 
 	  /* If high end of bin is below entry address,
 	     go for next bin.  */
@@ -414,12 +416,12 @@  hist_assign_samples_1 (histogram *r)
 	      DBG (SAMPLEDEBUG,
 		   printf (
 	       "[assign_samples] [0x%lx,0x%lx) %s gets %f ticks %ld overlap\n",
-			   (unsigned long) symtab.base[j].addr,
+			   (unsigned long) symtab->base[j].addr,
 			   (unsigned long) (sizeof (UNIT) * sym_high_pc),
-			   symtab.base[j].name, overlap * count_time / hist_scale,
+			   symtab->base[j].name, overlap * count_time / hist_scale,
 			   (long) overlap));
 
-	      addr = symtab.base[j].addr;
+	      addr = symtab->base[j].addr;
 	      credit = overlap * count_time / hist_scale;
 
 	      /* Credit symbol if it appears in INCL_FLAT or that
@@ -429,7 +431,7 @@  hist_assign_samples_1 (histogram *r)
 		  || (syms[INCL_FLAT].len == 0
 		      && !sym_lookup (&syms[EXCL_FLAT], addr)))
 		{
-		  symtab.base[j].hist.time += credit;
+		  symtab->base[j].hist.time += credit;
 		}
 	      else
 		{
@@ -569,6 +571,7 @@  hist_print (void)
   unsigned log_scale;
   double top_time;
   bfd_vma addr;
+  Sym_Table *symtab = get_symtab ();
 
   if (first_output)
     first_output = false;
@@ -592,12 +595,12 @@  hist_print (void)
 
   /* Sort the symbol table by time (call-count and name as secondary
      and tertiary keys).  */
-  time_sorted_syms = (Sym **) xmalloc (symtab.len * sizeof (Sym *));
+  time_sorted_syms = (Sym **) xmalloc (symtab->len * sizeof (Sym *));
 
-  for (sym_index = 0; sym_index < symtab.len; ++sym_index)
-    time_sorted_syms[sym_index] = &symtab.base[sym_index];
+  for (sym_index = 0; sym_index < symtab->len; ++sym_index)
+    time_sorted_syms[sym_index] = &symtab->base[sym_index];
 
-  qsort (time_sorted_syms, symtab.len, sizeof (Sym *), cmp_time);
+  qsort (time_sorted_syms, symtab->len, sizeof (Sym *), cmp_time);
 
   if (bsd_style_output)
     {
@@ -611,7 +614,7 @@  hist_print (void)
       top_dog = 0;
       top_time = 0.0;
 
-      for (sym_index = 0; sym_index < symtab.len; ++sym_index)
+      for (sym_index = 0; sym_index < symtab->len; ++sym_index)
 	{
 	  sym = time_sorted_syms[sym_index];
 
@@ -648,7 +651,7 @@  hist_print (void)
      I-cache misses etc.).  */
   print_header (SItab[log_scale].prefix);
 
-  for (sym_index = 0; sym_index < symtab.len; ++sym_index)
+  for (sym_index = 0; sym_index < symtab->len; ++sym_index)
     {
       addr = time_sorted_syms[sym_index]->addr;
 
diff --git a/gprof/i386.c b/gprof/i386.c
index 62f6f96b20a..350dcb238dd 100644
--- a/gprof/i386.c
+++ b/gprof/i386.c
@@ -52,6 +52,7 @@  i386_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
   unsigned char *instructp;
   Sym *child;
   bfd_vma pc, destpc;
+  Sym_Table *symtab = get_symtab ();
 
   DBG (CALLDEBUG, printf ("[findcall] %s: 0x%lx to 0x%lx\n",
 			  parent->name, (unsigned long) p_lowpc,
@@ -76,7 +77,7 @@  i386_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
 	  destpc = bfd_get_32 (core_bfd, instructp + 1) + pc + 5;
 	  if (hist_check_address (destpc))
 	    {
-	      child = sym_lookup (&symtab, destpc);
+	      child = sym_lookup (symtab, destpc);
 	      if (child && child->addr == destpc)
 		{
 		  /*
diff --git a/gprof/mips.c b/gprof/mips.c
index 0ccd17db525..873403c6a13 100644
--- a/gprof/mips.c
+++ b/gprof/mips.c
@@ -46,6 +46,7 @@  mips_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
   int offset;
   Sym *child;
   static bool inited = false;
+  Sym_Table *symtab = get_symtab ();
 
   if (!inited)
     {
@@ -75,7 +76,7 @@  mips_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
 	  dest_pc = (pc & ~(bfd_vma) 0xfffffff) | offset;
 	  if (hist_check_address (dest_pc))
 	    {
-	      child = sym_lookup (&symtab, dest_pc);
+	      child = sym_lookup (symtab, dest_pc);
               if (child)
 		{
 	          DBG (CALLDEBUG,
diff --git a/gprof/sparc.c b/gprof/sparc.c
index 019e58b185f..ac0975eb012 100644
--- a/gprof/sparc.c
+++ b/gprof/sparc.c
@@ -47,6 +47,7 @@  sparc_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
   bfd_vma pc, dest_pc;
   unsigned int insn;
   Sym *child;
+  Sym_Table *symtab = get_symtab ();
 
   DBG (CALLDEBUG, printf ("[find_call] %s: 0x%lx to 0x%lx\n",
 			  parent->name, (unsigned long) p_lowpc,
@@ -69,7 +70,7 @@  sparc_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
 			   ^ 0x20000000) - 0x20000000);
 	  if (hist_check_address (dest_pc))
 	    {
-	      child = sym_lookup (&symtab, dest_pc);
+	      child = sym_lookup (symtab, dest_pc);
 	      if (child)
 		{
 	          DBG (CALLDEBUG,
diff --git a/gprof/sym_ids.c b/gprof/sym_ids.c
index 9f26679cfc0..81be06c6a88 100644
--- a/gprof/sym_ids.c
+++ b/gprof/sym_ids.c
@@ -278,13 +278,14 @@  sym_id_parse (void)
   Sym *sym, *left, *right;
   struct sym_id *id;
   Sym_Table *tab;
+  Sym_Table *symtab = get_symtab_direct ();
 
   /* Convert symbol ids into Syms, so we can deal with them more easily.  */
   for (id = id_list; id; id = id->next)
     parse_id (id);
 
   /* First determine size of each table.  */
-  for (sym = symtab.base; sym < symtab.limit; ++sym)
+  for (sym = symtab->base; sym < symtab->limit; ++sym)
     {
       for (id = id_list; id; id = id->next)
 	{
@@ -315,7 +316,7 @@  sym_id_parse (void)
     }
 
   /* Make a second pass through symtab, creating syms as necessary.  */
-  for (sym = symtab.base; sym < symtab.limit; ++sym)
+  for (sym = symtab->base; sym < symtab->limit; ++sym)
     {
       for (id = id_list; id; id = id->next)
 	{
diff --git a/gprof/symtab.c b/gprof/symtab.c
index cc619aa728e..e8b0b340680 100644
--- a/gprof/symtab.c
+++ b/gprof/symtab.c
@@ -28,8 +28,40 @@ 
 
 static int cmp_addr (const void *, const void *);
 
-Sym_Table symtab;
+/* The symbol table.  */
+static Sym_Table symtab;
 
+/* Return the pointer to the symbol table.  */
+
+Sym_Table *
+get_symtab_direct (void)
+{
+  return &symtab;
+}
+
+/* Return the pointer to the symbol table and initialize it if it isn't
+   initialized yet.  */
+
+Sym_Table *
+get_symtab (void)
+{
+  static Sym_Table *symtab_p;
+  if (!symtab_p)
+    {
+      symtab_init ();
+
+      symtab_p = &symtab;
+    }
+  return symtab_p;
+}
+
+/* Set the symbol table to *LTAB.  */
+
+void
+set_symtab (Sym_Table *ltab)
+{
+  symtab = *ltab;
+}
 
 /* Initialize a symbol (so it's empty).  */
 
diff --git a/gprof/symtab.h b/gprof/symtab.h
index 436f665f9a5..19031b917b0 100644
--- a/gprof/symtab.h
+++ b/gprof/symtab.h
@@ -110,7 +110,9 @@  typedef struct
   }
 Sym_Table;
 
-extern Sym_Table symtab;	/* The symbol table.  */
+extern Sym_Table *get_symtab (void);
+extern Sym_Table *get_symtab_direct (void);
+extern void set_symtab       (Sym_Table *);
 
 extern void sym_init        (Sym *);
 extern void symtab_finalize (Sym_Table *);
diff --git a/gprof/vax.c b/gprof/vax.c
index fafe2b17b53..47cbe138b3d 100644
--- a/gprof/vax.c
+++ b/gprof/vax.c
@@ -238,6 +238,7 @@  vax_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
   operandenum firstmode;
   bfd_vma pc, destpc;
   static bool inited = false;
+  Sym_Table *symtab = get_symtab ();
 
   if (!inited)
     {
@@ -321,7 +322,7 @@  vax_find_call (Sym *parent, bfd_vma p_lowpc, bfd_vma p_highpc)
 	      destpc = pc + vax_offset (operand);
 	      if (hist_check_address (destpc))
 		{
-		  child = sym_lookup (&symtab, destpc);
+		  child = sym_lookup (symtab, destpc);
 		  if (child)
 		    {
 		      DBG (CALLDEBUG,
-- 
2.48.1