authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-10-16 12:28:13+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-12-02 22:05:21-05:00
log8e815000515182f06fa436668664e4329c407a3e
tree43af30351ba752d3fb19c7dffbf2fd501b3438f4
parent808306f49ac8f7fd57c10a48a0126fefd07ab690

macho: handle DWARFv5 when parsing debug info in objects


2 files changed, 301 insertions(+), 225 deletions(-)

src/link/MachO/Dwarf.zig+207-93
......@@ -1,25 +1,73 @@
1debug_info: []u8 = &[0]u8{},
2debug_abbrev: []u8 = &[0]u8{},
3debug_str: []u8 = &[0]u8{},
4debug_str_offsets: []u8 = &[0]u8{},
5
6pub fn deinit(dwarf: *Dwarf, allocator: Allocator) void {
7 allocator.free(dwarf.debug_info);
8 allocator.free(dwarf.debug_abbrev);
9 allocator.free(dwarf.debug_str);
10 allocator.free(dwarf.debug_str_offsets);
11}
12
13/// Pulls an offset into __debug_str section from a __debug_str_offs section.
14/// This is new in DWARFv5 and requires the producer to specify DW_FORM_strx* (`index` arg)
15/// but also DW_AT_str_offsets_base with DW_FORM_sec_offset (`base` arg) in the opening header
16/// of a "referencing entity" such as DW_TAG_compile_unit.
17fn getOffset(debug_str_offsets: []const u8, base: u64, index: u64, dw_fmt: DwarfFormat) u64 {
18 return switch (dw_fmt) {
19 .dwarf32 => @as(*align(1) const u32, @ptrCast(debug_str_offsets.ptr + base + index * @sizeOf(u32))).*,
20 .dwarf64 => @as(*align(1) const u64, @ptrCast(debug_str_offsets.ptr + base + index * @sizeOf(u64))).*,
21 };
22}
23
124pub const InfoReader = struct {
2 bytes: []const u8,
3 strtab: []const u8,
25 ctx: Dwarf,
426 pos: usize = 0,
527
6 pub fn readCompileUnitHeader(p: *InfoReader) !CompileUnitHeader {
28 fn bytes(p: InfoReader) []const u8 {
29 return p.ctx.debug_info;
30 }
31
32 pub fn readCompileUnitHeader(p: *InfoReader, macho_file: *MachO) !CompileUnitHeader {
33 _ = macho_file;
734 var length: u64 = try p.readInt(u32);
835 const is_64bit = length == 0xffffffff;
936 if (is_64bit) {
1037 length = try p.readInt(u64);
1138 }
1239 const dw_fmt: DwarfFormat = if (is_64bit) .dwarf64 else .dwarf32;
40 const version = try p.readInt(Version);
41 const rest: struct {
42 debug_abbrev_offset: u64,
43 address_size: u8,
44 unit_type: u8,
45 } = switch (version) {
46 4 => .{
47 .debug_abbrev_offset = try p.readOffset(dw_fmt),
48 .address_size = try p.readByte(),
49 .unit_type = 0,
50 },
51 5 => .{
52 // According to the spec, version 5 introduced .unit_type field in the header, and
53 // it reordered .debug_abbrev_offset with .address_size fields.
54 .unit_type = try p.readByte(),
55 .address_size = try p.readByte(),
56 .debug_abbrev_offset = try p.readOffset(dw_fmt),
57 },
58 else => return error.InvalidVersion,
59 };
1360 return .{
1461 .format = dw_fmt,
1562 .length = length,
16 .version = try p.readInt(u16),
17 .debug_abbrev_offset = try p.readOffset(dw_fmt),
18 .address_size = try p.readByte(),
63 .version = version,
64 .debug_abbrev_offset = rest.debug_abbrev_offset,
65 .address_size = rest.address_size,
66 .unit_type = rest.unit_type,
1967 };
2068 }
2169
22 pub fn seekToDie(p: *InfoReader, code: Code, cuh: CompileUnitHeader, abbrev_reader: *AbbrevReader) !void {
70 pub fn seekToDie(p: *InfoReader, code: Code, cuh: CompileUnitHeader, abbrev_reader: *AbbrevReader, macho_file: *MachO) !void {
2371 const cuh_length = math.cast(usize, cuh.length) orelse return error.Overflow;
2472 const end_pos = p.pos + switch (cuh.format) {
2573 .dwarf32 => @as(usize, 4),
......@@ -27,72 +75,100 @@ pub const InfoReader = struct {
2775 } + cuh_length;
2876 while (p.pos < end_pos) {
2977 const di_code = try p.readUleb128(u64);
30 if (di_code == 0) return error.Eof;
78 if (di_code == 0) return error.UnexpectedEndOfFile;
3179 if (di_code == code) return;
3280
33 while (try abbrev_reader.readAttr()) |attr| switch (attr.at) {
34 dwarf.FORM.sec_offset,
35 dwarf.FORM.ref_addr,
36 => {
37 _ = try p.readOffset(cuh.format);
38 },
81 while (try abbrev_reader.readAttr()) |attr| {
82 try p.skip(attr.form, cuh, macho_file);
83 }
84 }
85 return error.UnexpectedEndOfFile;
86 }
3987
40 dwarf.FORM.addr => {
41 _ = try p.readNBytes(cuh.address_size);
42 },
88 /// When skipping attributes, we don't really need to be able to handle them all
89 /// since we only ever care about the DW_TAG_compile_unit.
90 pub fn skip(p: *InfoReader, form: Form, cuh: CompileUnitHeader, macho_file: *MachO) !void {
91 _ = macho_file;
92 switch (form) {
93 dw.FORM.sec_offset,
94 dw.FORM.ref_addr,
95 => {
96 _ = try p.readOffset(cuh.format);
97 },
4398
44 dwarf.FORM.block1,
45 dwarf.FORM.block2,
46 dwarf.FORM.block4,
47 dwarf.FORM.block,
48 => {
49 _ = try p.readBlock(attr.form);
50 },
99 dw.FORM.addr => {
100 _ = try p.readNBytes(cuh.address_size);
101 },
51102
52 dwarf.FORM.exprloc => {
53 _ = try p.readExprLoc();
54 },
103 dw.FORM.block1,
104 dw.FORM.block2,
105 dw.FORM.block4,
106 dw.FORM.block,
107 => {
108 _ = try p.readBlock(form);
109 },
110
111 dw.FORM.exprloc => {
112 _ = try p.readExprLoc();
113 },
55114
56 dwarf.FORM.flag_present => {},
57
58 dwarf.FORM.data1,
59 dwarf.FORM.ref1,
60 dwarf.FORM.flag,
61 dwarf.FORM.data2,
62 dwarf.FORM.ref2,
63 dwarf.FORM.data4,
64 dwarf.FORM.ref4,
65 dwarf.FORM.data8,
66 dwarf.FORM.ref8,
67 dwarf.FORM.ref_sig8,
68 dwarf.FORM.udata,
69 dwarf.FORM.ref_udata,
70 dwarf.FORM.sdata,
115 dw.FORM.flag_present => {},
116
117 dw.FORM.data1,
118 dw.FORM.ref1,
119 dw.FORM.flag,
120 dw.FORM.data2,
121 dw.FORM.ref2,
122 dw.FORM.data4,
123 dw.FORM.ref4,
124 dw.FORM.data8,
125 dw.FORM.ref8,
126 dw.FORM.ref_sig8,
127 dw.FORM.udata,
128 dw.FORM.ref_udata,
129 dw.FORM.sdata,
130 => {
131 _ = try p.readConstant(form);
132 },
133
134 dw.FORM.strp,
135 dw.FORM.string,
136 => {
137 _ = try p.readString(form, cuh);
138 },
139
140 else => if (cuh.version >= 5) switch (form) {
141 dw.FORM.strx,
142 dw.FORM.strx1,
143 dw.FORM.strx2,
144 dw.FORM.strx3,
145 dw.FORM.strx4,
71146 => {
72 _ = try p.readConstant(attr.form);
147 // We are just iterating over the __debug_info data, so we don't care about an actual
148 // string, therefore we set the `base = 0`.
149 _ = try p.readStringIndexed(form, cuh, 0);
73150 },
74151
75 dwarf.FORM.strp,
76 dwarf.FORM.string,
152 dw.FORM.addrx,
153 dw.FORM.addrx1,
154 dw.FORM.addrx2,
155 dw.FORM.addrx3,
156 dw.FORM.addrx4,
77157 => {
78 _ = try p.readString(attr.form, cuh);
158 _ = try p.readIndex(form);
79159 },
80160
81 else => {
82 // TODO better errors
83 log.err("unhandled DW_FORM_* value with identifier {x}", .{attr.form});
84 return error.UnhandledDwFormValue;
85 },
86 };
161 else => return error.UnknownForm,
162 } else return error.UnknownForm,
87163 }
88164 }
89165
90166 pub fn readBlock(p: *InfoReader, form: Form) ![]const u8 {
91167 const len: u64 = switch (form) {
92 dwarf.FORM.block1 => try p.readByte(),
93 dwarf.FORM.block2 => try p.readInt(u16),
94 dwarf.FORM.block4 => try p.readInt(u32),
95 dwarf.FORM.block => try p.readUleb128(u64),
168 dw.FORM.block1 => try p.readByte(),
169 dw.FORM.block2 => try p.readInt(u16),
170 dw.FORM.block4 => try p.readInt(u32),
171 dw.FORM.block => try p.readUleb128(u64),
96172 else => unreachable,
97173 };
98174 return p.readNBytes(len);
......@@ -105,52 +181,79 @@ pub const InfoReader = struct {
105181
106182 pub fn readConstant(p: *InfoReader, form: Form) !u64 {
107183 return switch (form) {
108 dwarf.FORM.data1, dwarf.FORM.ref1, dwarf.FORM.flag => try p.readByte(),
109 dwarf.FORM.data2, dwarf.FORM.ref2 => try p.readInt(u16),
110 dwarf.FORM.data4, dwarf.FORM.ref4 => try p.readInt(u32),
111 dwarf.FORM.data8, dwarf.FORM.ref8, dwarf.FORM.ref_sig8 => try p.readInt(u64),
112 dwarf.FORM.udata, dwarf.FORM.ref_udata => try p.readUleb128(u64),
113 dwarf.FORM.sdata => @bitCast(try p.readIleb128(i64)),
184 dw.FORM.data1, dw.FORM.ref1, dw.FORM.flag => try p.readByte(),
185 dw.FORM.data2, dw.FORM.ref2 => try p.readInt(u16),
186 dw.FORM.data4, dw.FORM.ref4 => try p.readInt(u32),
187 dw.FORM.data8, dw.FORM.ref8, dw.FORM.ref_sig8 => try p.readInt(u64),
188 dw.FORM.udata, dw.FORM.ref_udata => try p.readUleb128(u64),
189 dw.FORM.sdata => @bitCast(try p.readIleb128(i64)),
114190 else => return error.UnhandledConstantForm,
115191 };
116192 }
117193
194 pub fn readIndex(p: *InfoReader, form: Form) !u64 {
195 return switch (form) {
196 dw.FORM.strx1, dw.FORM.addrx1 => try p.readByte(),
197 dw.FORM.strx2, dw.FORM.addrx2 => try p.readInt(u16),
198 dw.FORM.strx3, dw.FORM.addrx3 => error.UnhandledDwForm,
199 dw.FORM.strx4, dw.FORM.addrx4 => try p.readInt(u32),
200 dw.FORM.strx, dw.FORM.addrx => try p.readUleb128(u64),
201 else => return error.UnhandledIndexForm,
202 };
203 }
204
118205 pub fn readString(p: *InfoReader, form: Form, cuh: CompileUnitHeader) ![:0]const u8 {
119206 switch (form) {
120 dwarf.FORM.strp => {
207 dw.FORM.strp => {
121208 const off = try p.readOffset(cuh.format);
122209 const off_u = math.cast(usize, off) orelse return error.Overflow;
123 return mem.sliceTo(@as([*:0]const u8, @ptrCast(p.strtab.ptr + off_u)), 0);
210 return mem.sliceTo(@as([*:0]const u8, @ptrCast(p.ctx.debug_str.ptr + off_u)), 0);
124211 },
125 dwarf.FORM.string => {
212 dw.FORM.string => {
126213 const start = p.pos;
127 while (p.pos < p.bytes.len) : (p.pos += 1) {
128 if (p.bytes[p.pos] == 0) break;
214 while (p.pos < p.bytes().len) : (p.pos += 1) {
215 if (p.bytes()[p.pos] == 0) break;
129216 }
130 if (p.bytes[p.pos] != 0) return error.Eof;
131 return p.bytes[start..p.pos :0];
217 if (p.bytes()[p.pos] != 0) return error.UnexpectedEndOfFile;
218 return p.bytes()[start..p.pos :0];
219 },
220 else => unreachable,
221 }
222 }
223
224 pub fn readStringIndexed(p: *InfoReader, form: Form, cuh: CompileUnitHeader, base: u64) ![:0]const u8 {
225 switch (form) {
226 dw.FORM.strx,
227 dw.FORM.strx1,
228 dw.FORM.strx2,
229 dw.FORM.strx3,
230 dw.FORM.strx4,
231 => {
232 const index = try p.readIndex(form);
233 const off = getOffset(p.ctx.debug_str_offsets, base, index, cuh.format);
234 return mem.sliceTo(@as([*:0]const u8, @ptrCast(p.ctx.debug_str.ptr + off)), 0);
132235 },
133236 else => unreachable,
134237 }
135238 }
136239
137240 pub fn readByte(p: *InfoReader) !u8 {
138 if (p.pos + 1 > p.bytes.len) return error.Eof;
241 if (p.pos + 1 > p.bytes().len) return error.UnexpectedEndOfFile;
139242 defer p.pos += 1;
140 return p.bytes[p.pos];
243 return p.bytes()[p.pos];
141244 }
142245
143246 pub fn readNBytes(p: *InfoReader, num: u64) ![]const u8 {
144247 const num_usize = math.cast(usize, num) orelse return error.Overflow;
145 if (p.pos + num_usize > p.bytes.len) return error.Eof;
248 if (p.pos + num_usize > p.bytes().len) return error.UnexpectedEndOfFile;
146249 defer p.pos += num_usize;
147 return p.bytes[p.pos..][0..num_usize];
250 return p.bytes()[p.pos..][0..num_usize];
148251 }
149252
150253 pub fn readInt(p: *InfoReader, comptime Int: type) !Int {
151 if (p.pos + @sizeOf(Int) > p.bytes.len) return error.Eof;
254 if (p.pos + @sizeOf(Int) > p.bytes().len) return error.UnexpectedEndOfFile;
152255 defer p.pos += @sizeOf(Int);
153 return mem.readInt(Int, p.bytes[p.pos..][0..@sizeOf(Int)], .little);
256 return mem.readInt(Int, p.bytes()[p.pos..][0..@sizeOf(Int)], .little);
154257 }
155258
156259 pub fn readOffset(p: *InfoReader, dw_fmt: DwarfFormat) !u64 {
......@@ -161,7 +264,7 @@ pub const InfoReader = struct {
161264 }
162265
163266 pub fn readUleb128(p: *InfoReader, comptime Type: type) !Type {
164 var stream = std.io.fixedBufferStream(p.bytes[p.pos..]);
267 var stream = std.io.fixedBufferStream(p.bytes()[p.pos..]);
165268 var creader = std.io.countingReader(stream.reader());
166269 const value: Type = try leb.readUleb128(Type, creader.reader());
167270 p.pos += math.cast(usize, creader.bytes_read) orelse return error.Overflow;
......@@ -169,7 +272,7 @@ pub const InfoReader = struct {
169272 }
170273
171274 pub fn readIleb128(p: *InfoReader, comptime Type: type) !Type {
172 var stream = std.io.fixedBufferStream(p.bytes[p.pos..]);
275 var stream = std.io.fixedBufferStream(p.bytes()[p.pos..]);
173276 var creader = std.io.countingReader(stream.reader());
174277 const value: Type = try leb.readIleb128(Type, creader.reader());
175278 p.pos += math.cast(usize, creader.bytes_read) orelse return error.Overflow;
......@@ -182,11 +285,15 @@ pub const InfoReader = struct {
182285};
183286
184287pub const AbbrevReader = struct {
185 bytes: []const u8,
288 ctx: Dwarf,
186289 pos: usize = 0,
187290
291 fn bytes(p: AbbrevReader) []const u8 {
292 return p.ctx.debug_abbrev;
293 }
294
188295 pub fn hasMore(p: AbbrevReader) bool {
189 return p.pos < p.bytes.len;
296 return p.pos < p.bytes().len;
190297 }
191298
192299 pub fn readDecl(p: *AbbrevReader) !?AbbrevDecl {
......@@ -218,13 +325,13 @@ pub const AbbrevReader = struct {
218325 }
219326
220327 pub fn readByte(p: *AbbrevReader) !u8 {
221 if (p.pos + 1 > p.bytes.len) return error.Eof;
328 if (p.pos + 1 > p.bytes().len) return error.Eof;
222329 defer p.pos += 1;
223 return p.bytes[p.pos];
330 return p.bytes()[p.pos];
224331 }
225332
226333 pub fn readUleb128(p: *AbbrevReader, comptime Type: type) !Type {
227 var stream = std.io.fixedBufferStream(p.bytes[p.pos..]);
334 var stream = std.io.fixedBufferStream(p.bytes()[p.pos..]);
228335 var creader = std.io.countingReader(stream.reader());
229336 const value: Type = try leb.readUleb128(Type, creader.reader());
230337 p.pos += math.cast(usize, creader.bytes_read) orelse return error.Overflow;
......@@ -254,9 +361,10 @@ const AbbrevAttr = struct {
254361const CompileUnitHeader = struct {
255362 format: DwarfFormat,
256363 length: u64,
257 version: u16,
364 version: Version,
258365 debug_abbrev_offset: u64,
259366 address_size: u8,
367 unit_type: u8,
260368};
261369
262370const Die = struct {
......@@ -269,18 +377,24 @@ const DwarfFormat = enum {
269377 dwarf64,
270378};
271379
272const dwarf = std.dwarf;
380const dw = std.dwarf;
273381const leb = std.leb;
274382const log = std.log.scoped(.link);
275383const math = std.math;
276384const mem = std.mem;
277385const std = @import("std");
278
279const At = u64;
280const Code = u64;
281const Form = u64;
282const Tag = u64;
283
284pub const AT = dwarf.AT;
285pub const FORM = dwarf.FORM;
286pub const TAG = dwarf.TAG;
386const Allocator = mem.Allocator;
387const Dwarf = @This();
388const File = @import("file.zig").File;
389const MachO = @import("../MachO.zig");
390const Object = @import("Object.zig");
391
392pub const At = u64;
393pub const Code = u64;
394pub const Form = u64;
395pub const Tag = u64;
396pub const Version = u16;
397
398pub const AT = dw.AT;
399pub const FORM = dw.FORM;
400pub const TAG = dw.TAG;
src/link/MachO/Object.zig+94-132
......@@ -1359,151 +1359,102 @@ fn parseDebugInfo(self: *Object, macho_file: *MachO) !void {
13591359 defer tracy.end();
13601360
13611361 const gpa = macho_file.base.comp.gpa;
1362 const file = macho_file.getFileHandle(self.file_handle);
13621363
1363 var debug_info_index: ?usize = null;
1364 var debug_abbrev_index: ?usize = null;
1365 var debug_str_index: ?usize = null;
1364 var dwarf: Dwarf = .{};
1365 defer dwarf.deinit(gpa);
13661366
13671367 for (self.sections.items(.header), 0..) |sect, index| {
1368 const n_sect: u8 = @intCast(index);
13681369 if (sect.attrs() & macho.S_ATTR_DEBUG == 0) continue;
1369 if (mem.eql(u8, sect.sectName(), "__debug_info")) debug_info_index = index;
1370 if (mem.eql(u8, sect.sectName(), "__debug_abbrev")) debug_abbrev_index = index;
1371 if (mem.eql(u8, sect.sectName(), "__debug_str")) debug_str_index = index;
1370 if (mem.eql(u8, sect.sectName(), "__debug_info")) {
1371 dwarf.debug_info = try self.readSectionData(gpa, file, n_sect);
1372 }
1373 if (mem.eql(u8, sect.sectName(), "__debug_abbrev")) {
1374 dwarf.debug_abbrev = try self.readSectionData(gpa, file, n_sect);
1375 }
1376 if (mem.eql(u8, sect.sectName(), "__debug_str")) {
1377 dwarf.debug_str = try self.readSectionData(gpa, file, n_sect);
1378 }
1379 if (mem.eql(u8, sect.sectName(), "__debug_str_offs")) {
1380 dwarf.debug_str_offsets = try self.readSectionData(gpa, file, n_sect);
1381 }
13721382 }
13731383
1374 if (debug_info_index == null or debug_abbrev_index == null) return;
1375
1376 const slice = self.sections.slice();
1377 const file = macho_file.getFileHandle(self.file_handle);
1378 const debug_info = blk: {
1379 const sect = slice.items(.header)[debug_info_index.?];
1380 const size = math.cast(usize, sect.size) orelse return error.Overflow;
1381 const data = try gpa.alloc(u8, size);
1382 const amt = try file.preadAll(data, sect.offset + self.offset);
1383 if (amt != data.len) return error.InputOutput;
1384 break :blk data;
1385 };
1386 defer gpa.free(debug_info);
1387 const debug_abbrev = blk: {
1388 const sect = slice.items(.header)[debug_abbrev_index.?];
1389 const size = math.cast(usize, sect.size) orelse return error.Overflow;
1390 const data = try gpa.alloc(u8, size);
1391 const amt = try file.preadAll(data, sect.offset + self.offset);
1392 if (amt != data.len) return error.InputOutput;
1393 break :blk data;
1394 };
1395 defer gpa.free(debug_abbrev);
1396 const debug_str = if (debug_str_index) |sid| blk: {
1397 const sect = slice.items(.header)[sid];
1398 const size = math.cast(usize, sect.size) orelse return error.Overflow;
1399 const data = try gpa.alloc(u8, size);
1400 const amt = try file.preadAll(data, sect.offset + self.offset);
1401 if (amt != data.len) return error.InputOutput;
1402 break :blk data;
1403 } else &[0]u8{};
1404 defer gpa.free(debug_str);
1405
1406 self.compile_unit = self.findCompileUnit(.{
1407 .gpa = gpa,
1408 .debug_info = debug_info,
1409 .debug_abbrev = debug_abbrev,
1410 .debug_str = debug_str,
1411 }) catch null; // TODO figure out what errors are fatal, and when we silently fail
1412}
1413
1414fn findCompileUnit(self: *Object, args: struct {
1415 gpa: Allocator,
1416 debug_info: []const u8,
1417 debug_abbrev: []const u8,
1418 debug_str: []const u8,
1419}) !CompileUnit {
1420 var cu_wip: struct {
1421 comp_dir: ?[:0]const u8 = null,
1422 tu_name: ?[:0]const u8 = null,
1423 } = .{};
1424
1425 const gpa = args.gpa;
1426 var info_reader = dwarf.InfoReader{ .bytes = args.debug_info, .strtab = args.debug_str };
1427 var abbrev_reader = dwarf.AbbrevReader{ .bytes = args.debug_abbrev };
1428
1429 const cuh = try info_reader.readCompileUnitHeader();
1430 try abbrev_reader.seekTo(cuh.debug_abbrev_offset);
1431
1432 const cu_decl = (try abbrev_reader.readDecl()) orelse return error.Eof;
1433 if (cu_decl.tag != dwarf.TAG.compile_unit) return error.UnexpectedTag;
1434
1435 try info_reader.seekToDie(cu_decl.code, cuh, &abbrev_reader);
1436
1437 while (try abbrev_reader.readAttr()) |attr| switch (attr.at) {
1438 dwarf.AT.name => {
1439 cu_wip.tu_name = try info_reader.readString(attr.form, cuh);
1440 },
1441 dwarf.AT.comp_dir => {
1442 cu_wip.comp_dir = try info_reader.readString(attr.form, cuh);
1443 },
1444 else => switch (attr.form) {
1445 dwarf.FORM.sec_offset,
1446 dwarf.FORM.ref_addr,
1447 => {
1448 _ = try info_reader.readOffset(cuh.format);
1449 },
1384 if (dwarf.debug_info.len == 0) return;
14501385
1451 dwarf.FORM.addr => {
1452 _ = try info_reader.readNBytes(cuh.address_size);
1453 },
1386 self.compile_unit = try self.findCompileUnit(gpa, dwarf, macho_file);
1387}
14541388
1455 dwarf.FORM.block1,
1456 dwarf.FORM.block2,
1457 dwarf.FORM.block4,
1458 dwarf.FORM.block,
1459 => {
1460 _ = try info_reader.readBlock(attr.form);
1461 },
1389fn findCompileUnit(self: *Object, gpa: Allocator, ctx: Dwarf, macho_file: *MachO) !CompileUnit {
1390 var info_reader = Dwarf.InfoReader{ .ctx = ctx };
1391 var abbrev_reader = Dwarf.AbbrevReader{ .ctx = ctx };
14621392
1463 dwarf.FORM.exprloc => {
1464 _ = try info_reader.readExprLoc();
1465 },
1393 const cuh = try info_reader.readCompileUnitHeader(macho_file);
1394 try abbrev_reader.seekTo(cuh.debug_abbrev_offset);
14661395
1467 dwarf.FORM.flag_present => {},
1468
1469 dwarf.FORM.data1,
1470 dwarf.FORM.ref1,
1471 dwarf.FORM.flag,
1472 dwarf.FORM.data2,
1473 dwarf.FORM.ref2,
1474 dwarf.FORM.data4,
1475 dwarf.FORM.ref4,
1476 dwarf.FORM.data8,
1477 dwarf.FORM.ref8,
1478 dwarf.FORM.ref_sig8,
1479 dwarf.FORM.udata,
1480 dwarf.FORM.ref_udata,
1481 dwarf.FORM.sdata,
1482 => {
1483 _ = try info_reader.readConstant(attr.form);
1484 },
1396 const cu_decl = (try abbrev_reader.readDecl()) orelse return error.UnexpectedEndOfFile;
1397 if (cu_decl.tag != Dwarf.TAG.compile_unit) return error.UnexpectedTag;
14851398
1486 dwarf.FORM.strp,
1487 dwarf.FORM.string,
1488 => {
1489 _ = try info_reader.readString(attr.form, cuh);
1490 },
1399 try info_reader.seekToDie(cu_decl.code, cuh, &abbrev_reader, macho_file);
14911400
1492 else => {
1493 // TODO actual errors?
1494 log.err("unhandled DW_FORM_* value with identifier {x}", .{attr.form});
1495 return error.UnhandledForm;
1496 },
1497 },
1401 const Pos = struct {
1402 pos: usize,
1403 form: Dwarf.Form,
14981404 };
1499
1500 if (cu_wip.comp_dir == null) return error.MissingCompDir;
1501 if (cu_wip.tu_name == null) return error.MissingTuName;
1502
1503 return .{
1504 .comp_dir = try self.addString(gpa, cu_wip.comp_dir.?),
1505 .tu_name = try self.addString(gpa, cu_wip.tu_name.?),
1405 var saved: struct {
1406 tu_name: ?Pos,
1407 comp_dir: ?Pos,
1408 str_offsets_base: ?Pos,
1409 } = .{
1410 .tu_name = null,
1411 .comp_dir = null,
1412 .str_offsets_base = null,
15061413 };
1414 while (try abbrev_reader.readAttr()) |attr| {
1415 const pos: Pos = .{ .pos = info_reader.pos, .form = attr.form };
1416 switch (attr.at) {
1417 Dwarf.AT.name => saved.tu_name = pos,
1418 Dwarf.AT.comp_dir => saved.comp_dir = pos,
1419 Dwarf.AT.str_offsets_base => saved.str_offsets_base = pos,
1420 else => {},
1421 }
1422 try info_reader.skip(attr.form, cuh, macho_file);
1423 }
1424
1425 if (saved.comp_dir == null) return error.MissingCompDir;
1426 if (saved.tu_name == null) return error.MissingTuName;
1427
1428 const str_offsets_base: ?u64 = if (saved.str_offsets_base) |str_offsets_base| str_offsets_base: {
1429 try info_reader.seekTo(str_offsets_base.pos);
1430 break :str_offsets_base try info_reader.readOffset(cuh.format);
1431 } else null;
1432
1433 var cu: CompileUnit = .{ .comp_dir = .{}, .tu_name = .{} };
1434 for (&[_]struct { Pos, *MachO.String }{
1435 .{ saved.comp_dir.?, &cu.comp_dir },
1436 .{ saved.tu_name.?, &cu.tu_name },
1437 }) |tuple| {
1438 const pos, const str_offset_ptr = tuple;
1439 try info_reader.seekTo(pos.pos);
1440 str_offset_ptr.* = switch (pos.form) {
1441 Dwarf.FORM.strp,
1442 Dwarf.FORM.string,
1443 => try self.addString(gpa, try info_reader.readString(pos.form, cuh)),
1444 Dwarf.FORM.strx,
1445 Dwarf.FORM.strx1,
1446 Dwarf.FORM.strx2,
1447 Dwarf.FORM.strx3,
1448 Dwarf.FORM.strx4,
1449 => blk: {
1450 const base = str_offsets_base orelse return error.MalformedDwarf;
1451 break :blk try self.addString(gpa, try info_reader.readStringIndexed(pos.form, cuh, base));
1452 },
1453 else => return error.InvalidForm,
1454 };
1455 }
1456
1457 return cu;
15071458}
15081459
15091460pub fn resolveSymbols(self: *Object, macho_file: *MachO) !void {
......@@ -2561,6 +2512,17 @@ pub fn getUnwindRecord(self: *Object, index: UnwindInfo.Record.Index) *UnwindInf
25612512 return &self.unwind_records.items[index];
25622513}
25632514
2515/// Caller owns the memory.
2516pub fn readSectionData(self: Object, allocator: Allocator, file: File.Handle, n_sect: u8) ![]u8 {
2517 const header = self.sections.items(.header)[n_sect];
2518 const size = math.cast(usize, header.size) orelse return error.Overflow;
2519 const data = try allocator.alloc(u8, size);
2520 const amt = try file.preadAll(data, header.offset + self.offset);
2521 errdefer allocator.free(data);
2522 if (amt != data.len) return error.InputOutput;
2523 return data;
2524}
2525
25642526pub fn format(
25652527 self: *Object,
25662528 comptime unused_fmt_string: []const u8,
......@@ -3219,7 +3181,6 @@ const aarch64 = struct {
32193181};
32203182
32213183const assert = std.debug.assert;
3222const dwarf = @import("dwarf.zig");
32233184const eh_frame = @import("eh_frame.zig");
32243185const log = std.log.scoped(.link);
32253186const macho = std.macho;
......@@ -3233,6 +3194,7 @@ const Allocator = mem.Allocator;
32333194const Archive = @import("Archive.zig");
32343195const Atom = @import("Atom.zig");
32353196const Cie = eh_frame.Cie;
3197const Dwarf = @import("Dwarf.zig");
32363198const Fde = eh_frame.Fde;
32373199const File = @import("file.zig").File;
32383200const LoadCommandIterator = macho.LoadCommandIterator;