From e6a58f533abda9456a8bdbe704d23179224e55dd Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Sun, 27 Aug 2017 11:35:38 -0700 Subject: [PATCH] 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. --- drgn/cli/dump.py | 10 +-- drgn/dwarf/file.py | 16 ++--- drgn/dwarf/program.py | 8 +-- lldwarf/die.c | 62 +++++++++++++------ lldwarf/lldwarf.h | 14 +++-- lldwarf/module.c | 32 +++++----- tests/lldwarf/test_die.py | 124 +++++++++++++++++++------------------- 7 files changed, 147 insertions(+), 119 deletions(-) diff --git a/drgn/cli/dump.py b/drgn/cli/dump.py index 2b5b2547..fdf07cbe 100644 --- a/drgn/cli/dump.py +++ b/drgn/cli/dump.py @@ -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) diff --git a/drgn/dwarf/file.py b/drgn/dwarf/file.py index 5448e86a..06b99d2c 100644 --- a/drgn/dwarf/file.py +++ b/drgn/dwarf/file.py @@ -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: diff --git a/drgn/dwarf/program.py b/drgn/dwarf/program.py index d6c462a3..72dd2d88 100644 --- a/drgn/dwarf/program.py +++ b/drgn/dwarf/program.py @@ -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}' diff --git a/lldwarf/die.c b/lldwarf/die.c index de3675fd..6fb2d180 100644 --- a/lldwarf/die.c +++ b/lldwarf/die.c @@ -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 = { diff --git a/lldwarf/lldwarf.h b/lldwarf/lldwarf.h index 5a611c9c..7cc99c40 100644 --- a/lldwarf/lldwarf.h +++ b/lldwarf/lldwarf.h @@ -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, diff --git a/lldwarf/module.c b/lldwarf/module.c index ace03951..0f2aff45 100644 --- a/lldwarf/module.c +++ b/lldwarf/module.c @@ -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; } diff --git a/tests/lldwarf/test_die.py b/tests/lldwarf/test_die.py index b4c35ff5..cc027b34 100644 --- a/tests/lldwarf/test_die.py +++ b/tests/lldwarf/test_die.py @@ -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),)), ])