mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-09-10 01:59:53 +02:00
Naive implementation of reverse disassembling
Patch/Contributed by ccrause git-svn-id: trunk@62754 -
This commit is contained in:
parent
6d6903e246
commit
121b9389ee
@ -413,18 +413,22 @@ type
|
||||
TDbgDisassembler = class
|
||||
protected
|
||||
function GetLastErrorWasMemReadErr: Boolean; virtual;
|
||||
function FMaxInstrSz: integer; virtual; abstract;
|
||||
function FMinInstrSz: integer; virtual; abstract;
|
||||
function GetMaxInstrSize: integer; virtual; abstract;
|
||||
function GetMinInstrSize: integer; virtual; abstract;
|
||||
function GetCanReverseDisassemble: boolean; virtual;
|
||||
public
|
||||
constructor Create(AProcess: TDbgProcess); virtual; abstract;
|
||||
|
||||
procedure Disassemble(var AAddress: Pointer; out ACodeBytes: String; out ACode: String); virtual; abstract;
|
||||
procedure ReverseDisassemble(var AAddress: Pointer; out ACodeBytes: String; out ACode: String); virtual;
|
||||
|
||||
function GetInstructionInfo(AnAddress: TDBGPtr): TDbgDisassemblerInstruction; virtual; abstract;
|
||||
function GetFunctionFrameInfo(AnAddress: TDBGPtr; out AnIsOutsideFrame: Boolean): Boolean; virtual;
|
||||
|
||||
property LastErrorWasMemReadErr: Boolean read GetLastErrorWasMemReadErr;
|
||||
property MaxInstructionSize: integer read FMaxInstrSz; // abstract
|
||||
property MinInstructionSize: integer read FMinInstrSz; // abstract
|
||||
property MaxInstructionSize: integer read GetMaxInstrSize; // abstract
|
||||
property MinInstructionSize: integer read GetMinInstrSize; // abstract
|
||||
property CanReverseDisassemble: boolean read GetCanReverseDisassemble;
|
||||
end;
|
||||
TDbgDisassemblerClass = class of TDbgDisassembler;
|
||||
|
||||
@ -1302,6 +1306,35 @@ begin
|
||||
Result := False;
|
||||
end;
|
||||
|
||||
function TDbgDisassembler.GetCanReverseDisassemble: boolean;
|
||||
begin
|
||||
Result := false;
|
||||
end;
|
||||
|
||||
// Naive backwards scanner, decode MaxInstructionSize
|
||||
// if pointer to next instruction matches, done!
|
||||
// If not decrease instruction size and try again.
|
||||
// Many pitfalls with X86 instruction encoding...
|
||||
// Avr may give 130/65535 = 0.2% errors per instruction reverse decoded
|
||||
procedure TDbgDisassembler.ReverseDisassemble(var AAddress: Pointer; out
|
||||
ACodeBytes: String; out ACode: String);
|
||||
var
|
||||
i, instrLen: integer;
|
||||
tmpAddress: PtrUint;
|
||||
begin
|
||||
// Decode max instruction length backwards,
|
||||
instrLen := MaxInstructionSize + MinInstructionSize;
|
||||
repeat
|
||||
dec(instrLen, MinInstructionSize);
|
||||
tmpAddress := PtrUInt(AAddress) - instrLen;
|
||||
Disassemble(pointer(tmpAddress), ACodeBytes, ACode);
|
||||
until (tmpAddress >= PtrUInt(AAddress)) or (instrLen = MinInstructionSize);
|
||||
|
||||
// After disassemble tmpAddress points to the starting address of next instruction
|
||||
// Decrement with the instruction length to point to the start of this instruction
|
||||
AAddress := AAddress - instrLen;
|
||||
end;
|
||||
|
||||
function TDbgDisassembler.GetFunctionFrameInfo(AnAddress: TDBGPtr; out
|
||||
AnIsOutsideFrame: Boolean): Boolean;
|
||||
begin
|
||||
|
@ -73,17 +73,16 @@ type
|
||||
{ TAvrDisassembler }
|
||||
|
||||
TAvrDisassembler = class(TDbgDisassembler)
|
||||
private const
|
||||
FMaxInstructionSize = 4;
|
||||
FMinInstructionSize = 2;
|
||||
private
|
||||
FProcess: TDbgProcess;
|
||||
FLastErrWasMem: Boolean;
|
||||
FLastInstr: TAvrDisassemblerInstruction;
|
||||
function FMaxInstrSz: integer; override;
|
||||
function FMinInstrSz: integer; override;
|
||||
protected
|
||||
function GetLastErrorWasMemReadErr: Boolean; override;
|
||||
function GetMaxInstrSize: integer; override;
|
||||
function GetMinInstrSize: integer; override;
|
||||
function GetCanReverseDisassemble: boolean; override;
|
||||
|
||||
procedure Disassemble(var AAddress: Pointer; out ACodeBytes: String; out ACode: String); override;
|
||||
function GetInstructionInfo(AnAddress: TDBGPtr): TDbgDisassemblerInstruction; override;
|
||||
|
||||
@ -214,21 +213,26 @@ begin
|
||||
Result := 4;
|
||||
end;
|
||||
|
||||
function TAvrDisassembler.FMaxInstrSz: integer;
|
||||
begin
|
||||
result := FMaxInstructionSize;
|
||||
end;
|
||||
|
||||
function TAvrDisassembler.FMinInstrSz: integer;
|
||||
begin
|
||||
|
||||
end;
|
||||
|
||||
function TAvrDisassembler.GetLastErrorWasMemReadErr: Boolean;
|
||||
begin
|
||||
Result := FLastErrWasMem;
|
||||
end;
|
||||
|
||||
function TAvrDisassembler.GetMaxInstrSize: integer;
|
||||
begin
|
||||
Result := 4;
|
||||
end;
|
||||
|
||||
function TAvrDisassembler.GetMinInstrSize: integer;
|
||||
begin
|
||||
Result := 2;
|
||||
end;
|
||||
|
||||
function TAvrDisassembler.GetCanReverseDisassemble: boolean;
|
||||
begin
|
||||
Result := true;
|
||||
end;
|
||||
|
||||
procedure TAvrDisassembler.Disassemble(var AAddress: Pointer; out
|
||||
ACodeBytes: String; out ACode: String);
|
||||
var
|
||||
|
@ -241,10 +241,10 @@ type
|
||||
FLastErrWasMem: Boolean;
|
||||
FCodeBin: array[0..MAX_CODEBIN_LEN-1] of byte;
|
||||
FLastInstr: TX86DisassemblerInstruction;
|
||||
function FMaxInstrSz: integer; override;
|
||||
function FMinInstrSz: integer; override;
|
||||
protected
|
||||
function GetLastErrorWasMemReadErr: Boolean; override;
|
||||
function GetMaxInstrSize: integer; override;
|
||||
function GetMinInstrSize: integer; override;
|
||||
function ReadCodeAt(AnAddress: TDBGPtr; var ALen: Cardinal): Boolean; inline;
|
||||
procedure Disassemble(var AAddress: Pointer; out AnInstruction: TInstruction);
|
||||
public
|
||||
@ -3522,21 +3522,21 @@ end;
|
||||
|
||||
{ TX86Disassembler }
|
||||
|
||||
function TX86Disassembler.FMaxInstrSz: integer;
|
||||
begin
|
||||
result := FMaxInstructionSize;
|
||||
end;
|
||||
|
||||
function TX86Disassembler.FMinInstrSz: integer;
|
||||
begin
|
||||
result := FMinInstructionSize;
|
||||
end;
|
||||
|
||||
function TX86Disassembler.GetLastErrorWasMemReadErr: Boolean;
|
||||
begin
|
||||
Result := FLastErrWasMem;
|
||||
end;
|
||||
|
||||
function TX86Disassembler.GetMaxInstrSize: integer;
|
||||
begin
|
||||
Result := 16;
|
||||
end;
|
||||
|
||||
function TX86Disassembler.GetMinInstrSize: integer;
|
||||
begin
|
||||
Result := 1;
|
||||
end;
|
||||
|
||||
function TX86Disassembler.ReadCodeAt(AnAddress: TDBGPtr; var ALen: Cardinal
|
||||
): Boolean;
|
||||
begin
|
||||
|
@ -1296,7 +1296,7 @@ end;
|
||||
|
||||
function TFPDBGDisassembler.PrepareEntries(AnAddr: TDbgPtr; ALinesBefore, ALinesAfter: Integer): boolean;
|
||||
var
|
||||
ARange: TDBGDisassemblerEntryRange;
|
||||
ARange, AReversedRange: TDBGDisassemblerEntryRange;
|
||||
AnEntry: TDisassemblerEntry;
|
||||
CodeBin: TBytes;
|
||||
p: pointer;
|
||||
@ -1304,17 +1304,19 @@ var
|
||||
AStatement,
|
||||
ASrcFileName: string;
|
||||
ASrcFileLine: integer;
|
||||
i,j, sz, prevInstructionSize, bytesDisassembled: Integer;
|
||||
i,j, sz, bytesDisassembled, bufOffset: Integer;
|
||||
Sym: TFpSymbol;
|
||||
StatIndex: integer;
|
||||
FirstIndex: integer;
|
||||
ALastAddr: TDBGPtr;
|
||||
ALastAddr, tmpAddr, tmpPointer, prevInstructionSize: TDBGPtr;
|
||||
ADisassembler: FpDbgClasses.TDbgDisassembler;
|
||||
|
||||
begin
|
||||
Result := False;
|
||||
if (Debugger = nil) or not(Debugger.State = dsPause) then
|
||||
exit;
|
||||
|
||||
ADisassembler := TFpDebugDebugger(Debugger).FDbgController.CurrentProcess.Disassembler;
|
||||
Sym:=nil;
|
||||
ASrcFileLine:=0;
|
||||
ASrcFileName:='';
|
||||
@ -1324,10 +1326,110 @@ begin
|
||||
ARange.RangeStartAddr:=AnAddr;
|
||||
ALastAddr:=0;
|
||||
|
||||
Assert(ALinesBefore<>0,'TFPDBGDisassembler.PrepareEntries LinesBefore not supported');
|
||||
if (ALinesBefore > 0) and
|
||||
ADisassembler.CanReverseDisassemble then
|
||||
begin
|
||||
AReversedRange := TDBGDisassemblerEntryRange.Create;
|
||||
tmpAddr := AnAddr; // do not modify AnAddr in this loop
|
||||
// Large enough block of memory for whole loop
|
||||
sz := ADisassembler.MaxInstructionSize * ALinesBefore;
|
||||
SetLength(CodeBin, sz);
|
||||
|
||||
if ALinesAfter < 1 then exit;
|
||||
sz := ALinesAfter * TFpDebugDebugger(Debugger).FDbgController.CurrentProcess.Disassembler.MaxInstructionSize;
|
||||
// TODO: Check if AnAddr is at lower address than length(CodeBin)
|
||||
// and ensure ReadData size doesn't exceed available target memory.
|
||||
// Fill out of bounds memory in buffer with "safe" value e.g. 0
|
||||
if sz + ADisassembler.MaxInstructionSize > AnAddr then
|
||||
begin
|
||||
FillByte(CodeBin[0], sz, 0);
|
||||
// offset into buffer where active memory should start
|
||||
bufOffset := sz - AnAddr;
|
||||
// size of active memory to read
|
||||
sz := integer(AnAddr);
|
||||
end
|
||||
else
|
||||
begin
|
||||
bufOffset := 0;
|
||||
end;
|
||||
|
||||
// Everything now counts back from starting address...
|
||||
bytesDisassembled := 0;
|
||||
// Only read up to byte before this address
|
||||
if not TFpDebugDebugger(Debugger).ReadData(tmpAddr-sz, sz, CodeBin[bufOffset]) then
|
||||
DebugLn(Format('Reverse disassemble: Failed to read memory at %s.', [FormatAddress(tmpAddr)]))
|
||||
else
|
||||
for i := 0 to ALinesBefore-1 do
|
||||
begin
|
||||
if bytesDisassembled >= sz then
|
||||
break;
|
||||
|
||||
tmpPointer := TDBGPtr(@CodeBin[bufOffset]) + TDBGPtr(sz) - TDBGPtr(bytesDisassembled);
|
||||
p := pointer(tmpPointer);
|
||||
ADisassembler.ReverseDisassemble(p, ADump, AStatement); // give statement before pointer p, pointer p points to decoded instruction on return
|
||||
prevInstructionSize := tmpPointer - PtrUInt(p);
|
||||
bytesDisassembled := bytesDisassembled + prevInstructionSize;
|
||||
DebugLn(DBG_VERBOSE, format('Disassembled: [%.8X: %s] %s',[tmpAddr, ADump, Astatement]));
|
||||
|
||||
Dec(tmpAddr, prevInstructionSize);
|
||||
Sym := TFpDebugDebugger(Debugger).FDbgController.CurrentProcess.FindProcSymbol(tmpAddr);
|
||||
// If this is the last statement for this source-code-line, fill the
|
||||
// SrcStatementCount from the prior statements.
|
||||
if (assigned(sym) and ((ASrcFileName<>sym.FileName) or (ASrcFileLine<>sym.Line))) or
|
||||
(not assigned(sym) and ((ASrcFileLine<>0) or (ASrcFileName<>''))) then
|
||||
begin
|
||||
for j := 0 to StatIndex-1 do
|
||||
begin
|
||||
with AReversedRange.EntriesPtr[FirstIndex+j]^ do
|
||||
SrcStatementCount := StatIndex;
|
||||
end;
|
||||
StatIndex := 0;
|
||||
FirstIndex := i;
|
||||
end;
|
||||
|
||||
if assigned(sym) then
|
||||
begin
|
||||
ASrcFileName:=sym.FileName;
|
||||
ASrcFileLine:=sym.Line;
|
||||
sym.ReleaseReference;
|
||||
end
|
||||
else
|
||||
begin
|
||||
ASrcFileName:='';
|
||||
ASrcFileLine:=0;
|
||||
end;
|
||||
AnEntry.Addr := tmpAddr;
|
||||
AnEntry.Dump := ADump;
|
||||
AnEntry.Statement := AStatement;
|
||||
AnEntry.SrcFileLine:=ASrcFileLine;
|
||||
AnEntry.SrcFileName:=ASrcFileName;
|
||||
AnEntry.SrcStatementIndex:=StatIndex; // should be inverted for reverse parsing
|
||||
AReversedRange.Append(@AnEntry);
|
||||
inc(StatIndex);
|
||||
end;
|
||||
|
||||
if AReversedRange.Count>0 then
|
||||
begin
|
||||
// Update start of range
|
||||
ARange.RangeStartAddr := tmpAddr;
|
||||
// Copy range in revese order of entries
|
||||
for i := 0 to AReversedRange.Count-1 do
|
||||
begin
|
||||
// Reverse order of statements
|
||||
with AReversedRange.Entries[AReversedRange.Count-1 - i] do
|
||||
begin
|
||||
for j := 0 to SrcStatementCount-1 do
|
||||
SrcStatementIndex := SrcStatementCount - 1 - j;
|
||||
end;
|
||||
|
||||
ARange.Append(AReversedRange.EntriesPtr[AReversedRange.Count-1 - i]);
|
||||
end;
|
||||
end;
|
||||
// Entries are all pointers, don't free entries
|
||||
FreeAndNil(AReversedRange);
|
||||
end;
|
||||
|
||||
if ALinesAfter > 0 then
|
||||
begin
|
||||
sz := ALinesAfter * ADisassembler.MaxInstructionSize;
|
||||
SetLength(CodeBin, sz);
|
||||
bytesDisassembled := 0;
|
||||
if not TFpDebugDebugger(Debugger).ReadData(AnAddr, sz, CodeBin[0]) then
|
||||
@ -1339,8 +1441,7 @@ begin
|
||||
for i := 0 to ALinesAfter-1 do
|
||||
begin
|
||||
p := @CodeBin[bytesDisassembled];
|
||||
TFpDebugDebugger(Debugger).FDbgController.CurrentProcess
|
||||
.Disassembler.Disassemble(p, ADump, AStatement);
|
||||
ADisassembler.Disassemble(p, ADump, AStatement);
|
||||
|
||||
prevInstructionSize := p - @CodeBin[bytesDisassembled];
|
||||
bytesDisassembled := bytesDisassembled + prevInstructionSize;
|
||||
@ -1378,6 +1479,9 @@ begin
|
||||
inc(StatIndex);
|
||||
Inc(AnAddr, prevInstructionSize);
|
||||
end;
|
||||
end
|
||||
else
|
||||
ALastAddr := AnAddr;
|
||||
|
||||
if ARange.Count>0 then
|
||||
begin
|
||||
|
Loading…
Reference in New Issue
Block a user