return_value getReturnValue( const llvm::Type &type, const llvm::GenericValue &_value ) { switch ( type.getTypeID() ) { case llvm::Type::VoidTyID: return return_value(); case llvm::Type::IntegerTyID: case llvm::Type::FloatTyID: case llvm::Type::DoubleTyID: case llvm::Type::PointerTyID: default: throw InvalidArgument(); }; }
void VisitTFunction(const TFunction& type) { vector<llvm::Type*> llvmParams; for(auto& f : static_cast<TList&>(*type.parameter).fields) { Visit(f.type.get()); llvmParams.push_back(result); } Visit(type.result.get()); auto llvmResult = result; result = llvm::FunctionType::get(llvmResult, llvmParams, false); result = result->getPointerTo(); }
// 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; }
DataType llvm_type_to_nts_type ( const llvm::Type & t ) { if ( t.isIntegerTy() ) { auto & it = llvm::cast<llvm::IntegerType> ( t ); return DataType ( ScalarType::BitVector ( it.getBitWidth() ) ); } /*else if ( t.isPointerTy() ) { return nts::DataType::BitVector ( 64 ); // 64 bit pointers } */ else { throw std::logic_error ( "Only integer types are supported" ); } }
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; 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 ( 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.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 : %04lx \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 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*)¶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%04lx 0x%08x ", addr, data ); if ( i == 0 ) printf( "<<-- sp" ); } printf( "\n" ); #endif return true; }
void Stream::writeType(std::ostream &OS, const llvm::Type &Ty) { llvm::raw_os_ostream raw(OS); Ty.print(raw); }