Store CU and parent in DIE

Back-references from the DIE to the CU and the parent DIE will make it
much easier to implement several features.
This commit is contained in:
Omar Sandoval 2017-08-27 11:35:38 -07:00
parent 64f66f747f
commit e6a58f533a
7 changed files with 147 additions and 119 deletions

View File

@ -19,12 +19,12 @@ def dump_cu(dwarf_file, cu, cu_name, *, indent=0):
print(f'{prefix} is_64_bit = {cu.is_64_bit}')
def dump_die(dwarf_file, cu, die, *, indent=0, recurse=False):
def dump_die(dwarf_file, die, *, indent=0, recurse=False):
prefix = ' ' * indent
print(f'{prefix}<{die.cu_offset}> {tag_name(die.tag)}')
for name, form, value in die:
if form == DW_FORM.string or form == DW_FORM.strp:
value = repr(dwarf_file.at_string(cu, form, value))[1:]
value = repr(dwarf_file.at_string(die.cu, form, value))[1:]
elif form in {DW_FORM.data1, DW_FORM.data2, DW_FORM.data4, DW_FORM.data8}:
value = repr(value)[1:]
print(f'{prefix} {at_name(name)} ({form_name(form)}) = {value}')
@ -36,7 +36,7 @@ def dump_die(dwarf_file, cu, die, *, indent=0, recurse=False):
else:
if children is not None:
for child in children:
dump_die(dwarf_file, cu, child, indent=indent + 2, recurse=True)
dump_die(dwarf_file, child, indent=indent + 2, recurse=True)
def dump_lnp_include_directories(lnp, *, indent=0):
@ -152,8 +152,8 @@ def dump_cus(dwarf_file, args):
if args.die:
die = dwarf_file.cu_die(cu)
if args.recursive:
dwarf_file.parse_die_children(cu, die, recurse=True)
dump_die(dwarf_file, cu, die, indent=2, recurse=args.recursive)
dwarf_file.parse_die_children(die, recurse=True)
dump_die(dwarf_file, die, indent=2, recurse=args.recursive)
if (args.include_directories or args.file_names or args.lines or
args.line_number_program):
lnp = dwarf_file.cu_line_number_program_header(cu)

View File

@ -143,7 +143,7 @@ class DwarfFile:
def cu_name(self, cu: lldwarf.CompilationUnitHeader) -> bytes:
try:
return self.die_name(cu, self.cu_die(cu))
return self.die_name(self.cu_die(cu))
except KeyError:
return b''
@ -159,18 +159,19 @@ class DwarfFile:
debug_info = self.section('.debug_info')
abbrev_table = self.abbrev_table(cu.debug_abbrev_offset)
die_offset = cu.offset + (23 if cu.is_64_bit else 11)
die = lldwarf.parse_die(cu, abbrev_table, cu.offset, self._mmap,
die = lldwarf.parse_die(cu, None, abbrev_table, cu.offset, self._mmap,
die_offset, recurse=recurse)
cu.die = die
return die
def parse_die_children(self, cu: lldwarf.CompilationUnitHeader,
die: lldwarf.DwarfDie, *, recurse: bool=False) -> None:
def parse_die_children(self, die: lldwarf.DwarfDie, *,
recurse: bool=False) -> None:
if not hasattr(die, 'children'):
cu = die.cu
debug_info = self.section('.debug_info')
abbrev_table = self.abbrev_table(cu.debug_abbrev_offset)
offset = cu.offset + die.cu_offset + die.die_length
die.children = lldwarf.parse_die_siblings(cu, abbrev_table,
die.children = lldwarf.parse_die_siblings(cu, die, abbrev_table,
cu.offset, self._mmap,
offset=offset,
recurse=recurse)
@ -196,10 +197,9 @@ class DwarfFile:
high_pc = high_pc_value
return low_pc <= address < high_pc
def die_name(self, cu: lldwarf.CompilationUnitHeader,
die: lldwarf.DwarfDie) -> bytes:
def die_name(self, die: lldwarf.DwarfDie) -> bytes:
form, value = die.find(DW_AT.name)
return self.at_string(cu, form, value)
return self.at_string(die.cu, form, value)
def die_address(self, die: lldwarf.DwarfDie) -> int:
try:

View File

@ -51,10 +51,10 @@ class DwarfProgram:
symbol = dwarf_file.symbol(name)
dwarf_file, cu = self.find_cu_by_addr(symbol.st_value)
die = self._file.cu_die(cu)
dwarf_file.parse_die_children(cu, die)
dwarf_file.parse_die_children(die)
for child in die.children:
if (child.tag == DW_TAG.subprogram and
dwarf_file.die_name(cu, child).decode() == name):
dwarf_file.die_name(child).decode() == name):
return child
else:
raise ValueError('subprogram not found')
@ -84,7 +84,7 @@ class DwarfProgram:
cu: lldwarf.CompilationUnitHeader,
addr: int) -> lldwarf.DwarfDie:
die = dwarf_file.cu_die(cu)
dwarf_file.parse_die_children(cu, die)
dwarf_file.parse_die_children(die)
for child in die.children:
if (child.tag == DW_TAG.subprogram and
dwarf_file.die_contains_address(child, addr)):
@ -99,7 +99,7 @@ class DwarfProgram:
row = self._best_breakpoint_row(dwarf_file, cu, lnp, matrix, filename, lineno)
subprogram = self._find_subprogram_containing_address(dwarf_file, cu, row.address)
subprogram_name = dwarf_file.die_name(cu, subprogram).decode()
subprogram_name = dwarf_file.die_name(subprogram).decode()
subprogram_address = dwarf_file.die_address(subprogram)
assert row.address >= subprogram_address
return f'{subprogram_name}+0x{row.address - subprogram_address:x}'

