debug: fix resource (de)allocation for Elf and Coff targets

With this change, it is now possible to safely call
`var di = std.debug.openSelfDebugInfo(gpa)`. Calling then
`di.deinit()` on the object will correctly free all allocated
resources.

Ensure we store the result of `mmap` with correct alignment.
This commit is contained in:
Jakub Konka 2022-04-21 10:46:04 +02:00
parent 96c1314443
commit 28ca203b71
3 changed files with 40 additions and 18 deletions

View File

@ -4,8 +4,6 @@ const mem = std.mem;
const os = std.os; const os = std.os;
const File = std.fs.File; const File = std.fs.File;
const ArrayList = std.ArrayList;
// CoffHeader.machine values // CoffHeader.machine values
// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms680313(v=vs.85).aspx // see https://msdn.microsoft.com/en-us/library/windows/desktop/ms680313(v=vs.85).aspx
const IMAGE_FILE_MACHINE_I386 = 0x014c; const IMAGE_FILE_MACHINE_I386 = 0x014c;
@ -117,7 +115,7 @@ pub const Coff = struct {
coff_header: CoffHeader, coff_header: CoffHeader,
pe_header: OptionalHeader, pe_header: OptionalHeader,
sections: ArrayList(Section), sections: std.ArrayListUnmanaged(Section) = .{},
guid: [16]u8, guid: [16]u8,
age: u32, age: u32,
@ -128,12 +126,15 @@ pub const Coff = struct {
.allocator = allocator, .allocator = allocator,
.coff_header = undefined, .coff_header = undefined,
.pe_header = undefined, .pe_header = undefined,
.sections = ArrayList(Section).init(allocator),
.guid = undefined, .guid = undefined,
.age = undefined, .age = undefined,
}; };
} }
pub fn deinit(self: *Coff) void {
self.sections.deinit(self.allocator);
}
pub fn loadHeader(self: *Coff) !void { pub fn loadHeader(self: *Coff) !void {
const pe_pointer_offset = 0x3C; const pe_pointer_offset = 0x3C;
@ -291,7 +292,7 @@ pub const Coff = struct {
if (self.sections.items.len == self.coff_header.number_of_sections) if (self.sections.items.len == self.coff_header.number_of_sections)
return; return;
try self.sections.ensureTotalCapacityPrecise(self.coff_header.number_of_sections); try self.sections.ensureTotalCapacityPrecise(self.allocator, self.coff_header.number_of_sections);
const in = self.in_file.reader(); const in = self.in_file.reader();

View File

@ -41,7 +41,7 @@ pub const SymbolInfo = struct {
compile_unit_name: []const u8 = "???", compile_unit_name: []const u8 = "???",
line_info: ?LineInfo = null, line_info: ?LineInfo = null,
pub fn deinit(self: @This(), allocator: mem.Allocator) void { pub fn deinit(self: SymbolInfo, allocator: mem.Allocator) void {
if (self.line_info) |li| { if (self.line_info) |li| {
li.deinit(allocator); li.deinit(allocator);
} }
@ -50,6 +50,13 @@ pub const SymbolInfo = struct {
const PdbOrDwarf = union(enum) { const PdbOrDwarf = union(enum) {
pdb: pdb.Pdb, pdb: pdb.Pdb,
dwarf: DW.DwarfInfo, dwarf: DW.DwarfInfo,
fn deinit(self: *PdbOrDwarf, allocator: mem.Allocator) void {
switch (self.*) {
.pdb => |*inner| inner.deinit(),
.dwarf => |*inner| inner.deinit(allocator),
}
}
}; };
var stderr_mutex = std.Thread.Mutex{}; var stderr_mutex = std.Thread.Mutex{};
@ -793,6 +800,7 @@ fn readCoffDebugInfo(allocator: mem.Allocator, coff_file: File) !ModuleDebugInfo
errdefer coff_file.close(); errdefer coff_file.close();
const coff_obj = try allocator.create(coff.Coff); const coff_obj = try allocator.create(coff.Coff);
errdefer allocator.destroy(coff_obj);
coff_obj.* = coff.Coff.init(allocator, coff_file); coff_obj.* = coff.Coff.init(allocator, coff_file);
var di = ModuleDebugInfo{ var di = ModuleDebugInfo{
@ -1386,7 +1394,7 @@ pub const DebugInfo = struct {
pub const ModuleDebugInfo = switch (native_os) { pub const ModuleDebugInfo = switch (native_os) {
.macos, .ios, .watchos, .tvos => struct { .macos, .ios, .watchos, .tvos => struct {
base_address: usize, base_address: usize,
mapped_memory: []const u8, mapped_memory: []align(mem.page_size) const u8,
symbols: []const MachoSymbol, symbols: []const MachoSymbol,
strings: [:0]const u8, strings: [:0]const u8,
ofiles: OFileTable, ofiles: OFileTable,
@ -1406,6 +1414,7 @@ pub const ModuleDebugInfo = switch (native_os) {
} }
self.ofiles.deinit(); self.ofiles.deinit();
allocator.free(self.symbols); allocator.free(self.symbols);
os.munmap(self.mapped_memory);
} }
fn loadOFile(self: *@This(), allocator: mem.Allocator, o_file_path: []const u8) !OFileInfo { fn loadOFile(self: *@This(), allocator: mem.Allocator, o_file_path: []const u8) !OFileInfo {
@ -1609,18 +1618,20 @@ pub const ModuleDebugInfo = switch (native_os) {
debug_data: PdbOrDwarf, debug_data: PdbOrDwarf,
coff: *coff.Coff, coff: *coff.Coff,
pub fn allocator(self: @This()) mem.Allocator { fn deinit(self: *@This(), allocator: mem.Allocator) void {
return self.coff.allocator; self.debug_data.deinit(allocator);
self.coff.deinit();
allocator.destroy(self.coff);
} }
pub fn getSymbolAtAddress(self: *@This(), address: usize) !SymbolInfo { pub fn getSymbolAtAddress(self: *@This(), allocator: mem.Allocator, address: usize) !SymbolInfo {
// Translate the VA into an address into this object // Translate the VA into an address into this object
const relocated_address = address - self.base_address; const relocated_address = address - self.base_address;
switch (self.debug_data) { switch (self.debug_data) {
.dwarf => |*dwarf| { .dwarf => |*dwarf| {
const dwarf_address = relocated_address + self.coff.pe_header.image_base; const dwarf_address = relocated_address + self.coff.pe_header.image_base;
return getSymbolFromDwarf(dwarf_address, dwarf); return getSymbolFromDwarf(allocator, dwarf_address, dwarf);
}, },
.pdb => { .pdb => {
// fallthrough to pdb handling // fallthrough to pdb handling
@ -1666,17 +1677,28 @@ pub const ModuleDebugInfo = switch (native_os) {
.linux, .netbsd, .freebsd, .dragonfly, .openbsd, .haiku, .solaris => struct { .linux, .netbsd, .freebsd, .dragonfly, .openbsd, .haiku, .solaris => struct {
base_address: usize, base_address: usize,
dwarf: DW.DwarfInfo, dwarf: DW.DwarfInfo,
mapped_memory: []const u8, mapped_memory: []align(mem.page_size) const u8,
pub fn getSymbolAtAddress(self: *@This(), address: usize) !SymbolInfo { fn deinit(self: *@This(), allocator: mem.Allocator) void {
self.dwarf.deinit(allocator);
os.munmap(self.mapped_memory);
}
pub fn getSymbolAtAddress(self: *@This(), allocator: mem.Allocator, address: usize) !SymbolInfo {
// Translate the VA into an address into this object // Translate the VA into an address into this object
const relocated_address = address - self.base_address; const relocated_address = address - self.base_address;
return getSymbolFromDwarf(relocated_address, &self.dwarf); return getSymbolFromDwarf(allocator, relocated_address, &self.dwarf);
} }
}, },
.wasi => struct { .wasi => struct {
pub fn getSymbolAtAddress(self: *@This(), address: usize) !SymbolInfo { fn deinit(self: *@This(), allocator: mem.Allocator) void {
_ = self; _ = self;
_ = allocator;
}
pub fn getSymbolAtAddress(self: *@This(), allocator: mem.Allocator, address: usize) !SymbolInfo {
_ = self;
_ = allocator;
_ = address; _ = address;
return SymbolInfo{}; return SymbolInfo{};
} }
@ -1684,14 +1706,14 @@ pub const ModuleDebugInfo = switch (native_os) {
else => DW.DwarfInfo, else => DW.DwarfInfo,
}; };
fn getSymbolFromDwarf(address: u64, di: *DW.DwarfInfo) !SymbolInfo { fn getSymbolFromDwarf(allocator: mem.Allocator, address: u64, di: *DW.DwarfInfo) !SymbolInfo {
if (nosuspend di.findCompileUnit(address)) |compile_unit| { if (nosuspend di.findCompileUnit(address)) |compile_unit| {
return SymbolInfo{ return SymbolInfo{
.symbol_name = nosuspend di.getSymbolName(address) orelse "???", .symbol_name = nosuspend di.getSymbolName(address) orelse "???",
.compile_unit_name = compile_unit.die.getAttrString(di, DW.AT.name) catch |err| switch (err) { .compile_unit_name = compile_unit.die.getAttrString(di, DW.AT.name) catch |err| switch (err) {
error.MissingDebugInfo, error.InvalidDebugInfo => "???", error.MissingDebugInfo, error.InvalidDebugInfo => "???",
}, },
.line_info = nosuspend di.getLineNumberInfo(compile_unit.*, address) catch |err| switch (err) { .line_info = nosuspend di.getLineNumberInfo(allocator, compile_unit.*, address) catch |err| switch (err) {
error.MissingDebugInfo, error.InvalidDebugInfo => null, error.MissingDebugInfo, error.InvalidDebugInfo => null,
else => return err, else => return err,
}, },

View File

@ -764,7 +764,6 @@ pub const Pdb = struct {
const flags = @ptrCast(*LineNumberEntry.Flags, &line_num_entry.Flags); const flags = @ptrCast(*LineNumberEntry.Flags, &line_num_entry.Flags);
return debug.LineInfo{ return debug.LineInfo{
.allocator = self.allocator,
.file_name = source_file_name, .file_name = source_file_name,
.line = flags.Start, .line = flags.Start,
.column = column, .column = column,