| /* Copyright (C) 2021-2024 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 NO_STMT_LIST ((uint64_t) -1) |
| #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")); |
| } |
| |
| template<> void Vector<DwrFileName *> |
| ::dump (const char *msg) |
| { |
| Dprintf (1, "\n%s Vector<DwrFileName *> [%lld]: [dir_ind tstamp fsize]\n", |
| msg ? msg : NTXT (""), (long long) size ()); |
| for (long i = 0, sz = size (); i < sz; i++) |
| { |
| DwrFileName *fnp = get (i); |
| Dprintf (1, " %2ld %3lld %8lld %8lld %s\n", i, (long long) fnp->dir_index, |
| (long long) fnp->timestamp, (long long) fnp->file_size, |
| STR (fnp->fname)); |
| } |
| Dprintf (1, "\n"); |
| } |
| |
| static char * |
| get_string (DwrSec *sec, uint64_t off) |
| { |
| if (sec) |
| { |
| sec->offset = off; |
| return sec->GetString (); |
| } |
| return NULL; |
| } |
| |
| |
| ////////////////////////////////////////////////////////// |
| // 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); |
| CASE_S (DW_TAG_rvalue_reference_type); |
| CASE_S (DW_TAG_coarray_type); |
| CASE_S (DW_TAG_generic_subrange); |
| CASE_S (DW_TAG_dynamic_type); |
| CASE_S (DW_TAG_atomic_type); |
| CASE_S (DW_TAG_call_site); |
| CASE_S (DW_TAG_call_site_parameter); |
| CASE_S (DW_TAG_skeleton_unit); |
| CASE_S (DW_TAG_immutable_type); |
| CASE_S (0); |
| 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_GNU_locviews); |
| CASE_S (DW_AT_GNU_entry_view); |
| 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); |
| CASE_S (DW_AT_string_length_bit_size); |
| CASE_S (DW_AT_string_length_byte_size); |
| CASE_S (DW_AT_rank); |
| CASE_S (DW_AT_str_offsets_base); |
| CASE_S (DW_AT_addr_base); |
| CASE_S (DW_AT_rnglists_base); |
| CASE_S (DW_AT_dwo_name); |
| CASE_S (DW_AT_reference); |
| CASE_S (DW_AT_rvalue_reference); |
| CASE_S (DW_AT_macros); |
| CASE_S (DW_AT_call_all_calls); |
| CASE_S (DW_AT_call_all_source_calls); |
| CASE_S (DW_AT_call_all_tail_calls); |
| CASE_S (DW_AT_call_return_pc); |
| CASE_S (DW_AT_call_value); |
| CASE_S (DW_AT_call_origin); |
| CASE_S (DW_AT_call_parameter); |
| CASE_S (DW_AT_call_pc); |
| CASE_S (DW_AT_call_tail_call); |
| CASE_S (DW_AT_call_target); |
| CASE_S (DW_AT_call_target_clobbered); |
| CASE_S (DW_AT_call_data_location); |
| CASE_S (DW_AT_call_data_value); |
| CASE_S (DW_AT_noreturn); |
| CASE_S (DW_AT_alignment); |
| CASE_S (DW_AT_export_symbols); |
| CASE_S (DW_AT_deleted); |
| CASE_S (DW_AT_defaulted); |
| CASE_S (DW_AT_loclists_base); |
| |
| 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_data16); |
| CASE_S (DW_FORM_line_strp); |
| CASE_S (DW_FORM_implicit_const); |
| 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; |
| } |
| |
| char * |
| DwrCU::lnct2str (int ty) |
| { |
| static char buf[128]; |
| char *s; |
| switch (ty) |
| { |
| CASE_S (DW_LNCT_path); |
| CASE_S (DW_LNCT_directory_index); |
| CASE_S (DW_LNCT_timestamp); |
| CASE_S (DW_LNCT_size); |
| CASE_S (DW_LNCT_MD5); |
| CASE_S (DW_LNCT_lo_user); |
| CASE_S (DW_LNCT_hi_user); |
| default: s = NTXT ("???"); |
| break; |
| } |
| snprintf (buf, sizeof (buf), NTXT ("%s(%d)"), s, ty); |
| 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: |
| case DW_FORM_line_strp: |
| case DW_FORM_strp_sup: |
| case DW_FORM_implicit_const: |
| Dprintf (DUMP_DWARFLIB, " \"%s\"", atrp->u.str ? atrp->u.str : "<NULL>"); |
| break; |
| case DW_FORM_block: |
| case DW_FORM_block1: |
| case DW_FORM_block2: |
| case DW_FORM_block4: |
| case DW_FORM_data16: |
| 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_24 () |
| { |
| uint32_t n = 0; |
| if (bounds_violation (3)) |
| return n; |
| memcpy ((char *) &n, data + offset, 3); |
| offset += 3; |
| 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 off = offset; |
| while (offset < size) |
| if (data[offset++] == 0) |
| { // '\0' is inside section |
| if (off + 1 == offset) |
| return NULL; |
| return ((char *) data) + off; |
| } |
| return NULL; // The section is not '\0' terminated |
| } |
| |
| 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; |
| } |
| |
| uint64_t |
| DwrSec::get_value (int dw_form) |
| { |
| uint64_t v; |
| switch (dw_form) |
| { |
| case DW_FORM_line_strp: |
| case DW_FORM_strp: |
| case DW_FORM_strp_sup: |
| return GetRef (); |
| case DW_FORM_data1: |
| return Get_8 (); |
| case DW_FORM_data2: |
| return Get_16 (); |
| case DW_FORM_data4: |
| return Get_32 (); |
| case DW_FORM_data8: |
| return Get_64 (); |
| case DW_FORM_udata: |
| return GetULEB128 (); |
| case DW_FORM_data16: |
| offset += 16; |
| return offset - 16; |
| case DW_FORM_block: |
| v = GetULEB128 (); |
| offset += v; |
| return offset - v; |
| } |
| return 0; |
| } |
| |
| 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 = dbe_strdup (_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 (Dwarf *_dwarf, DwrSec *secp, char *dirName) |
| { |
| dwarf = _dwarf; |
| dir_names = NULL; |
| file_names = NULL; |
| lines = NULL; |
| fname = NULL; |
| // `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 (); |
| if (version == 5) |
| { |
| debug_lineSec->address_size = debug_lineSec->Get_8(); |
| debug_lineSec->segment_selector_size = debug_lineSec->Get_8(); |
| } |
| 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]); |
| } |
| |
| if (version == 5) |
| { |
| dir_names = read_file_names_dwarf5 (); |
| file_names = read_file_names_dwarf5 (); |
| } |
| else |
| { |
| dir_names = new Vector<DwrFileName *>; |
| dir_names->append (new DwrFileName (dirName)); |
| while (true) |
| { |
| char *s = debug_lineSec->GetString (); |
| if (s == NULL) |
| break; |
| dir_names->append (new DwrFileName (s)); |
| } |
| |
| file_names = new Vector<DwrFileName *>; |
| file_names->append (new DwrFileName (dirName)); |
| while (true) |
| { |
| char *s = debug_lineSec->GetString (); |
| if (s == NULL) |
| break; |
| DwrFileName *fnp = new DwrFileName (s); |
| fnp->dir_index = debug_lineSec->GetULEB128_32 (); |
| fnp->timestamp = debug_lineSec->GetULEB128 (); |
| fnp->file_size = debug_lineSec->GetULEB128 (); |
| file_names->append (fnp); |
| } |
| } |
| dump (); |
| } |
| |
| DwrLineRegs::~DwrLineRegs () |
| { |
| Destroy (dir_names); |
| Destroy (file_names); |
| Destroy (lines); |
| delete debug_lineSec; |
| } |
| |
| Vector <DwrFileName *> * |
| DwrLineRegs::read_file_names_dwarf5 () |
| { |
| |
| typedef struct |
| { |
| int type_code; |
| int form_code; |
| } t_entry_fmt; |
| |
| int efmt_cnt = debug_lineSec->Get_8 (); |
| Dprintf (DUMP_DWR_LINE_REGS, "\nRead names: offset=0x%llx entry_fmt_cnt=%d\n", |
| (long long) debug_lineSec->offset, efmt_cnt); |
| if (efmt_cnt == 0) |
| return NULL; |
| t_entry_fmt *efmt = (t_entry_fmt *) malloc (sizeof (t_entry_fmt) * efmt_cnt); |
| for (int i = 0; i < efmt_cnt; i++) |
| { |
| efmt[i].type_code = debug_lineSec->GetULEB128 (); |
| efmt[i].form_code = debug_lineSec->GetULEB128 (); |
| Dprintf (DUMP_DWR_LINE_REGS, " %2d %20s %s\n", i, |
| DwrCU::lnct2str (efmt[i].type_code), |
| DwrCU::form2str (efmt[i].form_code)); |
| } |
| |
| int cnt = debug_lineSec->GetULEB128_32 (); |
| Dprintf (DUMP_DWR_LINE_REGS, "\nRead names: offset=0x%llx names_cnt=%d\n", |
| (long long) debug_lineSec->offset, cnt); |
| Vector<DwrFileName *> *fnames = new Vector<DwrFileName *> (cnt); |
| for (int i = 0; i < cnt; i++) |
| { |
| int ind = 0; |
| uint64_t off = 0; |
| uint64_t tstamp = 0; |
| uint64_t fsize = 0; |
| char *nm = NULL; |
| for (int k = 0; k < efmt_cnt; k++) |
| switch (efmt[k].type_code) |
| { |
| case DW_LNCT_path: |
| if (efmt[k].form_code == DW_FORM_string) |
| nm = debug_lineSec->GetString (); |
| else |
| { |
| off = debug_lineSec->get_value (efmt[k].form_code); |
| if (efmt[k].form_code == DW_FORM_line_strp) |
| nm = get_string (dwarf->debug_line_strSec, off); |
| else if (efmt[k].form_code == DW_FORM_strp) |
| nm = get_string (dwarf->debug_strSec, off); |
| } |
| break; |
| case DW_LNCT_directory_index: |
| ind = debug_lineSec->get_value (efmt[k].form_code); |
| break; |
| case DW_LNCT_timestamp: |
| tstamp = debug_lineSec->get_value (efmt[k].form_code); |
| break; |
| case DW_LNCT_size: |
| fsize = debug_lineSec->get_value (efmt[k].form_code); |
| break; |
| case DW_LNCT_MD5: |
| (void) debug_lineSec->get_value (efmt[k].form_code); |
| break; |
| } |
| Dprintf (DUMP_DWR_LINE_REGS, " %3d ind=%d off=0x%08llx %s\n", |
| i, ind, (long long) off, STR (nm)); |
| DwrFileName *fnp = new DwrFileName (nm); |
| fnp->dir_index = ind; |
| fnp->timestamp = tstamp; |
| fnp->file_size = fsize; |
| fnames->append (fnp); |
| } |
| free (efmt); |
| return fnames; |
| } |
| |
| void |
| DwrLineRegs::dump () |
| { |
| if (!DUMP_DWR_LINE_REGS) |
| return; |
| if (dir_names) |
| dir_names->dump ("dir_names"); |
| if (file_names) |
| file_names->dump ("file_names"); |
| |
| 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 (); |
| 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) |
| { |
| 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->fname == NULL) |
| return NULL; |
| if (fnp->path) |
| return fnp->path; |
| |
| fnp->path = fnp->fname; |
| if (fnp->fname[0] == '/') |
| return fnp->path; |
| |
| char *dir = NULL; |
| if (dir_names) |
| { |
| if (fnp->dir_index < dir_names->size () && fnp->dir_index >= 0) |
| dir = dir_names->get (fnp->dir_index)->fname; |
| } |
| if (dir == NULL || *dir == 0) |
| return fnp->path; |
| |
| char *dir1 = NULL; |
| if (*dir != '/') |
| dir1 = dir_names->get(0)->fname; |
| if (dir1 && *dir != 0) |
| fnp->path = dbe_sprintf ("%s/%s/%s", dir1, dir, fnp->fname); |
| else |
| fnp->path = dbe_sprintf ("%s/%s", dir, fnp->fname); |
| fnp->path = canonical_path (fnp->path); |
| 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 (); |
| if (version == 5) |
| { |
| unit_type = debug_infoSec->Get_8 (); |
| address_size = debug_infoSec->Get_8 (); |
| debug_abbrev_offset = debug_infoSec->GetLong (); |
| } |
| else |
| { |
| unit_type = DW_UT_compile; |
| 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 = NO_STMT_LIST; |
| 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.len = 0; |
| atf.u.str = NULL; |
| atf.at_name = debug_abbrevSec->GetULEB128_32 (); |
| atf.at_form = debug_abbrevSec->GetULEB128_32 (); |
| if (atf.at_name == 0 && atf.at_form == 0) |
| break; |
| switch (atf.at_form) |
| { |
| case DW_FORM_implicit_const: |
| atf.len = debug_abbrevSec->GetSLEB128 (); |
| 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.offset = debug_infoSec->offset; |
| atf->u.str = debug_infoSec->GetString (); |
| break; |
| case DW_FORM_strp: |
| atf->u.offset = debug_infoSec->GetRef (); |
| atf->u.str = get_string (dwarf->debug_strSec, atf->u.offset); |
| 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: |
| if (version > 2) |
| atf->u.offset = debug_infoSec->GetRef (); |
| else |
| 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; |
| case DW_FORM_data16: // we never use this data. Skip 16 bytes |
| atf->len = 16; |
| (void) debug_infoSec->Get_64 (); |
| (void) debug_infoSec->Get_64 (); |
| break; |
| case DW_FORM_addrx: |
| case DW_FORM_strx: |
| case DW_FORM_loclistx: |
| case DW_FORM_rnglistx: |
| atf->u.offset = debug_infoSec->GetULEB128 (); |
| break; |
| case DW_FORM_addrx1: |
| case DW_FORM_strx1: |
| atf->u.offset = debug_infoSec->Get_8 (); |
| break; |
| case DW_FORM_addrx2: |
| case DW_FORM_strx2: |
| atf->u.offset = debug_infoSec->Get_16 (); |
| break; |
| case DW_FORM_addrx3: |
| case DW_FORM_strx3: |
| atf->u.offset = debug_infoSec->Get_24 (); |
| break; |
| case DW_FORM_addrx4: |
| case DW_FORM_strx4: |
| case DW_FORM_ref_sup4: |
| atf->u.offset = debug_infoSec->Get_32 (); |
| break; |
| case DW_FORM_ref_sup8: |
| atf->u.offset = debug_infoSec->Get_64 (); |
| break; |
| case DW_FORM_line_strp: |
| atf->u.offset = debug_infoSec->GetRef (); |
| atf->u.str = get_string (dwarf->debug_line_strSec, atf->u.offset); |
| break; |
| case DW_FORM_strp_sup: |
| atf->u.offset = debug_infoSec->GetRef (); |
| atf->u.str = NULL; |
| atf->len = 0; |
| break; |
| case DW_FORM_implicit_const: |
| atf->u.str = NULL; |
| 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"); |
| int64_t v; |
| if (read_data_attr(DW_AT_stmt_list, &v) == DW_DLV_OK) |
| stmt_list_offset = v; |
| 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_data16: |
| 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)); |
| } |
| } |
| if (lineReg == NULL) |
| return; |
| 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 = lineReg->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 && stmt_list_offset != NO_STMT_LIST) |
| dwrLineReg = new DwrLineRegs (dwarf, 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); |
| } |