diff --git a/lldb/include/lldb/Target/ABI.h b/lldb/include/lldb/Target/ABI.h index 977d10af5f39..8809c0047fa0 100644 --- a/lldb/include/lldb/Target/ABI.h +++ b/lldb/include/lldb/Target/ABI.h @@ -20,24 +20,58 @@ #include "llvm/ADT/ArrayRef.h" +// forward define the llvm::Type class +namespace llvm { class Type; } + namespace lldb_private { class ABI : public PluginInterface { public: + + struct CallArgument + { + enum eType + { + HostPointer = 0, /* pointer to host data */ + TargetValue , /* value is on the target or literal */ + }; + eType type; /* value of eType */ + size_t size; /* size in bytes of this argument */ + union { + lldb::addr_t value; /* literal value */ + uint8_t *data; /* host data pointer */ + }; + }; + virtual ~ABI(); virtual size_t GetRedZoneSize () const = 0; - + virtual bool - PrepareTrivialCall (Thread &thread, - lldb::addr_t sp, - lldb::addr_t functionAddress, - lldb::addr_t returnAddress, - llvm::ArrayRef args) const = 0; + PrepareTrivialCall ( lldb_private::Thread &thread, + lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t returnAddress, + llvm::ArrayRef args) const = 0; + + // Prepare trivial call used from ThreadPlanFunctionCallGDB + // AD: + // . Because i don't want to change other ABI's this is not declared pure virtual. + // The dummy implementation will simply fail. Only HexagonABI will currently + // use this method. + // . Two PrepareTrivialCall's is not good design so perhaps this should be combined. + // + virtual bool + PrepareTrivialCall ( lldb_private::Thread &thread, + lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t returnAddress, + llvm::Type &prototype, + llvm::ArrayRef args) const; virtual bool GetArgumentValues (Thread &thread, @@ -48,6 +82,12 @@ public: ClangASTType &type, bool persistent = true) const; + // specialized to work with llvm IR types + lldb::ValueObjectSP + GetReturnValueObject (Thread &thread, + llvm::Type &type, + bool persistent = true) const; + // Set the Return value object in the current frame as though a function with virtual Error SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value) = 0; @@ -56,8 +96,12 @@ protected: // This is the method the ABI will call to actually calculate the return value. // Don't put it in a persistent value object, that will be done by the ABI::GetReturnValueObject. virtual lldb::ValueObjectSP - GetReturnValueObjectImpl (Thread &thread, - ClangASTType &type) const = 0; + GetReturnValueObjectImpl (Thread &thread, ClangASTType &ast_type) const = 0; + + // specialized to work with llvm IR types + virtual lldb::ValueObjectSP + GetReturnValueObjectImpl( Thread &thread, llvm::Type &ir_type ) const; + public: virtual bool CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan) = 0; @@ -108,7 +152,6 @@ public: virtual bool FunctionCallsChangeCFA () = 0; - bool GetRegisterInfoByName (const ConstString &name, RegisterInfo &info); diff --git a/lldb/source/Plugins/ABI/CMakeLists.txt b/lldb/source/Plugins/ABI/CMakeLists.txt index 4ce15a11292a..74f164c31306 100644 --- a/lldb/source/Plugins/ABI/CMakeLists.txt +++ b/lldb/source/Plugins/ABI/CMakeLists.txt @@ -1,3 +1,4 @@ +add_subdirectory(SysV-hexagon) add_subdirectory(SysV-x86_64) add_subdirectory(MacOSX-i386) add_subdirectory(MacOSX-arm) diff --git a/lldb/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp b/lldb/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp new file mode 100644 index 000000000000..6bd68500d7a4 --- /dev/null +++ b/lldb/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.cpp @@ -0,0 +1,568 @@ +//===-- ABISysV_hexagon.cpp --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ABISysV_hexagon.h" + +#include "lldb/Core/ConstString.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/Error.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Core/Value.h" +#include "lldb/Core/ValueObjectConstResult.h" +#include "lldb/Core/ValueObjectRegister.h" +#include "lldb/Core/ValueObjectMemory.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/UnwindPlan.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Thread.h" + +#include "llvm/ADT/Triple.h" + +#include "llvm/IR/Type.h" + +using namespace lldb; +using namespace lldb_private; + +static RegisterInfo g_register_infos[] = +{ + // hexagon-core.xml + { "r00" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 0, 0, LLDB_INVALID_REGNUM, 0, 0 }, NULL, NULL }, + { "r01" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 1, 1, LLDB_INVALID_REGNUM, 1, 1 }, NULL, NULL }, + { "r02" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 2, 2, LLDB_INVALID_REGNUM, 2, 2 }, NULL, NULL }, + { "r03" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 3, 3, LLDB_INVALID_REGNUM, 3, 3 }, NULL, NULL }, + { "r04" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 4, 4, LLDB_INVALID_REGNUM, 4, 4 }, NULL, NULL }, + { "r05" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 5, 5, LLDB_INVALID_REGNUM, 5, 5 }, NULL, NULL }, + { "r06" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 6, 6, LLDB_INVALID_REGNUM, 6, 6 }, NULL, NULL }, + { "r07" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 7, 7, LLDB_INVALID_REGNUM, 7, 7 }, NULL, NULL }, + { "r08" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 8, 8, LLDB_INVALID_REGNUM, 8, 8 }, NULL, NULL }, + { "r09" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 9, 9, LLDB_INVALID_REGNUM, 9, 9 }, NULL, NULL }, + { "r10" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 10, 10, LLDB_INVALID_REGNUM, 10, 10 }, NULL, NULL }, + { "r11" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 11, 11, LLDB_INVALID_REGNUM, 11, 11 }, NULL, NULL }, + { "r12" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 12, 12, LLDB_INVALID_REGNUM, 12, 12 }, NULL, NULL }, + { "r13" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 13, 13, LLDB_INVALID_REGNUM, 13, 13 }, NULL, NULL }, + { "r14" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 14, 14, LLDB_INVALID_REGNUM, 14, 14 }, NULL, NULL }, + { "r15" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 15, 15, LLDB_INVALID_REGNUM, 15, 15 }, NULL, NULL }, + { "r16" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 16, 16, LLDB_INVALID_REGNUM, 16, 16 }, NULL, NULL }, + { "r17" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 17, 17, LLDB_INVALID_REGNUM, 17, 17 }, NULL, NULL }, + { "r18" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 18, 18, LLDB_INVALID_REGNUM, 18, 18 }, NULL, NULL }, + { "r19" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 19, 19, LLDB_INVALID_REGNUM, 19, 19 }, NULL, NULL }, + { "r20" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 20, 20, LLDB_INVALID_REGNUM, 20, 20 }, NULL, NULL }, + { "r21" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 21, 21, LLDB_INVALID_REGNUM, 21, 21 }, NULL, NULL }, + { "r22" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 22, 22, LLDB_INVALID_REGNUM, 22, 22 }, NULL, NULL }, + { "r23" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 23, 23, LLDB_INVALID_REGNUM, 23, 23 }, NULL, NULL }, + { "r24" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 24, 24, LLDB_INVALID_REGNUM, 24, 24 }, NULL, NULL }, + { "r25" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 25, 25, LLDB_INVALID_REGNUM, 25, 25 }, NULL, NULL }, + { "r26" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 26, 26, LLDB_INVALID_REGNUM, 26, 26 }, NULL, NULL }, + { "r27" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 27, 27, LLDB_INVALID_REGNUM, 27, 27 }, NULL, NULL }, + { "r28" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 28, 28, LLDB_INVALID_REGNUM, 28, 28 }, NULL, NULL }, + { "sp" ,"r29", 4, 0, eEncodingUint, eFormatAddressInfo, { 29, 29, LLDB_REGNUM_GENERIC_SP, 29, 29 }, NULL, NULL }, + { "fp" ,"r30", 4, 0, eEncodingUint, eFormatAddressInfo, { 30, 30, LLDB_REGNUM_GENERIC_FP, 30, 30 }, NULL, NULL }, + { "lr" ,"r31", 4, 0, eEncodingUint, eFormatAddressInfo, { 31, 31, LLDB_REGNUM_GENERIC_RA, 31, 31 }, NULL, NULL }, + { "sa0" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 32, 32, LLDB_INVALID_REGNUM, 32, 32 }, NULL, NULL }, + { "lc0" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 33, 33, LLDB_INVALID_REGNUM, 33, 33 }, NULL, NULL }, + { "sa1" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 34, 34, LLDB_INVALID_REGNUM, 34, 34 }, NULL, NULL }, + { "lc1" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 35, 35, LLDB_INVALID_REGNUM, 35, 35 }, NULL, NULL }, + // --> hexagon-v4/5/55/56-sim.xml + { "p3_0" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 36, 36, LLDB_INVALID_REGNUM, 36, 36 }, NULL, NULL }, +// PADDING { + { "p00" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 37, 37, LLDB_INVALID_REGNUM, 37, 37 }, NULL, NULL }, +// } + { "m0" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 38, 38, LLDB_INVALID_REGNUM, 38, 38 }, NULL, NULL }, + { "m1" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 39, 39, LLDB_INVALID_REGNUM, 39, 39 }, NULL, NULL }, + { "usr" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 40, 40, LLDB_INVALID_REGNUM, 40, 40 }, NULL, NULL }, + { "pc" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 41, 41, LLDB_REGNUM_GENERIC_PC, 41, 41 }, NULL, NULL }, + { "ugp" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 42, 42, LLDB_INVALID_REGNUM, 42, 42 }, NULL, NULL }, + { "gp" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 43, 43, LLDB_INVALID_REGNUM, 43, 43 }, NULL, NULL }, + { "cs0" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 44, 44, LLDB_INVALID_REGNUM, 44, 44 }, NULL, NULL }, + { "cs1" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 45, 45, LLDB_INVALID_REGNUM, 45, 45 }, NULL, NULL }, +// PADDING { + { "p01" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 46, 46, LLDB_INVALID_REGNUM, 46, 46 }, NULL, NULL }, + { "p02" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 47, 47, LLDB_INVALID_REGNUM, 47, 47 }, NULL, NULL }, + { "p03" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 48, 48, LLDB_INVALID_REGNUM, 48, 48 }, NULL, NULL }, + { "p04" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 49, 49, LLDB_INVALID_REGNUM, 49, 49 }, NULL, NULL }, + { "p05" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 50, 50, LLDB_INVALID_REGNUM, 50, 50 }, NULL, NULL }, + { "p06" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 51, 51, LLDB_INVALID_REGNUM, 51, 51 }, NULL, NULL }, + { "p07" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 52, 52, LLDB_INVALID_REGNUM, 52, 52 }, NULL, NULL }, + { "p08" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 53, 53, LLDB_INVALID_REGNUM, 53, 53 }, NULL, NULL }, + { "p09" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 54, 54, LLDB_INVALID_REGNUM, 54, 54 }, NULL, NULL }, + { "p10" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 55, 55, LLDB_INVALID_REGNUM, 55, 55 }, NULL, NULL }, + { "p11" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 56, 56, LLDB_INVALID_REGNUM, 56, 56 }, NULL, NULL }, + { "p12" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 57, 57, LLDB_INVALID_REGNUM, 57, 57 }, NULL, NULL }, + { "p13" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 58, 58, LLDB_INVALID_REGNUM, 58, 58 }, NULL, NULL }, + { "p14" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 59, 59, LLDB_INVALID_REGNUM, 59, 59 }, NULL, NULL }, + { "p15" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 60, 60, LLDB_INVALID_REGNUM, 60, 60 }, NULL, NULL }, + { "p16" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 61, 61, LLDB_INVALID_REGNUM, 61, 61 }, NULL, NULL }, + { "p17" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 62, 62, LLDB_INVALID_REGNUM, 62, 62 }, NULL, NULL }, + { "p18" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 63, 63, LLDB_INVALID_REGNUM, 63, 63 }, NULL, NULL }, +// } + { "sgp0" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 64, 64, LLDB_INVALID_REGNUM, 64, 64 }, NULL, NULL }, +// PADDING { + { "p19" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 65, 65, LLDB_INVALID_REGNUM, 65, 65 }, NULL, NULL }, +// } + { "stid" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 66, 66, LLDB_INVALID_REGNUM, 66, 66 }, NULL, NULL }, + { "elr" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 67, 67, LLDB_INVALID_REGNUM, 67, 67 }, NULL, NULL }, + { "badva0", "", 4, 0, eEncodingUint, eFormatAddressInfo, { 68, 68, LLDB_INVALID_REGNUM, 68, 68 }, NULL, NULL }, + { "badva1", "", 4, 0, eEncodingUint, eFormatAddressInfo, { 69, 69, LLDB_INVALID_REGNUM, 69, 69 }, NULL, NULL }, + { "ssr" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 70, 70, LLDB_INVALID_REGNUM, 70, 70 }, NULL, NULL }, + { "ccr" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 71, 71, LLDB_INVALID_REGNUM, 71, 71 }, NULL, NULL }, + { "htid" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 72, 72, LLDB_INVALID_REGNUM, 72, 72 }, NULL, NULL }, +// PADDING { + { "p20" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 73, 73, LLDB_INVALID_REGNUM, 73, 73 }, NULL, NULL }, +// } + { "imask" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 74, 74, LLDB_INVALID_REGNUM, 74, 74 }, NULL, NULL }, +// PADDING { + { "p21" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 75, 75, LLDB_INVALID_REGNUM, 75, 75 }, NULL, NULL }, + { "p22" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 76, 76, LLDB_INVALID_REGNUM, 76, 76 }, NULL, NULL }, + { "p23" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 77, 77, LLDB_INVALID_REGNUM, 77, 77 }, NULL, NULL }, + { "p24" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 78, 78, LLDB_INVALID_REGNUM, 78, 78 }, NULL, NULL }, + { "p25" , "", 4, 0, eEncodingInvalid, eFormatInvalid, { 79, 79, LLDB_INVALID_REGNUM, 79, 79 }, NULL, NULL }, + // } + { "g0" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 80, 80, LLDB_INVALID_REGNUM, 80, 80 }, NULL, NULL }, + { "g1" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 81, 81, LLDB_INVALID_REGNUM, 81, 81 }, NULL, NULL }, + { "g2" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 82, 82, LLDB_INVALID_REGNUM, 82, 82 }, NULL, NULL }, + { "g3" , "", 4, 0, eEncodingUint, eFormatAddressInfo, { 83, 83, LLDB_INVALID_REGNUM, 83, 83 }, NULL, NULL } +}; + +static const uint32_t k_num_register_infos = sizeof(g_register_infos)/sizeof(RegisterInfo); +static bool g_register_info_names_constified = false; + +const lldb_private::RegisterInfo * +ABISysV_hexagon::GetRegisterInfoArray ( uint32_t &count ) +{ + // Make the C-string names and alt_names for the register infos into const + // C-string values by having the ConstString unique the names in the global + // constant C-string pool. + if (!g_register_info_names_constified) + { + g_register_info_names_constified = true; + for (uint32_t i=0; i 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 1 +bool +ABISysV_hexagon::PrepareTrivialCall ( Thread &thread, + lldb::addr_t sp , + lldb::addr_t pc , + lldb::addr_t ra , + llvm::Type &prototype, + llvm::ArrayRef args) const +{ + // default number of register passed arguments for varg functions + const int nVArgRegParams = 1; + Error error; + + // grab the process so we have access to the memory for spilling + lldb::ProcessSP proc = thread.GetProcess( ); + + // push host data onto target + for ( int 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.get( )->WriteMemory( sp, arg.data, 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 + *((size_t*)(&arg.value)) = sp; + } + + +#if HEX_ABI_DEBUG + // print the original stack pointer + printf( "sp : %04x \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(); + + // get the register context for modifying all of the registers + RegisterContext *reg_ctx = thread.GetRegisterContext().get(); + if (!reg_ctx) + return false; + + // 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 this parameter type + llvm::Type *argType = prototype.getFunctionParamType( 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 ( int 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*)¶m, sizeof( param ), error ); + if ( !error.Success( ) ) + return false; + // + offs += 4; + } + + // update registers with current function call state + reg_ctx->WriteRegisterFromUnsigned ( 41, pc ); + reg_ctx->WriteRegisterFromUnsigned ( 31, ra ); + reg_ctx->WriteRegisterFromUnsigned ( 29, sp ); +// reg_ctx->WriteRegisterFromUnsigned ( FP ??? ); + +#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%04x 0x%08x ", addr, data ); + if ( i == 0 ) printf( "<<-- sp" ); + } + printf( "\n" ); +#endif + + return true; +} + +static bool +ReadIntegerArgument ( Scalar &scalar, + unsigned int bit_width, + bool is_signed, + Thread &thread, + uint32_t *argument_register_ids, + unsigned int ¤t_argument_register, + addr_t ¤t_stack_argument) +{ + return false; +} + +bool +ABISysV_hexagon::GetArgumentValues ( Thread &thread, ValueList &values ) const +{ + return false; +} + +Error +ABISysV_hexagon::SetReturnValueObject ( lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value_sp ) +{ + Error error; + return error; +} + +ValueObjectSP +ABISysV_hexagon::GetReturnValueObjectSimple ( Thread &thread, ClangASTType &return_clang_type ) const +{ + ValueObjectSP return_valobj_sp; + return return_valobj_sp; +} + +ValueObjectSP +ABISysV_hexagon::GetReturnValueObjectImpl ( Thread &thread, ClangASTType &return_clang_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->SetCFARegister(LLDB_REGNUM_GENERIC_SP); + row->SetCFAOffset(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->SetCFARegister(LLDB_REGNUM_GENERIC_FP); + row->SetCFAOffset(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); + 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( void ) +{ + PluginManager::RegisterPlugin + ( + GetPluginNameStatic(), + "System V ABI for hexagon targets", + CreateInstance + ); +} + +void +ABISysV_hexagon::Terminate( void ) +{ + 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( void ) +{ + return GetPluginNameStatic(); +} + +uint32_t +ABISysV_hexagon::GetPluginVersion( void ) +{ + 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; +} \ No newline at end of file diff --git a/lldb/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h b/lldb/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h new file mode 100644 index 000000000000..989c4a16710a --- /dev/null +++ b/lldb/source/Plugins/ABI/SysV-hexagon/ABISysV_hexagon.h @@ -0,0 +1,148 @@ +//===-- ABISysV_hexagon.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ABISysV_hexagon_h_ +#define liblldb_ABISysV_hexagon_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private.h" +#include "lldb/Target/ABI.h" + +class ABISysV_hexagon : + public lldb_private::ABI +{ +public: + + ~ABISysV_hexagon( void ) + { + } + + virtual size_t + GetRedZoneSize ( void ) const; + + virtual bool + PrepareTrivialCall ( lldb_private::Thread &thread, + lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t returnAddress, + llvm::ArrayRef args ) const; + + // special thread plan for GDB style non-jit function calls + virtual bool + PrepareTrivialCall ( lldb_private::Thread &thread, + lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t returnAddress, + llvm::Type &prototype, + llvm::ArrayRef args ) const; + + virtual bool + GetArgumentValues ( lldb_private::Thread &thread, + lldb_private::ValueList &values ) const; + + virtual lldb_private::Error + SetReturnValueObject ( lldb::StackFrameSP &frame_sp, + lldb::ValueObjectSP &new_value ); + +protected: + lldb::ValueObjectSP + GetReturnValueObjectSimple ( lldb_private::Thread &thread, + lldb_private::ClangASTType &ast_type ) const; + +public: + virtual lldb::ValueObjectSP + GetReturnValueObjectImpl ( lldb_private::Thread &thread, + lldb_private::ClangASTType &type ) const; + + // specialized to work with llvm IR types + virtual lldb::ValueObjectSP + GetReturnValueObjectImpl ( lldb_private::Thread &thread, llvm::Type &type ) const; + + virtual bool + CreateFunctionEntryUnwindPlan ( lldb_private::UnwindPlan &unwind_plan ); + + virtual bool + CreateDefaultUnwindPlan ( lldb_private::UnwindPlan &unwind_plan ); + + virtual bool + RegisterIsVolatile ( const lldb_private::RegisterInfo *reg_info ); + + virtual bool + StackUsesFrames ( void ) + { + return true; + } + + virtual bool + CallFrameAddressIsValid ( lldb::addr_t cfa ) + { + // Make sure the stack call frame addresses are 8 byte aligned + if (cfa & 0x07) + return false; // Not 8 byte aligned + if (cfa == 0) + return false; // Zero is not a valid stack address + return true; + } + + virtual bool + CodeAddressIsValid ( lldb::addr_t pc ) + { + // We have a 64 bit address space, so anything is valid as opcodes + // aren't fixed width... + return true; + } + + virtual bool + FunctionCallsChangeCFA ( void ) + { + return true; + } + + virtual const lldb_private::RegisterInfo * + GetRegisterInfoArray ( uint32_t &count ); + + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void + Initialize ( void ); + + static void + Terminate ( void ); + + static lldb::ABISP + CreateInstance ( const lldb_private::ArchSpec &arch ); + + static lldb_private::ConstString + GetPluginNameStatic ( void ); + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + virtual lldb_private::ConstString + GetPluginName ( void ); + + virtual uint32_t + GetPluginVersion ( void ); + +protected: + void + CreateRegisterMapIfNeeded ( void ); + + bool + RegisterIsCalleeSaved (const lldb_private::RegisterInfo *reg_info); + +private: + ABISysV_hexagon ( void ) : lldb_private::ABI() { } // Call CreateInstance instead. +}; + +#endif // liblldb_ABISysV_hexagon_h_ diff --git a/lldb/source/Plugins/ABI/SysV-hexagon/CMakeLists.txt b/lldb/source/Plugins/ABI/SysV-hexagon/CMakeLists.txt new file mode 100644 index 000000000000..c3f513224ef8 --- /dev/null +++ b/lldb/source/Plugins/ABI/SysV-hexagon/CMakeLists.txt @@ -0,0 +1,5 @@ +set(LLVM_NO_RTTI 1) + +add_lldb_library(lldbPluginABISysV_hexagon + ABISysV_hexagon.cpp + ) diff --git a/lldb/source/Plugins/ABI/SysV-hexagon/Makefile b/lldb/source/Plugins/ABI/SysV-hexagon/Makefile new file mode 100644 index 000000000000..23733c7e551e --- /dev/null +++ b/lldb/source/Plugins/ABI/SysV-hexagon/Makefile @@ -0,0 +1,14 @@ +##===- source/Plugins/ABI/SysV-hexagon/Makefile -------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LLDB_LEVEL := ../../../.. +LIBRARYNAME := lldbPluginABISysV_hexagon +BUILD_ARCHIVE = 1 + +include $(LLDB_LEVEL)/Makefile diff --git a/lldb/source/Target/ABI.cpp b/lldb/source/Target/ABI.cpp index 06215221d961..e02f360680fb 100644 --- a/lldb/source/Target/ABI.cpp +++ b/lldb/source/Target/ABI.cpp @@ -51,7 +51,6 @@ ABI::~ABI() { } - bool ABI::GetRegisterInfoByName (const ConstString &name, RegisterInfo &info) { @@ -172,4 +171,37 @@ ABI::GetReturnValueObject (Thread &thread, return return_valobj_sp; } +ValueObjectSP +ABI::GetReturnValueObject(Thread &thread, llvm::Type &ast_type, bool persistent) const +{ + ValueObjectSP return_valobj_sp; + return_valobj_sp = GetReturnValueObjectImpl( thread, ast_type ); + return return_valobj_sp; +} +// specialized to work with llvm IR types +// +// for now we will specify a default implementation so that we don't need to +// modify other ABIs +lldb::ValueObjectSP +ABI::GetReturnValueObjectImpl( Thread &thread, llvm::Type &ir_type ) const +{ + ValueObjectSP return_valobj_sp; + + /* this is a dummy and will only be called if an ABI does not override this */ + + return return_valobj_sp; +} + +bool +ABI::PrepareTrivialCall (Thread &thread, + lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t returnAddress, + llvm::Type &returntype, + llvm::ArrayRef args) const +{ + // dummy prepare trivial call + assert( !"Should never get here!" ); + return false; +}