mirror of
https://github.com/autc04/Retro68.git
synced 2024-06-01 15:41:39 +00:00
2204 lines
56 KiB
C++
2204 lines
56 KiB
C++
/* 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);
|
|
}
|