803 lines · cpp
1//===-- ABIMacOSX_arm64.cpp -----------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "ABIMacOSX_arm64.h"10 11#include <optional>12#include <vector>13 14#include "llvm/ADT/STLExtras.h"15#include "llvm/TargetParser/Triple.h"16 17#include "lldb/Core/Module.h"18#include "lldb/Core/PluginManager.h"19#include "lldb/Core/Value.h"20#include "lldb/Target/Process.h"21#include "lldb/Target/RegisterContext.h"22#include "lldb/Target/Target.h"23#include "lldb/Target/Thread.h"24#include "lldb/Utility/ConstString.h"25#include "lldb/Utility/LLDBLog.h"26#include "lldb/Utility/Log.h"27#include "lldb/Utility/RegisterValue.h"28#include "lldb/Utility/Scalar.h"29#include "lldb/Utility/Status.h"30#include "lldb/ValueObject/ValueObjectConstResult.h"31 32using namespace lldb;33using namespace lldb_private;34 35static const char *pluginDesc = "Mac OS X ABI for arm64 targets";36 37size_t ABIMacOSX_arm64::GetRedZoneSize() const { return 128; }38 39// Static Functions40 41ABISP42ABIMacOSX_arm64::CreateInstance(ProcessSP process_sp, const ArchSpec &arch) {43 const llvm::Triple::ArchType arch_type = arch.GetTriple().getArch();44 const llvm::Triple::VendorType vendor_type = arch.GetTriple().getVendor();45 46 if (vendor_type == llvm::Triple::Apple) {47 if (arch_type == llvm::Triple::aarch64 ||48 arch_type == llvm::Triple::aarch64_32) {49 return ABISP(50 new ABIMacOSX_arm64(std::move(process_sp), MakeMCRegisterInfo(arch)));51 }52 }53 54 return ABISP();55}56 57bool ABIMacOSX_arm64::PrepareTrivialCall(58 Thread &thread, lldb::addr_t sp, lldb::addr_t func_addr,59 lldb::addr_t return_addr, llvm::ArrayRef<lldb::addr_t> args) const {60 RegisterContext *reg_ctx = thread.GetRegisterContext().get();61 if (!reg_ctx)62 return false;63 64 Log *log = GetLog(LLDBLog::Expressions);65 66 if (log) {67 StreamString s;68 s.Printf("ABIMacOSX_arm64::PrepareTrivialCall (tid = 0x%" PRIx6469 ", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx6470 ", return_addr = 0x%" PRIx64,71 thread.GetID(), (uint64_t)sp, (uint64_t)func_addr,72 (uint64_t)return_addr);73 74 for (size_t i = 0; i < args.size(); ++i)75 s.Printf(", arg%d = 0x%" PRIx64, static_cast<int>(i + 1), args[i]);76 s.PutCString(")");77 log->PutString(s.GetString());78 }79 80 const uint32_t pc_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(81 eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);82 const uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(83 eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);84 const uint32_t ra_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(85 eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);86 87 // x0 - x7 contain first 8 simple args88 if (args.size() > 8) // TODO handle more than 8 arguments89 return false;90 91 for (size_t i = 0; i < args.size(); ++i) {92 const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo(93 eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + i);94 LLDB_LOGF(log, "About to write arg%d (0x%" PRIx64 ") into %s",95 static_cast<int>(i + 1), args[i], reg_info->name);96 if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i]))97 return false;98 }99 100 // Set "lr" to the return address101 if (!reg_ctx->WriteRegisterFromUnsigned(102 reg_ctx->GetRegisterInfoAtIndex(ra_reg_num), return_addr))103 return false;104 105 // Set "sp" to the requested value106 if (!reg_ctx->WriteRegisterFromUnsigned(107 reg_ctx->GetRegisterInfoAtIndex(sp_reg_num), sp))108 return false;109 110 // Set "pc" to the address requested111 if (!reg_ctx->WriteRegisterFromUnsigned(112 reg_ctx->GetRegisterInfoAtIndex(pc_reg_num), func_addr))113 return false;114 115 return true;116}117 118bool ABIMacOSX_arm64::GetArgumentValues(Thread &thread,119 ValueList &values) const {120 uint32_t num_values = values.GetSize();121 122 ExecutionContext exe_ctx(thread.shared_from_this());123 124 // Extract the register context so we can read arguments from registers125 126 RegisterContext *reg_ctx = thread.GetRegisterContext().get();127 128 if (!reg_ctx)129 return false;130 131 addr_t sp = 0;132 133 for (uint32_t value_idx = 0; value_idx < num_values; ++value_idx) {134 // We currently only support extracting values with Clang QualTypes. Do we135 // care about others?136 Value *value = values.GetValueAtIndex(value_idx);137 138 if (!value)139 return false;140 141 CompilerType value_type = value->GetCompilerType();142 std::optional<uint64_t> bit_size =143 llvm::expectedToOptional(value_type.GetBitSize(&thread));144 if (!bit_size)145 return false;146 147 bool is_signed = false;148 size_t bit_width = 0;149 if (value_type.IsIntegerOrEnumerationType(is_signed)) {150 bit_width = *bit_size;151 } else if (value_type.IsPointerOrReferenceType()) {152 bit_width = *bit_size;153 } else {154 // We only handle integer, pointer and reference types currently...155 return false;156 }157 158 if (bit_width <= (exe_ctx.GetProcessRef().GetAddressByteSize() * 8)) {159 if (value_idx < 8) {160 // Arguments 1-6 are in x0-x5...161 const RegisterInfo *reg_info = nullptr;162 // Search by generic ID first, then fall back to by name163 uint32_t arg_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(164 eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + value_idx);165 if (arg_reg_num != LLDB_INVALID_REGNUM) {166 reg_info = reg_ctx->GetRegisterInfoAtIndex(arg_reg_num);167 } else {168 switch (value_idx) {169 case 0:170 reg_info = reg_ctx->GetRegisterInfoByName("x0");171 break;172 case 1:173 reg_info = reg_ctx->GetRegisterInfoByName("x1");174 break;175 case 2:176 reg_info = reg_ctx->GetRegisterInfoByName("x2");177 break;178 case 3:179 reg_info = reg_ctx->GetRegisterInfoByName("x3");180 break;181 case 4:182 reg_info = reg_ctx->GetRegisterInfoByName("x4");183 break;184 case 5:185 reg_info = reg_ctx->GetRegisterInfoByName("x5");186 break;187 case 6:188 reg_info = reg_ctx->GetRegisterInfoByName("x6");189 break;190 case 7:191 reg_info = reg_ctx->GetRegisterInfoByName("x7");192 break;193 }194 }195 196 if (reg_info) {197 RegisterValue reg_value;198 199 if (reg_ctx->ReadRegister(reg_info, reg_value)) {200 if (is_signed)201 reg_value.SignExtend(bit_width);202 if (!reg_value.GetScalarValue(value->GetScalar()))203 return false;204 continue;205 }206 }207 return false;208 } else {209 if (sp == 0) {210 // Read the stack pointer if we already haven't read it211 sp = reg_ctx->GetSP(0);212 if (sp == 0)213 return false;214 }215 216 // Arguments 5 on up are on the stack217 const uint32_t arg_byte_size = (bit_width + (8 - 1)) / 8;218 Status error;219 if (!exe_ctx.GetProcessRef().ReadScalarIntegerFromMemory(220 sp, arg_byte_size, is_signed, value->GetScalar(), error))221 return false;222 223 sp += arg_byte_size;224 // Align up to the next 8 byte boundary if needed225 if (sp % 8) {226 sp >>= 3;227 sp += 1;228 sp <<= 3;229 }230 }231 }232 }233 return true;234}235 236Status237ABIMacOSX_arm64::SetReturnValueObject(lldb::StackFrameSP &frame_sp,238 lldb::ValueObjectSP &new_value_sp) {239 Status error;240 if (!new_value_sp) {241 error = Status::FromErrorString("Empty value object for return value.");242 return error;243 }244 245 CompilerType return_value_type = new_value_sp->GetCompilerType();246 if (!return_value_type) {247 error = Status::FromErrorString("Null clang type for return value.");248 return error;249 }250 251 Thread *thread = frame_sp->GetThread().get();252 253 RegisterContext *reg_ctx = thread->GetRegisterContext().get();254 255 if (reg_ctx) {256 DataExtractor data;257 Status data_error;258 const uint64_t byte_size = new_value_sp->GetData(data, data_error);259 if (data_error.Fail()) {260 error = Status::FromErrorStringWithFormat(261 "Couldn't convert return value to raw data: %s",262 data_error.AsCString());263 return error;264 }265 266 const uint32_t type_flags = return_value_type.GetTypeInfo(nullptr);267 if (type_flags & eTypeIsScalar || type_flags & eTypeIsPointer) {268 if (type_flags & eTypeIsInteger || type_flags & eTypeIsPointer) {269 // Extract the register context so we can read arguments from registers270 lldb::offset_t offset = 0;271 if (byte_size <= 16) {272 const RegisterInfo *x0_info = reg_ctx->GetRegisterInfoByName("x0", 0);273 if (byte_size <= 8) {274 uint64_t raw_value = data.GetMaxU64(&offset, byte_size);275 276 if (!reg_ctx->WriteRegisterFromUnsigned(x0_info, raw_value))277 error = Status::FromErrorString("failed to write register x0");278 } else {279 uint64_t raw_value = data.GetMaxU64(&offset, 8);280 281 if (reg_ctx->WriteRegisterFromUnsigned(x0_info, raw_value)) {282 const RegisterInfo *x1_info =283 reg_ctx->GetRegisterInfoByName("x1", 0);284 raw_value = data.GetMaxU64(&offset, byte_size - offset);285 286 if (!reg_ctx->WriteRegisterFromUnsigned(x1_info, raw_value))287 error = Status::FromErrorString("failed to write register x1");288 }289 }290 } else {291 error = Status::FromErrorString(292 "We don't support returning longer than 128 bit "293 "integer values at present.");294 }295 } else if (type_flags & eTypeIsFloat) {296 if (type_flags & eTypeIsComplex) {297 // Don't handle complex yet.298 error = Status::FromErrorString(299 "returning complex float values are not supported");300 } else {301 const RegisterInfo *v0_info = reg_ctx->GetRegisterInfoByName("v0", 0);302 303 if (v0_info) {304 if (byte_size <= 16) {305 RegisterValue reg_value;306 error = reg_value.SetValueFromData(*v0_info, data, 0, true);307 if (error.Success())308 if (!reg_ctx->WriteRegister(v0_info, reg_value))309 error =310 Status::FromErrorString("failed to write register v0");311 } else {312 error = Status::FromErrorString(313 "returning float values longer than 128 "314 "bits are not supported");315 }316 } else317 error = Status::FromErrorString(318 "v0 register is not available on this target");319 }320 }321 } else if (type_flags & eTypeIsVector) {322 if (byte_size > 0) {323 const RegisterInfo *v0_info = reg_ctx->GetRegisterInfoByName("v0", 0);324 325 if (v0_info) {326 if (byte_size <= v0_info->byte_size) {327 RegisterValue reg_value;328 error = reg_value.SetValueFromData(*v0_info, data, 0, true);329 if (error.Success()) {330 if (!reg_ctx->WriteRegister(v0_info, reg_value))331 error = Status::FromErrorString("failed to write register v0");332 }333 }334 }335 }336 }337 } else {338 error = Status::FromErrorString("no registers are available");339 }340 341 return error;342}343 344// AAPCS64 (Procedure Call Standard for the ARM 64-bit Architecture) says345// registers x19 through x28 and sp are callee preserved. v8-v15 are non-346// volatile (and specifically only the lower 8 bytes of these regs), the rest347// of the fp/SIMD registers are volatile.348//349// v. https://github.com/ARM-software/abi-aa/blob/main/aapcs64/350 351// We treat x29 as callee preserved also, else the unwinder won't try to352// retrieve fp saves.353 354bool ABIMacOSX_arm64::RegisterIsVolatile(const RegisterInfo *reg_info) {355 if (reg_info) {356 const char *name = reg_info->name;357 358 // Sometimes we'll be called with the "alternate" name for these registers;359 // recognize them as non-volatile.360 361 if (name[0] == 'p' && name[1] == 'c') // pc362 return false;363 if (name[0] == 'f' && name[1] == 'p') // fp364 return false;365 if (name[0] == 's' && name[1] == 'p') // sp366 return false;367 if (name[0] == 'l' && name[1] == 'r') // lr368 return false;369 370 if (name[0] == 'x') {371 // Volatile registers: x0-x18, x30 (lr)372 // Return false for the non-volatile gpr regs, true for everything else373 switch (name[1]) {374 case '1':375 switch (name[2]) {376 case '9':377 return false; // x19 is non-volatile378 default:379 return true;380 }381 break;382 case '2':383 switch (name[2]) {384 case '0':385 case '1':386 case '2':387 case '3':388 case '4':389 case '5':390 case '6':391 case '7':392 case '8':393 return false; // x20 - 28 are non-volatile394 case '9':395 return false; // x29 aka fp treat as non-volatile on Darwin396 default:397 return true;398 }399 case '3': // x30 aka lr treat as non-volatile400 if (name[2] == '0')401 return false;402 break;403 default:404 return true;405 }406 } else if (name[0] == 'v' || name[0] == 's' || name[0] == 'd') {407 // Volatile registers: v0-7, v16-v31408 // Return false for non-volatile fp/SIMD regs, true for everything else409 switch (name[1]) {410 case '8':411 case '9':412 return false; // v8-v9 are non-volatile413 case '1':414 switch (name[2]) {415 case '0':416 case '1':417 case '2':418 case '3':419 case '4':420 case '5':421 return false; // v10-v15 are non-volatile422 default:423 return true;424 }425 default:426 return true;427 }428 }429 }430 return true;431}432 433static bool LoadValueFromConsecutiveGPRRegisters(434 ExecutionContext &exe_ctx, RegisterContext *reg_ctx,435 const CompilerType &value_type,436 bool is_return_value, // false => parameter, true => return value437 uint32_t &NGRN, // NGRN (see ABI documentation)438 uint32_t &NSRN, // NSRN (see ABI documentation)439 DataExtractor &data) {440 std::optional<uint64_t> byte_size = llvm::expectedToOptional(441 value_type.GetByteSize(exe_ctx.GetBestExecutionContextScope()));442 if (!byte_size || *byte_size == 0)443 return false;444 445 std::unique_ptr<DataBufferHeap> heap_data_up(446 new DataBufferHeap(*byte_size, 0));447 const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder();448 Status error;449 450 CompilerType base_type;451 const uint32_t homogeneous_count =452 value_type.IsHomogeneousAggregate(&base_type);453 if (homogeneous_count > 0 && homogeneous_count <= 8) {454 // Make sure we have enough registers455 if (NSRN < 8 && (8 - NSRN) >= homogeneous_count) {456 if (!base_type)457 return false;458 std::optional<uint64_t> base_byte_size = llvm::expectedToOptional(459 base_type.GetByteSize(exe_ctx.GetBestExecutionContextScope()));460 if (!base_byte_size)461 return false;462 uint32_t data_offset = 0;463 464 for (uint32_t i = 0; i < homogeneous_count; ++i) {465 char v_name[8];466 ::snprintf(v_name, sizeof(v_name), "v%u", NSRN);467 const RegisterInfo *reg_info =468 reg_ctx->GetRegisterInfoByName(v_name, 0);469 if (reg_info == nullptr)470 return false;471 472 if (*base_byte_size > reg_info->byte_size)473 return false;474 475 RegisterValue reg_value;476 477 if (!reg_ctx->ReadRegister(reg_info, reg_value))478 return false;479 480 // Make sure we have enough room in "heap_data_up"481 if ((data_offset + *base_byte_size) <= heap_data_up->GetByteSize()) {482 const size_t bytes_copied = reg_value.GetAsMemoryData(483 *reg_info, heap_data_up->GetBytes() + data_offset,484 *base_byte_size, byte_order, error);485 if (bytes_copied != *base_byte_size)486 return false;487 data_offset += bytes_copied;488 ++NSRN;489 } else490 return false;491 }492 data.SetByteOrder(byte_order);493 data.SetAddressByteSize(exe_ctx.GetProcessRef().GetAddressByteSize());494 data.SetData(DataBufferSP(heap_data_up.release()));495 return true;496 }497 }498 499 const size_t max_reg_byte_size = 16;500 if (*byte_size <= max_reg_byte_size) {501 size_t bytes_left = *byte_size;502 uint32_t data_offset = 0;503 while (data_offset < *byte_size) {504 if (NGRN >= 8)505 return false;506 507 uint32_t reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(508 eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + NGRN);509 if (reg_num == LLDB_INVALID_REGNUM)510 return false;511 512 const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_num);513 if (reg_info == nullptr)514 return false;515 516 RegisterValue reg_value;517 518 if (!reg_ctx->ReadRegister(reg_info, reg_value))519 return false;520 521 const size_t curr_byte_size = std::min<size_t>(8, bytes_left);522 const size_t bytes_copied = reg_value.GetAsMemoryData(523 *reg_info, heap_data_up->GetBytes() + data_offset, curr_byte_size,524 byte_order, error);525 if (bytes_copied == 0)526 return false;527 if (bytes_copied >= bytes_left)528 break;529 data_offset += bytes_copied;530 bytes_left -= bytes_copied;531 ++NGRN;532 }533 } else {534 const RegisterInfo *reg_info = nullptr;535 if (is_return_value) {536 // The Darwin arm64 ABI doesn't write the return location back to x8537 // before returning from the function the way the x86_64 ABI does. So538 // we can't reconstruct stack based returns on exit from the function:539 return false;540 } else {541 // We are assuming we are stopped at the first instruction in a function542 // and that the ABI is being respected so all parameters appear where543 // they should be (functions with no external linkage can legally violate544 // the ABI).545 if (NGRN >= 8)546 return false;547 548 uint32_t reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(549 eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + NGRN);550 if (reg_num == LLDB_INVALID_REGNUM)551 return false;552 reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_num);553 if (reg_info == nullptr)554 return false;555 ++NGRN;556 }557 558 const lldb::addr_t value_addr =559 reg_ctx->ReadRegisterAsUnsigned(reg_info, LLDB_INVALID_ADDRESS);560 561 if (value_addr == LLDB_INVALID_ADDRESS)562 return false;563 564 if (exe_ctx.GetProcessRef().ReadMemory(565 value_addr, heap_data_up->GetBytes(), heap_data_up->GetByteSize(),566 error) != heap_data_up->GetByteSize()) {567 return false;568 }569 }570 571 data.SetByteOrder(byte_order);572 data.SetAddressByteSize(exe_ctx.GetProcessRef().GetAddressByteSize());573 data.SetData(DataBufferSP(heap_data_up.release()));574 return true;575}576 577ValueObjectSP ABIMacOSX_arm64::GetReturnValueObjectImpl(578 Thread &thread, CompilerType &return_compiler_type) const {579 ValueObjectSP return_valobj_sp;580 Value value;581 582 ExecutionContext exe_ctx(thread.shared_from_this());583 if (exe_ctx.GetTargetPtr() == nullptr || exe_ctx.GetProcessPtr() == nullptr)584 return return_valobj_sp;585 586 // value.SetContext (Value::eContextTypeClangType, return_compiler_type);587 value.SetCompilerType(return_compiler_type);588 589 RegisterContext *reg_ctx = thread.GetRegisterContext().get();590 if (!reg_ctx)591 return return_valobj_sp;592 593 std::optional<uint64_t> byte_size =594 llvm::expectedToOptional(return_compiler_type.GetByteSize(&thread));595 if (!byte_size)596 return return_valobj_sp;597 598 const uint32_t type_flags = return_compiler_type.GetTypeInfo(nullptr);599 if (type_flags & eTypeIsScalar || type_flags & eTypeIsPointer) {600 value.SetValueType(Value::ValueType::Scalar);601 602 bool success = false;603 if (type_flags & eTypeIsInteger || type_flags & eTypeIsPointer) {604 // Extract the register context so we can read arguments from registers605 if (*byte_size <= 8) {606 const RegisterInfo *x0_reg_info =607 reg_ctx->GetRegisterInfoByName("x0", 0);608 if (x0_reg_info) {609 uint64_t raw_value =610 thread.GetRegisterContext()->ReadRegisterAsUnsigned(x0_reg_info,611 0);612 const bool is_signed = (type_flags & eTypeIsSigned) != 0;613 switch (*byte_size) {614 default:615 break;616 case 16: // uint128_t617 // In register x0 and x1618 {619 const RegisterInfo *x1_reg_info =620 reg_ctx->GetRegisterInfoByName("x1", 0);621 622 if (x1_reg_info) {623 if (*byte_size <=624 x0_reg_info->byte_size + x1_reg_info->byte_size) {625 std::unique_ptr<DataBufferHeap> heap_data_up(626 new DataBufferHeap(*byte_size, 0));627 const ByteOrder byte_order =628 exe_ctx.GetProcessRef().GetByteOrder();629 RegisterValue x0_reg_value;630 RegisterValue x1_reg_value;631 if (reg_ctx->ReadRegister(x0_reg_info, x0_reg_value) &&632 reg_ctx->ReadRegister(x1_reg_info, x1_reg_value)) {633 Status error;634 if (x0_reg_value.GetAsMemoryData(635 *x0_reg_info, heap_data_up->GetBytes() + 0, 8,636 byte_order, error) &&637 x1_reg_value.GetAsMemoryData(638 *x1_reg_info, heap_data_up->GetBytes() + 8, 8,639 byte_order, error)) {640 DataExtractor data(641 DataBufferSP(heap_data_up.release()), byte_order,642 exe_ctx.GetProcessRef().GetAddressByteSize());643 644 return_valobj_sp = ValueObjectConstResult::Create(645 &thread, return_compiler_type, ConstString(""), data);646 return return_valobj_sp;647 }648 }649 }650 }651 }652 break;653 case sizeof(uint64_t):654 if (is_signed)655 value.GetScalar() = (int64_t)(raw_value);656 else657 value.GetScalar() = (uint64_t)(raw_value);658 success = true;659 break;660 661 case sizeof(uint32_t):662 if (is_signed)663 value.GetScalar() = (int32_t)(raw_value & UINT32_MAX);664 else665 value.GetScalar() = (uint32_t)(raw_value & UINT32_MAX);666 success = true;667 break;668 669 case sizeof(uint16_t):670 if (is_signed)671 value.GetScalar() = (int16_t)(raw_value & UINT16_MAX);672 else673 value.GetScalar() = (uint16_t)(raw_value & UINT16_MAX);674 success = true;675 break;676 677 case sizeof(uint8_t):678 if (is_signed)679 value.GetScalar() = (int8_t)(raw_value & UINT8_MAX);680 else681 value.GetScalar() = (uint8_t)(raw_value & UINT8_MAX);682 success = true;683 break;684 }685 }686 }687 } else if (type_flags & eTypeIsFloat) {688 if (type_flags & eTypeIsComplex) {689 // Don't handle complex yet.690 } else {691 if (*byte_size <= sizeof(long double)) {692 const RegisterInfo *v0_reg_info =693 reg_ctx->GetRegisterInfoByName("v0", 0);694 RegisterValue v0_value;695 if (reg_ctx->ReadRegister(v0_reg_info, v0_value)) {696 DataExtractor data;697 if (v0_value.GetData(data)) {698 lldb::offset_t offset = 0;699 if (*byte_size == sizeof(float)) {700 value.GetScalar() = data.GetFloat(&offset);701 success = true;702 } else if (*byte_size == sizeof(double)) {703 value.GetScalar() = data.GetDouble(&offset);704 success = true;705 } else if (*byte_size == sizeof(long double)) {706 value.GetScalar() = data.GetLongDouble(&offset);707 success = true;708 }709 }710 }711 }712 }713 }714 715 if (success)716 return_valobj_sp = ValueObjectConstResult::Create(717 thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));718 } else if (type_flags & eTypeIsVector) {719 if (*byte_size > 0) {720 721 const RegisterInfo *v0_info = reg_ctx->GetRegisterInfoByName("v0", 0);722 723 if (v0_info) {724 if (*byte_size <= v0_info->byte_size) {725 std::unique_ptr<DataBufferHeap> heap_data_up(726 new DataBufferHeap(*byte_size, 0));727 const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder();728 RegisterValue reg_value;729 if (reg_ctx->ReadRegister(v0_info, reg_value)) {730 Status error;731 if (reg_value.GetAsMemoryData(*v0_info, heap_data_up->GetBytes(),732 heap_data_up->GetByteSize(),733 byte_order, error)) {734 DataExtractor data(DataBufferSP(heap_data_up.release()),735 byte_order,736 exe_ctx.GetProcessRef().GetAddressByteSize());737 return_valobj_sp = ValueObjectConstResult::Create(738 &thread, return_compiler_type, ConstString(""), data);739 }740 }741 }742 }743 }744 } else if (type_flags & eTypeIsStructUnion || type_flags & eTypeIsClass) {745 DataExtractor data;746 747 uint32_t NGRN = 0; // Search ABI docs for NGRN748 uint32_t NSRN = 0; // Search ABI docs for NSRN749 const bool is_return_value = true;750 if (LoadValueFromConsecutiveGPRRegisters(751 exe_ctx, reg_ctx, return_compiler_type, is_return_value, NGRN, NSRN,752 data)) {753 return_valobj_sp = ValueObjectConstResult::Create(754 &thread, return_compiler_type, ConstString(""), data);755 }756 }757 return return_valobj_sp;758}759 760constexpr addr_t tbi_mask = 0xff80000000000000ULL;761constexpr addr_t pac_sign_extension = 0x0080000000000000ULL;762 763/// Consults the process for its {code, data} address masks and applies it to764/// `addr`.765static addr_t DoFixAddr(addr_t addr, bool is_code, ProcessSP process_sp) {766 if (!process_sp)767 return addr;768 769 addr_t mask = is_code ? process_sp->GetCodeAddressMask()770 : process_sp->GetDataAddressMask();771 if (mask == LLDB_INVALID_ADDRESS_MASK)772 mask = tbi_mask;773 774 if (addr & pac_sign_extension) {775 addr_t highmem_mask = is_code ? process_sp->GetHighmemCodeAddressMask()776 : process_sp->GetHighmemCodeAddressMask();777 if (highmem_mask != LLDB_INVALID_ADDRESS_MASK)778 return addr | highmem_mask;779 return addr | mask;780 }781 782 return addr & (~mask);783}784 785addr_t ABIMacOSX_arm64::FixCodeAddress(addr_t pc) {786 ProcessSP process_sp = GetProcessSP();787 return DoFixAddr(pc, true /*is_code*/, GetProcessSP());788}789 790addr_t ABIMacOSX_arm64::FixDataAddress(addr_t addr) {791 ProcessSP process_sp = GetProcessSP();792 return DoFixAddr(addr, false /*is_code*/, GetProcessSP());793}794 795void ABIMacOSX_arm64::Initialize() {796 PluginManager::RegisterPlugin(GetPluginNameStatic(), pluginDesc,797 CreateInstance);798}799 800void ABIMacOSX_arm64::Terminate() {801 PluginManager::UnregisterPlugin(CreateInstance);802}803