📄 jcldebug.pas
字号:
begin
Result := LineNumberFromAddr(Addr, Dummy);
end;
function Search_MapLineNumber(Item1, Item2: Pointer): Integer;
begin
Result := Integer(PJclMapLineNumber(Item1)^.Addr) - PInteger(Item2)^;
end;
function TJclMapScanner.LineNumberFromAddr(Addr: DWORD; var Offset: Integer): Integer;
var
I: Integer;
ModuleStartAddr: DWORD;
begin
ModuleStartAddr := ModuleStartFromAddr(Addr);
Result := 0;
Offset := 0;
I := SearchDynArray(FLineNumbers, SizeOf(FLineNumbers[0]), Search_MapLineNumber, @Addr, True);
if (I <> -1) and (FLineNumbers[I].Addr >= ModuleStartAddr) then
begin
Result := FLineNumbers[I].LineNumber;
Offset := Addr - FLineNumbers[I].Addr;
end;
end;
procedure TJclMapScanner.LineNumbersItem(LineNumber: Integer; const Address: TJclMapAddress);
var
C: Integer;
begin
// Try to eliminate invalid line numbers caused by bug in the linker
if (FLastValidAddr.Offset = 0) or ((Address.Offset > 0) and (Address.Offset <= FTopValidAddr) and
(FLastValidAddr.Segment = Address.Segment) and (FLastValidAddr.Offset < Address.Offset)) then
begin
FLastValidAddr := Address;
if FLineNumbersCnt mod 256 = 0 then
SetLength(FLineNumbers, FLineNumbersCnt + 256);
FLineNumbers[FLineNumbersCnt].Addr := Address.Offset;
FLineNumbers[FLineNumbersCnt].LineNumber := LineNumber;
Inc(FLineNumbersCnt);
if FNewUnitFileName <> nil then
begin
C := Length(FSourceNames);
SetLength(FSourceNames, C + 1);
FSourceNames[C].Addr := Address.Offset;
FSourceNames[C].ProcName := FNewUnitFileName;
FNewUnitFileName := nil;
end;
end
else
Inc(FLineNumberErrors);
end;
procedure TJclMapScanner.LineNumberUnitItem(UnitName, UnitFileName: PJclMapString);
begin
FNewUnitFileName := UnitFileName;
end;
function TJclMapScanner.ModuleNameFromAddr(Addr: DWORD): string;
var
I: Integer;
begin
Result := '';
for I := Length(FSegments) - 1 downto 0 do
if (FSegments[I].StartAddr <= Addr) and (FSegments[I].EndAddr >= Addr) then
begin
Result := MapStringToStr(FSegments[I].UnitName);
Break;
end;
end;
function TJclMapScanner.ModuleStartFromAddr(Addr: DWORD): DWORD;
var
I: Integer;
begin
Result := DWORD(-1);
for I := Length(FSegments) - 1 downto 0 do
if (FSegments[I].StartAddr <= Addr) and (FSegments[I].EndAddr >= Addr) then
begin
Result := FSegments[I].StartAddr;
Break;
end;
end;
function TJclMapScanner.ProcNameFromAddr(Addr: DWORD): string;
var
Dummy: Integer;
begin
Result := ProcNameFromAddr(Addr, Dummy);
end;
function Search_MapProcName(Item1, Item2: Pointer): Integer;
begin
Result := Integer(PJclMapProcName(Item1)^.Addr) - PInteger(Item2)^;
end;
function TJclMapScanner.ProcNameFromAddr(Addr: DWORD; var Offset: Integer): string;
var
I: Integer;
ModuleStartAddr: DWORD;
begin
ModuleStartAddr := ModuleStartFromAddr(Addr);
Result := '';
Offset := 0;
I := SearchDynArray(FProcNames, SizeOf(FProcNames[0]), Search_MapProcName, @Addr, True);
if (I <> -1) and (FProcNames[I].Addr >= ModuleStartAddr) then
begin
Result := MapStringToStr(FProcNames[I].ProcName);
Offset := Addr - FProcNames[I].Addr;
end;
end;
procedure TJclMapScanner.PublicsByNameItem(const Address: TJclMapAddress; Name: PJclMapString);
begin
{ TODO : What to do? }
end;
procedure TJclMapScanner.PublicsByValueItem(const Address: TJclMapAddress; Name: PJclMapString);
begin
if Address.Segment = 1 then
begin
if FProcNamesCnt mod 256 = 0 then
SetLength(FProcNames, FProcNamesCnt + 256);
FProcNames[FProcNamesCnt].Addr := Address.Offset;
FProcNames[FProcNamesCnt].ProcName := Name;
Inc(FProcNamesCnt);
end;
end;
procedure TJclMapScanner.Scan;
begin
FLastValidAddr.Segment := 0;
FLastValidAddr.Offset := 0;
FTopValidAddr := 0;
FLineNumberErrors := 0;
Parse;
SetLength(FLineNumbers, FLineNumbersCnt);
SetLength(FProcNames, FProcNamesCnt);
end;
procedure TJclMapScanner.SegmentItem(const Address: TJclMapAddress; Len: Integer;
GroupName, UnitName: PJclMapString);
var
C: Integer;
begin
if Address.Segment = 1 then
begin
C := Length(FSegments);
SetLength(FSegments, C + 1);
FSegments[C].StartAddr := Address.Offset;
FSegments[C].EndAddr := Address.Offset + Len;
FSegments[C].UnitName := UnitName;
FTopValidAddr := Max(FTopValidAddr, Address.Offset + Len);
end;
end;
function TJclMapScanner.SourceNameFromAddr(Addr: DWORD): string;
var
I: Integer;
ModuleStartAddr: DWORD;
begin
ModuleStartAddr := ModuleStartFromAddr(Addr);
Result := '';
I := SearchDynArray(FSourceNames, SizeOf(FSourceNames[0]), Search_MapProcName, @Addr, True);
if (I <> -1) and (FSourceNames[I].Addr >= ModuleStartAddr) then
Result := MapStringToStr(FSourceNames[I].ProcName);
end;
// JCL binary debug format string encoding/decoding routines
{ Strings are compressed to following 6bit format (A..D represents characters) and terminated with }
{ 6bit #0 char. First char = #1 indicates non compressed text, #2 indicates compressed text with }
{ leading '@' character }
{ }
{ 7 6 5 4 3 2 1 0 | }
{--------------------------------- }
{ B1 B0 A5 A4 A3 A2 A1 A0 | Data byte 0 }
{--------------------------------- }
{ C3 C2 C1 C0 B5 B4 B3 B2 | Data byte 1 }
{--------------------------------- }
{ D5 D4 D3 D2 D1 D0 C5 C4 | Data byte 2 }
{--------------------------------- }
{$OVERFLOWCHECKS OFF}
{$RANGECHECKS OFF}
function SimpleCryptString(const S: string): string;
var
I: Integer;
C: Byte;
P: PByte;
begin
SetLength(Result, Length(S));
P := PByte(Result);
for I := 1 to Length(S) do
begin
C := Ord(S[I]);
if C <> $AA then
C := C xor $AA;
P^ := C;
Inc(P);
end;
end;
function DecodeNameString(const S: PChar): string;
var
I, B: Integer;
C: Byte;
P: PByte;
Buffer: array [0..255] of Char;
begin
Result := '';
B := 0;
P := PByte(S);
case P^ of
1:
begin
Inc(P);
Result := SimpleCryptString(PChar(P));
Exit;
end;
2:
begin
Inc(P);
Buffer[B] := '@';
Inc(B);
end;
end;
I := 0;
C := 0;
repeat
case I and $03 of
0:
C := P^ and $3F;
1:
begin
C := (P^ shr 6) and $03;
Inc(P);
Inc(C, (P^ and $0F) shl 2);
end;
2:
begin
C := (P^ shr 4) and $0F;
Inc(P);
Inc(C, (P^ and $03) shl 4);
end;
3:
begin
C := (P^ shr 2) and $3F;
Inc(P);
end;
end;
case C of
$00:
Break;
$01..$0A:
Inc(C, Ord('0') - $01);
$0B..$24:
Inc(C, Ord('A') - $0B);
$25..$3E:
Inc(C, Ord('a') - $25);
$3F:
C := Ord('_');
end;
Buffer[B] := Chr(C);
Inc(B);
Inc(I);
until B >= SizeOf(Buffer) - 1;
Buffer[B] := AnsiNull;
Result := Buffer;
end;
function EncodeNameString(const S: string): string;
var
I, StartIndex: Integer;
C: Byte;
P: PByte;
begin
if (Length(S) > 1) and (S[1] = '@') then
StartIndex := 1
else
StartIndex := 0;
for I := StartIndex + 1 to Length(S) do
if not (S[I] in AnsiValidIdentifierLetters) then
begin
Result := #1 + SimpleCryptString(S) + #0;
Exit;
end;
SetLength(Result, Length(S) + StartIndex);
P := Pointer(Result);
if StartIndex = 1 then
P^ := 2 // store '@' leading char information
else
Dec(P);
for I := 0 to Length(S) - StartIndex do // including null char
begin
C := Byte(S[I + 1 + StartIndex]);
case Char(C) of
#0:
C := 0;
'0'..'9':
Dec(C, Ord('0') - $01);
'A'..'Z':
Dec(C, Ord('A') - $0B);
'a'..'z':
Dec(C, Ord('a') - $25);
'_':
C := $3F;
else
C := $3F;
end;
case I and $03 of
0:
begin
Inc(P);
P^ := C;
end;
1:
begin
P^ := P^ or (C and $03) shl 6;
Inc(P);
P^ := (C shr 2) and $0F;
end;
2:
begin
P^ := P^ or (C shl 4);
Inc(P);
P^ := (C shr 4) and $03;
end;
3:
P^ := P^ or (C shl 2);
end;
end;
SetLength(Result, DWORD(P) - DWORD(Pointer(Result)) + 1);
end;
{$IFDEF RANGECHECKS_ON}
{$RANGECHECKS ON}
{$ENDIF RANGECHECKS_ON}
{$IFDEF OVERFLOWCHECKS_ON}
{$OVERFLOWCHECKS ON}
{$ENDIF OVERFLOWCHECKS_ON}
function ConvertMapFileToJdbgFile(const MapFileName: TFileName): Boolean;
var
Dummy1: string;
Dummy2: Integer;
begin
Result := ConvertMapFileToJdbgFile(MapFileName, Dummy1, Dummy2);
end;
function ConvertMapFileToJdbgFile(const MapFileName: TFileName; var LinkerBugUnit: string;
var LineNumberErrors: Integer): Boolean;
var
JDbgFileName: TFileName;
Generator: TJclBinDebugGenerator;
begin
JDbgFileName := ChangeFileExt(MapFileName, JclDbgFileExtension);
Generator := TJclBinDebugGenerator.Create(MapFileName);
try
Result := (Generator.DataStream.Size > 0) and Generator.CalculateCheckSum;
if Result then
Generator.DataStream.SaveToFile(JDbgFileName);
LinkerBugUnit := Generator.LinkerBugUnitName;
LineNumberErrors := Generator.LineNumberErrors;
finally
Generator.Free;
end;
end;
function InsertDebugDataIntoExecutableFile(const ExecutableFileName, MapFileName: TFileName;
var LinkerBugUnit: string; var MapFileSize, JclDebugDataSize: Integer): Boolean;
var
Dummy: Integer;
begin
Result := InsertDebugDataIntoExecutableFile(ExecutableFileName, MapFileName, LinkerBugUnit,
MapFileSize, JclDebugDataSize, Dummy);
end;
function InsertDebugDataIntoExecutableFile(const ExecutableFileName, MapFileName: TFileName;
var LinkerBugUnit: string; var MapFileSize, JclDebugDataSize, LineNumberErrors: Integer): Boolean;
var
BinDebug: TJclBinDebugGenerator;
begin
BinDebug := TJclBinDebugGenerator.Create(MapFileName);
try
Result := InsertDebugDataIntoExecutableFile(ExecutableFileName, BinDebug,
LinkerBugUnit, MapFileSize, JclDebugDataSize, LineNumberErrors);
finally
BinDebug.Free;
end;
end;
function InsertDebugDataIntoExecutableFile(const ExecutableFileName: TFileName;
BinDebug: TJclBinDebugGenerator; var LinkerBugUnit: string;
var MapFileSize, JclDebugDataSize: Integer): Boolean;
var
Dummy: Integer;
begin
Result := InsertDebugDataIntoExecutableFile(ExecutableFileName, BinDebug, LinkerBugUnit,
MapFileSize, JclDebugDataSize, Dummy);
end;
function InsertDebugDataIntoExecutableFile(const ExecutableFileName: TFileName;
BinDebug: TJclBinDebugGenerator; var LinkerBugUnit: string;
var MapFileSize, JclDebugDataSize, LineNumberErrors: Integer): Boolean;
var
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -