authorgravatar for mason@gamesbymason.comMason Remaley <mason@gamesbymason.com> 2026-04-07 13:39:35-07:00
committergravatar for mason@gamesbymason.comMason Remaley <mason@gamesbymason.com> 2026-04-12 04:01:29-07:00
log781bab193b3ea026d2bd6adf8150bb6510205766
tree4e590e8cec6a082d69c006828581d14bd639324e
parent5c6885be53b0e7d791f13dee32cb945b3f8f0d7d

Iterates inline sites in the correct order


2 files changed, 88 insertions(+), 75 deletions(-)

lib/std/debug/Pdb.zig-6
...@@ -253,12 +253,6 @@ pub const InlineSiteSymIterator = struct {...@@ -253,12 +253,6 @@ pub const InlineSiteSymIterator = struct {
253 offset: usize,253 offset: usize,
254 end: usize,254 end: usize,
255255
256 pub const empty: InlineSiteSymIterator = .{
257 .module_index = 0,
258 .offset = 0,
259 .end = 0,
260 };
261
262 pub fn next(iter: *InlineSiteSymIterator, module: *Module) ?*align(1) pdb.InlineSiteSym {256 pub fn next(iter: *InlineSiteSymIterator, module: *Module) ?*align(1) pdb.InlineSiteSym {
263 while (iter.offset < iter.end) {257 while (iter.offset < iter.end) {
264 const inline_prefix: *align(1) pdb.RecordPrefix = @ptrCast(&module.symbols[iter.offset]);258 const inline_prefix: *align(1) pdb.RecordPrefix = @ptrCast(&module.symbols[iter.offset]);
lib/std/debug/SelfInfo/Windows.zig+88-69
...@@ -33,6 +33,7 @@ pub const SymbolIterator = struct {...@@ -33,6 +33,7 @@ pub const SymbolIterator = struct {
3333
34 pub fn deinit(self: *SymbolIterator, io: Io) void {34 pub fn deinit(self: *SymbolIterator, io: Io) void {
35 if (self.lock) |lock| lock.unlockShared(io);35 if (self.lock) |lock| lock.unlockShared(io);
36 self.symbols.deinit();
36 self.* = undefined;37 self.* = undefined;
37 }38 }
3839
...@@ -62,11 +63,10 @@ pub const SymbolIterator = struct {...@@ -62,11 +63,10 @@ pub const SymbolIterator = struct {
62 const pdb = if (di.pdb) |*pdb| pdb else unreachable;63 const pdb = if (di.pdb) |*pdb| pdb else unreachable;
6364
64 // Get the next inlinee if it exists65 // Get the next inlinee if it exists
65 while (info.inlinees.next(info.module)) |site| {66 if (info.proc) |proc| {
66 const parent: *align(1) const std.pdb.RecordPrefix = @ptrCast(&info.module.symbols[site.parent - @sizeOf(u16) * 2]);67 while (info.inline_sites.pop()) |site| {
67 if (pdb.getInlineeInfo(info.module, site.inlinee) catch null) |loc| {68 if (pdb.getInlineeInfo(info.module, site.inlinee) catch null) |loc| {
68 if (info.proc_sym) |proc_sym| {69 const offset_in_func = info.addr - proc.code_offset;
69 const offset_in_func = info.addr - proc_sym.code_offset;
70 if (try pdb.calculateOffset(site, loc, offset_in_func)) |offset| {70 if (try pdb.calculateOffset(site, loc, offset_in_func)) |offset| {
71 return .{71 return .{
72 .name = pdb.findInlineeName(site.inlinee),72 .name = pdb.findInlineeName(site.inlinee),
...@@ -81,15 +81,9 @@ pub const SymbolIterator = struct {...@@ -81,15 +81,9 @@ pub const SymbolIterator = struct {
81 // Return the main symbol and end the iterator81 // Return the main symbol and end the iterator
82 defer self.symbols = .none;82 defer self.symbols = .none;
83 return .{83 return .{
84 .name = if (info.proc_sym) |proc_sym|84 .name = if (info.proc) |proc| pdb.getSymbolName(proc) else null,
85 pdb.getSymbolName(proc_sym)
86 else
87 null,
88 .compile_unit_name = fs.path.basename(info.module.obj_file_name),85 .compile_unit_name = fs.path.basename(info.module.obj_file_name),
89 .source_location = pdb.getLineNumberInfo(86 .source_location = pdb.getLineNumberInfo(info.module, info.addr) catch null,
90 info.module,
91 info.addr,
92 ) catch null,
93 };87 };
94 },88 },
95 .dwarf => |info| {89 .dwarf => |info| {
...@@ -126,7 +120,9 @@ pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) SymbolIterator {...@@ -126,7 +120,9 @@ pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) SymbolIterator {
126 errdefer si.lock.unlockShared(io);120 errdefer si.lock.unlockShared(io);
127 const module = si.findModule(gpa, address) catch |err| return .failing(err);121 const module = si.findModule(gpa, address) catch |err| return .failing(err);
128 const di = module.getDebugInfo(gpa, io) catch |err| return .failing(err);122 const di = module.getDebugInfo(gpa, io) catch |err| return .failing(err);
129 const symbols = di.getSymbols(address - @intFromPtr(module.entry.DllBase)) catch |err| return .failing(err);123 const symbols = Module.DebugInfo.Symbols.init(di, address - @intFromPtr(module.entry.DllBase))
124 catch |err| return .failing(err);
125 errdefer comptime unreachable;
130 return .{126 return .{
131 .lock = &si.lock,127 .lock = &si.lock,
132 .module = module,128 .module = module,
...@@ -343,71 +339,94 @@ const Module = struct {...@@ -343,71 +339,94 @@ const Module = struct {
343 pub const Symbols = union(enum) {339 pub const Symbols = union(enum) {
344 pdb: struct {340 pdb: struct {
345 module: *Pdb.Module,341 module: *Pdb.Module,
346 proc_sym: ?*align(1) const std.pdb.ProcSym,342 proc: ?*align(1) const std.pdb.ProcSym,
347 addr: usize,
348 inlinees: Pdb.InlineSiteSymIterator,
349 },
350 dwarf: struct {
351 addr: usize,343 addr: usize,
344 /// Inline sites are stored in the pdb in reverse order, so we build up a list of up
345 /// front so that our iterator can return them in the correct order without doing an
346 /// n^2 search. We don't try to filter inline sites based on address until the user
347 /// calls `next` as this requires parsing binary annotations, and this is work we
348 /// may be able to elide if the caller chooses to early out before finishing
349 /// iteration, e.g. because they only wanted the topmost call.
350 inline_sites: std.ArrayList(*align(1) const std.pdb.InlineSiteSym),
352 },351 },
352 dwarf: struct { addr: usize },
353 none: void,353 none: void,
354 };354
355 fn getSymbols(di: *DebugInfo, vaddr: usize) Error!Symbols {355 fn init(di: *DebugInfo, vaddr: usize) Error!Symbols {
356 pdb: {356 const gpa = std.debug.getDebugInfoAllocator();
357 const pdb = &(di.pdb orelse break :pdb);357
358 var coff_section: *align(1) const coff.SectionHeader = undefined;358 pdb: {
359 const mod_index = for (pdb.sect_contribs) |sect_contrib| {359 const pdb = &(di.pdb orelse break :pdb);
360 if (sect_contrib.section > di.coff_section_headers.len) continue;360 var coff_section: *align(1) const coff.SectionHeader = undefined;
361 // Remember that SectionContribEntry.Section is 1-based.361 const mod_index = for (pdb.sect_contribs) |sect_contrib| {
362 coff_section = &di.coff_section_headers[sect_contrib.section - 1];362 if (sect_contrib.section > di.coff_section_headers.len) continue;
363363 // Remember that SectionContribEntry.Section is 1-based.
364 const vaddr_start = coff_section.virtual_address + sect_contrib.offset;364 coff_section = &di.coff_section_headers[sect_contrib.section - 1];
365 const vaddr_end = vaddr_start + sect_contrib.size;365
366 if (vaddr >= vaddr_start and vaddr < vaddr_end) {366 const vaddr_start = coff_section.virtual_address + sect_contrib.offset;
367 break sect_contrib.module_index;367 const vaddr_end = vaddr_start + sect_contrib.size;
368 if (vaddr >= vaddr_start and vaddr < vaddr_end) {
369 break sect_contrib.module_index;
370 }
371 } else {
372 // we have no information to add to the address
373 break :pdb;
374 };
375 const module = pdb.getModule(mod_index) catch |err| switch (err) {
376 error.InvalidDebugInfo,
377 error.MissingDebugInfo,
378 error.OutOfMemory,
379 => |e| return e,
380
381 error.ReadFailed,
382 error.EndOfStream,
383 => return error.InvalidDebugInfo,
384 } orelse {
385 return error.InvalidDebugInfo; // bad module index
386 };
387
388 const addr = vaddr - coff_section.virtual_address;
389 const maybe_proc = pdb.getProcSym(module, addr);
390
391 var inline_sites: std.ArrayList(*align(1) const std.pdb.InlineSiteSym) = .empty;
392 if (maybe_proc) |proc| {
393 var iter = pdb.getInlinees(module, proc);
394 while (iter.next(module)) |inline_site| {
395 try inline_sites.append(gpa, inline_site);
396 }
368 }397 }
369 } else {
370 // we have no information to add to the address
371 break :pdb;
372 };
373 const module = pdb.getModule(mod_index) catch |err| switch (err) {
374 error.InvalidDebugInfo,
375 error.MissingDebugInfo,
376 error.OutOfMemory,
377 => |e| return e,
378398
379 error.ReadFailed,399 return .{ .pdb = .{
380 error.EndOfStream,400 .module = module,
381 => return error.InvalidDebugInfo,401 .proc = maybe_proc,
382 } orelse {402 .addr = addr,
383 return error.InvalidDebugInfo; // bad module index403 .inline_sites = inline_sites,
384 };404 } };
405 }
385406
386 const addr = vaddr - coff_section.virtual_address;407 // Dwarf
387 const proc_sym = pdb.getProcSym(module, addr);408 dwarf: {
388 const inlinees: Pdb.InlineSiteSymIterator = if (proc_sym) |sym|409 if (di.dwarf == null) break :dwarf;
389 pdb.getInlinees(module, sym)410 const addr = vaddr + di.coff_image_base;
390 else411 return .{ .dwarf = .{
391 .empty;412 .addr = addr,
392 return .{ .pdb = .{413 } };
393 .module = module,414 }
394 .proc_sym = proc_sym,415
395 .addr = addr,416 return error.MissingDebugInfo;
396 .inlinees = inlinees,
397 } };
398 }417 }
399418
400 // Dwarf419 fn deinit(self: *Symbols) void {
401 dwarf: {420 switch (self.*) {
402 if (di.dwarf == null) break :dwarf;421 .pdb => |*info| {
403 const addr = vaddr + di.coff_image_base;422 const gpa = std.debug.getDebugInfoAllocator();
404 return .{ .dwarf = .{423 info.inline_sites.deinit(gpa);
405 .addr = addr,424 },
406 } };425 .dwarf, .none => {},
426 }
407 }427 }
428 };
408429
409 return error.MissingDebugInfo;
410 }
411 };430 };
412431
413 fn deinit(module: *Module, gpa: Allocator, io: Io) void {432 fn deinit(module: *Module, gpa: Allocator, io: Io) void {