Borland debug information
Working on Maupiti Island I learned how DOS programs stored debug information.
MZ executables would usually store debug information at the end of the binary file, with each compiler producing the information in it's own format. Borland tools would produce the following:
Format of Borland debugging information header (following load image): Offset Size Description ) 00h WORD signature 52FBh 02h WORD version ID 04h DWORD size of name pool in bytes 08h WORD number of names in name pool 0Ah WORD number of type entries 0Ch WORD number of structure members 0Eh WORD number of symbols 10h WORD number of global symbols 12h WORD number of modules 14h WORD number of locals (optional) 16h WORD number of scopes in table 18h WORD number of line-number entries 1Ah WORD number of include files 1Ch WORD number of segment records 1Eh WORD number of segment/file correlations 20h DWORD size of load image after removing uninitialized data and debug information 24h DWORD debugger hook; pointer into debugged program whose meaning depends on program flags 28h BYTE program flags bit 0: case-sensitive link bit 1: pascal overlay program 29h WORD no longer used 2Bh WORD size of data pool in bytes 2Dh BYTE padding 2Eh WORD size of following header extension (currently 00h, 10h, or 20h) 30h WORD number of classes 32h WORD number of parents 34h WORD number of global classes (currently unused) 36h WORD number of overloads (currently unused) 38h WORD number of scope classes 3Ah WORD number of module classes 3Ch WORD number of coverage offsets 3Eh DWORD offset relative to symbol base of name pool 42h WORD number of browser information records 44h WORD number of optimized symbol records 46h WORD debugging flags 48h 8 BYTEs padding Note: additional information on the Borland debugging info may be found in Borland's Open Architecture Handbook SeeAlso: #01600
with the help of Borland's Open Architecture Handbook I've created a template for 010Editor to parse the debug information.
typedef struct { WORD MZSignature; WORD UsedBytesInTheLastPage ; WORD FileSizeInPages ; WORD NumberOfRelocationItems ; WORD HeaderSizeInParagraphs ; WORD MinimumExtraParagraphs ; WORD MaximumExtraParagraphs ; WORD InitialRelativeSS ; WORD InitialSP ; WORD Checksum ; WORD InitialIP ; WORD InitialRelativeCS ; WORD AddressOfRelocationTable ; WORD OverlayNumber ; WORD Reserved[4] ; WORD OEMid ; WORD OEMinfo ; WORD Reserved2[10] ; LONG AddressOfNewExeHeader ; } IMAGE_DOS_HEADER; typedef struct { WORD magic_number ; WORD version_id ; DWORD names ; WORD names_count ; WORD types_count ; WORD members_count ; WORD symbols_count ; WORD globals_count ; WORD modules_count ; WORD locals_count ; WORD scopes_count ; WORD lines_count ; WORD source_count ; WORD segment_counts ; WORD correlation_count ; DWORD image_size ; DWORD debugger_hook ; BYTE program_flags ; // bit 0: case-sensitive link // bit 1: pascal overlay program WORD stringsegoffset ; WORD data_count ; BYTE filler1 ; WORD extension_size ; if (extension_size > 0) { WORD class_entries ; WORD parent_entries ; WORD global_classes ; WORD NumberOfOverloads ; WORD scope_class_entries ; WORD module_class_entries ; WORD CoverageOffsetCount ; DWORD NamePoolOffset ; WORD BrowserEntries ; WORD OptSymEntries ; WORD DebugFlags ; DWORD refInfoSize ; BYTE filler2[14]; } // 8 BYTEs padding } DEBUG_INFO_HEADER; typedef struct { unsigned short symbol_name ; unsigned short symbol_type; unsigned short symbol_offset ; unsigned short symbol_segment ; unsigned byte symbol_class : 3; unsigned byte has_valid_BP : 1; usigned byte return_address_word_offset : 3; } SYMBOL_RECORD ; typedef struct { unsigned short module_name ; unsigned char language; unsigned byte memory_model : 3; unsigned byte underbars_on : 1; unsigned short symbols_index; unsigned short symbols_count; unsigned short source_files_index; unsigned short source_files_count; unsigned short correlation_index; unsigned short correlation_count; } MODULE_HEADER ; LittleEndian(); Printf("EXE.bt Begin\n"); IMAGE_DOS_HEADER DosHeader ; if (DosHeader.MZSignature != 0x5A4D) { Printf("Invalid DOS Magic.\n"); return 1; } local DWORD extra_data_start = DosHeader.FileSizeInPages * 512; if (DosHeader.UsedBytesInTheLastPage) { extra_data_start -= (512 - DosHeader.UsedBytesInTheLastPage); } if (extra_data_start >= FileSize()) { Printf("No Debug Info.\n"); return 1; } FSeek(extra_data_start); DEBUG_INFO_HEADER DebugHeader ; if (DebugHeader.magic_number != 0x52FB) { Printf("Invalid Debug Info Signature.\n"); return 1; } SYMBOL_RECORD SymbolRecord[DebugHeader.symbols_count] ; MODULE_HEADER Module[DebugHeader.modules_count] ; string readName(unsigned short nameIndex) { int originalLocation = FTell(); FSeek(FileSize() - DebugHeader.names); local int i = 0; string name; int currLocation = FTell(); while(i < nameIndex) { name = ReadString(currLocation); FSeek(currLocation + ReadStringLength(currLocation)); currLocation = FTell(); i++; } FSeek(originalLocation); return name; } string readSymbol(SYMBOL_RECORD &sym) { return readName(sym.symbol_name); } string readModule(MODULE_HEADER &module) { return readName(module.module_name); }