wasm-linker: write debug sections from objects
We now link relocatable debug sections with the correct section symbol and then allocate and resolve the debug atoms before writing them into the final binary. Although this does perform the relocation, the actual relocations are not done correctly yet.
This commit is contained in:
@@ -2495,21 +2495,39 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
|
||||
}
|
||||
} else if (!self.base.options.strip) {
|
||||
if (self.dwarf) |*dwarf| {
|
||||
if (self.debug_info_index != null) {
|
||||
if (self.base.options.module) |mod| {
|
||||
try dwarf.writeDbgAbbrev(&self.base);
|
||||
// for debug info and ranges, the address is always 0,
|
||||
// as locations are always offsets relative to 'code' section.
|
||||
try dwarf.writeDbgInfoHeader(&self.base, mod, 0, code_section_size);
|
||||
try dwarf.writeDbgAranges(&self.base, 0, code_section_size);
|
||||
try dwarf.writeDbgLineHeader(&self.base, mod);
|
||||
}
|
||||
const mod = self.base.options.module.?;
|
||||
try dwarf.writeDbgAbbrev(&self.base);
|
||||
// for debug info and ranges, the address is always 0,
|
||||
// as locations are always offsets relative to 'code' section.
|
||||
try dwarf.writeDbgInfoHeader(&self.base, mod, 0, code_section_size);
|
||||
try dwarf.writeDbgAranges(&self.base, 0, code_section_size);
|
||||
try dwarf.writeDbgLineHeader(&self.base, mod);
|
||||
}
|
||||
|
||||
try emitDebugSection(file, self.debug_info.items, ".debug_info");
|
||||
try emitDebugSection(file, self.debug_aranges.items, ".debug_ranges");
|
||||
try emitDebugSection(file, self.debug_abbrev.items, ".debug_abbrev");
|
||||
try emitDebugSection(file, self.debug_line.items, ".debug_line");
|
||||
try emitDebugSection(file, dwarf.strtab.items, ".debug_str");
|
||||
var debug_bytes = std.ArrayList(u8).init(self.base.allocator);
|
||||
defer debug_bytes.deinit();
|
||||
|
||||
const debug_sections = .{
|
||||
.{ ".debug_info", self.debug_info_index },
|
||||
.{ ".debug_pubtypes", self.debug_pubtypes_index },
|
||||
.{ ".debug_abbrev", self.debug_abbrev_index },
|
||||
.{ ".debug_line", self.debug_line_index },
|
||||
.{ ".debug_str", self.debug_str_index },
|
||||
.{ ".debug_pubnames", self.debug_pubnames_index },
|
||||
.{ ".debug_loc", self.debug_loc_index },
|
||||
.{ ".debug_ranges", self.debug_ranges_index },
|
||||
};
|
||||
|
||||
inline for (debug_sections) |item| {
|
||||
if (item[1]) |index| {
|
||||
var atom = self.atoms.get(index).?.getFirst();
|
||||
while (true) {
|
||||
atom.resolveRelocs(self);
|
||||
try debug_bytes.appendSlice(atom.code.items);
|
||||
atom = atom.next orelse break;
|
||||
}
|
||||
try emitDebugSection(file, debug_bytes.items, item[0]);
|
||||
debug_bytes.clearRetainingCapacity();
|
||||
}
|
||||
}
|
||||
try self.emitNameSection(file, arena);
|
||||
@@ -2517,6 +2535,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
|
||||
}
|
||||
|
||||
fn emitDebugSection(file: fs.File, data: []const u8, name: []const u8) !void {
|
||||
if (data.len == 0) return;
|
||||
const header_offset = try reserveCustomSectionHeader(file);
|
||||
const writer = file.writer();
|
||||
try leb.writeULEB128(writer, @intCast(u32, name.len));
|
||||
|
||||
@@ -77,7 +77,7 @@ const RelocatableData = struct {
|
||||
/// The size in bytes of the data representing the segment within the section
|
||||
size: u32,
|
||||
/// The index within the section itself, or in case of a debug section,
|
||||
/// the offset within the `debug_names` table.
|
||||
/// the offset within the `string_table`.
|
||||
index: u32,
|
||||
/// The offset within the section where the data starts
|
||||
offset: u32,
|
||||
@@ -101,9 +101,16 @@ const RelocatableData = struct {
|
||||
return switch (self.type) {
|
||||
.data => .data,
|
||||
.code => .function,
|
||||
.debug => unreachable, // illegal, debug sections are not represented by a symbol
|
||||
.debug => .section,
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns the index within a section itself, or in case of a debug section,
|
||||
/// returns the section index within the object file.
|
||||
pub fn getIndex(self: RelocatableData) u32 {
|
||||
if (self.type == .debug) return self.section_index;
|
||||
return self.index;
|
||||
}
|
||||
};
|
||||
|
||||
pub const InitError = error{NotObjectFile} || ParseError || std.fs.File.ReadError;
|
||||
@@ -205,7 +212,7 @@ pub fn importedCountByKind(self: *const Object, kind: std.wasm.ExternalKind) u32
|
||||
|
||||
/// 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);
|
||||
return self.string_table.get(relocatable_data.index);
|
||||
}
|
||||
|
||||
/// Checks if the object file is an MVP version.
|
||||
@@ -363,6 +370,7 @@ fn Parser(comptime ReaderType: type) type {
|
||||
|
||||
if (std.mem.eql(u8, name, "linking")) {
|
||||
is_object_file.* = true;
|
||||
self.object.relocatable_data = relocatable_data.items; // at this point no new relocatable sections will appear so we're free to store them.
|
||||
try self.parseMetadata(gpa, @intCast(usize, reader.context.bytes_left));
|
||||
} else if (std.mem.startsWith(u8, name, "reloc")) {
|
||||
try self.parseRelocations(gpa);
|
||||
@@ -374,19 +382,16 @@ fn Parser(comptime ReaderType: type) type {
|
||||
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,
|
||||
.index = try self.object.string_table.put(gpa, name),
|
||||
.offset = len - debug_size,
|
||||
.section_index = section_index,
|
||||
});
|
||||
} else {
|
||||
log.info("found unknown custom section '{s}' - skipping parsing", .{name});
|
||||
try reader.skipBytes(reader.context.bytes_left, .{});
|
||||
}
|
||||
},
|
||||
@@ -551,9 +556,6 @@ 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
|
||||
@@ -774,7 +776,12 @@ fn Parser(comptime ReaderType: type) type {
|
||||
},
|
||||
.section => {
|
||||
symbol.index = try leb.readULEB128(u32, reader);
|
||||
symbol.name = try self.object.string_table.put(gpa, @tagName(symbol.tag));
|
||||
for (self.object.relocatable_data) |data| {
|
||||
if (data.section_index == symbol.index) {
|
||||
symbol.name = data.index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
else => {
|
||||
symbol.index = try leb.readULEB128(u32, reader);
|
||||
@@ -864,7 +871,6 @@ fn assertEnd(reader: anytype) !void {
|
||||
|
||||
/// Parses an object file into atoms, for code and data sections
|
||||
pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin: *Wasm) !void {
|
||||
log.debug("Parsing data section into atoms", .{});
|
||||
const Key = struct {
|
||||
kind: Symbol.Tag,
|
||||
index: u32,
|
||||
@@ -876,7 +882,7 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
|
||||
|
||||
for (self.symtable) |symbol, symbol_index| {
|
||||
switch (symbol.tag) {
|
||||
.function, .data => if (!symbol.isUndefined()) {
|
||||
.function, .data, .section => if (!symbol.isUndefined()) {
|
||||
const gop = try symbol_for_segment.getOrPut(.{ .kind = symbol.tag, .index = symbol.index });
|
||||
const sym_idx = @intCast(u32, symbol_index);
|
||||
if (!gop.found_existing) {
|
||||
@@ -925,13 +931,11 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
|
||||
|
||||
try atom.code.appendSlice(gpa, relocatable_data.data[0..relocatable_data.size]);
|
||||
|
||||
if (relocatable_data.type != .debug) {
|
||||
const symbols = symbol_for_segment.getPtr(.{
|
||||
.kind = relocatable_data.getSymbolKind(),
|
||||
.index = @intCast(u32, relocatable_data.index),
|
||||
}) orelse continue; // encountered a segment we do not create an atom for
|
||||
const sym_index = symbols.pop();
|
||||
atom.sym_index = sym_index;
|
||||
if (symbol_for_segment.getPtr(.{
|
||||
.kind = relocatable_data.getSymbolKind(),
|
||||
.index = relocatable_data.getIndex(),
|
||||
})) |symbols| {
|
||||
atom.sym_index = symbols.pop();
|
||||
|
||||
// symbols referencing the same atom will be added as alias
|
||||
// or as 'parent' when they are global.
|
||||
@@ -957,7 +961,7 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
|
||||
} else {
|
||||
try wasm_bin.atoms.putNoClobber(gpa, final_index, atom);
|
||||
}
|
||||
log.debug("Parsed into atom: '{s}'", .{self.string_table.get(self.symtable[atom.sym_index].name)});
|
||||
log.debug("Parsed into atom: '{s}' at segment index {d}", .{ self.string_table.get(self.symtable[atom.sym_index].name), final_index });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user