mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-15 20:39:14 +02:00
FpDebug: very basic/partial implementation for DW_OP_call_frame_cfa (register only)
This commit is contained in:
parent
747b9e5552
commit
a5c48c104e
@ -44,7 +44,7 @@ uses
|
|||||||
Classes, SysUtils, Maps, FpDbgUtil, FpDbgLoader, FpDbgInfo,
|
Classes, SysUtils, Maps, FpDbgUtil, FpDbgLoader, FpDbgInfo,
|
||||||
FpdMemoryTools, {$ifdef FORCE_LAZLOGGER_DUMMY} LazLoggerDummy {$else} LazLoggerBase {$endif}, LazClasses, LazFileUtils, DbgIntfBaseTypes,
|
FpdMemoryTools, {$ifdef FORCE_LAZLOGGER_DUMMY} LazLoggerDummy {$else} LazLoggerBase {$endif}, LazClasses, LazFileUtils, DbgIntfBaseTypes,
|
||||||
fgl, DbgIntfDebuggerBase, fpDbgSymTableContext,
|
fgl, DbgIntfDebuggerBase, fpDbgSymTableContext,
|
||||||
FpDbgCommon, FpErrorMessages, LazDebuggerIntf;
|
FpDbgCommon, FpErrorMessages, FpDbgDwarfCFI, LazDebuggerIntf;
|
||||||
|
|
||||||
type
|
type
|
||||||
TFPDEvent = (
|
TFPDEvent = (
|
||||||
@ -752,6 +752,7 @@ type
|
|||||||
procedure InitializeLoaders; virtual;
|
procedure InitializeLoaders; virtual;
|
||||||
procedure SetFileName(const AValue: String);
|
procedure SetFileName(const AValue: String);
|
||||||
procedure SetMode(AMode: TFPDMode); experimental; // for testcase
|
procedure SetMode(AMode: TFPDMode); experimental; // for testcase
|
||||||
|
function FindCallFrameInfo(AnAddress: TDBGPtr; out CIE: TDwarfCIE; out Row: TDwarfCallFrameInformationRow): Boolean;
|
||||||
public
|
public
|
||||||
constructor Create(const AProcess: TDbgProcess); virtual;
|
constructor Create(const AProcess: TDbgProcess); virtual;
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
@ -861,6 +862,7 @@ type
|
|||||||
FWatchPointData: TFpWatchPointData;
|
FWatchPointData: TFpWatchPointData;
|
||||||
FProcessConfig: TDbgProcessConfig;
|
FProcessConfig: TDbgProcessConfig;
|
||||||
FConfig: TDbgConfig;
|
FConfig: TDbgConfig;
|
||||||
|
function DoGetCfiFrameBase(AScope: TFpDbgLocationContext; AnAddr: TDBGPtr): TDBGPtr;
|
||||||
function GetDisassembler: TDbgAsmDecoder;
|
function GetDisassembler: TDbgAsmDecoder;
|
||||||
function GetLastLibrariesLoaded: TDbgLibraryArr;
|
function GetLastLibrariesLoaded: TDbgLibraryArr;
|
||||||
function GetLastLibrariesUnloaded: TDbgLibraryArr;
|
function GetLastLibrariesUnloaded: TDbgLibraryArr;
|
||||||
@ -946,6 +948,7 @@ type
|
|||||||
function FindProcSymbol(AAdress: TDbgPtr): TFpSymbol; overload;
|
function FindProcSymbol(AAdress: TDbgPtr): TFpSymbol; overload;
|
||||||
function FindSymbolScope(AThreadId, AStackFrame: Integer): TFpDbgSymbolScope;
|
function FindSymbolScope(AThreadId, AStackFrame: Integer): TFpDbgSymbolScope;
|
||||||
function FindProcStartEndPC(const AAdress: TDbgPtr; out AStartPC, AEndPC: TDBGPtr): boolean;
|
function FindProcStartEndPC(const AAdress: TDbgPtr; out AStartPC, AEndPC: TDBGPtr): boolean;
|
||||||
|
function FindCallFrameInfo(AnAddress: TDBGPtr; out CIE: TDwarfCIE; out Row: TDwarfCallFrameInformationRow): Boolean; reintroduce;
|
||||||
|
|
||||||
function GetLineAddresses(AFileName: String; ALine: Cardinal; var AResultList: TDBGPtrArray; ASymInstance: TDbgInstance = nil;
|
function GetLineAddresses(AFileName: String; ALine: Cardinal; var AResultList: TDBGPtrArray; ASymInstance: TDbgInstance = nil;
|
||||||
AFindSibling: TGetLineAddrFindSibling = fsNone; AMaxSiblingDistance: integer = 0): Boolean;
|
AFindSibling: TGetLineAddrFindSibling = fsNone; AMaxSiblingDistance: integer = 0): Boolean;
|
||||||
@ -1089,6 +1092,16 @@ const
|
|||||||
'deFailed'
|
'deFailed'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
(* TODO: refactor those methods to work with a Context, and move (partly) to CFI *)
|
||||||
|
// GetCanonicalFrameAddress: Get FrameBase
|
||||||
|
function GetCanonicalFrameAddress(RegisterValueList: TDbgRegisterValueList;
|
||||||
|
Row: TDwarfCallFrameInformationRow; out FrameBase: TDBGPtr): Boolean;
|
||||||
|
function TryObtainNextCallFrame( CurrentCallStackEntry: TDbgCallstackEntry;
|
||||||
|
CIE: TDwarfCIE; Size, NextIdx: Integer; Thread: TDbgThread;
|
||||||
|
Row: TDwarfCallFrameInformationRow; Process: TDbgProcess;
|
||||||
|
out NewCallStackEntry: TDbgCallstackEntry): Boolean;
|
||||||
|
|
||||||
function GetDbgProcessClass(ATargetInfo: TTargetDescriptor): TOSDbgClasses;
|
function GetDbgProcessClass(ATargetInfo: TTargetDescriptor): TOSDbgClasses;
|
||||||
|
|
||||||
procedure RegisterDbgOsClasses(ADbgOsClasses: TOSDbgClasses);
|
procedure RegisterDbgOsClasses(ADbgOsClasses: TOSDbgClasses);
|
||||||
@ -1097,7 +1110,6 @@ implementation
|
|||||||
|
|
||||||
uses
|
uses
|
||||||
FpDbgDwarfDataClasses,
|
FpDbgDwarfDataClasses,
|
||||||
FpDbgDwarfCFI,
|
|
||||||
FpDbgDwarf;
|
FpDbgDwarf;
|
||||||
|
|
||||||
type
|
type
|
||||||
@ -1106,7 +1118,7 @@ type
|
|||||||
function Find(a: TOSDbgClasses): Integer;
|
function Find(a: TOSDbgClasses): Integer;
|
||||||
end;
|
end;
|
||||||
var
|
var
|
||||||
DBG_VERBOSE, DBG_WARNINGS, DBG_BREAKPOINTS, FPDBG_COMMANDS: PLazLoggerLogGroup;
|
DBG_VERBOSE, DBG_WARNINGS, DBG_BREAKPOINTS, FPDBG_COMMANDS, FPDBG_DWARF_CFI_WARNINGS: PLazLoggerLogGroup;
|
||||||
RegisteredDbgProcessClasses: TOSDbgClassesList;
|
RegisteredDbgProcessClasses: TOSDbgClassesList;
|
||||||
|
|
||||||
function GetDbgProcessClass(ATargetInfo: TTargetDescriptor): TOSDbgClasses;
|
function GetDbgProcessClass(ATargetInfo: TTargetDescriptor): TOSDbgClasses;
|
||||||
@ -2315,6 +2327,15 @@ begin
|
|||||||
FMode := AMode;
|
FMode := AMode;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TDbgInstance.FindCallFrameInfo(AnAddress: TDBGPtr; out CIE: TDwarfCIE; out
|
||||||
|
Row: TDwarfCallFrameInformationRow): Boolean;
|
||||||
|
begin
|
||||||
|
if FDbgInfo <> nil then
|
||||||
|
Result := (FDbgInfo as TFpDwarfInfo).FindCallFrameInfo(AnAddress, CIE, Row)
|
||||||
|
else
|
||||||
|
Result := False;
|
||||||
|
end;
|
||||||
|
|
||||||
function TDbgInstance.GetPointerSize: Integer;
|
function TDbgInstance.GetPointerSize: Integer;
|
||||||
const
|
const
|
||||||
PTRSZ: array[TFPDMode] of Integer = (4, 8); // (dm32, dm64)
|
PTRSZ: array[TFPDMode] of Integer = (4, 8); // (dm32, dm64)
|
||||||
@ -2601,6 +2622,7 @@ begin
|
|||||||
if Frame <> nil then begin
|
if Frame <> nil then begin
|
||||||
Addr := Frame.AnAddress;
|
Addr := Frame.AnAddress;
|
||||||
Ctx := TFpDbgSimpleLocationContext.Create(MemManager, Addr, DBGPTRSIZE[Mode], AThreadId, AStackFrame);
|
Ctx := TFpDbgSimpleLocationContext.Create(MemManager, Addr, DBGPTRSIZE[Mode], AThreadId, AStackFrame);
|
||||||
|
Ctx.SetCfiFrameBaseCallback(@DoGetCfiFrameBase);
|
||||||
sym := Frame.ProcSymbol;
|
sym := Frame.ProcSymbol;
|
||||||
if sym <> nil then
|
if sym <> nil then
|
||||||
Result := sym.CreateSymbolScope(Ctx);
|
Result := sym.CreateSymbolScope(Ctx);
|
||||||
@ -2638,6 +2660,22 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TDbgProcess.FindCallFrameInfo(AnAddress: TDBGPtr; out CIE: TDwarfCIE; out
|
||||||
|
Row: TDwarfCallFrameInformationRow): Boolean;
|
||||||
|
var
|
||||||
|
Lib: TDbgLibrary;
|
||||||
|
begin
|
||||||
|
Result := inherited FindCallFrameInfo(AnAddress, CIE, Row);
|
||||||
|
if Result then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
for Lib in FLibMap do begin
|
||||||
|
Result := Lib.FindCallFrameInfo(AnAddress, CIE, Row);
|
||||||
|
if Result then
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function TDbgProcess.GetLineAddresses(AFileName: String; ALine: Cardinal;
|
function TDbgProcess.GetLineAddresses(AFileName: String; ALine: Cardinal;
|
||||||
var AResultList: TDBGPtrArray; ASymInstance: TDbgInstance;
|
var AResultList: TDBGPtrArray; ASymInstance: TDbgInstance;
|
||||||
AFindSibling: TGetLineAddrFindSibling; AMaxSiblingDistance: integer): Boolean;
|
AFindSibling: TGetLineAddrFindSibling; AMaxSiblingDistance: integer): Boolean;
|
||||||
@ -3059,6 +3097,29 @@ begin
|
|||||||
Result := FDisassembler;
|
Result := FDisassembler;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TDbgProcess.DoGetCfiFrameBase(AScope: TFpDbgLocationContext; AnAddr: TDBGPtr): TDBGPtr;
|
||||||
|
var
|
||||||
|
CIE: TDwarfCIE;
|
||||||
|
ROW: TDwarfCallFrameInformationRow;
|
||||||
|
Thrd: TDbgThread;
|
||||||
|
CStck: TDbgCallstackEntry;
|
||||||
|
begin
|
||||||
|
Result := 0;
|
||||||
|
if (not GetThread(AScope.ThreadId, Thrd)) or (Thrd = nil) then
|
||||||
|
exit;
|
||||||
|
if AScope.StackFrame >= Thrd.CallStackEntryList.Count then
|
||||||
|
exit;
|
||||||
|
CStck := Thrd.CallStackEntryList[AScope.StackFrame];
|
||||||
|
if CStck = nil then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
if not FindCallFrameInfo(AnAddr, CIE, ROW) then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
if not GetCanonicalFrameAddress(CStck.RegisterValueList ,ROW, Result) then
|
||||||
|
Result := 0;
|
||||||
|
end;
|
||||||
|
|
||||||
function TDbgProcess.GetLastLibrariesLoaded: TDbgLibraryArr;
|
function TDbgProcess.GetLastLibrariesLoaded: TDbgLibraryArr;
|
||||||
begin
|
begin
|
||||||
Result := FLibMap.FLibrariesAdded;
|
Result := FLibMap.FLibrariesAdded;
|
||||||
@ -4401,11 +4462,161 @@ begin
|
|||||||
Process.WatchPointData.RemoveOwnedWatchpoint(Self);
|
Process.WatchPointData.RemoveOwnedWatchpoint(Self);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function GetCanonicalFrameAddress(
|
||||||
|
RegisterValueList: TDbgRegisterValueList; Row: TDwarfCallFrameInformationRow; out
|
||||||
|
FrameBase: TDBGPtr): Boolean;
|
||||||
|
var
|
||||||
|
Rule: TDwarfCallFrameInformationRule;
|
||||||
|
Reg: TDbgRegisterValue;
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
// Get CFA (framebase)
|
||||||
|
|
||||||
|
Rule := Row.CFARule;
|
||||||
|
case Rule.CFARule of
|
||||||
|
cfaRegister:
|
||||||
|
begin
|
||||||
|
Reg := RegisterValueList.FindRegisterByDwarfIndex(Rule.&Register);
|
||||||
|
if Assigned(Reg) then
|
||||||
|
begin
|
||||||
|
FrameBase := Reg.NumValue;
|
||||||
|
{$PUSH}{$R-}{$Q-}
|
||||||
|
FrameBase := FrameBase + TDBGPtr(Rule.Offset);
|
||||||
|
{$POP}
|
||||||
|
Result := True;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
DebugLn(FPDBG_DWARF_CFI_WARNINGS, 'CFI requested a register [' +IntToStr(Rule.&Register)+ '] that is not available.');
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
cfaExpression:
|
||||||
|
begin
|
||||||
|
DebugLn(FPDBG_DWARF_CFI_WARNINGS, 'CFI-expressions are not supported. Not possible to obtain the CFA.');
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
DebugLn(FPDBG_DWARF_CFI_WARNINGS, 'CFI available but no rule to obtain the CFA.');
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
end; // case
|
||||||
|
end;
|
||||||
|
|
||||||
|
function TryObtainNextCallFrame(
|
||||||
|
CurrentCallStackEntry: TDbgCallstackEntry;
|
||||||
|
CIE: TDwarfCIE;
|
||||||
|
Size, NextIdx: Integer;
|
||||||
|
Thread: TDbgThread;
|
||||||
|
Row: TDwarfCallFrameInformationRow;
|
||||||
|
Process: TDbgProcess;
|
||||||
|
out NewCallStackEntry: TDbgCallstackEntry): Boolean;
|
||||||
|
|
||||||
|
function ProcessCFIColumn(Row: TDwarfCallFrameInformationRow; Column: Byte; CFA: QWord; AddressSize: Integer; Entry: TDbgCallstackEntry; out Value: TDbgPtr): Boolean;
|
||||||
|
var
|
||||||
|
Rule: TDwarfCallFrameInformationRule;
|
||||||
|
Reg: TDbgRegisterValue;
|
||||||
|
begin
|
||||||
|
Result := True;
|
||||||
|
Value := 0;
|
||||||
|
Rule := Row.RegisterArray[Column];
|
||||||
|
case Rule.RegisterRule of
|
||||||
|
cfiUndefined:
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
end;
|
||||||
|
cfiSameValue:
|
||||||
|
begin
|
||||||
|
Reg := CurrentCallStackEntry.RegisterValueList.FindRegisterByDwarfIndex(Column);
|
||||||
|
if Assigned(Reg) then
|
||||||
|
Value := Reg.NumValue
|
||||||
|
else
|
||||||
|
Result := False;
|
||||||
|
end;
|
||||||
|
cfiOffset:
|
||||||
|
begin
|
||||||
|
{$PUSH}{$R-}{$Q-}
|
||||||
|
Process.ReadData(CFA+TDBGPtr(Rule.Offset), AddressSize, Value);
|
||||||
|
{$POP}
|
||||||
|
end;
|
||||||
|
cfiValOffset:
|
||||||
|
begin
|
||||||
|
{$PUSH}{$R-}{$Q-}
|
||||||
|
Value := CFA+TDBGPtr(Rule.Offset);
|
||||||
|
{$POP}
|
||||||
|
end;
|
||||||
|
cfiRegister:
|
||||||
|
begin
|
||||||
|
Reg := CurrentCallStackEntry.RegisterValueList.FindRegisterByDwarfIndex(Rule.&Register);
|
||||||
|
if Assigned(Reg) then
|
||||||
|
Value := Reg.NumValue
|
||||||
|
else
|
||||||
|
Result := False;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
DebugLn(FPDBG_DWARF_CFI_WARNINGS, 'Encountered unsupported CFI registerrule.');
|
||||||
|
Result := False;
|
||||||
|
end;
|
||||||
|
end; // case
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
//Rule: TDwarfCallFrameInformationRule;
|
||||||
|
Reg: TDbgRegisterValue;
|
||||||
|
i: Integer;
|
||||||
|
ReturnAddress, Value: TDbgPtr;
|
||||||
|
FrameBase: TDBGPtr;
|
||||||
|
RegName: String;
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
NewCallStackEntry := nil;
|
||||||
|
// Get CFA (framebase)
|
||||||
|
if not GetCanonicalFrameAddress(CurrentCallStackEntry.RegisterValueList, Row, FrameBase) then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
Result := True;
|
||||||
|
// Get return ReturnAddress
|
||||||
|
if not ProcessCFIColumn(Row, CIE.ReturnAddressRegister, FrameBase, Size, CurrentCallStackEntry, ReturnAddress) then
|
||||||
|
// Yes, we were succesfull, but there is no return ReturnAddress, so keep
|
||||||
|
// NewCallStackEntry nil
|
||||||
|
begin
|
||||||
|
Result := True;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if ReturnAddress=0 then
|
||||||
|
// Yes, we were succesfull, but there is no frame left, so keep
|
||||||
|
// NewCallStackEntry nil
|
||||||
|
begin
|
||||||
|
Result := True;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
NewCallStackEntry := TDbgCallstackEntry.create(Thread, NextIdx, FrameBase, ReturnAddress);
|
||||||
|
|
||||||
|
// Fill other registers
|
||||||
|
for i := 0 to High(Row.RegisterArray) do
|
||||||
|
begin
|
||||||
|
if ProcessCFIColumn(Row, i, FrameBase, Size, CurrentCallStackEntry, Value) then
|
||||||
|
begin
|
||||||
|
Reg := CurrentCallStackEntry.RegisterValueList.FindRegisterByDwarfIndex(i);
|
||||||
|
if Assigned(Reg) then
|
||||||
|
RegName := Reg.Name
|
||||||
|
else
|
||||||
|
RegName := IntToStr(i);
|
||||||
|
NewCallStackEntry.RegisterValueList.DbgRegisterAutoCreate[RegName].SetValue(Value, IntToStr(Value),Size, i);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
initialization
|
initialization
|
||||||
DBG_VERBOSE := DebugLogger.FindOrRegisterLogGroup('DBG_VERBOSE' {$IFDEF DBG_VERBOSE} , True {$ENDIF} );
|
DBG_VERBOSE := DebugLogger.FindOrRegisterLogGroup('DBG_VERBOSE' {$IFDEF DBG_VERBOSE} , True {$ENDIF} );
|
||||||
DBG_WARNINGS := DebugLogger.FindOrRegisterLogGroup('DBG_WARNINGS' {$IFDEF DBG_WARNINGS} , True {$ENDIF} );
|
DBG_WARNINGS := DebugLogger.FindOrRegisterLogGroup('DBG_WARNINGS' {$IFDEF DBG_WARNINGS} , True {$ENDIF} );
|
||||||
DBG_BREAKPOINTS := DebugLogger.FindOrRegisterLogGroup('DBG_BREAKPOINTS' {$IFDEF DBG_BREAKPOINTS} , True {$ENDIF} );
|
DBG_BREAKPOINTS := DebugLogger.FindOrRegisterLogGroup('DBG_BREAKPOINTS' {$IFDEF DBG_BREAKPOINTS} , True {$ENDIF} );
|
||||||
FPDBG_COMMANDS := DebugLogger.FindOrRegisterLogGroup('FPDBG_COMMANDS' {$IFDEF FPDBG_COMMANDS} , True {$ENDIF} );
|
FPDBG_COMMANDS := DebugLogger.FindOrRegisterLogGroup('FPDBG_COMMANDS' {$IFDEF FPDBG_COMMANDS} , True {$ENDIF} );
|
||||||
|
FPDBG_DWARF_CFI_WARNINGS := DebugLogger.FindOrRegisterLogGroup('FPDBG_DWARF_CFI_WARNINGS' {$IFDEF FPDBG_DWARF_CFI_WARNINGS} , True {$ENDIF} );
|
||||||
|
|
||||||
TFpBreakPointTargetHandler.DBG__VERBOSE := DBG_VERBOSE;
|
TFpBreakPointTargetHandler.DBG__VERBOSE := DBG_VERBOSE;
|
||||||
TFpBreakPointTargetHandler.DBG__WARNINGS := DBG_WARNINGS;
|
TFpBreakPointTargetHandler.DBG__WARNINGS := DBG_WARNINGS;
|
||||||
|
@ -226,8 +226,8 @@ begin
|
|||||||
PrevStmtAddressOffs := 0;
|
PrevStmtAddressOffs := 0;
|
||||||
|
|
||||||
{$PUSH}{$R-}{$Q-}
|
{$PUSH}{$R-}{$Q-}
|
||||||
if (Process.DbgInfo as TFpDwarfInfo).FindCallFrameInfo(CodePointer - PrevStmtAddressOffs, CIE, Row) and
|
if Process.FindCallFrameInfo(CodePointer - PrevStmtAddressOffs, CIE, Row) and
|
||||||
TDwarfCallFrameInformation.TryObtainNextCallFrame(
|
TryObtainNextCallFrame(
|
||||||
ACurrentFrame, CIE, AddressSize, AFrameIndex, Thread, Row, Process, ANewFrame
|
ACurrentFrame, CIE, AddressSize, AFrameIndex, Thread, Row, Process, ANewFrame
|
||||||
)
|
)
|
||||||
{$POP}
|
{$POP}
|
||||||
|
@ -48,8 +48,7 @@ uses
|
|||||||
// FpDebug
|
// FpDebug
|
||||||
FpDbgCommon,
|
FpDbgCommon,
|
||||||
FpDbgUtil,
|
FpDbgUtil,
|
||||||
FpDbgDwarfConst,
|
FpDbgDwarfConst;
|
||||||
FpDbgClasses;
|
|
||||||
|
|
||||||
type
|
type
|
||||||
PDwarfCIEEntryHeader32 = ^TDwarfCIEEntryHeader32;
|
PDwarfCIEEntryHeader32 = ^TDwarfCIEEntryHeader32;
|
||||||
@ -189,15 +188,6 @@ type
|
|||||||
function FindFDEForAddress(AnAddress: TDBGPtr): TDwarfFDE;
|
function FindFDEForAddress(AnAddress: TDBGPtr): TDwarfFDE;
|
||||||
function FindCIEForOffset(AnOffset: QWord): TDwarfCIE;
|
function FindCIEForOffset(AnOffset: QWord): TDwarfCIE;
|
||||||
function GetRow(TargetInfo: TTargetDescriptor; AnAddress: TDBGPtr; out CIE: TDwarfCIE; out Row: TDwarfCallFrameInformationRow): Boolean;
|
function GetRow(TargetInfo: TTargetDescriptor; AnAddress: TDBGPtr; out CIE: TDwarfCIE; out Row: TDwarfCallFrameInformationRow): Boolean;
|
||||||
|
|
||||||
class function TryObtainNextCallFrame(
|
|
||||||
CurrentCallStackEntry: TDbgCallstackEntry;
|
|
||||||
CIE: TDwarfCIE;
|
|
||||||
Size, NextIdx: Integer;
|
|
||||||
Thread: TDbgThread;
|
|
||||||
Row: TDwarfCallFrameInformationRow;
|
|
||||||
Process: TDbgProcess;
|
|
||||||
out NewCallStackEntry: TDbgCallstackEntry): Boolean;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
@ -607,140 +597,6 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class function TDwarfCallFrameInformation.TryObtainNextCallFrame(
|
|
||||||
CurrentCallStackEntry: TDbgCallstackEntry;
|
|
||||||
CIE: TDwarfCIE;
|
|
||||||
Size, NextIdx: Integer;
|
|
||||||
Thread: TDbgThread;
|
|
||||||
Row: TDwarfCallFrameInformationRow;
|
|
||||||
Process: TDbgProcess;
|
|
||||||
out NewCallStackEntry: TDbgCallstackEntry): Boolean;
|
|
||||||
|
|
||||||
function ProcessCFIColumn(Row: TDwarfCallFrameInformationRow; Column: Byte; CFA: QWord; AddressSize: Integer; Entry: TDbgCallstackEntry; out Value: TDbgPtr): Boolean;
|
|
||||||
var
|
|
||||||
Rule: TDwarfCallFrameInformationRule;
|
|
||||||
Reg: TDbgRegisterValue;
|
|
||||||
begin
|
|
||||||
Result := True;
|
|
||||||
Value := 0;
|
|
||||||
Rule := Row.RegisterArray[Column];
|
|
||||||
case Rule.RegisterRule of
|
|
||||||
cfiUndefined:
|
|
||||||
begin
|
|
||||||
Result := False;
|
|
||||||
end;
|
|
||||||
cfiSameValue:
|
|
||||||
begin
|
|
||||||
Reg := CurrentCallStackEntry.RegisterValueList.FindRegisterByDwarfIndex(Column);
|
|
||||||
if Assigned(Reg) then
|
|
||||||
Value := Reg.NumValue
|
|
||||||
else
|
|
||||||
Result := False;
|
|
||||||
end;
|
|
||||||
cfiOffset:
|
|
||||||
begin
|
|
||||||
{$PUSH}{$R-}{$Q-}
|
|
||||||
Process.ReadData(CFA+TDBGPtr(Rule.Offset), AddressSize, Value);
|
|
||||||
{$POP}
|
|
||||||
end;
|
|
||||||
cfiValOffset:
|
|
||||||
begin
|
|
||||||
{$PUSH}{$R-}{$Q-}
|
|
||||||
Value := CFA+TDBGPtr(Rule.Offset);
|
|
||||||
{$POP}
|
|
||||||
end;
|
|
||||||
cfiRegister:
|
|
||||||
begin
|
|
||||||
Reg := CurrentCallStackEntry.RegisterValueList.FindRegisterByDwarfIndex(Rule.&Register);
|
|
||||||
if Assigned(Reg) then
|
|
||||||
Value := Reg.NumValue
|
|
||||||
else
|
|
||||||
Result := False;
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
DebugLn(FPDBG_DWARF_CFI_WARNINGS, 'Encountered unsupported CFI registerrule.');
|
|
||||||
Result := False;
|
|
||||||
end;
|
|
||||||
end; // case
|
|
||||||
end;
|
|
||||||
|
|
||||||
var
|
|
||||||
Rule: TDwarfCallFrameInformationRule;
|
|
||||||
Reg: TDbgRegisterValue;
|
|
||||||
i: Integer;
|
|
||||||
ReturnAddress, Value: TDbgPtr;
|
|
||||||
FrameBase: TDBGPtr;
|
|
||||||
RegName: String;
|
|
||||||
begin
|
|
||||||
Result := False;
|
|
||||||
NewCallStackEntry := nil;
|
|
||||||
// Get CFA (framebase)
|
|
||||||
Rule := Row.CFARule;
|
|
||||||
case Rule.CFARule of
|
|
||||||
cfaRegister:
|
|
||||||
begin
|
|
||||||
Reg := CurrentCallStackEntry.RegisterValueList.FindRegisterByDwarfIndex(Rule.&Register);
|
|
||||||
if Assigned(Reg) then
|
|
||||||
begin
|
|
||||||
FrameBase := Reg.NumValue;
|
|
||||||
{$PUSH}{$R-}{$Q-}
|
|
||||||
FrameBase := FrameBase + TDBGPtr(Rule.Offset);
|
|
||||||
{$POP}
|
|
||||||
end
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
DebugLn(FPDBG_DWARF_CFI_WARNINGS, 'CFI requested a register [' +IntToStr(Rule.&Register)+ '] that is not available.');
|
|
||||||
Exit;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
cfaExpression:
|
|
||||||
begin
|
|
||||||
DebugLn(FPDBG_DWARF_CFI_WARNINGS, 'CFI-expressions are not supported. Not possible to obtain the CFA.');
|
|
||||||
Exit;
|
|
||||||
end;
|
|
||||||
else
|
|
||||||
begin
|
|
||||||
DebugLn(FPDBG_DWARF_CFI_WARNINGS, 'CFI available but no rule to obtain the CFA.');
|
|
||||||
Exit;
|
|
||||||
end;
|
|
||||||
end; // case
|
|
||||||
|
|
||||||
Result := True;
|
|
||||||
// Get return ReturnAddress
|
|
||||||
if not ProcessCFIColumn(Row, CIE.ReturnAddressRegister, FrameBase, Size, CurrentCallStackEntry, ReturnAddress) then
|
|
||||||
// Yes, we were succesfull, but there is no return ReturnAddress, so keep
|
|
||||||
// NewCallStackEntry nil
|
|
||||||
begin
|
|
||||||
Result := True;
|
|
||||||
Exit;
|
|
||||||
end;
|
|
||||||
|
|
||||||
if ReturnAddress=0 then
|
|
||||||
// Yes, we were succesfull, but there is no frame left, so keep
|
|
||||||
// NewCallStackEntry nil
|
|
||||||
begin
|
|
||||||
Result := True;
|
|
||||||
Exit;
|
|
||||||
end;
|
|
||||||
|
|
||||||
NewCallStackEntry := TDbgCallstackEntry.create(Thread, NextIdx, FrameBase, ReturnAddress);
|
|
||||||
|
|
||||||
// Fill other registers
|
|
||||||
for i := 0 to High(Row.RegisterArray) do
|
|
||||||
begin
|
|
||||||
if ProcessCFIColumn(Row, i, FrameBase, Size, CurrentCallStackEntry, Value) then
|
|
||||||
begin
|
|
||||||
Reg := CurrentCallStackEntry.RegisterValueList.FindRegisterByDwarfIndex(i);
|
|
||||||
if Assigned(Reg) then
|
|
||||||
RegName := Reg.Name
|
|
||||||
else
|
|
||||||
RegName := IntToStr(i);
|
|
||||||
NewCallStackEntry.RegisterValueList.DbgRegisterAutoCreate[RegName].SetValue(Value, IntToStr(Value),Size, i);
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
{ TDwarfFDE }
|
{ TDwarfFDE }
|
||||||
|
|
||||||
constructor TDwarfFDE.Create(ACIEPointer: QWord; AnInitialLocation, ASegmentSelector: TDBGPtr; AnAddressRange: QWord);
|
constructor TDwarfFDE.Create(ACIEPointer: QWord; AnInitialLocation, ASegmentSelector: TDBGPtr; AnAddressRange: QWord);
|
||||||
|
@ -2624,13 +2624,21 @@ begin
|
|||||||
end;
|
end;
|
||||||
Push(FCurrentObjectAddress);
|
Push(FCurrentObjectAddress);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
DW_OP_call_frame_cfa: begin
|
||||||
|
NewValue := Context.CfiFrameBase;
|
||||||
|
if NewValue = 0 then begin
|
||||||
|
SetError(fpErrLocationParser);
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
FStack.PushTargetMem(NewValue);
|
||||||
|
end;
|
||||||
(*
|
(*
|
||||||
// --- DWARF3 ---
|
// --- DWARF3 ---
|
||||||
DW_OP_call2 = $98; // 1 2-byte offset of DIE
|
DW_OP_call2 = $98; // 1 2-byte offset of DIE
|
||||||
DW_OP_call4 = $99; // 1 4-byte offset of DIE
|
DW_OP_call4 = $99; // 1 4-byte offset of DIE
|
||||||
DW_OP_call_ref = $9a; // 1 4- or 8-byte offset of DIE
|
DW_OP_call_ref = $9a; // 1 4- or 8-byte offset of DIE
|
||||||
DW_OP_form_tls_address = $9b; // 0
|
DW_OP_form_tls_address = $9b; // 0
|
||||||
DW_OP_call_frame_cfa = $9c; // 0
|
|
||||||
DW_OP_bit_piece = $9d; // 2
|
DW_OP_bit_piece = $9d; // 2
|
||||||
*)
|
*)
|
||||||
// dwarf 4
|
// dwarf 4
|
||||||
|
@ -80,8 +80,16 @@ type
|
|||||||
|
|
||||||
{ TFpDbgLocationContext }
|
{ TFpDbgLocationContext }
|
||||||
|
|
||||||
|
TFpDbgLocationContext = class;
|
||||||
|
|
||||||
|
TGetCfiFrameBaseCallback = function(AScope: TFpDbgLocationContext; AnAddr: TDBGPtr): TDBGPtr of object;
|
||||||
|
|
||||||
TFpDbgLocationContext = class(TRefCountedObject)
|
TFpDbgLocationContext = class(TRefCountedObject)
|
||||||
private
|
private
|
||||||
|
FCfiFrameBaseCallback: TGetCfiFrameBaseCallback;
|
||||||
|
FCfiFrameBase: TDBGPtr;
|
||||||
|
|
||||||
|
function GetCfiFrameBase: TDBGPtr;
|
||||||
function GetLastMemError: TFpError;
|
function GetLastMemError: TFpError;
|
||||||
function GetPartialReadResultLenght: QWord;
|
function GetPartialReadResultLenght: QWord;
|
||||||
protected
|
protected
|
||||||
@ -93,12 +101,14 @@ type
|
|||||||
function GetMemModel: TFpDbgMemModel; virtual; abstract;
|
function GetMemModel: TFpDbgMemModel; virtual; abstract;
|
||||||
public
|
public
|
||||||
property Address: TDbgPtr read GetAddress;
|
property Address: TDbgPtr read GetAddress;
|
||||||
|
property CfiFrameBase: TDBGPtr read GetCfiFrameBase;
|
||||||
property ThreadId: Integer read GetThreadId;
|
property ThreadId: Integer read GetThreadId;
|
||||||
property StackFrame: Integer read GetStackFrame;
|
property StackFrame: Integer read GetStackFrame;
|
||||||
property SizeOfAddress: Integer read GetSizeOfAddress;
|
property SizeOfAddress: Integer read GetSizeOfAddress;
|
||||||
property MemManager: TFpDbgMemManager read GetMemManager;
|
property MemManager: TFpDbgMemManager read GetMemManager;
|
||||||
property MemModel: TFpDbgMemModel read GetMemModel;
|
property MemModel: TFpDbgMemModel read GetMemModel;
|
||||||
public
|
public
|
||||||
|
procedure SetCfiFrameBaseCallback(ACallback: TGetCfiFrameBaseCallback);
|
||||||
procedure ClearLastMemError;
|
procedure ClearLastMemError;
|
||||||
property LastMemError: TFpError read GetLastMemError;
|
property LastMemError: TFpError read GetLastMemError;
|
||||||
property PartialReadResultLenght: QWord read GetPartialReadResultLenght;
|
property PartialReadResultLenght: QWord read GetPartialReadResultLenght;
|
||||||
@ -977,11 +987,24 @@ begin
|
|||||||
Result := MemManager.LastError;
|
Result := MemManager.LastError;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TFpDbgLocationContext.GetCfiFrameBase: TDBGPtr;
|
||||||
|
begin
|
||||||
|
if FCfiFrameBaseCallback <> nil then
|
||||||
|
FCfiFrameBase := FCfiFrameBaseCallback(Self, Address);
|
||||||
|
FCfiFrameBaseCallback := nil; // Only call once
|
||||||
|
Result := FCfiFrameBase;
|
||||||
|
end;
|
||||||
|
|
||||||
function TFpDbgLocationContext.GetPartialReadResultLenght: QWord;
|
function TFpDbgLocationContext.GetPartialReadResultLenght: QWord;
|
||||||
begin
|
begin
|
||||||
Result := MemManager.PartialReadResultLenght;
|
Result := MemManager.PartialReadResultLenght;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TFpDbgLocationContext.SetCfiFrameBaseCallback(ACallback: TGetCfiFrameBaseCallback);
|
||||||
|
begin
|
||||||
|
FCfiFrameBaseCallback := ACallback;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TFpDbgLocationContext.ClearLastMemError;
|
procedure TFpDbgLocationContext.ClearLastMemError;
|
||||||
begin
|
begin
|
||||||
MemManager.ClearLastError;
|
MemManager.ClearLastError;
|
||||||
|
Loading…
Reference in New Issue
Block a user