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