Skip to content

[lldb] Support riscv32 ELF corefiles #115408

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 19, 2025
Merged

Conversation

JDevlieghere
Copy link
Member

@JDevlieghere JDevlieghere commented Nov 8, 2024

Add support for riscv32 ELF corefiles.

@JDevlieghere
Copy link
Member Author

I'm in an awkward position where I'm not able to share the riscv32 core files I've been testing this against. @ita-sc & @AlexeyMerzlyakov, I know you two have worked on riscv64, is there any chance you could help me generate a riscv32 core file I can use to write a test for this?

@JDevlieghere JDevlieghere marked this pull request as ready for review April 23, 2025 21:18
@llvmbot llvmbot added the lldb label Apr 23, 2025
@llvmbot
Copy link
Member

llvmbot commented Apr 23, 2025

@llvm/pr-subscribers-lldb

Author: Jonas Devlieghere (JDevlieghere)

Changes

Patch is 30.04 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/115408.diff

10 Files Affected:

  • (modified) lldb/source/Plugins/Process/Utility/CMakeLists.txt (+2)
  • (added) lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_riscv32.cpp (+81)
  • (added) lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_riscv32.h (+63)
  • (added) lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_riscv32.cpp (+142)
  • (added) lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_riscv32.h (+76)
  • (modified) lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.cpp (+4-5)
  • (added) lldb/source/Plugins/Process/Utility/RegisterInfos_riscv32.h (+185)
  • (modified) lldb/source/Plugins/Process/elf-core/CMakeLists.txt (+1)
  • (added) lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_riscv32.cpp (+81)
  • (added) lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_riscv32.h (+56)
