aboutsummaryrefslogtreecommitdiff
path: root/gprofng/src/DwarfLib.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gprofng/src/DwarfLib.cc')
-rw-r--r--gprofng/src/DwarfLib.cc2203
1 files changed, 2203 insertions, 0 deletions
diff --git a/gprofng/src/DwarfLib.cc b/gprofng/src/DwarfLib.cc
new file mode 100644
index 0000000..c8af0ab
--- /dev/null
+++ b/gprofng/src/DwarfLib.cc
@@ -0,0 +1,2203 @@
+/* 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 <ctype.h>
+
+#include "util.h"
+#include "Dwarf.h"
+#include "DwarfLib.h"
+#include "Elf.h"
+#include "Function.h"
+#include "Module.h"
+#include "StringBuilder.h"
+#include "DbeArray.h"
+#include "DbeSession.h"
+
+#define CASE_S(x) case x: s = (char *) #x; break
+
+static char *
+gelf_st_type2str (int type)
+{
+ static char buf[128];
+ char *s;
+ switch (type)
+ {
+ CASE_S (STT_NOTYPE);
+ CASE_S (STT_OBJECT);
+ CASE_S (STT_FUNC);
+ CASE_S (STT_SECTION);
+ CASE_S (STT_FILE);
+ CASE_S (STT_COMMON);
+ CASE_S (STT_TLS);
+ // CASE_S(STT_NUM);
+ CASE_S (STT_LOPROC);
+ CASE_S (STT_HIPROC);
+ default: s = NTXT ("???");
+ break;
+ }
+ snprintf (buf, sizeof (buf), NTXT ("%s(%d)"), s, type);
+ buf[sizeof (buf) - 1] = 0;
+ return buf;
+}
+
+static char *
+special_opcode2str (int opcode)
+{
+ static char buf[128];
+ snprintf (buf, sizeof (buf), NTXT ("SpecialOpcode: %3d"), opcode);
+ buf[sizeof (buf) - 1] = 0;
+ return buf;
+}
+
+static char *
+extended_opcode2str (int opcode)
+{
+ static char buf[128];
+ char *s;
+ switch (opcode)
+ {
+ CASE_S (DW_LNE_end_sequence);
+ CASE_S (DW_LNE_set_address);
+ CASE_S (DW_LNE_define_file);
+ default:
+ snprintf (buf, sizeof (buf), NTXT ("??? (%d)"), opcode);
+ buf[sizeof (buf) - 1] = 0;
+ s = buf;
+ break;
+ }
+ return s;
+}
+
+static char *
+standard_opcode2str (int opcode)
+{
+ static char buf[128];
+ char *s;
+ switch (opcode)
+ {
+ CASE_S (DW_LNS_copy);
+ CASE_S (DW_LNS_advance_pc);
+ CASE_S (DW_LNS_advance_line);
+ CASE_S (DW_LNS_set_file);
+ CASE_S (DW_LNS_set_column);
+ CASE_S (DW_LNS_negate_stmt);
+ CASE_S (DW_LNS_set_basic_block);
+ CASE_S (DW_LNS_const_add_pc);
+ CASE_S (DW_LNS_fixed_advance_pc);
+ default:
+ snprintf (buf, sizeof (buf), NTXT ("??? (%d)"), opcode);
+ buf[sizeof (buf) - 1] = 0;
+ s = buf;
+ break;
+ }
+ return s;
+}
+
+template<> void Vector<DwrInlinedSubr *>
+::dump (const char *msg)
+{
+ Dprintf (1, NTXT ("%s Vector<DwrInlinedSubr *> [%lld]\n"),
+ msg ? msg : NTXT (""), (long long) size ());
+ for (long i = 0, sz = size (); i < sz; i++)
+ {
+ DwrInlinedSubr *p = get (i);
+ Dprintf (1, NTXT ("%ld: "), (long) i);
+ p->dump ();
+ }
+}
+
+template<> void Vector<DwrLine *>
+::dump (const char *msg)
+{
+ Dprintf (1, "%s Vector<DwrLine *> [%lld]:\n address [file line column]\n",
+ msg ? msg : NTXT (""), (long long) size ());
+ for (long i = 0, sz = size (); i < sz; i++)
+ {
+ DwrLine *lnp = get (i);
+ Dprintf (1, NTXT (" %2lld 0x%08llx [ %2lld, %lld, %lld ] \n"),
+ (long long) i, (long long) lnp->address, (long long) lnp->file,
+ (long long) lnp->line, (long long) lnp->column);
+ }
+ Dprintf (1, NTXT ("\n\n"));
+}
+
+//////////////////////////////////////////////////////////
+// class ElfReloc
+
+ElfReloc::ElfReloc (Elf *_elf)
+{
+ elf = _elf;
+ reloc = NULL;
+ cur_reloc_ind = 0;
+}
+
+ElfReloc::~ElfReloc ()
+{
+ if (reloc)
+ {
+ reloc->destroy ();
+ delete reloc;
+ }
+}
+
+void
+ElfReloc::dump_rela_debug_sec (int sec)
+{
+ if (!DUMP_RELA_SEC)
+ return;
+ Elf_Internal_Shdr *shdr = elf->get_shdr (sec);
+ if (shdr == NULL)
+ return;
+
+ Elf_Data *data = elf->elf_getdata (sec);
+ if (data == NULL)
+ return;
+
+ uint64_t ScnSize = data->d_size;
+ uint64_t EntSize = shdr->sh_entsize;
+ if (ScnSize == 0 || EntSize == 0)
+ return;
+
+ Elf_Internal_Shdr *shdr_sym = elf->get_shdr (shdr->sh_link);
+ if (shdr_sym == NULL)
+ return;
+ Elf_Data *data_sym = elf->elf_getdata (shdr->sh_link);
+ Elf_Data *data_str = elf->elf_getdata (shdr_sym->sh_link);
+ char *Strtab = data_str ? (char*) data_str->d_buf : NULL;
+ Elf_Internal_Rela rela;
+ int n, cnt = (int) (ScnSize / EntSize);
+
+ char *sec_name = elf->get_sec_name (sec);
+ if (sec_name == NULL) // It can not be, but let's check
+ return;
+ Dprintf (DUMP_RELA_SEC,
+ "======= DwarfLib::dump_rela_debug_sec Section:%2d '%s'\n",
+ sec, sec_name);
+ Dprintf (DUMP_RELA_SEC,
+ " N |addend| offset | r_info | stt_type |\n");
+ for (n = 0; n < cnt; n++)
+ {
+ if (strncmp (sec_name, NTXT (".rela."), 6) == 0)
+ elf->elf_getrela (data, n, &rela);
+ else
+ {
+ elf->elf_getrel (data, n, &rela);
+ rela.r_addend = 0;
+ }
+ int ndx = (int) GELF_R_SYM (rela.r_info);
+ Elf_Internal_Shdr *secHdr;
+ Elf_Internal_Sym sym;
+ elf->elf_getsym (data_sym, ndx, &sym);
+ Dprintf (DUMP_RELA_SEC, NTXT ("%3d:%5d |%11lld |0x%016llx | %-15s|"),
+ n, (int) rela.r_addend,
+ (long long) rela.r_offset, (long long) rela.r_info,
+ gelf_st_type2str ((int) GELF_ST_TYPE (sym.st_info)));
+ switch (GELF_ST_TYPE (sym.st_info))
+ {
+ case STT_FUNC:
+ case STT_OBJECT:
+ case STT_NOTYPE:
+ secHdr = elf->get_shdr (sym.st_shndx);
+ if (secHdr)
+ Dprintf (DUMP_RELA_SEC, NTXT (" img_offset=0x%llx"),
+ (long long) (sym.st_value + secHdr->sh_offset));
+ if (Strtab && sym.st_name)
+ Dprintf (DUMP_RELA_SEC, NTXT (" %s"), Strtab + sym.st_name);
+ break;
+ case STT_SECTION:
+ secHdr = elf->get_shdr (sym.st_shndx);
+ if (secHdr)
+ {
+ Dprintf (DUMP_RELA_SEC, NTXT (" value=0x%016llx (%lld)"),
+ (long long) (secHdr->sh_offset + rela.r_addend),
+ (long long) (secHdr->sh_offset + rela.r_addend));
+ }
+ break;
+ default:
+ break;
+ }
+ Dprintf (DUMP_RELA_SEC, NTXT ("\n"));
+ }
+ Dprintf (DUMP_RELA_SEC, NTXT ("\n"));
+}
+
+void
+ElfReloc::dump ()
+{
+ if (!DUMP_ELF_RELOC || (reloc == NULL) || (reloc->size () == 0))
+ return;
+ Dprintf (DUMP_ELF_RELOC, NTXT ("======= ElfReloc::dump\n"));
+ Dprintf (DUMP_ELF_RELOC, NTXT (" N | offset | value | STT_TYPE\n"));
+ for (int i = 0; i < reloc->size (); i++)
+ {
+ Sreloc *srlc = reloc->fetch (i);
+ Dprintf (DUMP_ELF_RELOC, NTXT ("%3d:%11lld |%11lld | %s\n"),
+ i, (long long) srlc->offset, (long long) srlc->value,
+ gelf_st_type2str (srlc->stt_type));
+ }
+ Dprintf (DUMP_ELF_RELOC, NTXT ("\n"));
+}
+
+static int
+DwrRelocOffsetCmp (const void *a, const void *b)
+{
+ ElfReloc::Sreloc *item1 = *((ElfReloc::Sreloc **) a);
+ ElfReloc::Sreloc *item2 = *((ElfReloc::Sreloc **) b);
+ return item1->offset < item2->offset ? -1 :
+ item1->offset == item2->offset ? 0 : 1;
+}
+
+ElfReloc *
+ElfReloc::get_elf_reloc (Elf *elfp, char *sec_name, ElfReloc *rlc)
+{
+ int et = elfp->elf_getehdr ()->e_type;
+ if (et == ET_EXEC || et == ET_DYN)
+ return rlc;
+ int sec = elfp->elf_get_sec_num (sec_name);
+ if (sec == 0)
+ return rlc;
+ Elf_Internal_Shdr *shdr = elfp->get_shdr (sec);
+ if (shdr == NULL || shdr->sh_entsize == 0)
+ return rlc;
+
+ Elf_Data *data = elfp->elf_getdata (sec);
+ if (data == NULL || data->d_size == 0)
+ return rlc;
+
+ int cnt = (int) (data->d_size / shdr->sh_entsize);
+ Elf_Internal_Shdr *shdr_sym = elfp->get_shdr (shdr->sh_link);
+ if (shdr_sym == NULL)
+ return rlc;
+ Elf_Data *data_sym = elfp->elf_getdata (shdr->sh_link);
+ Vector<Sreloc *> *vp = NULL;
+
+ for (int n = 0; n < cnt; n++)
+ {
+ Elf_Internal_Shdr *secHdr;
+ Sreloc *srlc;
+ Elf_Internal_Rela rela;
+ if (strncmp (sec_name, NTXT (".rela."), 6) == 0)
+ elfp->elf_getrela (data, n, &rela);
+ else
+ {
+ elfp->elf_getrel (data, n, &rela);
+ rela.r_addend = 0;
+ }
+ int ndx = (int) GELF_R_SYM (rela.r_info);
+ Elf_Internal_Sym sym;
+ elfp->elf_getsym (data_sym, ndx, &sym);
+
+ srlc = new Sreloc;
+ srlc->offset = rela.r_offset;
+ srlc->value = 0;
+ srlc->stt_type = (int) GELF_ST_TYPE (sym.st_info);
+ switch (GELF_ST_TYPE (sym.st_info))
+ {
+ case STT_FUNC:
+ secHdr = elfp->get_shdr (sym.st_shndx);
+ if (secHdr)
+ srlc->value = secHdr->sh_offset + sym.st_value;
+ break;
+ case STT_OBJECT:
+ case STT_NOTYPE:
+ secHdr = elfp->get_shdr (shdr->sh_info);
+ if (secHdr)
+ {
+ srlc->offset = rela.r_info;
+ srlc->value = secHdr->sh_offset + rela.r_addend;
+ }
+ break;
+ case STT_SECTION:
+ secHdr = elfp->get_shdr (sym.st_shndx);
+ if (secHdr)
+ srlc->value = rela.r_addend;
+ break;
+ default:
+ srlc->value = 0;
+ break;
+ }
+ if (rlc == NULL)
+ {
+ rlc = new ElfReloc (elfp);
+ vp = rlc->reloc;
+ }
+ if (vp == NULL)
+ {
+ vp = new Vector<Sreloc*>;
+ rlc->reloc = vp;
+ }
+ vp->append (srlc);
+ }
+ if (vp)
+ vp->sort (DwrRelocOffsetCmp);
+ if (rlc)
+ {
+ rlc->dump_rela_debug_sec (sec);
+ rlc->dump ();
+ }
+ return rlc;
+}
+
+long long
+ElfReloc::get_reloc_addr (long long offset)
+{
+ Sreloc *srlc;
+ int i = cur_reloc_ind - 1;
+ if (i >= 0 && i < reloc->size ())
+ {
+ srlc = reloc->fetch (i);
+ if (srlc->offset > offset) // need to reset
+ cur_reloc_ind = 0;
+ }
+ for (; cur_reloc_ind < reloc->size (); cur_reloc_ind++)
+ {
+ srlc = reloc->fetch (cur_reloc_ind);
+ if (srlc->offset == offset)
+ return srlc->value;
+ if (srlc->offset > offset)
+ return 0;
+ }
+ return 0;
+}
+
+DwrLocation *
+DwrCU::dwr_get_location (DwrSec *secp, DwrLocation *lp)
+{
+ lp->offset = secp->offset;
+ lp->lc_number = 0;
+ lp->lc_number2 = 0;
+ lp->op = secp->Get_8 ();
+ switch (lp->op)
+ {
+ // registers
+ case DW_OP_reg0:
+ case DW_OP_reg1:
+ case DW_OP_reg2:
+ case DW_OP_reg3:
+ case DW_OP_reg4:
+ case DW_OP_reg5:
+ case DW_OP_reg6:
+ case DW_OP_reg7:
+ case DW_OP_reg8:
+ case DW_OP_reg9:
+ case DW_OP_reg10:
+ case DW_OP_reg11:
+ case DW_OP_reg12:
+ case DW_OP_reg13:
+ case DW_OP_reg14:
+ case DW_OP_reg15:
+ case DW_OP_reg16:
+ case DW_OP_reg17:
+ case DW_OP_reg18:
+ case DW_OP_reg19:
+ case DW_OP_reg20:
+ case DW_OP_reg21:
+ case DW_OP_reg22:
+ case DW_OP_reg23:
+ case DW_OP_reg24:
+ case DW_OP_reg25:
+ case DW_OP_reg26:
+ case DW_OP_reg27:
+ case DW_OP_reg28:
+ case DW_OP_reg29:
+ case DW_OP_reg30:
+ case DW_OP_reg31:
+ break;
+ case DW_OP_regx:
+ lp->lc_number = secp->GetULEB128 ();
+ break;
+ case DW_OP_breg0:
+ case DW_OP_breg1:
+ case DW_OP_breg2:
+ case DW_OP_breg3:
+ case DW_OP_breg4:
+ case DW_OP_breg5:
+ case DW_OP_breg6:
+ case DW_OP_breg7:
+ case DW_OP_breg8:
+ case DW_OP_breg9:
+ case DW_OP_breg10:
+ case DW_OP_breg11:
+ case DW_OP_breg12:
+ case DW_OP_breg13:
+ case DW_OP_breg14:
+ case DW_OP_breg15:
+ case DW_OP_breg16:
+ case DW_OP_breg17:
+ case DW_OP_breg18:
+ case DW_OP_breg19:
+ case DW_OP_breg20:
+ case DW_OP_breg21:
+ case DW_OP_breg22:
+ case DW_OP_breg23:
+ case DW_OP_breg24:
+ case DW_OP_breg25:
+ case DW_OP_breg26:
+ case DW_OP_breg27:
+ case DW_OP_breg28:
+ case DW_OP_breg29:
+ case DW_OP_breg30:
+ case DW_OP_breg31:
+ lp->lc_number = secp->GetSLEB128 ();
+ break;
+ case DW_OP_fbreg:
+ lp->lc_number = secp->GetSLEB128 ();
+ break;
+ case DW_OP_bregx:
+ lp->lc_number = secp->GetULEB128 ();
+ lp->lc_number2 = secp->GetSLEB128 ();
+ break;
+ case DW_OP_lit0:
+ case DW_OP_lit1:
+ case DW_OP_lit2:
+ case DW_OP_lit3:
+ case DW_OP_lit4:
+ case DW_OP_lit5:
+ case DW_OP_lit6:
+ case DW_OP_lit7:
+ case DW_OP_lit8:
+ case DW_OP_lit9:
+ case DW_OP_lit10:
+ case DW_OP_lit11:
+ case DW_OP_lit12:
+ case DW_OP_lit13:
+ case DW_OP_lit14:
+ case DW_OP_lit15:
+ case DW_OP_lit16:
+ case DW_OP_lit17:
+ case DW_OP_lit18:
+ case DW_OP_lit19:
+ case DW_OP_lit20:
+ case DW_OP_lit21:
+ case DW_OP_lit22:
+ case DW_OP_lit23:
+ case DW_OP_lit24:
+ case DW_OP_lit25:
+ case DW_OP_lit26:
+ case DW_OP_lit27:
+ case DW_OP_lit28:
+ case DW_OP_lit29:
+ case DW_OP_lit30:
+ case DW_OP_lit31:
+ lp->lc_number = lp->op - DW_OP_lit0;
+ break;
+ case DW_OP_addr:
+ lp->lc_number = secp->GetADDR ();
+ break;
+ case DW_OP_const1u:
+ lp->lc_number = secp->Get_8 ();
+ break;
+ case DW_OP_const1s:
+ {
+ signed char x;
+ x = secp->Get_8 ();
+ lp->lc_number = x;
+ }
+ break;
+ case DW_OP_const2u:
+ lp->lc_number = secp->Get_16 ();
+ break;
+ case DW_OP_const2s:
+ {
+ signed short x;
+ x = secp->Get_16 ();
+ lp->lc_number = x;
+ }
+ break;
+ case DW_OP_const4u:
+ lp->lc_number = secp->Get_32 ();
+ break;
+ case DW_OP_const4s:
+ {
+ signed int x;
+ x = secp->Get_32 ();
+ lp->lc_number = x;
+ }
+ break;
+ case DW_OP_const8u:
+ lp->lc_number = secp->Get_64 ();
+ break;
+ case DW_OP_const8s:
+ {
+ signed long long x;
+ x = secp->Get_64 ();
+ lp->lc_number = x;
+ }
+ break;
+ case DW_OP_plus_uconst:
+ case DW_OP_constu:
+ lp->lc_number = secp->GetULEB128 ();
+ break;
+ case DW_OP_consts:
+ lp->lc_number = secp->GetSLEB128 ();
+ break;
+
+ // Stack operations
+ case DW_OP_pick:
+ case DW_OP_deref_size:
+ case DW_OP_xderef_size:
+ lp->lc_number = secp->Get_8 ();
+ break;
+ case DW_OP_dup:
+ case DW_OP_drop:
+ case DW_OP_over:
+ case DW_OP_swap:
+ case DW_OP_rot:
+ case DW_OP_deref:
+ case DW_OP_xderef:
+ // Arithmetic and Logical Operations
+ case DW_OP_abs:
+ case DW_OP_and:
+ case DW_OP_div:
+ case DW_OP_minus:
+ case DW_OP_mod:
+ case DW_OP_mul:
+ case DW_OP_neg:
+ case DW_OP_not:
+ case DW_OP_or:
+ case DW_OP_plus:
+ case DW_OP_shl:
+ case DW_OP_shr:
+ case DW_OP_shra:
+ case DW_OP_xor:
+ case DW_OP_le:
+ case DW_OP_ge:
+ case DW_OP_eq:
+ case DW_OP_lt:
+ case DW_OP_gt:
+ case DW_OP_ne:
+ case DW_OP_nop:
+ break;
+ case DW_OP_skip:
+ case DW_OP_bra:
+ lp->lc_number = secp->Get_16 ();
+ break;
+ case DW_OP_piece:
+ lp->lc_number = secp->GetULEB128 ();
+ break;
+ case DW_OP_push_object_address: /* DWARF3 */
+ break;
+ case DW_OP_call2: /* DWARF3 */
+ lp->lc_number = secp->Get_16 ();
+ break;
+ case DW_OP_call4: /* DWARF3 */
+ lp->lc_number = secp->Get_32 ();
+ break;
+ case DW_OP_call_ref: /* DWARF3 */
+ lp->lc_number = secp->GetADDR ();
+ break;
+ default:
+ return (NULL);
+ }
+ return lp;
+}
+
+char *
+DwrCU::tag2str (int tag)
+{
+ static char buf[128];
+ char *s;
+
+ switch (tag)
+ {
+ CASE_S (DW_TAG_array_type);
+ CASE_S (DW_TAG_class_type);
+ CASE_S (DW_TAG_entry_point);
+ CASE_S (DW_TAG_enumeration_type);
+ CASE_S (DW_TAG_formal_parameter);
+ CASE_S (DW_TAG_imported_declaration);
+ CASE_S (DW_TAG_label);
+ CASE_S (DW_TAG_lexical_block);
+ CASE_S (DW_TAG_member);
+ CASE_S (DW_TAG_pointer_type);
+ CASE_S (DW_TAG_reference_type);
+ CASE_S (DW_TAG_compile_unit);
+ CASE_S (DW_TAG_string_type);
+ CASE_S (DW_TAG_structure_type);
+ CASE_S (DW_TAG_subroutine_type);
+ CASE_S (DW_TAG_typedef);
+ CASE_S (DW_TAG_union_type);
+ CASE_S (DW_TAG_unspecified_parameters);
+ CASE_S (DW_TAG_variant);
+ CASE_S (DW_TAG_common_block);
+ CASE_S (DW_TAG_common_inclusion);
+ CASE_S (DW_TAG_inheritance);
+ CASE_S (DW_TAG_inlined_subroutine);
+ CASE_S (DW_TAG_module);
+ CASE_S (DW_TAG_ptr_to_member_type);
+ CASE_S (DW_TAG_set_type);
+ CASE_S (DW_TAG_subrange_type);
+ CASE_S (DW_TAG_with_stmt);
+ CASE_S (DW_TAG_access_declaration);
+ CASE_S (DW_TAG_base_type);
+ CASE_S (DW_TAG_catch_block);
+ CASE_S (DW_TAG_const_type);
+ CASE_S (DW_TAG_constant);
+ CASE_S (DW_TAG_enumerator);
+ CASE_S (DW_TAG_file_type);
+ CASE_S (DW_TAG_friend);
+ CASE_S (DW_TAG_namelist);
+ CASE_S (DW_TAG_namelist_item);
+ CASE_S (DW_TAG_packed_type);
+ CASE_S (DW_TAG_subprogram);
+ CASE_S (DW_TAG_template_type_param);
+ CASE_S (DW_TAG_template_value_param);
+ CASE_S (DW_TAG_thrown_type);
+ CASE_S (DW_TAG_try_block);
+ CASE_S (DW_TAG_variant_part);
+ CASE_S (DW_TAG_variable);
+ CASE_S (DW_TAG_volatile_type);
+ CASE_S (DW_TAG_dwarf_procedure);
+ CASE_S (DW_TAG_restrict_type);
+ CASE_S (DW_TAG_interface_type);
+ CASE_S (DW_TAG_namespace);
+ CASE_S (DW_TAG_imported_module);
+ CASE_S (DW_TAG_unspecified_type);
+ CASE_S (DW_TAG_partial_unit);
+ CASE_S (DW_TAG_imported_unit);
+ CASE_S (DW_TAG_lo_user);
+ CASE_S (DW_TAG_MIPS_loop);
+ CASE_S (DW_TAG_format_label);
+ CASE_S (DW_TAG_function_template);
+ CASE_S (DW_TAG_class_template);
+ CASE_S (DW_TAG_GNU_BINCL);
+ CASE_S (DW_TAG_GNU_EINCL);
+ CASE_S (DW_TAG_GNU_call_site);
+ CASE_S (DW_TAG_GNU_call_site_parameter);
+ CASE_S (DW_TAG_SUN_codeflags);
+ CASE_S (DW_TAG_SUN_memop_info);
+ CASE_S (DW_TAG_hi_user);
+ CASE_S (DW_TAG_icc_compile_unit);
+ default: s = NTXT ("???");
+ break;
+ }
+ snprintf (buf, sizeof (buf), NTXT ("%s(%d)"), s, tag);
+ buf[sizeof (buf) - 1] = 0;
+ return buf;
+}
+
+char *
+DwrCU::at2str (int tag)
+{
+ static char buf[128];
+ char *s;
+ switch (tag)
+ {
+ CASE_S (DW_AT_sibling);
+ CASE_S (DW_AT_location);
+ CASE_S (DW_AT_name);
+ CASE_S (DW_AT_ordering);
+ CASE_S (DW_AT_subscr_data);
+ CASE_S (DW_AT_byte_size);
+ CASE_S (DW_AT_bit_offset);
+ CASE_S (DW_AT_bit_size);
+ CASE_S (DW_AT_element_list);
+ CASE_S (DW_AT_stmt_list);
+ CASE_S (DW_AT_low_pc);
+ CASE_S (DW_AT_high_pc);
+ CASE_S (DW_AT_language);
+ CASE_S (DW_AT_member);
+ CASE_S (DW_AT_discr);
+ CASE_S (DW_AT_discr_value);
+ CASE_S (DW_AT_visibility);
+ CASE_S (DW_AT_import);
+ CASE_S (DW_AT_string_length);
+ CASE_S (DW_AT_common_reference);
+ CASE_S (DW_AT_comp_dir);
+ CASE_S (DW_AT_const_value);
+ CASE_S (DW_AT_containing_type);
+ CASE_S (DW_AT_default_value);
+ CASE_S (DW_AT_inline);
+ CASE_S (DW_AT_is_optional);
+ CASE_S (DW_AT_lower_bound);
+ CASE_S (DW_AT_producer);
+ CASE_S (DW_AT_prototyped);
+ CASE_S (DW_AT_return_addr);
+ CASE_S (DW_AT_start_scope);
+ CASE_S (DW_AT_stride_size);
+ CASE_S (DW_AT_upper_bound);
+ CASE_S (DW_AT_abstract_origin);
+ CASE_S (DW_AT_accessibility);
+ CASE_S (DW_AT_address_class);
+ CASE_S (DW_AT_artificial);
+ CASE_S (DW_AT_base_types);
+ CASE_S (DW_AT_calling_convention);
+ CASE_S (DW_AT_count);
+ CASE_S (DW_AT_data_member_location);
+ CASE_S (DW_AT_decl_column);
+ CASE_S (DW_AT_decl_file);
+ CASE_S (DW_AT_decl_line);
+ CASE_S (DW_AT_declaration);
+ CASE_S (DW_AT_discr_list);
+ CASE_S (DW_AT_encoding);
+ CASE_S (DW_AT_external);
+ CASE_S (DW_AT_frame_base);
+ CASE_S (DW_AT_friend);
+ CASE_S (DW_AT_identifier_case);
+ CASE_S (DW_AT_macro_info);
+ CASE_S (DW_AT_namelist_item);
+ CASE_S (DW_AT_priority);
+ CASE_S (DW_AT_segment);
+ CASE_S (DW_AT_specification);
+ CASE_S (DW_AT_static_link);
+ CASE_S (DW_AT_type);
+ CASE_S (DW_AT_use_location);
+ CASE_S (DW_AT_variable_parameter);
+ CASE_S (DW_AT_virtuality);
+ CASE_S (DW_AT_vtable_elem_location);
+ CASE_S (DW_AT_allocated);
+ CASE_S (DW_AT_associated);
+ CASE_S (DW_AT_data_location);
+ CASE_S (DW_AT_byte_stride);
+ CASE_S (DW_AT_entry_pc);
+ CASE_S (DW_AT_use_UTF8);
+ CASE_S (DW_AT_extension);
+ CASE_S (DW_AT_ranges);
+ CASE_S (DW_AT_trampoline);
+ CASE_S (DW_AT_call_column);
+ CASE_S (DW_AT_call_file);
+ CASE_S (DW_AT_call_line);
+ CASE_S (DW_AT_description);
+ CASE_S (DW_AT_binary_scale);
+ CASE_S (DW_AT_decimal_scale);
+ CASE_S (DW_AT_small);
+ CASE_S (DW_AT_decimal_sign);
+ CASE_S (DW_AT_digit_count);
+ CASE_S (DW_AT_picture_string);
+ CASE_S (DW_AT_mutable);
+ CASE_S (DW_AT_threads_scaled);
+ CASE_S (DW_AT_explicit);
+ CASE_S (DW_AT_object_pointer);
+ CASE_S (DW_AT_endianity);
+ CASE_S (DW_AT_elemental);
+ CASE_S (DW_AT_pure);
+ CASE_S (DW_AT_recursive);
+ CASE_S (DW_AT_signature);
+ CASE_S (DW_AT_main_subprogram);
+ CASE_S (DW_AT_data_bit_offset);
+ CASE_S (DW_AT_const_expr);
+ CASE_S (DW_AT_enum_class);
+ CASE_S (DW_AT_linkage_name);
+ CASE_S (DW_AT_lo_user);
+ CASE_S (DW_AT_MIPS_fde);
+ CASE_S (DW_AT_MIPS_loop_begin);
+ CASE_S (DW_AT_MIPS_tail_loop_begin);
+ CASE_S (DW_AT_MIPS_epilog_begin);
+ CASE_S (DW_AT_MIPS_loop_unroll_factor);
+ CASE_S (DW_AT_MIPS_software_pipeline_depth);
+ CASE_S (DW_AT_MIPS_linkage_name);
+ CASE_S (DW_AT_MIPS_stride);
+ CASE_S (DW_AT_MIPS_abstract_name);
+ CASE_S (DW_AT_MIPS_clone_origin);
+ CASE_S (DW_AT_MIPS_has_inlines);
+ CASE_S (DW_AT_sf_names);
+ CASE_S (DW_AT_src_info);
+ CASE_S (DW_AT_mac_info);
+ CASE_S (DW_AT_src_coords);
+ CASE_S (DW_AT_body_begin);
+ CASE_S (DW_AT_body_end);
+ CASE_S (DW_AT_GNU_vector);
+ CASE_S (DW_AT_GNU_guarded_by);
+ CASE_S (DW_AT_GNU_pt_guarded_by);
+ CASE_S (DW_AT_GNU_guarded);
+ CASE_S (DW_AT_GNU_pt_guarded);
+ CASE_S (DW_AT_GNU_locks_excluded);
+ CASE_S (DW_AT_GNU_exclusive_locks_required);
+ CASE_S (DW_AT_GNU_shared_locks_required);
+ CASE_S (DW_AT_GNU_odr_signature);
+ CASE_S (DW_AT_GNU_template_name);
+ CASE_S (DW_AT_GNU_call_site_value);
+ CASE_S (DW_AT_GNU_call_site_data_value);
+ CASE_S (DW_AT_GNU_call_site_target);
+ CASE_S (DW_AT_GNU_call_site_target_clobbered);
+ CASE_S (DW_AT_GNU_tail_call);
+ CASE_S (DW_AT_GNU_all_tail_call_sites);
+ CASE_S (DW_AT_GNU_all_call_sites);
+ CASE_S (DW_AT_GNU_all_source_call_sites);
+ CASE_S (DW_AT_SUN_command_line);
+ CASE_S (DW_AT_SUN_func_offsets);
+ CASE_S (DW_AT_SUN_cf_kind);
+ CASE_S (DW_AT_SUN_func_offset);
+ CASE_S (DW_AT_SUN_memop_type_ref);
+ CASE_S (DW_AT_SUN_profile_id);
+ CASE_S (DW_AT_SUN_memop_signature);
+ CASE_S (DW_AT_SUN_obj_dir);
+ CASE_S (DW_AT_SUN_obj_file);
+ CASE_S (DW_AT_SUN_original_name);
+ CASE_S (DW_AT_SUN_link_name);
+ CASE_S (DW_AT_hi_user);
+ CASE_S (DW_AT_icc_flags);
+ default: s = NTXT ("???");
+ break;
+ }
+ snprintf (buf, sizeof (buf), NTXT ("%s(%d)"), s, tag);
+ buf[sizeof (buf) - 1] = 0;
+ return buf;
+}
+
+char *
+DwrCU::form2str (int tag)
+{
+ static char buf[128];
+ char *s;
+ switch (tag)
+ {
+ CASE_S (DW_FORM_addr);
+ CASE_S (DW_FORM_block2);
+ CASE_S (DW_FORM_block4);
+ CASE_S (DW_FORM_data2);
+ CASE_S (DW_FORM_data4);
+ CASE_S (DW_FORM_data8);
+ CASE_S (DW_FORM_string);
+ CASE_S (DW_FORM_block);
+ CASE_S (DW_FORM_block1);
+ CASE_S (DW_FORM_data1);
+ CASE_S (DW_FORM_flag);
+ CASE_S (DW_FORM_sdata);
+ CASE_S (DW_FORM_strp);
+ CASE_S (DW_FORM_udata);
+ CASE_S (DW_FORM_ref_addr);
+ CASE_S (DW_FORM_ref1);
+ CASE_S (DW_FORM_ref2);
+ CASE_S (DW_FORM_ref4);
+ CASE_S (DW_FORM_ref8);
+ CASE_S (DW_FORM_ref_udata);
+ CASE_S (DW_FORM_indirect);
+ CASE_S (DW_FORM_sec_offset);
+ CASE_S (DW_FORM_exprloc);
+ CASE_S (DW_FORM_flag_present);
+ CASE_S (DW_FORM_ref_sig8);
+ default: s = NTXT ("???");
+ break;
+ }
+ snprintf (buf, sizeof (buf), NTXT ("%s(%d)"), s, tag);
+ buf[sizeof (buf) - 1] = 0;
+ return buf;
+}
+
+void
+Dwr_Tag::dump ()
+{
+ Dprintf (DUMP_DWARFLIB,
+ "\n<%2d>:<0x%08llx> %-30s <abbrev %lld> offset=0x%llx %s\n",
+ (int) level, (long long) die, DwrCU::tag2str (tag), (long long) num,
+ (long long) offset,
+ hasChild ? NTXT ("DW_children_yes") : NTXT ("DW_children_no"));
+ for (int i1 = firstAttribute; i1 < lastAttribute; i1++)
+ {
+ Dwr_Attr *atrp = abbrevAtForm->get (i1);
+ Dprintf (DUMP_DWARFLIB, " %-30s ", DwrCU::at2str (atrp->at_name));
+ switch (atrp->at_form)
+ {
+ case DW_FORM_strp:
+ case DW_FORM_string:
+ Dprintf (DUMP_DWARFLIB, " \"%s\" len=%ld",
+ atrp->u.str ? atrp->u.str : NTXT ("<NULL>"),
+ (long) atrp->len);
+ break;
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ Dprintf (DUMP_DWARFLIB, " len=%3ld %p", (long) atrp->len,
+ atrp->u.str);
+ break;
+ case DW_FORM_addr:
+ case DW_FORM_data2:
+ case DW_FORM_data4:
+ case DW_FORM_data8:
+ case DW_FORM_data1:
+ case DW_FORM_flag:
+ case DW_FORM_sdata:
+ case DW_FORM_udata:
+ case DW_FORM_ref_addr:
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_udata:
+ case DW_FORM_indirect:
+ case DW_FORM_sec_offset:
+ case DW_FORM_exprloc:
+ case DW_FORM_ref_sig8:
+ case DW_FORM_flag_present:
+ Dprintf (DUMP_DWARFLIB, " 0x%llx (%lld)", (long long) atrp->u.val,
+ (long long) atrp->u.val);
+ break;
+ default:
+ DEBUG_CODE
+ {
+ Dprintf (1, "Attribute form 0x%llx (%lld) is not implemented\n",
+ (long long) atrp->at_form, (long long) atrp->at_form);
+ assert (false);
+ }
+ }
+ Dprintf (DUMP_DWARFLIB, NTXT ("\n"));
+ }
+}
+
+
+//////////////////////////////////////////////////////////
+// class DwrSec
+
+DwrSec::DwrSec (unsigned char *_data, uint64_t _size, bool _need_swap_endian, bool _addr32)
+{
+ isCopy = false;
+ data = _data;
+ sizeSec = _size;
+ size = (data ? _size : 0);
+ offset = 0;
+ fmt64 = false;
+ reloc = NULL;
+ need_swap_endian = _need_swap_endian;
+ addr32 = _addr32;
+}
+
+DwrSec::DwrSec (DwrSec *secp, uint64_t _offset)
+{
+ isCopy = true;
+ data = secp->data;
+ sizeSec = secp->sizeSec;
+ size = secp->size;
+ offset = _offset;
+ fmt64 = secp->fmt64;
+ reloc = secp->reloc;
+ need_swap_endian = secp->need_swap_endian;
+ addr32 = secp->addr32;
+}
+
+DwrSec::~DwrSec ()
+{
+ if (!isCopy)
+ delete reloc;
+}
+
+bool
+DwrSec::bounds_violation (uint64_t sz)
+{
+ if (offset + sz > size)
+ {
+ Dprintf (DEBUG_ERR_MSG, "DwrSec::bounds_violation: offset=%lld + sz=%lld > size=%lld\n",
+ (long long) offset, (long long) sz, (long long) size);
+ return true;
+ }
+ return false;
+}
+
+uint64_t
+DwrSec::ReadLength ()
+{
+ fmt64 = false;
+ uint64_t val = Get_32 ();
+ if (((uint32_t) val) == 0xffffffff)
+ {
+ fmt64 = true;
+ val = Get_64 ();
+ }
+ size = (val + offset < sizeSec) ? val + offset : sizeSec;
+ return size;
+}
+
+unsigned char
+DwrSec::Get_8 ()
+{
+ unsigned char n = 0;
+ if (bounds_violation (sizeof (char)))
+ return n;
+ n = data[offset];
+ offset += sizeof (char);
+ return n;
+}
+
+unsigned short
+DwrSec::Get_16 ()
+{
+ unsigned short n = 0;
+ if (bounds_violation (sizeof (short)))
+ return n;
+ memcpy ((char *) &n, data + offset, sizeof (short));
+ offset += sizeof (short);
+ if (need_swap_endian)
+ SWAP_ENDIAN (n);
+ return n;
+}
+
+uint32_t
+DwrSec::Get_32 ()
+{
+ uint32_t n = 0;
+ if (bounds_violation (sizeof (uint32_t)))
+ return n;
+ memcpy ((char *) &n, data + offset, sizeof (uint32_t));
+ offset += sizeof (uint32_t);
+ if (need_swap_endian)
+ SWAP_ENDIAN (n);
+ return n;
+}
+
+uint64_t
+DwrSec::Get_64 ()
+{
+ uint64_t n = 0;
+ if (bounds_violation (sizeof (uint64_t)))
+ return n;
+ memcpy ((char *) &n, data + offset, sizeof (uint64_t));
+ offset += sizeof (uint64_t);
+ if (need_swap_endian)
+ SWAP_ENDIAN (n);
+ return n;
+}
+
+char *
+DwrSec::GetData (uint64_t len)
+{
+ char *s = ((char *) data) + offset;
+ if (bounds_violation (len))
+ s = NULL;
+ offset += len;
+ return s;
+}
+
+char *
+DwrSec::GetString (uint64_t *lenp)
+{
+ if (offset < size)
+ {
+ uint64_t len = 0;
+ for (char *s = ((char *) data) + offset; offset + len < size; len++)
+ {
+ if (s[len] == 0)
+ { // '\0' is inside section
+ offset += len + 1;
+ if (len == 0)
+ return NULL;
+ if (lenp)
+ *lenp = len + 1;
+ return s;
+ }
+ }
+ offset += len;
+ return NULL; // The section is not '\0' terminated
+ }
+ return NULL;
+}
+
+uint64_t
+DwrSec::GetLong ()
+{
+ if (fmt64)
+ return Get_64 ();
+ return Get_32 ();
+}
+
+uint64_t
+DwrSec::GetADDR_32 ()
+{
+ uint64_t res = reloc ? reloc->get_reloc_addr (offset) : 0;
+ res += Get_32 ();
+ return res;
+}
+
+uint64_t
+DwrSec::GetADDR_64 ()
+{
+ uint64_t res = reloc ? reloc->get_reloc_addr (offset) : 0;
+ res += Get_64 ();
+ return res;
+}
+
+uint64_t
+DwrSec::GetADDR ()
+{
+ if (addr32)
+ return GetADDR_32 ();
+ return GetADDR_64 ();
+}
+
+uint64_t
+DwrSec::GetRef ()
+{
+ if (fmt64)
+ return GetADDR_64 ();
+ return GetADDR_32 ();
+}
+
+ULEB128
+DwrSec::GetULEB128 ()
+{
+ ULEB128 res = 0;
+ for (int shift = 0;; shift += 7)
+ {
+ ULEB128 val = Get_8 ();
+ res |= (val & 0x7f) << shift;
+ if ((val & 0x80) == 0)
+ break;
+ }
+ return res;
+}
+
+SLEB128
+DwrSec::GetSLEB128 ()
+{
+ ULEB128 res = 0, val = 0;
+ size_t shift;
+ for (shift = 0;;)
+ {
+ val = Get_8 ();
+ res |= (val & 0x7f) << shift;
+ shift += 7;
+ if ((val & 0x80) == 0)
+ break;
+ }
+ if ((val & 0x40) && (shift < 8 * sizeof (res)))
+ res |= -(((ULEB128) 1) << shift);
+ return (SLEB128) res;
+}
+
+static void
+fillBuf (unsigned char *s, int len, int col, unsigned char *buf)
+{
+ const char *nameX = "0123456789abcdef";
+ int i, n, posCh = 2 * col + col / 4 + 5;
+
+ if (len >= col)
+ len = col;
+ for (i = n = 0; i < len; i++, n += 2)
+ {
+ if ((i % 4) == 0 && i > 0)
+ {
+ buf[n] = ' ';
+ n++;
+ }
+ buf[n] = nameX[s[i] >> 4];
+ buf[n + 1] = nameX[s[i] & 0xf];
+ buf[posCh + i] = isprint (s[i]) ? s[i] : ' ';
+ }
+ buf[posCh + i] = 0;
+ for (i = n; i < posCh; i++)
+ buf[i] = ' ';
+}
+
+static void
+dumpArr (unsigned char *s, int len, int col, int num)
+{
+ unsigned char buf[128];
+ if (col <= 0)
+ return;
+ for (int i = 0; i < len; i += col, num += col)
+ {
+ fillBuf (s + i, len - i, col, buf);
+ Dprintf (DUMP_DWARFLIB, "%5d: %s\n", num, buf);
+ }
+}
+
+void
+DwrSec::dump (char *msg)
+{
+ if (sizeSec > 0)
+ {
+ Dprintf (DUMP_DWARFLIB, NTXT ("======= DwrSec::dump\n"));
+ if (msg)
+ Dprintf (DUMP_DWARFLIB, NTXT ("%s:\n"), msg);
+ dumpArr (data, (int) sizeSec, 32, 0);
+ Dprintf (DUMP_DWARFLIB, NTXT ("\n"));
+ }
+}
+
+//////////////////////////////////////////////////////////
+// class DwrFileNames
+
+DwrFileName::DwrFileName (char *_fname)
+{
+ path = NULL;
+ fname = _fname;
+ dir_index = 0;
+ timestamp = 0;
+ file_size = 0;
+ isUsed = false;
+}
+
+DwrFileName::~DwrFileName ()
+{
+ if (path != fname)
+ free (path);
+}
+
+
+//////////////////////////////////////////////////////////
+// class DwrLine
+DwrLine::DwrLine ()
+{
+ address = 0;
+ file = 0;
+ line = 0;
+ column = 0;
+}
+
+DwrLine::~DwrLine () { }
+
+
+//////////////////////////////////////////////////////////
+// class DwrLineRegs
+static int
+LineRegsCmp (const void *a, const void *b)
+{
+ DwrLine *item1 = *((DwrLine **) a);
+ DwrLine *item2 = *((DwrLine **) b);
+ return item1->address == item2->address ? 0 :
+ item1->address > item2->address ? 1 : -1;
+}
+
+DwrLineRegs::DwrLineRegs (DwrSec *secp, char *dirName)
+{
+ // `dwarfdump -vv -l` shows a line section (.debug_line)
+ debug_lineSec = secp;
+ uint64_t stmt_offset = debug_lineSec->offset;
+ uint64_t next_cu_offset = debug_lineSec->ReadLength ();
+ uint64_t header_offset = debug_lineSec->offset;
+ debug_lineSec->size = next_cu_offset;
+ version = debug_lineSec->Get_16 ();
+ header_length = debug_lineSec->GetLong ();
+ opcode_start = debug_lineSec->offset + header_length;
+ minimum_instruction_length = debug_lineSec->Get_8 ();
+ op_index_register = 0;
+ if (version == 4)
+ maximum_operations_per_instruction = debug_lineSec->Get_8 ();
+ else
+ maximum_operations_per_instruction = 1;
+ default_is_stmt = debug_lineSec->Get_8 ();
+ is_stmt = (default_is_stmt != 0);
+ line_base = debug_lineSec->Get_8 ();
+ line_range = debug_lineSec->Get_8 ();
+ opcode_base = debug_lineSec->Get_8 ();
+ standard_opcode_length = (Dwarf_Small*) debug_lineSec->GetData (opcode_base - 1);
+
+ if (DUMP_DWR_LINE_REGS)
+ {
+ Dprintf (DUMP_DWR_LINE_REGS,
+ "\n.debug_line version=%d stmt_offset=0x%llx"
+ "header_offset=0x%llx size=%lld dirname='%s'\n"
+ " header_length=0x%llx opcode_start=0x%llx"
+ "minimum_instruction_length=%d default_is_stmt=%d\n"
+ " line_base=%d line_range=%d opcode_base=%d\n",
+ (int) version, (long long) stmt_offset,
+ (long long) header_offset,
+ (long long) (next_cu_offset - header_offset), STR (dirName),
+ (long long) header_length, (long long) opcode_start,
+ (int) minimum_instruction_length, (int) default_is_stmt,
+ (int) line_base, (int) line_range, (int) opcode_base);
+ if (standard_opcode_length == NULL)
+ Dprintf (DUMP_DWR_LINE_REGS, "ERROR: standard_opcode_length is NULL\n");
+ for (int i = 0, sz = standard_opcode_length ? opcode_base - 1 : 0;
+ i < sz; i++)
+ Dprintf (DUMP_DWR_LINE_REGS, " opcode[%2d] length %2d\n", i,
+ (int) standard_opcode_length[i]);
+ }
+
+ include_directories = new Vector<char *>;
+ include_directories->append (dirName);
+ while (true)
+ {
+ char *s = debug_lineSec->GetString (NULL);
+ if (s == NULL)
+ break;
+ include_directories->append (s);
+ }
+
+ file_names = new Vector<DwrFileName *>;
+ while (true)
+ {
+ char *s = debug_lineSec->GetString (NULL);
+ if (s == NULL)
+ break;
+ DwrFileName *fnp = new DwrFileName (s);
+ fnp->path = NULL;
+ fnp->fname = s;
+ fnp->dir_index = debug_lineSec->GetULEB128_32 ();
+ fnp->timestamp = debug_lineSec->GetULEB128 ();
+ fnp->file_size = debug_lineSec->GetULEB128 ();
+ file_names->append (fnp);
+ }
+ lines = NULL;
+ dump ();
+}
+
+DwrLineRegs::~DwrLineRegs ()
+{
+ Destroy (file_names);
+ Destroy (lines);
+ delete debug_lineSec;
+ delete include_directories;
+}
+
+void
+DwrLineRegs::dump ()
+{
+ if (!DUMP_DWR_LINE_REGS)
+ return;
+ Dprintf (DUMP_DWR_LINE_REGS, NTXT ("\ninclude_directories size=%lld\n"), (long long) VecSize (include_directories));
+ for (long i = 0, sz = VecSize (include_directories); i < sz; i++)
+ {
+ char *s = include_directories->get (i);
+ Dprintf (DUMP_DWR_LINE_REGS, NTXT (" %2lld %s\n"), (long long) i, STR (s));
+ }
+
+ Dprintf (DUMP_DWR_LINE_REGS, NTXT ("\nfile_names size=%lld\n"), (long long) VecSize (file_names));
+ for (long i = 0, sz = VecSize (file_names); i < sz; i++)
+ {
+ DwrFileName *fnp = file_names->get (i);
+ Dprintf (DUMP_DWR_LINE_REGS, NTXT (" %2lld %-40s dir_index=%4lld timestamp=%8lld file_size=%lld\n"),
+ (long long) i, STR (fnp->fname),
+ (long long) fnp->dir_index, (long long) fnp->timestamp, (long long) fnp->file_size);
+ }
+ if (lines)
+ lines->dump (fname);
+ Dprintf (DUMP_DWR_LINE_REGS, NTXT ("\n\n"));
+}
+
+void
+DwrLineRegs::DoExtendedOpcode ()
+{
+ uint64_t size = debug_lineSec->GetULEB128 ();
+ if (size == 0)
+ {
+ Dprintf (DUMP_DWR_LINE_REGS, NTXT ("%-20s"), NTXT ("ExtendedOpCode: size=0"));
+ return;
+ }
+ Dwarf_Small opcode = debug_lineSec->Get_8 ();
+ Dprintf (DUMP_DWR_LINE_REGS, NTXT ("%-20s"), extended_opcode2str (opcode));
+ switch (opcode)
+ {
+ case DW_LNE_end_sequence:
+ end_sequence = true;
+ reset ();
+ break;
+ case DW_LNE_set_address:
+ address = debug_lineSec->GetADDR ();
+ break;
+ case DW_LNE_define_file:
+ // TODO, add file to file list
+ fname = debug_lineSec->GetString (NULL);
+ dir_index = debug_lineSec->GetULEB128 ();
+ timestamp = debug_lineSec->GetULEB128 ();
+ file_size = debug_lineSec->GetULEB128 ();
+ break;
+ default:
+ debug_lineSec->GetData (size - 1); // skip unknown opcode
+ break;
+ }
+}
+
+void
+DwrLineRegs::DoStandardOpcode (int opcode)
+{
+ switch (opcode)
+ {
+ case DW_LNS_copy:
+ basic_block = false;
+ EmitLine ();
+ break;
+ case DW_LNS_advance_pc:
+ address += debug_lineSec->GetULEB128 () * minimum_instruction_length;
+ break;
+ case DW_LNS_advance_line:
+ line += (int) debug_lineSec->GetSLEB128 ();
+ break;
+ case DW_LNS_set_file:
+ file = debug_lineSec->GetULEB128_32 ();
+ break;
+ case DW_LNS_set_column:
+ column = debug_lineSec->GetULEB128_32 ();
+ break;
+ case DW_LNS_negate_stmt:
+ is_stmt = -is_stmt;
+ break;
+ case DW_LNS_set_basic_block:
+ basic_block = true;
+ break;
+ case DW_LNS_const_add_pc:
+ address += ((255 - opcode_base) / line_range) * minimum_instruction_length;
+ break;
+ case DW_LNS_fixed_advance_pc:
+ address += debug_lineSec->Get_16 ();
+ break;
+ default: // skip unknown opcode/operands
+ debug_lineSec->GetData (standard_opcode_length ?
+ standard_opcode_length[opcode] : 1);
+ break;
+ }
+}
+
+void
+DwrLineRegs::DoSpecialOpcode (int opcode)
+{
+ int max_op_per_instr = maximum_operations_per_instruction == 0 ? 1
+ : maximum_operations_per_instruction;
+ int operation_advance = (opcode / line_range);
+ address += minimum_instruction_length * ((op_index_register + operation_advance) / max_op_per_instr);
+ op_index_register = (op_index_register + operation_advance) % max_op_per_instr;
+ line += line_base + (opcode % line_range);
+ basic_block = false;
+ EmitLine ();
+}
+
+void
+DwrLineRegs::reset ()
+{
+ dir_index = 0;
+ timestamp = 0;
+ file_size = 0;
+ address = 0;
+ file = 1;
+ line = 1;
+ column = 0;
+ is_stmt = (default_is_stmt != 0);
+ basic_block = false;
+ end_sequence = false;
+}
+
+void
+DwrLineRegs::EmitLine ()
+{
+ DwrLine *lnp = new DwrLine;
+
+ lnp->file = file;
+ lnp->line = line;
+ lnp->column = column;
+ lnp->address = address;
+ lines->append (lnp);
+ if ((file > 0) && (file < VecSize (file_names)))
+ {
+ DwrFileName *fnp = file_names->get (file);
+ fnp->isUsed = true;
+ }
+}
+
+Vector<DwrLine *> *
+DwrLineRegs::get_lines ()
+{
+ if (lines == NULL)
+ {
+ lines = new Vector<DwrLine *>;
+ debug_lineSec->offset = opcode_start;
+ reset ();
+ Dprintf (DUMP_DWR_LINE_REGS, "\n offset code address (file, line, column) stmt blck end_seq \n");
+ while (debug_lineSec->offset < debug_lineSec->size)
+ {
+ Dprintf (DUMP_DWR_LINE_REGS, NTXT ("0x%08llx "),
+ (long long) debug_lineSec->offset);
+ Dwarf_Small opcode = debug_lineSec->Get_8 ();
+ if (opcode == 0)
+ DoExtendedOpcode ();
+ else if (opcode < opcode_base)
+ {
+ DoStandardOpcode (opcode);
+ Dprintf (DUMP_DWR_LINE_REGS, NTXT ("%-20s"), standard_opcode2str (opcode));
+ }
+ else
+ {
+ DoSpecialOpcode (opcode - opcode_base);
+ Dprintf (DUMP_DWR_LINE_REGS, NTXT ("%-20s"),
+ special_opcode2str (opcode - opcode_base));
+ }
+ Dprintf (DUMP_DWR_LINE_REGS,
+ " 0x%08llx (%lld, %lld, %lld) %c %c %c\n",
+ (long long) address, (long long) file, (long long) line,
+ (long long) column, is_stmt ? 'T' : 'F',
+ basic_block ? 'T' : 'F', end_sequence ? 'T' : 'F');
+ }
+ lines->sort (LineRegsCmp);
+ if (DUMP_DWR_LINE_REGS)
+ lines->dump (fname);
+ }
+ return lines;
+}
+
+char *
+DwrLineRegs::getPath (int fn)
+{
+ fn--;
+ if ((fn >= VecSize (file_names)) || (fn < 0))
+ {
+ Dprintf (DEBUG_ERR_MSG, NTXT ("DwrLineRegs::getPath: fn=0x%lld file_names->size()=%lld\n"),
+ (long long) fn, (long long) VecSize (file_names));
+ return NULL;
+ }
+ DwrFileName *fnp = file_names->fetch (fn);
+ if (fnp->path)
+ return fnp->path;
+
+ char *dir = fnp->dir_index < include_directories->size () ?
+ include_directories->fetch (fnp->dir_index) : NULL;
+ if ((fnp->fname[0] == '/') || (dir == NULL) || (*dir == 0))
+ {
+ fnp->path = fnp->fname;
+ return fnp->path;
+ }
+
+ StringBuilder sb;
+ if (*dir != '/')
+ { // not absolute
+ char *s = include_directories->fetch (0);
+ sb.append (s);
+ sb.append ('/');
+ }
+ sb.append (dir);
+ sb.append ('/');
+ sb.append (fnp->fname);
+ fnp->path = canonical_path (sb.toString ());
+ return fnp->path;
+}
+
+DwrCU::DwrCU (Dwarf *_dwarf)
+{
+ dwarf = _dwarf;
+ cu_offset = dwarf->debug_infoSec->offset;
+ debug_infoSec = new DwrSec (dwarf->debug_infoSec, cu_offset);
+ next_cu_offset = debug_infoSec->ReadLength ();
+ if (next_cu_offset > debug_infoSec->sizeSec)
+ {
+ Dprintf (DEBUG_ERR_MSG,
+ "DwrCU::DwrCU: next_cu_offset(0x%llx) > debug_infoSec->sizeSec(%llx)\n",
+ (long long) next_cu_offset, (long long) debug_infoSec->sizeSec);
+ next_cu_offset = debug_infoSec->sizeSec;
+ }
+ debug_infoSec->size = next_cu_offset;
+ version = debug_infoSec->Get_16 ();
+ debug_abbrev_offset = debug_infoSec->GetLong ();
+ address_size = debug_infoSec->Get_8 ();
+ cu_header_offset = debug_infoSec->offset;
+ comp_dir = NULL;
+ module = NULL;
+ abbrevTable = NULL;
+ dwrInlinedSubrs = NULL;
+ srcFiles = NULL;
+ stmt_list_offset = 0;
+ dwrLineReg = NULL;
+ isMemop = false;
+ isGNU = false;
+ dwrTag.level = 0;
+
+ build_abbrevTable (dwarf->debug_abbrevSec, debug_abbrev_offset);
+#ifdef DEBUG
+ if (DUMP_DWARFLIB)
+ {
+ Dprintf (DUMP_DWARFLIB,
+ "CU_HEADER: header_offset = 0x%08llx %lld"
+ "next_header_offset=0x%08llx %lld\n"
+ " abbrev_offset = 0x%08llx %lld\n"
+ " unit_length = %lld\n"
+ " version = %d\n"
+ " address_size = %d\n"
+ " fmt64 = %s\n"
+ "debug_info: need_swap_endian=%s fmt64=%s addr32=%s\n",
+ (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),
+ (int) version, (int) address_size,
+ debug_infoSec->fmt64 ? "true" : "false",
+ debug_infoSec->need_swap_endian ? "true" : "false",
+ debug_infoSec->fmt64 ? "true" : "false",
+ debug_infoSec->addr32 ? "true" : "false");
+ Dprintf (DUMP_DWARFLIB, "\n.debug_abbrev cnt=%d offset=0x%08llx %lld\n",
+ (int) VecSize (abbrevTable), (long long) debug_abbrev_offset,
+ (long long) debug_abbrev_offset);
+ for (int i = 1, sz = VecSize (abbrevTable); i < sz; i++)
+ {
+ DwrAbbrevTable *abbTbl = abbrevTable->get (i);
+ Dprintf (DUMP_DWARFLIB, NTXT ("%5d: %-30s %-20s offset=0x%08llx\n"),
+ (int) i, DwrCU::tag2str (abbTbl->tag),
+ abbTbl->hasChild ? "DW_children_yes" : "DW_children_no",
+ (long long) abbTbl->offset);
+ for (int i1 = abbTbl->firstAtForm; i1 < abbTbl->lastAtForm; i1++)
+ {
+ Dwr_Attr *atf = abbrevAtForm->get (i1);
+ Dprintf (DUMP_DWARFLIB, " %-30s %s\n",
+ DwrCU::at2str (atf->at_name),
+ DwrCU::form2str (atf->at_form));
+ }
+ }
+ }
+#endif
+}
+
+DwrCU::~DwrCU ()
+{
+ delete debug_infoSec;
+ delete abbrevTable;
+ delete abbrevAtForm;
+ Destroy (dwrInlinedSubrs);
+ delete srcFiles;
+ delete dwrLineReg;
+ free (comp_dir);
+}
+
+void
+DwrCU::build_abbrevTable (DwrSec *_debug_abbrevSec, uint64_t _offset)
+{
+ if (abbrevTable)
+ return;
+ DwrSec *debug_abbrevSec = new DwrSec (_debug_abbrevSec, _offset);
+ abbrevTable = new DbeArray <DwrAbbrevTable>(128);
+ abbrevAtForm = new DbeArray <Dwr_Attr>(512);
+ abbrevTable->allocate (1); // skip first
+ abbrevAtForm->allocate (1); // skip first
+ for (int i = 1; debug_abbrevSec->offset < debug_abbrevSec->size; i++)
+ {
+ DwrAbbrevTable abbTbl;
+ abbTbl.offset = debug_abbrevSec->offset;
+ abbTbl.code = debug_abbrevSec->GetULEB128_32 ();
+ if (abbTbl.code == 0)
+ break;
+ else if (i != abbTbl.code)
+ {
+ dwarf->elf->append_msg (CMSG_ERROR, GTXT ("%s: the abbreviations table is corrupted (%lld <--> %lld)\n"),
+ get_basename (dwarf->elf->get_location ()),
+ (long long) i, (long long) abbTbl.code);
+ break;
+ }
+ abbTbl.tag = debug_abbrevSec->GetULEB128_32 ();
+ abbTbl.hasChild = (DW_children_yes == debug_abbrevSec->Get_8 ());
+ abbTbl.firstAtForm = abbrevAtForm->size ();
+ while (debug_abbrevSec->offset < debug_abbrevSec->size)
+ {
+ Dwr_Attr atf;
+ atf.at_name = debug_abbrevSec->GetULEB128_32 ();
+ atf.at_form = debug_abbrevSec->GetULEB128_32 ();
+ if (atf.at_name == 0 && atf.at_form == 0)
+ break;
+ abbrevAtForm->append (atf);
+ }
+ abbTbl.lastAtForm = abbrevAtForm->size ();
+ abbrevTable->append (abbTbl);
+ }
+ delete debug_abbrevSec;
+}
+
+int
+DwrCU::set_die (Dwarf_Die die)
+{
+ if (die > 0)
+ debug_infoSec->offset = die;
+ if (debug_infoSec->offset < cu_header_offset
+ || debug_infoSec->offset >= debug_infoSec->size)
+ return DW_DLV_ERROR;
+ dwrTag.offset = debug_infoSec->offset;
+ dwrTag.die = debug_infoSec->offset - cu_offset;
+ dwrTag.num = debug_infoSec->GetULEB128_32 ();
+ if (dwrTag.num == 0)
+ return DW_DLV_NO_ENTRY;
+ dwrTag.abbrevAtForm = abbrevAtForm;
+ DwrAbbrevTable *abbTbl = abbrevTable->get (dwrTag.num);
+ if (abbTbl == NULL)
+ { // corrupt dwarf
+ dwarf->elf->append_msg (CMSG_ERROR, GTXT ("%s: the abbreviation code (%lld) does not match for the Dwarf entry (0x%llx)\n"),
+ get_basename (dwarf->elf->get_location ()),
+ (long long) dwrTag.num, (long long) dwrTag.offset);
+ return DW_DLV_ERROR;
+ }
+ dwrTag.tag = abbTbl->tag;
+ dwrTag.hasChild = abbTbl->hasChild;
+ dwrTag.firstAttribute = abbTbl->firstAtForm;
+ dwrTag.lastAttribute = abbTbl->lastAtForm;
+ for (int k = abbTbl->firstAtForm; k < abbTbl->lastAtForm; k++)
+ {
+ Dwr_Attr *atf = abbrevAtForm->get (k);
+ int at_form = atf->at_form;
+ if (at_form == DW_FORM_indirect)
+ at_form = debug_infoSec->GetULEB128_32 ();
+ switch (at_form)
+ {
+ case DW_FORM_addr:
+ atf->u.offset = (address_size == 4) ? debug_infoSec->GetADDR_32 ()
+ : debug_infoSec->GetADDR_64 ();
+ break;
+ case DW_FORM_flag:
+ atf->u.offset = debug_infoSec->Get_8 ();
+ break;
+ case DW_FORM_block:
+ atf->len = debug_infoSec->GetULEB128 ();
+ atf->u.str = debug_infoSec->GetData (atf->len);
+ break;
+ case DW_FORM_block1:
+ atf->len = debug_infoSec->Get_8 ();
+ atf->u.str = debug_infoSec->GetData (atf->len);
+ break;
+ case DW_FORM_block2:
+ atf->len = debug_infoSec->Get_16 ();
+ atf->u.str = debug_infoSec->GetData (atf->len);
+ break;
+ case DW_FORM_block4:
+ atf->len = debug_infoSec->Get_32 ();
+ atf->u.str = debug_infoSec->GetData (atf->len);
+ break;
+ case DW_FORM_ref1:
+ atf->u.offset = debug_infoSec->Get_8 ();
+ break;
+ case DW_FORM_ref2:
+ atf->u.offset = debug_infoSec->Get_16 ();
+ break;
+ case DW_FORM_ref4:
+ atf->u.offset = debug_infoSec->Get_32 ();
+ break;
+ case DW_FORM_ref8:
+ atf->u.offset = debug_infoSec->Get_64 ();
+ break;
+ case DW_FORM_ref_udata:
+ atf->u.offset = debug_infoSec->GetULEB128 ();
+ break;
+ case DW_FORM_data1:
+ atf->u.offset = debug_infoSec->Get_8 ();
+ break;
+ case DW_FORM_data2:
+ atf->u.offset = debug_infoSec->Get_16 ();
+ break;
+ case DW_FORM_data4:
+ atf->u.offset = debug_infoSec->Get_32 ();
+ break;
+ case DW_FORM_data8:
+ atf->u.offset = debug_infoSec->Get_64 ();
+ break;
+ case DW_FORM_string:
+ atf->u.str = debug_infoSec->GetString (&atf->len);
+ break;
+ case DW_FORM_strp:
+ atf->u.offset = debug_infoSec->GetRef ();
+ if (dwarf->debug_strSec == NULL)
+ {
+ atf->u.str = NULL;
+ atf->len = 0;
+ }
+ else
+ {
+ dwarf->debug_strSec->offset = atf->u.offset;
+ atf->u.str = dwarf->debug_strSec->GetString (&atf->len);
+ }
+ break;
+ case DW_FORM_sdata:
+ atf->u.val = debug_infoSec->GetSLEB128 ();
+ break;
+ case DW_FORM_udata:
+ atf->u.offset = debug_infoSec->GetULEB128 ();
+ break;
+ case DW_FORM_ref_addr:
+ atf->u.offset = debug_infoSec->GetADDR ();
+ break;
+ case DW_FORM_sec_offset:
+ atf->u.offset = debug_infoSec->GetRef ();
+ break;
+ case DW_FORM_exprloc:
+ atf->u.offset = debug_infoSec->GetULEB128 ();
+ debug_infoSec->offset += atf->u.offset;
+ break;
+ case DW_FORM_flag_present:
+ atf->u.val = 1;
+ break;
+ case DW_FORM_ref_sig8:
+ atf->u.offset = debug_infoSec->GetADDR_64 ();
+ break;
+ default:
+ DEBUG_CODE
+ {
+ Dprintf (1, "Attribute form 0x%llx (%lld) is not implemented\n",
+ (long long) atf->at_form, (long long) atf->at_form);
+ assert (0);
+ }
+ atf->u.str = NULL;
+ atf->len = 0;
+ break;
+ }
+ }
+ dwrTag.dump ();
+ return DW_DLV_OK;
+}
+
+static char *
+composePath (char *dname, char *fname)
+{
+ char *s;
+ if (*fname == '/' || dname == NULL)
+ s = dbe_sprintf (NTXT ("%s"), fname);
+ else
+ s = dbe_sprintf (NTXT ("%s/%s"), dname, fname);
+ return canonical_path (s);
+}
+
+Module *
+DwrCU::parse_cu_header (LoadObject *lo)
+{
+ // Is tag always DW_TAG_compile_unit?
+ if (dwrTag.tag != DW_TAG_compile_unit)
+ {
+ Dprintf (DEBUG_ERR_MSG,
+ "parse_cu_header: die=0x%llx tag=%lld is not DW_TAG_compile_unit\n",
+ (long long) cu_offset, (long long) dwrTag.tag);
+ return NULL;
+ }
+
+ char *name = Dwarf_string (DW_AT_name);
+ if (name == NULL)
+ name = NTXT ("UnnamedUnit");
+ stmt_list_offset = Dwarf_data (DW_AT_stmt_list);
+ comp_dir = dbe_strdup (Dwarf_string (DW_AT_comp_dir));
+ char *dir_name = comp_dir ? StrChr (comp_dir, ':') : NULL;
+ char *orig_name = Dwarf_string (DW_AT_SUN_original_name);
+ char *path = composePath (dir_name, orig_name ? orig_name : name);
+
+ module = dwarf->stabs->append_Module (lo, path);
+ free (path);
+ if (module == NULL)
+ return NULL;
+ module->hasDwarf = true;
+ if (orig_name)
+ module->linkerStabName = composePath (dir_name, name);
+ module->lang_code = Dwarf_lang ();
+ module->comp_flags = dbe_strdup (Dwarf_string (DW_AT_SUN_command_line));
+ if (module->comp_flags == NULL)
+ module->comp_flags = dbe_strdup (Dwarf_string (DW_AT_icc_flags));
+ module->comp_dir = dbe_strdup (dir_name);
+
+ char *obj_file = Dwarf_string (DW_AT_SUN_obj_file);
+ char *obj_dir = Dwarf_string (DW_AT_SUN_obj_dir);
+ if (obj_dir && obj_file)
+ {
+ // object information may not be available
+ dir_name = StrChr (obj_dir, ':');
+ path = composePath (dir_name, obj_file);
+ if (module->dot_o_file == NULL)
+ module->dot_o_file = module->createLoadObject (path);
+ }
+ else
+ path = dbe_strdup (dwarf->stabs->path);
+ module->set_name (path);
+ return module;
+}
+
+Dwr_Attr *
+Dwr_Tag::get_attr (Dwarf_Half attr)
+{
+ for (long i = firstAttribute; i < lastAttribute; i++)
+ {
+ Dwr_Attr *atf = abbrevAtForm->get (i);
+ if (atf->at_name == attr)
+ return atf;
+ }
+ return NULL;
+}
+
+char *
+DwrCU::Dwarf_string (Dwarf_Half attr)
+{
+ Dwr_Attr *dwrAttr = dwrTag.get_attr (attr);
+ return dwrAttr ? dwrAttr->u.str : NULL;
+}
+
+uint64_t
+DwrCU::get_high_pc (uint64_t low_pc)
+{
+ Dwr_Attr *dwrAttr = dwrTag.get_attr (DW_AT_high_pc);
+ if (dwrAttr)
+ switch (dwrAttr->at_form)
+ {
+ case DW_FORM_addr:
+ return dwrAttr->u.offset;
+ default:
+ return dwrAttr->u.offset + low_pc;
+ }
+ return 0;
+}
+
+Dwarf_Addr
+DwrCU::Dwarf_addr (Dwarf_Half attr)
+{
+ Dwr_Attr *dwrAttr = dwrTag.get_attr (attr);
+ if (dwrAttr)
+ switch (dwrAttr->at_form)
+ {
+ case DW_FORM_addr:
+ return dwrAttr->u.offset;
+ }
+ return 0;
+}
+
+DwrSec*
+DwrCU::Dwarf_block (Dwarf_Half attr)
+{
+ Dwr_Attr *dwrAttr = dwrTag.get_attr (attr);
+ if (dwrAttr && dwrAttr->u.block)
+ switch (dwrAttr->at_form)
+ {
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ return new DwrSec (dwrAttr->u.block, dwrAttr->len,
+ dwarf->elf->need_swap_endian,
+ dwarf->elf->elf_getclass () == ELFCLASS32);
+ }
+ return NULL;
+}
+
+int
+DwrCU::read_data_attr (Dwarf_Half attr, int64_t *retVal)
+{
+ Dwr_Attr *dwrAttr = dwrTag.get_attr (attr);
+ if (dwrAttr)
+ switch (dwrAttr->at_form)
+ {
+ case DW_FORM_data1:
+ case DW_FORM_data2:
+ case DW_FORM_data4:
+ case DW_FORM_data8:
+ case DW_FORM_udata:
+ case DW_FORM_sec_offset:
+ *retVal = dwrAttr->u.val;
+ return DW_DLV_OK;
+
+ }
+ return DW_DLV_ERROR;
+}
+
+int
+DwrCU::read_ref_attr (Dwarf_Half attr, int64_t *retVal)
+{
+ Dwr_Attr *dwrAttr = dwrTag.get_attr (attr);
+ if (dwrAttr)
+ switch (dwrAttr->at_form)
+ {
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_udata:
+ case DW_FORM_sec_offset:
+ case DW_FORM_exprloc:
+ case DW_FORM_ref_sig8:
+ *retVal = dwrAttr->u.val;
+ return DW_DLV_OK;
+ }
+ return DW_DLV_ERROR;
+}
+
+int64_t
+DwrCU::Dwarf_data (Dwarf_Half attr)
+{
+ int64_t retVal;
+ if (read_data_attr (attr, &retVal) == DW_DLV_OK)
+ return retVal;
+ return 0;
+}
+
+int64_t
+DwrCU::Dwarf_ref (Dwarf_Half attr)
+{
+ int64_t retVal;
+ if (read_ref_attr (attr, &retVal) == DW_DLV_OK)
+ return retVal;
+ return 0;
+}
+
+Dwarf_Addr
+DwrCU::Dwarf_location (Dwarf_Attribute attr)
+{
+ DwrSec *secp = Dwarf_block (attr);
+ if (secp)
+ {
+ DwrLocation loc;
+ DwrLocation *lp = dwr_get_location (secp, &loc);
+ delete secp;
+ if (lp)
+ return lp->lc_number;
+ }
+ return 0;
+}
+
+void
+DwrCU::map_dwarf_lines (Module *mod)
+{
+ DwrLineRegs *lineReg = get_dwrLineReg ();
+ long inlinedSubrCnt = VecSize (dwrInlinedSubrs);
+ if (isGNU && (inlinedSubrCnt > 0))
+ {
+ Function *func = NULL;
+ mod->inlinedSubr = (InlinedSubr *) malloc (inlinedSubrCnt
+ * sizeof (InlinedSubr));
+ for (long i = 0; i < inlinedSubrCnt; i++)
+ {
+ DwrInlinedSubr *inlinedSubr = dwrInlinedSubrs->get (i);
+ uint64_t low_pc;
+ Function *f = dwarf->stabs->map_PC_to_func (inlinedSubr->low_pc,
+ low_pc, mod->functions);
+ if (f == NULL)
+ continue;
+ if (func != f)
+ {
+ func = f;
+ func->inlinedSubrCnt = 0;
+ func->inlinedSubr = mod->inlinedSubr + i;
+ }
+ InlinedSubr *p = func->inlinedSubr + func->inlinedSubrCnt;
+ func->inlinedSubrCnt++;
+ int fileno = inlinedSubr->file - 1;
+ 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;
+ p->low_pc = inlinedSubr->low_pc - low_pc;
+ p->level = inlinedSubr->level;
+ p->func = NULL;
+ p->fname = NULL;
+ if (set_die (inlinedSubr->abstract_origin) == DW_DLV_OK)
+ p->fname = dbe_strdup (Dwarf_string (DW_AT_name));
+ if (p->fname)
+ p->func = Stabs::find_func (p->fname, mod->functions,
+ Stabs::is_fortran (mod->lang_code));
+ }
+ }
+ Vector<DwrLine *> *lines = lineReg->get_lines ();
+
+ Include *includes = new Include;
+ includes->new_src_file (mod->getMainSrc (), 0, NULL);
+ char *path = NULL;
+ SourceFile *cur_src = NULL;
+ Function *cur_func = NULL;
+ for (long i = 0, sz = VecSize (lines); i < sz; i++)
+ {
+ DwrLine *dwrLine = lines->get (i);
+ char *filename = dwrLineReg->getPath (dwrLine->file);
+ if (filename == NULL)
+ continue;
+ uint64_t pc = dwrLine->address;
+ int lineno = dwrLine->line;
+ if (path != filename)
+ {
+ path = filename;
+ char *name = StrChr (path, ':');
+ SourceFile *src = mod->setIncludeFile (name);
+ if (cur_src != src)
+ {
+ includes->new_src_file (src, lineno, cur_func);
+ cur_src = src;
+ }
+ }
+ uint64_t low_pc;
+ Function *func = dwarf->stabs->map_PC_to_func (pc, low_pc, mod->functions);
+ if (func && (func->module == mod))
+ {
+ if (func != cur_func)
+ {
+ if (cur_func)
+ while (cur_func->popSrcFile () != NULL)
+ ;
+ cur_func = func;
+ includes->push_src_files (cur_func);
+ }
+ cur_func->add_PC_info (pc - low_pc, lineno);
+ }
+ }
+ if (cur_func)
+ while (cur_func->popSrcFile ())
+ ;
+ delete includes;
+}
+
+DwrLineRegs *
+DwrCU::get_dwrLineReg ()
+{
+ if (dwrLineReg == NULL)
+ dwrLineReg = new DwrLineRegs (new DwrSec (dwarf->debug_lineSec,
+ stmt_list_offset), comp_dir);
+ return dwrLineReg;
+}
+
+void
+DwrCU::parse_inlined_subroutine (Dwarf_cnt *ctx)
+{
+ int64_t abstract_origin = Dwarf_ref (DW_AT_abstract_origin);
+ int fileno = (int) Dwarf_data (DW_AT_call_file);
+ int lineno = (int) Dwarf_data (DW_AT_call_line);
+ int level = ctx->inlinedSubr ? (ctx->inlinedSubr->level + 1) : 0;
+ DwrInlinedSubr *inlinedSubr_old = ctx->inlinedSubr;
+
+ if (dwrInlinedSubrs == NULL)
+ dwrInlinedSubrs = new Vector<DwrInlinedSubr*>;
+ Dwr_Attr *dwrAttr = dwrTag.get_attr (DW_AT_ranges);
+ if (dwrAttr)
+ {
+ uint64_t ranges = Dwarf_ref (DW_AT_ranges);
+ if (dwarf->debug_rangesSec && (ranges < dwarf->debug_rangesSec->size))
+ {
+ dwarf->debug_rangesSec->offset = ranges;
+ for (;;)
+ {
+ uint64_t low_pc = dwarf->debug_rangesSec->GetADDR ();
+ uint64_t high_pc = dwarf->debug_rangesSec->GetADDR ();
+ if ((low_pc > 0) && (low_pc <= high_pc))
+ {
+ DwrInlinedSubr *p = new DwrInlinedSubr (abstract_origin,
+ low_pc, high_pc, fileno, lineno, level);
+ dwrInlinedSubrs->append (p);
+ ctx->inlinedSubr = p;
+ }
+ else
+ break;
+ }
+ }
+ }
+ else
+ {
+ uint64_t low_pc = Dwarf_addr (DW_AT_low_pc);
+ uint64_t high_pc = get_high_pc (low_pc);
+ if ((low_pc > 0) && (low_pc <= high_pc))
+ {
+ DwrInlinedSubr *p = new DwrInlinedSubr (abstract_origin, low_pc,
+ high_pc, fileno, lineno, level);
+ dwrInlinedSubrs->append (p);
+ ctx->inlinedSubr = p;
+ }
+ }
+ parseChild (ctx);
+ ctx->inlinedSubr = inlinedSubr_old;
+}
+
+
+//////////////////////////////////////////////////////////
+// class DwrInlinedSubr
+DwrInlinedSubr::DwrInlinedSubr (int64_t _abstract_origin, uint64_t _low_pc,
+ uint64_t _high_pc, int _file, int _line, int _level)
+{
+ abstract_origin = _abstract_origin;
+ low_pc = _low_pc;
+ high_pc = _high_pc;
+ file = _file;
+ line = _line;
+ level = _level;
+}
+
+void
+DwrInlinedSubr::dump ()
+{
+ Dprintf (DUMP_DWARFLIB,
+ " level=%d 0x%08llx [0x%08llx - 0x%08llx] file=%d line=%d\n",
+ (int) level, (long long) abstract_origin, (long long) low_pc,
+ (long long) high_pc, (int) file, (int) line);
+}