diff options
Diffstat (limited to 'gprofng/src/Stabs.cc')
-rw-r--r-- | gprofng/src/Stabs.cc | 2650 |
1 files changed, 2650 insertions, 0 deletions
diff --git a/gprofng/src/Stabs.cc b/gprofng/src/Stabs.cc new file mode 100644 index 00000000000..9f1247d1b4f --- /dev/null +++ b/gprofng/src/Stabs.cc @@ -0,0 +1,2650 @@ +/* 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; +} |