authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-08-28 21:32:53-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-08-28 22:41:06-07:00
log43fbc37a490442ffcecf9817877f542251fee664
treefab48f93c108fbab1544edc6cdc772c8a070b1d7
parent7da9e4b35e710d6b94114a21017630c5f15940bd

std.debug.Pdb: migrate more towards new Reader API

There was some bug in this branch, and rather than diagnosing it, I fully finished porting over to new Reader API. Did it fix the bug?

3 files changed, 189 insertions(+), 170 deletions(-)

lib/std/Io/Reader.zig+2-2
...@@ -143,8 +143,8 @@ pub const failing: Reader = .{...@@ -143,8 +143,8 @@ pub const failing: Reader = .{
143143
144/// This is generally safe to `@constCast` because it has an empty buffer, so144/// This is generally safe to `@constCast` because it has an empty buffer, so
145/// there is not really a way to accidentally attempt mutation of these fields.145/// there is not really a way to accidentally attempt mutation of these fields.
146const ending_state: Reader = .fixed(&.{});146pub const ending_instance: Reader = .fixed(&.{});
147pub const ending: *Reader = @constCast(&ending_state);147pub const ending: *Reader = @constCast(&ending_instance);
148148
149pub fn limited(r: *Reader, limit: Limit, buffer: []u8) Limited {149pub fn limited(r: *Reader, limit: Limit, buffer: []u8) Limited {
150 return .init(r, limit, buffer);150 return .init(r, limit, buffer);
lib/std/debug/Pdb.zig+153-151
...@@ -6,7 +6,7 @@ const assert = std.debug.assert;...@@ -6,7 +6,7 @@ const assert = std.debug.assert;
66
7const Pdb = @This();7const Pdb = @This();
88
9in_file: File,9file_reader: *File.Reader,
10msf: Msf,10msf: Msf,
11allocator: Allocator,11allocator: Allocator,
12string_table: ?*MsfStream,12string_table: ?*MsfStream,
...@@ -36,31 +36,28 @@ pub const Module = struct {...@@ -36,31 +36,28 @@ pub const Module = struct {
36 }36 }
37};37};
3838
39pub fn init(allocator: Allocator, path: []const u8) !Pdb {39pub fn init(gpa: Allocator, file_reader: *File.Reader) !Pdb {
40 const file = try std.fs.cwd().openFile(path, .{});
41 errdefer file.close();
42
43 return .{40 return .{
44 .in_file = file,41 .file_reader = file_reader,
45 .allocator = allocator,42 .allocator = gpa,
46 .string_table = null,43 .string_table = null,
47 .dbi = null,44 .dbi = null,
48 .msf = try Msf.init(allocator, file),45 .msf = try Msf.init(gpa, file_reader),
49 .modules = &[_]Module{},46 .modules = &.{},
50 .sect_contribs = &[_]pdb.SectionContribEntry{},47 .sect_contribs = &.{},
51 .guid = undefined,48 .guid = undefined,
52 .age = undefined,49 .age = undefined,
53 };50 };
54}51}
5552
56pub fn deinit(self: *Pdb) void {53pub fn deinit(self: *Pdb) void {
57 self.in_file.close();54 const gpa = self.allocator;
58 self.msf.deinit(self.allocator);55 self.msf.deinit(gpa);
59 for (self.modules) |*module| {56 for (self.modules) |*module| {
60 module.deinit(self.allocator);57 module.deinit(gpa);
61 }58 }
62 self.allocator.free(self.modules);59 gpa.free(self.modules);
63 self.allocator.free(self.sect_contribs);60 gpa.free(self.sect_contribs);
64}61}
6562
66pub fn parseDbiStream(self: *Pdb) !void {63pub fn parseDbiStream(self: *Pdb) !void {
...@@ -68,11 +65,7 @@ pub fn parseDbiStream(self: *Pdb) !void {...@@ -68,11 +65,7 @@ pub fn parseDbiStream(self: *Pdb) !void {
68 return error.InvalidDebugInfo;65 return error.InvalidDebugInfo;
6966
70 const gpa = self.allocator;67 const gpa = self.allocator;
7168 const reader = &stream.interface;
72 const deprecated_reader = stream.reader();
73 var adapted_buffer: [1024]u8 = undefined;
74 var adapted_reader = deprecated_reader.adaptToNewApi(&adapted_buffer);
75 const reader = &adapted_reader.new_interface;
7669
77 const header = try reader.takeStruct(std.pdb.DbiStreamHeader, .little);70 const header = try reader.takeStruct(std.pdb.DbiStreamHeader, .little);
78 if (header.version_header != 19990903) // V70, only value observed by LLVM team71 if (header.version_header != 19990903) // V70, only value observed by LLVM team
...@@ -113,7 +106,7 @@ pub fn parseDbiStream(self: *Pdb) !void {...@@ -113,7 +106,7 @@ pub fn parseDbiStream(self: *Pdb) !void {
113 this_record_len += march_forward_bytes;106 this_record_len += march_forward_bytes;
114 }107 }
115108
116 try modules.append(Module{109 try modules.append(.{
117 .mod_info = mod_info,110 .mod_info = mod_info,
118 .module_name = try module_name.toOwnedSlice(),111 .module_name = try module_name.toOwnedSlice(),
119 .obj_file_name = try obj_file_name.toOwnedSlice(),112 .obj_file_name = try obj_file_name.toOwnedSlice(),
...@@ -156,29 +149,28 @@ pub fn parseDbiStream(self: *Pdb) !void {...@@ -156,29 +149,28 @@ pub fn parseDbiStream(self: *Pdb) !void {
156}149}
157150
158pub fn parseInfoStream(self: *Pdb) !void {151pub fn parseInfoStream(self: *Pdb) !void {
159 var stream = self.getStream(pdb.StreamType.pdb) orelse152 var stream = self.getStream(pdb.StreamType.pdb) orelse return error.InvalidDebugInfo;
160 return error.InvalidDebugInfo;153 const reader = &stream.interface;
161 const reader = stream.reader();
162154
163 // Parse the InfoStreamHeader.155 // Parse the InfoStreamHeader.
164 const version = try reader.readInt(u32, .little);156 const version = try reader.takeInt(u32, .little);
165 const signature = try reader.readInt(u32, .little);157 const signature = try reader.takeInt(u32, .little);
166 _ = signature;158 _ = signature;
167 const age = try reader.readInt(u32, .little);159 const age = try reader.takeInt(u32, .little);
168 const guid = try reader.readBytesNoEof(16);160 const guid = try reader.takeArray(16);
169161
170 if (version != 20000404) // VC70, only value observed by LLVM team162 if (version != 20000404) // VC70, only value observed by LLVM team
171 return error.UnknownPDBVersion;163 return error.UnknownPDBVersion;
172164
173 self.guid = guid;165 self.guid = guid.*;
174 self.age = age;166 self.age = age;
175167
168 const gpa = self.allocator;
169
176 // Find the string table.170 // Find the string table.
177 const string_table_index = str_tab_index: {171 const string_table_index = str_tab_index: {
178 const name_bytes_len = try reader.readInt(u32, .little);172 const name_bytes_len = try reader.takeInt(u32, .little);
179 const name_bytes = try self.allocator.alloc(u8, name_bytes_len);173 const name_bytes = try reader.readAlloc(gpa, name_bytes_len);
180 defer self.allocator.free(name_bytes);
181 try reader.readNoEof(name_bytes);
182174
183 const HashTableHeader = extern struct {175 const HashTableHeader = extern struct {
184 size: u32,176 size: u32,
...@@ -188,23 +180,23 @@ pub fn parseInfoStream(self: *Pdb) !void {...@@ -188,23 +180,23 @@ pub fn parseInfoStream(self: *Pdb) !void {
188 return cap * 2 / 3 + 1;180 return cap * 2 / 3 + 1;
189 }181 }
190 };182 };
191 const hash_tbl_hdr = try reader.readStruct(HashTableHeader);183 const hash_tbl_hdr = try reader.takeStruct(HashTableHeader, .little);
192 if (hash_tbl_hdr.capacity == 0)184 if (hash_tbl_hdr.capacity == 0)
193 return error.InvalidDebugInfo;185 return error.InvalidDebugInfo;
194186
195 if (hash_tbl_hdr.size > HashTableHeader.maxLoad(hash_tbl_hdr.capacity))187 if (hash_tbl_hdr.size > HashTableHeader.maxLoad(hash_tbl_hdr.capacity))
196 return error.InvalidDebugInfo;188 return error.InvalidDebugInfo;
197189
198 const present = try readSparseBitVector(&reader, self.allocator);190 const present = try readSparseBitVector(reader, gpa);
199 defer self.allocator.free(present);191 defer gpa.free(present);
200 if (present.len != hash_tbl_hdr.size)192 if (present.len != hash_tbl_hdr.size)
201 return error.InvalidDebugInfo;193 return error.InvalidDebugInfo;
202 const deleted = try readSparseBitVector(&reader, self.allocator);194 const deleted = try readSparseBitVector(reader, gpa);
203 defer self.allocator.free(deleted);195 defer gpa.free(deleted);
204196
205 for (present) |_| {197 for (present) |_| {
206 const name_offset = try reader.readInt(u32, .little);198 const name_offset = try reader.takeInt(u32, .little);
207 const name_index = try reader.readInt(u32, .little);199 const name_index = try reader.takeInt(u32, .little);
208 if (name_offset > name_bytes.len)200 if (name_offset > name_bytes.len)
209 return error.InvalidDebugInfo;201 return error.InvalidDebugInfo;
210 const name = std.mem.sliceTo(name_bytes[name_offset..], 0);202 const name = std.mem.sliceTo(name_bytes[name_offset..], 0);
...@@ -302,14 +294,12 @@ pub fn getLineNumberInfo(self: *Pdb, module: *Module, address: u64) !std.debug.S...@@ -302,14 +294,12 @@ pub fn getLineNumberInfo(self: *Pdb, module: *Module, address: u64) !std.debug.S
302 const strtab_offset = @sizeOf(pdb.StringTableHeader) + chksum_hdr.file_name_offset;294 const strtab_offset = @sizeOf(pdb.StringTableHeader) + chksum_hdr.file_name_offset;
303 try self.string_table.?.seekTo(strtab_offset);295 try self.string_table.?.seekTo(strtab_offset);
304 const source_file_name = s: {296 const source_file_name = s: {
305 const deprecated_reader = self.string_table.?.reader();297 const string_reader = &self.string_table.?.interface;
306 var adapted_buffer: [1024]u8 = undefined;
307 var adapted_reader = deprecated_reader.adaptToNewApi(&adapted_buffer);
308 var source_file_name: std.Io.Writer.Allocating = .init(gpa);298 var source_file_name: std.Io.Writer.Allocating = .init(gpa);
309 defer source_file_name.deinit();299 defer source_file_name.deinit();
310 _ = try adapted_reader.new_interface.streamDelimiterLimit(&source_file_name.writer, 0, .limited(1024));300 _ = try string_reader.streamDelimiterLimit(&source_file_name.writer, 0, .limited(1024));
311 assert(adapted_reader.new_interface.buffered()[0] == 0); // TODO change streamDelimiterLimit API301 assert(string_reader.buffered()[0] == 0); // TODO change streamDelimiterLimit API
312 adapted_reader.new_interface.toss(1);302 string_reader.toss(1);
313 break :s try source_file_name.toOwnedSlice();303 break :s try source_file_name.toOwnedSlice();
314 };304 };
315 errdefer gpa.free(source_file_name);305 errdefer gpa.free(source_file_name);
...@@ -366,19 +356,16 @@ pub fn getModule(self: *Pdb, index: usize) !?*Module {...@@ -366,19 +356,16 @@ pub fn getModule(self: *Pdb, index: usize) !?*Module {
366356
367 const stream = self.getStreamById(mod.mod_info.module_sym_stream) orelse357 const stream = self.getStreamById(mod.mod_info.module_sym_stream) orelse
368 return error.MissingDebugInfo;358 return error.MissingDebugInfo;
369 const reader = stream.reader();359 const reader = &stream.interface;
370360
371 const signature = try reader.readInt(u32, .little);361 const signature = try reader.takeInt(u32, .little);
372 if (signature != 4)362 if (signature != 4)
373 return error.InvalidDebugInfo;363 return error.InvalidDebugInfo;
374364
375 mod.symbols = try self.allocator.alloc(u8, mod.mod_info.sym_byte_size - 4);365 const gpa = self.allocator;
376 errdefer self.allocator.free(mod.symbols);
377 try reader.readNoEof(mod.symbols);
378366
379 mod.subsect_info = try self.allocator.alloc(u8, mod.mod_info.c13_byte_size);367 mod.symbols = try reader.readAlloc(gpa, mod.mod_info.sym_byte_size - 4);
380 errdefer self.allocator.free(mod.subsect_info);368 mod.subsect_info = try reader.readAlloc(gpa, mod.mod_info.c13_byte_size);
381 try reader.readNoEof(mod.subsect_info);
382369
383 var sect_offset: usize = 0;370 var sect_offset: usize = 0;
384 var skip_len: usize = undefined;371 var skip_len: usize = undefined;
...@@ -404,8 +391,7 @@ pub fn getModule(self: *Pdb, index: usize) !?*Module {...@@ -404,8 +391,7 @@ pub fn getModule(self: *Pdb, index: usize) !?*Module {
404}391}
405392
406pub fn getStreamById(self: *Pdb, id: u32) ?*MsfStream {393pub fn getStreamById(self: *Pdb, id: u32) ?*MsfStream {
407 if (id >= self.msf.streams.len)394 if (id >= self.msf.streams.len) return null;
408 return null;
409 return &self.msf.streams[id];395 return &self.msf.streams[id];
410}396}
411397
...@@ -419,17 +405,14 @@ const Msf = struct {...@@ -419,17 +405,14 @@ const Msf = struct {
419 directory: MsfStream,405 directory: MsfStream,
420 streams: []MsfStream,406 streams: []MsfStream,
421407
422 fn init(allocator: Allocator, file: File) !Msf {408 fn init(gpa: Allocator, file_reader: *File.Reader) !Msf {
423 const in = file.deprecatedReader();409 const superblock = try file_reader.interface.takeStruct(pdb.SuperBlock, .little);
424
425 const superblock = try in.readStruct(pdb.SuperBlock);
426410
427 // Sanity checks
428 if (!std.mem.eql(u8, &superblock.file_magic, pdb.SuperBlock.expect_magic))411 if (!std.mem.eql(u8, &superblock.file_magic, pdb.SuperBlock.expect_magic))
429 return error.InvalidDebugInfo;412 return error.InvalidDebugInfo;
430 if (superblock.free_block_map_block != 1 and superblock.free_block_map_block != 2)413 if (superblock.free_block_map_block != 1 and superblock.free_block_map_block != 2)
431 return error.InvalidDebugInfo;414 return error.InvalidDebugInfo;
432 const file_len = try file.getEndPos();415 const file_len = try file_reader.getSize();
433 if (superblock.num_blocks * superblock.block_size != file_len)416 if (superblock.num_blocks * superblock.block_size != file_len)
434 return error.InvalidDebugInfo;417 return error.InvalidDebugInfo;
435 switch (superblock.block_size) {418 switch (superblock.block_size) {
...@@ -442,163 +425,182 @@ const Msf = struct {...@@ -442,163 +425,182 @@ const Msf = struct {
442 if (dir_block_count > superblock.block_size / @sizeOf(u32))425 if (dir_block_count > superblock.block_size / @sizeOf(u32))
443 return error.UnhandledBigDirectoryStream; // cf. BlockMapAddr comment.426 return error.UnhandledBigDirectoryStream; // cf. BlockMapAddr comment.
444427
445 try file.seekTo(superblock.block_size * superblock.block_map_addr);428 try file_reader.seekTo(superblock.block_size * superblock.block_map_addr);
446 const dir_blocks = try allocator.alloc(u32, dir_block_count);429 const dir_blocks = try gpa.alloc(u32, dir_block_count);
447 for (dir_blocks) |*b| {430 for (dir_blocks) |*b| {
448 b.* = try in.readInt(u32, .little);431 b.* = try file_reader.interface.takeInt(u32, .little);
449 }432 }
450 var directory = MsfStream.init(433 var directory_buffer: [64]u8 = undefined;
451 superblock.block_size,434 var directory = MsfStream.init(superblock.block_size, file_reader, dir_blocks, &directory_buffer);
452 file,
453 dir_blocks,
454 );
455435
456 const begin = directory.pos;436 const begin = directory.logicalPos();
457 const stream_count = try directory.reader().readInt(u32, .little);437 const stream_count = try directory.interface.takeInt(u32, .little);
458 const stream_sizes = try allocator.alloc(u32, stream_count);438 const stream_sizes = try gpa.alloc(u32, stream_count);
459 defer allocator.free(stream_sizes);439 defer gpa.free(stream_sizes);
460440
461 // Microsoft's implementation uses @as(u32, -1) for inexistent streams.441 // Microsoft's implementation uses @as(u32, -1) for inexistent streams.
462 // These streams are not used, but still participate in the file442 // These streams are not used, but still participate in the file
463 // and must be taken into account when resolving stream indices.443 // and must be taken into account when resolving stream indices.
464 const Nil = 0xFFFFFFFF;444 const nil_size = 0xFFFFFFFF;
465 for (stream_sizes) |*s| {445 for (stream_sizes) |*s| {
466 const size = try directory.reader().readInt(u32, .little);446 const size = try directory.interface.takeInt(u32, .little);
467 s.* = if (size == Nil) 0 else blockCountFromSize(size, superblock.block_size);447 s.* = if (size == nil_size) 0 else blockCountFromSize(size, superblock.block_size);
468 }448 }
469449
470 const streams = try allocator.alloc(MsfStream, stream_count);450 const streams = try gpa.alloc(MsfStream, stream_count);
451 errdefer gpa.free(streams);
452
471 for (streams, 0..) |*stream, i| {453 for (streams, 0..) |*stream, i| {
472 const size = stream_sizes[i];454 const size = stream_sizes[i];
473 if (size == 0) {455 if (size == 0) {
474 stream.* = MsfStream{456 stream.* = .empty;
475 .blocks = &[_]u32{},
476 };
477 } else {457 } else {
478 var blocks = try allocator.alloc(u32, size);458 const blocks = try gpa.alloc(u32, size);
479 var j: u32 = 0;459 errdefer gpa.free(blocks);
480 while (j < size) : (j += 1) {460 for (blocks) |*block| {
481 const block_id = try directory.reader().readInt(u32, .little);461 const block_id = try directory.interface.takeInt(u32, .little);
482 const n = (block_id % superblock.block_size);462 const n = (block_id % superblock.block_size);
483 // 0 is for pdb.SuperBlock, 1 and 2 for FPMs.463 // 0 is for pdb.SuperBlock, 1 and 2 for FPMs.
484 if (block_id == 0 or n == 1 or n == 2 or block_id * superblock.block_size > file_len)464 if (block_id == 0 or n == 1 or n == 2 or block_id * superblock.block_size > file_len)
485 return error.InvalidBlockIndex;465 return error.InvalidBlockIndex;
486 blocks[j] = block_id;466 block.* = block_id;
487 }467 }
488468 const buffer = try gpa.alloc(u8, 64);
489 stream.* = MsfStream.init(469 errdefer gpa.free(buffer);
490 superblock.block_size,470 stream.* = .init(superblock.block_size, file_reader, blocks, buffer);
491 file,
492 blocks,
493 );
494 }471 }
495 }472 }
496473
497 const end = directory.pos;474 const end = directory.logicalPos();
498 if (end - begin != superblock.num_directory_bytes)475 if (end - begin != superblock.num_directory_bytes)
499 return error.InvalidStreamDirectory;476 return error.InvalidStreamDirectory;
500477
501 return Msf{478 return .{
502 .directory = directory,479 .directory = directory,
503 .streams = streams,480 .streams = streams,
504 };481 };
505 }482 }
506483
507 fn deinit(self: *Msf, allocator: Allocator) void {484 fn deinit(self: *Msf, gpa: Allocator) void {
508 allocator.free(self.directory.blocks);485 gpa.free(self.directory.blocks);
509 for (self.streams) |*stream| {486 for (self.streams) |*stream| {
510 allocator.free(stream.blocks);487 gpa.free(stream.interface.buffer);
488 gpa.free(stream.blocks);
511 }489 }
512 allocator.free(self.streams);490 gpa.free(self.streams);
513 }491 }
514};492};
515493
516const MsfStream = struct {494const MsfStream = struct {
517 in_file: File = undefined,495 file_reader: *File.Reader,
518 pos: u64 = undefined,496 next_read_pos: u64,
519 blocks: []u32 = undefined,497 blocks: []u32,
520 block_size: u32 = undefined,498 block_size: u32,
521499 interface: std.Io.Reader,
522 pub const Error = @typeInfo(@typeInfo(@TypeOf(read)).@"fn".return_type.?).error_union.error_set;500 err: ?Error,
501
502 const Error = File.Reader.SeekError;
503
504 const empty: MsfStream = .{
505 .file_reader = undefined,
506 .next_read_pos = 0,
507 .blocks = &.{},
508 .block_size = undefined,
509 .interface = .ending_instance,
510 .err = null,
511 };
523512
524 fn init(block_size: u32, file: File, blocks: []u32) MsfStream {513 fn init(block_size: u32, file_reader: *File.Reader, blocks: []u32, buffer: []u8) MsfStream {
525 const stream = MsfStream{514 return .{
526 .in_file = file,515 .file_reader = file_reader,
527 .pos = 0,516 .next_read_pos = 0,
528 .blocks = blocks,517 .blocks = blocks,
529 .block_size = block_size,518 .block_size = block_size,
519 .interface = .{
520 .vtable = &.{ .stream = stream },
521 .buffer = buffer,
522 .seek = 0,
523 .end = 0,
524 },
525 .err = null,
530 };526 };
531
532 return stream;
533 }527 }
534528
535 fn read(self: *MsfStream, buffer: []u8) !usize {529 fn stream(r: *std.Io.Reader, w: *std.Io.Writer, limit: std.Io.Limit) std.Io.Reader.StreamError!usize {
536 var block_id = @as(usize, @intCast(self.pos / self.block_size));530 const ms: *MsfStream = @alignCast(@fieldParentPtr("interface", r));
537 if (block_id >= self.blocks.len) return 0; // End of Stream
538 var block = self.blocks[block_id];
539 var offset = self.pos % self.block_size;
540531
541 try self.in_file.seekTo(block * self.block_size + offset);532 var block_id: usize = @intCast(ms.next_read_pos / ms.block_size);
542 const in = self.in_file.deprecatedReader();533 if (block_id >= ms.blocks.len) return error.EndOfStream;
534 var block = ms.blocks[block_id];
535 var offset = ms.next_read_pos % ms.block_size;
543536
544 var size: usize = 0;537 ms.file_reader.seekTo(block * ms.block_size + offset) catch |err| {
545 var rem_buffer = buffer;538 ms.err = err;
546 while (size < buffer.len) {539 return error.ReadFailed;
547 const size_to_read = @min(self.block_size - offset, rem_buffer.len);540 };
548 size += try in.read(rem_buffer[0..size_to_read]);541
549 rem_buffer = buffer[size..];542 var remaining = @intFromEnum(limit);
550 offset += size_to_read;543 while (remaining != 0) {
544 const stream_len: usize = @min(remaining, ms.block_size - offset);
545 const n = try ms.file_reader.interface.stream(w, .limited(stream_len));
546 remaining -= n;
547 offset += n;
551548
552 // If we're at the end of a block, go to the next one.549 // If we're at the end of a block, go to the next one.
553 if (offset == self.block_size) {550 if (offset == ms.block_size) {
554 offset = 0;551 offset = 0;
555 block_id += 1;552 block_id += 1;
556 if (block_id >= self.blocks.len) break; // End of Stream553 if (block_id >= ms.blocks.len) break; // End of Stream
557 block = self.blocks[block_id];554 block = ms.blocks[block_id];
558 try self.in_file.seekTo(block * self.block_size);555 ms.file_reader.seekTo(block * ms.block_size) catch |err| {
556 ms.err = err;
557 return error.ReadFailed;
558 };
559 }559 }
560 }560 }
561561
562 self.pos += buffer.len;562 const total = @intFromEnum(limit) - remaining;
563 return buffer.len;563 ms.next_read_pos += total;
564 return total;
564 }565 }
565566
566 pub fn seekBy(self: *MsfStream, len: i64) !void {567 pub fn logicalPos(ms: *const MsfStream) u64 {
567 self.pos = @as(u64, @intCast(@as(i64, @intCast(self.pos)) + len));568 return ms.next_read_pos - ms.interface.bufferedLen();
568 if (self.pos >= self.blocks.len * self.block_size)
569 return error.EOF;
570 }569 }
571570
572 pub fn seekTo(self: *MsfStream, len: u64) !void {571 pub fn seekBy(ms: *MsfStream, len: i64) !void {
573 self.pos = len;572 ms.next_read_pos = @as(u64, @intCast(@as(i64, @intCast(ms.logicalPos())) + len));
574 if (self.pos >= self.blocks.len * self.block_size)573 if (ms.next_read_pos >= ms.blocks.len * ms.block_size) return error.EOF;
575 return error.EOF;574 ms.interface.tossBuffered();
576 }575 }
577576
578 fn getSize(self: *const MsfStream) u64 {577 pub fn seekTo(ms: *MsfStream, len: u64) !void {
579 return self.blocks.len * self.block_size;578 ms.next_read_pos = len;
579 if (ms.next_read_pos >= ms.blocks.len * ms.block_size) return error.EOF;
580 ms.interface.tossBuffered();
580 }581 }
581582
582 fn getFilePos(self: MsfStream) u64 {583 fn getSize(ms: *const MsfStream) u64 {
583 const block_id = self.pos / self.block_size;584 return ms.blocks.len * ms.block_size;
584 const block = self.blocks[block_id];
585 const offset = self.pos % self.block_size;
586
587 return block * self.block_size + offset;
588 }585 }
589586
590 pub fn reader(self: *MsfStream) std.io.GenericReader(*MsfStream, Error, read) {587 fn getFilePos(ms: *const MsfStream) u64 {
591 return .{ .context = self };588 const pos = ms.logicalPos();
589 const block_id = pos / ms.block_size;
590 const block = ms.blocks[block_id];
591 const offset = pos % ms.block_size;
592
593 return block * ms.block_size + offset;
592 }594 }
593};595};
594596
595fn readSparseBitVector(stream: anytype, allocator: Allocator) ![]u32 {597fn readSparseBitVector(reader: *std.Io.Reader, allocator: Allocator) ![]u32 {
596 const num_words = try stream.readInt(u32, .little);598 const num_words = try reader.takeInt(u32, .little);
597 var list = std.array_list.Managed(u32).init(allocator);599 var list = std.array_list.Managed(u32).init(allocator);
598 errdefer list.deinit();600 errdefer list.deinit();
599 var word_i: u32 = 0;601 var word_i: u32 = 0;
600 while (word_i != num_words) : (word_i += 1) {602 while (word_i != num_words) : (word_i += 1) {
601 const word = try stream.readInt(u32, .little);603 const word = try reader.takeInt(u32, .little);
602 var bit_i: u5 = 0;604 var bit_i: u5 = 0;
603 while (true) : (bit_i += 1) {605 while (true) : (bit_i += 1) {
604 if (word & (@as(u32, 1) << bit_i) != 0) {606 if (word & (@as(u32, 1) << bit_i) != 0) {
lib/std/debug/SelfInfo.zig+34-17
...@@ -713,22 +713,26 @@ pub const Module = switch (native_os) {...@@ -713,22 +713,26 @@ pub const Module = switch (native_os) {
713 },713 },
714 .uefi, .windows => struct {714 .uefi, .windows => struct {
715 base_address: usize,715 base_address: usize,
716 pdb: ?Pdb = null,716 pdb: ?Pdb,
717 dwarf: ?Dwarf = null,717 dwarf: ?Dwarf,
718 coff_image_base: u64,718 coff_image_base: u64,
719719
720 /// Only used if pdb is non-null720 /// Only used if pdb is non-null
721 coff_section_headers: []coff.SectionHeader,721 coff_section_headers: []coff.SectionHeader,
722722
723 pub fn deinit(self: *@This(), allocator: Allocator) void {723 pub fn deinit(self: *@This(), gpa: Allocator) void {
724 if (self.dwarf) |*dwarf| {724 if (self.dwarf) |*dwarf| {
725 dwarf.deinit(allocator);725 dwarf.deinit(gpa);
726 }726 }
727727
728 if (self.pdb) |*p| {728 if (self.pdb) |*p| {
729 gpa.free(p.file_reader.interface.buffer);
730 gpa.destroy(p.file_reader);
729 p.deinit();731 p.deinit();
730 allocator.free(self.coff_section_headers);732 gpa.free(self.coff_section_headers);
731 }733 }
734
735 self.* = undefined;
732 }736 }
733737
734 fn getSymbolFromPdb(self: *@This(), relocated_address: usize) !?std.debug.Symbol {738 fn getSymbolFromPdb(self: *@This(), relocated_address: usize) !?std.debug.Symbol {
...@@ -970,23 +974,25 @@ fn readMachODebugInfo(allocator: Allocator, macho_file: File) !Module {...@@ -970,23 +974,25 @@ fn readMachODebugInfo(allocator: Allocator, macho_file: File) !Module {
970 };974 };
971}975}
972976
973fn readCoffDebugInfo(allocator: Allocator, coff_obj: *coff.Coff) !Module {977fn readCoffDebugInfo(gpa: Allocator, coff_obj: *coff.Coff) !Module {
974 nosuspend {978 nosuspend {
975 var di: Module = .{979 var di: Module = .{
976 .base_address = undefined,980 .base_address = undefined,
977 .coff_image_base = coff_obj.getImageBase(),981 .coff_image_base = coff_obj.getImageBase(),
978 .coff_section_headers = undefined,982 .coff_section_headers = undefined,
983 .pdb = null,
984 .dwarf = null,
979 };985 };
980986
981 if (coff_obj.getSectionByName(".debug_info")) |_| {987 if (coff_obj.getSectionByName(".debug_info")) |_| {
982 // This coff file has embedded DWARF debug info988 // This coff file has embedded DWARF debug info
983 var sections: Dwarf.SectionArray = Dwarf.null_section_array;989 var sections: Dwarf.SectionArray = Dwarf.null_section_array;
984 errdefer for (sections) |section| if (section) |s| if (s.owned) allocator.free(s.data);990 errdefer for (sections) |section| if (section) |s| if (s.owned) gpa.free(s.data);
985991
986 inline for (@typeInfo(Dwarf.Section.Id).@"enum".fields, 0..) |section, i| {992 inline for (@typeInfo(Dwarf.Section.Id).@"enum".fields, 0..) |section, i| {
987 sections[i] = if (coff_obj.getSectionByName("." ++ section.name)) |section_header| blk: {993 sections[i] = if (coff_obj.getSectionByName("." ++ section.name)) |section_header| blk: {
988 break :blk .{994 break :blk .{
989 .data = try coff_obj.getSectionDataAlloc(section_header, allocator),995 .data = try coff_obj.getSectionDataAlloc(section_header, gpa),
990 .virtual_address = section_header.virtual_address,996 .virtual_address = section_header.virtual_address,
991 .owned = true,997 .owned = true,
992 };998 };
...@@ -999,7 +1005,7 @@ fn readCoffDebugInfo(allocator: Allocator, coff_obj: *coff.Coff) !Module {...@@ -999,7 +1005,7 @@ fn readCoffDebugInfo(allocator: Allocator, coff_obj: *coff.Coff) !Module {
999 .is_macho = false,1005 .is_macho = false,
1000 };1006 };
10011007
1002 try Dwarf.open(&dwarf, allocator);1008 try Dwarf.open(&dwarf, gpa);
1003 di.dwarf = dwarf;1009 di.dwarf = dwarf;
1004 }1010 }
10051011
...@@ -1008,20 +1014,31 @@ fn readCoffDebugInfo(allocator: Allocator, coff_obj: *coff.Coff) !Module {...@@ -1008,20 +1014,31 @@ fn readCoffDebugInfo(allocator: Allocator, coff_obj: *coff.Coff) !Module {
1008 if (fs.path.isAbsolute(raw_path)) {1014 if (fs.path.isAbsolute(raw_path)) {
1009 break :blk raw_path;1015 break :blk raw_path;
1010 } else {1016 } else {
1011 const self_dir = try fs.selfExeDirPathAlloc(allocator);1017 const self_dir = try fs.selfExeDirPathAlloc(gpa);
1012 defer allocator.free(self_dir);1018 defer gpa.free(self_dir);
1013 break :blk try fs.path.join(allocator, &.{ self_dir, raw_path });1019 break :blk try fs.path.join(gpa, &.{ self_dir, raw_path });
1014 }1020 }
1015 };1021 };
1016 defer if (path.ptr != raw_path.ptr) allocator.free(path);1022 defer if (path.ptr != raw_path.ptr) gpa.free(path);
10171023
1018 di.pdb = Pdb.init(allocator, path) catch |err| switch (err) {1024 const pdb_file = std.fs.cwd().openFile(path, .{}) catch |err| switch (err) {
1019 error.FileNotFound, error.IsDir => {1025 error.FileNotFound, error.IsDir => {
1020 if (di.dwarf == null) return error.MissingDebugInfo;1026 if (di.dwarf == null) return error.MissingDebugInfo;
1021 return di;1027 return di;
1022 },1028 },
1023 else => return err,1029 else => |e| return e,
1024 };1030 };
1031 errdefer pdb_file.close();
1032
1033 const pdb_file_reader_buffer = try gpa.alloc(u8, 4096);
1034 errdefer gpa.free(pdb_file_reader_buffer);
1035
1036 const pdb_file_reader = try gpa.create(File.Reader);
1037 errdefer gpa.destroy(pdb_file_reader);
1038
1039 pdb_file_reader.* = pdb_file.reader(pdb_file_reader_buffer);
1040
1041 di.pdb = try Pdb.init(gpa, pdb_file_reader);
1025 try di.pdb.?.parseInfoStream();1042 try di.pdb.?.parseInfoStream();
1026 try di.pdb.?.parseDbiStream();1043 try di.pdb.?.parseDbiStream();
10271044
...@@ -1029,8 +1046,8 @@ fn readCoffDebugInfo(allocator: Allocator, coff_obj: *coff.Coff) !Module {...@@ -1029,8 +1046,8 @@ fn readCoffDebugInfo(allocator: Allocator, coff_obj: *coff.Coff) !Module {
1029 return error.InvalidDebugInfo;1046 return error.InvalidDebugInfo;
10301047
1031 // Only used by the pdb path1048 // Only used by the pdb path
1032 di.coff_section_headers = try coff_obj.getSectionHeadersAlloc(allocator);1049 di.coff_section_headers = try coff_obj.getSectionHeadersAlloc(gpa);
1033 errdefer allocator.free(di.coff_section_headers);1050 errdefer gpa.free(di.coff_section_headers);
10341051
1035 return di;1052 return di;
1036 }1053 }