| ... | @@ -171,7 +171,7 @@ pub const Instruction = union(Opcode) { | ... | @@ -171,7 +171,7 @@ pub const Instruction = union(Opcode) { |
| 171 | advance_loc4: InstructionType(.{ .delta = .u32_delta }), | 171 | advance_loc4: InstructionType(.{ .delta = .u32_delta }), |
| 172 | undefined: InstructionType(.{ .register = .uleb128_register }), | 172 | undefined: InstructionType(.{ .register = .uleb128_register }), |
| 173 | same_value: InstructionType(.{ .register = .uleb128_register }), | 173 | same_value: InstructionType(.{ .register = .uleb128_register }), |
| 174 | register: InstructionType(.{ .register = .uleb128_register, .offset = .uleb128_offset }), | 174 | register: InstructionType(.{ .register = .uleb128_register, .target_register = .uleb128_register }), |
| 175 | remember_state: InstructionType(.{}), | 175 | remember_state: InstructionType(.{}), |
| 176 | restore_state: InstructionType(.{}), | 176 | restore_state: InstructionType(.{}), |
| 177 | def_cfa: InstructionType(.{ .register = .uleb128_register, .offset = .uleb128_offset }), | 177 | def_cfa: InstructionType(.{ .register = .uleb128_register, .offset = .uleb128_offset }), |
| ... | @@ -229,15 +229,20 @@ pub const VirtualMachine = struct { | ... | @@ -229,15 +229,20 @@ pub const VirtualMachine = struct { |
| 229 | architectural: void, | 229 | architectural: void, |
| 230 | }; | 230 | }; |
| 231 | | 231 | |
| 232 | /// Each row contains unwinding rules for a set of registers at a specific location in the | 232 | /// Each row contains unwinding rules for a set of registers. |
| 233 | pub const Row = struct { | 233 | pub const Row = struct { |
| 234 | /// Offset from pc_begin | 234 | /// Offset from `FrameDescriptionEntry.pc_begin` |
| 235 | offset: u64 = 0, | 235 | offset: u64 = 0, |
| | 236 | |
| 236 | /// Special-case column that defines the CFA (Canonical Frame Address) rule. | 237 | /// Special-case column that defines the CFA (Canonical Frame Address) rule. |
| 237 | /// The register field of this column defines the register that CFA is derived | 238 | /// The register field of this column defines the register that CFA is derived |
| 238 | /// from, while other columns define registers in terms of the CFA. | 239 | /// from, while other columns define register rules in terms of the CFA. |
| 239 | cfa: Column = .{}, | 240 | cfa: Column = .{}, |
| 240 | columns: ColumnRange = .{}, | 241 | columns: ColumnRange = .{}, |
| | 242 | |
| | 243 | /// Indicates that the next write to any column in this row needs to copy |
| | 244 | /// the backing column storage first. |
| | 245 | copy_on_write: bool = false, |
| 241 | }; | 246 | }; |
| 242 | | 247 | |
| 243 | pub const Column = struct { | 248 | pub const Column = struct { |
| ... | @@ -339,6 +344,17 @@ pub const VirtualMachine = struct { | ... | @@ -339,6 +344,17 @@ pub const VirtualMachine = struct { |
| 339 | self.stepTo(allocator, pc, cie, fde, @sizeOf(usize), builtin.target.cpu.arch.endian()); | 344 | self.stepTo(allocator, pc, cie, fde, @sizeOf(usize), builtin.target.cpu.arch.endian()); |
| 340 | } | 345 | } |
| 341 | | 346 | |
| | 347 | fn resolveCopyOnWrite(self: *VirtualMachine, allocator: std.mem.Allocator) !void { |
| | 348 | if (!self.current_row.copy_on_write) return; |
| | 349 | |
| | 350 | const new_start = self.columns.items.len; |
| | 351 | if (self.current_row.columns.len > 0) { |
| | 352 | try self.columns.ensureUnusedCapacity(allocator, self.current_row.columns.len); |
| | 353 | self.columns.appendSliceAssumeCapacity(self.rowColumns(self.current_row)); |
| | 354 | self.current_row.columns.start = new_start; |
| | 355 | } |
| | 356 | } |
| | 357 | |
| 342 | /// Executes a single instruction. | 358 | /// Executes a single instruction. |
| 343 | /// If this instruction is from the CIE, `is_initial` should be set. | 359 | /// If this instruction is from the CIE, `is_initial` should be set. |
| 344 | /// Returns the value of `current_row` before executing this instruction | 360 | /// Returns the value of `current_row` before executing this instruction |
| ... | @@ -355,14 +371,36 @@ pub const VirtualMachine = struct { | ... | @@ -355,14 +371,36 @@ pub const VirtualMachine = struct { |
| 355 | | 371 | |
| 356 | const prev_row = self.current_row; | 372 | const prev_row = self.current_row; |
| 357 | switch (instruction) { | 373 | switch (instruction) { |
| 358 | inline .advance_loc, .advance_loc1, .advance_loc2, .advance_loc4 => |i| { | 374 | .set_loc => |i| { |
| | 375 | if (i.operands.address <= self.current_row.offset) return error.InvalidOperation; |
| | 376 | // TODO: Check cie.segment_selector_size != for DWARFV4 |
| | 377 | self.current_row.offset = i.operands.address; |
| | 378 | }, |
| | 379 | inline .advance_loc, |
| | 380 | .advance_loc1, |
| | 381 | .advance_loc2, |
| | 382 | .advance_loc4, |
| | 383 | => |i| { |
| 359 | self.current_row.offset += i.operands.delta * cie.code_alignment_factor; | 384 | self.current_row.offset += i.operands.delta * cie.code_alignment_factor; |
| | 385 | self.current_row.copy_on_write = true; |
| 360 | }, | 386 | }, |
| 361 | inline .offset, .offset_extended => |i| { | 387 | inline .offset, |
| | 388 | .offset_extended, |
| | 389 | .offset_extended_sf, |
| | 390 | => |i| { |
| | 391 | try self.resolveCopyOnWrite(allocator); |
| 362 | const column = try self.getOrAddColumn(allocator, i.operands.register); | 392 | const column = try self.getOrAddColumn(allocator, i.operands.register); |
| 363 | column.rule = .{ .offset = @intCast(i64, i.operands.offset) * cie.data_alignment_factor }; | 393 | column.rule = .{ .offset = @intCast(i64, i.operands.offset) * cie.data_alignment_factor }; |
| 364 | }, | 394 | }, |
| 365 | inline .restore, .restore_extended => |i| { | 395 | // .offset_extended_sf => |i| { |
| | 396 | // try self.resolveCopyOnWrite(allocator); |
| | 397 | // const column = try self.getOrAddColumn(allocator, i.operands.register); |
| | 398 | // column.rule = .{ .offset = i.operands.offset * cie.data_alignment_factor }; |
| | 399 | // }, |
| | 400 | inline .restore, |
| | 401 | .restore_extended, |
| | 402 | => |i| { |
| | 403 | try self.resolveCopyOnWrite(allocator); |
| 366 | if (self.cie_row) |cie_row| { | 404 | if (self.cie_row) |cie_row| { |
| 367 | const column = try self.getOrAddColumn(allocator, i.operands.register); | 405 | const column = try self.getOrAddColumn(allocator, i.operands.register); |
| 368 | column.rule = for (self.rowColumns(cie_row)) |cie_column| { | 406 | column.rule = for (self.rowColumns(cie_row)) |cie_column| { |
| ... | @@ -371,20 +409,31 @@ pub const VirtualMachine = struct { | ... | @@ -371,20 +409,31 @@ pub const VirtualMachine = struct { |
| 371 | } else return error.InvalidOperation; | 409 | } else return error.InvalidOperation; |
| 372 | }, | 410 | }, |
| 373 | .nop => {}, | 411 | .nop => {}, |
| 374 | .set_loc => {}, | 412 | .undefined => |i| { |
| 375 | .undefined => {}, | 413 | try self.resolveCopyOnWrite(allocator); |
| 376 | .same_value => {}, | 414 | const column = try self.getOrAddColumn(allocator, i.operands.register); |
| 377 | .register => {}, | 415 | column.rule = .{ .undefined = {} }; |
| | 416 | }, |
| | 417 | .same_value => |i| { |
| | 418 | try self.resolveCopyOnWrite(allocator); |
| | 419 | const column = try self.getOrAddColumn(allocator, i.operands.register); |
| | 420 | column.rule = .{ .same_value = {} }; |
| | 421 | }, |
| | 422 | .register => |i| { |
| | 423 | try self.resolveCopyOnWrite(allocator); |
| | 424 | const column = try self.getOrAddColumn(allocator, i.operands.register); |
| | 425 | column.rule = .{ .register = i.operands.target_register }; |
| | 426 | }, |
| 378 | .remember_state => { | 427 | .remember_state => { |
| 379 | try self.stack.append(allocator, self.current_row.columns); | 428 | try self.stack.append(allocator, self.current_row.columns); |
| 380 | errdefer _ = self.stack.pop(); | 429 | self.current_row.copy_on_write = true; |
| 381 | | 430 | |
| 382 | const new_start = self.columns.items.len; | 431 | // const new_start = self.columns.items.len; |
| 383 | if (self.current_row.columns.len > 0) { | 432 | // if (self.current_row.columns.len > 0) { |
| 384 | try self.columns.ensureUnusedCapacity(allocator, self.current_row.columns.len); | 433 | // try self.columns.ensureUnusedCapacity(allocator, self.current_row.columns.len); |
| 385 | self.columns.appendSliceAssumeCapacity(self.rowColumns(self.current_row)); | 434 | // self.columns.appendSliceAssumeCapacity(self.rowColumns(self.current_row)); |
| 386 | self.current_row.columns.start = new_start; | 435 | // self.current_row.columns.start = new_start; |
| 387 | } | 436 | // } |
| 388 | }, | 437 | }, |
| 389 | .restore_state => { | 438 | .restore_state => { |
| 390 | const restored_columns = self.stack.popOrNull() orelse return error.InvalidOperation; | 439 | const restored_columns = self.stack.popOrNull() orelse return error.InvalidOperation; |
| ... | @@ -396,29 +445,48 @@ pub const VirtualMachine = struct { | ... | @@ -396,29 +445,48 @@ pub const VirtualMachine = struct { |
| 396 | self.columns.appendSliceAssumeCapacity(self.columns.items[restored_columns.start..][0..restored_columns.len]); | 445 | self.columns.appendSliceAssumeCapacity(self.columns.items[restored_columns.start..][0..restored_columns.len]); |
| 397 | }, | 446 | }, |
| 398 | .def_cfa => |i| { | 447 | .def_cfa => |i| { |
| | 448 | try self.resolveCopyOnWrite(allocator); |
| 399 | self.current_row.cfa = .{ | 449 | self.current_row.cfa = .{ |
| 400 | .register = i.operands.register, | 450 | .register = i.operands.register, |
| 401 | .rule = .{ .offset = @intCast(i64, i.operands.offset) }, | 451 | .rule = .{ .offset = @intCast(i64, i.operands.offset) }, |
| 402 | }; | 452 | }; |
| 403 | }, | 453 | }, |
| | 454 | .def_cfa_sf => |i| { |
| | 455 | try self.resolveCopyOnWrite(allocator); |
| | 456 | self.current_row.cfa = .{ |
| | 457 | .register = i.operands.register, |
| | 458 | .rule = .{ .offset = i.operands.offset * cie.data_alignment_factor }, |
| | 459 | }; |
| | 460 | }, |
| 404 | .def_cfa_register => |i| { | 461 | .def_cfa_register => |i| { |
| 405 | // TODO: Verify the the current row is using a register and offset (validation) | 462 | try self.resolveCopyOnWrite(allocator); |
| | 463 | if (self.current_row.cfa.register == null or self.current_row.cfa.rule != .offset) return error.InvalidOperation; |
| 406 | self.current_row.cfa.register = i.operands.register; | 464 | self.current_row.cfa.register = i.operands.register; |
| 407 | }, | 465 | }, |
| 408 | .def_cfa_offset => |i| { | 466 | .def_cfa_offset => |i| { |
| 409 | // TODO: Verify the the current row is using a register and offset (validation) | 467 | try self.resolveCopyOnWrite(allocator); |
| | 468 | if (self.current_row.cfa.register == null or self.current_row.cfa.rule != .offset) return error.InvalidOperation; |
| 410 | self.current_row.cfa.rule = .{ .offset = @intCast(i64, i.operands.offset) }; | 469 | self.current_row.cfa.rule = .{ .offset = @intCast(i64, i.operands.offset) }; |
| 411 | }, | 470 | }, |
| | 471 | .def_cfa_offset_sf => |i| { |
| | 472 | try self.resolveCopyOnWrite(allocator); |
| | 473 | if (self.current_row.cfa.register == null or self.current_row.cfa.rule != .offset) return error.InvalidOperation; |
| | 474 | self.current_row.cfa.rule = .{ .offset = i.operands.offset * cie.data_alignment_factor }; |
| | 475 | }, |
| 412 | .def_cfa_expression => |i| { | 476 | .def_cfa_expression => |i| { |
| | 477 | try self.resolveCopyOnWrite(allocator); |
| 413 | self.current_row.cfa.register = undefined; | 478 | self.current_row.cfa.register = undefined; |
| 414 | self.current_row.cfa.rule = .{ | 479 | self.current_row.cfa.rule = .{ |
| 415 | .expression = i.operands.block, | 480 | .expression = i.operands.block, |
| 416 | }; | 481 | }; |
| 417 | }, | 482 | }, |
| 418 | .expression => {}, | 483 | .expression => |i| { |
| 419 | .offset_extended_sf => {}, | 484 | try self.resolveCopyOnWrite(allocator); |
| 420 | .def_cfa_sf => {}, | 485 | const column = try self.getOrAddColumn(allocator, i.operands.register); |
| 421 | .def_cfa_offset_sf => {}, | 486 | column.rule = .{ |
| | 487 | .expression = i.operands.block, |
| | 488 | }; |
| | 489 | }, |
| 422 | .val_offset => {}, | 490 | .val_offset => {}, |
| 423 | .val_offset_sf => {}, | 491 | .val_offset_sf => {}, |
| 424 | .val_expression => {}, | 492 | .val_expression => {}, |