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 {...@@ -1494,18 +1494,34 @@ pub const DwarfInfo = struct {
1494 }1494 }
14951495
1496 const id_len = @as(u8, if (is_64) 8 else 4);1496 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];
1498 const id = try reader.readInt(u32, di.endian);1498 const id = try reader.readInt(u32, di.endian);
14991499
1500 // TODO: Get section_offset here (pass in from headers)1500 // TODO: Get section_offset here (pass in from headers)
15011501
1502 if (id == 0) {1502 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 );
1504 try di.cie_map.put(allocator, length_offset, cie);1512 try di.cie_map.put(allocator, length_offset, cie);
1505 } else {1513 } else {
1506 const cie_offset = stream.pos - 4 - id;1514 const cie_offset = stream.pos - 4 - id;
1507 const cie = di.cie_map.get(cie_offset) orelse return badDwarf();1515 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 );
1509 try di.fde_list.append(allocator, fde);1525 try di.fde_list.append(allocator, fde);
1510 }1526 }
1511 }1527 }
...@@ -1557,6 +1573,11 @@ const EhPointerContext = struct {...@@ -1557,6 +1573,11 @@ const EhPointerContext = struct {
1557 // The address of the pointer field itself1573 // The address of the pointer field itself
1558 pc_rel_base: u64,1574 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
1560 // These relative addressing modes are only used in specific cases, and1581 // These relative addressing modes are only used in specific cases, and
1561 // might not be available / required in all parsing contexts1582 // might not be available / required in all parsing contexts
1562 data_rel_base: ?u64 = null,1583 data_rel_base: ?u64 = null,
...@@ -1570,7 +1591,7 @@ fn readEhPointer(reader: anytype, enc: u8, addr_size_bytes: u8, ctx: EhPointerCo...@@ -1570,7 +1591,7 @@ fn readEhPointer(reader: anytype, enc: u8, addr_size_bytes: u8, ctx: EhPointerCo
1570 const value: union(enum) {1591 const value: union(enum) {
1571 signed: i64,1592 signed: i64,
1572 unsigned: u64,1593 unsigned: u64,
1573 } = switch (enc & 0x0f) {1594 } = switch (enc & EH.PE.type_mask) {
1574 EH.PE.absptr => .{1595 EH.PE.absptr => .{
1575 .unsigned = switch (addr_size_bytes) {1596 .unsigned = switch (addr_size_bytes) {
1576 2 => try reader.readInt(u16, endian),1597 2 => try reader.readInt(u16, endian),
...@@ -1590,33 +1611,31 @@ fn readEhPointer(reader: anytype, enc: u8, addr_size_bytes: u8, ctx: EhPointerCo...@@ -1590,33 +1611,31 @@ fn readEhPointer(reader: anytype, enc: u8, addr_size_bytes: u8, ctx: EhPointerCo
1590 else => return badDwarf(),1611 else => return badDwarf(),
1591 };1612 };
15921613
1593 const relative_to = enc & 0xf0;1614 var base = switch (enc & EH.PE.rel_mask) {
1594 var base = switch (relative_to) {
1595 EH.PE.pcrel => ctx.pc_rel_base,1615 EH.PE.pcrel => ctx.pc_rel_base,
1596 EH.PE.textrel => ctx.text_rel_base orelse return error.PointerBaseNotSpecified,1616 EH.PE.textrel => ctx.text_rel_base orelse return error.PointerBaseNotSpecified,
1597 EH.PE.datarel => ctx.data_rel_base orelse return error.PointerBaseNotSpecified,1617 EH.PE.datarel => ctx.data_rel_base orelse return error.PointerBaseNotSpecified,
1598 EH.PE.funcrel => ctx.function_rel_base orelse return error.PointerBaseNotSpecified,1618 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 },
1607 else => null,1619 else => null,
1608 };1620 };
16091621
1610 if (base) |b| {1622 const ptr = if (base) |b| switch (value) {
1611 return switch (value) {1623 .signed => |s| @intCast(u64, s + @intCast(i64, b)),
1612 .signed => |s| @intCast(u64, s + @intCast(i64, b)),1624 .unsigned => |u| u + b,
1613 .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,
1614 };1636 };
1615 } else {1637 } else {
1616 return switch (value) {1638 return ptr;
1617 .signed => |s| @intCast(u64, s),
1618 .unsigned => |u| u,
1619 };
1620 }1639 }
1621}1640}
16221641
...@@ -1668,6 +1687,7 @@ pub const CommonInformationEntry = struct {...@@ -1668,6 +1687,7 @@ pub const CommonInformationEntry = struct {
1668 cie_bytes: []const u8,1687 cie_bytes: []const u8,
1669 section_base: u64,1688 section_base: u64,
1670 section_offset: u64,1689 section_offset: u64,
1690 is_runtime: bool,
1671 length_offset: u64,1691 length_offset: u64,
1672 addr_size_bytes: u8,1692 addr_size_bytes: u8,
1673 endian: std.builtin.Endian,1693 endian: std.builtin.Endian,
...@@ -1735,7 +1755,10 @@ pub const CommonInformationEntry = struct {...@@ -1735,7 +1755,10 @@ pub const CommonInformationEntry = struct {
1735 reader,1755 reader,
1736 personality_enc.?,1756 personality_enc.?,
1737 addr_size_bytes,1757 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 },
1739 endian,1762 endian,
1740 );1763 );
1741 },1764 },
...@@ -1785,6 +1808,7 @@ pub const FrameDescriptionEntry = struct {...@@ -1785,6 +1808,7 @@ pub const FrameDescriptionEntry = struct {
1785 fde_bytes: []const u8,1808 fde_bytes: []const u8,
1786 section_base: u64,1809 section_base: u64,
1787 section_offset: u64,1810 section_offset: u64,
1811 is_runtime: bool,
1788 cie: CommonInformationEntry,1812 cie: CommonInformationEntry,
1789 addr_size_bytes: u8,1813 addr_size_bytes: u8,
1790 endian: std.builtin.Endian,1814 endian: std.builtin.Endian,
...@@ -1798,15 +1822,21 @@ pub const FrameDescriptionEntry = struct {...@@ -1798,15 +1822,21 @@ pub const FrameDescriptionEntry = struct {
1798 reader,1822 reader,
1799 cie.fde_pointer_enc,1823 cie.fde_pointer_enc,
1800 addr_size_bytes,1824 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 },
1802 endian,1829 endian,
1803 ) orelse return badDwarf();1830 ) orelse return badDwarf();
18041831
1805 const pc_range = try readEhPointer(1832 const pc_range = try readEhPointer(
1806 reader,1833 reader,
1807 cie.fde_pointer_enc & 0x0f,1834 cie.fde_pointer_enc,
1808 addr_size_bytes,1835 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 },
1810 endian,1840 endian,
1811 ) orelse return badDwarf();1841 ) orelse return badDwarf();
18121842
...@@ -1819,9 +1849,12 @@ pub const FrameDescriptionEntry = struct {...@@ -1819,9 +1849,12 @@ pub const FrameDescriptionEntry = struct {
1819 const lsda_pointer = if (cie.lsda_pointer_enc != EH.PE.omit)1849 const lsda_pointer = if (cie.lsda_pointer_enc != EH.PE.omit)
1820 try readEhPointer(1850 try readEhPointer(
1821 reader,1851 reader,
1822 cie.lsda_pointer_enc & 0x0f,1852 cie.lsda_pointer_enc,
1823 addr_size_bytes,1853 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 },
1825 endian,1858 endian,
1826 )1859 )
1827 else1860 else
lib/std/dwarf/EH.zig+6
...@@ -1,6 +1,10 @@...@@ -1,6 +1,10 @@
1pub const PE = struct {1pub const PE = struct {
2 pub const absptr = 0x00;2 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
4 pub const uleb128 = 0x01;8 pub const uleb128 = 0x01;
5 pub const udata2 = 0x02;9 pub const udata2 = 0x02;
6 pub const udata4 = 0x03;10 pub const udata4 = 0x03;
...@@ -10,11 +14,13 @@ pub const PE = struct {...@@ -10,11 +14,13 @@ pub const PE = struct {
10 pub const sdata4 = 0x0B;14 pub const sdata4 = 0x0B;
11 pub const sdata8 = 0x0C;15 pub const sdata8 = 0x0C;
1216
17 pub const rel_mask = 0x70;
13 pub const pcrel = 0x10;18 pub const pcrel = 0x10;
14 pub const textrel = 0x20;19 pub const textrel = 0x20;
15 pub const datarel = 0x30;20 pub const datarel = 0x30;
16 pub const funcrel = 0x40;21 pub const funcrel = 0x40;
17 pub const aligned = 0x50;22 pub const aligned = 0x50;
23
18 pub const indirect = 0x80;24 pub const indirect = 0x80;
1925
20 pub const omit = 0xff;26 pub const omit = 0xff;
lib/std/dwarf/call_frame.zig+28-25
...@@ -216,16 +216,35 @@ pub const Instruction = union(Opcode) {...@@ -216,16 +216,35 @@ pub const Instruction = union(Opcode) {
216 }216 }
217};217};
218218
219/// See section 6.4.1 of the DWARF5 specification219/// This is a virtual machine that runs DWARF call frame instructions.
220/// See section 6.4.1 of the DWARF5 specification.
220pub const VirtualMachine = struct {221pub const VirtualMachine = struct {
222
221 const RegisterRule = union(enum) {223 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
222 undefined: void,229 undefined: void,
223 same_value: void,230 same_value: void,
231
232 // offset(N)
224 offset: i64,233 offset: i64,
234
235 // val_offset(N)
225 val_offset: i64,236 val_offset: i64,
237
238 // register(R)
226 register: u8,239 register: u8,
240
241 // expression(E)
227 expression: []const u8,242 expression: []const u8,
243
244 // val_expression(E)
228 val_expression: []const u8,245 val_expression: []const u8,
246
247 // Augmenter-defined rule
229 architectural: void,248 architectural: void,
230 };249 };
231250
...@@ -248,7 +267,7 @@ pub const VirtualMachine = struct {...@@ -248,7 +267,7 @@ pub const VirtualMachine = struct {
248 pub const Column = struct {267 pub const Column = struct {
249 /// Register can only null in the case of the CFA column268 /// Register can only null in the case of the CFA column
250 register: ?u8 = null,269 register: ?u8 = null,
251 rule: RegisterRule = .{ .undefined = {} },270 rule: RegisterRule = .{ .default = {} },
252 };271 };
253272
254 const ColumnRange = struct {273 const ColumnRange = struct {
...@@ -264,13 +283,6 @@ pub const VirtualMachine = struct {...@@ -264,13 +283,6 @@ pub const VirtualMachine = struct {
264 /// The result of executing the CIE's initial_instructions283 /// The result of executing the CIE's initial_instructions
265 cie_row: ?Row = null,284 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
274 pub fn deinit(self: *VirtualMachine, allocator: std.mem.Allocator) void {286 pub fn deinit(self: *VirtualMachine, allocator: std.mem.Allocator) void {
275 self.stack.deinit(allocator);287 self.stack.deinit(allocator);
276 self.columns.deinit(allocator);288 self.columns.deinit(allocator);
...@@ -357,7 +369,7 @@ pub const VirtualMachine = struct {...@@ -357,7 +369,7 @@ pub const VirtualMachine = struct {
357369
358 /// Executes a single instruction.370 /// Executes a single instruction.
359 /// If this instruction is from the CIE, `is_initial` should be set.371 /// If this instruction is from the CIE, `is_initial` should be set.
360 /// Returns the value of `current_row` before executing this instruction372 /// Returns the value of `current_row` before executing this instruction.
361 pub fn step(373 pub fn step(
362 self: *VirtualMachine,374 self: *VirtualMachine,
363 allocator: std.mem.Allocator,375 allocator: std.mem.Allocator,
...@@ -367,13 +379,16 @@ pub const VirtualMachine = struct {...@@ -367,13 +379,16 @@ pub const VirtualMachine = struct {
367 ) !Row {379 ) !Row {
368 // CIE instructions must be run before FDE instructions380 // CIE instructions must be run before FDE instructions
369 assert(!is_initial or self.cie_row == null);381 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
372 const prev_row = self.current_row;387 const prev_row = self.current_row;
373 switch (instruction) {388 switch (instruction) {
374 .set_loc => |i| {389 .set_loc => |i| {
375 if (i.operands.address <= self.current_row.offset) return error.InvalidOperation;390 if (i.operands.address <= self.current_row.offset) return error.InvalidOperation;
376 // TODO: Check cie.segment_selector_size != for DWARFV4391 // TODO: Check cie.segment_selector_size != 0 for DWARFV4
377 self.current_row.offset = i.operands.address;392 self.current_row.offset = i.operands.address;
378 },393 },
379 inline .advance_loc,394 inline .advance_loc,
...@@ -392,11 +407,6 @@ pub const VirtualMachine = struct {...@@ -392,11 +407,6 @@ pub const VirtualMachine = struct {
392 const column = try self.getOrAddColumn(allocator, i.operands.register);407 const column = try self.getOrAddColumn(allocator, i.operands.register);
393 column.rule = .{ .offset = @intCast(i64, i.operands.offset) * cie.data_alignment_factor };408 column.rule = .{ .offset = @intCast(i64, i.operands.offset) * cie.data_alignment_factor };
394 },409 },
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 // },
400 inline .restore,410 inline .restore,
401 .restore_extended,411 .restore_extended,
402 => |i| {412 => |i| {
...@@ -405,7 +415,7 @@ pub const VirtualMachine = struct {...@@ -405,7 +415,7 @@ pub const VirtualMachine = struct {
405 const column = try self.getOrAddColumn(allocator, i.operands.register);415 const column = try self.getOrAddColumn(allocator, i.operands.register);
406 column.rule = for (self.rowColumns(cie_row)) |cie_column| {416 column.rule = for (self.rowColumns(cie_row)) |cie_column| {
407 if (cie_column.register == i.operands.register) break cie_column.rule;417 if (cie_column.register == i.operands.register) break cie_column.rule;
408 } else .{ .undefined = {} };418 } else .{ .default = {} };
409 } else return error.InvalidOperation;419 } else return error.InvalidOperation;
410 },420 },
411 .nop => {},421 .nop => {},
...@@ -427,13 +437,6 @@ pub const VirtualMachine = struct {...@@ -427,13 +437,6 @@ pub const VirtualMachine = struct {
427 .remember_state => {437 .remember_state => {
428 try self.stack.append(allocator, self.current_row.columns);438 try self.stack.append(allocator, self.current_row.columns);
429 self.current_row.copy_on_write = true;439 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 // }
437 },440 },
438 .restore_state => {441 .restore_state => {
439 const restored_columns = self.stack.popOrNull() orelse return error.InvalidOperation;442 const restored_columns = self.stack.popOrNull() orelse return error.InvalidOperation;