DBG: Refactor Disassembler

git-svn-id: trunk@28360 -
This commit is contained in:
martin 2010-11-20 00:33:38 +00:00
parent 4eaba3647b
commit dee17fe6e4
2 changed files with 421 additions and 158 deletions

View File

@ -1030,6 +1030,7 @@ type
property OnCurrent: TNotifyEvent read FOnCurrent write FOnCurrent; property OnCurrent: TNotifyEvent read FOnCurrent write FOnCurrent;
end; end;
{%region ***** Disassembler ***** }
(******************************************************************************) (******************************************************************************)
(******************************************************************************) (******************************************************************************)
(** **) (** **)
@ -1150,9 +1151,19 @@ type
TDBGDisassemblerEntryMapMergeEvent TDBGDisassemblerEntryMapMergeEvent
= procedure(MergeReceiver, MergeGiver: TDBGDisassemblerEntryRange) of object; = procedure(MergeReceiver, MergeGiver: TDBGDisassemblerEntryRange) of object;
{ TDBGDisassemblerEntryMapIterator }
TDBGDisassemblerEntryMap = class;
TDBGDisassemblerEntryMapIterator = class(TMapIterator)
public
function GetRangeForAddr(AnAddr: TDbgPtr; IncludeNextAddr: Boolean = False): TDBGDisassemblerEntryRange;
function NextRange: TDBGDisassemblerEntryRange;
function PreviousRange: TDBGDisassemblerEntryRange;
end;
TDBGDisassemblerEntryMap = class(TMap) TDBGDisassemblerEntryMap = class(TMap)
private private
FIterator: TMapIterator; FIterator: TDBGDisassemblerEntryMapIterator;
FOnDelete: TNotifyEvent; FOnDelete: TNotifyEvent;
FOnMerge: TDBGDisassemblerEntryMapMergeEvent; FOnMerge: TDBGDisassemblerEntryMapMergeEvent;
FFreeItemLock: Boolean; FFreeItemLock: Boolean;
@ -1200,6 +1211,7 @@ type
property OnChange: TNotifyEvent read FOnChange write FOnChange; property OnChange: TNotifyEvent read FOnChange write FOnChange;
end; end;
{%endregion ^^^^^ Disassembler ^^^^^ }
(******************************************************************************) (******************************************************************************)
(******************************************************************************) (******************************************************************************)
@ -5168,6 +5180,46 @@ begin
AOffs := AnAddr - FEntries[Result].Addr; AOffs := AnAddr - FEntries[Result].Addr;
end; end;
{ TDBGDisassemblerEntryMapIterator }
function TDBGDisassemblerEntryMapIterator.GetRangeForAddr(AnAddr: TDbgPtr;
IncludeNextAddr: Boolean): TDBGDisassemblerEntryRange;
begin
Result := nil;
if not Locate(AnAddr)
then if not BOM
then Previous;
if BOM
then exit;
GetData(Result);
if not Result.ContainsAddr(AnAddr, IncludeNextAddr)
then Result := nil;
end;
function TDBGDisassemblerEntryMapIterator.NextRange: TDBGDisassemblerEntryRange;
begin
Result := nil;
if EOM
then exit;
Next;
if not EOM
then GetData(Result);
end;
function TDBGDisassemblerEntryMapIterator.PreviousRange: TDBGDisassemblerEntryRange;
begin
Result := nil;
if BOM
then exit;
Previous;
if not BOM
then GetData(Result);
end;
{ TDBGDisassemblerEntryMap } { TDBGDisassemblerEntryMap }
procedure TDBGDisassemblerEntryMap.ReleaseData(ADataPtr: Pointer); procedure TDBGDisassemblerEntryMap.ReleaseData(ADataPtr: Pointer);
@ -5184,7 +5236,7 @@ end;
constructor TDBGDisassemblerEntryMap.Create(AIdType: TMapIdType; ADataSize: Cardinal); constructor TDBGDisassemblerEntryMap.Create(AIdType: TMapIdType; ADataSize: Cardinal);
begin begin
inherited; inherited;
FIterator := TMapIterator.Create(Self); FIterator := TDBGDisassemblerEntryMapIterator.Create(Self);
end; end;
destructor TDBGDisassemblerEntryMap.Destroy; destructor TDBGDisassemblerEntryMap.Destroy;
@ -5249,17 +5301,7 @@ end;
function TDBGDisassemblerEntryMap.GetRangeForAddr(AnAddr: TDbgPtr; function TDBGDisassemblerEntryMap.GetRangeForAddr(AnAddr: TDbgPtr;
IncludeNextAddr: Boolean = False): TDBGDisassemblerEntryRange; IncludeNextAddr: Boolean = False): TDBGDisassemblerEntryRange;
begin begin
Result := nil; Result := FIterator.GetRangeForAddr(AnAddr, IncludeNextAddr);
if not FIterator.Locate(AnAddr)
then if not FIterator.BOM
then FIterator.Previous;
if FIterator.BOM
then exit;
FIterator.GetData(Result);
if not Result.ContainsAddr(AnAddr, IncludeNextAddr)
then Result := nil;
end; end;
{ TDBGDisassembler } { TDBGDisassembler }

View File

