xref: /netbsd-src/external/gpl3/binutils.old/dist/gprof/call_graph.c (revision e992f068c547fd6e84b3f104dc2340adcc955732)
175fd0b74Schristos /* call_graph.c  -  Create call graphs.
275fd0b74Schristos 
3*e992f068Schristos    Copyright (C) 1999-2022 Free Software Foundation, Inc.
475fd0b74Schristos 
575fd0b74Schristos    This file is part of GNU Binutils.
675fd0b74Schristos 
775fd0b74Schristos    This program is free software; you can redistribute it and/or modify
875fd0b74Schristos    it under the terms of the GNU General Public License as published by
975fd0b74Schristos    the Free Software Foundation; either version 3 of the License, or
1075fd0b74Schristos    (at your option) any later version.
1175fd0b74Schristos 
1275fd0b74Schristos    This program is distributed in the hope that it will be useful,
1375fd0b74Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
1475fd0b74Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1575fd0b74Schristos    GNU General Public License for more details.
1675fd0b74Schristos 
1775fd0b74Schristos    You should have received a copy of the GNU General Public License
1875fd0b74Schristos    along with this program; if not, write to the Free Software
1975fd0b74Schristos    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
2075fd0b74Schristos    02110-1301, USA.  */
2175fd0b74Schristos 
2275fd0b74Schristos #include "gprof.h"
2375fd0b74Schristos #include "search_list.h"
2475fd0b74Schristos #include "source.h"
2575fd0b74Schristos #include "symtab.h"
2675fd0b74Schristos #include "cg_arcs.h"
2775fd0b74Schristos #include "call_graph.h"
2875fd0b74Schristos #include "corefile.h"
2975fd0b74Schristos #include "gmon_io.h"
3075fd0b74Schristos #include "gmon_out.h"
3175fd0b74Schristos #include "sym_ids.h"
3275fd0b74Schristos 
3375fd0b74Schristos void
cg_tally(bfd_vma from_pc,bfd_vma self_pc,unsigned long count)3475fd0b74Schristos cg_tally (bfd_vma from_pc, bfd_vma self_pc, unsigned long count)
3575fd0b74Schristos {
3675fd0b74Schristos   Sym *parent;
3775fd0b74Schristos   Sym *child;
3875fd0b74Schristos 
3975fd0b74Schristos   parent = sym_lookup (&symtab, from_pc);
4075fd0b74Schristos   child = sym_lookup (&symtab, self_pc);
4175fd0b74Schristos 
4275fd0b74Schristos   if (child == NULL || parent == NULL)
4375fd0b74Schristos     return;
4475fd0b74Schristos 
4575fd0b74Schristos   /* If we're doing line-by-line profiling, both the parent and the
4675fd0b74Schristos      child will probably point to line symbols instead of function
4775fd0b74Schristos      symbols.  For the parent this is fine, since this identifies the
4875fd0b74Schristos      line number in the calling routing, but the child should always
4975fd0b74Schristos      point to a function entry point, so we back up in the symbol
5075fd0b74Schristos      table until we find it.
5175fd0b74Schristos 
5275fd0b74Schristos      For normal profiling, is_func will be set on all symbols, so this
5375fd0b74Schristos      code will do nothing.  */
5475fd0b74Schristos   while (child >= symtab.base && ! child->is_func)
5575fd0b74Schristos     --child;
5675fd0b74Schristos 
5775fd0b74Schristos   if (child < symtab.base)
5875fd0b74Schristos     return;
5975fd0b74Schristos 
6075fd0b74Schristos   /* Keep arc if it is on INCL_ARCS table or if the INCL_ARCS table
6175fd0b74Schristos      is empty and it is not in the EXCL_ARCS table.  */
6275fd0b74Schristos   if (sym_id_arc_is_present (&syms[INCL_ARCS], parent, child)
6375fd0b74Schristos       || (syms[INCL_ARCS].len == 0
6475fd0b74Schristos 	  && !sym_id_arc_is_present (&syms[EXCL_ARCS], parent, child)))
6575fd0b74Schristos     {
6675fd0b74Schristos       child->ncalls += count;
6775fd0b74Schristos       DBG (TALLYDEBUG,
6875fd0b74Schristos 	   printf (_("[cg_tally] arc from %s to %s traversed %lu times\n"),
6975fd0b74Schristos 		   parent->name, child->name, count));
7075fd0b74Schristos       arc_add (parent, child, count);
7175fd0b74Schristos     }
7275fd0b74Schristos }
7375fd0b74Schristos 
7475fd0b74Schristos /* Read a record from file IFP describing an arc in the function
7575fd0b74Schristos    call-graph and the count of how many times the arc has been
7675fd0b74Schristos    traversed.  FILENAME is the name of file IFP and is provided
7775fd0b74Schristos    for formatting error-messages only.  */
7875fd0b74Schristos 
7975fd0b74Schristos void
cg_read_rec(FILE * ifp,const char * filename)8075fd0b74Schristos cg_read_rec (FILE *ifp, const char *filename)
8175fd0b74Schristos {
8275fd0b74Schristos   bfd_vma from_pc, self_pc;
8375fd0b74Schristos   unsigned int count;
8475fd0b74Schristos 
8575fd0b74Schristos   if (gmon_io_read_vma (ifp, &from_pc)
8675fd0b74Schristos       || gmon_io_read_vma (ifp, &self_pc)
8775fd0b74Schristos       || gmon_io_read_32 (ifp, &count))
8875fd0b74Schristos     {
8975fd0b74Schristos       fprintf (stderr, _("%s: %s: unexpected end of file\n"),
9075fd0b74Schristos 	       whoami, filename);
9175fd0b74Schristos       done (1);
9275fd0b74Schristos     }
9375fd0b74Schristos 
9475fd0b74Schristos   DBG (SAMPLEDEBUG,
9575fd0b74Schristos        printf ("[cg_read_rec] frompc 0x%lx selfpc 0x%lx count %lu\n",
9675fd0b74Schristos 	       (unsigned long) from_pc, (unsigned long) self_pc,
9775fd0b74Schristos 	       (unsigned long) count));
9875fd0b74Schristos   /* Add this arc:  */
9975fd0b74Schristos   cg_tally (from_pc, self_pc, count);
10075fd0b74Schristos }
10175fd0b74Schristos 
10275fd0b74Schristos /* Write all the arcs in the call-graph to file OFP.  FILENAME is
10375fd0b74Schristos    the name of OFP and is provided for formatting error-messages
10475fd0b74Schristos    only.  */
10575fd0b74Schristos 
10675fd0b74Schristos void
cg_write_arcs(FILE * ofp,const char * filename)10775fd0b74Schristos cg_write_arcs (FILE *ofp, const char *filename)
10875fd0b74Schristos {
10975fd0b74Schristos   Arc *arc;
11075fd0b74Schristos   Sym *sym;
11175fd0b74Schristos 
11275fd0b74Schristos   for (sym = symtab.base; sym < symtab.limit; sym++)
11375fd0b74Schristos     {
11475fd0b74Schristos       for (arc = sym->cg.children; arc; arc = arc->next_child)
11575fd0b74Schristos 	{
11675fd0b74Schristos 	  if (gmon_io_write_8 (ofp, GMON_TAG_CG_ARC)
11775fd0b74Schristos 	      || gmon_io_write_vma (ofp, arc->parent->addr)
11875fd0b74Schristos 	      || gmon_io_write_vma (ofp, arc->child->addr)
11975fd0b74Schristos 	      || gmon_io_write_32 (ofp, arc->count))
12075fd0b74Schristos 	    {
12175fd0b74Schristos 	      perror (filename);
12275fd0b74Schristos 	      done (1);
12375fd0b74Schristos 	    }
12475fd0b74Schristos 	  DBG (SAMPLEDEBUG,
12575fd0b74Schristos 	     printf ("[cg_write_arcs] frompc 0x%lx selfpc 0x%lx count %lu\n",
12675fd0b74Schristos 		     (unsigned long) arc->parent->addr,
12775fd0b74Schristos 		     (unsigned long) arc->child->addr, arc->count));
12875fd0b74Schristos 	}
12975fd0b74Schristos     }
13075fd0b74Schristos }
131