================
@@ -302,12 +304,56 @@ static lldb::UnwindPlanSP
GetAArch64TrapHandlerUnwindPlan(ConstString name) {
return unwind_plan_sp;
}
+static lldb::UnwindPlanSP GetRISCVTrapHandlerUnwindPlan(ConstString name) {
+ if (name != "__vdso_rt_sigreturn")
+ return UnwindPlanSP{};
+
+ UnwindPlan::Row row;
+
+ // 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(std::move(row));
+ unwind_plan_sp->SetSourceName("RISC-V Linux sigcontext");
+ unwind_plan_sp->SetSourcedFromCompiler(eLazyBoolYes);
----------------
jasonmolenda wrote:
@DavidSpickett FWIW my thinking on this was never super clear, sorry it's a bit
confusing.
When the unwinder has a variety of unwind plans to choose from, it needs to
decide which might be preferable over another that could also be used in a
given context. We might have an assembly instruction unwind plan and a
compiler generated eh_frame or dwarf debug_frame unwind plan. All things being
equal, the compiler generated unwind plan is the better choice.
A secondary, and trickier issue, is that unwind information can be
"asynchronous" -- valid at very instruction, including the middle of prologues
and epilogues, or "synchronous" -- valid only in the body of the function,
typically at places where it may throw an exception, or an exception may need
to be passed up from a callee. Some unwind sources like arm index or Darwin's
compact unwind are purely synchronous, they only describe the unwind state in
the body of the function, where an exception could be thrown. eh_frame and
debug_frame are a bit annoying here because they have no indication whether
they are asynchronous or synchronous, but because gdb relies on eh_frame
exclusively on Linux, the compilers usually generate asynchronous-valid
eh_frame instructions.
We only need to worry about this latter issue of asynchronous/synchronous when
we are unwinding from the currently-executing function. This is either frame
0, or a frame that faulted/excepted into a fault/exception handler (it did not
execute a proper function call).
I doubt the SourcedFromCompiler is actually doing anything important here, but
if this were a non-zero-stack frame and the unwinder was trying to choose
between an instruction emulation unwind plan and this unwind plan, we
definitely want to use this unwind plan. So I probably set it to eLazyBoolYes
for that reason.
https://github.com/llvm/llvm-project/pull/166531
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits