mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-06 13:39:17 +02:00
fpdebug - Add xtensa support
This commit is contained in:
parent
0ce49ed855
commit
c6781743e8
@ -11,7 +11,7 @@ type
|
||||
// Target information, could be different from host debugger
|
||||
TMachineType = (mtNone, mtSPARC, mt386, mt68K, mtPPC, mtPPC64, mtARM, mtARM64,
|
||||
mtOLD_ALPHA, mtIA_64, mtX86_64, mtAVR8, mtALPHA,
|
||||
mtMIPS, mtMIPSEL,mtLA64);
|
||||
mtMIPS, mtMIPSEL,mtLA64, mtXTENSA);
|
||||
TBitness = (bNone, b32, b64);
|
||||
TByteOrder = (boNone, boLSB, boMSB);
|
||||
TOperatingSystem = (osNone, osBSD, osDarwin, osEmbedded, osLinux, osUnix, osMac, osWindows);
|
||||
|
1088
components/fpdebug/fpdbgdisasxtensa.pas
Normal file
1088
components/fpdebug/fpdbgdisasxtensa.pas
Normal file
File diff suppressed because it is too large
Load Diff
@ -856,7 +856,7 @@ begin
|
||||
EnterCriticalSection(fCS);
|
||||
try
|
||||
result := SendCmdWaitForReply('g', reply) and ((length(reply) > 4) and (reply[1] <> 'E'))
|
||||
and (length(reply) = 2*sz);
|
||||
and (length(reply) >= 2*sz);
|
||||
finally
|
||||
LeaveCriticalSection(fCS);
|
||||
end;
|
||||
|
@ -58,6 +58,9 @@ type
|
||||
procedure SetRegisterValue(AName: string; AValue: QWord); override;
|
||||
procedure StoreRegisters; override;
|
||||
procedure RestoreRegisters; override;
|
||||
|
||||
// Read access to internal registers
|
||||
property InternalRegs: TInitializedRegisters read FRegs;
|
||||
end;
|
||||
|
||||
{ TDbgRspProcess }
|
||||
|
528
components/fpdebug/fpdbgxtensaclasses.pas
Normal file
528
components/fpdebug/fpdbgxtensaclasses.pas
Normal file
@ -0,0 +1,528 @@
|
||||
unit FpDbgXtensaClasses;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
{$packrecords c}
|
||||
{$modeswitch advancedrecords}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes,
|
||||
SysUtils,
|
||||
FpDbgClasses,
|
||||
DbgIntfBaseTypes, DbgIntfDebuggerBase,
|
||||
{$ifdef FORCE_LAZLOGGER_DUMMY} LazLoggerDummy {$else} LazLoggerBase {$endif},
|
||||
FpDbgRsp, FpDbgRspClasses, FpDbgCommon, FpdMemoryTools,
|
||||
FpErrorMessages;
|
||||
|
||||
const
|
||||
SPindexDwarf = 1; // Also known as a1, Index refers to active window
|
||||
PCIndexDwarf = 100; // Dwarf index (assumed)
|
||||
nPC = 'PC';
|
||||
nReturnPC = 'a0';
|
||||
nSP = 'a1';
|
||||
ReturnPCIndexDwarf = 0; // Also known as a0, Index refers to active window
|
||||
WindowBaseIndex = 65;
|
||||
WindowStartIndex = 66;
|
||||
PSIndex = 67;
|
||||
nWindowBase = 'windowbase';
|
||||
nWindowStart = 'windowstart';
|
||||
nPS = 'ps';
|
||||
|
||||
type
|
||||
{ TDbgXtensaThread }
|
||||
|
||||
TDbgXtensaThread = class(TDbgRspThread)
|
||||
private
|
||||
const
|
||||
lastCPURegIndex = 64; // PC + 64 registers
|
||||
// Offsets to load specific registers from register data
|
||||
// These are byte offsets, to be used when reading from the raw byte register data
|
||||
WindowBaseOffset = 276; // Dependent on Windowed option...
|
||||
WindowStartOffset = 280; // "
|
||||
PSOffset = 292; // "
|
||||
RegArrayByteLength = 420; // Depends on qemu options, but this seems to be the smallest size to handle. Only show basic registers, so rest can be ignored for now.
|
||||
// Ordered registers index
|
||||
// PC, ar0..ar63, wb, ws, ps
|
||||
PCindex = 0; // Offset into raw register array
|
||||
|
||||
protected
|
||||
procedure LoadRegisterCache; override;
|
||||
procedure SaveRegisterCache; override;
|
||||
function GetReturnPC: TDbgPtr;
|
||||
function GetStackUnwinder: TDbgStackUnwinder; override;
|
||||
public
|
||||
destructor Destroy; override;
|
||||
procedure LoadRegisterValues; override;
|
||||
procedure SetRegisterValue(AName: string; AValue: QWord); override;
|
||||
function GetInstructionPointerRegisterValue: TDbgPtr; override;
|
||||
function GetStackBasePointerRegisterValue: TDbgPtr; override;
|
||||
// procedure SetInstructionPointerRegisterValue(AValue: TDbgPtr); override;
|
||||
function GetStackPointerRegisterValue: TDbgPtr; override;
|
||||
// procedure SetStackPointerRegisterValue(AValue: TDbgPtr); override;
|
||||
end;
|
||||
|
||||
{ TDbgXtensaProcess }
|
||||
|
||||
TDbgXtensaProcess = class(TDbgRspProcess)
|
||||
private const
|
||||
FNumRegisters = 68; // pc, ar0..ar63, WindowBase, WindowStart, PS
|
||||
protected
|
||||
function CreateThread(AthreadIdentifier: THandle; out IsMainThread: boolean): TDbgThread; override;
|
||||
function CreateBreakPointTargetHandler: TFpBreakPointTargetHandler; override;
|
||||
public
|
||||
class function isSupported(target: TTargetDescriptor): boolean; override;
|
||||
constructor Create(const AFileName: string; AnOsClasses: TOSDbgClasses;
|
||||
AMemManager: TFpDbgMemManager; AMemModel: TFpDbgMemModel;
|
||||
AProcessConfig: TDbgProcessConfig = nil); override;
|
||||
destructor Destroy; override;
|
||||
end;
|
||||
|
||||
TXtensaBreakInfo = object
|
||||
const
|
||||
_CODE: DWord = $F06D; // ILL.N -> this is a 16 bit narrow instruction
|
||||
end;
|
||||
|
||||
TXtensaBreakPointTargetHandler = specialize TRspBreakPointTargetHandler<Word, TXtensaBreakInfo>;
|
||||
|
||||
|
||||
{ TDbgStackUnwinderXtensa }
|
||||
|
||||
TDbgStackUnwinderXtensa = class(TDbgStackUnwinder)
|
||||
private
|
||||
FThread: TDbgThread;
|
||||
FProcess: TDbgProcess;
|
||||
FAddressSize: Integer;
|
||||
FLastFrameBaseIncreased: Boolean;
|
||||
FCodeReadErrCnt: integer;
|
||||
|
||||
FWindowBase: uint32;
|
||||
FWindowStart: uint32;
|
||||
protected
|
||||
property Process: TDbgProcess read FProcess;
|
||||
property Thread: TDbgThread read FThread;
|
||||
property AddressSize: Integer read FAddressSize;
|
||||
public
|
||||
constructor Create(AProcess: TDbgProcess);
|
||||
procedure InitForThread(AThread: TDbgThread); override;
|
||||
procedure InitForFrame(ACurrentFrame: TDbgCallstackEntry; out CodePointer,
|
||||
StackPointer, FrameBasePointer: TDBGPtr); override;
|
||||
procedure GetTopFrame(out CodePointer, StackPointer, FrameBasePointer: TDBGPtr;
|
||||
out ANewFrame: TDbgCallstackEntry); override;
|
||||
function Unwind(AFrameIndex: integer; var CodePointer, StackPointer,
|
||||
FrameBasePointer: TDBGPtr; ACurrentFrame: TDbgCallstackEntry; out
|
||||
ANewFrame: TDbgCallstackEntry): TTDbgStackUnwindResult; override;
|
||||
end;
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
FpDbgDisasXtensa, FpDbgDwarfDataClasses;
|
||||
|
||||
var
|
||||
DBG_VERBOSE, DBG_WARNINGS: PLazLoggerLogGroup;
|
||||
|
||||
{ TDbgXtensaThread }
|
||||
|
||||
procedure TDbgXtensaThread.LoadRegisterCache;
|
||||
var
|
||||
regs: TBytes;
|
||||
i: integer;
|
||||
begin
|
||||
if not FRegs.Initialized then
|
||||
begin
|
||||
SetLength(regs, RegArrayByteLength);
|
||||
FRegs.Initialized := TDbgXtensaProcess(Process).RspConnection.ReadRegisters(regs[0], length(regs));
|
||||
// 32 bit LE registers
|
||||
for i := 0 to lastCPURegIndex do // PC, ar0..ar63
|
||||
FRegs.regs[i] := regs[4*i] + (regs[4*i + 1] shl 8) + (regs[4*i + 2] shl 16) + (regs[4*i + 3] shl 24);
|
||||
|
||||
i := WindowBaseOffset;
|
||||
FRegs.regs[WindowBaseIndex] := regs[i] + (regs[i + 1] shl 8) + (regs[i + 2] shl 16) + (regs[i + 3] shl 24);
|
||||
i := WindowStartOffset;
|
||||
FRegs.regs[WindowStartIndex] := regs[i] + (regs[i + 1] shl 8) + (regs[i + 2] shl 16) + (regs[i + 3] shl 24);
|
||||
i := PSOffset;
|
||||
FRegs.regs[PSIndex] := regs[i] + (regs[i + 1] shl 8) + (regs[i + 2] shl 16) + (regs[i + 3] shl 24);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TDbgXtensaThread.SaveRegisterCache;
|
||||
procedure CopyDWordToByteArray( const val: DWord; regs: PByte);
|
||||
begin
|
||||
regs[0] := val;
|
||||
regs[1] := val shr 8;
|
||||
regs[2] := val shr 16;
|
||||
regs[3] := val shr 24;
|
||||
end;
|
||||
|
||||
var
|
||||
regs: TBytes;
|
||||
i: Integer;
|
||||
begin
|
||||
exit; // TODO: Need to determine which other registers will also change in case of a subroutine call on the debugger side.
|
||||
|
||||
if FRegsChanged then
|
||||
begin
|
||||
SetLength(regs, RegArrayByteLength);
|
||||
for i := 0 to lastCPURegIndex do
|
||||
CopyDWordToByteArray(FRegs.regs[i], @regs[4*i]);
|
||||
|
||||
CopyDWordToByteArray(FRegs.regs[WindowBaseIndex], @regs[WindowBaseOffset]);
|
||||
CopyDWordToByteArray(FRegs.regs[WindowStartIndex], @regs[WindowStartOffset]);
|
||||
CopyDWordToByteArray(FRegs.regs[PSIndex], @regs[PSOffset]);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TDbgXtensaThread.GetReturnPC: TDbgPtr;
|
||||
var
|
||||
wb: TDBGPtr;
|
||||
begin
|
||||
Result := 0;
|
||||
if TDbgXtensaProcess(Process).FIsTerminating then
|
||||
begin
|
||||
DebugLn(DBG_WARNINGS, 'TDbgXtensaProcess.GetStackPointerRegisterValue called while FIsTerminating is set.');
|
||||
exit;
|
||||
end;
|
||||
|
||||
if not ReadThreadState then
|
||||
exit;
|
||||
|
||||
DebugLn(DBG_VERBOSE, 'TDbgXtensaProcess.GetStackPointerRegisterValue requesting stack registers.');
|
||||
// Windowed ABI: retPC in a0
|
||||
ReadDebugReg(WindowBaseIndex, wb);
|
||||
wb := wb * 4;
|
||||
ReadDebugReg(wb+1, result);
|
||||
end;
|
||||
|
||||
function TDbgXtensaThread.GetStackUnwinder: TDbgStackUnwinder;
|
||||
begin
|
||||
if FUnwinder = nil then
|
||||
FUnwinder := TDbgStackUnwinderXtensa.Create(Process);
|
||||
Result := FUnwinder;
|
||||
end;
|
||||
|
||||
destructor TDbgXtensaThread.Destroy;
|
||||
begin
|
||||
if Assigned(FUnwinder) then
|
||||
FreeAndNil(FUnwinder);
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
procedure TDbgXtensaThread.LoadRegisterValues;
|
||||
var
|
||||
i, j, wb: integer;
|
||||
begin
|
||||
if TDbgXtensaProcess(Process).FIsTerminating or (TDbgXtensaProcess(Process).FStatus = SIGHUP) then
|
||||
begin
|
||||
DebugLn(DBG_WARNINGS, 'TDbgXtensaProcess.LoadRegisterValues called while FIsTerminating is set.');
|
||||
exit;
|
||||
end;
|
||||
|
||||
if not ReadThreadState then
|
||||
exit;
|
||||
|
||||
LoadRegisterCache;
|
||||
|
||||
if FRegs.Initialized then
|
||||
begin
|
||||
{ FRegs.regs start with PC, then the 64 core registers,
|
||||
then a bunch of other system and optionally user registers.
|
||||
Only load currently visible registers, PC and WindowBaseOffset for now.
|
||||
The start of currently visible core registers is given by WindowBaseOffset }
|
||||
|
||||
// WindowBaseOffset is a 4 bit value
|
||||
wb := 4 * (FRegs.regs[WindowBaseIndex] and $0F);
|
||||
// Returned registers start with PC, followed by core register file, so offset index by 1
|
||||
for i := 0 to 15 do
|
||||
begin
|
||||
// Index should wrap around to start of register file
|
||||
j := ((wb+i) and 63) + 1;
|
||||
FRegisterValueList.DbgRegisterAutoCreate['a'+IntToStr(i)].SetValue(FRegs.regs[j], IntToStr(FRegs.regs[j]), 4, i);
|
||||
end;
|
||||
|
||||
FRegisterValueList.DbgRegisterAutoCreate[nPC].SetValue(FRegs.regs[0], IntToStr(FRegs.regs[0]), 4, 0);
|
||||
FRegisterValueList.DbgRegisterAutoCreate[nWindowBase].SetValue(byte(FRegs.regs[WindowBaseIndex]), IntToStr(byte(FRegs.regs[WindowBaseIndex])),1 , WindowBaseIndex);
|
||||
FRegisterValueList.DbgRegisterAutoCreate[nWindowStart].SetValue(word(FRegs.regs[WindowStartIndex]), IntToStr(word(FRegs.regs[WindowStartIndex])),2 , WindowStartIndex);
|
||||
FRegisterValueList.DbgRegisterAutoCreate[nPS].SetValue(byte(FRegs.regs[PSIndex]), IntToStr(byte(FRegs.regs[PSIndex])),1 , 0);
|
||||
FRegisterValueList.DbgRegisterAutoCreate[nPS].SetValue(byte(FRegs.regs[PSIndex]), IntToStr(byte(FRegs.regs[PSIndex])),1 , 0);
|
||||
FRegisterValueListValid := true;
|
||||
end
|
||||
else
|
||||
DebugLn(DBG_WARNINGS, 'Warning: Could not update registers');
|
||||
end;
|
||||
|
||||
procedure TDbgXtensaThread.SetRegisterValue(AName: string; AValue: QWord);
|
||||
var
|
||||
i, err: integer;
|
||||
res: boolean;
|
||||
begin
|
||||
if AName[1] = 'a' then
|
||||
begin
|
||||
val(copy(AName, 2, length(Aname)), i, err);
|
||||
res := (err = 0) and (i <= 15);
|
||||
if res then
|
||||
res := TDbgRspProcess(Process).RspConnection.WriteDebugReg(i, byte(AValue));
|
||||
end
|
||||
else if AName = nPC then
|
||||
res := TDbgRspProcess(Process).RspConnection.WriteDebugReg(PCindex, dword(AValue))
|
||||
else
|
||||
res := False;
|
||||
|
||||
if not res then
|
||||
DebugLn(DBG_WARNINGS, 'Error setting register %s to %u', [AName, AValue]);
|
||||
end;
|
||||
|
||||
function TDbgXtensaThread.GetInstructionPointerRegisterValue: TDbgPtr;
|
||||
begin
|
||||
Result := 0;
|
||||
if TDbgXtensaProcess(Process).FIsTerminating then
|
||||
begin
|
||||
DebugLn(DBG_WARNINGS, 'TDbgXtensaProcess.GetInstructionPointerRegisterValue called while FIsTerminating is set.');
|
||||
exit;
|
||||
end;
|
||||
|
||||
if not ReadThreadState then
|
||||
exit;
|
||||
|
||||
DebugLn(DBG_VERBOSE, 'TDbgXtensaProcess.GetInstructionPointerRegisterValue requesting PC.');
|
||||
ReadDebugReg(PCindex, Result);
|
||||
end;
|
||||
|
||||
function TDbgXtensaThread.GetStackBasePointerRegisterValue: TDbgPtr;
|
||||
begin
|
||||
Result := 0;
|
||||
if TDbgXtensaProcess(Process).FIsTerminating then
|
||||
begin
|
||||
DebugLn(DBG_WARNINGS, 'TDbgXtensaProcess.GetStackBasePointerRegisterValue called while FIsTerminating is set.');
|
||||
exit;
|
||||
end;
|
||||
|
||||
if not ReadThreadState then
|
||||
exit;
|
||||
|
||||
DebugLn(DBG_VERBOSE, 'TDbgXtensaProcess.GetStackBasePointerRegisterValue requesting base registers.');
|
||||
// Todo: check FPC implementation of stack frame for ESP32
|
||||
Result := GetStackPointerRegisterValue;
|
||||
end;
|
||||
|
||||
function TDbgXtensaThread.GetStackPointerRegisterValue: TDbgPtr;
|
||||
var
|
||||
wb: TDBGPtr;
|
||||
begin
|
||||
Result := 0;
|
||||
if TDbgXtensaProcess(Process).FIsTerminating then
|
||||
begin
|
||||
DebugLn(DBG_WARNINGS, 'TDbgXtensaProcess.GetStackPointerRegisterValue called while FIsTerminating is set.');
|
||||
exit;
|
||||
end;
|
||||
|
||||
if not ReadThreadState then
|
||||
exit;
|
||||
|
||||
DebugLn(DBG_VERBOSE, 'TDbgXtensaProcess.GetStackPointerRegisterValue requesting stack registers.');
|
||||
// Windowed ABI: SP in a1
|
||||
if ReadDebugReg(WindowBaseIndex, wb) then
|
||||
begin
|
||||
wb := wb * 4;
|
||||
ReadDebugReg(wb+2, result);
|
||||
end
|
||||
else
|
||||
Result := 0;
|
||||
end;
|
||||
|
||||
{ TDbgXtensaProcess }
|
||||
|
||||
function TDbgXtensaProcess.CreateThread(AthreadIdentifier: THandle; out IsMainThread: boolean): TDbgThread;
|
||||
begin
|
||||
IsMainThread:=False;
|
||||
if AthreadIdentifier<>feInvalidHandle then
|
||||
begin
|
||||
IsMainThread := AthreadIdentifier=ProcessID;
|
||||
result := TDbgXtensaThread.Create(Self, AthreadIdentifier, AthreadIdentifier);
|
||||
end
|
||||
else
|
||||
result := nil;
|
||||
end;
|
||||
|
||||
function
|
||||
TDbgXtensaProcess.CreateBreakPointTargetHandler: TFpBreakPointTargetHandler;
|
||||
begin
|
||||
Result := TXtensaBreakPointTargetHandler.Create(Self);
|
||||
end;
|
||||
|
||||
constructor TDbgXtensaProcess.Create(const AFileName: string;
|
||||
AnOsClasses: TOSDbgClasses; AMemManager: TFpDbgMemManager;
|
||||
AMemModel: TFpDbgMemModel; AProcessConfig: TDbgProcessConfig);
|
||||
begin
|
||||
FRegArrayLength := FNumRegisters;
|
||||
inherited Create(AFileName, AnOsClasses, AMemManager, AMemModel, AProcessConfig);
|
||||
end;
|
||||
|
||||
destructor TDbgXtensaProcess.Destroy;
|
||||
begin
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
class function TDbgXtensaProcess.isSupported(target: TTargetDescriptor): boolean;
|
||||
begin
|
||||
result := (target.OS = osEmbedded) and (target.machineType = mtXTENSA);
|
||||
end;
|
||||
|
||||
{ TDbgStackUnwinderXtensa }
|
||||
|
||||
constructor TDbgStackUnwinderXtensa.Create(AProcess: TDbgProcess);
|
||||
begin
|
||||
FProcess := AProcess;
|
||||
FAddressSize := 4;
|
||||
FCodeReadErrCnt := 0;
|
||||
end;
|
||||
|
||||
procedure TDbgStackUnwinderXtensa.InitForThread(AThread: TDbgThread);
|
||||
begin
|
||||
FThread := AThread;
|
||||
end;
|
||||
|
||||
procedure TDbgStackUnwinderXtensa.InitForFrame(
|
||||
ACurrentFrame: TDbgCallstackEntry; out CodePointer, StackPointer,
|
||||
FrameBasePointer: TDBGPtr);
|
||||
var
|
||||
R: TDbgRegisterValue;
|
||||
begin
|
||||
CodePointer := ACurrentFrame.AnAddress;
|
||||
|
||||
// Frame pointer is a7 (if used)
|
||||
FrameBasePointer := ACurrentFrame.FrameAdress;
|
||||
|
||||
StackPointer := 0;
|
||||
R := ACurrentFrame.RegisterValueList.FindRegisterByDwarfIndex(SPindexDwarf);
|
||||
if R = nil then exit;
|
||||
StackPointer := R.NumValue;
|
||||
end;
|
||||
|
||||
procedure TDbgStackUnwinderXtensa.GetTopFrame(out CodePointer, StackPointer,
|
||||
FrameBasePointer: TDBGPtr; out ANewFrame: TDbgCallstackEntry);
|
||||
var
|
||||
i: Integer;
|
||||
R: TDbgRegisterValue;
|
||||
begin
|
||||
FLastFrameBaseIncreased := True;
|
||||
CodePointer := Thread.GetInstructionPointerRegisterValue;
|
||||
StackPointer := Thread.GetStackPointerRegisterValue;
|
||||
FrameBasePointer := Thread.GetStackBasePointerRegisterValue;
|
||||
ANewFrame := TDbgCallstackEntry.create(Thread, 0, FrameBasePointer, CodePointer);
|
||||
|
||||
// Frame pointer may not have been updated yet
|
||||
if FrameBasePointer > StackPointer then
|
||||
FrameBasePointer := StackPointer;
|
||||
|
||||
i := Thread.RegisterValueList.Count;
|
||||
while i > 0 do begin
|
||||
dec(i);
|
||||
R := Thread.RegisterValueList[i];
|
||||
ANewFrame.RegisterValueList.DbgRegisterAutoCreate[R.Name].SetValue(R.NumValue, R.StrValue, R.Size, R.DwarfIdx);
|
||||
end;
|
||||
|
||||
FWindowBase := ANewFrame.RegisterValueList.FindRegisterByDwarfIndex(WindowBaseIndex).NumValue and $F;
|
||||
FWindowStart := ANewFrame.RegisterValueList.FindRegisterByDwarfIndex(WindowStartIndex).NumValue and $FFFF;
|
||||
end;
|
||||
|
||||
function TDbgStackUnwinderXtensa.Unwind(AFrameIndex: integer; var CodePointer,
|
||||
StackPointer, FrameBasePointer: TDBGPtr; ACurrentFrame: TDbgCallstackEntry;
|
||||
out ANewFrame: TDbgCallstackEntry): TTDbgStackUnwindResult;
|
||||
const
|
||||
MAX_FRAMES = 500; // safety net
|
||||
Size = 4;
|
||||
var
|
||||
Address, returnAddress: TDBGPtr;
|
||||
callSize: byte;
|
||||
j, k, stackRegCount: integer;
|
||||
spilled: boolean;
|
||||
stackRegs: array of TDBGPtr;
|
||||
tmpReg: uint32;
|
||||
LastFrameBase: TDBGPtr;
|
||||
begin
|
||||
ANewFrame := nil;
|
||||
Result := suFailed;
|
||||
|
||||
if (StackPointer > $40000000) or (StackPointer < $3F000000) or
|
||||
(CodePointer < $40000001) or not FLastFrameBaseIncreased then
|
||||
exit;
|
||||
|
||||
LastFrameBase := FrameBasePointer;
|
||||
|
||||
ReturnAddress := ACurrentFrame.RegisterValueList.FindRegisterByName(nReturnPC).NumValue;
|
||||
spilled := FWindowStart and (1 shl FWindowBase) = 0;
|
||||
|
||||
FCodeReadErrCnt := 0;
|
||||
|
||||
callSize := uint32(returnAddress) shr 30;
|
||||
if callsize = 0 then
|
||||
exit;
|
||||
|
||||
Address := (returnAddress and $3FFFFFFF) or $40000000;
|
||||
// Check if start of this window frame is live or spilled
|
||||
if not spilled then
|
||||
begin
|
||||
// Move window base to previous window frame
|
||||
// Wraparound subtraction
|
||||
FWindowBase := (FWindowBase + 16 - callsize) and $F;
|
||||
spilled := FWindowStart and (1 shl FWindowBase) = 0;
|
||||
end;
|
||||
|
||||
stackRegCount := 4*callSize;
|
||||
SetLength(stackRegs, stackRegCount);
|
||||
if not spilled then
|
||||
begin
|
||||
// Live registers, read from register file
|
||||
j := ((4*FWindowBase) and 63);
|
||||
for k := 0 to stackRegCount-1 do
|
||||
stackRegs[k] := TDbgRspThread(Thread).InternalRegs.regs[((j+k) and 63)+1]; // wraparound indexing
|
||||
end
|
||||
else
|
||||
begin
|
||||
// Registers spilled to stack, read from memory
|
||||
for j := 0 to callSize-1 do
|
||||
begin
|
||||
for k := 0 to 3 do
|
||||
begin
|
||||
if j = 0 then
|
||||
begin
|
||||
if not Process.ReadData(StackPointer-16+4*k, 4, tmpReg) then Break;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if (stackRegs[1] < $3F000000) or
|
||||
not Process.ReadData(stackRegs[1]-16+4*k, 4, tmpReg) then
|
||||
Break;
|
||||
end;
|
||||
stackRegs[4*j + k] := NtoLE(tmpReg);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
returnAddress := stackRegs[0];
|
||||
StackPointer := stackRegs[1];
|
||||
FrameBasePointer := StackPointer;
|
||||
|
||||
ANewFrame:= TDbgCallstackEntry.create(Thread, AFrameIndex, FrameBasePointer, Address);
|
||||
ANewFrame.RegisterValueList.DbgRegisterAutoCreate[nPC].SetValue(Address, IntToStr(Address),Size, PCIndexDwarf);
|
||||
ANewFrame.RegisterValueList.DbgRegisterAutoCreate[nReturnPC].SetValue(returnAddress, IntToStr(returnAddress),Size, ReturnPCIndexDwarf);
|
||||
ANewFrame.RegisterValueList.DbgRegisterAutoCreate[nSP].SetValue(StackPointer, IntToStr(StackPointer),Size, SPindexDwarf);
|
||||
// In case a7 is used as frame pointer
|
||||
ANewFrame.RegisterValueList.DbgRegisterAutoCreate['a7'].SetValue(byte(FrameBasePointer), IntToStr(byte(FrameBasePointer)),Size, 7);
|
||||
ANewFrame.RegisterValueList.DbgRegisterAutoCreate[nWindowBase].SetValue(FWindowBase, IntToStr(FWindowBase), 1, WindowBaseIndex);
|
||||
ANewFrame.RegisterValueList.DbgRegisterAutoCreate[nWindowStart].SetValue(FWindowStart, IntToStr(FWindowStart), 2 , WindowStartIndex);
|
||||
|
||||
FLastFrameBaseIncreased := (FrameBasePointer <> 0) and (FrameBasePointer > LastFrameBase);
|
||||
Result := suSuccess;
|
||||
end;
|
||||
|
||||
initialization
|
||||
DBG_VERBOSE := DebugLogger.FindOrRegisterLogGroup('DBG_VERBOSE' {$IFDEF DBG_VERBOSE} , True {$ENDIF} );
|
||||
DBG_WARNINGS := DebugLogger.FindOrRegisterLogGroup('DBG_WARNINGS' {$IFDEF DBG_WARNINGS} , True {$ENDIF} );
|
||||
RegisterDbgOsClasses(TOSDbgClasses.Create(
|
||||
TDbgXtensaProcess,
|
||||
TDbgXtensaThread,
|
||||
TXtensaAsmDecoder));
|
||||
end.
|
@ -233,6 +233,18 @@ File(s) with other licenses (see also header in file(s):
|
||||
<Filename Value="fpdbgcpux86.pas"/>
|
||||
<UnitName Value="fpdbgcpux86"/>
|
||||
</Item>
|
||||
<Item>
|
||||
<Filename Value="fpdbgrspclasses.pas"/>
|
||||
<UnitName Value="FpDbgRspClasses"/>
|
||||
</Item>
|
||||
<Item>
|
||||
<Filename Value="fpdbgdisasxtensa.pas"/>
|
||||
<UnitName Value="FpDbgDisasXtensa"/>
|
||||
</Item>
|
||||
<Item>
|
||||
<Filename Value="fpdbgxtensaclasses.pas"/>
|
||||
<UnitName Value="FpDbgXtensaClasses"/>
|
||||
</Item>
|
||||
</Files>
|
||||
<i18n>
|
||||
<EnableI18N Value="True"/>
|
||||
|
@ -16,7 +16,8 @@ uses
|
||||
FpDbgDwarfDataClasses, FpDbgDwarfFreePascal, fpDbgSymTableContext,
|
||||
fpDbgSymTable, FpDbgAvrClasses, FpDbgDisasAvr, FpDbgRsp, FpDbgCommon,
|
||||
FpImgReaderWinPETypes, FpDbgHardcodedFreepascalInfo, FpDbgCallContextInfo,
|
||||
FpWatchResultData, FpDbgDwarfCFI, FpDbgCpuX86;
|
||||
FpWatchResultData, FpDbgDwarfCFI, FpDbgCpuX86, FpDbgRspClasses,
|
||||
FpDbgDisasXtensa, FpDbgXtensaClasses;
|
||||
|
||||
implementation
|
||||
|
||||
|
@ -141,6 +141,7 @@ begin
|
||||
EM_IA_64: result := mtIA_64;
|
||||
EM_X86_64: result := mtX86_64;
|
||||
EM_AVR: result := mtAVR8;
|
||||
EM_XTENSA: result := mtXTENSA;
|
||||
EM_ALPHA: result := mtALPHA;
|
||||
else
|
||||
result := mtNone;
|
||||
@ -149,7 +150,7 @@ begin
|
||||
// If OS is not encoded in header, take some guess based on machine type
|
||||
if FTargetInfo.OS = osNone then
|
||||
begin
|
||||
if result = mtAVR8 then
|
||||
if result in [mtAVR8, mtXTENSA] then
|
||||
FTargetInfo.OS := osEmbedded
|
||||
else
|
||||
// Default to the same as host...
|
||||
|
@ -154,6 +154,7 @@ const
|
||||
EM_IA_64 = 50;
|
||||
EM_X86_64 = 62;
|
||||
EM_AVR = 83;
|
||||
EM_XTENSA = 94;
|
||||
EM_ALPHA = $9026; //unofficial, but used by gnu toolchain
|
||||
|
||||
//elf version {Elf32_Hdr.e_version}
|
||||
|
@ -16,7 +16,7 @@ uses
|
||||
FpPascalParser, FPDbgController, FpDbgDwarfDataClasses, FpDbgDwarfFreePascal,
|
||||
FpDbgDwarf, FpDbgUtil,
|
||||
DebuggerPropertiesBase,
|
||||
FpDbgRsp, FpDbgAvrClasses;
|
||||
FpDbgRsp, FpDbgAvrClasses, FpDbgXtensaClasses;
|
||||
|
||||
type
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user