📄 jcltd32.pas
字号:
must be fabricated and emitted to the SUBSECTION_TYPE_GLOBAL_SYMBOLS section.
*******************************************************************************}
type
TSymbolProcInfo = packed record
pParent: DWORD;
pEnd: DWORD;
pNext: DWORD;
Size: DWORD; // Length in bytes of this procedure
DebugStart: DWORD; // Offset in bytes from the start of the procedure to
// the point where the stack frame has been set up.
DebugEnd: DWORD; // Offset in bytes from the start of the procedure to
// the point where the procedure is ready to return
// and has calculated its return value, if any.
// Frame and register variables an still be viewed.
Offset: DWORD; // Offset portion of the segmented address of
// the start of the procedure in the code segment
Segment: Word; // Segment portion of the segmented address of
// the start of the procedure in the code segment
ProcType: DWORD; // Type of the procedure type record
NearFar: Byte; // Type of return the procedure makes:
// 0 near
// 4 far
Reserved: Byte;
NameIndex: DWORD; // Name index of procedure
end;
type
{ Symbol Information Records }
PSymbolInfo = ^TSymbolInfo;
TSymbolInfo = packed record
Size: Word;
SymbolType: Word;
case Word of
SYMBOL_TYPE_LPROC32, SYMBOL_TYPE_GPROC32:
(Proc: TSymbolProcInfo;);
end;
PSymbolInfos = ^TSymbolInfos;
TSymbolInfos = packed record
Signature: DWORD;
Symbols: array [0..0] of TSymbolInfo;
end;
{$IFDEF SUPPORTS_EXTSYM}
{$EXTERNALSYM Borland32BitSymbolFileSignatureForDelphi}
{$EXTERNALSYM Borland32BitSymbolFileSignatureForBCB}
{$EXTERNALSYM SUBSECTION_TYPE_MODULE}
{$EXTERNALSYM SUBSECTION_TYPE_TYPES}
{$EXTERNALSYM SUBSECTION_TYPE_SYMBOLS}
{$EXTERNALSYM SUBSECTION_TYPE_ALIGN_SYMBOLS}
{$EXTERNALSYM SUBSECTION_TYPE_SOURCE_MODULE}
{$EXTERNALSYM SUBSECTION_TYPE_GLOBAL_SYMBOLS}
{$EXTERNALSYM SUBSECTION_TYPE_GLOBAL_TYPES}
{$EXTERNALSYM SUBSECTION_TYPE_NAMES}
{$EXTERNALSYM SYMBOL_TYPE_COMPILE}
{$EXTERNALSYM SYMBOL_TYPE_REGISTER}
{$EXTERNALSYM SYMBOL_TYPE_CONST}
{$EXTERNALSYM SYMBOL_TYPE_UDT}
{$EXTERNALSYM SYMBOL_TYPE_SSEARCH}
{$EXTERNALSYM SYMBOL_TYPE_END}
{$EXTERNALSYM SYMBOL_TYPE_SKIP}
{$EXTERNALSYM SYMBOL_TYPE_CVRESERVE}
{$EXTERNALSYM SYMBOL_TYPE_OBJNAME}
{$EXTERNALSYM SYMBOL_TYPE_BPREL16}
{$EXTERNALSYM SYMBOL_TYPE_LDATA16}
{$EXTERNALSYM SYMBOL_TYPE_GDATA16}
{$EXTERNALSYM SYMBOL_TYPE_PUB16}
{$EXTERNALSYM SYMBOL_TYPE_LPROC16}
{$EXTERNALSYM SYMBOL_TYPE_GPROC16}
{$EXTERNALSYM SYMBOL_TYPE_THUNK16}
{$EXTERNALSYM SYMBOL_TYPE_BLOCK16}
{$EXTERNALSYM SYMBOL_TYPE_WITH16}
{$EXTERNALSYM SYMBOL_TYPE_LABEL16}
{$EXTERNALSYM SYMBOL_TYPE_CEXMODEL16}
{$EXTERNALSYM SYMBOL_TYPE_VFTPATH16}
{$EXTERNALSYM SYMBOL_TYPE_BPREL32}
{$EXTERNALSYM SYMBOL_TYPE_LDATA32}
{$EXTERNALSYM SYMBOL_TYPE_GDATA32}
{$EXTERNALSYM SYMBOL_TYPE_PUB32}
{$EXTERNALSYM SYMBOL_TYPE_LPROC32}
{$EXTERNALSYM SYMBOL_TYPE_GPROC32}
{$EXTERNALSYM SYMBOL_TYPE_THUNK32}
{$EXTERNALSYM SYMBOL_TYPE_BLOCK32}
{$EXTERNALSYM SYMBOL_TYPE_WITH32}
{$EXTERNALSYM SYMBOL_TYPE_LABEL32}
{$EXTERNALSYM SYMBOL_TYPE_CEXMODEL32}
{$EXTERNALSYM SYMBOL_TYPE_VFTPATH32}
{$ENDIF SUPPORTS_EXTSYM}
// TD32 information related classes
type
TJclModuleInfo = class(TObject)
private
FNameIndex: DWORD;
FSegments: PSegmentInfoArray;
FSegmentCount: Integer;
function GetSegment(const Idx: Integer): TSegmentInfo;
protected
constructor Create(pModInfo: PModuleInfo);
public
property NameIndex: DWORD read FNameIndex;
property SegmentCount: Integer read FSegmentCount; //GetSegmentCount;
property Segment[const Idx: Integer]: TSegmentInfo read GetSegment; default;
end;
TJclLineInfo = class(TObject)
private
FLineNo: DWORD;
FOffset: DWORD;
protected
constructor Create(ALineNo, AOffset: DWORD);
public
property LineNo: DWORD read FLineNo;
property Offset: DWORD read FOffset;
end;
TJclSourceModuleInfo = class(TObject)
private
FLines: TObjectList;
FSegments: POffsetPairArray;
FSegmentCount: Integer;
FNameIndex: DWORD;
function GetLine(const Idx: Integer): TJclLineInfo;
function GetLineCount: Integer;
function GetSegment(const Idx: Integer): TOffsetPair;
protected
constructor Create(pSrcFile: PSourceFileEntry; Base: DWORD);
public
destructor Destroy; override;
function FindLine(const AAddr: DWORD; var ALine: TJclLineInfo): Boolean;
property NameIndex: DWORD read FNameIndex;
property LineCount: Integer read GetLineCount;
property Line[const Idx: Integer]: TJclLineInfo read GetLine; default;
property SegmentCount: Integer read FSegmentCount; //GetSegmentCount;
property Segment[const Idx: Integer]: TOffsetPair read GetSegment;
end;
TJclSymbolInfo = class(TObject)
private
FSymbolType: Word;
protected
constructor Create(pSymInfo: PSymbolInfo); virtual;
property SymbolType: Word read FSymbolType;
end;
TJclProcSymbolInfo = class(TJclSymbolInfo)
private
FNameIndex: DWORD;
FOffset: DWORD;
FSize: DWORD;
protected
constructor Create(pSymInfo: PSymbolInfo); override;
public
property NameIndex: DWORD read FNameIndex;
property Offset: DWORD read FOffset;
property Size: DWORD read FSize;
end;
TJclLocalProcSymbolInfo = class(TJclProcSymbolInfo);
TJclGlobalProcSymbolInfo = class(TJclProcSymbolInfo);
// TD32 parser
TJclTD32InfoParser = class(TObject)
private
FBase: Pointer;
FData: TCustomMemoryStream;
FNames: TList;
FModules: TObjectList;
FSourceModules: TObjectList;
FSymbols: TObjectList;
FValidData: Boolean;
function GetName(const Idx: Integer): string;
function GetNameCount: Integer;
function GetSymbol(const Idx: Integer): TJclSymbolInfo;
function GetSymbolCount: Integer;
function GetModule(const Idx: Integer): TJclModuleInfo;
function GetModuleCount: Integer;
function GetSourceModule(const Idx: Integer): TJclSourceModuleInfo;
function GetSourceModuleCount: Integer;
protected
procedure Analyse;
procedure AnalyseNames(const pSubsection: Pointer; const Size: DWORD); virtual;
procedure AnalyseAlignSymbols(pSymbols: PSymbolInfos; const Size: DWORD); virtual;
procedure AnalyseModules(pModInfo: PModuleInfo; const Size: DWORD); virtual;
procedure AnalyseSourceModules(pSrcModInfo: PSourceModuleInfo; const Size: DWORD); virtual;
procedure AnalyseUnknownSubSection(const pSubsection: Pointer; const Size: DWORD); virtual;
function LfaToVa(Lfa: DWORD): Pointer;
public
constructor Create(const ATD32Data: TCustomMemoryStream); // Data mustn't be freed before the class is destroyed
destructor Destroy; override;
function FindModule(const AAddr: DWORD; var AMod: TJclModuleInfo): Boolean;
function FindSourceModule(const AAddr: DWORD; var ASrcMod: TJclSourceModuleInfo): Boolean;
function FindProc(const AAddr: DWORD; var AProc: TJclProcSymbolInfo): Boolean;
class function IsTD32Sign(const Sign: TJclTD32FileSignature): Boolean;
class function IsTD32DebugInfoValid(const DebugData: Pointer; const DebugDataSize: LongWord): Boolean;
property Data: TCustomMemoryStream read FData;
property Names[const Idx: Integer]: string read GetName;
property NameCount: Integer read GetNameCount;
property Symbols[const Idx: Integer]: TJclSymbolInfo read GetSymbol;
property SymbolCount: Integer read GetSymbolCount;
property Modules[const Idx: Integer]: TJclModuleInfo read GetModule;
property ModuleCount: Integer read GetModuleCount;
property SourceModules[const Idx: Integer]: TJclSourceModuleInfo read GetSourceModule;
property SourceModuleCount: Integer read GetSourceModuleCount;
property ValidData: Boolean read FValidData;
end;
// TD32 scanner with source location methods
TJclTD32InfoScanner = class(TJclTD32InfoParser)
public
function LineNumberFromAddr(AAddr: DWORD; var Offset: Integer): Integer; overload;
function LineNumberFromAddr(AAddr: DWORD): Integer; overload;
function ProcNameFromAddr(AAddr: DWORD): string; overload;
function ProcNameFromAddr(AAddr: DWORD; var Offset: Integer): string; overload;
function ModuleNameFromAddr(AAddr: DWORD): string;
function SourceNameFromAddr(AAddr: DWORD): string;
end;
// PE Image with TD32 information and source location support
TJclPeBorTD32Image = class(TJclPeBorImage)
private
FIsTD32DebugPresent: Boolean;
FTD32DebugData: TCustomMemoryStream;
FTD32Scanner: TJclTD32InfoScanner;
protected
procedure AfterOpen; override;
procedure Clear; override;
procedure ClearDebugData;
procedure CheckDebugData;
function IsDebugInfoInImage(var DataStream: TCustomMemoryStream): Boolean;
function IsDebugInfoInTds(var DataStream: TCustomMemoryStream): Boolean;
public
property IsTD32DebugPresent: Boolean read FIsTD32DebugPresent;
property TD32DebugData: TCustomMemoryStream read FTD32DebugData;
property TD32Scanner: TJclTD32InfoScanner read FTD32Scanner;
end;
implementation
uses
JclResources, JclSysUtils;
const
TurboDebuggerSymbolExt = '.tds';
//=== { TJclModuleInfo } =====================================================
constructor TJclModuleInfo.Create(pModInfo: PModuleInfo);
begin
Assert(Assigned(pModInfo));
inherited Create;
FNameIndex := pModInfo.NameIndex;
FSegments := @pModInfo.Segments[0];
FSegmentCount := pModInfo.SegmentCount;
end;
function TJclModuleInfo.GetSegment(const Idx: Integer): TSegmentInfo;
begin
Assert((0 <= Idx) and (Idx < FSegmentCount));
Result := FSegments[Idx];
end;
//=== { TJclLineInfo } =======================================================
constructor TJclLineInfo.Create(ALineNo, AOffset: DWORD);
begin
inherited Create;
FLineNo := ALineNo;
FOffset := AOffset;
end;
//=== { TJclSourceModuleInfo } ===============================================
constructor TJclSourceModuleInfo.Create(pSrcFile: PSourceFileEntry; Base: DWORD);
type
PArrayOfWord = ^TArrayOfWord;
TArrayOfWord = array [0..0] of Word;
var
I, J: Integer;
pLineEntry: PLineMappingEntry;
begin
Assert(Assigned(pSrcFile));
inherited Create;
FNameIndex := pSrcFile.NameIndex;
FLines := TObjectList.Create;
{$RANGECHECKS OFF}
for I := 0 to pSrcFile.SegmentCount - 1 do
begin
pLineEntry := PLineMappingEntry(Base + pSrcFile.BaseSrcLines[I]);
for J := 0 to pLineEntry.PairCount - 1 do
FLines.Add(TJclLineInfo.Create(
PArrayOfWord(@pLineEntry.Offsets[pLineEntry.PairCount])^[J],
pLineEntry.Offsets[J]));
end;
FSegments := @pSrcFile.BaseSrcLines[pSrcFile.SegmentCount];
FSegmentCount := pSrcFile.SegmentCount;
{$IFDEF RANGECHECKS_ON}
{$RANGECHECKS ON}
{$ENDIF RANGECHECKS_ON}
end;
destructor TJclSourceModuleInfo.Destroy;
begin
FreeAndNil(FLines);
inherited Destroy;
end;
function TJclSourceModuleInfo.GetLine(const Idx: Integer): TJclLineInfo;
begin
Result := TJclLineInfo(FLines.Items[Idx]);
end;
function TJclSourceModuleInfo.GetLineCount: Integer;
begin
Result := FLines.Count;
end;
function TJclSourceModuleInfo.GetSegment(const Idx: Integer): TOffsetPair;
begin
Assert((0 <= Idx) and (Idx < FSegmentCount));
Result := FSegments[Idx];
end;
function TJclSourceModuleInfo.FindLine(const AAddr: DWORD; var ALine: TJclLineInfo): Boolean;
var
I: Integer;
begin
for I := 0 to LineCount - 1 do
with Line[I] do
begin
if AAddr = Offset then
begin
Result := True;
ALine := Line[I];
Exit;
end
else
if (I > 1) and (Line[I - 1].Offset < AAddr) and (AAddr < Offset) then
begin
Result := True;
ALine := Line[I-1];
Exit;
end;
end;
Result := False;
ALine := nil;
end;
//=== { TJclSymbolInfo } =====================================================
constructor TJclSymbolInfo.Create(pSymInfo: PSymbolInfo);
begin
Assert(Assigned(pSymInfo));
inherited Create;
FSymbolType := pSymInfo.SymbolType;
end;
//=== { TJclProcSymbolInfo } =================================================
constructor TJclProcSymbolInfo.Create(pSymInfo: PSymbolInfo);
begin
Assert(Assigned(pSymInfo));
inherited Create(pSymInfo);
with pSymInfo^ do
begin
FNameIndex := Proc.NameIndex;
FOffset := Proc.Offset;
FSize := Proc.Size;
end;
end;
//=== { TJclTD32InfoParser } =================================================
constructor TJclTD32InfoParser.Create(const ATD32Data: TCustomMemoryStream);
begin
Assert(Assigned(ATD32Data));
inherited Create;
FNames := TList.Create;
FModules := TObjectList.Create;
FSourceModules := TObjectList.Create;
FSymbols := TObjectList.Create;
FNames.Add(nil);
FData := ATD32Data;
FBase := FData.Memory;
FValidData := IsTD32DebugInfoValid(FBase, FData.Size);
if FValidData then
Analyse;
end;
destructor TJclTD32InfoParser.Destroy;
begin
FreeAndNil(FSymbols);
FreeAndNil(FSourceModules);
FreeAndNil(FModules);
FreeAndNil(FNames);
inherited Destroy;
end;
procedure TJclTD32InfoParser.Analyse;
var
I: Integer;
pDirHeader: PDirectoryHeader;
pSubsection: Pointer;
begin
pDirHeader := PDirectoryHeader(LfaToVa(PJclTD32FileSignature(LfaToVa(0)).Offset));
while True do
begin
Assert(pDirHeader.DirEntrySize = SizeOf(TDirectoryEntry));
{$RANGECHECKS OFF}
for I := 0 to pDirHeader.DirEntryCount - 1 do
with pDirHeader.DirEntries[I] do
begin
pSubsection := LfaToVa(Offset);
case SubsectionType of
SUBSECTION_TYPE_MODULE:
AnalyseModules(pSubsection, Size);
SUBSECTION_TYPE_ALIGN_SYMBOLS:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -