authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-05-11 01:52:45-04:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-07-20 22:58:13-04:00
log69399fbb82ea74fce4fb6bbfec5ab2cbfa435c1a
treede5962dc4d073de59e317cdd76546d1b92b8cfee
parenta0a40c2e7e177bed7032ddd3d271016127ae9205

- add default register rule

- fixup eh pointer decoding

3 files changed, 95 insertions(+), 53 deletions(-)

lib/std/dwarf.zig+61-28
......@@ -1494,18 +1494,34 @@ pub const DwarfInfo = struct {
14941494 }
14951495
14961496 const id_len = @as(u8, if (is_64) 8 else 4);
1497 const entry_bytes = eh_frame[stream.pos..][0..length - id_len];
1497 const entry_bytes = eh_frame[stream.pos..][0 .. length - id_len];
14981498 const id = try reader.readInt(u32, di.endian);
14991499
15001500 // TODO: Get section_offset here (pass in from headers)
15011501
15021502 if (id == 0) {
1503 const cie = try CommonInformationEntry.parse(entry_bytes, @ptrToInt(eh_frame.ptr), 0, length_offset, @sizeOf(usize), di.endian);
1503 const cie = try CommonInformationEntry.parse(
1504 entry_bytes,
1505 @ptrToInt(eh_frame.ptr),
1506 0,
1507 true,
1508 length_offset,
1509 @sizeOf(usize),
1510 di.endian,
1511 );
15041512 try di.cie_map.put(allocator, length_offset, cie);
15051513 } else {
15061514 const cie_offset = stream.pos - 4 - id;
15071515 const cie = di.cie_map.get(cie_offset) orelse return badDwarf();
1508 const fde = try FrameDescriptionEntry.parse(entry_bytes, @ptrToInt(eh_frame.ptr), 0, cie, @sizeOf(usize), di.endian);
1516 const fde = try FrameDescriptionEntry.parse(
1517 entry_bytes,
1518 @ptrToInt(eh_frame.ptr),
1519 0,
1520 true,
1521 cie,
1522 @sizeOf(usize),
1523 di.endian,
1524 );
15091525 try di.fde_list.append(allocator, fde);
15101526 }
15111527 }
......@@ -1557,6 +1573,11 @@ const EhPointerContext = struct {
15571573 // The address of the pointer field itself
15581574 pc_rel_base: u64,
15591575
1576 // Whether or not to follow indirect pointers. This should only be
1577 // used when decoding pointers at runtime using the current process's
1578 // debug info.
1579 follow_indirect: bool,
1580
15601581 // These relative addressing modes are only used in specific cases, and
15611582 // might not be available / required in all parsing contexts
15621583 data_rel_base: ?u64 = null,
......@@ -1570,7 +1591,7 @@ fn readEhPointer(reader: anytype, enc: u8, addr_size_bytes: u8, ctx: EhPointerCo
15701591 const value: union(enum) {
15711592 signed: i64,
15721593 unsigned: u64,
1573 } = switch (enc & 0x0f) {
1594 } = switch (enc & EH.PE.type_mask) {
15741595 EH.PE.absptr => .{
15751596 .unsigned = switch (addr_size_bytes) {
15761597 2 => try reader.readInt(u16, endian),
......@@ -1590,33 +1611,31 @@ fn readEhPointer(reader: anytype, enc: u8, addr_size_bytes: u8, ctx: EhPointerCo
15901611 else => return badDwarf(),
15911612 };
15921613
1593 const relative_to = enc & 0xf0;
1594 var base = switch (relative_to) {
1614 var base = switch (enc & EH.PE.rel_mask) {
15951615 EH.PE.pcrel => ctx.pc_rel_base,
15961616 EH.PE.textrel => ctx.text_rel_base orelse return error.PointerBaseNotSpecified,
15971617 EH.PE.datarel => ctx.data_rel_base orelse return error.PointerBaseNotSpecified,
15981618 EH.PE.funcrel => ctx.function_rel_base orelse return error.PointerBaseNotSpecified,
1599 EH.PE.indirect => {
1600 switch (addr_size_bytes) {
1601 2 => return @intToPtr(*const u16, value.unsigned).*,
1602 4 => return @intToPtr(*const u32, value.unsigned).*,
1603 8 => return @intToPtr(*const u64, value.unsigned).*,
1604 else => return error.UnsupportedAddrSize,
1605 }
1606 },
16071619 else => null,
16081620 };
16091621
1610 if (base) |b| {
1611 return switch (value) {
1612 .signed => |s| @intCast(u64, s + @intCast(i64, b)),
1613 .unsigned => |u| u + b,
1622 const ptr = if (base) |b| switch (value) {
1623 .signed => |s| @intCast(u64, s + @intCast(i64, b)),
1624 .unsigned => |u| u + b,
1625 } else switch (value) {
1626 .signed => |s| @intCast(u64, s),
1627 .unsigned => |u| u,
1628 };
1629
1630 if ((enc & EH.PE.indirect) > 0 and ctx.follow_indirect) {
1631 return switch (addr_size_bytes) {
1632 2 => return @intToPtr(*const u16, ptr).*,
1633 4 => return @intToPtr(*const u32, ptr).*,
1634 8 => return @intToPtr(*const u64, ptr).*,
1635 else => return error.UnsupportedAddrSize,
16141636 };
16151637 } else {
1616 return switch (value) {
1617 .signed => |s| @intCast(u64, s),
1618 .unsigned => |u| u,
1619 };
1638 return ptr;
16201639 }
16211640}
16221641
......@@ -1668,6 +1687,7 @@ pub const CommonInformationEntry = struct {
16681687 cie_bytes: []const u8,
16691688 section_base: u64,
16701689 section_offset: u64,
1690 is_runtime: bool,
16711691 length_offset: u64,
16721692 addr_size_bytes: u8,
16731693 endian: std.builtin.Endian,
......@@ -1735,7 +1755,10 @@ pub const CommonInformationEntry = struct {
17351755 reader,
17361756 personality_enc.?,
17371757 addr_size_bytes,
1738 .{ .pc_rel_base = @ptrToInt(&cie_bytes[stream.pos]) - section_base + section_offset },
1758 .{
1759 .pc_rel_base = @ptrToInt(&cie_bytes[stream.pos]) - section_base + section_offset,
1760 .follow_indirect = is_runtime,
1761 },
17391762 endian,
17401763 );
17411764 },
......@@ -1785,6 +1808,7 @@ pub const FrameDescriptionEntry = struct {
17851808 fde_bytes: []const u8,
17861809 section_base: u64,
17871810 section_offset: u64,
1811 is_runtime: bool,
17881812 cie: CommonInformationEntry,
17891813 addr_size_bytes: u8,
17901814 endian: std.builtin.Endian,
......@@ -1798,15 +1822,21 @@ pub const FrameDescriptionEntry = struct {
17981822 reader,
17991823 cie.fde_pointer_enc,
18001824 addr_size_bytes,
1801 .{ .pc_rel_base = @ptrToInt(&fde_bytes[stream.pos]) - section_base + section_offset },
1825 .{
1826 .pc_rel_base = @ptrToInt(&fde_bytes[stream.pos]) - section_base + section_offset,
1827 .follow_indirect = is_runtime,
1828 },
18021829 endian,
18031830 ) orelse return badDwarf();
18041831
18051832 const pc_range = try readEhPointer(
18061833 reader,
1807 cie.fde_pointer_enc & 0x0f,
1834 cie.fde_pointer_enc,
18081835 addr_size_bytes,
1809 .{ .pc_rel_base = @ptrToInt(&fde_bytes[stream.pos]) - section_base + section_offset },
1836 .{
1837 .pc_rel_base = 0,
1838 .follow_indirect = false,
1839 },
18101840 endian,
18111841 ) orelse return badDwarf();
18121842
......@@ -1819,9 +1849,12 @@ pub const FrameDescriptionEntry = struct {
18191849 const lsda_pointer = if (cie.lsda_pointer_enc != EH.PE.omit)
18201850 try readEhPointer(
18211851 reader,
1822 cie.lsda_pointer_enc & 0x0f,
1852 cie.lsda_pointer_enc,
18231853 addr_size_bytes,
1824 .{ .pc_rel_base = @ptrToInt(&fde_bytes[stream.pos]) },
1854 .{
1855 .pc_rel_base = @ptrToInt(&fde_bytes[stream.pos]) - section_base + section_offset,
1856 .follow_indirect = is_runtime,
1857 },
18251858 endian,
18261859 )
18271860 else
lib/std/dwarf/EH.zig+6
......@@ -1,6 +1,10 @@
11pub const PE = struct {
22 pub const absptr = 0x00;
33
4 pub const size_mask = 0x7;
5 pub const sign_mask = 0x8;
6 pub const type_mask = size_mask | sign_mask;
7
48 pub const uleb128 = 0x01;
59 pub const udata2 = 0x02;
610 pub const udata4 = 0x03;
......@@ -10,11 +14,13 @@ pub const PE = struct {
1014 pub const sdata4 = 0x0B;
1115 pub const sdata8 = 0x0C;
1216
17 pub const rel_mask = 0x70;
1318 pub const pcrel = 0x10;
1419 pub const textrel = 0x20;
1520 pub const datarel = 0x30;
1621 pub const funcrel = 0x40;
1722 pub const aligned = 0x50;
23
1824 pub const indirect = 0x80;
1925
2026 pub const omit = 0xff;
lib/std/dwarf/call_frame.zig+28-25
......@@ -216,16 +216,35 @@ pub const Instruction = union(Opcode) {
216216 }
217217};
218218
219/// See section 6.4.1 of the DWARF5 specification
219/// This is a virtual machine that runs DWARF call frame instructions.
220/// See section 6.4.1 of the DWARF5 specification.
220221pub const VirtualMachine = struct {
222
221223 const RegisterRule = union(enum) {
224 // The spec says that the default rule for each column is the undefined rule.
225 // However, it also allows ABI / compiler authors to specify alternate defaults, so
226 // there is a distinction made here.
227 default: void,
228
222229 undefined: void,
223230 same_value: void,
231
232 // offset(N)
224233 offset: i64,
234
235 // val_offset(N)
225236 val_offset: i64,
237
238 // register(R)
226239 register: u8,
240
241 // expression(E)
227242 expression: []const u8,
243
244 // val_expression(E)
228245 val_expression: []const u8,
246
247 // Augmenter-defined rule
229248 architectural: void,
230249 };
231250
......@@ -248,7 +267,7 @@ pub const VirtualMachine = struct {
248267 pub const Column = struct {
249268 /// Register can only null in the case of the CFA column
250269 register: ?u8 = null,
251 rule: RegisterRule = .{ .undefined = {} },
270 rule: RegisterRule = .{ .default = {} },
252271 };
253272
254273 const ColumnRange = struct {
......@@ -264,13 +283,6 @@ pub const VirtualMachine = struct {
264283 /// The result of executing the CIE's initial_instructions
265284 cie_row: ?Row = null,
266285
267 pub fn reset(self: *VirtualMachine) void {
268 self.stack.clearRetainingCapacity();
269 self.columns.clearRetainingCapacity();
270 self.current_row = .{};
271 self.cie_row = null;
272 }
273
274286 pub fn deinit(self: *VirtualMachine, allocator: std.mem.Allocator) void {
275287 self.stack.deinit(allocator);
276288 self.columns.deinit(allocator);
......@@ -357,7 +369,7 @@ pub const VirtualMachine = struct {
357369
358370 /// Executes a single instruction.
359371 /// If this instruction is from the CIE, `is_initial` should be set.
360 /// Returns the value of `current_row` before executing this instruction
372 /// Returns the value of `current_row` before executing this instruction.
361373 pub fn step(
362374 self: *VirtualMachine,
363375 allocator: std.mem.Allocator,
......@@ -367,13 +379,16 @@ pub const VirtualMachine = struct {
367379 ) !Row {
368380 // CIE instructions must be run before FDE instructions
369381 assert(!is_initial or self.cie_row == null);
370 if (!is_initial and self.cie_row == null) self.cie_row = self.current_row;
382 if (!is_initial and self.cie_row == null) {
383 self.cie_row = self.current_row;
384 self.current_row.copy_on_write = true;
385 }
371386
372387 const prev_row = self.current_row;
373388 switch (instruction) {
374389 .set_loc => |i| {
375390 if (i.operands.address <= self.current_row.offset) return error.InvalidOperation;
376 // TODO: Check cie.segment_selector_size != for DWARFV4
391 // TODO: Check cie.segment_selector_size != 0 for DWARFV4
377392 self.current_row.offset = i.operands.address;
378393 },
379394 inline .advance_loc,
......@@ -392,11 +407,6 @@ pub const VirtualMachine = struct {
392407 const column = try self.getOrAddColumn(allocator, i.operands.register);
393408 column.rule = .{ .offset = @intCast(i64, i.operands.offset) * cie.data_alignment_factor };
394409 },
395 // .offset_extended_sf => |i| {
396 // try self.resolveCopyOnWrite(allocator);
397 // const column = try self.getOrAddColumn(allocator, i.operands.register);
398 // column.rule = .{ .offset = i.operands.offset * cie.data_alignment_factor };
399 // },
400410 inline .restore,
401411 .restore_extended,
402412 => |i| {
......@@ -405,7 +415,7 @@ pub const VirtualMachine = struct {
405415 const column = try self.getOrAddColumn(allocator, i.operands.register);
406416 column.rule = for (self.rowColumns(cie_row)) |cie_column| {
407417 if (cie_column.register == i.operands.register) break cie_column.rule;
408 } else .{ .undefined = {} };
418 } else .{ .default = {} };
409419 } else return error.InvalidOperation;
410420 },
411421 .nop => {},
......@@ -427,13 +437,6 @@ pub const VirtualMachine = struct {
427437 .remember_state => {
428438 try self.stack.append(allocator, self.current_row.columns);
429439 self.current_row.copy_on_write = true;
430
431 // const new_start = self.columns.items.len;
432 // if (self.current_row.columns.len > 0) {
433 // try self.columns.ensureUnusedCapacity(allocator, self.current_row.columns.len);
434 // self.columns.appendSliceAssumeCapacity(self.rowColumns(self.current_row));
435 // self.current_row.columns.start = new_start;
436 // }
437440 },
438441 .restore_state => {
439442 const restored_columns = self.stack.popOrNull() orelse return error.InvalidOperation;