diff options
Diffstat (limited to 'gprofng/src/DwarfLib.cc')
-rw-r--r-- | gprofng/src/DwarfLib.cc | 333 |
1 files changed, 321 insertions, 12 deletions
diff --git a/gprofng/src/DwarfLib.cc b/gprofng/src/DwarfLib.cc index d399c33..79be8cf 100644 --- a/gprofng/src/DwarfLib.cc +++ b/gprofng/src/DwarfLib.cc @@ -27,9 +27,9 @@ #include "Elf.h" #include "Function.h" #include "Module.h" -#include "StringBuilder.h" #include "DbeArray.h" #include "DbeSession.h" +#include "Symbol.h" #define NO_STMT_LIST ((uint64_t) -1) #define CASE_S(x) case x: s = (char *) #x; break @@ -998,7 +998,6 @@ Dwr_Tag::dump () case DW_FORM_strx2: case DW_FORM_strx3: case DW_FORM_strx4: - case DW_FORM_implicit_const: Dprintf (DUMP_DWARFLIB, " \"%s\"", atrp->u.str ? atrp->u.str : "<NULL>"); break; case DW_FORM_block: @@ -1037,6 +1036,7 @@ Dwr_Tag::dump () case DW_FORM_exprloc: case DW_FORM_ref_sig8: case DW_FORM_flag_present: + case DW_FORM_implicit_const: Dprintf (DUMP_DWARFLIB, " 0x%llx (%lld)", (long long) atrp->u.val, (long long) atrp->u.val); break; @@ -1095,6 +1095,7 @@ DwrSec::bounds_violation (uint64_t sz) { Dprintf (DEBUG_ERR_MSG, "DwrSec::bounds_violation: offset=%lld + sz=%lld > size=%lld\n", (long long) offset, (long long) sz, (long long) size); + offset = size; return true; } return false; @@ -1795,6 +1796,12 @@ DwrLineRegs::getPath (int fn) DwrCU::DwrCU (Dwarf *_dwarf) { dwarf = _dwarf; + tmp_syms = new Vector<Symbol*>(); + rng_list = NULL; + rng_list_inited = false; + base_address = 0; + symbols = NULL; + symbols_sorted_by_name = NULL; cu_offset = dwarf->debug_infoSec->offset; debug_infoSec = new DwrSec (dwarf->debug_infoSec, cu_offset); next_cu_offset = debug_infoSec->ReadLength (); @@ -1847,7 +1854,7 @@ DwrCU::DwrCU (Dwarf *_dwarf) (long long) cu_offset, (long long) cu_offset, (long long) next_cu_offset, (long long) next_cu_offset, (long long) debug_abbrev_offset, (long long) debug_abbrev_offset, - (long long) (next_cu_offset - cu_offset), + (long long) (next_cu_offset), (int) version, (int) address_size, debug_infoSec->fmt64 ? "true" : "false", debug_infoSec->need_swap_endian ? "true" : "false", @@ -1883,6 +1890,9 @@ DwrCU::~DwrCU () Destroy (dwrInlinedSubrs); delete srcFiles; delete dwrLineReg; + delete symbols; + delete symbols_sorted_by_name; + delete tmp_syms; free (comp_dir); } @@ -1925,7 +1935,7 @@ DwrCU::build_abbrevTable (DwrSec *_debug_abbrevSec, uint64_t _offset) switch (atf.at_form) { case DW_FORM_implicit_const: - atf.len = debug_abbrevSec->GetSLEB128 (); + atf.u.val = debug_abbrevSec->GetSLEB128 (); break; } abbrevAtForm->append (atf); @@ -1945,7 +1955,7 @@ DwrCU::set_die (Dwarf_Die die) || debug_infoSec->offset >= debug_infoSec->size) return DW_DLV_ERROR; dwrTag.offset = debug_infoSec->offset; - dwrTag.die = debug_infoSec->offset - cu_offset; + dwrTag.die = debug_infoSec->offset; dwrTag.num = debug_infoSec->GetULEB128_32 (); if (dwrTag.num == 0) return DW_DLV_NO_ENTRY; @@ -1994,19 +2004,19 @@ DwrCU::set_die (Dwarf_Die die) atf->u.str = debug_infoSec->GetData (atf->len); break; case DW_FORM_ref1: - atf->u.offset = debug_infoSec->Get_8 (); + atf->u.offset = debug_infoSec->Get_8 () + cu_offset; break; case DW_FORM_ref2: - atf->u.offset = debug_infoSec->Get_16 (); + atf->u.offset = debug_infoSec->Get_16 () + cu_offset; break; case DW_FORM_ref4: - atf->u.offset = debug_infoSec->Get_32 (); + atf->u.offset = debug_infoSec->Get_32 () + cu_offset; break; case DW_FORM_ref8: - atf->u.offset = debug_infoSec->Get_64 (); + atf->u.offset = debug_infoSec->Get_64 () + cu_offset; break; case DW_FORM_ref_udata: - atf->u.offset = debug_infoSec->GetULEB128 (); + atf->u.offset = debug_infoSec->GetULEB128 () + cu_offset; break; case DW_FORM_data1: atf->u.offset = debug_infoSec->Get_8 (); @@ -2109,7 +2119,7 @@ DwrCU::set_die (Dwarf_Die die) atf->len = 0; break; case DW_FORM_implicit_const: - atf->u.str = NULL; + // atf->u.val is already set break; default: DEBUG_CODE @@ -2187,9 +2197,241 @@ DwrCU::parse_cu_header (LoadObject *lo) else path = dbe_strdup (dwarf->stabs->path); module->set_name (path); + + // create a list of functions in this CU + base_address = get_low_pc (); + Vector <Range *> *ranges = get_ranges (); + if (ranges) + { + Vector <Symbol *> *syms = dwarf->stabs->get_symbols (); + symbols = Symbol::find_symbols (syms, ranges, new Vector <Symbol *> ()); + symbols_sorted_by_name = Symbol::sort_by_name (symbols); + if (DUMP_ELF_SYM) + symbols->dump ("DwrCU::parse_cu_header: symbols"); + Destroy (ranges); + } return module; } + +static int +cmp_ExtRange (const void *a, const void *b) +{ + uint64_t a1 = *((uint64_t *) a); + ExtRange *rng = *((ExtRange **) b); + uint64_t b1 = rng->offset; + return a1 < b1 ? -1 : (a1 == b1 ? 0 : 1); +} + +static int +cmp_offset (const void *a, const void *b) +{ + uint64_t off = *((uint64_t *) a); + Dwr_rng_entry *rng = *((Dwr_rng_entry **) b); + return off < rng->offset ? -1 : (off < rng->length ? 0 : 1); +} + +static int +rangeCmp (const void *a, const void *b) +{ + Range *item1 = *((Range **) a); + Range *item2 = *((Range **) b); + return item1->low < item2->low ? -1 : (item1->low == item2->low ? 0 : 1); +} + +Vector <Range *> * +DwrCU::get_ranges () +{ + Vector <Range *> *ranges = NULL; + Dwr_Attr *dwrAttr = dwrTag.get_attr (DW_AT_ranges); + if (dwrAttr) + { + uint64_t offset = dwrAttr->u.offset; + Dprintf (DUMP_DWARFLIB, "DwrCU::get_ranges: 0x%llx\n", (long long) offset); + if (version < 5) + ranges = dwarf->get_ranges (offset); + else + { + if (rng_list == NULL && !rng_list_inited) + { + rng_list_inited = true; + // Find the corresponding section in .debug_rnglists + Vector <Dwr_rng_entry *> *rng_entrys = dwarf->get_debug_rnglists (); + if (rng_entrys == NULL) + return NULL; + int ind = rng_entrys->bisearch (0, -1, &offset, cmp_offset); + if (ind != -1) + rng_list = rng_entrys->get (ind); + else + { + Dprintf (1, "Cannot find rnglist. DW_AT_ranges=0x%llx\n", + (long long) offset); + return NULL; + } + } + if (rng_list == NULL) + return NULL; + int ind = rng_list->ranges->bisearch (0, -1, &offset, cmp_ExtRange); + if (ind == -1) + { + Dprintf (1, "Cannot find rnglist. DW_AT_ranges=0x%llx\n", + (long long) offset); + return NULL; + } + ranges = new Vector <Range *> (); + for (long i = ind, sz = VecSize (rng_list->ranges); i < sz; i++) + { + ExtRange *r = rng_list->ranges->get (i); + if (r->high == 0) + break; + ranges->append (new Range (r->low + base_address, + r->high + base_address)); + } + } + } + else + { + uint64_t low_pc = Dwarf_addr (DW_AT_low_pc); + if (low_pc > 0) + { + uint64_t high_pc = get_high_pc (low_pc); + ranges = new Vector <Range *> (1); + ranges->append (new Range (low_pc, high_pc)); + Dprintf (DUMP_DWARFLIB, "DwrCU::get_ranges: pc=0x%llx\n", + (long long) low_pc); + } + } + if (ranges) + { + ranges->sort (rangeCmp); + if (DUMP_DWARFLIB) + ranges->dump ("DwrCU::get_ranges:"); + } + return ranges; +} + +Vector<Symbol *> * +DwrCU::get_symbols (Vector<Symbol *> *syms) +{ + if (syms) + syms->reset (); + Vector <Range *> *ranges = get_ranges (); + if (ranges) + { + syms = Symbol::find_symbols (symbols, ranges, syms); + Destroy (ranges); + } + if (syms) + { + Symbol *sym = Symbol::get_symbol (symbols_sorted_by_name, + get_linkage_name ()); + if (sym) + syms->append (sym); + } + if (syms && DUMP_ELF_SYM) + syms->dump ("DwrCU::get_symbols:"); + return syms; +} + +void +DwrCU::set_source (Function *func) +{ + int lineno = (int) Dwarf_data (DW_AT_decl_line); + func->setLineFirst (lineno); + + int fileno = (int) Dwarf_data (DW_AT_decl_file); + func->setDefSrc (get_source (fileno)); +} + +SourceFile * +DwrCU::get_source (int fileno) +{ + if (fileno > 0 && fileno < VecSize (srcFiles)) + return srcFiles->get (fileno); + return NULL; +} + +void +DwrCU::inherit_prop (int64_t offset, source_t *src) +{ + if (src->lineno == 0) + src->lineno = (int) Dwarf_data (DW_AT_decl_line); + if (src->sf == NULL) + src->sf = get_source ((int) Dwarf_data (DW_AT_decl_file)); + + int64_t old_offset = dwrTag.offset; + if (set_die (offset) == DW_DLV_OK) + { + if (src->lineno == 0) + src->lineno = (int) Dwarf_data (DW_AT_decl_line); + if (src->sf == NULL) + src->sf = get_source ((int) Dwarf_data (DW_AT_decl_file)); + + Dwr_Attr *dwrAttr = dwrTag.get_attr (DW_AT_specification); + if (dwrAttr) + inherit_prop (dwrAttr->u.offset, src); + else + { + Symbol *sym = Symbol::get_symbol (symbols_sorted_by_name, + get_linkage_name ()); + if (sym) + update_source (sym, src); + } + } + set_die (old_offset); +} + +void +DwrCU::set_up_funcs (int64_t offset) +{ + // get symbols from DW_AT_ranges, DW_AT_low_pc, DW_AT_linkage_name + Vector<Symbol *> *syms = get_symbols (tmp_syms); + if (VecSize (syms) == 0) + return; + + // Find previous declaration to inherit settings. + source_t src = {.lineno = 0, .sf = NULL}; + inherit_prop (offset, &src); + + for (int i = 0, sz = VecSize (syms); i < sz; i++) + { + Symbol *sym = syms->get (i); + update_source (sym, &src); + if (sym->alias) + update_source (sym->alias, &src); + } +} + +/* Create a function if necessary. + * Update the source information */ +void +DwrCU::update_source (Symbol *sym, source_t *src) +{ + Function *f = sym->createFunction (module); + f->setLineFirst (src->lineno); + f->setDefSrc (src->sf); +} + +Symbol * +DwrCU::find_declaration (int64_t offset, source_t *src) +{ + int64_t old_offset = dwrTag.offset; + Symbol *sym = NULL; + if (set_die (offset) == DW_DLV_OK) + { + if (src->lineno == 0) + src->lineno = (int) Dwarf_data (DW_AT_decl_line); + if (src->sf == NULL) + src->sf = get_source ((int) Dwarf_data (DW_AT_decl_file)); + + sym = Symbol::get_symbol (symbols_sorted_by_name, get_linkage_name ()); + if (sym && sym->func == NULL) + update_source (sym, src); + } + set_die (old_offset); + return sym; +} + Dwr_Attr * Dwr_Tag::get_attr (Dwarf_Half attr) { @@ -2269,6 +2511,7 @@ DwrCU::read_data_attr (Dwarf_Half attr, int64_t *retVal) case DW_FORM_data16: case DW_FORM_udata: case DW_FORM_sec_offset: + case DW_FORM_implicit_const: *retVal = dwrAttr->u.val; return DW_DLV_OK; @@ -2357,7 +2600,7 @@ DwrCU::map_dwarf_lines (Module *mod) InlinedSubr *p = func->inlinedSubr + func->inlinedSubrCnt; func->inlinedSubrCnt++; int fileno = inlinedSubr->file - 1; - SourceFile *sf = ((fileno >= 0) && (fileno < VecSize (srcFiles))) ? + SourceFile *sf = ((fileno > 0) && (fileno < VecSize (srcFiles))) ? srcFiles->get (fileno) : dbeSession->get_Unknown_Source (); p->dbeLine = sf->find_dbeline (inlinedSubr->line); p->high_pc = inlinedSubr->high_pc - low_pc; @@ -2502,3 +2745,69 @@ DwrInlinedSubr::dump () (int) level, (long long) abstract_origin, (long long) low_pc, (long long) high_pc, (int) file, (int) line); } + + +////////////////////////////////////////////////////////// +// class Dwr_rng_entry +Dwr_rng_entry::Dwr_rng_entry () +{ + ranges = new Vector <ExtRange *>(); +} + +Dwr_rng_entry::~Dwr_rng_entry () +{ + delete ranges; +} + +void +Dwr_rng_entry::dump () +{ + Dprintf (DUMP_DWARFLIB, "offset=0x%08llx length=0x%08llx fmt=%d version=%d " + "addr_size=%d seg_size=%d offset_entry_count=0x%llx\n", + (long long) offset, (long long) (length - offset), fmt64 ? 64 : 32, + (int) version, (int) address_size, (int) segment_selector_size, + (long long) offset_entry_count); + for (long i = 0, sz = VecSize (ranges); i < sz; i++) + { + ExtRange *p = ranges->get (i); + Dprintf (DUMP_DWARFLIB, " %8ld: 0x%08llx 0x%08llx-0x%08llx [%lld-%lld)\n", + i, (long long) p->offset, (long long) p->low, (long long) p->high, + (long long) p->low, (long long) p->high); + } +} + +char * +Dwr_rng_entry::rng_entry2str (int val) +{ + char *s; + switch (val) + { + CASE_S (DW_RLE_end_of_list); + CASE_S (DW_RLE_base_address); + CASE_S (DW_RLE_start_length); + CASE_S (DW_RLE_offset_pair); + CASE_S (DW_RLE_start_end); + CASE_S (DW_RLE_base_addressx); + CASE_S (DW_RLE_startx_endx); + CASE_S (DW_RLE_startx_length); + default: s = (char *) "???"; + break; + } + return s; +} + +template<> void Vector<Dwr_rng_entry *>::dump (const char *msg) +{ + if (!DUMP_DWARFLIB) + return; + if (msg == NULL) + msg = "#"; + Dprintf (1, NTXT ("\n%s Vector<Dwr_rng_entry *> [%lld]\n"), msg, (long long) size ()); + for (long i = 0, sz = size (); i < sz; i++) + { + Dwr_rng_entry *p = get (i); + Dprintf (1, " %3ld ", i); + p->dump (); + } +} + |