mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-11-10 21:09:32 +01:00
FpDebugServer: Added disassemble command
git-svn-id: trunk@49287 -
This commit is contained in:
parent
bff355cf81
commit
a8ae389b6f
@ -205,6 +205,28 @@ begin
|
|||||||
end;
|
end;
|
||||||
JSonEvent.Add('callstack', JSonStackArray);
|
JSonEvent.Add('callstack', JSonStackArray);
|
||||||
end;
|
end;
|
||||||
|
if length(AnEvent.DisassemblerEntryArray)>0 then
|
||||||
|
begin
|
||||||
|
JSonStackArray := TJSONArray.Create;
|
||||||
|
for i := 0 to high(AnEvent.DisassemblerEntryArray) do
|
||||||
|
begin
|
||||||
|
JSonStackEntry := TJSONObject.Create;
|
||||||
|
JSonStackEntry.Add('address', FormatAddress(AnEvent.DisassemblerEntryArray[i].Addr));
|
||||||
|
JSonStackEntry.Add('dump', AnEvent.DisassemblerEntryArray[i].Dump);
|
||||||
|
JSonStackEntry.Add('statement', AnEvent.DisassemblerEntryArray[i].Statement);
|
||||||
|
JSonStackEntry.Add('srcfilename', AnEvent.DisassemblerEntryArray[i].SrcFileName);
|
||||||
|
JSonStackEntry.Add('srcfileline', AnEvent.DisassemblerEntryArray[i].SrcFileLine);
|
||||||
|
JSonStackEntry.Add('srcstatementindex', AnEvent.DisassemblerEntryArray[i].SrcStatementIndex);
|
||||||
|
JSonStackEntry.Add('srcstatementcount', AnEvent.DisassemblerEntryArray[i].SrcStatementCount);
|
||||||
|
JSonStackEntry.Add('functionname', AnEvent.DisassemblerEntryArray[i].FuncName);
|
||||||
|
JSonStackEntry.Add('offset', AnEvent.DisassemblerEntryArray[i].Offset);
|
||||||
|
JSonStackArray.Add(JSonStackEntry);
|
||||||
|
end;
|
||||||
|
JSonEvent.Add('disassembly', JSonStackArray);
|
||||||
|
JSonEvent.Add('startaddress', FormatAddress(AnEvent.Addr1));
|
||||||
|
JSonEvent.Add('endaddress', FormatAddress(AnEvent.Addr2));
|
||||||
|
JSonEvent.Add('lastentryendaddress', FormatAddress(AnEvent.Addr3));
|
||||||
|
end;
|
||||||
result := JSonEvent.AsJSON;
|
result := JSonEvent.AsJSON;
|
||||||
finally
|
finally
|
||||||
JSonEvent.Free;
|
JSonEvent.Free;
|
||||||
|
|||||||
@ -49,6 +49,7 @@ type
|
|||||||
Line: integer;
|
Line: integer;
|
||||||
end;
|
end;
|
||||||
TFpDebugEventCallStackEntryArray = array of TFpDebugEventCallStackEntry;
|
TFpDebugEventCallStackEntryArray = array of TFpDebugEventCallStackEntry;
|
||||||
|
TFpDebugEventDisassemblerEntryArray = array of TDisassemblerEntry;
|
||||||
|
|
||||||
// This record is used to pass debugging-events. Not every field is applicable for each type of event.
|
// This record is used to pass debugging-events. Not every field is applicable for each type of event.
|
||||||
TFpDebugEvent = record
|
TFpDebugEvent = record
|
||||||
@ -63,7 +64,11 @@ type
|
|||||||
BreakpointAddr: TDBGPtr;
|
BreakpointAddr: TDBGPtr;
|
||||||
LocationRec: TDBGLocationRec;
|
LocationRec: TDBGLocationRec;
|
||||||
Validity: TDebuggerDataState;
|
Validity: TDebuggerDataState;
|
||||||
|
Addr1: TDBGPtr;
|
||||||
|
Addr2: TDBGPtr;
|
||||||
|
Addr3: TDBGPtr;
|
||||||
StackEntryArray: TFpDebugEventCallStackEntryArray;
|
StackEntryArray: TFpDebugEventCallStackEntryArray;
|
||||||
|
DisassemblerEntryArray: TFpDebugEventDisassemblerEntryArray;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// Each listener should implement this interface.
|
// Each listener should implement this interface.
|
||||||
@ -317,6 +322,10 @@ begin
|
|||||||
AnEvent.LocationRec.Address:=0;
|
AnEvent.LocationRec.Address:=0;
|
||||||
AnEvent.Validity:=ddsUnknown;
|
AnEvent.Validity:=ddsUnknown;
|
||||||
SetLength(AnEvent.StackEntryArray,0);
|
SetLength(AnEvent.StackEntryArray,0);
|
||||||
|
SetLength(AnEvent.DisassemblerEntryArray,0);
|
||||||
|
AnEvent.Addr1:=0;
|
||||||
|
AnEvent.Addr2:=0;
|
||||||
|
AnEvent.Addr3:=0;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TFpDebugThread.FControllerDebugInfoLoaded(Sender: TObject);
|
procedure TFpDebugThread.FControllerDebugInfoLoaded(Sender: TObject);
|
||||||
|
|||||||
@ -200,12 +200,150 @@ type
|
|||||||
procedure ComposeSuccessEvent(var AnEvent: TFpDebugEvent); override;
|
procedure ComposeSuccessEvent(var AnEvent: TFpDebugEvent); override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TFpDebugThreadDisassembleCommand }
|
||||||
|
|
||||||
|
TFpDebugThreadDisassembleCommand = class(TFpDebugThreadCommand)
|
||||||
|
private
|
||||||
|
FAddressValue: TDBGPtr;
|
||||||
|
FLines: integer;
|
||||||
|
FDisassemblerEntryArray: TFpDebugEventDisassemblerEntryArray;
|
||||||
|
FStartAddr: TDBGPtr;
|
||||||
|
FEndAddr: TDBGPtr;
|
||||||
|
FLastEntryEndAddr: TDBGPtr;
|
||||||
|
function GetAddress: string;
|
||||||
|
procedure SetAddress(AValue: string);
|
||||||
|
public
|
||||||
|
constructor Create(AListenerIdentifier: integer; AnUID: variant; AOnLog: TOnLog); override;
|
||||||
|
function Execute(AController: TDbgController; out DoProcessLoop: boolean): boolean; override;
|
||||||
|
class function TextName: string; override;
|
||||||
|
procedure ComposeSuccessEvent(var AnEvent: TFpDebugEvent); override;
|
||||||
|
published
|
||||||
|
property Address: string read GetAddress write SetAddress;
|
||||||
|
property Lines: integer read FLines write FLines;
|
||||||
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
{ TFpDebugThreadCommandList }
|
uses
|
||||||
|
FpDbgDisasX86;
|
||||||
|
|
||||||
|
{ TFpDebugThreadDisassembleCommand }
|
||||||
|
|
||||||
|
function TFpDebugThreadDisassembleCommand.GetAddress: string;
|
||||||
|
begin
|
||||||
|
result := FormatAddress(FAddressValue);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TFpDebugThreadDisassembleCommand.SetAddress(AValue: string);
|
||||||
|
begin
|
||||||
|
FAddressValue := Hex2Dec(AValue);
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TFpDebugThreadDisassembleCommand.Create(AListenerIdentifier: integer; AnUID: variant; AOnLog: TOnLog);
|
||||||
|
begin
|
||||||
|
inherited Create(AListenerIdentifier, AnUID, AOnLog);
|
||||||
|
FLines:=10;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TFpDebugThreadDisassembleCommand.Execute(AController: TDbgController; out DoProcessLoop: boolean): boolean;
|
||||||
var
|
var
|
||||||
GFpDebugThreadCommandList: TFpDebugThreadCommandList = nil;
|
AnAddr: TDBGPtr;
|
||||||
|
CodeBin: array[0..20] of byte;
|
||||||
|
p: pointer;
|
||||||
|
ADump,
|
||||||
|
AStatement,
|
||||||
|
ASrcFileName: string;
|
||||||
|
ASrcFileLine: integer;
|
||||||
|
i,j: Integer;
|
||||||
|
Sym: TFpDbgSymbol;
|
||||||
|
StatIndex: integer;
|
||||||
|
FirstIndex: integer;
|
||||||
|
|
||||||
|
begin
|
||||||
|
result := false;
|
||||||
|
DoProcessLoop:=false;
|
||||||
|
if not assigned(AController.CurrentProcess) then
|
||||||
|
begin
|
||||||
|
log('Failed to dissasemble: No process', dllInfo);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
Sym:=nil;
|
||||||
|
ASrcFileLine:=0;
|
||||||
|
ASrcFileName:='';
|
||||||
|
StatIndex:=0;
|
||||||
|
FirstIndex:=0;
|
||||||
|
if FAddressValue=0 then
|
||||||
|
FStartAddr:=AController.CurrentProcess.GetInstructionPointerRegisterValue
|
||||||
|
else
|
||||||
|
FStartAddr:=FAddressValue;
|
||||||
|
AnAddr:=FStartAddr;
|
||||||
|
setlength(FDisassemblerEntryArray, FLines);
|
||||||
|
|
||||||
|
for i := 0 to FLines-1 do
|
||||||
|
begin
|
||||||
|
FDisassemblerEntryArray[i].Addr:=AnAddr;
|
||||||
|
if not AController.CurrentProcess.ReadData(AnAddr, sizeof(CodeBin),CodeBin) then
|
||||||
|
begin
|
||||||
|
Log(Format('Disassemble: Failed to read memory at %s.', [FormatAddress(AnAddr)]), dllDebug);
|
||||||
|
FDisassemblerEntryArray[i].Statement := 'Failed to read memory';
|
||||||
|
inc(AnAddr);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
p := @CodeBin;
|
||||||
|
FpDbgDisasX86.Disassemble(p, AController.CurrentProcess.Mode=dm64, ADump, AStatement);
|
||||||
|
|
||||||
|
Sym := AController.CurrentProcess.FindSymbol(AnAddr);
|
||||||
|
|
||||||
|
// 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
|
||||||
|
FDisassemblerEntryArray[FirstIndex+j].SrcStatementCount:=StatIndex;
|
||||||
|
StatIndex:=0;
|
||||||
|
FirstIndex:=i;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if assigned(sym) then
|
||||||
|
begin
|
||||||
|
ASrcFileName:=sym.FileName;
|
||||||
|
ASrcFileLine:=sym.Line;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
ASrcFileName:='';
|
||||||
|
ASrcFileLine:=0;
|
||||||
|
end;
|
||||||
|
FDisassemblerEntryArray[i].Dump := ADump;
|
||||||
|
FDisassemblerEntryArray[i].Statement := AStatement;
|
||||||
|
FDisassemblerEntryArray[i].SrcFileLine:=ASrcFileLine;
|
||||||
|
FDisassemblerEntryArray[i].SrcFileName:=ASrcFileName;
|
||||||
|
FDisassemblerEntryArray[i].SrcStatementIndex:=StatIndex;
|
||||||
|
inc(StatIndex);
|
||||||
|
FEndAddr:=AnAddr;
|
||||||
|
Inc(AnAddr, {%H-}PtrUInt(p) - {%H-}PtrUInt(@CodeBin));
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
FLastEntryEndAddr:=AnAddr;
|
||||||
|
result := true;
|
||||||
|
end;
|
||||||
|
|
||||||
|
class function TFpDebugThreadDisassembleCommand.TextName: string;
|
||||||
|
begin
|
||||||
|
result := 'disassemble';
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TFpDebugThreadDisassembleCommand.ComposeSuccessEvent(var AnEvent: TFpDebugEvent);
|
||||||
|
begin
|
||||||
|
inherited ComposeSuccessEvent(AnEvent);
|
||||||
|
AnEvent.DisassemblerEntryArray := FDisassemblerEntryArray;
|
||||||
|
AnEvent.Addr1:=FStartAddr;
|
||||||
|
AnEvent.Addr2:=FEndAddr;
|
||||||
|
AnEvent.Addr3:=FLastEntryEndAddr;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TFpDebugThreadSetConsoleTtyCommand }
|
{ TFpDebugThreadSetConsoleTtyCommand }
|
||||||
|
|
||||||
@ -582,6 +720,11 @@ begin
|
|||||||
result := 'addbreakpoint';
|
result := 'addbreakpoint';
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TFpDebugThreadCommandList }
|
||||||
|
|
||||||
|
var
|
||||||
|
GFpDebugThreadCommandList: TFpDebugThreadCommandList = nil;
|
||||||
|
|
||||||
class function TFpDebugThreadCommandList.instance: TFpDebugThreadCommandList;
|
class function TFpDebugThreadCommandList.instance: TFpDebugThreadCommandList;
|
||||||
begin
|
begin
|
||||||
if not assigned(GFpDebugThreadCommandList) then
|
if not assigned(GFpDebugThreadCommandList) then
|
||||||
@ -661,6 +804,7 @@ initialization
|
|||||||
TFpDebugThreadCommandList.instance.Add(TFpDebugThreadGetLocationInfoCommand);
|
TFpDebugThreadCommandList.instance.Add(TFpDebugThreadGetLocationInfoCommand);
|
||||||
TFpDebugThreadCommandList.instance.Add(TFpDebugThreadEvaluateCommand);
|
TFpDebugThreadCommandList.instance.Add(TFpDebugThreadEvaluateCommand);
|
||||||
TFpDebugThreadCommandList.instance.Add(TFpDebugThreadStackTraceCommand);
|
TFpDebugThreadCommandList.instance.Add(TFpDebugThreadStackTraceCommand);
|
||||||
|
TFpDebugThreadCommandList.instance.Add(TFpDebugThreadDisassembleCommand);
|
||||||
finalization
|
finalization
|
||||||
GFpDebugThreadCommandList.Free;
|
GFpDebugThreadCommandList.Free;
|
||||||
end.
|
end.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user