Skip to content

Commit 5c25880

Browse files
committed
Implement PTRACE_SEIZE when a process is coredumping
1 parent 1a7cd92 commit 5c25880

File tree

2 files changed

+113
-7
lines changed

2 files changed

+113
-7
lines changed

lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp

Lines changed: 109 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -312,10 +312,26 @@ NativeProcessLinux::Manager::Attach(
312312
Log *log = GetLog(POSIXLog::Process);
313313
LLDB_LOG(log, "pid = {0:x}", pid);
314314

315-
auto tids_or = NativeProcessLinux::Attach(pid);
316-
if (!tids_or)
317-
return tids_or.takeError();
318-
ArrayRef<::pid_t> tids = *tids_or;
315+
// This safety check lets us decide if we should
316+
// seize or attach.
317+
ProcessInstanceInfo process_info;
318+
if (!Host::GetProcessInfo(pid, process_info))
319+
return llvm::make_error<StringError>("Unable to read process info",
320+
llvm::inconvertibleErrorCode());
321+
322+
std::vector<::pid_t> tids;
323+
if (process_info.IsCoreDumping()) {
324+
auto attached_or = NativeProcessLinux::Seize(pid);
325+
if (!attached_or)
326+
return attached_or.takeError();
327+
tids = std::move(*attached_or);
328+
} else {
329+
auto attached_or = NativeProcessLinux::Attach(pid);
330+
if (!attached_or)
331+
return attached_or.takeError();
332+
tids = std::move(*attached_or);
333+
}
334+
319335
llvm::Expected<ArchSpec> arch_or =
320336
NativeRegisterContextLinux::DetermineArchitecture(tids[0]);
321337
if (!arch_or)
@@ -444,6 +460,88 @@ NativeProcessLinux::NativeProcessLinux(::pid_t pid, int terminal_fd,
444460
SetState(StateType::eStateStopped, false);
445461
}
446462

463+
llvm::Expected<std::vector<::pid_t>> NativeProcessLinux::Seize(::pid_t pid) {
464+
Log *log = GetLog(POSIXLog::Process);
465+
466+
uint64_t options = GetDefaultPtraceOpts();
467+
Status status;
468+
// Use a map to keep track of the threads which we have attached/need to
469+
// attach.
470+
Host::TidMap tids_to_attach;
471+
while (Host::FindProcessThreads(pid, tids_to_attach)) {
472+
for (Host::TidMap::iterator it = tids_to_attach.begin();
473+
it != tids_to_attach.end();) {
474+
if (it->second == true) {
475+
continue;
476+
}
477+
lldb::tid_t tid = it->first;
478+
if ((status = PtraceWrapper(PTRACE_SEIZE, tid, nullptr, (void *)options))
479+
.Fail()) {
480+
// No such thread. The thread may have exited. More error handling
481+
// may be needed.
482+
if (status.GetError() == ESRCH) {
483+
it = tids_to_attach.erase(it);
484+
continue;
485+
}
486+
if (status.GetError() == EPERM) {
487+
// Depending on the value of ptrace_scope, we can return a
488+
// different error that suggests how to fix it.
489+
return AddPtraceScopeNote(status.ToError());
490+
}
491+
return status.ToError();
492+
}
493+
494+
if ((status = PtraceWrapper(PTRACE_INTERRUPT, tid)).Fail()) {
495+
// No such thread. The thread may have exited. More error handling
496+
// may be needed.
497+
if (status.GetError() == ESRCH) {
498+
it = tids_to_attach.erase(it);
499+
continue;
500+
}
501+
if (status.GetError() == EPERM) {
502+
// Depending on the value of ptrace_scope, we can return a
503+
// different error that suggests how to fix it.
504+
return AddPtraceScopeNote(status.ToError());
505+
}
506+
return status.ToError();
507+
}
508+
509+
int wpid =
510+
llvm::sys::RetryAfterSignal(-1, ::waitpid, tid, nullptr, __WALL);
511+
// Need to use __WALL otherwise we receive an error with errno=ECHLD At
512+
// this point we should have a thread stopped if waitpid succeeds.
513+
if (wpid < 0) {
514+
// No such thread. The thread may have exited. More error handling
515+
// may be needed.
516+
if (errno == ESRCH) {
517+
it = tids_to_attach.erase(it);
518+
continue;
519+
}
520+
return llvm::errorCodeToError(
521+
std::error_code(errno, std::generic_category()));
522+
}
523+
524+
LLDB_LOG(log, "adding tid = {0}", tid);
525+
it->second = true;
526+
527+
// move the loop forward
528+
++it;
529+
}
530+
}
531+
532+
size_t tid_count = tids_to_attach.size();
533+
if (tid_count == 0)
534+
return llvm::make_error<StringError>("No such process",
535+
llvm::inconvertibleErrorCode());
536+
537+
std::vector<::pid_t> tids;
538+
tids.reserve(tid_count);
539+
for (const auto &p : tids_to_attach)
540+
tids.push_back(p.first);
541+
542+
return std::move(tids);
543+
}
544+
447545
llvm::Expected<std::vector<::pid_t>> NativeProcessLinux::Attach(::pid_t pid) {
448546
Log *log = GetLog(POSIXLog::Process);
449547

@@ -513,8 +611,8 @@ llvm::Expected<std::vector<::pid_t>> NativeProcessLinux::Attach(::pid_t pid) {
513611
return std::move(tids);
514612
}
515613

516-
Status NativeProcessLinux::SetDefaultPtraceOpts(lldb::pid_t pid) {
517-
long ptrace_opts = 0;
614+
uint64_t NativeProcessLinux::GetDefaultPtraceOpts() {
615+
uint64_t ptrace_opts = 0;
518616

519617
// Have the child raise an event on exit. This is used to keep the child in
520618
// limbo until it is destroyed.
@@ -537,6 +635,11 @@ Status NativeProcessLinux::SetDefaultPtraceOpts(lldb::pid_t pid) {
537635
// the child finishes sharing memory.
538636
ptrace_opts |= PTRACE_O_TRACEVFORKDONE;
539637

638+
return ptrace_opts;
639+
}
640+
641+
Status NativeProcessLinux::SetDefaultPtraceOpts(lldb::pid_t pid) {
642+
uint64_t ptrace_opts = GetDefaultPtraceOpts();
540643
return PtraceWrapper(PTRACE_SETOPTIONS, pid, nullptr, (void *)ptrace_opts);
541644
}
542645

lldb/source/Plugins/Process/Linux/NativeProcessLinux.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,6 @@ class NativeProcessLinux : public NativeProcessELF,
175175
private:
176176
Manager &m_manager;
177177
ArchSpec m_arch;
178-
179178
LazyBool m_supports_mem_region = eLazyBoolCalculate;
180179
std::vector<std::pair<MemoryRegionInfo, FileSpec>> m_mem_region_cache;
181180

@@ -191,9 +190,13 @@ class NativeProcessLinux : public NativeProcessELF,
191190

192191
// Returns a list of process threads that we have attached to.
193192
static llvm::Expected<std::vector<::pid_t>> Attach(::pid_t pid);
193+
// Returns a list of process threads that we have seized and interrupted.
194+
static llvm::Expected<std::vector<::pid_t>> Seize(::pid_t pid);
194195

195196
static Status SetDefaultPtraceOpts(const lldb::pid_t);
196197

198+
static uint64_t GetDefaultPtraceOpts();
199+
197200
bool TryHandleWaitStatus(lldb::pid_t pid, WaitStatus status);
198201

199202
void MonitorCallback(NativeThreadLinux &thread, WaitStatus status);

0 commit comments

Comments
 (0)