mib updated this revision to Diff 245424.
mib retitled this revision from "[lldb/Target] Add process crash-info command"
to "[lldb/Plugins] Add `platform process crash-info` command".
mib edited the summary of this revision.
mib added a comment.
Moved implementation from Process to Platform / PlatformDarwin and made it more
generic and extensive so other platforms could also use it.
Added documentation and addressed comments.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D74657/new/
https://reviews.llvm.org/D74657
Files:
lldb/bindings/interface/SBPlatform.i
lldb/include/lldb/API/SBPlatform.h
lldb/include/lldb/API/SBStructuredData.h
lldb/include/lldb/API/SBTarget.h
lldb/include/lldb/Target/Platform.h
lldb/include/lldb/Target/Process.h
lldb/source/API/SBPlatform.cpp
lldb/source/Commands/CommandObjectPlatform.cpp
lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h
lldb/source/Target/Platform.cpp
lldb/test/API/commands/platform/process/crash-info/Makefile
lldb/test/API/commands/platform/process/crash-info/TestPlatformProcessCrashInfo.py
lldb/test/API/commands/platform/process/crash-info/main.c
Index: lldb/test/API/commands/platform/process/crash-info/main.c
===================================================================
--- /dev/null
+++ lldb/test/API/commands/platform/process/crash-info/main.c
@@ -0,0 +1,7 @@
+#include <stdlib.h>
+int main() {
+ int *var = malloc(sizeof(int));
+ free(var);
+ free(var);
+ return 0;
+}
Index: lldb/test/API/commands/platform/process/crash-info/TestPlatformProcessCrashInfo.py
===================================================================
--- /dev/null
+++ lldb/test/API/commands/platform/process/crash-info/TestPlatformProcessCrashInfo.py
@@ -0,0 +1,63 @@
+"""
+Test lldb platform process crash info.
+"""
+
+import os
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+class PlatformProcessCrashInfoTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ def setUp(self):
+ TestBase.setUp(self)
+ self.runCmd("settings set auto-confirm true")
+
+ def tearDown(self):
+ self.runCmd("settings clear auto-confirm")
+ TestBase.tearDown(self)
+
+ @skipUnlessDarwin
+ def test_cli(self):
+ """Test that platform process crash-info fetches the extended crash
+ information array from the command-line properly."""
+ self.build()
+ exe = self.getBuildArtifact("a.out")
+ self.expect("file " + exe,
+ patterns=["Current executable set to .*a.out"])
+
+ self.expect('process launch',
+ patterns=["Process .* launched: .*a.out"])
+
+ self.expect('platform process crash-info',
+ patterns=["\"message\".*pointer being freed was not allocated"])
+
+
+ @skipUnlessDarwin
+ def test_api(self):
+ """Test that platform process crash-info fetches the extended crash
+ information array from the api properly."""
+ self.build()
+ target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
+ self.assertTrue(target, VALID_TARGET)
+
+ target.LaunchSimple(None, None, os.getcwd())
+
+ platform = target.GetPlatform()
+
+ stream = lldb.SBStream()
+ self.assertTrue(stream)
+
+ crash_info = platform.GetExtendedCrashInformation(target)
+
+ error = crash_info.GetAsJSON(stream)
+
+ self.assertTrue(error.Success())
+
+ self.assertTrue(crash_info.IsValid())
+
+ self.assertIn("pointer being freed was not allocated", stream.GetData())
Index: lldb/test/API/commands/platform/process/crash-info/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/commands/platform/process/crash-info/Makefile
@@ -0,0 +1,4 @@
+C_SOURCES := main.c
+
+include Makefile.rules
+
Index: lldb/source/Target/Platform.cpp
===================================================================
--- lldb/source/Target/Platform.cpp
+++ lldb/source/Target/Platform.cpp
@@ -384,7 +384,8 @@
m_rsync_opts(), m_rsync_prefix(), m_supports_ssh(false), m_ssh_opts(),
m_ignores_remote_hostname(false), m_trap_handlers(),
m_calculated_trap_handlers(false),
- m_module_cache(std::make_unique<ModuleCache>()) {
+ m_module_cache(std::make_unique<ModuleCache>()),
+ m_extended_crash_info(nullptr) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT));
LLDB_LOGF(log, "%p Platform::Platform()", static_cast<void *>(this));
}
Index: lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h
===================================================================
--- lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h
+++ lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h
@@ -12,6 +12,7 @@
#include "Plugins/Platform/POSIX/PlatformPOSIX.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/StructuredData.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/FileSystem.h"
@@ -84,7 +85,44 @@
iPhoneOS,
};
+ lldb_private::StructuredData::DictionarySP
+ FetchExtendedCrashInformation(lldb_private::Target &target) override;
+
protected:
+ // This struct should only be available in macOS but could be used on other
+ // platforms. #ifdef HAVE_CRASHREPORTERCLIENT_H #include
+ // <CrashReporterClient.h> #endif
+ struct CrashInfoAnnotations {
+ uint64_t version; // unsigned long
+ uint64_t message; // char *
+ uint64_t signature_string; // char *
+ uint64_t backtrace; // char *
+ uint64_t message2; // char *
+ uint64_t thread; // uint64_t
+ uint64_t dialog_mode; // unsigned int
+ uint64_t abort_cause; // unsigned int
+ };
+
+ /// Extract the `__crash_info` annotations from each of of the target's
+ /// modules.
+ ///
+ /// If the platform have a crashed processes with a `__crash_info` section,
+ /// extract the section to gather the messages annotations and the abort
+ /// cause.
+ ///
+ /// \param[in] target
+ /// The target running the crashed process.
+ /// \param[in] log
+ /// The log pointer initialized with the right logging channel
+ ///
+ /// \return
+ /// A structured data array containing at each entry in each entry, the
+ /// module spec, its UUID, the crash messages and the abort cause. Or a
+ /// nullptr if the process has no crash information entry.
+ lldb_private::StructuredData::ArraySP
+ ExtractCrashInfoAnnotations(lldb_private::Target &target,
+ lldb_private::Log *log);
+
void ReadLibdispatchOffsetsAddress(lldb_private::Process *process);
void ReadLibdispatchOffsets(lldb_private::Process *process);
Index: lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
===================================================================
--- lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
+++ lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
@@ -19,6 +19,7 @@
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/Section.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Host/XML.h"
@@ -1501,6 +1502,125 @@
return std::make_tuple(version, build);
}
+StructuredData::DictionarySP
+PlatformDarwin::FetchExtendedCrashInformation(lldb_private::Target &target) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ StructuredData::ArraySP annotations =
+ ExtractCrashInfoAnnotations(target, log);
+
+ if (!annotations) {
+ LLDB_LOG(log, "Couldn't extract crash information annotations");
+ }
+
+ if (!m_extended_crash_info)
+ m_extended_crash_info = std::make_shared<StructuredData::Dictionary>();
+
+ if (annotations)
+ m_extended_crash_info->AddItem("crash-info annotations", annotations);
+
+ return m_extended_crash_info;
+}
+
+StructuredData::ArraySP
+PlatformDarwin::ExtractCrashInfoAnnotations(Target &target, Log *log) {
+ ProcessSP process_sp = target.GetProcessSP();
+ StructuredData::ArraySP array_sp = std::make_shared<StructuredData::Array>();
+
+ for (ModuleSP module : target.GetImages().Modules()) {
+ SectionList *sections = module->GetSectionList();
+
+ std::string module_name = module->GetSpecificationDescription();
+
+ if (!sections) {
+ LLDB_LOG(log, "Module {0} doesn't have any section!", module_name);
+ continue;
+ }
+
+ ConstString section_name("__crash_info");
+ SectionSP crash_info = sections->FindSectionByName(section_name);
+ if (!crash_info) {
+ LLDB_LOG(log, "Module {0} doesn't have section {1}!", module_name,
+ section_name);
+ continue;
+ }
+
+ addr_t load_addr = crash_info->GetLoadBaseAddress(&target);
+
+ if (load_addr == LLDB_INVALID_ADDRESS) {
+ LLDB_LOG(log, "Module {0} has an invalid '{1}' section load address: {2}",
+ module_name, section_name, load_addr);
+ continue;
+ }
+
+ Status error;
+ CrashInfoAnnotations annotations;
+ size_t expected_size = sizeof(CrashInfoAnnotations);
+ size_t bytes_read = process_sp->ReadMemoryFromInferior(
+ load_addr, &annotations, expected_size, error);
+
+ if (expected_size != bytes_read || error.Fail()) {
+ LLDB_LOG(log, "Failed to read {0} section from memory in module {1}: {2}",
+ section_name, module_name, error);
+ continue;
+ }
+
+ // initial support added for version 5
+ if (annotations.version < 5) {
+ LLDB_LOG(log,
+ "Annotation version lower than 5 unsupported! Module {0} has "
+ "version {1} instead.",
+ module_name, annotations.version);
+ continue;
+ }
+
+ if (!annotations.message) {
+ LLDB_LOG(log, "No message available for module {0}.", module_name);
+ continue;
+ }
+
+ std::string message;
+ bytes_read =
+ process_sp->ReadCStringFromMemory(annotations.message, message, error);
+
+ if (message.empty() || bytes_read != message.size() || error.Fail()) {
+ LLDB_LOG(log, "Failed to read the message from memory in module {0}: {1}",
+ module_name, error);
+ continue;
+ }
+
+ // Remove trailing newline from message
+ if (message.back() == '\n')
+ message.pop_back();
+
+ if (!annotations.message2) {
+ LLDB_LOG(log, "No message2 available for module {0}.", module_name);
+ }
+
+ std::string message2;
+ bytes_read = process_sp->ReadCStringFromMemory(annotations.message2,
+ message2, error);
+
+ if (!message2.empty() && bytes_read == message2.size() && error.Success()) {
+ if (message2.back() == '\n')
+ message2.pop_back();
+ }
+
+ StructuredData::DictionarySP entry_sp =
+ std::make_shared<StructuredData::Dictionary>();
+
+ entry_sp->AddStringItem("image", module->GetFileSpec().GetPath(false));
+ entry_sp->AddStringItem("uuid", module->GetUUID().GetAsString());
+ entry_sp->AddStringItem("message", message);
+ entry_sp->AddStringItem("message2", message2);
+ entry_sp->AddIntegerItem("abort-cause", annotations.abort_cause);
+
+ array_sp->AddItem(entry_sp);
+ }
+
+ return array_sp;
+}
+
void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType(
Target *target, std::vector<std::string> &options, SDKType sdk_type) {
const std::vector<std::string> apple_arguments = {
Index: lldb/source/Commands/CommandObjectPlatform.cpp
===================================================================
--- lldb/source/Commands/CommandObjectPlatform.cpp
+++ lldb/source/Commands/CommandObjectPlatform.cpp
@@ -1517,14 +1517,64 @@
CommandOptions m_options;
};
+// CommandObjectPlatformProcessCrashInfo
+#pragma mark CommandObjectPlatformProcessCrashInfo
+
+class CommandObjectPlatformProcessCrashInfo : public CommandObjectParsed {
+public:
+ CommandObjectPlatformProcessCrashInfo(CommandInterpreter &interpreter)
+ : CommandObjectParsed(interpreter, "platform process crash-info",
+ "Fetch the platform's process crash information",
+ "process crash-info",
+ eCommandRequiresProcess |
+ eCommandTryTargetAPILock) {}
+
+ ~CommandObjectPlatformProcessCrashInfo() override = default;
+
+ bool DoExecute(Args &command, CommandReturnObject &result) override {
+ Stream &strm = result.GetOutputStream();
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+
+ PlatformSP platform_sp(
+ GetDebugger().GetPlatformList().GetSelectedPlatform());
+ if (!platform_sp) {
+ result.AppendError("Couldn'retrieve the selected platform");
+ return result.Succeeded();
+ }
+
+ if (command.GetArgumentCount()) {
+ result.AppendError("`process crash-info` takes no arguments");
+ return result.Succeeded();
+ }
+
+ // No need to check "process" for validity as eCommandRequiresProcess
+ // ensures it is valid
+ Target &target = GetSelectedTarget();
+ ProcessSP process_sp = target.GetProcessSP();
+
+ StructuredData::ObjectSP crash_info_sp =
+ platform_sp->FetchExtendedCrashInformation(target);
+
+ if (!crash_info_sp) {
+ result.AppendError("Couldn't fetch the crash information");
+ return result.Succeeded();
+ }
+
+ crash_info_sp->Dump(strm);
+
+ return result.Succeeded();
+ }
+};
+
class CommandObjectPlatformProcess : public CommandObjectMultiword {
public:
// Constructors and Destructors
CommandObjectPlatformProcess(CommandInterpreter &interpreter)
- : CommandObjectMultiword(interpreter, "platform process",
- "Commands to query, launch and attach to "
- "processes on the current platform.",
- "platform process [attach|launch|list] ...") {
+ : CommandObjectMultiword(
+ interpreter, "platform process",
+ "Commands to query, launch and attach to "
+ "processes on the current platform.",
+ "platform process [attach|launch|list|crash-info] ...") {
LoadSubCommand(
"attach",
CommandObjectSP(new CommandObjectPlatformProcessAttach(interpreter)));
@@ -1535,6 +1585,9 @@
interpreter)));
LoadSubCommand("list", CommandObjectSP(new CommandObjectPlatformProcessList(
interpreter)));
+ LoadSubCommand("crash-info",
+ CommandObjectSP(
+ new CommandObjectPlatformProcessCrashInfo(interpreter)));
}
~CommandObjectPlatformProcess() override = default;
Index: lldb/source/API/SBPlatform.cpp
===================================================================
--- lldb/source/API/SBPlatform.cpp
+++ lldb/source/API/SBPlatform.cpp
@@ -11,7 +11,9 @@
#include "lldb/API/SBError.h"
#include "lldb/API/SBFileSpec.h"
#include "lldb/API/SBLaunchInfo.h"
+#include "lldb/API/SBTarget.h"
#include "lldb/API/SBUnixSignals.h"
+#include "lldb/Core/StructuredDataImpl.h"
#include "lldb/Host/File.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Target.h"
@@ -643,6 +645,21 @@
return LLDB_RECORD_RESULT(SBUnixSignals());
}
+SBStructuredData SBPlatform::GetExtendedCrashInformation(SBTarget &target) {
+ LLDB_RECORD_METHOD(lldb::SBStructuredData, SBPlatform,
+ GetExtendedCrashInformation, (lldb::SBTarget &), target);
+
+ SBStructuredData data;
+ PlatformSP platform_sp(GetSP());
+ if (!platform_sp)
+ return LLDB_RECORD_RESULT(data);
+
+ StructuredData::ObjectSP fetched_data =
+ platform_sp->FetchExtendedCrashInformation(*target.GetSP().get());
+ data.m_impl_up->SetObjectSP(fetched_data);
+ return LLDB_RECORD_RESULT(data);
+}
+
namespace lldb_private {
namespace repro {
@@ -736,6 +753,8 @@
(const char *, uint32_t));
LLDB_REGISTER_METHOD_CONST(lldb::SBUnixSignals, SBPlatform, GetUnixSignals,
());
+ LLDB_REGISTER_METHOD(lldb::SBStructuredData, SBPlatform,
+ GetExtendedCrashInformation, (lldb::SBTarget &));
}
}
Index: lldb/include/lldb/Target/Process.h
===================================================================
--- lldb/include/lldb/Target/Process.h
+++ lldb/include/lldb/Target/Process.h
@@ -1267,7 +1267,7 @@
/// LLDB_INVALID_ADDRESS.
///
/// \return
- /// A StructureDataSP object which, if non-empty, will contain the
+ /// A StructuredDataSP object which, if non-empty, will contain the
/// information the DynamicLoader needs to get the initial scan of
/// solibs resolved.
virtual lldb_private::StructuredData::ObjectSP
Index: lldb/include/lldb/Target/Platform.h
===================================================================
--- lldb/include/lldb/Target/Platform.h
+++ lldb/include/lldb/Target/Platform.h
@@ -23,6 +23,7 @@
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/StructuredData.h"
#include "lldb/Utility/Timeout.h"
#include "lldb/Utility/UserIDResolver.h"
#include "lldb/lldb-private-forward.h"
@@ -823,6 +824,25 @@
virtual size_t ConnectToWaitingProcesses(lldb_private::Debugger &debugger,
lldb_private::Status &error);
+ /// Gather all of crash informations into a structured data dictionnary.
+ ///
+ /// If the platform have a crashed processes with crash information entries,
+ /// gather all the entries into an structured data dictionnary or return a
+ /// nullptr. This dictionnary is generic and extensible, as it contains an
+ /// array for each different type of crash information.
+ ///
+ /// \param[in] target
+ /// The target running the crashed process.
+ ///
+ /// \return
+ /// A Structured Data Dictionnary containing at each entry an array for
+ /// each different crash information type. Or a nullptr if the process has
+ /// no crash information entry.
+ virtual StructuredData::DictionarySP
+ FetchExtendedCrashInformation(lldb_private::Target &target) {
+ return nullptr;
+ }
+
protected:
bool m_is_host;
// Set to true when we are able to actually set the OS version while being
@@ -858,6 +878,7 @@
std::vector<ConstString> m_trap_handlers;
bool m_calculated_trap_handlers;
const std::unique_ptr<ModuleCache> m_module_cache;
+ StructuredData::DictionarySP m_extended_crash_info;
/// Ask the Platform subclass to fill in the list of trap handler names
///
Index: lldb/include/lldb/API/SBTarget.h
===================================================================
--- lldb/include/lldb/API/SBTarget.h
+++ lldb/include/lldb/API/SBTarget.h
@@ -829,6 +829,7 @@
friend class SBFunction;
friend class SBInstruction;
friend class SBModule;
+ friend class SBPlatform;
friend class SBProcess;
friend class SBSection;
friend class SBSourceManager;
Index: lldb/include/lldb/API/SBStructuredData.h
===================================================================
--- lldb/include/lldb/API/SBStructuredData.h
+++ lldb/include/lldb/API/SBStructuredData.h
@@ -90,6 +90,7 @@
protected:
friend class SBTraceOptions;
friend class SBDebugger;
+ friend class SBPlatform;
friend class SBTarget;
friend class SBThread;
friend class SBThreadPlan;
Index: lldb/include/lldb/API/SBPlatform.h
===================================================================
--- lldb/include/lldb/API/SBPlatform.h
+++ lldb/include/lldb/API/SBPlatform.h
@@ -10,6 +10,7 @@
#define LLDB_API_SBPLATFORM_H
#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBStructuredData.h"
#include <functional>
@@ -152,6 +153,8 @@
SBUnixSignals GetUnixSignals() const;
+ SBStructuredData GetExtendedCrashInformation(SBTarget &target);
+
protected:
friend class SBDebugger;
friend class SBTarget;
Index: lldb/bindings/interface/SBPlatform.i
===================================================================
--- lldb/bindings/interface/SBPlatform.i
+++ lldb/bindings/interface/SBPlatform.i
@@ -192,6 +192,11 @@
lldb::SBUnixSignals
GetUnixSignals();
+ %feature("autodoc", "
+ Returns the platform's process extended crash information.") GetExtendedCrashInformation;
+ lldb::SBStructuredData
+ GetExtendedCrashInformation (lldb::SBTarget& target);
+
};
} // namespace lldb
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits