| ... | @@ -33,6 +33,7 @@ pub const SymbolIterator = struct { | ... | @@ -33,6 +33,7 @@ pub const SymbolIterator = struct { |
| 33 | | 33 | |
| 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 | } |
| 38 | | 39 | |
| ... | @@ -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; |
| 63 | | 64 | |
| 64 | // Get the next inlinee if it exists | 65 | // 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 iterator | 81 | // 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; |
| 363 | | 363 | // 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, | | |
| 378 | | 398 | |
| 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 index | 403 | .inline_sites = inline_sites, |
| 384 | }; | 404 | } }; |
| | 405 | } |
| 385 | | 406 | |
| 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 | else | 411 | 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 | } |
| 399 | | 418 | |
| 400 | // Dwarf | 419 | 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 | }; |
| 408 | | 429 | |
| 409 | return error.MissingDebugInfo; | | |
| 410 | } | | |
| 411 | }; | 430 | }; |
| 412 | | 431 | |
| 413 | fn deinit(module: *Module, gpa: Allocator, io: Io) void { | 432 | fn deinit(module: *Module, gpa: Allocator, io: Io) void { |