[RISC-V] Add partial SOS 'clrstack' command implementation. (#4356)
authorMikhail Kurinnoi <m.kurinnoi@samsung.com>
Tue, 31 Oct 2023 15:39:59 +0000 (18:39 +0300)
committerMikhail Kurinnoi <m.kurinnoi@samsung.com>
Mon, 4 Dec 2023 14:07:29 +0000 (17:07 +0300)
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.<ReadStdin>g____PInvoke|44_0(Byte*, Int32)
0000003FD9F44F70 0000003f353b5370 [InlinedCallFrame: 0000003fd9f44f70] Interop+Sys.<ReadStdin>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

17 files changed:
src/Microsoft.Diagnostics.DebugServices.Implementation/ThreadService.cs
src/SOS/SOS.Extensions/TargetFromFromDebuggerServices.cs
src/SOS/SOS.Hosting/DataTargetWrapper.cs
src/SOS/SOS.Hosting/DbgEng/Interop/Enums/ImageFileMachine.cs
src/SOS/SOS.Hosting/SOSHost.cs
src/SOS/Strike/CMakeLists.txt
src/SOS/Strike/disasm.cpp
src/SOS/Strike/disasm.h
src/SOS/Strike/disasmRISCV64.cpp [new file with mode: 0644]
src/SOS/Strike/exts.cpp
src/SOS/Strike/exts.h
src/SOS/Strike/strike.cpp
src/SOS/Strike/util.h
src/shared/gcdump/gcdumpnonx86.cpp
src/shared/gcdump/gcinfodecoder.cpp
src/shared/gcdump/gcinfodumper.cpp
src/shared/inc/gcinfodecoder.h

index 4c89c0c83a9979acafbeceb824a8e2cc5d317494..de9149330d14836927452d5427250f2e41081011 100644 (file)
@@ -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}");
             }
index e0c2bee85b63234079439fd4f79491d1628b86de..6e29077ef1a87660d7ab09f155cced4b7d512218 100644 (file)
@@ -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}"),
                 };
             }
index 303e88d825009b84d9b60760d889fa8cdb994e77..f61cbd4310404ab7d5a58db4f669b423514d8699 100644 (file)
@@ -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;
index ebda53b00656998bffd4abb1e6c110cd2c4c34f8..cb9ed62a245b01a52ed5b36ef209996fc3aa9767 100644 (file)
@@ -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
     }
 }
index 0fe569a0faffd59e5058cb7db02095d40798720c..3891c006390ff1004141821c8ef030e19c156bd6 100644 (file)
@@ -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;
index 52456d73870124bac75e07b8d6b49e9532b4bc64..8b095e69ac6be7d4d5739bad276a9db584006892 100644 (file)
@@ -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})
index 10590c165db740462560387e2fa6dabcbddfb8d7..b116c72b98e753e52392774dcd300199632fb826 100644 (file)
@@ -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
 //
index a09e5abecf9a57a6d4fbdb0be91bbceff9e3b2ca..714e0fddab6b9b78afcd1f009e9533b184dfa608 100644 (file)
@@ -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<void(ULONG*, UINT*, BYTE*)> 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 (file)
index 0000000..531fbd7
--- /dev/null
@@ -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 <dbghelp.h>
+
+#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<void(ULONG*, UINT*, BYTE*)> 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<PTR_BYTE>(gcInfoToken.Info), methodSize, 0);
+}
+
index 112e42bd988040d4b9613855e571fae7789d6d5c..2d519030636a82736029bb8b1611e7adc58458fa 100644 (file)
@@ -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);
index 96876879a7bbceeb7e0ffc43251f30ac653ef2b7..35a1959d9614005a07e0c06e819c0ffb26302581 100644 (file)
 // 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
index 0d7aad0d49215a2fe1405ecf5d1ae52cebfc8eff..6b693259e97f7986fe0515e669ee86e5eef43cc5 100644 (file)
@@ -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");
index 8eb3f60e52299da9c80ab804ede03c68322aea1c..88a27f97c24a2f875c08622f311223fb8ab4f866 100644 (file)
@@ -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;
index 80f24a659c4b500a0e681886e2e4e087f19f29ae..2492c4d29ed2218fdaa3f9ff1c6bad94d6d29524 100644 (file)
@@ -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
index c8e1bf3a39ecf7d5233ce98f22b89a52e29d302c..adb22d70231540320cb80e4d444b75cc92c52af2 100644 (file)
@@ -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 )
index 41c427e6357f563eef44c55c94a78c30fee8774c..79b09ae0400d414cebda501616f00036eeb5e47b 100644 (file)
@@ -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) = &regdisp.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
index 6ccdbe4aae665861f8d5317dffa49c8fcecdcca1..2b18fd0dd2f011fbc647a7563c6aad5957da0bea 100644 (file)
@@ -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