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 {
483483 pub fn initWithContext(first_address: ?usize, debug_info: *DebugInfo, context: *const os.ucontext_t) !StackIterator {
484484 var iterator = init(first_address, null);
485485 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);
487487 iterator.last_error = null;
488488 return iterator;
489489 }
490490
491491 pub fn deinit(self: *StackIterator) void {
492 if (have_ucontext) {
493 if (self.debug_info) |debug_info| {
494 self.dwarf_context.deinit(debug_info.allocator);
495 }
492 if (have_ucontext and self.debug_info != null) {
493 self.dwarf_context.deinit();
496494 }
497495 }
498496
......@@ -599,7 +597,7 @@ pub const StackIterator = struct {
599597 if (try module.getDwarfInfoForAddress(self.debug_info.?.allocator, self.dwarf_context.pc)) |di| {
600598 self.dwarf_context.reg_ctx.eh_frame = true;
601599 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);
603601 } else return error.MissingDebugInfo;
604602 }
605603
lib/std/dwarf.zig+46-33
......@@ -163,15 +163,9 @@ const PcRange = struct {
163163const Func = struct {
164164 pc_range: ?PcRange,
165165 name: ?[]const u8,
166
167 fn deinit(func: *Func, allocator: mem.Allocator) void {
168 if (func.name) |name| {
169 allocator.free(name);
170 }
171 }
172166};
173167
174const CompileUnit = struct {
168pub const CompileUnit = struct {
175169 version: u16,
176170 is_64: bool,
177171 die: *Die,
......@@ -181,6 +175,7 @@ const CompileUnit = struct {
181175 addr_base: usize,
182176 rnglists_base: usize,
183177 loclists_base: usize,
178 frame_base: ?*const FormValue,
184179};
185180
186181const AbbrevTable = std.ArrayList(AbbrevTableEntry);
......@@ -216,7 +211,7 @@ const AbbrevAttr = struct {
216211 payload: i64,
217212};
218213
219const FormValue = union(enum) {
214pub const FormValue = union(enum) {
220215 Address: u64,
221216 AddrOffset: usize,
222217 Block: []u8,
......@@ -298,7 +293,7 @@ const Die = struct {
298293
299294 fn getAttrAddr(
300295 self: *const Die,
301 di: *DwarfInfo,
296 di: *const DwarfInfo,
302297 id: u64,
303298 compile_unit: CompileUnit,
304299 ) error{ InvalidDebugInfo, MissingDebugInfo }!u64 {
......@@ -708,9 +703,6 @@ pub const DwarfInfo = struct {
708703 allocator.destroy(cu.die);
709704 }
710705 di.compile_unit_list.deinit(allocator);
711 for (di.func_list.items) |*func| {
712 func.deinit(allocator);
713 }
714706 di.func_list.deinit(allocator);
715707 di.cie_map.deinit(allocator);
716708 di.fde_list.deinit(allocator);
......@@ -793,6 +785,7 @@ pub const DwarfInfo = struct {
793785 .addr_base = if (die_obj.getAttr(AT.addr_base)) |fv| try fv.getUInt(usize) else 0,
794786 .rnglists_base = if (die_obj.getAttr(AT.rnglists_base)) |fv| try fv.getUInt(usize) else 0,
795787 .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),
796789 };
797790 },
798791 TAG.subprogram, TAG.inlined_subroutine, TAG.subroutine, TAG.entry_point => {
......@@ -802,8 +795,7 @@ pub const DwarfInfo = struct {
802795 // Prevent endless loops
803796 while (depth > 0) : (depth -= 1) {
804797 if (this_die_obj.getAttr(AT.name)) |_| {
805 const name = try this_die_obj.getAttrString(di, AT.name, di.section(.debug_str), compile_unit);
806 break :x try allocator.dupe(u8, name);
798 break :x try this_die_obj.getAttrString(di, AT.name, di.section(.debug_str), compile_unit);
807799 } else if (this_die_obj.getAttr(AT.abstract_origin)) |_| {
808800 // Follow the DIE it points to and repeat
809801 const ref_offset = try this_die_obj.getAttrRef(AT.abstract_origin);
......@@ -834,7 +826,7 @@ pub const DwarfInfo = struct {
834826 break :x null;
835827 };
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: {
838830 if (die_obj.getAttr(AT.high_pc)) |high_pc_value| {
839831 const pc_end = switch (high_pc_value.*) {
840832 FormValue.Address => |value| value,
......@@ -852,9 +844,11 @@ pub const DwarfInfo = struct {
852844 .end = pc_end,
853845 },
854846 });
847
848 break :blk true;
855849 }
856850
857 break :blk true;
851 break :blk false;
858852 } else |err| blk: {
859853 if (err != error.MissingDebugInfo) return err;
860854 break :blk false;
......@@ -867,7 +861,7 @@ pub const DwarfInfo = struct {
867861 };
868862
869863 while (try iter.next()) |range| {
870 found_range = true;
864 range_added = true;
871865 try di.func_list.append(allocator, Func{
872866 .name = fn_name,
873867 .pc_range = .{
......@@ -878,7 +872,7 @@ pub const DwarfInfo = struct {
878872 }
879873 }
880874
881 if (!found_range) {
875 if (fn_name != null and !range_added) {
882876 try di.func_list.append(allocator, Func{
883877 .name = fn_name,
884878 .pc_range = null,
......@@ -952,6 +946,7 @@ pub const DwarfInfo = struct {
952946 .addr_base = if (compile_unit_die.getAttr(AT.addr_base)) |fv| try fv.getUInt(usize) else 0,
953947 .rnglists_base = if (compile_unit_die.getAttr(AT.rnglists_base)) |fv| try fv.getUInt(usize) else 0,
954948 .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),
955950 };
956951
957952 compile_unit.pc_range = x: {
......@@ -987,11 +982,11 @@ pub const DwarfInfo = struct {
987982 const DebugRangeIterator = struct {
988983 base_address: u64,
989984 section_type: DwarfSection,
990 di: *DwarfInfo,
985 di: *const DwarfInfo,
991986 compile_unit: *const CompileUnit,
992987 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() {
995990 const section_type = if (compile_unit.version >= 5) DwarfSection.debug_rnglists else DwarfSection.debug_ranges;
996991 const debug_ranges = di.section(section_type) orelse return error.MissingDebugInfo;
997992
......@@ -1129,7 +1124,7 @@ pub const DwarfInfo = struct {
11291124 }
11301125 };
11311126
1132 pub fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit {
1127 pub fn findCompileUnit(di: *const DwarfInfo, target_address: u64) !*const CompileUnit {
11331128 for (di.compile_unit_list.items) |*compile_unit| {
11341129 if (compile_unit.pc_range) |range| {
11351130 if (target_address >= range.start and target_address < range.end) return compile_unit;
......@@ -1630,7 +1625,7 @@ pub const DwarfInfo = struct {
16301625 }
16311626 }
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 {
16341629 if (!comptime abi.isSupportedArch(builtin.target.cpu.arch)) return error.UnsupportedCpuArchitecture;
16351630 if (context.pc == 0) return 0;
16361631
......@@ -1678,10 +1673,11 @@ pub const DwarfInfo = struct {
16781673 cie = di.cie_map.get(fde.cie_length_offset) orelse return error.MissingCIE;
16791674 }
16801675
1676 const compile_unit: ?*const CompileUnit = di.findCompileUnit(fde.pc_begin) catch null;
16811677 context.vm.reset();
16821678 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);
16851681 const row = &context.vm.current_row;
16861682
16871683 context.cfa = switch (row.cfa.rule) {
......@@ -1690,12 +1686,19 @@ pub const DwarfInfo = struct {
16901686 const value = mem.readIntSliceNative(usize, try abi.regBytes(&context.ucontext, register, context.reg_ctx));
16911687 break :blk try call_frame.applyOffset(value, offset);
16921688 },
1693 .expression => |expression| {
1694
1695 // TODO: Evaluate expression
1696 _ = expression;
1697
1698 return error.UnimplementedTODO;
1689 .expression => |expression| blk: {
1690 context.stack_machine.reset();
1691 const value = try context.stack_machine.run(
1692 expression,
1693 context.allocator,
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;
16991702 },
17001703 else => return error.InvalidCFARule,
17011704 };
......@@ -1713,7 +1716,13 @@ pub const DwarfInfo = struct {
17131716 has_next_ip = column.rule != .undefined;
17141717 }
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 );
17171726 }
17181727 }
17191728
......@@ -1738,16 +1747,19 @@ pub const DwarfInfo = struct {
17381747};
17391748
17401749pub const UnwindContext = struct {
1750 allocator: mem.Allocator,
17411751 cfa: ?usize,
17421752 pc: usize,
17431753 ucontext: os.ucontext_t,
17441754 reg_ctx: abi.RegisterContext,
17451755 isValidMemory: *const fn (address: usize) bool,
17461756 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 {
17491760 const pc = mem.readIntSliceNative(usize, try abi.regBytes(ucontext, abi.ipRegNum(), null));
17501761 return .{
1762 .allocator = allocator,
17511763 .cfa = null,
17521764 .pc = pc,
17531765 .ucontext = ucontext.*,
......@@ -1756,8 +1768,9 @@ pub const UnwindContext = struct {
17561768 };
17571769 }
17581770
1759 pub fn deinit(self: *UnwindContext, allocator: mem.Allocator) void {
1760 self.vm.deinit(allocator);
1771 pub fn deinit(self: *UnwindContext) void {
1772 self.vm.deinit(self.allocator);
1773 self.stack_machine.deinit(self.allocator);
17611774 }
17621775
17631776 pub fn getFp(self: *const UnwindContext) !usize {
lib/std/dwarf/call_frame.zig+48-21
......@@ -183,9 +183,9 @@ pub const Instruction = union(Opcode) {
183183 offset_extended_sf: InstructionType(.{ .register = .uleb128_register, .offset = .sleb128_offset }),
184184 def_cfa_sf: InstructionType(.{ .register = .uleb128_register, .offset = .sleb128_offset }),
185185 def_cfa_offset_sf: InstructionType(.{ .offset = .sleb128_offset }),
186 val_offset: InstructionType(.{ .a = .uleb128_offset, .b = .uleb128_offset }),
187 val_offset_sf: InstructionType(.{ .a = .uleb128_offset, .b = .sleb128_offset }),
188 val_expression: InstructionType(.{ .a = .uleb128_offset, .block = .block }),
186 val_offset: InstructionType(.{ .register = .uleb128_register, .offset = .uleb128_offset }),
187 val_offset_sf: InstructionType(.{ .register = .uleb128_register, .offset = .sleb128_offset }),
188 val_expression: InstructionType(.{ .register = .uleb128_register, .block = .block }),
189189
190190 fn readOperands(
191191 self: *Instruction,
......@@ -292,7 +292,14 @@ pub const VirtualMachine = struct {
292292 rule: RegisterRule = .{ .default = {} },
293293
294294 /// 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 {
296303 switch (self.rule) {
297304 .default => {
298305 const register = self.register orelse return error.InvalidRegister;
......@@ -321,14 +328,21 @@ pub const VirtualMachine = struct {
321328 @memcpy(out, try abi.regBytes(&context.ucontext, register, context.reg_ctx));
322329 },
323330 .expression => |expression| {
324 // TODO
325 _ = expression;
326 unreachable;
331 context.stack_machine.reset();
332 const value = try context.stack_machine.run(expression, context.allocator, compile_unit, ucontext, reg_ctx, context.cfa.?);
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.*);
327339 },
328340 .val_expression => |expression| {
329 // TODO
330 _ = expression;
331 unreachable;
341 context.stack_machine.reset();
342 const value = try context.stack_machine.run(expression, context.allocator, compile_unit, ucontext, reg_ctx, context.cfa.?);
343
344 if (value != .generic) return error.InvalidExpressionValue;
345 mem.writeIntSliceNative(usize, out, value.generic);
332346 },
333347 .architectural => return error.UnimplementedRule,
334348 }
......@@ -546,12 +560,16 @@ pub const VirtualMachine = struct {
546560 .def_cfa_offset => |i| {
547561 try self.resolveCopyOnWrite(allocator);
548562 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 };
550566 },
551567 .def_cfa_offset_sf => |i| {
552568 try self.resolveCopyOnWrite(allocator);
553569 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 };
555573 },
556574 .def_cfa_expression => |i| {
557575 try self.resolveCopyOnWrite(allocator);
......@@ -567,17 +585,26 @@ pub const VirtualMachine = struct {
567585 .expression = i.operands.block,
568586 };
569587 },
570 .val_offset => {
571 // TODO: Implement
572 unreachable;
588 .val_offset => |i| {
589 try self.resolveCopyOnWrite(allocator);
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 };
573594 },
574 .val_offset_sf => {
575 // TODO: Implement
576 unreachable;
595 .val_offset_sf => |i| {
596 try self.resolveCopyOnWrite(allocator);
597 const column = try self.getOrAddColumn(allocator, i.operands.register);
598 column.rule = .{
599 .val_offset = i.operands.offset * cie.data_alignment_factor,
600 };
577601 },
578 .val_expression => {
579 // TODO: Implement
580 unreachable;
602 .val_expression => |i| {
603 try self.resolveCopyOnWrite(allocator);
604 const column = try self.getOrAddColumn(allocator, i.operands.register);
605 column.rule = .{
606 .val_expression = i.operands.block,
607 };
581608 },
582609 }
583610
lib/std/dwarf/expressions.zig+193-27
......@@ -2,6 +2,9 @@ const std = @import("std");
22const builtin = @import("builtin");
33const OP = @import("OP.zig");
44const leb = @import("../leb128.zig");
5const dwarf = @import("../dwarf.zig");
6const abi = dwarf.abi;
7const mem = std.mem;
58
69pub const StackMachineOptions = struct {
710 /// The address size of the target architecture
......@@ -33,9 +36,10 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {
3336 };
3437
3538 return struct {
36 const Value = union(enum) {
39 const Self = @This();
40
41 const Operand = union(enum) {
3742 generic: addr_type,
38 const_type: []const u8,
3943 register: u8,
4044 base_register: struct {
4145 base_register: u8,
......@@ -46,7 +50,11 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {
4650 offset: i64,
4751 },
4852 block: []const u8,
49 base_type: struct {
53 register_type: struct {
54 register: u8,
55 type_offset: u64,
56 },
57 const_type: struct {
5058 type_offset: u64,
5159 value_bytes: []const u8,
5260 },
......@@ -56,9 +64,31 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {
5664 },
5765 };
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
5981 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 {
6292 const int_info = @typeInfo(@TypeOf(value)).Int;
6393 if (@sizeOf(@TypeOf(value)) > options.addr_size) {
6494 return .{ .generic = switch (int_info.signedness) {
......@@ -73,7 +103,7 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {
73103 }
74104 }
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 {
77107 const reader = stream.reader();
78108 return switch (opcode) {
79109 OP.addr,
......@@ -87,8 +117,8 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {
87117 OP.const1s => generic(try reader.readByteSigned()),
88118 OP.const2u,
89119 OP.call2,
90 OP.call4,
91120 => generic(try reader.readInt(u16, options.endian)),
121 OP.call4 => generic(try reader.readInt(u32, options.endian)),
92122 OP.const2s,
93123 OP.bra,
94124 OP.skip,
......@@ -114,21 +144,35 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {
114144 .offset = try leb.readILEB128(i64, reader),
115145 } },
116146 OP.regx => .{ .register = try leb.readULEB128(u8, reader) },
117 OP.bregx, OP.regval_type => .{ .base_register = .{
118 .base_register = try leb.readULEB128(u8, reader),
119 .offset = try leb.readILEB128(i64, reader),
120 } },
147 OP.bregx => blk: {
148 const base_register = try leb.readULEB128(u8, reader);
149 const offset = try leb.readILEB128(i64, reader);
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 },
121163 OP.piece => .{
122164 .composite_location = .{
123165 .size = try leb.readULEB128(u8, reader),
124166 .offset = 0,
125167 },
126168 },
127 OP.bit_piece => .{
128 .composite_location = .{
129 .size = try leb.readULEB128(u8, reader),
130 .offset = try leb.readILEB128(i64, reader),
131 },
169 OP.bit_piece => blk: {
170 const size = try leb.readULEB128(u8, reader);
171 const offset = try leb.readILEB128(i64, reader);
172 break :blk .{ .composite_location = .{
173 .size = size,
174 .offset = offset,
175 } };
132176 },
133177 OP.implicit_value, OP.entry_value => blk: {
134178 const size = try leb.readULEB128(u8, reader);
......@@ -145,7 +189,7 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {
145189 if (stream.pos + size > stream.buffer.len) return error.InvalidExpression;
146190 const value_bytes = stream.buffer[stream.pos..][0..size];
147191 stream.pos += size;
148 break :blk .{ .base_type = .{
192 break :blk .{ .const_type = .{
149193 .type_offset = type_offset,
150194 .value_bytes = value_bytes,
151195 } };
......@@ -163,22 +207,144 @@ pub fn StackMachine(comptime options: StackMachineOptions) type {
163207 };
164208 }
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
166227 pub fn step(
167 self: *StackMachine,
168 stream: std.io.FixedBufferStream([]const u8),
228 self: *Self,
229 stream: *std.io.FixedBufferStream([]const u8),
169230 allocator: std.mem.Allocator,
170 ) !void {
171 if (@sizeOf(usize) != addr_type or options.endian != builtin.target.cpu.arch.endian())
231 compile_unit: ?*const dwarf.CompileUnit,
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())
172236 @compileError("Execution of non-native address sizees / endianness is not supported");
173237
174 const opcode = try stream.reader.readByte();
175 _ = opcode;
176 _ = self;
177 _ = allocator;
238 const opcode = try stream.reader().readByte();
239 if (options.call_frame_mode) {
240 // Certain opcodes are not allowed in a CFA context, see 6.4.2
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) {
180 // OP.addr => try self.stack.append(allocator, try readOperand(stream, opcode)),
181 // }
347 return stream.pos < stream.buffer.len;
182348 }
183349 };
184350}