@ -369,11 +369,11 @@ type
function GetValue(const AName : string): string; function GetValue(const AName : string): string;
function GetValuePtr(const AName: string): TPCharWithLen; function GetValuePtr(const AName: string): TPCharWithLen;
public public
constructor Create(const AResultValues: String); constructor Create(const AResultValues: String); overload;
constructor Create(const AResultValues: TPCharWithLen); constructor Create(const AResultValues: TPCharWithLen); overload;
constructor Create(AResult: TGDBMIExecResult); constructor Create(AResult: TGDBMIExecResult); overload;
constructor Create(const AResultValues: String; const APath: array of String); constructor Create(const AResultValues: String; const APath: array of String); overload;
constructor Create(AResult: TGDBMIExecResult; const APath: array of String); constructor Create(AResult: TGDBMIExecResult; const APath: array of String); overload;
procedure Delete(AIndex: Integer); procedure Delete(AIndex: Integer);
procedure Init(const AResultValues: String); procedure Init(const AResultValues: String);
procedure Init(AResultValues: PChar; ALength: Integer); procedure Init(AResultValues: PChar; ALength: Integer);
@ -395,6 +395,7 @@ type
FNameValueList: TGDBMINameValueList; FNameValueList: TGDBMINameValueList;
procedure PreParse; virtual; abstract; procedure PreParse; virtual; abstract;
public public
constructor Create;
constructor Create(const AResultValues: String); constructor Create(const AResultValues: String);
constructor Create(AResult: TGDBMIExecResult); constructor Create(AResult: TGDBMIExecResult);
destructor Destroy; override; destructor Destroy; override;
@ -419,30 +420,6 @@ type
property Addr: TDBGPtr read FAddr; property Addr: TDBGPtr read FAddr;
end; end;
{ TGDBMIDisassembleResultList }
TGDBMIDisassembleResultList = class(TGDBMINameValueBasedList)
private
FCount: Integer;
FHasSourceInfo: Boolean;
FItems: array of record
AsmEntry: TPCharWithLen;
SrcFile: TPCharWithLen;
SrcLine: TPCharWithLen;
ParsedInfo: TDisassemblerEntry;
end;
function GetItem(Index: Integer): PDisassemblerEntry;
procedure ParseItem(Index: Integer);
procedure SetCount(const AValue: Integer);
procedure SetItem(Index: Integer; const AValue: PDisassemblerEntry);
protected
procedure PreParse; override;
public
property Count: Integer read FCount write SetCount;
property HasSourceInfo: Boolean read FHasSourceInfo;
property Item[Index: Integer]: PDisassemblerEntry read GetItem write SetItem;
end;
{%endregion *^^^* TGDBMINameValueList and Parsers *^^^* } {%endregion *^^^* TGDBMINameValueList and Parsers *^^^* }
{%region ***** TGDBMIDebuggerCommands ***** } {%region ***** TGDBMIDebuggerCommands ***** }
@ -887,6 +864,81 @@ const
DAssBytesPerCommandMax = 24; // Max possible len. Only used for up to 5 lines DAssBytesPerCommandMax = 24; // Max possible len. Only used for up to 5 lines
type type
{ TGDBMIDisassembleResultList }
TGDBMIDisassembleResultList = class(TGDBMINameValueBasedList)
private
FCount: Integer;
FHasSourceInfo: Boolean;
FItems: array of record
AsmEntry: TPCharWithLen;
SrcFile: TPCharWithLen;
SrcLine: TPCharWithLen;
ParsedInfo: TDisassemblerEntry;
end;
HasItemPointerList: Boolean;
ItemPointerList: Array of PDisassemblerEntry;
function GetItem(Index: Integer): PDisassemblerEntry;
function GetLastItem: PDisassemblerEntry;
procedure ParseItem(Index: Integer);
procedure SetCount(const AValue: Integer);
procedure SetItem(Index: Integer; const AValue: PDisassemblerEntry);
procedure SetLastItem(const AValue: PDisassemblerEntry);
protected
procedure PreParse; override;
public
property Count: Integer read FCount write SetCount;
property HasSourceInfo: Boolean read FHasSourceInfo;
property Item[Index: Integer]: PDisassemblerEntry read GetItem write SetItem;
property LastItem: PDisassemblerEntry read GetLastItem write SetLastItem;
function SortByAddress: Boolean;
public
// only valid as long a src object exists, and not modified
constructor CreateSubList(ASource: TGDBMIDisassembleResultList; AStartIdx, ACount: Integer);
procedure InitSubList(ASource: TGDBMIDisassembleResultList; AStartIdx, ACount: Integer);
end;
{ TGDBMIDisassembleResultFunctionIterator }
TGDBMIDisassembleResultFunctionIterator = class
private
FCurIdx: Integer;
FIndexOfLocateAddress: Integer;
FOffsetOfLocateAddress: Integer;
FIndexOfCounterAddress: Integer;
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;
function NextSubList(var AResultList: TGDBMIDisassembleResultList): Boolean;
// Current SubList
function IsFirstSubList: Boolean;
function CurrentFixedAddr: TDBGPtr; // Addr[0] - Offs[0]
// About the next SubList
function NextStartAddr: TDBGPtr;
function NextStartOffs: Integer;
// Overall
function CountLinesAfterCounterAddr: Integer; // count up to Startof Current SubList
property CurrentIndex: Integer read FCurIdx;
property NextIndex: Integer read FStartIdx;
property StartedAtIndex: Integer read FStartedAtIndex;
property IndexOfLocateAddress: Integer read FIndexOfLocateAddress;
property OffsetOfLocateAddress: Integer read FOffsetOfLocateAddress;
property IndexOfCounterAddress: Integer read FIndexOfCounterAddress;
property List: TGDBMIDisassembleResultList read FList;
end;
{ TGDBMIDebuggerCommandDisassembe } { TGDBMIDebuggerCommandDisassembe }
TGDBMIDisAssAddrRange = record TGDBMIDisAssAddrRange = record
@ -901,7 +953,7 @@ type
FOnProgress: TNotifyEvent; FOnProgress: TNotifyEvent;
FStartAddr: TDbgPtr; FStartAddr: TDbgPtr;
FKnownRanges: TDBGDisassemblerEntryMap; FKnownRanges: TDBGDisassemblerEntryMap;
FRangeIterator: TMapIterator; FRangeIterator: TDBGDisassemblerEntryMapIterator;
FMemDumpsNeeded: array of TGDBMIDisAssAddrRange; FMemDumpsNeeded: array of TGDBMIDisAssAddrRange;
procedure DoProgress; procedure DoProgress;
protected protected
@ -1223,6 +1275,11 @@ end;
{ TGDBMINameValueBasedList } { TGDBMINameValueBasedList }
constructor TGDBMINameValueBasedList.Create;
begin
FNameValueList := TGDBMINameValueList.Create;
end;
constructor TGDBMINameValueBasedList.Create(const AResultValues: String); constructor TGDBMINameValueBasedList.Create(const AResultValues: String);
begin begin
FNameValueList := TGDBMINameValueList.Create(AResultValues); FNameValueList := TGDBMINameValueList.Create(AResultValues);
@ -1270,6 +1327,7 @@ begin
then then
debugln(['WARNING: TGDBMIDisassembleResultList: Unexpected Entries']); debugln(['WARNING: TGDBMIDisassembleResultList: Unexpected Entries']);
{$ENDIF} {$ENDIF}
HasItemPointerList := False;
FNameValueList.SetPath('asm_insns'); FNameValueList.SetPath('asm_insns');
FCount := 0; FCount := 0;
SetLength(FItems, FNameValueList.Count * 4); SetLength(FItems, FNameValueList.Count * 4);
@ -1327,8 +1385,64 @@ begin
FreeAndNil(SrcList); FreeAndNil(SrcList);
end; end;
function TGDBMIDisassembleResultList.GetLastItem: PDisassemblerEntry;
begin
if HasItemPointerList
then begin
Result := ItemPointerList[Count - 1];
exit;
end;
ParseItem(Count - 1);
Result := @FItems[Count - 1].ParsedInfo;
end;
function TGDBMIDisassembleResultList.SortByAddress: Boolean;
var
i, j: Integer;
Itm1: PDisassemblerEntry;
begin
Result := True;
SetLength(ItemPointerList, FCount);
for i := 0 to Count - 1 do begin
Itm1 := Item[i];
j := i - 1;
while j >= 0 do begin
if ItemPointerList[j]^.Addr > Itm1^.Addr
then ItemPointerList[j+1] := ItemPointerList[j]
else break;
dec(j);
end;
ItemPointerList[j+1] := Itm1;
end;
HasItemPointerList := True;
end;
constructor TGDBMIDisassembleResultList.CreateSubList(ASource: TGDBMIDisassembleResultList;
AStartIdx, ACount: Integer);
begin
Create;
InitSubList(ASource, AStartIdx, ACount);
end;
procedure TGDBMIDisassembleResultList.InitSubList(ASource: TGDBMIDisassembleResultList;
AStartIdx, ACount: Integer);
var
i: Integer;
begin
SetLength(ItemPointerList, ACount);
FCount := ACount;
for i := 0 to ACount - 1 do
ItemPointerList[i] := ASource.Item[AStartIdx + i];
HasItemPointerList := True;
end;
function TGDBMIDisassembleResultList.GetItem(Index: Integer): PDisassemblerEntry; function TGDBMIDisassembleResultList.GetItem(Index: Integer): PDisassemblerEntry;
begin begin
if HasItemPointerList
then begin
Result := ItemPointerList[Index];
exit;
end;
ParseItem(Index); ParseItem(Index);
Result := @FItems[Index].ParsedInfo; Result := @FItems[Index].ParsedInfo;
end; end;
@ -1365,10 +1479,158 @@ end;
procedure TGDBMIDisassembleResultList.SetItem(Index: Integer; procedure TGDBMIDisassembleResultList.SetItem(Index: Integer;
const AValue: PDisassemblerEntry); const AValue: PDisassemblerEntry);
begin begin
if HasItemPointerList
then begin
ItemPointerList[Index]^ := AValue^;
exit;
end;
FItems[Index].ParsedInfo := AValue^; FItems[Index].ParsedInfo := AValue^;
FItems[Index].AsmEntry.Ptr := nil; FItems[Index].AsmEntry.Ptr := nil;
end; end;
procedure TGDBMIDisassembleResultList.SetLastItem(const AValue: PDisassemblerEntry);
begin
if HasItemPointerList
then begin
ItemPointerList[Count - 1]^ := AValue^;
exit;
end;
FItems[Count - 1].ParsedInfo := AValue^;
FItems[Count - 1].AsmEntry.Ptr := nil;
end;
{ TGDBMIDisassembleResultFunctionIterator }
constructor TGDBMIDisassembleResultFunctionIterator.Create(AList: TGDBMIDisassembleResultList;
AStartIdx: Integer; AIgnoreLast: Boolean; 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;
FOffsetOfLocateAddress := -1;
FIndexOfCounterAddress := -1;
end;
function TGDBMIDisassembleResultFunctionIterator.EOL: Boolean;
begin
Result := FStartIdx > FMaxIdx ;
end;
function TGDBMIDisassembleResultFunctionIterator.NextSubList
(var AResultList: TGDBMIDisassembleResultList): Boolean;
var
WasBeforeStart: Boolean;
HasPrcName: Boolean;
PrcBaseAddr: TDBGPtr;
Itm: PDisassemblerEntry;
NextIdx: Integer;
HasLocate: Boolean;
begin
FCurIdx := FStartIdx;
if FStartIdx > FMaxIdx
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 := FList.Item[FStartIdx]^.FuncName <> ''; // can use offsets
{$PUSH}{$IFnDEF DBGMI_WITH_DISASS_OVERFLOW}{$Q-}{$ENDIF} // Overflow is allowed to occur
PrcBaseAddr := FList.Item[FStartIdx]^.Addr - FList.Item[FStartIdx]^.Offset;
{$POP}
WasBeforeStart := FList.Item[FStartIdx]^.Addr < FAddressToLocate;
HasLocate := False;
NextIdx := FStartIdx + 1;
while NextIdx <= FMaxIdx do
begin
Itm := FList.Item[NextIdx];
{$PUSH}{$IFnDEF DBGMI_WITH_DISASS_OVERFLOW}{$Q-}{$ENDIF} // Overflow is allowed to occur
// Also check the next statement after PrcName.
// If it has FOffsetOfLocateAddress > 0, then FAddressToLocate is in current block, but not matched
if (Itm^.Addr = FAddressToLocate)
then begin
FIndexOfLocateAddress := NextIdx;
FOffsetOfLocateAddress := 0;
WasBeforeStart := False;
HasLocate := True;
end
else if WasBeforeStart and (Itm^.Addr > FAddressToLocate)
then begin
FIndexOfLocateAddress := NextIdx - 1;
FOffsetOfLocateAddress := FAddressToLocate - FList.Item[NextIdx-1]^.Addr;
WasBeforeStart := False;
HasLocate := True;
end;
if (Itm^.Addr = FAddForLineAfterCounter)
or ((Itm^.Addr > FAddForLineAfterCounter) and (FIndexOfCounterAddress < 0))
then FIndexOfCounterAddress := NextIdx;
if (HasPrcName <> (Itm^.FuncName <> ''))
or (HasPrcName and (PrcBaseAddr <> Itm^.Addr - Itm^.Offset))
then break;
{$POP}
inc(NextIdx);
end;
if AResultList = nil
then AResultList := TGDBMIDisassembleResultList.CreateSubList(FList, FStartIdx, NextIdx - FStartIdx)
else AResultList.InitSubList(FList, FStartIdx, NextIdx - FStartIdx);
FStartIdx := NextIdx;
// Does the next address look good?
// And is AStartAddrHit ok
Result := ((NextIdx > FMaxIdx) or (FList.Item[NextIdx]^.Offset = 0))
and ( (not HasLocate) or ((FIndexOfLocateAddress < 0) or (FOffsetOfLocateAddress = 0)) );
end;
function TGDBMIDisassembleResultFunctionIterator.IsFirstSubList: Boolean;
begin
Result := FStartedAtIndex = FStartIdx;
end;
function TGDBMIDisassembleResultFunctionIterator.CountLinesAfterCounterAddr: Integer;
begin
Result := -1;
if FIndexOfCounterAddress >= 0 then
Result := CurrentIndex - IndexOfCounterAddress - 1;
end;
function TGDBMIDisassembleResultFunctionIterator.CurrentFixedAddr: TDBGPtr;
begin
Result := FList.Item[CurrentIndex]^.Addr - FList.Item[CurrentIndex]^.Offset;
end;
function TGDBMIDisassembleResultFunctionIterator.NextStartAddr: TDBGPtr;
begin
if NextIndex <= FMaxIdx
then Result := FList.Item[NextIndex]^.Addr
else Result := FLastSubListEndAddr;
end;
function TGDBMIDisassembleResultFunctionIterator.NextStartOffs: Integer;
begin
if NextIndex <= FMaxIdx
then Result := FList.Item[NextIndex]^.Offset
else Result := 0;
end;
{ TGDBMIMemoryDumpResultList } { TGDBMIMemoryDumpResultList }
function TGDBMIMemoryDumpResultList.GetItemNum(Index: Integer): Integer; function TGDBMIMemoryDumpResultList.GetItemNum(Index: Integer): Integer;
@ -1557,43 +1819,6 @@ function TGDBMIDebuggerCommandDisassembe.DoExecute: Boolean;
else Result := TGDBMIMemoryDumpResultList.Create(R); else Result := TGDBMIMemoryDumpResultList.Create(R);
end; end;
function GetRangeForAddr(AnAddr: TDBGPtr; APrevious: Boolean = True): TDBGDisassemblerEntryRange;
begin
Result := nil;
if not FRangeIterator.Locate(AnAddr)
then if not FRangeIterator.BOM
then FRangeIterator.Previous;
if FRangeIterator.BOM
then exit;
FRangeIterator.GetData(Result);
if (not APrevious) and not(Result.ContainsAddr(AnAddr))
then Result := nil;
end;
function GetNextRange: TDBGDisassemblerEntryRange;
begin
Result := nil;
if FRangeIterator.EOM
then exit;
FRangeIterator.Next;
if not FRangeIterator.EOM
then FRangeIterator.GetData(Result);
end;
function GetPrevRange: TDBGDisassemblerEntryRange;
begin
Result := nil;
if FRangeIterator.BOM
then exit;
FRangeIterator.Previous;
if not FRangeIterator.BOM
then FRangeIterator.GetData(Result);
end;
function AdjustToKnowFunctionStart(var AStartAddr: TDbgPtr): Boolean; function AdjustToKnowFunctionStart(var AStartAddr: TDbgPtr): Boolean;
var var
DisAssList: TGDBMIDisassembleResultList; DisAssList: TGDBMIDisassembleResultList;
@ -1844,13 +2069,12 @@ function TGDBMIDebuggerCommandDisassembe.DoExecute: Boolean;
StopAfterAddress: TDBGPtr; StopAfterNumLines: Integer StopAfterAddress: TDBGPtr; StopAfterNumLines: Integer
): Boolean; ): Boolean;
var var
DisAssList, DisAssListNew, DisAssListWithSrc: TGDBMIDisassembleResultList; DisAssIterator: TGDBMIDisassembleResultFunctionIterator;
NextProcIdx, StartIdx, StartOffs: Integer; DisAssList, DisAssListCurrentSub, DisAssListWithSrc: TGDBMIDisassembleResultList;
i, j, Cnt, InitialIndex, GotLinesAfter: Integer; i, Cnt: Integer;
NewRange: TDBGDisassemblerEntryRange; NewRange: TDBGDisassemblerEntryRange;
NextProcAddr: TDBGPtr;
OrigLastAddress, OrigFirstAddress: TDBGPtr; OrigLastAddress, OrigFirstAddress: TDBGPtr;
FirstLoopRun, BlockOk, GotFullDisAss: Boolean; BlockOk, GotFullDisAss: Boolean;
s: String; s: String;
Itm: TDisassemblerEntry; Itm: TDisassemblerEntry;
begin begin
@ -1879,8 +2103,9 @@ function TGDBMIDebuggerCommandDisassembe.DoExecute: Boolean;
*) *)
Result := False; Result := False;
DisAssList := nil; DisAssList := nil;
DisAssListNew := nil; DisAssListCurrentSub := nil;
DisAssListWithSrc := nil; DisAssListWithSrc := nil;
DisAssIterator := nil;
OrigLastAddress := ALastAddr; OrigLastAddress := ALastAddr;
OrigFirstAddress := AFirstAddr; OrigFirstAddress := AFirstAddr;
@ -1891,24 +2116,26 @@ function TGDBMIDebuggerCommandDisassembe.DoExecute: Boolean;
if DiscardAtStart if DiscardAtStart
then StartAddr := StartAddr - 5 * DAssBytesPerCommandMax; then StartAddr := StartAddr - 5 * DAssBytesPerCommandMax;
// Adjust ALastAddr
if ALastAddr < AFirstAddr if ALastAddr < AFirstAddr
then begin then begin
ALastAddr := AFirstAddr + 2 * DAssBytesPerCommandMax; ALastAddr := AFirstAddr + 2 * DAssBytesPerCommandMax;
AEndIsKnownStatement := False; AEndIsKnownStatement := False;
end end
else else if not AEndIsKnownStatement
if not AEndIsKnownStatement
then ALastAddr := ALastAddr + 2 * DAssBytesPerCommandMax; then ALastAddr := ALastAddr + 2 * DAssBytesPerCommandMax;
// check if we have an overall source-info // 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) // we can only do that, if we know the offset of firstaddr (limit to 15 avg lines, should be enough)
if (AFirstAddrOffs >= 0) if (AFirstAddrOffs >= 0)
then DisAssListWithSrc := ExecDisassmble then DisAssListWithSrc := ExecDisassmble
(AFirstAddr - Min(AFirstAddrOffs, 15 * DAssBytesPerCommandAvg), ALastAddr, True); (AFirstAddr - Min(AFirstAddrOffs, 15 * DAssBytesPerCommandAvg), ALastAddr, True);
GotFullDisAss := (DisAssListWithSrc <> nil) and (DisAssListWithSrc.Count > 0) and DisAssListWithSrc.HasSourceInfo; GotFullDisAss := (DisAssListWithSrc <> nil) and (DisAssListWithSrc.Count > 0) and DisAssListWithSrc.HasSourceInfo;
if (DisAssListWithSrc <> nil) and (DisAssListWithSrc.Count > 0) and (not DisAssListWithSrc.HasSourceInfo) if (DisAssListWithSrc <> nil) and (DisAssListWithSrc.Count > 0) and (not DisAssListWithSrc.HasSourceInfo)
then begin then begin
// got data, but no mem dump // got data, but no src info
DisAssList := DisAssListWithSrc; DisAssList := DisAssListWithSrc;
DisAssListWithSrc := nil; DisAssListWithSrc := nil;
end; end;
@ -1918,6 +2145,7 @@ function TGDBMIDebuggerCommandDisassembe.DoExecute: Boolean;
if DisAssList = nil if DisAssList = nil
then DisAssList := ExecDisassmble(AFirstAddr, ALastAddr, False); then DisAssList := ExecDisassmble(AFirstAddr, ALastAddr, False);
Cnt := DisAssList.Count; Cnt := DisAssList.Count;
if Cnt < 2 if Cnt < 2
then begin then begin
@ -1957,6 +2185,7 @@ function TGDBMIDebuggerCommandDisassembe.DoExecute: Boolean;
AFirstAddr := DisAssList.Item[i]^.Addr; AFirstAddr := DisAssList.Item[i]^.Addr;
end; end;
NewRange := TDBGDisassemblerEntryRange.Create; NewRange := TDBGDisassemblerEntryRange.Create;
NewRange.Capacity := Cnt; NewRange.Capacity := Cnt;
if AEndIsKnownStatement if AEndIsKnownStatement
@ -1965,123 +2194,114 @@ function TGDBMIDebuggerCommandDisassembe.DoExecute: Boolean;
NewRange.RangeStartAddr := AFirstAddr; NewRange.RangeStartAddr := AFirstAddr;
NewRange.RangeEndAddr := OrigLastAddress; NewRange.RangeEndAddr := OrigLastAddress;
InitialIndex := i; DisAssIterator := TGDBMIDisassembleResultFunctionIterator.Create
GotLinesAfter := 0; (DisAssList, i, not AEndIsKnownStatement, ALastAddr, FStartAddr, FEndAddr);
NextProcAddr := 0;
while i < Cnt while not DisAssIterator.EOL
do begin do begin
if (StopAfterAddress <> 0) and (GotLinesAfter > StopAfterNumLines) then BlockOk := DisAssIterator.NextSubList(DisAssListCurrentSub);
begin
// got enough lines if (StopAfterAddress <> 0)
NewRange.LastEntryEndAddr := NextProcAddr; and (DisAssIterator.CountLinesAfterCounterAddr > StopAfterNumLines) // got enough lines
NewRange.RangeEndAddr := NextProcAddr; // only if the next block is good to go
and not ( (not BlockOk) or (DisAssListCurrentSub.Item[0]^.Offset <> 0) or (not GotFullDisAss) )
then begin
NewRange.LastEntryEndAddr := DisAssIterator.NextStartAddr;
NewRange.RangeEndAddr := DisAssIterator.NextStartAddr;
break; break;
end; end;
FirstLoopRun := i = InitialIndex; if (not DisAssIterator.IsFirstSubList) and (DisAssListCurrentSub.Item[0]^.Offset <> 0)
BlockOk := FindProcEnd(DisAssList, i, NextProcIdx, StartIdx, StartOffs, not AEndIsKnownStatement);
if (DisAssList.Item[i]^.Addr >= StopAfterAddress)
then inc(GotLinesAfter, NextProcIdx - i)
else if StartIdx > 0
then inc(GotLinesAfter, NextProcIdx - StartIdx - 1);
if NextProcIdx < Cnt
then NextProcAddr := DisAssList.Item[NextProcIdx]^.Addr - DisAssList.Item[NextProcIdx]^.Offset
else NextProcAddr := ALastAddr;
if (not FirstLoopRun) and (DisAssList.Item[i]^.Offset <> 0)
then begin then begin
// Current block starts with offset. Adjust and disassemble again // Current block starts with offset. Adjust and disassemble again
// Try with source first, in case it returns dat without source // Try with source first, in case it returns dat without source
if GotFullDisAss if GotFullDisAss
then begin then begin
//get the source-less code as reference //get the source-less code as reference
DisAssListNew := ExecDisassmble(DisAssList.Item[i]^.Addr - DisAssList.Item[i]^.Offset, DisAssListCurrentSub := ExecDisassmble(DisAssIterator.CurrentFixedAddr,
NextProcAddr, False, DisAssListNew); DisAssIterator.NextStartAddr, False, DisAssListCurrentSub);
CopyToRange(DisAssListNew, NewRange, 0, DisAssListNew.Count, DisAssListWithSrc); CopyToRange(DisAssListCurrentSub, NewRange, 0, DisAssListCurrentSub.Count, DisAssListWithSrc);
i := NextProcIdx; Result := Result or (DisAssListCurrentSub.Count > 0);
Result := True;
continue; continue;
end end
else begin else begin
DisAssListWithSrc := ExecDisassmble(DisAssList.Item[i]^.Addr - DisAssList.Item[i]^.Offset, // Try source first
NextProcAddr, True, DisAssListWithSrc); DisAssListWithSrc := ExecDisassmble(DisAssIterator.CurrentFixedAddr,
DisAssIterator.NextStartAddr, True, DisAssListWithSrc);
if (DisAssListWithSrc.Count > 0) and (not DisAssListWithSrc.HasSourceInfo) if (DisAssListWithSrc.Count > 0) and (not DisAssListWithSrc.HasSourceInfo)
then begin then begin
// no source avail, but got data // no source avail, but got data
CopyToRange(DisAssListWithSrc, NewRange, 0, DisAssListWithSrc.Count); CopyToRange(DisAssListWithSrc, NewRange, 0, DisAssListWithSrc.Count);
i := NextProcIdx;
Result := True; Result := True;
continue; continue;
end; end;
//get the source-less code as reference //get the source-less code as reference
DisAssListNew := ExecDisassmble(DisAssList.Item[i]^.Addr - DisAssList.Item[i]^.Offset, DisAssListCurrentSub := ExecDisassmble(DisAssIterator.CurrentFixedAddr,
NextProcAddr, False, DisAssListNew); DisAssIterator.NextStartAddr, False, DisAssListCurrentSub);
CopyToRange(DisAssListNew, NewRange, 0, DisAssListNew.Count, DisAssListWithSrc); CopyToRange(DisAssListCurrentSub, NewRange, 0, DisAssListCurrentSub.Count, DisAssListWithSrc);
i := NextProcIdx; Result := Result or (DisAssListCurrentSub.Count > 0);
Result := True;
continue; continue;
end; end;
end; end;
// Todo: Check for wrong start stmnt offset // Todo: Check for wrong start stmnt offset
if not BlockOk if not BlockOk
and (NextProcIdx < Cnt) and (DisAssList.Item[NextProcIdx]^.Offset <> 0) and (DisAssIterator.NextStartOffs <> 0)
then begin then begin
// overlap into next proc // overlap into next proc
{$IFDEF DBG_VERBOSE} {$IFDEF DBG_VERBOSE}
debugln(['WARNING: FindProcEnd found an overlap at block end: FromIdx=', i,' NextIdx=', NextProcIdx, ' StartIdx=', StartIdx, ' StartOffs=',StartOffs ]); debugln(['WARNING: FindProcEnd found an overlap at block end: FromIdx=', DisAssIterator.CurrentIndex,
' NextIdx=', DisAssIterator.NextIndex, ' StartIdx=', DisAssIterator.IndexOfLocateAddress, ' StartOffs=', DisAssIterator.OffsetOfLocateAddress]);
{$ENDIF} {$ENDIF}
j := DisAssList.Item[NextProcIdx]^.Offset; s := DisAssListCurrentSub.LastItem^.Dump;
s := DisAssList.Item[NextProcIdx-1]^.Dump; s := copy(s, 1, Max(0, length(s) - DisAssIterator.NextStartOffs * 2));
s := copy(s, 1, Max(0, length(s) - j*2));
if s = '' if s = ''
then s := ' '; then s := ' ';
DisAssList.Item[NextProcIdx-1]^.Dump := s; DisAssListCurrentSub.LastItem^.Dump := s;
DisAssList.Item[NextProcIdx-1]^.Statement := ''; DisAssListCurrentSub.LastItem^.Statement := '';
BlockOk := True; BlockOk := True;
end; end;
if BlockOk if BlockOk
then begin then begin
// Got a good block // Got a good block
if (DisAssList.Item[i]^.FuncName <> '') if (DisAssListCurrentSub.Item[0]^.FuncName <> '')
then begin then begin
// Try to get source-info (up to NextProcAddr) // Try to get source-info (up to DisAssIterator.NextStartAddr)
// Subtract offset from StartAddress, in case this is the first block // Subtract offset from StartAddress, in case this is the first block
// (we may continue existing data, but src info must be retrieved in full, or may be incomplete) // (we may continue existing data, but src info must be retrieved in full, or may be incomplete)
// If we are in FirstLoopRun, we already tried // If we are in IsFirstSubList, we already tried
if (not GotFullDisAss) and (not FirstLoopRun) if (not GotFullDisAss) and (not DisAssIterator.IsFirstSubList)
then DisAssListWithSrc := ExecDisassmble(DisAssList.Item[i]^.Addr - DisAssList.Item[i]^.Offset, then DisAssListWithSrc := ExecDisassmble(DisAssIterator.CurrentFixedAddr,
NextProcAddr, True, DisAssListWithSrc); DisAssIterator.NextStartAddr, True, DisAssListWithSrc);
// We may have less lines with source, as we stripped padding at the end // We may have less lines with source, as we stripped padding at the end
if (DisAssListWithSrc <> nil) and DisAssListWithSrc.HasSourceInfo if (DisAssListWithSrc <> nil) and DisAssListWithSrc.HasSourceInfo
then begin then begin
CopyToRange(DisAssList, NewRange, i, NextProcIdx - i, DisAssListWithSrc); CopyToRange(DisAssListCurrentSub, NewRange, 0, DisAssListCurrentSub.Count, DisAssListWithSrc);
i := NextProcIdx; Result := Result or (DisAssListCurrentSub.Count > 0);
Result := True;
continue; continue;
end; end;
end; end;
CopyToRange(DisAssList, NewRange, i, NextProcIdx - i); CopyToRange(DisAssListCurrentSub, NewRange, 0, DisAssListCurrentSub.Count);
i := NextProcIdx; Result := Result or (DisAssListCurrentSub.Count > 0);
Result := True;
continue; continue;
end; end;
// Got a problematic block // Got a problematic block
{$IFDEF DBG_VERBOSE} {$IFDEF DBG_VERBOSE}
debugln(['WARNING: FindProcEnd reported an issue FromIdx=', i,' NextIdx=', NextProcIdx, ' StartIdx=', StartIdx, ' StartOffs=',StartOffs ]); debugln(['WARNING: FindProcEnd reported an issue FromIdx=', DisAssIterator.CurrentIndex,' NextIdx=',
DisAssIterator.NextIndex, ' StartIdx=', DisAssIterator.IndexOfLocateAddress, ' StartOffs=', DisAssIterator.OffsetOfLocateAddress]);
{$ENDIF} {$ENDIF}
if DiscardAtStart and (StartIdx >= 0) and (StartOffs <> 0) if DiscardAtStart
and (DisAssIterator.IndexOfLocateAddress >= DisAssIterator.CurrentIndex) // in current list
and (DisAssIterator.OffsetOfLocateAddress <> 0)
then begin then begin
// FStartAddr is in the middle of a statement. Maybe move the Range? // FStartAddr is in the middle of a statement. Maybe move the Range?
end; end;
CopyToRange(DisAssList, NewRange, i, NextProcIdx - i); CopyToRange(DisAssListCurrentSub, NewRange, 0, DisAssListCurrentSub.Count);
i := NextProcIdx; Result := Result or (DisAssListCurrentSub.Count > 0);
Result := True;
end; end;
if NewRange.LastEntryEndAddr > NewRange.RangeEndAddr if NewRange.LastEntryEndAddr > NewRange.RangeEndAddr
@ -2120,8 +2340,9 @@ function TGDBMIDebuggerCommandDisassembe.DoExecute: Boolean;
FKnownRanges.AddRange(NewRange); // NewRange is now owned by FKnownRanges FKnownRanges.AddRange(NewRange); // NewRange is now owned by FKnownRanges
NewRange := nil; NewRange := nil;
FreeAndNil(DisAssIterator);
FreeAndNil(DisAssList); FreeAndNil(DisAssList);
FreeAndNil(DisAssListNew); FreeAndNil(DisAssListCurrentSub);
FreeAndNil(DisAssListWithSrc); FreeAndNil(DisAssListWithSrc);
end; end;
@ -2136,13 +2357,13 @@ function TGDBMIDebuggerCommandDisassembe.DoExecute: Boolean;
for i := 0 to length(FMemDumpsNeeded) - 1 do for i := 0 to length(FMemDumpsNeeded) - 1 do
begin begin
FirstAddr := FMemDumpsNeeded[i].FirstAddr; FirstAddr := FMemDumpsNeeded[i].FirstAddr;
Rng := GetRangeForAddr(FirstAddr, True); Rng := FRangeIterator.GetRangeForAddr(FirstAddr, True);
if rng <> nil if rng <> nil
then MemDump := ExecMemDump(FirstAddr, FMemDumpsNeeded[i].LastAddr - FirstAddr, MemDump); then MemDump := ExecMemDump(FirstAddr, FMemDumpsNeeded[i].LastAddr - FirstAddr, MemDump);
while (Rng <> nil) and (Rng.FirstAddr <= FMemDumpsNeeded[i].LastAddr) do while (Rng <> nil) and (Rng.FirstAddr <= FMemDumpsNeeded[i].LastAddr) do
begin begin
AddMemDumpToRange(Rng, MemDump, FMemDumpsNeeded[i].FirstAddr, FMemDumpsNeeded[i].LastAddr); AddMemDumpToRange(Rng, MemDump, FMemDumpsNeeded[i].FirstAddr, FMemDumpsNeeded[i].LastAddr);
Rng := GetNextRange; Rng := FRangeIterator.NextRange;
end; end;
end; end;
FreeAndNil(MemDump); FreeAndNil(MemDump);
@ -2169,7 +2390,7 @@ begin
// or the rng before (if not to far back) // or the rng before (if not to far back)
TryStartAtOffs := -1; TryStartAtOffs := -1;
DiscardAtStart := False; DiscardAtStart := False;
RngBefore := GetRangeForAddr(FStartAddr, True); RngBefore := FRangeIterator.GetRangeForAddr(FStartAddr, True);
{$PUSH}{$IFnDEF DBGMI_WITH_DISASS_OVERFLOW}{$Q-}{$R-}{$ENDIF} // Overflow is allowed to occur {$PUSH}{$IFnDEF DBGMI_WITH_DISASS_OVERFLOW}{$Q-}{$R-}{$ENDIF} // Overflow is allowed to occur
if (RngBefore <> nil) if (RngBefore <> nil)
and (TryStartAt > RngBefore.EntriesPtr[RngBefore.Count - 1]^.Addr) and (TryStartAt > RngBefore.EntriesPtr[RngBefore.Count - 1]^.Addr)
@ -2211,7 +2432,7 @@ begin
break; break;
end; end;
RngAfter := GetNextRange; RngAfter := FRangeIterator.NextRange;
// adjust TryEndAt // adjust TryEndAt
if (RngAfter <> nil) and (TryEndAt >= RngAfter.RangeStartAddr) if (RngAfter <> nil) and (TryEndAt >= RngAfter.RangeStartAddr)
then TryEndAt := RngAfter.RangeStartAddr; then TryEndAt := RngAfter.RangeStartAddr;
@ -2226,7 +2447,7 @@ begin
end; end;
// prepare the next range // prepare the next range
RngBefore := GetRangeForAddr(FStartAddr, False); RngBefore := FRangeIterator.GetRangeForAddr(FStartAddr, False);
if (RngBefore = nil) if (RngBefore = nil)
then begin 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 ', TryStartAt,' to ', TryEndAt]);
@ -2239,7 +2460,7 @@ begin
end; end;
// Find LinesBefore // Find LinesBefore
RngAfter := GetRangeForAddr(FStartAddr, False); RngAfter := FRangeIterator.GetRangeForAddr(FStartAddr, False);
GotCnt := -1; GotCnt := -1;
while(True) while(True)
do begin do begin
@ -2262,7 +2483,7 @@ begin
TryEndAt := RngAfter.RangeStartAddr; TryEndAt := RngAfter.RangeStartAddr;
TryStartAt := TryEndAt - 1; TryStartAt := TryEndAt - 1;
// and adjust // and adjust
RngBefore := GetPrevRange; RngBefore := FRangeIterator.PreviousRange;
{$PUSH}{$IFnDEF DBGMI_WITH_DISASS_OVERFLOW}{$Q-}{$R-}{$ENDIF} // Overflow is allowed to occur {$PUSH}{$IFnDEF DBGMI_WITH_DISASS_OVERFLOW}{$Q-}{$R-}{$ENDIF} // Overflow is allowed to occur
if (RngBefore <> nil) if (RngBefore <> nil)
and (TryStartAt > RngBefore.EntriesPtr[RngBefore.Count - 1]^.Addr) and (TryStartAt > RngBefore.EntriesPtr[RngBefore.Count - 1]^.Addr)
@ -2281,7 +2502,7 @@ begin
break; break;
end; end;
RngAfter := GetRangeForAddr(FStartAddr, False); RngAfter := FRangeIterator.GetRangeForAddr(FStartAddr, False);
end; end;
DoProgress; DoProgress;
@ -2295,7 +2516,7 @@ constructor TGDBMIDebuggerCommandDisassembe.Create(AOwner: TGDBMIDebugger;
begin begin
inherited Create(AOwner); inherited Create(AOwner);
FKnownRanges := AKnownRanges; FKnownRanges := AKnownRanges;
FRangeIterator:= TMapIterator.Create(FKnownRanges); FRangeIterator:= TDBGDisassemblerEntryMapIterator.Create(FKnownRanges);
FStartAddr := AStartAddr; FStartAddr := AStartAddr;
FEndAddr := AEndAddr; FEndAddr := AEndAddr;
FLinesBefore := ALinesBefore; FLinesBefore := ALinesBefore;