diff --git a/lldb/source/Plugins/Process/Utility/CMakeLists.txt b/lldb/source/Plugins/Process/Utility/CMakeLists.txt
index 308ea29e31ad7..5ffd2d7114cc9 100644
--- a/lldb/source/Plugins/Process/Utility/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/Utility/CMakeLists.txt
@@ -39,6 +39,7 @@ add_lldb_library(lldbPluginProcessUtility
   RegisterContextPOSIX_arm64.cpp
   RegisterContextPOSIX_loongarch64.cpp
   RegisterContextPOSIX_mips64.cpp
+  RegisterContextPOSIX_riscv32.cpp
   RegisterContextPOSIX_powerpc.cpp
   RegisterContextPOSIX_ppc64le.cpp
   RegisterContextPOSIX_riscv64.cpp
@@ -53,6 +54,7 @@ add_lldb_library(lldbPluginProcessUtility
   RegisterInfoPOSIX_arm64.cpp
   RegisterInfoPOSIX_loongarch64.cpp
   RegisterInfoPOSIX_ppc64le.cpp
+  RegisterInfoPOSIX_riscv32.cpp
   RegisterInfoPOSIX_riscv64.cpp
   StopInfoMachException.cpp
   ThreadMemory.cpp
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_riscv32.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_riscv32.cpp
new file mode 100644
index 0000000000000..64064f86cea04
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_riscv32.cpp
@@ -0,0 +1,81 @@
+//===-- RegisterContextPOSIX_riscv32.cpp ------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextPOSIX_riscv32.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "lldb/Utility/Scalar.h"
+#include "llvm/Support/Compiler.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextPOSIX_riscv32::RegisterContextPOSIX_riscv32(
+    lldb_private::Thread &thread,
+    std::unique_ptr<RegisterInfoPOSIX_riscv32> register_info)
+    : lldb_private::RegisterContext(thread, 0),
+      m_register_info_up(std::move(register_info)) {}
+
+RegisterContextPOSIX_riscv32::~RegisterContextPOSIX_riscv32() = default;
+
+void RegisterContextPOSIX_riscv32::invalidate() {}
+
+void RegisterContextPOSIX_riscv32::InvalidateAllRegisters() {}
+
+size_t RegisterContextPOSIX_riscv32::GetRegisterCount() {
+  return m_register_info_up->GetRegisterCount();
+}
+
+size_t RegisterContextPOSIX_riscv32::GetGPRSize() {
+  return m_register_info_up->GetGPRSize();
+}
+
+unsigned RegisterContextPOSIX_riscv32::GetRegisterSize(unsigned int reg) {
+  return m_register_info_up->GetRegisterInfo()[reg].byte_size;
+}
+
+unsigned RegisterContextPOSIX_riscv32::GetRegisterOffset(unsigned int reg) {
+  return m_register_info_up->GetRegisterInfo()[reg].byte_offset;
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextPOSIX_riscv32::GetRegisterInfoAtIndex(size_t reg) {
+  if (reg < GetRegisterCount())
+    return &GetRegisterInfo()[reg];
+
+  return nullptr;
+}
+
+size_t RegisterContextPOSIX_riscv32::GetRegisterSetCount() {
+  return m_register_info_up->GetRegisterCount();
+}
+
+const lldb_private::RegisterSet *
+RegisterContextPOSIX_riscv32::GetRegisterSet(size_t set) {
+  return m_register_info_up->GetRegisterSet(set);
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextPOSIX_riscv32::GetRegisterInfo() {
+  return m_register_info_up->GetRegisterInfo();
+}
+
+bool RegisterContextPOSIX_riscv32::IsGPR(unsigned int reg) {
+  return m_register_info_up->GetRegisterSetFromRegisterIndex(reg) ==
+         RegisterInfoPOSIX_riscv32::eRegsetMaskDefault;
+}
+
+bool RegisterContextPOSIX_riscv32::IsFPR(unsigned int reg) {
+  return m_register_info_up->GetRegisterSetFromRegisterIndex(reg) ==
+         RegisterInfoPOSIX_riscv32::eRegsetMaskFP;
+}
diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_riscv32.h b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_riscv32.h
new file mode 100644
index 0000000000000..0c25ce11f5754
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_riscv32.h
@@ -0,0 +1,63 @@
+//===-- RegisterContextPOSIX_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_REGISTERCONTEXTPOSIX_RISCV32_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_RISCV32_H
+
+#include "RegisterInfoInterface.h"
+#include "RegisterInfoPOSIX_riscv32.h"
+#include "lldb-riscv-register-enums.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/Log.h"
+
+class RegisterContextPOSIX_riscv32 : public lldb_private::RegisterContext {
+public:
+  RegisterContextPOSIX_riscv32(
+      lldb_private::Thread &thread,
+      std::unique_ptr<RegisterInfoPOSIX_riscv32> register_info);
+
+  ~RegisterContextPOSIX_riscv32() override;
+
+  void invalidate();
+
+  void InvalidateAllRegisters() override;
+
+  size_t GetRegisterCount() override;
+
+  virtual size_t GetGPRSize();
+
+  virtual unsigned GetRegisterSize(unsigned reg);
+
+  virtual unsigned GetRegisterOffset(unsigned reg);
+
+  const lldb_private::RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
+
+  size_t GetRegisterSetCount() override;
+
+  const lldb_private::RegisterSet *GetRegisterSet(size_t set) override;
+
+protected:
+  std::unique_ptr<RegisterInfoPOSIX_riscv32> m_register_info_up;
+
+  virtual const lldb_private::RegisterInfo *GetRegisterInfo();
+
+  bool IsGPR(unsigned reg);
+
+  bool IsFPR(unsigned reg);
+
+  size_t GetFPRSize() { return sizeof(RegisterInfoPOSIX_riscv32::FPR); }
+
+  uint32_t GetRegNumFCSR() const { return fpr_fcsr_riscv; }
+
+  virtual bool ReadGPR() = 0;
+  virtual bool ReadFPR() = 0;
+  virtual bool WriteGPR() = 0;
+  virtual bool WriteFPR() = 0;
+};
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_RISCV32_H
diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_riscv32.cpp b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_riscv32.cpp
new file mode 100644
index 0000000000000..e213b4a4a1820
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_riscv32.cpp
@@ -0,0 +1,142 @@
+//===-- RegisterInfoPOSIX_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 "RegisterInfoPOSIX_riscv32.h"
+#include "lldb/Utility/Flags.h"
+#include "lldb/lldb-defines.h"
+#include "llvm/Support/Compiler.h"
+
+#include <cassert>
+#include <stddef.h>
+
+#define GPR_OFFSET(idx) ((idx) * 4 + 0)
+#define FPR_OFFSET(idx) ((idx) * 4 + sizeof(RegisterInfoPOSIX_riscv32::GPR))
+
+#define REG_CONTEXT_SIZE                                                       \
+  (sizeof(RegisterInfoPOSIX_riscv32::GPR) +                                    \
+   sizeof(RegisterInfoPOSIX_riscv32::FPR))
+
+#define DECLARE_REGISTER_INFOS_RISCV32_STRUCT
+#include "RegisterInfos_riscv32.h"
+#undef DECLARE_REGISTER_INFOS_RISCV32_STRUCT
+
+const lldb_private::RegisterInfo *RegisterInfoPOSIX_riscv32::GetRegisterInfoPtr(
+    const lldb_private::ArchSpec &target_arch) {
+  switch (target_arch.GetMachine()) {
+  case llvm::Triple::riscv32:
+    return g_register_infos_riscv32_le;
+  default:
+    assert(false && "Unhandled target architecture.");
+    return nullptr;
+  }
+}
+
+uint32_t RegisterInfoPOSIX_riscv32::GetRegisterInfoCount(
+    const lldb_private::ArchSpec &target_arch) {
+  switch (target_arch.GetMachine()) {
+  case llvm::Triple::riscv32:
+    return static_cast<uint32_t>(sizeof(g_register_infos_riscv32_le) /
+                                 sizeof(g_register_infos_riscv32_le[0]));
+  default:
+    assert(false && "Unhandled target architecture.");
+    return 0;
+  }
+}
+
+// Number of register sets provided by this context.
+enum {
+  k_num_gpr_registers = gpr_last_riscv - gpr_first_riscv + 1,
+  k_num_fpr_registers = fpr_last_riscv - fpr_first_riscv + 1,
+  k_num_register_sets = 2
+};
+
+// RISC-V32 general purpose registers.
+static const uint32_t g_gpr_regnums_riscv32[] = {
+    gpr_pc_riscv,  gpr_ra_riscv,       gpr_sp_riscv,  gpr_x3_riscv,
+    gpr_x4_riscv,  gpr_x5_riscv,       gpr_x6_riscv,  gpr_x7_riscv,
+    gpr_fp_riscv,  gpr_x9_riscv,       gpr_x10_riscv, gpr_x11_riscv,
+    gpr_x12_riscv, gpr_x13_riscv,      gpr_x14_riscv, gpr_x15_riscv,
+    gpr_x16_riscv, gpr_x17_riscv,      gpr_x18_riscv, gpr_x19_riscv,
+    gpr_x20_riscv, gpr_x21_riscv,      gpr_x22_riscv, gpr_x23_riscv,
+    gpr_x24_riscv, gpr_x25_riscv,      gpr_x26_riscv, gpr_x27_riscv,
+    gpr_x28_riscv, gpr_x29_riscv,      gpr_x30_riscv, gpr_x31_riscv,
+    gpr_x0_riscv,  LLDB_INVALID_REGNUM};
+
+static_assert(((sizeof g_gpr_regnums_riscv32 /
+                sizeof g_gpr_regnums_riscv32[0]) -
+               1) == k_num_gpr_registers,
+              "g_gpr_regnums_riscv32 has wrong number of register infos");
+
+// RISC-V32 floating point registers.
+static const uint32_t g_fpr_regnums_riscv32[] = {
+    fpr_f0_riscv,   fpr_f1_riscv,       fpr_f2_riscv,  fpr_f3_riscv,
+    fpr_f4_riscv,   fpr_f5_riscv,       fpr_f6_riscv,  fpr_f7_riscv,
+    fpr_f8_riscv,   fpr_f9_riscv,       fpr_f10_riscv, fpr_f11_riscv,
+    fpr_f12_riscv,  fpr_f13_riscv,      fpr_f14_riscv, fpr_f15_riscv,
+    fpr_f16_riscv,  fpr_f17_riscv,      fpr_f18_riscv, fpr_f19_riscv,
+    fpr_f20_riscv,  fpr_f21_riscv,      fpr_f22_riscv, fpr_f23_riscv,
+    fpr_f24_riscv,  fpr_f25_riscv,      fpr_f26_riscv, fpr_f27_riscv,
+    fpr_f28_riscv,  fpr_f29_riscv,      fpr_f30_riscv, fpr_f31_riscv,
+    fpr_fcsr_riscv, LLDB_INVALID_REGNUM};
+
+static_assert(((sizeof g_fpr_regnums_riscv32 /
+                sizeof g_fpr_regnums_riscv32[0]) -
+               1) == k_num_fpr_registers,
+              "g_fpr_regnums_riscv32 has wrong number of register infos");
+
+// Register sets for RISC-V32.
+static const lldb_private::RegisterSet g_reg_sets_riscv32[k_num_register_sets] =
+    {{"General Purpose Registers", "gpr", k_num_gpr_registers,
+      g_gpr_regnums_riscv32},
+     {"Floating Point Registers", "fpr", k_num_fpr_registers,
+      g_fpr_regnums_riscv32}};
+
+RegisterInfoPOSIX_riscv32::RegisterInfoPOSIX_riscv32(
+    const lldb_private::ArchSpec &target_arch, lldb_private::Flags opt_regsets)
+    : lldb_private::RegisterInfoAndSetInterface(target_arch),
+      m_register_info_p(GetRegisterInfoPtr(target_arch)),
+      m_register_info_count(GetRegisterInfoCount(target_arch)),
+      m_opt_regsets(opt_regsets) {}
+
+uint32_t RegisterInfoPOSIX_riscv32::GetRegisterCount() const {
+  return m_register_info_count;
+}
+
+size_t RegisterInfoPOSIX_riscv32::GetGPRSize() const {
+  return sizeof(struct RegisterInfoPOSIX_riscv32::GPR);
+}
+
+size_t RegisterInfoPOSIX_riscv32::GetFPRSize() const {
+  return sizeof(struct RegisterInfoPOSIX_riscv32::FPR);
+}
+
+const lldb_private::RegisterInfo *
+RegisterInfoPOSIX_riscv32::GetRegisterInfo() const {
+  return m_register_info_p;
+}
+
+size_t RegisterInfoPOSIX_riscv32::GetRegisterSetCount() const {
+  return k_num_register_sets;
+}
+
+size_t RegisterInfoPOSIX_riscv32::GetRegisterSetFromRegisterIndex(
+    uint32_t reg_index) const {
+  // coverity[unsigned_compare]
+  if (reg_index >= gpr_first_riscv && reg_index <= gpr_last_riscv)
+    return eRegsetMaskDefault;
+  if (reg_index >= fpr_first_riscv && reg_index <= fpr_last_riscv)
+    return eRegsetMaskFP;
+  return LLDB_INVALID_REGNUM;
+}
+
+const lldb_private::RegisterSet *
+RegisterInfoPOSIX_riscv32::GetRegisterSet(size_t set_index) const {
+  if (set_index < GetRegisterSetCount())
+    return &g_reg_sets_riscv32[set_index];
+  return nullptr;
+}
diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_riscv32.h b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_riscv32.h
new file mode 100644
index 0000000000000..f8d85f9e72893
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_riscv32.h
@@ -0,0 +1,76 @@
+//===-- RegisterInfoPOSIX_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_REGISTERINFOPOSIX_RISCV32_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOPOSIX_RISCV32_H
+
+#include "RegisterInfoAndSetInterface.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/Flags.h"
+#include "lldb/lldb-private.h"
+
+#include <map>
+
+class RegisterInfoPOSIX_riscv32
+    : public lldb_private::RegisterInfoAndSetInterface {
+public:
+  static const lldb_private::RegisterInfo *
+  GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch);
+  static uint32_t
+  GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch);
+
+public:
+  // RISC-V32 register set mask value
+  enum {
+    eRegsetMaskDefault = 0,
+    eRegsetMaskFP = 1,
+    eRegsetMaskAll = -1,
+  };
+
+  struct GPR {
+    // note: gpr[0] is pc, not x0
+    uint32_t gpr[32];
+  };
+
+  struct FPR {
+    uint32_t fpr[32];
+    uint32_t fcsr;
+  };
+
+  struct VPR {
+    // The size should be VLEN*32 in bits, but we don't have VLEN here.
+    void *vpr;
+  };
+
+  RegisterInfoPOSIX_riscv32(const lldb_private::ArchSpec &target_arch,
+                            lldb_private::Flags flags);
+
+  size_t GetGPRSize() const override;
+
+  size_t GetFPRSize() const override;
+
+  const lldb_private::RegisterInfo *GetRegisterInfo() const override;
+
+  uint32_t GetRegisterCount() const override;
+
+  const lldb_private::RegisterSet *
+  GetRegisterSet(size_t reg_set) const override;
+
+  size_t GetRegisterSetCount() const override;
+
+  size_t GetRegisterSetFromRegisterIndex(uint32_t reg_index) const override;
+
+  bool IsFPPresent() const { return m_opt_regsets.AnySet(eRegsetMaskFP); }
+
+private:
+  const lldb_private::RegisterInfo *m_register_info_p;
+  uint32_t m_register_info_count;
+  lldb_private::Flags m_opt_regsets;
+};
+
+#endif
diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.cpp b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.cpp
index 4a3737795848e..a0be54fc76cd5 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.cpp
@@ -6,14 +6,13 @@
 //
 //===---------------------------------------------------------------------===//
 
-#include <cassert>
-#include <lldb/Utility/Flags.h>
-#include <stddef.h>
-
+#include "RegisterInfoPOSIX_riscv64.h"
+#include "lldb/Utility/Flags.h"
 #include "lldb/lldb-defines.h"
 #include "llvm/Support/Compiler.h"
 
-#include "RegisterInfoPOSIX_riscv64.h"
+#include <cassert>
+#include <stddef.h>
 
 #define GPR_OFFSET(idx) ((idx)*8 + 0)
 #define FPR_OFFSET(idx) ((idx)*8 + sizeof(RegisterInfoPOSIX_riscv64::GPR))
diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfos_riscv32.h b/lldb/source/Plugins/Process/Utility/RegisterInfos_riscv32.h
new file mode 100644
index 0000000000000..ab6fec829bbce
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/RegisterInfos_riscv32.h
@@ -0,0 +1,185 @@
+//===-- RegisterInfos_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
+//
+//===----------------------------------------------------------------------===//
+
+#ifdef DECLARE_REGISTER_INFOS_RISCV32_STRUCT
+
+#include "Utility/RISCV_DWARF_Registers.h"
+#include "lldb-riscv-register-enums.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-private.h"
+
+#include <stddef.h>
+
+#ifndef GPR_OFFSET
+#error GPR_OFFSET must be defined before including this header file
+#endif
+
+#ifndef FPR_OFFSET
+#error FPR_OFFSET must be defined before including this header file
+#endif
+
+using namespace riscv_dwarf;
+
+// clang-format off
+
+// I suppose EHFrame and DWARF are the same.
+#define KIND_HELPER(reg, generic_kind)                                         \
+  {                                                                            \
+    riscv_dwarf::dwarf_##reg, riscv_dwarf::dwarf_##reg, generic_kind,          \
+    LLDB_INVALID_REGNUM, reg##_riscv                                           \
+  }
+
+// Generates register kinds array for vector registers
+#define GPR32_KIND(reg, generic_kind) KIND_HELPER(reg, generic_kind)
+
+// FPR register kinds array for vector registers
+#define FPR32_KIND(reg, generic_kind) KIND_HELPER(reg, generic_kind)
+
+// VPR register kinds array for vector registers
+#define VPR_KIND(reg, generic_kind) KIND_HELPER(reg, generic_kind)
+
+// Defines a 32-bit general purpose register
+#define DEFINE_GPR32(reg, generic_kind) DEFINE_GPR32_ALT(reg, reg, generic_kind)
+
+// Defines a 32-bit general purpose register
+#define DEFINE_GPR32_ALT(reg, alt, generic_kind)                               \
+  {                                                                            \
+    #reg, #alt, 4, GPR_OFFSET(gpr_##reg##_riscv - gpr_first_riscv),            \
+    lldb::eEncodingUint, lldb::eFormatHex,                                     \
+    GPR32_KIND(gpr_##reg, generic_kind), nullptr, nullptr, nullptr,            \
+  }
+
+#define DEFINE_FPR32(reg, generic_kind) DEFINE_FPR32_ALT(reg, reg, generic_kind)
+
+#define DEFINE_FPR32_ALT(reg, alt, generic_kind) DEFINE_FPR_ALT(reg, alt, 4, generic_kind)
+
+#define DEFINE_FPR_ALT(reg, alt, size, generic_kind)                           \
+  {                                                                            \
+    #reg, #alt, size, FPR_OFFSET(fpr_##reg##_riscv - fpr_first_riscv),         \
+    lldb::eEncodingUint, lldb::eFormatHex,                                     \
+    FPR32_KIND(fpr_##reg, generic_kind), nullptr, nullptr, nullptr,           \
+  }
+
+#define DEFINE_VPR(reg, generic_kind) DEFINE_VPR_ALT(reg, reg, generic_kind)
+
+// Defines a scalable vector register, with default size 128 bits
+// The byte offset 0 is a placeholder, which should be corrected at runtime.
+#define DEFINE_VPR_ALT(reg, alt, generic_kind)                                 \
+  {                                                                            \
+    #reg, #alt, 16, 0, lldb::eEncodingVector, lldb::eFormatVectorOfUInt8,      \
+    VPR_KIND(vpr_##reg, generic_kind), nullptr, nullptr, nullptr               \
+  }
+
+// clang-format on
+
+static lldb_private::RegisterInfo g_register_infos_riscv32_le[] = {
+    // DEFINE_GPR32(name, GENERIC KIND)
+    DEFINE_GPR32(pc, LLDB_REGNUM_GENERIC_PC),
+    DEFINE_GPR32_ALT(ra, x1, LLDB_REGNUM_GENERIC_RA),
+    DEFINE_GPR32_ALT(sp, x2, LLDB_REGNUM_GENERIC_SP),
+    DEFINE_GPR32_ALT(gp, x3, LLDB_INVALID_REGNUM),
+    DEFINE_GPR32_ALT(tp, x4, LLDB_INVALID_REGNUM),
+    DEFINE_GPR32_ALT(t0, x5, LLDB_INVALID_REGNUM),
+    DEFINE_GPR32_ALT(t1, x6, LLDB_INVALID_REGNUM),
+    DEFINE_GPR32_ALT(t2, x7, LLDB_INVALID_REGNUM),
+    DEFINE_GPR32_ALT(fp, x8, LLDB_REGNUM_GENERIC_FP),
+    DEFINE_GPR32_ALT(s1, x9, LLDB_INVALID_REGNUM),
+    DEFINE_GPR32_ALT(a0, x10, LLDB_REGNUM_GENERIC_ARG1),
+    DEFINE_GPR32_ALT(a1, x11, LLDB_REGNUM_GENERIC_ARG2),
+    DEFINE_GPR32_ALT(a2, x12, LLDB_REGNUM_GENERIC_ARG3),
+    DEFINE_GPR32_ALT(a3, x13, LLDB_REGNUM_GENERIC_ARG4),
+    DEFINE_GPR32_ALT(a4, x14, LLDB_REGNUM_GENERIC_ARG5),
+    DEFINE_GPR32_ALT(a5, x15, LLDB_REGNUM_GENERIC_ARG6),
+    DEFINE_GPR32_ALT(a6, x16, LLDB_REGNUM_GENERIC_ARG7),
+    DEFINE_GPR32_ALT(a7, x17, LLDB_REGNUM_GENERIC_ARG8),
+    DEFINE_GPR32_ALT(s2, x18, LLDB_INVALID_REGNUM),
+    DEFINE_GPR32_ALT(s3, x19, LLDB_INVALID_REGNUM),
+    DEFINE_GPR32_...
[truncated]

uint32_t fcsr;
};

struct VPR {
Copy link
Collaborator

@jasonmolenda jasonmolenda Apr 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see why we're including data store for the VPR vector register, or adding the register definitions below. There are no read or write accesses to these, and it'd prob be less confusing if they weren't listed at all.
It may be a "if we had VPR register data in a corefile, we'd store it here" and the read/write methods are TBD, that's fine in that case.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ISTR the 64-bit has some mentions of the vector registers but we don't actually support them yet.

But I agree, leave them out until they are supposed to be useable.

Copy link
Collaborator

@jasonmolenda jasonmolenda left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me, straightforward corefile impl of these registers.

DEFINE_GPR32_ALT(t4, x29, LLDB_INVALID_REGNUM),
DEFINE_GPR32_ALT(t5, x30, LLDB_INVALID_REGNUM),
DEFINE_GPR32_ALT(t6, x31, LLDB_INVALID_REGNUM),
DEFINE_GPR32_ALT(zero, x0, LLDB_INVALID_REGNUM),
Copy link
Collaborator

@jasonmolenda jasonmolenda Apr 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand defining x0/zero here, the GPR object doesn't have any place for the $x0 value to be stored (fine - it's zero). It seems like the ReadRegister method needs to explicitly check to see if x0 is being read, and return a UInt32 0 value for that reg. I'm pretty sure this code as written will access 4 bytes past the end of the GPR object when someone asks for the value of $x0.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this scheme was copied somewhat from RegisterInfoPOSIX_riscv64 and RegisterInfos_riscv64.h and I have to wonder if that class shares the same problem with $x0. The GPR object is 32 64-bit entries, and $zero / $x0 has an offset past the end of the struct.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jasonmolenda I had the same thought when we were internally implementing 32 bit core dumps, and realized that the zero register can be another "register" that the dumper uses to communicate interesting data. I know our internal team that wanted this plans to use it for something (I don't know what).

uint32_t fcsr;
};

struct VPR {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ISTR the 64-bit has some mentions of the vector registers but we don't actually support them yet.

But I agree, leave them out until they are supposed to be useable.

@AlexeyMerzlyakov
Copy link
Contributor

AlexeyMerzlyakov commented Apr 24, 2025

@JDevlieghere, to get coredump file I've used make-core.sh script on the target H/W. Generated file should be minimal as possible. On of the way to do this - is to restrict the the number of unnecessary mappings written to the corefile by setting coredump_filter (https://man7.org/linux/man-pages/man5/core.5.html) on the target. Something like echo 0x01 > /proc/self/coredump_filter. I've used to choose minimal necessary bitset empirically, by trying setting different bits to 0 unless the test won't broken.

Unfortunately, I have only RISC-V 64 target (with Kernel & rootfs) in my access, so I am not sure whether I could easily generate core-file to you for RISC-V 32 target.

@DavidSpickett
Copy link
Collaborator

You could adapt commands from https://github.com/llvm/llvm-project/tree/main/lldb/scripts/lldb-test-qemu, if you have an existing Ubuntu system of some other architecture.

https://lldb.llvm.org/resources/qemu-testing.html

Support riscv32 ELF corefiles.
@JDevlieghere JDevlieghere changed the title [lldb] Support riscv32 corefiles [lldb] Support riscv32 ELF corefiles May 19, 2025
@jasonmolenda
Copy link
Collaborator

I see the latest update includes the necessary changes to ThreadElfCore, that looks good.

I'm still curious what this code does when reading x0. The RegisterContext GPR struct defines 32 elements, pc + x1-x31, and the offset of x0 would be the 33rd element. But instead of using that GPR struct, this PR points into the corefile byte range where the GPRs are stored -- I'm assuming the elf file stores pc in the 0th position just like the RegisterContext does. Is the GPR register file in an rv32 corefile 32 elements long or 33? Are we reading past the end of the 32-element GPR registers when we read x0 and it happens to just be value 0, or maybe it's undefined and no one really read x0 so they don't notice?

I still wonder about having RegisterContextCorePOSIX_riscv32::ReadRegister return UInt32(0) when x0 is requested. This code is largely the same as the rv64 corefile support which would have the same issue, if it is an issue, so I probably shouldn't worry so much. I suspect we can skate past an Address Sanitizer catching this even if we read one entry past the GPR range in the corefile because it's all mapped corefile data.

@JDevlieghere
Copy link
Member Author

@jasonmolenda Yes, my understanding is that the GPRs are 338=264 bytes for riscv64 and 334=132 bytes for riscv32. The FPR start at offset 132.

@JDevlieghere JDevlieghere merged commit dfabd61 into llvm:main May 19, 2025
10 checks passed
@JDevlieghere JDevlieghere deleted the riscv32 branch May 19, 2025 23:04
@DavidSpickett
Copy link
Collaborator

  1. This went in without tests, intentional?
  2. Seems like a release note worthy feature.

@JDevlieghere
Copy link
Member Author

  1. This went in without tests, intentional?

Intentional insofar that I cannot share the core files I tested this against, and that I don't know/have a way to generate one that I can check in.

  1. Seems like a release note worthy feature.

I can add a release note 👍

@DavidSpickett
Copy link
Collaborator

DavidSpickett commented May 27, 2025

@asb might have a RISC-V Linux system handy to generate a core file from.

lldb/test/API/functionalities/postmortem/elf-core/main_fpr.c would cover GPR and FPR, I think that's all we need here. It can be added to lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py like the RV64 ones were.

If @asb can generate them I think @JDevlieghere can update the tests without needing access to the system itself.

sivan-shani pushed a commit to sivan-shani/llvm-project that referenced this pull request Jun 3, 2025
Add support for riscv32 ELF corefiles.
ajaden-codes pushed a commit to Jaddyen/llvm-project that referenced this pull request Jun 6, 2025
Add support for riscv32 ELF corefiles.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants