Skip to content

Commit 97e7292

Browse files
committed
Ugh - for x86_64, the signal trampoline has DWARF unwind info
1 parent b5af6b6 commit 97e7292

File tree

3 files changed

+25
-6
lines changed

3 files changed

+25
-6
lines changed

dwarfproc.cc

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,19 +43,26 @@ StackFrame::scopeIP(Process &proc) const
4343
// the process's register state - this is the currently executing
4444
// instruction, so accurately reflects the position in the top stack frame.
4545
//
46-
// The other is for signal trampolines - In this case, the return address
46+
// Next, signal trampolines - For the trampoline itself, the return address
4747
// has been synthesized to be the entrypoint of a function (eg,
4848
// __restore_rt) to handle return from the signal handler, and will be the
4949
// first instruction in the function - there's no previous call instruction
5050
// to point at, so we use it directly.
51+
//
52+
// Finally, for the function that was running when the signal was invoked -
53+
// The signal was invoked asynchronously, so again, we have no call
54+
// instruction to walk back into.
5155
auto raw = rawIP();
5256
if (raw == 0)
5357
return { proc, raw };
5458
if (mechanism == UnwindMechanism::MACHINEREGS
5559
|| mechanism == UnwindMechanism::TRAMPOLINE)
5660
return { proc, raw };
61+
5762
if (isSignalTrampoline)
5863
return { proc, raw };
64+
if (unwoundFromTrampoline)
65+
return { proc, raw };
5966
ProcessLocation location(proc, raw);
6067

6168
const auto *lcie = location.cie();
@@ -498,7 +505,9 @@ StackFrame::StackFrame(UnwindMechanism mechanism, const Elf::CoreRegisters &regs
498505
, cfa(0)
499506
, mechanism(mechanism)
500507
, isSignalTrampoline(false)
501-
{}
508+
, unwoundFromTrampoline(false)
509+
{
510+
}
502511

503512
std::optional<Elf::CoreRegisters> StackFrame::unwind(Process &p) {
504513
ProcessLocation location = scopeIP(p);
@@ -518,8 +527,6 @@ std::optional<Elf::CoreRegisters> StackFrame::unwind(Process &p) {
518527

519528
using namespace Dwarf;
520529

521-
522-
523530
DWARFReader r(cfi->io, fde->instructions, fde->end);
524531

525532
auto iter = location.dwarf()->callFrameForAddr.find(objaddr);

libpstack/proc.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,12 +132,20 @@ class ProcessLocation {
132132

133133
class StackFrame {
134134
public:
135-
Elf::Addr rawIP() const;
135+
[[nodiscard]] Elf::Addr rawIP() const;
136136
ProcessLocation scopeIP(Process &) const;
137137
Elf::CoreRegisters regs;
138138
Elf::Addr cfa;
139139
UnwindMechanism mechanism;
140+
141+
// This frame is a signal trampoline, eg, at a function like
142+
// __kernel_rt_sigreturn
140143
bool isSignalTrampoline;
144+
145+
// This frame was unwound from a signal trampoline - implying didn't call
146+
// the function above it on the stack.
147+
bool unwoundFromTrampoline;
148+
141149
StackFrame(UnwindMechanism mechanism, const Elf::CoreRegisters &regs);
142150
StackFrame &operator = (const StackFrame &) = default;
143151
StackFrame(const StackFrame &) = default;

process.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,9 @@ ThreadStack::unwind(Process &p, Elf::CoreRegisters &regs)
988988
break;
989989
auto &newRegs = *maybeNewRegs;
990990
stack.emplace_back(UnwindMechanism::DWARF, newRegs);
991+
if (prev.isSignalTrampoline) {
992+
stack.back().unwoundFromTrampoline = true;
993+
}
991994
#ifdef __aarch64__
992995
auto &cur = stack.back();
993996
if (newRegs.pc == trampoline)
@@ -1023,7 +1026,8 @@ ThreadStack::unwind(Process &p, Elf::CoreRegisters &regs)
10231026
// register rather than a pushd return address
10241027

10251028
if (prev.mechanism == UnwindMechanism::MACHINEREGS
1026-
|| prev.mechanism == UnwindMechanism::TRAMPOLINE) {
1029+
|| prev.mechanism == UnwindMechanism::TRAMPOLINE
1030+
|| prev.unwoundFromTrampoline ) {
10271031
ProcessLocation badip = { p, IP(prev.regs) };
10281032
if (!badip.inObject() || (badip.codeloc->phdr().p_flags & PF_X) == 0) {
10291033
auto newRegs = prev.regs; // start with a copy of prev frames regs.

0 commit comments

Comments
 (0)