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) {...@@ -50,189 +50,246 @@ const Opcode = enum(u8) {
50 pub const hi_user = 0x3f;50 pub const hi_user = 0x3f;
51};51};
5252
53const Operand = enum {53fn readBlock(stream: *std.io.FixedBufferStream([]const u8)) ![]const u8 {
54 opcode_delta,54 const reader = stream.reader();
55 opcode_register,55 const block_len = try leb.readULEB128(usize, reader);
56 uleb128_register,56 if (stream.pos + block_len > stream.buffer.len) return error.InvalidOperand;
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;
10757
108 return block;58 const block = stream.buffer[stream.pos..][0..block_len];
109 },59 reader.context.pos += block_len;
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 }
15660
157 return .{ .operands = operands };61 return block;
158 }
159 };
160}62}
16163
162pub const Instruction = union(Opcode) {64pub const Instruction = union(Opcode) {
163 advance_loc: InstructionType(.{ .delta = .opcode_delta }),65 advance_loc: struct {
164 offset: InstructionType(.{ .register = .opcode_register, .offset = .uleb128_offset }),66 delta: u8,
165 offset_extended: InstructionType(.{ .register = .uleb128_register, .offset = .uleb128_offset }),67 },
166 restore: InstructionType(.{ .register = .opcode_register }),68 offset: struct {
167 restore_extended: InstructionType(.{ .register = .uleb128_register }),69 register: u8,
168 nop: InstructionType(.{}),70 offset: u64,
169 set_loc: InstructionType(.{ .address = .address }),71 },
170 advance_loc1: InstructionType(.{ .delta = .u8_delta }),72 offset_extended: struct {
171 advance_loc2: InstructionType(.{ .delta = .u16_delta }),73 register: u8,
172 advance_loc4: InstructionType(.{ .delta = .u32_delta }),74 offset: u64,
173 undefined: InstructionType(.{ .register = .uleb128_register }),75 },
174 same_value: InstructionType(.{ .register = .uleb128_register }),76 restore: struct {
175 register: InstructionType(.{ .register = .uleb128_register, .target_register = .uleb128_register }),77 register: u8,
176 remember_state: InstructionType(.{}),78 },
177 restore_state: InstructionType(.{}),79 restore_extended: struct {
178 def_cfa: InstructionType(.{ .register = .uleb128_register, .offset = .uleb128_offset }),80 register: u8,
179 def_cfa_register: InstructionType(.{ .register = .uleb128_register }),81 },
180 def_cfa_offset: InstructionType(.{ .offset = .uleb128_offset }),82 nop: void,
181 def_cfa_expression: InstructionType(.{ .block = .block }),83 set_loc: struct {
182 expression: InstructionType(.{ .register = .uleb128_register, .block = .block }),84 address: u64,
183 offset_extended_sf: InstructionType(.{ .register = .uleb128_register, .offset = .sleb128_offset }),85 },
184 def_cfa_sf: InstructionType(.{ .register = .uleb128_register, .offset = .sleb128_offset }),86 advance_loc1: struct {
185 def_cfa_offset_sf: InstructionType(.{ .offset = .sleb128_offset }),87 delta: u8,
186 val_offset: InstructionType(.{ .register = .uleb128_register, .offset = .uleb128_offset }),88 },
187 val_offset_sf: InstructionType(.{ .register = .uleb128_register, .offset = .sleb128_offset }),89 advance_loc2: struct {
188 val_expression: InstructionType(.{ .register = .uleb128_register, .block = .block }),90 delta: u16,
18991 },
190 fn readOperands(92 advance_loc4: struct {
191 self: *Instruction,93 delta: u32,
192 stream: *std.io.FixedBufferStream([]const u8),94 },
193 opcode_value: ?u6,95 undefined: struct {
194 addr_size_bytes: u8,96 register: u8,
195 endian: std.builtin.Endian,97 },
196 ) !void {98 same_value: struct {
197 switch (self.*) {99 register: u8,
198 inline else => |*inst| inst.* = try @TypeOf(inst.*).read(stream, opcode_value, addr_size_bytes, endian),100 },
199 }101 register: struct {
200 }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
202 pub fn read(148 pub fn read(
203 stream: *std.io.FixedBufferStream([]const u8),149 stream: *std.io.FixedBufferStream([]const u8),
204 addr_size_bytes: u8,150 addr_size_bytes: u8,
205 endian: std.builtin.Endian,151 endian: std.builtin.Endian,
206
207 ) !Instruction {152 ) !Instruction {
208 switch (try stream.reader().readByte()) {153 const reader = stream.reader();
154 switch (try reader.readByte()) {
209 Opcode.lo_inline...Opcode.hi_inline => |opcode| {155 Opcode.lo_inline...Opcode.hi_inline => |opcode| {
210 const e: Opcode = @enumFromInt(opcode & 0b11000000);156 const e: Opcode = @enumFromInt(opcode & 0b11000000);
211 switch (e) {157 const value: u6 = @intCast(opcode & 0b111111);
212 inline .advance_loc,158 return switch (e) {
213 .offset,159 .advance_loc => .{
214 .restore,160 .advance_loc = .{ .delta = value },
215 => |tag| {161 },
216 var result = @unionInit(Instruction, @tagName(tag), undefined);162 .offset => .{
217 try result.readOperands(stream, @as(u6, @intCast(opcode & 0b111111)), addr_size_bytes, endian);163 .offset = .{
218 return result;164 .register = value,
165 .offset = try leb.readULEB128(u64, reader),
166 },
167 },
168 .restore => .{
169 .restore = .{ .register = value },
219 },170 },
220 else => unreachable,171 else => unreachable,
221 }172 };
222 },173 },
223 Opcode.lo_reserved...Opcode.hi_reserved => |opcode| {174 Opcode.lo_reserved...Opcode.hi_reserved => |opcode| {
224 const e: Opcode = @enumFromInt(opcode);175 const e: Opcode = @enumFromInt(opcode);
225 switch (e) {176 return switch (e) {
226 .advance_loc,177 .advance_loc,
227 .offset,178 .offset,
228 .restore,179 .restore,
229 => unreachable,180 => unreachable,
230 inline else => |tag| {181 .nop => .{ .nop = {} },
231 var result = @unionInit(Instruction, @tagName(tag), undefined);182 .set_loc => .{
232 try result.readOperands(stream, null, addr_size_bytes, endian);183 .set_loc = .{
233 return result;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) },
234 },200 },
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 };
236 },293 },
237 Opcode.lo_user...Opcode.hi_user => return error.UnimplementedUserOpcode,294 Opcode.lo_user...Opcode.hi_user => return error.UnimplementedUserOpcode,
238 else => return error.InvalidOpcode,295 else => return error.InvalidOpcode,
...@@ -492,16 +549,16 @@ pub const VirtualMachine = struct {...@@ -492,16 +549,16 @@ pub const VirtualMachine = struct {
492 const prev_row = self.current_row;549 const prev_row = self.current_row;
493 switch (instruction) {550 switch (instruction) {
494 .set_loc => |i| {551 .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;
496 // TODO: Check cie.segment_selector_size != 0 for DWARFV4553 // TODO: Check cie.segment_selector_size != 0 for DWARFV4
497 self.current_row.offset = i.operands.address;554 self.current_row.offset = i.address;
498 },555 },
499 inline .advance_loc,556 inline .advance_loc,
500 .advance_loc1,557 .advance_loc1,
501 .advance_loc2,558 .advance_loc2,
502 .advance_loc4,559 .advance_loc4,
503 => |i| {560 => |i| {
504 self.current_row.offset += i.operands.delta * cie.code_alignment_factor;561 self.current_row.offset += i.delta * cie.code_alignment_factor;
505 self.current_row.copy_on_write = true;562 self.current_row.copy_on_write = true;
506 },563 },
507 inline .offset,564 inline .offset,
...@@ -509,35 +566,35 @@ pub const VirtualMachine = struct {...@@ -509,35 +566,35 @@ pub const VirtualMachine = struct {
509 .offset_extended_sf,566 .offset_extended_sf,
510 => |i| {567 => |i| {
511 try self.resolveCopyOnWrite(allocator);568 try self.resolveCopyOnWrite(allocator);
512 const column = try self.getOrAddColumn(allocator, i.operands.register);569 const column = try self.getOrAddColumn(allocator, i.register);
513 column.rule = .{ .offset = @as(i64, @intCast(i.operands.offset)) * cie.data_alignment_factor };570 column.rule = .{ .offset = @as(i64, @intCast(i.offset)) * cie.data_alignment_factor };
514 },571 },
515 inline .restore,572 inline .restore,
516 .restore_extended,573 .restore_extended,
517 => |i| {574 => |i| {
518 try self.resolveCopyOnWrite(allocator);575 try self.resolveCopyOnWrite(allocator);
519 if (self.cie_row) |cie_row| {576 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);
521 column.rule = for (self.rowColumns(cie_row)) |cie_column| {578 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;
523 } else .{ .default = {} };580 } else .{ .default = {} };
524 } else return error.InvalidOperation;581 } else return error.InvalidOperation;
525 },582 },
526 .nop => {},583 .nop => {},
527 .undefined => |i| {584 .undefined => |i| {
528 try self.resolveCopyOnWrite(allocator);585 try self.resolveCopyOnWrite(allocator);
529 const column = try self.getOrAddColumn(allocator, i.operands.register);586 const column = try self.getOrAddColumn(allocator, i.register);
530 column.rule = .{ .undefined = {} };587 column.rule = .{ .undefined = {} };
531 },588 },
532 .same_value => |i| {589 .same_value => |i| {
533 try self.resolveCopyOnWrite(allocator);590 try self.resolveCopyOnWrite(allocator);
534 const column = try self.getOrAddColumn(allocator, i.operands.register);591 const column = try self.getOrAddColumn(allocator, i.register);
535 column.rule = .{ .same_value = {} };592 column.rule = .{ .same_value = {} };
536 },593 },
537 .register => |i| {594 .register => |i| {
538 try self.resolveCopyOnWrite(allocator);595 try self.resolveCopyOnWrite(allocator);
539 const column = try self.getOrAddColumn(allocator, i.operands.register);596 const column = try self.getOrAddColumn(allocator, i.register);
540 column.rule = .{ .register = i.operands.target_register };597 column.rule = .{ .register = i.target_register };
541 },598 },
542 .remember_state => {599 .remember_state => {
543 try self.stack.append(allocator, self.current_row.columns);600 try self.stack.append(allocator, self.current_row.columns);
...@@ -555,69 +612,69 @@ pub const VirtualMachine = struct {...@@ -555,69 +612,69 @@ pub const VirtualMachine = struct {
555 .def_cfa => |i| {612 .def_cfa => |i| {
556 try self.resolveCopyOnWrite(allocator);613 try self.resolveCopyOnWrite(allocator);
557 self.current_row.cfa = .{614 self.current_row.cfa = .{
558 .register = i.operands.register,615 .register = i.register,
559 .rule = .{ .val_offset = @intCast(i.operands.offset) },616 .rule = .{ .val_offset = @intCast(i.offset) },
560 };617 };
561 },618 },
562 .def_cfa_sf => |i| {619 .def_cfa_sf => |i| {
563 try self.resolveCopyOnWrite(allocator);620 try self.resolveCopyOnWrite(allocator);
564 self.current_row.cfa = .{621 self.current_row.cfa = .{
565 .register = i.operands.register,622 .register = i.register,
566 .rule = .{ .val_offset = i.operands.offset * cie.data_alignment_factor },623 .rule = .{ .val_offset = i.offset * cie.data_alignment_factor },
567 };624 };
568 },625 },
569 .def_cfa_register => |i| {626 .def_cfa_register => |i| {
570 try self.resolveCopyOnWrite(allocator);627 try self.resolveCopyOnWrite(allocator);
571 if (self.current_row.cfa.register == null or self.current_row.cfa.rule != .val_offset) return error.InvalidOperation;628 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;
573 },630 },
574 .def_cfa_offset => |i| {631 .def_cfa_offset => |i| {
575 try self.resolveCopyOnWrite(allocator);632 try self.resolveCopyOnWrite(allocator);
576 if (self.current_row.cfa.register == null or self.current_row.cfa.rule != .val_offset) return error.InvalidOperation;633 if (self.current_row.cfa.register == null or self.current_row.cfa.rule != .val_offset) return error.InvalidOperation;
577 self.current_row.cfa.rule = .{634 self.current_row.cfa.rule = .{
578 .val_offset = @intCast(i.operands.offset),635 .val_offset = @intCast(i.offset),
579 };636 };
580 },637 },
581 .def_cfa_offset_sf => |i| {638 .def_cfa_offset_sf => |i| {
582 try self.resolveCopyOnWrite(allocator);639 try self.resolveCopyOnWrite(allocator);
583 if (self.current_row.cfa.register == null or self.current_row.cfa.rule != .val_offset) return error.InvalidOperation;640 if (self.current_row.cfa.register == null or self.current_row.cfa.rule != .val_offset) return error.InvalidOperation;
584 self.current_row.cfa.rule = .{641 self.current_row.cfa.rule = .{
585 .val_offset = i.operands.offset * cie.data_alignment_factor,642 .val_offset = i.offset * cie.data_alignment_factor,
586 };643 };
587 },644 },
588 .def_cfa_expression => |i| {645 .def_cfa_expression => |i| {
589 try self.resolveCopyOnWrite(allocator);646 try self.resolveCopyOnWrite(allocator);
590 self.current_row.cfa.register = undefined;647 self.current_row.cfa.register = undefined;
591 self.current_row.cfa.rule = .{648 self.current_row.cfa.rule = .{
592 .expression = i.operands.block,649 .expression = i.block,
593 };650 };
594 },651 },
595 .expression => |i| {652 .expression => |i| {
596 try self.resolveCopyOnWrite(allocator);653 try self.resolveCopyOnWrite(allocator);
597 const column = try self.getOrAddColumn(allocator, i.operands.register);654 const column = try self.getOrAddColumn(allocator, i.register);
598 column.rule = .{655 column.rule = .{
599 .expression = i.operands.block,656 .expression = i.block,
600 };657 };
601 },658 },
602 .val_offset => |i| {659 .val_offset => |i| {
603 try self.resolveCopyOnWrite(allocator);660 try self.resolveCopyOnWrite(allocator);
604 const column = try self.getOrAddColumn(allocator, i.operands.register);661 const column = try self.getOrAddColumn(allocator, i.register);
605 column.rule = .{662 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,
607 };664 };
608 },665 },
609 .val_offset_sf => |i| {666 .val_offset_sf => |i| {
610 try self.resolveCopyOnWrite(allocator);667 try self.resolveCopyOnWrite(allocator);
611 const column = try self.getOrAddColumn(allocator, i.operands.register);668 const column = try self.getOrAddColumn(allocator, i.register);
612 column.rule = .{669 column.rule = .{
613 .val_offset = i.operands.offset * cie.data_alignment_factor,670 .val_offset = i.offset * cie.data_alignment_factor,
614 };671 };
615 },672 },
616 .val_expression => |i| {673 .val_expression => |i| {
617 try self.resolveCopyOnWrite(allocator);674 try self.resolveCopyOnWrite(allocator);
618 const column = try self.getOrAddColumn(allocator, i.operands.register);675 const column = try self.getOrAddColumn(allocator, i.register);
619 column.rule = .{676 column.rule = .{
620 .val_expression = i.operands.block,677 .val_expression = i.block,
621 };678 };
622 },679 },
623 }680 }