mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-23 05:39:29 +02:00
FpDebug: fix for some missing stackframes
(cherry picked from commit 8da9f2d084
)
This commit is contained in:
parent
6ecf0f00f4
commit
70e8e1e211
@ -655,6 +655,8 @@ type
|
||||
|
||||
function GetInstructionInfo(AnAddress: TDBGPtr): TDbgAsmInstruction; virtual; abstract;
|
||||
function GetFunctionFrameInfo(AnAddress: TDBGPtr; out AnIsOutsideFrame: Boolean): Boolean; virtual;
|
||||
function IsAfterCallInstruction(AnAddress: TDBGPtr): boolean; virtual;
|
||||
function UnwindFrame(var AnAddress, AStackPtr, AFramePtr: TDBGPtr; AQuick: boolean): boolean; virtual;
|
||||
|
||||
property LastErrorWasMemReadErr: Boolean read GetLastErrorWasMemReadErr;
|
||||
property MaxInstructionSize: integer read GetMaxInstrSize; // abstract
|
||||
@ -1875,6 +1877,17 @@ begin
|
||||
Result := False;
|
||||
end;
|
||||
|
||||
function TDbgAsmDecoder.IsAfterCallInstruction(AnAddress: TDBGPtr): boolean;
|
||||
begin
|
||||
Result := True; // if we don't know, then assume yes
|
||||
end;
|
||||
|
||||
function TDbgAsmDecoder.UnwindFrame(var AnAddress, AStackPtr,
|
||||
AFramePtr: TDBGPtr; AQuick: boolean): boolean;
|
||||
begin
|
||||
Result := False;
|
||||
end;
|
||||
|
||||
{ TDbgInstance }
|
||||
|
||||
|
||||
@ -3299,6 +3312,7 @@ const
|
||||
MAX_FRAMES = 150000; // safety net
|
||||
var
|
||||
Address, FrameBase, LastFrameBase, Dummy: QWord;
|
||||
PrevAddress, PrevFrameBase, PrevStackPtr: QWord;
|
||||
Size, CountNeeded, IP, BP, CodeReadErrCnt, SP, i,
|
||||
PrevStmtAddressOffs: integer;
|
||||
AnEntry, NewEntry: TDbgCallstackEntry;
|
||||
@ -3310,6 +3324,37 @@ var
|
||||
Row: TDwarfCallFrameInformationRow;
|
||||
CIE: TDwarfCIE;
|
||||
CU: TDwarfCompilationUnit;
|
||||
|
||||
procedure CheckFrame(var NextEntry: TDbgCallstackEntry; AForce: boolean = False);
|
||||
begin
|
||||
if (not AForce) and (NextEntry <> nil) and Process.Disassembler.IsAfterCallInstruction(Address) then
|
||||
exit;
|
||||
|
||||
if not Process.Disassembler.UnwindFrame(PrevAddress, PrevStackPtr, PrevFrameBase, False) then
|
||||
exit;
|
||||
|
||||
if (NextEntry <> nil) and
|
||||
(Address = PrevAddress) and (FrameBase = PrevFrameBase) and (StackPtr = PrevStackPtr)
|
||||
then
|
||||
exit;
|
||||
if not Process.Disassembler.IsAfterCallInstruction(PrevAddress) then
|
||||
exit;
|
||||
|
||||
Address := PrevAddress;
|
||||
FrameBase := PrevFrameBase;
|
||||
StackPtr := PrevStackPtr;
|
||||
NextEntry.Free;
|
||||
NextEntry := TDbgCallstackEntry.create(Self, NextIdx, FrameBase, Address);
|
||||
NextEntry.RegisterValueList.DbgRegisterAutoCreate[nIP].SetValue(Address, IntToStr(Address),Size, IP);
|
||||
NextEntry.RegisterValueList.DbgRegisterAutoCreate[nBP].SetValue(FrameBase, IntToStr(FrameBase),Size, BP);
|
||||
NextEntry.RegisterValueList.DbgRegisterAutoCreate[nSP].SetValue(StackPtr, IntToStr(StackPtr),Size, SP);
|
||||
LastFrameBase := FrameBase;
|
||||
{$PUSH}{$R-}{$Q-}
|
||||
if LastFrameBase > 0 then
|
||||
LastFrameBase := LastFrameBase - 1;
|
||||
{$POP}
|
||||
end;
|
||||
|
||||
begin
|
||||
// TODO: use AFrameRequired // check if already partly done
|
||||
if FCallStackEntryList = nil then
|
||||
@ -3385,8 +3430,13 @@ begin
|
||||
CodeReadErrCnt := 0;
|
||||
while (CountNeeded > 0) do
|
||||
begin
|
||||
PrevAddress := Address;
|
||||
PrevFrameBase := FrameBase;
|
||||
PrevStackPtr := StackPtr;
|
||||
{$PUSH}{$R-}{$Q-}
|
||||
if (Process.DbgInfo as TFpDwarfInfo).FindCallFrameInfo(Address - PrevStmtAddressOffs, CIE, Row) and
|
||||
TDwarfCallFrameInformation.TryObtainNextCallFrame(AnEntry, CIE, Size, NextIdx, Self, Row, Process, NewEntry)
|
||||
{$POP}
|
||||
then begin
|
||||
PrevStmtAddressOffs := 1;
|
||||
if not Assigned(NewEntry) then begin
|
||||
@ -3396,7 +3446,6 @@ begin
|
||||
Break;
|
||||
end
|
||||
else begin
|
||||
FCallStackEntryList.Add(NewEntry);
|
||||
Address := NewEntry.AnAddress;
|
||||
StackReg := NewEntry.RegisterValueList.FindRegisterByDwarfIndex(SP);
|
||||
FrameReg := NewEntry.RegisterValueList.FindRegisterByDwarfIndex(BP);
|
||||
@ -3406,6 +3455,8 @@ begin
|
||||
FrameBase := FrameReg.FNumValue;
|
||||
end;
|
||||
AnEntry := NewEntry;
|
||||
CheckFrame(NewEntry);
|
||||
FCallStackEntryList.Add(NewEntry);
|
||||
Dec(CountNeeded);
|
||||
inc(NextIdx);
|
||||
If (NextIdx > MAX_FRAMES) then
|
||||
@ -3416,6 +3467,33 @@ begin
|
||||
end;
|
||||
PrevStmtAddressOffs := 1;
|
||||
|
||||
if Process.Disassembler.UnwindFrame(PrevAddress, PrevStackPtr, PrevFrameBase, True) and
|
||||
Process.Disassembler.IsAfterCallInstruction(PrevAddress)
|
||||
then begin
|
||||
Address := PrevAddress;
|
||||
FrameBase := PrevFrameBase;
|
||||
StackPtr := PrevStackPtr;
|
||||
AnEntry := TDbgCallstackEntry.create(Self, NextIdx, FrameBase, Address);
|
||||
AnEntry.RegisterValueList.DbgRegisterAutoCreate[nIP].SetValue(Address, IntToStr(Address),Size, IP);
|
||||
AnEntry.RegisterValueList.DbgRegisterAutoCreate[nBP].SetValue(FrameBase, IntToStr(FrameBase),Size, BP);
|
||||
AnEntry.RegisterValueList.DbgRegisterAutoCreate[nSP].SetValue(StackPtr, IntToStr(StackPtr),Size, SP);
|
||||
FCallStackEntryList.Add(AnEntry);
|
||||
Dec(CountNeeded);
|
||||
inc(NextIdx);
|
||||
CodeReadErrCnt := 0;
|
||||
If (NextIdx > MAX_FRAMES) then
|
||||
break;
|
||||
LastFrameBase := FrameBase;
|
||||
{$PUSH}{$R-}{$Q-}
|
||||
if LastFrameBase > 0 then
|
||||
LastFrameBase := LastFrameBase - 1;
|
||||
{$POP}
|
||||
continue;
|
||||
end;
|
||||
Address := PrevAddress;
|
||||
FrameBase := PrevFrameBase;
|
||||
StackPtr := PrevStackPtr;
|
||||
|
||||
if (FrameBase <> 0) and (FrameBase > LastFrameBase)
|
||||
then begin
|
||||
if StackPtr = 0 then
|
||||
@ -3446,7 +3524,8 @@ begin
|
||||
else begin
|
||||
{$PUSH}{$R-}{$Q-}
|
||||
StackPtr := StackPtr + 1 * Size; // After popping return-addr from "StackPtr"
|
||||
LastFrameBase := LastFrameBase - 1; // Make the loop think thas LastFrameBase was smaller
|
||||
if LastFrameBase > 0 then
|
||||
LastFrameBase := LastFrameBase - 1; // Make the loop think thas LastFrameBase was smaller
|
||||
{$POP}
|
||||
// last stack has no frame
|
||||
//AnEntry.RegisterValueList.DbgRegisterAutoCreate[nBP].SetValue(0, '0',Size, BP);
|
||||
@ -3463,6 +3542,7 @@ begin
|
||||
AnEntry.RegisterValueList.DbgRegisterAutoCreate[nIP].SetValue(Address, IntToStr(Address),Size, IP);
|
||||
AnEntry.RegisterValueList.DbgRegisterAutoCreate[nBP].SetValue(FrameBase, IntToStr(FrameBase),Size, BP);
|
||||
AnEntry.RegisterValueList.DbgRegisterAutoCreate[nSP].SetValue(StackPtr, IntToStr(StackPtr),Size, SP);
|
||||
CheckFrame(AnEntry, FrameBase < StackPtr);
|
||||
FCallStackEntryList.Add(AnEntry);
|
||||
Dec(CountNeeded);
|
||||
inc(NextIdx);
|
||||
@ -3471,7 +3551,14 @@ begin
|
||||
break;
|
||||
end
|
||||
else
|
||||
Break;
|
||||
begin
|
||||
AnEntry := nil;
|
||||
CheckFrame(AnEntry);
|
||||
if AnEntry <> nil then
|
||||
FCallStackEntryList.Add(AnEntry)
|
||||
else
|
||||
Break;
|
||||
end;
|
||||
end;
|
||||
if CountNeeded > 0 then // there was an error / not possible to read more frames
|
||||
FCallStackEntryList.SetHasReadAllAvailableFrames;
|
||||
|
@ -568,6 +568,9 @@ type
|
||||
|
||||
function GetFunctionFrameInfo(AnAddress: TDBGPtr; out
|
||||
AnIsOutsideFrame: Boolean): Boolean; override;
|
||||
function IsAfterCallInstruction(AnAddress: TDBGPtr): boolean; override;
|
||||
// Only Modify the values if result is true
|
||||
function UnwindFrame(var AnAddress, AStackPtr, AFramePtr: TDBGPtr; AQuick: boolean): boolean; override;
|
||||
end;
|
||||
|
||||
implementation
|
||||
@ -5172,6 +5175,288 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TX86AsmDecoder.IsAfterCallInstruction(AnAddress: TDBGPtr): boolean;
|
||||
const
|
||||
MAX_RET_LEN = 10;
|
||||
var
|
||||
BytesRead: Cardinal;
|
||||
i: Integer;
|
||||
instr: TDbgAsmInstruction;
|
||||
begin
|
||||
BytesRead := MAX_RET_LEN;
|
||||
Result := (AnAddress > MAX_RET_LEN) and ReadCodeAt(AnAddress - MAX_RET_LEN, BytesRead) and
|
||||
(BytesRead = MAX_RET_LEN);
|
||||
if not Result then begin
|
||||
BytesRead := 5;
|
||||
Result := (AnAddress > MAX_RET_LEN) and ReadCodeAt(AnAddress - MAX_RET_LEN, BytesRead) and
|
||||
(BytesRead = MAX_RET_LEN);
|
||||
end;
|
||||
if not Result then
|
||||
exit;
|
||||
|
||||
// can be a false positive
|
||||
Result := (FCodeBin[MAX_RET_LEN-3] in [$9A, $E8]) or (FCodeBin[MAX_RET_LEN-5] in [$9A, $E8]);
|
||||
if Result then
|
||||
exit;
|
||||
|
||||
for i := 2 to 6 do
|
||||
if (FCodeBin[MAX_RET_LEN - i] = $FF) and
|
||||
(FCodeBin[MAX_RET_LEN + 1 - i] and $38 in [$10, $18])
|
||||
then begin
|
||||
instr := GetInstructionInfo(AnAddress - i);
|
||||
Result := instr.IsCallInstruction;
|
||||
exit;
|
||||
end;
|
||||
if (FCodeBin[MAX_RET_LEN-10] = $FF) and
|
||||
(FCodeBin[MAX_RET_LEN + 1 - 10] and $38 in [$10, $18])
|
||||
then begin
|
||||
instr := GetInstructionInfo(AnAddress-10);
|
||||
Result := instr.IsCallInstruction;
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TX86AsmDecoder.UnwindFrame(var AnAddress, AStackPtr,
|
||||
AFramePtr: TDBGPtr; AQuick: boolean): boolean;
|
||||
|
||||
function IsRegister(Val, Reg: String): boolean;
|
||||
begin
|
||||
Result := (Length(val) >= 2) and (val[1] in ['r', 'e']) and (strlcomp(@Val[2], PChar(Reg), Length(Reg)) = 0);
|
||||
end;
|
||||
function RegisterSize(Reg: String): Cardinal;
|
||||
begin
|
||||
Result := 4;
|
||||
if (Reg <> '') and (Reg[1] = 'r') then
|
||||
Result := 8;
|
||||
end;
|
||||
|
||||
const
|
||||
MAX_SEARCH_ADDR = 1000;
|
||||
MAX_SEARCH_CNT = 80;
|
||||
var
|
||||
NewAddr, NewStack, NewFrame, MaxAddr, StartStack: TDBGPtr;
|
||||
Cnt: Integer;
|
||||
instr: TX86AsmInstruction;
|
||||
RSize: Cardinal;
|
||||
Val: Int64;
|
||||
CurAddr: PByte;
|
||||
begin
|
||||
Result := False;
|
||||
NewAddr := AnAddress;
|
||||
NewStack := AStackPtr;
|
||||
StartStack := AStackPtr;
|
||||
NewFrame := AFramePtr;
|
||||
|
||||
{$PUSH}{$R-}{$Q-}
|
||||
MaxAddr := AnAddress + MAX_SEARCH_ADDR;
|
||||
{$POP}
|
||||
Cnt := MAX_SEARCH_CNT;
|
||||
if AQuick then Cnt := 10;
|
||||
|
||||
while (NewAddr < MaxAddr) and (Cnt > 0) do begin
|
||||
dec(Cnt);
|
||||
instr := TX86AsmInstruction(GetInstructionInfo(NewAddr));
|
||||
if instr.InstructionLength <= 0 then
|
||||
exit;
|
||||
NewAddr := NewAddr + instr.InstructionLength;
|
||||
CurAddr := @instr.FCodeBin[0];
|
||||
|
||||
case instr.X86OpCode of
|
||||
OPret:
|
||||
begin
|
||||
if instr.X86Instruction.OperCnt > 1 then
|
||||
exit;
|
||||
|
||||
Val := 0;
|
||||
if instr.X86Instruction.OperCnt = 1 then
|
||||
Val := ValueFromMem(CurAddr[Instr.X86Instruction.Operand[1].CodeIndex], Instr.X86Instruction.Operand[1].ByteCount, Instr.X86Instruction.Operand[1].FormatFlags);
|
||||
NewAddr := 0;
|
||||
if FProcess.Mode = dm32 then begin
|
||||
if not FProcess.ReadData(NewStack, 4, NewAddr, RSize) then
|
||||
exit;
|
||||
inc(NewStack, 4 + Val);
|
||||
end
|
||||
else begin
|
||||
if not FProcess.ReadData(NewStack, 8, NewAddr, RSize) then
|
||||
exit;
|
||||
inc(NewStack, 8 + Val);
|
||||
end;
|
||||
Result := True;
|
||||
AnAddress := NewAddr;
|
||||
AStackPtr := NewStack;
|
||||
AFramePtr := NewFrame;
|
||||
exit;
|
||||
end;
|
||||
OPpush:
|
||||
begin
|
||||
if AQuick then
|
||||
exit;
|
||||
if (instr.X86Instruction.OperCnt <> 1) or
|
||||
IsRegister(instr.X86Instruction.Operand[1].Value, 'bp') or
|
||||
IsRegister(instr.X86Instruction.Operand[1].Value, 'sp')
|
||||
then begin
|
||||
exit; // false
|
||||
end;
|
||||
{$PUSH}{$R-}{$Q-}
|
||||
NewStack := NewStack - RegisterSize(instr.X86Instruction.Operand[1].Value);
|
||||
{$POP}
|
||||
end;
|
||||
OPpusha, OPpushf:
|
||||
exit; // false
|
||||
OPpopa, OPpopad:
|
||||
exit; // false
|
||||
OPpop:
|
||||
begin
|
||||
if instr.X86Instruction.OperCnt <> 1 then
|
||||
exit;
|
||||
if not(instr.X86Instruction.Operand[1].Value[1] in ['e', 'r'])
|
||||
then
|
||||
exit; // false
|
||||
if IsRegister(instr.X86Instruction.Operand[1].Value, 'bp')
|
||||
then begin
|
||||
if NewStack < StartStack then
|
||||
exit;
|
||||
NewFrame := 0;
|
||||
RSize := RegisterSize(instr.X86Instruction.Operand[1].Value);
|
||||
if not FProcess.ReadData(NewStack, RSize, NewFrame, RSize) then
|
||||
exit;
|
||||
end;
|
||||
{$PUSH}{$R-}{$Q-}
|
||||
NewStack := NewStack + RegisterSize(instr.X86Instruction.Operand[1].Value);
|
||||
{$POP}
|
||||
end;
|
||||
OPleave:
|
||||
begin
|
||||
NewStack := NewFrame;
|
||||
NewFrame := 0;
|
||||
if FProcess.Mode = dm32 then begin
|
||||
if not FProcess.ReadData(NewStack, 4, NewFrame, RSize) then
|
||||
exit;
|
||||
inc(NewStack, 4);
|
||||
end
|
||||
else begin
|
||||
if not FProcess.ReadData(NewStack, 8, NewFrame, RSize) then
|
||||
exit;
|
||||
inc(NewStack, 8);
|
||||
end;
|
||||
end;
|
||||
OPmov:
|
||||
begin
|
||||
if instr.X86Instruction.OperCnt <> 2 then
|
||||
exit;
|
||||
|
||||
if IsRegister(instr.X86Instruction.Operand[1].Value, 'sp')
|
||||
then begin
|
||||
if (not IsRegister(instr.X86Instruction.Operand[2].Value, 'bp')) or
|
||||
(Instr.X86Instruction.Operand[2].ByteCount <> 0) or
|
||||
(Instr.X86Instruction.Operand[2].ByteCount2 <> 0) or
|
||||
(ofMemory in Instr.X86Instruction.Operand[2].Flags)
|
||||
then
|
||||
exit;
|
||||
NewStack := NewFrame;
|
||||
end;
|
||||
end;
|
||||
OPlea:
|
||||
begin
|
||||
if instr.X86Instruction.OperCnt <> 2 then
|
||||
exit;
|
||||
if IsRegister(instr.X86Instruction.Operand[1].Value, 'bp')
|
||||
then begin
|
||||
if (not IsRegister(instr.X86Instruction.Operand[2].Value, 'bp%s')) or
|
||||
(Instr.X86Instruction.Operand[2].ByteCount = 0) or
|
||||
(Instr.X86Instruction.Operand[2].ByteCount2 <> 0) or
|
||||
not(ofMemory in Instr.X86Instruction.Operand[2].Flags)
|
||||
then
|
||||
exit;
|
||||
|
||||
Val := ValueFromMem(CurAddr[Instr.X86Instruction.Operand[2].CodeIndex], Instr.X86Instruction.Operand[2].ByteCount, Instr.X86Instruction.Operand[2].FormatFlags);
|
||||
{$PUSH}{$R-}{$Q-}
|
||||
NewFrame := NewFrame + Val;
|
||||
{$POP}
|
||||
end;
|
||||
if IsRegister(instr.X86Instruction.Operand[1].Value, 'sp')
|
||||
then begin
|
||||
if (Instr.X86Instruction.Operand[2].ByteCount = 0) or
|
||||
(Instr.X86Instruction.Operand[2].ByteCount2 <> 0) or
|
||||
not(ofMemory in Instr.X86Instruction.Operand[2].Flags)
|
||||
then
|
||||
exit;
|
||||
|
||||
if (IsRegister(instr.X86Instruction.Operand[2].Value, 'sp%s')) then begin
|
||||
Val := ValueFromMem(CurAddr[Instr.X86Instruction.Operand[2].CodeIndex], Instr.X86Instruction.Operand[2].ByteCount, Instr.X86Instruction.Operand[2].FormatFlags);
|
||||
{$PUSH}{$R-}{$Q-}
|
||||
NewStack := NewStack + Val;
|
||||
{$POP}
|
||||
end
|
||||
else
|
||||
if (IsRegister(instr.X86Instruction.Operand[2].Value, 'bp%s')) then begin
|
||||
Val := ValueFromMem(CurAddr[Instr.X86Instruction.Operand[2].CodeIndex], Instr.X86Instruction.Operand[2].ByteCount, Instr.X86Instruction.Operand[2].FormatFlags);
|
||||
{$PUSH}{$R-}{$Q-}
|
||||
NewStack := NewFrame + Val;
|
||||
{$POP}
|
||||
end
|
||||
else
|
||||
exit;
|
||||
end;
|
||||
end;
|
||||
OPadd:
|
||||
begin
|
||||
if instr.X86Instruction.OperCnt <> 2 then
|
||||
exit;
|
||||
if IsRegister(instr.X86Instruction.Operand[1].Value, 'sp')
|
||||
then begin
|
||||
if (instr.X86Instruction.Operand[2].Value <> '%s') or
|
||||
(Instr.X86Instruction.Operand[2].ByteCount = 0) or
|
||||
(Instr.X86Instruction.Operand[2].ByteCount2 <> 0) or
|
||||
(ofMemory in Instr.X86Instruction.Operand[2].Flags)
|
||||
then
|
||||
exit;
|
||||
|
||||
Val := ValueFromMem(CurAddr[Instr.X86Instruction.Operand[2].CodeIndex], Instr.X86Instruction.Operand[2].ByteCount, Instr.X86Instruction.Operand[2].FormatFlags);
|
||||
{$PUSH}{$R-}{$Q-}
|
||||
NewStack := NewStack + Val;
|
||||
{$POP}
|
||||
end;
|
||||
end;
|
||||
OPjmp:
|
||||
begin
|
||||
if AQuick then
|
||||
exit;
|
||||
if instr.X86Instruction.OperCnt <> 1 then
|
||||
exit;
|
||||
if (instr.X86Instruction.Operand[1].Value <> '%s') then
|
||||
exit; // false
|
||||
if (Instr.X86Instruction.Operand[1].ByteCount = 0) or
|
||||
(Instr.X86Instruction.Operand[1].ByteCount > 2) or
|
||||
(Instr.X86Instruction.Operand[1].ByteCount2 <> 0)
|
||||
then
|
||||
exit;
|
||||
|
||||
Val := ValueFromMem(CurAddr[Instr.X86Instruction.Operand[1].CodeIndex], Instr.X86Instruction.Operand[1].ByteCount, Instr.X86Instruction.Operand[1].FormatFlags);
|
||||
if Val <= 0 then
|
||||
exit;
|
||||
|
||||
{$PUSH}{$R-}{$Q-}
|
||||
NewAddr := NewAddr + Val
|
||||
{$POP}
|
||||
end;
|
||||
OPjmpe, OPint, OPint1, OPint3:
|
||||
exit; // false
|
||||
else
|
||||
begin
|
||||
if (instr.X86Instruction.OperCnt >= 1) and
|
||||
(not(ofMemory in Instr.X86Instruction.Operand[1].Flags)) and
|
||||
( IsRegister(instr.X86Instruction.Operand[1].Value, 'bp') or
|
||||
IsRegister(instr.X86Instruction.Operand[1].Value, 'sp')
|
||||
)
|
||||
then begin
|
||||
exit; // false
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
initialization
|
||||
DBG_WARNINGS := DebugLogger.FindOrRegisterLogGroup('DBG_WARNINGS' {$IFDEF DBG_WARNINGS} , True {$ENDIF} );
|
||||
|
@ -206,6 +206,7 @@ function QuickUtf8UpperCase(const AText: String): String;
|
||||
function QuickUtf8LowerCase(const AText: String): String;
|
||||
|
||||
function AlignPtr(Src: Pointer; Alignment: Byte): Pointer;
|
||||
function ValueFromMem(const AValue; ASize: Byte; AFlags: THexValueFormatFlags): Int64;
|
||||
function HexValue(const AValue; ASize: Byte; AFlags: THexValueFormatFlags): String;
|
||||
function FormatAddress(const AAddress): String;
|
||||
|
||||
@ -436,6 +437,28 @@ begin
|
||||
Result := HexValue(AAddress, DBGPTRSIZE[GMode], [hvfIncludeHexchar]);
|
||||
end;
|
||||
|
||||
function ValueFromMem(const AValue; ASize: Byte; AFlags: THexValueFormatFlags
|
||||
): Int64;
|
||||
var
|
||||
p: PByte;
|
||||
begin
|
||||
Result := 0;
|
||||
if ASize > 8 then
|
||||
Exit;
|
||||
if ASize = 0 then
|
||||
Exit;
|
||||
|
||||
p := @AValue;
|
||||
if p[ASize - 1] < $80
|
||||
then Exclude(AFlags, hvfSigned);
|
||||
|
||||
if hvfSigned in AFlags
|
||||
then Result := -1
|
||||
else Result := 0;
|
||||
|
||||
Move(AValue, Result, ASize);
|
||||
end;
|
||||
|
||||
function HexValue(const AValue; ASize: Byte; AFlags: THexValueFormatFlags): String;
|
||||
var
|
||||
i: Int64;
|
||||
|
Loading…
Reference in New Issue
Block a user