Sunday, March 30, 2008

TDM#10: BorDebug – Return of the Giant

"The Delphi linker has always had the option of including so-called Turbo Debugger (TD32) debug information (on the Linker page of the Project Options dialog). The internal IDE Debugger does not normally use this information (Delphi 4 and 5 uses it when debugging external DLLs and EXE files), but instead relies on internal compiler structures build during an interactive compile.

External tools such as Borland’s Turbo Debugger[i] does rely on the TD32 information tacked at the end of the EXE or DLL file to enable symbolic debugging. This information is also used by a number of third party tools such as Numega’s BoundsChecker[ii], Turbo Power’s suite of Sleuth QA[iii] tools, Atanas Stoyanov’s freeware MemProof memory checking tool[iv], AutomatedQA’s QTime profiler[v], and Intel’s VTune sampling profiler [vi]

In this article we will see how we can utilise a relatively new DLL from Borland, BorDebug.DLL, to read and interpret the TD32 debug information in our own applications. [...]

We will discuss the functionality provided by the BorDebug DLL, present an import unit that gives us access to it from our Delphi applications, look at a set of wrapper classes to simplify the usage and show some simple demonstration programs."

H. Vassbotn, TDM, November 2000

unit HVBorDebug;
Simplified class interface for the BorDebug API
Written by Hallvard Vassbotn (,
April 1999 - September 2000

15.04.99 HV Created
30.09.00 HV Updated and revised

Windows, Classes, TypInfo, BorDebug, SysUtils;

// ... removed a lot of stuff - see the code on disk
TBorDebug = class(TObject)
constructor Create(const aFilename: string = '');
destructor Destroy; override;
procedure Open;
procedure Close;
property Handle: TBorDebHandle read GetHandle;
property FileName: string;
property SkipNames: boolean;
property CacheNames: boolean;
property Active: boolean;
property NameCount: TItemCount;
property Names[Index: TNameIndex]: string;
property UnmangledNames[Index: TNameIndex]: string;
property RegisterName[RegIndex: TRegNameIndex]: string;
property SubSectionCount: TItemCount;
property SubSections[Index: TSubSectionIndex]: TBorDebugSubSection;
function CreateModule(const SubSection: TBorDebugSubSection): TBorDebugModule;
function CreateSrcModule(const SubSection: TBorDebugSubSection ): TBorDebugSrcModule;
procedure StartSymbols(const SubSection: TBorDebugSubSection);
function GetNextSymbol(var Symbol: TBorDebugSymbol): boolean;
function CreateSymbolInfo(const Symbol: TBorDebugSymbol): TSymbolInfo;
function CreateTypeInfo(const aType: TBorDebugType): TTypeInfo;
property TypeFromIndex[TypeIndex: TTypeIndex]: TBorDebugType;
property TypeFromOffset[Offset: TFileOffset]: TBorDebugType;
property TypeName[TypeIndex: TTypeIndex]: string;
property GlobalSymbols[const SubSection: TBorDebugSubSection]: TBorDebugGlobalSymbol;
property TypeCount: TItemCount;
property TypesSignature: TSignature;
property SubSectionDirectoryOffset: TFileOffset;

TBorDebugModule = class(TBorDebugObject)
constructor Create(BorDebug: TBorDebug; Offset: TFileOffset);
destructor Destroy; override;
property Overlay : TOverlayIndex ;
property LibIndex : TLibraryIndex ;
property Style : TDebuggingStyle;
property TimeStamp : TBDTimeStamp ;
property SegmentCount : TItemCount ;
property NameIndex : TNameIndex ;
property Name : string ;
property ModuleSegmentList : TList ;
property Segments[Index: integer]: TModuleSegment;

TBorDebugSrcModule = class(TBorDebugObject)
constructor Create(BorDebug: TBorDebug; Offset: TFileOffset);
destructor Destroy; override;
property RangeCount : TItemCount ;
property RangeSegments : PSegmentIndices;
property RangeSegmentStarts : PSegmentOffsets;
property RangeSegmentEnds : PSegmentOffsets;
property SourceCount : TItemCount ;
property SourceOffsets : PFileOffsets ;
property NameIndices : PNameIndices ;
property RangeCounts : PItemCounts ;
property SourceFileList : TList ;
property SourceFiles[Index: integer]: TSourceFileEntry;
property SourceNames[Index: integer]: string;

TModuleSegment = class(TObject)
constructor Create(Module: TBorDebugModule; SegmentIndex: TSegmentIndex);
property LinkerSegment : TLinkerSegmentIndex;
property Offset : TFileOffset ;
property Size : TByteCount ;
property Flags : TSegmentFlags ;

TSourceFileEntry = class(TObject)
constructor Create(SrcModule: TBorDebugSrcModule; SourceFileIndex: TSourceFileIndex);
destructor Destroy; override;
property BorDebug : TBorDebug ;
property Handle : TBorDebHandle ;
property Offset : TFileOffset ;
property SrcModule : TBorDebugSrcModule;
property Name : string ;
property NameIndex : TNameIndex ;
property SourceFileIndex : TSourceFileIndex;
property RangeSegments : PSegmentIndices ;
property RangeSegmentStarts : PSegmentOffsets ;
property RangeSegmentEnds : PSegmentOffsets ;
property LineNumberCounts : PItemCounts ;
property LineNumerOffsetList: TList ;
property RangeCount : TItemCount ;
property RangeLineNumbers[Index: integer]: TLineNumberOffsets;

TLineNumberOffsets = class(TObject)
constructor Create(SourceFile: TSourceFileEntry; RangeIndex: TRangeIndex);
destructor Destroy; override;
property SourceFile : TSourceFileEntry;
property LineNumbers : PLineNumbers ;
property LineOffsets : PSegmentOffsets ;
property LineCount : TItemCount ;
property RangeIndex : TRangeIndex ;

TSymbolInfo = class(TObject)
constructor Create(BorDebug: TBorDebug; Symbol: TBorDebugSymbol);
destructor Destroy; override;
function GetTypeIndex(var TypeIndex: TTypeIndex): boolean;
function GetNameIndex(var NameIndex: TNameIndex): boolean;
property Symbol : TBorDebugSymbol;
property SymbolOffset : TFileOffset ;
property Len : TByteCount ;
property Kind : TSymbolKind ;
property Info : TSymbolInfoRec ;
property KindAsString : string ;

TTypeInfo = class(TObject)
constructor Create(BorDebug: TBorDebug; aType: TBorDebugType);
destructor Destroy; override;
property BDType : TBorDebugType ;
property TypeIndex : TTypeIndex ;
property TypeOffset : TFileOffset ;
property Length : TByteCount ;
property TypeKind : TTypeKind ;
property Info : TTypeInfoRec ;
property NameIndex : TNameIndex ;
property KindAsString : string ;

As usual you can read the full article (PDF) and download the full, original code (zip). Enjoy! ;)

[i] Turbo Debugger, a free download:

[ii] Numega BoundsChecker for Delphi:

[iii] Turbo Power Sleuth QA Suite:

[iv] Atanas Stoyanov’s MemProof home page:

[v] QTime:

[vi] VTune:


Giel said...


Doesn't the "full article(pdf)" link point to the wrong file?

Anonymous said...

Please, post a correct example of an article

Hallvard Vassbotn said...

Oops - the dangers of copy'n'paste ;).

The PDF and ZIP links have been corrected now - thanks for letting me know!

Giel said...

Thanks for fixing it!

Delphi said...

it's a good blog, will you visit mine at

thank you

Copyright © 2004-2007 by Hallvard Vassbotn