[Lldb-commits] [lldb] [LLDB] Ptrace seize dead process (PR #137041)
Jacob Lalonde via lldb-commits
lldb-commits at lists.llvm.org
Thu Apr 24 15:26:12 PDT 2025
https://github.com/Jlalond updated https://github.com/llvm/llvm-project/pull/137041
>From 94248d8526064859c2f3eda0ac82d61f299100b2 Mon Sep 17 00:00:00 2001
From: Jacob Lalonde <jalalonde at fb.com>
Date: Tue, 22 Apr 2025 16:35:00 -0700
Subject: [PATCH 1/2] Create proc status reader
---
.../Plugins/Process/Utility/CMakeLists.txt | 1 +
.../Process/Utility/LinuxProcStatus.cpp | 42 +++++++++++++++++++
.../Plugins/Process/Utility/LinuxProcStatus.h | 22 ++++++++++
3 files changed, 65 insertions(+)
create mode 100644 lldb/source/Plugins/Process/Utility/LinuxProcStatus.cpp
create mode 100644 lldb/source/Plugins/Process/Utility/LinuxProcStatus.h
diff --git a/lldb/source/Plugins/Process/Utility/CMakeLists.txt b/lldb/source/Plugins/Process/Utility/CMakeLists.txt
index d29605fddd5cb..8db3a6879b618 100644
--- a/lldb/source/Plugins/Process/Utility/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/Utility/CMakeLists.txt
@@ -6,6 +6,7 @@ add_lldb_library(lldbPluginProcessUtility
HistoryUnwind.cpp
InferiorCallPOSIX.cpp
LinuxProcMaps.cpp
+ LinuxProcStatus.cpp
LinuxSignals.cpp
MemoryTagManagerAArch64MTE.cpp
NativeProcessSoftwareSingleStep.cpp
diff --git a/lldb/source/Plugins/Process/Utility/LinuxProcStatus.cpp b/lldb/source/Plugins/Process/Utility/LinuxProcStatus.cpp
new file mode 100644
index 0000000000000..75575d62210f0
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/LinuxProcStatus.cpp
@@ -0,0 +1,42 @@
+//===-- LinuxProcMaps.cpp ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "LinuxProcStatus.h"
+#include <sstream>
+#include <string>
+#include <vector>
+
+static std::vector<std::string> SplitLines(llvm::StringRef proc_status) {
+ std::istringstream inputstream(proc_status.str());
+ std::vector<std::string> lines;
+ std::string line;
+ while (std::getline(inputstream, line)) {
+ lines.push_back(line);
+ }
+ return lines;
+}
+
+lldb_private::StructuredData::Dictionary
+ParseProcStatus(llvm::StringRef proc_status) {
+ std::vector<std::string> lines = SplitLines(proc_status);
+ lldb_private::StructuredData::Dictionary proc_status_data;
+ for (auto &str : lines) {
+ // proc/pid/status is a delineated by a colon, so we split all the lines
+ // and then return a structureddata of each name : value. We keep these
+ // all as text, and let the caller sort the type they want them as.
+ size_t colonPos = str.find(':');
+ if (colonPos == std::string::npos) {
+ continue;
+ }
+ std::string name = str.substr(0, colonPos);
+ std::string value = str.substr(colonPos + 1);
+ proc_status_data.AddStringItem(name, value);
+ }
+
+ return proc_status_data;
+}
diff --git a/lldb/source/Plugins/Process/Utility/LinuxProcStatus.h b/lldb/source/Plugins/Process/Utility/LinuxProcStatus.h
new file mode 100644
index 0000000000000..28e01ac9ff74e
--- /dev/null
+++ b/lldb/source/Plugins/Process/Utility/LinuxProcStatus.h
@@ -0,0 +1,22 @@
+//===-- LinuxProcStatus.h ---------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LINUXPROCSTATUS_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LINUXPROCSTATUS_H
+
+#include "lldb/Utility/StructuredData.h"
+#include "lldb/lldb-forward.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace lldb_private {
+
+StructuredData::Dictionary ParseProcStatus(llvm::StringRef proc_status);
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LINUXPROCSTATUS_H
>From 3b10fcdbbaf80bc1d21e9e6757f7cf5056ad54a0 Mon Sep 17 00:00:00 2001
From: Jacob Lalonde <jalalonde at fb.com>
Date: Wed, 23 Apr 2025 11:31:01 -0700
Subject: [PATCH 2/2] Fix tabs, newlines, and spaces getting in the structured
data
---
.../Process/Linux/NativeProcessLinux.cpp | 80 ++++++++++++++++---
.../Process/Utility/LinuxProcStatus.cpp | 12 ++-
2 files changed, 78 insertions(+), 14 deletions(-)
diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
index 7f2aba0e4eb2c..f052931e1d377 100644
--- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -23,6 +23,7 @@
#include "NativeThreadLinux.h"
#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
#include "Plugins/Process/Utility/LinuxProcMaps.h"
+#include "Plugins/Process/Utility/LinuxProcStatus.h"
#include "Procfs.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Host/Host.h"
@@ -443,10 +444,29 @@ NativeProcessLinux::NativeProcessLinux(::pid_t pid, int terminal_fd,
SetCurrentThreadID(tids[0]);
SetState(StateType::eStateStopped, false);
}
+static bool IsCoredumping(lldb::pid_t pid) {
+ auto BufferOrError = getProcFile(pid, "status");
+ if (!BufferOrError)
+ return false;
+
+ lldb_private::StructuredData::Dictionary proc_status =
+ ParseProcStatus(BufferOrError.get()->getBuffer());
+
+ if (!proc_status.HasKey("CoreDumping"))
+ return false;
+
+ llvm::StringRef result;
+ if (!proc_status.GetValueForKeyAsString("CoreDumping", result))
+ return false;
+
+ return result == "1";
+}
llvm::Expected<std::vector<::pid_t>> NativeProcessLinux::Attach(::pid_t pid) {
Log *log = GetLog(POSIXLog::Process);
+ bool coreDumping = IsCoredumping(pid);
+ LLDB_LOG(log, "{0} coredumping: {1}", pid, coreDumping);
Status status;
// Use a map to keep track of the threads which we have attached/need to
// attach.
@@ -457,21 +477,55 @@ llvm::Expected<std::vector<::pid_t>> NativeProcessLinux::Attach(::pid_t pid) {
if (it->second == false) {
lldb::tid_t tid = it->first;
- // Attach to the requested process.
- // An attach will cause the thread to stop with a SIGSTOP.
- if ((status = PtraceWrapper(PTRACE_ATTACH, tid)).Fail()) {
- // No such thread. The thread may have exited. More error handling
- // may be needed.
- if (status.GetError() == ESRCH) {
- it = tids_to_attach.erase(it);
- continue;
+ if (!coreDumping) {
+ // Attach to the requested process.
+ // An attach will cause the thread to stop with a SIGSTOP.
+ if ((status = PtraceWrapper(PTRACE_ATTACH, tid)).Fail()) {
+ // No such thread. The thread may have exited. More error handling
+ // may be needed.
+ if (status.GetError() == ESRCH) {
+ it = tids_to_attach.erase(it);
+ continue;
+ }
+ if (status.GetError() == EPERM) {
+ // Depending on the value of ptrace_scope, we can return a
+ // different error that suggests how to fix it.
+ return AddPtraceScopeNote(status.ToError());
+ }
+ return status.ToError();
}
- if (status.GetError() == EPERM) {
- // Depending on the value of ptrace_scope, we can return a different
- // error that suggests how to fix it.
- return AddPtraceScopeNote(status.ToError());
+ } else {
+ long options = PTRACE_O_TRACEEXIT | PTRACE_O_TRACESYSGOOD;
+ if ((status =
+ PtraceWrapper(PTRACE_SEIZE, tid, nullptr, (void *)options))
+ .Fail()) {
+ // No such thread. The thread may have exited. More error handling
+ // may be needed.
+ if (status.GetError() == ESRCH) {
+ it = tids_to_attach.erase(it);
+ continue;
+ }
+ if (status.GetError() == EPERM) {
+ // Depending on the value of ptrace_scope, we can return a
+ // different error that suggests how to fix it.
+ return AddPtraceScopeNote(status.ToError());
+ }
+ return status.ToError();
+ }
+ if ((status = PtraceWrapper(PTRACE_INTERRUPT, tid)).Fail()) {
+ // No such thread. The thread may have exited. More error handling
+ // may be needed.
+ if (status.GetError() == ESRCH) {
+ it = tids_to_attach.erase(it);
+ continue;
+ }
+ if (status.GetError() == EPERM) {
+ // Depending on the value of ptrace_scope, we can return a
+ // different error that suggests how to fix it.
+ return AddPtraceScopeNote(status.ToError());
+ }
+ return status.ToError();
}
- return status.ToError();
}
int wpid =
diff --git a/lldb/source/Plugins/Process/Utility/LinuxProcStatus.cpp b/lldb/source/Plugins/Process/Utility/LinuxProcStatus.cpp
index 75575d62210f0..b18dfce2da1a3 100644
--- a/lldb/source/Plugins/Process/Utility/LinuxProcStatus.cpp
+++ b/lldb/source/Plugins/Process/Utility/LinuxProcStatus.cpp
@@ -12,6 +12,8 @@
#include <vector>
static std::vector<std::string> SplitLines(llvm::StringRef proc_status) {
+ // Push everything to an input stream and then read it to a vec
+ // line by line
std::istringstream inputstream(proc_status.str());
std::vector<std::string> lines;
std::string line;
@@ -22,7 +24,7 @@ static std::vector<std::string> SplitLines(llvm::StringRef proc_status) {
}
lldb_private::StructuredData::Dictionary
-ParseProcStatus(llvm::StringRef proc_status) {
+lldb_private::ParseProcStatus(llvm::StringRef proc_status) {
std::vector<std::string> lines = SplitLines(proc_status);
lldb_private::StructuredData::Dictionary proc_status_data;
for (auto &str : lines) {
@@ -35,6 +37,14 @@ ParseProcStatus(llvm::StringRef proc_status) {
}
std::string name = str.substr(0, colonPos);
std::string value = str.substr(colonPos + 1);
+ // All the leading values have a tab character, but
+ // that's not explicitly documented on the man page so
+ // we have this check to strip the tab, and any newline or
+ // space characters
+ value.erase(std::remove_if(
+ value.begin(), value.end(),
+ [](char c) { return c == '\t' || c == '\n' || c == ' '; }),
+ value.end());
proc_status_data.AddStringItem(name, value);
}
More information about the lldb-commits
mailing list