| ... | ... | @@ -233,17 +233,10 @@ pub const Instruction = union(Opcode) { |
| 233 | 233 | .register => {}, |
| 234 | 234 | .remember_state => {}, |
| 235 | 235 | .restore_state => {}, |
| 236 | | .def_cfa => |i| { |
| 237 | | try abi.writeRegisterName(writer, arch, i.operands.register); |
| 238 | | try writer.print(" {d:<1}", .{@intCast(i64, i.operands.offset)}); |
| 239 | | }, |
| 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 | | }, |
| 236 | .def_cfa => |i| try writer.print("{} {d:<1}", .{ abi.fmtRegister(i.operands.register, arch), @intCast(i64, i.operands.offset)}), |
| 237 | .def_cfa_register => |i| try abi.writeRegisterName(writer, arch, i.operands.register), |
| 238 | .def_cfa_offset => |i| try writer.print("{d:<1}", .{@intCast(i64, i.operands.offset)}), |
| 239 | .def_cfa_expression => |i| try writeExpression(writer, i.operands.block, arch, addr_size_bytes, endian), |
| 247 | 240 | .expression => {}, |
| 248 | 241 | .offset_extended_sf => {}, |
| 249 | 242 | .def_cfa_sf => {}, |
| ... | ... | @@ -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 | 314 | /// See section 6.4.1 of the DWARF5 specification |
| 332 | 315 | pub const VirtualMachine = struct { |
| 333 | 316 | const RegisterRule = union(enum) { |
| ... | ... | @@ -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 | 374 | pub const Row = struct { |
| 392 | 375 | /// Offset from pc_begin |
| 393 | 376 | offset: u64 = 0, |
| ... | ... | @@ -395,31 +378,33 @@ pub const VirtualMachine = struct { |
| 395 | 378 | /// The register field of this column defines the register that CFA is derived |
| 396 | 379 | /// from, while other columns define registers in terms of the CFA. |
| 397 | 380 | cfa: Column = .{}, |
| 381 | columns: ColumnRange = .{}, |
| 382 | }; |
| 383 | |
| 384 | const ColumnRange = struct { |
| 398 | 385 | /// Index into `columns` of the first column in this row. |
| 399 | | columns_start: usize = undefined, |
| 400 | | columns_len: u8 = 0, |
| 386 | start: usize = undefined, |
| 387 | len: u8 = 0, |
| 401 | 388 | }; |
| 402 | 389 | |
| 403 | 390 | columns: std.ArrayListUnmanaged(Column) = .{}, |
| 404 | | row_stack: std.ArrayListUnmanaged(Row) = .{}, |
| 391 | stack: std.ArrayListUnmanaged(ColumnRange) = .{}, |
| 405 | 392 | current_row: Row = .{}, |
| 406 | 393 | |
| 407 | | // TODO: Add stack machine stack |
| 408 | | |
| 409 | 394 | pub fn reset(self: *VirtualMachine) void { |
| 410 | | self.row_stack.clearRetainingCapacity(); |
| 395 | self.stack.clearRetainingCapacity(); |
| 411 | 396 | self.columns.clearRetainingCapacity(); |
| 412 | 397 | self.current_row = .{}; |
| 413 | 398 | } |
| 414 | 399 | |
| 415 | 400 | pub fn deinit(self: *VirtualMachine, allocator: std.mem.Allocator) void { |
| 416 | | self.row_stack.deinit(allocator); |
| 401 | self.stack.deinit(allocator); |
| 417 | 402 | self.columns.deinit(allocator); |
| 418 | 403 | self.* = undefined; |
| 419 | 404 | } |
| 420 | 405 | |
| 421 | 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 | 410 | fn getOrAddColumn(self: *VirtualMachine, allocator: std.mem.Allocator, register: u8) !*Column { |
| ... | ... | @@ -427,10 +412,10 @@ pub const VirtualMachine = struct { |
| 427 | 412 | if (c.register == register) return c; |
| 428 | 413 | } |
| 429 | 414 | |
| 430 | | if (self.current_row.columns_len == 0) { |
| 431 | | self.current_row.columns_start = self.columns.items.len; |
| 415 | if (self.current_row.columns.len == 0) { |
| 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 | 420 | const column = try self.columns.addOne(allocator); |
| 436 | 421 | column.* = .{ |
| ... | ... | @@ -443,7 +428,7 @@ pub const VirtualMachine = struct { |
| 443 | 428 | pub fn step(self: *VirtualMachine, allocator: std.mem.Allocator, cie: dwarf.CommonInformationEntry, instruction: Instruction) !void { |
| 444 | 429 | switch (instruction) { |
| 445 | 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 | 433 | .offset => |i| { |
| 449 | 434 | const column = try self.getOrAddColumn(allocator, i.operands.register); |
| ... | ... | @@ -458,18 +443,22 @@ pub const VirtualMachine = struct { |
| 458 | 443 | .same_value => {}, |
| 459 | 444 | .register => {}, |
| 460 | 445 | .remember_state => { |
| 461 | | |
| 462 | | // TODO: The row stack only actually needs the column information |
| 463 | | // TODO: Also it needs to copy the columns because changes can edit the referenced columns |
| 464 | | // TODO: This function could push the column range onto the stack, the copy the columns and update current row |
| 465 | | |
| 466 | | try self.row_stack.append(allocator, self.current_row); |
| 446 | try self.stack.append(allocator, self.current_row.columns); |
| 447 | errdefer _ = self.stack.pop(); |
| 448 | |
| 449 | const new_start = self.columns.items.len; |
| 450 | if (self.current_row.columns.len > 0) { |
| 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 | 457 | .restore_state => { |
| 469 | | if (self.row_stack.items.len == 0) return error.InvalidOperation; |
| 470 | | const row = self.row_stack.pop(); |
| 471 | | self.current_row.columns_len = row.columns_len; |
| 472 | | self.current_row.columns_start = row.columns_start; |
| 458 | // TODO: Is it possible to remove the duplicate from above? Other instructions may have added columns since then though |
| 459 | const columns = self.stack.popOrNull() orelse return error.InvalidOperation; |
| 460 | self.current_row.columns.len = columns.len; |
| 461 | self.current_row.columns.start = columns.start; |
| 473 | 462 | }, |
| 474 | 463 | .def_cfa => |i| { |
| 475 | 464 | self.current_row.cfa = .{ |
| ... | ... | @@ -477,8 +466,12 @@ pub const VirtualMachine = struct { |
| 477 | 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 | 473 | .def_cfa_offset => |i| { |
| 474 | // TODO: Verify the the current row is using a register and offset (validation) |
| 482 | 475 | self.current_row.cfa.rule = .{ .offset = @intCast(i64, i.operands.offset) }; |
| 483 | 476 | }, |
| 484 | 477 | .def_cfa_expression => |i| { |