Author: Jason Molenda
Date: 2025-04-23T22:10:15-07:00
New Revision: 096ab51de03437e38f97a48b8f2d453fb903414a

URL: 
https://github.com/llvm/llvm-project/commit/096ab51de03437e38f97a48b8f2d453fb903414a
DIFF: 
https://github.com/llvm/llvm-project/commit/096ab51de03437e38f97a48b8f2d453fb903414a.diff

LOG: [lldb][MachO] MachO corefile support for riscv32 binaries (#137092)

Add support for reading a macho corefile with CPU_TYPE_RISCV and the
riscv32 general purpose register file. I added code for the floating
point and exception registers too, but haven't exercised this. If we
start putting the full CSR register bank in a riscv corefile, it'll be
in separate 4k byte chunks, but I don't have a corefile to test against
that so I haven't written the code to read it.

The RegisterContextDarwin_riscv32 is copied & in the style of the other
RegisterContextDarwin classes; it's not the first choice I would make
for representing this, but it wasn't worth changing for this cputype.

rdar://145014653

Added: 
    lldb/source/Plugins/Process/Utility/RegisterContextDarwin_riscv32.cpp
    lldb/source/Plugins/Process/Utility/RegisterContextDarwin_riscv32.h
    lldb/test/API/macosx/riscv32-corefile/Makefile
    lldb/test/API/macosx/riscv32-corefile/TestRV32MachOCorefile.py
    lldb/test/API/macosx/riscv32-corefile/create-empty-riscv-corefile.cpp

Modified: 
    lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
    lldb/source/Plugins/Process/Utility/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp 
b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
index f31b56b9f81e6..9d5e0f886a4a5 100644
--- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
+++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
@@ -12,6 +12,7 @@
 #include "Plugins/Process/Utility/RegisterContextDarwin_arm.h"
 #include "Plugins/Process/Utility/RegisterContextDarwin_arm64.h"
 #include "Plugins/Process/Utility/RegisterContextDarwin_i386.h"
+#include "Plugins/Process/Utility/RegisterContextDarwin_riscv32.h"
 #include "Plugins/Process/Utility/RegisterContextDarwin_x86_64.h"
 #include "lldb/Core/Debugger.h"
 #include "lldb/Core/Module.h"
@@ -769,6 +770,147 @@ class RegisterContextDarwin_arm64_Mach : public 
RegisterContextDarwin_arm64 {
   }
 };
 
+class RegisterContextDarwin_riscv32_Mach
+    : public RegisterContextDarwin_riscv32 {
+public:
+  RegisterContextDarwin_riscv32_Mach(lldb_private::Thread &thread,
+                                     const DataExtractor &data)
+      : RegisterContextDarwin_riscv32(thread, 0) {
+    SetRegisterDataFrom_LC_THREAD(data);
+  }
+
+  void InvalidateAllRegisters() override {
+    // Do nothing... registers are always valid...
+  }
+
+  void SetRegisterDataFrom_LC_THREAD(const DataExtractor &data) {
+    lldb::offset_t offset = 0;
+    SetError(GPRRegSet, Read, -1);
+    SetError(FPURegSet, Read, -1);
+    SetError(EXCRegSet, Read, -1);
+    SetError(CSRRegSet, Read, -1);
+    bool done = false;
+    while (!done) {
+      int flavor = data.GetU32(&offset);
+      uint32_t count = data.GetU32(&offset);
+      lldb::offset_t next_thread_state = offset + (count * 4);
+      switch (flavor) {
+      case GPRRegSet:
+        // x0-x31 + pc
+        if (count >= 32) {
+          for (uint32_t i = 0; i < 32; ++i)
+            ((uint32_t *)&gpr.x0)[i] = data.GetU32(&offset);
+          gpr.pc = data.GetU32(&offset);
+          SetError(GPRRegSet, Read, 0);
+        }
+        offset = next_thread_state;
+        break;
+      case FPURegSet: {
+        // f0-f31 + fcsr
+        if (count >= 32) {
+          for (uint32_t i = 0; i < 32; ++i)
+            ((uint32_t *)&fpr.f0)[i] = data.GetU32(&offset);
+          fpr.fcsr = data.GetU32(&offset);
+          SetError(FPURegSet, Read, 0);
+        }
+      }
+        offset = next_thread_state;
+        break;
+      case EXCRegSet:
+        if (count == 3) {
+          exc.exception = data.GetU32(&offset);
+          exc.fsr = data.GetU32(&offset);
+          exc.far = data.GetU32(&offset);
+          SetError(EXCRegSet, Read, 0);
+        }
+        offset = next_thread_state;
+        break;
+      default:
+        done = true;
+        break;
+      }
+    }
+  }
+
+  static bool Create_LC_THREAD(Thread *thread, Stream &data) {
+    RegisterContextSP reg_ctx_sp(thread->GetRegisterContext());
+    if (reg_ctx_sp) {
+      RegisterContext *reg_ctx = reg_ctx_sp.get();
+
+      data.PutHex32(GPRRegSet); // Flavor
+      data.PutHex32(GPRWordCount);
+      PrintRegisterValue(reg_ctx, "x0", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x1", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x2", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x3", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x4", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x5", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x6", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x7", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x8", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x9", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x10", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x11", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x12", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x13", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x14", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x15", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x16", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x17", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x18", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x19", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x20", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x21", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x22", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x23", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x24", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x25", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x26", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x27", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x28", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x29", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x30", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "x31", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "pc", nullptr, 4, data);
+      data.PutHex32(0); // uint32_t pad at the end
+
+      // Write out the EXC registers
+      data.PutHex32(EXCRegSet);
+      data.PutHex32(EXCWordCount);
+      PrintRegisterValue(reg_ctx, "exception", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "fsr", nullptr, 4, data);
+      PrintRegisterValue(reg_ctx, "far", nullptr, 4, data);
+      return true;
+    }
+    return false;
+  }
+
+protected:
+  int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override { return -1; }
+
+  int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override { return -1; }
+
+  int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override { return -1; }
+
+  int DoReadCSR(lldb::tid_t tid, int flavor, CSR &csr) override { return -1; }
+
+  int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override {
+    return 0;
+  }
+
+  int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override {
+    return 0;
+  }
+
+  int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override {
+    return 0;
+  }
+
+  int DoWriteCSR(lldb::tid_t tid, int flavor, const CSR &csr) override {
+    return 0;
+  }
+};
+
 static uint32_t MachHeaderSizeFromMagic(uint32_t magic) {
   switch (magic) {
   case MH_MAGIC:
@@ -5827,6 +5969,11 @@ ObjectFileMachO::GetThreadContextAtIndex(uint32_t idx,
         reg_ctx_sp =
             std::make_shared<RegisterContextDarwin_x86_64_Mach>(thread, data);
         break;
+
+      case llvm::MachO::CPU_TYPE_RISCV:
+        reg_ctx_sp =
+            std::make_shared<RegisterContextDarwin_riscv32_Mach>(thread, data);
+        break;
       }
     }
   }
@@ -6695,6 +6842,11 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP 
&process_sp,
               RegisterContextDarwin_x86_64_Mach::Create_LC_THREAD(
                   thread_sp.get(), LC_THREAD_datas[thread_idx]);
               break;
+
+            case llvm::MachO::CPU_TYPE_RISCV:
+              RegisterContextDarwin_riscv32_Mach::Create_LC_THREAD(
+                  thread_sp.get(), LC_THREAD_datas[thread_idx]);
+              break;
             }
           }
         }

diff  --git a/lldb/source/Plugins/Process/Utility/CMakeLists.txt 
b/lldb/source/Plugins/Process/Utility/CMakeLists.txt
index f269f5d7d4d74..d29605fddd5cb 100644
--- a/lldb/source/Plugins/Process/Utility/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/Utility/CMakeLists.txt
@@ -20,6 +20,7 @@ add_lldb_library(lldbPluginProcessUtility
   RegisterContextDarwin_arm.cpp
   RegisterContextDarwin_arm64.cpp
   RegisterContextDarwin_i386.cpp
+  RegisterContextDarwin_riscv32.cpp
   RegisterContextDarwin_x86_64.cpp
   RegisterContextDummy.cpp
   RegisterContextFreeBSD_i386.cpp

diff  --git 
a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_riscv32.cpp 
b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_riscv32.cpp
new file mode 100644
index 0000000000000..14f5bc3ea8c49
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_riscv32.cpp
@@ -0,0 +1,1313 @@
+//===-- RegisterContextDarwin_riscv32.cpp
+//------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Scalar.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Compiler.h"
+
+#include <cstddef>
+
+#include <memory>
+
+#include "RegisterContextDarwin_riscv32.h"
+#include "Utility/RISCV_DWARF_Registers.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+enum {
+  gpr_x0 = 0,
+  gpr_x1,
+  gpr_x2,
+  gpr_x3,
+  gpr_x4,
+  gpr_x5,
+  gpr_x6,
+  gpr_x7,
+  gpr_x8,
+  gpr_x9,
+  gpr_x10,
+  gpr_x11,
+  gpr_x12,
+  gpr_x13,
+  gpr_x14,
+  gpr_x15,
+  gpr_x16,
+  gpr_x17,
+  gpr_x18,
+  gpr_x19,
+  gpr_x20,
+  gpr_x21,
+  gpr_x22,
+  gpr_x23,
+  gpr_x24,
+  gpr_x25,
+  gpr_x26,
+  gpr_x27,
+  gpr_x28,
+  gpr_x29,
+  gpr_x30,
+  gpr_x31,
+  gpr_pc,
+
+  fpr_f0,
+  fpr_f1,
+  fpr_f2,
+  fpr_f3,
+  fpr_f4,
+  fpr_f5,
+  fpr_f6,
+  fpr_f7,
+  fpr_f8,
+  fpr_f9,
+  fpr_f10,
+  fpr_f11,
+  fpr_f12,
+  fpr_f13,
+  fpr_f14,
+  fpr_f15,
+  fpr_f16,
+  fpr_f17,
+  fpr_f18,
+  fpr_f19,
+  fpr_f20,
+  fpr_f21,
+  fpr_f22,
+  fpr_f23,
+  fpr_f24,
+  fpr_f25,
+  fpr_f26,
+  fpr_f27,
+  fpr_f28,
+  fpr_f29,
+  fpr_f30,
+  fpr_f31,
+  fpr_fcsr,
+
+  exc_exception,
+  exc_fsr,
+  exc_far,
+
+  csr_bank,
+
+  k_num_registers
+};
+
+/* clang-format off */
+#define GPR_OFFSET(reg)                                                        
\
+  (LLVM_EXTENSION offsetof(RegisterContextDarwin_riscv32::GPR, reg))
+#define FPU_OFFSET(reg)                                                        
\
+  (LLVM_EXTENSION offsetof(RegisterContextDarwin_riscv32::FPU, reg) +          
\
+   sizeof(RegisterContextDarwin_riscv32::GPR))
+#define EXC_OFFSET(reg)                                                        
\
+  (LLVM_EXTENSION offsetof(RegisterContextDarwin_riscv32::EXC, reg) +          
\
+   sizeof(RegisterContextDarwin_riscv32::GPR) +                                
\
+   sizeof(RegisterContextDarwin_riscv32::FPU))
+
+// These macros will auto define the register name, alt name, register size,
+// register offset, encoding, format and native register. This ensures that the
+// register state structures are defined correctly and have the correct sizes
+// and offsets.
+#define DEFINE_GPR_ABI(reg, canon)                                             
\
+      #reg, #canon,                                                            
\
+      sizeof(((RegisterContextDarwin_riscv32::GPR *)nullptr)->canon),          
\
+      GPR_OFFSET(canon), eEncodingUint, eFormatHex
+#define DEFINE_GPR(reg)                                                        
\
+      #reg, nullptr,                                                           
\
+      sizeof(((RegisterContextDarwin_riscv32::GPR *)nullptr)->reg),            
\
+      GPR_OFFSET(reg), eEncodingUint, eFormatHex
+#define DEFINE_FPU_ABI(reg, canon)                                             
\
+      #reg, #canon,                                                            
\
+      sizeof(((RegisterContextDarwin_riscv32::FPU *)nullptr)->canon),          
\
+      FPU_OFFSET(canon), eEncodingUint, eFormatHex
+#define DEFINE_FPU(reg)                                                        
\
+      #reg, nullptr,                                                           
\
+      sizeof(((RegisterContextDarwin_riscv32::FPU *)nullptr)->reg),            
\
+      FPU_OFFSET(reg), eEncodingUint, eFormatHex
+#define DEFINE_EXC(reg)                                                        
\
+      #reg, nullptr,                                                           
\
+      sizeof(((RegisterContextDarwin_riscv32::EXC *)nullptr)->reg),            
\
+      EXC_OFFSET(reg), eEncodingUint, eFormatHex
+#define REG_CONTEXT_SIZE                                                       
\
+  (sizeof(RegisterContextDarwin_riscv32::GPR) +                                
\
+   sizeof(RegisterContextDarwin_riscv32::FPU) +                                
\
+   sizeof(RegisterContextDarwin_riscv32::EXC) +                                
\
+   sizeof(RegisterContextDarwin_riscv32::CSR))
+/* clang-format on */
+
+static RegisterInfo g_register_infos[] = {
+    {
+        DEFINE_GPR_ABI(zero, x0),
+        {riscv_dwarf::dwarf_gpr_x0, riscv_dwarf::dwarf_gpr_x0,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x0},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(ra, x1),
+        {riscv_dwarf::dwarf_gpr_x1, riscv_dwarf::dwarf_gpr_x1,
+         LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM, gpr_x1},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(sp, x2),
+        {riscv_dwarf::dwarf_gpr_x2, riscv_dwarf::dwarf_gpr_x2,
+         LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM, gpr_x2},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(gp, x3),
+        {riscv_dwarf::dwarf_gpr_x3, riscv_dwarf::dwarf_gpr_x3,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x3},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(tp, x4),
+        {riscv_dwarf::dwarf_gpr_x4, riscv_dwarf::dwarf_gpr_x4,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x4},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(t0, x5),
+        {riscv_dwarf::dwarf_gpr_x5, riscv_dwarf::dwarf_gpr_x5,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x5},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(t1, x6),
+        {riscv_dwarf::dwarf_gpr_x6, riscv_dwarf::dwarf_gpr_x6,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x6},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(t2, x7),
+        {riscv_dwarf::dwarf_gpr_x7, riscv_dwarf::dwarf_gpr_x7,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x7},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(fp, x8),
+        {riscv_dwarf::dwarf_gpr_x8, riscv_dwarf::dwarf_gpr_x8,
+         LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM, gpr_x8},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(s1, x9),
+        {riscv_dwarf::dwarf_gpr_x9, riscv_dwarf::dwarf_gpr_x9,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x9},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(a0, x10),
+        {riscv_dwarf::dwarf_gpr_x10, riscv_dwarf::dwarf_gpr_x10,
+         LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM, gpr_x10},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(a1, x11),
+        {riscv_dwarf::dwarf_gpr_x11, riscv_dwarf::dwarf_gpr_x11,
+         LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM, gpr_x11},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(a2, x12),
+        {riscv_dwarf::dwarf_gpr_x12, riscv_dwarf::dwarf_gpr_x12,
+         LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM, gpr_x12},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(a3, x13),
+        {riscv_dwarf::dwarf_gpr_x13, riscv_dwarf::dwarf_gpr_x13,
+         LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM, gpr_x13},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(a4, x14),
+        {riscv_dwarf::dwarf_gpr_x14, riscv_dwarf::dwarf_gpr_x14,
+         LLDB_REGNUM_GENERIC_ARG5, LLDB_INVALID_REGNUM, gpr_x14},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(a5, x15),
+        {riscv_dwarf::dwarf_gpr_x15, riscv_dwarf::dwarf_gpr_x15,
+         LLDB_REGNUM_GENERIC_ARG6, LLDB_INVALID_REGNUM, gpr_x15},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(a6, x16),
+        {riscv_dwarf::dwarf_gpr_x16, riscv_dwarf::dwarf_gpr_x16,
+         LLDB_REGNUM_GENERIC_ARG7, LLDB_INVALID_REGNUM, gpr_x16},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(a7, x17),
+        {riscv_dwarf::dwarf_gpr_x17, riscv_dwarf::dwarf_gpr_x17,
+         LLDB_REGNUM_GENERIC_ARG8, LLDB_INVALID_REGNUM, gpr_x17},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(s2, x18),
+        {riscv_dwarf::dwarf_gpr_x18, riscv_dwarf::dwarf_gpr_x18,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x18},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(s3, x19),
+        {riscv_dwarf::dwarf_gpr_x19, riscv_dwarf::dwarf_gpr_x19,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x19},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(s4, x20),
+        {riscv_dwarf::dwarf_gpr_x20, riscv_dwarf::dwarf_gpr_x20,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x20},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(s5, x21),
+        {riscv_dwarf::dwarf_gpr_x21, riscv_dwarf::dwarf_gpr_x21,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x21},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(s6, x22),
+        {riscv_dwarf::dwarf_gpr_x22, riscv_dwarf::dwarf_gpr_x22,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x22},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(s7, x23),
+        {riscv_dwarf::dwarf_gpr_x23, riscv_dwarf::dwarf_gpr_x23,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x23},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(s8, x24),
+        {riscv_dwarf::dwarf_gpr_x24, riscv_dwarf::dwarf_gpr_x24,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x24},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(s9, x25),
+        {riscv_dwarf::dwarf_gpr_x25, riscv_dwarf::dwarf_gpr_x25,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x25},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(s10, x26),
+        {riscv_dwarf::dwarf_gpr_x26, riscv_dwarf::dwarf_gpr_x26,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x26},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(s11, x27),
+        {riscv_dwarf::dwarf_gpr_x27, riscv_dwarf::dwarf_gpr_x27,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x27},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(t3, x28),
+        {riscv_dwarf::dwarf_gpr_x28, riscv_dwarf::dwarf_gpr_x28,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x28},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(t4, x29),
+        {riscv_dwarf::dwarf_gpr_x29, riscv_dwarf::dwarf_gpr_x29,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x29},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(t5, x30),
+        {riscv_dwarf::dwarf_gpr_x30, riscv_dwarf::dwarf_gpr_x30,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x30},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR_ABI(t6, x31),
+        {riscv_dwarf::dwarf_gpr_x31, riscv_dwarf::dwarf_gpr_x31,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x31},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_GPR(pc),
+        {riscv_dwarf::dwarf_gpr_pc, riscv_dwarf::dwarf_gpr_pc,
+         LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM, gpr_pc},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+
+    {
+        DEFINE_FPU_ABI(ft0, f0),
+        {riscv_dwarf::dwarf_fpr_f0, riscv_dwarf::dwarf_fpr_f0,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f0},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(ft1, f1),
+        {riscv_dwarf::dwarf_fpr_f1, riscv_dwarf::dwarf_fpr_f1,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f1},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(ft2, f2),
+        {riscv_dwarf::dwarf_fpr_f2, riscv_dwarf::dwarf_fpr_f2,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f2},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(ft3, f3),
+        {riscv_dwarf::dwarf_fpr_f3, riscv_dwarf::dwarf_fpr_f3,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f3},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(ft4, f4),
+        {riscv_dwarf::dwarf_fpr_f4, riscv_dwarf::dwarf_fpr_f4,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f4},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(ft5, f5),
+        {riscv_dwarf::dwarf_fpr_f5, riscv_dwarf::dwarf_fpr_f5,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f5},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(ft6, f6),
+        {riscv_dwarf::dwarf_fpr_f6, riscv_dwarf::dwarf_fpr_f6,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f6},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(ft7, f7),
+        {riscv_dwarf::dwarf_fpr_f7, riscv_dwarf::dwarf_fpr_f7,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f7},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(fs0, f8),
+        {riscv_dwarf::dwarf_fpr_f8, riscv_dwarf::dwarf_fpr_f8,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f8},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(fs1, f9),
+        {riscv_dwarf::dwarf_fpr_f9, riscv_dwarf::dwarf_fpr_f9,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f9},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(fa0, f10),
+        {riscv_dwarf::dwarf_fpr_f10, riscv_dwarf::dwarf_fpr_f10,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f10},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(fa1, f11),
+        {riscv_dwarf::dwarf_fpr_f11, riscv_dwarf::dwarf_fpr_f11,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f11},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(fa2, f12),
+        {riscv_dwarf::dwarf_fpr_f12, riscv_dwarf::dwarf_fpr_f12,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f12},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(fa3, f13),
+        {riscv_dwarf::dwarf_fpr_f13, riscv_dwarf::dwarf_fpr_f13,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f13},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(fa4, f14),
+        {riscv_dwarf::dwarf_fpr_f14, riscv_dwarf::dwarf_fpr_f14,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f14},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(fa5, f15),
+        {riscv_dwarf::dwarf_fpr_f15, riscv_dwarf::dwarf_fpr_f15,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f15},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(fa6, f16),
+        {riscv_dwarf::dwarf_fpr_f16, riscv_dwarf::dwarf_fpr_f16,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f16},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(fa7, f17),
+        {riscv_dwarf::dwarf_fpr_f17, riscv_dwarf::dwarf_fpr_f17,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f17},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(fs2, f18),
+        {riscv_dwarf::dwarf_fpr_f18, riscv_dwarf::dwarf_fpr_f18,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f18},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(fs3, f19),
+        {riscv_dwarf::dwarf_fpr_f19, riscv_dwarf::dwarf_fpr_f19,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f19},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(fs4, f20),
+        {riscv_dwarf::dwarf_fpr_f20, riscv_dwarf::dwarf_fpr_f20,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f20},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(fs5, f21),
+        {riscv_dwarf::dwarf_fpr_f21, riscv_dwarf::dwarf_fpr_f21,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f21},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(fs6, f22),
+        {riscv_dwarf::dwarf_fpr_f22, riscv_dwarf::dwarf_fpr_f22,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f22},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(fs7, f23),
+        {riscv_dwarf::dwarf_fpr_f23, riscv_dwarf::dwarf_fpr_f23,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f23},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(fs8, f24),
+        {riscv_dwarf::dwarf_fpr_f24, riscv_dwarf::dwarf_fpr_f24,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f24},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(fs9, f25),
+        {riscv_dwarf::dwarf_fpr_f25, riscv_dwarf::dwarf_fpr_f25,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f25},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(fs10, f26),
+        {riscv_dwarf::dwarf_fpr_f26, riscv_dwarf::dwarf_fpr_f26,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f26},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(fs11, f27),
+        {riscv_dwarf::dwarf_fpr_f27, riscv_dwarf::dwarf_fpr_f27,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f27},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(ft8, f28),
+        {riscv_dwarf::dwarf_fpr_f28, riscv_dwarf::dwarf_fpr_f28,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f28},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(ft9, f29),
+        {riscv_dwarf::dwarf_fpr_f29, riscv_dwarf::dwarf_fpr_f29,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f29},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(ft10, f30),
+        {riscv_dwarf::dwarf_fpr_f30, riscv_dwarf::dwarf_fpr_f30,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f30},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU_ABI(ft11, f31),
+        {riscv_dwarf::dwarf_fpr_f31, riscv_dwarf::dwarf_fpr_f31,
+         LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_f31},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_FPU(fcsr),
+        {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+         LLDB_INVALID_REGNUM, fpr_fcsr},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+
+    {
+        DEFINE_EXC(exception),
+        {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+         LLDB_INVALID_REGNUM, exc_exception},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_EXC(fsr),
+        {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+         LLDB_INVALID_REGNUM, exc_fsr},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {
+        DEFINE_EXC(far),
+        {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+         LLDB_INVALID_REGNUM, exc_far},
+        nullptr,
+        nullptr,
+        nullptr,
+    },
+    {"csr",
+     nullptr,
+     1024 * sizeof(uint32_t),
+     0,
+     eEncodingVector,
+     eFormatVectorOfUInt32,
+     {LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+      LLDB_INVALID_REGNUM, csr_bank},
+     nullptr,
+     nullptr,
+     nullptr}};
+
+static size_t k_num_register_infos = std::size(g_register_infos);
+
+RegisterContextDarwin_riscv32::RegisterContextDarwin_riscv32(
+    Thread &thread, uint32_t concrete_frame_idx)
+    : RegisterContext(thread, concrete_frame_idx), gpr(), fpr(), exc() {
+  uint32_t i;
+  for (i = 0; i < kNumErrors; i++) {
+    gpr_errs[i] = -1;
+    fpr_errs[i] = -1;
+    exc_errs[i] = -1;
+    csr_errs[i] = -1;
+  }
+}
+
+RegisterContextDarwin_riscv32::~RegisterContextDarwin_riscv32() = default;
+
+void RegisterContextDarwin_riscv32::InvalidateAllRegisters() {
+  InvalidateAllRegisterStates();
+}
+
+size_t RegisterContextDarwin_riscv32::GetRegisterCount() {
+  assert(k_num_register_infos == k_num_registers);
+  return k_num_registers;
+}
+
+const RegisterInfo *
+RegisterContextDarwin_riscv32::GetRegisterInfoAtIndex(size_t reg) {
+  assert(k_num_register_infos == k_num_registers);
+  if (reg < k_num_registers)
+    return &g_register_infos[reg];
+  return nullptr;
+}
+
+size_t RegisterContextDarwin_riscv32::GetRegisterInfosCount() {
+  return k_num_register_infos;
+}
+
+const RegisterInfo *RegisterContextDarwin_riscv32::GetRegisterInfos() {
+  return g_register_infos;
+}
+
+// General purpose registers
+static uint32_t g_gpr_regnums[] = {
+    gpr_x0,  gpr_x1,  gpr_x2,  gpr_x3,  gpr_x4,  gpr_x5,  gpr_x6,
+    gpr_x7,  gpr_x8,  gpr_x9,  gpr_x10, gpr_x11, gpr_x12, gpr_x13,
+    gpr_x14, gpr_x15, gpr_x16, gpr_x17, gpr_x18, gpr_x19, gpr_x20,
+    gpr_x21, gpr_x22, gpr_x23, gpr_x24, gpr_x25, gpr_x26, gpr_x27,
+    gpr_x28, gpr_x29, gpr_x30, gpr_x31, gpr_pc};
+
+// Floating point registers
+static uint32_t g_fpr_regnums[] = {
+    fpr_f0,  fpr_f1,  fpr_f2,  fpr_f3,  fpr_f4,  fpr_f5,  fpr_f6,
+    fpr_f7,  fpr_f8,  fpr_f9,  fpr_f10, fpr_f11, fpr_f12, fpr_f13,
+    fpr_f14, fpr_f15, fpr_f16, fpr_f17, fpr_f18, fpr_f19, fpr_f20,
+    fpr_f21, fpr_f22, fpr_f23, fpr_f24, fpr_f25, fpr_f26, fpr_f27,
+    fpr_f28, fpr_f29, fpr_f30, fpr_f31, fpr_fcsr};
+
+// Exception registers
+
+static uint32_t g_exc_regnums[] = {exc_exception, exc_fsr, exc_far};
+
+// CSR bank registers
+static uint32_t g_csr_regnums[] = {csr_bank};
+
+// Number of registers in each register set
+const size_t k_num_gpr_registers = std::size(g_gpr_regnums);
+const size_t k_num_fpr_registers = std::size(g_fpr_regnums);
+const size_t k_num_exc_registers = std::size(g_exc_regnums);
+const size_t k_num_csr_registers = std::size(g_csr_regnums);
+
+// Register set definitions. The first definitions at register set index of
+// zero is for all registers, followed by other registers sets. The register
+// information for the all register set need not be filled in.
+static const RegisterSet g_reg_sets[] = {
+    {
+        "General Purpose Registers",
+        "gpr",
+        k_num_gpr_registers,
+        g_gpr_regnums,
+    },
+    {"Floating Point Registers", "fpr", k_num_fpr_registers, g_fpr_regnums},
+    {"Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums},
+    {"CSR register bank", "csr", k_num_csr_registers, g_csr_regnums}};
+
+const size_t k_num_regsets = std::size(g_reg_sets);
+
+size_t RegisterContextDarwin_riscv32::GetRegisterSetCount() {
+  return k_num_regsets;
+}
+
+const RegisterSet *
+RegisterContextDarwin_riscv32::GetRegisterSet(size_t reg_set) {
+  if (reg_set < k_num_regsets)
+    return &g_reg_sets[reg_set];
+  return nullptr;
+}
+
+// Register information definitions for 32 bit riscv32.
+int RegisterContextDarwin_riscv32::GetSetForNativeRegNum(int reg_num) {
+  if (reg_num < fpr_f0)
+    return GPRRegSet;
+  else if (reg_num < exc_exception)
+    return FPURegSet;
+  else if (reg_num < csr_bank)
+    return EXCRegSet;
+  else if (reg_num < k_num_registers)
+    return CSRRegSet;
+  return -1;
+}
+
+void RegisterContextDarwin_riscv32::LogGPR(Log *log, const char *title) {
+  if (log) {
+    if (title)
+      LLDB_LOGF(log, "%s", title);
+    for (uint32_t i = 0; i < k_num_gpr_registers; i++) {
+      uint32_t reg = gpr_x0 + i;
+      LLDB_LOGF(log, "%12s = 0x%4.4x", g_register_infos[reg].name,
+                (&gpr.x0)[reg]);
+    }
+  }
+}
+
+int RegisterContextDarwin_riscv32::ReadGPR(bool force) {
+  int set = GPRRegSet;
+  if (force || !RegisterSetIsCached(set)) {
+    SetError(set, Read, DoReadGPR(GetThreadID(), set, gpr));
+  }
+  return GetError(set, Read);
+}
+
+int RegisterContextDarwin_riscv32::ReadFPU(bool force) {
+  int set = FPURegSet;
+  if (force || !RegisterSetIsCached(set)) {
+    SetError(set, Read, DoReadFPU(GetThreadID(), set, fpr));
+  }
+  return GetError(set, Read);
+}
+
+int RegisterContextDarwin_riscv32::ReadEXC(bool force) {
+  int set = EXCRegSet;
+  if (force || !RegisterSetIsCached(set)) {
+    SetError(set, Read, DoReadEXC(GetThreadID(), set, exc));
+  }
+  return GetError(set, Read);
+}
+
+int RegisterContextDarwin_riscv32::ReadCSR(bool force) {
+  int set = CSRRegSet;
+  if (force || !RegisterSetIsCached(set)) {
+    SetError(set, Read, DoReadCSR(GetThreadID(), set, csr));
+  }
+  return GetError(set, Read);
+}
+
+int RegisterContextDarwin_riscv32::WriteGPR() {
+  int set = GPRRegSet;
+  if (!RegisterSetIsCached(set)) {
+    SetError(set, Write, -1);
+    return -1;
+  }
+  SetError(set, Write, DoWriteGPR(GetThreadID(), set, gpr));
+  SetError(set, Read, -1);
+  return GetError(set, Write);
+}
+
+int RegisterContextDarwin_riscv32::WriteFPU() {
+  int set = FPURegSet;
+  if (!RegisterSetIsCached(set)) {
+    SetError(set, Write, -1);
+    return -1;
+  }
+  SetError(set, Write, DoWriteFPU(GetThreadID(), set, fpr));
+  SetError(set, Read, -1);
+  return GetError(set, Write);
+}
+
+int RegisterContextDarwin_riscv32::WriteEXC() {
+  int set = EXCRegSet;
+  if (!RegisterSetIsCached(set)) {
+    SetError(set, Write, -1);
+    return -1;
+  }
+  SetError(set, Write, DoWriteEXC(GetThreadID(), set, exc));
+  SetError(set, Read, -1);
+  return GetError(set, Write);
+}
+
+int RegisterContextDarwin_riscv32::WriteCSR() {
+  int set = CSRRegSet;
+  if (!RegisterSetIsCached(set)) {
+    SetError(set, Write, -1);
+    return -1;
+  }
+  SetError(set, Write, DoWriteCSR(GetThreadID(), set, csr));
+  SetError(set, Read, -1);
+  return GetError(set, Write);
+}
+
+int RegisterContextDarwin_riscv32::ReadRegisterSet(uint32_t set, bool force) {
+  switch (set) {
+  case GPRRegSet:
+    return ReadGPR(force);
+  case FPURegSet:
+    return ReadFPU(force);
+  case EXCRegSet:
+    return ReadEXC(force);
+  case CSRRegSet:
+    return ReadCSR(force);
+  default:
+    break;
+  }
+  return -1;
+}
+
+int RegisterContextDarwin_riscv32::WriteRegisterSet(uint32_t set) {
+  // Make sure we have a valid context to set.
+  if (RegisterSetIsCached(set)) {
+    switch (set) {
+    case GPRRegSet:
+      return WriteGPR();
+    case FPURegSet:
+      return WriteFPU();
+    case EXCRegSet:
+      return WriteEXC();
+    case CSRRegSet:
+      return WriteCSR();
+    default:
+      break;
+    }
+  }
+  return -1;
+}
+
+bool RegisterContextDarwin_riscv32::ReadRegister(const RegisterInfo *reg_info,
+                                                 RegisterValue &value) {
+  const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+  int set = RegisterContextDarwin_riscv32::GetSetForNativeRegNum(reg);
+
+  if (set == -1)
+    return false;
+
+  if (ReadRegisterSet(set, false) != 0)
+    return false;
+
+  switch (reg) {
+  case gpr_x0:
+  case gpr_x1:
+  case gpr_x2:
+  case gpr_x3:
+  case gpr_x4:
+  case gpr_x5:
+  case gpr_x6:
+  case gpr_x7:
+  case gpr_x8:
+  case gpr_x9:
+  case gpr_x10:
+  case gpr_x11:
+  case gpr_x12:
+  case gpr_x13:
+  case gpr_x14:
+  case gpr_x15:
+  case gpr_x16:
+  case gpr_x17:
+  case gpr_x18:
+  case gpr_x19:
+  case gpr_x20:
+  case gpr_x21:
+  case gpr_x22:
+  case gpr_x23:
+  case gpr_x24:
+  case gpr_x25:
+  case gpr_x26:
+  case gpr_x27:
+  case gpr_x28:
+  case gpr_x29:
+  case gpr_x30:
+  case gpr_x31:
+  case gpr_pc:
+    value = (&gpr.x0)[reg - gpr_x0];
+    break;
+
+  case fpr_f0:
+  case fpr_f1:
+  case fpr_f2:
+  case fpr_f3:
+  case fpr_f4:
+  case fpr_f5:
+  case fpr_f6:
+  case fpr_f7:
+  case fpr_f8:
+  case fpr_f9:
+  case fpr_f10:
+  case fpr_f11:
+  case fpr_f12:
+  case fpr_f13:
+  case fpr_f14:
+  case fpr_f15:
+  case fpr_f16:
+  case fpr_f17:
+  case fpr_f18:
+  case fpr_f19:
+  case fpr_f20:
+  case fpr_f21:
+  case fpr_f22:
+  case fpr_f23:
+  case fpr_f24:
+  case fpr_f25:
+  case fpr_f26:
+  case fpr_f27:
+  case fpr_f28:
+  case fpr_f29:
+  case fpr_f30:
+  case fpr_f31:
+  case fpr_fcsr:
+    value = (&fpr.f0)[reg - fpr_f0];
+    break;
+
+  case exc_exception:
+    value = exc.exception;
+    break;
+
+  case exc_fsr:
+    value = exc.fsr;
+    break;
+
+  case exc_far:
+    value = exc.far;
+    break;
+
+  case csr_bank:
+    // These values don't fit into scalar types,
+    // RegisterContext::ReadRegisterBytes() must be used for these registers
+    //::memcpy (reg_value.value.vector.uint8, fpu.stmm[reg - fpu_stmm0].bytes,
+    // 10);
+
+    // AArch64 copies NEON registers with
+    // value.SetBytes(csr.bytes, reg_info->byte_size,
+    //                endian::InlHostByteOrder());
+    return false;
+
+  default:
+    return false;
+  }
+  return true;
+}
+
+bool RegisterContextDarwin_riscv32::WriteRegister(const RegisterInfo *reg_info,
+                                                  const RegisterValue &value) {
+  const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+  int set = GetSetForNativeRegNum(reg);
+
+  if (set == -1)
+    return false;
+
+  if (ReadRegisterSet(set, false) != 0)
+    return false;
+
+  switch (reg) {
+  case gpr_x0:
+  case gpr_x1:
+  case gpr_x2:
+  case gpr_x3:
+  case gpr_x4:
+  case gpr_x5:
+  case gpr_x6:
+  case gpr_x7:
+  case gpr_x8:
+  case gpr_x9:
+  case gpr_x10:
+  case gpr_x11:
+  case gpr_x12:
+  case gpr_x13:
+  case gpr_x14:
+  case gpr_x15:
+  case gpr_x16:
+  case gpr_x17:
+  case gpr_x18:
+  case gpr_x19:
+  case gpr_x20:
+  case gpr_x21:
+  case gpr_x22:
+  case gpr_x23:
+  case gpr_x24:
+  case gpr_x25:
+  case gpr_x26:
+  case gpr_x27:
+  case gpr_x28:
+  case gpr_x29:
+  case gpr_x30:
+  case gpr_x31:
+  case gpr_pc:
+    (&gpr.x0)[reg - gpr_x0] = value.GetAsUInt32();
+    break;
+
+  case fpr_f0:
+  case fpr_f1:
+  case fpr_f2:
+  case fpr_f3:
+  case fpr_f4:
+  case fpr_f5:
+  case fpr_f6:
+  case fpr_f7:
+  case fpr_f8:
+  case fpr_f9:
+  case fpr_f10:
+  case fpr_f11:
+  case fpr_f12:
+  case fpr_f13:
+  case fpr_f14:
+  case fpr_f15:
+  case fpr_f16:
+  case fpr_f17:
+  case fpr_f18:
+  case fpr_f19:
+  case fpr_f20:
+  case fpr_f21:
+  case fpr_f22:
+  case fpr_f23:
+  case fpr_f24:
+  case fpr_f25:
+  case fpr_f26:
+  case fpr_f27:
+  case fpr_f28:
+  case fpr_f29:
+  case fpr_f30:
+  case fpr_f31:
+  case fpr_fcsr:
+    (&fpr.f0)[reg - fpr_f0] = value.GetAsUInt32();
+    break;
+
+  case exc_exception:
+    exc.exception = value.GetAsUInt32();
+    break;
+
+  case exc_fsr:
+    exc.fsr = value.GetAsUInt32();
+    break;
+
+  case exc_far:
+    exc.far = value.GetAsUInt32();
+    break;
+
+  case csr_bank:
+    // These values don't fit into scalar types,
+    // RegisterContext::ReadRegisterBytes() must be used for these registers
+    //::memcpy(csr.bytes, value.GetBytes(),
+    // value.GetByteSize());
+    return false;
+
+  default:
+    return false;
+  }
+  return WriteRegisterSet(set) == 0;
+}
+
+bool RegisterContextDarwin_riscv32::ReadAllRegisterValues(
+    lldb::WritableDataBufferSP &data_sp) {
+  data_sp = std::make_shared<DataBufferHeap>(REG_CONTEXT_SIZE, 0);
+  if (ReadGPR(false) == 0 && ReadFPU(false) == 0 && ReadEXC(false) == 0 &&
+      ReadCSR(false) == 0) {
+    uint8_t *dst = data_sp->GetBytes();
+    ::memcpy(dst, &gpr, sizeof(gpr));
+    dst += sizeof(gpr);
+
+    ::memcpy(dst, &fpr, sizeof(fpr));
+    dst += sizeof(gpr);
+
+    ::memcpy(dst, &exc, sizeof(exc));
+    return true;
+
+    ::memcpy(dst, &csr, sizeof(csr));
+    return true;
+  }
+  return false;
+}
+
+bool RegisterContextDarwin_riscv32::WriteAllRegisterValues(
+    const lldb::DataBufferSP &data_sp) {
+  if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) {
+    const uint8_t *src = data_sp->GetBytes();
+    ::memcpy(&gpr, src, sizeof(gpr));
+    src += sizeof(gpr);
+
+    ::memcpy(&fpr, src, sizeof(fpr));
+    src += sizeof(fpr);
+
+    ::memcpy(&exc, src, sizeof(exc));
+    src += sizeof(exc);
+
+    ::memcpy(&csr, src, sizeof(csr));
+    uint32_t success_count = 0;
+
+    if (WriteGPR() == 0)
+      ++success_count;
+    if (WriteFPU() == 0)
+      ++success_count;
+    if (WriteEXC() == 0)
+      ++success_count;
+    if (WriteCSR() == 0)
+      ++success_count;
+    return success_count == 3;
+  }
+  return false;
+}
+
+uint32_t RegisterContextDarwin_riscv32::ConvertRegisterKindToRegisterNumber(
+    lldb::RegisterKind kind, uint32_t reg) {
+  if (kind == eRegisterKindGeneric) {
+    switch (reg) {
+    case LLDB_REGNUM_GENERIC_PC:
+      return gpr_pc;
+    case LLDB_REGNUM_GENERIC_SP:
+      return gpr_x2;
+    case LLDB_REGNUM_GENERIC_FP:
+      return gpr_x8;
+    case LLDB_REGNUM_GENERIC_RA:
+      return gpr_x1;
+    default:
+      break;
+    }
+  } else if (kind == eRegisterKindEHFrame || kind == eRegisterKindDWARF) {
+    switch (reg) {
+    case riscv_dwarf::dwarf_gpr_x0:
+    case riscv_dwarf::dwarf_gpr_x1:
+    case riscv_dwarf::dwarf_gpr_x2:
+    case riscv_dwarf::dwarf_gpr_x3:
+    case riscv_dwarf::dwarf_gpr_x4:
+    case riscv_dwarf::dwarf_gpr_x5:
+    case riscv_dwarf::dwarf_gpr_x6:
+    case riscv_dwarf::dwarf_gpr_x7:
+    case riscv_dwarf::dwarf_gpr_x8:
+    case riscv_dwarf::dwarf_gpr_x9:
+    case riscv_dwarf::dwarf_gpr_x10:
+    case riscv_dwarf::dwarf_gpr_x11:
+    case riscv_dwarf::dwarf_gpr_x12:
+    case riscv_dwarf::dwarf_gpr_x13:
+    case riscv_dwarf::dwarf_gpr_x14:
+    case riscv_dwarf::dwarf_gpr_x15:
+    case riscv_dwarf::dwarf_gpr_x16:
+    case riscv_dwarf::dwarf_gpr_x17:
+    case riscv_dwarf::dwarf_gpr_x18:
+    case riscv_dwarf::dwarf_gpr_x19:
+    case riscv_dwarf::dwarf_gpr_x20:
+    case riscv_dwarf::dwarf_gpr_x21:
+    case riscv_dwarf::dwarf_gpr_x22:
+    case riscv_dwarf::dwarf_gpr_x23:
+    case riscv_dwarf::dwarf_gpr_x24:
+    case riscv_dwarf::dwarf_gpr_x25:
+    case riscv_dwarf::dwarf_gpr_x26:
+    case riscv_dwarf::dwarf_gpr_x27:
+    case riscv_dwarf::dwarf_gpr_x28:
+    case riscv_dwarf::dwarf_gpr_x29:
+    case riscv_dwarf::dwarf_gpr_x30:
+    case riscv_dwarf::dwarf_gpr_x31:
+      return gpr_x0 + (reg - riscv_dwarf::dwarf_gpr_x0);
+
+    case riscv_dwarf::dwarf_fpr_f0:
+    case riscv_dwarf::dwarf_fpr_f1:
+    case riscv_dwarf::dwarf_fpr_f2:
+    case riscv_dwarf::dwarf_fpr_f3:
+    case riscv_dwarf::dwarf_fpr_f4:
+    case riscv_dwarf::dwarf_fpr_f5:
+    case riscv_dwarf::dwarf_fpr_f6:
+    case riscv_dwarf::dwarf_fpr_f7:
+    case riscv_dwarf::dwarf_fpr_f8:
+    case riscv_dwarf::dwarf_fpr_f9:
+    case riscv_dwarf::dwarf_fpr_f10:
+    case riscv_dwarf::dwarf_fpr_f11:
+    case riscv_dwarf::dwarf_fpr_f12:
+    case riscv_dwarf::dwarf_fpr_f13:
+    case riscv_dwarf::dwarf_fpr_f14:
+    case riscv_dwarf::dwarf_fpr_f15:
+    case riscv_dwarf::dwarf_fpr_f16:
+    case riscv_dwarf::dwarf_fpr_f17:
+    case riscv_dwarf::dwarf_fpr_f18:
+    case riscv_dwarf::dwarf_fpr_f19:
+    case riscv_dwarf::dwarf_fpr_f20:
+    case riscv_dwarf::dwarf_fpr_f21:
+    case riscv_dwarf::dwarf_fpr_f22:
+    case riscv_dwarf::dwarf_fpr_f23:
+    case riscv_dwarf::dwarf_fpr_f24:
+    case riscv_dwarf::dwarf_fpr_f25:
+    case riscv_dwarf::dwarf_fpr_f26:
+    case riscv_dwarf::dwarf_fpr_f27:
+    case riscv_dwarf::dwarf_fpr_f28:
+    case riscv_dwarf::dwarf_fpr_f29:
+    case riscv_dwarf::dwarf_fpr_f30:
+    case riscv_dwarf::dwarf_fpr_f31:
+      return fpr_f0 + (reg - riscv_dwarf::dwarf_fpr_f0);
+
+    default:
+      break;
+    }
+  } else if (kind == eRegisterKindLLDB) {
+    return reg;
+  }
+  return LLDB_INVALID_REGNUM;
+}

diff  --git 
a/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_riscv32.h 
b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_riscv32.h
new file mode 100644
index 0000000000000..22d61aef712a6
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_riscv32.h
@@ -0,0 +1,260 @@
+//===-- RegisterContextDarwin_riscv32.h -------------------------*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_RISCV32_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_RISCV32_H
+
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/lldb-private.h"
+
+class RegisterContextDarwin_riscv32 : public lldb_private::RegisterContext {
+public:
+  RegisterContextDarwin_riscv32(lldb_private::Thread &thread,
+                                uint32_t concrete_frame_idx);
+
+  ~RegisterContextDarwin_riscv32() override;
+
+  void InvalidateAllRegisters() override;
+
+  size_t GetRegisterCount() override;
+
+  const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) 
override;
+
+  size_t GetRegisterSetCount() override;
+
+  const lldb_private::RegisterSet *GetRegisterSet(size_t set) override;
+
+  bool ReadRegister(const lldb_private::RegisterInfo *reg_info,
+                    lldb_private::RegisterValue &value) override;
+
+  bool WriteRegister(const lldb_private::RegisterInfo *reg_info,
+                     const lldb_private::RegisterValue &value) override;
+
+  bool ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override;
+
+  bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;
+
+  uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
+                                               uint32_t num) override;
+
+  struct GPR {
+    uint32_t x0;
+    uint32_t x1;
+    uint32_t x2;
+    uint32_t x3;
+    uint32_t x4;
+    uint32_t x5;
+    uint32_t x6;
+    uint32_t x7;
+    uint32_t x8;
+    uint32_t x9;
+    uint32_t x10;
+    uint32_t x11;
+    uint32_t x12;
+    uint32_t x13;
+    uint32_t x14;
+    uint32_t x15;
+    uint32_t x16;
+    uint32_t x17;
+    uint32_t x18;
+    uint32_t x19;
+    uint32_t x20;
+    uint32_t x21;
+    uint32_t x22;
+    uint32_t x23;
+    uint32_t x24;
+    uint32_t x25;
+    uint32_t x26;
+    uint32_t x27;
+    uint32_t x28;
+    uint32_t x29;
+    uint32_t x30;
+    uint32_t x31;
+    uint32_t pc;
+  };
+
+  struct FPU {
+    uint32_t f0;
+    uint32_t f1;
+    uint32_t f2;
+    uint32_t f3;
+    uint32_t f4;
+    uint32_t f5;
+    uint32_t f6;
+    uint32_t f7;
+    uint32_t f8;
+    uint32_t f9;
+    uint32_t f10;
+    uint32_t f11;
+    uint32_t f12;
+    uint32_t f13;
+    uint32_t f14;
+    uint32_t f15;
+    uint32_t f16;
+    uint32_t f17;
+    uint32_t f18;
+    uint32_t f19;
+    uint32_t f20;
+    uint32_t f21;
+    uint32_t f22;
+    uint32_t f23;
+    uint32_t f24;
+    uint32_t f25;
+    uint32_t f26;
+    uint32_t f27;
+    uint32_t f28;
+    uint32_t f29;
+    uint32_t f30;
+    uint32_t f31;
+    uint32_t fcsr;
+  };
+
+  struct EXC {
+    uint32_t exception;
+    uint32_t fsr;
+    uint32_t far;
+  };
+
+  struct CSR {
+    uint32_t csr[1024];
+  };
+
+protected:
+  enum {
+    GPRRegSet = 2,  // RV32_THREAD_STATE
+    EXCRegSet = 3,  // RV32_EXCEPTION_STATE
+    FPURegSet = 4,  // RV_FP32_STATE
+    CSRRegSet1 = 6, // RV_CSR_STATE1
+    CSRRegSet2 = 7, // RV_CSR_STATE2
+    CSRRegSet3 = 8, // RV_CSR_STATE3
+    CSRRegSet4 = 9, // RV_CSR_STATE4
+    CSRRegSet = 10  // full 16kbyte CSR reg bank
+  };
+
+  enum {
+    GPRWordCount = sizeof(GPR) / sizeof(uint32_t),
+    FPUWordCount = sizeof(FPU) / sizeof(uint32_t),
+    EXCWordCount = sizeof(EXC) / sizeof(uint32_t),
+    CSRWordCount = sizeof(CSR) / sizeof(uint32_t)
+  };
+
+  enum { Read = 0, Write = 1, kNumErrors = 2 };
+
+  GPR gpr;
+  FPU fpr;
+  EXC exc;
+  CSR csr;
+  int gpr_errs[2]; // Read/Write errors
+  int fpr_errs[2]; // Read/Write errors
+  int exc_errs[2]; // Read/Write errors
+  int csr_errs[2]; // Read/Write errors
+
+  void InvalidateAllRegisterStates() {
+    SetError(GPRRegSet, Read, -1);
+    SetError(FPURegSet, Read, -1);
+    SetError(EXCRegSet, Read, -1);
+    SetError(CSRRegSet, Read, -1);
+  }
+
+  int GetError(int flavor, uint32_t err_idx) const {
+    if (err_idx < kNumErrors) {
+      switch (flavor) {
+      // When getting all errors, just OR all values together to see if
+      // we got any kind of error.
+      case GPRRegSet:
+        return gpr_errs[err_idx];
+      case FPURegSet:
+        return fpr_errs[err_idx];
+      case EXCRegSet:
+        return exc_errs[err_idx];
+      case CSRRegSet:
+        return csr_errs[err_idx];
+      default:
+        break;
+      }
+    }
+    return -1;
+  }
+
+  bool SetError(int flavor, uint32_t err_idx, int err) {
+    if (err_idx < kNumErrors) {
+      switch (flavor) {
+      case GPRRegSet:
+        gpr_errs[err_idx] = err;
+        return true;
+
+      case FPURegSet:
+        fpr_errs[err_idx] = err;
+        return true;
+
+      case EXCRegSet:
+        exc_errs[err_idx] = err;
+        return true;
+
+      case CSRRegSet:
+        csr_errs[err_idx] = err;
+        return true;
+
+      default:
+        break;
+      }
+    }
+    return false;
+  }
+
+  bool RegisterSetIsCached(int set) const { return GetError(set, Read) == 0; }
+
+  void LogGPR(lldb_private::Log *log, const char *title);
+
+  int ReadGPR(bool force);
+
+  int ReadFPU(bool force);
+
+  int ReadEXC(bool force);
+
+  int ReadCSR(bool force);
+
+  int WriteGPR();
+
+  int WriteFPU();
+
+  int WriteEXC();
+
+  int WriteCSR();
+
+  // Subclasses override these to do the actual reading.
+  virtual int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) = 0;
+
+  virtual int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpr) = 0;
+
+  virtual int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) = 0;
+
+  virtual int DoReadCSR(lldb::tid_t tid, int flavor, CSR &exc) = 0;
+
+  virtual int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) = 0;
+
+  virtual int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpr) = 0;
+
+  virtual int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) = 0;
+
+  virtual int DoWriteCSR(lldb::tid_t tid, int flavor, const CSR &exc) = 0;
+
+  int ReadRegisterSet(uint32_t set, bool force);
+
+  int WriteRegisterSet(uint32_t set);
+
+  static uint32_t GetRegisterNumber(uint32_t reg_kind, uint32_t reg_num);
+
+  static int GetSetForNativeRegNum(int reg_num);
+
+  static size_t GetRegisterInfosCount();
+
+  static const lldb_private::RegisterInfo *GetRegisterInfos();
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTDARWIN_RISCV32_H

diff  --git a/lldb/test/API/macosx/riscv32-corefile/Makefile 
b/lldb/test/API/macosx/riscv32-corefile/Makefile
new file mode 100644
index 0000000000000..04f268758d00c
--- /dev/null
+++ b/lldb/test/API/macosx/riscv32-corefile/Makefile
@@ -0,0 +1,7 @@
+MAKE_DSYM := NO
+CXX_SOURCES := create-empty-riscv-corefile.cpp
+EXE := create-empty-riscv-corefile
+
+all: create-empty-riscv-corefile
+
+include Makefile.rules

diff  --git a/lldb/test/API/macosx/riscv32-corefile/TestRV32MachOCorefile.py 
b/lldb/test/API/macosx/riscv32-corefile/TestRV32MachOCorefile.py
new file mode 100644
index 0000000000000..8d11821d38985
--- /dev/null
+++ b/lldb/test/API/macosx/riscv32-corefile/TestRV32MachOCorefile.py
@@ -0,0 +1,82 @@
+"""Test that all of the GPR registers are read correctly from a riscv32 
corefile."""
+
+import os
+import re
+import subprocess
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestRV32MachOCorefile(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
+    @skipUnlessDarwin
+    def test_riscv32_gpr_corefile_registers(self):
+        self.build()
+        create_corefile = self.getBuildArtifact("create-empty-riscv-corefile")
+        corefile = self.getBuildArtifact("core")
+        call(create_corefile + " " + corefile, shell=True)
+
+        target = self.dbg.CreateTarget("")
+        process = target.LoadCore(corefile)
+
+        process = target.GetProcess()
+        self.assertEqual(process.GetNumThreads(), 1)
+
+        thread = process.GetThreadAtIndex(0)
+        self.assertEqual(thread.GetNumFrames(), 1)
+
+        frame = thread.GetFrameAtIndex(0)
+        gpr_regs = frame.registers.GetValueAtIndex(0)
+
+        self.assertEqual(gpr_regs.GetName(), "General Purpose Registers")
+        self.assertEqual(gpr_regs.GetNumChildren(), 33)
+        regnames = [
+            "zero",
+            "ra",
+            "sp",
+            "gp",
+            "tp",
+            "t0",
+            "t1",
+            "t2",
+            "fp",
+            "s1",
+            "a0",
+            "a1",
+            "a2",
+            "a3",
+            "a4",
+            "a5",
+            "a6",
+            "a7",
+            "s2",
+            "s3",
+            "s4",
+            "s5",
+            "s6",
+            "s7",
+            "s8",
+            "s9",
+            "s10",
+            "s11",
+            "t3",
+            "t4",
+            "t5",
+            "t6",
+            "pc",
+        ]
+
+        idx = 0
+        while idx < len(regnames):
+            self.assertEqual(gpr_regs.GetChildAtIndex(idx).GetName(), 
regnames[idx])
+            idx = idx + 1
+
+        idx = 0
+        while idx < len(regnames):
+            val = idx | (idx << 8) | (idx << 16) | (idx << 24)
+            
self.assertEqual(gpr_regs.GetChildAtIndex(idx).GetValueAsUnsigned(), val)
+            idx = idx + 1

diff  --git 
a/lldb/test/API/macosx/riscv32-corefile/create-empty-riscv-corefile.cpp 
b/lldb/test/API/macosx/riscv32-corefile/create-empty-riscv-corefile.cpp
new file mode 100644
index 0000000000000..907cca3b70b41
--- /dev/null
+++ b/lldb/test/API/macosx/riscv32-corefile/create-empty-riscv-corefile.cpp
@@ -0,0 +1,116 @@
+#include <inttypes.h>
+#include <mach-o/loader.h>
+#include <mach/thread_status.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string>
+#include <sys/errno.h>
+#include <uuid/uuid.h>
+#include <vector>
+
+#define CPU_TYPE_RISCV 24
+#define CPU_SUBTYPE_RISCV_ALL 0
+#define RV32_THREAD_STATE 2
+// x0-x31 + pc, all 32-bit
+#define RV32_THREAD_STATE_COUNT 33
+
+union uint32_buf {
+  uint8_t bytebuf[4];
+  uint32_t val;
+};
+
+union uint64_buf {
+  uint8_t bytebuf[8];
+  uint64_t val;
+};
+
+void add_uint64(std::vector<uint8_t> &buf, uint64_t val) {
+  uint64_buf conv;
+  conv.val = val;
+  for (int i = 0; i < 8; i++)
+    buf.push_back(conv.bytebuf[i]);
+}
+
+void add_uint32(std::vector<uint8_t> &buf, uint32_t val) {
+  uint32_buf conv;
+  conv.val = val;
+  for (int i = 0; i < 4; i++)
+    buf.push_back(conv.bytebuf[i]);
+}
+
+std::vector<uint8_t> lc_thread_load_command() {
+  std::vector<uint8_t> data;
+  add_uint32(data, LC_THREAD); // thread_command.cmd
+  add_uint32(data, 4 + 4 + 4 + 4 +
+                       (RV32_THREAD_STATE_COUNT * 4)); // 
thread_command.cmdsize
+  add_uint32(data, RV32_THREAD_STATE);                 // thread_command.flavor
+  add_uint32(data, RV32_THREAD_STATE_COUNT);           // thread_command.count
+  for (int i = 0; i < RV32_THREAD_STATE_COUNT; i++) {
+    add_uint32(data, i | (i << 8) | (i << 16) | (i << 24));
+  }
+  return data;
+}
+
+int main(int argc, char **argv) {
+  if (argc != 2) {
+    fprintf(stderr,
+            "usage: create-empty-riscv-corefile output-corefile-name\n");
+    exit(1);
+  }
+
+  cpu_type_t cputype = CPU_TYPE_RISCV;
+  cpu_subtype_t cpusubtype = CPU_SUBTYPE_RISCV_ALL;
+
+  // An array of load commands (in the form of byte arrays)
+  std::vector<std::vector<uint8_t>> load_commands;
+
+  // An array of corefile contents (page data, lc_note data, etc)
+  std::vector<uint8_t> payload;
+
+  // First add all the load commands / payload so we can figure out how large
+  // the load commands will actually be.
+  load_commands.push_back(lc_thread_load_command());
+
+  int size_of_load_commands = 0;
+  for (const auto &lc : load_commands)
+    size_of_load_commands += lc.size();
+
+  int header_and_load_cmd_room =
+      sizeof(struct mach_header_64) + size_of_load_commands;
+
+  // Erase the load commands / payload now that we know how much space is
+  // needed, redo it.
+  load_commands.clear();
+  payload.clear();
+
+  load_commands.push_back(lc_thread_load_command());
+
+  struct mach_header mh;
+  mh.magic = MH_MAGIC;
+  mh.cputype = cputype;
+
+  mh.cpusubtype = cpusubtype;
+  mh.filetype = MH_CORE;
+  mh.ncmds = load_commands.size();
+  mh.sizeofcmds = size_of_load_commands;
+  mh.flags = 0;
+
+  FILE *f = fopen(argv[1], "w");
+
+  if (f == nullptr) {
+    fprintf(stderr, "Unable to open file %s for writing\n", argv[1]);
+    exit(1);
+  }
+
+  fwrite(&mh, sizeof(struct mach_header), 1, f);
+
+  for (const auto &lc : load_commands)
+    fwrite(lc.data(), lc.size(), 1, f);
+
+  fseek(f, header_and_load_cmd_room, SEEK_SET);
+
+  fwrite(payload.data(), payload.size(), 1, f);
+
+  fclose(f);
+}


        
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to