📄 dwarfutils.pas
字号:
TDwarfSubroutine = class
name: string;
node: PDwarfNode;
lowPC, highPC: uint32;
fileIndex, line, column: integer;
end;
TDwarfVariable = class
name: string;
node: PDwarfNode;
fileIndex, line, column: integer;
startScope: uint32;
loc: PDwarfAttribute;
typ: PDwarfAttribute;
end;
TDwarfType = class
name: string;
node: PDwarfNode;
fileIndex, line, column: integer;
isBasic: boolean; // Whether or not its a basic type (if true, encoding is valid)
encoding: integer; // DW_ATE_*
size: integer; // size (in bytes)
bitSize, bitOffset: integer; // for sub-byte variables (I'll probably ignore it)
end;
//////////////////////////////////////////////////////////////////////
var
dwarf: TDwarfFile;
function ProcessDWARF(elf: TELFFile; dir: string): TDwarfFile;
procedure ProcessNode(cunit: TCompilationUnit; node: PDwarfNode);
function DoLineProgram(building: boolean; cunit: TCompilationUnit; target: uint32; var hit: TLineHit): boolean;
function FindLineInP(target: uint32; var hit: TLineHit): boolean;
procedure WalkVariables(var res: TStringList);
function ExamineVariable(name: string): integer;
function LocationSM(block: TDwarfBlock; var inRegister, notOptimized: boolean): uint32;
function FindAttribute(node: PDwarfNode; name: uint32): PDwarfAttribute;
//////////////////////////////////////////////////////////////////////
implementation ///////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
uses
observerCSource;
//////////////////////////////////////////////////////////////////////
const
tagStrings: array[0..DW_TAG_volatile_type] of string = (
'DW_TAG_null',
'DW_TAG_array_type',
'DW_TAG_class_type',
'DW_TAG_entry_point',
'DW_TAG_enumeration_type',
'DW_TAG_formal_parameter',
'',
'',
'DW_TAG_imported_declaration',
'',
'DW_TAG_label',
'DW_TAG_lexical_block',
'',
'DW_TAG_member',
'',
'DW_TAG_pointer_type',
'DW_TAG_reference_type',
'DW_TAG_compile_unit',
'DW_TAG_string_type',
'DW_TAG_structure_type',
'',
'DW_TAG_subroutine_type',
'DW_TAG_typedef',
'DW_TAG_union_type',
'DW_TAG_unspecified_parameters',
'DW_TAG_variant',
'DW_TAG_common_block',
'DW_TAG_common_inclusion',
'DW_TAG_inheritance',
'DW_TAG_inlined_subroutine',
'DW_TAG_module',
'DW_TAG_ptr_to_member_type',
'DW_TAG_set_type',
'DW_TAG_subrange_type',
'DW_TAG_with_stmt',
'DW_TAG_access_declaration',
'DW_TAG_base_type',
'DW_TAG_catch_block',
'DW_TAG_const_type',
'DW_TAG_constant',
'DW_TAG_enumerator',
'DW_TAG_file_type',
'DW_TAG_friend',
'DW_TAG_namelist',
'DW_TAG_namelist_item',
'DW_TAG_packed_type',
'DW_TAG_subprogram',
'DW_TAG_template_type_param',
'DW_TAG_template_value_param',
'DW_TAG_thrown_type',
'DW_TAG_try_block',
'DW_TAG_variant_part',
'DW_TAG_variable',
'DW_TAG_volatile_type'
);
attribStrings: array[0..DW_AT_vtable_elem_location] of string = (
'',
'DW_AT_sibling',
'DW_AT_location',
'DW_AT_name',
'',
'',
'',
'',
'',
'DW_AT_ordering',
'',
'DW_AT_byte_size',
'DW_AT_bit_offset',
'DW_AT_bit_size',
'',
'',
'DW_AT_stmt_list',
'DW_AT_low_pc',
'DW_AT_high_pc',
'DW_AT_language',
'',
'DW_AT_discr',
'DW_AT_discr_value',
'DW_AT_visibility',
'DW_AT_import',
'DW_AT_string_length',
'DW_AT_common_reference',
'DW_AT_comp_dir',
'DW_AT_const_value',
'DW_AT_containing_type',
'DW_AT_default_value',
'',
'DW_AT_inline',
'DW_AT_is_optional',
'DW_AT_lower_bound',
'',
'',
'DW_AT_producer',
'',
'DW_AT_prototyped',
'',
'',
'DW_AT_return_addr',
'',
'DW_AT_start_scope',
'',
'DW_AT_stride_size',
'DW_AT_upper_bound',
'',
'DW_AT_abstract_origin',
'DW_AT_accessibility',
'DW_AT_address_class',
'DW_AT_artificial',
'DW_AT_base_types',
'DW_AT_calling_convention',
'DW_AT_count',
'DW_AT_data_member_location',
'DW_AT_decl_column',
'DW_AT_decl_file',
'DW_AT_decl_line',
'DW_AT_declaration',
'DW_AT_discr_list',
'DW_AT_encoding',
'DW_AT_external',
'DW_AT_frame_base',
'DW_AT_friend',
'DW_AT_identifier_case',
'DW_AT_macro_info',
'DW_AT_namelist_item',
'DW_AT_priority',
'DW_AT_segment',
'DW_AT_specification',
'DW_AT_static_link',
'DW_AT_type',
'DW_AT_use_location',
'DW_AT_variable_parameter',
'DW_AT_virtuality',
'DW_AT_vtable_elem_location'
);
formStrings: array[0..DW_FORM_indirect] of string = (
'Unknown form 0',
'DW_FORM_addr',
'Unknown form 2',
'DW_FORM_block2',
'DW_FORM_block4',
'DW_FORM_data2',
'DW_FORM_data4',
'DW_FORM_data8',
'DW_FORM_string',
'DW_FORM_block',
'DW_FORM_block1',
'DW_FORM_data1',
'DW_FORM_flag',
'DW_FORM_sdata',
'DW_FORM_strp',
'DW_FORM_udata',
'DW_FORM_ref_addr',
'DW_FORM_ref1',
'DW_FORM_ref2',
'DW_FORM_ref4',
'DW_FORM_ref8',
'DW_FORM_ref_udata',
'DW_FORM_indirect');
langStrings: array[0..DW_LANG_Modula2] of string = (
'',
'DW_LANG_C89',
'DW_LANG_C',
'DW_LANG_Ada83',
'DW_LANG_C_plus_plus',
'DW_LANG_Cobol74',
'DW_LANG_Cobol85',
'DW_LANG_Fortran77',
'DW_LANG_Fortran90',
'DW_LANG_Pascal83',
'DW_LANG_Modula2');
//////////////////////////////////////////////////////////////////////
function DwarfFormToString(form: uint32): string;
begin
if form <= DW_FORM_indirect then
Result := formStrings[form]
else
Result := Format('<unk. form $%x>', [form]);
end;
//////////////////////////////////////////////////////////////////////
function DwarfAttributeToString(attrib: uint32): string;
begin
if attrib <= DW_AT_vtable_elem_location then
Result := attribStrings[attrib]
else begin
if attrib = $2000 then
Result := 'DW_AT_proc_body'
else if attrib = $2001 then
Result := 'DW_AT_save_offset'
else if attrib = $2002 then
Result := 'DW_AT_codeseg_base'
else if attrib = $2007 then
Result := 'DW_AT_MIPS_linkage_name'
else
Result := Format('<unk. attribute $%x>', [attrib]);
end;
end;
//////////////////////////////////////////////////////////////////////
function DwarfTagToString(tag: uint32): string;
begin
if tag <= DW_TAG_volatile_type then
Result := tagStrings[tag]
else
Result := Format('<unk. tag $%x>', [tag]);
end;
//////////////////////////////////////////////////////////////////////
function DwarfLangToString(lang: uint32): string;
begin
if lang <= DW_LANG_Modula2 then
Result := langStrings[lang]
else
Result := Format('<unk. lang $%x>', [lang]);
end;
//////////////////////////////////////////////////////////////////////
var
debugAbbrev, debugAranges, debugFrame, debugInfo, debugLine,
debugLoc, debugMacInfo, debugPubNames, debugStr: TElfSection;
//////////////////////////////////////////////////////////////////////
function ReadTSRegister(index: integer): integer;
begin
Result := vmGetRegister(index);
end;
//////////////////////////////////////////////////////////////////////
function ReadTSAddress(addr: uint32): uint32;
begin
Result := vmReadWord(addr);
end;
//////////////////////////////////////////////////////////////////////
function ReadTSUint8(addr: uint32): uint32;
begin
Result := vmReadByte(addr);
end;
//////////////////////////////////////////////////////////////////////
procedure ReadAttribute(attrib: PDwarfAttribute);
var
temp: uint32;
begin
with debugInfo do begin
case attrib^.format of
DW_FORM_addr: attrib^.address := ReadAddress;
DW_FORM_block2: begin
attrib^.block.size := ReadUint16;
attrib^.block.data := dataPointer;
SeekRelAddress(attrib^.block.size);
end;
DW_FORM_block4: begin
attrib^.block.size := ReadUint32;
attrib^.block.data := dataPointer;
SeekRelAddress(attrib^.block.size);
end;
DW_FORM_data2: attrib^.data := ReadUint16;
DW_FORM_data4: attrib^.data := ReadUint32;
DW_FORM_data8: attrib^.data := ReadUint64;
DW_FORM_string: attrib^.st := ReadString;
DW_FORM_block: begin
attrib^.block.size := ReadLEB128;
attrib^.block.data := dataPointer;
SeekRelAddress(attrib^.block.size);
end;
DW_FORM_block1: begin
attrib^.block.size := ReadUint8;
attrib^.block.data := dataPointer;
SeekRelAddress(attrib^.block.size);
end;
DW_FORM_data1: attrib^.data := ReadUint8;
DW_FORM_flag: attrib^.flag := ReadUint8 <> 0;
DW_FORM_sdata: attrib^.data := ReadSLEB128;
DW_FORM_strp: begin
temp := ReadUint32;
if debugStr <> nil then
attrib^.st := pointer(uint32(debugStr.data) + temp);// todo: should be a readstring?
end;
DW_FORM_udata: attrib^.data := ReadLEB128;
DW_FORM_ref_addr: attrib^.offset := ReadAddress;
DW_FORM_ref1: attrib^.offset := ReadUint8;
DW_FORM_ref2: attrib^.offset := ReadUint16;
DW_FORM_ref4: attrib^.offset := ReadUint32;
DW_FORM_ref8: attrib^.offset := ReadUint64;
DW_FORM_ref_udata: attrib^.offset := ReadLEB128;
DW_FORM_indirect: begin
attrib^.format := ReadLEB128;
if attrib^.format <> DW_FORM_indirect then
ReadAttribute(attrib)
else
logWriteLn('dwarfUtils.ReadAttribute: Error, DW_FORM_indirect loop');
end;
else
logWriteLn('dwarfUtils.ReadAttribute: Error, unknown form ' + IntToStr(attrib^.format));
end;
end;
end;
//////////////////////////////////////////////////////////////////////
// returns true if found, false otherwise
function FindAbbreviation(cunit: TCompilationUnit; abbreviation: uint32): boolean;
var
code, a, b: uint32;
begin
debugAbbrev.Seek(cunit.abbrevOffset);
repeat
// Read the abbreviation code (abbrev = 0 denotes the end entry)
code := debugAbbrev.ReadLEB128;
if code = abbreviation then begin
Result := true;
Exit;
end;
// Eat the tag and children flag
debugAbbrev.ReadLEB128;
debugAbbrev.ReadUint8;
// Skip over the attributes
repeat
a := debugAbbrev.ReadLEB128;
b := debugAbbrev.ReadLEB128;
until (a = 0) and (b = 0);
until code = 0;
Result := false;
end;
//////////////////////////////////////////////////////////////////////
function ReadNode(cunit: TCompilationUnit): PDwarfNode;
var
lastAttrib: ^PDwarfAttribute;
attrib: PDwarfAttribute;
abbrev: uint32;
lnode, node: PDwarfNode;
name, format: uint32;
begin
Result := nil;
node := nil;
// Read the abbreviation from the .debug_info section
repeat
// Check the abbreviation code (0 is a reserved code)
abbrev := debugInfo.ReadLEB128;
if abbrev = 0 then Break;
// Create a new sibling node
lnode := node;
GetMem(node, SizeOf(TDwarfNode));
if Assigned(lnode) then lnode^.next := node else Result := node;
// Initialize the new node
node^.abbreviation := abbrev;
node^.next := nil;
node^.attribs := nil;
node^.kids := nil;
node^.tag := DW_TAG_friend;
// Read the attribute names and formats from the .debug_abbrev section
if FindAbbreviation(cunit, node^.abbreviation) then begin
node^.tag := debugAbbrev.ReadLEB128;
node^.hasChildren := debugAbbrev.ReadUint8 = DW_CHILDREN_yes;
lastAttrib := @(node^.attribs);
repeat
name := debugAbbrev.ReadLEB128;
format := debugAbbrev.ReadLEB128;
if (name = 0) and (format = 0) then begin
lastAttrib^ := nil;
Break;
end else begin
// Create a new attribute
GetMem(attrib, SizeOf(TDwarfAttribute));
attrib^.name := name;
attrib^.format := format;
attrib^.next := nil;
ReadAttribute(attrib);
lastAttrib^ := attrib;
lastAttrib := @(attrib^.next);
end;
until false;
// Read the attribute data from the .debug_info section
{ attrib := node^.attribs;
while attrib <> nil do begin
ReadAttribute(attrib);
attrib := attrib^.next;
end;}
// Recursively get all the children
if node^.hasChildren then node^.kids := ReadNode(cunit);
end else
logWriteLn('dwarfUtils.ReadNode: Error, abbreviation ' + IntToStr(node^.abbreviation) + ' not found in .debug_abbrev contribution for current compilation unit');
until false;
end;
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
function LocationSM(block: TDwarfBlock; var inRegister, notOptimized: boolean): uint32;
var
stackIndex: integer;
stack: array[0..63] of uint32;
procedure Push(addr: uint32);
begin
stackIndex := (stackIndex-1) and 63;
stack[stackIndex] := addr;
end;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -