aboutsummaryrefslogtreecommitdiff
path: root/gprofng/src/Dwarf.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gprofng/src/Dwarf.cc')
-rw-r--r--gprofng/src/Dwarf.cc1041
1 files changed, 1041 insertions, 0 deletions
diff --git a/gprofng/src/Dwarf.cc b/gprofng/src/Dwarf.cc
new file mode 100644
index 0000000..eb8bd9e
--- /dev/null
+++ b/gprofng/src/Dwarf.cc
@@ -0,0 +1,1041 @@
+/* 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 "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<ANON=%lld>", spec,
+ (long long) cu_die_offset);
+ }
+ else
+ {
+ if (nm)
+ dobj_name = dbe_sprintf ("%s", nm);
+ else
+ dobj_name = dbe_sprintf ("<ANON=%lld>", (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<DwrCU *>;
+
+ 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<SourceFile *> (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<datatype_t*>;
+ 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<int64_t, Dwr_type*>;
+ ctx.put_dwr_type (0, 0); // for DOBJ_UNSPECIFIED
+ dwrCU->read_hwcprof_info (&ctx);
+
+ Vector<inst_info_t*> *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<int64_t> *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<inst_info_t*>;
+ 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;
+ }
+}