Skip to content

Commit 720fed5

Browse files
committed
Fix the ptrace(PTRACE_ATTACH, ...) protocol
After we attach, the first signal we receive may not be our stop signal. Check for the SIGSTOP, and if that's not what we received, then redeliver, and continue until we get the actual stop.
1 parent f066f08 commit 720fed5

3 files changed

Lines changed: 44 additions & 24 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
cmake_minimum_required(VERSION 3.10)
22
set(PSTACK_SOVERSION 2.16)
3-
set(PSTACK_VERSION 2.16)
3+
set(PSTACK_VERSION 2.16.1)
44
project(pstack LANGUAGES C CXX VERSION "${PSTACK_VERSION}" )
55

66
include (GNUInstallDirs)

live.cc

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -180,12 +180,44 @@ LiveProcess::stop(lwpid_t tid) {
180180
}
181181
tcb.ptraceErr = 0;
182182

183-
int status = 0;
184-
pid_t waitedpid = waitpid(tid, &status, tid == this->pid ? 0 : __WCLONE);
185-
if (waitedpid == -1)
186-
*context.debug << "failed to stop LWP " << tid << ": wait failed: " << strerror(errno) << "\n";
187-
else if (context.verbose >= 1)
188-
*context.debug << "suspend LWP " << tid << std::endl;
183+
// If anything breaks from here on, we'll PT_DETACH, and send a SIGCONT in
184+
// case there's any confusion
185+
186+
for (int count = 0; tcb.ptraceErr == 0; ++count) {
187+
int status = 0;
188+
pid_t waitedpid = waitpid(tid, &status, tid == this->pid ? 0 : __WCLONE);
189+
if (waitedpid == -1) {
190+
if (errno != EINTR) {
191+
tcb.ptraceErr = errno;
192+
*context.debug << "failed to stop LWP " << tid << ": wait failed: " << strerror(errno) << "\n";
193+
} else {
194+
*context.debug << "interrupted stopping LWP " << tid << ": retry\n";
195+
}
196+
} else if (!WIFSTOPPED(status)) {
197+
tcb.ptraceErr = EINVAL;
198+
*context.debug << "wait doesn't report LWP stopped? " << status << "\n";
199+
} else if (WSTOPSIG(status) != SIGSTOP) {
200+
*context.debug << "got signal " << WSTOPSIG(status)
201+
<< " while waiting for " << tid << " to stop - deliver and retry.";
202+
siginfo_t si;
203+
if (ptrace(PTRACE_GETSIGINFO, tid, nullptr, &si) != -1) {
204+
*context.debug << " new siginfo: " << SigInfo{si};
205+
}
206+
*context.debug << "\n";
207+
208+
if (ptrace(PTRACE_CONT, tid, nullptr, WSTOPSIG(status)) == -1) {
209+
tcb.ptraceErr = errno;
210+
*context.debug << "...failed " << errno << "\n";
211+
}
212+
} else {
213+
if (context.verbose >= 1)
214+
*context.debug << "suspended LWP " << tid << " (attempt " << count+1 << ")" << std::endl;
215+
return;
216+
}
217+
}
218+
*context.debug << "sending SIGCONT to " << tid << " and detaching\n";
219+
kill(tid, SIGCONT); // don't leave it hanging if we messed up.
220+
ptrace(PT_DETACH, tid, caddr_t(1), 0);
189221
}
190222

191223
// Parse [s]maps for this pid. We use "smaps" just for vmflags for now.

process.cc

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1422,7 +1422,11 @@ std::ostream &operator << (std::ostream &os, const SigInfo &sip) {
14221422
#else
14231423
<< "si_signo " << si.si_signo
14241424
#endif
1425-
<< ", si_code " << si.si_code;
1425+
<< ", si_code " << si.si_code
1426+
<< ", si_pid " << si.si_pid
1427+
<< ", si_fd " << si.si_fd
1428+
<< ", si_addr " << si.si_addr
1429+
;
14261430

14271431
auto codesforsig = codes.find( si.si_signo );
14281432
if (codesforsig == codes.end()) {
@@ -1434,22 +1438,6 @@ std::ostream &operator << (std::ostream &os, const SigInfo &sip) {
14341438
if (code != codesforsig->second.end())
14351439
os << " - " << code->second;
14361440
}
1437-
1438-
switch (si.si_signo) {
1439-
case SIGILL:
1440-
case SIGFPE:
1441-
case SIGBUS:
1442-
case SIGTRAP:
1443-
#ifdef SIGEMT
1444-
case SIGEMT:
1445-
#endif
1446-
case SIGSEGV: {
1447-
os << ", fault address " << std::hex << si.si_addr << std::dec;
1448-
break;
1449-
}
1450-
1451-
1452-
}
14531441
return os;
14541442
}}
14551443

0 commit comments

Comments
 (0)