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 <jalalo...@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 <jalalo...@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); } _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits