authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-07-03 03:45:06-04:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-07-20 22:58:14-04:00
logb85f84061aebb6c61ab9ca42d8147e8b76154818
treee979dc3519fb83ed23680888605e1057217527b9
parent62598c2187a63a7eb2d8c9f3dca0664ec5db270e

dwarf: don't dupe function names, as they are backed by the memory mapped sections

dwarf: const-correctness fixups dwarf: implement the remaining register rules dwarf: start implmenting the DWARF expression stack machine

4 files changed, 291 insertions(+), 87 deletions(-)

lib/std/debug.zig+4-6
...@@ -483,16 +483,14 @@ pub const StackIterator = struct {...@@ -483,16 +483,14 @@ pub const StackIterator = struct {
483 pub fn initWithContext(first_address: ?usize, debug_info: *DebugInfo, context: *const os.ucontext_t) !StackIterator {483 pub fn initWithContext(first_address: ?usize, debug_info: *DebugInfo, context: *const os.ucontext_t) !StackIterator {
484 var iterator = init(first_address, null);484 var iterator = init(first_address, null);
485 iterator.debug_info = debug_info;485 iterator.debug_info = debug_info;
486 iterator.dwarf_context = try DW.UnwindContext.init(context, &isValidMemory);486 iterator.dwarf_context = try DW.UnwindContext.init(debug_info.allocator, context, &isValidMemory);
487 iterator.last_error = null;487 iterator.last_error = null;
488 return iterator;488 return iterator;
489 }489 }
490490
491 pub fn deinit(self: *StackIterator) void {491 pub fn deinit(self: *StackIterator) void {
492 if (have_ucontext) {492 if (have_ucontext and self.debug_info != null) {
493 if (self.debug_info) |debug_info| {493 self.dwarf_context.deinit();
494 self.dwarf_context.deinit(debug_info.allocator);
495 }
496 }494 }
497 }495 }
498496
...@@ -599,7 +597,7 @@ pub const StackIterator = struct {...@@ -599,7 +597,7 @@ pub const StackIterator = struct {
599 if (try module.getDwarfInfoForAddress(self.debug_info.?.allocator, self.dwarf_context.pc)) |di| {597 if (try module.getDwarfInfoForAddress(self.debug_info.?.allocator, self.dwarf_context.pc)) |di| {
600 self.dwarf_context.reg_ctx.eh_frame = true;598 self.dwarf_context.reg_ctx.eh_frame = true;
601 self.dwarf_context.reg_ctx.is_macho = di.is_macho;599 self.dwarf_context.reg_ctx.is_macho = di.is_macho;
602 return di.unwindFrame(self.debug_info.?.allocator, &self.dwarf_context, module.base_address);600 return di.unwindFrame(&self.dwarf_context, module.base_address);
603 } else return error.MissingDebugInfo;601 } else return error.MissingDebugInfo;
604 }602 }
605603
lib/std/dwarf.zig+46-33
...@@ -163,15 +163,9 @@ const PcRange = struct {...@@ -163,15 +163,9 @@ const PcRange = struct {
163const Func = struct {163const Func = struct {
164 pc_range: ?PcRange,164 pc_range: ?PcRange,
165 name: ?[]const u8,165 name: ?[]const u8,
166
167 fn deinit(func: *Func, allocator: mem.Allocator) void {
168 if (func.name) |name| {
169 allocator.free(name);
170 }
171 }
172};166};
173167
174const CompileUnit = struct {168pub const CompileUnit = struct {
175 version: u16,169 version: u16,
176 is_64: bool,170 is_64: bool,
177 die: *Die,171 die: *Die,
...@@ -181,6 +175,7 @@ const CompileUnit = struct {...@@ -181,6 +175,7 @@ const CompileUnit = struct {
181 addr_base: usize,175 addr_base: usize,
182 rnglists_base: usize,176 rnglists_base: usize,
183 loclists_base: usize,177 loclists_base: usize,
178 frame_base: ?*const FormValue,
184};179};
185180
186const AbbrevTable = std.ArrayList(AbbrevTableEntry);181const AbbrevTable = std.ArrayList(AbbrevTableEntry);
...@@ -216,7 +211,7 @@ const AbbrevAttr = struct {...@@ -216,7 +211,7 @@ const AbbrevAttr = struct {
216 payload: i64,211 payload: i64,
217};212};
218213
219const FormValue = union(enum) {214pub const FormValue = union(enum) {
220 Address: u64,215 Address: u64,
221 AddrOffset: usize,216 AddrOffset: usize,
222 Block: []u8,217 Block: []u8,
...@@ -298,7 +293,7 @@ const Die = struct {...@@ -298,7 +293,7 @@ const Die = struct {
298293
299 fn getAttrAddr(294 fn getAttrAddr(
300 self: *const Die,295 self: *const Die,
301 di: *DwarfInfo,296 di: *const DwarfInfo,
302 id: u64,297 id: u64,
303 compile_unit: CompileUnit,298 compile_unit: CompileUnit,
304 ) error{ InvalidDebugInfo, MissingDebugInfo }!u64 {299 ) error{ InvalidDebugInfo, MissingDebugInfo }!u64 {
...@@ -708,9 +703,6 @@ pub const DwarfInfo = struct {...@@ -708,9 +703,6 @@ pub const DwarfInfo = struct {
708 allocator.destroy(cu.die);703 allocator.destroy(cu.die);
709 }704 }
710 di.compile_unit_list.deinit(allocator);705 di.compile_unit_list.deinit(allocator);
711 for (di.func_list.items) |*func| {
712 func.deinit(allocator);
713 }
714 di.func_list.deinit(allocator);706 di.func_list.deinit(allocator);
715 di.cie_map.deinit(allocator);707 di.cie_map.deinit(allocator);
716 di.fde_list.deinit(allocator);708 di.fde_list.deinit(allocator);
...@@ -793,6 +785,7 @@ pub const DwarfInfo = struct {...@@ -793,6 +785,7 @@ pub const DwarfInfo = struct {
793 .addr_base = if (die_obj.getAttr(AT.addr_base)) |fv| try fv.getUInt(usize) else 0,785 .addr_base = if (die_obj.getAttr(AT.addr_base)) |fv| try fv.getUInt(usize) else 0,
794 .rnglists_base = if (die_obj.getAttr(AT.rnglists_base)) |fv| try fv.getUInt(usize) else 0,786 .rnglists_base = if (die_obj.getAttr(AT.rnglists_base)) |fv| try fv.getUInt(usize) else 0,
795 .loclists_base = if (die_obj.getAttr(AT.loclists_base)) |fv| try fv.getUInt(usize) else 0,787 .loclists_base = if (die_obj.getAttr(AT.loclists_base)) |fv| try fv.getUInt(usize) else 0,
788 .frame_base = die_obj.getAttr(AT.frame_base),
796 };789 };
797 },790 },
798 TAG.subprogram, TAG.inlined_subroutine, TAG.subroutine, TAG.entry_point => {791 TAG.subprogram, TAG.inlined_subroutine, TAG.subroutine, TAG.entry_point => {
...@@ -802,8 +795,7 @@ pub const DwarfInfo = struct {...@@ -802,8 +795,7 @@ pub const DwarfInfo = struct {
802 // Prevent endless loops795 // Prevent endless loops
803 while (depth > 0) : (depth -= 1) {796 while (depth > 0) : (depth -= 1) {
804 if (this_die_obj.getAttr(AT.name)) |_| {797 if (this_die_obj.getAttr(AT.name)) |_| {
805 const name = try this_die_obj.getAttrString(di, AT.name, di.section(.debug_str), compile_unit);798 break :x try this_die_obj.getAttrString(di, AT.name, di.section(.debug_str), compile_unit);
806 break :x try allocator.dupe(u8, name);
807 } else if (this_die_obj.getAttr(AT.abstract_origin)) |_| {799 } else if (this_die_obj.getAttr(AT.abstract_origin)) |_| {
808 // Follow the DIE it points to and repeat800 // Follow the DIE it points to and repeat
809 const ref_offset = try this_die_obj.getAttrRef(AT.abstract_origin);801 const ref_offset = try this_die_obj.getAttrRef(AT.abstract_origin);
...@@ -834,7 +826,7 @@ pub const DwarfInfo = struct {...@@ -834,7 +826,7 @@ pub const DwarfInfo = struct {
834 break :x null;826 break :x null;
835 };827 };
836828
837 var found_range = if (die_obj.getAttrAddr(di, AT.low_pc, compile_unit)) |low_pc| blk: {829 var range_added = if (die_obj.getAttrAddr(di, AT.low_pc, compile_unit)) |low_pc| blk: {
838 if (die_obj.getAttr(AT.high_pc)) |high_pc_value| {830 if (die_obj.getAttr(AT.high_pc)) |high_pc_value| {
839 const pc_end = switch (high_pc_value.*) {831 const pc_end = switch (high_pc_value.*) {
840 FormValue.Address => |value| value,832 FormValue.Address => |value| value,
...@@ -852,9 +844,11 @@ pub const DwarfInfo = struct {...@@ -852,9 +844,11 @@ pub const DwarfInfo = struct {
852 .end = pc_end,844 .end = pc_end,
853 },845 },
854 });846 });
847
848 break :blk true;
855 }849 }
856850
857 break :blk true;851 break :blk false;
858 } else |err| blk: {852 } else |err| blk: {
859 if (err != error.MissingDebugInfo) return err;853 if (err != error.MissingDebugInfo) return err;
860 break :blk false;854 break :blk false;
...@@ -867,7 +861,7 @@ pub const DwarfInfo = struct {...@@ -867,7 +861,7 @@ pub const DwarfInfo = struct {
867 };861 };
868862
869 while (try iter.next()) |range| {863 while (try iter.next()) |range| {
870 found_range = true;864 range_added = true;
871 try di.func_list.append(allocator, Func{865 try di.func_list.append(allocator, Func{
872 .name = fn_name,866 .name = fn_name,
873 .pc_range = .{867 .pc_range = .{
...@@ -878,7 +872,7 @@ pub const DwarfInfo = struct {...@@ -878,7 +872,7 @@ pub const DwarfInfo = struct {
878 }872 }
879 }873 }
880874
881 if (!found_range) {875 if (fn_name != null and !range_added) {
882 try di.func_list.append(allocator, Func{876 try di.func_list.append(allocator, Func{
883 .name = fn_name,877 .name = fn_name,
884 .pc_range = null,878 .pc_range = null,
...@@ -952,6 +946,7 @@ pub const DwarfInfo = struct {...@@ -952,6 +946,7 @@ pub const DwarfInfo = struct {
952 .addr_base = if (compile_unit_die.getAttr(AT.addr_base)) |fv| try fv.getUInt(usize) else 0,946 .addr_base = if (compile_unit_die.getAttr(AT.addr_base)) |fv| try fv.getUInt(usize) else 0,
953 .rnglists_base = if (compile_unit_die.getAttr(AT.rnglists_base)) |fv| try fv.getUInt(usize) else 0,947 .rnglists_base = if (compile_unit_die.getAttr(AT.rnglists_base)) |fv| try fv.getUInt(usize) else 0,
954 .loclists_base = if (compile_unit_die.getAttr(AT.loclists_base)) |fv| try fv.getUInt(usize) else 0,948 .loclists_base = if (compile_unit_die.getAttr(AT.loclists_base)) |fv| try fv.getUInt(usize) else 0,
949 .frame_base = compile_unit_die.getAttr(AT.frame_base),
955 };950 };
956951
957 compile_unit.pc_range = x: {952 compile_unit.pc_range = x: {
...@@ -987,11 +982,11 @@ pub const DwarfInfo = struct {...@@ -987,11 +982,11 @@ pub const DwarfInfo = struct {
987 const DebugRangeIterator = struct {982 const DebugRangeIterator = struct {
988 base_address: u64,983 base_address: u64,
989 section_type: DwarfSection,984 section_type: DwarfSection,
990 di: *DwarfInfo,985 di: *const DwarfInfo,
991 compile_unit: *const CompileUnit,986 compile_unit: *const CompileUnit,
992 stream: io.FixedBufferStream([]const u8),987 stream: io.FixedBufferStream([]const u8),
993988
994 pub fn init(ranges_value: *const FormValue, di: *DwarfInfo, compile_unit: *const CompileUnit) !@This() {989 pub fn init(ranges_value: *const FormValue, di: *const DwarfInfo, compile_unit: *const CompileUnit) !@This() {
995 const section_type = if (compile_unit.version >= 5) DwarfSection.debug_rnglists else DwarfSection.debug_ranges;990 const section_type = if (compile_unit.version >= 5) DwarfSection.debug_rnglists else DwarfSection.debug_ranges;
996 const debug_ranges = di.section(section_type) orelse return error.MissingDebugInfo;991 const debug_ranges = di.section(section_type) orelse return error.MissingDebugInfo;
997992
...@@ -1129,7 +1124,7 @@ pub const DwarfInfo = struct {...@@ -1129,7 +1124,7 @@ pub const DwarfInfo = struct {
1129 }1124 }
1130 };1125 };
11311126
1132 pub fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit {1127 pub fn findCompileUnit(di: *const DwarfInfo, target_address: u64) !*const CompileUnit {
1133 for (di.compile_unit_list.items) |*compile_unit| {1128 for (di.compile_unit_list.items) |*compile_unit| {
1134 if (compile_unit.pc_range) |range| {1129 if (compile_unit.pc_range) |range| {
1135 if (target_address >= range.start and target_address < range.end) return compile_unit;1130 if (target_address >= range.start and target_address < range.end) return compile_unit;
...@@ -1630,7 +1625,7 @@ pub const DwarfInfo = struct {...@@ -1630,7 +1625,7 @@ pub const DwarfInfo = struct {
1630 }1625 }
1631 }1626 }
16321627
1633 pub fn unwindFrame(di: *const DwarfInfo, allocator: mem.Allocator, context: *UnwindContext, module_base_address: usize) !usize {1628 pub fn unwindFrame(di: *const DwarfInfo, context: *UnwindContext, module_base_address: usize) !usize {
1634 if (!comptime abi.isSupportedArch(builtin.target.cpu.arch)) return error.UnsupportedCpuArchitecture;1629 if (!comptime abi.isSupportedArch(builtin.target.cpu.arch)) return error.UnsupportedCpuArchitecture;
1635 if (context.pc == 0) return 0;1630 if (context.pc == 0) return 0;
16361631
...@@ -1678,10 +1673,11 @@ pub const DwarfInfo = struct {...@@ -1678,10 +1673,11 @@ pub const DwarfInfo = struct {
1678 cie = di.cie_map.get(fde.cie_length_offset) orelse return error.MissingCIE;1673 cie = di.cie_map.get(fde.cie_length_offset) orelse return error.MissingCIE;
1679 }1674 }
16801675
1676 const compile_unit: ?*const CompileUnit = di.findCompileUnit(fde.pc_begin) catch null;
1681 context.vm.reset();1677 context.vm.reset();
1682 context.reg_ctx.eh_frame = cie.version != 4;1678 context.reg_ctx.eh_frame = cie.version != 4;
16831679
1684 _ = try context.vm.runToNative(allocator, mapped_pc, cie, fde);1680 _ = try context.vm.runToNative(context.allocator, mapped_pc, cie, fde);
1685 const row = &context.vm.current_row;1681 const row = &context.vm.current_row;
16861682
1687 context.cfa = switch (row.cfa.rule) {1683 context.cfa = switch (row.cfa.rule) {
...@@ -1690,12 +1686,19 @@ pub const DwarfInfo = struct {...@@ -1690,12 +1686,19 @@ pub const DwarfInfo = struct {
1690 const value = mem.readIntSliceNative(usize, try abi.regBytes(&context.ucontext, register, context.reg_ctx));1686 const value = mem.readIntSliceNative(usize, try abi.regBytes(&context.ucontext, register, context.reg_ctx));
1691 break :blk try call_frame.applyOffset(value, offset);1687 break :blk try call_frame.applyOffset(value, offset);
1692 },1688 },
1693 .expression => |expression| {1689 .expression => |expression| blk: {
16941690 context.stack_machine.reset();
1695 // TODO: Evaluate expression1691 const value = try context.stack_machine.run(
1696 _ = expression;1692 expression,
16971693 context.allocator,
1698 return error.UnimplementedTODO;1694 compile_unit,
1695 &context.ucontext,
1696 context.reg_ctx,
1697 context.cfa orelse 0,
1698 );
1699
1700 if (value != .generic) return error.InvalidExpressionValue;
1701 break :blk value.generic;
1699 },1702 },
1700 else => return error.InvalidCFARule,1703 else => return error.InvalidCFARule,
1701 };1704 };
...@@ -1713,7 +1716,13 @@ pub const DwarfInfo = struct {...@@ -1713,7 +1716,13 @@ pub const DwarfInfo = struct {
1713 has_next_ip = column.rule != .undefined;1716 has_next_ip = column.rule != .undefined;
1714 }1717 }
17151718
1716 try column.resolveValue(context.*, dest);1719 try column.resolveValue(
1720 context,
1721 compile_unit,
1722 &context.ucontext,
1723 context.reg_ctx,
1724 dest,
1725 );
1717 }1726 }
1718 }1727 }
17191728
...@@ -1738,16 +1747,19 @@ pub const DwarfInfo = struct {...@@ -1738,16 +1747,19 @@ pub const DwarfInfo = struct {
1738};1747};
17391748
1740pub const UnwindContext = struct {1749pub const UnwindContext = struct {
1750 allocator: mem.Allocator,
1741 cfa: ?usize,1751 cfa: ?usize,
1742 pc: usize,1752 pc: usize,
1743 ucontext: os.ucontext_t,1753 ucontext: os.ucontext_t,
1744 reg_ctx: abi.RegisterContext,1754 reg_ctx: abi.RegisterContext,
1745 isValidMemory: *const fn (address: usize) bool,1755 isValidMemory: *const fn (address: usize) bool,
1746 vm: call_frame.VirtualMachine = .{},1756 vm: call_frame.VirtualMachine = .{},
1757 stack_machine: expressions.StackMachine(.{ .call_frame_mode = true }) = .{},
17471758
1748 pub fn init(ucontext: *const os.ucontext_t, isValidMemory: *const fn (address: usize) bool) !UnwindContext {1759 pub fn init(allocator: mem.Allocator, ucontext: *const os.ucontext_t, isValidMemory: *const fn (address: usize) bool) !UnwindContext {
1749 const pc = mem.readIntSliceNative(usize, try abi.regBytes(ucontext, abi.ipRegNum(), null));1760 const pc = mem.readIntSliceNative(usize, try abi.regBytes(ucontext, abi.ipRegNum(), null));
1750 return .{1761 return .{
1762 .allocator = allocator,
1751 .cfa = null,1763 .cfa = null,
1752 .pc = pc,1764 .pc = pc,
1753 .ucontext = ucontext.*,1765 .ucontext = ucontext.*,
...@@ -1756,8 +1768,9 @@ pub const UnwindContext = struct {...@@ -1756,8 +1768,9 @@ pub const UnwindContext = struct {
1756 };1768 };
1757 }1769 }
17581770
1759 pub fn deinit(self: *UnwindContext, allocator: mem.Allocator) void {1771 pub fn deinit(self: *UnwindContext) void {
1760 self.vm.deinit(allocator);1772 self.vm.deinit(self.allocator);
1773 self.stack_machine.deinit(self.allocator);
1761 }1774 }
17621775
1763 pub fn getFp(self: *const UnwindContext) !usize {1776 pub fn getFp(self: *const UnwindContext) !usize {
lib/std/dwarf/call_frame.zig+48-21
...@@ -183,9 +183,9 @@ pub const Instruction = union(Opcode) {...@@ -183,9 +183,9 @@ pub const Instruction = union(Opcode) {
183 offset_extended_sf: InstructionType(.{ .register = .uleb128_register, .offset = .sleb128_offset }),183 offset_extended_sf: InstructionType(.{ .register = .uleb128_register, .offset = .sleb128_offset }),
184 def_cfa_sf: InstructionType(.{ .register = .uleb128_register, .offset = .sleb128_offset }),184 def_cfa_sf: InstructionType(.{ .register = .uleb128_register, .offset = .sleb128_offset }),
185 def_cfa_offset_sf: InstructionType(.{ .offset = .sleb128_offset }),185 def_cfa_offset_sf: InstructionType(.{ .offset = .sleb128_offset }),
186 val_offset: InstructionType(.{ .a = .uleb128_offset, .b = .uleb128_offset }),186 val_offset: InstructionType(.{ .register = .uleb128_register, .offset = .uleb128_offset }),
187 val_offset_sf: InstructionType(.{ .a = .uleb128_offset, .b = .sleb128_offset }),187 val_offset_sf: InstructionType(.{ .register = .uleb128_register, .offset = .sleb128_offset }),
188 val_expression: InstructionType(.{ .a = .uleb128_offset, .block = .block }),188 val_expression: InstructionType(.{ .register = .uleb128_register, .block = .block }),
189189
190 fn readOperands(190 fn readOperands(
191 self: *Instruction,191 self: *Instruction,
...@@ -292,7 +292,14 @@ pub const VirtualMachine = struct {...@@ -292,7 +292,14 @@ pub const VirtualMachine = struct {
292 rule: RegisterRule = .{ .default = {} },292 rule: RegisterRule = .{ .default = {} },
293293
294 /// Resolves the register rule and places the result into `out` (see dwarf.abi.regBytes)294 /// Resolves the register rule and places the result into `out` (see dwarf.abi.regBytes)
295 pub fn resolveValue(self: Column, context: dwarf.UnwindContext, out: []u8) !void {295 pub fn resolveValue(
296 self: Column,
297 context: *dwarf.UnwindContext,
298 compile_unit: ?*const dwarf.CompileUnit,
299 ucontext: *const std.os.ucontext_t,
300 reg_ctx: abi.RegisterContext,
301 out: []u8,
302 ) !void {
296 switch (self.rule) {303 switch (self.rule) {
297 .default => {304 .default => {
298 const register = self.register orelse return error.InvalidRegister;305 const register = self.register orelse return error.InvalidRegister;
...@@ -321,14 +328,21 @@ pub const VirtualMachine = struct {...@@ -321,14 +328,21 @@ pub const VirtualMachine = struct {
321 @memcpy(out, try abi.regBytes(&context.ucontext, register, context.reg_ctx));328 @memcpy(out, try abi.regBytes(&context.ucontext, register, context.reg_ctx));
322 },329 },
323 .expression => |expression| {330 .expression => |expression| {
324 // TODO331 context.stack_machine.reset();
325 _ = expression;332 const value = try context.stack_machine.run(expression, context.allocator, compile_unit, ucontext, reg_ctx, context.cfa.?);
326 unreachable;333
334 if (value != .generic) return error.InvalidExpressionValue;
335 if (!context.isValidMemory(value.generic)) return error.InvalidExpressionAddress;
336
337 const ptr: *usize = @ptrFromInt(value.generic);
338 mem.writeIntSliceNative(usize, out, ptr.*);
327 },339 },
328 .val_expression => |expression| {340 .val_expression => |expression| {
329 // TODO341 context.stack_machine.reset();
330 _ = expression;342 const value = try context.stack_machine.run(expression, context.allocator, compile_unit, ucontext, reg_ctx, context.cfa.?);
331 unreachable;343
344 if (value != .generic) return error.InvalidExpressionValue;
345 mem.writeIntSliceNative(usize, out, value.generic);
332 },346 },
333 .architectural => return error.UnimplementedRule,347 .architectural => return error.UnimplementedRule,
334 }348 }
...@@ -546,12 +560,16 @@ pub const VirtualMachine = struct {...@@ -546,12 +560,16 @@ pub const VirtualMachine = struct {
546 .def_cfa_offset => |i| {560 .def_cfa_offset => |i| {
547 try self.resolveCopyOnWrite(allocator);561 try self.resolveCopyOnWrite(allocator);
548 if (self.current_row.cfa.register == null or self.current_row.cfa.rule != .val_offset) return error.InvalidOperation;562 if (self.current_row.cfa.register == null or self.current_row.cfa.rule != .val_offset) return error.InvalidOperation;
549 self.current_row.cfa.rule = .{ .val_offset = @intCast(i.operands.offset) };563 self.current_row.cfa.rule = .{
564 .val_offset = @intCast(i.operands.offset),
565 };
550 },566 },
551 .def_cfa_offset_sf => |i| {567 .def_cfa_offset_sf => |i| {
552 try self.resolveCopyOnWrite(allocator);568 try self.resolveCopyOnWrite(allocator);
553 if (self.current_row.cfa.register == null or self.current_row.cfa.rule != .val_offset) return error.InvalidOperation;569 if (self.current_row.cfa.register == null or self.current_row.cfa.rule != .val_offset) return error.InvalidOperation;
554 self.current_row.cfa.rule = .{ .val_offset = i.operands.offset * cie.data_alignment_factor };570 self.current_row.cfa.rule = .{
571 .val_offset = i.operands.offset * cie.data_alignment_factor,
572 };
555 },573 },
556 .def_cfa_expression => |i| {574 .def_cfa_expression => |i| {
557 try self.resolveCopyOnWrite(allocator);575 try self.resolveCopyOnWrite(allocator);
...@@ -567,17 +585,26 @@ pub const VirtualMachine = struct {...@@ -567,17 +585,26 @@ pub const VirtualMachine = struct {
567 .expression = i.operands.block,585 .expression = i.operands.block,
568 };586 };
569 },587 },
570 .val_offset => {588 .val_offset => |i| {
571 // TODO: Implement589 try self.resolveCopyOnWrite(allocator);
572 unreachable;590 const column = try self.getOrAddColumn(allocator, i.operands.register);
591 column.rule = .{
592 .val_offset = @as(i64, @intCast(i.operands.offset)) * cie.data_alignment_factor,
593 };
573 },594 },
574 .val_offset_sf => {595 .val_offset_sf => |i| {
575 // TODO: Implement596 try self.resolveCopyOnWrite(allocator);
576 unreachable;597 const column = try self.getOrAddColumn(allocator, i.operands.register);
598 column.rule = .{
599 .val_offset = i.operands.offset * cie.data_alignment_factor,
600 };
577 },601 },
578 .val_expression => {602 .val_expression => |i| {
579 // TODO: Implement603 try self.resolveCopyOnWrite(allocator);
580 unreachable;604 const column = try self.getOrAddColumn(allocator, i.operands.register);
605 column.rule = .{
606 .val_expression = i.operands.block,
607 };
581 },608 },
582 }609 }
583610
lib/std/dwarf/expressions.zig+193-27
...@@ -2,6 +2,9 @@ const std = @import("std");...@@ -2,6 +2,9 @@ const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const OP = @import("OP.zig");3const OP = @import("OP.zig");
4const leb = @import("../leb128.zig");4const leb = @import("../leb128.zig");
5const dwarf = @import("../dwarf.zig");
6const abi = dwarf.abi;
7const mem = std.mem;
58
6pub const StackMachineOptions = struct {9pub const StackMachineOptions = struct {
7 /// The address size of the target architecture10 /// The address size of the target architecture
...@@ -33,9 +36,10 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {...@@ -33,9 +36,10 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {
33 };36 };
3437
35 return struct {38 return struct {
36 const Value = union(enum) {39 const Self = @This();
40
41 const Operand = union(enum) {
37 generic: addr_type,42 generic: addr_type,
38 const_type: []const u8,
39 register: u8,43 register: u8,
40 base_register: struct {44 base_register: struct {
41 base_register: u8,45 base_register: u8,
...@@ -46,7 +50,11 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {...@@ -46,7 +50,11 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {
46 offset: i64,50 offset: i64,
47 },51 },
48 block: []const u8,52 block: []const u8,
49 base_type: struct {53 register_type: struct {
54 register: u8,
55 type_offset: u64,
56 },
57 const_type: struct {
50 type_offset: u64,58 type_offset: u64,
51 value_bytes: []const u8,59 value_bytes: []const u8,
52 },60 },
...@@ -56,9 +64,31 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {...@@ -56,9 +64,31 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {
56 },64 },
57 };65 };
5866
67 const Value = union(enum) {
68 generic: addr_type,
69 regval_type: struct {
70 // Offset of DW_TAG_base_type DIE
71 type_offset: u64,
72 value: addr_type,
73 },
74 const_type: struct {
75 // Offset of DW_TAG_base_type DIE
76 type_offset: u64,
77 value_bytes: []const u8,
78 },
79 };
80
59 stack: std.ArrayListUnmanaged(Value) = .{},81 stack: std.ArrayListUnmanaged(Value) = .{},
6082
61 fn generic(value: anytype) Value {83 pub fn reset(self: *Self) void {
84 self.stack.clearRetainingCapacity();
85 }
86
87 pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
88 self.stack.deinit(allocator);
89 }
90
91 fn generic(value: anytype) Operand {
62 const int_info = @typeInfo(@TypeOf(value)).Int;92 const int_info = @typeInfo(@TypeOf(value)).Int;
63 if (@sizeOf(@TypeOf(value)) > options.addr_size) {93 if (@sizeOf(@TypeOf(value)) > options.addr_size) {
64 return .{ .generic = switch (int_info.signedness) {94 return .{ .generic = switch (int_info.signedness) {
...@@ -73,7 +103,7 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {...@@ -73,7 +103,7 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {
73 }103 }
74 }104 }
75105
76 pub fn readOperand(stream: *std.io.FixedBufferStream([]const u8), opcode: u8) !?Value {106 pub fn readOperand(stream: *std.io.FixedBufferStream([]const u8), opcode: u8) !?Operand {
77 const reader = stream.reader();107 const reader = stream.reader();
78 return switch (opcode) {108 return switch (opcode) {
79 OP.addr,109 OP.addr,
...@@ -87,8 +117,8 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {...@@ -87,8 +117,8 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {
87 OP.const1s => generic(try reader.readByteSigned()),117 OP.const1s => generic(try reader.readByteSigned()),
88 OP.const2u,118 OP.const2u,
89 OP.call2,119 OP.call2,
90 OP.call4,
91 => generic(try reader.readInt(u16, options.endian)),120 => generic(try reader.readInt(u16, options.endian)),
121 OP.call4 => generic(try reader.readInt(u32, options.endian)),
92 OP.const2s,122 OP.const2s,
93 OP.bra,123 OP.bra,
94 OP.skip,124 OP.skip,
...@@ -114,21 +144,35 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {...@@ -114,21 +144,35 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {
114 .offset = try leb.readILEB128(i64, reader),144 .offset = try leb.readILEB128(i64, reader),
115 } },145 } },
116 OP.regx => .{ .register = try leb.readULEB128(u8, reader) },146 OP.regx => .{ .register = try leb.readULEB128(u8, reader) },
117 OP.bregx, OP.regval_type => .{ .base_register = .{147 OP.bregx => blk: {
118 .base_register = try leb.readULEB128(u8, reader),148 const base_register = try leb.readULEB128(u8, reader);
119 .offset = try leb.readILEB128(i64, reader),149 const offset = try leb.readILEB128(i64, reader);
120 } },150 break :blk .{ .base_register = .{
151 .base_register = base_register,
152 .offset = offset,
153 } };
154 },
155 OP.regval_type => blk: {
156 const register = try leb.readULEB128(u8, reader);
157 const type_offset = try leb.readULEB128(u64, reader);
158 break :blk .{ .register_type = .{
159 .register = register,
160 .type_offset = type_offset,
161 } };
162 },
121 OP.piece => .{163 OP.piece => .{
122 .composite_location = .{164 .composite_location = .{
123 .size = try leb.readULEB128(u8, reader),165 .size = try leb.readULEB128(u8, reader),
124 .offset = 0,166 .offset = 0,
125 },167 },
126 },168 },
127 OP.bit_piece => .{169 OP.bit_piece => blk: {
128 .composite_location = .{170 const size = try leb.readULEB128(u8, reader);
129 .size = try leb.readULEB128(u8, reader),171 const offset = try leb.readILEB128(i64, reader);
130 .offset = try leb.readILEB128(i64, reader),172 break :blk .{ .composite_location = .{
131 },173 .size = size,
174 .offset = offset,
175 } };
132 },176 },
133 OP.implicit_value, OP.entry_value => blk: {177 OP.implicit_value, OP.entry_value => blk: {
134 const size = try leb.readULEB128(u8, reader);178 const size = try leb.readULEB128(u8, reader);
...@@ -145,7 +189,7 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {...@@ -145,7 +189,7 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {
145 if (stream.pos + size > stream.buffer.len) return error.InvalidExpression;189 if (stream.pos + size > stream.buffer.len) return error.InvalidExpression;
146 const value_bytes = stream.buffer[stream.pos..][0..size];190 const value_bytes = stream.buffer[stream.pos..][0..size];
147 stream.pos += size;191 stream.pos += size;
148 break :blk .{ .base_type = .{192 break :blk .{ .const_type = .{
149 .type_offset = type_offset,193 .type_offset = type_offset,
150 .value_bytes = value_bytes,194 .value_bytes = value_bytes,
151 } };195 } };
...@@ -163,22 +207,144 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {...@@ -163,22 +207,144 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {
163 };207 };
164 }208 }
165209
210 pub fn run(
211 self: *Self,
212 expression: []const u8,
213 allocator: std.mem.Allocator,
214 compile_unit: ?*const dwarf.CompileUnit,
215 ucontext: *const std.os.ucontext_t,
216 reg_ctx: abi.RegisterContext,
217 initial_value: usize,
218 ) !Value {
219 try self.stack.append(allocator, .{ .generic = initial_value });
220 var stream = std.io.fixedBufferStream(expression);
221 while (try self.step(&stream, allocator, compile_unit, ucontext, reg_ctx)) {}
222 if (self.stack.items.len == 0) return error.InvalidExpression;
223 return self.stack.items[self.stack.items.len - 1];
224 }
225
226 /// Reads an opcode and its operands from the stream and executes it
166 pub fn step(227 pub fn step(
167 self: *StackMachine,228 self: *Self,
168 stream: std.io.FixedBufferStream([]const u8),229 stream: *std.io.FixedBufferStream([]const u8),
169 allocator: std.mem.Allocator,230 allocator: std.mem.Allocator,
170 ) !void {231 compile_unit: ?*const dwarf.CompileUnit,
171 if (@sizeOf(usize) != addr_type or options.endian != builtin.target.cpu.arch.endian())232 ucontext: *const std.os.ucontext_t,
233 reg_ctx: dwarf.abi.RegisterContext,
234 ) !bool {
235 if (@sizeOf(usize) != @sizeOf(addr_type) or options.endian != comptime builtin.target.cpu.arch.endian())
172 @compileError("Execution of non-native address sizees / endianness is not supported");236 @compileError("Execution of non-native address sizees / endianness is not supported");
173237
174 const opcode = try stream.reader.readByte();238 const opcode = try stream.reader().readByte();
175 _ = opcode;239 if (options.call_frame_mode) {
176 _ = self;240 // Certain opcodes are not allowed in a CFA context, see 6.4.2
177 _ = allocator;241 switch (opcode) {
242 OP.addrx,
243 OP.call2,
244 OP.call4,
245 OP.call_ref,
246 OP.const_type,
247 OP.constx,
248 OP.convert,
249 OP.deref_type,
250 OP.regval_type,
251 OP.reinterpret,
252 OP.push_object_address,
253 OP.call_frame_cfa,
254 => return error.InvalidCFAExpression,
255 else => {},
256 }
257 }
258
259 switch (opcode) {
260
261 // 2.5.1.1: Literal Encodings
262 OP.lit0...OP.lit31,
263 OP.addr,
264 OP.const1u,
265 OP.const2u,
266 OP.const4u,
267 OP.const8u,
268 OP.const1s,
269 OP.const2s,
270 OP.const4s,
271 OP.const8s,
272 OP.constu,
273 OP.consts,
274 => try self.stack.append(allocator, .{ .generic = (try readOperand(stream, opcode)).?.generic }),
275
276 OP.const_type => {
277 const const_type = (try readOperand(stream, opcode)).?.const_type;
278 try self.stack.append(allocator, .{ .const_type = .{
279 .type_offset = const_type.type_offset,
280 .value_bytes = const_type.value_bytes,
281 } });
282 },
283
284 OP.addrx, OP.constx => {
285 const debug_addr_index = (try readOperand(stream, opcode)).?.generic;
286
287 // TODO: Read item from .debug_addr, this requires need DW_AT_addr_base of the compile unit, push onto stack as generic
288
289 _ = debug_addr_index;
290 unreachable;
291 },
292
293 // 2.5.1.2: Register Values
294 OP.fbreg => {
295 if (compile_unit == null) return error.ExpressionRequiresCompileUnit;
296 if (compile_unit.?.frame_base == null) return error.ExpressionRequiresFrameBase;
297
298 const offset: i64 = @intCast((try readOperand(stream, opcode)).?.generic);
299 _ = offset;
300
301 switch (compile_unit.?.frame_base.?.*) {
302 .ExprLoc => {
303 // TODO: Run this expression in a nested stack machine
304 return error.UnimplementedOpcode;
305 },
306 .LocListOffset => {
307 // TODO: Read value from .debug_loclists
308 return error.UnimplementedOpcode;
309 },
310 .SecOffset => {
311 // TODO: Read value from .debug_loclists
312 return error.UnimplementedOpcode;
313 },
314 else => return error.InvalidFrameBase,
315 }
316 },
317 OP.breg0...OP.breg31, OP.bregx => {
318 const base_register = (try readOperand(stream, opcode)).?.base_register;
319 var value: i64 = @intCast(mem.readIntSliceNative(usize, try abi.regBytes(ucontext, base_register.base_register, reg_ctx)));
320 value += base_register.offset;
321 try self.stack.append(allocator, .{ .generic = @intCast(value) });
322 },
323 OP.regval_type => {
324 const register_type = (try readOperand(stream, opcode)).?.register_type;
325 const value = mem.readIntSliceNative(usize, try abi.regBytes(ucontext, register_type.register, reg_ctx));
326 try self.stack.append(allocator, .{
327 .regval_type = .{
328 .value = value,
329 .type_offset = register_type.type_offset,
330 },
331 });
332 },
333
334 // 2.5.1.3: Stack Operations
335
336 OP.dup => {},
337
338 else => {
339 std.debug.print("Unimplemented DWARF expression opcode: {x}\n", .{opcode});
340 unreachable;
341 },
342
343 // These have already been handled by readOperand
344 OP.lo_user...OP.hi_user => unreachable,
345 }
178346
179 // switch (opcode) {347 return stream.pos < stream.buffer.len;
180 // OP.addr => try self.stack.append(allocator, try readOperand(stream, opcode)),
181 // }
182 }348 }
183 };349 };
184}350}