lazarus/components/fpdebug/test/dwarfviewer/unit1.pas
2024-05-23 20:04:36 +02:00

963 lines
31 KiB
ObjectPascal

unit Unit1;
{$mode objfpc}{$H+}
interface
uses
FpImgReaderWinPE, Classes, SysUtils, math, FileUtil, LazLogger, LazLoggerProfiling, LazSysUtils,
FpDbgLoader, FpDbgDwarf, FpDbgDwarfConst, FpPascalParser, FpDbgInfo, FpDbgDwarfDataClasses,
FpDbgUtil, FpdMemoryTools, Forms, Controls, Graphics, Dialogs, StdCtrls, ComCtrls, EditBtn,
Menus, Clipbrd, maps, laz.VirtualTrees, types, fgl, strutils;
type
TTreeNodeData = record
Text: String;
Data: Integer;
Num, Link: Integer;
end;
PTreeNodeData = ^TTreeNodeData;
TNameMap = specialize TFPGMap<AnsiString, AnsiString>;
{ TForm1 }
TForm1 = class(TForm)
btnCopyAll: TButton;
btnLoad: TButton;
btnShowUnit: TButton;
btnCopyOne: TButton;
btnLines: TButton;
btnUnload: TButton;
FileNameEdit1: TFileNameEdit;
CompUnitListBox: TListBox;
VStringTree: TLazVirtualStringTree;
StatusBar1: TStatusBar;
procedure btnCopyAllClick(Sender: TObject);
procedure btnCopyOneClick(Sender: TObject);
procedure btnLoadClick(Sender: TObject);
procedure btnShowUnitClick(Sender: TObject);
procedure btnLinesClick(Sender: TObject);
procedure btnUnloadClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormDropFiles(Sender: TObject; const FileNames: array of String);
procedure VStringTreeDblClick(Sender: TObject);
procedure VStringTreeFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
procedure VStringTreeGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex; TextType: TVSTTextType; var CellText: String);
procedure VStringTreeInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
var InitialStates: TVirtualNodeInitStates);
procedure VStringTreeNewText(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex; const NewText: String);
procedure VStringTreeNodeDblClick(Sender: TBaseVirtualTree; const HitInfo: THitInfo);
private
{ private declarations }
NameList: TNameMap;
FFileName: String;
FTestCaseTexts: TStringList;
FImageLoaderList: TDbgImageLoaderList;
FMemModel: TFpDbgMemModel;
FDwarfInfo: TFpDwarfInfo;
FCUCount : Integer;
FShowingUnit: Boolean;
function GetDataPtr(n: PVirtualNode): PTreeNodeData; inline;
procedure GotoNode(n: PVirtualNode);
public
constructor Create(TheOwner: TComponent); override;
{ public declarations }
procedure LoadDwarf;
procedure UnLoadDwarf;
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
type
TDwarfCompilationUnitHack = class(TDwarfCompilationUnit)
public
property FirstScope;
property AbbrevList;
end;
{ TForm1 }
procedure TForm1.btnLoadClick(Sender: TObject);
var
i: Integer;
begin
if FileNameEdit1.FileName = '' then
FileNameEdit1.RunDialog;
FFileName := FileNameEdit1.FileName;
LoadDwarf;
if FDwarfInfo = nil then
exit;
CompUnitListBox.Clear;
for i := 0 to FCUCount - 1 do begin
CompUnitListBox.AddItem(FDwarfInfo.CompilationUnits[i].FileName,
FDwarfInfo.CompilationUnits[i] );
end;
end;
procedure TForm1.btnCopyOneClick(Sender: TObject);
var
n: PVirtualNode;
i: PtrInt;
begin
n := VStringTree.GetFirstSelected;
if n = nil then exit;
i := GetDataPtr(n)^.Data - 1;
if i < 0 then exit;
debugln(['TForm1.MenuItem1Click ']);
Clipboard.AsText := FTestCaseTexts[i];
end;
procedure TForm1.btnLinesClick(Sender: TObject);
const
B: Array [Boolean] of string = ('F', 'T');
var
i: Integer;
Node, ParentNode: PVirtualNode;
CU: TDwarfCompilationUnitHack;
SM: TDwarfLineInfoStateMachine;
begin
VStringTree.BeginUpdate;
try
VStringTree.Clear;
i := CompUnitListBox.ItemIndex;
if i < 0 then exit;
CU := TDwarfCompilationUnitHack(CompUnitListBox.Items.Objects[i]);
if CU = nil then exit;
SM := CU.FLineInfo.StateMachine;
SM.Reset;
ParentNode := nil;
while SM.NextLine do
begin
Node := VStringTree.AddChild(ParentNode);
if VStringTree.IsVisible[Node] then ; // init the node
GetDataPtr(Node)^.Text :=
Format('Line: %2d, Col: %2d, Addr: %s, IsStmt: %s, Basic: %s, EndSeq: %s, Prol: %s, Epil: %s, ISA: %u, File: %s // Ended: %s',
[SM.Line, SM.Column, IntToHex(SM.Address,16), b[SM.IsStmt], b[SM.BasicBlock],
b[SM.EndSequence], b[SM.PrologueEnd], b[SM.EpilogueBegin], SM.Isa, sm.FileName, b[SM.Ended] ]);
if ParentNode = nil then ParentNode := Node;
if SM.EndSequence then begin
ParentNode := nil;
if not SM.NextLine then break;
end;
end;
finally
VStringTree.EndUpdate;
end;
end;
procedure TForm1.btnUnloadClick(Sender: TObject);
begin
UnLoadDwarf;
end;
procedure TForm1.btnCopyAllClick(Sender: TObject);
var
nm: TStringList;
vars: String;
procedure AddChildren(n: PVirtualNode; var s: string; idnt: String);
var
i: PtrInt;
s2: String;
begin
n := VStringTree.GetFirstChildNoInit(n);
while n <> nil do begin
i := GetDataPtr(n)^.Data-1;
s2 := 'XXXXXXXXXXX.';
if i >= 0 then
s2 := FTestCaseTexts[i];
nm.Add(copy(s2, 1, max(0, pos('.', s2)-1)));
if i >= 0 then begin
vars := vars + nm[nm.Count-1] +', ';
if s2 <> '' then begin
s2 := nm[nm.Count-1] + ' := ' + nm[nm.Count-2] + '.GetNewChild;' +LineEnding
+ s2;
s2 := AnsiReplaceStr(s2, LineEnding, LineEnding+idnt);
s := s + idnt + s2 + LineEnding;;
end;
end;
AddChildren(n, s, idnt+' ');
nm.Delete(nm.Count-1);
VStringTree.GetNextSiblingNoInit(n);
end;
end;
var
s: String;
i: PtrInt;
i2: Integer;
n: PVirtualNode;
begin
nm := TStringList.Create;
n := VStringTree.GetFirstSelected;
if n = nil then exit;
i := GetDataPtr(n)^.Data-1;
if i < 0 then exit;
debugln(['TForm1.MenuItem1Click ']);
s := FTestCaseTexts[i] + LineEnding;
nm.Add(copy(s, 1, pos('.',s)-1));
vars := vars + nm[nm.Count-1] +', ';
AddChildren(n, s, ' ');
s := 'var '+vars + LineEnding + LineEnding + LineEnding + s;
for i2 := 0 to NameList.count - 1 do
s := AnsiReplaceStr(s, NameList.Keys[i2], NameList.Data[i2]);
Clipboard.AsText := s;
nm.Free;
end;
procedure TForm1.LoadDwarf;
var
ImageLoader: TDbgImageLoader;
begin
UnLoadDwarf;
ImageLoader := TDbgImageLoader.Create(FFileName);
FImageLoaderList := TDbgImageLoaderList.Create(True);
ImageLoader.AddToLoaderList(FImageLoaderList);
FMemModel := TFpDbgMemModel.Create;
FDwarfInfo := TFpDwarfInfo.Create(FImageLoaderList, nil, FMemModel);
FCUCount := FDwarfInfo.LoadCompilationUnits;
end;
procedure TForm1.btnShowUnitClick(Sender: TObject);
var
CU: TDwarfCompilationUnitHack;
BaseScopeAddr: Pointer;
function ToHex(var p: pbyte; l : integer):String; inline;
begin
Result := '';
while l > 0 do begin
Result := IntToHex(p^,2) + Result;
inc(p);
dec(l);
end;
end;
function ToHexCommaList(p: pbyte; l : integer):String;
begin
Result := '';
while l > 0 do begin
if Result <> ''
then Result := Result + ', ' + '$'+IntToHex(p^,2)
else Result := Result + '$'+IntToHex(p^,2);
inc(p);
dec(l);
end;
end;
function DecodeLocation(AData: PByte; ASize: QWord): String;
function MakeAddressString(AData: Pointer): string;
begin
Result := '$'+IntToHex(PLongWord(AData)^, 8)
//Result := '$'+IntToHex(PQWord(AData)^, 16);
end;
var
MaxData: PByte;
v: Int64;
begin
Result:='';
MaxData := AData + ASize - 1;
while AData <= MaxData do
begin
if Result <> '' then Result := Result + ', ';
case AData^ of
DW_OP_addr: begin
Result := Result + 'DW_OP_addr, AddrB(' + MakeAddressString(@AData[1]) + ')';
Inc(AData, 4);
end;
DW_OP_deref: begin
Result := Result + 'DW_OP_deref';
end;
DW_OP_const1u: begin
Result := Result + 'DW_OP_const1u, ' + IntToStr(AData[1]);
Inc(AData, 1);
end;
DW_OP_const1s: begin
Result := Result + 'DW_OP_const1s, ' + IntToStr(PShortInt(@AData[1])^);
Inc(AData, 1);
end;
DW_OP_const2u: begin
Result := Result + 'DW_OP_const2u, NumU(' + IntToStr(PWord(@AData[1])^) + ',2)';
Inc(AData, 2);
end;
DW_OP_const2s: begin
Result := Result + 'DW_OP_const2s, NumS(' + IntToStr(PSmallInt(@AData[1])^) + ',2)';
Inc(AData, 2);
end;
DW_OP_const4u: begin
Result := Result + 'DW_OP_const4u, NumU(' + IntToStr(PLongWord(@AData[1])^) + ',4)';
Inc(AData, 4);
end;
DW_OP_const4s: begin
Result := Result + 'DW_OP_const4s, NumS(' + IntToStr(PLongInt(@AData[1])^) + ',4)';
Inc(AData, 4);
end;
DW_OP_const8u: begin
Result := Result + 'DW_OP_const8u, NumU' + IntToStr(PQWord(@AData[1])^) + ',8)';
Inc(AData, 8);
end;
DW_OP_const8s: begin
Result := Result + 'DW_OP_const8s, NumS' + IntToStr(PInt64(@AData[1])^) + ',8)';
Inc(AData, 8);
end;
DW_OP_constu: begin
Inc(AData);
Result := Result + 'DW_OP_constu, ULEB' + IntToStr(ULEB128toOrdinal(AData)) + ')';
Dec(AData);
end;
DW_OP_consts: begin
Inc(AData);
Result := Result + 'DW_OP_consts, SLEB(' + IntToStr(SLEB128toOrdinal(AData)) + ')';
Dec(AData);
end;
DW_OP_dup: begin
Result := Result + 'DW_OP_dup';
end;
DW_OP_drop: begin
Result := Result + 'DW_OP_drop';
end;
DW_OP_over: begin
Result := Result + 'DW_OP_over';
end;
DW_OP_pick: begin
Result := Result + 'DW_OP_pick, ' + IntToStr(AData[1]);
Inc(AData, 1);
end;
DW_OP_swap: begin
Result := Result + 'DW_OP_swap';
end;
DW_OP_rot: begin
Result := Result + 'DW_OP_rot';
end;
DW_OP_xderef: begin
Result := Result + 'DW_OP_xderef';
end;
DW_OP_abs: begin
Result := Result + 'DW_OP_abs';
end;
DW_OP_and: begin
Result := Result + 'DW_OP_and';
end;
DW_OP_div: begin
Result := Result + 'DW_OP_div';
end;
DW_OP_minus: begin
Result := Result + 'DW_OP_minus';
end;
DW_OP_mod: begin
Result := Result + 'DW_OP_mod';
end;
DW_OP_mul: begin
Result := Result + 'DW_OP_mul';
end;
DW_OP_neg: begin
Result := Result + 'DW_OP_neg';
end;
DW_OP_not: begin
Result := Result + 'DW_OP_not';
end;
DW_OP_or: begin
Result := Result + 'DW_OP_or';
end;
DW_OP_plus: begin
Result := Result + 'DW_OP_plus';
end;
DW_OP_plus_uconst: begin
Inc(AData);
Result := Result + 'DW_OP_plus_uconst, ULEB(' + IntToStr(ULEB128toOrdinal(AData))+')';
Dec(AData);
end;
DW_OP_shl: begin
Result := Result + 'DW_OP_shl';
end;
DW_OP_shr: begin
Result := Result + 'DW_OP_shr';
end;
DW_OP_shra: begin
Result := Result + 'DW_OP_shra';
end;
DW_OP_xor: begin
Result := Result + 'DW_OP_xor';
end;
DW_OP_skip: begin
Result := Result + 'DW_OP_skip, NumS(' + IntToStr(PSmallInt(@AData[1])^) + ',2)';
Inc(AData, 2);
end;
DW_OP_bra: begin
Result := Result + 'DW_OP_bra, NumS(' + IntToStr(PSmallInt(@AData[1])^) + ',2)';
Inc(AData, 2);
end;
DW_OP_eq: begin
Result := Result + 'DW_OP_eq';
end;
DW_OP_ge: begin
Result := Result + 'DW_OP_ge';
end;
DW_OP_gt: begin
Result := Result + 'DW_OP_gt';
end;
DW_OP_le: begin
Result := Result + 'DW_OP_le';
end;
DW_OP_lt: begin
Result := Result + 'DW_OP_lt';
end;
DW_OP_ne: begin
Result := Result + 'DW_OP_ne';
end;
DW_OP_lit0..DW_OP_lit31: begin
Result := Result + 'DW_OP_lit' + IntToStr(AData^ - DW_OP_lit0);
end;
DW_OP_reg0..DW_OP_reg31: begin
Result := Result + 'DW_OP_reg' + IntToStr(AData^ - DW_OP_reg0);
end;
DW_OP_breg0..DW_OP_breg31: begin
Result := Result + 'DW_OP_breg' + IntToStr(AData^ - DW_OP_breg0);
Inc(AData);
v := SLEB128toOrdinal(AData);
Dec(AData);
Result := Result + ', SLEB(';
Result := Result + IntToStr(v) + ')';
end;
DW_OP_regx: begin
Inc(AData);
Result := Result + 'DW_OP_regx, ULEB(' + IntToStr(ULEB128toOrdinal(AData)) + ')';
Dec(AData);
end;
DW_OP_fbreg: begin
Inc(AData);
Result := Result + 'DW_OP_fbreg, SLEB(' + IntToStr(SLEB128toOrdinal(AData)) + ')';
Dec(AData);
end;
DW_OP_bregx: begin
Inc(AData);
Result := Result + 'DW_OP_bregx, ULEB(' + IntToStr(ULEB128toOrdinal(AData)) + ')';
v := SLEB128toOrdinal(AData);
Dec(AData);
Result := Result + ', SLEB(';
Result := Result + IntToStr(v) + ')';
end;
DW_OP_piece: begin
Inc(AData);
Result := Result + 'DW_OP_piece, ULEB(' + IntToStr(ULEB128toOrdinal(AData)) + ')';
Dec(AData);
end;
DW_OP_deref_size: begin
Result := Result + 'DW_OP_deref_size, ' + IntToStr(AData[1]);
Inc(AData);
end;
DW_OP_xderef_size: begin
Result := Result + 'DW_OP_xderef_size, ' + IntToStr(AData[1]);
Inc(AData);
end;
DW_OP_nop: begin
Result := Result + 'DW_OP_nop';
end;
DW_OP_push_object_address: begin
Result := Result + 'DW_OP_push_object_address';
end;
DW_OP_call2: begin
Result := Result + 'DW_OP_call2, ' + IntToStr(PWord(@AData[1])^);
Inc(AData, 2);
end;
DW_OP_call4: begin
Result := Result + 'DW_OP_call4, ' + IntToStr(PLongWord(@AData[1])^);
Inc(AData, 4);
end;
DW_OP_call_ref: begin
Result := Result + 'DW_OP_call_ref, AddrB(' + MakeAddressString(@AData[1]) + ')';
Inc(AData, 4);
end;
DW_OP_form_tls_address: begin
Result := Result + 'DW_OP_form_tls_address';
end;
DW_OP_call_frame_cfa: begin
Result := Result + 'DW_OP_call_frame_cfa';
end;
DW_OP_bit_piece: begin
Inc(AData);
Result := Result + 'DW_OP_bit_piece, ULEB(' + IntToStr(ULEB128toOrdinal(AData)) + '), ULEB(' + IntToStr(ULEB128toOrdinal(AData)) + ')';
Dec(AData);
end;
DW_OP_lo_user..DW_OP_hi_user: begin
Result := Result + 'DW_OP_user, ' + IntToStr(AData^);
end;
else begin
Result := Result + 'Unknown DW_OP_' + IntToStr(AData^);
result := Result + ' RemainCnt:' + IntToStr(MaxData - AData);
break;
end
end;
Inc(AData);
//Result := Result +' / ';
end;
end;
function AddAbbrev(AParent: PVirtualNode; s: TDwarfScopeInfo; Def: TDwarfAbbrev;
var PascalTestCAseCode: String; namePreFix: String = ''): String;
var
p: Pointer;
Form: Cardinal;
Attribute: Cardinal;
i: Integer;
s1, s2, s3, s4, stest: String;
ValueSize: QWord;
Value: qword;
SValue: int64;
p2: Pointer;
AddedNode: PVirtualNode;
lnk: Integer;
nptr: PTreeNodeData;
begin
Result := '';
PascalTestCAseCode := '';
p := s.Entry;
ULEB128toOrdinal(p);
for i := def.index to Def.index + Def.count - 1 do begin
Form := CU.AbbrevList.EntryPointer[i]^.Form;
Attribute := CU.AbbrevList.EntryPointer[i]^.Attribute;
s1 := DwarfAttributeToString(Attribute);
s2 := DwarfAttributeFormToString(Form);
p2 := p;
case Form of
DW_FORM_addr : begin
s3 := ToHex(p, cu.AddressSize {4} {FCU.FAddressSize});
PascalTestCAseCode := PascalTestCAseCode +
Format(namePreFix+'AddAddr(%s, %s, $%s);%s', [s1, s2, s3, LineEnding]);
end;
DW_FORM_exprloc,
DW_FORM_block : begin
p2 := p;
ValueSize := ULEB128toOrdinal(p);
stest := ToHexCommaList(p,ValueSize);
p2 := p;
s3 := IntToStr(ValueSize) + ': ' + ToHex(p, ValueSize);
if (Attribute = DW_AT_location) or (Attribute = DW_AT_data_location) or (Attribute = DW_AT_data_member_location) then
PascalTestCAseCode := PascalTestCAseCode +
Format(namePreFix+'Add(%s, %s, BytesLenU([%s])); // %s%s', [s1, s2, DecodeLocation(p2, ValueSize), stest, LineEnding])
else
PascalTestCAseCode := PascalTestCAseCode +
Format(namePreFix+'Add(%s, %s, BytesLenU([%s]));%s', [s1, s2, stest, LineEnding]);
end;
DW_FORM_block1 : begin
ValueSize := PByte(p)^;
Inc(p, 1);
p2 := p;
stest := ToHexCommaList(p,ValueSize);
s3 := IntToStr(ValueSize) + ': ' + ToHex(p, ValueSize);
if (Attribute = DW_AT_location) or (Attribute = DW_AT_data_location) or (Attribute = DW_AT_data_member_location) then
PascalTestCAseCode := PascalTestCAseCode +
Format(namePreFix+'Add(%s, %s, BytesLen1([%s])); // %s%s', [s1, s2, DecodeLocation(p2, ValueSize), stest, LineEnding])
else
PascalTestCAseCode := PascalTestCAseCode +
Format(namePreFix+'Add(%s, %s, BytesLen1([%s]));%s', [s1, s2, stest, LineEnding]);
end;
DW_FORM_block2 : begin
ValueSize := PWord(p)^;
Inc(p, 2);
p2 := p;
stest := ToHexCommaList(p,ValueSize);
s3 := IntToStr(ValueSize) + ': ' + ToHex(p, ValueSize);
if (Attribute = DW_AT_location) or (Attribute = DW_AT_data_location) or (Attribute = DW_AT_data_member_location) then
PascalTestCAseCode := PascalTestCAseCode +
Format(namePreFix+'Add(%s, %s, BytesLen2([%s])); // %s%s', [s1, s2, DecodeLocation(p2, ValueSize), stest, LineEnding])
else
PascalTestCAseCode := PascalTestCAseCode +
Format(namePreFix+'Add(%s, %s, BytesLen2([%s]));%s', [s1, s2, stest, LineEnding]);
end;
DW_FORM_block4 : begin
ValueSize := PLongWord(p)^;
Inc(p, 4);
p2 := p;
stest := ToHexCommaList(p,ValueSize);
s3 := IntToStr(ValueSize) + ': ' + ToHex(p, ValueSize);
if (Attribute = DW_AT_location) or (Attribute = DW_AT_data_location) or (Attribute = DW_AT_data_member_location) then
PascalTestCAseCode := PascalTestCAseCode +
Format(namePreFix+'Add(%s, %s, BytesLen4([%s])); // %s%s', [s1, s2, DecodeLocation(p2, ValueSize), stest, LineEnding])
else
PascalTestCAseCode := PascalTestCAseCode +
Format(namePreFix+'Add(%s, %s, BytesLen4([%s]));%s', [s1, s2, stest, LineEnding]);
end;
DW_FORM_data1 : begin
stest := ToHexCommaList(p,1);
s3 := ToHex(p, 1);
PascalTestCAseCode := PascalTestCAseCode +
Format(namePreFix+'Add(%s, %s, [%s]);%s', [s1, s2, stest, LineEnding]);
end;
DW_FORM_data2 : begin
stest := ToHexCommaList(p,2);
s3 := ToHex(p, 2);
PascalTestCAseCode := PascalTestCAseCode +
Format(namePreFix+'Add(%s, %s, [%s]);%s', [s1, s2, stest, LineEnding]);
end;
DW_FORM_data4 : begin
stest := ToHexCommaList(p,4);
s3 := ToHex(p, 4);
PascalTestCAseCode := PascalTestCAseCode +
Format(namePreFix+'Add(%s, %s, [%s]);%s', [s1, s2, stest, LineEnding]);
end;
DW_FORM_data8 : begin
stest := ToHexCommaList(p,8);
s3 := ToHex(p, 8);
PascalTestCAseCode := PascalTestCAseCode +
Format(namePreFix+'Add(%s, %s, [%s]);%s', [s1, s2, stest, LineEnding]);
end;
DW_FORM_sdata : begin
SValue := SLEB128toOrdinal(p);
s3 := IntToStr(SValue);
PascalTestCAseCode := PascalTestCAseCode +
Format(namePreFix+'AddSLEB(%s, %s, %d);%s', [s1, s2, SValue, LineEnding]);
end;
DW_FORM_udata : begin
Value := ULEB128toOrdinal(p);
s3 := IntToStr(Value);
PascalTestCAseCode := PascalTestCAseCode +
Format(namePreFix+'AddULEB(%s, %s, %u);%s', [s1, s2, Value, LineEnding]);
end;
DW_FORM_flag : begin
stest := ToHexCommaList(p,1);
s3 := ToHex(p, 1);
PascalTestCAseCode := PascalTestCAseCode +
Format(namePreFix+'Add(%s, %s, [%s]);%s', [s1, s2, stest, LineEnding]);
end;
DW_FORM_ref1 : begin
stest := ToHexCommaList(p,1);
s3 := ToHex(p, 1);
PascalTestCAseCode := PascalTestCAseCode +
Format(namePreFix+'AddRef(%s, %s, @Info__%s_); // %s %s', [s1, s2, IntToStr(PByte(p-1)^), stest, LineEnding]);
//Format(namePreFix+'AddRef(%s, %s, FOO); // %s %s', [s1, s2, stest, LineEnding]);
end;
DW_FORM_ref2 : begin
stest := ToHexCommaList(p,3);
s3 := ToHex(p, 2);
PascalTestCAseCode := PascalTestCAseCode +
Format(namePreFix+'AddRef(%s, %s, @Info__%s_); // %s %s', [s1, s2, IntToStr(PWord(p-2)^), stest, LineEnding]);
//Format(namePreFix+'AddRef(%s, %s, FOO); // %s %s', [s1, s2, stest, LineEnding]);
end;
DW_FORM_ref4 : begin
stest := ToHexCommaList(p,4);
lnk := PInteger(p)^ -11;
s4 := IntToHex(PInteger(p)^ -11, 8);;
s3 := ToHex(p, 4) + ' // '+ s4;
PascalTestCAseCode := PascalTestCAseCode +
Format(namePreFix+'AddRef(%s, %s, @Info__%s_); // %s %s', [s1, s2, IntToStr(PDWord(p-4)^), stest, LineEnding]);
//Format(namePreFix+'AddRef(%s, %s, FOO); // %s %s', [s1, s2, stest, LineEnding]);
end;
DW_FORM_ref8 : begin
stest := ToHexCommaList(p,8);
s3 := ToHex(p, 8);
PascalTestCAseCode := PascalTestCAseCode +
Format(namePreFix+'AddRef(%s, %s, @Info__%s_); // %s %s', [s1, s2, IntToStr(PQWord(p-8)^), stest, LineEnding]);
//Format(namePreFix+'AddRef(%s, %s, FOO); // %s %s', [s1, s2, stest, LineEnding]);
end;
DW_FORM_ref_udata: begin
Value := ULEB128toOrdinal(p);
s3 := IntToStr(Value);
PascalTestCAseCode := PascalTestCAseCode +
Format(namePreFix+'AddRef(%s, %s, FOO); // %u // ULEB %s', [s1, s2, Value, LineEnding]);
end;
DW_FORM_ref_addr : begin
stest := ToHexCommaList(p,4);
s3 := ToHex(p, 4 {FCU.FAddressSize});
PascalTestCAseCode := PascalTestCAseCode +
Format(namePreFix+'AddRef(%s, %s, FOO); // %s // %s', [s1, s2, stest, LineEnding]);
end;
DW_FORM_string : begin
s3 := copy(pchar(p),1,1000);
while pbyte( p)^ <> 0 do begin
inc(pbyte(p));
end;
inc(pbyte(p));
PascalTestCAseCode := PascalTestCAseCode +
Format(namePreFix+'Add(%s, %s, ''%s''+#0);%s', [s1, s2, s3, LineEnding]);
end;
DW_FORM_strp : begin
stest := ToHexCommaList(p,4);
s3 := ToHex(p, 4 {FCU.FAddressSize});
PascalTestCAseCode := PascalTestCAseCode +
Format(namePreFix+'Add(%s, %s, [%s]);%s', [s1, s2, stest, LineEnding]);
end;
DW_FORM_indirect : begin
Value := ULEB128toOrdinal(p);
s3 := IntToStr(Value);
//Form := ULEB128toOrdinal(p);
//Continue;
PascalTestCAseCode := PascalTestCAseCode +
Format(namePreFix+'AddULEB(%s, %s, %u);%s', [s1, s2, Value, LineEnding]);
end;
DW_FORM_sec_offset: begin
if CU.IsDwarf64 then begin
Value := PQWord(p)^;
s3 := ToHex(p, 8);
inc(p, 8);
end
else begin
Value := PLongWord(P)^;
s3 := ToHex(p, 4);
inc(p, 4);
end;
end;
DW_FORM_flag_present: begin
s3 := 'Yes';
end;
DW_FORM_ref_sig8: begin
Value := PQWord(p)^;
s3 := ToHex(p, 8);
inc(p, 8);
end;
else
s3 := '?????';
PascalTestCAseCode := PascalTestCAseCode +
Format(namePreFix+'Add(%s, %s, %s);%s', [s1, s2, '???????????', LineEnding]);
end;
if Attribute = DW_AT_name then Result := s3;
if (Attribute = DW_AT_location) or (Attribute = DW_AT_data_location) or (Attribute = DW_AT_data_member_location)
or (Attribute = DW_AT_upper_bound) or (Attribute = DW_AT_lower_bound)
then begin
stest := DecodeLocation(p2, ValueSize);
s3 := s3 + ' // ' +stest;
end;
AddedNode := VStringTree.AddChild(AParent);
if VStringTree.IsVisible[AddedNode] then ; // init the node
nptr := GetDataPtr(AddedNode);
VStringTree.Text[AddedNode, 0] := Format(' -- Attr: %20s(%4x) Form: %18s(%4x) >> %s', [s1, Attribute, s2, Form, s3]);
nptr^.Link := lnk;
end;
end;
function AddNode(AParent, Asibling: PVirtualNode; s: TDwarfScopeInfo): PVirtualNode;
var
p: Pointer;
Abbrev: QWord;
Node: PVirtualNode;
s2: TDwarfScopeInfo;
n: PVirtualNode;
i: Integer;
Def: TDwarfAbbrev;
entryname: String;
TestCaseText: String;
NMLIdx: Integer;
pre, sName, t: String;
nptr: PTreeNodeData;
begin
Result := nil;
p := s.Entry;
Abbrev := ULEB128toOrdinal(p);
p := s.Entry;
CU.GetDefinition(p, Def);
Node := VStringTree.AddChild(AParent);
if VStringTree.IsVisible[Node] then ; // init the node
GetDataPtr(Node)^.Text := Format('Abr: %d Tag: %d %s ', [Abbrev, Def.tag, DwarfTagToString(Def.tag)]);
sName := 'Info__'+IntToStr(s.Entry - BaseScopeAddr + 11)+'_.';
entryname := AddAbbrev(Node, s, Def, TestCaseText, sName);
pre := '';
Case def.tag of
DW_TAG_base_type, DW_TAG_string_type, DW_TAG_union_type, DW_TAG_ptr_to_member_type,
DW_TAG_file_type, DW_TAG_thrown_type, DW_TAG_subroutine_type, DW_TAG_packed_type,
DW_TAG_const_type, DW_TAG_volatile_type, DW_TAG_reference_type,
DW_TAG_subrange_type, DW_TAG_enumeration_type,
DW_TAG_enumerator, DW_TAG_set_type, DW_TAG_structure_type, DW_TAG_class_type,
DW_TAG_array_type: pre:= 'Type';
DW_TAG_typedef: pre:= 'TypeDecl';
DW_TAG_pointer_type: pre:= 'TypePtr';
DW_TAG_variable, DW_TAG_formal_parameter, DW_TAG_member: pre:= 'Var';
DW_TAG_subprogram: pre:= 'Prog';
DW_TAG_compile_unit: pre:= 'Unit';
else pre:= 'XX';
end;
pre := pre + entryname;
pre := AnsiReplaceStr(pre, '$', '');
pre := AnsiReplaceStr(pre, '.', '_');
pre := AnsiReplaceStr(pre, ' ', '_');
pre := AnsiReplaceStr(pre, ' ', '_');
NameList['Info__'+IntToStr(s.Entry - BaseScopeAddr + 11)+'_']
:= pre+'_'+IntToStr(FTestCaseTexts.Count);
i := 0;
if s.HasChild then i := 1;
TestCaseText :=
Format('%sTag := %s;%s',
[sName, DwarfTagToString(Def.tag), LineEnding])
+ Format('%sChildren := %d;%s', [sName, i, LineEnding])
+ TestCaseText;
GetDataPtr(node)^.Data := FTestCaseTexts.Add(TestCaseText)+1;
i := 0;
if s.HasChild then begin
n:=nil;
s2 := s.Child;
while s2.IsValid do begin
n := AddNode(Node,n,s2);
s2.GoNext;
inc(i);
if (i and 255) = 0 then begin
StatusBar1.SimpleText := IntToHex(s2.Index,8) + ' / '+ IntToHex(s2.ScopeListPtr^.HighestKnown,8)+' // '+format('%2.1f',[s2.Index*100/s2.ScopeListPtr^.HighestKnown]);
Application.ProcessMessages;
if not FShowingUnit then break;
end;
end;
end;
t := Format('At %4x Abr: %d Tag: %d %s ChildCnt: %d %s', [s.Entry-BaseScopeAddr, Abbrev, Def.tag, DwarfTagToString(Def.tag), i, entryname]);
nptr := GetDataPtr(Node);
nptr^.Text := t;
nptr^.Num:= s.Entry-BaseScopeAddr;
end;
var
i: Integer;
s: TDwarfScopeInfo;
Node: PVirtualNode;
begin
FShowingUnit := not FShowingUnit;//////////////////
if not FShowingUnit then exit;/////////////////
VStringTree.BeginUpdate;
try
VStringTree.Clear;
i := CompUnitListBox.ItemIndex;
if i < 0 then exit;
CU := TDwarfCompilationUnitHack(CompUnitListBox.Items.Objects[i]);
if CU = nil then exit;
s := CU.FirstScope;
BaseScopeAddr := s.Entry;
Node := nil;
while s.IsValid do begin
Node := AddNode(nil,Node,s);
s.GoNext;
end;
finally
VStringTree.EndUpdate;
FShowingUnit := False; ////////////////////
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
FTestCaseTexts:= TStringList.Create;
FTestCaseTexts.Capacity := 5000;
NameList:= TNameMap.Create;
NameList.Capacity := 5000;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
UnLoadDwarf;
FTestCaseTexts.Free;
end;
procedure TForm1.FormDropFiles(Sender: TObject; const FileNames: array of String
);
begin
if Length(FileNames) > 0 then
FileNameEdit1.Text := FileNames[0];
end;
procedure TForm1.VStringTreeDblClick(Sender: TObject);
begin
end;
procedure TForm1.VStringTreeFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
begin
PTreeNodeData(VStringTree.GetNodeData(Node))^.Text := '';
end;
procedure TForm1.VStringTreeGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex; TextType: TVSTTextType; var CellText: String);
var
nd: PTreeNodeData;
begin
nd := PTreeNodeData(VStringTree.GetNodeData(Node));
CellText := nd^.Text;
end;
procedure TForm1.VStringTreeInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
var InitialStates: TVirtualNodeInitStates);
begin
Pointer(PTreeNodeData(VStringTree.GetNodeData(Node))^.Text) := nil;
end;
procedure TForm1.VStringTreeNewText(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex; const NewText: String);
begin
PTreeNodeData(VStringTree.GetNodeData(Node))^.Text := NewText;
end;
procedure TForm1.VStringTreeNodeDblClick(Sender: TBaseVirtualTree; const HitInfo: THitInfo);
var
n: PVirtualNode;
nptr, nptr2: PTreeNodeData;
begin
if HitInfo.HitNode = nil then exit;
nptr := GetDataPtr(HitInfo.HitNode);
if nptr^.Link = 0 then exit;
for n in VStringTree.Nodes do begin
nptr2 := GetDataPtr(n);
if nptr2^.Num = nptr^.Link then begin
GotoNode(n);
exit;
end;
end;
end;
function TForm1.GetDataPtr(n: PVirtualNode): PTreeNodeData;
begin
result := PTreeNodeData(VStringTree.GetNodeData(N));
end;
procedure TForm1.GotoNode(n: PVirtualNode);
begin
VStringTree.FocusedNode := n;
end;
constructor TForm1.Create(TheOwner: TComponent);
begin
inherited Create(TheOwner);
VStringTree.NodeDataSize := sizeof(TTreeNodeData);
end;
procedure TForm1.UnLoadDwarf;
begin
FreeAndNil(FDwarfInfo);
FreeAndNil(FImageLoaderList);
FreeAndNil(FMemModel);
FCUCount := 0;
end;
end.