/* Copyright (C) 2021-2026 Free Software Foundation, Inc. Contributed by Oracle. 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, 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, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h"#include <assert.h>#include <string.h>#include <ctype.h> #include "demangle.h"#include "util.h"#include "DbeSession.h"#include "Function.h"#include "Module.h"#include "LoadObject.h"#include "Settings.h"#include "DbeFile.h"#include "DbeView.h" struct SrcInfo{ DbeLine *src_line; SrcInfo *included_from; SrcInfo *next;}; struct PCInfo{ int64_t offset; int64_t size; SrcInfo *src_info;}; Function::Function (uint64_t _id){ id = _id; instr_id = id << 32; derivedNode = NULL; module = NULL; line_first = line_last = -1; isOutlineFunction = false; name = NULL; mangled_name = NULL; match_name = NULL; comparable_name = NULL; img_fname = NULL; img_offset = 0; chksum = 0; flags = 0; size = 0; save_addr = FUNC_NO_SAVE; linetab = NULL; def_source = NULL; indexStabsLink = NULL; elfSym = NULL; sources = NULL; instrs = new Vector<DbeInstr*>; addrs = NULL; name_buf = NULL; current_name_format = Histable::NA; curr_srcinfo = NULL; curr_srcfile = NULL; srcinfo_list = NULL; defaultDbeLine = NULL; usrfunc = NULL; alias = NULL; instHTable = NULL; addrIndexHTable = NULL; isUsed = false; isHideFunc = false; inlinedSubr = NULL; inlinedSubrCnt = 0;} Function::~Function (){ free (mangled_name); free (match_name); free (comparable_name); free (name_buf); Destroy (linetab); Destroy (instrs); while (srcinfo_list) { SrcInfo *t = srcinfo_list; srcinfo_list = t->next; delete t; } delete sources; delete addrs; delete[] instHTable; delete[] addrIndexHTable; if (indexStabsLink) // Remove a link to the current function indexStabsLink->indexStabsLink = NULL;} char *Function::get_name (NameFormat nfmt){ if (nfmt == Histable::NA) { DbeView *dbeView = dbeSession->getView (0); if (dbeView) nfmt = dbeView->get_name_format (); } if (name_buf && (nfmt == current_name_format || nfmt == Histable::NA)) return name_buf; free (name_buf); current_name_format = nfmt; bool soname_fmt = Histable::soname_fmt (nfmt); int fname_fmt = Histable::fname_fmt (nfmt); if (fname_fmt == Histable::MANGLED) name_buf = xstrdup (mangled_name); else { if (module && module->is_fortran () && (streq (name, "MAIN") || streq (name, "MAIN_"))) name_buf = xstrdup (match_name); else name_buf = xstrdup (name); if (fname_fmt == Histable::SHORT) { int i = get_paren (name_buf); if (i != -1) name_buf[i] = (char) 0; } } if (soname_fmt) { char *fname = dbe_sprintf (NTXT ("%s [%s]"), name_buf, module->loadobject->get_name ()); free (name_buf); name_buf = fname; } return name_buf;} uint64_tFunction::get_addr (){ LoadObject *lo = module ? module->loadobject : NULL; int seg_idx = lo ? lo->seg_idx : -1; return MAKE_ADDRESS (seg_idx, img_offset);} Histable *Function::convertto (Histable_type type, Histable *obj){ Histable *res = NULL; SourceFile *source = (SourceFile*) obj; switch (type) { case INSTR: res = find_dbeinstr (0, 0); break; case LINE: { // mapPCtoLine will implicitly read line info if necessary res = mapPCtoLine (0, source); break; } case FUNCTION: res = this; break; case SOURCEFILE: res = def_source; break; default: assert (0); } return res;} voidFunction::set_name (char *string){ if (string == NULL) return; set_mangled_name (string); // strip away any globalization prefix, and save result for matching char *mname = string; if (strncmp (string, "$X", 2) == 0 || strncmp (string, ".X", 2) == 0) { // name was globalized char *n = strchr (string + 2, (int) '.'); if (n != NULL) mname = n + 1; } set_match_name (mname); name = NULL; if (module) { if (name == NULL && *match_name == '_') { int flag = DMGL_PARAMS; if (module->lang_code == Sp_lang_java) flag |= DMGL_JAVA; name = cplus_demangle (match_name, flag); } } if (name == NULL) // got demangled string name = dbe_strdup (match_name); set_comparable_name (name);} voidFunction::set_mangled_name (const char *string){ if (string) { free (mangled_name); mangled_name = dbe_strdup (string); }} voidFunction::set_match_name (const char *string){ if (string) { free (match_name); match_name = dbe_strdup (string); }} voidFunction::set_comparable_name (const char *string){ if (string) { free (comparable_name); comparable_name = dbe_strdup (string); // remove blanks from comparable_name for (char *s = comparable_name, *s1 = comparable_name;;) { if (*s == 0) { *s1 = 0; break; } else if (*s != ' ') { *s1 = *s; s1++; } s++; } }} // This function looks at the name of a function, and determines whether// or not it may be a derived function -- outline, mtask, or clone --// If it is, it writes the function name as demangled,// and sets a pointer to the function from which it was derivedvoidFunction::findDerivedFunctions () { MPFuncTypes ftype; int index; Function *fitem; unsigned long long line_no; char *namefmt; char *subname = mangled_name; char *demname; // see if we've already done this if ((flags & FUNC_FLAG_RESDER) != 0) return; // set flag for future flags = flags | FUNC_FLAG_RESDER; if (module == NULL) return; if (*subname != '_' || subname[1] != '$') // Not a specially named function return; // look for the current versions of naming if (strncmp (subname + 2, NTXT ("d1"), 2) == 0) // doall function ftype = MPF_DOALL; else if (strncmp (subname + 2, "p1", 2) == 0) // parallel region function ftype = MPF_PAR; else if (strncmp (subname + 2, "l1", 2) == 0) // single thread loop setup ftype = MPF_DOALL; else if (strncmp (subname + 2, "s1", 2) == 0) // parallel section function ftype = MPF_SECT; else if (strncmp (subname + 2, "t1", 2) == 0) // task function ftype = MPF_TASK; else if (strncmp (subname + 2, "o1", 2) == 0) // outline function { ftype = MPF_OUTL; isOutlineFunction = true; } else if (strncmp (subname + 2, "c1", 2) == 0) // clone function ftype = MPF_CLONE; else // Not an encoded name, just return return; // we know it's one of the above prefixes char *sub = dbe_strdup (name + 4); // starting with base-26 number char *p = sub; // skip the base-26 number, and extract the line number while (isalpha ((int) (*p)) != 0 && *p != 0) p++; line_no = atoll (p); // skip past the number to to the . while (*p != '.' && *p != 0) p++; if (*p == 0) { // can't be right free (sub); return; } // skip the trailing . p++; subname = p; bool foundmatch = false; // Find the function from which it is derived -- the one that matched subname Vec_loop (Function*, module->functions, index, fitem) { if (streq (subname, fitem->mangled_name)) { // found it foundmatch = true; usrfunc = fitem; // set the derived node if ((fitem->flags & FUNC_FLAG_RESDER) == 0) // ensure that it, too, is resolved if derived fitem->findDerivedFunctions (); // Build a demangled name switch (ftype) { case MPF_OUTL: isOutlineFunction = true; namefmt = GTXT ("%s -- outline code from line %lld [%s]"); derivedNode = fitem->find_dbeinstr (PCLineFlag, line_no); break; case MPF_PAR: namefmt = GTXT ("%s -- OMP parallel region from line %lld [%s]"); break; case MPF_DOALL: namefmt = GTXT ("%s -- Parallel loop from line %lld [%s]"); break; case MPF_SECT: namefmt = GTXT ("%s -- OMP sections from line %lld [%s]"); break; case MPF_CLONE: // Note that clones are handled differently -- no line number and // clones are NOT shown as called from the original // so after constructing the name, just return // later, establish link from clone to parent demname = dbe_sprintf (GTXT ("%s -- cloned version [%s]"), fitem->get_name (), name); free (name); // set the name to the demangled version name = demname; free (sub); derivedNode = fitem->find_dbeinstr (PCLineFlag, line_no); return; case MPF_TASK: namefmt = GTXT ("%s -- OMP task from line %lld [%s]"); break; default: free (sub); return; } // Finally, construct the demangled name demname = dbe_sprintf (namefmt, fitem->get_name (), line_no, name); free (name); name = demname; setLineFirst ((int) line_no); break; } } if (foundmatch == false && ftype == MPF_OUTL) { // Even if derived node was not found, we can demangle demname = dbe_sprintf (GTXT ("%s -- outline code [%s]"), subname, mangled_name); free (name); name = demname; } free (sub);} SrcInfo *Function::new_srcInfo (){ SrcInfo *t = new SrcInfo (); t->src_line = NULL; t->included_from = NULL; t->next = srcinfo_list; srcinfo_list = t; return t;} voidFunction::pushSrcFile (SourceFile* source, int /*lineno*/){ // create new file stack if (curr_srcfile == NULL) { curr_srcfile = source; return; } SrcInfo *src_info = new_srcInfo (); // In the ideal world, we need a DbeLine(III) here, // but right now it would make us later believe that there are // instructions generated for #include lines. To avoid that, // we ask for a DbeLine(II). src_info->src_line = curr_srcfile->find_dbeline (this, 0 /*lineno*/); if (src_info->src_line) { src_info->included_from = curr_srcinfo; curr_srcinfo = src_info; } curr_srcfile = source; setSource ();} SourceFile *Function::popSrcFile (){ if (curr_srcinfo != NULL) { curr_srcfile = curr_srcinfo->src_line->sourceFile; curr_srcinfo = curr_srcinfo->included_from; } else curr_srcfile = NULL; return curr_srcfile;} voidFunction::copy_PCInfo (Function *from){ if (line_first <= 0) line_first = from->line_first; if (line_last <= 0) line_last = from->line_last; if (def_source == NULL) def_source = from->def_source; for (int i = 0, sz = from->linetab ? from->linetab->size () : 0; i < sz; i++) { PCInfo *pcinf = from->linetab->fetch (i); DbeLine *dbeLine = pcinf->src_info->src_line; add_PC_info (pcinf->offset, dbeLine->lineno, dbeLine->sourceFile); }} voidFunction::add_PC_info (uint64_t offset, int lineno, SourceFile *cur_src){ if (lineno <= 0 || size < 0 || offset >= (uint64_t) size) return; if (cur_src == NULL) cur_src = curr_srcfile ? curr_srcfile : def_source; if (linetab == NULL) linetab = new Vector<PCInfo*>; int left = 0; int right = linetab->size () - 1; DbeLine *dbeline; while (left <= right) { int x = (left + right) / 2; PCInfo *pcinf = linetab->fetch (x); uint64_t pcinf_offset = ((uint64_t) pcinf->offset); if (offset == pcinf_offset) {Lines 1–500 of 1162. Load more
/* Copyright (C) 2021-2026 Free Software Foundation, Inc. Contributed by Oracle. 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, 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, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" #include <assert.h> #include <string.h> #include <ctype.h> #include "demangle.h" #include "util.h" #include "DbeSession.h" #include "Function.h" #include "Module.h" #include "LoadObject.h" #include "Settings.h" #include "DbeFile.h" #include "DbeView.h" struct SrcInfo { DbeLine *src_line; SrcInfo *included_from; SrcInfo *next; }; struct PCInfo { int64_t offset; int64_t size; SrcInfo *src_info; }; Function::Function (uint64_t _id) { id = _id; instr_id = id << 32; derivedNode = NULL; module = NULL; line_first = line_last = -1; isOutlineFunction = false; name = NULL; mangled_name = NULL; match_name = NULL; comparable_name = NULL; img_fname = NULL; img_offset = 0; chksum = 0; flags = 0; size = 0; save_addr = FUNC_NO_SAVE; linetab = NULL; def_source = NULL; indexStabsLink = NULL; elfSym = NULL; sources = NULL; instrs = new Vector<DbeInstr*>; addrs = NULL; name_buf = NULL; current_name_format = Histable::NA; curr_srcinfo = NULL; curr_srcfile = NULL; srcinfo_list = NULL; defaultDbeLine = NULL; usrfunc = NULL; alias = NULL; instHTable = NULL; addrIndexHTable = NULL; isUsed = false; isHideFunc = false; inlinedSubr = NULL; inlinedSubrCnt = 0; } Function::~Function () { free (mangled_name); free (match_name); free (comparable_name); free (name_buf); Destroy (linetab); Destroy (instrs); while (srcinfo_list) { SrcInfo *t = srcinfo_list; srcinfo_list = t->next; delete t; } delete sources; delete addrs; delete[] instHTable; delete[] addrIndexHTable; if (indexStabsLink) // Remove a link to the current function indexStabsLink->indexStabsLink = NULL; } char * Function::get_name (NameFormat nfmt) { if (nfmt == Histable::NA) { DbeView *dbeView = dbeSession->getView (0); if (dbeView) nfmt = dbeView->get_name_format (); } if (name_buf && (nfmt == current_name_format || nfmt == Histable::NA)) return name_buf; free (name_buf); current_name_format = nfmt; bool soname_fmt = Histable::soname_fmt (nfmt); int fname_fmt = Histable::fname_fmt (nfmt); if (fname_fmt == Histable::MANGLED) name_buf = xstrdup (mangled_name); else { if (module && module->is_fortran () && (streq (name, "MAIN") || streq (name, "MAIN_"))) name_buf = xstrdup (match_name); else name_buf = xstrdup (name); if (fname_fmt == Histable::SHORT) { int i = get_paren (name_buf); if (i != -1) name_buf[i] = (char) 0; } } if (soname_fmt) { char *fname = dbe_sprintf (NTXT ("%s [%s]"), name_buf, module->loadobject->get_name ()); free (name_buf); name_buf = fname; } return name_buf; } uint64_t Function::get_addr () { LoadObject *lo = module ? module->loadobject : NULL; int seg_idx = lo ? lo->seg_idx : -1; return MAKE_ADDRESS (seg_idx, img_offset); } Histable * Function::convertto (Histable_type type, Histable *obj) { Histable *res = NULL; SourceFile *source = (SourceFile*) obj; switch (type) { case INSTR: res = find_dbeinstr (0, 0); break; case LINE: { // mapPCtoLine will implicitly read line info if necessary res = mapPCtoLine (0, source); break; } case FUNCTION: res = this; break; case SOURCEFILE: res = def_source; break; default: assert (0); } return res; } void Function::set_name (char *string) { if (string == NULL) return; set_mangled_name (string); // strip away any globalization prefix, and save result for matching char *mname = string; if (strncmp (string, "$X", 2) == 0 || strncmp (string, ".X", 2) == 0) { // name was globalized char *n = strchr (string + 2, (int) '.'); if (n != NULL) mname = n + 1; } set_match_name (mname); name = NULL; if (module) { if (name == NULL && *match_name == '_') { int flag = DMGL_PARAMS; if (module->lang_code == Sp_lang_java) flag |= DMGL_JAVA; name = cplus_demangle (match_name, flag); } } if (name == NULL) // got demangled string name = dbe_strdup (match_name); set_comparable_name (name); } void Function::set_mangled_name (const char *string) { if (string) { free (mangled_name); mangled_name = dbe_strdup (string); } } void Function::set_match_name (const char *string) { if (string) { free (match_name); match_name = dbe_strdup (string); } } void Function::set_comparable_name (const char *string) { if (string) { free (comparable_name); comparable_name = dbe_strdup (string); // remove blanks from comparable_name for (char *s = comparable_name, *s1 = comparable_name;;) { if (*s == 0) { *s1 = 0; break; } else if (*s != ' ') { *s1 = *s; s1++; } s++; } } } // This function looks at the name of a function, and determines whether // or not it may be a derived function -- outline, mtask, or clone -- // If it is, it writes the function name as demangled, // and sets a pointer to the function from which it was derived void Function::findDerivedFunctions () { MPFuncTypes ftype; int index; Function *fitem; unsigned long long line_no; char *namefmt; char *subname = mangled_name; char *demname; // see if we've already done this if ((flags & FUNC_FLAG_RESDER) != 0) return; // set flag for future flags = flags | FUNC_FLAG_RESDER; if (module == NULL) return; if (*subname != '_' || subname[1] != '$') // Not a specially named function return; // look for the current versions of naming if (strncmp (subname + 2, NTXT ("d1"), 2) == 0) // doall function ftype = MPF_DOALL; else if (strncmp (subname + 2, "p1", 2) == 0) // parallel region function ftype = MPF_PAR; else if (strncmp (subname + 2, "l1", 2) == 0) // single thread loop setup ftype = MPF_DOALL; else if (strncmp (subname + 2, "s1", 2) == 0) // parallel section function ftype = MPF_SECT; else if (strncmp (subname + 2, "t1", 2) == 0) // task function ftype = MPF_TASK; else if (strncmp (subname + 2, "o1", 2) == 0) // outline function { ftype = MPF_OUTL; isOutlineFunction = true; } else if (strncmp (subname + 2, "c1", 2) == 0) // clone function ftype = MPF_CLONE; else // Not an encoded name, just return return; // we know it's one of the above prefixes char *sub = dbe_strdup (name + 4); // starting with base-26 number char *p = sub; // skip the base-26 number, and extract the line number while (isalpha ((int) (*p)) != 0 && *p != 0) p++; line_no = atoll (p); // skip past the number to to the . while (*p != '.' && *p != 0) p++; if (*p == 0) { // can't be right free (sub); return; } // skip the trailing . p++; subname = p; bool foundmatch = false; // Find the function from which it is derived -- the one that matched subname Vec_loop (Function*, module->functions, index, fitem) { if (streq (subname, fitem->mangled_name)) { // found it foundmatch = true; usrfunc = fitem; // set the derived node if ((fitem->flags & FUNC_FLAG_RESDER) == 0) // ensure that it, too, is resolved if derived fitem->findDerivedFunctions (); // Build a demangled name switch (ftype) { case MPF_OUTL: isOutlineFunction = true; namefmt = GTXT ("%s -- outline code from line %lld [%s]"); derivedNode = fitem->find_dbeinstr (PCLineFlag, line_no); break; case MPF_PAR: namefmt = GTXT ("%s -- OMP parallel region from line %lld [%s]"); break; case MPF_DOALL: namefmt = GTXT ("%s -- Parallel loop from line %lld [%s]"); break; case MPF_SECT: namefmt = GTXT ("%s -- OMP sections from line %lld [%s]"); break; case MPF_CLONE: // Note that clones are handled differently -- no line number and // clones are NOT shown as called from the original // so after constructing the name, just return // later, establish link from clone to parent demname = dbe_sprintf (GTXT ("%s -- cloned version [%s]"), fitem->get_name (), name); free (name); // set the name to the demangled version name = demname; free (sub); derivedNode = fitem->find_dbeinstr (PCLineFlag, line_no); return; case MPF_TASK: namefmt = GTXT ("%s -- OMP task from line %lld [%s]"); break; default: free (sub); return; } // Finally, construct the demangled name demname = dbe_sprintf (namefmt, fitem->get_name (), line_no, name); free (name); name = demname; setLineFirst ((int) line_no); break; } } if (foundmatch == false && ftype == MPF_OUTL) { // Even if derived node was not found, we can demangle demname = dbe_sprintf (GTXT ("%s -- outline code [%s]"), subname, mangled_name); free (name); name = demname; } free (sub); } SrcInfo * Function::new_srcInfo () { SrcInfo *t = new SrcInfo (); t->src_line = NULL; t->included_from = NULL; t->next = srcinfo_list; srcinfo_list = t; return t; } void Function::pushSrcFile (SourceFile* source, int /*lineno*/) { // create new file stack if (curr_srcfile == NULL) { curr_srcfile = source; return; } SrcInfo *src_info = new_srcInfo (); // In the ideal world, we need a DbeLine(III) here, // but right now it would make us later believe that there are // instructions generated for #include lines. To avoid that, // we ask for a DbeLine(II). src_info->src_line = curr_srcfile->find_dbeline (this, 0 /*lineno*/); if (src_info->src_line) { src_info->included_from = curr_srcinfo; curr_srcinfo = src_info; } curr_srcfile = source; setSource (); } SourceFile * Function::popSrcFile () { if (curr_srcinfo != NULL) { curr_srcfile = curr_srcinfo->src_line->sourceFile; curr_srcinfo = curr_srcinfo->included_from; } else curr_srcfile = NULL; return curr_srcfile; } void Function::copy_PCInfo (Function *from) { if (line_first <= 0) line_first = from->line_first; if (line_last <= 0) line_last = from->line_last; if (def_source == NULL) def_source = from->def_source; for (int i = 0, sz = from->linetab ? from->linetab->size () : 0; i < sz; i++) { PCInfo *pcinf = from->linetab->fetch (i); DbeLine *dbeLine = pcinf->src_info->src_line; add_PC_info (pcinf->offset, dbeLine->lineno, dbeLine->sourceFile); } } void Function::add_PC_info (uint64_t offset, int lineno, SourceFile *cur_src) { if (lineno <= 0 || size < 0 || offset >= (uint64_t) size) return; if (cur_src == NULL) cur_src = curr_srcfile ? curr_srcfile : def_source; if (linetab == NULL) linetab = new Vector<PCInfo*>; int left = 0; int right = linetab->size () - 1; DbeLine *dbeline; while (left <= right) { int x = (left + right) / 2; PCInfo *pcinf = linetab->fetch (x); uint64_t pcinf_offset = ((uint64_t) pcinf->offset); if (offset == pcinf_offset) {