The debug directory, at data directory 6, lists pieces of debug information. The most useful is the CodeView entry, which names the PDB file that holds the program’s symbols, with a GUID that a debugger matches against the PDB. Other entries describe how the program was optimised, how it was built, and which security features it is compatible with.
Debug directory entries
IMAGE_DEBUG_DIRECTORY, 28 bytes each; data directory 6’s size divided by 28 is the number of entries:
| Offset | Size | Type | Field | Meaning |
|---|---|---|---|---|
| 0 | 4 | u32 | Characteristics | Reserved, 0. |
| 4 | 4 | u32 | TimeDateStamp | When the debug data was made. |
| 8 | 2 | u16 | MajorVersion | The version of the debug data format. |
| 10 | 2 | u16 | MinorVersion | |
| 12 | 4 | u32 | Type | What the data is; see Types. |
| 16 | 4 | u32 | SizeOfData | The size of the data. |
| 20 | 4 | u32 | AddressOfRawData | The data’s RVA when it is loaded, or 0 when it is not. |
| 24 | 4 | u32 | PointerToRawData | The data’s file offset. |
00009570 00 00 00 00 21 09 1C 56 00 00 00 00 0D 00 00 00
00009580 00 02 00 00 F4 A1 00 00 F4 95 00 00
0xA170 (file 0x9570): type 13, POGO; 512 bytes at RVA 0xA1F4, file offset 0x95F4EDK II’s GenFw and Apple’s mtoc, tools that make EFI images, count the CodeView data after the entries in data directory 6’s size, so it is not a multiple of 28. The explorer stops at the first entry that would run into data an earlier entry points at, and says so.
Types
| Type | Name | Data |
|---|---|---|
| 0 | UNKNOWN | Unknown; ignored. |
| 1 | COFF | COFF debug information: line numbers and symbols. |
| 2 | CODEVIEW | The CodeView record: the PDB file’s name and identity. |
| 3 | FPO | Frame pointer omission records. |
| 4 | MISC | The location of a .DBG file. |
| 5 | EXCEPTION | A copy of the exception table. |
| 6 | FIXUP | Reserved. |
| 7 | OMAP_TO_SRC | A map from the image’s RVAs to the RVAs before the image was rearranged. |
| 8 | OMAP_FROM_SRC | The reverse map. |
| 9 | BORLAND | Reserved for Borland. |
| 10 | RESERVED10 | Reserved; named BBT in some headers. |
| 11 | CLSID | Reserved. |
| 12 | VC_FEATURE | Counts of compiler features (from winnt.h). |
| 13 | POGO | The section contributions (from winnt.h). |
| 14 | ILTCG | Marks link-time code generation from IL (from winnt.h). |
| 15 | MPX | Intel MPX (from winnt.h). |
| 16 | REPRO | Marks a reproducible build. |
| 17 | Embedded Portable PDB | A compressed Portable PDB (named in .NET’s PE-COFF specification). |
| 19 | PDB checksum | A checksum of the PDB (named in .NET’s PE-COFF specification). |
| 20 | EX_DLLCHARACTERISTICS | More DLL characteristics. |
Microsoft’s PE specification lists types 0 to 11, 16, 17, 19 and 20. In the files examined for this site the commonest were CODEVIEW with a PDB path, MISC, REPRO, PDB checksum, FPO, VC_FEATURE and POGO.
CodeView
The data starts with a 4-byte signature that says its form:
| Signature | Written by | Then |
|---|---|---|
RSDS | Visual C++ .NET (7.0) and later: CodeView 7.0 | a GUID (16 bytes), the Age (4), and the PDB path in UTF-8, ending in a zero byte |
NB10 | Visual C++ 2.0 to 6.0 | an Offset (4, 0), a Signature (4, a time stamp), the Age (4) and the PDB path, ending in a zero byte |
NB09, NB11 and the like | older tools | CodeView data held in the file itself |
MTOC | Apple’s EFI tools | seen in Apple .efi files |
A debugger looks for the PDB named by the path, and accepts it only if the GUID and the Age (NB10: the Signature and Age) match those stored in the PDB. The explorer shows the path in the Program tab.
POGO
A list of the section contributions the linker put together: each named part of a
section, such as .text$mn for ordinary code or .CRT$XCA for
the start of the C++ initialisers. POGO is Microsoft’s short name for profile-guided
optimisation. The data is a 4-byte signature, then entries:
| Offset | Size | Type | Field | Meaning |
|---|---|---|---|---|
| 0 | 4 | u32 | RVA | Where the contribution starts. |
| 4 | 4 | u32 | Size | Its size. |
| 8 | varies | char[] | Name | Its name, ending in a zero byte, padded with zeros to a multiple of 4 bytes. |
000095F4 00 00 00 00 00 10 00 00 9E 7F 00 00 2E 74 65 78
00009604 74 24 6D 6E 00 00 00 00 00 90 00 00 10 02 00 00
00009614 2E 69 64 61 74 61 24 35 00 00 00 00
.text$mn, 32,670 bytes at 0x1000; .idata$5, the import address tables, 528 bytes at 0x9000; 26 entries in allThe signature was 0 in the Visual C++ 2015 files looked at. Write-ups report other
values, LTCG and PGU, which have not been confirmed
here.
MISC
IMAGE_DEBUG_MISC, used to find a separate .DBG file of symbols, as older
tools wrote:
| Offset | Size | Type | Field | Meaning |
|---|---|---|---|---|
| 0 | 4 | u32 | DataType | 1, EXENAME: the data is the image’s name. |
| 4 | 4 | u32 | Length | The length of the record, a multiple of 4. |
| 8 | 1 | u8 | Unicode | 1 when the name is UTF-16, 0 when it is ASCII. |
| 9 | 3 | u8[3] | Reserved | 0. |
| 12 | varies | – | Data | The image’s name. |
VC_FEATURE
Five 4-byte counts of the objects in the link: those from compilers older than
Visual C++ 11, the C and C++ objects, and those built with /GS,
/sdl and guardN. These names are the ones dumpbin reports, taken from
write-ups; Microsoft’s page does not describe the entry.
REPRO
Marks a reproducible build. The data is empty, or a 4-byte length and a hash of the build’s input. When it is present, the TimeDateStamp fields of the file are hash bits, not times; see Time stamp.
FPO
Frame pointer omission records, which tell a debugger how to walk the stack through x86 functions that do not set up EBP. Each FPO_DATA record is 16 bytes:
| Offset | Size | Type | Field | Meaning |
|---|---|---|---|---|
| 0 | 4 | u32 | ulOffStart | The function’s first byte. |
| 4 | 4 | u32 | cbProcSize | The function’s size. |
| 8 | 4 | u32 | cdwLocals | The size of its locals, in dwords. |
| 12 | 2 | u16 | cdwParams | The size of its parameters, in dwords. |
| 14 | 2 | u16 | Bits | cbProlog (bits 0–7, the prolog’s length), cbRegs (8–10, registers saved), fHasSEH (11), fUseBP (12), reserved (13), cbFrame (14–15: 0 FRAME_FPO, 1 FRAME_TRAP, 2 FRAME_TSS). |
EX_DLLCHARACTERISTICS
A 4-byte word of flags beyond those in the optional header’s
DllCharacteristics.
Microsoft’s page lists 0x01 CET_COMPAT, compatible with the CET shadow
stack, and 0x40 FORWARD_CFI_COMPAT. The explorer also names
0x02, 0x04, 0x08, 0x10,
0x20 and 0x80 from winnt.h.
Embedded Portable PDB
A .NET compiler can put the program’s Portable PDB inside the file. The data is the
signature MPDB, the PDB’s uncompressed size (4 bytes), then the PDB
compressed with Deflate.
PDB checksum
A checksum of the PDB, so that a symbol server can check the file it hands out. The
data is the name of the algorithm, in UTF-8 and ending in a zero byte, such as
SHA256, then the checksum’s bytes.