authorgravatar for mason@gamesbymason.comMason Remaley <mason@gamesbymason.com> 2026-04-11 01:01:22-07:00
committergravatar for mason@gamesbymason.comMason Remaley <mason@gamesbymason.com> 2026-04-12 04:01:30-07:00
log334f40576e48e7204455f264c883f9ea86588e1a
treeca7043b94d43e493c16ed91e16593806bcdb0da0
parent4efbb27aa2b841357c03d6ab158418ccad022415

Cleans up some PDB parsing logic


1 files changed, 34 insertions(+), 29 deletions(-)

lib/std/debug/Pdb.zig+34-29
......@@ -315,6 +315,21 @@ pub const BinaryAnnotation = union(enum) {
315315 file_id: ?u32,
316316 code_offset: u32,
317317 code_length: ?u32,
318
319 /// Resolves a partial range to a range with a definite length, or returns null if this
320 /// is not possible.
321 fn resolve(self: PartialRange, next_code_offset: ?u32) ?Range {
322 return .{
323 .line_offset = self.line_offset,
324 .file_id = self.file_id,
325 .code_offset = self.code_offset,
326 .code_length = b: {
327 if (self.code_length) |l| break :b l;
328 const end = next_code_offset orelse return null;
329 break :b end - self.code_offset;
330 },
331 };
332 }
318333 };
319334
320335 pub fn init(annotations: Iterator) RangeIterator {
......@@ -391,6 +406,8 @@ pub const BinaryAnnotation = union(enum) {
391406 },
392407 }
393408
409 // If we have a new code offset, return the previous range if it exists, resolving
410 // its length if necessary.
394411 switch (annotation) {
395412 .change_code_offset,
396413 .change_code_offset_and_line_offset,
......@@ -398,38 +415,16 @@ pub const BinaryAnnotation = union(enum) {
398415 => {},
399416 else => continue,
400417 }
401
402 if (self.prev) |*prev| {
403 if (prev.code_length == null) {
404 prev.code_length = self.curr.code_offset - prev.code_offset;
405 }
406 }
407
408 defer self.prev = .{
409 .code_offset = self.curr.code_offset,
410 .code_length = self.curr.code_length,
411 .line_offset = self.curr.line_offset,
412 .file_id = self.curr.file_id,
413 };
418 defer self.prev = self.curr;
414419 const prev = self.prev orelse continue;
415 const prev_code_length = prev.code_length orelse continue;
416 return .{
417 .code_offset = prev.code_offset,
418 .code_length = prev_code_length,
419 .line_offset = prev.line_offset,
420 .file_id = prev.file_id,
421 };
420 return prev.resolve(self.curr.code_offset);
422421 }
423422
423 // If we've processed all the binary operations but still have a previous range leftover
424 // with a known length, return it.
424425 const prev = self.prev orelse return null;
425426 defer self.prev = null;
426 const prev_code_length = prev.code_length orelse return null;
427 return .{
428 .code_offset = prev.code_offset,
429 .code_length = prev_code_length,
430 .line_offset = prev.line_offset,
431 .file_id = prev.file_id,
432 };
427 return prev.resolve(null);
433428 }
434429 };
435430
......@@ -452,6 +447,10 @@ pub const BinaryAnnotation = union(enum) {
452447 try takePackedU32(reader),
453448 ) orelse return error.ReadFailed;
454449 switch (op) {
450 // Microsoft's docs say that invalid is used as padding, though it is left ambiguous
451 // whether padding is allowed internally or only after all instructions are complete.
452 // Empircally, the latter appears to be the case, at lest with the output from LLVM that
453 // I've tested.
455454 .invalid => return error.EndOfStream,
456455 .code_offset => return .{
457456 .code_offset = try expect(takePackedU32(reader)),
......@@ -547,13 +546,19 @@ pub const BinaryAnnotation = union(enum) {
547546};
548547
549548pub fn findInlineeName(self: *const Pdb, inlinee: u32) ?[]const u8 {
549 // According to LLVM, the high bit *can* be used to indicate that a type index comes from the
550 // ipi stream in which case that bit needs to be cleared. LLVM doesn't generate data in this
551 // manner, but we may as well handle it since it just involves a single bitwise and.
552 // https://llvm.org/docs/PDB/TpiStream.html#type-indices
553 const type_index = inlinee & 0x7FFFFFFF;
554
550555 var reader: Io.Reader = .fixed(self.ipi orelse return null);
551556 const header = reader.takeStructPointer(pdb.IpiStreamHeader) catch return null;
552 for (header.type_index_begin..header.type_index_end) |type_index| {
557 for (header.type_index_begin..header.type_index_end) |curr_type_index| {
553558 const prefix = reader.takeStructPointer(pdb.LfRecordPrefix) catch return null;
554559 reader.discardAll(prefix.len - @sizeOf(@FieldType(pdb.LfRecordPrefix, "len"))) catch return null;
555560
556 if (type_index == inlinee) {
561 if (curr_type_index == type_index) {
557562 switch (prefix.kind) {
558563 .func_id => {
559564 const func: *align(1) pdb.LfFuncId = @ptrCast(prefix);