| ... | ... | @@ -33,6 +33,7 @@ pub const SymbolIterator = struct { |
| 33 | 33 | |
| 34 | 34 | pub fn deinit(self: *SymbolIterator, io: Io) void { |
| 35 | 35 | if (self.lock) |lock| lock.unlockShared(io); |
| 36 | self.symbols.deinit(); |
| 36 | 37 | self.* = undefined; |
| 37 | 38 | } |
| 38 | 39 | |
| ... | ... | @@ -62,11 +63,10 @@ pub const SymbolIterator = struct { |
| 62 | 63 | const pdb = if (di.pdb) |*pdb| pdb else unreachable; |
| 63 | 64 | |
| 64 | 65 | // Get the next inlinee if it exists |
| 65 | | while (info.inlinees.next(info.module)) |site| { |
| 66 | | const parent: *align(1) const std.pdb.RecordPrefix = @ptrCast(&info.module.symbols[site.parent - @sizeOf(u16) * 2]); |
| 67 | | 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_sym.code_offset; |
| 66 | if (info.proc) |proc| { |
| 67 | while (info.inline_sites.pop()) |site| { |
| 68 | if (pdb.getInlineeInfo(info.module, site.inlinee) catch null) |loc| { |
| 69 | const offset_in_func = info.addr - proc.code_offset; |
| 70 | 70 | if (try pdb.calculateOffset(site, loc, offset_in_func)) |offset| { |
| 71 | 71 | return .{ |
| 72 | 72 | .name = pdb.findInlineeName(site.inlinee), |
| ... | ... | @@ -81,15 +81,9 @@ pub const SymbolIterator = struct { |
| 81 | 81 | // Return the main symbol and end the iterator |
| 82 | 82 | defer self.symbols = .none; |
| 83 | 83 | return .{ |
| 84 | | .name = if (info.proc_sym) |proc_sym| |
| 85 | | pdb.getSymbolName(proc_sym) |
| 86 | | else |
| 87 | | null, |
| 84 | .name = if (info.proc) |proc| pdb.getSymbolName(proc) else null, |
| 88 | 85 | .compile_unit_name = fs.path.basename(info.module.obj_file_name), |
| 89 | | .source_location = pdb.getLineNumberInfo( |
| 90 | | info.module, |
| 91 | | info.addr, |
| 92 | | ) catch null, |
| 86 | .source_location = pdb.getLineNumberInfo(info.module, info.addr) catch null, |
| 93 | 87 | }; |
| 94 | 88 | }, |
| 95 | 89 | .dwarf => |info| { |
| ... | ... | @@ -126,7 +120,9 @@ pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) SymbolIterator { |
| 126 | 120 | errdefer si.lock.unlockShared(io); |
| 127 | 121 | const module = si.findModule(gpa, address) catch |err| return .failing(err); |
| 128 | 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 | 126 | return .{ |
| 131 | 127 | .lock = &si.lock, |
| 132 | 128 | .module = module, |
| ... | ... | @@ -343,71 +339,94 @@ const Module = struct { |
| 343 | 339 | pub const Symbols = union(enum) { |
| 344 | 340 | pdb: struct { |
| 345 | 341 | module: *Pdb.Module, |
| 346 | | proc_sym: ?*align(1) const std.pdb.ProcSym, |
| 347 | | addr: usize, |
| 348 | | inlinees: Pdb.InlineSiteSymIterator, |
| 349 | | }, |
| 350 | | dwarf: struct { |
| 342 | proc: ?*align(1) const std.pdb.ProcSym, |
| 351 | 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 | 353 | none: void, |
| 354 | | }; |
| 355 | | fn getSymbols(di: *DebugInfo, vaddr: usize) Error!Symbols { |
| 356 | | pdb: { |
| 357 | | const pdb = &(di.pdb orelse break :pdb); |
| 358 | | var coff_section: *align(1) const coff.SectionHeader = undefined; |
| 359 | | const mod_index = for (pdb.sect_contribs) |sect_contrib| { |
| 360 | | if (sect_contrib.section > di.coff_section_headers.len) continue; |
| 361 | | // Remember that SectionContribEntry.Section is 1-based. |
| 362 | | coff_section = &di.coff_section_headers[sect_contrib.section - 1]; |
| 363 | | |
| 364 | | const vaddr_start = coff_section.virtual_address + sect_contrib.offset; |
| 365 | | const vaddr_end = vaddr_start + sect_contrib.size; |
| 366 | | if (vaddr >= vaddr_start and vaddr < vaddr_end) { |
| 367 | | break sect_contrib.module_index; |
| 354 | |
| 355 | fn init(di: *DebugInfo, vaddr: usize) Error!Symbols { |
| 356 | const gpa = std.debug.getDebugInfoAllocator(); |
| 357 | |
| 358 | pdb: { |
| 359 | const pdb = &(di.pdb orelse break :pdb); |
| 360 | var coff_section: *align(1) const coff.SectionHeader = undefined; |
| 361 | const mod_index = for (pdb.sect_contribs) |sect_contrib| { |
| 362 | if (sect_contrib.section > di.coff_section_headers.len) continue; |
| 363 | // Remember that SectionContribEntry.Section is 1-based. |
| 364 | coff_section = &di.coff_section_headers[sect_contrib.section - 1]; |
| 365 | |
| 366 | const vaddr_start = coff_section.virtual_address + sect_contrib.offset; |
| 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, |
| 380 | | error.EndOfStream, |
| 381 | | => return error.InvalidDebugInfo, |
| 382 | | } orelse { |
| 383 | | return error.InvalidDebugInfo; // bad module index |
| 384 | | }; |
| 399 | return .{ .pdb = .{ |
| 400 | .module = module, |
| 401 | .proc = maybe_proc, |
| 402 | .addr = addr, |
| 403 | .inline_sites = inline_sites, |
| 404 | } }; |
| 405 | } |
| 385 | 406 | |
| 386 | | const addr = vaddr - coff_section.virtual_address; |
| 387 | | const proc_sym = pdb.getProcSym(module, addr); |
| 388 | | const inlinees: Pdb.InlineSiteSymIterator = if (proc_sym) |sym| |
| 389 | | pdb.getInlinees(module, sym) |
| 390 | | else |
| 391 | | .empty; |
| 392 | | return .{ .pdb = .{ |
| 393 | | .module = module, |
| 394 | | .proc_sym = proc_sym, |
| 395 | | .addr = addr, |
| 396 | | .inlinees = inlinees, |
| 397 | | } }; |
| 407 | // Dwarf |
| 408 | dwarf: { |
| 409 | if (di.dwarf == null) break :dwarf; |
| 410 | const addr = vaddr + di.coff_image_base; |
| 411 | return .{ .dwarf = .{ |
| 412 | .addr = addr, |
| 413 | } }; |
| 414 | } |
| 415 | |
| 416 | return error.MissingDebugInfo; |
| 398 | 417 | } |
| 399 | 418 | |
| 400 | | // Dwarf |
| 401 | | dwarf: { |
| 402 | | if (di.dwarf == null) break :dwarf; |
| 403 | | const addr = vaddr + di.coff_image_base; |
| 404 | | return .{ .dwarf = .{ |
| 405 | | .addr = addr, |
| 406 | | } }; |
| 419 | fn deinit(self: *Symbols) void { |
| 420 | switch (self.*) { |
| 421 | .pdb => |*info| { |
| 422 | const gpa = std.debug.getDebugInfoAllocator(); |
| 423 | info.inline_sites.deinit(gpa); |
| 424 | }, |
| 425 | .dwarf, .none => {}, |
| 426 | } |
| 407 | 427 | } |
| 428 | }; |
| 408 | 429 | |
| 409 | | return error.MissingDebugInfo; |
| 410 | | } |
| 411 | 430 | }; |
| 412 | 431 | |
| 413 | 432 | fn deinit(module: *Module, gpa: Allocator, io: Io) void { |