/* basic_blocks.c - Basic-block level related code: reading/writing of basic-block info to/from gmon.out; computing and formatting of basic-block related statistics. Copyright (C) 1999-2025 Free Software Foundation, Inc. This file is part of GNU Binutils. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" #include "util.h" #include "Elf.h" /* link to bfd.h fixes bfd* */ #include "gp-gmon.h" #include "basic_blocks.h" #include "gmon_io.h" #include "gmon_out.h" #include "symtab.h" /* Skip over variable length string. */ static void fskip_string (FILE *fp) { int ch; while ((ch = fgetc (fp)) != EOF) { if (ch == '\0') break; } } /* Read a basic-block record from file IFP. FILENAME is the name of file IFP and is provided for formatting error-messages only. */ void bb_read_rec (FILE *ifp, const char *filename, bool line_granularity, const char *whoami) { unsigned int nblocks, b; bfd_vma addr, ncalls; Sym *sym; Sym_Table *symtab; if (gmon_io_read_32 (ifp, &nblocks)) { fprintf (stderr, "%s: %s: unexpected end of file\n", whoami, filename); done (1); } symtab = get_symtab (whoami); nblocks = bfd_get_32 (core_bfd, (bfd_byte *) & nblocks); if (gmon_file_version == 0) fskip_string (ifp); for (b = 0; b < nblocks; ++b) { if (gmon_file_version == 0) { int line_num; /* Version 0 had lots of extra stuff that we don't care about anymore. */ if ((fread (&ncalls, sizeof (ncalls), 1, ifp) != 1) || (fread (&addr, sizeof (addr), 1, ifp) != 1) || (fskip_string (ifp), false) || (fskip_string (ifp), false) || (fread (&line_num, sizeof (line_num), 1, ifp) != 1)) { perror (filename); done (1); } } else if (gmon_io_read_vma (ifp, &addr, whoami) || gmon_io_read_vma (ifp, &ncalls, whoami)) { perror (filename); done (1); } /* Basic-block execution counts are meaningful only if we're profiling at the line-by-line level: */ if (line_granularity) { sym = sym_lookup (symtab, addr); if (sym) { int i; DBG (BBDEBUG, printf ("[bb_read_rec] 0x%lx->0x%lx (%s:%d) cnt=%lu\n", (unsigned long) addr, (unsigned long) sym->addr, sym->name, sym->line_num, (unsigned long) ncalls)); for (i = 0; i < NBBS; i++) { if (! sym->bb_addr[i] || sym->bb_addr[i] == addr) { sym->bb_addr[i] = addr; sym->bb_calls[i] += ncalls; break; } } } } else { static bool user_warned = false; if (!user_warned) { user_warned = true; fprintf (stderr, "%s: warning: ignoring basic-block exec counts (use -l or --line)\n", whoami); } } } return; }