Skip to content

Instantly share code, notes, and snippets.

@AltimorTASDK
Last active December 24, 2022 23:57
Show Gist options
  • Save AltimorTASDK/e0df8095f2faf569c1645e3aacc42b69 to your computer and use it in GitHub Desktop.
Save AltimorTASDK/e0df8095f2faf569c1645e3aacc42b69 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from ghidra.app.script import *
from ghidra.app.services import DataTypeManagerService
from ghidra.app.util.bin import BinaryReader, ByteArrayProvider, \
MemoryByteProvider
from ghidra.program.model.address import Address, AddressOutOfBoundsException
from ghidra.program.model.data import CategoryPath, DataTypeConflictHandler, \
DataType, DataTypePath, ArrayDataType, \
EnumDataType, \
StructureDataType, UnionDataType, \
FunctionDefinitionDataType, \
CharDataType, \
SignedByteDataType, ByteDataType, \
ShortDataType, UnsignedShortDataType, \
IntegerDataType, UnsignedIntegerDataType, \
LongDataType, UnsignedLongDataType, \
FloatDataType, DoubleDataType, \
VoidDataType, BooleanDataType, \
PointerDataType, LongLongDataType, \
UnsignedLongLongDataType
from ghidra.program.model.lang import Register
from ghidra.program.model.listing import ParameterImpl, LocalVariableImpl, \
VariableStorage
from ghidra.program.model.listing.Function import FunctionUpdateType
from ghidra.program.model.symbol import SourceType
from ghidra.program.model.util import CodeUnitInsertionException
TAG_padding = 0x0000
TAG_array_type = 0x0001
TAG_class_type = 0x0002
TAG_entry_point = 0x0003
TAG_enumeration_type = 0x0004
TAG_formal_parameter = 0x0005
TAG_global_subroutine = 0x0006
TAG_global_variable = 0x0007
TAG_label = 0x000A
TAG_lexical_block = 0x000B
TAG_local_variable = 0x000C
TAG_member = 0x000D
TAG_pointer_type = 0x000F
TAG_reference_type = 0x0010
TAG_compile_unit = 0x0011
TAG_string_type = 0x0012
TAG_structure_type = 0x0013
TAG_subroutine = 0x0014
TAG_subroutine_type = 0x0015
TAG_typedef = 0x0016
TAG_union_type = 0x0017
TAG_unspecified_parameters = 0x0018
TAG_variant = 0x0019
TAG_common_block = 0x001A
TAG_common_inclusion = 0x001B
TAG_inheritance = 0x001C
TAG_inlined_subroutine = 0x001D
TAG_module = 0x001E
TAG_ptr_to_member_type = 0x001F
TAG_set_type = 0x0020
TAG_subrange_type = 0x0021
TAG_with_stmt = 0x0022
TAG_lo_user = 0x4080
TAG_hi_user = 0xFFFF
TAG_NAMES = {
None: "",
TAG_padding: "TAG_padding",
TAG_array_type: "TAG_array_type",
TAG_class_type: "TAG_class_type",
TAG_entry_point: "TAG_entry_point",
TAG_enumeration_type: "TAG_enumeration_type",
TAG_formal_parameter: "TAG_formal_parameter",
TAG_global_subroutine: "TAG_global_subroutine",
TAG_global_variable: "TAG_global_variable",
TAG_label: "TAG_label",
TAG_lexical_block: "TAG_lexical_block",
TAG_local_variable: "TAG_local_variable",
TAG_member: "TAG_member",
TAG_pointer_type: "TAG_pointer_type",
TAG_reference_type: "TAG_reference_type",
TAG_compile_unit: "TAG_compile_unit",
TAG_string_type: "TAG_string_type",
TAG_structure_type: "TAG_structure_type",
TAG_subroutine: "TAG_subroutine",
TAG_subroutine_type: "TAG_subroutine_type",
TAG_typedef: "TAG_typedef",
TAG_union_type: "TAG_union_type",
TAG_unspecified_parameters: "TAG_unspecified_parameters",
TAG_variant: "TAG_variant",
TAG_common_block: "TAG_common_block",
TAG_common_inclusion: "TAG_common_inclusion",
TAG_inheritance: "TAG_inheritance",
TAG_inlined_subroutine: "TAG_inlined_subroutine",
TAG_module: "TAG_module",
TAG_ptr_to_member_type: "TAG_ptr_to_member_type",
TAG_set_type: "TAG_set_type",
TAG_subrange_type: "TAG_subrange_type",
TAG_with_stmt: "TAG_with_stmt",
TAG_lo_user: "TAG_lo_user",
TAG_hi_user: "TAG_hi_user",
}
FORM_ADDR = 1
FORM_REF = 2
FORM_BLOCK2 = 3
FORM_BLOCK4 = 4
FORM_DATA2 = 5
FORM_DATA4 = 6
FORM_DATA8 = 7
FORM_STRING = 8
AT_sibling = 0x0010
AT_location = 0x0020
AT_name = 0x0030
AT_fund_type = 0x0050
AT_mod_fund_type = 0x0060
AT_user_def_type = 0x0070
AT_mod_u_d_type = 0x0080
AT_ordering = 0x0090
AT_subscr_data = 0x00A0
AT_byte_size = 0x00B0
AT_bit_offset = 0x00C0
AT_bit_size = 0x00D0
AT_element_list = 0x00F0
AT_stmt_list = 0x0100
AT_low_pc = 0x0110
AT_high_pc = 0x0120
AT_language = 0x0130
AT_member = 0x0140
AT_discr = 0x0150
AT_discr_value = 0x0160
AT_string_length = 0x0190
AT_common_reference = 0x01A0
AT_comp_dir = 0x01B0
AT_const_value = 0x01C0
AT_containing_type = 0x01D0
AT_default_value = 0x01E0
AT_friends = 0x01F0
AT_inline = 0x0200
AT_is_optional = 0x0210
AT_lower_bound = 0x0220
AT_program = 0x0230
AT_private = 0x0240
AT_producer = 0x0250
AT_protected = 0x0260
AT_prototyped = 0x0270
AT_public = 0x0280
AT_pure_virtual = 0x0290
AT_return_addr = 0x02A0
AT_specification = 0x02B0
AT_start_scope = 0x02C0
AT_stride_size = 0x02E0
AT_upper_bound = 0x02F0
AT_virtual = 0x0300
AT_lo_user = 0x2000
AT_hi_user = 0x3FF0
AT_symbol_name = 0x2000
ATTRIBUTE_NAMES = {
AT_sibling: "AT_sibling",
AT_location: "AT_location",
AT_name: "AT_name",
AT_fund_type: "AT_fund_type",
AT_mod_fund_type: "AT_mod_fund_type",
AT_user_def_type: "AT_user_def_type",
AT_mod_u_d_type: "AT_mod_u_d_type",
AT_ordering: "AT_ordering",
AT_subscr_data: "AT_subscr_data",
AT_byte_size: "AT_byte_size",
AT_bit_offset: "AT_bit_offset",
AT_bit_size: "AT_bit_size",
AT_element_list: "AT_element_list",
AT_stmt_list: "AT_stmt_list",
AT_low_pc: "AT_low_pc",
AT_high_pc: "AT_high_pc",
AT_language: "AT_language",
AT_member: "AT_member",
AT_discr: "AT_discr",
AT_discr_value: "AT_discr_value",
AT_string_length: "AT_string_length",
AT_common_reference: "AT_common_reference",
AT_comp_dir: "AT_comp_dir",
AT_const_value: "AT_const_value",
AT_containing_type: "AT_containing_type",
AT_default_value: "AT_default_value",
AT_friends: "AT_friends",
AT_inline: "AT_inline",
AT_is_optional: "AT_is_optional",
AT_lower_bound: "AT_lower_bound",
AT_program: "AT_program",
AT_private: "AT_private",
AT_producer: "AT_producer",
AT_protected: "AT_protected",
AT_prototyped: "AT_prototyped",
AT_public: "AT_public",
AT_pure_virtual: "AT_pure_virtual",
AT_return_addr: "AT_return_addr",
AT_specification: "AT_specification",
AT_start_scope: "AT_start_scope",
AT_stride_size: "AT_stride_size",
AT_upper_bound: "AT_upper_bound",
AT_virtual: "AT_virtual",
AT_symbol_name: "AT_symbol_name",
}
OP_REG = 0x01
OP_BASEREG = 0x02
OP_ADDR = 0x03
OP_CONST = 0x04
OP_DEREF2 = 0x05
OP_DEREF = 0x06
OP_DEREF4 = 0x06
OP_ADD = 0x07
OP_lo_user = 0xe0
OP_hi_user = 0xff
REGISTERS = ([currentProgram.getRegister("r%d" % r) for r in range( 0, 32)] +
[currentProgram.getRegister("f%d" % r) for r in range(32, 64)])
FT_char = 0x0001
FT_signed_char = 0x0002
FT_unsigned_char = 0x0003
FT_short = 0x0004
FT_signed_short = 0x0005
FT_unsigned_short = 0x0006
FT_integer = 0x0007
FT_signed_integer = 0x0008
FT_unsigned_integer = 0x0009
FT_long = 0x000a
FT_signed_long = 0x000b
FT_unsigned_long = 0x000c
FT_pointer = 0x000d
FT_float = 0x000e
FT_dbl_prec_float = 0x000f
FT_ext_prec_float = 0x0010
FT_complex = 0x0011
FT_dbl_prec_complex = 0x0012
FT_void = 0x0014
FT_boolean = 0x0015
FT_ext_prec_complex = 0x0016
FT_label = 0x0017
FT_lo_user = 0x8000
FT_hi_user = 0xffff
FT_int64 = 0x8008
FT_uint64 = 0x8208
TYPE_MAP = {
FT_char: CharDataType.dataType,
FT_signed_char: SignedByteDataType.dataType,
FT_unsigned_char: ByteDataType.dataType,
FT_short: ShortDataType.dataType,
FT_signed_short: ShortDataType.dataType,
FT_unsigned_short: UnsignedShortDataType.dataType,
FT_integer: IntegerDataType.dataType,
FT_signed_integer: IntegerDataType.dataType,
FT_unsigned_integer: UnsignedIntegerDataType.dataType,
FT_long: LongDataType.dataType,
FT_signed_long: LongDataType.dataType,
FT_unsigned_long: UnsignedLongDataType.dataType,
FT_float: FloatDataType.dataType,
FT_dbl_prec_float: DoubleDataType.dataType,
FT_void: VoidDataType.dataType,
FT_boolean: BooleanDataType.dataType,
FT_pointer: PointerDataType.dataType,
FT_int64: LongLongDataType.dataType,
FT_uint64: UnsignedLongLongDataType.dataType,
}
MOD_pointer_to = 0x01
MOD_reference_to = 0x02
MOD_const = 0x03
MOD_volatile = 0x04
MOD_lo_user = 0x80
MOD_hi_user = 0xff
FMT_FT_C_C = 0x0
FMT_FT_C_X = 0x1
FMT_FT_X_C = 0x2
FMT_FT_X_X = 0x3
FMT_UT_C_C = 0x4
FMT_UT_C_X = 0x5
FMT_UT_X_C = 0x6
FMT_UT_X_X = 0x7
FMT_ET = 0x8
CONFLICT_HANDLER = DataTypeConflictHandler.REPLACE_HANDLER
dt_manager = currentProgram.dataTypeManager
dt_manager_service = state.tool.getService(
DataTypeManagerService) # type: DataTypeManagerService
builtins = dt_manager_service.builtInDataTypesManager
little_endian = not currentProgram.memory.bigEndian
class DIE:
def __init__(self, parent, offset, size, tag, attributes):
self.offset = offset
self.size = size
self.tag = tag
self.attributes = attributes
self.parent = parent
self.children = []
class Location:
class Register:
def __init__(self, register):
self.register = register
def __str__(self):
return str(self.register)
class Stack:
def __init__(self, offset):
self.offset = offset
def __str__(self):
return "Stack[{:X}]".format(self.offset)
class Offset:
def __init__(self, offset):
self.offset = offset
def __str__(self):
return "+{:X}".format(self.offset)
class Address:
def __init__(self, address):
self.address = address
def __str__(self):
return str(self.address)
def has_data(reader):
return reader.pointerIndex < reader.length()
def byte_reader(data):
return BinaryReader(ByteArrayProvider(data), little_endian)
def get_debug_address(offset):
space = currentProgram.getAddressFactory().getAddressSpace(".debug")
return space.getAddress(offset)
def get_stack_address(offset):
space = currentProgram.getAddressFactory().getStackSpace()
return space.getAddress(offset)
def parse_location_atom(data):
reader = byte_reader(data)
atom = reader.readNextByte()
if atom == OP_REG:
result = Location.Register(REGISTERS[reader.readNextUnsignedInt()])
elif atom == OP_BASEREG:
if reader.readNextUnsignedInt() != 1:
raise ValueError("Only r1 is supported for OP_BASEREG")
if reader.readNextByte() != OP_CONST:
raise ValueError("OP_BASEREG must precede OP_CONST")
result = Location.Stack(reader.readNextInt())
if reader.readNextByte() != OP_ADD:
raise ValueError("OP_BASEREG + OP_CONST must precede OP_ADD")
elif atom == OP_CONST:
result = Location.Offset(reader.readNextInt())
if reader.readNextByte() != OP_ADD:
raise ValueError("OP_CONST must precede OP_ADD")
elif atom == OP_ADDR:
result = Location.Address(toAddr(reader.readNextUnsignedInt()))
else:
raise ValueError("Unhandled location atom type {}".format(atom))
if has_data(reader):
raise ValueError("Unconsumed data in location atom")
return result
def get_fundamental_type(data):
return TYPE_MAP[data]
def parse_type_modifiers(dt, data):
reader = byte_reader(data)
while has_data(reader):
mod = reader.readNextByte()
if mod in [MOD_pointer_to, MOD_reference_to]:
dt = dt_manager.getPointer(dt)
return dt
def parse_array_subscript(data, second_pass):
reader = byte_reader(data)
dimensions = []
while has_data(reader):
fmt = reader.readNextByte()
if fmt == FMT_ET:
dt = read_attribute(reader, second_pass)[1]
elif fmt == FMT_FT_C_C:
get_fundamental_type(reader.readNextUnsignedShort()) # Index type
min_index = reader.readNextInt()
max_index = reader.readNextInt()
dimensions.append(max_index - min_index + 1)
for dimension in reversed(dimensions):
dt = ArrayDataType(dt.clone(dt_manager), dimension, -1, dt_manager)
return dt
def parse_enum_elements(data):
reader = byte_reader(data)
result = {}
while has_data(reader):
value = reader.readNextInt()
name = reader.readNextNullTerminatedAsciiString()
result[name] = value
return result
user_type_cache = {}
def get_user_type(address, second_pass):
if not second_pass:
return DataType.DEFAULT
return user_type_cache[address.offset]
def parse_user_type(data, second_pass):
address = get_debug_address(byte_reader(data).readNextUnsignedInt())
return get_user_type(address, second_pass)
def read_attribute(reader, second_pass):
offset = reader.pointerIndex
pair = reader.readNextUnsignedShort()
attribute, form = (pair & ~0xF, pair & 0xF)
if form == FORM_ADDR:
data = toAddr(reader.readNextUnsignedInt())
elif form == FORM_REF:
data = get_debug_address(reader.readNextUnsignedInt())
elif form == FORM_BLOCK2:
data = reader.readNextByteArray(reader.readNextUnsignedShort())
elif form == FORM_BLOCK4:
data = reader.readNextByteArray(reader.readNextUnsignedInt())
elif form == FORM_DATA2:
data = reader.readNextUnsignedShort()
elif form == FORM_DATA4:
data = reader.readNextUnsignedInt()
elif form == FORM_DATA8:
data = reader.readNextLong()
elif form == FORM_STRING:
data = reader.readNextNullTerminatedAsciiString()
else:
raise ValueError("Bad attribute form at {:08X}".format(offset))
if attribute == AT_location:
data = parse_location_atom(data)
elif attribute == AT_fund_type:
data = get_fundamental_type(data)
elif attribute == AT_mod_fund_type:
data = parse_type_modifiers(get_fundamental_type(data[-1]), data[:-1])
elif attribute in [AT_user_def_type, AT_containing_type, AT_member]:
data = get_user_type(data, second_pass)
elif attribute == AT_mod_u_d_type:
dt = parse_user_type(data[-4:], second_pass)
data = parse_type_modifiers(dt, data[:-4])
elif attribute == AT_subscr_data:
data = parse_array_subscript(data, second_pass)
elif attribute == AT_element_list:
data = parse_enum_elements(data)
elif attribute == AT_ordering:
raise NotImplementedError
elif attribute == AT_stride_size:
raise NotImplementedError
return (attribute, data)
def is_reader_index_in_range(reader, end):
try:
return reader.pointerIndex < end.offset
except AddressOutOfBoundsException:
return False
def get_die_name(die):
if AT_name in die.attributes:
return die.attributes[AT_name].replace("\\", "/")
else:
return "${:08X}".format(die.offset)
def get_die_path(die):
path = []
while die is not None:
path = get_die_name(die).split("/") + path
die = die.parent
name = path.pop()
return CategoryPath(CategoryPath.ROOT, ["DWARF"] + path), name
def is_die_type(die):
return die.tag in [TAG_enumeration_type, TAG_array_type,
TAG_structure_type, TAG_class_type, TAG_union_type,
TAG_subroutine_type, TAG_ptr_to_member_type]
def get_referenced_type(die):
for at in [AT_fund_type, AT_mod_fund_type,
AT_user_def_type, AT_mod_u_d_type]:
if at in die.attributes:
return die.attributes[at]
return VoidDataType.dataType
def create_die_type(die):
path, typename = get_die_path(die)
if die.tag == TAG_enumeration_type:
size = die.attributes[AT_byte_size]
dt = EnumDataType(path, typename, size, dt_manager)
for name, value in die.attributes[AT_element_list].items():
dt.add(name, value)
dt_manager.addDataType(dt, CONFLICT_HANDLER)
elif die.tag == TAG_array_type:
dt = die.attributes[AT_subscr_data]
if AT_name in die.attributes:
dt = dt.copy(dt_manager)
dt.setNameAndCategory(path, typename)
dt_manager.addDataType(dt, CONFLICT_HANDLER)
elif die.tag in [TAG_structure_type, TAG_class_type]:
size = die.attributes[AT_byte_size]
dt = StructureDataType(path, typename, size, dt_manager)
dt_manager.addDataType(dt, CONFLICT_HANDLER)
elif die.tag == TAG_union_type:
dt = UnionDataType(path, typename, dt_manager)
dt_manager.addDataType(dt, CONFLICT_HANDLER)
elif die.tag == TAG_subroutine_type:
dt = FunctionDefinitionDataType(path, typename, dt_manager)
dt_manager.addDataType(dt, CONFLICT_HANDLER)
elif die.tag == TAG_ptr_to_member_type:
dt = PointerDataType(DataType.DEFAULT)
else:
raise NotImplementedError
user_type_cache[die.offset] = dt
return dt
def add_struct_member(dt, member):
location = member.attributes[AT_location]
if not isinstance(location, Location.Offset):
raise ValueError
if AT_bit_offset in member.attributes:
return
member_dt = get_referenced_type(member)
member_name = get_die_name(member)
overlapping = dt.getComponentContaining(location.offset)
if location.offset >= dt.length:
dt.insertAtOffset(location.offset, member_dt, -1, member_name, None)
elif overlapping is None or overlapping.dataType is DataType.DEFAULT:
dt.replaceAtOffset(location.offset, member_dt, -1, member_name, None)
else:
other_dt = overlapping.dataType
union_offset = min(location.offset, overlapping.offset)
union_name = dt.name + "$u{:08X}".format(union_offset)
if isinstance(other_dt, UnionDataType) and other_dt.name == union_name:
# There's already an anonymous union to add to
union = overlapping.dataType
ordinal = union.getNumDefinedComponents()
if location.offset == overlapping.offset:
union.insert(ordinal, member_dt, -1, member_name, None)
elif location.offset >= overlapping.offset:
union = UnionDataType(dt.categoryPath, union_name, dt_manager)
union.insert(0, other_dt, -1, overlapping.fieldName, None)
if location.offset == overlapping.offset:
union.insert(1, member_dt, -1, member_name, None)
name = "$u{:08X}".format(union_offset)
dt.replaceAtOffset(union_offset, union, -1, name, None)
if location.offset > union_offset:
# Create a struct to pad with
offset = location.offset - overlapping.offset
size = member_dt.length + offset
struct_name = union_name + "$" + member_name
struct = StructureDataType(dt.categoryPath, struct_name, size,
dt_manager)
struct.replaceAtOffset(offset, member_dt, -1, "$v", None)
dt_manager.addDataType(struct, CONFLICT_HANDLER)
ordinal = union.getNumDefinedComponents()
union.insert(ordinal, struct, -1, member_name, None)
dt_manager.addDataType(union, CONFLICT_HANDLER)
dt_manager.addDataType(dt, CONFLICT_HANDLER)
def define_die_type(die):
dt = user_type_cache[die.offset]
if die.tag == TAG_subroutine_type:
dt.returnType = get_referenced_type(die)
elif die.tag in [TAG_structure_type, TAG_class_type]:
members = [m for m in die.children if m.tag == TAG_member]
for member in sorted(members,
key=lambda m: m.attributes[AT_location].offset):
add_struct_member(dt, member)
elif die.tag == TAG_ptr_to_member_type:
target = get_referenced_type(die)
dt.dataTypeReplaced(DataType.DEFAULT, target)
if AT_name in die.attributes:
outer = die.attributes[AT_containing_type]
dt.name = target.name + "$" + outer.name + "$" + dt.name
dt_manager.addDataType(dt, CONFLICT_HANDLER)
def is_die_function(die):
return die.tag in [TAG_global_subroutine, TAG_subroutine]
def define_die_function(die):
program = currentProgram
address = die.attributes[AT_low_pc]
removeFunctionAt(address)
function_name = die.attributes[AT_name]
if AT_member in die.attributes:
outer = die.attributes[AT_member]
function_name = "{}::{}".format(outer.name, function_name)
function = createFunction(address, function_name)
if function is None:
return
function.setReturnType(get_referenced_type(die), SourceType.USER_DEFINED)
parameters = []
parameter_names = []
for child in die.children:
child_name = get_die_name(child)
child_dt = get_referenced_type(child)
if child.tag == TAG_formal_parameter:
for variable in function.allVariables:
if variable.name == child_name:
function.removeVariable(variable)
parameters.append(ParameterImpl(child_name, child_dt, program))
parameter_names.append(child_name)
elif child.tag == TAG_local_variable:
location = child.attributes[AT_location]
if isinstance(location, Location.Register):
if location.register is None:
continue
variable_address = location.register.address
elif isinstance(location, Location.Stack):
variable_address = get_stack_address(location.offset)
else:
raise NotImplementedError
if child_name in parameter_names:
continue
variable = LocalVariableImpl(child_name, 0, child_dt,
variable_address, program)
for other in function.localVariables:
if other.name == child_name:
function.removeVariable(other)
function.addLocalVariable(variable, SourceType.USER_DEFINED)
TYPE = FunctionUpdateType.DYNAMIC_STORAGE_FORMAL_PARAMS
function.replaceParameters(parameters, TYPE, True, SourceType.USER_DEFINED)
def handle_globals(die):
for child in die.children:
if child.tag not in [TAG_global_variable, TAG_local_variable]:
continue
location = child.attributes[AT_location]
if not isinstance(location, Location.Address):
raise NotImplementedError
dt = get_referenced_type(child)
for offset in range(dt.length):
old_data = getDataContaining(location.address.add(offset))
if old_data is not None:
removeData(old_data)
try:
createData(location.address, dt)
createLabel(location.address, get_die_name(child), True)
except CodeUnitInsertionException:
pass
def read_die(reader, second_pass, parent=None):
offset = reader.pointerIndex
size = reader.readNextUnsignedInt()
if size == 4:
return DIE(parent, offset, size, None, {})
tag = reader.readNextUnsignedShort()
if tag == TAG_padding:
reader.pointerIndex = offset + size
return DIE(parent, offset, size, tag, {})
attributes = {}
while reader.pointerIndex < offset + size:
key, value = read_attribute(reader, second_pass)
attributes[key] = value
if reader.pointerIndex != offset + size:
raise IndexError
die = DIE(parent, offset, size, tag, attributes)
while is_reader_index_in_range(reader, attributes[AT_sibling]):
die.children.append(read_die(reader, second_pass, die))
if second_pass:
if is_die_type(die):
define_die_type(die)
elif is_die_function(die):
define_die_function(die)
elif die.tag == TAG_compile_unit:
handle_globals(die)
else:
if is_die_type(die):
create_die_type(die)
return die
def print_die_tree(die, indent=0):
prefix = " " * indent
path = DataTypePath(*get_die_path(die))
print("{}{:04X}: <{}> {} [{}]"
.format(prefix, die.offset, die.size, TAG_NAMES[die.tag], path))
for at, value in die.attributes.items():
if isinstance(value, int):
value = "{:X}".format(value)
if at in ATTRIBUTE_NAMES:
print("{} {}({})".format(prefix, ATTRIBUTE_NAMES[at], value))
else:
print("{} AT_{:04X}({})".format(prefix, at, value))
println()
for child in die.children:
print_die_tree(child, indent + 1)
def main():
section = currentProgram.memory.getBlock(".debug")
provider = MemoryByteProvider(currentProgram.memory, section.start)
reader = BinaryReader(provider, little_endian)
while has_data(reader):
read_die(reader, False)
reader.pointerIndex = 0
while has_data(reader):
#print_die_tree(read_die(reader, True))
read_die(reader, True)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment