Last active
December 24, 2022 23:57
-
-
Save AltimorTASDK/e0df8095f2faf569c1645e3aacc42b69 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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