Files
clang-p2996/lldb/source/Plugins/ABI/Mips/ABISysV_mips.cpp
David Spickett 57c8fee1b9 [lldb] Add dummy field to RegisterInfo for register flags use later
This structure is supposed to be trivial, so we cannot simply do
"= nullptr;" on the new member. Doing that means you are non trivial,
regardless of whether you emulate the previously implied constructor somehow.

The next option is to update every use of brace initialisation.

Given that this is some hundreds of lines, this change just adds a dummy
pointer that is set to nullptr. Subsequent changes will actually use that
to point to register flags information.

Note: This change is not clang-format-ted because it changes a bunch of
areas that are not themselves formatted. It would just add noise.

Reviewed By: jasonmolenda, JDevlieghere

Differential Revision: https://reviews.llvm.org/D145568
2023-04-13 11:30:00 +00:00

1056 lines
27 KiB
C++

//===-- ABISysV_mips.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 "ABISysV_mips.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/TargetParser/Triple.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Value.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Core/ValueObjectMemory.h"
#include "lldb/Core/ValueObjectRegister.h"
#include "lldb/Symbol/UnwindPlan.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/DataExtractor.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/RegisterValue.h"
#include "lldb/Utility/Status.h"
#include <optional>
using namespace lldb;
using namespace lldb_private;
LLDB_PLUGIN_DEFINE(ABISysV_mips)
enum dwarf_regnums {
dwarf_r0 = 0,
dwarf_r1,
dwarf_r2,
dwarf_r3,
dwarf_r4,
dwarf_r5,
dwarf_r6,
dwarf_r7,
dwarf_r8,
dwarf_r9,
dwarf_r10,
dwarf_r11,
dwarf_r12,
dwarf_r13,
dwarf_r14,
dwarf_r15,
dwarf_r16,
dwarf_r17,
dwarf_r18,
dwarf_r19,
dwarf_r20,
dwarf_r21,
dwarf_r22,
dwarf_r23,
dwarf_r24,
dwarf_r25,
dwarf_r26,
dwarf_r27,
dwarf_r28,
dwarf_r29,
dwarf_r30,
dwarf_r31,
dwarf_sr,
dwarf_lo,
dwarf_hi,
dwarf_bad,
dwarf_cause,
dwarf_pc
};
static const RegisterInfo g_register_infos[] = {
// NAME ALT SZ OFF ENCODING FORMAT EH_FRAME
// DWARF GENERIC PROCESS PLUGINS
// LLDB NATIVE VALUE REGS INVALIDATE REGS
// ======== ====== == === ============= =========== ============
// ============== ============ =================
// =================== ========== =================
{"r0",
"zero",
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r0, dwarf_r0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r1",
"AT",
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r1, dwarf_r1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r2",
"v0",
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r2, dwarf_r2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r3",
"v1",
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r3, dwarf_r3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r4",
nullptr,
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r4, dwarf_r4, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r5",
nullptr,
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r5, dwarf_r5, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r6",
nullptr,
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r6, dwarf_r6, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r7",
nullptr,
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r7, dwarf_r7, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r8",
"arg5",
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r8, dwarf_r8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r9",
"arg6",
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r9, dwarf_r9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r10",
"arg7",
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r10, dwarf_r10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r11",
"arg8",
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r11, dwarf_r11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r12",
nullptr,
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r12, dwarf_r12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r13",
nullptr,
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r13, dwarf_r13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r14",
nullptr,
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r14, dwarf_r14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r15",
nullptr,
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r15, dwarf_r15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r16",
nullptr,
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r16, dwarf_r16, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r17",
nullptr,
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r17, dwarf_r17, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r18",
nullptr,
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r18, dwarf_r18, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r19",
nullptr,
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r19, dwarf_r19, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r20",
nullptr,
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r20, dwarf_r20, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r21",
nullptr,
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r21, dwarf_r21, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r22",
nullptr,
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r22, dwarf_r22, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r23",
nullptr,
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r23, dwarf_r23, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r24",
nullptr,
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r24, dwarf_r24, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r25",
nullptr,
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r25, dwarf_r25, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r26",
nullptr,
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r26, dwarf_r26, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r27",
nullptr,
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r27, dwarf_r27, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r28",
"gp",
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r28, dwarf_r28, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r29",
nullptr,
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r29, dwarf_r29, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r30",
nullptr,
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r30, dwarf_r30, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"r31",
nullptr,
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_r31, dwarf_r31, LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"sr",
nullptr,
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_sr, dwarf_sr, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"lo",
nullptr,
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_lo, dwarf_lo, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"hi",
nullptr,
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_hi, dwarf_hi, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"bad",
nullptr,
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_bad, dwarf_bad, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"cause",
nullptr,
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_cause, dwarf_cause, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
{"pc",
nullptr,
4,
0,
eEncodingUint,
eFormatHex,
{dwarf_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM,
LLDB_INVALID_REGNUM},
nullptr,
nullptr,
nullptr,
},
};
static const uint32_t k_num_register_infos = std::size(g_register_infos);
const lldb_private::RegisterInfo *
ABISysV_mips::GetRegisterInfoArray(uint32_t &count) {
count = k_num_register_infos;
return g_register_infos;
}
size_t ABISysV_mips::GetRedZoneSize() const { return 0; }
// Static Functions
ABISP
ABISysV_mips::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) {
const llvm::Triple::ArchType arch_type = arch.GetTriple().getArch();
if ((arch_type == llvm::Triple::mips) ||
(arch_type == llvm::Triple::mipsel)) {
return ABISP(
new ABISysV_mips(std::move(process_sp), MakeMCRegisterInfo(arch)));
}
return ABISP();
}
bool ABISysV_mips::PrepareTrivialCall(Thread &thread, addr_t sp,
addr_t func_addr, addr_t return_addr,
llvm::ArrayRef<addr_t> args) const {
Log *log = GetLog(LLDBLog::Expressions);
if (log) {
StreamString s;
s.Printf("ABISysV_mips::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%zd = 0x%" PRIx64, i + 1, args[i]);
s.PutCString(")");
log->PutString(s.GetString());
}
RegisterContext *reg_ctx = thread.GetRegisterContext().get();
if (!reg_ctx)
return false;
const RegisterInfo *reg_info = nullptr;
RegisterValue reg_value;
// Argument registers
const char *reg_names[] = {"r4", "r5", "r6", "r7"};
llvm::ArrayRef<addr_t>::iterator ai = args.begin(), ae = args.end();
// Write arguments to registers
for (size_t i = 0; i < std::size(reg_names); ++i) {
if (ai == ae)
break;
reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_ARG1 + i);
LLDB_LOGF(log, "About to write arg%zd (0x%" PRIx64 ") into %s", i + 1,
args[i], reg_info->name);
if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i]))
return false;
++ai;
}
// If we have more than 4 arguments --Spill onto the stack
if (ai != ae) {
// No of arguments to go on stack
size_t num_stack_regs = args.size();
// Allocate needed space for args on the stack
sp -= (num_stack_regs * 4);
// Keep the stack 8 byte aligned
sp &= ~(8ull - 1ull);
// just using arg1 to get the right size
const RegisterInfo *reg_info = reg_ctx->GetRegisterInfo(
eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1);
addr_t arg_pos = sp + 16;
size_t i = 4;
for (; ai != ae; ++ai) {
reg_value.SetUInt32(*ai);
LLDB_LOGF(log, "About to write arg%zd (0x%" PRIx64 ") at 0x%" PRIx64 "",
i + 1, args[i], arg_pos);
if (reg_ctx
->WriteRegisterValueToMemory(reg_info, arg_pos,
reg_info->byte_size, reg_value)
.Fail())
return false;
arg_pos += reg_info->byte_size;
i++;
}
}
Status error;
const RegisterInfo *pc_reg_info =
reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
const RegisterInfo *sp_reg_info =
reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
const RegisterInfo *ra_reg_info =
reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);
const RegisterInfo *r25_info = reg_ctx->GetRegisterInfoByName("r25", 0);
const RegisterInfo *r0_info = reg_ctx->GetRegisterInfoByName("zero", 0);
LLDB_LOGF(log, "Writing R0: 0x%" PRIx64, (uint64_t)0);
/* Write r0 with 0, in case we are stopped in syscall,
* such setting prevents automatic decrement of the PC.
* This clears the bug 23659 for MIPS.
*/
if (!reg_ctx->WriteRegisterFromUnsigned(r0_info, (uint64_t)0))
return false;
LLDB_LOGF(log, "Writing SP: 0x%" PRIx64, (uint64_t)sp);
// Set "sp" to the requested value
if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_info, sp))
return false;
LLDB_LOGF(log, "Writing RA: 0x%" PRIx64, (uint64_t)return_addr);
// Set "ra" to the return address
if (!reg_ctx->WriteRegisterFromUnsigned(ra_reg_info, return_addr))
return false;
LLDB_LOGF(log, "Writing PC: 0x%" PRIx64, (uint64_t)func_addr);
// Set pc to the address of the called function.
if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_info, func_addr))
return false;
LLDB_LOGF(log, "Writing r25: 0x%" PRIx64, (uint64_t)func_addr);
// All callers of position independent functions must place the address of
// the called function in t9 (r25)
if (!reg_ctx->WriteRegisterFromUnsigned(r25_info, func_addr))
return false;
return true;
}
bool ABISysV_mips::GetArgumentValues(Thread &thread, ValueList &values) const {
return false;
}
Status ABISysV_mips::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 compiler_type = new_value_sp->GetCompilerType();
if (!compiler_type) {
error.SetErrorString("Null clang type for return value.");
return error;
}
Thread *thread = frame_sp->GetThread().get();
bool is_signed;
uint32_t count;
bool is_complex;
RegisterContext *reg_ctx = thread->GetRegisterContext().get();
bool set_it_simple = false;
if (compiler_type.IsIntegerOrEnumerationType(is_signed) ||
compiler_type.IsPointerType()) {
DataExtractor data;
Status data_error;
size_t num_bytes = 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;
}
lldb::offset_t offset = 0;
if (num_bytes <= 8) {
const RegisterInfo *r2_info = reg_ctx->GetRegisterInfoByName("r2", 0);
if (num_bytes <= 4) {
uint32_t raw_value = data.GetMaxU32(&offset, num_bytes);
if (reg_ctx->WriteRegisterFromUnsigned(r2_info, raw_value))
set_it_simple = true;
} else {
uint32_t raw_value = data.GetMaxU32(&offset, 4);
if (reg_ctx->WriteRegisterFromUnsigned(r2_info, raw_value)) {
const RegisterInfo *r3_info = reg_ctx->GetRegisterInfoByName("r3", 0);
uint32_t raw_value = data.GetMaxU32(&offset, num_bytes - offset);
if (reg_ctx->WriteRegisterFromUnsigned(r3_info, raw_value))
set_it_simple = true;
}
}
} else {
error.SetErrorString("We don't support returning longer than 64 bit "
"integer values at present.");
}
} else if (compiler_type.IsFloatingPointType(count, is_complex)) {
if (is_complex)
error.SetErrorString(
"We don't support returning complex values at present");
else
error.SetErrorString(
"We don't support returning float values at present");
}
if (!set_it_simple)
error.SetErrorString(
"We only support setting simple integer return types at present.");
return error;
}
ValueObjectSP ABISysV_mips::GetReturnValueObjectSimple(
Thread &thread, CompilerType &return_compiler_type) const {
ValueObjectSP return_valobj_sp;
return return_valobj_sp;
}
ValueObjectSP ABISysV_mips::GetReturnValueObjectImpl(
Thread &thread, CompilerType &return_compiler_type) const {
ValueObjectSP return_valobj_sp;
Value value;
if (!return_compiler_type)
return return_valobj_sp;
ExecutionContext exe_ctx(thread.shared_from_this());
if (exe_ctx.GetTargetPtr() == nullptr || exe_ctx.GetProcessPtr() == nullptr)
return return_valobj_sp;
Target *target = exe_ctx.GetTargetPtr();
const ArchSpec target_arch = target->GetArchitecture();
ByteOrder target_byte_order = target_arch.GetByteOrder();
value.SetCompilerType(return_compiler_type);
uint32_t fp_flag =
target_arch.GetFlags() & lldb_private::ArchSpec::eMIPS_ABI_FP_mask;
RegisterContext *reg_ctx = thread.GetRegisterContext().get();
if (!reg_ctx)
return return_valobj_sp;
bool is_signed = false;
bool is_complex = false;
uint32_t count = 0;
// In MIPS register "r2" (v0) holds the integer function return values
const RegisterInfo *r2_reg_info = reg_ctx->GetRegisterInfoByName("r2", 0);
std::optional<uint64_t> bit_width = return_compiler_type.GetBitSize(&thread);
if (!bit_width)
return return_valobj_sp;
if (return_compiler_type.IsIntegerOrEnumerationType(is_signed)) {
switch (*bit_width) {
default:
return return_valobj_sp;
case 64: {
const RegisterInfo *r3_reg_info = reg_ctx->GetRegisterInfoByName("r3", 0);
uint64_t raw_value;
raw_value = reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT32_MAX;
raw_value |= ((uint64_t)(reg_ctx->ReadRegisterAsUnsigned(r3_reg_info, 0) &
UINT32_MAX))
<< 32;
if (is_signed)
value.GetScalar() = (int64_t)raw_value;
else
value.GetScalar() = (uint64_t)raw_value;
} break;
case 32:
if (is_signed)
value.GetScalar() = (int32_t)(
reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT32_MAX);
else
value.GetScalar() = (uint32_t)(
reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT32_MAX);
break;
case 16:
if (is_signed)
value.GetScalar() = (int16_t)(
reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT16_MAX);
else
value.GetScalar() = (uint16_t)(
reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT16_MAX);
break;
case 8:
if (is_signed)
value.GetScalar() = (int8_t)(
reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT8_MAX);
else
value.GetScalar() = (uint8_t)(
reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0) & UINT8_MAX);
break;
}
} else if (return_compiler_type.IsPointerType()) {
uint32_t ptr =
thread.GetRegisterContext()->ReadRegisterAsUnsigned(r2_reg_info, 0) &
UINT32_MAX;
value.GetScalar() = ptr;
} else if (return_compiler_type.IsAggregateType()) {
// Structure/Vector is always passed in memory and pointer to that memory
// is passed in r2.
uint64_t mem_address = reg_ctx->ReadRegisterAsUnsigned(
reg_ctx->GetRegisterInfoByName("r2", 0), 0);
// We have got the address. Create a memory object out of it
return_valobj_sp = ValueObjectMemory::Create(
&thread, "", Address(mem_address, nullptr), return_compiler_type);
return return_valobj_sp;
} else if (return_compiler_type.IsFloatingPointType(count, is_complex)) {
if (IsSoftFloat(fp_flag)) {
uint64_t raw_value = reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0);
if (count != 1 && is_complex)
return return_valobj_sp;
switch (*bit_width) {
default:
return return_valobj_sp;
case 32:
static_assert(sizeof(float) == sizeof(uint32_t));
value.GetScalar() = *((float *)(&raw_value));
break;
case 64:
static_assert(sizeof(double) == sizeof(uint64_t));
const RegisterInfo *r3_reg_info =
reg_ctx->GetRegisterInfoByName("r3", 0);
if (target_byte_order == eByteOrderLittle)
raw_value =
((reg_ctx->ReadRegisterAsUnsigned(r3_reg_info, 0)) << 32) |
raw_value;
else
raw_value = (raw_value << 32) |
reg_ctx->ReadRegisterAsUnsigned(r3_reg_info, 0);
value.GetScalar() = *((double *)(&raw_value));
break;
}
}
else {
const RegisterInfo *f0_info = reg_ctx->GetRegisterInfoByName("f0", 0);
RegisterValue f0_value;
DataExtractor f0_data;
reg_ctx->ReadRegister(f0_info, f0_value);
f0_value.GetData(f0_data);
lldb::offset_t offset = 0;
if (count == 1 && !is_complex) {
switch (*bit_width) {
default:
return return_valobj_sp;
case 64: {
static_assert(sizeof(double) == sizeof(uint64_t));
const RegisterInfo *f1_info = reg_ctx->GetRegisterInfoByName("f1", 0);
RegisterValue f1_value;
DataExtractor f1_data;
reg_ctx->ReadRegister(f1_info, f1_value);
DataExtractor *copy_from_extractor = nullptr;
WritableDataBufferSP data_sp(new DataBufferHeap(8, 0));
DataExtractor return_ext(
data_sp, target_byte_order,
target->GetArchitecture().GetAddressByteSize());
if (target_byte_order == eByteOrderLittle) {
copy_from_extractor = &f0_data;
copy_from_extractor->CopyByteOrderedData(
offset, 4, data_sp->GetBytes(), 4, target_byte_order);
f1_value.GetData(f1_data);
copy_from_extractor = &f1_data;
copy_from_extractor->CopyByteOrderedData(
offset, 4, data_sp->GetBytes() + 4, 4, target_byte_order);
} else {
copy_from_extractor = &f0_data;
copy_from_extractor->CopyByteOrderedData(
offset, 4, data_sp->GetBytes() + 4, 4, target_byte_order);
f1_value.GetData(f1_data);
copy_from_extractor = &f1_data;
copy_from_extractor->CopyByteOrderedData(
offset, 4, data_sp->GetBytes(), 4, target_byte_order);
}
value.GetScalar() = (double)return_ext.GetDouble(&offset);
break;
}
case 32: {
static_assert(sizeof(float) == sizeof(uint32_t));
value.GetScalar() = (float)f0_data.GetFloat(&offset);
break;
}
}
} else {
// not handled yet
return return_valobj_sp;
}
}
} else {
// not handled yet
return return_valobj_sp;
}
// If we get here, we have a valid Value, so make our ValueObject out of it:
return_valobj_sp = ValueObjectConstResult::Create(
thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));
return return_valobj_sp;
}
bool ABISysV_mips::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) {
unwind_plan.Clear();
unwind_plan.SetRegisterKind(eRegisterKindDWARF);
UnwindPlan::RowSP row(new UnwindPlan::Row);
// Our Call Frame Address is the stack pointer value
row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_r29, 0);
// The previous PC is in the RA
row->SetRegisterLocationToRegister(dwarf_pc, dwarf_r31, true);
unwind_plan.AppendRow(row);
// All other registers are the same.
unwind_plan.SetSourceName("mips at-func-entry default");
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
unwind_plan.SetReturnAddressRegister(dwarf_r31);
return true;
}
bool ABISysV_mips::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
unwind_plan.Clear();
unwind_plan.SetRegisterKind(eRegisterKindDWARF);
UnwindPlan::RowSP row(new UnwindPlan::Row);
row->SetUnspecifiedRegistersAreUndefined(true);
row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_r29, 0);
row->SetRegisterLocationToRegister(dwarf_pc, dwarf_r31, true);
unwind_plan.AppendRow(row);
unwind_plan.SetSourceName("mips default unwind plan");
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
return true;
}
bool ABISysV_mips::RegisterIsVolatile(const RegisterInfo *reg_info) {
return !RegisterIsCalleeSaved(reg_info);
}
bool ABISysV_mips::IsSoftFloat(uint32_t fp_flags) const {
return (fp_flags == lldb_private::ArchSpec::eMIPS_ABI_FP_SOFT);
}
bool ABISysV_mips::RegisterIsCalleeSaved(const RegisterInfo *reg_info) {
if (reg_info) {
// Preserved registers are :
// r16-r23, r28, r29, r30, r31
const char *name = reg_info->name;
if (name[0] == 'r') {
switch (name[1]) {
case '1':
if (name[2] == '6' || name[2] == '7' || name[2] == '8' ||
name[2] == '9') // r16-r19
return name[3] == '\0';
break;
case '2':
if (name[2] == '0' || name[2] == '1' || name[2] == '2' ||
name[2] == '3' // r20-r23
|| name[2] == '8' || name[2] == '9') // r28 and r29
return name[3] == '\0';
break;
case '3':
if (name[2] == '0' || name[2] == '1') // r30 and r31
return name[3] == '\0';
break;
}
if (name[0] == 'g' && name[1] == 'p' && name[2] == '\0') // gp (r28)
return true;
if (name[0] == 's' && name[1] == 'p' && name[2] == '\0') // sp (r29)
return true;
if (name[0] == 'f' && name[1] == 'p' && name[2] == '\0') // fp (r30)
return true;
if (name[0] == 'r' && name[1] == 'a' && name[2] == '\0') // ra (r31)
return true;
}
}
return false;
}
void ABISysV_mips::Initialize() {
PluginManager::RegisterPlugin(
GetPluginNameStatic(), "System V ABI for mips targets", CreateInstance);
}
void ABISysV_mips::Terminate() {
PluginManager::UnregisterPlugin(CreateInstance);
}