(root)/
binutils-2.41/
gprof/
call_graph.c
       1  /* call_graph.c  -  Create call graphs.
       2  
       3     Copyright (C) 1999-2023 Free Software Foundation, Inc.
       4  
       5     This file is part of GNU Binutils.
       6  
       7     This program is free software; you can redistribute it and/or modify
       8     it under the terms of the GNU General Public License as published by
       9     the Free Software Foundation; either version 3 of the License, or
      10     (at your option) any later version.
      11  
      12     This program is distributed in the hope that it will be useful,
      13     but WITHOUT ANY WARRANTY; without even the implied warranty of
      14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15     GNU General Public License for more details.
      16  
      17     You should have received a copy of the GNU General Public License
      18     along with this program; if not, write to the Free Software
      19     Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
      20     02110-1301, USA.  */
      21  
      22  #include "gprof.h"
      23  #include "search_list.h"
      24  #include "source.h"
      25  #include "symtab.h"
      26  #include "cg_arcs.h"
      27  #include "call_graph.h"
      28  #include "corefile.h"
      29  #include "gmon_io.h"
      30  #include "gmon_out.h"
      31  #include "sym_ids.h"
      32  
      33  void
      34  cg_tally (bfd_vma from_pc, bfd_vma self_pc, unsigned long count)
      35  {
      36    Sym *parent;
      37    Sym *child;
      38  
      39    parent = sym_lookup (&symtab, from_pc);
      40    child = sym_lookup (&symtab, self_pc);
      41  
      42    if (child == NULL || parent == NULL)
      43      return;
      44  
      45    /* If we're doing line-by-line profiling, both the parent and the
      46       child will probably point to line symbols instead of function
      47       symbols.  For the parent this is fine, since this identifies the
      48       line number in the calling routing, but the child should always
      49       point to a function entry point, so we back up in the symbol
      50       table until we find it.
      51  
      52       For normal profiling, is_func will be set on all symbols, so this
      53       code will do nothing.  */
      54    while (child >= symtab.base && ! child->is_func)
      55      --child;
      56  
      57    if (child < symtab.base)
      58      return;
      59  
      60    /* Keep arc if it is on INCL_ARCS table or if the INCL_ARCS table
      61       is empty and it is not in the EXCL_ARCS table.  */
      62    if (sym_id_arc_is_present (&syms[INCL_ARCS], parent, child)
      63        || (syms[INCL_ARCS].len == 0
      64  	  && !sym_id_arc_is_present (&syms[EXCL_ARCS], parent, child)))
      65      {
      66        child->ncalls += count;
      67        DBG (TALLYDEBUG,
      68  	   printf (_("[cg_tally] arc from %s to %s traversed %lu times\n"),
      69  		   parent->name, child->name, count));
      70        arc_add (parent, child, count);
      71      }
      72  }
      73  
      74  /* Read a record from file IFP describing an arc in the function
      75     call-graph and the count of how many times the arc has been
      76     traversed.  FILENAME is the name of file IFP and is provided
      77     for formatting error-messages only.  */
      78  
      79  void
      80  cg_read_rec (FILE *ifp, const char *filename)
      81  {
      82    bfd_vma from_pc, self_pc;
      83    unsigned int count;
      84  
      85    if (gmon_io_read_vma (ifp, &from_pc)
      86        || gmon_io_read_vma (ifp, &self_pc)
      87        || gmon_io_read_32 (ifp, &count))
      88      {
      89        fprintf (stderr, _("%s: %s: unexpected end of file\n"),
      90  	       whoami, filename);
      91        done (1);
      92      }
      93  
      94    DBG (SAMPLEDEBUG,
      95         printf ("[cg_read_rec] frompc 0x%lx selfpc 0x%lx count %lu\n",
      96  	       (unsigned long) from_pc, (unsigned long) self_pc,
      97  	       (unsigned long) count));
      98    /* Add this arc:  */
      99    cg_tally (from_pc, self_pc, count);
     100  }
     101  
     102  /* Write all the arcs in the call-graph to file OFP.  FILENAME is
     103     the name of OFP and is provided for formatting error-messages
     104     only.  */
     105  
     106  void
     107  cg_write_arcs (FILE *ofp, const char *filename)
     108  {
     109    Arc *arc;
     110    Sym *sym;
     111  
     112    for (sym = symtab.base; sym < symtab.limit; sym++)
     113      {
     114        for (arc = sym->cg.children; arc; arc = arc->next_child)
     115  	{
     116  	  if (gmon_io_write_8 (ofp, GMON_TAG_CG_ARC)
     117  	      || gmon_io_write_vma (ofp, arc->parent->addr)
     118  	      || gmon_io_write_vma (ofp, arc->child->addr)
     119  	      || gmon_io_write_32 (ofp, arc->count))
     120  	    {
     121  	      perror (filename);
     122  	      done (1);
     123  	    }
     124  	  DBG (SAMPLEDEBUG,
     125  	     printf ("[cg_write_arcs] frompc 0x%lx selfpc 0x%lx count %lu\n",
     126  		     (unsigned long) arc->parent->addr,
     127  		     (unsigned long) arc->child->addr, arc->count));
     128  	}
     129      }
     130  }