wasm/Object: parse debug sections into reloc data

Rather than storing the name of a debug section into the structure
`RelocatableData`, we use the `index` field as an offset into the
debug names table. This means we do not have to store an extra 16 bytes
for non-debug sections which can be massive for object files where each
data symbol has its own data section. The name of a debug section
can then be retrieved again when needed by using the offset and
then reading until the 0-delimiter.
This commit is contained in:
Luuk de Gram
2022-08-29 20:13:55 +02:00
parent 924679abc4
commit 9a92f3d290
2 changed files with 44 additions and 7 deletions

View File

@@ -1782,7 +1782,7 @@ pub fn getMatchingSegment(self: *Wasm, object_index: u16, relocatable_index: u32
});
break :blk index;
},
.custom => return error.@"TODO: Custom section relocations for wasm",
.debug => return error.@"TODO: Custom section relocations for wasm",
}
}

View File

@@ -63,16 +63,21 @@ relocatable_data: []const RelocatableData = &.{},
/// import name, module name and export names. Each string will be deduplicated
/// and returns an offset into the table.
string_table: Wasm.StringTable = .{},
/// All the names of each debug section found in the current object file.
/// Each name is terminated by a null-terminator. The name can be found,
/// from the `index` offset within the `RelocatableData`.
debug_names: [:0]const u8,
/// Represents a single item within a section (depending on its `type`)
const RelocatableData = struct {
/// The type of the relocatable data
type: enum { data, code, custom },
type: enum { data, code, debug },
/// Pointer to the data of the segment, where its length is written to `size`
data: [*]u8,
/// The size in bytes of the data representing the segment within the section
size: u32,
/// The index within the section itself
/// The index within the section itself, or in case of a debug section,
/// the offset within the `debug_names` table.
index: u32,
/// The offset within the section where the data starts
offset: u32,
@@ -96,7 +101,7 @@ const RelocatableData = struct {
return switch (self.type) {
.data => .data,
.code => .function,
.custom => .section,
.debug => unreachable, // illegal, debug sections are not represented by a symbol
};
}
};
@@ -111,6 +116,7 @@ pub fn create(gpa: Allocator, file: std.fs.File, name: []const u8, maybe_max_siz
var object: Object = .{
.file = file,
.name = try gpa.dupe(u8, name),
.debug_names = &.{},
};
var is_object_file: bool = false;
@@ -197,6 +203,11 @@ pub fn importedCountByKind(self: *const Object, kind: std.wasm.ExternalKind) u32
} else i;
}
/// From a given `RelocatableDate`, find the corresponding debug section name
pub fn getDebugName(self: *const Object, relocatable_data: RelocatableData) []const u8 {
return std.mem.sliceTo(self.debug_names[relocatable_data.index..], 0);
}
/// Checks if the object file is an MVP version.
/// When that's the case, we check if there's an import table definiton with its name
/// set to '__indirect_function_table". When that's also the case,
@@ -328,10 +339,15 @@ fn Parser(comptime ReaderType: type) type {
self.object.version = version;
var relocatable_data = std.ArrayList(RelocatableData).init(gpa);
var debug_names = std.ArrayList(u8).init(gpa);
errdefer while (relocatable_data.popOrNull()) |rel_data| {
gpa.free(rel_data.data[0..rel_data.size]);
} else relocatable_data.deinit();
errdefer {
while (relocatable_data.popOrNull()) |rel_data| {
gpa.free(rel_data.data[0..rel_data.size]);
} else relocatable_data.deinit();
gpa.free(debug_names.items);
debug_names.deinit();
}
var section_index: u32 = 0;
while (self.reader.reader().readByte()) |byte| : (section_index += 1) {
@@ -352,6 +368,24 @@ fn Parser(comptime ReaderType: type) type {
try self.parseRelocations(gpa);
} else if (std.mem.eql(u8, name, "target_features")) {
try self.parseFeatures(gpa);
} else if (std.mem.startsWith(u8, name, ".debug")) {
const debug_size = @intCast(u32, reader.context.bytes_left);
const debug_content = try gpa.alloc(u8, debug_size);
errdefer gpa.free(debug_content);
try reader.readNoEof(debug_content);
const debug_name_index = @intCast(u32, debug_names.items.len);
try debug_names.ensureUnusedCapacity(name.len + 1);
debug_names.appendSliceAssumeCapacity(try gpa.dupe(u8, name));
debug_names.appendAssumeCapacity(0);
try relocatable_data.append(.{
.type = .debug,
.data = debug_content.ptr,
.size = debug_size,
.index = debug_name_index,
.offset = len - debug_size,
.section_index = section_index,
});
} else {
try reader.skipBytes(reader.context.bytes_left, .{});
}
@@ -517,6 +551,9 @@ fn Parser(comptime ReaderType: type) type {
else => |e| return e,
}
self.object.relocatable_data = relocatable_data.toOwnedSlice();
const names = debug_names.toOwnedSlice();
self.object.debug_names = names[0 .. names.len - 1 :0];
}
/// Based on the "features" custom section, parses it into a list of