authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-05-08 02:28:39-04:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-07-20 22:58:13-04:00
log38303d7b9cd3eb12c59636e84b9a411b07ad79af
tree0a83adebf6ab67b49af4d41cb1096fd1f8b11149
parent8b8d6271371c66eb703bdbe6f13e0426c4c2436f

add VirtualMachine to run CFA instructions


1 files changed, 160 insertions(+), 3 deletions(-)

lib/std/dwarf/call_frame.zig+160-3
......@@ -217,13 +217,170 @@ pub const Instruction = union(Opcode) {
217217 .restore_state => {},
218218 .def_cfa => |i| {
219219 try abi.writeRegisterName(writer, arch, i.operands.register);
220 try writer.print(" +{}", .{ i.operands.offset });
220 try writer.print(" {}", .{ fmtOffset(@intCast(i64, i.operands.offset)) });
221221 },
222222 .def_cfa_register => {},
223 .def_cfa_offset => {},
223 .def_cfa_offset => |i| {
224 try writer.print("{}", .{ fmtOffset(@intCast(i64, i.operands.offset)) });
225 },
224226 .def_cfa_expression => |i| {
225 try writer.print("TODO parse expressions: {x}", .{ std.fmt.fmtSliceHexLower(i.operands.block) });
227 try writer.print("TODO(parse expressions data {x})", .{ std.fmt.fmtSliceHexLower(i.operands.block) });
228 },
229 .expression => {},
230 .offset_extended_sf => {},
231 .def_cfa_sf => {},
232 .def_cfa_offset_sf => {},
233 .val_offset => {},
234 .val_offset_sf => {},
235 .val_expression => {},
236 }
237 }
238
239};
240
241
242fn formatOffset(data: i64, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
243 _ = fmt;
244 if (data >= 0) try writer.writeByte('+');
245 return std.fmt.formatInt(data, 10, .lower, options, writer);
246}
247
248fn fmtOffset(offset: i64) std.fmt.Formatter(formatOffset) {
249 return .{ .data = offset };
250}
251
252/// See section 6.4.1 of the DWARF5 specification
253pub const VirtualMachine = struct {
254
255 const RegisterRule = union(enum) {
256 undefined: void,
257 same_value: void,
258 offset: i64,
259 val_offset: i64,
260 register: u8,
261 expression: []const u8,
262 val_expression: []const u8,
263 architectural: void,
264 };
265
266 const Column = struct {
267 register: u8 = undefined,
268 rule: RegisterRule = .{ .undefined = {} },
269
270 pub fn writeRule(self: Column, writer: anytype, is_cfa: bool, arch: ?std.Target.Cpu.Arch) !void {
271 if (is_cfa) {
272 try writer.writeAll("CFA");
273 } else {
274 try abi.writeRegisterName(writer, arch, self.register);
275 }
276
277 try writer.writeByte('=');
278 switch (self.rule) {
279 .undefined => {},
280 .same_value => try writer.writeAll("S"),
281 .offset => |offset| {
282 if (is_cfa) {
283 try abi.writeRegisterName(writer, arch, self.register);
284 try writer.print("{}", .{ fmtOffset(offset) });
285 } else {
286 try writer.print("[CFA{}]", .{ fmtOffset(offset) });
287 }
288 },
289 .val_offset => |offset| {
290 if (is_cfa) {
291 try abi.writeRegisterName(writer, arch, self.register);
292 try writer.print("{}", .{ fmtOffset(offset) });
293 } else {
294 try writer.print("CFA{}", .{ fmtOffset(offset) });
295 }
296 },
297 .register => |register| try abi.writeRegisterName(writer, arch, register),
298 .expression => try writer.writeAll("TODO(expression)"),
299 .val_expression => try writer.writeAll("TODO(val_expression)"),
300 .architectural => try writer.writeAll("TODO(architectural)"),
301 }
302 }
303 };
304
305 pub const Row = struct {
306 /// Offset from pc_begin
307 offset: u64 = 0,
308 cfa: Column = .{},
309 /// Index into `columns` of the first column in this row
310 columns_start: usize = undefined,
311 columns_len: u8 = 0,
312 };
313
314 rows: std.ArrayListUnmanaged(Row) = .{},
315 columns: std.ArrayListUnmanaged(Column) = .{},
316 current_row: Row = .{},
317
318 pub fn reset(self: *VirtualMachine) void {
319 self.rows.clearRetainingCapacity();
320 self.columns.clearRetainingCapacity();
321 self.current_row = .{};
322 }
323
324 pub fn deinit(self: *VirtualMachine, allocator: std.mem.Allocator) void {
325 self.rows.deinit(allocator);
326 self.columns.deinit(allocator);
327 self.* = undefined;
328 }
329
330 pub fn getColumns(self: VirtualMachine, row: Row) []Column {
331 return self.columns.items[row.columns_start..][0..row.columns_len];
332 }
333
334 fn getOrAddColumn(self: *VirtualMachine, allocator: std.mem.Allocator, register: u8) !*Column {
335 for (self.getColumns(self.current_row)) |*c| {
336 if (c.register == register) return c;
337 }
338
339 if (self.current_row.columns_len == 0) {
340 self.current_row.columns_start = self.columns.items.len;
341 }
342 self.current_row.columns_len += 1;
343
344 const column = try self.columns.addOne(allocator);
345 column.* = .{
346 .register = register,
347 };
348
349 return column;
350 }
351
352 pub fn step(self: *VirtualMachine, allocator: std.mem.Allocator, cie: dwarf.CommonInformationEntry, instruction: Instruction) !void {
353 switch (instruction) {
354 inline .advance_loc, .advance_loc1, .advance_loc2, .advance_loc4 => |i| {
355 self.current_row.offset += i.operands.delta;
356 },
357 .offset => |i| {
358 const column = try self.getOrAddColumn(allocator, i.operands.register);
359 column.rule = .{ .offset = @intCast(i64, i.operands.offset) * cie.data_alignment_factor };
360 },
361 .restore => {},
362 .nop => {},
363 .set_loc => {},
364 .offset_extended => {},
365 .restore_extended => {},
366 .undefined => {},
367 .same_value => {},
368 .register => {},
369 .remember_state => {},
370 .restore_state => {},
371 .def_cfa => |i| {
372 self.current_row.cfa = .{
373 .register = i.operands.register,
374 .rule = .{ .offset = @intCast(i64, i.operands.offset) },
375 };
376 },
377 .def_cfa_register => {},
378 .def_cfa_offset => |i| {
379 self.current_row.cfa.rule = .{
380 .offset = @intCast(i64, i.operands.offset)
381 };
226382 },
383 .def_cfa_expression => {},
227384 .expression => {},
228385 .offset_extended_sf => {},
229386 .def_cfa_sf => {},