LazDebuggerFp, FpDebug: Disassembler now annotates lines with call,jmp,je,... with info on the target address.

This commit is contained in:
Martin 2023-03-15 00:19:25 +01:00
parent 57e0738de1
commit ee4e48864e
5 changed files with 104 additions and 5 deletions

View File

@ -1010,6 +1010,9 @@ type
SrcFileLine: Integer; // Line in SrcFile
SrcStatementIndex: SmallInt; // Index of Statement, within list of Stmnt of the same SrcLine
SrcStatementCount: SmallInt; // Count of Statements for this SrcLine
TargetAddr: TDbgPtr; // Absolute Addr for relative jump/call
TargetName, TargetFile: String;
TargetLine: Integer;
end;
TDisassemblerAddressValidity =

View File

@ -632,6 +632,11 @@ type
function InstructionLength: Integer; virtual;
end;
TDbgInstInfo = record
InstrType: (itAny, itJump);
InstrTargetOffs: Int64; // offset from the START address of instruction
end;
{ TDbgAsmDecoder }
TDbgAsmDecoder = class
@ -643,7 +648,8 @@ type
public
constructor Create(AProcess: TDbgProcess); virtual; abstract;
procedure Disassemble(var AAddress: Pointer; out ACodeBytes: String; out ACode: String); virtual; abstract;
procedure Disassemble(var AAddress: Pointer; out ACodeBytes: String; out ACode: String; out AnInfo: TDbgInstInfo); virtual; overload;
procedure Disassemble(var AAddress: Pointer; out ACodeBytes: String; out ACode: String); virtual; abstract; overload;
procedure ReverseDisassemble(var AAddress: Pointer; out ACodeBytes: String; out ACode: String); virtual;
function GetInstructionInfo(AnAddress: TDBGPtr): TDbgAsmInstruction; virtual; abstract;
@ -1830,6 +1836,13 @@ begin
Result := false;
end;
procedure TDbgAsmDecoder.Disassemble(var AAddress: Pointer; out
ACodeBytes: String; out ACode: String; out AnInfo: TDbgInstInfo);
begin
AnInfo := Default(TDbgInstInfo);
Disassemble(AAddress, ACodeBytes, ACode);
end;
// Naive backwards scanner, decode MaxInstructionSize
// if pointer to next instruction matches, done!
// If not decrease instruction size and try again.

View File

