| ... | ... | @@ -17,7 +17,10 @@ pub const ExpressionContext = struct { |
| 17 | 17 | /// The compilation unit this expression relates to, if any |
| 18 | 18 | compile_unit: ?*const dwarf.CompileUnit = null, |
| 19 | 19 | |
| 20 | | // .debug_addr section |
| 20 | /// When evaluating a user-presented expression, this is the address of the object being evaluated |
| 21 | object_address: ?*const anyopaque = null, |
| 22 | |
| 23 | /// .debug_addr section |
| 21 | 24 | debug_addr: ?[]const u8 = null, |
| 22 | 25 | |
| 23 | 26 | /// Thread context |
| ... | ... | @@ -465,9 +468,11 @@ pub fn StackMachine(comptime options: ExpressionOptions) type { |
| 465 | 468 | }, |
| 466 | 469 | } |
| 467 | 470 | }, |
| 468 | | OP.push_object_address, |
| 469 | | OP.form_tls_address, |
| 470 | | => { |
| 471 | OP.push_object_address => { |
| 472 | if (context.object_address == null) return error.IncompleteExpressionContext; |
| 473 | try self.stack.append(allocator, .{ .generic = @intFromPtr(context.object_address.?) }); |
| 474 | }, |
| 475 | OP.form_tls_address => { |
| 471 | 476 | return error.UnimplementedExpressionOpcode; |
| 472 | 477 | }, |
| 473 | 478 | OP.call_frame_cfa => { |
| ... | ... | @@ -1106,28 +1111,34 @@ test "DWARF expressions" { |
| 1106 | 1111 | .reg_context = reg_context, |
| 1107 | 1112 | }; |
| 1108 | 1113 | |
| 1109 | | // TODO: Test fbreg (once implemented): mock a DIE and point compile_unit.frame_base at it |
| 1114 | // Only test register operations on arch / os that have them implemented |
| 1115 | if (abi.regBytes(&thread_context, 0, reg_context)) |_| { |
| 1110 | 1116 | |
| 1111 | | mem.writeIntSliceNative(usize, try abi.regBytes(&thread_context, 0, reg_context), 0xee); |
| 1112 | | mem.writeIntSliceNative(usize, try abi.regBytes(&thread_context, abi.fpRegNum(reg_context), reg_context), 1); |
| 1113 | | mem.writeIntSliceNative(usize, try abi.regBytes(&thread_context, abi.spRegNum(reg_context), reg_context), 2); |
| 1114 | | mem.writeIntSliceNative(usize, try abi.regBytes(&thread_context, abi.ipRegNum(), reg_context), 3); |
| 1117 | // TODO: Test fbreg (once implemented): mock a DIE and point compile_unit.frame_base at it |
| 1115 | 1118 | |
| 1116 | | try b.writeBreg(writer, abi.fpRegNum(reg_context), @as(usize, 100)); |
| 1117 | | try b.writeBreg(writer, abi.spRegNum(reg_context), @as(usize, 200)); |
| 1118 | | try b.writeBregx(writer, abi.ipRegNum(), @as(usize, 300)); |
| 1119 | | try b.writeRegvalType(writer, @as(u8, 0), @as(usize, 400)); |
| 1119 | mem.writeIntSliceNative(usize, try abi.regBytes(&thread_context, 0, reg_context), 0xee); |
| 1120 | mem.writeIntSliceNative(usize, try abi.regBytes(&thread_context, abi.fpRegNum(reg_context), reg_context), 1); |
| 1121 | mem.writeIntSliceNative(usize, try abi.regBytes(&thread_context, abi.spRegNum(reg_context), reg_context), 2); |
| 1122 | mem.writeIntSliceNative(usize, try abi.regBytes(&thread_context, abi.ipRegNum(), reg_context), 3); |
| 1120 | 1123 | |
| 1121 | | _ = try stack_machine.run(program.items, allocator, context, 0); |
| 1124 | try b.writeBreg(writer, abi.fpRegNum(reg_context), @as(usize, 100)); |
| 1125 | try b.writeBreg(writer, abi.spRegNum(reg_context), @as(usize, 200)); |
| 1126 | try b.writeBregx(writer, abi.ipRegNum(), @as(usize, 300)); |
| 1127 | try b.writeRegvalType(writer, @as(u8, 0), @as(usize, 400)); |
| 1122 | 1128 | |
| 1123 | | const regval_type = stack_machine.stack.popOrNull().?.regval_type; |
| 1124 | | try testing.expectEqual(@as(usize, 400), regval_type.type_offset); |
| 1125 | | try testing.expectEqual(@as(u8, @sizeOf(usize)), regval_type.type_size); |
| 1126 | | try testing.expectEqual(@as(usize, 0xee), regval_type.value); |
| 1129 | _ = try stack_machine.run(program.items, allocator, context, 0); |
| 1127 | 1130 | |
| 1128 | | try testing.expectEqual(@as(usize, 303), stack_machine.stack.popOrNull().?.generic); |
| 1129 | | try testing.expectEqual(@as(usize, 202), stack_machine.stack.popOrNull().?.generic); |
| 1130 | | try testing.expectEqual(@as(usize, 101), stack_machine.stack.popOrNull().?.generic); |
| 1131 | const regval_type = stack_machine.stack.popOrNull().?.regval_type; |
| 1132 | try testing.expectEqual(@as(usize, 400), regval_type.type_offset); |
| 1133 | try testing.expectEqual(@as(u8, @sizeOf(usize)), regval_type.type_size); |
| 1134 | try testing.expectEqual(@as(usize, 0xee), regval_type.value); |
| 1135 | |
| 1136 | try testing.expectEqual(@as(usize, 303), stack_machine.stack.popOrNull().?.generic); |
| 1137 | try testing.expectEqual(@as(usize, 202), stack_machine.stack.popOrNull().?.generic); |
| 1138 | try testing.expectEqual(@as(usize, 101), stack_machine.stack.popOrNull().?.generic); |
| 1139 | } else |err| { |
| 1140 | if (err != error.UnimplementedArch and err != error.UnimplementedOs) return err; |
| 1141 | } |
| 1131 | 1142 | } |
| 1132 | 1143 | |
| 1133 | 1144 | // Stack operations |
| ... | ... | @@ -1242,7 +1253,14 @@ test "DWARF expressions" { |
| 1242 | 1253 | try testing.expectEqual(@as(u8, 1), xderef_type.type_size); |
| 1243 | 1254 | try testing.expectEqual(@as(usize, @as(*const u8, @ptrCast(&deref_target)).*), xderef_type.value); |
| 1244 | 1255 | |
| 1245 | | // TODO: Test OP.push_object_address |
| 1256 | context.object_address = &deref_target; |
| 1257 | |
| 1258 | stack_machine.reset(); |
| 1259 | program.clearRetainingCapacity(); |
| 1260 | try b.writeOpcode(writer, OP.push_object_address); |
| 1261 | _ = try stack_machine.run(program.items, allocator, context, null); |
| 1262 | try testing.expectEqual(@as(usize, @intFromPtr(context.object_address.?)), stack_machine.stack.popOrNull().?.generic); |
| 1263 | |
| 1246 | 1264 | // TODO: Test OP.form_tls_address |
| 1247 | 1265 | |
| 1248 | 1266 | context.cfa = @truncate(0xccddccdd_ccddccdd); |
| ... | ... | @@ -1437,6 +1455,69 @@ test "DWARF expressions" { |
| 1437 | 1455 | |
| 1438 | 1456 | } |
| 1439 | 1457 | |
| 1458 | // Type conversions |
| 1459 | { |
| 1460 | var context = ExpressionContext{}; |
| 1461 | stack_machine.reset(); |
| 1462 | program.clearRetainingCapacity(); |
| 1463 | |
| 1464 | // TODO: Test typed OP.convert once implemented |
| 1465 | |
| 1466 | const value: usize = @truncate(0xffeeffee_ffeeffee); |
| 1467 | var value_bytes: [options.addr_size]u8 = undefined; |
| 1468 | mem.writeIntSliceNative(usize, &value_bytes, value); |
| 1469 | |
| 1470 | // Convert to generic type |
| 1471 | stack_machine.reset(); |
| 1472 | program.clearRetainingCapacity(); |
| 1473 | try b.writeConstType(writer, @as(usize, 0), options.addr_size, &value_bytes); |
| 1474 | try b.writeConvert(writer, @as(usize, 0)); |
| 1475 | _ = try stack_machine.run(program.items, allocator, context, null); |
| 1476 | try testing.expectEqual(value, stack_machine.stack.popOrNull().?.generic); |
| 1477 | |
| 1478 | // Reinterpret to generic type |
| 1479 | stack_machine.reset(); |
| 1480 | program.clearRetainingCapacity(); |
| 1481 | try b.writeConstType(writer, @as(usize, 0), options.addr_size, &value_bytes); |
| 1482 | try b.writeReinterpret(writer, @as(usize, 0)); |
| 1483 | _ = try stack_machine.run(program.items, allocator, context, null); |
| 1484 | try testing.expectEqual(value, stack_machine.stack.popOrNull().?.generic); |
| 1485 | |
| 1486 | // Reinterpret to new type |
| 1487 | const die_offset: usize = 0xffee; |
| 1488 | |
| 1489 | stack_machine.reset(); |
| 1490 | program.clearRetainingCapacity(); |
| 1491 | try b.writeConstType(writer, @as(usize, 0), options.addr_size, &value_bytes); |
| 1492 | try b.writeReinterpret(writer, die_offset); |
| 1493 | _ = try stack_machine.run(program.items, allocator, context, null); |
| 1494 | const const_type = stack_machine.stack.popOrNull().?.const_type; |
| 1495 | try testing.expectEqual(die_offset, const_type.type_offset); |
| 1496 | |
| 1497 | stack_machine.reset(); |
| 1498 | program.clearRetainingCapacity(); |
| 1499 | try b.writeLiteral(writer, 0); |
| 1500 | try b.writeReinterpret(writer, die_offset); |
| 1501 | _ = try stack_machine.run(program.items, allocator, context, null); |
| 1502 | const regval_type = stack_machine.stack.popOrNull().?.regval_type; |
| 1503 | try testing.expectEqual(die_offset, regval_type.type_offset); |
| 1504 | } |
| 1505 | |
| 1506 | // Special operations |
| 1507 | { |
| 1508 | var context = ExpressionContext{}; |
| 1509 | stack_machine.reset(); |
| 1510 | program.clearRetainingCapacity(); |
| 1511 | |
| 1512 | try b.writeOpcode(writer, OP.nop); |
| 1513 | _ = try stack_machine.run(program.items, allocator, context, null); |
| 1514 | try testing.expect(stack_machine.stack.popOrNull() == null); |
| 1515 | |
| 1516 | |
| 1517 | |
| 1518 | |
| 1519 | } |
| 1520 | |
| 1440 | 1521 | |
| 1441 | 1522 | } |
| 1442 | 1523 | |