Skip to content

Conversation

@sga-sc
Copy link
Contributor

@sga-sc sga-sc commented Nov 5, 2025

This patch introduces special unwind plan for trap handling for RISC-V and fixes TestHandleAbort

@llvmbot
Copy link
Member

llvmbot commented Nov 5, 2025

@llvm/pr-subscribers-lldb

@llvm/pr-subscribers-backend-risc-v

Author: Georgiy Samoylov (sga-sc)

Changes

This patch introduces special unwind plan for trap handling for RISC-V


Full diff: https://github.com/llvm/llvm-project/pull/166531.diff

2 Files Affected:

  • (modified) lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp (+4)
  • (modified) lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp (+48-1)
diff --git a/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp b/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp
index a5547a4699ca9..d209980d65589 100644
--- a/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp
+++ b/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp
@@ -735,6 +735,8 @@ UnwindPlanSP ABISysV_riscv::CreateFunctionEntryUnwindPlan() {
   plan_sp->AppendRow(std::move(row));
   plan_sp->SetSourceName("riscv function-entry unwind plan");
   plan_sp->SetSourcedFromCompiler(eLazyBoolNo);
+  plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo);
+
   return plan_sp;
 }
 
@@ -761,6 +763,8 @@ UnwindPlanSP ABISysV_riscv::CreateDefaultUnwindPlan() {
   plan_sp->SetSourceName("riscv default unwind plan");
   plan_sp->SetSourcedFromCompiler(eLazyBoolNo);
   plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
+  plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo);
+
   return plan_sp;
 }
 
diff --git a/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp b/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp
index da14da44f5939..d7c15f19f5d69 100644
--- a/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp
+++ b/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp
@@ -15,6 +15,7 @@
 #endif
 
 #include "Plugins/Process/Utility/LinuxSignals.h"
+#include "Plugins/Process/Utility/lldb-riscv-register-enums.h"
 #include "Utility/ARM64_DWARF_Registers.h"
 #include "lldb/Core/Debugger.h"
 #include "lldb/Core/PluginManager.h"
@@ -220,6 +221,7 @@ void PlatformLinux::CalculateTrapHandlerSymbolNames() {
   m_trap_handlers.push_back(ConstString("_sigtramp"));
   m_trap_handlers.push_back(ConstString("__kernel_rt_sigreturn"));
   m_trap_handlers.push_back(ConstString("__restore_rt"));
+  m_trap_handlers.push_back(ConstString("__vdso_rt_sigreturn"));
 }
 
 static lldb::UnwindPlanSP GetAArch64TrapHandlerUnwindPlan(ConstString name) {
@@ -302,12 +304,57 @@ static lldb::UnwindPlanSP GetAArch64TrapHandlerUnwindPlan(ConstString name) {
   return unwind_plan_sp;
 }
 
+static lldb::UnwindPlanSP GetRISCVTrapHandlerUnwindPlan(ConstString name) {
+  if (name != "__vdso_rt_sigreturn")
+    return UnwindPlanSP{};
+
+  UnwindPlan::RowSP row = std::make_shared<UnwindPlan::Row>();
+  row->SetOffset(0);
+
+  // In the signal trampoline frame, sp points to an rt_sigframe[1], which is:
+  //  - 128-byte siginfo struct
+  //  - ucontext struct:
+  //     - 8-byte long (uc_flags)
+  //     - 8-byte pointer (*uc_link)
+  //     - 24-byte struct (uc_stack)
+  //     - 8-byte struct (uc_sigmask)
+  //     - 120-byte of padding to allow sigset_t to be expanded in the future
+  //     - 8 bytes of padding because sigcontext has 16-byte alignment
+  //     - struct sigcontext uc_mcontext
+  // [1]
+  // https://github.com/torvalds/linux/blob/master/arch/riscv/kernel/signal.c
+
+  constexpr size_t siginfo_size = 128;
+  constexpr size_t uc_flags_size = 8;
+  constexpr size_t uc_link_ptr_size = 8;
+  constexpr size_t uc_stack_size = 24;
+  constexpr size_t uc_sigmask_size = 8;
+  constexpr size_t padding_size = 128;
+
+  constexpr size_t offset = siginfo_size + uc_flags_size + uc_link_ptr_size +
+                            uc_stack_size + uc_sigmask_size + padding_size;
+
+  row->GetCFAValue().SetIsRegisterPlusOffset(gpr_sp_riscv, offset);
+  for (uint32_t reg_num = 0; reg_num <= 31; ++reg_num)
+    row->SetRegisterLocationToAtCFAPlusOffset(reg_num, reg_num * 8, false);
+
+  UnwindPlanSP unwind_plan_sp = std::make_shared<UnwindPlan>(eRegisterKindLLDB);
+  unwind_plan_sp->AppendRow(row);
+  unwind_plan_sp->SetSourceName("RISC-V Linux sigcontext");
+  unwind_plan_sp->SetSourcedFromCompiler(eLazyBoolYes);
+  unwind_plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
+  unwind_plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolYes);
+
+  return unwind_plan_sp;
+}
+
 lldb::UnwindPlanSP
 PlatformLinux::GetTrapHandlerUnwindPlan(const llvm::Triple &triple,
                                         ConstString name) {
   if (triple.isAArch64())
     return GetAArch64TrapHandlerUnwindPlan(name);
-
+  if (triple.isRISCV())
+    return GetRISCVTrapHandlerUnwindPlan(name);
   return {};
 }
 

@DavidSpickett
Copy link
Collaborator

Unless this fixes an existing test case, you could adapt the one from 9db2541 to work for RISC-V.

I put it in the AArch64 folder but it can be moved somewhere generic. The specific bits are the x register naming and the undefined encoding.

@sga-sc
Copy link
Contributor Author

sga-sc commented Nov 5, 2025

I forgot to mention that this patch fixes TestHandleAbort on RISC-V. I'll change PR description for this

…p handling

After we introduced a special unwind plan for trap handling, we should
mark that other unwind plans for RISC-V can't be used in the same case.
@sga-sc sga-sc force-pushed the users/sga-sc/lldb_handle_abort branch from 3b72ba2 to f52f1e7 Compare November 5, 2025 12:42
@DavidSpickett
Copy link
Collaborator

Cool. Now I see that I enabled that test for AArch64 Linux at the time, but added the new one to check the register values. Not sure why I didn't hack something into the existing one.

Anyway, this is a net improvement as is and if you want to add more checks later there's something for you to crib from.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants