authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-09-02 15:58:08-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-09-02 15:58:08-04:00
log98dc943c0784b93ed28099bb75044c536174a144
tree5f1ba858f8de71a48519057656fbc63d8c136ab5
parent6ddbd345aa085291f540e6d1b436edad32fe9a69

rework code to avoid duplicate operations


5 files changed, 448 insertions(+), 305 deletions(-)

std/coff.zig-8
...@@ -83,7 +83,6 @@ pub const Coff = struct {...@@ -83,7 +83,6 @@ pub const Coff = struct {
83 fn loadOptionalHeader(self: *Coff, file_stream: *io.FileInStream) !void {83 fn loadOptionalHeader(self: *Coff, file_stream: *io.FileInStream) !void {
84 const in = &file_stream.stream;84 const in = &file_stream.stream;
85 self.pe_header.magic = try in.readIntLe(u16);85 self.pe_header.magic = try in.readIntLe(u16);
86 std.debug.warn("reading pe optional\n");
87 // For now we're only interested in finding the reference to the .pdb,86 // For now we're only interested in finding the reference to the .pdb,
88 // so we'll skip most of this header, which size is different in 3287 // so we'll skip most of this header, which size is different in 32
89 // 64 bits by the way.88 // 64 bits by the way.
...@@ -97,11 +96,9 @@ pub const Coff = struct {...@@ -97,11 +96,9 @@ pub const Coff = struct {
97 else96 else
98 return error.InvalidPEMagic;97 return error.InvalidPEMagic;
9998
100 std.debug.warn("skipping {}\n", skip_size);
101 try self.in_file.seekForward(skip_size);99 try self.in_file.seekForward(skip_size);
102100
103 const number_of_rva_and_sizes = try in.readIntLe(u32);101 const number_of_rva_and_sizes = try in.readIntLe(u32);
104 //std.debug.warn("indicating {} data dirs\n", number_of_rva_and_sizes);
105 if (number_of_rva_and_sizes != IMAGE_NUMBEROF_DIRECTORY_ENTRIES)102 if (number_of_rva_and_sizes != IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
106 return error.InvalidPEHeader;103 return error.InvalidPEHeader;
107104
...@@ -110,9 +107,7 @@ pub const Coff = struct {...@@ -110,9 +107,7 @@ pub const Coff = struct {
110 .virtual_address = try in.readIntLe(u32),107 .virtual_address = try in.readIntLe(u32),
111 .size = try in.readIntLe(u32),108 .size = try in.readIntLe(u32),
112 };109 };
113 //std.debug.warn("data_dir @ {x}, size {}\n", data_dir.virtual_address, data_dir.size);
114 }110 }
115 std.debug.warn("loaded data directories\n");
116 }111 }
117112
118 pub fn getPdbPath(self: *Coff, buffer: []u8) !usize {113 pub fn getPdbPath(self: *Coff, buffer: []u8) !usize {
...@@ -123,7 +118,6 @@ pub const Coff = struct {...@@ -123,7 +118,6 @@ pub const Coff = struct {
123 // debug_directory.118 // debug_directory.
124 const debug_dir = &self.pe_header.data_directory[DEBUG_DIRECTORY];119 const debug_dir = &self.pe_header.data_directory[DEBUG_DIRECTORY];
125 const file_offset = debug_dir.virtual_address - header.virtual_address + header.pointer_to_raw_data;120 const file_offset = debug_dir.virtual_address - header.virtual_address + header.pointer_to_raw_data;
126 std.debug.warn("file offset {x}\n", file_offset);
127 try self.in_file.seekTo(file_offset + debug_dir.size);121 try self.in_file.seekTo(file_offset + debug_dir.size);
128122
129 var file_stream = io.FileInStream.init(self.in_file);123 var file_stream = io.FileInStream.init(self.in_file);
...@@ -134,7 +128,6 @@ pub const Coff = struct {...@@ -134,7 +128,6 @@ pub const Coff = struct {
134 // 'RSDS' indicates PDB70 format, used by lld.128 // 'RSDS' indicates PDB70 format, used by lld.
135 if (!mem.eql(u8, cv_signature, "RSDS"))129 if (!mem.eql(u8, cv_signature, "RSDS"))
136 return error.InvalidPEMagic;130 return error.InvalidPEMagic;
137 std.debug.warn("cv_signature {}\n", cv_signature);
138 try in.readNoEof(self.guid[0..]);131 try in.readNoEof(self.guid[0..]);
139 self.age = try in.readIntLe(u32);132 self.age = try in.readIntLe(u32);
140133
...@@ -181,7 +174,6 @@ pub const Coff = struct {...@@ -181,7 +174,6 @@ pub const Coff = struct {
181 },174 },
182 });175 });
183 }176 }
184 std.debug.warn("loaded {} sections\n", self.coff_header.number_of_sections);
185 }177 }
186178
187 pub fn getSection(self: *Coff, comptime name: []const u8) ?*Section {179 pub fn getSection(self: *Coff, comptime name: []const u8) ?*Section {
std/debug/index.zig+386-41
...@@ -20,6 +20,17 @@ pub const runtime_safety = switch (builtin.mode) {...@@ -20,6 +20,17 @@ pub const runtime_safety = switch (builtin.mode) {
20 builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => false,20 builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => false,
21};21};
2222
23const Module = struct {
24 mod_info: pdb.ModInfo,
25 module_name: []u8,
26 obj_file_name: []u8,
27
28 populated: bool,
29 symbols: []u8,
30 subsect_info: []u8,
31 checksums: []u32,
32};
33
23/// Tries to write to stderr, unbuffered, and ignores any error returned.34/// Tries to write to stderr, unbuffered, and ignores any error returned.
24/// Does not append a newline.35/// Does not append a newline.
25var stderr_file: os.File = undefined;36var stderr_file: os.File = undefined;
...@@ -258,12 +269,277 @@ pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: us...@@ -258,12 +269,277 @@ pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: us
258 }269 }
259}270}
260271
261fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {272fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_address: usize, tty_color: bool) !void {
273 const allocator = getDebugInfoAllocator();
262 const base_address = os.getBaseAddress();274 const base_address = os.getBaseAddress();
263 const relative_address = address - base_address;275 const relative_address = relocated_address - base_address;
264 std.debug.warn("{x} - {x} => {x}\n", address, base_address, relative_address);276
265 try di.pdb.getSourceLine(relative_address);277 var coff_section: *coff.Section = undefined;
266 return error.UnsupportedDebugInfo;278 const mod_index = for (di.sect_contribs) |sect_contrib| {
279 coff_section = &di.coff.sections.toSlice()[sect_contrib.Section];
280
281 const vaddr_start = coff_section.header.virtual_address + sect_contrib.Offset;
282 const vaddr_end = vaddr_start + sect_contrib.Size;
283 if (relative_address >= vaddr_start and relative_address < vaddr_end) {
284 break sect_contrib.ModuleIndex;
285 }
286 } else {
287 // we have no information to add to the address
288 if (tty_color) {
289 try out_stream.print("???:?:?: ");
290 setTtyColor(TtyColor.Dim);
291 try out_stream.print("0x{x} in ??? (???)", relocated_address);
292 setTtyColor(TtyColor.Reset);
293 try out_stream.print("\n\n\n");
294 } else {
295 try out_stream.print("???:?:?: 0x{x} in ??? (???)\n\n\n", relocated_address);
296 }
297 return;
298 };
299
300 const mod = &di.modules[mod_index];
301 try populateModule(di, mod);
302 const obj_basename = os.path.basename(mod.obj_file_name);
303
304 var symbol_i: usize = 0;
305 const symbol_name = while (symbol_i != mod.symbols.len) {
306 const prefix = @ptrCast(*pdb.RecordPrefix, &mod.symbols[symbol_i]);
307 if (prefix.RecordLen < 2)
308 return error.InvalidDebugInfo;
309 switch (prefix.RecordKind) {
310 pdb.SymbolKind.S_LPROC32 => {
311 const proc_sym = @ptrCast(*pdb.ProcSym, &mod.symbols[symbol_i + @sizeOf(pdb.RecordPrefix)]);
312 const vaddr_start = coff_section.header.virtual_address + proc_sym.CodeOffset;
313 const vaddr_end = vaddr_start + proc_sym.CodeSize;
314 if (relative_address >= vaddr_start and relative_address < vaddr_end) {
315 break mem.toSliceConst(u8, @ptrCast([*]u8, proc_sym) + @sizeOf(pdb.ProcSym));
316 }
317 },
318 else => {},
319 }
320 symbol_i += prefix.RecordLen + @sizeOf(u16);
321 if (symbol_i > mod.symbols.len)
322 return error.InvalidDebugInfo;
323 } else "???";
324
325 const subsect_info = mod.subsect_info;
326
327 var sect_offset: usize = 0;
328 var skip_len: usize = undefined;
329 const opt_line_info = subsections: while (sect_offset != subsect_info.len) : (sect_offset += skip_len) {
330 const subsect_hdr = @ptrCast(*pdb.DebugSubsectionHeader, &subsect_info[sect_offset]);
331 skip_len = subsect_hdr.Length;
332 sect_offset += @sizeOf(pdb.DebugSubsectionHeader);
333
334 switch (subsect_hdr.Kind) {
335 pdb.DebugSubsectionKind.Lines => {
336 var line_index: usize = sect_offset;
337
338 const line_hdr = @ptrCast(*pdb.LineFragmentHeader, &subsect_info[line_index]);
339 if (line_hdr.RelocSegment == 0) return error.MissingDebugInfo;
340 line_index += @sizeOf(pdb.LineFragmentHeader);
341
342 const block_hdr = @ptrCast(*pdb.LineBlockFragmentHeader, &subsect_info[line_index]);
343 line_index += @sizeOf(pdb.LineBlockFragmentHeader);
344
345 const has_column = line_hdr.Flags.LF_HaveColumns;
346
347 const frag_vaddr_start = coff_section.header.virtual_address + line_hdr.RelocOffset;
348 const frag_vaddr_end = frag_vaddr_start + line_hdr.CodeSize;
349 if (relative_address >= frag_vaddr_start and relative_address < frag_vaddr_end) {
350 var line_i: usize = 0;
351 const start_line_index = line_index;
352 while (line_i < block_hdr.NumLines) : (line_i += 1) {
353 const line_num_entry = @ptrCast(*pdb.LineNumberEntry, &subsect_info[line_index]);
354 line_index += @sizeOf(pdb.LineNumberEntry);
355 const flags = @ptrCast(*pdb.LineNumberEntry.Flags, &line_num_entry.Flags);
356 const vaddr_start = frag_vaddr_start + line_num_entry.Offset;
357 const vaddr_end = if (flags.End == 0) frag_vaddr_end else vaddr_start + flags.End;
358 if (relative_address >= vaddr_start and relative_address < vaddr_end) {
359 const chksum_index = block_hdr.NameIndex;
360 std.debug.warn("looking up checksum {}\n", chksum_index);
361 const strtab_offset = mod.checksums[chksum_index];
362 try di.pdb.string_table.seekTo(@sizeOf(pdb.PDBStringTableHeader) + strtab_offset);
363 const source_file_name = try di.pdb.string_table.readNullTermString(allocator);
364 const line = flags.Start;
365 const column = if (has_column) blk: {
366 line_index = start_line_index + @sizeOf(pdb.LineNumberEntry) * block_hdr.NumLines;
367 line_index += @sizeOf(pdb.ColumnNumberEntry) * line_i;
368 const col_num_entry = @ptrCast(*pdb.ColumnNumberEntry, &subsect_info[line_index]);
369 break :blk col_num_entry.StartColumn;
370 } else 0;
371 break :subsections LineInfo{
372 .allocator = allocator,
373 .file_name = source_file_name,
374 .line = line,
375 .column = column,
376 };
377 }
378 }
379 break :subsections null;
380 }
381 },
382 else => {},
383 }
384
385 if (sect_offset > subsect_info.len)
386 return error.InvalidDebugInfo;
387 } else null;
388
389 if (tty_color) {
390 if (opt_line_info) |li| {
391 try out_stream.print("{}:{}:{}: ", li.file_name, li.line, li.column);
392 } else {
393 try out_stream.print("???:?:?: ");
394 }
395 setTtyColor(TtyColor.Dim);
396 try out_stream.print("0x{x} in {} ({})", relocated_address, symbol_name, obj_basename);
397 setTtyColor(TtyColor.Reset);
398
399 if (opt_line_info) |line_info| {
400 try out_stream.print("\n");
401 if (printLineFromFile(out_stream, line_info)) {
402 if (line_info.column == 0) {
403 try out_stream.write("\n");
404 } else {
405 {
406 var col_i: usize = 1;
407 while (col_i < line_info.column) : (col_i += 1) {
408 try out_stream.writeByte(' ');
409 }
410 }
411 setTtyColor(TtyColor.Green);
412 try out_stream.write("^");
413 setTtyColor(TtyColor.Reset);
414 try out_stream.write("\n");
415 }
416 } else |err| switch (err) {
417 error.EndOfFile => {},
418 else => return err,
419 }
420 } else {
421 try out_stream.print("\n\n\n");
422 }
423 } else {
424 if (opt_line_info) |li| {
425 try out_stream.print("{}:{}:{}: 0x{x} in {} ({})\n\n\n", li.file_name, li.line, li.column, relocated_address, symbol_name, obj_basename);
426 } else {
427 try out_stream.print("???:?:?: 0x{x} in {} ({})\n\n\n", relocated_address, symbol_name, obj_basename);
428 }
429 }
430}
431
432const TtyColor = enum{
433 Red,
434 Green,
435 Cyan,
436 White,
437 Dim,
438 Bold,
439 Reset,
440};
441
442/// TODO this is a special case hack right now. clean it up and maybe make it part of std.fmt
443fn setTtyColor(tty_color: TtyColor) void {
444 const S = struct {
445 var attrs: windows.WORD = undefined;
446 var init_attrs = false;
447 };
448 if (!S.init_attrs) {
449 S.init_attrs = true;
450 var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
451 // TODO handle error
452 _ = windows.GetConsoleScreenBufferInfo(stderr_file.handle, &info);
453 S.attrs = info.wAttributes;
454 }
455
456 // TODO handle errors
457 switch (tty_color) {
458 TtyColor.Red => {
459 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED|windows.FOREGROUND_INTENSITY);
460 },
461 TtyColor.Green => {
462 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN|windows.FOREGROUND_INTENSITY);
463 },
464 TtyColor.Cyan => {
465 _ = windows.SetConsoleTextAttribute(stderr_file.handle,
466 windows.FOREGROUND_GREEN|windows.FOREGROUND_BLUE|windows.FOREGROUND_INTENSITY);
467 },
468 TtyColor.White, TtyColor.Bold => {
469 _ = windows.SetConsoleTextAttribute(stderr_file.handle,
470 windows.FOREGROUND_RED|windows.FOREGROUND_GREEN|windows.FOREGROUND_BLUE|windows.FOREGROUND_INTENSITY);
471 },
472 TtyColor.Dim => {
473 _ = windows.SetConsoleTextAttribute(stderr_file.handle,
474 windows.FOREGROUND_RED|windows.FOREGROUND_GREEN|windows.FOREGROUND_BLUE);
475 },
476 TtyColor.Reset => {
477 _ = windows.SetConsoleTextAttribute(stderr_file.handle, S.attrs);
478 },
479 }
480}
481
482fn populateModule(di: *DebugInfo, mod: *Module) !void {
483 if (mod.populated)
484 return;
485 const allocator = getDebugInfoAllocator();
486
487 if (mod.mod_info.C11ByteSize != 0)
488 return error.InvalidDebugInfo;
489
490 if (mod.mod_info.C13ByteSize == 0)
491 return error.MissingDebugInfo;
492
493 const modi = di.pdb.getStreamById(mod.mod_info.ModuleSymStream) orelse return error.MissingDebugInfo;
494
495 const signature = try modi.stream.readIntLe(u32);
496 if (signature != 4)
497 return error.InvalidDebugInfo;
498
499 mod.symbols = try allocator.alloc(u8, mod.mod_info.SymByteSize - 4);
500 try modi.stream.readNoEof(mod.symbols);
501
502 mod.subsect_info = try allocator.alloc(u8, mod.mod_info.C13ByteSize);
503 try modi.stream.readNoEof(mod.subsect_info);
504
505 var checksum_list = ArrayList(u32).init(allocator);
506 var sect_offset: usize = 0;
507 var skip_len: usize = undefined;
508 while (sect_offset != mod.subsect_info.len) : (sect_offset += skip_len) {
509 const subsect_hdr = @ptrCast(*pdb.DebugSubsectionHeader, &mod.subsect_info[sect_offset]);
510 skip_len = subsect_hdr.Length;
511 sect_offset += @sizeOf(pdb.DebugSubsectionHeader);
512
513 switch (subsect_hdr.Kind) {
514 pdb.DebugSubsectionKind.FileChecksums => {
515 var chksum_index: usize = sect_offset;
516
517 while (chksum_index != mod.subsect_info.len) {
518 const chksum_hdr = @ptrCast(*pdb.FileChecksumEntryHeader, &mod.subsect_info[chksum_index]);
519 std.debug.warn("{} {}\n", checksum_list.len, chksum_hdr);
520 try checksum_list.append(chksum_hdr.FileNameOffset);
521 const len = @sizeOf(pdb.FileChecksumEntryHeader) + chksum_hdr.ChecksumSize;
522 chksum_index += len + (len % 4);
523 if (chksum_index > mod.subsect_info.len)
524 return error.InvalidDebugInfo;
525 }
526
527 },
528 else => {},
529 }
530
531 if (sect_offset > mod.subsect_info.len)
532 return error.InvalidDebugInfo;
533 }
534 mod.checksums = checksum_list.toOwnedSlice();
535
536 for (mod.checksums) |strtab_offset| {
537 try di.pdb.string_table.seekTo(@sizeOf(pdb.PDBStringTableHeader) + strtab_offset);
538 const source_file_name = try di.pdb.string_table.readNullTermString(allocator);
539 std.debug.warn("{}={}\n", strtab_offset, source_file_name);
540 }
541
542 mod.populated = true;
267}543}
268544
269fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const MachoSymbol {545fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const MachoSymbol {
...@@ -425,6 +701,8 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {...@@ -425,6 +701,8 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
425 var di = DebugInfo{701 var di = DebugInfo{
426 .coff = coff_obj,702 .coff = coff_obj,
427 .pdb = undefined,703 .pdb = undefined,
704 .sect_contribs = undefined,
705 .modules = undefined,
428 };706 };
429707
430 try di.coff.loadHeader();708 try di.coff.loadHeader();
...@@ -432,15 +710,12 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {...@@ -432,15 +710,12 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
432 var path_buf: [windows.MAX_PATH]u8 = undefined;710 var path_buf: [windows.MAX_PATH]u8 = undefined;
433 const len = try di.coff.getPdbPath(path_buf[0..]);711 const len = try di.coff.getPdbPath(path_buf[0..]);
434 const raw_path = path_buf[0..len];712 const raw_path = path_buf[0..len];
435 std.debug.warn("pdb raw path {}\n", raw_path);
436713
437 const path = try os.path.resolve(allocator, raw_path);714 const path = try os.path.resolve(allocator, raw_path);
438 std.debug.warn("pdb resolved path {}\n", path);
439715
440 try di.pdb.openFile(di.coff, path);716 try di.pdb.openFile(di.coff, path);
441717
442 var pdb_stream = di.pdb.getStream(pdb.StreamType.Pdb) orelse return error.InvalidDebugInfo;718 var pdb_stream = di.pdb.getStream(pdb.StreamType.Pdb) orelse return error.InvalidDebugInfo;
443 std.debug.warn("pdb real filepos {}\n", pdb_stream.getFilePos());
444 const version = try pdb_stream.stream.readIntLe(u32);719 const version = try pdb_stream.stream.readIntLe(u32);
445 const signature = try pdb_stream.stream.readIntLe(u32);720 const signature = try pdb_stream.stream.readIntLe(u32);
446 const age = try pdb_stream.stream.readIntLe(u32);721 const age = try pdb_stream.stream.readIntLe(u32);
...@@ -448,51 +723,119 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {...@@ -448,51 +723,119 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
448 try pdb_stream.stream.readNoEof(guid[0..]);723 try pdb_stream.stream.readNoEof(guid[0..]);
449 if (!mem.eql(u8, di.coff.guid, guid) or di.coff.age != age)724 if (!mem.eql(u8, di.coff.guid, guid) or di.coff.age != age)
450 return error.InvalidDebugInfo;725 return error.InvalidDebugInfo;
451 std.debug.warn("v {} s {} a {}\n", version, signature, age);
452 // We validated the executable and pdb match.726 // We validated the executable and pdb match.
453727
454 const name_bytes_len = try pdb_stream.stream.readIntLe(u32);728 const string_table_index = str_tab_index: {
455 const name_bytes = try allocator.alloc(u8, name_bytes_len);729 const name_bytes_len = try pdb_stream.stream.readIntLe(u32);
456 try pdb_stream.stream.readNoEof(name_bytes);730 const name_bytes = try allocator.alloc(u8, name_bytes_len);
731 try pdb_stream.stream.readNoEof(name_bytes);
457732
458 const HashTableHeader = packed struct {733 const HashTableHeader = packed struct {
459 Size: u32,734 Size: u32,
460 Capacity: u32,735 Capacity: u32,
461736
462 fn maxLoad(cap: u32) u32 {737 fn maxLoad(cap: u32) u32 {
463 return cap * 2 / 3 + 1;738 return cap * 2 / 3 + 1;
739 }
740 };
741 var hash_tbl_hdr: HashTableHeader = undefined;
742 try pdb_stream.stream.readStruct(HashTableHeader, &hash_tbl_hdr);
743 if (hash_tbl_hdr.Capacity == 0)
744 return error.InvalidDebugInfo;
745
746 if (hash_tbl_hdr.Size > HashTableHeader.maxLoad(hash_tbl_hdr.Capacity))
747 return error.InvalidDebugInfo;
748
749 const present = try readSparseBitVector(&pdb_stream.stream, allocator);
750 if (present.len != hash_tbl_hdr.Size)
751 return error.InvalidDebugInfo;
752 const deleted = try readSparseBitVector(&pdb_stream.stream, allocator);
753
754 const Bucket = struct {
755 first: u32,
756 second: u32,
757 };
758 const bucket_list = try allocator.alloc(Bucket, present.len);
759 for (present) |_| {
760 const name_offset = try pdb_stream.stream.readIntLe(u32);
761 const name_index = try pdb_stream.stream.readIntLe(u32);
762 const name = mem.toSlice(u8, name_bytes.ptr + name_offset);
763 if (mem.eql(u8, name, "/names")) {
764 break :str_tab_index name_index;
765 }
464 }766 }
767 return error.MissingDebugInfo;
465 };768 };
466 var hash_tbl_hdr: HashTableHeader = undefined;
467 try pdb_stream.stream.readStruct(HashTableHeader, &hash_tbl_hdr);
468 if (hash_tbl_hdr.Capacity == 0)
469 return error.InvalidDebugInfo;
470769
471 if (hash_tbl_hdr.Size > HashTableHeader.maxLoad(hash_tbl_hdr.Capacity))770 di.pdb.string_table = di.pdb.getStreamById(string_table_index) orelse return error.InvalidDebugInfo;
472 return error.InvalidDebugInfo;771 di.pdb.dbi = di.pdb.getStream(pdb.StreamType.Dbi) orelse return error.MissingDebugInfo;
473772
474 std.debug.warn("{}\n", hash_tbl_hdr);773 const dbi = di.pdb.dbi;
475774
476 const present = try readSparseBitVector(&pdb_stream.stream, allocator);775 // Dbi Header
477 if (present.len != hash_tbl_hdr.Size)776 var dbi_stream_header: pdb.DbiStreamHeader = undefined;
478 return error.InvalidDebugInfo;777 try dbi.stream.readStruct(pdb.DbiStreamHeader, &dbi_stream_header);
479 const deleted = try readSparseBitVector(&pdb_stream.stream, allocator);778 const mod_info_size = dbi_stream_header.ModInfoSize;
779 const section_contrib_size = dbi_stream_header.SectionContributionSize;
480780
481 const Bucket = struct {781 var modules = ArrayList(Module).init(allocator);
482 first: u32,782
483 second: u32,783 // Module Info Substream
484 };784 var mod_info_offset: usize = 0;
485 const bucket_list = try allocator.alloc(Bucket, present.len);785 while (mod_info_offset != mod_info_size) {
486 const string_table_index = for (present) |_| {786 var mod_info: pdb.ModInfo = undefined;
487 const name_offset = try pdb_stream.stream.readIntLe(u32);787 try dbi.stream.readStruct(pdb.ModInfo, &mod_info);
488 const name_index = try pdb_stream.stream.readIntLe(u32);788 var this_record_len: usize = @sizeOf(pdb.ModInfo);
489 const name = mem.toSlice(u8, name_bytes.ptr + name_offset);789
490 if (mem.eql(u8, name, "/names")) {790 const module_name = try dbi.readNullTermString(allocator);
491 break name_index;791 this_record_len += module_name.len + 1;
792
793 const obj_file_name = try dbi.readNullTermString(allocator);
794 this_record_len += obj_file_name.len + 1;
795
796 const march_forward_bytes = this_record_len % 4;
797 if (march_forward_bytes != 0) {
798 try dbi.seekForward(march_forward_bytes);
799 this_record_len += march_forward_bytes;
492 }800 }
493 } else return error.MissingDebugInfo;
494801
495 di.pdb.string_table = di.pdb.getStreamById(string_table_index) orelse return error.InvalidDebugInfo;802 try modules.append(Module{
803 .mod_info = mod_info,
804 .module_name = module_name,
805 .obj_file_name = obj_file_name,
806
807 .populated = false,
808 .symbols = undefined,
809 .subsect_info = undefined,
810 .checksums = undefined,
811 });
812
813 mod_info_offset += this_record_len;
814 if (mod_info_offset > mod_info_size)
815 return error.InvalidDebugInfo;
816 }
817
818 di.modules = modules.toOwnedSlice();
819
820 // Section Contribution Substream
821 var sect_contribs = ArrayList(pdb.SectionContribEntry).init(allocator);
822 var sect_cont_offset: usize = 0;
823 if (section_contrib_size != 0) {
824 const ver = @intToEnum(pdb.SectionContrSubstreamVersion, try dbi.stream.readIntLe(u32));
825 if (ver != pdb.SectionContrSubstreamVersion.Ver60)
826 return error.InvalidDebugInfo;
827 sect_cont_offset += @sizeOf(u32);
828 }
829 while (sect_cont_offset != section_contrib_size) {
830 const entry = try sect_contribs.addOne();
831 try dbi.stream.readStruct(pdb.SectionContribEntry, entry);
832 sect_cont_offset += @sizeOf(pdb.SectionContribEntry);
833
834 if (sect_cont_offset > section_contrib_size)
835 return error.InvalidDebugInfo;
836 }
837
838 di.sect_contribs = sect_contribs.toOwnedSlice();
496839
497 return di;840 return di;
498}841}
...@@ -715,6 +1058,8 @@ pub const DebugInfo = switch (builtin.os) {...@@ -715,6 +1058,8 @@ pub const DebugInfo = switch (builtin.os) {
715 builtin.Os.windows => struct {1058 builtin.Os.windows => struct {
716 pdb: pdb.Pdb,1059 pdb: pdb.Pdb,
717 coff: *coff.Coff,1060 coff: *coff.Coff,
1061 sect_contribs: []pdb.SectionContribEntry,
1062 modules: []Module,
718 },1063 },
719 builtin.Os.linux => struct {1064 builtin.Os.linux => struct {
720 self_exe_file: os.File,1065 self_exe_file: os.File,
std/os/windows/index.zig+13
...@@ -15,6 +15,7 @@ test "import" {...@@ -15,6 +15,7 @@ test "import" {
1515
16pub const ERROR = @import("error.zig");16pub const ERROR = @import("error.zig");
1717
18pub const SHORT = c_short;
18pub const BOOL = c_int;19pub const BOOL = c_int;
19pub const BOOLEAN = BYTE;20pub const BOOLEAN = BYTE;
20pub const BYTE = u8;21pub const BYTE = u8;
...@@ -364,3 +365,15 @@ pub const FILE_FLAG_RANDOM_ACCESS = 0x10000000;...@@ -364,3 +365,15 @@ pub const FILE_FLAG_RANDOM_ACCESS = 0x10000000;
364pub const FILE_FLAG_SESSION_AWARE = 0x00800000;365pub const FILE_FLAG_SESSION_AWARE = 0x00800000;
365pub const FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000;366pub const FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000;
366pub const FILE_FLAG_WRITE_THROUGH = 0x80000000;367pub const FILE_FLAG_WRITE_THROUGH = 0x80000000;
368
369pub const SMALL_RECT = extern struct {
370 Left: SHORT,
371 Top: SHORT,
372 Right: SHORT,
373 Bottom: SHORT,
374};
375
376pub const COORD = extern struct {
377 X: SHORT,
378 Y: SHORT,
379};
std/os/windows/kernel32.zig+18
...@@ -72,6 +72,8 @@ pub extern "kernel32" stdcallcc fn GetCommandLineA() LPSTR;...@@ -72,6 +72,8 @@ pub extern "kernel32" stdcallcc fn GetCommandLineA() LPSTR;
7272
73pub extern "kernel32" stdcallcc fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: *DWORD) BOOL;73pub extern "kernel32" stdcallcc fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: *DWORD) BOOL;
7474
75pub extern "kernel32" stdcallcc fn GetConsoleScreenBufferInfo(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: *CONSOLE_SCREEN_BUFFER_INFO) BOOL;
76
75pub extern "kernel32" stdcallcc fn GetCurrentDirectoryA(nBufferLength: DWORD, lpBuffer: ?[*]CHAR) DWORD;77pub extern "kernel32" stdcallcc fn GetCurrentDirectoryA(nBufferLength: DWORD, lpBuffer: ?[*]CHAR) DWORD;
76pub extern "kernel32" stdcallcc fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: ?[*]WCHAR) DWORD;78pub extern "kernel32" stdcallcc fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: ?[*]WCHAR) DWORD;
7779
...@@ -179,6 +181,8 @@ pub extern "kernel32" stdcallcc fn ReadFile(...@@ -179,6 +181,8 @@ pub extern "kernel32" stdcallcc fn ReadFile(
179181
180pub extern "kernel32" stdcallcc fn RemoveDirectoryA(lpPathName: LPCSTR) BOOL;182pub extern "kernel32" stdcallcc fn RemoveDirectoryA(lpPathName: LPCSTR) BOOL;
181183
184pub extern "kernel32" stdcallcc fn SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) BOOL;
185
182pub extern "kernel32" stdcallcc fn SetFilePointerEx(186pub extern "kernel32" stdcallcc fn SetFilePointerEx(
183 in_fFile: HANDLE,187 in_fFile: HANDLE,
184 in_liDistanceToMove: LARGE_INTEGER,188 in_liDistanceToMove: LARGE_INTEGER,
...@@ -234,3 +238,17 @@ pub const FILE_NOTIFY_CHANGE_LAST_WRITE = 16;...@@ -234,3 +238,17 @@ pub const FILE_NOTIFY_CHANGE_LAST_WRITE = 16;
234pub const FILE_NOTIFY_CHANGE_DIR_NAME = 2;238pub const FILE_NOTIFY_CHANGE_DIR_NAME = 2;
235pub const FILE_NOTIFY_CHANGE_FILE_NAME = 1;239pub const FILE_NOTIFY_CHANGE_FILE_NAME = 1;
236pub const FILE_NOTIFY_CHANGE_ATTRIBUTES = 4;240pub const FILE_NOTIFY_CHANGE_ATTRIBUTES = 4;
241
242
243pub const CONSOLE_SCREEN_BUFFER_INFO = extern struct {
244 dwSize: COORD,
245 dwCursorPosition: COORD,
246 wAttributes: WORD,
247 srWindow: SMALL_RECT,
248 dwMaximumWindowSize: COORD,
249};
250
251pub const FOREGROUND_BLUE = 1;
252pub const FOREGROUND_GREEN = 2;
253pub const FOREGROUND_RED = 4;
254pub const FOREGROUND_INTENSITY = 8;
std/pdb.zig+31-256
...@@ -10,7 +10,7 @@ const coff = std.coff;...@@ -10,7 +10,7 @@ const coff = std.coff;
10const ArrayList = std.ArrayList;10const ArrayList = std.ArrayList;
1111
12// https://llvm.org/docs/PDB/DbiStream.html#stream-header12// https://llvm.org/docs/PDB/DbiStream.html#stream-header
13const DbiStreamHeader = packed struct {13pub const DbiStreamHeader = packed struct {
14 VersionSignature: i32,14 VersionSignature: i32,
15 VersionHeader: u32,15 VersionHeader: u32,
16 Age: u32,16 Age: u32,
...@@ -33,7 +33,7 @@ const DbiStreamHeader = packed struct {...@@ -33,7 +33,7 @@ const DbiStreamHeader = packed struct {
33 Padding: u32,33 Padding: u32,
34};34};
3535
36const SectionContribEntry = packed struct {36pub const SectionContribEntry = packed struct {
37 Section: u16,37 Section: u16,
38 Padding1: [2]u8,38 Padding1: [2]u8,
39 Offset: u32,39 Offset: u32,
...@@ -45,7 +45,7 @@ const SectionContribEntry = packed struct {...@@ -45,7 +45,7 @@ const SectionContribEntry = packed struct {
45 RelocCrc: u32,45 RelocCrc: u32,
46};46};
4747
48const ModInfo = packed struct {48pub const ModInfo = packed struct {
49 Unused1: u32,49 Unused1: u32,
50 SectionContr: SectionContribEntry,50 SectionContr: SectionContribEntry,
51 Flags: u16,51 Flags: u16,
...@@ -63,12 +63,12 @@ const ModInfo = packed struct {...@@ -63,12 +63,12 @@ const ModInfo = packed struct {
63 //ObjFileName: char[],63 //ObjFileName: char[],
64};64};
6565
66const SectionMapHeader = packed struct {66pub const SectionMapHeader = packed struct {
67 Count: u16, /// Number of segment descriptors67 Count: u16, /// Number of segment descriptors
68 LogCount: u16, /// Number of logical segment descriptors68 LogCount: u16, /// Number of logical segment descriptors
69};69};
7070
71const SectionMapEntry = packed struct {71pub const SectionMapEntry = packed struct {
72 Flags: u16 , /// See the SectionMapEntryFlags enum below.72 Flags: u16 , /// See the SectionMapEntryFlags enum below.
73 Ovl: u16 , /// Logical overlay number73 Ovl: u16 , /// Logical overlay number
74 Group: u16 , /// Group index into descriptor array.74 Group: u16 , /// Group index into descriptor array.
...@@ -86,12 +86,6 @@ pub const StreamType = enum(u16) {...@@ -86,12 +86,6 @@ pub const StreamType = enum(u16) {
86 Ipi = 4,86 Ipi = 4,
87};87};
8888
89const Module = struct {
90 mod_info: ModInfo,
91 module_name: []u8,
92 obj_file_name: []u8,
93};
94
95/// Duplicate copy of SymbolRecordKind, but using the official CV names. Useful89/// Duplicate copy of SymbolRecordKind, but using the official CV names. Useful
96/// for reference purposes and when dealing with unknown record types.90/// for reference purposes and when dealing with unknown record types.
97pub const SymbolKind = packed enum(u16) {91pub const SymbolKind = packed enum(u16) {
...@@ -293,9 +287,9 @@ pub const SymbolKind = packed enum(u16) {...@@ -293,9 +287,9 @@ pub const SymbolKind = packed enum(u16) {
293 S_GTHREAD32 = 4371,287 S_GTHREAD32 = 4371,
294};288};
295289
296const TypeIndex = u32;290pub const TypeIndex = u32;
297291
298const ProcSym = packed struct {292pub const ProcSym = packed struct {
299 Parent: u32 ,293 Parent: u32 ,
300 End: u32 ,294 End: u32 ,
301 Next: u32 ,295 Next: u32 ,
...@@ -310,7 +304,7 @@ const ProcSym = packed struct {...@@ -310,7 +304,7 @@ const ProcSym = packed struct {
310 // Name: [*]u8,304 // Name: [*]u8,
311};305};
312306
313const ProcSymFlags = packed struct {307pub const ProcSymFlags = packed struct {
314 HasFP: bool,308 HasFP: bool,
315 HasIRET: bool,309 HasIRET: bool,
316 HasFRET: bool,310 HasFRET: bool,
...@@ -321,24 +315,24 @@ const ProcSymFlags = packed struct {...@@ -321,24 +315,24 @@ const ProcSymFlags = packed struct {
321 HasOptimizedDebugInfo: bool,315 HasOptimizedDebugInfo: bool,
322};316};
323317
324const SectionContrSubstreamVersion = enum(u32) {318pub const SectionContrSubstreamVersion = enum(u32) {
325 Ver60 = 0xeffe0000 + 19970605,319 Ver60 = 0xeffe0000 + 19970605,
326 V2 = 0xeffe0000 + 20140516320 V2 = 0xeffe0000 + 20140516
327};321};
328322
329const RecordPrefix = packed struct {323pub const RecordPrefix = packed struct {
330 RecordLen: u16, /// Record length, starting from &RecordKind.324 RecordLen: u16, /// Record length, starting from &RecordKind.
331 RecordKind: SymbolKind, /// Record kind enum (SymRecordKind or TypeRecordKind)325 RecordKind: SymbolKind, /// Record kind enum (SymRecordKind or TypeRecordKind)
332};326};
333327
334const LineFragmentHeader = packed struct {328pub const LineFragmentHeader = packed struct {
335 RelocOffset: u32, /// Code offset of line contribution.329 RelocOffset: u32, /// Code offset of line contribution.
336 RelocSegment: u16, /// Code segment of line contribution.330 RelocSegment: u16, /// Code segment of line contribution.
337 Flags: LineFlags,331 Flags: LineFlags,
338 CodeSize: u32, /// Code size of this line contribution.332 CodeSize: u32, /// Code size of this line contribution.
339};333};
340334
341const LineFlags = packed struct {335pub const LineFlags = packed struct {
342 LF_HaveColumns: bool, /// CV_LINES_HAVE_COLUMNS336 LF_HaveColumns: bool, /// CV_LINES_HAVE_COLUMNS
343 unused: u15,337 unused: u15,
344};338};
...@@ -347,7 +341,7 @@ const LineFlags = packed struct {...@@ -347,7 +341,7 @@ const LineFlags = packed struct {
347/// header. The structure definitions follow.341/// header. The structure definitions follow.
348/// LineNumberEntry Lines[NumLines];342/// LineNumberEntry Lines[NumLines];
349/// ColumnNumberEntry Columns[NumLines];343/// ColumnNumberEntry Columns[NumLines];
350const LineBlockFragmentHeader = packed struct {344pub const LineBlockFragmentHeader = packed struct {
351 /// Offset of FileChecksum entry in File345 /// Offset of FileChecksum entry in File
352 /// checksums buffer. The checksum entry then346 /// checksums buffer. The checksum entry then
353 /// contains another offset into the string347 /// contains another offset into the string
...@@ -358,7 +352,7 @@ const LineBlockFragmentHeader = packed struct {...@@ -358,7 +352,7 @@ const LineBlockFragmentHeader = packed struct {
358};352};
359353
360354
361const LineNumberEntry = packed struct {355pub const LineNumberEntry = packed struct {
362 Offset: u32, /// Offset to start of code bytes for line number356 Offset: u32, /// Offset to start of code bytes for line number
363 Flags: u32,357 Flags: u32,
364358
...@@ -370,19 +364,19 @@ const LineNumberEntry = packed struct {...@@ -370,19 +364,19 @@ const LineNumberEntry = packed struct {
370 };364 };
371};365};
372366
373const ColumnNumberEntry = packed struct {367pub const ColumnNumberEntry = packed struct {
374 StartColumn: u16,368 StartColumn: u16,
375 EndColumn: u16,369 EndColumn: u16,
376};370};
377371
378/// Checksum bytes follow.372/// Checksum bytes follow.
379const FileChecksumEntryHeader = packed struct {373pub const FileChecksumEntryHeader = packed struct {
380 FileNameOffset: u32, /// Byte offset of filename in global string table.374 FileNameOffset: u32, /// Byte offset of filename in global string table.
381 ChecksumSize: u8, /// Number of bytes of checksum.375 ChecksumSize: u8, /// Number of bytes of checksum.
382 ChecksumKind: u8, /// FileChecksumKind376 ChecksumKind: u8, /// FileChecksumKind
383};377};
384378
385const DebugSubsectionKind = packed enum(u32) {379pub const DebugSubsectionKind = packed enum(u32) {
386 None = 0,380 None = 0,
387 Symbols = 0xf1,381 Symbols = 0xf1,
388 Lines = 0xf2,382 Lines = 0xf2,
...@@ -402,11 +396,25 @@ const DebugSubsectionKind = packed enum(u32) {...@@ -402,11 +396,25 @@ const DebugSubsectionKind = packed enum(u32) {
402 CoffSymbolRVA = 0xfd,396 CoffSymbolRVA = 0xfd,
403};397};
404398
399
400pub const DebugSubsectionHeader = packed struct {
401 Kind: DebugSubsectionKind, /// codeview::DebugSubsectionKind enum
402 Length: u32, /// number of bytes occupied by this record.
403};
404
405
406pub const PDBStringTableHeader = packed struct {
407 Signature: u32, /// PDBStringTableSignature
408 HashVersion: u32, /// 1 or 2
409 ByteSize: u32, /// Number of bytes of names buffer.
410};
411
405pub const Pdb = struct {412pub const Pdb = struct {
406 in_file: os.File,413 in_file: os.File,
407 allocator: *mem.Allocator,414 allocator: *mem.Allocator,
408 coff: *coff.Coff,415 coff: *coff.Coff,
409 string_table: *MsfStream,416 string_table: *MsfStream,
417 dbi: *MsfStream,
410418
411 msf: Msf,419 msf: Msf,
412420
...@@ -428,230 +436,6 @@ pub const Pdb = struct {...@@ -428,230 +436,6 @@ pub const Pdb = struct {
428 const id = @enumToInt(stream);436 const id = @enumToInt(stream);
429 return self.getStreamById(id);437 return self.getStreamById(id);
430 }438 }
431
432 pub fn getSourceLine(self: *Pdb, address: usize) !void {
433 const dbi = self.getStream(StreamType.Dbi) orelse return error.InvalidDebugInfo;
434
435 // Dbi Header
436 var header: DbiStreamHeader = undefined;
437 try dbi.stream.readStruct(DbiStreamHeader, &header);
438 std.debug.warn("{}\n", header);
439 warn("after header dbi stream at {} (file offset)\n", dbi.getFilePos());
440
441 var modules = ArrayList(Module).init(self.allocator);
442
443 // Module Info Substream
444 var mod_info_offset: usize = 0;
445 while (mod_info_offset != header.ModInfoSize) {
446 var mod_info: ModInfo = undefined;
447 try dbi.stream.readStruct(ModInfo, &mod_info);
448 std.debug.warn("{}\n", mod_info);
449 var this_record_len: usize = @sizeOf(ModInfo);
450
451 const module_name = try dbi.readNullTermString(self.allocator);
452 std.debug.warn("module_name '{}'\n", module_name);
453 this_record_len += module_name.len + 1;
454
455 const obj_file_name = try dbi.readNullTermString(self.allocator);
456 std.debug.warn("obj_file_name '{}'\n", obj_file_name);
457 this_record_len += obj_file_name.len + 1;
458
459 const march_forward_bytes = this_record_len % 4;
460 if (march_forward_bytes != 0) {
461 try dbi.seekForward(march_forward_bytes);
462 this_record_len += march_forward_bytes;
463 }
464
465 try modules.append(Module{
466 .mod_info = mod_info,
467 .module_name = module_name,
468 .obj_file_name = obj_file_name,
469 });
470
471 mod_info_offset += this_record_len;
472 if (mod_info_offset > header.ModInfoSize)
473 return error.InvalidDebugInfo;
474 }
475
476 // Section Contribution Substream
477 var sect_contribs = ArrayList(SectionContribEntry).init(self.allocator);
478 std.debug.warn("looking at Section Contributinos now\n");
479 var sect_cont_offset: usize = 0;
480 if (header.SectionContributionSize != 0) {
481 const ver = @intToEnum(SectionContrSubstreamVersion, try dbi.stream.readIntLe(u32));
482 if (ver != SectionContrSubstreamVersion.Ver60)
483 return error.InvalidDebugInfo;
484 sect_cont_offset += @sizeOf(u32);
485 }
486 while (sect_cont_offset != header.SectionContributionSize) {
487 const entry = try sect_contribs.addOne();
488 try dbi.stream.readStruct(SectionContribEntry, entry);
489 std.debug.warn("{}\n", entry);
490 sect_cont_offset += @sizeOf(SectionContribEntry);
491
492 if (sect_cont_offset > header.SectionContributionSize)
493 return error.InvalidDebugInfo;
494 }
495 //std.debug.warn("looking at section map now\n");
496 //if (header.SectionMapSize == 0)
497 // return error.MissingDebugInfo;
498
499 //var sect_map_hdr: SectionMapHeader = undefined;
500 //try dbi.stream.readStruct(SectionMapHeader, &sect_map_hdr);
501
502 //const sect_entries = try self.allocator.alloc(SectionMapEntry, sect_map_hdr.Count);
503 //const as_bytes = @sliceToBytes(sect_entries);
504 //if (as_bytes.len + @sizeOf(SectionMapHeader) != header.SectionMapSize)
505 // return error.InvalidDebugInfo;
506 //try dbi.stream.readNoEof(as_bytes);
507
508 //for (sect_entries) |sect_entry| {
509 // std.debug.warn("{}\n", sect_entry);
510 //}
511
512 var coff_section: *coff.Section = undefined;
513 const mod_index = for (sect_contribs.toSlice()) |sect_contrib| {
514 coff_section = &self.coff.sections.toSlice()[sect_contrib.Section];
515 std.debug.warn("looking in coff name: {}\n", mem.toSliceConst(u8, &coff_section.header.name));
516
517 const vaddr_start = coff_section.header.virtual_address + sect_contrib.Offset;
518 const vaddr_end = vaddr_start + sect_contrib.Size;
519 if (address >= vaddr_start and address < vaddr_end) {
520 std.debug.warn("found sect contrib: {}\n", sect_contrib);
521 break sect_contrib.ModuleIndex;
522 }
523 } else return error.MissingDebugInfo;
524
525 const mod = &modules.toSlice()[mod_index];
526 const modi = self.getStreamById(mod.mod_info.ModuleSymStream) orelse return error.InvalidDebugInfo;
527
528 const signature = try modi.stream.readIntLe(u32);
529 if (signature != 4)
530 return error.InvalidDebugInfo;
531
532 const symbols = try self.allocator.alloc(u8, mod.mod_info.SymByteSize - 4);
533 std.debug.warn("read {} bytes of symbol info\n", symbols.len);
534 try modi.stream.readNoEof(symbols);
535 var symbol_i: usize = 0;
536 const proc_sym = while (symbol_i != symbols.len) {
537 const prefix = @ptrCast(*RecordPrefix, &symbols[symbol_i]);
538 if (prefix.RecordLen < 2)
539 return error.InvalidDebugInfo;
540 switch (prefix.RecordKind) {
541 SymbolKind.S_LPROC32 => {
542 const proc_sym = @ptrCast(*ProcSym, &symbols[symbol_i + @sizeOf(RecordPrefix)]);
543 const vaddr_start = coff_section.header.virtual_address + proc_sym.CodeOffset;
544 const vaddr_end = vaddr_start + proc_sym.CodeSize;
545 std.debug.warn(" {}\n", proc_sym);
546 if (address >= vaddr_start and address < vaddr_end) {
547 break proc_sym;
548 }
549 },
550 else => {},
551 }
552 symbol_i += prefix.RecordLen + @sizeOf(u16);
553 if (symbol_i > symbols.len)
554 return error.InvalidDebugInfo;
555 } else return error.MissingDebugInfo;
556
557 std.debug.warn("found in {s}: {}\n", @ptrCast([*]u8, proc_sym) + @sizeOf(ProcSym), proc_sym);
558
559 if (mod.mod_info.C11ByteSize != 0)
560 return error.InvalidDebugInfo;
561
562 if (mod.mod_info.C13ByteSize == 0) {
563 return error.MissingDebugInfo;
564 }
565
566 const subsect_info = try self.allocator.alloc(u8, mod.mod_info.C13ByteSize);
567 std.debug.warn("read C13 line info {} bytes\n", subsect_info.len);
568 const line_info_file_pos = modi.getFilePos();
569 try modi.stream.readNoEof(subsect_info);
570
571 const DebugSubsectionHeader = packed struct {
572 Kind: DebugSubsectionKind, /// codeview::DebugSubsectionKind enum
573 Length: u32, /// number of bytes occupied by this record.
574 };
575 var sect_offset: usize = 0;
576 var skip_len: usize = undefined;
577 var have_line_info: bool = false;
578 subsections: while (sect_offset != subsect_info.len) : (sect_offset += skip_len) {
579 const subsect_hdr = @ptrCast(*DebugSubsectionHeader, &subsect_info[sect_offset]);
580 skip_len = subsect_hdr.Length;
581 sect_offset += @sizeOf(DebugSubsectionHeader);
582
583 switch (subsect_hdr.Kind) {
584 DebugSubsectionKind.Lines => {
585 if (have_line_info)
586 continue :subsections;
587
588 var line_index: usize = sect_offset;
589
590 const line_hdr = @ptrCast(*LineFragmentHeader, &subsect_info[line_index]);
591 if (line_hdr.RelocSegment == 0) return error.MissingDebugInfo;
592 std.debug.warn("{}\n", line_hdr);
593 line_index += @sizeOf(LineFragmentHeader);
594
595 const block_hdr = @ptrCast(*LineBlockFragmentHeader, &subsect_info[line_index]);
596 std.debug.warn("{}\n", block_hdr);
597 line_index += @sizeOf(LineBlockFragmentHeader);
598
599 const has_column = line_hdr.Flags.LF_HaveColumns;
600 std.debug.warn("has column: {}\n", has_column);
601
602 const frag_vaddr_start = coff_section.header.virtual_address + line_hdr.RelocOffset;
603 const frag_vaddr_end = frag_vaddr_start + line_hdr.CodeSize;
604 if (address >= frag_vaddr_start and address < frag_vaddr_end) {
605 std.debug.warn("found line listing\n");
606 var line_i: usize = 0;
607 const start_line_index = line_index;
608 while (line_i < block_hdr.NumLines) : (line_i += 1) {
609 const line_num_entry = @ptrCast(*LineNumberEntry, &subsect_info[line_index]);
610 line_index += @sizeOf(LineNumberEntry);
611 const flags = @ptrCast(*LineNumberEntry.Flags, &line_num_entry.Flags);
612 std.debug.warn("{} {}\n", line_num_entry, flags);
613 const vaddr_start = frag_vaddr_start + line_num_entry.Offset;
614 const vaddr_end = if (flags.End == 0) frag_vaddr_end else vaddr_start + flags.End;
615 std.debug.warn("test {x} <= {x} < {x}\n", vaddr_start, address, vaddr_end);
616 if (address >= vaddr_start and address < vaddr_end) {
617 std.debug.warn("{} line {}\n", block_hdr.NameIndex, flags.Start);
618 if (has_column) {
619 line_index = start_line_index + @sizeOf(LineNumberEntry) * block_hdr.NumLines;
620 line_index += @sizeOf(ColumnNumberEntry) * line_i;
621 const col_num_entry = @ptrCast(*ColumnNumberEntry, &subsect_info[line_index]);
622 std.debug.warn("col {}\n", col_num_entry.StartColumn);
623 }
624 have_line_info = true;
625 continue :subsections;
626 }
627 }
628 return error.MissingDebugInfo;
629 }
630
631 },
632 DebugSubsectionKind.FileChecksums => {
633 var chksum_index: usize = sect_offset;
634
635 while (chksum_index != subsect_info.len) {
636 const chksum_hdr = @ptrCast(*FileChecksumEntryHeader, &subsect_info[chksum_index]);
637 std.debug.warn("{}\n", chksum_hdr);
638 const len = @sizeOf(FileChecksumEntryHeader) + chksum_hdr.ChecksumSize;
639 chksum_index += len + (len % 4);
640 if (chksum_index > subsect_info.len)
641 return error.InvalidDebugInfo;
642 }
643
644 },
645 else => {
646 std.debug.warn("ignore subsection {}\n", @tagName(subsect_hdr.Kind));
647 },
648 }
649
650 if (sect_offset > subsect_info.len)
651 return error.InvalidDebugInfo;
652 }
653 std.debug.warn("end subsections\n");
654 }
655};439};
656440
657// see https://llvm.org/docs/PDB/MsfFile.html441// see https://llvm.org/docs/PDB/MsfFile.html
...@@ -687,13 +471,11 @@ const Msf = struct {...@@ -687,13 +471,11 @@ const Msf = struct {
687 );471 );
688472
689 const stream_count = try self.directory.stream.readIntLe(u32);473 const stream_count = try self.directory.stream.readIntLe(u32);
690 warn("stream count {}\n", stream_count);
691474
692 const stream_sizes = try allocator.alloc(u32, stream_count);475 const stream_sizes = try allocator.alloc(u32, stream_count);
693 for (stream_sizes) |*s| {476 for (stream_sizes) |*s| {
694 const size = try self.directory.stream.readIntLe(u32);477 const size = try self.directory.stream.readIntLe(u32);
695 s.* = blockCountFromSize(size, superblock.BlockSize);478 s.* = blockCountFromSize(size, superblock.BlockSize);
696 warn("stream {}B {} blocks\n", size, s.*);
697 }479 }
698480
699 self.streams = try allocator.alloc(MsfStream, stream_count);481 self.streams = try allocator.alloc(MsfStream, stream_count);
...@@ -784,13 +566,10 @@ const MsfStream = struct {...@@ -784,13 +566,10 @@ const MsfStream = struct {
784 const in = &file_stream.stream;566 const in = &file_stream.stream;
785 try file.seekTo(pos);567 try file.seekTo(pos);
786568
787 warn("stream with blocks");
788 var i: u32 = 0;569 var i: u32 = 0;
789 while (i < block_count) : (i += 1) {570 while (i < block_count) : (i += 1) {
790 stream.blocks[i] = try in.readIntLe(u32);571 stream.blocks[i] = try in.readIntLe(u32);
791 warn(" {}", stream.blocks[i]);
792 }572 }
793 warn("\n");
794573
795 return stream;574 return stream;
796 }575 }
...@@ -812,10 +591,6 @@ const MsfStream = struct {...@@ -812,10 +591,6 @@ const MsfStream = struct {
812 var block = self.blocks[block_id];591 var block = self.blocks[block_id];
813 var offset = self.pos % self.block_size;592 var offset = self.pos % self.block_size;
814593
815 //std.debug.warn("seek {} read {}B: block_id={} block={} offset={}\n",
816 // block * self.block_size + offset,
817 // buffer.len, block_id, block, offset);
818
819 try self.in_file.seekTo(block * self.block_size + offset);594 try self.in_file.seekTo(block * self.block_size + offset);
820 var file_stream = io.FileInStream.init(self.in_file);595 var file_stream = io.FileInStream.init(self.in_file);
821 const in = &file_stream.stream;596 const in = &file_stream.stream;