master
  1//! Program Data Base debugging information format.
  2//!
  3//! This namespace contains unopinionated types and data definitions only. For
  4//! an implementation of parsing and caching PDB information, see
  5//! `std.debug.Pdb`.
  6//!
  7//! Most of this is based on information gathered from LLVM source code,
  8//! documentation and/or contributors.
  9
 10const std = @import("std.zig");
 11const math = std.math;
 12const mem = std.mem;
 13const coff = std.coff;
 14const fs = std.fs;
 15const File = std.fs.File;
 16const debug = std.debug;
 17
 18const ArrayList = std.ArrayList;
 19
 20/// https://llvm.org/docs/PDB/DbiStream.html#stream-header
 21pub const DbiStreamHeader = extern struct {
 22    version_signature: i32,
 23    version_header: u32,
 24    age: u32,
 25    global_stream_index: u16,
 26    build_number: u16,
 27    public_stream_index: u16,
 28    pdb_dll_version: u16,
 29    sym_record_stream: u16,
 30    pdb_dll_rbld: u16,
 31    mod_info_size: u32,
 32    section_contribution_size: u32,
 33    section_map_size: u32,
 34    source_info_size: i32,
 35    type_server_size: i32,
 36    mfc_type_server_index: u32,
 37    optional_dbg_header_size: i32,
 38    ec_substream_size: i32,
 39    flags: u16,
 40    machine: u16,
 41    padding: u32,
 42};
 43
 44pub const SectionContribEntry = extern struct {
 45    /// COFF Section index, 1-based
 46    section: u16,
 47    padding1: [2]u8,
 48    offset: u32,
 49    size: u32,
 50    characteristics: u32,
 51    module_index: u16,
 52    padding2: [2]u8,
 53    data_crc: u32,
 54    reloc_crc: u32,
 55};
 56
 57pub const ModInfo = extern struct {
 58    unused1: u32,
 59    section_contr: SectionContribEntry,
 60    flags: u16,
 61    module_sym_stream: u16,
 62    sym_byte_size: u32,
 63    c11_byte_size: u32,
 64    c13_byte_size: u32,
 65    source_file_count: u16,
 66    padding: [2]u8,
 67    unused2: u32,
 68    source_file_name_index: u32,
 69    pdb_file_path_name_index: u32,
 70    // These fields are variable length
 71    //module_name: char[],
 72    //obj_file_name: char[],
 73};
 74
 75pub const SectionMapHeader = extern struct {
 76    /// Number of segment descriptors
 77    count: u16,
 78
 79    /// Number of logical segment descriptors
 80    log_count: u16,
 81};
 82
 83pub const SectionMapEntry = extern struct {
 84    /// See the SectionMapEntryFlags enum below.
 85    flags: u16,
 86
 87    /// Logical overlay number
 88    ovl: u16,
 89
 90    /// Group index into descriptor array.
 91    group: u16,
 92    frame: u16,
 93
 94    /// Byte index of segment / group name in string table, or 0xFFFF.
 95    section_name: u16,
 96
 97    /// Byte index of class in string table, or 0xFFFF.
 98    class_name: u16,
 99
100    /// Byte offset of the logical segment within physical segment.  If group is set in flags, this is the offset of the group.
101    offset: u32,
102
103    /// Byte count of the segment or group.
104    section_length: u32,
105};
106
107pub const StreamType = enum(u16) {
108    pdb = 1,
109    tpi = 2,
110    dbi = 3,
111    ipi = 4,
112};
113
114/// Duplicate copy of SymbolRecordKind, but using the official CV names. Useful
115/// for reference purposes and when dealing with unknown record types.
116pub const SymbolKind = enum(u16) {
117    compile = 1,
118    register_16t = 2,
119    constant_16t = 3,
120    udt_16t = 4,
121    ssearch = 5,
122    skip = 7,
123    cvreserve = 8,
124    objname_st = 9,
125    endarg = 10,
126    coboludt_16t = 11,
127    manyreg_16t = 12,
128    @"return" = 13,
129    entrythis = 14,
130    bprel16 = 256,
131    ldata16 = 257,
132    gdata16 = 258,
133    pub16 = 259,
134    lproc16 = 260,
135    gproc16 = 261,
136    thunk16 = 262,
137    block16 = 263,
138    with16 = 264,
139    label16 = 265,
140    cexmodel16 = 266,
141    vftable16 = 267,
142    regrel16 = 268,
143    bprel32_16t = 512,
144    ldata32_16t = 513,
145    gdata32_16t = 514,
146    pub32_16t = 515,
147    lproc32_16t = 516,
148    gproc32_16t = 517,
149    thunk32_st = 518,
150    block32_st = 519,
151    with32_st = 520,
152    label32_st = 521,
153    cexmodel32 = 522,
154    vftable32_16t = 523,
155    regrel32_16t = 524,
156    lthread32_16t = 525,
157    gthread32_16t = 526,
158    slink32 = 527,
159    lprocmips_16t = 768,
160    gprocmips_16t = 769,
161    procref_st = 1024,
162    dataref_st = 1025,
163    @"align" = 1026,
164    lprocref_st = 1027,
165    oem = 1028,
166    ti16_max = 4096,
167    register_st = 4097,
168    constant_st = 4098,
169    udt_st = 4099,
170    coboludt_st = 4100,
171    manyreg_st = 4101,
172    bprel32_st = 4102,
173    ldata32_st = 4103,
174    gdata32_st = 4104,
175    pub32_st = 4105,
176    lproc32_st = 4106,
177    gproc32_st = 4107,
178    vftable32 = 4108,
179    regrel32_st = 4109,
180    lthread32_st = 4110,
181    gthread32_st = 4111,
182    lprocmips_st = 4112,
183    gprocmips_st = 4113,
184    compile2_st = 4115,
185    manyreg2_st = 4116,
186    lprocia64_st = 4117,
187    gprocia64_st = 4118,
188    localslot_st = 4119,
189    paramslot_st = 4120,
190    annotation = 4121,
191    gmanproc_st = 4122,
192    lmanproc_st = 4123,
193    reserved1 = 4124,
194    reserved2 = 4125,
195    reserved3 = 4126,
196    reserved4 = 4127,
197    lmandata_st = 4128,
198    gmandata_st = 4129,
199    manframerel_st = 4130,
200    manregister_st = 4131,
201    manslot_st = 4132,
202    manmanyreg_st = 4133,
203    manregrel_st = 4134,
204    manmanyreg2_st = 4135,
205    mantypref = 4136,
206    unamespace_st = 4137,
207    st_max = 4352,
208    with32 = 4356,
209    manyreg = 4362,
210    lprocmips = 4372,
211    gprocmips = 4373,
212    manyreg2 = 4375,
213    lprocia64 = 4376,
214    gprocia64 = 4377,
215    localslot = 4378,
216    paramslot = 4379,
217    manframerel = 4382,
218    manregister = 4383,
219    manslot = 4384,
220    manmanyreg = 4385,
221    manregrel = 4386,
222    manmanyreg2 = 4387,
223    unamespace = 4388,
224    dataref = 4390,
225    annotationref = 4392,
226    tokenref = 4393,
227    gmanproc = 4394,
228    lmanproc = 4395,
229    attr_framerel = 4398,
230    attr_register = 4399,
231    attr_regrel = 4400,
232    attr_manyreg = 4401,
233    sepcode = 4402,
234    local_2005 = 4403,
235    defrange_2005 = 4404,
236    defrange2_2005 = 4405,
237    discarded = 4411,
238    lprocmips_id = 4424,
239    gprocmips_id = 4425,
240    lprocia64_id = 4426,
241    gprocia64_id = 4427,
242    defrange_hlsl = 4432,
243    gdata_hlsl = 4433,
244    ldata_hlsl = 4434,
245    local_dpc_groupshared = 4436,
246    defrange_dpc_ptr_tag = 4439,
247    dpc_sym_tag_map = 4440,
248    armswitchtable = 4441,
249    pogodata = 4444,
250    inlinesite2 = 4445,
251    mod_typeref = 4447,
252    ref_minipdb = 4448,
253    pdbmap = 4449,
254    gdata_hlsl32 = 4450,
255    ldata_hlsl32 = 4451,
256    gdata_hlsl32_ex = 4452,
257    ldata_hlsl32_ex = 4453,
258    fastlink = 4455,
259    inlinees = 4456,
260    end = 6,
261    inlinesite_end = 4430,
262    proc_id_end = 4431,
263    thunk32 = 4354,
264    trampoline = 4396,
265    section = 4406,
266    coffgroup = 4407,
267    @"export" = 4408,
268    lproc32 = 4367,
269    gproc32 = 4368,
270    lproc32_id = 4422,
271    gproc32_id = 4423,
272    lproc32_dpc = 4437,
273    lproc32_dpc_id = 4438,
274    register = 4358,
275    pub32 = 4366,
276    procref = 4389,
277    lprocref = 4391,
278    envblock = 4413,
279    inlinesite = 4429,
280    local = 4414,
281    defrange = 4415,
282    defrange_subfield = 4416,
283    defrange_register = 4417,
284    defrange_framepointer_rel = 4418,
285    defrange_subfield_register = 4419,
286    defrange_framepointer_rel_full_scope = 4420,
287    defrange_register_rel = 4421,
288    block32 = 4355,
289    label32 = 4357,
290    objname = 4353,
291    compile2 = 4374,
292    compile3 = 4412,
293    frameproc = 4114,
294    callsiteinfo = 4409,
295    filestatic = 4435,
296    heapallocsite = 4446,
297    framecookie = 4410,
298    callees = 4442,
299    callers = 4443,
300    udt = 4360,
301    coboludt = 4361,
302    buildinfo = 4428,
303    bprel32 = 4363,
304    regrel32 = 4369,
305    constant = 4359,
306    manconstant = 4397,
307    ldata32 = 4364,
308    gdata32 = 4365,
309    lmandata = 4380,
310    gmandata = 4381,
311    lthread32 = 4370,
312    gthread32 = 4371,
313};
314
315pub const TypeIndex = u32;
316
317// TODO According to this header:
318// https://github.com/microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L3722
319// we should define RecordPrefix as part of the ProcSym structure.
320// This might be important when we start generating PDB in self-hosted with our own PE linker.
321pub const ProcSym = extern struct {
322    parent: u32,
323    end: u32,
324    next: u32,
325    code_size: u32,
326    dbg_start: u32,
327    dbg_end: u32,
328    function_type: TypeIndex,
329    code_offset: u32,
330    segment: u16,
331    flags: ProcSymFlags,
332    name: [1]u8, // null-terminated
333};
334
335pub const ProcSymFlags = packed struct {
336    has_fp: bool,
337    has_iret: bool,
338    has_fret: bool,
339    is_no_return: bool,
340    is_unreachable: bool,
341    has_custom_calling_conv: bool,
342    is_no_inline: bool,
343    has_optimized_debug_info: bool,
344};
345
346pub const SectionContrSubstreamVersion = enum(u32) {
347    Ver60 = 0xeffe0000 + 19970605,
348    V2 = 0xeffe0000 + 20140516,
349    _,
350};
351
352pub const RecordPrefix = extern struct {
353    /// Record length, starting from &record_kind.
354    record_len: u16,
355
356    /// Record kind enum (SymRecordKind or TypeRecordKind)
357    record_kind: SymbolKind,
358};
359
360/// The following variable length array appears immediately after the header.
361/// The structure definition follows.
362/// LineBlockFragmentHeader Blocks[]
363/// Each `LineBlockFragmentHeader` as specified below.
364pub const LineFragmentHeader = extern struct {
365    /// Code offset of line contribution.
366    reloc_offset: u32,
367
368    /// Code segment of line contribution.
369    reloc_segment: u16,
370    flags: LineFlags,
371
372    /// Code size of this line contribution.
373    code_size: u32,
374};
375
376pub const LineFlags = packed struct {
377    /// CV_LINES_HAVE_COLUMNS
378    have_columns: bool,
379    unused: u15,
380};
381
382/// The following two variable length arrays appear immediately after the
383/// header.  The structure definitions follow.
384/// LineNumberEntry   Lines[NumLines];
385/// ColumnNumberEntry Columns[NumLines];
386pub const LineBlockFragmentHeader = extern struct {
387    /// Offset of FileChecksum entry in File
388    /// checksums buffer.  The checksum entry then
389    /// contains another offset into the string
390    /// table of the actual name.
391    name_index: u32,
392    num_lines: u32,
393
394    /// code size of block, in bytes
395    block_size: u32,
396};
397
398pub const LineNumberEntry = extern struct {
399    /// Offset to start of code bytes for line number
400    offset: u32,
401    flags: Flags,
402
403    pub const Flags = packed struct(u32) {
404        /// Start line number
405        start: u24,
406        /// Delta of lines to the end of the expression. Still unclear.
407        // TODO figure out the point of this field.
408        end: u7,
409        is_statement: bool,
410    };
411};
412
413pub const ColumnNumberEntry = extern struct {
414    start_column: u16,
415    end_column: u16,
416};
417
418/// Checksum bytes follow.
419pub const FileChecksumEntryHeader = extern struct {
420    /// Byte offset of filename in global string table.
421    file_name_offset: u32,
422    /// Number of bytes of checksum.
423    checksum_size: u8,
424    /// FileChecksumKind
425    checksum_kind: u8,
426};
427
428pub const DebugSubsectionKind = enum(u32) {
429    none = 0,
430    symbols = 0xf1,
431    lines = 0xf2,
432    string_table = 0xf3,
433    file_checksums = 0xf4,
434    frame_data = 0xf5,
435    inlinee_lines = 0xf6,
436    cross_scope_imports = 0xf7,
437    cross_scope_exports = 0xf8,
438
439    // These appear to relate to .Net assembly info.
440    il_lines = 0xf9,
441    func_md_token_map = 0xfa,
442    type_md_token_map = 0xfb,
443    merged_assembly_input = 0xfc,
444
445    coff_symbol_rva = 0xfd,
446};
447
448pub const DebugSubsectionHeader = extern struct {
449    /// codeview::DebugSubsectionKind enum
450    kind: DebugSubsectionKind,
451
452    /// number of bytes occupied by this record.
453    length: u32,
454};
455
456pub const StringTableHeader = extern struct {
457    /// PDBStringTableSignature
458    signature: u32,
459    /// 1 or 2
460    hash_version: u32,
461    /// Number of bytes of names buffer.
462    byte_size: u32,
463};
464
465// https://llvm.org/docs/PDB/MsfFile.html#the-superblock
466pub const SuperBlock = extern struct {
467    /// The LLVM docs list a space between C / C++ but empirically this is not the case.
468    pub const expect_magic = "Microsoft C/C++ MSF 7.00\r\n\x1a\x44\x53\x00\x00\x00";
469
470    file_magic: [expect_magic.len]u8,
471
472    /// The block size of the internal file system. Valid values are 512, 1024,
473    /// 2048, and 4096 bytes. Certain aspects of the MSF file layout vary depending
474    /// on the block sizes. For the purposes of LLVM, we handle only block sizes of
475    /// 4KiB, and all further discussion assumes a block size of 4KiB.
476    block_size: u32,
477
478    /// The index of a block within the file, at which begins a bitfield representing
479    /// the set of all blocks within the file which are “free” (i.e. the data within
480    /// that block is not used). See The Free Block Map for more information. Important:
481    /// FreeBlockMapBlock can only be 1 or 2!
482    free_block_map_block: u32,
483
484    /// The total number of blocks in the file. NumBlocks * BlockSize should equal the
485    /// size of the file on disk.
486    num_blocks: u32,
487
488    /// The size of the stream directory, in bytes. The stream directory contains
489    /// information about each stream’s size and the set of blocks that it occupies.
490    /// It will be described in more detail later.
491    num_directory_bytes: u32,
492
493    unknown: u32,
494    /// The index of a block within the MSF file. At this block is an array of
495    /// ulittle32_t’s listing the blocks that the stream directory resides on.
496    /// For large MSF files, the stream directory (which describes the block
497    /// layout of each stream) may not fit entirely on a single block. As a
498    /// result, this extra layer of indirection is introduced, whereby this
499    /// block contains the list of blocks that the stream directory occupies,
500    /// and the stream directory itself can be stitched together accordingly.
501    /// The number of ulittle32_t’s in this array is given by
502    /// ceil(NumDirectoryBytes / BlockSize).
503    // Note: microsoft-pdb code actually suggests this is a variable-length
504    // array. If the indices of blocks occupied by the Stream Directory didn't
505    // fit in one page, there would be other u32 following it.
506    // This would mean the Stream Directory is bigger than BlockSize / sizeof(u32)
507    // blocks. We're not even close to this with a 1GB pdb file, and LLVM didn't
508    // implement it so we're kind of safe making this assumption for now.
509    block_map_addr: u32,
510};