@ -562,6 +562,7 @@ type
constructor Create(AProcess: TDbgProcess); override;
destructor Destroy; override;
procedure Disassemble(var AAddress: Pointer; out ACodeBytes: String; out ACode: String; out AnInfo: TDbgInstInfo); override;
procedure Disassemble(var AAddress: Pointer; out ACodeBytes: String; out ACode: String); override;
function GetInstructionInfo(AnAddress: TDBGPtr): TDbgAsmInstruction; override;
@ -4915,7 +4916,8 @@ begin
Result := FInstruction.OpCode.Opcode;
end;
procedure TX86AsmDecoder.Disassemble(var AAddress: Pointer; out ACodeBytes: String; out ACode: String);
procedure TX86AsmDecoder.Disassemble(var AAddress: Pointer; out
ACodeBytes: String; out ACode: String; out AnInfo: TDbgInstInfo);
const
MEMPTR: array[TOperandSize] of string = (
{ os0 } '',
@ -4938,10 +4940,12 @@ var
Instr: TInstruction;
S, Soper: String;
n, i: Integer;
TargetAddrOffs: Int64;
HasMem: Boolean;
OpcodeName: String;
Code: PByte;
begin
AnInfo := default(TDbgInstInfo);
Code := AAddress;
Disassembler.Disassemble(FProcess.Mode, AAddress, Instr);
@ -4989,6 +4993,28 @@ begin
{$endif}
if (Instr.OpCode.Opcode in [OPcall, OPj__, OPjcxz, OPjecxz, OPjmp, OPjmpe, OPjrcxz]) and
(Instr.OperCnt = 1) and
(hvfSigned in Instr.Operand[1].FormatFlags)
then begin
TargetAddrOffs := 1;
case Instr.Operand[1].ByteCount of
1: TargetAddrOffs := smallint(PByte(@Code[Instr.Operand[1].CodeIndex])^);
2: TargetAddrOffs := shortint(PWord(@Code[Instr.Operand[1].CodeIndex])^);
4: TargetAddrOffs := Integer(PDWord(@Code[Instr.Operand[1].CodeIndex])^);
8: TargetAddrOffs := Int64(PQWord(@Code[Instr.Operand[1].CodeIndex])^);
end;
if TargetAddrOffs <> 1 then begin
AnInfo.InstrType := itJump;
{$PUSH}{$R-}{$Q-}
if not (hvfPrefixPositive in Instr.Operand[1].FormatFlags) then
TargetAddrOffs := -TargetAddrOffs;
AnInfo.InstrTargetOffs := TDbgPtr(AAddress) - TDbgPtr(Code) + TargetAddrOffs;
{$POP}
end;
end;
OpcodeName := OPCODE_PREFIX[Instr.OpCode.Prefix];
OpcodeName := OpcodeName + OPCODE_NAME[Instr.OpCode.Opcode];
OpcodeName := OpcodeName + OPCODE_SUFFIX[Instr.OpCode.Suffix];
@ -5021,6 +5047,14 @@ begin
ACodeBytes := S;
end;
procedure TX86AsmDecoder.Disassemble(var AAddress: Pointer; out
ACodeBytes: String; out ACode: String);
var
AnInfo: TDbgInstInfo;
begin
Disassemble(AAddress, ACodeBytes, ACode, AnInfo);
end;
function TX86AsmDecoder.GetInstructionInfo(AnAddress: TDBGPtr): TDbgAsmInstruction;
begin
if (FLastInstr = nil) or (FLastInstr.RefCount > 1) then begin

View File

@ -2136,6 +2136,7 @@ var
ADisassembler: TDbgAsmDecoder;
AOffset: longint;
RealReadLen: Cardinal;
AnInfo: TDbgInstInfo;
procedure AddInfoToRange(ALineAddr: TDBGPtr; ATargetRange: TDBGDisassemblerEntryRange);
var
@ -2176,6 +2177,27 @@ var
AnEntry.FuncName := AFuncName;
AnEntry.SrcStatementIndex:=StatIndex;
AnEntry.Offset := AOffset;
AnEntry.TargetAddr := 0;
AnEntry.TargetName := '';
AnEntry.TargetFile := '';
AnEntry.TargetLine := 0;
if AnInfo.InstrType = itJump then begin
{$PUSH}{$R-}{$Q-}
AnEntry.TargetAddr := ALineAddr + AnInfo.InstrTargetOffs;
{$POP}
Sym := TFpDebugDebugger(Debugger).FDbgController.CurrentProcess.FindProcSymbol(AnEntry.TargetAddr);
if Sym <> nil then begin
AnEntry.TargetName := Sym.Name;
AnEntry.TargetFile := Sym.FileName;
AnEntry.TargetLine := Sym.Line;
{$PUSH}{$R-}{$Q-}
AOffset := int32(int64(AnEntry.TargetAddr) - int64(Sym.Address.Address));
{$POP}
if AOffset <> 0 then
AnEntry.TargetName := AnEntry.TargetName + '+' + IntToStr(AOffset);
Sym.ReleaseReference;
end;
end;
ATargetRange.Append(@AnEntry);
inc(StatIndex);
end;
@ -2284,7 +2306,7 @@ begin
else begin
while tmpAddr < AnAddr do begin
p := @CodeBin[bytesDisassembled];
ADisassembler.Disassemble(p, ADump, AStatement);
ADisassembler.Disassemble(p, ADump, AStatement, AnInfo);
prevInstructionSize := p - @CodeBin[bytesDisassembled];
if prevInstructionSize = 0 then
@ -2308,6 +2330,10 @@ begin
AnEntry.FuncName := '';
AnEntry.SrcStatementIndex:=StatIndex;
AnEntry.Offset := -1;
AnEntry.TargetAddr := 0;
AnEntry.TargetName := '';
AnEntry.TargetFile := '';
AnEntry.TargetLine := 0;
ARange.Append(@AnEntry);
inc(StatIndex);
end;
@ -2332,7 +2358,7 @@ begin
for i := 0 to ALinesAfter-1 do
begin
p := @CodeBin[bytesDisassembled];
ADisassembler.Disassemble(p, ADump, AStatement);
ADisassembler.Disassemble(p, ADump, AStatement, AnInfo);
prevInstructionSize := p - @CodeBin[bytesDisassembled];
bytesDisassembled := bytesDisassembled + prevInstructionSize;

View File

@ -44,6 +44,7 @@ type
FileName, FullFileName: String;
SourceLine: Integer;
ImageIndex: Integer;
TargetAddr: TDbgPtr; // Absolute Addr for relative jump/call
end;
TAsmDlgLineEntries = Array of TAsmDlgLineEntry;
@ -1068,7 +1069,7 @@ var
DoneLocation: TDBGPtr;
DoneTopLine, DoneLineCount: Integer;
DoneCountBefore, DoneCountAfter: Integer;
Line, Idx: Integer;
Line, Idx, W: Integer;
Itm, NextItm, PrevItm: PDisassemblerEntry;
LineIsSrc, HasLineOutOfRange: Boolean;
s: String;
@ -1091,6 +1092,11 @@ begin
end;
FUpdating := True;
if FDebugger = nil
then W := 16
else W := FDebugger.TargetWidth div 4;
try
FUpdateNeeded := False;
DoneLocation := FCurrentLocation;
@ -1260,6 +1266,23 @@ begin
ALineMap[Line].Statement := Itm^.Statement;
ALineMap[Line].SourceLine := Itm^.SrcFileLine;
ALineMap[Line].ImageIndex := -1;
ALineMap[Line].TargetAddr := Itm^.TargetAddr;
s := StringOfChar(' ', min(4, 40 - Length(ALineMap[Line].Statement))) + '#';
if Itm^.TargetAddr <> 0 then begin
ALineMap[Line].Statement := ALineMap[Line].Statement + s + ' $' + IntToHex(Itm^.TargetAddr, W);
s := '';
end;
if Itm^.TargetName <> '' then begin
ALineMap[Line].Statement := ALineMap[Line].Statement + s + ' ' + Itm^.TargetName;
s := '';
end;
if Itm^.TargetFile <> '' then begin
ALineMap[Line].Statement := ALineMap[Line].Statement + s + ' ' + ExtractFileName(Itm^.TargetFile);
if Itm^.TargetLine <> 0 then
ALineMap[Line].Statement := ALineMap[Line].Statement + ':' + IntToStr(Itm^.TargetLine);
s := '';
end;
inc(Line);
inc(idx);