From: Mikhail Kurinnoi Date: Tue, 31 Oct 2023 15:39:59 +0000 (+0300) Subject: [RISC-V] Add partial SOS 'clrstack' command implementation. (#4356) X-Git-Tag: accepted/tizen/unified/20241231.014852~40^2~300 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c022813174a1b4f0ea6889b40bf66db0e201f52e;p=platform%2Fcore%2Fdotnet%2Fdiagnostics.git [RISC-V] Add partial SOS 'clrstack' command implementation. (#4356) Changes: - add partial SOS 'clrstack' command implementation; - add more RISC-V related code (some still not tested or NYI, but need for proper SOS build); This changes allow start and use dotnet-dump+SOS with current runtime upstream on RISC-V board: ``` mkurinnoi@starfive:~$ ./dotnet/corerun ./tools/dotnet-dump.dll ps 221935 corerun /home/mkurinnoi/dotnet/corerun ./dotnet/corerun ./test_hr.dll mkurinnoi@starfive:~$ ./dotnet/corerun ./tools/dotnet-dump.dll collect --process-id 221935 Writing full to /home/mkurinnoi/core_20231024_104410 Complete mkurinnoi@starfive:~$ ./dotnet/corerun ./tools/dotnet-dump.dll analyze /home/mkurinnoi/core_20231024_104410 Loading core dump: /home/mkurinnoi/core_20231024_104410 ... Ready to process analysis commands. Type 'help' to list available commands or 'help [command]' to get detailed help on a command. Type 'quit' or 'exit' to exit the session. > clrstack OS Thread Id: 0x362ef (0) Child SP IP Call Site 0000003FD9F44F70 0000000000000000 [InlinedCallFrame: 0000003fd9f44f70] Interop+Sys.g____PInvoke|44_0(Byte*, Int32) 0000003FD9F44F70 0000003f353b5370 [InlinedCallFrame: 0000003fd9f44f70] Interop+Sys.g____PInvoke|44_0(Byte*, Int32) 0000003FD9F44F50 0000003F353B5370 ILStubClass.IL_STUB_PInvoke(Byte*, Int32) 0000003FD9F45050 0000003F353B51D4 Interop+Sys.ReadStdin(Byte*, Int32) [/home/runtime/src/libraries/System.Console/src/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs @ 800] 0000003FD9F45080 0000003F353B507C System.IO.StdInReader.ReadStdin(Byte*, Int32) [/home/runtime/src/libraries/System.Console/src/System/IO/StdInReader.cs @ 83] 0000003FD9F450B0 0000003F353B4BD4 System.IO.StdInReader.ReadKey() [/home/runtime/src/libraries/System.Console/src/System/IO/StdInReader.cs @ 337] 0000003FD9F45560 0000003F353B363C System.IO.StdInReader.ReadLineCore(Boolean) [/home/runtime/src/libraries/System.Console/src/System/IO/StdInReader.cs @ 160] 0000003FD9F45740 0000003F353B32AC System.IO.StdInReader.ReadLine() [/home/runtime/src/libraries/System.Console/src/System/IO/StdInReader.cs @ 90] 0000003FD9F457A0 0000003F353B3154 System.IO.SyncTextReader.ReadLine() [/home/runtime/src/libraries/System.Console/src/System/IO/SyncTextReader.cs @ 77] 0000003FD9F457F0 0000003F353B1064 System.Console.ReadLine() [/home/runtime/src/libraries/System.Console/src/System/Console.cs @ 752] 0000003FD9F45820 0000003F3536DF10 TestApp.Program.Main(System.String[]) [/home/viewizard/Desktop/projects_test/test_hr/Program.cs @ 11] > q ``` Note, I only start SOS commands implementation for RISC-V (almost nothing work now). CC @clamp03 @wscho77 @HJLeee @JongHeonChoi @t-mustafin @gbalykov --- diff --git a/src/Microsoft.Diagnostics.DebugServices.Implementation/ThreadService.cs b/src/Microsoft.Diagnostics.DebugServices.Implementation/ThreadService.cs index 4c89c0c83..de9149330 100644 --- a/src/Microsoft.Diagnostics.DebugServices.Implementation/ThreadService.cs +++ b/src/Microsoft.Diagnostics.DebugServices.Implementation/ThreadService.cs @@ -59,6 +59,12 @@ namespace Microsoft.Diagnostics.DebugServices.Implementation contextType = typeof(ArmContext); break; + case (Architecture)9 /* Architecture.RiscV64 */: + _contextSize = RiscV64Context.Size; + _contextFlags = RiscV64Context.ContextControl | RiscV64Context.ContextInteger | RiscV64Context.ContextFloatingPoint; + contextType = typeof(RiscV64Context); + break; + default: throw new PlatformNotSupportedException($"Unsupported architecture: {Target.Architecture}"); } diff --git a/src/SOS/SOS.Extensions/TargetFromFromDebuggerServices.cs b/src/SOS/SOS.Extensions/TargetFromFromDebuggerServices.cs index e0c2bee85..6e29077ef 100644 --- a/src/SOS/SOS.Extensions/TargetFromFromDebuggerServices.cs +++ b/src/SOS/SOS.Extensions/TargetFromFromDebuggerServices.cs @@ -54,6 +54,7 @@ namespace SOS.Extensions IMAGE_FILE_MACHINE.THUMB2 => Architecture.Arm, IMAGE_FILE_MACHINE.AMD64 => Architecture.X64, IMAGE_FILE_MACHINE.ARM64 => Architecture.Arm64, + IMAGE_FILE_MACHINE.RISCV64 => (Architecture)9 /* Architecture.RiscV64 */, _ => throw new PlatformNotSupportedException($"Machine type not supported: {type}"), }; } diff --git a/src/SOS/SOS.Hosting/DataTargetWrapper.cs b/src/SOS/SOS.Hosting/DataTargetWrapper.cs index 303e88d82..f61cbd431 100644 --- a/src/SOS/SOS.Hosting/DataTargetWrapper.cs +++ b/src/SOS/SOS.Hosting/DataTargetWrapper.cs @@ -112,6 +112,7 @@ namespace SOS.Hosting Architecture.X86 => IMAGE_FILE_MACHINE.I386, Architecture.Arm => IMAGE_FILE_MACHINE.THUMB2, Architecture.Arm64 => IMAGE_FILE_MACHINE.ARM64, + (Architecture)9 /* Architecture.RiscV64 */ => IMAGE_FILE_MACHINE.RISCV64, _ => IMAGE_FILE_MACHINE.UNKNOWN, }; return HResult.S_OK; diff --git a/src/SOS/SOS.Hosting/DbgEng/Interop/Enums/ImageFileMachine.cs b/src/SOS/SOS.Hosting/DbgEng/Interop/Enums/ImageFileMachine.cs index ebda53b00..cb9ed62a2 100644 --- a/src/SOS/SOS.Hosting/DbgEng/Interop/Enums/ImageFileMachine.cs +++ b/src/SOS/SOS.Hosting/DbgEng/Interop/Enums/ImageFileMachine.cs @@ -35,6 +35,7 @@ namespace SOS.Hosting.DbgEng.Interop AMD64 = 0x8664, // AMD64 (K8) M32R = 0x9041, // M32R little-endian ARM64 = 0xAA64, // ARM64 Little-endian - CEE = 0xC0EE + CEE = 0xC0EE, + RISCV64 = 0x5064 } } diff --git a/src/SOS/SOS.Hosting/SOSHost.cs b/src/SOS/SOS.Hosting/SOSHost.cs index 0fe569a0f..3891c0063 100644 --- a/src/SOS/SOS.Hosting/SOSHost.cs +++ b/src/SOS/SOS.Hosting/SOSHost.cs @@ -183,6 +183,9 @@ namespace SOS.Hosting case Architecture.Arm64: *type = IMAGE_FILE_MACHINE.ARM64; break; + case (Architecture)9 /* Architecture.RiscV64 */: + *type = IMAGE_FILE_MACHINE.RISCV64; + break; default: *type = IMAGE_FILE_MACHINE.UNKNOWN; break; diff --git a/src/SOS/Strike/CMakeLists.txt b/src/SOS/Strike/CMakeLists.txt index 52456d738..8b095e69a 100644 --- a/src/SOS/Strike/CMakeLists.txt +++ b/src/SOS/Strike/CMakeLists.txt @@ -219,6 +219,10 @@ elseif(CLR_CMAKE_HOST_ARCH_ARM64) set(SOS_SOURCES_ARCH disasmARM64.cpp ) +elseif(CLR_CMAKE_HOST_ARCH_RISCV64) + set(SOS_SOURCES_ARCH + disasmRISCV64.cpp + ) endif() list(APPEND SOS_SOURCES ${SOS_SOURCES_ARCH}) diff --git a/src/SOS/Strike/disasm.cpp b/src/SOS/Strike/disasm.cpp index 10590c165..b116c72b9 100644 --- a/src/SOS/Strike/disasm.cpp +++ b/src/SOS/Strike/disasm.cpp @@ -1127,6 +1127,19 @@ LPCSTR ARM64Machine::s_SPName = "sp"; #endif // SOS_TARGET_ARM64 +#ifdef SOS_TARGET_RISCV64 +/// +/// RISCV64Machine implementation +/// +LPCSTR RISCV64Machine::s_DumpStackHeading = "ChildFP RetAddr Caller, Callee\n"; +LPCSTR RISCV64Machine::s_GCRegs[30] = {"r0", "ra", "gp", "tp", "t0", "t1", "t2", "s1", "a0", + "a1", "a2", "a3", "a4", "a5", "a6", "a7", "s2", "s3", + "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", + "t3", "t4", "t5", "t6"}; +LPCSTR RISCV64Machine::s_SPName = "sp"; + +#endif // SOS_TARGET_RISCV64 + // // GCEncodingInfo class member implementations // diff --git a/src/SOS/Strike/disasm.h b/src/SOS/Strike/disasm.h index a09e5abec..714e0fdda 100644 --- a/src/SOS/Strike/disasm.h +++ b/src/SOS/Strike/disasm.h @@ -401,6 +401,76 @@ private: }; // class ARM64Machine #endif // SOS_TARGET_ARM64 + + +#ifdef SOS_TARGET_RISCV64 + +/// RISCV64 Machine specific code +class RISCV64Machine : public IMachine +{ +public: + typedef RISCV64_CONTEXT TGT_CTXT; + + static IMachine* GetInstance() + { static RISCV64Machine s_RISCV64MachineInstance; return &s_RISCV64MachineInstance; } + + ULONG GetPlatform() const { return IMAGE_FILE_MACHINE_RISCV64; } + ULONG GetContextSize() const { return sizeof(RISCV64_CONTEXT); } + ULONG GetFullContextFlags() const { return 0x01000007L; } + void SetContextFlags(BYTE* context, ULONG32 contextFlags) { ((RISCV64_CONTEXT*)context)->ContextFlags = contextFlags; }; + + virtual void Unassembly( + TADDR IPBegin, + TADDR IPEnd, + TADDR IPAskedFor, + TADDR GCStressCodeCopy, + GCEncodingInfo *pGCEncodingInfo, + SOSEHInfo *pEHInfo, + BOOL bSuppressLines, + BOOL bDisplayOffsets, + std::function displayIL) const; + virtual void IsReturnAddress( + TADDR retAddr, + TADDR* whereCalled) const; + virtual BOOL GetExceptionContext ( + TADDR stack, + TADDR PC, + TADDR *cxrAddr, + CROSS_PLATFORM_CONTEXT * cxr, + TADDR *exrAddr, + PEXCEPTION_RECORD exr) const; + + // retrieve stack pointer, frame pointer, and instruction pointer from the target context + virtual TADDR GetSP(const CROSS_PLATFORM_CONTEXT & ctx) const { return ctx.RiscV64Context.Sp; } + virtual TADDR GetBP(const CROSS_PLATFORM_CONTEXT & ctx) const { return ctx.RiscV64Context.Fp; } + virtual TADDR GetIP(const CROSS_PLATFORM_CONTEXT & ctx) const { return ctx.RiscV64Context.Pc; } + + virtual void FillSimpleContext(StackTrace_SimpleContext * dest, LPVOID srcCtx) const; + virtual void FillTargetContext(LPVOID destCtx, LPVOID srcCtx, int idx = 0) const; + + virtual LPCSTR GetDumpStackHeading() const { return s_DumpStackHeading; } + virtual LPCSTR GetSPName() const { return s_SPName; } + virtual void GetGCRegisters(LPCSTR** regNames, unsigned int* cntRegs) const + { _ASSERTE(cntRegs != NULL); *regNames = s_GCRegs; *cntRegs = ARRAY_SIZE(s_GCRegs);} + + virtual void DumpGCInfo(GCInfoToken gcInfoToken, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const; + + int StackWalkIPAdjustOffset() const { return 4; } + +private: + RISCV64Machine() {} + ~RISCV64Machine() {} + RISCV64Machine(const RISCV64Machine& machine); // undefined + RISCV64Machine & operator=(const RISCV64Machine&); // undefined + + static LPCSTR s_DumpStackHeading; + static LPCSTR s_GCRegs[30]; + static LPCSTR s_SPName; + +}; // class RISCV64Machine + +#endif // SOS_TARGET_RISCV64 + #ifdef _MSC_VER #pragma warning(pop) #endif // _MSC_VER @@ -478,4 +548,19 @@ inline void ARM64Machine::FillTargetContext(LPVOID destCtx, LPVOID srcCtx, int i } #endif // SOS_TARGET_ARM64 +#ifdef SOS_TARGET_RISCV64 +inline void RISCV64Machine::FillSimpleContext(StackTrace_SimpleContext * dest, LPVOID srcCtx) const +{ + TGT_CTXT& src = *(TGT_CTXT*) srcCtx; + dest->StackOffset = src.Sp; + dest->FrameOffset = src.Fp; + dest->InstructionOffset = src.Pc; +} + +inline void RISCV64Machine::FillTargetContext(LPVOID destCtx, LPVOID srcCtx, int idx /*= 0*/) const +{ + TGT_CTXT* dest = (TGT_CTXT*)destCtx + idx; + *dest = *(TGT_CTXT*)srcCtx; +} +#endif // SOS_TARGET_RISCV64 #endif // __disasm_h__ diff --git a/src/SOS/Strike/disasmRISCV64.cpp b/src/SOS/Strike/disasmRISCV64.cpp new file mode 100644 index 000000000..531fbd7da --- /dev/null +++ b/src/SOS/Strike/disasmRISCV64.cpp @@ -0,0 +1,156 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#undef _TARGET_AMD64_ +#ifndef _TARGET_RISCV64_ +#define _TARGET_RISCV64_ +#endif + +#undef TARGET_AMD64 +#ifndef TARGET_RISCV64 +#define TARGET_RISCV64 +#endif + +#include "strike.h" +#include "util.h" +#include + +#include "disasm.h" + +#include "corhdr.h" +#include "cor.h" +#include "dacprivate.h" + +namespace RISCV64GCDump +{ +#undef TARGET_X86 +#undef LIMITED_METHOD_CONTRACT +#define LIMITED_METHOD_DAC_CONTRACT ((void)0) +#define SUPPORTS_DAC ((void)0) +#define LF_GCROOTS +#define LL_INFO1000 +#define LOG(x) +#define LOG_PIPTR(pObjRef, gcFlags, hCallBack) +#define DAC_ARG(x) +#include "gcdumpnonx86.cpp" +} + +#if !defined(_TARGET_WIN64_) +#error This file only supports SOS targeting RISCV64 from a 64-bit debugger +#endif + +#if !defined(SOS_TARGET_RISCV64) +#error This file should be used to support SOS targeting RISCV64 debuggees +#endif + + +void RISCV64Machine::IsReturnAddress(TADDR retAddr, TADDR* whereCalled) const +{ + *whereCalled = 0; + _ASSERTE("RISCV64:NYI"); +} + +// Determine if a value is MT/MD/Obj +static void HandleValue(TADDR value) +{ + // A MethodTable? + if (IsMethodTable(value)) + { + NameForMT_s (value, g_mdName,mdNameLen); + ExtOut (" (MT: %S)", g_mdName); + return; + } + + // A Managed Object? + TADDR dwMTAddr; + move_xp (dwMTAddr, value); + if (IsStringObject(value)) + { + ExtOut (" (\""); + StringObjectContent (value, TRUE); + ExtOut ("\")"); + return; + } + else if (IsMethodTable(dwMTAddr)) + { + NameForMT_s (dwMTAddr, g_mdName,mdNameLen); + ExtOut (" (Object: %S)", g_mdName); + return; + } + + // A MethodDesc? + if (IsMethodDesc(value)) + { + NameForMD_s (value, g_mdName,mdNameLen); + ExtOut (" (MD: %S)", g_mdName); + return; + } + + // A JitHelper? + const char* name = HelperFuncName(value); + if (name) { + ExtOut (" (JitHelp: %s)", name); + return; + } + + // A call to managed code? + // RISCV64TODO: not (yet) implemented. perhaps we don't need it at all. + + // Random symbol. + char Symbol[1024]; + if (SUCCEEDED(g_ExtSymbols->GetNameByOffset(TO_CDADDR(value), Symbol, 1024, + NULL, NULL))) + { + if (Symbol[0] != '\0') + { + ExtOut (" (%s)", Symbol); + return; + } + } + +} + +/**********************************************************************\ +* Routine Description: * +* * +* Unassembly a managed code. Translating managed object, * +* call. * +* * +\**********************************************************************/ +void RISCV64Machine::Unassembly ( + TADDR PCBegin, + TADDR PCEnd, + TADDR PCAskedFor, + TADDR GCStressCodeCopy, + GCEncodingInfo *pGCEncodingInfo, + SOSEHInfo *pEHInfo, + BOOL bSuppressLines, + BOOL bDisplayOffsets, + std::function displayIL) const +{ + _ASSERTE("RISCV64:NYI"); +} + +BOOL RISCV64Machine::GetExceptionContext (TADDR stack, TADDR PC, TADDR *cxrAddr, CROSS_PLATFORM_CONTEXT * cxr, + TADDR * exrAddr, PEXCEPTION_RECORD exr) const +{ + _ASSERTE("RISCV64:NYI"); + return FALSE; +} + +/// +/// Dump RISCV GCInfo table +/// +void RISCV64Machine::DumpGCInfo(GCInfoToken gcInfoToken, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const +{ + if (bPrintHeader) + { + ExtOut("Pointer table:\n"); + } + + RISCV64GCDump::GCDump gcDump(gcInfoToken.Version, encBytes, 5, true); + gcDump.gcPrintf = gcPrintf; + + gcDump.DumpGCTable(dac_cast(gcInfoToken.Info), methodSize, 0); +} + diff --git a/src/SOS/Strike/exts.cpp b/src/SOS/Strike/exts.cpp index 112e42bd9..2d5190306 100644 --- a/src/SOS/Strike/exts.cpp +++ b/src/SOS/Strike/exts.cpp @@ -132,6 +132,12 @@ GetTargetMachine(ULONG processorType) targetMachine = ARM64Machine::GetInstance(); } #endif // SOS_TARGET_ARM64 +#ifdef SOS_TARGET_RISCV64 + if (processorType == IMAGE_FILE_MACHINE_RISCV64) + { + targetMachine = RISCV64Machine::GetInstance(); + } +#endif // SOS_TARGET_RISCV64 return targetMachine; } @@ -161,6 +167,9 @@ ArchQuery(void) case IMAGE_FILE_MACHINE_ARM64: architecture = "arm64"; break; + case IMAGE_FILE_MACHINE_RISCV64: + architecture = "riscv64"; + break; } ExtErr("SOS does not support the current target architecture '%s' (0x%04x). A 32 bit target may require a 32 bit debugger or vice versa. In general, try to use the same bitness for the debugger and target process.\n", architecture, processorType); diff --git a/src/SOS/Strike/exts.h b/src/SOS/Strike/exts.h index 96876879a..35a1959d9 100644 --- a/src/SOS/Strike/exts.h +++ b/src/SOS/Strike/exts.h @@ -56,6 +56,10 @@ // printing CDA values. #define CDA_TO_UL64(cda) ((ULONG64)(TO_TADDR(cda))) +#ifndef IMAGE_FILE_MACHINE_RISCV64 +#define IMAGE_FILE_MACHINE_RISCV64 0x5064 // RISCV64 +#endif // !IMAGE_FILE_MACHINE_RISCV64 + typedef struct _TADDR_RANGE { TADDR start; @@ -493,6 +497,7 @@ inline BOOL IsDbgTargetX86() { return g_targetMachine->GetPlatform() == IMAGE inline BOOL IsDbgTargetAmd64() { return g_targetMachine->GetPlatform() == IMAGE_FILE_MACHINE_AMD64; } inline BOOL IsDbgTargetArm() { return g_targetMachine->GetPlatform() == IMAGE_FILE_MACHINE_ARMNT; } inline BOOL IsDbgTargetArm64() { return g_targetMachine->GetPlatform() == IMAGE_FILE_MACHINE_ARM64; } +inline BOOL IsDbgTargetRiscV64(){ return g_targetMachine->GetPlatform() == IMAGE_FILE_MACHINE_RISCV64; } inline BOOL IsDbgTargetWin64() { return IsDbgTargetAmd64(); } /* Returns the instruction pointer for the given CONTEXT. We need this and its family of diff --git a/src/SOS/Strike/strike.cpp b/src/SOS/Strike/strike.cpp index 0d7aad0d4..6b693259e 100644 --- a/src/SOS/Strike/strike.cpp +++ b/src/SOS/Strike/strike.cpp @@ -10962,6 +10962,13 @@ public: ExtOut(" cpsr=%08x fpcr=%08x fpsr=%08x\n", context.Arm64Context.Cpsr, context.Arm64Context.Fpcr, context.Arm64Context.Fpsr); } #endif +#if defined(SOS_TARGET_RISCV64) + if (IsDbgTargetRiscV64()) + { + ExtOut("RISCV64:NYI\n"); + } +#endif + if (!foundPlatform) { ExtOut("Can't display register values for this platform\n"); diff --git a/src/SOS/Strike/util.h b/src/SOS/Strike/util.h index 8eb3f60e5..88a27f97c 100644 --- a/src/SOS/Strike/util.h +++ b/src/SOS/Strike/util.h @@ -2416,6 +2416,54 @@ typedef struct { } ARM64_CONTEXT; +///RISCV64 Context +#define RISCV64_MAX_BREAKPOINTS 8 +#define RISCV64_MAX_WATCHPOINTS 2 +typedef struct { + + DWORD ContextFlags; + + DWORD64 R0; + DWORD64 Ra; + DWORD64 Sp; + DWORD64 Gp; + DWORD64 Tp; + DWORD64 T0; + DWORD64 T1; + DWORD64 T2; + DWORD64 Fp; + DWORD64 S1; + DWORD64 A0; + DWORD64 A1; + DWORD64 A2; + DWORD64 A3; + DWORD64 A4; + DWORD64 A5; + DWORD64 A6; + DWORD64 A7; + DWORD64 S2; + DWORD64 S3; + DWORD64 S4; + DWORD64 S5; + DWORD64 S6; + DWORD64 S7; + DWORD64 S8; + DWORD64 S9; + DWORD64 S10; + DWORD64 S11; + DWORD64 T3; + DWORD64 T4; + DWORD64 T5; + DWORD64 T6; + DWORD64 Pc; + + ULONGLONG F[32]; + DWORD Fcsr; + + DWORD Padding[3]; + +} RISCV64_CONTEXT; + typedef struct _CROSS_PLATFORM_CONTEXT { _CROSS_PLATFORM_CONTEXT() {} @@ -2425,6 +2473,7 @@ typedef struct _CROSS_PLATFORM_CONTEXT { AMD64_CONTEXT Amd64Context; ARM_CONTEXT ArmContext; ARM64_CONTEXT Arm64Context; + RISCV64_CONTEXT RiscV64Context; }; } CROSS_PLATFORM_CONTEXT, *PCROSS_PLATFORM_CONTEXT; diff --git a/src/shared/gcdump/gcdumpnonx86.cpp b/src/shared/gcdump/gcdumpnonx86.cpp index 80f24a659..2492c4d29 100644 --- a/src/shared/gcdump/gcdumpnonx86.cpp +++ b/src/shared/gcdump/gcdumpnonx86.cpp @@ -70,6 +70,45 @@ PCSTR GetRegName (UINT32 regnum) _snprintf_s(szRegName, ARRAY_SIZE(szRegName), sizeof(szRegName), "r%u", regnum); return szRegName; +#elif defined(TARGET_RISCV64) + switch (regnum) + { + case 0: return "r0"; + case 1: return "ra"; + case 2: return "sp"; + case 3: return "gp"; + case 4: return "tp"; + case 5: return "t0"; + case 6: return "t1"; + case 7: return "t2"; + case 8: return "fp"; + case 9: return "s1"; + case 10: return "a0"; + case 11: return "a1"; + case 12: return "a2"; + case 13: return "a3"; + case 14: return "a4"; + case 15: return "a5"; + case 16: return "a6"; + case 17: return "a7"; + case 18: return "s2"; + case 19: return "s3"; + case 20: return "s4"; + case 21: return "s5"; + case 22: return "s6"; + case 23: return "s7"; + case 24: return "s8"; + case 25: return "s9"; + case 26: return "s10"; + case 27: return "s11"; + case 28: return "t3"; + case 29: return "t4"; + case 30: return "t5"; + case 31: return "t6"; + case 32: return "pc"; + } + + return "???"; #endif } @@ -285,7 +324,7 @@ size_t GCDump::DumpGCTable(PTR_CBYTE gcInfoBlock, | DECODE_GC_LIFETIMES | DECODE_PROLOG_LENGTH | DECODE_RETURN_KIND -#if defined(TARGET_ARM) || defined(TARGET_ARM64) +#if defined(TARGET_ARM) || defined(TARGET_ARM64) || defined(TARGET_RISCV64) | DECODE_HAS_TAILCALLS #endif ), @@ -438,7 +477,7 @@ size_t GCDump::DumpGCTable(PTR_CBYTE gcInfoBlock, #ifdef TARGET_AMD64 gcPrintf("Wants Report Only Leaf: %u\n", hdrdecoder.WantsReportOnlyLeaf()); -#elif defined(TARGET_ARM) || defined(TARGET_ARM64) +#elif defined(TARGET_ARM) || defined(TARGET_ARM64) || defined(TARGET_RISCV64) gcPrintf("Has tailcalls: %u\n", hdrdecoder.HasTailCalls()); #endif // TARGET_AMD64 #ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA diff --git a/src/shared/gcdump/gcinfodecoder.cpp b/src/shared/gcdump/gcinfodecoder.cpp index c8e1bf3a3..adb22d702 100644 --- a/src/shared/gcdump/gcinfodecoder.cpp +++ b/src/shared/gcdump/gcinfodecoder.cpp @@ -130,7 +130,7 @@ GcInfoDecoder::GcInfoDecoder( int hasStackBaseRegister = headerFlags & GC_INFO_HAS_STACK_BASE_REGISTER; #ifdef TARGET_AMD64 m_WantsReportOnlyLeaf = ((headerFlags & GC_INFO_WANTS_REPORT_ONLY_LEAF) != 0); -#elif defined(TARGET_ARM) || defined(TARGET_ARM64) +#elif defined(TARGET_ARM) || defined(TARGET_ARM64) || defined(TARGET_RISCV64) m_HasTailCalls = ((headerFlags & GC_INFO_HAS_TAILCALLS) != 0); #endif // TARGET_AMD64 int hasSizeOfEditAndContinuePreservedArea = headerFlags & GC_INFO_HAS_EDIT_AND_CONTINUE_PRESERVED_SLOTS; @@ -361,7 +361,7 @@ bool GcInfoDecoder::IsSafePoint(UINT32 codeOffset) if(m_NumSafePoints == 0) return false; -#if defined(TARGET_AMD64) || defined(TARGET_ARM) || defined(TARGET_ARM64) +#if defined(TARGET_AMD64) || defined(TARGET_ARM) || defined(TARGET_ARM64)|| defined(TARGET_RISCV64) // Safepoints are encoded with a -1 adjustment codeOffset--; #endif @@ -381,7 +381,7 @@ UINT32 GcInfoDecoder::FindSafePoint(UINT32 breakOffset) const UINT32 numBitsPerOffset = CeilOfLog2(NORMALIZE_CODE_OFFSET(m_CodeLength)); UINT32 result = m_NumSafePoints; -#if defined(TARGET_ARM) || defined(TARGET_ARM64) +#if defined(TARGET_ARM) || defined(TARGET_ARM64) || defined(TARGET_RISCV64) // Safepoints are encoded with a -1 adjustment // but normalizing them masks off the low order bit // Thus only bother looking if the address is odd @@ -428,7 +428,7 @@ void GcInfoDecoder::EnumerateSafePoints(EnumerateSafePointsCallback *pCallback, UINT32 normOffset = (UINT32)m_Reader.Read(numBitsPerOffset); UINT32 offset = DENORMALIZE_CODE_OFFSET(normOffset) + 2; -#if defined(TARGET_AMD64) || defined(TARGET_ARM) || defined(TARGET_ARM64) +#if defined(TARGET_AMD64) || defined(TARGET_ARM) || defined(TARGET_ARM64) || defined(TARGET_RISCV64) // Safepoints are encoded with a -1 adjustment offset--; #endif @@ -1742,6 +1742,143 @@ OBJECTREF* GcInfoDecoder::GetCapturedRegister( } #endif // TARGET_UNIX && !FEATURE_REDHAWK +#elif defined(TARGET_RISCV64) + +#if defined(TARGET_UNIX) && !defined(FEATURE_REDHAWK) +OBJECTREF* GcInfoDecoder::GetCapturedRegister( + int regNum, + PREGDISPLAY pRD + ) +{ + _ASSERTE(regNum >= 1 && regNum <= 31); + + // The fields of CONTEXT are in the same order as + // the processor encoding numbers. + + DWORD64 *pR0 = &pRD->pCurrentContext->R0; + + return (OBJECTREF*)(pR0 + regNum); +} +#endif // TARGET_UNIX && !FEATURE_REDHAWK + +OBJECTREF* GcInfoDecoder::GetRegisterSlot( + int regNum, + PREGDISPLAY pRD + ) +{ + _ASSERTE((regNum == 1) || (regNum >= 5 && regNum <= 31)); + +#ifdef FEATURE_REDHAWK + PTR_UIntNative* ppReg = &pRD->pR0; + + return (OBJECTREF*)*(ppReg + regNum); +#else + if(regNum == 1) + { + return (OBJECTREF*) pRD->pCurrentContextPointers->Ra; + } + else if (regNum < 8) + { + return (OBJECTREF*)*(DWORD64**)(&pRD->volatileCurrContextPointers.T0 + (regNum - 5)); + } + else if(regNum == 8) + { + return (OBJECTREF*) pRD->pCurrentContextPointers->Fp; + } + else if (regNum == 9) + { + return (OBJECTREF*) pRD->pCurrentContextPointers->S1; + } + else if (regNum < 18) + { + return (OBJECTREF*)*(DWORD64**)(&pRD->volatileCurrContextPointers.A0 + (regNum - 10)); + } + else if (regNum < 28) + { + return (OBJECTREF*)*(DWORD64**)(&pRD->pCurrentContextPointers->S2 + (regNum-18)); + } + return (OBJECTREF*)*(DWORD64**)(&pRD->volatileCurrContextPointers.T3 + (regNum-28)); +#endif +} + +bool GcInfoDecoder::IsScratchRegister(int regNum, PREGDISPLAY pRD) +{ + _ASSERTE(regNum >= 0 && regNum <= 31); + + return (regNum >= 5 && regNum <= 7) || (regNum >= 10 and regNum <= 17) || regNum >= 28 || regNum == 1; +} + +bool GcInfoDecoder::IsScratchStackSlot(INT32 spOffset, GcStackSlotBase spBase, PREGDISPLAY pRD) +{ +#ifdef FIXED_STACK_PARAMETER_SCRATCH_AREA + _ASSERTE( m_Flags & DECODE_GC_LIFETIMES ); + + TADDR pSlot = (TADDR) GetStackSlot(spOffset, spBase, pRD); + _ASSERTE(pSlot >= pRD->SP); + + return (pSlot < pRD->SP + m_SizeOfStackOutgoingAndScratchArea); +#else + return FALSE; +#endif +} + +void GcInfoDecoder::ReportRegisterToGC( + int regNum, + unsigned gcFlags, + PREGDISPLAY pRD, + unsigned flags, + GCEnumCallback pCallBack, + void * hCallBack) +{ + GCINFODECODER_CONTRACT; + + _ASSERTE(regNum > 0 && regNum <= 31); + + LOG((LF_GCROOTS, LL_INFO1000, "Reporting " FMT_REG, regNum )); + + OBJECTREF* pObjRef = GetRegisterSlot( regNum, pRD ); +#if defined(TARGET_UNIX) && !defined(FEATURE_REDHAWK) && !defined(SOS_TARGET_RISCV64) + // On PAL, we don't always have the context pointers available due to + // a limitation of an unwinding library. In such case, the context + // pointers for some nonvolatile registers are NULL. + // In such case, we let the pObjRef point to the captured register + // value in the context and pin the object itself. + if (pObjRef == NULL) + { + // Report a pinned object to GC only in the promotion phase when the + // GC is scanning roots. + GCCONTEXT* pGCCtx = (GCCONTEXT*)(hCallBack); + if (!pGCCtx->sc->promotion) + { + return; + } + + pObjRef = GetCapturedRegister(regNum, pRD); + + gcFlags |= GC_CALL_PINNED; + } +#endif // TARGET_UNIX && !SOS_TARGET_RISCV64 + +#ifdef _DEBUG + if(IsScratchRegister(regNum, pRD)) + { + // Scratch registers cannot be reported for non-leaf frames + _ASSERTE(flags & ActiveStackFrame); + } + + LOG((LF_GCROOTS, LL_INFO1000, /* Part Two */ + "at" FMT_ADDR "as ", DBG_ADDR(pObjRef) )); + + VALIDATE_ROOT((gcFlags & GC_CALL_INTERIOR), hCallBack, pObjRef); + + LOG_PIPTR(pObjRef, gcFlags, hCallBack); +#endif //_DEBUG + + gcFlags |= CHECK_APP_DOMAIN; + + pCallBack(hCallBack, pObjRef, gcFlags DAC_ARG(DacSlotLocation(regNum, 0, false))); +} + #else // Unknown platform OBJECTREF* GcInfoDecoder::GetRegisterSlot( @@ -1827,6 +1964,8 @@ int GcInfoDecoder::GetStackReg(int spBase) int esp = 13; #elif defined(TARGET_ARM64) int esp = 31; +#elif defined(TARGET_RISCV64) + int esp = 2; #endif if( GC_SP_REL == spBase ) diff --git a/src/shared/gcdump/gcinfodumper.cpp b/src/shared/gcdump/gcinfodumper.cpp index 41c427e63..79b09ae04 100644 --- a/src/shared/gcdump/gcinfodumper.cpp +++ b/src/shared/gcdump/gcinfodumper.cpp @@ -185,6 +185,44 @@ BOOL GcInfoDumper::ReportPointerRecord ( REG(Lr, Lr), { FIELD_OFFSET(T_CONTEXT, Sp) }, #undef REG +#elif defined(TARGET_RISCV64) +#undef REG +#define REG(reg, field) { offsetof(RiscV64VolatileContextPointer, field) } + REG(zero, R0), + REG(a0, A0), + REG(a1, A1), + REG(a2, A2), + REG(a3, A3), + REG(a4, A4), + REG(a5, A5), + REG(a6, A6), + REG(a7, A7), + REG(t0, T0), + REG(t1, T1), + REG(t2, T2), + REG(t3, T3), + REG(t4, T4), + REG(t5, T5), + REG(t6, T6), +#undef REG +#define REG(reg, field) { offsetof(T_KNONVOLATILE_CONTEXT_POINTERS, field) } + REG(s1, S1), + REG(s2, S2), + REG(s3, S3), + REG(s4, S4), + REG(s5, S5), + REG(s6, S6), + REG(s7, S7), + REG(s8, S8), + REG(s9, S9), + REG(s10, S10), + REG(s11, S11), + REG(ra, Ra), + REG(gp, Gp), + REG(tp, Tp), + REG(fp, Fp), + { offsetof(T_CONTEXT, Sp) }, +#undef REG #else PORTABILITY_ASSERT("GcInfoDumper::ReportPointerRecord is not implemented on this platform.") #endif @@ -202,6 +240,9 @@ PORTABILITY_ASSERT("GcInfoDumper::ReportPointerRecord is not implemented on this #elif defined(TARGET_ARM) iSPRegister = (FIELD_OFFSET(T_CONTEXT, Sp) - FIELD_OFFSET(T_CONTEXT, R0)) / sizeof(ULONG); UINT iBFRegister = m_StackBaseRegister; +#elif defined(TARGET_RISCV64) + assert(!"unimplemented on RISCV64 yet"); + iSPRegister = 0; #endif #if defined(TARGET_ARM) || defined(TARGET_ARM64) @@ -597,6 +638,9 @@ GcInfoDumper::EnumerateStateChangesResults GcInfoDumper::EnumerateStateChanges ( { *(ppVolatileReg+iReg) = ®disp.pCurrentContext->X0 + iReg; } +#elif defined(TARGET_RISCV64) +#pragma message("Unimplemented for RISCV64 yet.") + assert(!"unimplemented on RISCV64 yet"); #else PORTABILITY_ASSERT("GcInfoDumper::EnumerateStateChanges is not implemented on this platform.") #endif diff --git a/src/shared/inc/gcinfodecoder.h b/src/shared/inc/gcinfodecoder.h index 6ccdbe4aa..2b18fd0dd 100644 --- a/src/shared/inc/gcinfodecoder.h +++ b/src/shared/inc/gcinfodecoder.h @@ -85,6 +85,8 @@ inline TADDR GetSP(T_CONTEXT* context) return (TADDR)context->Sp; #elif defined(TARGET_ARM64) return (TADDR)context->Sp; +#elif defined(TARGET_RISCV64) + return (TADDR)context->Sp; #else _ASSERTE(!"nyi for platform"); #endif @@ -98,6 +100,8 @@ inline PCODE GetIP(T_CONTEXT* context) return (PCODE)context->Pc; #elif defined(TARGET_ARM64) return (PCODE)context->Pc; +#elif defined(TARGET_RISCV64) + return (PCODE)context->Pc; #else _ASSERTE(!"nyi for platform"); #endif @@ -214,7 +218,7 @@ enum GcInfoDecoderFlags DECODE_RETURN_KIND = 0x2000, #if defined(TARGET_ARM) || defined(TARGET_ARM64) || defined(TARGET_RISCV64) DECODE_HAS_TAILCALLS = 0x4000, -#endif // TARGET_ARM || TARGET_ARM64 +#endif // TARGET_ARM || TARGET_ARM64 || TARGET_RISCV64 }; enum GcInfoHeaderFlags