llvm-project/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp
Jim Ingham 33f9fc77d1 Don't report memory return values on MacOS_arm64 of SysV_arm64 ABI's.
They don't require that the memory return address be restored prior to
function exit, so there's no guarantee the value is correct.  It's better
to return nothing that something that's not accurate.

Differential Revision: https://reviews.llvm.org/D121348
2022-03-14 15:25:40 -07:00

843 lines
28 KiB
C++

//===-- ABIMacOSX_arm64.cpp -----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "ABIMacOSX_arm64.h"
#include <vector>
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Triple.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Value.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Symbol/UnwindPlan.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/RegisterValue.h"
#include "lldb/Utility/Scalar.h"
#include "lldb/Utility/Status.h"
#include "Utility/ARM64_DWARF_Registers.h"
using namespace lldb;
using namespace lldb_private;
static const char *pluginDesc = "Mac OS X ABI for arm64 targets";
size_t ABIMacOSX_arm64::GetRedZoneSize() const { return 128; }
// Static Functions
ABISP
ABIMacOSX_arm64::CreateInstance(ProcessSP process_sp, const ArchSpec &arch) {
const llvm::Triple::ArchType arch_type = arch.GetTriple().getArch();
const llvm::Triple::VendorType vendor_type = arch.GetTriple().getVendor();
if (vendor_type == llvm::Triple::Apple) {
if (arch_type == llvm::Triple::aarch64 ||
arch_type == llvm::Triple::aarch64_32) {
return ABISP(
new ABIMacOSX_arm64(std::move(process_sp), MakeMCRegisterInfo(arch)));
}
}
return ABISP();
}
bool ABIMacOSX_arm64::PrepareTrivialCall(
Thread &thread, lldb::addr_t sp, lldb::addr_t func_addr,
lldb::addr_t return_addr, llvm::ArrayRef<lldb::addr_t> args) const {
RegisterContext *reg_ctx = thread.GetRegisterContext().get();
if (!reg_ctx)
return false;
Log *log = GetLog(LLDBLog::Expressions);
if (log) {
StreamString s;
s.Printf("ABIMacOSX_arm64::PrepareTrivialCall (tid = 0x%" PRIx64
", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64
", return_addr = 0x%" PRIx64,
thread.GetID(), (uint64_t)sp, (uint64_t)func_addr,
(uint64_t)return_addr);
for (size_t i = 0; i < args.size(); ++i)
s.Printf(", arg%d = 0x%" PRIx64, static_cast<int>(i + 1), args[i]);
s.PutCString(")");
log->PutString(s.GetString());
}
const uint32_t pc_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(
eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
const uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(
eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
const uint32_t ra_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(
eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);
// x0 - x7 contain first 8 simple args
if (args.size() > 8) // TODO handle more than 8 arguments
return false;
for (size_t i = 0; i < args.size(); ++i) {
const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo(
eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + i);
LLDB_LOGF(log, "About to write arg%d (0x%" PRIx64 ") into %s",
static_cast<int>(i + 1), args[i], reg_info->name);
if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i]))
return false;
}
// Set "lr" to the return address
if (!reg_ctx->WriteRegisterFromUnsigned(
reg_ctx->GetRegisterInfoAtIndex(ra_reg_num), return_addr))
return false;
// Set "sp" to the requested value
if (!reg_ctx->WriteRegisterFromUnsigned(
reg_ctx->GetRegisterInfoAtIndex(sp_reg_num), sp))
return false;
// Set "pc" to the address requested
if (!reg_ctx->WriteRegisterFromUnsigned(
reg_ctx->GetRegisterInfoAtIndex(pc_reg_num), func_addr))
return false;
return true;
}
bool ABIMacOSX_arm64::GetArgumentValues(Thread &thread,
ValueList &values) const {
uint32_t num_values = values.GetSize();
ExecutionContext exe_ctx(thread.shared_from_this());
// Extract the register context so we can read arguments from registers
RegisterContext *reg_ctx = thread.GetRegisterContext().get();
if (!reg_ctx)
return false;
addr_t sp = 0;
for (uint32_t value_idx = 0; value_idx < num_values; ++value_idx) {
// We currently only support extracting values with Clang QualTypes. Do we
// care about others?
Value *value = values.GetValueAtIndex(value_idx);
if (!value)
return false;
CompilerType value_type = value->GetCompilerType();
llvm::Optional<uint64_t> bit_size = value_type.GetBitSize(&thread);
if (!bit_size)
return false;
bool is_signed = false;
size_t bit_width = 0;
if (value_type.IsIntegerOrEnumerationType(is_signed)) {
bit_width = *bit_size;
} else if (value_type.IsPointerOrReferenceType()) {
bit_width = *bit_size;
} else {
// We only handle integer, pointer and reference types currently...
return false;
}
if (bit_width <= (exe_ctx.GetProcessRef().GetAddressByteSize() * 8)) {
if (value_idx < 8) {
// Arguments 1-6 are in x0-x5...
const RegisterInfo *reg_info = nullptr;
// Search by generic ID first, then fall back to by name
uint32_t arg_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(
eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + value_idx);
if (arg_reg_num != LLDB_INVALID_REGNUM) {
reg_info = reg_ctx->GetRegisterInfoAtIndex(arg_reg_num);
} else {
switch (value_idx) {
case 0:
reg_info = reg_ctx->GetRegisterInfoByName("x0");
break;
case 1:
reg_info = reg_ctx->GetRegisterInfoByName("x1");
break;
case 2:
reg_info = reg_ctx->GetRegisterInfoByName("x2");
break;
case 3:
reg_info = reg_ctx->GetRegisterInfoByName("x3");
break;
case 4:
reg_info = reg_ctx->GetRegisterInfoByName("x4");
break;
case 5:
reg_info = reg_ctx->GetRegisterInfoByName("x5");
break;
case 6:
reg_info = reg_ctx->GetRegisterInfoByName("x6");
break;
case 7:
reg_info = reg_ctx->GetRegisterInfoByName("x7");
break;
}
}
if (reg_info) {
RegisterValue reg_value;
if (reg_ctx->ReadRegister(reg_info, reg_value)) {
if (is_signed)
reg_value.SignExtend(bit_width);
if (!reg_value.GetScalarValue(value->GetScalar()))
return false;
continue;
}
}
return false;
} else {
if (sp == 0) {
// Read the stack pointer if we already haven't read it
sp = reg_ctx->GetSP(0);
if (sp == 0)
return false;
}
// Arguments 5 on up are on the stack
const uint32_t arg_byte_size = (bit_width + (8 - 1)) / 8;
Status error;
if (!exe_ctx.GetProcessRef().ReadScalarIntegerFromMemory(
sp, arg_byte_size, is_signed, value->GetScalar(), error))
return false;
sp += arg_byte_size;
// Align up to the next 8 byte boundary if needed
if (sp % 8) {
sp >>= 3;
sp += 1;
sp <<= 3;
}
}
}
}
return true;
}
Status
ABIMacOSX_arm64::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
lldb::ValueObjectSP &new_value_sp) {
Status error;
if (!new_value_sp) {
error.SetErrorString("Empty value object for return value.");
return error;
}
CompilerType return_value_type = new_value_sp->GetCompilerType();
if (!return_value_type) {
error.SetErrorString("Null clang type for return value.");
return error;
}
Thread *thread = frame_sp->GetThread().get();
RegisterContext *reg_ctx = thread->GetRegisterContext().get();
if (reg_ctx) {
DataExtractor data;
Status data_error;
const uint64_t byte_size = new_value_sp->GetData(data, data_error);
if (data_error.Fail()) {
error.SetErrorStringWithFormat(
"Couldn't convert return value to raw data: %s",
data_error.AsCString());
return error;
}
const uint32_t type_flags = return_value_type.GetTypeInfo(nullptr);
if (type_flags & eTypeIsScalar || type_flags & eTypeIsPointer) {
if (type_flags & eTypeIsInteger || type_flags & eTypeIsPointer) {
// Extract the register context so we can read arguments from registers
lldb::offset_t offset = 0;
if (byte_size <= 16) {
const RegisterInfo *x0_info = reg_ctx->GetRegisterInfoByName("x0", 0);
if (byte_size <= 8) {
uint64_t raw_value = data.GetMaxU64(&offset, byte_size);
if (!reg_ctx->WriteRegisterFromUnsigned(x0_info, raw_value))
error.SetErrorString("failed to write register x0");
} else {
uint64_t raw_value = data.GetMaxU64(&offset, 8);
if (reg_ctx->WriteRegisterFromUnsigned(x0_info, raw_value)) {
const RegisterInfo *x1_info =
reg_ctx->GetRegisterInfoByName("x1", 0);
raw_value = data.GetMaxU64(&offset, byte_size - offset);
if (!reg_ctx->WriteRegisterFromUnsigned(x1_info, raw_value))
error.SetErrorString("failed to write register x1");
}
}
} else {
error.SetErrorString("We don't support returning longer than 128 bit "
"integer values at present.");
}
} else if (type_flags & eTypeIsFloat) {
if (type_flags & eTypeIsComplex) {
// Don't handle complex yet.
error.SetErrorString(
"returning complex float values are not supported");
} else {
const RegisterInfo *v0_info = reg_ctx->GetRegisterInfoByName("v0", 0);
if (v0_info) {
if (byte_size <= 16) {
if (byte_size <= RegisterValue::GetMaxByteSize()) {
RegisterValue reg_value;
error = reg_value.SetValueFromData(v0_info, data, 0, true);
if (error.Success()) {
if (!reg_ctx->WriteRegister(v0_info, reg_value))
error.SetErrorString("failed to write register v0");
}
} else {
error.SetErrorStringWithFormat(
"returning float values with a byte size of %" PRIu64
" are not supported",
byte_size);
}
} else {
error.SetErrorString("returning float values longer than 128 "
"bits are not supported");
}
} else {
error.SetErrorString("v0 register is not available on this target");
}
}
}
} else if (type_flags & eTypeIsVector) {
if (byte_size > 0) {
const RegisterInfo *v0_info = reg_ctx->GetRegisterInfoByName("v0", 0);
if (v0_info) {
if (byte_size <= v0_info->byte_size) {
RegisterValue reg_value;
error = reg_value.SetValueFromData(v0_info, data, 0, true);
if (error.Success()) {
if (!reg_ctx->WriteRegister(v0_info, reg_value))
error.SetErrorString("failed to write register v0");
}
}
}
}
}
} else {
error.SetErrorString("no registers are available");
}
return error;
}
bool ABIMacOSX_arm64::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) {
unwind_plan.Clear();
unwind_plan.SetRegisterKind(eRegisterKindDWARF);
uint32_t lr_reg_num = arm64_dwarf::lr;
uint32_t sp_reg_num = arm64_dwarf::sp;
uint32_t pc_reg_num = arm64_dwarf::pc;
UnwindPlan::RowSP row(new UnwindPlan::Row);
// Our previous Call Frame Address is the stack pointer
row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 0);
// Our previous PC is in the LR
row->SetRegisterLocationToRegister(pc_reg_num, lr_reg_num, true);
unwind_plan.AppendRow(row);
// All other registers are the same.
unwind_plan.SetSourceName("arm64 at-func-entry default");
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
return true;
}
bool ABIMacOSX_arm64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
unwind_plan.Clear();
unwind_plan.SetRegisterKind(eRegisterKindDWARF);
uint32_t fp_reg_num = arm64_dwarf::fp;
uint32_t pc_reg_num = arm64_dwarf::pc;
UnwindPlan::RowSP row(new UnwindPlan::Row);
const int32_t ptr_size = 8;
row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size);
row->SetOffset(0);
row->SetUnspecifiedRegistersAreUndefined(true);
row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);
unwind_plan.AppendRow(row);
unwind_plan.SetSourceName("arm64-apple-darwin default unwind plan");
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
return true;
}
// AAPCS64 (Procedure Call Standard for the ARM 64-bit Architecture) says
// registers x19 through x28 and sp are callee preserved. v8-v15 are non-
// volatile (and specifically only the lower 8 bytes of these regs), the rest
// of the fp/SIMD registers are volatile.
//
// v. https://github.com/ARM-software/abi-aa/blob/main/aapcs64/
// We treat x29 as callee preserved also, else the unwinder won't try to
// retrieve fp saves.
bool ABIMacOSX_arm64::RegisterIsVolatile(const RegisterInfo *reg_info) {
if (reg_info) {
const char *name = reg_info->name;
// Sometimes we'll be called with the "alternate" name for these registers;
// recognize them as non-volatile.
if (name[0] == 'p' && name[1] == 'c') // pc
return false;
if (name[0] == 'f' && name[1] == 'p') // fp
return false;
if (name[0] == 's' && name[1] == 'p') // sp
return false;
if (name[0] == 'l' && name[1] == 'r') // lr
return false;
if (name[0] == 'x') {
// Volatile registers: x0-x18, x30 (lr)
// Return false for the non-volatile gpr regs, true for everything else
switch (name[1]) {
case '1':
switch (name[2]) {
case '9':
return false; // x19 is non-volatile
default:
return true;
}
break;
case '2':
switch (name[2]) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
return false; // x20 - 28 are non-volatile
case '9':
return false; // x29 aka fp treat as non-volatile on Darwin
default:
return true;
}
case '3': // x30 aka lr treat as non-volatile
if (name[2] == '0')
return false;
break;
default:
return true;
}
} else if (name[0] == 'v' || name[0] == 's' || name[0] == 'd') {
// Volatile registers: v0-7, v16-v31
// Return false for non-volatile fp/SIMD regs, true for everything else
switch (name[1]) {
case '8':
case '9':
return false; // v8-v9 are non-volatile
case '1':
switch (name[2]) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
return false; // v10-v15 are non-volatile
default:
return true;
}
default:
return true;
}
}
}
return true;
}
static bool LoadValueFromConsecutiveGPRRegisters(
ExecutionContext &exe_ctx, RegisterContext *reg_ctx,
const CompilerType &value_type,
bool is_return_value, // false => parameter, true => return value
uint32_t &NGRN, // NGRN (see ABI documentation)
uint32_t &NSRN, // NSRN (see ABI documentation)
DataExtractor &data) {
llvm::Optional<uint64_t> byte_size =
value_type.GetByteSize(exe_ctx.GetBestExecutionContextScope());
if (!byte_size || *byte_size == 0)
return false;
std::unique_ptr<DataBufferHeap> heap_data_up(
new DataBufferHeap(*byte_size, 0));
const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder();
Status error;
CompilerType base_type;
const uint32_t homogeneous_count =
value_type.IsHomogeneousAggregate(&base_type);
if (homogeneous_count > 0 && homogeneous_count <= 8) {
// Make sure we have enough registers
if (NSRN < 8 && (8 - NSRN) >= homogeneous_count) {
if (!base_type)
return false;
llvm::Optional<uint64_t> base_byte_size =
base_type.GetByteSize(exe_ctx.GetBestExecutionContextScope());
if (!base_byte_size)
return false;
uint32_t data_offset = 0;
for (uint32_t i = 0; i < homogeneous_count; ++i) {
char v_name[8];
::snprintf(v_name, sizeof(v_name), "v%u", NSRN);
const RegisterInfo *reg_info =
reg_ctx->GetRegisterInfoByName(v_name, 0);
if (reg_info == nullptr)
return false;
if (*base_byte_size > reg_info->byte_size)
return false;
RegisterValue reg_value;
if (!reg_ctx->ReadRegister(reg_info, reg_value))
return false;
// Make sure we have enough room in "heap_data_up"
if ((data_offset + *base_byte_size) <= heap_data_up->GetByteSize()) {
const size_t bytes_copied = reg_value.GetAsMemoryData(
reg_info, heap_data_up->GetBytes() + data_offset, *base_byte_size,
byte_order, error);
if (bytes_copied != *base_byte_size)
return false;
data_offset += bytes_copied;
++NSRN;
} else
return false;
}
data.SetByteOrder(byte_order);
data.SetAddressByteSize(exe_ctx.GetProcessRef().GetAddressByteSize());
data.SetData(DataBufferSP(heap_data_up.release()));
return true;
}
}
const size_t max_reg_byte_size = 16;
if (*byte_size <= max_reg_byte_size) {
size_t bytes_left = *byte_size;
uint32_t data_offset = 0;
while (data_offset < *byte_size) {
if (NGRN >= 8)
return false;
uint32_t reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(
eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + NGRN);
if (reg_num == LLDB_INVALID_REGNUM)
return false;
const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_num);
if (reg_info == nullptr)
return false;
RegisterValue reg_value;
if (!reg_ctx->ReadRegister(reg_info, reg_value))
return false;
const size_t curr_byte_size = std::min<size_t>(8, bytes_left);
const size_t bytes_copied = reg_value.GetAsMemoryData(
reg_info, heap_data_up->GetBytes() + data_offset, curr_byte_size,
byte_order, error);
if (bytes_copied == 0)
return false;
if (bytes_copied >= bytes_left)
break;
data_offset += bytes_copied;
bytes_left -= bytes_copied;
++NGRN;
}
} else {
const RegisterInfo *reg_info = nullptr;
if (is_return_value) {
// The Darwin arm64 ABI doesn't write the return location back to x8
// before returning from the function the way the x86_64 ABI does. So
// we can't reconstruct stack based returns on exit from the function:
return false;
} else {
// We are assuming we are stopped at the first instruction in a function
// and that the ABI is being respected so all parameters appear where
// they should be (functions with no external linkage can legally violate
// the ABI).
if (NGRN >= 8)
return false;
uint32_t reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(
eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + NGRN);
if (reg_num == LLDB_INVALID_REGNUM)
return false;
reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_num);
if (reg_info == nullptr)
return false;
++NGRN;
}
if (reg_info == nullptr)
return false;
const lldb::addr_t value_addr =
reg_ctx->ReadRegisterAsUnsigned(reg_info, LLDB_INVALID_ADDRESS);
if (value_addr == LLDB_INVALID_ADDRESS)
return false;
if (exe_ctx.GetProcessRef().ReadMemory(
value_addr, heap_data_up->GetBytes(), heap_data_up->GetByteSize(),
error) != heap_data_up->GetByteSize()) {
return false;
}
}
data.SetByteOrder(byte_order);
data.SetAddressByteSize(exe_ctx.GetProcessRef().GetAddressByteSize());
data.SetData(DataBufferSP(heap_data_up.release()));
return true;
}
ValueObjectSP ABIMacOSX_arm64::GetReturnValueObjectImpl(
Thread &thread, CompilerType &return_compiler_type) const {
ValueObjectSP return_valobj_sp;
Value value;
ExecutionContext exe_ctx(thread.shared_from_this());
if (exe_ctx.GetTargetPtr() == nullptr || exe_ctx.GetProcessPtr() == nullptr)
return return_valobj_sp;
// value.SetContext (Value::eContextTypeClangType, return_compiler_type);
value.SetCompilerType(return_compiler_type);
RegisterContext *reg_ctx = thread.GetRegisterContext().get();
if (!reg_ctx)
return return_valobj_sp;
llvm::Optional<uint64_t> byte_size =
return_compiler_type.GetByteSize(&thread);
if (!byte_size)
return return_valobj_sp;
const uint32_t type_flags = return_compiler_type.GetTypeInfo(nullptr);
if (type_flags & eTypeIsScalar || type_flags & eTypeIsPointer) {
value.SetValueType(Value::ValueType::Scalar);
bool success = false;
if (type_flags & eTypeIsInteger || type_flags & eTypeIsPointer) {
// Extract the register context so we can read arguments from registers
if (*byte_size <= 8) {
const RegisterInfo *x0_reg_info =
reg_ctx->GetRegisterInfoByName("x0", 0);
if (x0_reg_info) {
uint64_t raw_value =
thread.GetRegisterContext()->ReadRegisterAsUnsigned(x0_reg_info,
0);
const bool is_signed = (type_flags & eTypeIsSigned) != 0;
switch (*byte_size) {
default:
break;
case 16: // uint128_t
// In register x0 and x1
{
const RegisterInfo *x1_reg_info =
reg_ctx->GetRegisterInfoByName("x1", 0);
if (x1_reg_info) {
if (*byte_size <=
x0_reg_info->byte_size + x1_reg_info->byte_size) {
std::unique_ptr<DataBufferHeap> heap_data_up(
new DataBufferHeap(*byte_size, 0));
const ByteOrder byte_order =
exe_ctx.GetProcessRef().GetByteOrder();
RegisterValue x0_reg_value;
RegisterValue x1_reg_value;
if (reg_ctx->ReadRegister(x0_reg_info, x0_reg_value) &&
reg_ctx->ReadRegister(x1_reg_info, x1_reg_value)) {
Status error;
if (x0_reg_value.GetAsMemoryData(
x0_reg_info, heap_data_up->GetBytes() + 0, 8,
byte_order, error) &&
x1_reg_value.GetAsMemoryData(
x1_reg_info, heap_data_up->GetBytes() + 8, 8,
byte_order, error)) {
DataExtractor data(
DataBufferSP(heap_data_up.release()), byte_order,
exe_ctx.GetProcessRef().GetAddressByteSize());
return_valobj_sp = ValueObjectConstResult::Create(
&thread, return_compiler_type, ConstString(""), data);
return return_valobj_sp;
}
}
}
}
}
break;
case sizeof(uint64_t):
if (is_signed)
value.GetScalar() = (int64_t)(raw_value);
else
value.GetScalar() = (uint64_t)(raw_value);
success = true;
break;
case sizeof(uint32_t):
if (is_signed)
value.GetScalar() = (int32_t)(raw_value & UINT32_MAX);
else
value.GetScalar() = (uint32_t)(raw_value & UINT32_MAX);
success = true;
break;
case sizeof(uint16_t):
if (is_signed)
value.GetScalar() = (int16_t)(raw_value & UINT16_MAX);
else
value.GetScalar() = (uint16_t)(raw_value & UINT16_MAX);
success = true;
break;
case sizeof(uint8_t):
if (is_signed)
value.GetScalar() = (int8_t)(raw_value & UINT8_MAX);
else
value.GetScalar() = (uint8_t)(raw_value & UINT8_MAX);
success = true;
break;
}
}
}
} else if (type_flags & eTypeIsFloat) {
if (type_flags & eTypeIsComplex) {
// Don't handle complex yet.
} else {
if (*byte_size <= sizeof(long double)) {
const RegisterInfo *v0_reg_info =
reg_ctx->GetRegisterInfoByName("v0", 0);
RegisterValue v0_value;
if (reg_ctx->ReadRegister(v0_reg_info, v0_value)) {
DataExtractor data;
if (v0_value.GetData(data)) {
lldb::offset_t offset = 0;
if (*byte_size == sizeof(float)) {
value.GetScalar() = data.GetFloat(&offset);
success = true;
} else if (*byte_size == sizeof(double)) {
value.GetScalar() = data.GetDouble(&offset);
success = true;
} else if (*byte_size == sizeof(long double)) {
value.GetScalar() = data.GetLongDouble(&offset);
success = true;
}
}
}
}
}
}
if (success)
return_valobj_sp = ValueObjectConstResult::Create(
thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));
} else if (type_flags & eTypeIsVector) {
if (*byte_size > 0) {
const RegisterInfo *v0_info = reg_ctx->GetRegisterInfoByName("v0", 0);
if (v0_info) {
if (*byte_size <= v0_info->byte_size) {
std::unique_ptr<DataBufferHeap> heap_data_up(
new DataBufferHeap(*byte_size, 0));
const ByteOrder byte_order = exe_ctx.GetProcessRef().GetByteOrder();
RegisterValue reg_value;
if (reg_ctx->ReadRegister(v0_info, reg_value)) {
Status error;
if (reg_value.GetAsMemoryData(v0_info, heap_data_up->GetBytes(),
heap_data_up->GetByteSize(),
byte_order, error)) {
DataExtractor data(DataBufferSP(heap_data_up.release()),
byte_order,
exe_ctx.GetProcessRef().GetAddressByteSize());
return_valobj_sp = ValueObjectConstResult::Create(
&thread, return_compiler_type, ConstString(""), data);
}
}
}
}
}
} else if (type_flags & eTypeIsStructUnion || type_flags & eTypeIsClass) {
DataExtractor data;
uint32_t NGRN = 0; // Search ABI docs for NGRN
uint32_t NSRN = 0; // Search ABI docs for NSRN
const bool is_return_value = true;
if (LoadValueFromConsecutiveGPRRegisters(
exe_ctx, reg_ctx, return_compiler_type, is_return_value, NGRN, NSRN,
data)) {
return_valobj_sp = ValueObjectConstResult::Create(
&thread, return_compiler_type, ConstString(""), data);
}
}
return return_valobj_sp;
}
lldb::addr_t ABIMacOSX_arm64::FixAddress(addr_t pc, addr_t mask) {
lldb::addr_t pac_sign_extension = 0x0080000000000000ULL;
// Darwin systems originally couldn't determine the proper value
// dynamically, so the most common value was hardcoded. This has
// largely been cleaned up, but there are still a handful of
// environments that assume the default value is set to this value
// and there's no dynamic value to correct it.
// When no mask is specified, set it to 39 bits of addressing (0..38).
if (mask == 0) {
// ~((1ULL<<39)-1)
mask = 0xffffff8000000000;
}
return (pc & pac_sign_extension) ? pc | mask : pc & (~mask);
}
void ABIMacOSX_arm64::Initialize() {
PluginManager::RegisterPlugin(GetPluginNameStatic(), pluginDesc,
CreateInstance);
}
void ABIMacOSX_arm64::Terminate() {
PluginManager::UnregisterPlugin(CreateInstance);
}