| author | |
| committer | |
| log | 4efbb27aa2b841357c03d6ab158418ccad022415 |
| tree | 2e61e2cdcb42580a7c892d120f6d2ac2effbfbab |
| parent | 9edbf00ddfb3f8316d82e191b7aca281a0939ac0 |
Also fixes some memory management issues5 files changed, 93 insertions(+), 85 deletions(-)
lib/std/debug.zig+13-9| ... | ... | @@ -38,12 +38,8 @@ pub const cpu_context = @import("debug/cpu_context.zig"); |
| 38 | 38 | /// pub const init: SelfInfo; |
| 39 | 39 | /// pub fn deinit(si: *SelfInfo, io: Io) void; |
| 40 | 40 | /// |
| 41 | /// /// Returns the the symbols and source locations of the instruction at `address`. Often this | |
| 42 | /// /// will return a single result, but in the case of inlines it may return multiple. When | |
| 43 | /// /// multiple results are returned, they are sorted from innermost to outermost. | |
| 44 | /// pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) SelfInfoError![]const Symbol; | |
| 45 | /// /// Frees symbols returned from `getSymbols`. | |
| 46 | /// pub fn freeSymbols(si: *SelfInfo, symbols: []const Symbol) void; | |
| 41 | /// /// Returns the the symbols and source locations of the instruction at `address`. | |
| 42 | /// pub fn getSymbols(si: *SelfInfo, io: Io, address: usize, include_inline_callers: bool) SelfInfoError![]Symbol; | |
| 47 | 43 | /// /// Returns a name for the "module" (e.g. shared library or executable image) containing `address`. |
| 48 | 44 | /// pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) SelfInfoError![]const u8; |
| 49 | 45 | /// pub fn getModuleSlide(si: *SelfInfo, io: Io, address: usize) SelfInfoError!usize; |
| ... | ... | @@ -233,6 +229,11 @@ pub const Symbol = struct { |
| 233 | 229 | .compile_unit_name = null, |
| 234 | 230 | .source_location = null, |
| 235 | 231 | }; |
| 232 | ||
| 233 | pub fn deinit(self: *Symbol, gpa: Allocator) void { | |
| 234 | if (self.source_location) |sl| gpa.free(sl.file_name); | |
| 235 | self.* = undefined; | |
| 236 | } | |
| 236 | 237 | }; |
| 237 | 238 | |
| 238 | 239 | /// Deprecated because it returns the optimization mode of the standard |
| ... | ... | @@ -1192,7 +1193,8 @@ fn printSourceAtAddress( |
| 1192 | 1193 | t: Io.Terminal, |
| 1193 | 1194 | options: PrintSourceAddressOptions, |
| 1194 | 1195 | ) Writer.Error!void { |
| 1195 | const symbols: []const Symbol = debug_info.getSymbols(io, options.address) catch |err| { | |
| 1196 | const gpa = getDebugInfoAllocator(); | |
| 1197 | const symbols: []Symbol = debug_info.getSymbols(io, options.address, options.resolve_inline_callers) catch |err| { | |
| 1196 | 1198 | t.setColor(.dim) catch {}; |
| 1197 | 1199 | defer t.setColor(.reset) catch {}; |
| 1198 | 1200 | switch (err) { |
| ... | ... | @@ -1211,7 +1213,10 @@ fn printSourceAtAddress( |
| 1211 | 1213 | } |
| 1212 | 1214 | return printLineInfo(io, t, debug_info, null, options.address, null, null); |
| 1213 | 1215 | }; |
| 1214 | defer debug_info.freeSymbols(symbols); | |
| 1216 | defer { | |
| 1217 | for (symbols) |*symbol| symbol.deinit(gpa); | |
| 1218 | gpa.free(symbols); | |
| 1219 | } | |
| 1215 | 1220 | for (symbols) |symbol| { |
| 1216 | 1221 | try printLineInfo( |
| 1217 | 1222 | io, |
| ... | ... | @@ -1222,7 +1227,6 @@ fn printSourceAtAddress( |
| 1222 | 1227 | symbol.name, |
| 1223 | 1228 | symbol.compile_unit_name, |
| 1224 | 1229 | ); |
| 1225 | if (!options.resolve_inline_callers) break; | |
| 1226 | 1230 | } |
| 1227 | 1231 | } |
| 1228 | 1232 | fn printLineInfo( |
lib/std/debug/Dwarf.zig+13-8| ... | ... | @@ -1545,17 +1545,22 @@ fn getStringGeneric(opt_str: ?[]const u8, offset: u64) ![:0]const u8 { |
| 1545 | 1545 | return str[casted_offset..last :0]; |
| 1546 | 1546 | } |
| 1547 | 1547 | |
| 1548 | pub fn getSymbols(di: *Dwarf, gpa: Allocator, endian: Endian, address: u64) std.debug.SelfInfoError![]const std.debug.Symbol { | |
| 1549 | const symbol = try gpa.create(std.debug.Symbol); | |
| 1550 | errdefer gpa.destroy(symbol); | |
| 1548 | pub fn getSymbols(di: *Dwarf, gpa: Allocator, endian: Endian, address: u64, resolve_inline_callers: bool) std.debug.SelfInfoError![]std.debug.Symbol { | |
| 1549 | _ = resolve_inline_callers; | |
| 1550 | ||
| 1551 | var symbols: std.ArrayList(std.debug.Symbol) = try .initCapacity(gpa, 1); | |
| 1552 | errdefer { | |
| 1553 | for (symbols.items) |*symbol| symbol.deinit(gpa); | |
| 1554 | symbols.deinit(gpa); | |
| 1555 | } | |
| 1551 | 1556 | const compile_unit = di.findCompileUnit(endian, address) catch |err| switch (err) { |
| 1552 | 1557 | error.EndOfStream, error.Overflow => { |
| 1553 | symbol.* = .unknown; | |
| 1554 | return symbol[0..1]; | |
| 1558 | symbols.appendAssumeCapacity(.unknown); | |
| 1559 | return symbols.toOwnedSlice(gpa); | |
| 1555 | 1560 | }, |
| 1556 | 1561 | else => |e| return e, |
| 1557 | 1562 | }; |
| 1558 | symbol.* = .{ | |
| 1563 | symbols.appendAssumeCapacity(.{ | |
| 1559 | 1564 | .name = di.getSymbolName(address), |
| 1560 | 1565 | .compile_unit_name = compile_unit.die.getAttrString(di, endian, std.dwarf.AT.name, di.section(.debug_str), compile_unit) catch |err| switch (err) { |
| 1561 | 1566 | error.MissingDebugInfo, error.InvalidDebugInfo => null, |
| ... | ... | @@ -1569,8 +1574,8 @@ pub fn getSymbols(di: *Dwarf, gpa: Allocator, endian: Endian, address: u64) std. |
| 1569 | 1574 | => return error.InvalidDebugInfo, |
| 1570 | 1575 | else => |e| return e, |
| 1571 | 1576 | }, |
| 1572 | }; | |
| 1573 | return symbol[0..1]; | |
| 1577 | }); | |
| 1578 | return symbols.toOwnedSlice(gpa); | |
| 1574 | 1579 | } |
| 1575 | 1580 | |
| 1576 | 1581 | /// DWARF5 7.4: "In the 32-bit DWARF format, all values that represent lengths of DWARF sections and |
lib/std/debug/SelfInfo/Elf.zig+10-17| ... | ... | @@ -30,7 +30,7 @@ pub fn deinit(si: *SelfInfo, io: Io) void { |
| 30 | 30 | if (si.unwind_cache) |cache| gpa.free(cache); |
| 31 | 31 | } |
| 32 | 32 | |
| 33 | pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) Error![]const std.debug.Symbol { | |
| 33 | pub fn getSymbols(si: *SelfInfo, io: Io, address: usize, resolve_inline_callers: bool) Error![]std.debug.Symbol { | |
| 34 | 34 | const gpa = std.debug.getDebugInfoAllocator(); |
| 35 | 35 | const module = try si.findModule(gpa, io, address, .exclusive); |
| 36 | 36 | defer si.rwlock.unlock(io); |
| ... | ... | @@ -53,27 +53,20 @@ pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) Error![]const std.debug |
| 53 | 53 | }; |
| 54 | 54 | loaded_elf.scanned_dwarf = true; |
| 55 | 55 | } |
| 56 | return dwarf.getSymbols(gpa, native_endian, vaddr); | |
| 56 | return dwarf.getSymbols(gpa, native_endian, vaddr, resolve_inline_callers); | |
| 57 | 57 | } |
| 58 | 58 | // When DWARF is unavailable, fall back to searching the symtab. |
| 59 | const symbol = try gpa.create(std.debug.Symbol); | |
| 60 | errdefer gpa.destroy(symbol); | |
| 61 | symbol.* = loaded_elf.file.searchSymtab(gpa, vaddr) catch |err| switch (err) { | |
| 59 | var symbols: std.ArrayList(std.debug.Symbol) = try .initCapacity(gpa, 1); | |
| 60 | errdefer { | |
| 61 | for (symbols.items) |*symbol| symbol.deinit(gpa); | |
| 62 | symbols.deinit(gpa); | |
| 63 | } | |
| 64 | symbols.appendAssumeCapacity(loaded_elf.file.searchSymtab(gpa, vaddr) catch |err| switch (err) { | |
| 62 | 65 | error.NoSymtab, error.NoStrtab => return error.MissingDebugInfo, |
| 63 | 66 | error.BadSymtab => return error.InvalidDebugInfo, |
| 64 | 67 | error.OutOfMemory => |e| return e, |
| 65 | }; | |
| 66 | return symbol[0..1]; | |
| 67 | } | |
| 68 | pub fn freeSymbols(si: *SelfInfo, symbols: []const std.debug.Symbol) void { | |
| 69 | _ = si; | |
| 70 | const gpa = std.debug.getDebugInfoAllocator(); | |
| 71 | for (symbols) |symbol| { | |
| 72 | if (symbol.source_location) |source_location| { | |
| 73 | gpa.free(source_location.file_name); | |
| 74 | } | |
| 75 | } | |
| 76 | gpa.free(symbols); | |
| 68 | }); | |
| 69 | return symbols.toOwnedSlice(gpa); | |
| 77 | 70 | } |
| 78 | 71 | pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) Error![]const u8 { |
| 79 | 72 | const gpa = std.debug.getDebugInfoAllocator(); |
lib/std/debug/SelfInfo/MachO.zig+17-22| ... | ... | @@ -36,15 +36,20 @@ pub const SymbolIterator = struct { |
| 36 | 36 | } |
| 37 | 37 | }; |
| 38 | 38 | |
| 39 | pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) Error![]const std.debug.Symbol { | |
| 39 | pub fn getSymbols(si: *SelfInfo, io: Io, address: usize, resolve_inline_callers: bool) Error![]std.debug.Symbol { | |
| 40 | _ = resolve_inline_callers; | |
| 41 | ||
| 40 | 42 | const gpa = std.debug.getDebugInfoAllocator(); |
| 41 | 43 | const module = try si.findModule(gpa, io, address); |
| 42 | 44 | defer si.mutex.unlock(io); |
| 43 | 45 | |
| 44 | 46 | const file = try module.getFile(gpa, io); |
| 45 | 47 | |
| 46 | const symbol = try gpa.create(std.debug.Symbol); | |
| 47 | errdefer gpa.destroy(symbol); | |
| 48 | var symbols: std.ArrayList(std.debug.Symbol) = try .initCapacity(gpa, 1); | |
| 49 | errdefer { | |
| 50 | for (symbols.items) |*symbol| symbol.deinit(gpa); | |
| 51 | symbols.deinit(gpa); | |
| 52 | } | |
| 48 | 53 | |
| 49 | 54 | // This is not necessarily the same as the vmaddr_slide that dyld would report. This is |
| 50 | 55 | // because the segments in the file on disk might differ from the ones in memory. Normally |
| ... | ... | @@ -60,25 +65,25 @@ pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) Error![]const std.debug |
| 60 | 65 | |
| 61 | 66 | const ofile_dwarf, const ofile_vaddr = file.getDwarfForAddress(gpa, io, vaddr) catch { |
| 62 | 67 | // Return at least the symbol name if available. |
| 63 | symbol.* = .{ | |
| 68 | symbols.appendAssumeCapacity(.{ | |
| 64 | 69 | .name = try file.lookupSymbolName(vaddr), |
| 65 | 70 | .compile_unit_name = null, |
| 66 | 71 | .source_location = null, |
| 67 | }; | |
| 68 | return symbol[0..1]; | |
| 72 | }); | |
| 73 | return symbols.toOwnedSlice(gpa); | |
| 69 | 74 | }; |
| 70 | 75 | |
| 71 | 76 | const compile_unit = ofile_dwarf.findCompileUnit(native_endian, ofile_vaddr) catch { |
| 72 | 77 | // Return at least the symbol name if available. |
| 73 | symbol.* = .{ | |
| 78 | symbols.appendAssumeCapacity(.{ | |
| 74 | 79 | .name = try file.lookupSymbolName(vaddr), |
| 75 | 80 | .compile_unit_name = null, |
| 76 | 81 | .source_location = null, |
| 77 | }; | |
| 78 | return symbol[0..1]; | |
| 82 | }); | |
| 83 | return symbols.toOwnedSlice(gpa); | |
| 79 | 84 | }; |
| 80 | 85 | |
| 81 | symbol.* = .{ | |
| 86 | symbols.appendAssumeCapacity(.{ | |
| 82 | 87 | .name = ofile_dwarf.getSymbolName(ofile_vaddr) orelse |
| 83 | 88 | try file.lookupSymbolName(vaddr), |
| 84 | 89 | .compile_unit_name = compile_unit.die.getAttrString( |
| ... | ... | @@ -96,18 +101,8 @@ pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) Error![]const std.debug |
| 96 | 101 | compile_unit, |
| 97 | 102 | ofile_vaddr, |
| 98 | 103 | ) catch null, |
| 99 | }; | |
| 100 | return symbol[0..1]; | |
| 101 | } | |
| 102 | pub fn freeSymbols(si: *SelfInfo, symbols: []const std.debug.Symbol) void { | |
| 103 | _ = si; | |
| 104 | const gpa = std.debug.getDebugInfoAllocator(); | |
| 105 | for (symbols) |symbol| { | |
| 106 | if (symbol.source_location) |source_location| { | |
| 107 | gpa.free(source_location.file_name); | |
| 108 | } | |
| 109 | } | |
| 110 | gpa.free(symbols); | |
| 104 | }); | |
| 105 | return symbols.toOwnedSlice(gpa); | |
| 111 | 106 | } |
| 112 | 107 | pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) Error![]const u8 { |
| 113 | 108 | _ = si; |
lib/std/debug/SelfInfo/Windows.zig+40-29| ... | ... | @@ -25,24 +25,13 @@ pub fn deinit(si: *SelfInfo, io: Io) void { |
| 25 | 25 | si.modules.deinit(gpa); |
| 26 | 26 | } |
| 27 | 27 | |
| 28 | pub fn getSymbols(si: *SelfInfo, io: Io, address: usize) Error![]const std.debug.Symbol { | |
| 28 | pub fn getSymbols(si: *SelfInfo, io: Io, address: usize, resolve_inline_callers: bool) Error![]std.debug.Symbol { | |
| 29 | 29 | const gpa = std.debug.getDebugInfoAllocator(); |
| 30 | 30 | try si.lock.lockShared(io); |
| 31 | 31 | defer si.lock.unlockShared(io); |
| 32 | 32 | const module = try si.findModule(gpa, address); |
| 33 | 33 | const di = try module.getDebugInfo(gpa, io); |
| 34 | return di.getSymbols(gpa, address - @intFromPtr(module.entry.DllBase)); | |
| 35 | } | |
| 36 | ||
| 37 | pub fn freeSymbols(si: *SelfInfo, symbols: []const std.debug.Symbol) void { | |
| 38 | _ = si; | |
| 39 | const gpa = std.debug.getDebugInfoAllocator(); | |
| 40 | for (symbols) |symbol| { | |
| 41 | if (symbol.source_location) |source_location| { | |
| 42 | gpa.free(source_location.file_name); | |
| 43 | } | |
| 44 | } | |
| 45 | gpa.free(symbols); | |
| 34 | return di.getSymbols(gpa, address - @intFromPtr(module.entry.DllBase), resolve_inline_callers); | |
| 46 | 35 | } |
| 47 | 36 | |
| 48 | 37 | pub fn getModuleName(si: *SelfInfo, io: Io, address: usize) Error![]const u8 { |
| ... | ... | @@ -252,7 +241,7 @@ const Module = struct { |
| 252 | 241 | arena.deinit(); |
| 253 | 242 | } |
| 254 | 243 | |
| 255 | fn getSymbols(di: *DebugInfo, gpa: Allocator, vaddr: usize) Error![]const std.debug.Symbol { | |
| 244 | fn getSymbols(di: *DebugInfo, gpa: Allocator, vaddr: usize, resolve_inline_callers: bool) Error![]std.debug.Symbol { | |
| 256 | 245 | pdb: { |
| 257 | 246 | const pdb = &(di.pdb orelse break :pdb); |
| 258 | 247 | var coff_section: *align(1) const coff.SectionHeader = undefined; |
| ... | ... | @@ -285,8 +274,12 @@ const Module = struct { |
| 285 | 274 | |
| 286 | 275 | const addr = vaddr - coff_section.virtual_address; |
| 287 | 276 | const maybe_proc = pdb.getProcSym(module, addr); |
| 288 | var symbols: std.ArrayList(std.debug.Symbol) = .empty; | |
| 289 | errdefer symbols.deinit(gpa); | |
| 277 | const compile_unit_name = fs.path.basename(module.obj_file_name); | |
| 278 | var symbols: std.ArrayList(std.debug.Symbol) = try .initCapacity(gpa, 1); | |
| 279 | errdefer { | |
| 280 | for (symbols.items) |*symbol| symbol.deinit(gpa); | |
| 281 | symbols.deinit(gpa); | |
| 282 | } | |
| 290 | 283 | |
| 291 | 284 | if (maybe_proc) |proc| { |
| 292 | 285 | const offset_in_func = addr - proc.code_offset; |
| ... | ... | @@ -315,25 +308,43 @@ const Module = struct { |
| 315 | 308 | if (inline_site.inlinee == last_inlinee) continue; |
| 316 | 309 | last_inlinee = inline_site.inlinee; |
| 317 | 310 | |
| 311 | // If we're appending this symbol, resolve the name. If we're replacing the | |
| 312 | // last symbol, clear the previous symbols and wait to resolve the name | |
| 313 | // until we've reached the last symbol to avoid doing work and then | |
| 314 | // throwing it out. | |
| 315 | const name = b: { | |
| 316 | if (resolve_inline_callers) break :b pdb.findInlineeName(inline_site.inlinee); | |
| 317 | symbols.items.len = 0; | |
| 318 | break :b null; | |
| 319 | }; | |
| 320 | ||
| 318 | 321 | try symbols.append(gpa, .{ |
| 319 | .name = pdb.findInlineeName(inline_site.inlinee), | |
| 320 | .compile_unit_name = fs.path.basename(module.obj_file_name), | |
| 322 | .name = name, | |
| 323 | .compile_unit_name = compile_unit_name, | |
| 321 | 324 | .source_location = loc, |
| 322 | 325 | }); |
| 323 | 326 | } |
| 324 | 327 | |
| 325 | // Inline sites are stored in the pdb in reverse order, so we reverse the | |
| 326 | // matching sites here. We could alternatively use the parent fields to | |
| 327 | // determine the order, but this would introduce seemingly unecessary | |
| 328 | // complexity. | |
| 329 | std.mem.reverse(std.debug.Symbol, symbols.items); | |
| 328 | if (resolve_inline_callers) { | |
| 329 | // Inline sites are stored in the pdb in reverse order, so we reverse the | |
| 330 | // matching sites here. We could alternatively use the parent fields to | |
| 331 | // determine the order, but this would introduce seemingly unecessary | |
| 332 | // complexity. | |
| 333 | std.mem.reverse(std.debug.Symbol, symbols.items); | |
| 334 | } else if (last_inlinee) |inlinee| { | |
| 335 | // If we haven't resolved the name yet, resolve it now | |
| 336 | symbols.items[symbols.items.len - 1].name = pdb.findInlineeName(inlinee); | |
| 337 | } | |
| 330 | 338 | } |
| 331 | 339 | |
| 332 | try symbols.append(gpa, .{ | |
| 333 | .name = if (maybe_proc) |proc| pdb.getSymbolName(proc) else null, | |
| 334 | .compile_unit_name = fs.path.basename(module.obj_file_name), | |
| 335 | .source_location = pdb.getLineNumberInfo(module, addr) catch null, | |
| 336 | }); | |
| 340 | // If there's room for another symbol, add the actual proc | |
| 341 | if (resolve_inline_callers or symbols.items.len == 0) { | |
| 342 | try symbols.append(gpa, .{ | |
| 343 | .name = if (maybe_proc) |proc| pdb.getSymbolName(proc) else null, | |
| 344 | .compile_unit_name = compile_unit_name, | |
| 345 | .source_location = pdb.getLineNumberInfo(module, addr) catch null, | |
| 346 | }); | |
| 347 | } | |
| 337 | 348 | |
| 338 | 349 | return symbols.toOwnedSlice(gpa); |
| 339 | 350 | } |
| ... | ... | @@ -341,7 +352,7 @@ const Module = struct { |
| 341 | 352 | dwarf: { |
| 342 | 353 | const dwarf = &(di.dwarf orelse break :dwarf); |
| 343 | 354 | const addr = vaddr + di.coff_image_base; |
| 344 | return dwarf.getSymbols(gpa, native_endian, addr); | |
| 355 | return dwarf.getSymbols(gpa, native_endian, addr, resolve_inline_callers); | |
| 345 | 356 | } |
| 346 | 357 | |
| 347 | 358 | return error.MissingDebugInfo; |