| /* Copyright (C) 2021-2024 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 <sys/param.h> | |
| #include "util.h" | |
| #include "Elf.h" | |
| #include "Dwarf.h" | |
| #include "stab.h" | |
| #include "DbeSession.h" | |
| #include "CompCom.h" | |
| #include "Stabs.h" | |
| #include "LoadObject.h" | |
| #include "Module.h" | |
| #include "Function.h" | |
| #include "info.h" | |
| #include "StringBuilder.h" | |
| #include "DbeFile.h" | |
| #include "StringMap.h" | |
| #define DISASM_REL_NONE 0 /* symtab search only */ | |
| #define DISASM_REL_ONLY 1 /* relocation search only */ | |
| #define DISASM_REL_TARG 2 /* relocatoin then symtab */ | |
| /////////////////////////////////////////////////////////////////////////////// | |
| // class StabReader | |
| class StabReader | |
| { | |
| public: | |
| StabReader (Elf *_elf, Platform_t platform, int StabSec, int StabStrSec); | |
| ~StabReader () { }; | |
| char *get_type_name (int t); | |
| char *get_stab (struct stab *np, bool comdat); | |
| void parse_N_OPT (Module *mod, char *str); | |
| int stabCnt; | |
| int stabNum; | |
| private: | |
| Elf *elf; | |
| char *StabData; | |
| char *StabStrtab; | |
| char *StabStrtabEnd; | |
| int StrTabSize; | |
| int StabEntSize; | |
| }; | |
| /////////////////////////////////////////////////////////////////////////////// | |
| // class Symbol | |
| class Symbol | |
| { | |
| public: | |
| Symbol (Vector<Symbol*> *vec = NULL); | |
| ~Symbol () | |
| { | |
| free (name); | |
| } | |
| inline Symbol * | |
| cardinal () | |
| { | |
| return alias ? alias : this; | |
| } | |
| static void dump (Vector<Symbol*> *vec, char*msg); | |
| Function *func; | |
| Sp_lang_code lang_code; | |
| uint64_t value; // st_value used in sym_name() | |
| uint64_t save; | |
| int64_t size; | |
| uint64_t img_offset; // image offset in the ELF file | |
| char *name; | |
| Symbol *alias; | |
| int local_ind; | |
| int flags; | |
| bool defined; | |
| }; | |
| Symbol::Symbol (Vector<Symbol*> *vec) | |
| { | |
| func = NULL; | |
| lang_code = Sp_lang_unknown; | |
| value = 0; | |
| save = 0; | |
| size = 0; | |
| img_offset = 0; | |
| name = NULL; | |
| alias = NULL; | |
| local_ind = -1; | |
| flags = 0; | |
| defined = false; | |
| if (vec) | |
| vec->append (this); | |
| } | |
| void | |
| Symbol::dump (Vector<Symbol*> *vec, char*msg) | |
| { | |
| if (!DUMP_ELF_SYM || vec == NULL || vec->size () == 0) | |
| return; | |
| printf (NTXT ("======= Symbol::dump: %s =========\n" | |
| " value | img_offset | flags|local_ind|\n"), msg); | |
| for (int i = 0; i < vec->size (); i++) | |
| { | |
| Symbol *sp = vec->fetch (i); | |
| printf (NTXT (" %3d %8lld |0x%016llx |%5d |%8d |%s\n"), | |
| i, (long long) sp->value, (long long) sp->img_offset, sp->flags, | |
| sp->local_ind, sp->name ? sp->name : NTXT ("NULL")); | |
| } | |
| printf (NTXT ("\n===== END of Symbol::dump: %s =========\n\n"), msg); | |
| } | |
| // end of class Symbol | |
| /////////////////////////////////////////////////////////////////////////////// | |
| /////////////////////////////////////////////////////////////////////////////// | |
| // class Reloc | |
| class Reloc | |
| { | |
| public: | |
| Reloc (); | |
| ~Reloc (); | |
| uint64_t type; | |
| uint64_t value; | |
| uint64_t addend; | |
| char *name; | |
| }; | |
| Reloc::Reloc () | |
| { | |
| type = 0; | |
| value = 0; | |
| addend = 0; | |
| name = NULL; | |
| } | |
| Reloc::~Reloc () | |
| { | |
| free (name); | |
| } | |
| // end of class Reloc | |
| /////////////////////////////////////////////////////////////////////////////// | |
| enum | |
| { | |
| SYM_PLT = 1 << 0, | |
| SYM_UNDEF = 1 << 1 | |
| }; | |
| enum Section_type | |
| { | |
| COMM1_SEC = 0x10000000, | |
| COMM_SEC = 0x20000000, | |
| INFO_SEC = 0x30000000, | |
| LOOP_SEC = 0x40000000 | |
| }; | |
| struct cpf_stabs_t | |
| { | |
| uint32_t type; // Archive::AnalyzerInfoType | |
| uint32_t offset; // offset in .__analyzer_info | |
| Module *module; // table for appropriate Module | |
| }; | |
| static char *get_info_com (int type, int32_t copy_inout); | |
| static char *get_lp_com (unsigned hints, int parallel, char *dep); | |
| static int ComCmp (const void *a, const void *b); | |
| static ino64_t _src_inode = 0; | |
| static char *_src_name; | |
| // Comparing name | |
| static int | |
| SymNameCmp (const void *a, const void *b) | |
| { | |
| Symbol *item1 = *((Symbol **) a); | |
| Symbol *item2 = *((Symbol **) b); | |
| return (item1->name == NULL) ? -1 : | |
| (item2->name == NULL) ? 1 : strcmp (item1->name, item2->name); | |
| } | |
| // Comparing value: for sorting | |
| static int | |
| SymValueCmp (const void *a, const void *b) | |
| { | |
| Symbol *item1 = *((Symbol **) a); | |
| Symbol *item2 = *((Symbol **) b); | |
| return (item1->value > item2->value) ? 1 : | |
| (item1->value == item2->value) ? SymNameCmp (a, b) : -1; | |
| } | |
| // Comparing value: for searching (source name is always NULL) | |
| static int | |
| SymFindCmp (const void *a, const void *b) | |
| { | |
| Symbol *item1 = *((Symbol **) a); | |
| Symbol *item2 = *((Symbol **) b); | |
| if (item1->value < item2->value) | |
| return -1; | |
| if (item1->value < item2->value + item2->size | |
| || item1->value == item2->value) // item2->size == 0 | |
| return 0; | |
| return 1; | |
| } | |
| // Comparing value for sorting. It is used only for searching aliases. | |
| static int | |
| SymImgOffsetCmp (const void *a, const void *b) | |
| { | |
| Symbol *item1 = *((Symbol **) a); | |
| Symbol *item2 = *((Symbol **) b); | |
| return (item1->img_offset > item2->img_offset) ? 1 : | |
| (item1->img_offset == item2->img_offset) ? SymNameCmp (a, b) : -1; | |
| } | |
| static int | |
| RelValueCmp (const void *a, const void *b) | |
| { | |
| Reloc *item1 = *((Reloc **) a); | |
| Reloc *item2 = *((Reloc **) b); | |
| return (item1->value > item2->value) ? 1 : | |
| (item1->value == item2->value) ? 0 : -1; | |
| } | |
| Stabs * | |
| Stabs::NewStabs (char *_path, char *lo_name) | |
| { | |
| Stabs *stabs = new Stabs (_path, lo_name); | |
| if (stabs->status != Stabs::DBGD_ERR_NONE) | |
| { | |
| delete stabs; | |
| return NULL; | |
| } | |
| return stabs; | |
| } | |
| Stabs::Stabs (char *_path, char *_lo_name) | |
| { | |
| path = dbe_strdup (_path); | |
| lo_name = dbe_strdup (_lo_name); | |
| SymLstByName = NULL; | |
| pltSym = NULL; | |
| SymLst = new Vector<Symbol*>; | |
| RelLst = new Vector<Reloc*>; | |
| RelPLTLst = new Vector<Reloc*>; | |
| LocalLst = new Vector<Symbol*>; | |
| LocalFile = new Vector<char*>; | |
| LocalFileIdx = new Vector<int>; | |
| last_PC_to_sym = NULL; | |
| dwarf = NULL; | |
| elfDbg = NULL; | |
| elfDis = NULL; | |
| stabsModules = NULL; | |
| textsz = 0; | |
| wsize = Wnone; | |
| st_check_symtab = st_check_relocs = false; | |
| status = DBGD_ERR_NONE; | |
| if (openElf (false) == NULL) | |
| return; | |
| switch (elfDis->elf_getclass ()) | |
| { | |
| case ELFCLASS32: | |
| wsize = W32; | |
| break; | |
| case ELFCLASS64: | |
| wsize = W64; | |
| break; | |
| } | |
| isRelocatable = elfDis->elf_getehdr ()->e_type == ET_REL; | |
| for (unsigned int pnum = 0; pnum < elfDis->elf_getehdr ()->e_phnum; pnum++) | |
| { | |
| Elf_Internal_Phdr *phdr = elfDis->get_phdr (pnum); | |
| if (phdr->p_type == PT_LOAD && phdr->p_flags == (PF_R | PF_X)) | |
| { | |
| if (textsz == 0) | |
| textsz = phdr->p_memsz; | |
| else | |
| { | |
| textsz = 0; | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| Stabs::~Stabs () | |
| { | |
| delete SymLstByName; | |
| Destroy (SymLst); | |
| Destroy (RelLst); | |
| Destroy (RelPLTLst); | |
| Destroy (LocalFile); | |
| delete elfDis; | |
| delete dwarf; | |
| delete LocalLst; | |
| delete LocalFileIdx; | |
| delete stabsModules; | |
| free (path); | |
| free (lo_name); | |
| } | |
| Elf * | |
| Stabs::openElf (char *fname, Stab_status &st) | |
| { | |
| Elf::Elf_status elf_status; | |
| Elf *elf = Elf::elf_begin (fname, &elf_status); | |
| if (elf == NULL) | |
| { | |
| switch (elf_status) | |
| { | |
| case Elf::ELF_ERR_CANT_OPEN_FILE: | |
| case Elf::ELF_ERR_CANT_MMAP: | |
| case Elf::ELF_ERR_BIG_FILE: | |
| st = DBGD_ERR_CANT_OPEN_FILE; | |
| break; | |
| case Elf::ELF_ERR_BAD_ELF_FORMAT: | |
| default: | |
| st = DBGD_ERR_BAD_ELF_FORMAT; | |
| break; | |
| } | |
| return NULL; | |
| } | |
| if (elf->elf_version (EV_CURRENT) == EV_NONE) | |
| { | |
| // ELF library out of date | |
| delete elf; | |
| st = DBGD_ERR_BAD_ELF_LIB; | |
| return NULL; | |
| } | |
| Elf_Internal_Ehdr *ehdrp = elf->elf_getehdr (); | |
| if (ehdrp == NULL) | |
| { | |
| // check machine | |
| delete elf; | |
| st = DBGD_ERR_BAD_ELF_FORMAT; | |
| return NULL; | |
| } | |
| switch (ehdrp->e_machine) | |
| { | |
| case EM_SPARC: | |
| platform = Sparc; | |
| break; | |
| case EM_SPARC32PLUS: | |
| platform = Sparcv8plus; | |
| break; | |
| case EM_SPARCV9: | |
| platform = Sparcv9; | |
| break; | |
| case EM_386: | |
| // case EM_486: | |
| platform = Intel; | |
| break; | |
| case EM_X86_64: | |
| platform = Amd64; | |
| break; | |
| case EM_AARCH64: | |
| platform = Aarch64; | |
| break; | |
| default: | |
| platform = Unknown; | |
| break; | |
| } | |
| return elf; | |
| } | |
| Elf * | |
| Stabs::openElf (bool dbg_info) | |
| { | |
| if (status != DBGD_ERR_NONE) | |
| return NULL; | |
| if (elfDis == NULL) | |
| { | |
| elfDis = openElf (path, status); | |
| if (elfDis == NULL) | |
| return NULL; | |
| } | |
| if (!dbg_info) | |
| return elfDis; | |
| if (elfDbg == NULL) | |
| { | |
| elfDbg = elfDis->find_ancillary_files (lo_name); | |
| if (elfDbg == NULL) | |
| elfDbg = elfDis; | |
| } | |
| return elfDbg; | |
| } | |
| bool | |
| Stabs::read_symbols (Vector<Function*> *functions) | |
| { | |
| if (openElf (true) == NULL) | |
| return false; | |
| check_Symtab (); | |
| check_Relocs (); | |
| if (functions) | |
| { | |
| Function *fp; | |
| int index; | |
| Vec_loop (Function*, functions, index, fp) | |
| { | |
| fp->img_fname = path; | |
| } | |
| } | |
| return true; | |
| } | |
| char * | |
| Stabs::sym_name (uint64_t target, uint64_t instr, int flag) | |
| { | |
| long index; | |
| if (flag == DISASM_REL_ONLY || flag == DISASM_REL_TARG) | |
| { | |
| Reloc *relptr = new Reloc; | |
| relptr->value = instr; | |
| index = RelLst->bisearch (0, -1, &relptr, RelValueCmp); | |
| if (index >= 0) | |
| { | |
| delete relptr; | |
| return RelLst->fetch (index)->name; | |
| } | |
| if (!is_relocatable ()) | |
| { | |
| relptr->value = target; | |
| index = RelPLTLst->bisearch (0, -1, &relptr, RelValueCmp); | |
| if (index >= 0) | |
| { | |
| delete relptr; | |
| return RelPLTLst->fetch (index)->name; | |
| } | |
| } | |
| delete relptr; | |
| } | |
| if (flag == DISASM_REL_NONE || flag == DISASM_REL_TARG || !is_relocatable ()) | |
| { | |
| Symbol *sptr; | |
| sptr = map_PC_to_sym (target); | |
| if (sptr && sptr->value == target) | |
| return sptr->name; | |
| } | |
| return NULL; | |
| } | |
| Symbol * | |
| Stabs::map_PC_to_sym (uint64_t pc) | |
| { | |
| if (pc == 0) | |
| return NULL; | |
| if (last_PC_to_sym && last_PC_to_sym->value <= pc | |
| && last_PC_to_sym->value + last_PC_to_sym->size > pc) | |
| return last_PC_to_sym; | |
| Symbol *sym = new Symbol; | |
| sym->value = pc; | |
| long index = SymLst->bisearch (0, -1, &sym, SymFindCmp); | |
| delete sym; | |
| if (index >= 0) | |
| { | |
| last_PC_to_sym = SymLst->fetch (index)->cardinal (); | |
| return last_PC_to_sym; | |
| } | |
| return NULL; | |
| } | |
| Function * | |
| Stabs::map_PC_to_func (uint64_t pc, uint64_t &low_pc, Vector<Function*> *functions) | |
| { | |
| int index; | |
| Function *func; | |
| Symbol *sptr = map_PC_to_sym (pc); | |
| if (sptr == NULL) | |
| return NULL; | |
| if (sptr->func) | |
| { | |
| low_pc = sptr->value; | |
| return sptr->func; | |
| } | |
| if (functions) | |
| { | |
| Vec_loop (Function*, functions, index, func) | |
| { | |
| if (func->img_offset == sptr->img_offset) | |
| { | |
| sptr->func = func->cardinal (); | |
| low_pc = sptr->value; | |
| return sptr->func; | |
| } | |
| } | |
| } | |
| return NULL; | |
| } | |
| Stabs::Stab_status | |
| Stabs::read_stabs (ino64_t srcInode, Module *module, Vector<ComC*> *comComs, | |
| bool readDwarf) | |
| { | |
| if (module) | |
| module->setIncludeFile (NULL); | |
| if (openElf (true) == NULL) | |
| return status; | |
| check_Symtab (); | |
| // read compiler commentary from .compcom1, .compcom, | |
| // .info, .loops, and .loopview sections | |
| if (comComs) | |
| { | |
| _src_inode = srcInode; | |
| _src_name = module && module->file_name ? get_basename (module->file_name) : NULL; | |
| if (!check_Comm (comComs)) | |
| // .loops, and .loopview are now in .compcom | |
| check_Loop (comComs); | |
| // should not read it after .info goes into .compcom | |
| check_Info (comComs); | |
| comComs->sort (ComCmp); | |
| } | |
| // get stabs info | |
| Stab_status statusStabs = DBGD_ERR_NO_STABS; | |
| #define SRC_LINE_STABS(sec, secStr, comdat) \ | |
| if ((elfDbg->sec) && (elfDbg->secStr) && \ | |
| srcline_Stabs(module, elfDbg->sec, elfDbg->secStr, comdat) == DBGD_ERR_NONE) \ | |
| statusStabs = DBGD_ERR_NONE | |
| SRC_LINE_STABS (stabExcl, stabExclStr, false); | |
| SRC_LINE_STABS (stab, stabStr, false); | |
| SRC_LINE_STABS (stabIndex, stabIndexStr, true); | |
| // read Dwarf, if any sections found | |
| if (elfDbg->dwarf && readDwarf) | |
| { | |
| openDwarf ()->srcline_Dwarf (module); | |
| if (dwarf && dwarf->status == DBGD_ERR_NONE) | |
| return DBGD_ERR_NONE; | |
| } | |
| return statusStabs; | |
| } | |
| static int | |
| ComCmp (const void *a, const void *b) | |
| { | |
| ComC *item1 = *((ComC **) a); | |
| ComC *item2 = *((ComC **) b); | |
| return (item1->line > item2->line) ? 1 : | |
| (item1->line < item2->line) ? -1 : | |
| (item1->sec > item2->sec) ? 1 : | |
| (item1->sec < item2->sec) ? -1 : 0; | |
| } | |
| static int | |
| check_src_name (char *srcName) | |
| { | |
| if (_src_name && srcName && streq (_src_name, get_basename (srcName))) | |
| return 1; | |
| if (_src_inode == (ino64_t) - 1) | |
| return 0; | |
| DbeFile *dbeFile = dbeSession->getDbeFile (srcName, DbeFile::F_SOURCE); | |
| char *path = dbeFile->get_location (); | |
| return (path == NULL || dbeFile->sbuf.st_ino != _src_inode) ? 0 : 1; | |
| } | |
| bool | |
| Stabs::check_Comm (Vector<ComC*> *comComs) | |
| { | |
| int sz = comComs->size (); | |
| Elf *elf = openElf (true); | |
| if (elf == NULL) | |
| return false; | |
| for (unsigned int sec = 1; sec < elf->elf_getehdr ()->e_shnum; sec++) | |
| { | |
| char *name = elf->get_sec_name (sec); | |
| if (name == NULL) | |
| continue; | |
| Section_type sec_type; | |
| if (streq (name, NTXT (".compcom"))) | |
| sec_type = COMM_SEC; | |
| else if (streq (name, NTXT (".compcom1"))) | |
| sec_type = COMM1_SEC; | |
| else | |
| continue; | |
| // find header, set messages id & visibility if succeed | |
| CompComment *cc = new CompComment (elf, sec); | |
| int cnt = cc->compcom_open ((CheckSrcName) check_src_name); | |
| // process messages | |
| for (int index = 0; index < cnt; index++) | |
| { | |
| int visible; | |
| compmsg msg; | |
| char *str = cc->compcom_format (index, &msg, visible); | |
| if (str) | |
| { | |
| ComC *citem = new ComC; | |
| citem->sec = sec_type + index; | |
| citem->type = msg.msg_type; | |
| citem->visible = visible; | |
| citem->line = (msg.lineno < 1) ? 1 : msg.lineno; | |
| citem->com_str = str; | |
| comComs->append (citem); | |
| } | |
| } | |
| delete cc; | |
| } | |
| return (sz != comComs->size ()); | |
| } | |
| static int | |
| targetOffsetCmp (const void *a, const void *b) | |
| { | |
| uint32_t o1 = ((target_info_t *) a)->offset; | |
| uint32_t o2 = ((target_info_t *) b)->offset; | |
| return (o1 >= o2); | |
| } | |
| void | |
| Stabs::check_AnalyzerInfo () | |
| { | |
| Elf *elf = openElf (true); | |
| if ((elf == NULL) || (elf->analyzerInfo == 0)) | |
| { | |
| Dprintf (DEBUG_STABS, NTXT ("Stabs::check_AnalyzerInfo: Null AnalyzerInfo section\n")); | |
| return; // inappropriate, but ignored anyway | |
| } | |
| Elf_Data *data = elf->elf_getdata (elf->analyzerInfo); | |
| int InfoSize = (int) data->d_size; | |
| char *InfoData = (char *) data->d_buf; | |
| int InfoAlign = (int) data->d_align; | |
| AnalyzerInfoHdr h; | |
| unsigned infoHdr_sz = sizeof (AnalyzerInfoHdr); | |
| int table, entry; | |
| int read = 0; | |
| Module *mitem; | |
| int index = 0; | |
| if (InfoSize <= 0) | |
| return; | |
| uint64_t baseAddr = elf->get_baseAddr (); | |
| Dprintf (DEBUG_STABS, NTXT ("Stabs::check_AnalyzerInfo size=%d @0x%lx (align=%d) base=0x%llx\n"), | |
| InfoSize, (ul_t) InfoData, InfoAlign, (long long) baseAddr); | |
| Dprintf (DEBUG_STABS, NTXT ("analyzerInfoMap has %lld entries\n"), (long long) analyzerInfoMap.size ()); | |
| if (analyzerInfoMap.size () == 0) | |
| { | |
| Dprintf (DEBUG_STABS, NTXT ("No analyzerInfoMap available!\n")); | |
| return; | |
| } | |
| // verify integrity of analyzerInfoMap before reading analyzerInfo | |
| unsigned count = 0; | |
| Module *lastmod = NULL; | |
| for (index = 0; index < analyzerInfoMap.size (); index++) | |
| { | |
| cpf_stabs_t map = analyzerInfoMap.fetch (index); | |
| if (map.type > 3) | |
| { | |
| Dprintf (DEBUG_STABS, NTXT ("analyzerInfo contains table of unknown type %d for %s\n"), | |
| map.type, map.module->get_name ()); | |
| return; | |
| } | |
| if (map.module != lastmod) | |
| { | |
| if (lastmod != NULL) | |
| Dprintf (DEBUG_STABS, "analyzerInfo contains %d 0x0 offset tables for %s\n", | |
| count, lastmod->get_name ()); | |
| count = 0; | |
| } | |
| count += (map.offset == 0x0); // only check for 0x0 tables for now | |
| if (count > 4) | |
| { | |
| Dprintf (DEBUG_STABS, NTXT ("analyzerInfo contains too many 0x0 offset tables for %s\n"), | |
| map.module->get_name ()); | |
| return; | |
| } | |
| lastmod = map.module; | |
| } | |
| index = 0; | |
| while ((index < analyzerInfoMap.size ()) && (read < InfoSize)) | |
| { | |
| for (table = 0; table < 3; table++) | |
| { // memory operations (ld, st, prefetch) | |
| // read the table header | |
| memcpy ((void *) &h, (const void *) InfoData, infoHdr_sz); | |
| InfoData += infoHdr_sz; | |
| read += infoHdr_sz; | |
| // use map for appropriate module | |
| cpf_stabs_t map = analyzerInfoMap.fetch (index); | |
| index++; | |
| mitem = map.module; | |
| Dprintf (DEBUG_STABS, "Table %d offset=0x%04x " | |
| "text_labelref=0x%08llx entries=%d version=%d\n" | |
| "itype %d offset=0x%04x module=%s\n", table, read, | |
| (long long) (h.text_labelref - baseAddr), h.entries, | |
| h.version, map.type, map.offset, map.module->get_name ()); | |
| // read the table entries | |
| for (entry = 0; entry < h.entries; entry++) | |
| { | |
| memop_info_t *m = new memop_info_t; | |
| unsigned memop_info_sz = sizeof (memop_info_t); | |
| memcpy ((void *) m, (const void *) InfoData, memop_info_sz); | |
| InfoData += memop_info_sz; | |
| read += memop_info_sz; | |
| m->offset += (uint32_t) (h.text_labelref - baseAddr); | |
| Dprintf (DEBUG_STABS, NTXT ("%4d(%d): offset=0x%04x id=0x%08x sig=0x%08x dtid=0x%08x\n"), | |
| entry, table, m->offset, m->id, m->signature, m->datatype_id); | |
| switch (table) | |
| { | |
| case CPF_INSTR_TYPE_LD: | |
| mitem->ldMemops.append (m); | |
| break; | |
| case CPF_INSTR_TYPE_ST: | |
| mitem->stMemops.append (m); | |
| break; | |
| case CPF_INSTR_TYPE_PREFETCH: | |
| mitem->pfMemops.append (m); | |
| break; | |
| } | |
| } | |
| // following re-alignment should be redundant | |
| //InfoData+=(read%InfoAlign); read+=(read%InfoAlign); // re-align | |
| } | |
| for (table = 3; table < 4; table++) | |
| { // branch targets | |
| memcpy ((void *) &h, (const void *) InfoData, infoHdr_sz); | |
| InfoData += infoHdr_sz; | |
| read += infoHdr_sz; | |
| // use map for appropriate module | |
| cpf_stabs_t map = analyzerInfoMap.fetch (index); | |
| index++; | |
| mitem = map.module; | |
| Dprintf (DEBUG_STABS, "Table %d offset=0x%04x " | |
| "text_labelref=0x%08llx entries=%d version=%d\n" | |
| "itype %d offset=0x%04x module=%s\n", table, read, | |
| (long long) (h.text_labelref - baseAddr), h.entries, | |
| h.version, map.type, map.offset, map.module->get_name ()); | |
| for (entry = 0; entry < h.entries; entry++) | |
| { | |
| target_info_t *t = new target_info_t; | |
| unsigned target_info_sz = sizeof (target_info_t); | |
| memcpy ((void *) t, (const void *) InfoData, target_info_sz); | |
| InfoData += target_info_sz; | |
| read += target_info_sz; | |
| t->offset += (uint32_t) (h.text_labelref - baseAddr); | |
| Dprintf (DEBUG_STABS, NTXT ("%4d(%d): offset=0x%04x\n"), entry, | |
| table, t->offset); | |
| // the list of branch targets needs to be in offset sorted order | |
| // and doing it here before archiving avoids the need to do it | |
| // each time the archive is read. | |
| mitem->bTargets.incorporate (t, targetOffsetCmp); | |
| } | |
| Dprintf (DEBUG_STABS, NTXT ("bTargets for %s has %lld items (last=0x%04x)\n"), | |
| mitem->get_name (), (long long) mitem->bTargets.size (), | |
| (mitem->bTargets.fetch (mitem->bTargets.size () - 1))->offset); | |
| Dprintf (DEBUG_STABS, "read=%d at end of bTargets (InfoData=0x%lx)\n", | |
| read, (ul_t) InfoData); | |
| InfoData += (read % InfoAlign); | |
| read += (read % InfoAlign); // re-align | |
| Dprintf (DEBUG_STABS, "read=%d at end of bTargets (InfoData=0x%lx)\n", | |
| read, (ul_t) InfoData); | |
| } | |
| Dprintf (DEBUG_STABS, "Stabs::check_AnalyzerInfo bytes read=%lld (index=%lld/%lld)\n", | |
| (long long) read, (long long) index, | |
| (long long) analyzerInfoMap.size ()); | |
| } | |
| } | |
| void | |
| Stabs::check_Info (Vector<ComC*> *comComs) | |
| { | |
| Elf *elf = openElf (true); | |
| if (elf == NULL || elf->info == 0) | |
| return; | |
| Elf_Data *data = elf->elf_getdata (elf->info); | |
| uint64_t InfoSize = data->d_size; | |
| char *InfoData = (char *) data->d_buf; | |
| bool get_src = false; | |
| for (int h_num = 0; InfoSize; h_num++) | |
| { | |
| if (InfoSize < sizeof (struct info_header)) | |
| return; | |
| struct info_header *h = (struct info_header*) InfoData; | |
| if (h->endian != '\0' || h->magic[0] != 'S' || h->magic[1] != 'U' | |
| || h->magic[2] != 'N') | |
| return; | |
| if (h->len < InfoSize || h->len < sizeof (struct info_header) || (h->len & 3)) | |
| return; | |
| char *fname = InfoData + sizeof (struct info_header); | |
| InfoData += h->len; | |
| InfoSize -= h->len; | |
| get_src = check_src_name (fname); | |
| for (uint32_t e_num = 0; e_num < h->cnt; ++e_num) | |
| { | |
| if (InfoSize < sizeof (struct entry_header)) | |
| return; | |
| struct entry_header *e = (struct entry_header*) InfoData; | |
| if (InfoSize < e->len) | |
| return; | |
| int32_t copy_inout = 0; | |
| if (e->len > sizeof (struct entry_header)) | |
| if (e->type == F95_COPYINOUT) | |
| copy_inout = *(int32_t*) (InfoData + sizeof (struct entry_header)); | |
| InfoData += e->len; | |
| InfoSize -= e->len; | |
| if (get_src) | |
| { | |
| ComC *citem = new ComC; | |
| citem->sec = INFO_SEC + h_num; | |
| citem->type = e->msgnum & 0xFFFFFF; | |
| citem->visible = CCMV_ALL; | |
| citem->line = e->line; | |
| citem->com_str = get_info_com (citem->type, copy_inout); | |
| comComs->append (citem); | |
| } | |
| } | |
| if (get_src) | |
| break; | |
| } | |
| } | |
| static char * | |
| get_info_com (int type, int32_t copy_inout) | |
| { | |
| switch (type) | |
| { | |
| case 1: | |
| return dbe_sprintf (GTXT ("In the call below, parameter number %d caused a copy-in -- loop(s) inserted"), | |
| copy_inout); | |
| case 2: | |
| return dbe_sprintf (GTXT ("In the call below, parameter number %d caused a copy-out -- loop(s) inserted"), | |
| copy_inout); | |
| case 3: | |
| return dbe_sprintf (GTXT ("In the call below, parameter number %d caused a copy-in and a copy-out -- loops inserted"), | |
| copy_inout); | |
| case 4: | |
| return dbe_strdup (GTXT ("Alignment of variables in common block may cause performance degradation")); | |
| case 5: | |
| return dbe_strdup (GTXT ("DO statement bounds lead to no executions of the loop")); | |
| default: | |
| return dbe_strdup (NTXT ("")); | |
| } | |
| } | |
| void | |
| Stabs::check_Loop (Vector<ComC*> *comComs) | |
| { | |
| Elf *elf = openElf (true); | |
| if (elf == NULL) | |
| return; | |
| StringBuilder sb; | |
| for (unsigned int sec = 1; sec < elf->elf_getehdr ()->e_shnum; sec++) | |
| { | |
| char *name = elf->get_sec_name (sec); | |
| if (name == NULL) | |
| continue; | |
| if (!streq (name, NTXT (".loops")) && !streq (name, NTXT (".loopview"))) | |
| continue; | |
| Elf_Data *data = elf->elf_getdata (sec); | |
| size_t LoopSize = (size_t) data->d_size, len; | |
| char *LoopData = (char *) data->d_buf; | |
| int remainder, i; | |
| char src[2 * MAXPATHLEN], buf1[MAXPATHLEN], buf2[MAXPATHLEN]; | |
| char **dep_str = NULL; | |
| bool get_src = false; | |
| while ((LoopSize > 0) && !get_src && | |
| (strncmp (LoopData, NTXT ("Source:"), 7) == 0)) | |
| { | |
| // The first three items in a .loops subsection are three strings. | |
| // Source: ... | |
| // Version: ... | |
| // Number of loops: ... | |
| sscanf (LoopData, NTXT ("%*s%s"), src); | |
| len = strlen (LoopData) + 1; | |
| LoopData += len; | |
| LoopSize -= len; | |
| sscanf (LoopData, NTXT ("%*s%*s%s"), buf1); | |
| // double version = atof(buf1); | |
| len = strlen (LoopData) + 1; | |
| LoopData += len; | |
| LoopSize -= len; | |
| get_src = check_src_name (src); | |
| sscanf (LoopData, NTXT ("%*s%*s%*s%s%s"), buf1, buf2); | |
| int n_loop = atoi (buf1); | |
| int n_depend = atoi (buf2); | |
| len = strlen (LoopData) + 1; | |
| LoopData += len; | |
| LoopSize -= len; | |
| if (get_src && (n_loop > 0)) | |
| { | |
| dep_str = new char*[n_loop]; | |
| for (i = 0; i < n_loop; i++) | |
| dep_str[i] = NULL; | |
| } | |
| // printf("Source: %s\nVersion: %f\nLoop#: %d\nDepend#: %d\n", | |
| // src, version, n_loop, n_depend); | |
| // Read in the strings that contain the list of variables that cause | |
| // data dependencies inside of loops. Not every loop has such a list | |
| // of variables. | |
| // | |
| // Example: if loop #54 has data dependencies caused by the | |
| // variables named i, j and foo, then the string that represents | |
| // this in the .loops section looks like this: | |
| // | |
| // .asciz "54:i.j.foo" | |
| // | |
| // The variable names are delimited with . | |
| // | |
| // For now, store these strings in an array, and add them into | |
| // the loop structure when we read in the numeric loop info | |
| // (that's what we read in next.) | |
| // | |
| // printf("\tDependenncies:\n"); | |
| for (i = 0; i < n_depend; i++) | |
| { | |
| len = strlen (LoopData) + 1; | |
| LoopData += len; | |
| LoopSize -= len; | |
| if (dep_str != NULL) | |
| { | |
| char *dep_buf1 = dbe_strdup (LoopData); | |
| char *ptr = strtok (dep_buf1, NTXT (":")); | |
| if (ptr != NULL) | |
| { | |
| int index = atoi (ptr); | |
| bool dep_first = true; | |
| sb.setLength (0); | |
| while ((ptr = strtok (NULL, NTXT (", "))) != NULL) | |
| { | |
| if (dep_first) | |
| dep_first = false; | |
| else | |
| sb.append (NTXT (", ")); | |
| sb.append (ptr); | |
| } | |
| if (sb.length () > 0 && index < n_loop) | |
| dep_str[index] = sb.toString (); | |
| } | |
| free (dep_buf1); | |
| } | |
| } | |
| // Adjust Data pointer so that it is word aligned. | |
| remainder = (int) (((unsigned long) LoopData) % 4); | |
| if (remainder != 0) | |
| { | |
| len = 4 - remainder; | |
| LoopData += len; | |
| LoopSize -= len; | |
| } | |
| // Read in the loop info, one loop at a time. | |
| for (i = 0; i < n_loop; i++) | |
| { | |
| int loopid = *((int *) LoopData); | |
| LoopData += 4; | |
| int line_no = *((int *) LoopData); | |
| if (line_no < 1) // compiler has trouble on this | |
| line_no = 1; | |
| LoopData += 4; | |
| // int nest = *((int *) LoopData); | |
| LoopData += 4; | |
| int parallel = *((int *) LoopData); | |
| LoopData += 4; | |
| unsigned hints = *((unsigned *) LoopData); | |
| LoopData += 4; | |
| // int count = *((int *) LoopData); | |
| LoopData += 4; | |
| LoopSize -= 24; | |
| if (!get_src || (loopid >= n_loop)) | |
| continue; | |
| ComC *citem = new ComC; | |
| citem->sec = LOOP_SEC + i; | |
| citem->type = hints; | |
| citem->visible = CCMV_ALL; | |
| citem->line = line_no; | |
| citem->com_str = get_lp_com (hints, parallel, dep_str[loopid]); | |
| comComs->append (citem); | |
| } | |
| if (dep_str) | |
| { | |
| for (i = 0; i < n_loop; i++) | |
| free (dep_str[i]); | |
| delete[] dep_str; | |
| dep_str = NULL; | |
| } | |
| } | |
| } | |
| } | |
| static char * | |
| get_lp_com (unsigned hints, int parallel, char *dep) | |
| { | |
| StringBuilder sb; | |
| if (parallel == -1) | |
| sb.append (GTXT ("Loop below is serial, but parallelizable: ")); | |
| else if (parallel == 0) | |
| sb.append (GTXT ("Loop below is not parallelized: ")); | |
| else | |
| sb.append (GTXT ("Loop below is parallelized: ")); | |
| switch (hints) | |
| { | |
| case 0: | |
| // No loop mesg will print | |
| // strcat(com, GTXT("no hint available")); | |
| break; | |
| case 1: | |
| sb.append (GTXT ("loop contains procedure call")); | |
| break; | |
| case 2: | |
| sb.append (GTXT ("compiler generated two versions of this loop")); | |
| break; | |
| case 3: | |
| { | |
| StringBuilder sb_tmp; | |
| sb_tmp.sprintf (GTXT ("the variable(s) \"%s\" cause a data dependency in this loop"), | |
| dep ? dep : GTXT ("<Unknown>")); | |
| sb.append (&sb_tmp); | |
| } | |
| break; | |
| case 4: | |
| sb.append (GTXT ("loop was significantly transformed during optimization")); | |
| break; | |
| case 5: | |
| sb.append (GTXT ("loop may or may not hold enough work to be profitably parallelized")); | |
| break; | |
| case 6: | |
| sb.append (GTXT ("loop was marked by user-inserted pragma")); | |
| break; | |
| case 7: | |
| sb.append (GTXT ("loop contains multiple exits")); | |
| break; | |
| case 8: | |
| sb.append (GTXT ("loop contains I/O, or other function calls, that are not MT safe")); | |
| break; | |
| case 9: | |
| sb.append (GTXT ("loop contains backward flow of control")); | |
| break; | |
| case 10: | |
| sb.append (GTXT ("loop may have been distributed")); | |
| break; | |
| case 11: | |
| sb.append (GTXT ("two loops or more may have been fused")); | |
| break; | |
| case 12: | |
| sb.append (GTXT ("two or more loops may have been interchanged")); | |
| break; | |
| default: | |
| break; | |
| } | |
| return sb.toString (); | |
| } | |
| StabReader::StabReader (Elf *_elf, Platform_t platform, int StabSec, int StabStrSec) | |
| { | |
| stabCnt = -1; | |
| stabNum = 0; | |
| if (_elf == NULL) | |
| return; | |
| elf = _elf; | |
| // Get ELF data | |
| Elf_Data *data = elf->elf_getdata (StabSec); | |
| if (data == NULL) | |
| return; | |
| uint64_t stabSize = data->d_size; | |
| StabData = (char *) data->d_buf; | |
| Elf_Internal_Shdr *shdr = elf->get_shdr (StabSec); | |
| if (shdr == NULL) | |
| return; | |
| // GCC bug: sh_entsize is 20 for 64 apps on Linux | |
| StabEntSize = (platform == Amd64 || platform == Sparcv9) ? 12 : (unsigned) shdr->sh_entsize; | |
| if (stabSize == 0 || StabEntSize == 0) | |
| return; | |
| data = elf->elf_getdata (StabStrSec); | |
| if (data == NULL) | |
| return; | |
| shdr = elf->get_shdr (StabStrSec); | |
| if (shdr == NULL) | |
| return; | |
| StabStrtab = (char *) data->d_buf; | |
| StabStrtabEnd = StabStrtab + shdr->sh_size; | |
| StrTabSize = 0; | |
| stabCnt = (int) (stabSize / StabEntSize); | |
| } | |
| char * | |
| StabReader::get_stab (struct stab *np, bool comdat) | |
| { | |
| struct stab *stbp = (struct stab *) (StabData + stabNum * StabEntSize); | |
| stabNum++; | |
| *np = *stbp; | |
| np->n_desc = elf->decode (stbp->n_desc); | |
| np->n_strx = elf->decode (stbp->n_strx); | |
| np->n_value = elf->decode (stbp->n_value); | |
| switch (np->n_type) | |
| { | |
| case N_UNDF: | |
| case N_ILDPAD: | |
| // Start of new stab section (or padding) | |
| StabStrtab += StrTabSize; | |
| StrTabSize = np->n_value; | |
| } | |
| char *str = NULL; | |
| if (np->n_strx) | |
| { | |
| if (comdat && np->n_type == N_FUN && np->n_other == 1) | |
| { | |
| if (np->n_strx == 1) | |
| StrTabSize++; | |
| str = StabStrtab + StrTabSize; | |
| // Each COMDAT string must be sized to find the next string: | |
| StrTabSize += strlen (str) + 1; | |
| } | |
| else | |
| str = StabStrtab + np->n_strx; | |
| if (str >= StabStrtabEnd) | |
| str = NULL; | |
| } | |
| if (DEBUG_STABS) | |
| { | |
| char buf[128]; | |
| char *s = get_type_name (np->n_type); | |
| if (s == NULL) | |
| { | |
| snprintf (buf, sizeof (buf), NTXT ("n_type=%d"), np->n_type); | |
| s = buf; | |
| } | |
| if (str) | |
| { | |
| Dprintf (DEBUG_STABS, NTXT ("%4d: .stabs \"%s\",%s,0x%x,0x%x,0x%x\n"), | |
| stabNum - 1, str, s, (int) np->n_other, (int) np->n_desc, | |
| (int) np->n_value); | |
| } | |
| else | |
| Dprintf (DEBUG_STABS, NTXT ("%4d: .stabn %s,0x%x,0x%x,0x%x\n"), | |
| stabNum - 1, s, (int) np->n_other, (int) np->n_desc, | |
| (int) np->n_value); | |
| } | |
| return str; | |
| } | |
| void | |
| StabReader::parse_N_OPT (Module *mod, char *str) | |
| { | |
| if (mod == NULL || str == NULL) | |
| return; | |
| for (char *s = str; 1; s++) | |
| { | |
| switch (*s) | |
| { | |
| case 'd': | |
| if (s[1] == 'i' && s[2] == ';') | |
| { | |
| delete mod->dot_o_file; | |
| mod->dot_o_file = NULL; | |
| } | |
| break; | |
| case 's': | |
| if ((s[1] == 'i' || s[1] == 'n') && s[2] == ';') | |
| { | |
| delete mod->dot_o_file; | |
| mod->dot_o_file = NULL; | |
| } | |
| break; | |
| } | |
| s = strchr (s, ';'); | |
| if (s == NULL) | |
| break; | |
| } | |
| } | |
| Stabs::Stab_status | |
| Stabs::srcline_Stabs (Module *module, unsigned int StabSec, | |
| unsigned int StabStrSec, bool comdat) | |
| { | |
| StabReader *stabReader = new StabReader (openElf (true), platform, StabSec, StabStrSec); | |
| int tot = stabReader->stabCnt; | |
| if (tot < 0) | |
| { | |
| delete stabReader; | |
| return DBGD_ERR_NO_STABS; | |
| } | |
| int n, lineno; | |
| char *sbase, *n_so = NTXT (""), curr_src[2 * MAXPATHLEN]; | |
| Function *newFunc; | |
| Sp_lang_code _lang_code = module->lang_code; | |
| Vector<Function*> *functions = module->functions; | |
| bool no_stabs = true; | |
| *curr_src = '\0'; | |
| Function *func = NULL; | |
| int phase = 0; | |
| int stabs_level = 0; | |
| int xline = 0; | |
| // Find module | |
| for (n = 0; n < tot; n++) | |
| { | |
| struct stab stb; | |
| char *str = stabReader->get_stab (&stb, comdat); | |
| if (stb.n_type == N_UNDF) | |
| phase = 0; | |
| else if (stb.n_type == N_SO) | |
| { | |
| if (str == NULL || *str == '\0') | |
| continue; | |
| if (phase == 0) | |
| { | |
| phase = 1; | |
| n_so = str; | |
| continue; | |
| } | |
| phase = 0; | |
| sbase = str; | |
| if (*str == '/') | |
| { | |
| if (streq (sbase, module->file_name)) | |
| break; | |
| } | |
| else | |
| { | |
| size_t last = strlen (n_so); | |
| if (n_so[last - 1] == '/') | |
| last--; | |
| if (strncmp (n_so, module->file_name, last) == 0 && | |
| module->file_name[last] == '/' && | |
| streq (sbase, module->file_name + last + 1)) | |
| break; | |
| } | |
| } | |
| } | |
| if (n >= tot) | |
| { | |
| delete stabReader; | |
| return DBGD_ERR_NO_STABS; | |
| } | |
| Include *includes = new Include; | |
| includes->new_src_file (module->getMainSrc (), 0, NULL); | |
| module->hasStabs = true; | |
| *curr_src = '\0'; | |
| phase = 0; | |
| for (n++; n < tot; n++) | |
| { | |
| struct stab stb; | |
| char *str = stabReader->get_stab (&stb, comdat); | |
| int n_desc = (int) ((unsigned short) stb.n_desc); | |
| switch (stb.n_type) | |
| { | |
| case N_UNDF: | |
| case N_SO: | |
| case N_ENDM: | |
| n = tot; | |
| break; | |
| case N_ALIAS: | |
| if (str == NULL) | |
| break; | |
| if (is_fortran (_lang_code)) | |
| { | |
| char *p = strchr (str, ':'); | |
| if (p && streq (p + 1, NTXT ("FMAIN"))) | |
| { | |
| Function *afunc = find_func (NTXT ("MAIN"), functions, true); | |
| if (afunc) | |
| afunc->set_match_name (dbe_strndup (str, p - str)); | |
| break; | |
| } | |
| } | |
| case N_FUN: | |
| case N_OUTL: | |
| if (str == NULL) | |
| break; | |
| if (*str == '@') | |
| { | |
| str++; | |
| if (*str == '>' || *str == '<') | |
| str++; | |
| } | |
| if (stabs_level != 0) | |
| break; | |
| // find address of the enclosed function | |
| newFunc = find_func (str, functions, is_fortran (_lang_code)); | |
| if (newFunc == NULL) | |
| break; | |
| if (func) | |
| while (func->popSrcFile ()) | |
| ; | |
| func = newFunc; | |
| // First line info to cover function from the beginning | |
| lineno = xline + n_desc; | |
| if (lineno > 0) | |
| { | |
| // Set the chain of includes for the new function | |
| includes->push_src_files (func); | |
| func->add_PC_info (0, lineno); | |
| no_stabs = false; | |
| } | |
| break; | |
| case N_ENTRY: | |
| break; | |
| case N_CMDLINE: | |
| if (str && !module->comp_flags) | |
| { | |
| char *comp_flags = strchr (str, ';'); | |
| if (comp_flags) | |
| { | |
| module->comp_flags = dbe_strdup (comp_flags + 1); | |
| module->comp_dir = dbe_strndup (str, comp_flags - str); | |
| } | |
| } | |
| break; | |
| case N_LBRAC: | |
| stabs_level++; | |
| break; | |
| case N_RBRAC: | |
| stabs_level--; | |
| break; | |
| case N_XLINE: | |
| xline = n_desc << 16; | |
| break; | |
| case N_SLINE: | |
| if (func == NULL) | |
| break; | |
| no_stabs = false; | |
| lineno = xline + n_desc; | |
| if (func->line_first <= 0) | |
| { | |
| // Set the chain of includes for the new function | |
| includes->push_src_files (func); | |
| func->add_PC_info (0, lineno); | |
| break; | |
| } | |
| if (func->curr_srcfile == NULL) | |
| includes->push_src_files (func); | |
| if (func->line_first != lineno || | |
| !streq (curr_src, func->getDefSrc ()->get_name ())) | |
| func->add_PC_info (stb.n_value, lineno); | |
| break; | |
| case N_OPT: | |
| if ((str != NULL) && streq (str, NTXT ("gcc2_compiled."))) | |
| _lang_code = Sp_lang_gcc; | |
| switch (elfDbg->elf_getehdr ()->e_type) | |
| { | |
| case ET_EXEC: | |
| case ET_DYN: | |
| // set the real object timestamp from the executable's N_OPT stab | |
| // due to bug #4796329 | |
| module->real_timestamp = stb.n_value; | |
| break; | |
| default: | |
| module->curr_timestamp = stb.n_value; | |
| break; | |
| } | |
| break; | |
| case N_GSYM: | |
| if ((str == NULL) || strncmp (str, NTXT ("__KAI_K"), 7)) | |
| break; | |
| str += 7; | |
| if (!strncmp (str, NTXT ("CC_"), 3)) | |
| _lang_code = Sp_lang_KAI_KCC; | |
| else if (!strncmp (str, NTXT ("cc_"), 3)) | |
| _lang_code = Sp_lang_KAI_Kcc; | |
| else if (!strncmp (str, NTXT ("PTS_"), 4) && | |
| (_lang_code != Sp_lang_KAI_KCC) && | |
| (_lang_code != Sp_lang_KAI_Kcc)) | |
| _lang_code = Sp_lang_KAI_KPTS; | |
| break; | |
| case N_BINCL: | |
| includes->new_include_file (module->setIncludeFile (str), func); | |
| break; | |
| case N_EINCL: | |
| includes->end_include_file (func); | |
| break; | |
| case N_SOL: | |
| if (str == NULL) | |
| break; | |
| lineno = xline + n_desc; | |
| if (lineno > 0 && func && func->line_first <= 0) | |
| { | |
| includes->push_src_files (func); | |
| func->add_PC_info (0, lineno); | |
| no_stabs = false; | |
| } | |
| if (streq (sbase, str)) | |
| { | |
| module->setIncludeFile (NULL); | |
| snprintf (curr_src, sizeof (curr_src), NTXT ("%s"), module->file_name); | |
| includes->new_src_file (module->getMainSrc (), lineno, func); | |
| } | |
| else | |
| { | |
| if (streq (sbase, get_basename (str))) | |
| { | |
| module->setIncludeFile (NULL); | |
| snprintf (curr_src, sizeof (curr_src), NTXT ("%s"), module->file_name); | |
| includes->new_src_file (module->setIncludeFile (curr_src), lineno, func); | |
| } | |
| else | |
| { | |
| if (*str == '/') | |
| snprintf (curr_src, sizeof (curr_src), NTXT ("%s"), str); | |
| else | |
| { | |
| size_t last = strlen (n_so); | |
| if (last == 0 || n_so[last - 1] != '/') | |
| snprintf (curr_src, sizeof (curr_src), NTXT ("%s/%s"), n_so, str); | |
| else | |
| snprintf (curr_src, sizeof (curr_src), NTXT ("%s%s"), n_so, str); | |
| } | |
| includes->new_src_file (module->setIncludeFile (curr_src), lineno, func); | |
| } | |
| } | |
| break; | |
| } | |
| } | |
| delete includes; | |
| delete stabReader; | |
| return no_stabs ? DBGD_ERR_NO_STABS : DBGD_ERR_NONE; | |
| }//srcline_Stabs | |
| static bool | |
| cmp_func_name (char *fname, size_t len, char *name, bool fortran) | |
| { | |
| return (strncmp (name, fname, len) == 0 | |
| && (name[len] == 0 | |
| || (fortran && name[len] == '_' && name[len + 1] == 0))); | |
| } | |
| Function * | |
| Stabs::find_func (char *fname, Vector<Function*> *functions, bool fortran, bool inner_names) | |
| { | |
| char *arg, *name; | |
| Function *item; | |
| int index; | |
| size_t len; | |
| len = strlen (fname); | |
| arg = strchr (fname, ':'); | |
| if (arg != NULL) | |
| { | |
| if (arg[1] == 'P') // Prototype for function | |
| return NULL; | |
| len -= strlen (arg); | |
| } | |
| Vec_loop (Function*, functions, index, item) | |
| { | |
| name = item->get_mangled_name (); | |
| if (cmp_func_name (fname, len, name, fortran)) | |
| return item->cardinal (); | |
| } | |
| if (inner_names) | |
| { | |
| // Dwarf subprograms may only have plain (non-linker) names | |
| // Retry with inner names only | |
| Vec_loop (Function*, functions, index, item) | |
| { | |
| name = strrchr (item->get_mangled_name (), '.'); | |
| if (!name) continue; | |
| name++; | |
| if (cmp_func_name (fname, len, name, fortran)) | |
| return item->cardinal (); | |
| } | |
| } | |
| return NULL; | |
| } | |
| Map<const char*, Symbol*> * | |
| Stabs::get_elf_symbols () | |
| { | |
| Elf *elf = openElf (false); | |
| if (elf->elfSymbols == NULL) | |
| { | |
| Map<const char*, Symbol*> *elfSymbols = new StringMap<Symbol*>(128, 128); | |
| elf->elfSymbols = elfSymbols; | |
| for (int i = 0, sz = SymLst ? SymLst->size () : 0; i < sz; i++) | |
| { | |
| Symbol *sym = SymLst->fetch (i); | |
| elfSymbols->put (sym->name, sym); | |
| } | |
| } | |
| return elf->elfSymbols; | |
| } | |
| void | |
| Stabs::read_dwarf_from_dot_o (Module *mod) | |
| { | |
| Dprintf (DEBUG_STABS, NTXT ("stabsModules: %s\n"), STR (mod->get_name ())); | |
| Vector<Module*> *mods = mod->dot_o_file->seg_modules; | |
| char *bname = get_basename (mod->get_name ()); | |
| for (int i1 = 0, sz1 = mods ? mods->size () : 0; i1 < sz1; i1++) | |
| { | |
| Module *m = mods->fetch (i1); | |
| Dprintf (DEBUG_STABS, NTXT (" MOD: %s\n"), STR (m->get_name ())); | |
| if (dbe_strcmp (bname, get_basename (m->get_name ())) == 0) | |
| { | |
| mod->indexStabsLink = m; | |
| m->indexStabsLink = mod; | |
| break; | |
| } | |
| } | |
| if (mod->indexStabsLink) | |
| { | |
| mod->dot_o_file->objStabs->openDwarf ()->srcline_Dwarf (mod->indexStabsLink); | |
| Map<const char*, Symbol*> *elfSymbols = get_elf_symbols (); | |
| Vector<Function*> *funcs = mod->indexStabsLink->functions; | |
| for (int i1 = 0, sz1 = funcs ? funcs->size () : 0; i1 < sz1; i1++) | |
| { | |
| Function *f1 = funcs->fetch (i1); | |
| Symbol *sym = elfSymbols->get (f1->get_mangled_name ()); | |
| if (sym == NULL) | |
| continue; | |
| Dprintf (DEBUG_STABS, NTXT (" Symbol: %s func=%p\n"), STR (sym->name), sym->func); | |
| Function *f = sym->func; | |
| if (f->indexStabsLink) | |
| continue; | |
| f->indexStabsLink = f1; | |
| f1->indexStabsLink = f; | |
| f->copy_PCInfo (f1); | |
| } | |
| } | |
| } | |
| Stabs::Stab_status | |
| Stabs::read_archive (LoadObject *lo) | |
| { | |
| if (openElf (true) == NULL) | |
| return status; | |
| check_Symtab (); | |
| if (elfDbg->dwarf) | |
| openDwarf ()->archive_Dwarf (lo); | |
| // get Module/Function lists from stabs info | |
| Stab_status statusStabs = DBGD_ERR_NO_STABS; | |
| #define ARCHIVE_STABS(sec, secStr, comdat) \ | |
| if ((elfDbg->sec) != 0 && (elfDbg->secStr) != 0 && \ | |
| archive_Stabs(lo, elfDbg->sec, elfDbg->secStr, comdat) == DBGD_ERR_NONE) \ | |
| statusStabs = DBGD_ERR_NONE | |
| // prefer index stabs (where they exist) since they're most appropriate | |
| // for loadobjects and might have N_CPROF stabs for ABS/CPF | |
| ARCHIVE_STABS (stabIndex, stabIndexStr, true); | |
| ARCHIVE_STABS (stabExcl, stabExclStr, false); | |
| ARCHIVE_STABS (stab, stabStr, false); | |
| // Add all unassigned functions to the <unknown> module | |
| Symbol *sitem, *alias; | |
| int index; | |
| Vec_loop (Symbol*, SymLst, index, sitem) | |
| { | |
| if (sitem->func || (sitem->size == 0) || (sitem->flags & SYM_UNDEF)) | |
| continue; | |
| alias = sitem->alias; | |
| if (alias) | |
| { | |
| if (alias->func == NULL) | |
| { | |
| alias->func = createFunction (lo, lo->noname, alias); | |
| alias->func->alias = alias->func; | |
| } | |
| if (alias != sitem) | |
| { | |
| sitem->func = createFunction (lo, alias->func->module, sitem); | |
| sitem->func->alias = alias->func; | |
| } | |
| } | |
| else | |
| sitem->func = createFunction (lo, lo->noname, sitem); | |
| } | |
| if (pltSym) | |
| { | |
| pltSym->func = createFunction (lo, lo->noname, pltSym); | |
| pltSym->func->flags |= FUNC_FLAG_PLT; | |
| } | |
| // need Module association, so this must be done after handling Modules | |
| check_AnalyzerInfo (); | |
| if (dwarf && dwarf->status == DBGD_ERR_NONE) | |
| return DBGD_ERR_NONE; | |
| return statusStabs; | |
| }//read_archive | |
| Function * | |
| Stabs::createFunction (LoadObject *lo, Module *module, Symbol *sym) | |
| { | |
| Function *func = dbeSession->createFunction (); | |
| func->module = module; | |
| func->img_fname = path; | |
| func->img_offset = sym->img_offset; | |
| func->save_addr = sym->save; | |
| func->size = sym->size; | |
| func->set_name (sym->name); | |
| func->elfSym = sym; | |
| module->functions->append (func); | |
| lo->functions->append (func); | |
| return func; | |
| } | |
| void | |
| Stabs::fixSymtabAlias () | |
| { | |
| int ind, i, k; | |
| Symbol *sym, *bestAlias; | |
| SymLst->sort (SymImgOffsetCmp); | |
| ind = SymLst->size () - 1; | |
| for (i = 0; i < ind; i++) | |
| { | |
| bestAlias = SymLst->fetch (i); | |
| if (bestAlias->img_offset == 0) // Ignore this bad symbol | |
| continue; | |
| sym = SymLst->fetch (i + 1); | |
| if (bestAlias->img_offset != sym->img_offset) | |
| { | |
| if ((bestAlias->size == 0) || | |
| (sym->img_offset < bestAlias->img_offset + bestAlias->size)) | |
| bestAlias->size = sym->img_offset - bestAlias->img_offset; | |
| continue; | |
| } | |
| // Find a "best" alias | |
| size_t bestLen = strlen (bestAlias->name); | |
| int64_t maxSize = bestAlias->size; | |
| for (k = i + 1; k <= ind; k++) | |
| { | |
| sym = SymLst->fetch (k); | |
| if (bestAlias->img_offset != sym->img_offset) | |
| { // no more aliases | |
| if ((maxSize == 0) || | |
| (sym->img_offset < bestAlias->img_offset + maxSize)) | |
| maxSize = sym->img_offset - bestAlias->img_offset; | |
| break; | |
| } | |
| if (maxSize < sym->size) | |
| maxSize = sym->size; | |
| size_t len = strlen (sym->name); | |
| if (len < bestLen) | |
| { | |
| bestAlias = sym; | |
| bestLen = len; | |
| } | |
| } | |
| for (; i < k; i++) | |
| { | |
| sym = SymLst->fetch (i); | |
| sym->alias = bestAlias; | |
| sym->size = maxSize; | |
| } | |
| i--; | |
| } | |
| } | |
| void | |
| Stabs::check_Symtab () | |
| { | |
| if (st_check_symtab) | |
| return; | |
| st_check_symtab = true; | |
| Elf *elf = openElf (true); | |
| if (elf == NULL) | |
| return; | |
| if (elf->plt != 0) | |
| { | |
| Elf_Internal_Shdr *shdr = elf->get_shdr (elf->plt); | |
| if (shdr) | |
| { | |
| pltSym = new Symbol (SymLst); | |
| pltSym->value = shdr->sh_addr; | |
| pltSym->size = shdr->sh_size; | |
| pltSym->img_offset = shdr->sh_offset; | |
| pltSym->name = dbe_strdup (NTXT ("@plt")); | |
| pltSym->flags |= SYM_PLT; | |
| } | |
| } | |
| if (elf->symtab) | |
| readSymSec (elf->symtab, elf); | |
| else | |
| { | |
| readSymSec (elf->SUNW_ldynsym, elf); | |
| readSymSec (elf->dynsym, elf); | |
| } | |
| } | |
| void | |
| Stabs::readSymSec (unsigned int sec, Elf *elf) | |
| { | |
| Symbol *sitem; | |
| Sp_lang_code local_lcode; | |
| if (sec == 0) | |
| return; | |
| // Get ELF data | |
| Elf_Data *data = elf->elf_getdata (sec); | |
| if (data == NULL) | |
| return; | |
| uint64_t SymtabSize = data->d_size; | |
| Elf_Internal_Shdr *shdr = elf->get_shdr (sec); | |
| if ((SymtabSize == 0) || (shdr->sh_entsize == 0)) | |
| return; | |
| Elf_Data *data_str = elf->elf_getdata (shdr->sh_link); | |
| if (data_str == NULL) | |
| return; | |
| char *Strtab = (char *) data_str->d_buf; | |
| // read func symbolic table | |
| for (unsigned int n = 0, tot = SymtabSize / shdr->sh_entsize; n < tot; n++) | |
| { | |
| Elf_Internal_Sym Sym; | |
| elf->elf_getsym (data, n, &Sym); | |
| const char *st_name = Sym.st_name < data_str->d_size ? | |
| (Strtab + Sym.st_name) : NTXT ("no_name"); | |
| switch (GELF_ST_TYPE (Sym.st_info)) | |
| { | |
| case STT_FUNC: | |
| if (Sym.st_size == 0) | |
| break; | |
| if (Sym.st_shndx == 0) | |
| { | |
| if (Sym.st_value == 0) | |
| break; | |
| sitem = new Symbol (SymLst); | |
| sitem->flags |= SYM_UNDEF; | |
| if (pltSym) | |
| sitem->img_offset = pltSym->img_offset + | |
| Sym.st_value - pltSym->value; | |
| } | |
| else | |
| { | |
| Elf_Internal_Shdr *shdrp = elfDis->get_shdr (Sym.st_shndx); | |
| if (shdrp == NULL) | |
| break; | |
| sitem = new Symbol (SymLst); | |
| sitem->img_offset = shdrp->sh_offset + | |
| Sym.st_value - shdrp->sh_addr; | |
| } | |
| sitem->size = Sym.st_size; | |
| sitem->name = dbe_strdup (st_name); | |
| sitem->value = is_relocatable () ? sitem->img_offset : Sym.st_value; | |
| if (GELF_ST_BIND (Sym.st_info) == STB_LOCAL) | |
| { | |
| sitem->local_ind = LocalFile->size () - 1; | |
| LocalLst->append (sitem); | |
| } | |
| break; | |
| case STT_NOTYPE: | |
| if (streq (st_name, NTXT ("gcc2_compiled."))) | |
| { | |
| sitem = new Symbol (SymLst); | |
| sitem->lang_code = Sp_lang_gcc; | |
| sitem->name = dbe_strdup (st_name); | |
| sitem->local_ind = LocalFile->size () - 1; | |
| LocalLst->append (sitem); | |
| } | |
| break; | |
| case STT_OBJECT: | |
| if (!strncmp (st_name, NTXT ("__KAI_KPTS_"), 11)) | |
| local_lcode = Sp_lang_KAI_KPTS; | |
| else if (!strncmp (st_name, NTXT ("__KAI_KCC_"), 10)) | |
| local_lcode = Sp_lang_KAI_KCC; | |
| else if (!strncmp (st_name, NTXT ("__KAI_Kcc_"), 10)) | |
| local_lcode = Sp_lang_KAI_Kcc; | |
| else | |
| break; | |
| sitem = new Symbol (LocalLst); | |
| sitem->lang_code = local_lcode; | |
| sitem->name = dbe_strdup (st_name); | |
| break; | |
| case STT_FILE: | |
| { | |
| int last = LocalFile->size () - 1; | |
| if (last >= 0 && LocalFileIdx->fetch (last) == LocalLst->size ()) | |
| { | |
| // There were no local functions in the latest file. | |
| free (LocalFile->get (last)); | |
| LocalFile->store (last, dbe_strdup (st_name)); | |
| } | |
| else | |
| { | |
| LocalFile->append (dbe_strdup (st_name)); | |
| LocalFileIdx->append (LocalLst->size ()); | |
| } | |
| break; | |
| } | |
| } | |
| } | |
| fixSymtabAlias (); | |
| SymLst->sort (SymValueCmp); | |
| get_save_addr (elf->need_swap_endian); | |
| dump (); | |
| }//check_Symtab | |
| void | |
| Stabs::check_Relocs () | |
| { | |
| // We may have many relocation tables to process: .rela.text%foo, | |
| // rela.text%bar, etc. On Intel, compilers generate .rel.text sections | |
| // which have to be processed as well. A lot of rework is needed here. | |
| Symbol *sptr = NULL; | |
| if (st_check_relocs) | |
| return; | |
| st_check_relocs = true; | |
| Elf *elf = openElf (false); | |
| if (elf == NULL) | |
| return; | |
| for (unsigned int sec = 1; sec < elf->elf_getehdr ()->e_shnum; sec++) | |
| { | |
| bool use_rela, use_PLT; | |
| char *name = elf->get_sec_name (sec); | |
| if (name == NULL) | |
| continue; | |
| if (strncmp (name, NTXT (".rela.text"), 10) == 0) | |
| { | |
| use_rela = true; | |
| use_PLT = false; | |
| } | |
| else if (streq (name, NTXT (".rela.plt"))) | |
| { | |
| use_rela = true; | |
| use_PLT = true; | |
| } | |
| else if (strncmp (name, NTXT (".rel.text"), 9) == 0) | |
| { | |
| use_rela = false; | |
| use_PLT = false; | |
| } | |
| else if (streq (name, NTXT (".rel.plt"))) | |
| { | |
| use_rela = false; | |
| use_PLT = true; | |
| } | |
| else | |
| continue; | |
| Elf_Internal_Shdr *shdr = elf->get_shdr (sec); | |
| if (shdr == NULL) | |
| continue; | |
| // Get ELF data | |
| Elf_Data *data = elf->elf_getdata (sec); | |
| if (data == NULL) | |
| continue; | |
| uint64_t ScnSize = data->d_size; | |
| uint64_t EntSize = shdr->sh_entsize; | |
| if ((ScnSize == 0) || (EntSize == 0)) | |
| continue; | |
| int tot = (int) (ScnSize / EntSize); | |
| // Get corresponding text section | |
| Elf_Internal_Shdr *shdr_txt = elf->get_shdr (shdr->sh_info); | |
| if (shdr_txt == NULL) | |
| continue; | |
| if (!(shdr_txt->sh_flags & SHF_EXECINSTR)) | |
| continue; | |
| // Get corresponding symbol table section | |
| Elf_Internal_Shdr *shdr_sym = elf->get_shdr (shdr->sh_link); | |
| if (shdr_sym == NULL) | |
| continue; | |
| Elf_Data *data_sym = elf->elf_getdata (shdr->sh_link); | |
| // Get corresponding string table section | |
| Elf_Data *data_str = elf->elf_getdata (shdr_sym->sh_link); | |
| if (data_str == NULL) | |
| continue; | |
| char *Strtab = (char*) data_str->d_buf; | |
| for (int n = 0; n < tot; n++) | |
| { | |
| Elf_Internal_Sym sym; | |
| Elf_Internal_Rela rela; | |
| char *symName; | |
| if (use_rela) | |
| elf->elf_getrela (data, n, &rela); | |
| else | |
| { | |
| // GElf_Rela is extended GElf_Rel | |
| elf->elf_getrel (data, n, &rela); | |
| rela.r_addend = 0; | |
| } | |
| int ndx = (int) GELF_R_SYM (rela.r_info); | |
| elf->elf_getsym (data_sym, ndx, &sym); | |
| switch (GELF_ST_TYPE (sym.st_info)) | |
| { | |
| case STT_FUNC: | |
| case STT_OBJECT: | |
| case STT_NOTYPE: | |
| if (sym.st_name == 0 || sym.st_name >= data_str->d_size) | |
| continue; | |
| symName = Strtab + sym.st_name; | |
| break; | |
| case STT_SECTION: | |
| { | |
| Elf_Internal_Shdr *secHdr = elf->get_shdr (sym.st_shndx); | |
| if (secHdr == NULL) | |
| continue; | |
| if (sptr == NULL) | |
| sptr = new Symbol; | |
| sptr->value = secHdr->sh_offset + rela.r_addend; | |
| long index = SymLst->bisearch (0, -1, &sptr, SymFindCmp); | |
| if (index == -1) | |
| continue; | |
| Symbol *sp = SymLst->fetch (index); | |
| if (sptr->value != sp->value) | |
| continue; | |
| symName = sp->name; | |
| break; | |
| } | |
| default: | |
| continue; | |
| } | |
| Reloc *reloc = new Reloc; | |
| reloc->name = dbe_strdup (symName); | |
| reloc->type = GELF_R_TYPE (rela.r_info); | |
| reloc->value = use_PLT ? rela.r_offset | |
| : rela.r_offset + shdr_txt->sh_offset; | |
| reloc->addend = rela.r_addend; | |
| if (use_PLT) | |
| RelPLTLst->append (reloc); | |
| else | |
| RelLst->append (reloc); | |
| } | |
| } | |
| delete sptr; | |
| RelLst->sort (RelValueCmp); | |
| } //check_Relocs | |
| void | |
| Stabs::get_save_addr (bool need_swap_endian) | |
| { | |
| if (elfDis->is_Intel ()) | |
| { | |
| for (int j = 0, sz = SymLst ? SymLst->size () : 0; j < sz; j++) | |
| { | |
| Symbol *sitem = SymLst->fetch (j); | |
| sitem->save = 0; | |
| } | |
| return; | |
| } | |
| for (int j = 0, sz = SymLst ? SymLst->size () : 0; j < sz; j++) | |
| { | |
| Symbol *sitem = SymLst->fetch (j); | |
| sitem->save = FUNC_NO_SAVE; | |
| // If an image offset is not known skip it. | |
| // Works for artificial symbols like '@plt' as well. | |
| if (sitem->img_offset == 0) | |
| continue; | |
| bool is_o7_moved = false; | |
| int64_t off = sitem->img_offset; | |
| for (int i = 0; i < sitem->size; i += 4) | |
| { | |
| unsigned int cmd; | |
| if (elfDis->get_data (off, sizeof (cmd), &cmd) == NULL) | |
| break; | |
| if (need_swap_endian) | |
| SWAP_ENDIAN (cmd); | |
| off += sizeof (cmd); | |
| if ((cmd & 0xffffc000) == 0x9de38000) | |
| { // save %sp, ??, %sp | |
| sitem->save = i; | |
| break; | |
| } | |
| else if ((cmd & 0xc0000000) == 0x40000000 || // call ?? | |
| (cmd & 0xfff80000) == 0xbfc00000) | |
| { // jmpl ??, %o7 | |
| if (!is_o7_moved) | |
| { | |
| sitem->save = FUNC_ROOT; | |
| break; | |
| } | |
| } | |
| else if ((cmd & 0xc1ffe01f) == 0x8010000f) // or %g0,%o7,?? | |
| is_o7_moved = true; | |
| } | |
| } | |
| } | |
| uint64_t | |
| Stabs::mapOffsetToAddress (uint64_t img_offset) | |
| { | |
| Elf *elf = openElf (false); | |
| if (elf == NULL) | |
| return 0; | |
| if (is_relocatable ()) | |
| return img_offset; | |
| for (unsigned int sec = 1; sec < elf->elf_getehdr ()->e_shnum; sec++) | |
| { | |
| Elf_Internal_Shdr *shdr = elf->get_shdr (sec); | |
| if (shdr == NULL) | |
| continue; | |
| if (img_offset >= (uint64_t) shdr->sh_offset | |
| && img_offset < (uint64_t) (shdr->sh_offset + shdr->sh_size)) | |
| return shdr->sh_addr + (img_offset - shdr->sh_offset); | |
| } | |
| return 0; | |
| } | |
| Stabs::Stab_status | |
| Stabs::archive_Stabs (LoadObject *lo, unsigned int StabSec, | |
| unsigned int StabStrSec, bool comdat) | |
| { | |
| StabReader *stabReader = new StabReader (openElf (true), platform, StabSec, StabStrSec); | |
| int tot = stabReader->stabCnt; | |
| if (tot < 0) | |
| { | |
| delete stabReader; | |
| return DBGD_ERR_NO_STABS; | |
| } | |
| char *sbase = NTXT (""), *arg, *fname, sname[2 * MAXPATHLEN]; | |
| int lastMod, phase, stabs_level, modCnt = 0; | |
| Function *func = NULL; | |
| Module *mod; | |
| #define INIT_MOD phase = 0; stabs_level = 0; *sname = '\0'; mod = NULL | |
| bool updateStabsMod = false; | |
| if (comdat && ((elfDbg->elf_getehdr ()->e_type == ET_EXEC) || (elfDbg->elf_getehdr ()->e_type == ET_DYN))) | |
| { | |
| if (stabsModules == NULL) | |
| stabsModules = new Vector<Module*>(); | |
| updateStabsMod = true; | |
| } | |
| INIT_MOD; | |
| lastMod = lo->seg_modules->size (); | |
| for (int n = 0; n < tot; n++) | |
| { | |
| struct stab stb; | |
| char *str = stabReader->get_stab (&stb, comdat); | |
| switch (stb.n_type) | |
| { | |
| case N_FUN: | |
| // Ignore a COMDAT function, if there are two or more modules in 'lo' | |
| if (comdat && stb.n_other == 1 && modCnt > 1) | |
| break; | |
| case N_OUTL: | |
| case N_ALIAS: | |
| case N_ENTRY: | |
| if (mod == NULL || str == NULL | |
| || (stb.n_type != N_ENTRY && stabs_level != 0)) | |
| break; | |
| if (*str == '@') | |
| { | |
| str++; | |
| if (*str == '>' || *str == '<') | |
| str++; | |
| } | |
| fname = dbe_strdup (str); | |
| arg = strchr (fname, ':'); | |
| if (arg != NULL) | |
| { | |
| if (!strncmp (arg, NTXT (":P"), 2)) | |
| { // just prototype | |
| free (fname); | |
| break; | |
| } | |
| *arg = '\0'; | |
| } | |
| func = append_Function (mod, fname); | |
| free (fname); | |
| break; | |
| case N_CMDLINE: | |
| if (str && mod) | |
| { | |
| char *comp_flags = strchr (str, ';'); | |
| if (comp_flags) | |
| { | |
| mod->comp_flags = dbe_strdup (comp_flags + 1); | |
| mod->comp_dir = dbe_strndup (str, comp_flags - str); | |
| } | |
| } | |
| break; | |
| case N_LBRAC: | |
| stabs_level++; | |
| break; | |
| case N_RBRAC: | |
| stabs_level--; | |
| break; | |
| case N_UNDF: | |
| INIT_MOD; | |
| break; | |
| case N_ENDM: | |
| INIT_MOD; | |
| break; | |
| case N_OPT: | |
| stabReader->parse_N_OPT (mod, str); | |
| if (mod && (str != NULL) && streq (str, NTXT ("gcc2_compiled."))) | |
| // Is it anachronism ? | |
| mod->lang_code = Sp_lang_gcc; | |
| break; | |
| case N_GSYM: | |
| if (mod && (str != NULL)) | |
| { | |
| if (strncmp (str, NTXT ("__KAI_K"), 7)) | |
| break; | |
| str += 7; | |
| if (!strncmp (str, NTXT ("CC_"), 3)) | |
| mod->lang_code = Sp_lang_KAI_KCC; | |
| else if (!strncmp (str, NTXT ("cc_"), 3)) | |
| mod->lang_code = Sp_lang_KAI_Kcc; | |
| else if (!strncmp (str, NTXT ("PTS_"), 4) && | |
| (mod->lang_code != Sp_lang_KAI_KCC) && | |
| (mod->lang_code != Sp_lang_KAI_Kcc)) | |
| mod->lang_code = Sp_lang_KAI_KPTS; | |
| } | |
| break; | |
| case N_SO: | |
| if (str == NULL || *str == '\0') | |
| { | |
| INIT_MOD; | |
| break; | |
| } | |
| if (phase == 0) | |
| { | |
| phase = 1; | |
| sbase = str; | |
| } | |
| else | |
| { | |
| if (*str == '/') | |
| sbase = str; | |
| else | |
| { | |
| size_t last = strlen (sbase); | |
| if (last == 0 || sbase[last - 1] != '/') | |
| snprintf (sname, sizeof (sname), NTXT ("%s/%s"), sbase, str); | |
| else | |
| snprintf (sname, sizeof (sname), NTXT ("%s%s"), sbase, str); | |
| sbase = sname; | |
| } | |
| mod = append_Module (lo, sbase, lastMod); | |
| if (updateStabsMod) | |
| stabsModules->append (mod); | |
| mod->hasStabs = true; | |
| modCnt++; | |
| if ((mod->lang_code != Sp_lang_gcc) && | |
| (mod->lang_code != Sp_lang_KAI_KPTS) && | |
| (mod->lang_code != Sp_lang_KAI_KCC) && | |
| (mod->lang_code != Sp_lang_KAI_Kcc)) | |
| mod->lang_code = (Sp_lang_code) stb.n_desc; | |
| *sname = '\0'; | |
| phase = 0; | |
| } | |
| break; | |
| case N_OBJ: | |
| if (str == NULL) | |
| break; | |
| if (phase == 0) | |
| { | |
| phase = 1; | |
| sbase = str; | |
| } | |
| else | |
| { | |
| if (*str == '/') | |
| sbase = str; | |
| else | |
| { | |
| size_t last = strlen (sbase); | |
| if (last == 0 || sbase[last - 1] != '/') | |
| snprintf (sname, sizeof (sname), NTXT ("%s/%s"), sbase, str); | |
| else | |
| snprintf (sname, sizeof (sname), NTXT ("%s%s"), sbase, str); | |
| sbase = sname; | |
| } | |
| if (mod && (mod->dot_o_file == NULL)) | |
| { | |
| if (strcmp (sbase, NTXT ("/")) == 0) | |
| mod->set_name (dbe_strdup (path)); | |
| else | |
| { | |
| mod->set_name (dbe_strdup (sbase)); | |
| mod->dot_o_file = mod->createLoadObject (sbase); | |
| } | |
| } | |
| *sname = '\0'; | |
| phase = 0; | |
| } | |
| break; | |
| case N_CPROF: | |
| cpf_stabs_t map; | |
| Dprintf (DEBUG_STABS, NTXT ("N_CPROF n_desc=%x n_value=0x%04x mod=%s\n"), | |
| stb.n_desc, stb.n_value, (mod == NULL) ? NTXT ("???") : mod->get_name ()); | |
| map.type = stb.n_desc; | |
| map.offset = stb.n_value; | |
| map.module = mod; | |
| analyzerInfoMap.append (map); | |
| break; | |
| } | |
| } | |
| delete stabReader; | |
| return func ? DBGD_ERR_NONE : DBGD_ERR_NO_STABS; | |
| } | |
| Module * | |
| Stabs::append_Module (LoadObject *lo, char *name, int lastMod) | |
| { | |
| Module *module; | |
| int size; | |
| Symbol *sitem; | |
| if (lo->seg_modules != NULL) | |
| { | |
| size = lo->seg_modules->size (); | |
| if (size < lastMod) | |
| lastMod = size; | |
| for (int i = 0; i < lastMod; i++) | |
| { | |
| module = lo->seg_modules->fetch (i); | |
| if (module->linkerStabName && streq (module->linkerStabName, name)) | |
| return module; | |
| } | |
| } | |
| module = dbeSession->createModule (lo, NULL); | |
| module->set_file_name (dbe_strdup (name)); | |
| module->linkerStabName = dbe_strdup (module->file_name); | |
| // Append all functions with 'local_ind == -1' to the module. | |
| if (LocalLst->size () > 0) | |
| { | |
| sitem = LocalLst->fetch (0); | |
| if (!sitem->defined && sitem->local_ind == -1) | |
| // Append all functions with 'local_ind == -1' to the module. | |
| append_local_funcs (module, 0); | |
| } | |
| // Append local func | |
| char *basename = get_basename (name); | |
| size = LocalFile->size (); | |
| for (int i = 0; i < size; i++) | |
| { | |
| if (streq (basename, LocalFile->fetch (i))) | |
| { | |
| int local_ind = LocalFileIdx->fetch (i); | |
| if (local_ind >= LocalLst->size ()) | |
| break; | |
| sitem = LocalLst->fetch (local_ind); | |
| if (!sitem->defined) | |
| { | |
| append_local_funcs (module, local_ind); | |
| break; | |
| } | |
| } | |
| } | |
| return module; | |
| } | |
| void | |
| Stabs::append_local_funcs (Module *module, int first_ind) | |
| { | |
| Symbol *sitem = LocalLst->fetch (first_ind); | |
| int local_ind = sitem->local_ind; | |
| int size = LocalLst->size (); | |
| for (int i = first_ind; i < size; i++) | |
| { | |
| sitem = LocalLst->fetch (i); | |
| if (sitem->local_ind != local_ind) | |
| break; | |
| sitem->defined = true; | |
| // 3rd party compiled. e.g., Gcc or KAI compiled | |
| if (sitem->lang_code != Sp_lang_unknown) | |
| { | |
| if (module->lang_code == Sp_lang_unknown) | |
| module->lang_code = sitem->lang_code; | |
| continue; | |
| } | |
| if (sitem->func) | |
| continue; | |
| Function *func = dbeSession->createFunction (); | |
| sitem->func = func; | |
| func->img_fname = path; | |
| func->img_offset = sitem->img_offset; | |
| func->save_addr = sitem->save; | |
| func->size = sitem->size; | |
| func->module = module; | |
| func->set_name (sitem->name); | |
| module->functions->append (func); | |
| module->loadobject->functions->append (func); | |
| } | |
| } | |
| Function * | |
| Stabs::append_Function (Module *module, char *fname) | |
| { | |
| Symbol *sitem, *sptr; | |
| Function *func; | |
| long sid, index; | |
| char *name; | |
| if (SymLstByName == NULL) | |
| { | |
| SymLstByName = SymLst->copy (); | |
| SymLstByName->sort (SymNameCmp); | |
| } | |
| sptr = new Symbol; | |
| if (module->lang_code == N_SO_FORTRAN || module->lang_code == N_SO_FORTRAN90) | |
| { | |
| char *fortran = dbe_sprintf (NTXT ("%s_"), fname); // FORTRAN name | |
| sptr->name = fortran; | |
| sid = SymLstByName->bisearch (0, -1, &sptr, SymNameCmp); | |
| if (sid == -1) | |
| { | |
| free (fortran); | |
| sptr->name = fname; | |
| sid = SymLstByName->bisearch (0, -1, &sptr, SymNameCmp); | |
| } | |
| else | |
| fname = fortran; | |
| } | |
| else | |
| { | |
| sptr->name = fname; | |
| sid = SymLstByName->bisearch (0, -1, &sptr, SymNameCmp); | |
| } | |
| sptr->name = NULL; | |
| delete sptr; | |
| if (sid == -1) | |
| { | |
| Vec_loop (Symbol*, SymLstByName, index, sitem) | |
| { | |
| if (strncmp (sitem->name, NTXT ("$X"), 2) == 0 | |
| || strncmp (sitem->name, NTXT (".X"), 2) == 0) | |
| { | |
| char *n = strchr (((sitem->name) + 2), (int) '.'); | |
| if (n != NULL) | |
| name = n + 1; | |
| else | |
| name = sitem->name; | |
| } | |
| else | |
| name = sitem->name; | |
| if (name != NULL && fname != NULL && (strcmp (name, fname) == 0)) | |
| { | |
| sid = index; | |
| break; | |
| } | |
| } | |
| } | |
| if (sid != -1) | |
| { | |
| sitem = SymLstByName->fetch (sid); | |
| if (sitem->alias) | |
| sitem = sitem->alias; | |
| if (sitem->func) | |
| return sitem->func; | |
| sitem->func = func = dbeSession->createFunction (); | |
| func->img_fname = path; | |
| func->img_offset = sitem->img_offset; | |
| func->save_addr = sitem->save; | |
| func->size = sitem->size; | |
| } | |
| else | |
| func = dbeSession->createFunction (); | |
| func->module = module; | |
| func->set_name (fname); | |
| module->functions->append (func); | |
| module->loadobject->functions->append (func); | |
| return func; | |
| } | |
| Function * | |
| Stabs::append_Function (Module *module, char *linkerName, uint64_t pc) | |
| { | |
| Dprintf (DEBUG_STABS, NTXT ("Stabs::append_Function: module=%s linkerName=%s pc=0x%llx\n"), | |
| STR (module->get_name ()), STR (linkerName), (unsigned long long) pc); | |
| long i; | |
| Symbol *sitem = NULL, *sp; | |
| Function *func; | |
| sp = new Symbol; | |
| if (pc) | |
| { | |
| sp->value = pc; | |
| i = SymLst->bisearch (0, -1, &sp, SymFindCmp); | |
| if (i != -1) | |
| sitem = SymLst->fetch (i); | |
| } | |
| if (!sitem && linkerName) | |
| { | |
| if (SymLstByName == NULL) | |
| { | |
| SymLstByName = SymLst->copy (); | |
| SymLstByName->sort (SymNameCmp); | |
| } | |
| sp->name = linkerName; | |
| i = SymLstByName->bisearch (0, -1, &sp, SymNameCmp); | |
| sp->name = NULL; | |
| if (i != -1) | |
| sitem = SymLstByName->fetch (i); | |
| } | |
| delete sp; | |
| if (!sitem) | |
| return NULL; | |
| if (sitem->alias) | |
| sitem = sitem->alias; | |
| if (sitem->func) | |
| return sitem->func; | |
| sitem->func = func = dbeSession->createFunction (); | |
| func->img_fname = path; | |
| func->img_offset = sitem->img_offset; | |
| func->save_addr = sitem->save; | |
| func->size = sitem->size; | |
| func->module = module; | |
| func->set_name (sitem->name); //XXXX ?? Now call it to set obj->name | |
| module->functions->append (func); | |
| module->loadobject->functions->append (func); | |
| return func; | |
| }// Stabs::append_Function | |
| Dwarf * | |
| Stabs::openDwarf () | |
| { | |
| if (dwarf == NULL) | |
| { | |
| dwarf = new Dwarf (this); | |
| check_Symtab (); | |
| } | |
| return dwarf; | |
| } | |
| void | |
| Stabs::read_hwcprof_info (Module *module) | |
| { | |
| openDwarf ()->read_hwcprof_info (module); | |
| } | |
| void | |
| Stabs::dump () | |
| { | |
| if (!DUMP_ELF_SYM) | |
| return; | |
| printf (NTXT ("\n======= Stabs::dump: %s =========\n"), path ? path : NTXT ("NULL")); | |
| int i, sz; | |
| if (LocalFile) | |
| { | |
| sz = LocalFile->size (); | |
| for (i = 0; i < sz; i++) | |
| printf (" %3d: %5d '%s'\n", i, LocalFileIdx->fetch (i), | |
| LocalFile->fetch (i)); | |
| } | |
| Symbol::dump (SymLst, NTXT ("SymLst")); | |
| Symbol::dump (LocalLst, NTXT ("LocalLst")); | |
| printf (NTXT ("\n===== END of Stabs::dump: %s =========\n\n"), | |
| path ? path : NTXT ("NULL")); | |
| } | |
| /////////////////////////////////////////////////////////////////////////////// | |
| // Class Include | |
| Include::Include () | |
| { | |
| stack = new Vector<SrcFileInfo*>; | |
| } | |
| Include::~Include () | |
| { | |
| Destroy (stack); | |
| } | |
| void | |
| Include::new_src_file (SourceFile *source, int lineno, Function *func) | |
| { | |
| for (int index = stack->size () - 1; index >= 0; index--) | |
| { | |
| if (source == stack->fetch (index)->srcfile) | |
| { | |
| for (int i = stack->size () - 1; i > index; i--) | |
| { | |
| delete stack->remove (i); | |
| if (func && func->line_first > 0) | |
| func->popSrcFile (); | |
| } | |
| return; | |
| } | |
| } | |
| if (func && func->line_first > 0) | |
| func->pushSrcFile (source, lineno); | |
| SrcFileInfo *sfinfo = new SrcFileInfo; | |
| sfinfo->srcfile = source; | |
| sfinfo->lineno = lineno; | |
| stack->append (sfinfo); | |
| } | |
| void | |
| Include::push_src_files (Function *func) | |
| { | |
| int index; | |
| SrcFileInfo *sfinfo; | |
| if (func->line_first <= 0 && stack->size () > 0) | |
| { | |
| sfinfo = stack->fetch (stack->size () - 1); | |
| func->setDefSrc (sfinfo->srcfile); | |
| } | |
| Vec_loop (SrcFileInfo*, stack, index, sfinfo) | |
| { | |
| func->pushSrcFile (sfinfo->srcfile, sfinfo->lineno); | |
| } | |
| } | |
| void | |
| Include::new_include_file (SourceFile *source, Function *func) | |
| { | |
| if (stack->size () == 1 && stack->fetch (0)->srcfile == source) | |
| // workaroud for gcc; gcc creates 'N_BINCL' stab for main source | |
| return; | |
| if (func && func->line_first > 0) | |
| func->pushSrcFile (source, 0); | |
| SrcFileInfo *sfinfo = new SrcFileInfo; | |
| sfinfo->srcfile = source; | |
| sfinfo->lineno = 0; | |
| stack->append (sfinfo); | |
| } | |
| void | |
| Include::end_include_file (Function *func) | |
| { | |
| int index = stack->size () - 1; | |
| if (index > 0) | |
| { | |
| delete stack->remove (index); | |
| if (func && func->line_first > 0) | |
| func->popSrcFile (); | |
| } | |
| } | |
| #define RET_S(x) if (t == x) return (char *) #x | |
| char * | |
| StabReader::get_type_name (int t) | |
| { | |
| RET_S (N_UNDF); | |
| RET_S (N_ABS); | |
| RET_S (N_TEXT); | |
| RET_S (N_DATA); | |
| RET_S (N_BSS); | |
| RET_S (N_COMM); | |
| RET_S (N_FN); | |
| RET_S (N_EXT); | |
| RET_S (N_TYPE); | |
| RET_S (N_GSYM); | |
| RET_S (N_FNAME); | |
| RET_S (N_FUN); | |
| RET_S (N_OUTL); | |
| RET_S (N_STSYM); | |
| RET_S (N_TSTSYM); | |
| RET_S (N_LCSYM); | |
| RET_S (N_TLCSYM); | |
| RET_S (N_MAIN); | |
| RET_S (N_ROSYM); | |
| RET_S (N_FLSYM); | |
| RET_S (N_TFLSYM); | |
| RET_S (N_PC); | |
| RET_S (N_CMDLINE); | |
| RET_S (N_OBJ); | |
| RET_S (N_OPT); | |
| RET_S (N_RSYM); | |
| RET_S (N_SLINE); | |
| RET_S (N_XLINE); | |
| RET_S (N_ILDPAD); | |
| RET_S (N_SSYM); | |
| RET_S (N_ENDM); | |
| RET_S (N_SO); | |
| RET_S (N_MOD); | |
| RET_S (N_EMOD); | |
| RET_S (N_READ_MOD); | |
| RET_S (N_ALIAS); | |
| RET_S (N_LSYM); | |
| RET_S (N_BINCL); | |
| RET_S (N_SOL); | |
| RET_S (N_PSYM); | |
| RET_S (N_EINCL); | |
| RET_S (N_ENTRY); | |
| RET_S (N_SINCL); | |
| RET_S (N_LBRAC); | |
| RET_S (N_EXCL); | |
| RET_S (N_USING); | |
| RET_S (N_ISYM); | |
| RET_S (N_ESYM); | |
| RET_S (N_PATCH); | |
| RET_S (N_CONSTRUCT); | |
| RET_S (N_DESTRUCT); | |
| RET_S (N_CODETAG); | |
| RET_S (N_FUN_CHILD); | |
| RET_S (N_RBRAC); | |
| RET_S (N_BCOMM); | |
| RET_S (N_TCOMM); | |
| RET_S (N_ECOMM); | |
| RET_S (N_XCOMM); | |
| RET_S (N_ECOML); | |
| RET_S (N_WITH); | |
| RET_S (N_LENG); | |
| RET_S (N_CPROF); | |
| RET_S (N_BROWS); | |
| RET_S (N_FUN_PURE); | |
| RET_S (N_FUN_ELEMENTAL); | |
| RET_S (N_FUN_RECURSIVE); | |
| RET_S (N_FUN_AMD64_PARMDUMP); | |
| RET_S (N_SYM_OMP_TLS); | |
| RET_S (N_SO_AS); | |
| RET_S (N_SO_C); | |
| RET_S (N_SO_ANSI_C); | |
| RET_S (N_SO_CC); | |
| RET_S (N_SO_FORTRAN); | |
| RET_S (N_SO_FORTRAN77); | |
| RET_S (N_SO_PASCAL); | |
| RET_S (N_SO_FORTRAN90); | |
| RET_S (N_SO_JAVA); | |
| RET_S (N_SO_C99); | |
| return NULL; | |
| } |