/* Copyright (C) 2021-2023 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 "util.h" #include "DbeSession.h" #include "Elf.h" #include "Stabs.h" #include "Dwarf.h" #include "DataObject.h" #include "Function.h" #include "LoadObject.h" #include "Module.h" #include "DefaultMap.h" static int datatypeCmp (const void *a, const void *b) { uint32_t o1 = ((datatype_t *) a)->datatype_id; uint32_t o2 = ((datatype_t *) b)->datatype_id; return o1 == o2 ? 0 : (o1 < o2 ? -1 : 1); } 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 ? 0 : (o1 < o2 ? -1 : 1); } ////////////////////////////////////////////////////////// // class Dwr_type class Dwr_type { public: Dwr_type (int64_t _cu_die_offset, int _tag) { cu_die_offset = _cu_die_offset; tag = _tag; name = NULL; dobj_name = NULL; dtype = NULL; extent = 0; parent = 0; child = 0; next = 0; ref_type = 0; size = 0; elems = 0; offset = -1; bit_size = 0; }; char *name, *dobj_name; int64_t cu_die_offset, ref_type, extent, parent, child, next; int64_t size, elems, offset; int tag, bit_size; DataObject *get_dobj (Dwarf_cnt *ctx); char *get_dobjname (Dwarf_cnt *ctx); char *dump (); private: datatype_t *dtype; datatype_t *get_datatype (Dwarf_cnt *ctx); void get_dobj_for_members (Dwarf_cnt *ctx); void set_dobjname (char *spec, char *nm); }; ////////////////////////////////////////////////////////// // class Dwarf_cnt Dwarf_cnt::Dwarf_cnt () { cu_offset = 0; parent = 0; module = NULL; name = NULL; func = NULL; fortranMAIN = NULL; dwr_types = NULL; inlinedSubr = NULL; level = 0; } Dwr_type * Dwarf_cnt::get_dwr_type (int64_t cu_die_offset) { Dwr_type *t = dwr_types->get (cu_die_offset); if (t == NULL) { Dprintf (DUMP_DWARFLIB, "DWARF_ERROR: %s:%d wrong cu_die_offset=%lld in Dwarf_cnt::get_dwr_type\n", get_basename (__FILE__), (int) __LINE__, (long long) cu_die_offset); t = put_dwr_type (cu_die_offset, 0); // DOBJ_UNSPECIFIED } return t; } Dwr_type * Dwarf_cnt::put_dwr_type (int64_t cu_die_offset, int tag) { Dwr_type *t = new Dwr_type (cu_die_offset, tag); dwr_types->put (cu_die_offset, t); return t; } Dwr_type * Dwarf_cnt::put_dwr_type (Dwr_Tag *dwrTag) { Dwr_type *t = new Dwr_type (dwrTag->die, dwrTag->tag); dwr_types->put (dwrTag->die, t); return t; } ////////////////////////////////////////////////////////// // class Dwr_type char * Dwr_type::dump () { char *s = dbe_sprintf ("%lld %-15s name='%s' parent=%lld next=%lld child=%lld dtype=%llx", (long long) cu_die_offset, DwrCU::tag2str (tag), STR (name), (long long) parent, (long long) next, (long long) child, (long long) dtype); return s; } void Dwr_type::set_dobjname (char *spec, char *nm) { if (spec) { if (nm) dobj_name = dbe_sprintf ("%s%s", spec, nm); else dobj_name = dbe_sprintf ("%s", spec, (long long) cu_die_offset); } else { if (nm) dobj_name = dbe_sprintf ("%s", nm); else dobj_name = dbe_sprintf ("", (long long) cu_die_offset); } } char * Dwr_type::get_dobjname (Dwarf_cnt *ctx) { if (dobj_name) return dobj_name; switch (tag) { case DW_TAG_base_type: set_dobjname (NULL, name); for (int i = 0, len = (int) strlen (dobj_name); i < len; i++) { if (dobj_name[i] == ' ') dobj_name[i] = '_'; } break; case DW_TAG_constant: case DW_TAG_formal_parameter: case DW_TAG_variable: { Dwr_type *t = ctx->get_dwr_type (ref_type); set_dobjname (NULL, t->get_dobjname (ctx)); break; } case DW_TAG_unspecified_type: set_dobjname (NTXT ("unspecified:"), name); break; case DW_TAG_enumeration_type: set_dobjname (NTXT ("enumeration:"), name); break; case DW_TAG_typedef: { Dwr_type *t = ctx->get_dwr_type (ref_type); dobj_name = dbe_sprintf ("%s=%s", name, t->get_dobjname (ctx)); break; } case DW_TAG_const_type: set_dobjname (NTXT ("const+"), name); break; case DW_TAG_volatile_type: set_dobjname (NTXT ("volatile+"), name); break; case DW_TAG_pointer_type: { Dwr_type *t = ctx->get_dwr_type (ref_type); set_dobjname (NTXT ("pointer+"), t->get_dobjname (ctx)); break; } case DW_TAG_reference_type: { Dwr_type *t = ctx->get_dwr_type (ref_type); set_dobjname (NTXT ("reference+"), t->get_dobjname (ctx)); break; } case DW_TAG_array_type: { Dwr_type *t = ctx->get_dwr_type (ref_type); if (elems > 0) dobj_name = dbe_sprintf ("array[%lld]:%s", (long long) elems, t->get_dobjname (ctx)); else dobj_name = dbe_sprintf ("array[]:%s", t->get_dobjname (ctx)); break; } case DW_TAG_structure_type: set_dobjname (NTXT ("structure:"), name); break; case DW_TAG_union_type: set_dobjname (NTXT ("union:"), name); break; case DW_TAG_class_type: set_dobjname (NTXT ("class:"), name); break; case DW_TAG_member: { Dwr_type *t = ctx->get_dwr_type (ref_type); if (bit_size > 0) dobj_name = dbe_sprintf (NTXT ("%s:%lld"), t->get_dobjname (ctx), (long long) bit_size); else dobj_name = dbe_sprintf (NTXT ("%s"), t->get_dobjname (ctx)); break; } default: Dprintf (DUMP_DWARFLIB, NTXT ("DWARF_ERROR: %s:%d No case for %s cu_die_offset=%lld\n"), get_basename (__FILE__), (int) __LINE__, DwrCU::tag2str (tag), (long long) cu_die_offset); set_dobjname (NTXT ("Undefined:"), NULL); break; } return dobj_name; } datatype_t* Dwr_type::get_datatype (Dwarf_cnt *ctx) { if (dtype) return dtype; dtype = new datatype_t; dtype->datatype_id = (unsigned) cu_die_offset; dtype->memop_refs = 0; dtype->event_data = 0; dtype->dobj = NULL; ctx->module->datatypes->incorporate (dtype, datatypeCmp); return dtype; } DataObject * Dwr_type::get_dobj (Dwarf_cnt *ctx) { if (dtype == NULL) dtype = get_datatype (ctx); dtype->memop_refs++; DataObject *dobj = dtype->dobj; if (dobj) return dobj; if (tag == 0) dobj = dbeSession->find_dobj_by_name (PTXT (DOBJ_UNSPECIFIED)); else { dobj = dbeSession->createDataObject (); dobj->size = size; dobj->offset = offset; dobj->scope = ctx->func ? (Histable*) ctx->func : (Histable*) ctx->module; } dtype->dobj = dobj; if (parent) { Dwr_type *t = ctx->get_dwr_type (parent); dobj->parent = t->get_dobj (ctx); } if (ref_type) { Dwr_type *t = ctx->get_dwr_type (ref_type); t->get_dobj (ctx); if (size == 0) { size = t->size; dobj->size = size; } } switch (tag) { case 0: break; case DW_TAG_array_type: case DW_TAG_base_type: case DW_TAG_unspecified_type: case DW_TAG_enumeration_type: case DW_TAG_typedef: case DW_TAG_const_type: case DW_TAG_volatile_type: case DW_TAG_pointer_type: case DW_TAG_reference_type: dobj->set_dobjname (get_dobjname (ctx), NULL); break; case DW_TAG_structure_type: case DW_TAG_union_type: case DW_TAG_class_type: dobj->set_dobjname (get_dobjname (ctx), NULL); dobj->master = dbeSession->find_dobj_by_name (dobj_name); get_dobj_for_members (ctx); break; case DW_TAG_constant: case DW_TAG_formal_parameter: case DW_TAG_member: case DW_TAG_variable: if (dobj->parent == NULL) dobj->parent = dbeSession->get_Scalars_DataObject (); dobj->set_dobjname (get_dobjname (ctx), name); break; default: Dprintf (DUMP_DWARFLIB, NTXT ("DWARF_ERROR: %s:%d No case for %s cu_die_offset=%lld\n"), get_basename (__FILE__), (int) __LINE__, DwrCU::tag2str (tag), (long long) cu_die_offset); break; } return dobj; } void Dwr_type::get_dobj_for_members (Dwarf_cnt *ctx) { for (int64_t i = child; i != 0;) { Dwr_type *t = ctx->get_dwr_type (i); t->get_dobj (ctx); i = t->next; } } ////////////////////////////////////////////////////////// // class Dwarf Dwarf::Dwarf (Stabs *_stabs) { stabs = _stabs; status = Stabs::DBGD_ERR_NONE; dwrCUs = 0; debug_infoSec = NULL; debug_abbrevSec = NULL; debug_strSec = NULL; debug_lineSec = NULL; debug_rangesSec = NULL; elf = stabs->openElf (true); if (elf == NULL) { status = Stabs::DBGD_ERR_BAD_ELF_FORMAT; return; } debug_infoSec = dwrGetSec (NTXT (".debug_info")); if (debug_infoSec) { debug_infoSec->reloc = ElfReloc::get_elf_reloc (elf, NTXT (".rela.debug_info"), NULL); debug_infoSec->reloc = ElfReloc::get_elf_reloc (elf, NTXT (".rel.debug_info"), debug_infoSec->reloc); if (debug_infoSec->reloc) debug_infoSec->reloc->dump (); } debug_abbrevSec = dwrGetSec (NTXT (".debug_abbrev")); debug_strSec = dwrGetSec (NTXT (".debug_str")); debug_lineSec = dwrGetSec (NTXT (".debug_line")); debug_rangesSec = dwrGetSec (NTXT (".debug_ranges")); if ((debug_infoSec == NULL) || (debug_abbrevSec == NULL) || (debug_lineSec == NULL)) { status = Stabs::DBGD_ERR_NO_DWARF; return; } } Dwarf::~Dwarf () { delete debug_infoSec; delete debug_abbrevSec; delete debug_strSec; delete debug_lineSec; delete debug_rangesSec; Destroy (dwrCUs); } DwrSec * Dwarf::dwrGetSec (const char *sec_name) { int secN = elf->elf_get_sec_num (sec_name); if (secN > 0) { Elf_Data *elfData = elf->elf_getdata (secN); if (elfData) return new DwrSec ((unsigned char *) elfData->d_buf, elfData->d_size, elf->need_swap_endian, elf->elf_getclass () == ELFCLASS32); } return NULL; } uint64_t DwrCU::get_low_pc () { uint64_t pc = Dwarf_addr (DW_AT_low_pc); if (pc) return pc; return pc; } char * DwrCU::get_linkage_name () { char *nm = Dwarf_string (DW_AT_linkage_name); if (nm != NULL) return nm; nm = Dwarf_string (DW_AT_SUN_link_name); if (nm != NULL) return nm; return Dwarf_string (DW_AT_MIPS_linkage_name); } void DwrCU::parseChild (Dwarf_cnt *ctx) { if (!dwrTag.hasChild) return; uint64_t old_size = debug_infoSec->size; uint64_t next_die_offset = 0; Dwarf_Die next_die; if (read_ref_attr (DW_AT_sibling, &next_die) == DW_DLV_OK) { next_die_offset = next_die + cu_offset; if (next_die_offset <= debug_infoSec->offset) { Dprintf (DEBUG_ERR_MSG, NTXT ("DwrCU::parseChild: next_die(0x%llx) <= debug_infoSec->offset(%llx)\n"), (long long) next_die, (long long) debug_infoSec->offset); next_die_offset = 0; } else if (debug_infoSec->size > next_die_offset) debug_infoSec->size = next_die_offset; } dwrTag.level++; ctx->level++; for (;;) { if (set_die (0) != DW_DLV_OK) break; Function *func; char *old_name; int hasChild = dwrTag.hasChild; switch (dwrTag.tag) { case DW_TAG_imported_declaration: if (Stabs::is_fortran (ctx->module->lang_code)) { char *link_name = Dwarf_string (DW_AT_name); ctx->fortranMAIN = NULL; parseChild (ctx); hasChild = 0; if (ctx->fortranMAIN) { ctx->fortranMAIN->set_match_name (link_name); ctx->fortranMAIN = NULL; } } break; case DW_TAG_subprogram: if (dwrTag.get_attr (DW_AT_abstract_origin)) break; if (dwrTag.get_attr (DW_AT_declaration)) { // Only declaration if (Stabs::is_fortran (ctx->module->lang_code)) { char *link_name = Dwarf_string (DW_AT_name); if (link_name && streq (link_name, NTXT ("MAIN"))) ctx->fortranMAIN = Stabs::find_func (NTXT ("MAIN"), ctx->module->functions, true, true); } if (get_linkage_name () == NULL) break; } func = append_Function (ctx); if (func) { if (Stabs::is_fortran (ctx->module->lang_code) && streq (func->get_match_name (), NTXT ("MAIN"))) ctx->fortranMAIN = func; old_name = ctx->name; Function *old_func = ctx->func; ctx->name = func->get_match_name (); ctx->func = func; parseChild (ctx); hasChild = 0; ctx->name = old_name; ctx->func = old_func; } break; case DW_TAG_module: old_name = ctx->name; ctx->name = Dwarf_string (DW_AT_SUN_link_name); parseChild (ctx); hasChild = 0; ctx->name = old_name; break; case DW_TAG_class_type: old_name = ctx->name; ctx->name = Dwarf_string (DW_AT_name); parseChild (ctx); hasChild = 0; ctx->name = old_name; break; case DW_TAG_structure_type: old_name = ctx->name; ctx->name = NULL; parseChild (ctx); hasChild = 0; ctx->name = old_name; break; case DW_TAG_namespace: old_name = ctx->name; ctx->name = Dwarf_string (DW_AT_name); parseChild (ctx); hasChild = 0; ctx->name = old_name; break; case DW_TAG_lexical_block: old_name = ctx->name; ctx->name = NULL; parseChild (ctx); hasChild = 0; ctx->name = old_name; break; case DW_TAG_SUN_memop_info: isMemop = true; break; case DW_TAG_inlined_subroutine: if (ctx->module) { parse_inlined_subroutine (ctx); hasChild = 0; } break; default: // No more special cases break; } if (hasChild) parseChild (ctx); } ctx->level--; dwrTag.level--; if (next_die_offset != 0) debug_infoSec->offset = next_die_offset; debug_infoSec->size = old_size; } bool Dwarf::archive_Dwarf (LoadObject *lo) { if (debug_infoSec == NULL) return false; if (dwrCUs) return true; dwrCUs = new Vector; debug_infoSec->offset = 0; while (debug_infoSec->offset < debug_infoSec->sizeSec) { DwrCU *dwrCU = new DwrCU (this); dwrCUs->append (dwrCU); debug_infoSec->size = debug_infoSec->sizeSec; debug_infoSec->offset = dwrCU->next_cu_offset; if (dwrCU->set_die (dwrCU->cu_header_offset) != DW_DLV_OK) { Dprintf (1, "DwrCU::archive_Dwarf: CU=%lld (offset=0x%llx); set_die(0x%llx) failed\n", (long long) dwrCUs->size (), (long long) dwrCU->cu_offset, (long long) dwrCU->cu_header_offset); continue; } Module *mod = dwrCU->parse_cu_header (lo); if (mod) { mod->hdrOffset = dwrCUs->size (); DwrLineRegs *lineReg = dwrCU->get_dwrLineReg (); dwrCU->srcFiles = new Vector (VecSize (lineReg->file_names)); for (long i = 0, sz = VecSize (lineReg->file_names); i < sz; i++) { char *fname = lineReg->getPath (i + 1); SourceFile *sf = mod->findSource (fname, true); dwrCU->srcFiles->append (sf); } Dwarf_cnt ctx; ctx.module = mod; dwrCU->parseChild (&ctx); if (dwrCU->dwrInlinedSubrs && DUMP_DWARFLIB) { char msg[128]; char *lo_name = mod->loadobject ? mod->loadobject->get_name () : NULL; snprintf (msg, sizeof (msg), NTXT ("\ndwrCUs[%lld]: %s:%s\n"), (long long) dwrCUs->size (), STR (lo_name), STR (mod->get_name ())); dwrCU->dwrInlinedSubrs->dump (msg); } } } return true; } void Dwarf::srcline_Dwarf (Module *module) { if (module == NULL || module->hdrOffset == 0) return; DwrCU *dwrCU = dwrCUs->get (module->hdrOffset - 1); dwrCU->map_dwarf_lines (module); } // parse hwcprof info for given module in loadobject void Dwarf::read_hwcprof_info (Module *module) { if (module->datatypes || (module->hdrOffset == 0)) return; DwrCU *dwrCU = dwrCUs->get (module->hdrOffset - 1); if (!dwrCU->isMemop) return; module->datatypes = new Vector; if (dwrCU->set_die (dwrCU->cu_header_offset) != DW_DLV_OK) { Dprintf (1, "Dwarf::read_hwcprof_info: CU=%lld (offset=0x%llx); set_die(0x%llx) failed\n", (long long) module->hdrOffset, (long long) dwrCU->cu_offset, (long long) dwrCU->cu_header_offset); return; } Dwarf_cnt ctx; ctx.module = module; ctx.cu_offset = dwrCU->cu_offset; // CU header offset; ctx.dwr_types = new DefaultMap; ctx.put_dwr_type (0, 0); // for DOBJ_UNSPECIFIED dwrCU->read_hwcprof_info (&ctx); Vector *infoList = module->infoList; Dprintf (DUMP_DWARFLIB, "\n\n ### Dwarf::read_hwcprof_info: module: '%s' infoList->size()=%lld\n", STR (module->get_name ()), (long long) (infoList ? infoList->size () : -1)); for (int i = 0, sz = infoList ? infoList->size () : -1; i < sz; i++) { inst_info_t *ip = infoList->fetch (i); memop_info_t *mp = ip->memop; Dwr_type *t = ctx.get_dwr_type (mp->datatype_id); t->get_dobj (&ctx); } #ifdef DEBUG Dprintf (DUMP_DWARFLIB, "\n\n ### Dwarf::read_hwcprof_info: '%s' infoList->size()=%lld\n", STR (module->get_name ()), (long long) (infoList ? infoList->size () : 1)); for (int i = 0, sz = infoList ? infoList->size () : -1; i < sz; i++) { inst_info_t *ip = infoList->fetch (i); memop_info_t *mp = ip->memop; Dprintf (DUMP_DWARFLIB, " %d id=%lld offset=%lld signature=%lld datatype_id=%lld \n", i, (long long) mp->id, (long long) mp->offset, (long long) mp->signature, (long long) mp->datatype_id); } Vector *keys = ctx.dwr_types->keySet (); Dprintf (DUMP_DWARFLIB, "\n\n ### Dwarf::read_hwcprof_info: '%s' keys->size()=%lld\n", STR (module->get_name ()), (long long) (keys ? keys->size () : -1)); for (int i = 0, sz = keys->size (); i < sz; i++) { int64_t ind = keys->fetch (i); Dwr_type *t = ctx.get_dwr_type (ind); Dprintf (DUMP_DWARFLIB, NTXT (" %d %lld %s\n"), i, (long long) ind, t->dump ()); } #endif } void DwrCU::read_hwcprof_info (Dwarf_cnt *ctx) { if (!dwrTag.hasChild) return; uint64_t old_size = debug_infoSec->size; uint64_t next_die_offset = 0; Dwarf_Die next_die; if (read_ref_attr (DW_AT_sibling, &next_die) == DW_DLV_OK) { next_die_offset = next_die + cu_offset; if (next_die_offset <= debug_infoSec->offset) next_die_offset = 0; else if (debug_infoSec->size > next_die_offset) debug_infoSec->size = next_die_offset; } dwrTag.level++; ctx->level++; for (;;) { if (set_die (0) != DW_DLV_OK) break; Dprintf (DUMP_DWARFLIB, NTXT ("%s:%d <%lld:%lld> cu_die=%lld %-15s\n"), get_basename (__FILE__), (int) __LINE__, (long long) ctx->level, (long long) dwrTag.die, (long long) dwrTag.offset, DwrCU::tag2str (dwrTag.tag)); switch (dwrTag.tag) { case DW_TAG_SUN_memop_info: { if (ctx->func == NULL) break; Dwarf_Unsigned mid = Dwarf_data (DW_AT_SUN_profile_id); Dwarf_Unsigned off = Dwarf_data (DW_AT_SUN_func_offset); Dwarf_Unsigned sig = Dwarf_data (DW_AT_SUN_memop_signature); Dwarf_Off ref = Dwarf_ref (DW_AT_SUN_memop_type_ref); // define memop entry memop_info_t *memop = new memop_info_t; memop->id = (unsigned) mid; memop->signature = (unsigned) sig; memop->datatype_id = ref ? (unsigned) ref : 0; memop->offset = (unsigned) (ctx->func->img_offset + off); // define instop entry inst_info_t *instop = new inst_info_t; instop->type = CPF_INSTR_TYPE_PREFETCH; // XXXX UNKNOWN instop->offset = memop->offset; instop->memop = memop; if (ctx->module->infoList == NULL) ctx->module->infoList = new Vector; ctx->module->infoList->append (instop); break; } case DW_TAG_SUN_codeflags: { if (ctx->func == NULL) break; Dwarf_Unsigned kind = Dwarf_data (DW_AT_SUN_cf_kind); if (kind == DW_ATCF_SUN_branch_target) { DwrSec *secp = Dwarf_block (DW_AT_SUN_func_offsets); if (secp) { int foffset = 0; for (int i = 0; secp->offset < secp->size; i++) { int val = (int) secp->GetSLEB128 (); if (i == 0 || val != 0) { foffset += val; target_info_t *t = new target_info_t; t->offset = (unsigned) (ctx->func->img_offset + foffset); ctx->module->bTargets.incorporate (t, targetOffsetCmp); } } delete(secp); } } break; } case DW_TAG_subprogram: { Function *old_func = ctx->func; if (dwrTag.get_attr (DW_AT_abstract_origin) || dwrTag.get_attr (DW_AT_declaration)) ctx->func = NULL; else ctx->func = append_Function (ctx); read_hwcprof_info (ctx); ctx->func = old_func; break; } case DW_TAG_base_type: { Dwr_type *t = ctx->put_dwr_type (dwrTag.die, dwrTag.tag); t->name = Dwarf_string (DW_AT_name); t->size = Dwarf_data (DW_AT_byte_size); break; } case DW_TAG_unspecified_type: ctx->put_dwr_type (dwrTag.die, dwrTag.tag); break; case DW_TAG_enumeration_type: { Dwr_type *t = ctx->put_dwr_type (dwrTag.die, dwrTag.tag); t->name = Dwarf_string (DW_AT_name); t->size = Dwarf_data (DW_AT_byte_size); break; } case DW_TAG_constant: case DW_TAG_formal_parameter: case DW_TAG_variable: case DW_TAG_typedef: case DW_TAG_const_type: case DW_TAG_volatile_type: { Dwr_type *t = ctx->put_dwr_type (dwrTag.die, dwrTag.tag); t->name = Dwarf_string (DW_AT_name); t->ref_type = Dwarf_ref (DW_AT_type); break; } case DW_TAG_pointer_type: case DW_TAG_reference_type: { Dwr_type *t = ctx->put_dwr_type (dwrTag.die, dwrTag.tag); t->name = Dwarf_string (DW_AT_name); t->ref_type = Dwarf_ref (DW_AT_type); t->size = (dwarf->stabs->get_class () == W64) ? 8 : 4; break; } case DW_TAG_array_type: { Dwr_type *t = ctx->put_dwr_type (dwrTag.die, dwrTag.tag); t->name = Dwarf_string (DW_AT_name); t->ref_type = Dwarf_ref (DW_AT_type); t->size = Dwarf_data (DW_AT_byte_size); ctx->size = -1; read_hwcprof_info (ctx); t->elems = ctx->size; break; } case DW_TAG_subrange_type: { int64_t ref_type = Dwarf_ref (DW_AT_type); int64_t hi = Dwarf_data (DW_AT_upper_bound); int64_t lo = Dwarf_data (DW_AT_lower_bound); int64_t ss = Dwarf_data (DW_AT_stride_size); ctx->size = 1 + hi - lo; if (ss != 0) ctx->size /= ss; Dprintf (DUMP_DWARFLIB, "Got subrange [%lld:%lld:%lld] indexed <%lld>: size=%lld\n", (long long) lo, (long long) hi, (long long) ss, (long long) ref_type, (long long) ctx->size); break; } case DW_TAG_structure_type: case DW_TAG_union_type: case DW_TAG_class_type: { Dwr_type *t = ctx->put_dwr_type (dwrTag.die, dwrTag.tag); t->name = Dwarf_string (DW_AT_name); t->size = Dwarf_data (DW_AT_byte_size); t->extent = Dwarf_ref (DW_AT_sibling); int64_t old_parent = ctx->parent; ctx->parent = t->cu_die_offset; char *old_name = ctx->name; ctx->name = (dwrTag.tag == DW_TAG_class_type) ? Dwarf_string (DW_AT_name) : NULL; read_hwcprof_info (ctx); ctx->name = old_name; ctx->parent = old_parent; // Reverse children for (int64_t i = t->child, last = 0; i != 0;) { Dwr_type *t1 = ctx->get_dwr_type (i); t->child = i; i = t1->next; t1->next = last; last = t->child; } break; } case DW_TAG_member: { if (ctx->parent == 0) { Dprintf (DUMP_DWARFLIB, NTXT ("DWARF_ERROR: %s:%d %s cu_die_offset=%lld\n"), get_basename (__FILE__), (int) __LINE__, DwrCU::tag2str (dwrTag.tag), (long long) dwrTag.die); break; } Dwr_type *t = ctx->put_dwr_type (dwrTag.die, dwrTag.tag); t->name = Dwarf_string (DW_AT_name); t->ref_type = Dwarf_ref (DW_AT_type); t->offset = Dwarf_location (DW_AT_data_member_location); Dwr_type *parent = ctx->get_dwr_type (ctx->parent); t->parent = ctx->parent; t->next = parent->child; // a reverse order of members parent->child = t->cu_die_offset; t->bit_size = (uint32_t) Dwarf_data (DW_AT_bit_size); break; } case DW_TAG_module: { char *old_name = ctx->name; ctx->name = Dwarf_string (DW_AT_SUN_link_name); read_hwcprof_info (ctx); ctx->name = old_name; break; } case DW_TAG_namespace: { char *old_name = ctx->name; ctx->name = Dwarf_string (DW_AT_name); read_hwcprof_info (ctx); ctx->name = old_name; break; } case DW_TAG_lexical_block: { char *old_name = ctx->name; ctx->name = NULL; read_hwcprof_info (ctx); ctx->name = old_name; break; } default: // No more special cases read_hwcprof_info (ctx); break; } } ctx->level--; dwrTag.level--; if (next_die_offset != 0) debug_infoSec->offset = next_die_offset; debug_infoSec->size = old_size; } // Append function to module Function * DwrCU::append_Function (Dwarf_cnt *ctx) { char *outerName = ctx->name, *name, tmpname[2048]; Function *func; char *fname = Dwarf_string (DW_AT_name); if (fname && outerName && !strchr (fname, '.')) { size_t outerlen = strlen (outerName); if (outerlen > 0 && outerName[outerlen - 1] == '_') { outerlen--; snprintf (tmpname, sizeof (tmpname), NTXT ("%s"), outerName); snprintf (tmpname + outerlen, sizeof (tmpname) - outerlen, NTXT (".%s_"), fname); } else snprintf (tmpname, sizeof (tmpname), NTXT ("%s.%s"), outerName, fname); name = tmpname; Dprintf (DUMP_DWARFLIB, NTXT ("Generated innerfunc name %s\n"), name); } else name = fname; char *link_name = get_linkage_name (); if (link_name == NULL) link_name = name; uint64_t pc = get_low_pc (); func = dwarf->stabs->append_Function (module, link_name, pc); if (func != NULL) { int lineno = (int) Dwarf_data (DW_AT_decl_line); func->set_match_name (name); if (lineno > 0) { func->setLineFirst (lineno); if (dwrLineReg == NULL) dwrLineReg = new DwrLineRegs (new DwrSec (dwarf->debug_lineSec, stmt_list_offset), comp_dir); int fileno = ((int) Dwarf_data (DW_AT_decl_file)) - 1; SourceFile *sf = ((fileno >= 0) && (fileno < VecSize (srcFiles))) ? srcFiles->get (fileno) : module->getMainSrc (); func->setDefSrc (sf); func->pushSrcFile (func->def_source, 0); func->popSrcFile (); } } return func; } // Get language code Sp_lang_code DwrCU::Dwarf_lang () { char *str = Dwarf_string (DW_AT_producer); if (str && strncmp (str, NTXT ("GNU"), 3) == 0) isGNU = true; int64_t lang = Dwarf_data (DW_AT_language); switch (lang) { case DW_LANG_C89: case DW_LANG_C: return Sp_lang_c; // Sp_lang_ansic? case DW_LANG_C99: return Sp_lang_c99; case DW_LANG_C_plus_plus: return isGNU ? Sp_lang_gcc : Sp_lang_cplusplus; case DW_LANG_Fortran90: return Sp_lang_fortran90; case DW_LANG_Fortran77: return Sp_lang_fortran; case DW_LANG_Java: return Sp_lang_java; case DW_LANG_Mips_Assembler: case DW_LANG_SUN_Assembler: return Sp_lang_asm; case DW_LANG_Pascal83: return Sp_lang_pascal; default: case DW_LANG_Ada83: case DW_LANG_Cobol74: case DW_LANG_Cobol85: case DW_LANG_Modula2: case DW_LANG_Ada95: case DW_LANG_Fortran95: case DW_LANG_lo_user: return Sp_lang_unknown; } }