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