| /* Copyright (C) 2021 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 pltSym; |
| 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 = (off_t) sym->img_offset; |
| func->save_addr = sym->save; |
| func->size = (uint32_t) 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 (elfDis->plt != 0) |
| { |
| Elf_Internal_Shdr *shdr = elfDis->get_shdr (elfDis->plt); |
| if (shdr) |
| { |
| pltSym = new Symbol (); |
| 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: |
| // Skip UNDEF symbols (bug 4817083) |
| if (Sym.st_shndx == 0) |
| { |
| if (Sym.st_value == 0) |
| break; |
| sitem = new Symbol (SymLst); |
| sitem->flags |= SYM_UNDEF; |
| if (pltSym) |
| sitem->img_offset = (uint32_t) (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 = (uint32_t) (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 = (off_t) sitem->img_offset; |
| func->save_addr = (uint32_t) sitem->save; |
| func->size = (uint32_t) 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 = (off_t) sitem->img_offset; |
| func->save_addr = (uint32_t) sitem->save; |
| func->size = (uint32_t) 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 = (off_t) sitem->img_offset; |
| func->save_addr = (uint32_t) sitem->save; |
| func->size = (uint32_t) 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; |
| } |