📄 dwarfutils.pas
字号:
logWriteLn('.');
end;}
end;
//////////////////////////////////////////////////////////////////////
function FindAttribute(node: PDwarfNode; name: uint32): PDwarfAttribute;
var
attrib: PDwarfAttribute;
begin
Result := nil;
attrib := node^.attribs;
while attrib <> nil do begin
if attrib^.name = name then begin
Result := attrib;
Exit;
end;
attrib := attrib^.next;
end;
end;
//////////////////////////////////////////////////////////////////////
procedure ReadSubroutine(cunit: TCompilationUnit; node: PDwarfNode);
var
attrib: PDwarfAttribute;
sub: TDwarfSubroutine;
begin
sub := TDwarfSubroutine.Create;
sub.node := node;
// Read the name
attrib := FindAttribute(node, DW_AT_name);
if attrib <> nil then sub.name := attrib^.st else sub.name := '';
// Read the PC ranges
attrib := FindAttribute(node, DW_AT_low_pc);
if attrib = nil then sub.lowPC := $FFFFFFFF else sub.lowPC := attrib^.address;
attrib := FindAttribute(node, DW_AT_high_pc);
if attrib = nil then sub.highPC := 0 else sub.highPC := attrib^.address;
// Read the possible declaration position in the source code
attrib := FindAttribute(node, DW_AT_decl_file);
if attrib = nil then sub.fileIndex := 0 else sub.fileIndex := attrib^.data;
attrib := FindAttribute(node, DW_AT_decl_line);
if attrib = nil then sub.line := 0 else sub.line := attrib^.data;
attrib := FindAttribute(node, DW_AT_decl_column);
if attrib = nil then sub.column := 0 else sub.column := attrib^.data;
cunit.functions.AddObject(sub.name, sub);
logWriteLn(Format('Function "%s" compiles to %8.8x..%8.8x, defined in file %d at (%d: %d)', [sub.name, sub.lowPC, sub.highPC, sub.fileIndex, sub.line, sub.column]));
end;
//////////////////////////////////////////////////////////////////////
procedure ReadVariable(cunit: TCompilationUnit; node: PDwarfNode);
var
attrib: PDwarfAttribute;
v: TDwarfVariable;
begin
v := TDwarfVariable.Create;
v.node := node;
// Read the name
attrib := FindAttribute(node, DW_AT_name);
if attrib <> nil then v.name := attrib^.st else v.name := '';
// if its defining, it'll have a DW_AT_location, otherwise, it
// will have a DW_AT_declaration
// however, if its missing the DW_AT_declaration, and the
// DW_AT_location is also missing or if it describes a null entry
// then the variable was in the source code, but not in the compiled
// program, i.e. unused variables compiled out
// C++ union/struct/class defining declarations will have a
// DW_AT_specification attribute and will not duplicate any data
// contained in the DW_AT_specs pointed to
// Read the possible declaration position in the source code
attrib := FindAttribute(node, DW_AT_decl_file);
if attrib = nil then v.fileIndex := 0 else v.fileIndex := attrib^.data;
attrib := FindAttribute(node, DW_AT_decl_line);
if attrib = nil then v.line := 0 else v.line := attrib^.data;
attrib := FindAttribute(node, DW_AT_decl_column);
if attrib = nil then v.column := 0 else v.column := attrib^.data;
attrib := FindAttribute(node, DW_AT_location);
if attrib <> nil then v.loc := attrib;
attrib := FindAttribute(node, DW_AT_type);
if attrib <> nil then v.typ := attrib;
attrib := FindAttribute(v.node, DW_AT_start_scope);
if attrib <> nil then v.startScope := attrib.address else v.startScope := 0;
cunit.variables.AddObject(v.name, v);
logWriteLn(Format('Variable "%s", defined in file %d at (%d: %d)', [v.name, v.fileIndex, v.line, v.column]));
end;
//////////////////////////////////////////////////////////////////////
function dwarfLookupVal(cmd: string): string;
var
cunit: TCompilationUnit;
i: integer;
v: TDwarfVariable;
inReg, notOptimized: boolean;
addr: uint32;
begin
logwriteln('fixme in dwarfLookupVal');
Result := cmd + ' is not accessable at this location or the expression is too complex';
if Assigned(dwarf) then begin
// Find the current compilation unit
cunit := Dwarf.FindContainingUnit(vmCurrentPC);
if cunit <> nil then begin
i := cunit.variables.IndexOf(cmd);
if i > -1 then begin
v := TDwarfVariable(cunit.variables.Objects[i]);
// Result := Format('defined in %d at (%d: %d)', [v.fileIndex, v.line, v.column]);
if Assigned(v.loc) and (v.startScope <= vmCurrentPC) then begin
addr := LocationSM(v.loc.block, inReg, notOptimized);
if inReg then begin
addr := addr and 15;
Result := Format('%s is %8.8x, in r%d', [cmd, vmGetRegister(addr), addr]);
end else begin
Result := Format('%s is %8.8x, at u32[$%8.8x]', [cmd, vmReadWord(addr), addr]);
end;
end;
end;
end;
end;
logWriteLn(Result);
end;
//////////////////////////////////////////////////////////////////////
procedure ReadType(cunit: TCompilationUnit; node: PDwarfNode);
var
attrib: PDwarfAttribute;
v: TDwarfType;
begin
v := TDwarfType.Create;
v.node := node;
// Read the name
attrib := FindAttribute(node, DW_AT_name);
if attrib <> nil then v.name := attrib^.st else v.name := '';
// Read the possible declaration position in the source code
attrib := FindAttribute(node, DW_AT_decl_file);
if attrib = nil then v.fileIndex := 0 else v.fileIndex := attrib^.data;
attrib := FindAttribute(node, DW_AT_decl_line);
if attrib = nil then v.line := 0 else v.line := attrib^.data;
attrib := FindAttribute(node, DW_AT_decl_column);
if attrib = nil then v.column := 0 else v.column := attrib^.data;
cunit.types.AddObject(v.name, v);
logWriteLn(Format('Type "%s", defined in file %d at (%d: %d)', [v.name, v.fileIndex, v.line, v.column]));
end;
//////////////////////////////////////////////////////////////////////
procedure ProcessNode(cunit: TCompilationUnit; node: PDwarfNode);
var
attrib: PDwarfAttribute;
hitless: TLineHit;
begin
while node <> nil do begin
case node^.tag of
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: begin
attrib := FindAttribute(node, DW_AT_language);
if attrib = nil then cunit.lang := DW_LANG_C89 else cunit.lang := attrib^.data;
// if (cunit.lang <> DW_LANG_C89) and (cunit.lang <> DW_LANG_C) and (cunit.lang <> DW_LANG_C_plus_plus) then
// raise EBadDwarf.CreateFmt('DWARF compilation unit contains an unsupported language %s', [DwarfLangToString(cunit.lang)]);
// Read the PC ranges
attrib := FindAttribute(node, DW_AT_low_pc);
if attrib = nil then
cunit.lowPC := $FFFFFFFF
else
cunit.lowPC := attrib^.address;
attrib := FindAttribute(node, DW_AT_high_pc);
if attrib = nil then
cunit.highPC := 0
else
cunit.highPC := attrib^.address;
// Read the statement offset
attrib := FindAttribute(node, DW_AT_stmt_list);
if attrib <> nil then begin
cunit.statementOffset := attrib^.data;
DoLineProgram(true, cunit, 0, hitless);
end else
cunit.statementOffset := $FFFFFFFF;
// Read the macro offset
attrib := FindAttribute(node, DW_AT_macro_info);
if attrib <> nil then
cunit.macroOffset := attrib^.address;
logWriteLn(Format('*** Compilation Unit with a range of %.8x to %.8x', [cunit.lowPC, cunit.highPC]));
end;
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: ReadType(cunit, node);
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: ReadSubroutine(cunit, node);
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: ReadVariable(cunit, node);
DW_TAG_volatile_type: ;
end;
if node.hasChildren then
ProcessNode(cunit, node^.kids);
node := node^.next;
end;
end;
//////////////////////////////////////////////////////////////////////
function ExamineVariable(name: string): integer;
var
compUnit: TCompilationUnit;
// attrib: PDwarfAttribute;
i: integer;
v: TDwarfVariable;
inReg, notOptimized: boolean;
addr: uint32;
currentPC: uint32;
begin
Result := 0;
if not assigned(dwarf) then Exit;
currentPC := vmCurrentPC;
compUnit := dwarf.FindContainingUnit(currentPC);
if compUnit <> nil then begin
for i := 0 to compUnit.variables.Count - 1 do begin
v := TDwarfVariable(compUnit.variables.Objects[i]);
if v.name = name then begin
if Assigned(v.loc) and (v.startScope <= currentPC) then begin
addr := LocationSM(v.loc.block, inReg, notOptimized);
if inReg then
Result := vmGetRegister(addr and 15)
else
Result := vmReadWord(addr);
end;
Exit;
end;
end;
end;
end;
//////////////////////////////////////////////////////////////////////
procedure WalkVariables(var res: TStringList);
var
compUnit: TCompilationUnit;
// attrib: PDwarfAttribute;
i, k: integer;
v: TDwarfVariable;
inReg, notOptimized: boolean;
addr: uint32;
begin
if not assigned(dwarf) then Exit;
res.clear;
res.Add('Valid variables at PC = ' + IntToHex(vmCurrentPC, 8));
for k := 0 to dwarf.compUnits.Count - 1 do begin
compUnit := TCompilationUnit(dwarf.compUnits[k]);
if (vmCurrentPC >= compUnit.lowPC) and (vmCurrentPC <= compUnit.highPC) then begin
for i := 0 to compUnit.variables.Count - 1 do begin
v := TDwarfVariable(compUnit.variables.Objects[i]);
// attrib := FindAttribute(v.node, DW_AT_location);
if Assigned(v.loc) and (v.startScope <= vmCurrentPC) then begin
addr := LocationSM(v.loc.block, inReg, notOptimized);
if inReg then begin
addr := addr and 15;
res.Add(Format('%s is $%8.8x, in r%d', [v.name, vmGetRegister(addr), addr]));
end else begin
res.Add(Format('%s is $%8.8x, at u32[$%8.8x]', [v.name, vmReadWord(addr), addr]));
end;
end;
end;
end;
end;
for i := 0 to res.count - 1 do logWriteLn(res.strings[i]);
end;
//////////////////////////////////////////////////////////////////////
function conWalkVariables(params: string): string;
var
junk: TStringList;
begin
junk := TStringList.Create;
WalkVariables(junk);
junk.Free;
end;
//////////////////////////////////////////////////////////////////////
// TDwarfFile ////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
constructor TDwarfFile.Create;
begin
varList := TStringList.Create;
compUnits := TObjectList.Create;
end;
//////////////////////////////////////////////////////////////////////
destructor TDwarfFile.Destroy;
begin
logWriteLn('Clearing DWARF file');
varList.Free;
compUnits.Free;
closeSourceFiles;
inherited;
end;
//////////////////////////////////////////////////////////////////////
procedure TDwarfFile.DestroyNode(node: PDwarfNode);
var
lastNode: PDwarfNode;
lastAttrib, attrib: PDwarfAttribute;
begin
// Destroy a node and all of its siblings
while node <> nil do begin
// Free the attributes
attrib := node^.attribs;
while attrib <> nil do begin
lastAttrib := attrib;
attrib := attrib^.next;
FreeMem(lastAttrib, SizeOf(TDwarfAttribute));
end;
// Recursively wax all the children
if node.hasChildren then
DestroyNode(node^.kids);
// Free the node
lastNode := node;
node := node^.next;
FreeMem(lastNode, SizeOf(TDwarfNode));
end;
end;
//////////////////////////////////////////////////////////////////////
function TDwarfFile.FindContainingUnit(address: uint32): TCompilationUnit;
var
i: integer;
cunit: TCompilationUnit;
begin
Result := nil;
for i := 0 to dwarf.compUnits.Count - 1 do begin
cunit := TCompilationUnit(dwarf.compUnits.Items[i]);
if (address >= cunit.lowPC) and (address < cunit.highPC) then begin
Result := cunit;
Exit;
end;
end;
end;
//////////////////////////////////////////////////////////////////////
// TCompilationUnit //////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
constructor TCompilationUnit.Create;
begin
// Read the compilation unit header
unitLength := debugInfo.ReadUint32;
producerVersion := debugInfo.ReadUint16;
abbrevOffset := debugInfo.ReadUint32;
addressSize := debugInfo.ReadUint8;
// Chunk out some memory
dirs := TStringList.Create;
files := TStringList.Create;
functions := TStringList.Create;
types := TStringList.Create;
classes := TStringList.Create;
variables := TStringList.Create;
// Read all the nodes in the compilation unit
rootNode := ReadNode(self);
// Read all the nodes hither and dither
ProcessNode(self, rootNode);
end;
//////////////////////////////////////////////////////////////////////
destructor TCompilationUnit.Destroy;
begin
// Free all of the nodes that belong to this compilation unit
dwarf.DestroyNode(rootNode);
// Free the string lists
variables.Free;
classes.Free;
types.Free;
functions.Free;
files.Free;
dirs.Free;
end;
//////////////////////////////////////////////////////////////////////
begin
logAddCommand('expressionEvaluator', dwarfLookupVal, 'Evaluates an expression');
logAddCommand('walkVariables', conWalkVariables, 'Display active variables if valid DWARF data is present');
end.
//////////////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -