📄 jcldebug.pas
字号:
Module: HMODULE;
NtHeaders: PImageNtHeaders;
begin
Result := nil;
Module := ModuleFromAddr(Addr);
if Module > 0 then
begin
NtHeaders := PeMapImgNtHeaders(Pointer(Module));
if NtHeaders <> nil then
begin
Result := TJclModuleInfo.Create;
Result.FStartAddr := Pointer(Module);
Result.FSize := NtHeaders^.OptionalHeader.SizeOfImage;
Result.FEndAddr := Pointer(Module + Result.FSize - 1);
if SystemModule then
Result.FSystemModule := True
else
Result.FSystemModule := IsSystemModule(Module);
end;
end;
if Result <> nil then
Add(Result);
end;
function TJclModuleInfoList.GetItems(Index: Integer): TJclModuleInfo;
begin
Result := TJclModuleInfo(Get(Index));
end;
function TJclModuleInfoList.GetModuleFromAddress(Addr: Pointer): TJclModuleInfo;
var
I: Integer;
Item: TJclModuleInfo;
begin
Result := nil;
for I := 0 to Count - 1 do
begin
Item := Items[I];
if (Cardinal(Item.StartAddr) <= Cardinal(Addr)) and (Cardinal(Item.EndAddr) > Cardinal(Addr)) then
begin
Result := Item;
Break;
end;
end;
if DynamicBuild and (Result = nil) then
Result := CreateItemForAddress(Addr, False);
end;
function TJclModuleInfoList.IsSystemModuleAddress(Addr: Pointer): Boolean;
var
Item: TJclModuleInfo;
begin
Item := ModuleFromAddress[Addr];
Result := (Item <> nil) and Item.SystemModule;
end;
function TJclModuleInfoList.IsValidModuleAddress(Addr: Pointer): Boolean;
begin
Result := ModuleFromAddress[Addr] <> nil;
end;
//=== { TJclAbstractMapParser } ==============================================
constructor TJclAbstractMapParser.Create(const MapFileName: TFileName);
begin
if FileExists(MapFileName) then
FStream := TJclFileMappingStream.Create(MapFileName, fmOpenRead or fmShareDenyWrite);
end;
destructor TJclAbstractMapParser.Destroy;
begin
FreeAndNil(FStream);
inherited Destroy;
end;
function TJclAbstractMapParser.GetLinkerBugUnitName: string;
begin
Result := MapStringToStr(FLinkerBugUnitName);
end;
class function TJclAbstractMapParser.MapStringToStr(MapString: PJclMapString): string;
var
P: PChar;
begin
if MapString = nil then
begin
Result := '';
Exit;
end;
if MapString^ = '(' then
begin
Inc(MapString);
P := MapString;
while not (P^ in [AnsiCarriageReturn, ')']) do
Inc(P);
end
else
begin
P := MapString;
while not (P^ in [AnsiSpace, AnsiCarriageReturn, '(']) do
Inc(P);
end;
SetString(Result, MapString, P - MapString);
end;
procedure TJclAbstractMapParser.Parse;
const
TableHeader = 'Start Length Name Class';
SegmentsHeader = 'Detailed map of segments';
PublicsByNameHeader = 'Address Publics by Name';
PublicsByValueHeader = 'Address Publics by Value';
LineNumbersPrefix = 'Line numbers for';
ResourceFilesHeader = 'Bound resource files';
var
CurrPos, EndPos: PChar;
A, PreviousA: TJclMapAddress;
L: Integer;
P1, P2: PJclMapString;
procedure SkipWhiteSpace;
begin
while CurrPos^ in AnsiWhiteSpace do
Inc(CurrPos);
end;
procedure SkipEndLine;
begin
while CurrPos^ <> AnsiLineFeed do
Inc(CurrPos);
SkipWhiteSpace;
end;
function Eof: Boolean;
begin
Result := (CurrPos >= EndPos);
end;
function IsDecDigit: Boolean;
begin
Result := CurrPos^ in AnsiDecDigits;
end;
function ReadTextLine: string;
var
P: PChar;
begin
P := CurrPos;
while not (CurrPos^ in [AnsiCarriageReturn, AnsiNull]) do
Inc(CurrPos);
SetString(Result, P, CurrPos - P);
end;
function ReadDecValue: Integer;
begin
Result := 0;
while CurrPos^ in AnsiDecDigits do
begin
Result := Result * 10 + (Ord(CurrPos^) - Ord('0'));
Inc(CurrPos);
end;
end;
{$OVERFLOWCHECKS OFF}
function ReadHexValue: Integer;
var
C: Char;
begin
Result := 0;
repeat
C := CurrPos^;
case C of
'0'..'9':
begin
Result := Result * 16;
Inc(Result, Ord(C) - Ord('0'));
end;
'A'..'F':
begin
Result := Result * 16;
Inc(Result, Ord(C) - Ord('A') + 10);
end;
'a'..'f':
begin
Result := Result * 16;
Inc(Result, Ord(C) - Ord('a') + 10);
end;
'H', 'h':
begin
Inc(CurrPos);
Break;
end;
else
Break;
end;
Inc(CurrPos);
until False;
end;
{$IFDEF OVERFLOWCHECKS_ON}
{$OVERFLOWCHECKS ON}
{$ENDIF OVERFLOWCHECKS_ON}
function ReadAddress: TJclMapAddress;
begin
Result.Segment := ReadHexValue;
if CurrPos^ = ':' then
begin
Inc(CurrPos);
Result.Offset := ReadHexValue;
end
else
Result.Offset := 0;
end;
function ReadString: PJclMapString;
begin
SkipWhiteSpace;
Result := CurrPos;
while not (CurrPos^ in AnsiWhiteSpace) do
Inc(CurrPos);
end;
procedure FindParam(Param: Char);
begin
while not ((CurrPos^ = Param) and ((CurrPos + 1)^ = '=')) do
Inc(CurrPos);
Inc(CurrPos, 2);
end;
function SyncToHeader(const Header: string): Boolean;
var
S: string;
begin
Result := False;
while not Eof do
begin
S := Trim(ReadTextLine);
Result := Pos(Header, S) = 1;
if Result then
Break;
SkipEndLine;
end;
if not Eof then
SkipWhiteSpace;
end;
function SyncToPrefix(const Prefix: string): Boolean;
var
I: Integer;
P: PChar;
S: string;
begin
if Eof then
begin
Result := False;
Exit;
end;
SkipWhiteSpace;
I := Length(Prefix);
P := CurrPos;
while not Eof and (not (P^ in [AnsiCarriageReturn, AnsiNull])) and (I > 0) do
begin
Inc(P);
Dec(I);
end;
SetString(S, CurrPos, Length(Prefix));
Result := (S = Prefix);
if Result then
CurrPos := P;
SkipWhiteSpace;
end;
begin
if FStream <> nil then
begin
FLinkerBug := False;
PreviousA.Segment := 0;
PreviousA.Offset := 0;
CurrPos := FStream.Memory;
EndPos := CurrPos + FStream.Size;
if SyncToHeader(TableHeader) then
while IsDecDigit do
begin
A := ReadAddress;
SkipWhiteSpace;
L := ReadHexValue;
P1 := ReadString;
P2 := ReadString;
SkipEndLine;
ClassTableItem(A, L, P1, P2);
end;
if SyncToHeader(SegmentsHeader) then
while IsDecDigit do
begin
A := ReadAddress;
SkipWhiteSpace;
L := ReadHexValue;
FindParam('C');
P1 := ReadString;
FindParam('M');
P2 := ReadString;
SkipEndLine;
SegmentItem(A, L, P1, P2);
end;
if SyncToHeader(PublicsByNameHeader) then
while IsDecDigit do
begin
A := ReadAddress;
P1 := ReadString;
SkipWhiteSpace;
PublicsByNameItem(A, P1);
end;
if SyncToHeader(PublicsByValueHeader) then
while IsDecDigit do
begin
A := ReadAddress;
P1 := ReadString;
SkipWhiteSpace;
PublicsByValueItem(A, P1);
end;
while SyncToPrefix(LineNumbersPrefix) do
begin
FLastUnitName := CurrPos;
FLastUnitFileName := CurrPos;
while FLastUnitFileName^ <> '(' do
Inc(FLastUnitFileName);
SkipEndLine;
LineNumberUnitItem(FLastUnitName, FLastUnitFileName);
repeat
SkipWhiteSpace;
L := ReadDecValue;
SkipWhiteSpace;
A := ReadAddress;
SkipWhiteSpace;
LineNumbersItem(L, A);
if (not FLinkerBug) and (A.Offset < PreviousA.Offset) then
begin
FLinkerBugUnitName := FLastUnitName;
FLinkerBug := True;
end;
PreviousA := A;
until not IsDecDigit;
end;
end;
end;
//=== { TJclMapParser 0 ======================================================
procedure TJclMapParser.ClassTableItem(const Address: TJclMapAddress;
Len: Integer; SectionName, GroupName: PJclMapString);
begin
if Assigned(FOnClassTable) then
FOnClassTable(Self, Address, Len, MapStringToStr(SectionName), MapStringToStr(GroupName));
end;
procedure TJclMapParser.LineNumbersItem(LineNumber: Integer; const Address: TJclMapAddress);
begin
if Assigned(FOnLineNumbers) then
FOnLineNumbers(Self, LineNumber, Address);
end;
procedure TJclMapParser.LineNumberUnitItem(UnitName, UnitFileName: PJclMapString);
begin
if Assigned(FOnLineNumberUnit) then
FOnLineNumberUnit(Self, MapStringToStr(UnitName), MapStringToStr(UnitFileName));
end;
procedure TJclMapParser.PublicsByNameItem(const Address: TJclMapAddress;
Name: PJclMapString);
begin
if Assigned(FOnPublicsByName) then
FOnPublicsByName(Self, Address, MapStringToStr(Name));
end;
procedure TJclMapParser.PublicsByValueItem(const Address: TJclMapAddress;
Name: PJclMapString);
begin
if Assigned(FOnPublicsByValue) then
FOnPublicsByValue(Self, Address, MapStringToStr(Name));
end;
procedure TJclMapParser.SegmentItem(const Address: TJclMapAddress;
Len: Integer; GroupName, UnitName: PJclMapString);
begin
if Assigned(FOnSegmentItem) then
FOnSegmentItem(Self, Address, Len, MapStringToStr(GroupName), MapStringToStr(UnitName));
end;
//=== { TJclMapScanner } =====================================================
constructor TJclMapScanner.Create(const MapFileName: TFileName);
begin
inherited Create(MapFileName);
Scan;
end;
procedure TJclMapScanner.ClassTableItem(const Address: TJclMapAddress; Len: Integer;
SectionName, GroupName: PJclMapString);
begin
end;
function TJclMapScanner.LineNumberFromAddr(Addr: DWORD): Integer;
var
Dummy: Integer;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -