Path: blob/main/contrib/llvm-project/lldb/source/Plugins/ABI/Mips/ABISysV_mips64.cpp
39645 views
//===-- ABISysV_mips64.cpp ------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "ABISysV_mips64.h"910#include "llvm/ADT/STLExtras.h"11#include "llvm/TargetParser/Triple.h"1213#include "lldb/Core/Module.h"14#include "lldb/Core/PluginManager.h"15#include "lldb/Core/Value.h"16#include "lldb/Core/ValueObjectConstResult.h"17#include "lldb/Core/ValueObjectMemory.h"18#include "lldb/Core/ValueObjectRegister.h"19#include "lldb/Symbol/UnwindPlan.h"20#include "lldb/Target/Process.h"21#include "lldb/Target/RegisterContext.h"22#include "lldb/Target/StackFrame.h"23#include "lldb/Target/Target.h"24#include "lldb/Target/Thread.h"25#include "lldb/Utility/ConstString.h"26#include "lldb/Utility/DataExtractor.h"27#include "lldb/Utility/LLDBLog.h"28#include "lldb/Utility/Log.h"29#include "lldb/Utility/RegisterValue.h"30#include "lldb/Utility/Status.h"31#include <optional>3233using namespace lldb;34using namespace lldb_private;3536LLDB_PLUGIN_DEFINE(ABISysV_mips64)3738enum dwarf_regnums {39dwarf_r0 = 0,40dwarf_r1,41dwarf_r2,42dwarf_r3,43dwarf_r4,44dwarf_r5,45dwarf_r6,46dwarf_r7,47dwarf_r8,48dwarf_r9,49dwarf_r10,50dwarf_r11,51dwarf_r12,52dwarf_r13,53dwarf_r14,54dwarf_r15,55dwarf_r16,56dwarf_r17,57dwarf_r18,58dwarf_r19,59dwarf_r20,60dwarf_r21,61dwarf_r22,62dwarf_r23,63dwarf_r24,64dwarf_r25,65dwarf_r26,66dwarf_r27,67dwarf_r28,68dwarf_r29,69dwarf_r30,70dwarf_r31,71dwarf_sr,72dwarf_lo,73dwarf_hi,74dwarf_bad,75dwarf_cause,76dwarf_pc77};7879static const RegisterInfo g_register_infos_mips64[] = {80// NAME ALT SZ OFF ENCODING FORMAT EH_FRAME81// DWARF GENERIC PROCESS PLUGIN82// LLDB NATIVE83// ======== ====== == === ============= ========== =============84// ================= ==================== =================85// ====================86{"r0",87"zero",888,890,90eEncodingUint,91eFormatHex,92{dwarf_r0, dwarf_r0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,93LLDB_INVALID_REGNUM},94nullptr,95nullptr,96nullptr,97},98{"r1",99"AT",1008,1010,102eEncodingUint,103eFormatHex,104{dwarf_r1, dwarf_r1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,105LLDB_INVALID_REGNUM},106nullptr,107nullptr,108nullptr,109110},111{"r2",112"v0",1138,1140,115eEncodingUint,116eFormatHex,117{dwarf_r2, dwarf_r2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,118LLDB_INVALID_REGNUM},119nullptr,120nullptr,121nullptr,122},123{"r3",124"v1",1258,1260,127eEncodingUint,128eFormatHex,129{dwarf_r3, dwarf_r3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,130LLDB_INVALID_REGNUM},131nullptr,132nullptr,133nullptr,134},135{"r4",136nullptr,1378,1380,139eEncodingUint,140eFormatHex,141{dwarf_r4, dwarf_r4, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM,142LLDB_INVALID_REGNUM},143nullptr,144nullptr,145nullptr,146},147{"r5",148nullptr,1498,1500,151eEncodingUint,152eFormatHex,153{dwarf_r5, dwarf_r5, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM,154LLDB_INVALID_REGNUM},155nullptr,156nullptr,157nullptr,158},159{"r6",160nullptr,1618,1620,163eEncodingUint,164eFormatHex,165{dwarf_r6, dwarf_r6, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM,166LLDB_INVALID_REGNUM},167nullptr,168nullptr,169nullptr,170},171{"r7",172nullptr,1738,1740,175eEncodingUint,176eFormatHex,177{dwarf_r7, dwarf_r7, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM,178LLDB_INVALID_REGNUM},179nullptr,180nullptr,181nullptr,182},183{"r8",184nullptr,1858,1860,187eEncodingUint,188eFormatHex,189{dwarf_r8, dwarf_r8, LLDB_REGNUM_GENERIC_ARG5, LLDB_INVALID_REGNUM,190LLDB_INVALID_REGNUM},191nullptr,192nullptr,193nullptr,194},195{"r9",196nullptr,1978,1980,199eEncodingUint,200eFormatHex,201{dwarf_r9, dwarf_r9, LLDB_REGNUM_GENERIC_ARG6, LLDB_INVALID_REGNUM,202LLDB_INVALID_REGNUM},203nullptr,204nullptr,205nullptr,206},207{"r10",208nullptr,2098,2100,211eEncodingUint,212eFormatHex,213{dwarf_r10, dwarf_r10, LLDB_REGNUM_GENERIC_ARG7, LLDB_INVALID_REGNUM,214LLDB_INVALID_REGNUM},215nullptr,216nullptr,217nullptr,218},219{"r11",220nullptr,2218,2220,223eEncodingUint,224eFormatHex,225{dwarf_r11, dwarf_r11, LLDB_REGNUM_GENERIC_ARG8, LLDB_INVALID_REGNUM,226LLDB_INVALID_REGNUM},227nullptr,228nullptr,229nullptr,230},231{"r12",232nullptr,2338,2340,235eEncodingUint,236eFormatHex,237{dwarf_r12, dwarf_r12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,238LLDB_INVALID_REGNUM},239nullptr,240nullptr,241nullptr,242},243{"r13",244nullptr,2458,2460,247eEncodingUint,248eFormatHex,249{dwarf_r13, dwarf_r13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,250LLDB_INVALID_REGNUM},251nullptr,252nullptr,253nullptr,254},255{"r14",256nullptr,2578,2580,259eEncodingUint,260eFormatHex,261{dwarf_r14, dwarf_r14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,262LLDB_INVALID_REGNUM},263nullptr,264nullptr,265nullptr,266},267{"r15",268nullptr,2698,2700,271eEncodingUint,272eFormatHex,273{dwarf_r15, dwarf_r15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,274LLDB_INVALID_REGNUM},275nullptr,276nullptr,277nullptr,278},279{"r16",280nullptr,2818,2820,283eEncodingUint,284eFormatHex,285{dwarf_r16, dwarf_r16, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,286LLDB_INVALID_REGNUM},287nullptr,288nullptr,289nullptr,290},291{"r17",292nullptr,2938,2940,295eEncodingUint,296eFormatHex,297{dwarf_r17, dwarf_r17, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,298LLDB_INVALID_REGNUM},299nullptr,300nullptr,301nullptr,302},303{"r18",304nullptr,3058,3060,307eEncodingUint,308eFormatHex,309{dwarf_r18, dwarf_r18, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,310LLDB_INVALID_REGNUM},311nullptr,312nullptr,313nullptr,314},315{"r19",316nullptr,3178,3180,319eEncodingUint,320eFormatHex,321{dwarf_r19, dwarf_r19, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,322LLDB_INVALID_REGNUM},323nullptr,324nullptr,325nullptr,326},327{"r20",328nullptr,3298,3300,331eEncodingUint,332eFormatHex,333{dwarf_r20, dwarf_r20, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,334LLDB_INVALID_REGNUM},335nullptr,336nullptr,337nullptr,338},339{"r21",340nullptr,3418,3420,343eEncodingUint,344eFormatHex,345{dwarf_r21, dwarf_r21, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,346LLDB_INVALID_REGNUM},347nullptr,348nullptr,349nullptr,350},351{"r22",352nullptr,3538,3540,355eEncodingUint,356eFormatHex,357{dwarf_r22, dwarf_r22, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,358LLDB_INVALID_REGNUM},359nullptr,360nullptr,361nullptr,362},363{"r23",364nullptr,3658,3660,367eEncodingUint,368eFormatHex,369{dwarf_r23, dwarf_r23, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,370LLDB_INVALID_REGNUM},371nullptr,372nullptr,373nullptr,374},375{"r24",376nullptr,3778,3780,379eEncodingUint,380eFormatHex,381{dwarf_r24, dwarf_r24, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,382LLDB_INVALID_REGNUM},383nullptr,384nullptr,385nullptr,386},387{"r25",388nullptr,3898,3900,391eEncodingUint,392eFormatHex,393{dwarf_r25, dwarf_r25, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,394LLDB_INVALID_REGNUM},395nullptr,396nullptr,397nullptr,398},399{"r26",400nullptr,4018,4020,403eEncodingUint,404eFormatHex,405{dwarf_r26, dwarf_r26, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,406LLDB_INVALID_REGNUM},407nullptr,408nullptr,409nullptr,410},411{"r27",412nullptr,4138,4140,415eEncodingUint,416eFormatHex,417{dwarf_r27, dwarf_r27, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,418LLDB_INVALID_REGNUM},419nullptr,420nullptr,421nullptr,422},423{"r28",424"gp",4258,4260,427eEncodingUint,428eFormatHex,429{dwarf_r28, dwarf_r28, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,430LLDB_INVALID_REGNUM},431nullptr,432nullptr,433nullptr,434},435{"r29",436nullptr,4378,4380,439eEncodingUint,440eFormatHex,441{dwarf_r29, dwarf_r29, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM,442LLDB_INVALID_REGNUM},443nullptr,444nullptr,445nullptr,446},447{"r30",448nullptr,4498,4500,451eEncodingUint,452eFormatHex,453{dwarf_r30, dwarf_r30, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM,454LLDB_INVALID_REGNUM},455nullptr,456nullptr,457nullptr,458},459{"r31",460nullptr,4618,4620,463eEncodingUint,464eFormatHex,465{dwarf_r31, dwarf_r31, LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM,466LLDB_INVALID_REGNUM},467nullptr,468nullptr,469nullptr,470},471{"sr",472nullptr,4734,4740,475eEncodingUint,476eFormatHex,477{dwarf_sr, dwarf_sr, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM,478LLDB_INVALID_REGNUM},479nullptr,480nullptr,481nullptr,482},483{"lo",484nullptr,4858,4860,487eEncodingUint,488eFormatHex,489{dwarf_lo, dwarf_lo, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,490LLDB_INVALID_REGNUM},491nullptr,492nullptr,493nullptr,494},495{"hi",496nullptr,4978,4980,499eEncodingUint,500eFormatHex,501{dwarf_hi, dwarf_hi, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,502LLDB_INVALID_REGNUM},503nullptr,504nullptr,505nullptr,506},507{"bad",508nullptr,5098,5100,511eEncodingUint,512eFormatHex,513{dwarf_bad, dwarf_bad, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,514LLDB_INVALID_REGNUM},515nullptr,516nullptr,517nullptr,518},519{"cause",520nullptr,5218,5220,523eEncodingUint,524eFormatHex,525{dwarf_cause, dwarf_cause, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,526LLDB_INVALID_REGNUM},527nullptr,528nullptr,529nullptr,530},531{"pc",532nullptr,5338,5340,535eEncodingUint,536eFormatHex,537{dwarf_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM,538LLDB_INVALID_REGNUM},539nullptr,540nullptr,541nullptr,542},543};544545static const uint32_t k_num_register_infos = std::size(g_register_infos_mips64);546547const lldb_private::RegisterInfo *548ABISysV_mips64::GetRegisterInfoArray(uint32_t &count) {549count = k_num_register_infos;550return g_register_infos_mips64;551}552553size_t ABISysV_mips64::GetRedZoneSize() const { return 0; }554555// Static Functions556557ABISP558ABISysV_mips64::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) {559if (arch.GetTriple().isMIPS64())560return ABISP(561new ABISysV_mips64(std::move(process_sp), MakeMCRegisterInfo(arch)));562return ABISP();563}564565bool ABISysV_mips64::PrepareTrivialCall(Thread &thread, addr_t sp,566addr_t func_addr, addr_t return_addr,567llvm::ArrayRef<addr_t> args) const {568Log *log = GetLog(LLDBLog::Expressions);569570if (log) {571StreamString s;572s.Printf("ABISysV_mips64::PrepareTrivialCall (tid = 0x%" PRIx64573", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64574", return_addr = 0x%" PRIx64,575thread.GetID(), (uint64_t)sp, (uint64_t)func_addr,576(uint64_t)return_addr);577578for (size_t i = 0; i < args.size(); ++i)579s.Printf(", arg%zd = 0x%" PRIx64, i + 1, args[i]);580s.PutCString(")");581log->PutString(s.GetString());582}583584RegisterContext *reg_ctx = thread.GetRegisterContext().get();585if (!reg_ctx)586return false;587588const RegisterInfo *reg_info = nullptr;589590if (args.size() > 8) // TODO handle more than 8 arguments591return false;592593for (size_t i = 0; i < args.size(); ++i) {594reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric,595LLDB_REGNUM_GENERIC_ARG1 + i);596LLDB_LOGF(log, "About to write arg%zd (0x%" PRIx64 ") into %s", i + 1,597args[i], reg_info->name);598if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i]))599return false;600}601602// First, align the SP603604LLDB_LOGF(log, "16-byte aligning SP: 0x%" PRIx64 " to 0x%" PRIx64,605(uint64_t)sp, (uint64_t)(sp & ~0xfull));606607sp &= ~(0xfull); // 16-byte alignment608609Status error;610const RegisterInfo *pc_reg_info =611reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);612const RegisterInfo *sp_reg_info =613reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);614const RegisterInfo *ra_reg_info =615reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);616const RegisterInfo *r25_info = reg_ctx->GetRegisterInfoByName("r25", 0);617const RegisterInfo *r0_info = reg_ctx->GetRegisterInfoByName("zero", 0);618619LLDB_LOGF(log, "Writing R0: 0x%" PRIx64, (uint64_t)0);620621/* Write r0 with 0, in case we are stopped in syscall,622* such setting prevents automatic decrement of the PC.623* This clears the bug 23659 for MIPS.624*/625if (!reg_ctx->WriteRegisterFromUnsigned(r0_info, (uint64_t)0))626return false;627628LLDB_LOGF(log, "Writing SP: 0x%" PRIx64, (uint64_t)sp);629630// Set "sp" to the requested value631if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_info, sp))632return false;633634LLDB_LOGF(log, "Writing RA: 0x%" PRIx64, (uint64_t)return_addr);635636// Set "ra" to the return address637if (!reg_ctx->WriteRegisterFromUnsigned(ra_reg_info, return_addr))638return false;639640LLDB_LOGF(log, "Writing PC: 0x%" PRIx64, (uint64_t)func_addr);641642// Set pc to the address of the called function.643if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_info, func_addr))644return false;645646LLDB_LOGF(log, "Writing r25: 0x%" PRIx64, (uint64_t)func_addr);647648// All callers of position independent functions must place the address of649// the called function in t9 (r25)650if (!reg_ctx->WriteRegisterFromUnsigned(r25_info, func_addr))651return false;652653return true;654}655656bool ABISysV_mips64::GetArgumentValues(Thread &thread,657ValueList &values) const {658return false;659}660661Status ABISysV_mips64::SetReturnValueObject(lldb::StackFrameSP &frame_sp,662lldb::ValueObjectSP &new_value_sp) {663Status error;664if (!new_value_sp) {665error.SetErrorString("Empty value object for return value.");666return error;667}668669CompilerType compiler_type = new_value_sp->GetCompilerType();670if (!compiler_type) {671error.SetErrorString("Null clang type for return value.");672return error;673}674675Thread *thread = frame_sp->GetThread().get();676677RegisterContext *reg_ctx = thread->GetRegisterContext().get();678679if (!reg_ctx)680error.SetErrorString("no registers are available");681682DataExtractor data;683Status data_error;684size_t num_bytes = new_value_sp->GetData(data, data_error);685if (data_error.Fail()) {686error.SetErrorStringWithFormat(687"Couldn't convert return value to raw data: %s",688data_error.AsCString());689return error;690}691692const uint32_t type_flags = compiler_type.GetTypeInfo(nullptr);693694if (type_flags & eTypeIsScalar || type_flags & eTypeIsPointer) {695if (type_flags & eTypeIsInteger || type_flags & eTypeIsPointer) {696lldb::offset_t offset = 0;697698if (num_bytes <= 16) {699const RegisterInfo *r2_info = reg_ctx->GetRegisterInfoByName("r2", 0);700if (num_bytes <= 8) {701uint64_t raw_value = data.GetMaxU64(&offset, num_bytes);702703if (!reg_ctx->WriteRegisterFromUnsigned(r2_info, raw_value))704error.SetErrorString("failed to write register r2");705} else {706uint64_t raw_value = data.GetMaxU64(&offset, 8);707if (reg_ctx->WriteRegisterFromUnsigned(r2_info, raw_value)) {708const RegisterInfo *r3_info =709reg_ctx->GetRegisterInfoByName("r3", 0);710raw_value = data.GetMaxU64(&offset, num_bytes - offset);711712if (!reg_ctx->WriteRegisterFromUnsigned(r3_info, raw_value))713error.SetErrorString("failed to write register r3");714} else715error.SetErrorString("failed to write register r2");716}717} else {718error.SetErrorString("We don't support returning longer than 128 bit "719"integer values at present.");720}721} else if (type_flags & eTypeIsFloat) {722error.SetErrorString("TODO: Handle Float Types.");723}724} else if (type_flags & eTypeIsVector) {725error.SetErrorString("returning vector values are not supported");726}727728return error;729}730731ValueObjectSP ABISysV_mips64::GetReturnValueObjectSimple(732Thread &thread, CompilerType &return_compiler_type) const {733ValueObjectSP return_valobj_sp;734return return_valobj_sp;735}736737ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl(738Thread &thread, CompilerType &return_compiler_type) const {739ValueObjectSP return_valobj_sp;740Value value;741Status error;742743ExecutionContext exe_ctx(thread.shared_from_this());744if (exe_ctx.GetTargetPtr() == nullptr || exe_ctx.GetProcessPtr() == nullptr)745return return_valobj_sp;746747value.SetCompilerType(return_compiler_type);748749RegisterContext *reg_ctx = thread.GetRegisterContext().get();750if (!reg_ctx)751return return_valobj_sp;752753Target *target = exe_ctx.GetTargetPtr();754const ArchSpec target_arch = target->GetArchitecture();755ByteOrder target_byte_order = target_arch.GetByteOrder();756std::optional<uint64_t> byte_size = return_compiler_type.GetByteSize(&thread);757if (!byte_size)758return return_valobj_sp;759const uint32_t type_flags = return_compiler_type.GetTypeInfo(nullptr);760uint32_t fp_flag =761target_arch.GetFlags() & lldb_private::ArchSpec::eMIPS_ABI_FP_mask;762763const RegisterInfo *r2_info = reg_ctx->GetRegisterInfoByName("r2", 0);764const RegisterInfo *r3_info = reg_ctx->GetRegisterInfoByName("r3", 0);765assert(r2_info && r3_info && "Basic registers should always be present.");766767if (type_flags & eTypeIsScalar || type_flags & eTypeIsPointer) {768value.SetValueType(Value::ValueType::Scalar);769770bool success = false;771if (type_flags & eTypeIsInteger || type_flags & eTypeIsPointer) {772// Extract the register context so we can read arguments from registers773// In MIPS register "r2" (v0) holds the integer function return values774775uint64_t raw_value = reg_ctx->ReadRegisterAsUnsigned(r2_info, 0);776777const bool is_signed = (type_flags & eTypeIsSigned) != 0;778switch (*byte_size) {779default:780break;781782case sizeof(uint64_t):783if (is_signed)784value.GetScalar() = (int64_t)(raw_value);785else786value.GetScalar() = (uint64_t)(raw_value);787success = true;788break;789790case sizeof(uint32_t):791if (is_signed)792value.GetScalar() = (int32_t)(raw_value & UINT32_MAX);793else794value.GetScalar() = (uint32_t)(raw_value & UINT32_MAX);795success = true;796break;797798case sizeof(uint16_t):799if (is_signed)800value.GetScalar() = (int16_t)(raw_value & UINT16_MAX);801else802value.GetScalar() = (uint16_t)(raw_value & UINT16_MAX);803success = true;804break;805806case sizeof(uint8_t):807if (is_signed)808value.GetScalar() = (int8_t)(raw_value & UINT8_MAX);809else810value.GetScalar() = (uint8_t)(raw_value & UINT8_MAX);811success = true;812break;813}814} else if (type_flags & eTypeIsFloat) {815if (type_flags & eTypeIsComplex) {816// Don't handle complex yet.817} else if (IsSoftFloat(fp_flag)) {818uint64_t raw_value = reg_ctx->ReadRegisterAsUnsigned(r2_info, 0);819switch (*byte_size) {820case 4:821value.GetScalar() = *((float *)(&raw_value));822success = true;823break;824case 8:825value.GetScalar() = *((double *)(&raw_value));826success = true;827break;828case 16:829uint64_t result[2];830if (target_byte_order == eByteOrderLittle) {831result[0] = raw_value;832result[1] = reg_ctx->ReadRegisterAsUnsigned(r3_info, 0);833value.GetScalar() = *((long double *)(result));834} else {835result[0] = reg_ctx->ReadRegisterAsUnsigned(r3_info, 0);836result[1] = raw_value;837value.GetScalar() = *((long double *)(result));838}839success = true;840break;841}842843} else {844if (*byte_size <= sizeof(long double)) {845const RegisterInfo *f0_info = reg_ctx->GetRegisterInfoByName("f0", 0);846847RegisterValue f0_value;848DataExtractor f0_data;849850reg_ctx->ReadRegister(f0_info, f0_value);851852f0_value.GetData(f0_data);853854lldb::offset_t offset = 0;855if (*byte_size == sizeof(float)) {856value.GetScalar() = (float)f0_data.GetFloat(&offset);857success = true;858} else if (*byte_size == sizeof(double)) {859value.GetScalar() = (double)f0_data.GetDouble(&offset);860success = true;861} else if (*byte_size == sizeof(long double)) {862const RegisterInfo *f2_info =863reg_ctx->GetRegisterInfoByName("f2", 0);864RegisterValue f2_value;865DataExtractor f2_data;866reg_ctx->ReadRegister(f2_info, f2_value);867DataExtractor *copy_from_extractor = nullptr;868WritableDataBufferSP data_sp(new DataBufferHeap(16, 0));869DataExtractor return_ext(870data_sp, target_byte_order,871target->GetArchitecture().GetAddressByteSize());872873if (target_byte_order == eByteOrderLittle) {874copy_from_extractor = &f0_data;875copy_from_extractor->CopyByteOrderedData(8760, 8, data_sp->GetBytes(), *byte_size - 8, target_byte_order);877f2_value.GetData(f2_data);878copy_from_extractor = &f2_data;879copy_from_extractor->CopyByteOrderedData(8800, 8, data_sp->GetBytes() + 8, *byte_size - 8,881target_byte_order);882} else {883copy_from_extractor = &f0_data;884copy_from_extractor->CopyByteOrderedData(8850, 8, data_sp->GetBytes() + 8, *byte_size - 8,886target_byte_order);887f2_value.GetData(f2_data);888copy_from_extractor = &f2_data;889copy_from_extractor->CopyByteOrderedData(8900, 8, data_sp->GetBytes(), *byte_size - 8, target_byte_order);891}892893return_valobj_sp = ValueObjectConstResult::Create(894&thread, return_compiler_type, ConstString(""), return_ext);895return return_valobj_sp;896}897}898}899}900901if (success)902return_valobj_sp = ValueObjectConstResult::Create(903thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));904} else if (type_flags & eTypeIsStructUnion || type_flags & eTypeIsClass ||905type_flags & eTypeIsVector) {906// Any structure of up to 16 bytes in size is returned in the registers.907if (*byte_size <= 16) {908WritableDataBufferSP data_sp(new DataBufferHeap(16, 0));909DataExtractor return_ext(data_sp, target_byte_order,910target->GetArchitecture().GetAddressByteSize());911912RegisterValue r2_value, r3_value, f0_value, f1_value, f2_value;913// Tracks how much bytes of r2 and r3 registers we've consumed so far914uint32_t integer_bytes = 0;915916// True if return values are in FP return registers.917bool use_fp_regs = false;918// True if we found any non floating point field in structure.919bool found_non_fp_field = false;920// True if return values are in r2 register.921bool use_r2 = false;922// True if return values are in r3 register.923bool use_r3 = false;924// True if the result is copied into our data buffer925bool sucess = false;926std::string name;927bool is_complex;928uint32_t count;929const uint32_t num_children = return_compiler_type.GetNumFields();930931// A structure consisting of one or two FP values (and nothing else) will932// be returned in the two FP return-value registers i.e fp0 and fp2.933if (num_children <= 2) {934uint64_t field_bit_offset = 0;935936// Check if this structure contains only floating point fields937for (uint32_t idx = 0; idx < num_children; idx++) {938CompilerType field_compiler_type =939return_compiler_type.GetFieldAtIndex(idx, name, &field_bit_offset,940nullptr, nullptr);941942if (field_compiler_type.IsFloatingPointType(count, is_complex))943use_fp_regs = true;944else945found_non_fp_field = true;946}947948if (use_fp_regs && !found_non_fp_field) {949// We have one or two FP-only values in this structure. Get it from950// f0/f2 registers.951DataExtractor f0_data, f1_data, f2_data;952const RegisterInfo *f0_info = reg_ctx->GetRegisterInfoByName("f0", 0);953const RegisterInfo *f1_info = reg_ctx->GetRegisterInfoByName("f1", 0);954const RegisterInfo *f2_info = reg_ctx->GetRegisterInfoByName("f2", 0);955956reg_ctx->ReadRegister(f0_info, f0_value);957reg_ctx->ReadRegister(f2_info, f2_value);958959f0_value.GetData(f0_data);960961for (uint32_t idx = 0; idx < num_children; idx++) {962CompilerType field_compiler_type =963return_compiler_type.GetFieldAtIndex(964idx, name, &field_bit_offset, nullptr, nullptr);965std::optional<uint64_t> field_byte_width =966field_compiler_type.GetByteSize(&thread);967if (!field_byte_width)968return return_valobj_sp;969970DataExtractor *copy_from_extractor = nullptr;971uint64_t return_value[2];972offset_t offset = 0;973974if (idx == 0) {975// This case is for long double type.976if (*field_byte_width == 16) {977978// If structure contains long double type, then it is returned979// in fp0/fp1 registers.980if (target_byte_order == eByteOrderLittle) {981return_value[0] = f0_data.GetU64(&offset);982reg_ctx->ReadRegister(f1_info, f1_value);983f1_value.GetData(f1_data);984offset = 0;985return_value[1] = f1_data.GetU64(&offset);986} else {987return_value[1] = f0_data.GetU64(&offset);988reg_ctx->ReadRegister(f1_info, f1_value);989f1_value.GetData(f1_data);990offset = 0;991return_value[0] = f1_data.GetU64(&offset);992}993994f0_data.SetData(return_value, *field_byte_width,995target_byte_order);996}997copy_from_extractor = &f0_data; // This is in f0, copy from998// register to our result999// structure1000} else {1001f2_value.GetData(f2_data);1002// This is in f2, copy from register to our result structure1003copy_from_extractor = &f2_data;1004}10051006// Sanity check to avoid crash1007if (!copy_from_extractor ||1008*field_byte_width > copy_from_extractor->GetByteSize())1009return return_valobj_sp;10101011// copy the register contents into our data buffer1012copy_from_extractor->CopyByteOrderedData(10130, *field_byte_width,1014data_sp->GetBytes() + (field_bit_offset / 8), *field_byte_width,1015target_byte_order);1016}10171018// The result is in our data buffer. Create a variable object out of1019// it1020return_valobj_sp = ValueObjectConstResult::Create(1021&thread, return_compiler_type, ConstString(""), return_ext);10221023return return_valobj_sp;1024}1025}10261027// If we reach here, it means this structure either contains more than1028// two fields or it contains at least one non floating point type. In1029// that case, all fields are returned in GP return registers.1030for (uint32_t idx = 0; idx < num_children; idx++) {1031uint64_t field_bit_offset = 0;1032bool is_signed;1033uint32_t padding;10341035CompilerType field_compiler_type = return_compiler_type.GetFieldAtIndex(1036idx, name, &field_bit_offset, nullptr, nullptr);1037std::optional<uint64_t> field_byte_width =1038field_compiler_type.GetByteSize(&thread);10391040// if we don't know the size of the field (e.g. invalid type), just1041// bail out1042if (!field_byte_width || *field_byte_width == 0)1043break;10441045uint32_t field_byte_offset = field_bit_offset / 8;10461047if (field_compiler_type.IsIntegerOrEnumerationType(is_signed) ||1048field_compiler_type.IsPointerType() ||1049field_compiler_type.IsFloatingPointType(count, is_complex)) {1050padding = field_byte_offset - integer_bytes;10511052if (integer_bytes < 8) {1053// We have not yet consumed r2 completely.1054if (integer_bytes + *field_byte_width + padding <= 8) {1055// This field fits in r2, copy its value from r2 to our result1056// structure1057integer_bytes = integer_bytes + *field_byte_width +1058padding; // Increase the consumed bytes.1059use_r2 = true;1060} else {1061// There isn't enough space left in r2 for this field, so this1062// will be in r3.1063integer_bytes = integer_bytes + *field_byte_width +1064padding; // Increase the consumed bytes.1065use_r3 = true;1066}1067}1068// We already have consumed at-least 8 bytes that means r2 is done,1069// and this field will be in r3. Check if this field can fit in r3.1070else if (integer_bytes + *field_byte_width + padding <= 16) {1071integer_bytes = integer_bytes + *field_byte_width + padding;1072use_r3 = true;1073} else {1074// There isn't any space left for this field, this should not1075// happen as we have already checked the overall size is not1076// greater than 16 bytes. For now, return a nullptr return value1077// object.1078return return_valobj_sp;1079}1080}1081}1082// Vector types up to 16 bytes are returned in GP return registers1083if (type_flags & eTypeIsVector) {1084if (*byte_size <= 8)1085use_r2 = true;1086else {1087use_r2 = true;1088use_r3 = true;1089}1090}10911092if (use_r2) {1093reg_ctx->ReadRegister(r2_info, r2_value);10941095const size_t bytes_copied = r2_value.GetAsMemoryData(1096*r2_info, data_sp->GetBytes(), r2_info->byte_size,1097target_byte_order, error);1098if (bytes_copied != r2_info->byte_size)1099return return_valobj_sp;1100sucess = true;1101}1102if (use_r3) {1103reg_ctx->ReadRegister(r3_info, r3_value);1104const size_t bytes_copied = r3_value.GetAsMemoryData(1105*r3_info, data_sp->GetBytes() + r2_info->byte_size,1106r3_info->byte_size, target_byte_order, error);11071108if (bytes_copied != r3_info->byte_size)1109return return_valobj_sp;1110sucess = true;1111}1112if (sucess) {1113// The result is in our data buffer. Create a variable object out of1114// it1115return_valobj_sp = ValueObjectConstResult::Create(1116&thread, return_compiler_type, ConstString(""), return_ext);1117}1118return return_valobj_sp;1119}11201121// Any structure/vector greater than 16 bytes in size is returned in1122// memory. The pointer to that memory is returned in r2.1123uint64_t mem_address = reg_ctx->ReadRegisterAsUnsigned(1124reg_ctx->GetRegisterInfoByName("r2", 0), 0);11251126// We have got the address. Create a memory object out of it1127return_valobj_sp = ValueObjectMemory::Create(1128&thread, "", Address(mem_address, nullptr), return_compiler_type);1129}1130return return_valobj_sp;1131}11321133bool ABISysV_mips64::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) {1134unwind_plan.Clear();1135unwind_plan.SetRegisterKind(eRegisterKindDWARF);11361137UnwindPlan::RowSP row(new UnwindPlan::Row);11381139// Our Call Frame Address is the stack pointer value1140row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_r29, 0);11411142// The previous PC is in the RA1143row->SetRegisterLocationToRegister(dwarf_pc, dwarf_r31, true);1144unwind_plan.AppendRow(row);11451146// All other registers are the same.11471148unwind_plan.SetSourceName("mips64 at-func-entry default");1149unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);1150unwind_plan.SetReturnAddressRegister(dwarf_r31);1151return true;1152}11531154bool ABISysV_mips64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {1155unwind_plan.Clear();1156unwind_plan.SetRegisterKind(eRegisterKindDWARF);11571158UnwindPlan::RowSP row(new UnwindPlan::Row);11591160row->SetUnspecifiedRegistersAreUndefined(true);1161row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_r29, 0);11621163row->SetRegisterLocationToRegister(dwarf_pc, dwarf_r31, true);11641165unwind_plan.AppendRow(row);1166unwind_plan.SetSourceName("mips64 default unwind plan");1167unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);1168unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);1169unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);1170return true;1171}11721173bool ABISysV_mips64::RegisterIsVolatile(const RegisterInfo *reg_info) {1174return !RegisterIsCalleeSaved(reg_info);1175}11761177bool ABISysV_mips64::IsSoftFloat(uint32_t fp_flag) const {1178return (fp_flag == lldb_private::ArchSpec::eMIPS_ABI_FP_SOFT);1179}11801181bool ABISysV_mips64::RegisterIsCalleeSaved(const RegisterInfo *reg_info) {1182if (reg_info) {1183// Preserved registers are :1184// r16-r23, r28, r29, r30, r3111851186int reg = ((reg_info->byte_offset) / 8);11871188bool save = (reg >= 16) && (reg <= 23);1189save |= (reg >= 28) && (reg <= 31);11901191return save;1192}1193return false;1194}11951196void ABISysV_mips64::Initialize() {1197PluginManager::RegisterPlugin(1198GetPluginNameStatic(), "System V ABI for mips64 targets", CreateInstance);1199}12001201void ABISysV_mips64::Terminate() {1202PluginManager::UnregisterPlugin(CreateInstance);1203}120412051206