| ... | @@ -233,17 +233,10 @@ pub const Instruction = union(Opcode) { | ... | @@ -233,17 +233,10 @@ pub const Instruction = union(Opcode) { |
| 233 | .register => {}, | 233 | .register => {}, |
| 234 | .remember_state => {}, | 234 | .remember_state => {}, |
| 235 | .restore_state => {}, | 235 | .restore_state => {}, |
| 236 | .def_cfa => |i| { | 236 | .def_cfa => |i| try writer.print("{} {d:<1}", .{ abi.fmtRegister(i.operands.register, arch), @intCast(i64, i.operands.offset)}), |
| 237 | try abi.writeRegisterName(writer, arch, i.operands.register); | 237 | .def_cfa_register => |i| try abi.writeRegisterName(writer, arch, i.operands.register), |
| 238 | try writer.print(" {d:<1}", .{@intCast(i64, i.operands.offset)}); | 238 | .def_cfa_offset => |i| try writer.print("{d:<1}", .{@intCast(i64, i.operands.offset)}), |
| 239 | }, | 239 | .def_cfa_expression => |i| try writeExpression(writer, i.operands.block, arch, addr_size_bytes, endian), |
| 240 | .def_cfa_register => {}, | | |
| 241 | .def_cfa_offset => |i| { | | |
| 242 | try writer.print("{d:<1}", .{@intCast(i64, i.operands.offset)}); | | |
| 243 | }, | | |
| 244 | .def_cfa_expression => |i| { | | |
| 245 | try writeExpression(writer, i.operands.block, arch, addr_size_bytes, endian); | | |
| 246 | }, | | |
| 247 | .expression => {}, | 240 | .expression => {}, |
| 248 | .offset_extended_sf => {}, | 241 | .offset_extended_sf => {}, |
| 249 | .def_cfa_sf => {}, | 242 | .def_cfa_sf => {}, |
| ... | @@ -318,16 +311,6 @@ fn writeExpression( | ... | @@ -318,16 +311,6 @@ fn writeExpression( |
| 318 | } | 311 | } |
| 319 | } | 312 | } |
| 320 | | 313 | |
| 321 | // fn formatOffset(data: i64, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { | | |
| 322 | // _ = fmt; | | |
| 323 | // if (data >= 0) try writer.writeByte('+'); | | |
| 324 | // return std.fmt.formatInt(data, 10, .lower, options, writer); | | |
| 325 | // } | | |
| 326 | | | |
| 327 | // fn fmtOffset(offset: i64) std.fmt.Formatter(formatOffset) { | | |
| 328 | // return .{ .data = offset }; | | |
| 329 | // } | | |
| 330 | | | |
| 331 | /// See section 6.4.1 of the DWARF5 specification | 314 | /// See section 6.4.1 of the DWARF5 specification |
| 332 | pub const VirtualMachine = struct { | 315 | pub const VirtualMachine = struct { |
| 333 | const RegisterRule = union(enum) { | 316 | const RegisterRule = union(enum) { |
| ... | @@ -387,7 +370,7 @@ pub const VirtualMachine = struct { | ... | @@ -387,7 +370,7 @@ pub const VirtualMachine = struct { |
| 387 | } | 370 | } |
| 388 | }; | 371 | }; |
| 389 | | 372 | |
| 390 | /// Each row contains unwinding rules for a set of registers at a specific location in the program. | 373 | /// Each row contains unwinding rules for a set of registers at a specific location in the |
| 391 | pub const Row = struct { | 374 | pub const Row = struct { |
| 392 | /// Offset from pc_begin | 375 | /// Offset from pc_begin |
| 393 | offset: u64 = 0, | 376 | offset: u64 = 0, |
| ... | @@ -395,31 +378,33 @@ pub const VirtualMachine = struct { | ... | @@ -395,31 +378,33 @@ pub const VirtualMachine = struct { |
| 395 | /// The register field of this column defines the register that CFA is derived | 378 | /// The register field of this column defines the register that CFA is derived |
| 396 | /// from, while other columns define registers in terms of the CFA. | 379 | /// from, while other columns define registers in terms of the CFA. |
| 397 | cfa: Column = .{}, | 380 | cfa: Column = .{}, |
| | 381 | columns: ColumnRange = .{}, |
| | 382 | }; |
| | 383 | |
| | 384 | const ColumnRange = struct { |
| 398 | /// Index into `columns` of the first column in this row. | 385 | /// Index into `columns` of the first column in this row. |
| 399 | columns_start: usize = undefined, | 386 | start: usize = undefined, |
| 400 | columns_len: u8 = 0, | 387 | len: u8 = 0, |
| 401 | }; | 388 | }; |
| 402 | | 389 | |
| 403 | columns: std.ArrayListUnmanaged(Column) = .{}, | 390 | columns: std.ArrayListUnmanaged(Column) = .{}, |
| 404 | row_stack: std.ArrayListUnmanaged(Row) = .{}, | 391 | stack: std.ArrayListUnmanaged(ColumnRange) = .{}, |
| 405 | current_row: Row = .{}, | 392 | current_row: Row = .{}, |
| 406 | | 393 | |
| 407 | // TODO: Add stack machine stack | | |
| 408 | | | |
| 409 | pub fn reset(self: *VirtualMachine) void { | 394 | pub fn reset(self: *VirtualMachine) void { |
| 410 | self.row_stack.clearRetainingCapacity(); | 395 | self.stack.clearRetainingCapacity(); |
| 411 | self.columns.clearRetainingCapacity(); | 396 | self.columns.clearRetainingCapacity(); |
| 412 | self.current_row = .{}; | 397 | self.current_row = .{}; |
| 413 | } | 398 | } |
| 414 | | 399 | |
| 415 | pub fn deinit(self: *VirtualMachine, allocator: std.mem.Allocator) void { | 400 | pub fn deinit(self: *VirtualMachine, allocator: std.mem.Allocator) void { |
| 416 | self.row_stack.deinit(allocator); | 401 | self.stack.deinit(allocator); |
| 417 | self.columns.deinit(allocator); | 402 | self.columns.deinit(allocator); |
| 418 | self.* = undefined; | 403 | self.* = undefined; |
| 419 | } | 404 | } |
| 420 | | 405 | |
| 421 | pub fn getColumns(self: VirtualMachine, row: Row) []Column { | 406 | pub fn getColumns(self: VirtualMachine, row: Row) []Column { |
| 422 | return self.columns.items[row.columns_start..][0..row.columns_len]; | 407 | return self.columns.items[row.columns.start..][0..row.columns.len]; |
| 423 | } | 408 | } |
| 424 | | 409 | |
| 425 | fn getOrAddColumn(self: *VirtualMachine, allocator: std.mem.Allocator, register: u8) !*Column { | 410 | fn getOrAddColumn(self: *VirtualMachine, allocator: std.mem.Allocator, register: u8) !*Column { |
| ... | @@ -427,10 +412,10 @@ pub const VirtualMachine = struct { | ... | @@ -427,10 +412,10 @@ pub const VirtualMachine = struct { |
| 427 | if (c.register == register) return c; | 412 | if (c.register == register) return c; |
| 428 | } | 413 | } |
| 429 | | 414 | |
| 430 | if (self.current_row.columns_len == 0) { | 415 | if (self.current_row.columns.len == 0) { |
| 431 | self.current_row.columns_start = self.columns.items.len; | 416 | self.current_row.columns.start = self.columns.items.len; |
| 432 | } | 417 | } |
| 433 | self.current_row.columns_len += 1; | 418 | self.current_row.columns.len += 1; |
| 434 | | 419 | |
| 435 | const column = try self.columns.addOne(allocator); | 420 | const column = try self.columns.addOne(allocator); |
| 436 | column.* = .{ | 421 | column.* = .{ |
| ... | @@ -443,7 +428,7 @@ pub const VirtualMachine = struct { | ... | @@ -443,7 +428,7 @@ pub const VirtualMachine = struct { |
| 443 | pub fn step(self: *VirtualMachine, allocator: std.mem.Allocator, cie: dwarf.CommonInformationEntry, instruction: Instruction) !void { | 428 | pub fn step(self: *VirtualMachine, allocator: std.mem.Allocator, cie: dwarf.CommonInformationEntry, instruction: Instruction) !void { |
| 444 | switch (instruction) { | 429 | switch (instruction) { |
| 445 | inline .advance_loc, .advance_loc1, .advance_loc2, .advance_loc4 => |i| { | 430 | inline .advance_loc, .advance_loc1, .advance_loc2, .advance_loc4 => |i| { |
| 446 | self.current_row.offset += i.operands.delta; | 431 | self.current_row.offset += i.operands.delta * cie.code_alignment_factor; |
| 447 | }, | 432 | }, |
| 448 | .offset => |i| { | 433 | .offset => |i| { |
| 449 | const column = try self.getOrAddColumn(allocator, i.operands.register); | 434 | const column = try self.getOrAddColumn(allocator, i.operands.register); |
| ... | @@ -458,18 +443,22 @@ pub const VirtualMachine = struct { | ... | @@ -458,18 +443,22 @@ pub const VirtualMachine = struct { |
| 458 | .same_value => {}, | 443 | .same_value => {}, |
| 459 | .register => {}, | 444 | .register => {}, |
| 460 | .remember_state => { | 445 | .remember_state => { |
| 461 | | 446 | try self.stack.append(allocator, self.current_row.columns); |
| 462 | // TODO: The row stack only actually needs the column information | 447 | errdefer _ = self.stack.pop(); |
| 463 | // TODO: Also it needs to copy the columns because changes can edit the referenced columns | 448 | |
| 464 | // TODO: This function could push the column range onto the stack, the copy the columns and update current row | 449 | const new_start = self.columns.items.len; |
| 465 | | 450 | if (self.current_row.columns.len > 0) { |
| 466 | try self.row_stack.append(allocator, self.current_row); | 451 | // Since we're copying from the same backing array, ensure it won't be reallocated |
| | 452 | try self.columns.ensureUnusedCapacity(allocator, self.current_row.columns.len); |
| | 453 | self.columns.appendSliceAssumeCapacity(self.getColumns(self.current_row)); |
| | 454 | self.current_row.columns.start = new_start; |
| | 455 | } |
| 467 | }, | 456 | }, |
| 468 | .restore_state => { | 457 | .restore_state => { |
| 469 | if (self.row_stack.items.len == 0) return error.InvalidOperation; | 458 | // TODO: Is it possible to remove the duplicate from above? Other instructions may have added columns since then though |
| 470 | const row = self.row_stack.pop(); | 459 | const columns = self.stack.popOrNull() orelse return error.InvalidOperation; |
| 471 | self.current_row.columns_len = row.columns_len; | 460 | self.current_row.columns.len = columns.len; |
| 472 | self.current_row.columns_start = row.columns_start; | 461 | self.current_row.columns.start = columns.start; |
| 473 | }, | 462 | }, |
| 474 | .def_cfa => |i| { | 463 | .def_cfa => |i| { |
| 475 | self.current_row.cfa = .{ | 464 | self.current_row.cfa = .{ |
| ... | @@ -477,8 +466,12 @@ pub const VirtualMachine = struct { | ... | @@ -477,8 +466,12 @@ pub const VirtualMachine = struct { |
| 477 | .rule = .{ .offset = @intCast(i64, i.operands.offset) }, | 466 | .rule = .{ .offset = @intCast(i64, i.operands.offset) }, |
| 478 | }; | 467 | }; |
| 479 | }, | 468 | }, |
| 480 | .def_cfa_register => {}, | 469 | .def_cfa_register => |i| { |
| | 470 | // TODO: Verify the the current row is using a register and offset (validation) |
| | 471 | self.current_row.cfa.register = i.operands.register; |
| | 472 | }, |
| 481 | .def_cfa_offset => |i| { | 473 | .def_cfa_offset => |i| { |
| | 474 | // TODO: Verify the the current row is using a register and offset (validation) |
| 482 | self.current_row.cfa.rule = .{ .offset = @intCast(i64, i.operands.offset) }; | 475 | self.current_row.cfa.rule = .{ .offset = @intCast(i64, i.operands.offset) }; |
| 483 | }, | 476 | }, |
| 484 | .def_cfa_expression => |i| { | 477 | .def_cfa_expression => |i| { |