blob: 6794f7d072100925fc77511d32cc448660a62e34 [file] [log] [blame]
//===-- ABISysV_hexagon.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_hexagon.h"
#include "llvm/ADT/Triple.h"
#include "llvm/IR/DerivedTypes.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/Log.h"
#include "lldb/Utility/RegisterValue.h"
#include "lldb/Utility/Status.h"
using namespace lldb;
using namespace lldb_private;
LLDB_PLUGIN_DEFINE_ADV(ABISysV_hexagon, ABIHexagon)
static const RegisterInfo g_register_infos[] = {
// hexagon-core.xml
{"r00",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{0, 0, LLDB_INVALID_REGNUM, 0, 0},
nullptr,
nullptr,
nullptr,
0},
{"r01",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{1, 1, LLDB_INVALID_REGNUM, 1, 1},
nullptr,
nullptr,
nullptr,
0},
{"r02",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{2, 2, LLDB_INVALID_REGNUM, 2, 2},
nullptr,
nullptr,
nullptr,
0},
{"r03",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{3, 3, LLDB_INVALID_REGNUM, 3, 3},
nullptr,
nullptr,
nullptr,
0},
{"r04",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{4, 4, LLDB_INVALID_REGNUM, 4, 4},
nullptr,
nullptr,
nullptr,
0},
{"r05",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{5, 5, LLDB_INVALID_REGNUM, 5, 5},
nullptr,
nullptr,
nullptr,
0},
{"r06",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{6, 6, LLDB_INVALID_REGNUM, 6, 6},
nullptr,
nullptr,
nullptr,
0},
{"r07",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{7, 7, LLDB_INVALID_REGNUM, 7, 7},
nullptr,
nullptr,
nullptr,
0},
{"r08",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{8, 8, LLDB_INVALID_REGNUM, 8, 8},
nullptr,
nullptr,
nullptr,
0},
{"r09",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{9, 9, LLDB_INVALID_REGNUM, 9, 9},
nullptr,
nullptr,
nullptr,
0},
{"r10",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{10, 10, LLDB_INVALID_REGNUM, 10, 10},
nullptr,
nullptr,
nullptr,
0},
{"r11",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{11, 11, LLDB_INVALID_REGNUM, 11, 11},
nullptr,
nullptr,
nullptr,
0},
{"r12",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{12, 12, LLDB_INVALID_REGNUM, 12, 12},
nullptr,
nullptr,
nullptr,
0},
{"r13",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{13, 13, LLDB_INVALID_REGNUM, 13, 13},
nullptr,
nullptr,
nullptr,
0},
{"r14",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{14, 14, LLDB_INVALID_REGNUM, 14, 14},
nullptr,
nullptr,
nullptr,
0},
{"r15",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{15, 15, LLDB_INVALID_REGNUM, 15, 15},
nullptr,
nullptr,
nullptr,
0},
{"r16",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{16, 16, LLDB_INVALID_REGNUM, 16, 16},
nullptr,
nullptr,
nullptr,
0},
{"r17",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{17, 17, LLDB_INVALID_REGNUM, 17, 17},
nullptr,
nullptr,
nullptr,
0},
{"r18",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{18, 18, LLDB_INVALID_REGNUM, 18, 18},
nullptr,
nullptr,
nullptr,
0},
{"r19",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{19, 19, LLDB_INVALID_REGNUM, 19, 19},
nullptr,
nullptr,
nullptr,
0},
{"r20",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{20, 20, LLDB_INVALID_REGNUM, 20, 20},
nullptr,
nullptr,
nullptr,
0},
{"r21",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{21, 21, LLDB_INVALID_REGNUM, 21, 21},
nullptr,
nullptr,
nullptr,
0},
{"r22",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{22, 22, LLDB_INVALID_REGNUM, 22, 22},
nullptr,
nullptr,
nullptr,
0},
{"r23",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{23, 23, LLDB_INVALID_REGNUM, 23, 23},
nullptr,
nullptr,
nullptr,
0},
{"r24",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{24, 24, LLDB_INVALID_REGNUM, 24, 24},
nullptr,
nullptr,
nullptr,
0},
{"r25",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{25, 25, LLDB_INVALID_REGNUM, 25, 25},
nullptr,
nullptr,
nullptr,
0},
{"r26",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{26, 26, LLDB_INVALID_REGNUM, 26, 26},
nullptr,
nullptr,
nullptr,
0},
{"r27",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{27, 27, LLDB_INVALID_REGNUM, 27, 27},
nullptr,
nullptr,
nullptr,
0},
{"r28",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{28, 28, LLDB_INVALID_REGNUM, 28, 28},
nullptr,
nullptr,
nullptr,
0},
{"sp",
"r29",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{29, 29, LLDB_REGNUM_GENERIC_SP, 29, 29},
nullptr,
nullptr,
nullptr,
0},
{"fp",
"r30",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{30, 30, LLDB_REGNUM_GENERIC_FP, 30, 30},
nullptr,
nullptr,
nullptr,
0},
{"lr",
"r31",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{31, 31, LLDB_REGNUM_GENERIC_RA, 31, 31},
nullptr,
nullptr,
nullptr,
0},
{"sa0",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{32, 32, LLDB_INVALID_REGNUM, 32, 32},
nullptr,
nullptr,
nullptr,
0},
{"lc0",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{33, 33, LLDB_INVALID_REGNUM, 33, 33},
nullptr,
nullptr,
nullptr,
0},
{"sa1",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{34, 34, LLDB_INVALID_REGNUM, 34, 34},
nullptr,
nullptr,
nullptr,
0},
{"lc1",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{35, 35, LLDB_INVALID_REGNUM, 35, 35},
nullptr,
nullptr,
nullptr,
0},
// --> hexagon-v4/5/55/56-sim.xml
{"p3_0",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{36, 36, LLDB_INVALID_REGNUM, 36, 36},
nullptr,
nullptr,
nullptr,
0},
// PADDING {
{"p00",
"",
4,
0,
eEncodingInvalid,
eFormatInvalid,
{37, 37, LLDB_INVALID_REGNUM, 37, 37},
nullptr,
nullptr,
nullptr,
0},
// }
{"m0",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{38, 38, LLDB_INVALID_REGNUM, 38, 38},
nullptr,
nullptr,
nullptr,
0},
{"m1",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{39, 39, LLDB_INVALID_REGNUM, 39, 39},
nullptr,
nullptr,
nullptr,
0},
{"usr",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{40, 40, LLDB_INVALID_REGNUM, 40, 40},
nullptr,
nullptr,
nullptr,
0},
{"pc",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{41, 41, LLDB_REGNUM_GENERIC_PC, 41, 41},
nullptr,
nullptr,
nullptr,
0},
{"ugp",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{42, 42, LLDB_INVALID_REGNUM, 42, 42},
nullptr,
nullptr,
nullptr,
0},
{"gp",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{43, 43, LLDB_INVALID_REGNUM, 43, 43},
nullptr,
nullptr,
nullptr,
0},
{"cs0",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{44, 44, LLDB_INVALID_REGNUM, 44, 44},
nullptr,
nullptr,
nullptr,
0},
{"cs1",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{45, 45, LLDB_INVALID_REGNUM, 45, 45},
nullptr,
nullptr,
nullptr,
0},
// PADDING {
{"p01",
"",
4,
0,
eEncodingInvalid,
eFormatInvalid,
{46, 46, LLDB_INVALID_REGNUM, 46, 46},
nullptr,
nullptr,
nullptr,
0},
{"p02",
"",
4,
0,
eEncodingInvalid,
eFormatInvalid,
{47, 47, LLDB_INVALID_REGNUM, 47, 47},
nullptr,
nullptr,
nullptr,
0},
{"p03",
"",
4,
0,
eEncodingInvalid,
eFormatInvalid,
{48, 48, LLDB_INVALID_REGNUM, 48, 48},
nullptr,
nullptr,
nullptr,
0},
{"p04",
"",
4,
0,
eEncodingInvalid,
eFormatInvalid,
{49, 49, LLDB_INVALID_REGNUM, 49, 49},
nullptr,
nullptr,
nullptr,
0},
{"p05",
"",
4,
0,
eEncodingInvalid,
eFormatInvalid,
{50, 50, LLDB_INVALID_REGNUM, 50, 50},
nullptr,
nullptr,
nullptr,
0},
{"p06",
"",
4,
0,
eEncodingInvalid,
eFormatInvalid,
{51, 51, LLDB_INVALID_REGNUM, 51, 51},
nullptr,
nullptr,
nullptr,
0},
{"p07",
"",
4,
0,
eEncodingInvalid,
eFormatInvalid,
{52, 52, LLDB_INVALID_REGNUM, 52, 52},
nullptr,
nullptr,
nullptr,
0},
{"p08",
"",
4,
0,
eEncodingInvalid,
eFormatInvalid,
{53, 53, LLDB_INVALID_REGNUM, 53, 53},
nullptr,
nullptr,
nullptr,
0},
{"p09",
"",
4,
0,
eEncodingInvalid,
eFormatInvalid,
{54, 54, LLDB_INVALID_REGNUM, 54, 54},
nullptr,
nullptr,
nullptr,
0},
{"p10",
"",
4,
0,
eEncodingInvalid,
eFormatInvalid,
{55, 55, LLDB_INVALID_REGNUM, 55, 55},
nullptr,
nullptr,
nullptr,
0},
{"p11",
"",
4,
0,
eEncodingInvalid,
eFormatInvalid,
{56, 56, LLDB_INVALID_REGNUM, 56, 56},
nullptr,
nullptr,
nullptr,
0},
{"p12",
"",
4,
0,
eEncodingInvalid,
eFormatInvalid,
{57, 57, LLDB_INVALID_REGNUM, 57, 57},
nullptr,
nullptr,
nullptr,
0},
{"p13",
"",
4,
0,
eEncodingInvalid,
eFormatInvalid,
{58, 58, LLDB_INVALID_REGNUM, 58, 58},
nullptr,
nullptr,
nullptr,
0},
{"p14",
"",
4,
0,
eEncodingInvalid,
eFormatInvalid,
{59, 59, LLDB_INVALID_REGNUM, 59, 59},
nullptr,
nullptr,
nullptr,
0},
{"p15",
"",
4,
0,
eEncodingInvalid,
eFormatInvalid,
{60, 60, LLDB_INVALID_REGNUM, 60, 60},
nullptr,
nullptr,
nullptr,
0},
{"p16",
"",
4,
0,
eEncodingInvalid,
eFormatInvalid,
{61, 61, LLDB_INVALID_REGNUM, 61, 61},
nullptr,
nullptr,
nullptr,
0},
{"p17",
"",
4,
0,
eEncodingInvalid,
eFormatInvalid,
{62, 62, LLDB_INVALID_REGNUM, 62, 62},
nullptr,
nullptr,
nullptr,
0},
{"p18",
"",
4,
0,
eEncodingInvalid,
eFormatInvalid,
{63, 63, LLDB_INVALID_REGNUM, 63, 63},
nullptr,
nullptr,
nullptr,
0},
// }
{"sgp0",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{64, 64, LLDB_INVALID_REGNUM, 64, 64},
nullptr,
nullptr,
nullptr,
0},
// PADDING {
{"p19",
"",
4,
0,
eEncodingInvalid,
eFormatInvalid,
{65, 65, LLDB_INVALID_REGNUM, 65, 65},
nullptr,
nullptr,
nullptr,
0},
// }
{"stid",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{66, 66, LLDB_INVALID_REGNUM, 66, 66},
nullptr,
nullptr,
nullptr,
0},
{"elr",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{67, 67, LLDB_INVALID_REGNUM, 67, 67},
nullptr,
nullptr,
nullptr,
0},
{"badva0",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{68, 68, LLDB_INVALID_REGNUM, 68, 68},
nullptr,
nullptr,
nullptr,
0},
{"badva1",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{69, 69, LLDB_INVALID_REGNUM, 69, 69},
nullptr,
nullptr,
nullptr,
0},
{"ssr",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{70, 70, LLDB_INVALID_REGNUM, 70, 70},
nullptr,
nullptr,
nullptr,
0},
{"ccr",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{71, 71, LLDB_INVALID_REGNUM, 71, 71},
nullptr,
nullptr,
nullptr,
0},
{"htid",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{72, 72, LLDB_INVALID_REGNUM, 72, 72},
nullptr,
nullptr,
nullptr,
0},
// PADDING {
{"p20",
"",
4,
0,
eEncodingInvalid,
eFormatInvalid,
{73, 73, LLDB_INVALID_REGNUM, 73, 73},
nullptr,
nullptr,
nullptr,
0},
// }
{"imask",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{74, 74, LLDB_INVALID_REGNUM, 74, 74},
nullptr,
nullptr,
nullptr,
0},
// PADDING {
{"p21",
"",
4,
0,
eEncodingInvalid,
eFormatInvalid,
{75, 75, LLDB_INVALID_REGNUM, 75, 75},
nullptr,
nullptr,
nullptr,
0},
{"p22",
"",
4,
0,
eEncodingInvalid,
eFormatInvalid,
{76, 76, LLDB_INVALID_REGNUM, 76, 76},
nullptr,
nullptr,
nullptr,
0},
{"p23",
"",
4,
0,
eEncodingInvalid,
eFormatInvalid,
{77, 77, LLDB_INVALID_REGNUM, 77, 77},
nullptr,
nullptr,
nullptr,
0},
{"p24",
"",
4,
0,
eEncodingInvalid,
eFormatInvalid,
{78, 78, LLDB_INVALID_REGNUM, 78, 78},
nullptr,
nullptr,
nullptr,
0},
{"p25",
"",
4,
0,
eEncodingInvalid,
eFormatInvalid,
{79, 79, LLDB_INVALID_REGNUM, 79, 79},
nullptr,
nullptr,
nullptr,
0},
// }
{"g0",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{80, 80, LLDB_INVALID_REGNUM, 80, 80},
nullptr,
nullptr,
nullptr,
0},
{"g1",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{81, 81, LLDB_INVALID_REGNUM, 81, 81},
nullptr,
nullptr,
nullptr,
0},
{"g2",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{82, 82, LLDB_INVALID_REGNUM, 82, 82},
nullptr,
nullptr,
nullptr,
0},
{"g3",
"",
4,
0,
eEncodingUint,
eFormatAddressInfo,
{83, 83, LLDB_INVALID_REGNUM, 83, 83},
nullptr,
nullptr,
nullptr,
0}};
static const uint32_t k_num_register_infos =
sizeof(g_register_infos) / sizeof(RegisterInfo);
const lldb_private::RegisterInfo *
ABISysV_hexagon::GetRegisterInfoArray(uint32_t &count) {
count = k_num_register_infos;
return g_register_infos;
}
/*
http://en.wikipedia.org/wiki/Red_zone_%28computing%29
In computing, a red zone is a fixed size area in memory beyond the stack
pointer that has not been
"allocated". This region of memory is not to be modified by
interrupt/exception/signal handlers.
This allows the space to be used for temporary data without the extra
overhead of modifying the
stack pointer. The x86-64 ABI mandates a 128 byte red zone.[1] The OpenRISC
toolchain assumes a
128 byte red zone though it is not documented.
*/
size_t ABISysV_hexagon::GetRedZoneSize() const { return 0; }
// Static Functions
ABISP
ABISysV_hexagon::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) {
if (arch.GetTriple().getArch() == llvm::Triple::hexagon) {
return ABISP(
new ABISysV_hexagon(std::move(process_sp), MakeMCRegisterInfo(arch)));
}
return ABISP();
}
bool ABISysV_hexagon::PrepareTrivialCall(Thread &thread, lldb::addr_t sp,
lldb::addr_t pc, lldb::addr_t ra,
llvm::ArrayRef<addr_t> args) const {
// we don't use the traditional trivial call specialized for jit
return false;
}
/*
// AD:
// . safeguard the current stack
// . how can we know that the called function will create its own frame
properly?
// . we could manually make a new stack first:
// 2. push RA
// 3. push FP
// 4. FP = SP
// 5. SP = SP ( since no locals in our temp frame )
// AD 6/05/2014
// . variable argument list parameters are not passed via registers, they are
passed on
// the stack. This presents us with a problem, since we need to know when
the valist
// starts. Currently I can find out if a function is varg, but not how many
// real parameters it takes. Thus I don't know when to start spilling the
vargs. For
// the time being, to progress, I will assume that it takes on real parameter
before
// the vargs list starts.
// AD 06/05/2014
// . how do we adhere to the stack alignment requirements
// AD 06/05/2014
// . handle 64bit values and their register / stack requirements
*/
#define HEX_ABI_DEBUG 0
bool ABISysV_hexagon::PrepareTrivialCall(
Thread &thread, lldb::addr_t sp, lldb::addr_t pc, lldb::addr_t ra,
llvm::Type &prototype, llvm::ArrayRef<ABI::CallArgument> args) const {
// default number of register passed arguments for varg functions
const int nVArgRegParams = 1;
Status error;
// grab the process so we have access to the memory for spilling
lldb::ProcessSP proc = thread.GetProcess();
// get the register context for modifying all of the registers
RegisterContext *reg_ctx = thread.GetRegisterContext().get();
if (!reg_ctx)
return false;
uint32_t pc_reg = reg_ctx->ConvertRegisterKindToRegisterNumber(
eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
if (pc_reg == LLDB_INVALID_REGNUM)
return false;
uint32_t ra_reg = reg_ctx->ConvertRegisterKindToRegisterNumber(
eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);
if (ra_reg == LLDB_INVALID_REGNUM)
return false;
uint32_t sp_reg = reg_ctx->ConvertRegisterKindToRegisterNumber(
eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
if (sp_reg == LLDB_INVALID_REGNUM)
return false;
// push host data onto target
for (size_t i = 0; i < args.size(); i++) {
const ABI::CallArgument &arg = args[i];
// skip over target values
if (arg.type == ABI::CallArgument::TargetValue)
continue;
// round up to 8 byte multiple
size_t argSize = (arg.size | 0x7) + 1;
// create space on the stack for this data
sp -= argSize;
// write this argument onto the stack of the host process
proc->WriteMemory(sp, arg.data_up.get(), arg.size, error);
if (error.Fail())
return false;
// update the argument with the target pointer
// XXX: This is a gross hack for getting around the const
*const_cast<lldb::addr_t *>(&arg.value) = sp;
}
#if HEX_ABI_DEBUG
// print the original stack pointer
printf("sp : %04" PRIx64 " \n", sp);
#endif
// make sure number of parameters matches prototype
assert(prototype.getFunctionNumParams() == args.size());
// check if this is a variable argument function
bool isVArg = prototype.isFunctionVarArg();
// number of arguments passed by register
int nRegArgs = nVArgRegParams;
if (!isVArg) {
// number of arguments is limited by [R0 : R5] space
nRegArgs = args.size();
if (nRegArgs > 6)
nRegArgs = 6;
}
// pass arguments that are passed via registers
for (int i = 0; i < nRegArgs; i++) {
// get the parameter as a u32
uint32_t param = (uint32_t)args[i].value;
// write argument into register
if (!reg_ctx->WriteRegisterFromUnsigned(i, param))
return false;
}
// number of arguments to spill onto stack
int nSpillArgs = args.size() - nRegArgs;
// make space on the stack for arguments
sp -= 4 * nSpillArgs;
// align stack on an 8 byte boundary
if (sp & 7)
sp -= 4;
// arguments that are passed on the stack
for (size_t i = nRegArgs, offs = 0; i < args.size(); i++) {
// get the parameter as a u32
uint32_t param = (uint32_t)args[i].value;
// write argument to stack
proc->WriteMemory(sp + offs, (void *)&param, sizeof(param), error);
if (!error.Success())
return false;
//
offs += 4;
}
// update registers with current function call state
reg_ctx->WriteRegisterFromUnsigned(pc_reg, pc);
reg_ctx->WriteRegisterFromUnsigned(ra_reg, ra);
reg_ctx->WriteRegisterFromUnsigned(sp_reg, sp);
#if HEX_ABI_DEBUG
// quick and dirty stack dumper for debugging
for (int i = -8; i < 8; i++) {
uint32_t data = 0;
lldb::addr_t addr = sp + i * 4;
proc->ReadMemory(addr, (void *)&data, sizeof(data), error);
printf("\n0x%04" PRIx64 " 0x%08x ", addr, data);
if (i == 0)
printf("<<-- sp");
}
printf("\n");
#endif
return true;
}
bool ABISysV_hexagon::GetArgumentValues(Thread &thread,
ValueList &values) const {
return false;
}
Status
ABISysV_hexagon::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
lldb::ValueObjectSP &new_value_sp) {
Status error;
return error;
}
ValueObjectSP ABISysV_hexagon::GetReturnValueObjectSimple(
Thread &thread, CompilerType &return_compiler_type) const {
ValueObjectSP return_valobj_sp;
return return_valobj_sp;
}
ValueObjectSP ABISysV_hexagon::GetReturnValueObjectImpl(
Thread &thread, CompilerType &return_compiler_type) const {
ValueObjectSP return_valobj_sp;
return return_valobj_sp;
}
// called when we are on the first instruction of a new function for hexagon
// the return address is in RA (R31)
bool ABISysV_hexagon::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) {
unwind_plan.Clear();
unwind_plan.SetRegisterKind(eRegisterKindGeneric);
unwind_plan.SetReturnAddressRegister(LLDB_REGNUM_GENERIC_RA);
UnwindPlan::RowSP row(new UnwindPlan::Row);
// Our Call Frame Address is the stack pointer value
row->GetCFAValue().SetIsRegisterPlusOffset(LLDB_REGNUM_GENERIC_SP, 4);
row->SetOffset(0);
// The previous PC is in the LR
row->SetRegisterLocationToRegister(LLDB_REGNUM_GENERIC_PC,
LLDB_REGNUM_GENERIC_RA, true);
unwind_plan.AppendRow(row);
unwind_plan.SetSourceName("hexagon at-func-entry default");
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
return true;
}
bool ABISysV_hexagon::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
unwind_plan.Clear();
unwind_plan.SetRegisterKind(eRegisterKindGeneric);
uint32_t fp_reg_num = LLDB_REGNUM_GENERIC_FP;
uint32_t sp_reg_num = LLDB_REGNUM_GENERIC_SP;
uint32_t pc_reg_num = LLDB_REGNUM_GENERIC_PC;
UnwindPlan::RowSP row(new UnwindPlan::Row);
row->SetUnspecifiedRegistersAreUndefined(true);
row->GetCFAValue().SetIsRegisterPlusOffset(LLDB_REGNUM_GENERIC_FP, 8);
row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, -8, true);
row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, -4, true);
row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
unwind_plan.AppendRow(row);
unwind_plan.SetSourceName("hexagon default unwind plan");
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
return true;
}
/*
Register Usage Saved By
R0 - R5 parameters(a) -
R6 - R15 Scratch(b) Caller
R16 - R27 Scratch Callee
R28 Scratch(b) Caller
R29 - R31 Stack Frames Callee(c)
P3:0 Processor State Caller
a = the caller can change parameter values
b = R14 - R15 and R28 are used by the procedure linkage table
c = R29 - R31 are saved and restored by allocframe() and deallocframe()
*/
bool ABISysV_hexagon::RegisterIsVolatile(const RegisterInfo *reg_info) {
return !RegisterIsCalleeSaved(reg_info);
}
bool ABISysV_hexagon::RegisterIsCalleeSaved(const RegisterInfo *reg_info) {
int reg = ((reg_info->byte_offset) / 4);
bool save = (reg >= 16) && (reg <= 27);
save |= (reg >= 29) && (reg <= 32);
return save;
}
void ABISysV_hexagon::Initialize() {
PluginManager::RegisterPlugin(GetPluginNameStatic(),
"System V ABI for hexagon targets",
CreateInstance);
}
void ABISysV_hexagon::Terminate() {
PluginManager::UnregisterPlugin(CreateInstance);
}
lldb_private::ConstString ABISysV_hexagon::GetPluginNameStatic() {
static ConstString g_name("sysv-hexagon");
return g_name;
}
// PluginInterface protocol
lldb_private::ConstString ABISysV_hexagon::GetPluginName() {
return GetPluginNameStatic();
}
uint32_t ABISysV_hexagon::GetPluginVersion() { return 1; }
// get value object specialized to work with llvm IR types
lldb::ValueObjectSP
ABISysV_hexagon::GetReturnValueObjectImpl(lldb_private::Thread &thread,
llvm::Type &retType) const {
Value value;
ValueObjectSP vObjSP;
// get the current register context
RegisterContext *reg_ctx = thread.GetRegisterContext().get();
if (!reg_ctx)
return vObjSP;
// for now just pop R0 to find the return value
const lldb_private::RegisterInfo *r0_info =
reg_ctx->GetRegisterInfoAtIndex(0);
if (r0_info == nullptr)
return vObjSP;
// void return type
if (retType.isVoidTy()) {
value.GetScalar() = 0;
}
// integer / pointer return type
else if (retType.isIntegerTy() || retType.isPointerTy()) {
// read r0 register value
lldb_private::RegisterValue r0_value;
if (!reg_ctx->ReadRegister(r0_info, r0_value))
return vObjSP;
// push r0 into value
uint32_t r0_u32 = r0_value.GetAsUInt32();
// account for integer size
if (retType.isIntegerTy() && retType.isSized()) {
uint64_t size = retType.getScalarSizeInBits();
uint64_t mask = (1ull << size) - 1;
// mask out higher order bits then the type we expect
r0_u32 &= mask;
}
value.GetScalar() = r0_u32;
}
// unsupported return type
else
return vObjSP;
// pack the value into a ValueObjectSP
vObjSP = ValueObjectConstResult::Create(thread.GetStackFrameAtIndex(0).get(),
value, ConstString(""));
return vObjSP;
}