mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-26 23:00:15 +02:00
GDB: more refactor for disassembler
git-svn-id: trunk@28374 -
This commit is contained in:
parent
e0fced8a5c
commit
25abe82bd4
@ -858,10 +858,21 @@ type
|
||||
{%region ***** Disassembler ***** }
|
||||
|
||||
const
|
||||
// Some values to calculate how many bytes to disassemble for a given amount of lines
|
||||
// Those values are only guesses
|
||||
DAssBytesPerCommandAvg = 8; // Average len: Used for LinesBefore/LinesAfter. (should rather be to big than to small)
|
||||
DAssBytesPerCommandMax = 24; // Max possible len. Only used for up to 5 lines
|
||||
(* Some values to calculate how many bytes to disassemble for a given amount of lines
|
||||
Those values are only guesses *)
|
||||
// DAssBytesPerCommandAvg: Average len: Used for LinesBefore/LinesAfter.
|
||||
// (should rather be to big than to small)
|
||||
DAssBytesPerCommandAvg = 8;
|
||||
// Max possible len of a statement in byte. Only used for up to 5 lines
|
||||
DAssBytesPerCommandMax = 24;
|
||||
// Maximum alignment between to procedures (for detecion of gaps, after dis-ass with source)
|
||||
DAssBytesPerCommandAlign = 16;
|
||||
// If we have a range with more then DAssRangeOverFuncTreshold * DAssBytesPerCommandAvg
|
||||
// then prefer the Range-end as start, rather than the known func start
|
||||
// (otherwhise re-dissassemble the whole function, including the part already known)
|
||||
// The assumption is, that no single *source* statement starting before this range,
|
||||
// will ever reach into the next statement (where the next statement already started / mixed addresses)
|
||||
DAssRangeOverFuncTreshold = 15;
|
||||
type
|
||||
|
||||
{ TGDBMIDisassembleResultList }
|
||||
@ -909,12 +920,10 @@ type
|
||||
FList: TGDBMIDisassembleResultList;
|
||||
FStartedAtIndex: Integer;
|
||||
FStartIdx, FMaxIdx: Integer;
|
||||
FIgnoreLast: Boolean;
|
||||
FLastSubListEndAddr: TDBGPtr;
|
||||
FAddressToLocate, FAddForLineAfterCounter: TDBGPtr;
|
||||
public
|
||||
constructor Create(AList: TGDBMIDisassembleResultList; AStartIdx: Integer;
|
||||
AIgnoreLast: Boolean;
|
||||
ALastSubListEndAddr: TDBGPtr;
|
||||
AnAddressToLocate, AnAddForLineAfterCounter: TDBGPtr);
|
||||
function EOL: Boolean;
|
||||
@ -1502,22 +1511,16 @@ end;
|
||||
{ TGDBMIDisassembleResultFunctionIterator }
|
||||
|
||||
constructor TGDBMIDisassembleResultFunctionIterator.Create(AList: TGDBMIDisassembleResultList;
|
||||
AStartIdx: Integer; AIgnoreLast: Boolean; ALastSubListEndAddr: TDBGPtr;
|
||||
AStartIdx: Integer; ALastSubListEndAddr: TDBGPtr;
|
||||
AnAddressToLocate, AnAddForLineAfterCounter: TDBGPtr);
|
||||
begin
|
||||
FList := AList;
|
||||
FStartedAtIndex := AStartIdx;
|
||||
FStartIdx := AStartIdx;
|
||||
FIgnoreLast := AIgnoreLast;
|
||||
FLastSubListEndAddr := ALastSubListEndAddr;
|
||||
FAddressToLocate := AnAddressToLocate;
|
||||
FAddForLineAfterCounter := AnAddForLineAfterCounter;
|
||||
FMaxIdx := FList.Count - 1;
|
||||
if FIgnoreLast
|
||||
then begin
|
||||
FLastSubListEndAddr := FList.Item[FMaxIdx]^.Addr;
|
||||
dec(FMaxIdx);
|
||||
end;
|
||||
if FStartIdx > FMaxIdx
|
||||
then raise Exception.Create('internal error');
|
||||
FIndexOfLocateAddress := 1;
|
||||
@ -1577,8 +1580,9 @@ begin
|
||||
WasBeforeStart := False;
|
||||
HasLocate := True;
|
||||
end;
|
||||
if (Itm^.Addr = FAddForLineAfterCounter)
|
||||
or ((Itm^.Addr > FAddForLineAfterCounter) and (FIndexOfCounterAddress < 0))
|
||||
if (FAddForLineAfterCounter > 0)
|
||||
and ( (Itm^.Addr = FAddForLineAfterCounter)
|
||||
or ((Itm^.Addr > FAddForLineAfterCounter) and (FIndexOfCounterAddress < 0)) )
|
||||
then FIndexOfCounterAddress := NextIdx;
|
||||
|
||||
if (HasPrcName <> (Itm^.FuncName <> ''))
|
||||
@ -1786,6 +1790,39 @@ begin
|
||||
end;
|
||||
|
||||
function TGDBMIDebuggerCommandDisassembe.DoExecute: Boolean;
|
||||
type
|
||||
TAddressValidity =
|
||||
(avFoundFunction, avFoundRange, avFoundStatemnet, // known address
|
||||
avGuessed, // guessed
|
||||
avExternRequest, // As requested by external caller
|
||||
avPadded // Padded, because address was not known for sure
|
||||
);
|
||||
TAddress = record
|
||||
Value, GuessedValue: TDBGPtr;
|
||||
Offset: Integer;
|
||||
Validity: TAddressValidity;
|
||||
end;
|
||||
|
||||
const
|
||||
TrustedValidity = [avFoundFunction, avFoundRange, avFoundStatemnet];
|
||||
|
||||
function InitAddress(AValue: TDBGPtr; AValidity: TAddressValidity;
|
||||
AnOffset: Integer = -1): TAddress;
|
||||
begin
|
||||
Result.Value := AValue;
|
||||
Result.GuessedValue := AValue;;
|
||||
Result.Offset := AnOffset;
|
||||
Result.Validity := AValidity;
|
||||
end;
|
||||
|
||||
function DbgsAddr(const AnAddr: TAddress): string;
|
||||
const
|
||||
ValidityName: array [TAddressValidity] of string =
|
||||
('FoundFunction', 'FoundRange', 'FoundStatemnet', 'Guessed', 'ExternRequest', 'Padded');
|
||||
begin
|
||||
Result := Format('[[ Value=%u, Guessed=%u, Offset=%d, Validity=%s ]]',
|
||||
[AnAddr.Value, AnAddr.GuessedValue, AnAddr.Offset, ValidityName[AnAddr.Validity]]);
|
||||
end;
|
||||
|
||||
function ExecDisassmble(AStartAddr, AnEndAddr: TDbgPtr; WithSrc: Boolean;
|
||||
AResultList: TGDBMIDisassembleResultList = nil): TGDBMIDisassembleResultList;
|
||||
@ -1819,137 +1856,76 @@ function TGDBMIDebuggerCommandDisassembe.DoExecute: Boolean;
|
||||
else Result := TGDBMIMemoryDumpResultList.Create(R);
|
||||
end;
|
||||
|
||||
function AdjustToKnowFunctionStart(var AStartAddr: TDbgPtr): Boolean;
|
||||
// Set Value, based on GuessedValue
|
||||
function AdjustToKnowFunctionStart(var AStartAddr: TAddress): Boolean;
|
||||
var
|
||||
DisAssList: TGDBMIDisassembleResultList;
|
||||
DisAssItm: PDisassemblerEntry;
|
||||
begin
|
||||
Result := False;
|
||||
DisAssList := ExecDisassmble(AStartAddr-1, AStartAddr, False);
|
||||
DisAssList := ExecDisassmble(AStartAddr.GuessedValue -1, AStartAddr.GuessedValue, False);
|
||||
if DisAssList.Count > 0 then begin
|
||||
DisAssItm := DisAssList.Item[0];
|
||||
if (DisAssItm^.FuncName <> '') and (DisAssItm^.Addr <> 0) and (DisAssItm^.Offset >= 0)
|
||||
then begin
|
||||
AStartAddr := DisAssItm^.Addr - DisAssItm^.Offset; // This should always be good
|
||||
AStartAddr.Value := DisAssItm^.Addr - DisAssItm^.Offset; // This should always be good
|
||||
AStartAddr.Offset := 0;
|
||||
AStartAddr.Validity := avFoundFunction;
|
||||
Result := True;
|
||||
end;
|
||||
end;
|
||||
FreeAndNil(DisAssList);
|
||||
end;
|
||||
|
||||
function AdjustToRangeOrKnowFunctionStart(var AStartAddr: TDbgPtr;
|
||||
ARangeBefore: TDBGDisassemblerEntryRange; AGuessedStart: TDBGPtr;
|
||||
out AStartOffs: Integer; out ADiscardAtart: Boolean): Boolean;
|
||||
const
|
||||
RngBeforeMaxStmtOverlap = 20; // do ot dissasemble more then this statements again, if we have an overlap with a previous range
|
||||
// Set Value, based on GuessedValue
|
||||
function AdjustToRangeOrKnowFunctionStart(var AStartAddr: TAddress;
|
||||
ARangeBefore: TDBGDisassemblerEntryRange): Boolean;
|
||||
begin
|
||||
Result := False;
|
||||
AStartOffs := -1;
|
||||
ADiscardAtart := False;
|
||||
AStartAddr.Offset := -1;
|
||||
AStartAddr.Validity := avGuessed;
|
||||
if AdjustToKnowFunctionStart(AStartAddr)
|
||||
then begin
|
||||
// funtion found
|
||||
AStartOffs := 0;
|
||||
if (ARangeBefore <> nil) and (ARangeBefore.Count > RngBeforeMaxStmtOverlap)
|
||||
and (ARangeBefore.EntriesPtr[ARangeBefore.Count - RngBeforeMaxStmtOverlap]^.Addr > AStartAddr)
|
||||
// funtion found, check for range
|
||||
if (ARangeBefore <> nil) and (ARangeBefore.LastAddr > AStartAddr.Value)
|
||||
and (ARangeBefore.Count > DAssRangeOverFuncTreshold)
|
||||
and (ARangeBefore.EntriesPtr[ARangeBefore.Count - 1]^.Offset > DAssRangeOverFuncTreshold * DAssBytesPerCommandAvg)
|
||||
then begin
|
||||
// got a big overlap, don't redo the whole function
|
||||
{$IFDEF DBG_VERBOSE}
|
||||
debugln(['INFO: Restarting inside previous range for known function-start=', AStartAddr,' and ARangeBefore=', dbgs(ARangeBefore)]);
|
||||
debugln(['INFO: Restarting inside previous range for known function-start=', DbgsAddr(AStartAddr),' and ARangeBefore=', dbgs(ARangeBefore)]);
|
||||
{$ENDIF}
|
||||
// redo one statement
|
||||
AStartAddr := ARangeBefore.EntriesPtr[ARangeBefore.Count - 2]^.Addr;
|
||||
{$PUSH}{$IFnDEF DBGMI_WITH_DISASS_OVERFLOW}{$Q-}{$R-}{$ENDIF} // Overflow is allowed to occur
|
||||
AStartOffs := AStartAddr - ARangeBefore.EntriesPtr[ARangeBefore.Count - RngBeforeMaxStmtOverlap]^.Addr ;
|
||||
AStartAddr.Value := ARangeBefore.EntriesPtr[ARangeBefore.Count - 1]^.Addr;
|
||||
AStartAddr.Offset := ARangeBefore.EntriesPtr[ARangeBefore.Count - 1]^.Offset;
|
||||
AStartAddr.Validity := avFoundRange;
|
||||
//AStartAddr - ARangeBefore.EntriesPtr[ARangeBefore.Count - DAssRangeOverFuncTreshold]^.Addr ;
|
||||
{$POP}
|
||||
end
|
||||
end
|
||||
else begin
|
||||
{$IFDEF DBG_VERBOSE}
|
||||
debugln(['INFO: No known function-start for ', AStartAddr,' ARangeBefore=', dbgs(ARangeBefore)]);
|
||||
debugln(['INFO: No known function-start for ', DbgsAddr(AStartAddr),' ARangeBefore=', dbgs(ARangeBefore)]);
|
||||
{$ENDIF}
|
||||
// no function found
|
||||
if ARangeBefore <> nil
|
||||
// no function found // check distance to previous range
|
||||
// The distance of range before has been checked by the caller
|
||||
if (ARangeBefore <> nil)
|
||||
then begin
|
||||
AStartAddr := ARangeBefore.EntriesPtr[ARangeBefore.Count - Min(2, ARangeBefore.Count)]^.Addr;
|
||||
{$PUSH}{$IFnDEF DBGMI_WITH_DISASS_OVERFLOW}{$Q-}{$R-}{$ENDIF} // Overflow is allowed to occur
|
||||
if (ARangeBefore.Count > RngBeforeMaxStmtOverlap)
|
||||
then AStartOffs := AStartAddr - ARangeBefore.EntriesPtr[ARangeBefore.Count - RngBeforeMaxStmtOverlap]^.Addr ;
|
||||
AStartAddr.Value := ARangeBefore.EntriesPtr[ARangeBefore.Count - 1]^.Addr;
|
||||
AStartAddr.Offset := ARangeBefore.EntriesPtr[ARangeBefore.Count - 1]^.Offset;
|
||||
AStartAddr.Validity := avFoundRange;
|
||||
{$POP}
|
||||
end
|
||||
else begin
|
||||
AStartAddr := AGuessedStart;
|
||||
ADiscardAtart := True;
|
||||
AStartAddr.Value := AStartAddr.GuessedValue;
|
||||
AStartAddr.Offset := -1;
|
||||
AStartAddr.Validity := avGuessed;;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
function FindProcEnd(const ADisAssList: TGDBMIDisassembleResultList;
|
||||
AFromIndex: Integer;
|
||||
out ANextIndex: Integer; // Index of first Statement in next Procedure (or code without Proc)
|
||||
out AStartAddrFoundIndex, // Index of statement that has FStartAddr (or -1)
|
||||
AStartAddrFoundOffset: Integer; // FStartAddr was found n bytes from statement (-1, if FStartAddr was not in block)
|
||||
AIgnoreLast: Boolean = False
|
||||
): Boolean;
|
||||
var
|
||||
Cnt: Integer;
|
||||
WasBeforeStart: Boolean;
|
||||
HasPrcName: Boolean;
|
||||
PrcBaseAddr: TDBGPtr;
|
||||
Itm: PDisassemblerEntry;
|
||||
begin
|
||||
Cnt := ADisAssList.Count;
|
||||
if AIgnoreLast
|
||||
then dec(Cnt);
|
||||
if AFromIndex >= Cnt
|
||||
then raise Exception.Create('internal error');
|
||||
|
||||
(* The name may change in the middle of a function. Check for either:
|
||||
- change between no-name and has-name
|
||||
- change of the base-address (addr-offset), if the offset is valid (if has-name)
|
||||
*)
|
||||
HasPrcName := ADisAssList.Item[AFromIndex]^.FuncName <> ''; // can use offsets
|
||||
{$PUSH}{$IFnDEF DBGMI_WITH_DISASS_OVERFLOW}{$Q-}{$ENDIF} // Overflow is allowed to occur
|
||||
PrcBaseAddr := ADisAssList.Item[AFromIndex]^.Addr - ADisAssList.Item[AFromIndex]^.Offset;
|
||||
{$POP}
|
||||
|
||||
WasBeforeStart := ADisAssList.Item[AFromIndex]^.Addr < FStartAddr;
|
||||
AStartAddrFoundIndex := -1;
|
||||
AStartAddrFoundOffset := -1;
|
||||
|
||||
ANextIndex := AFromIndex;
|
||||
while ANextIndex < Cnt do
|
||||
begin
|
||||
Itm := ADisAssList.Item[ANextIndex];
|
||||
{$PUSH}{$IFnDEF DBGMI_WITH_DISASS_OVERFLOW}{$Q-}{$ENDIF} // Overflow is allowed to occur
|
||||
// Also check the next statement after PrcName.
|
||||
// If it has AStartAddrFoundOffset > 0, then FStartAddr is in current block, but not matched
|
||||
if (Itm^.Addr = FStartAddr)
|
||||
then begin
|
||||
AStartAddrFoundIndex := ANextIndex;
|
||||
AStartAddrFoundOffset := 0;
|
||||
WasBeforeStart := False;
|
||||
end
|
||||
else if WasBeforeStart and (Itm^.Addr > FStartAddr)
|
||||
then begin
|
||||
AStartAddrFoundIndex := ANextIndex - 1;
|
||||
AStartAddrFoundOffset := FStartAddr - ADisAssList.Item[ANextIndex-1]^.Addr;
|
||||
WasBeforeStart := False;
|
||||
end;
|
||||
|
||||
if (HasPrcName <> (Itm^.FuncName <> ''))
|
||||
or (HasPrcName and (PrcBaseAddr <> Itm^.Addr - Itm^.Offset))
|
||||
then break;
|
||||
{$POP}
|
||||
|
||||
inc(ANextIndex);
|
||||
end;
|
||||
// Does the next address look good?
|
||||
// And is AStartAddrHit ok
|
||||
Result := ((ANextIndex >= Cnt) or (ADisAssList.Item[ANextIndex]^.Offset = 0))
|
||||
and ( (AStartAddrFoundIndex < 0) or (AStartAddrFoundOffset = 0) );
|
||||
end;
|
||||
|
||||
procedure CopyToRange(const ADisAssList: TGDBMIDisassembleResultList;
|
||||
const ADestRange: TDBGDisassemblerEntryRange; AFromIndex, ACount: Integer;
|
||||
const ASrcInfoDisAssList: TGDBMIDisassembleResultList = nil);
|
||||
@ -2063,9 +2039,32 @@ function TGDBMIDebuggerCommandDisassembe.DoExecute: Boolean;
|
||||
end;
|
||||
end;
|
||||
|
||||
function DoDisassembleRange(AFirstAddr, ALastAddr: TDBGPtr;
|
||||
DiscardAtStart: Boolean; AFirstAddrOffs: Integer;
|
||||
AEndIsKnownStatement: Boolean;
|
||||
(* Known issues with GDB's disassembler results:
|
||||
** "-data-disassemble -s ### -e ### -- 1" with source
|
||||
* Result may not be sorted by addresses
|
||||
=>
|
||||
* Result may be empty, even where "-- 0" (no src info) does return data
|
||||
=> Remedy: disassemble those secions without src-info
|
||||
If function-offset is available, this can be done per function
|
||||
* Result may be missing src-info, even if src-info is available for parts of the result
|
||||
This seems to be the case, if no src info is available for the start address,
|
||||
then src-info for later addresses will be ignored.
|
||||
=> Remedy: if function offset is available, disassembl;e per function
|
||||
* Contains address gaps, as it does not show fillbytes, between functions
|
||||
** "-data-disassemble -s ### -e ### -- 0" without source (probably both (with/without src)
|
||||
* "func-name" may change, while "offset" keeps increasing
|
||||
This was seen after the end of a procedure, with 0x00 bytes filling up to the next proc
|
||||
=> Remedy: None, can be ignored
|
||||
* In contineous disassemble a function may not be started at offset=0.
|
||||
This seems to happen after 0x00 fill bytes.
|
||||
The func-name changes and the offset restarts at a lower value (but not 0)
|
||||
=> Remedy: discard data, and re-disassemble
|
||||
*)
|
||||
// Returns True: If some data was added
|
||||
// False: if failed to add anything
|
||||
function DoDisassembleRange(AFirstAddr, ALastAddr: TAddress;
|
||||
//DiscardAtStart: Boolean; AFirstAddrOffs: Integer;
|
||||
//AEndIsKnownStatement: Boolean;
|
||||
StopAfterAddress: TDBGPtr; StopAfterNumLines: Integer
|
||||
): Boolean;
|
||||
var
|
||||
@ -2073,64 +2072,50 @@ function TGDBMIDebuggerCommandDisassembe.DoExecute: Boolean;
|
||||
DisAssList, DisAssListCurrentSub, DisAssListWithSrc: TGDBMIDisassembleResultList;
|
||||
i, Cnt: Integer;
|
||||
NewRange: TDBGDisassemblerEntryRange;
|
||||
OrigLastAddress, OrigFirstAddress: TDBGPtr;
|
||||
OrigLastAddress, OrigFirstAddress: TAddress;
|
||||
BlockOk, GotFullDisAss: Boolean;
|
||||
s: String;
|
||||
Itm: TDisassemblerEntry;
|
||||
begin
|
||||
// Returns True: If some data was added
|
||||
// False: if failed to add anything
|
||||
(* Known issues with GDB's disassembler results:
|
||||
** "-data-disassemble -s ### -e ### -- 1" with source
|
||||
* Result may not be sorted by addresses
|
||||
=>
|
||||
* Result may be empty, even where "-- 0" (no src info) does return data
|
||||
=> Remedy: disassemble those secions without src-info
|
||||
If function-offset is available, this can be done per function
|
||||
* Result may be missing src-info, even if src-info is available for parts of the result
|
||||
This seems to be the case, if no src info is available for the start address,
|
||||
then src-info for later addresses will be ignored.
|
||||
=> Remedy: if function offset is available, disassembl;e per function
|
||||
* Contains address gaps, as it does not show fillbytes, between functions
|
||||
** "-data-disassemble -s ### -e ### -- 0" without source (probably both (with/without src)
|
||||
* "func-name" may change, while "offset" keeps increasing
|
||||
This was seen after the end of a procedure, with 0x00 bytes filling up to the next proc
|
||||
=> Remedy: None, can be ignored
|
||||
* In contineous disassemble a function may not be started at offset=0.
|
||||
This seems to happen after 0x00 fill bytes.
|
||||
The func-name changes and the offset restarts at a lower value (but not 0)
|
||||
=> Remedy: discard data, and re-disassemble
|
||||
*)
|
||||
Result := False;
|
||||
DisAssList := nil;
|
||||
DisAssListCurrentSub := nil;
|
||||
DisAssListWithSrc := nil;
|
||||
DisAssIterator := nil;
|
||||
OrigLastAddress := ALastAddr;
|
||||
OrigFirstAddress := AFirstAddr;
|
||||
OrigLastAddress := ALastAddr;
|
||||
|
||||
// No nice startingpoint found, just start to disassemble aprox 5 instructions
|
||||
// before it and hope that when we started in the middle of an instruction it
|
||||
// get sorted out.
|
||||
// The 4st for lines from the result must be discarded
|
||||
if DiscardAtStart
|
||||
then StartAddr := StartAddr - 5 * DAssBytesPerCommandMax;
|
||||
NewRange := TDBGDisassemblerEntryRange.Create;
|
||||
|
||||
// No nice startingpoint found, just start to disassemble aprox 5 instructions before it
|
||||
// and hope that when we started in the middle of an instruction it get sorted out.
|
||||
// If so, the 4st for lines from the result must be discarded
|
||||
if not (AFirstAddr.Validity in TrustedValidity)
|
||||
then begin
|
||||
AFirstAddr.Value := AFirstAddr.Value - 5 * DAssBytesPerCommandMax;
|
||||
AFirstAddr.Validity := avPadded;
|
||||
end;
|
||||
|
||||
// Adjust ALastAddr
|
||||
if ALastAddr < AFirstAddr
|
||||
if ALastAddr.Value < AFirstAddr.Value
|
||||
then begin
|
||||
ALastAddr := AFirstAddr + 2 * DAssBytesPerCommandMax;
|
||||
AEndIsKnownStatement := False;
|
||||
ALastAddr.Value := AFirstAddr.Value + 2 * DAssBytesPerCommandMax;
|
||||
ALastAddr.Validity := avPadded;
|
||||
end
|
||||
else if not AEndIsKnownStatement
|
||||
then ALastAddr := ALastAddr + 2 * DAssBytesPerCommandMax;
|
||||
else
|
||||
if not (ALastAddr.Validity in TrustedValidity)
|
||||
then begin
|
||||
ALastAddr.Value := ALastAddr.Value + 2 * DAssBytesPerCommandMax;
|
||||
ALastAddr.Validity := avPadded;
|
||||
end;
|
||||
|
||||
|
||||
// check if we have an overall source-info
|
||||
// we can only do that, if we know the offset of firstaddr (limit to 15 avg lines, should be enough)
|
||||
if (AFirstAddrOffs >= 0)
|
||||
// we can only do that, if we know the offset of firstaddr (limit to DAssRangeOverFuncTreshold avg lines, should be enough)
|
||||
if (AFirstAddr.Offset >= 0)
|
||||
then DisAssListWithSrc := ExecDisassmble
|
||||
(AFirstAddr - Min(AFirstAddrOffs, 15 * DAssBytesPerCommandAvg), ALastAddr, True);
|
||||
(AFirstAddr.Value - Min(AFirstAddr.Offset, DAssRangeOverFuncTreshold * DAssBytesPerCommandAvg),
|
||||
ALastAddr.Value, True);
|
||||
GotFullDisAss := (DisAssListWithSrc <> nil) and (DisAssListWithSrc.Count > 0) and DisAssListWithSrc.HasSourceInfo;
|
||||
|
||||
if (DisAssListWithSrc <> nil) and (DisAssListWithSrc.Count > 0) and (not DisAssListWithSrc.HasSourceInfo)
|
||||
@ -2143,7 +2128,7 @@ function TGDBMIDebuggerCommandDisassembe.DoExecute: Boolean;
|
||||
// Given that disassembler with source has gaps, or may be empty at all,
|
||||
// and also would need sorting => let's start without src-info
|
||||
if DisAssList = nil
|
||||
then DisAssList := ExecDisassmble(AFirstAddr, ALastAddr, False);
|
||||
then DisAssList := ExecDisassmble(AFirstAddr.Value, ALastAddr.Value, False);
|
||||
|
||||
|
||||
Cnt := DisAssList.Count;
|
||||
@ -2151,12 +2136,11 @@ function TGDBMIDebuggerCommandDisassembe.DoExecute: Boolean;
|
||||
then begin
|
||||
debugln('Error failed to get enough data for dsassemble');
|
||||
// create a dummy range, so we will not retry
|
||||
NewRange := TDBGDisassemblerEntryRange.Create;
|
||||
NewRange.Capacity := 1;
|
||||
NewRange.LastEntryEndAddr := ALastAddr;
|
||||
NewRange.RangeStartAddr := AFirstAddr;
|
||||
NewRange.RangeEndAddr := OrigLastAddress;
|
||||
Itm.Addr := AFirstAddr;
|
||||
NewRange.RangeStartAddr := AFirstAddr.Value;
|
||||
NewRange.RangeEndAddr := OrigLastAddress.Value;
|
||||
NewRange.LastEntryEndAddr := OrigLastAddress.Value;
|
||||
Itm.Addr := AFirstAddr.Value;
|
||||
Itm.Dump := ' ';
|
||||
Itm.SrcFileLine := 0;
|
||||
Itm.Offset := 0;
|
||||
@ -2165,44 +2149,44 @@ function TGDBMIDebuggerCommandDisassembe.DoExecute: Boolean;
|
||||
FKnownRanges.AddRange(NewRange); // NewRange is now owned by FKnownRanges
|
||||
NewRange := nil;
|
||||
FreeAndNil(DisAssList);
|
||||
FreeAndNil(DisAssListWithSrc);
|
||||
exit;
|
||||
end;
|
||||
|
||||
// we may have gotten more lines than ask, and the last line we don't know the length
|
||||
if not( AEndIsKnownStatement and (DisAssList.Item[Cnt - 1]^.Addr < ALastAddr) )
|
||||
if (ALastAddr.Validity = avPadded) or (DisAssList.LastItem^.Addr >= ALastAddr.Value)
|
||||
then begin
|
||||
dec(cnt);
|
||||
ALastAddr := DisAssList.Item[Cnt]^.Addr;
|
||||
AEndIsKnownStatement := False;
|
||||
ALastAddr.Value := DisAssList.LastItem^.Addr;
|
||||
ALastAddr.Validity := avFoundStatemnet;
|
||||
dec(Cnt);
|
||||
DisAssList.Count := Cnt;
|
||||
end;
|
||||
// ALastAddr.Value is now the address after the last statement;
|
||||
|
||||
i := 0;
|
||||
if DiscardAtStart
|
||||
if not (AFirstAddr.Validity = avPadded)
|
||||
then begin
|
||||
// drop up to 4 entries, if possible
|
||||
while (i < 4) and (i + 1 < Cnt) and (DisAssList.Item[i+1]^.Addr <= OrigFirstAddress)
|
||||
while (i < 4) and (i + 1 < Cnt) and (DisAssList.Item[i+1]^.Addr <= OrigFirstAddress.Value)
|
||||
do inc(i);
|
||||
AFirstAddr := DisAssList.Item[i]^.Addr;
|
||||
AFirstAddr.Value := DisAssList.Item[i]^.Addr;
|
||||
AFirstAddr.Validity := avFoundStatemnet;
|
||||
end;
|
||||
|
||||
|
||||
NewRange := TDBGDisassemblerEntryRange.Create;
|
||||
NewRange.Capacity := Cnt;
|
||||
if AEndIsKnownStatement
|
||||
then NewRange.LastEntryEndAddr := ALastAddr
|
||||
else NewRange.LastEntryEndAddr := DisAssList.Item[Cnt]^.Addr;
|
||||
NewRange.RangeStartAddr := AFirstAddr;
|
||||
NewRange.RangeEndAddr := OrigLastAddress;
|
||||
NewRange.Capacity := Max(NewRange.Capacity, NewRange.Count + Cnt);
|
||||
NewRange.LastEntryEndAddr := ALastAddr.Value;
|
||||
NewRange.RangeStartAddr := AFirstAddr.Value;
|
||||
NewRange.RangeEndAddr := OrigLastAddress.Value; // we have/will have tried our best to get everything to this value. If we didn't then neither will we later
|
||||
|
||||
DisAssIterator := TGDBMIDisassembleResultFunctionIterator.Create
|
||||
(DisAssList, i, not AEndIsKnownStatement, ALastAddr, FStartAddr, FEndAddr);
|
||||
(DisAssList, i, ALastAddr.Value, FStartAddr, StopAfterAddress);
|
||||
|
||||
while not DisAssIterator.EOL
|
||||
do begin
|
||||
BlockOk := DisAssIterator.NextSubList(DisAssListCurrentSub);
|
||||
|
||||
if (StopAfterAddress <> 0)
|
||||
and (DisAssIterator.CountLinesAfterCounterAddr > StopAfterNumLines) // got enough lines
|
||||
if (DisAssIterator.CountLinesAfterCounterAddr > StopAfterNumLines) // got enough lines
|
||||
// only if the next block is good to go
|
||||
and not ( (not BlockOk) or (DisAssListCurrentSub.Item[0]^.Offset <> 0) or (not GotFullDisAss) )
|
||||
then begin
|
||||
@ -2293,12 +2277,12 @@ function TGDBMIDebuggerCommandDisassembe.DoExecute: Boolean;
|
||||
debugln(['WARNING: FindProcEnd reported an issue FromIdx=', DisAssIterator.CurrentIndex,' NextIdx=',
|
||||
DisAssIterator.NextIndex, ' StartIdx=', DisAssIterator.IndexOfLocateAddress, ' StartOffs=', DisAssIterator.OffsetOfLocateAddress]);
|
||||
{$ENDIF}
|
||||
if DiscardAtStart
|
||||
and (DisAssIterator.IndexOfLocateAddress >= DisAssIterator.CurrentIndex) // in current list
|
||||
and (DisAssIterator.OffsetOfLocateAddress <> 0)
|
||||
then begin
|
||||
// FStartAddr is in the middle of a statement. Maybe move the Range?
|
||||
end;
|
||||
//if DisAssIterator.IsFirstSubList and (not(AFirstAddr.Validity in TrustedValidity))
|
||||
//and (DisAssIterator.IndexOfLocateAddress >= DisAssIterator.CurrentIndex) // in current list
|
||||
//and (DisAssIterator.OffsetOfLocateAddress <> 0)
|
||||
//then begin
|
||||
// // FStartAddr is in the middle of a statement. Maybe move the Range?
|
||||
//end;
|
||||
|
||||
CopyToRange(DisAssListCurrentSub, NewRange, 0, DisAssListCurrentSub.Count);
|
||||
Result := Result or (DisAssListCurrentSub.Count > 0);
|
||||
@ -2370,9 +2354,9 @@ function TGDBMIDebuggerCommandDisassembe.DoExecute: Boolean;
|
||||
end;
|
||||
|
||||
var
|
||||
TryStartAt, TryEndAt, TmpAddr: TDbgPtr;
|
||||
DiscardAtStart: Boolean;
|
||||
GotCnt, LastGotCnt, TryStartAtOffs: Integer;
|
||||
TryStartAt, TryEndAt: TAddress;
|
||||
TmpAddr: TDBGPtr;
|
||||
GotCnt, LastGotCnt: Integer;
|
||||
RngBefore, RngAfter: TDBGDisassemblerEntryRange;
|
||||
begin
|
||||
Result := True;
|
||||
@ -2385,23 +2369,22 @@ begin
|
||||
the boundaries of the 1ast unknown section after FStartAddr
|
||||
*)
|
||||
// Guess the maximum Addr-Range which needs to be disassembled
|
||||
TryStartAt := FStartAddr;
|
||||
TryStartAt := InitAddress(FStartAddr, avExternRequest, -1);
|
||||
// Find the begin of the function at TryStartAt
|
||||
// or the rng before (if not to far back)
|
||||
TryStartAtOffs := -1;
|
||||
DiscardAtStart := False;
|
||||
|
||||
RngBefore := FRangeIterator.GetRangeForAddr(FStartAddr, True);
|
||||
{$PUSH}{$IFnDEF DBGMI_WITH_DISASS_OVERFLOW}{$Q-}{$R-}{$ENDIF} // Overflow is allowed to occur
|
||||
if (RngBefore <> nil)
|
||||
and (TryStartAt > RngBefore.EntriesPtr[RngBefore.Count - 1]^.Addr)
|
||||
and (TryStartAt - RngBefore.EntriesPtr[RngBefore.Count - 1]^.Addr > FLinesBefore * DAssBytesPerCommandAvg)
|
||||
and (TryStartAt.Value > RngBefore.EntriesPtr[RngBefore.Count - 1]^.Addr)
|
||||
and (TryStartAt.Value - RngBefore.EntriesPtr[RngBefore.Count - 1]^.Addr > FLinesBefore * DAssBytesPerCommandAvg)
|
||||
then RngBefore := nil;
|
||||
{$POP}
|
||||
AdjustToRangeOrKnowFunctionStart(TryStartAt, RngBefore,
|
||||
FStartAddr - FLinesBefore * DAssBytesPerCommandAvg, TryStartAtOffs, DiscardAtStart);
|
||||
TryStartAt.GuessedValue := FStartAddr - FLinesBefore * DAssBytesPerCommandAvg;
|
||||
AdjustToRangeOrKnowFunctionStart(TryStartAt, RngBefore);
|
||||
|
||||
// Guess Maximum, will adjust later
|
||||
TryEndAt := FEndAddr + FLinesAfter * DAssBytesPerCommandAvg;
|
||||
TryEndAt := InitAddress(FEndAddr + FLinesAfter * DAssBytesPerCommandAvg, avGuessed);
|
||||
|
||||
// Read as many unknown ranges, until LinesAfter is met
|
||||
GotCnt := -1;
|
||||
@ -2422,7 +2405,7 @@ begin
|
||||
if (GotCnt >= FLinesAfter)
|
||||
then break;
|
||||
// adjust end address
|
||||
TryEndAt := RngBefore.RangeEndAddr + (FLinesAfter-GotCnt) * DAssBytesPerCommandAvg;
|
||||
TryEndAt := InitAddress(RngBefore.RangeEndAddr + (FLinesAfter-GotCnt) * DAssBytesPerCommandAvg, avGuessed);
|
||||
end
|
||||
else GotCnt := 0;
|
||||
end;
|
||||
@ -2434,15 +2417,17 @@ begin
|
||||
|
||||
RngAfter := FRangeIterator.NextRange;
|
||||
// adjust TryEndAt
|
||||
if (RngAfter <> nil) and (TryEndAt >= RngAfter.RangeStartAddr)
|
||||
then TryEndAt := RngAfter.RangeStartAddr;
|
||||
if (RngAfter <> nil) and (TryEndAt.Value >= RngAfter.RangeStartAddr)
|
||||
then begin
|
||||
TryEndAt.Value := RngAfter.RangeStartAddr;
|
||||
TryEndAt.Validity := avFoundRange;
|
||||
end;
|
||||
|
||||
// Try to disassemble the range
|
||||
if not DoDisassembleRange(TryStartAt, TryEndAt, DiscardAtStart, TryStartAtOffs,
|
||||
False, TmpAddr, FLinesAfter-GotCnt)
|
||||
if not DoDisassembleRange(TryStartAt, TryEndAt, TmpAddr, FLinesAfter-GotCnt)
|
||||
then begin
|
||||
// disassemble failed
|
||||
debugln(['ERROR: Failed to disassemble from ', TryStartAt,' to ', TryEndAt]);
|
||||
debugln(['ERROR: Failed to disassemble from ', DbgsAddr(TryStartAt),' to ', DbgsAddr(TryEndAt)]);
|
||||
break;
|
||||
end;
|
||||
|
||||
@ -2450,13 +2435,13 @@ begin
|
||||
RngBefore := FRangeIterator.GetRangeForAddr(FStartAddr, False);
|
||||
if (RngBefore = nil)
|
||||
then begin
|
||||
debugln(['INTERNAL ERROR: (linesafter) Missing the data, that was just disassembled: from ', TryStartAt,' to ', TryEndAt]);
|
||||
debugln(['INTERNAL ERROR: (linesafter) Missing the data, that was just disassembled: from ', DbgsAddr(TryStartAt),' to ', DbgsAddr(TryEndAt)]);
|
||||
break;
|
||||
end;
|
||||
|
||||
TryStartAt := RngBefore.RangeEndAddr;
|
||||
TryEndAt := FEndAddr + FLinesAfter * DAssBytesPerCommandAvg;
|
||||
DiscardAtStart := False;
|
||||
TryStartAt.Value := RngBefore.RangeEndAddr;
|
||||
TryStartAt.Validity := avFoundRange;
|
||||
TryEndAt := InitAddress(FEndAddr + FLinesAfter * DAssBytesPerCommandAvg, avGuessed);
|
||||
end;
|
||||
|
||||
// Find LinesBefore
|
||||
@ -2467,7 +2452,7 @@ begin
|
||||
LastGotCnt:= GotCnt;
|
||||
if (RngAfter = nil)
|
||||
then begin
|
||||
debugln(['INTERNAL ERROR: (linesbefore) Missing the data, that was disassembled: from ', TryStartAt,' to ', TryEndAt]);
|
||||
debugln(['INTERNAL ERROR: (linesbefore) Missing the data, that was disassembled: from ', DbgsAddr(TryStartAt),' to ', DbgsAddr(TryEndAt)]);
|
||||
break;
|
||||
end;
|
||||
|
||||
@ -2480,25 +2465,24 @@ begin
|
||||
break;
|
||||
end;
|
||||
|
||||
TryEndAt := RngAfter.RangeStartAddr;
|
||||
TryStartAt := TryEndAt - 1;
|
||||
TryEndAt := InitAddress(RngAfter.RangeStartAddr, avFoundRange);
|
||||
TryStartAt := InitAddress(TryEndAt.Value - 1, avGuessed);
|
||||
TryStartAt.GuessedValue := TryEndAt.Value - (FLinesBefore - GotCnt) * DAssBytesPerCommandAvg;
|
||||
// and adjust
|
||||
RngBefore := FRangeIterator.PreviousRange;
|
||||
{$PUSH}{$IFnDEF DBGMI_WITH_DISASS_OVERFLOW}{$Q-}{$R-}{$ENDIF} // Overflow is allowed to occur
|
||||
if (RngBefore <> nil)
|
||||
and (TryStartAt > RngBefore.EntriesPtr[RngBefore.Count - 1]^.Addr)
|
||||
and (TryStartAt - RngBefore.EntriesPtr[RngBefore.Count - 1]^.Addr > (FLinesBefore - GotCnt) * DAssBytesPerCommandAvg)
|
||||
and (TryStartAt.Value > RngBefore.EntriesPtr[RngBefore.Count - 1]^.Addr)
|
||||
and (TryStartAt.Value - RngBefore.EntriesPtr[RngBefore.Count - 1]^.Addr > (FLinesBefore - GotCnt) * DAssBytesPerCommandAvg)
|
||||
then RngBefore := nil;
|
||||
{$POP}
|
||||
AdjustToRangeOrKnowFunctionStart(TryStartAt, RngBefore,
|
||||
TryEndAt - (FLinesBefore - GotCnt) * DAssBytesPerCommandAvg, TryStartAtOffs, DiscardAtStart);
|
||||
AdjustToRangeOrKnowFunctionStart(TryStartAt, RngBefore);
|
||||
|
||||
// Try to disassemble the range
|
||||
if not DoDisassembleRange(TryStartAt, TryEndAt, DiscardAtStart, TryStartAtOffs,
|
||||
True, 0, -1)
|
||||
if not DoDisassembleRange(TryStartAt, TryEndAt, 0, -1)
|
||||
then begin
|
||||
// disassemble failed
|
||||
debugln(['ERROR: Failed to disassemble from ', TryStartAt,' to ', TryEndAt]);
|
||||
debugln(['ERROR: Failed to disassemble from ', DbgsAddr(TryStartAt),' to ', DbgsAddr(TryEndAt)]);
|
||||
break;
|
||||
end;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user