View File

@ -99,8 +99,10 @@ static PyObject *DwarfDie_new(PyTypeObject *subtype, PyObject *args,
PyObject *kwds)
{
static char *keywords[] = {
"cu_offset", "die_length", "tag", "children", "attributes", NULL
"cu", "parent", "cu_offset", "die_length", "tag", "children", "attributes", NULL
};
PyObject *cu;
PyObject *parent;
PyObject *cu_offset;
PyObject *die_length;
PyObject *tag;
@ -109,9 +111,9 @@ static PyObject *DwarfDie_new(PyTypeObject *subtype, PyObject *args,
DwarfDie *die = NULL;
Py_ssize_t i, len;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOOOO:DwarfDie", keywords,
&cu_offset, &die_length, &tag, &children,
&attribs))
if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOOOOOO:DwarfDie", keywords,
&cu, &parent, &cu_offset, &die_length,
&tag, &children, &attribs))
return NULL;
tmp = PySequence_Tuple(attribs);
@ -125,6 +127,10 @@ static PyObject *DwarfDie_new(PyTypeObject *subtype, PyObject *args,
die->dict = PyDict_New();
if (!die->dict)
goto err;
die->cu = cu;
Py_INCREF(cu);
die->parent = parent;
Py_INCREF(parent);
die->cu_offset = PyLong_AsSsize_t(cu_offset);
if (PyErr_Occurred()) {
if (PyErr_ExceptionMatches(PyExc_OverflowError))
@ -214,8 +220,9 @@ static PyObject *DwarfDie_repr(DwarfDie *self)
goto out;
/* XXX: children = NULL? */
ret = PyUnicode_FromFormat("DwarfDie(cu_offset=%zd, die_length=%zd, tag=%llu, children=%R, attributes=%R)",
self->cu_offset, self->die_length,
ret = PyUnicode_FromFormat("DwarfDie(cu=%R, parent=%R, cu_offset=%zd, die_length=%zd, tag=%llu, children=%R, attributes=%R)",
self->cu, self->parent, self->cu_offset,
self->die_length,
(unsigned long long)self->tag,
self->children, tmp);
@ -506,7 +513,7 @@ block:
}
PyObject *LLDwarf_ParseDieSiblings(Py_buffer *buffer, Py_ssize_t *offset,
CompilationUnitHeader *cu,
CompilationUnitHeader *cu, PyObject *parent,
PyObject *abbrev_table, Py_ssize_t cu_offset,
bool recurse)
{
@ -519,8 +526,9 @@ PyObject *LLDwarf_ParseDieSiblings(Py_buffer *buffer, Py_ssize_t *offset,
for (;;) {
PyObject *child;
child = LLDwarf_ParseDie(buffer, offset, cu, abbrev_table,
cu_offset, recurse, true);
child = LLDwarf_ParseDie(buffer, offset, cu, parent,
abbrev_table, cu_offset, recurse,
true);
if (PyErr_Occurred())
goto err;
if (!child)
@ -540,9 +548,9 @@ err:
}
PyObject *LLDwarf_ParseDie(Py_buffer *buffer, Py_ssize_t *offset,
CompilationUnitHeader *cu, PyObject *abbrev_table,
Py_ssize_t cu_offset, bool recurse,
bool jump_to_sibling)
CompilationUnitHeader *cu, PyObject *parent,
PyObject *abbrev_table, Py_ssize_t cu_offset,
bool recurse, bool jump_to_sibling)
{
Py_ssize_t orig_offset;
DwarfDie *die;
@ -579,6 +587,12 @@ PyObject *LLDwarf_ParseDie(Py_buffer *buffer, Py_ssize_t *offset,
if (!die->dict)
goto err;
die->cu = (PyObject *)cu;
Py_INCREF(cu);
die->parent = parent;
Py_INCREF(parent);
die->cu_offset = orig_offset - cu_offset;
die->tag = decl->tag;
die->children = NULL;
@ -601,6 +615,7 @@ PyObject *LLDwarf_ParseDie(Py_buffer *buffer, Py_ssize_t *offset,
die->children = Py_None;
} else if (recurse || (jump_to_sibling && !sibling)) {
die->children = LLDwarf_ParseDieSiblings(buffer, offset, cu,
(PyObject *)die,
abbrev_table,
cu_offset, true);
if (!die->children)
@ -635,6 +650,10 @@ static PyMethodDef DwarfDie_methods[] = {
};
static PyMemberDef DwarfDie_members[] = {
{"cu", T_OBJECT, offsetof(DwarfDie, cu), 0,
"CU this DIE was parsed from"},
{"parent", T_OBJECT, offsetof(DwarfDie, parent), 0,
"the parent DIE of this DIE"},
{"cu_offset", T_UINT64T, offsetof(DwarfDie, cu_offset), 0,
"offset from the beginning of the CU where this DIE starts"},
{"die_length", T_UINT64T, offsetof(DwarfDie, die_length), 0,
@ -648,14 +667,17 @@ static PyMemberDef DwarfDie_members[] = {
};
#define DwarfDie_DOC \
"DwarfDie(cu_offset, die_length, tag, children, attribs) -> new debugging information entry\n\n" \
"Create a new DWARF debugging information entry. len(die) is the\n" \
"number of attributes and die[i] is the ith attribute.\n\n" \
"Arguments:\n" \
"cu_offset -- integer offset\n" \
"die_length -- intger length\n" \
"tag -- integer tag of the DIE\n" \
"children -- list of children DIEs\n" \
"DwarfDie(cu, parent, cu_offset, die_length, tag, children,\n" \
" attribs) -> new debugging information entry\n\n" \
"Create a new DWARF debugging information entry. len(die) is the\n" \
"number of attributes and die[i] is the ith attribute.\n\n" \
"Arguments:\n" \
"cu -- CompilationUnitHeader\n" \
"parent -- DwarfDie or None\n" \
"cu_offset -- integer offset\n" \
"die_length -- intger length\n" \
"tag -- integer tag of the DIE\n" \
"children -- list of children DIEs\n" \
"attribs -- iterable of (name, form, value) triples"
PyTypeObject DwarfDie_type = {

View File

@ -88,6 +88,8 @@ struct DwarfAttrib {
typedef struct {
PyObject_VAR_HEAD
PyObject *dict;
PyObject *cu;
PyObject *parent;
Py_ssize_t cu_offset;
Py_ssize_t die_length;
uint64_t tag;
@ -155,13 +157,13 @@ PyObject *LLDwarf_ParseArangeTableHeader(Py_buffer *buffer, Py_ssize_t *offset);
PyObject *LLDwarf_ParseCompilationUnitHeader(Py_buffer *buffer,
Py_ssize_t *offset);
PyObject *LLDwarf_ParseDie(Py_buffer *buffer, Py_ssize_t *offset,
CompilationUnitHeader *cu, PyObject *abbrev_table,
Py_ssize_t cu_offset, bool recurse,
bool jump_to_sibling);
CompilationUnitHeader *cu, PyObject *parent,
PyObject *abbrev_table, Py_ssize_t cu_offset,
bool recurse, bool jump_to_sibling);
PyObject *LLDwarf_ParseDieSiblings(Py_buffer *buffer, Py_ssize_t *offset,
CompilationUnitHeader *cu,
PyObject *abbrev_table,
Py_ssize_t cu_offset, bool recurse);
CompilationUnitHeader *cu, PyObject *parent,
PyObject *abbrev_table, Py_ssize_t cu_offset,
bool recurse);
PyObject *LLDwarf_ParseLineNumberProgramHeader(Py_buffer *buffer,
Py_ssize_t *offset);
PyObject *LLDwarf_ExecuteLineNumberProgram(Py_buffer *buffer,

View File

@ -254,21 +254,22 @@ static PyObject *parse_compilation_unit_header(PyObject *self, PyObject *args,
static PyObject *parse_die(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *keywords[] = {
"cu", "abbrev_table", "cu_offset", "buffer", "offset", "recurse", NULL,
"cu", "parent", "abbrev_table", "cu_offset", "buffer", "offset",
"recurse", NULL,
};
PyObject *cu, *abbrev_table;
PyObject *cu, *parent, *abbrev_table;
Py_ssize_t cu_offset;
Py_buffer buffer;
Py_ssize_t offset = 0;
int recurse = 0;
PyObject *ret;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O!ny*|np:parse_die",
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!OO!ny*|np:parse_die",
keywords,
(PyObject *)&CompilationUnitHeader_type, &cu,
(PyObject *)&PyDict_Type, &abbrev_table,
&cu_offset, &buffer, &offset,
&recurse))
&parent, (PyObject *)&PyDict_Type,
&abbrev_table, &cu_offset, &buffer,
&offset, &recurse))
return NULL;
if (offset < 0) {
@ -278,7 +279,7 @@ static PyObject *parse_die(PyObject *self, PyObject *args, PyObject *kwds)
}
ret = LLDwarf_ParseDie(&buffer, &offset, (CompilationUnitHeader *)cu,
abbrev_table, cu_offset, recurse, false);
parent, abbrev_table, cu_offset, recurse, false);
if (!ret && !PyErr_Occurred()) {
Py_INCREF(Py_None);
ret = Py_None;
@ -291,21 +292,22 @@ static PyObject *parse_die_siblings(PyObject *self, PyObject *args,
PyObject *kwds)
{
static char *keywords[] = {
"cu", "abbrev_table", "cu_offset", "buffer", "offset", "recurse", NULL,
"cu", "parent", "abbrev_table", "cu_offset", "buffer", "offset",
"recurse", NULL,
};
PyObject *cu, *abbrev_table;
PyObject *cu, *parent, *abbrev_table;
Py_ssize_t cu_offset;
Py_buffer buffer;
Py_ssize_t offset = 0;
int recurse = 0;
PyObject *ret;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O!ny*|np:parse_die_siblings",
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!OO!ny*|np:parse_die_siblings",
keywords,
(PyObject *)&CompilationUnitHeader_type, &cu,
(PyObject *)&PyDict_Type, &abbrev_table,
&cu_offset, &buffer, &offset,
&recurse))
(PyObject *)&CompilationUnitHeader_type,
&cu, &parent, (PyObject *)&PyDict_Type,
&abbrev_table, &cu_offset, &buffer,
&offset, &recurse))
return NULL;
if (offset < 0) {
@ -315,7 +317,7 @@ static PyObject *parse_die_siblings(PyObject *self, PyObject *args,
}
ret = LLDwarf_ParseDieSiblings(&buffer, &offset, (CompilationUnitHeader *)cu,
abbrev_table, cu_offset, recurse);
parent, abbrev_table, cu_offset, recurse);
PyBuffer_Release(&buffer);
return ret;
}

View File

@ -5,101 +5,101 @@ import unittest
class TestDieObject(unittest.TestCase):
def test_find(self):
die = lldwarf.DwarfDie(0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.sdata, -99),))
die = lldwarf.DwarfDie(None, None, 0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.sdata, -99),))
self.assertEqual(die.find(DW_AT.lo_user), (DW_FORM.sdata, -99))
with self.assertRaises(KeyError):
die.find(DW_AT.name)
def test_init_errors(self):
with self.assertRaises(TypeError):
lldwarf.DwarfDie(0, 10, DW_TAG.lo_user, None, None)
lldwarf.DwarfDie(None, None, 0, 10, DW_TAG.lo_user, None, None)
with self.assertRaises(TypeError):
lldwarf.DwarfDie(0, 10, DW_TAG.lo_user, None, (None,))
lldwarf.DwarfDie(None, None, 0, 10, DW_TAG.lo_user, None, (None,))
with self.assertRaises(TypeError):
lldwarf.DwarfDie(0, 10, DW_TAG.lo_user, None, ((None, None, None),))
lldwarf.DwarfDie(None, None, 0, 10, DW_TAG.lo_user, None, ((None, None, None),))
with self.assertRaisesRegex(ValueError, 'triple'):
lldwarf.DwarfDie(0, 10, DW_TAG.lo_user, None, ((1, 2, 3, 4),))
lldwarf.DwarfDie(None, None, 0, 10, DW_TAG.lo_user, None, ((1, 2, 3, 4),))
def test_init_overflow(self):
with self.assertRaisesRegex(OverflowError, 'offset'):
lldwarf.DwarfDie(2**63, 10, DW_TAG.lo_user, None, ())
lldwarf.DwarfDie(None, None, 2**63, 10, DW_TAG.lo_user, None, ())
with self.assertRaisesRegex(OverflowError, 'die_length'):
lldwarf.DwarfDie(0, 2**63, DW_TAG.lo_user, None, ())
lldwarf.DwarfDie(None, None, 0, 2**63, DW_TAG.lo_user, None, ())
with self.assertRaisesRegex(OverflowError, 'tag'):
lldwarf.DwarfDie(0, 10, 2**64, None, ())
lldwarf.DwarfDie(None, None, 0, 10, 2**64, None, ())
with self.assertRaisesRegex(OverflowError, 'name'):
lldwarf.DwarfDie(0, 10, DW_TAG.lo_user, None, ((2**64, DW_FORM.flag_present, True),))
lldwarf.DwarfDie(None, None, 0, 10, DW_TAG.lo_user, None, ((2**64, DW_FORM.flag_present, True),))
with self.assertRaisesRegex(OverflowError, 'form'):
lldwarf.DwarfDie(0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, 2**64, True),))
lldwarf.DwarfDie(None, None, 0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, 2**64, True),))
def test_udata(self):
die = lldwarf.DwarfDie(0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.udata, 2**33),))
die = lldwarf.DwarfDie(None, None, 0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.udata, 2**33),))
self.assertEqual(die[0], (DW_AT.lo_user, DW_FORM.udata, 2**33))
with self.assertRaises(OverflowError):
lldwarf.DwarfDie(0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.udata, 2**64),))
lldwarf.DwarfDie(None, None, 0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.udata, 2**64),))
with self.assertRaises(TypeError):
lldwarf.DwarfDie(0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.udata, 'foo'),))
lldwarf.DwarfDie(None, None, 0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.udata, 'foo'),))
def test_sdata(self):
die = lldwarf.DwarfDie(0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.sdata, -2**33),))
die = lldwarf.DwarfDie(None, None, 0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.sdata, -2**33),))
self.assertEqual(die[0], (DW_AT.lo_user, DW_FORM.sdata, -2**33))
with self.assertRaises(OverflowError):
lldwarf.DwarfDie(0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.sdata, 2**63),))
lldwarf.DwarfDie(None, None, 0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.sdata, 2**63),))
with self.assertRaises(TypeError):
lldwarf.DwarfDie(0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.sdata, 'foo'),))
lldwarf.DwarfDie(None, None, 0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.sdata, 'foo'),))
def test_string(self):
die = lldwarf.DwarfDie(0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.string, (0, 20)),))
die = lldwarf.DwarfDie(None, None, 0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.string, (0, 20)),))
self.assertEqual(die[0], (DW_AT.lo_user, DW_FORM.string, (0, 20)))
with self.assertRaises(TypeError):
lldwarf.DwarfDie(0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.string, None),))
lldwarf.DwarfDie(None, None, 0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.string, None),))
with self.assertRaises(TypeError):
lldwarf.DwarfDie(0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.string, (None, None)),))
lldwarf.DwarfDie(None, None, 0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.string, (None, None)),))
with self.assertRaises(ValueError):
lldwarf.DwarfDie(0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.string, (1, 2, 3)),))
lldwarf.DwarfDie(None, None, 0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.string, (1, 2, 3)),))
with self.assertRaisesRegex(OverflowError, 'offset'):
lldwarf.DwarfDie(0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.string, (2**63, 1)),))
lldwarf.DwarfDie(None, None, 0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.string, (2**63, 1)),))
with self.assertRaisesRegex(OverflowError, 'length'):
lldwarf.DwarfDie(0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.string, (0, 2**63)),))
lldwarf.DwarfDie(None, None, 0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.string, (0, 2**63)),))
def test_data(self):
with self.assertRaises(TypeError):
lldwarf.DwarfDie(0, 0, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.data1, 64),))
lldwarf.DwarfDie(None, None, 0, 0, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.data1, 64),))
with self.assertRaises(ValueError):
lldwarf.DwarfDie(0, 0, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.data1, b'aa'),))
lldwarf.DwarfDie(None, None, 0, 0, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.data1, b'aa'),))
with self.assertRaises(ValueError):
lldwarf.DwarfDie(0, 0, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.data2, b'aaa'),))
lldwarf.DwarfDie(None, None, 0, 0, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.data2, b'aaa'),))
with self.assertRaises(ValueError):
lldwarf.DwarfDie(0, 0, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.data4, b'aaa'),))
lldwarf.DwarfDie(None, None, 0, 0, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.data4, b'aaa'),))
with self.assertRaises(ValueError):
lldwarf.DwarfDie(0, 0, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.data8, b''),))
lldwarf.DwarfDie(None, None, 0, 0, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.data8, b''),))
def test_flag(self):
die = lldwarf.DwarfDie(0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.flag, True),))
die = lldwarf.DwarfDie(None, None, 0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.flag, True),))
self.assertEqual(die[0], (DW_AT.lo_user, DW_FORM.flag, True))
die = lldwarf.DwarfDie(0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.flag, 0),))
die = lldwarf.DwarfDie(None, None, 0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.flag, 0),))
self.assertEqual(die[0], (DW_AT.lo_user, DW_FORM.flag, False))
def test_flag_present(self):
die = lldwarf.DwarfDie(0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.flag_present, True),))
die = lldwarf.DwarfDie(None, None, 0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.flag_present, True),))
self.assertEqual(die[0], (DW_AT.lo_user, DW_FORM.flag_present, True))
die = lldwarf.DwarfDie(0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.flag_present, 0),))
die = lldwarf.DwarfDie(None, None, 0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.flag_present, 0),))
self.assertEqual(die[0], (DW_AT.lo_user, DW_FORM.flag_present, True))
def test_unknown_form(self):
with self.assertRaisesRegex(ValueError, f'unknown form {2**64 - 1}'):
lldwarf.DwarfDie(0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, 2**64 - 1, None),))
lldwarf.DwarfDie(None, None, 0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, 2**64 - 1, None),))
def test_repr(self):
die = lldwarf.DwarfDie(0, 10, DW_TAG.lo_user, None, ())
self.assertEqual(repr(die), f'DwarfDie(cu_offset=0, die_length=10, tag={DW_TAG.lo_user.value}, children=None, attributes=())')
die = lldwarf.DwarfDie(0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.flag, True),))
self.assertEqual(repr(die), f'DwarfDie(cu_offset=0, die_length=10, tag={DW_TAG.lo_user.value}, children=None, attributes=(({DW_AT.lo_user.value}, {DW_FORM.flag.value}, True),))')
die = lldwarf.DwarfDie(None, None, 0, 10, DW_TAG.lo_user, None, ())
self.assertEqual(repr(die), f'DwarfDie(cu=None, parent=None, cu_offset=0, die_length=10, tag={DW_TAG.lo_user.value}, children=None, attributes=())')
die = lldwarf.DwarfDie(None, None, 0, 10, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.flag, True),))
self.assertEqual(repr(die), f'DwarfDie(cu=None, parent=None, cu_offset=0, die_length=10, tag={DW_TAG.lo_user.value}, children=None, attributes=(({DW_AT.lo_user.value}, {DW_FORM.flag.value}, True),))')
def test_recursive_repr(self):
die = lldwarf.DwarfDie(0, 10, DW_TAG.lo_user, None, ())
die = lldwarf.DwarfDie(None, None, 0, 10, DW_TAG.lo_user, None, ())
die.children = [die]
self.assertEqual(repr(die), f'DwarfDie(cu_offset=0, die_length=10, tag={DW_TAG.lo_user.value}, children=[DwarfDie(...)], attributes=())')
self.assertEqual(repr(die), f'DwarfDie(cu=None, parent=None, cu_offset=0, die_length=10, tag={DW_TAG.lo_user.value}, children=[DwarfDie(...)], attributes=())')
header = lldwarf.CompilationUnitHeader(
@ -131,30 +131,30 @@ header64 = lldwarf.CompilationUnitHeader(
class TestParseDie(unittest.TestCase):
def test_negative_offset(self):
with self.assertRaises(ValueError):
lldwarf.parse_die(header, {}, 0, b'', -1)
lldwarf.parse_die(header, None, {}, 0, b'', -1)
with self.assertRaises(ValueError):
lldwarf.parse_die_siblings(header, {}, 0, b'', -1)
lldwarf.parse_die_siblings(header, None, {}, 0, b'', -1)
def test_bad_cu(self):
with self.assertRaises(TypeError):
lldwarf.parse_die(None, {}, 0, b'')
lldwarf.parse_die(None, None, {}, 0, b'')
def test_bad_abbrev_table(self):
with self.assertRaises(TypeError):
lldwarf.parse_die(header, None, 0, b'')
lldwarf.parse_die(header, None, None, 0, b'')
def test_null(self):
self.assertIsNone(lldwarf.parse_die(header, {}, 0, b'\0'))
self.assertIsNone(lldwarf.parse_die(header, None, {}, 0, b'\0'))
def test_unknown_abbreviation(self):
with self.assertRaisesRegex(ValueError, 'unknown abbreviation code'):
lldwarf.parse_die(header, {}, 0, b'\x01\xff')
lldwarf.parse_die(header, None, {}, 0, b'\x01\xff')
def assertDie(self, header, abbrev_table, buf, die_args):
tag, children, attribs = die_args
die = lldwarf.DwarfDie(0, len(buf), tag, children, attribs)
die = lldwarf.DwarfDie(header, None, 0, len(buf), tag, children, attribs)
self.assertEqual(tuple(die), tuple(attribs))
self.assertEqual(lldwarf.parse_die(header, abbrev_table, 0, buf), die)
self.assertEqual(lldwarf.parse_die(header, None, abbrev_table, 0, buf), die)
def test_address(self):
abbrev_table = {
@ -174,7 +174,7 @@ class TestParseDie(unittest.TestCase):
is_64_bit=False,
)
with self.assertRaisesRegex(ValueError, 'unsupported address size'):
lldwarf.parse_die(bogus_header, abbrev_table, 0, b'\x01\xff')
lldwarf.parse_die(bogus_header, None, abbrev_table, 0, b'\x01\xff')
def test_block(self):
abbrev_table = {
@ -196,7 +196,7 @@ class TestParseDie(unittest.TestCase):
self.assertDie(header, abbrev_table, b'\x05\x0f012345678901234',
(DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.exprloc, (2, 15)),)))
with self.assertRaisesRegex(ValueError, 'attribute length too big'):
lldwarf.parse_die(header, abbrev_table, 0, b'\x05\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01')
lldwarf.parse_die(header, None, abbrev_table, 0, b'\x05\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01')
def test_data(self):
abbrev_table = {
@ -231,11 +231,11 @@ class TestParseDie(unittest.TestCase):
(DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.sdata, -1),)))
with self.assertRaises(OverflowError):
lldwarf.DwarfDie(0, 0, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.udata, 2**64),))
lldwarf.DwarfDie(None, None, 0, 0, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.udata, 2**64),))
with self.assertRaises(OverflowError):
lldwarf.DwarfDie(0, 0, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.sdata, 2**63),))
lldwarf.DwarfDie(None, None, 0, 0, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.sdata, 2**63),))
with self.assertRaises(OverflowError):
lldwarf.DwarfDie(0, 0, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.sdata, -2**63 - 1),))
lldwarf.DwarfDie(None, None, 0, 0, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.sdata, -2**63 - 1),))
def test_flag(self):
abbrev_table = {
@ -306,17 +306,19 @@ class TestParseDie(unittest.TestCase):
(DW_AT.lo_user, DW_FORM.string, (5, 4)))))
with self.assertRaisesRegex(ValueError, 'unterminated string'):
lldwarf.parse_die(header, abbrev_table, 0, b'\x01foo')
lldwarf.parse_die(header, None, abbrev_table, 0, b'\x01foo')
@unittest.skip('recursive ==')
def test_recursive(self):
abbrev_table = {
1: lldwarf.AbbrevDecl(DW_TAG.lo_user, True, ((DW_AT.lo_user, DW_FORM.udata),)),
2: lldwarf.AbbrevDecl(DW_TAG.lo_user + 1, False, ((DW_AT.lo_user + 1, DW_FORM.sdata),)),
}
die = lldwarf.parse_die(header, abbrev_table, 0, b'\x01\x01\x02\x02\x00', recurse=True)
die = lldwarf.parse_die(header, None, abbrev_table, 0, b'\x01\x01\x02\x02\x00', recurse=True)
child = lldwarf.DwarfDie(2, 2, DW_TAG.lo_user + 1, None, ((DW_AT.lo_user + 1, DW_FORM.sdata, 2),))
parent = lldwarf.DwarfDie(0, 2, DW_TAG.lo_user, [child], ((DW_AT.lo_user, DW_FORM.udata, 1),))
child = lldwarf.DwarfDie(header, None, 2, 2, DW_TAG.lo_user + 1, None, ((DW_AT.lo_user + 1, DW_FORM.sdata, 2),))
parent = lldwarf.DwarfDie(header, None, 0, 2, DW_TAG.lo_user, [child], ((DW_AT.lo_user, DW_FORM.udata, 1),))
child.parent = parent
self.assertEqual(die, parent)
@ -325,10 +327,10 @@ class TestParseDie(unittest.TestCase):
1: lldwarf.AbbrevDecl(DW_TAG.lo_user, False, ((DW_AT.lo_user, DW_FORM.udata),)),
2: lldwarf.AbbrevDecl(DW_TAG.lo_user + 1, False, ((DW_AT.lo_user + 1, DW_FORM.sdata),)),
}
siblings = lldwarf.parse_die_siblings(header, abbrev_table, 0, b'\x01\x01\x02\x02\x00')
siblings = lldwarf.parse_die_siblings(header, None, abbrev_table, 0, b'\x01\x01\x02\x02\x00')
self.assertEqual(siblings, [
lldwarf.DwarfDie(0, 2, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.udata, 1),)),
lldwarf.DwarfDie(2, 2, DW_TAG.lo_user + 1, None, ((DW_AT.lo_user + 1, DW_FORM.sdata, 2),)),
lldwarf.DwarfDie(header, None, 0, 2, DW_TAG.lo_user, None, ((DW_AT.lo_user, DW_FORM.udata, 1),)),
lldwarf.DwarfDie(header, None, 2, 2, DW_TAG.lo_user + 1, None, ((DW_AT.lo_user + 1, DW_FORM.sdata, 2),)),
])
def test_siblings_skip(self):
@ -336,10 +338,10 @@ class TestParseDie(unittest.TestCase):
1: lldwarf.AbbrevDecl(DW_TAG.lo_user, True, ((DW_AT.sibling, DW_FORM.udata),)),
2: lldwarf.AbbrevDecl(DW_TAG.lo_user + 1, False, ((DW_AT.lo_user + 1, DW_FORM.sdata),)),
}
siblings = lldwarf.parse_die_siblings(header, abbrev_table, 0, b'\x01\x04\x02\x02\x02\x03\x00')
parent_die = lldwarf.DwarfDie(0, 2, DW_TAG.lo_user, None, ((DW_AT.sibling, DW_FORM.udata, 4),))
siblings = lldwarf.parse_die_siblings(header, None, abbrev_table, 0, b'\x01\x04\x02\x02\x02\x03\x00')
parent_die = lldwarf.DwarfDie(header, None, 0, 2, DW_TAG.lo_user, None, ((DW_AT.sibling, DW_FORM.udata, 4),))
del parent_die.children
self.assertEqual(siblings, [
parent_die,
lldwarf.DwarfDie(4, 2, DW_TAG.lo_user + 1, None, ((DW_AT.lo_user + 1, DW_FORM.sdata, 3),)),
lldwarf.DwarfDie(header, None, 4, 2, DW_TAG.lo_user + 1, None, ((DW_AT.lo_user + 1, DW_FORM.sdata, 3),)),
])