| ... | ... | @@ -63,16 +63,21 @@ relocatable_data: []const RelocatableData = &.{}, |
| 63 | 63 | /// import name, module name and export names. Each string will be deduplicated |
| 64 | 64 | /// and returns an offset into the table. |
| 65 | 65 | string_table: Wasm.StringTable = .{}, |
| 66 | /// All the names of each debug section found in the current object file. |
| 67 | /// Each name is terminated by a null-terminator. The name can be found, |
| 68 | /// from the `index` offset within the `RelocatableData`. |
| 69 | debug_names: [:0]const u8, |
| 66 | 70 | |
| 67 | 71 | /// Represents a single item within a section (depending on its `type`) |
| 68 | 72 | const RelocatableData = struct { |
| 69 | 73 | /// The type of the relocatable data |
| 70 | | type: enum { data, code, custom }, |
| 74 | type: enum { data, code, debug }, |
| 71 | 75 | /// Pointer to the data of the segment, where its length is written to `size` |
| 72 | 76 | data: [*]u8, |
| 73 | 77 | /// The size in bytes of the data representing the segment within the section |
| 74 | 78 | size: u32, |
| 75 | | /// The index within the section itself |
| 79 | /// The index within the section itself, or in case of a debug section, |
| 80 | /// the offset within the `debug_names` table. |
| 76 | 81 | index: u32, |
| 77 | 82 | /// The offset within the section where the data starts |
| 78 | 83 | offset: u32, |
| ... | ... | @@ -96,7 +101,7 @@ const RelocatableData = struct { |
| 96 | 101 | return switch (self.type) { |
| 97 | 102 | .data => .data, |
| 98 | 103 | .code => .function, |
| 99 | | .custom => .section, |
| 104 | .debug => unreachable, // illegal, debug sections are not represented by a symbol |
| 100 | 105 | }; |
| 101 | 106 | } |
| 102 | 107 | }; |
| ... | ... | @@ -111,6 +116,7 @@ pub fn create(gpa: Allocator, file: std.fs.File, name: []const u8, maybe_max_siz |
| 111 | 116 | var object: Object = .{ |
| 112 | 117 | .file = file, |
| 113 | 118 | .name = try gpa.dupe(u8, name), |
| 119 | .debug_names = &.{}, |
| 114 | 120 | }; |
| 115 | 121 | |
| 116 | 122 | var is_object_file: bool = false; |
| ... | ... | @@ -197,6 +203,11 @@ pub fn importedCountByKind(self: *const Object, kind: std.wasm.ExternalKind) u32 |
| 197 | 203 | } else i; |
| 198 | 204 | } |
| 199 | 205 | |
| 206 | /// From a given `RelocatableDate`, find the corresponding debug section name |
| 207 | pub fn getDebugName(self: *const Object, relocatable_data: RelocatableData) []const u8 { |
| 208 | return std.mem.sliceTo(self.debug_names[relocatable_data.index..], 0); |
| 209 | } |
| 210 | |
| 200 | 211 | /// Checks if the object file is an MVP version. |
| 201 | 212 | /// When that's the case, we check if there's an import table definiton with its name |
| 202 | 213 | /// set to '__indirect_function_table". When that's also the case, |
| ... | ... | @@ -328,10 +339,15 @@ fn Parser(comptime ReaderType: type) type { |
| 328 | 339 | |
| 329 | 340 | self.object.version = version; |
| 330 | 341 | var relocatable_data = std.ArrayList(RelocatableData).init(gpa); |
| 331 | | |
| 332 | | errdefer while (relocatable_data.popOrNull()) |rel_data| { |
| 333 | | gpa.free(rel_data.data[0..rel_data.size]); |
| 334 | | } else relocatable_data.deinit(); |
| 342 | var debug_names = std.ArrayList(u8).init(gpa); |
| 343 | |
| 344 | errdefer { |
| 345 | while (relocatable_data.popOrNull()) |rel_data| { |
| 346 | gpa.free(rel_data.data[0..rel_data.size]); |
| 347 | } else relocatable_data.deinit(); |
| 348 | gpa.free(debug_names.items); |
| 349 | debug_names.deinit(); |
| 350 | } |
| 335 | 351 | |
| 336 | 352 | var section_index: u32 = 0; |
| 337 | 353 | while (self.reader.reader().readByte()) |byte| : (section_index += 1) { |
| ... | ... | @@ -352,6 +368,24 @@ fn Parser(comptime ReaderType: type) type { |
| 352 | 368 | try self.parseRelocations(gpa); |
| 353 | 369 | } else if (std.mem.eql(u8, name, "target_features")) { |
| 354 | 370 | try self.parseFeatures(gpa); |
| 371 | } else if (std.mem.startsWith(u8, name, ".debug")) { |
| 372 | const debug_size = @intCast(u32, reader.context.bytes_left); |
| 373 | const debug_content = try gpa.alloc(u8, debug_size); |
| 374 | errdefer gpa.free(debug_content); |
| 375 | try reader.readNoEof(debug_content); |
| 376 | |
| 377 | const debug_name_index = @intCast(u32, debug_names.items.len); |
| 378 | try debug_names.ensureUnusedCapacity(name.len + 1); |
| 379 | debug_names.appendSliceAssumeCapacity(try gpa.dupe(u8, name)); |
| 380 | debug_names.appendAssumeCapacity(0); |
| 381 | try relocatable_data.append(.{ |
| 382 | .type = .debug, |
| 383 | .data = debug_content.ptr, |
| 384 | .size = debug_size, |
| 385 | .index = debug_name_index, |
| 386 | .offset = len - debug_size, |
| 387 | .section_index = section_index, |
| 388 | }); |
| 355 | 389 | } else { |
| 356 | 390 | try reader.skipBytes(reader.context.bytes_left, .{}); |
| 357 | 391 | } |
| ... | ... | @@ -517,6 +551,9 @@ fn Parser(comptime ReaderType: type) type { |
| 517 | 551 | else => |e| return e, |
| 518 | 552 | } |
| 519 | 553 | self.object.relocatable_data = relocatable_data.toOwnedSlice(); |
| 554 | |
| 555 | const names = debug_names.toOwnedSlice(); |
| 556 | self.object.debug_names = names[0 .. names.len - 1 :0]; |
| 520 | 557 | } |
| 521 | 558 | |
| 522 | 559 | /// Based on the "features" custom section, parses it into a list of |