authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-07-24 10:43:14-04:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-07-24 10:43:14-04:00
logd1ed1c167bc3227398037b8e7ad2937146edf7a3
treede50ee4a737bc6900e1723b4cccbf601c57fd484
parent20ce7455b9acea004e985b4f4d4b1133899ea77b

simplify call frame instruction parser


1 files changed, 244 insertions(+), 187 deletions(-)

lib/std/dwarf/call_frame.zig+244-187
......@@ -50,189 +50,246 @@ const Opcode = enum(u8) {
5050 pub const hi_user = 0x3f;
5151};
5252
53const Operand = enum {
54 opcode_delta,
55 opcode_register,
56 uleb128_register,
57 uleb128_offset,
58 sleb128_offset,
59 address,
60 u8_delta,
61 u16_delta,
62 u32_delta,
63 block,
64
65 fn Storage(comptime self: Operand) type {
66 return switch (self) {
67 .opcode_delta, .opcode_register => u8,
68 .uleb128_register => u8,
69 .uleb128_offset => u64,
70 .sleb128_offset => i64,
71 .address => u64,
72 .u8_delta => u8,
73 .u16_delta => u16,
74 .u32_delta => u32,
75 .block => []const u8,
76 };
77 }
78
79 fn read(
80 comptime self: Operand,
81 stream: *std.io.FixedBufferStream([]const u8),
82 opcode_value: ?u6,
83 addr_size_bytes: u8,
84 endian: std.builtin.Endian,
85 ) !Storage(self) {
86 const reader = stream.reader();
87 return switch (self) {
88 .opcode_delta, .opcode_register => opcode_value orelse return error.InvalidOperand,
89 .uleb128_register => try leb.readULEB128(u8, reader),
90 .uleb128_offset => try leb.readULEB128(u64, reader),
91 .sleb128_offset => try leb.readILEB128(i64, reader),
92 .address => switch (addr_size_bytes) {
93 2 => try reader.readInt(u16, endian),
94 4 => try reader.readInt(u32, endian),
95 8 => try reader.readInt(u64, endian),
96 else => return error.InvalidAddrSize,
97 },
98 .u8_delta => try reader.readByte(),
99 .u16_delta => try reader.readInt(u16, endian),
100 .u32_delta => try reader.readInt(u32, endian),
101 .block => {
102 const block_len = try leb.readULEB128(usize, reader);
103 if (stream.pos + block_len > stream.buffer.len) return error.InvalidOperand;
104
105 const block = stream.buffer[stream.pos..][0..block_len];
106 reader.context.pos += block_len;
53fn readBlock(stream: *std.io.FixedBufferStream([]const u8)) ![]const u8 {
54 const reader = stream.reader();
55 const block_len = try leb.readULEB128(usize, reader);
56 if (stream.pos + block_len > stream.buffer.len) return error.InvalidOperand;
10757
108 return block;
109 },
110 };
111 }
112};
113
114fn InstructionType(comptime definition: anytype) type {
115 const definition_type = @typeInfo(@TypeOf(definition));
116 assert(definition_type == .Struct);
117
118 const definition_len = definition_type.Struct.fields.len;
119 comptime var fields: [definition_len]std.builtin.Type.StructField = undefined;
120 inline for (definition_type.Struct.fields, &fields) |definition_field, *operands_field| {
121 const opcode = std.enums.nameCast(Operand, @field(definition, definition_field.name));
122 const storage_type = opcode.Storage();
123 operands_field.* = .{
124 .name = definition_field.name,
125 .type = storage_type,
126 .default_value = null,
127 .is_comptime = false,
128 .alignment = @alignOf(storage_type),
129 };
130 }
131
132 const InstructionOperands = @Type(.{
133 .Struct = .{
134 .layout = .Auto,
135 .fields = &fields,
136 .decls = &.{},
137 .is_tuple = false,
138 },
139 });
140
141 return struct {
142 const Self = @This();
143 operands: InstructionOperands,
144
145 pub fn read(
146 stream: *std.io.FixedBufferStream([]const u8),
147 opcode_value: ?u6,
148 addr_size_bytes: u8,
149 endian: std.builtin.Endian,
150 ) !Self {
151 var operands: InstructionOperands = undefined;
152 inline for (definition_type.Struct.fields) |definition_field| {
153 const operand = comptime std.enums.nameCast(Operand, @field(definition, definition_field.name));
154 @field(operands, definition_field.name) = try operand.read(stream, opcode_value, addr_size_bytes, endian);
155 }
58 const block = stream.buffer[stream.pos..][0..block_len];
59 reader.context.pos += block_len;
15660
157 return .{ .operands = operands };
158 }
159 };
61 return block;
16062}
16163
16264pub const Instruction = union(Opcode) {
163 advance_loc: InstructionType(.{ .delta = .opcode_delta }),
164 offset: InstructionType(.{ .register = .opcode_register, .offset = .uleb128_offset }),
165 offset_extended: InstructionType(.{ .register = .uleb128_register, .offset = .uleb128_offset }),
166 restore: InstructionType(.{ .register = .opcode_register }),
167 restore_extended: InstructionType(.{ .register = .uleb128_register }),
168 nop: InstructionType(.{}),
169 set_loc: InstructionType(.{ .address = .address }),
170 advance_loc1: InstructionType(.{ .delta = .u8_delta }),
171 advance_loc2: InstructionType(.{ .delta = .u16_delta }),
172 advance_loc4: InstructionType(.{ .delta = .u32_delta }),
173 undefined: InstructionType(.{ .register = .uleb128_register }),
174 same_value: InstructionType(.{ .register = .uleb128_register }),
175 register: InstructionType(.{ .register = .uleb128_register, .target_register = .uleb128_register }),
176 remember_state: InstructionType(.{}),
177 restore_state: InstructionType(.{}),
178 def_cfa: InstructionType(.{ .register = .uleb128_register, .offset = .uleb128_offset }),
179 def_cfa_register: InstructionType(.{ .register = .uleb128_register }),
180 def_cfa_offset: InstructionType(.{ .offset = .uleb128_offset }),
181 def_cfa_expression: InstructionType(.{ .block = .block }),
182 expression: InstructionType(.{ .register = .uleb128_register, .block = .block }),
183 offset_extended_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 }),
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 }),
189
190 fn readOperands(
191 self: *Instruction,
192 stream: *std.io.FixedBufferStream([]const u8),
193 opcode_value: ?u6,
194 addr_size_bytes: u8,
195 endian: std.builtin.Endian,
196 ) !void {
197 switch (self.*) {
198 inline else => |*inst| inst.* = try @TypeOf(inst.*).read(stream, opcode_value, addr_size_bytes, endian),
199 }
200 }
65 advance_loc: struct {
66 delta: u8,
67 },
68 offset: struct {
69 register: u8,
70 offset: u64,
71 },
72 offset_extended: struct {
73 register: u8,
74 offset: u64,
75 },
76 restore: struct {
77 register: u8,
78 },
79 restore_extended: struct {
80 register: u8,
81 },
82 nop: void,
83 set_loc: struct {
84 address: u64,
85 },
86 advance_loc1: struct {
87 delta: u8,
88 },
89 advance_loc2: struct {
90 delta: u16,
91 },
92 advance_loc4: struct {
93 delta: u32,
94 },
95 undefined: struct {
96 register: u8,
97 },
98 same_value: struct {
99 register: u8,
100 },
101 register: struct {
102 register: u8,
103 target_register: u8,
104 },
105 remember_state: void,
106 restore_state: void,
107 def_cfa: struct {
108 register: u8,
109 offset: u64,
110 },
111 def_cfa_register: struct {
112 register: u8,
113 },
114 def_cfa_offset: struct {
115 offset: u64,
116 },
117 def_cfa_expression: struct {
118 block: []const u8,
119 },
120 expression: struct {
121 register: u8,
122 block: []const u8,
123 },
124 offset_extended_sf: struct {
125 register: u8,
126 offset: i64,
127 },
128 def_cfa_sf: struct {
129 register: u8,
130 offset: i64,
131 },
132 def_cfa_offset_sf: struct {
133 offset: i64,
134 },
135 val_offset: struct {
136 register: u8,
137 offset: u64,
138 },
139 val_offset_sf: struct {
140 register: u8,
141 offset: i64,
142 },
143 val_expression: struct {
144 register: u8,
145 block: []const u8,
146 },
201147
202148 pub fn read(
203149 stream: *std.io.FixedBufferStream([]const u8),
204150 addr_size_bytes: u8,
205151 endian: std.builtin.Endian,
206
207152 ) !Instruction {
208 switch (try stream.reader().readByte()) {
153 const reader = stream.reader();
154 switch (try reader.readByte()) {
209155 Opcode.lo_inline...Opcode.hi_inline => |opcode| {
210156 const e: Opcode = @enumFromInt(opcode & 0b11000000);
211 switch (e) {
212 inline .advance_loc,
213 .offset,
214 .restore,
215 => |tag| {
216 var result = @unionInit(Instruction, @tagName(tag), undefined);
217 try result.readOperands(stream, @as(u6, @intCast(opcode & 0b111111)), addr_size_bytes, endian);
218 return result;
157 const value: u6 = @intCast(opcode & 0b111111);
158 return switch (e) {
159 .advance_loc => .{
160 .advance_loc = .{ .delta = value },
161 },
162 .offset => .{
163 .offset = .{
164 .register = value,
165 .offset = try leb.readULEB128(u64, reader),
166 },
167 },
168 .restore => .{
169 .restore = .{ .register = value },
219170 },
220171 else => unreachable,
221 }
172 };
222173 },
223174 Opcode.lo_reserved...Opcode.hi_reserved => |opcode| {
224175 const e: Opcode = @enumFromInt(opcode);
225 switch (e) {
176 return switch (e) {
226177 .advance_loc,
227178 .offset,
228179 .restore,
229180 => unreachable,
230 inline else => |tag| {
231 var result = @unionInit(Instruction, @tagName(tag), undefined);
232 try result.readOperands(stream, null, addr_size_bytes, endian);
233 return result;
181 .nop => .{ .nop = {} },
182 .set_loc => .{
183 .set_loc = .{
184 .address = switch (addr_size_bytes) {
185 2 => try reader.readInt(u16, endian),
186 4 => try reader.readInt(u32, endian),
187 8 => try reader.readInt(u64, endian),
188 else => return error.InvalidAddrSize,
189 },
190 },
191 },
192 .advance_loc1 => .{
193 .advance_loc1 = .{ .delta = try reader.readByte() },
194 },
195 .advance_loc2 => .{
196 .advance_loc2 = .{ .delta = try reader.readInt(u16, endian) },
197 },
198 .advance_loc4 => .{
199 .advance_loc4 = .{ .delta = try reader.readInt(u32, endian) },
234200 },
235 }
201 .offset_extended => .{
202 .offset_extended = .{
203 .register = try leb.readULEB128(u8, reader),
204 .offset = try leb.readULEB128(u64, reader),
205 },
206 },
207 .restore_extended => .{
208 .restore_extended = .{
209 .register = try leb.readULEB128(u8, reader),
210 },
211 },
212 .undefined => .{
213 .undefined = .{
214 .register = try leb.readULEB128(u8, reader),
215 },
216 },
217 .same_value => .{
218 .same_value = .{
219 .register = try leb.readULEB128(u8, reader),
220 },
221 },
222 .register => .{
223 .register = .{
224 .register = try leb.readULEB128(u8, reader),
225 .target_register = try leb.readULEB128(u8, reader),
226 },
227 },
228 .remember_state => .{ .remember_state = {} },
229 .restore_state => .{ .restore_state = {} },
230 .def_cfa => .{
231 .def_cfa = .{
232 .register = try leb.readULEB128(u8, reader),
233 .offset = try leb.readULEB128(u64, reader),
234 },
235 },
236 .def_cfa_register => .{
237 .def_cfa_register = .{
238 .register = try leb.readULEB128(u8, reader),
239 },
240 },
241 .def_cfa_offset => .{
242 .def_cfa_offset = .{
243 .offset = try leb.readULEB128(u64, reader),
244 },
245 },
246 .def_cfa_expression => .{
247 .def_cfa_expression = .{
248 .block = try readBlock(stream),
249 },
250 },
251 .expression => .{
252 .expression = .{
253 .register = try leb.readULEB128(u8, reader),
254 .block = try readBlock(stream),
255 },
256 },
257 .offset_extended_sf => .{
258 .offset_extended_sf = .{
259 .register = try leb.readULEB128(u8, reader),
260 .offset = try leb.readILEB128(i64, reader),
261 },
262 },
263 .def_cfa_sf => .{
264 .def_cfa_sf = .{
265 .register = try leb.readULEB128(u8, reader),
266 .offset = try leb.readILEB128(i64, reader),
267 },
268 },
269 .def_cfa_offset_sf => .{
270 .def_cfa_offset_sf = .{
271 .offset = try leb.readILEB128(i64, reader),
272 },
273 },
274 .val_offset => .{
275 .val_offset = .{
276 .register = try leb.readULEB128(u8, reader),
277 .offset = try leb.readULEB128(u64, reader),
278 },
279 },
280 .val_offset_sf => .{
281 .val_offset_sf = .{
282 .register = try leb.readULEB128(u8, reader),
283 .offset = try leb.readILEB128(i64, reader),
284 },
285 },
286 .val_expression => .{
287 .val_expression = .{
288 .register = try leb.readULEB128(u8, reader),
289 .block = try readBlock(stream),
290 },
291 },
292 };
236293 },
237294 Opcode.lo_user...Opcode.hi_user => return error.UnimplementedUserOpcode,
238295 else => return error.InvalidOpcode,
......@@ -492,16 +549,16 @@ pub const VirtualMachine = struct {
492549 const prev_row = self.current_row;
493550 switch (instruction) {
494551 .set_loc => |i| {
495 if (i.operands.address <= self.current_row.offset) return error.InvalidOperation;
552 if (i.address <= self.current_row.offset) return error.InvalidOperation;
496553 // TODO: Check cie.segment_selector_size != 0 for DWARFV4
497 self.current_row.offset = i.operands.address;
554 self.current_row.offset = i.address;
498555 },
499556 inline .advance_loc,
500557 .advance_loc1,
501558 .advance_loc2,
502559 .advance_loc4,
503560 => |i| {
504 self.current_row.offset += i.operands.delta * cie.code_alignment_factor;
561 self.current_row.offset += i.delta * cie.code_alignment_factor;
505562 self.current_row.copy_on_write = true;
506563 },
507564 inline .offset,
......@@ -509,35 +566,35 @@ pub const VirtualMachine = struct {
509566 .offset_extended_sf,
510567 => |i| {
511568 try self.resolveCopyOnWrite(allocator);
512 const column = try self.getOrAddColumn(allocator, i.operands.register);
513 column.rule = .{ .offset = @as(i64, @intCast(i.operands.offset)) * cie.data_alignment_factor };
569 const column = try self.getOrAddColumn(allocator, i.register);
570 column.rule = .{ .offset = @as(i64, @intCast(i.offset)) * cie.data_alignment_factor };
514571 },
515572 inline .restore,
516573 .restore_extended,
517574 => |i| {
518575 try self.resolveCopyOnWrite(allocator);
519576 if (self.cie_row) |cie_row| {
520 const column = try self.getOrAddColumn(allocator, i.operands.register);
577 const column = try self.getOrAddColumn(allocator, i.register);
521578 column.rule = for (self.rowColumns(cie_row)) |cie_column| {
522 if (cie_column.register == i.operands.register) break cie_column.rule;
579 if (cie_column.register == i.register) break cie_column.rule;
523580 } else .{ .default = {} };
524581 } else return error.InvalidOperation;
525582 },
526583 .nop => {},
527584 .undefined => |i| {
528585 try self.resolveCopyOnWrite(allocator);
529 const column = try self.getOrAddColumn(allocator, i.operands.register);
586 const column = try self.getOrAddColumn(allocator, i.register);
530587 column.rule = .{ .undefined = {} };
531588 },
532589 .same_value => |i| {
533590 try self.resolveCopyOnWrite(allocator);
534 const column = try self.getOrAddColumn(allocator, i.operands.register);
591 const column = try self.getOrAddColumn(allocator, i.register);
535592 column.rule = .{ .same_value = {} };
536593 },
537594 .register => |i| {
538595 try self.resolveCopyOnWrite(allocator);
539 const column = try self.getOrAddColumn(allocator, i.operands.register);
540 column.rule = .{ .register = i.operands.target_register };
596 const column = try self.getOrAddColumn(allocator, i.register);
597 column.rule = .{ .register = i.target_register };
541598 },
542599 .remember_state => {
543600 try self.stack.append(allocator, self.current_row.columns);
......@@ -555,69 +612,69 @@ pub const VirtualMachine = struct {
555612 .def_cfa => |i| {
556613 try self.resolveCopyOnWrite(allocator);
557614 self.current_row.cfa = .{
558 .register = i.operands.register,
559 .rule = .{ .val_offset = @intCast(i.operands.offset) },
615 .register = i.register,
616 .rule = .{ .val_offset = @intCast(i.offset) },
560617 };
561618 },
562619 .def_cfa_sf => |i| {
563620 try self.resolveCopyOnWrite(allocator);
564621 self.current_row.cfa = .{
565 .register = i.operands.register,
566 .rule = .{ .val_offset = i.operands.offset * cie.data_alignment_factor },
622 .register = i.register,
623 .rule = .{ .val_offset = i.offset * cie.data_alignment_factor },
567624 };
568625 },
569626 .def_cfa_register => |i| {
570627 try self.resolveCopyOnWrite(allocator);
571628 if (self.current_row.cfa.register == null or self.current_row.cfa.rule != .val_offset) return error.InvalidOperation;
572 self.current_row.cfa.register = i.operands.register;
629 self.current_row.cfa.register = i.register;
573630 },
574631 .def_cfa_offset => |i| {
575632 try self.resolveCopyOnWrite(allocator);
576633 if (self.current_row.cfa.register == null or self.current_row.cfa.rule != .val_offset) return error.InvalidOperation;
577634 self.current_row.cfa.rule = .{
578 .val_offset = @intCast(i.operands.offset),
635 .val_offset = @intCast(i.offset),
579636 };
580637 },
581638 .def_cfa_offset_sf => |i| {
582639 try self.resolveCopyOnWrite(allocator);
583640 if (self.current_row.cfa.register == null or self.current_row.cfa.rule != .val_offset) return error.InvalidOperation;
584641 self.current_row.cfa.rule = .{
585 .val_offset = i.operands.offset * cie.data_alignment_factor,
642 .val_offset = i.offset * cie.data_alignment_factor,
586643 };
587644 },
588645 .def_cfa_expression => |i| {
589646 try self.resolveCopyOnWrite(allocator);
590647 self.current_row.cfa.register = undefined;
591648 self.current_row.cfa.rule = .{
592 .expression = i.operands.block,
649 .expression = i.block,
593650 };
594651 },
595652 .expression => |i| {
596653 try self.resolveCopyOnWrite(allocator);
597 const column = try self.getOrAddColumn(allocator, i.operands.register);
654 const column = try self.getOrAddColumn(allocator, i.register);
598655 column.rule = .{
599 .expression = i.operands.block,
656 .expression = i.block,
600657 };
601658 },
602659 .val_offset => |i| {
603660 try self.resolveCopyOnWrite(allocator);
604 const column = try self.getOrAddColumn(allocator, i.operands.register);
661 const column = try self.getOrAddColumn(allocator, i.register);
605662 column.rule = .{
606 .val_offset = @as(i64, @intCast(i.operands.offset)) * cie.data_alignment_factor,
663 .val_offset = @as(i64, @intCast(i.offset)) * cie.data_alignment_factor,
607664 };
608665 },
609666 .val_offset_sf => |i| {
610667 try self.resolveCopyOnWrite(allocator);
611 const column = try self.getOrAddColumn(allocator, i.operands.register);
668 const column = try self.getOrAddColumn(allocator, i.register);
612669 column.rule = .{
613 .val_offset = i.operands.offset * cie.data_alignment_factor,
670 .val_offset = i.offset * cie.data_alignment_factor,
614671 };
615672 },
616673 .val_expression => |i| {
617674 try self.resolveCopyOnWrite(allocator);
618 const column = try self.getOrAddColumn(allocator, i.operands.register);
675 const column = try self.getOrAddColumn(allocator, i.register);
619676 column.rule = .{
620 .val_expression = i.operands.block,
677 .val_expression = i.block,
621678 };
622679 },
623680 }