clayborg created this revision.
clayborg added reviewers: zturner, labath, lemo.
Each process plug-in can create its own custom commands. I figured it would be
nice to be able to dump things from the minidump file from the lldb command
line, so I added the start of the some custom commands.
Currently you can dump:
- minidump stream directory
- all linux specifc streams, most of which are strings
- each linux stream individually if desired, or all with --linux
The idea is we can expand the command set to dump more things, search for data
in the core file, and much more. This patch gets us started.
https://reviews.llvm.org/D55727
Files:
source/Plugins/Process/minidump/MinidumpParser.cpp
source/Plugins/Process/minidump/MinidumpParser.h
source/Plugins/Process/minidump/MinidumpTypes.h
source/Plugins/Process/minidump/ProcessMinidump.cpp
source/Plugins/Process/minidump/ProcessMinidump.h
Index: source/Plugins/Process/minidump/ProcessMinidump.h
===================================================================
--- source/Plugins/Process/minidump/ProcessMinidump.h
+++ source/Plugins/Process/minidump/ProcessMinidump.h
@@ -49,6 +49,8 @@
bool CanDebug(lldb::TargetSP target_sp,
bool plugin_specified_by_name) override;
+ CommandObject *GetPluginCommandObject() override;
+
Status DoLoadCore() override;
DynamicLoader *GetDynamicLoader() override { return nullptr; }
@@ -104,6 +106,7 @@
FileSpec m_core_file;
llvm::ArrayRef<MinidumpThread> m_thread_list;
const MinidumpExceptionStream *m_active_exception;
+ lldb::CommandObjectSP m_command_sp;
bool m_is_wow64;
};
Index: source/Plugins/Process/minidump/ProcessMinidump.cpp
===================================================================
--- source/Plugins/Process/minidump/ProcessMinidump.cpp
+++ source/Plugins/Process/minidump/ProcessMinidump.cpp
@@ -10,10 +10,17 @@
#include "ProcessMinidump.h"
#include "ThreadMinidump.h"
+#include "lldb/Core/DumpDataExtractor.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Section.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/OptionArgParser.h"
+#include "lldb/Interpreter/OptionGroupBoolean.h"
#include "lldb/Target/JITLoaderList.h"
#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Target/SectionLoadList.h"
@@ -398,3 +405,242 @@
}
return *m_jit_loaders_ap;
}
+
+class CommandObjectProcessMinidumpDump : public CommandObjectParsed {
+private:
+ OptionGroupOptions m_option_group;
+ OptionGroupBoolean m_dump_all;
+ OptionGroupBoolean m_dump_directory;
+ OptionGroupBoolean m_dump_linux_cpuinfo;
+ OptionGroupBoolean m_dump_linux_proc_status;
+ OptionGroupBoolean m_dump_linux_lsb_release;
+ OptionGroupBoolean m_dump_linux_cmdline;
+ OptionGroupBoolean m_dump_linux_environ;
+ OptionGroupBoolean m_dump_linux_auxv;
+ OptionGroupBoolean m_dump_linux_maps;
+ OptionGroupBoolean m_dump_linux_proc_stat;
+ OptionGroupBoolean m_dump_linux_proc_uptime;
+ OptionGroupBoolean m_dump_linux_proc_fd;
+ OptionGroupBoolean m_dump_linux_all;
+
+ void SetDefaultOptionsIfNoneAreSet() {
+ if (m_dump_all.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_all.GetOptionValue().GetCurrentValue() ||
+ m_dump_directory.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_cpuinfo.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_proc_status.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_lsb_release.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_cmdline.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_environ.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_auxv.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_maps.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_proc_stat.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_proc_uptime.GetOptionValue().GetCurrentValue() ||
+ m_dump_linux_proc_fd.GetOptionValue().GetCurrentValue())
+ return;
+ // If no options were set, then dump everything
+ m_dump_all.GetOptionValue().SetCurrentValue(true);
+ }
+ bool DumpAll() const {
+ return m_dump_all.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpDirectory() const {
+ return DumpAll() ||
+ m_dump_directory.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinux() const {
+ return DumpAll() || m_dump_linux_all.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinuxCPUInfo() const {
+ return DumpLinux() ||
+ m_dump_linux_cpuinfo.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinuxProcStatus() const {
+ return DumpLinux() ||
+ m_dump_linux_proc_status.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinuxProcStat() const {
+ return DumpLinux() ||
+ m_dump_linux_proc_stat.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinuxLSBRelease() const {
+ return DumpLinux() ||
+ m_dump_linux_lsb_release.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinuxCMDLine() const {
+ return DumpLinux() ||
+ m_dump_linux_cmdline.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinuxEnviron() const {
+ return DumpLinux() ||
+ m_dump_linux_environ.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinuxAuxv() const {
+ return DumpLinux() ||
+ m_dump_linux_auxv.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinuxMaps() const {
+ return DumpLinux() ||
+ m_dump_linux_maps.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinuxProcUptime() const {
+ return DumpLinux() ||
+ m_dump_linux_proc_uptime.GetOptionValue().GetCurrentValue();
+ }
+ bool DumpLinuxProcFD() const {
+ return DumpLinux() ||
+ m_dump_linux_proc_fd.GetOptionValue().GetCurrentValue();
+ }
+public:
+#define INIT_BOOL(VAR, LONG, SHORT, DESC) \
+ VAR(LLDB_OPT_SET_1, false, LONG, SHORT, DESC, false, true)
+#define APPEND_OPT(VAR) \
+ m_option_group.Append(&VAR, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1)
+
+ CommandObjectProcessMinidumpDump(CommandInterpreter &interpreter)
+ : CommandObjectParsed(interpreter, "process plugin dump",
+ "Dump information from the minidump file.", NULL),
+ m_option_group(),
+ INIT_BOOL(m_dump_all, "all", 'a',
+ "Dump the everything in the minidump."),
+ INIT_BOOL(m_dump_directory, "directory", 'd',
+ "Dump the minidump directory map."),
+ INIT_BOOL(m_dump_linux_cpuinfo, "cpuinfo", 'C',
+ "Dump linux /proc/cpuinfo."),
+ INIT_BOOL(m_dump_linux_proc_status, "status", 's',
+ "Dump linux /proc/<pid>/status."),
+ INIT_BOOL(m_dump_linux_lsb_release, "lsb-release", 'r',
+ "Dump linux /etc/lsb-release."),
+ INIT_BOOL(m_dump_linux_cmdline, "cmdline", 'c',
+ "Dump linux /proc/<pid>/cmdline."),
+ INIT_BOOL(m_dump_linux_environ, "environ", 'e',
+ "Dump linux /proc/<pid>/environ."),
+ INIT_BOOL(m_dump_linux_auxv, "auxv", 'x',
+ "Dump linux /proc/<pid>/auxv."),
+ INIT_BOOL(m_dump_linux_maps, "maps", 'm',
+ "Dump linux /proc/<pid>/maps."),
+ INIT_BOOL(m_dump_linux_proc_stat, "stat", 'S',
+ "Dump linux /proc/<pid>/stat."),
+ INIT_BOOL(m_dump_linux_proc_uptime, "uptime", 'u',
+ "Dump linux process uptime."),
+ INIT_BOOL(m_dump_linux_proc_fd, "fd", 'f',
+ "Dump linux /proc/<pid>/fd."),
+ INIT_BOOL(m_dump_linux_all, "linux", 'l',
+ "Dump all linux streams.") {
+ APPEND_OPT(m_dump_all);
+ APPEND_OPT(m_dump_directory);
+ APPEND_OPT(m_dump_linux_cpuinfo);
+ APPEND_OPT(m_dump_linux_proc_status);
+ APPEND_OPT(m_dump_linux_lsb_release);
+ APPEND_OPT(m_dump_linux_cmdline);
+ APPEND_OPT(m_dump_linux_environ);
+ APPEND_OPT(m_dump_linux_auxv);
+ APPEND_OPT(m_dump_linux_maps);
+ APPEND_OPT(m_dump_linux_proc_stat);
+ APPEND_OPT(m_dump_linux_proc_uptime);
+ APPEND_OPT(m_dump_linux_proc_fd);
+ APPEND_OPT(m_dump_linux_all);
+ m_option_group.Finalize();
+ }
+
+ ~CommandObjectProcessMinidumpDump() {}
+
+ Options *GetOptions() override { return &m_option_group; }
+
+ bool DoExecute(Args &command, CommandReturnObject &result) override {
+ const size_t argc = command.GetArgumentCount();
+ if (argc > 0) {
+ result.AppendErrorWithFormat("'%s' take no arguments, only options",
+ m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ SetDefaultOptionsIfNoneAreSet();
+
+ ProcessMinidump *process =
+ (ProcessMinidump *)m_interpreter.GetExecutionContext().GetProcessPtr();
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ Stream &s = result.GetOutputStream();
+ MinidumpParser &minidump = process->m_minidump_parser;
+ if (DumpDirectory()) {
+ s.Printf("RVA SIZE TYPE MinidumpStreamType\n");
+ s.Printf("---------- ---------- ---------- --------------------------\n");
+ minidump.ForEachStreamType(
+ [&](uint32_t stream_type,
+ const MinidumpLocationDescriptor &loc_desc) -> bool {
+ s.Printf("0x%8.8x 0x%8.8x 0x%8.8x %s\n",
+ (uint32_t)loc_desc.rva,
+ (uint32_t)loc_desc.data_size, stream_type,
+ MinidumpParser::GetStreamTypeAsString(
+ stream_type));
+ return true; // Keep iterating
+ });
+ s.Printf("\n");
+ }
+ auto DumpTextStream = [&](MinidumpStreamType stream_type,
+ const char *label = nullptr) -> void {
+ auto bytes = minidump.GetStream(stream_type);
+ if (!bytes.empty()) {
+ if (label == nullptr)
+ label = MinidumpParser::GetStreamTypeAsString((uint32_t)stream_type);
+ s.Printf("%s:\n%s\n\n", label, bytes.data());
+ }
+ };
+ auto DumpBinaryStream = [&](MinidumpStreamType stream_type,
+ const char *label = nullptr) -> void {
+ auto bytes = minidump.GetStream(stream_type);
+ if (!bytes.empty()) {
+ if (label == nullptr)
+ label = MinidumpParser::GetStreamTypeAsString((uint32_t)stream_type);
+ s.Printf("%s:\n", label);
+ DataExtractor data(bytes.data(), bytes.size(), eByteOrderLittle,
+ process->GetAddressByteSize());
+ DumpDataExtractor(data, &s, 0, lldb::eFormatBytesWithASCII, 1,
+ bytes.size(), 16, 0, 0, 0);
+ s.Printf("\n\n");
+ }
+ };
+
+ if (DumpLinuxCPUInfo())
+ DumpTextStream(MinidumpStreamType::LinuxCPUInfo, "/proc/cpuinfo");
+ if (DumpLinuxProcStatus())
+ DumpTextStream(MinidumpStreamType::LinuxProcStatus, "/proc/PID/status");
+ if (DumpLinuxLSBRelease())
+ DumpTextStream(MinidumpStreamType::LinuxLSBRelease, "/etc/lsb-release");
+ if (DumpLinuxCMDLine())
+ DumpTextStream(MinidumpStreamType::LinuxCMDLine, "/proc/PID/cmdline");
+ if (DumpLinuxEnviron())
+ DumpTextStream(MinidumpStreamType::LinuxEnviron, "/proc/PID/environ");
+ if (DumpLinuxAuxv())
+ DumpBinaryStream(MinidumpStreamType::LinuxAuxv, "/proc/PID/auxv");
+ if (DumpLinuxMaps())
+ DumpTextStream(MinidumpStreamType::LinuxMaps, "/proc/PID/maps");
+ if (DumpLinuxProcStat())
+ DumpTextStream(MinidumpStreamType::LinuxProcStat, "/proc/PID/stat");
+ if (DumpLinuxProcUptime())
+ DumpTextStream(MinidumpStreamType::LinuxProcUptime, "uptime");
+ if (DumpLinuxProcFD())
+ DumpTextStream(MinidumpStreamType::LinuxProcFD, "/proc/PID/fd");
+ return true;
+ }
+};
+
+class CommandObjectMultiwordProcessMinidump : public CommandObjectMultiword {
+public:
+ CommandObjectMultiwordProcessMinidump(CommandInterpreter &interpreter)
+ : CommandObjectMultiword(interpreter, "process plugin",
+ "Commands for operating on a ProcessMinidump process.",
+ "process plugin <subcommand> [<subcommand-options>]") {
+ LoadSubCommand("dump",
+ CommandObjectSP(new CommandObjectProcessMinidumpDump(interpreter)));
+ }
+
+ ~CommandObjectMultiwordProcessMinidump() {}
+};
+
+CommandObject *ProcessMinidump::GetPluginCommandObject() {
+ if (!m_command_sp)
+ m_command_sp.reset(new CommandObjectMultiwordProcessMinidump(
+ GetTarget().GetDebugger().GetCommandInterpreter()));
+ return m_command_sp.get();
+}
Index: source/Plugins/Process/minidump/MinidumpTypes.h
===================================================================
--- source/Plugins/Process/minidump/MinidumpTypes.h
+++ source/Plugins/Process/minidump/MinidumpTypes.h
@@ -96,7 +96,10 @@
LinuxEnviron = 0x47670007, /* /proc/$x/environ */
LinuxAuxv = 0x47670008, /* /proc/$x/auxv */
LinuxMaps = 0x47670009, /* /proc/$x/maps */
- LinuxDSODebug = 0x4767000A
+ LinuxDSODebug = 0x4767000A,
+ LinuxProcStat = 0x4767000B, /* /proc/$x/maps */
+ LinuxProcUptime = 0x4767000C, /* uptime */
+ LinuxProcFD = 0x4767000D, /* /proc/$x/fb */
};
// for MinidumpSystemInfo.processor_arch
Index: source/Plugins/Process/minidump/MinidumpParser.h
===================================================================
--- source/Plugins/Process/minidump/MinidumpParser.h
+++ source/Plugins/Process/minidump/MinidumpParser.h
@@ -90,6 +90,14 @@
// Perform consistency checks and initialize internal data structures
Status Initialize();
+ static const char *GetStreamTypeAsString(uint32_t stream_type);
+
+ typedef std::function<bool(uint32_t stream_type,
+ const MinidumpLocationDescriptor &loc_desc)>
+ Callback;
+
+ void ForEachStreamType(Callback const &callback) const;
+
private:
MinidumpParser(const lldb::DataBufferSP &data_buf_sp);
Index: source/Plugins/Process/minidump/MinidumpParser.cpp
===================================================================
--- source/Plugins/Process/minidump/MinidumpParser.cpp
+++ source/Plugins/Process/minidump/MinidumpParser.cpp
@@ -660,3 +660,55 @@
return error;
}
+
+#define ENUM_TO_CSTR(ST) case (uint32_t)MinidumpStreamType::ST: return #ST
+
+const char *
+MinidumpParser::GetStreamTypeAsString(uint32_t stream_type) {
+ switch (stream_type) {
+ ENUM_TO_CSTR(Unused);
+ ENUM_TO_CSTR(Reserved0);
+ ENUM_TO_CSTR(Reserved1);
+ ENUM_TO_CSTR(ThreadList);
+ ENUM_TO_CSTR(ModuleList);
+ ENUM_TO_CSTR(MemoryList);
+ ENUM_TO_CSTR(Exception);
+ ENUM_TO_CSTR(SystemInfo);
+ ENUM_TO_CSTR(ThreadExList);
+ ENUM_TO_CSTR(Memory64List);
+ ENUM_TO_CSTR(CommentA);
+ ENUM_TO_CSTR(CommentW);
+ ENUM_TO_CSTR(HandleData);
+ ENUM_TO_CSTR(FunctionTable);
+ ENUM_TO_CSTR(UnloadedModuleList);
+ ENUM_TO_CSTR(MiscInfo);
+ ENUM_TO_CSTR(MemoryInfoList);
+ ENUM_TO_CSTR(ThreadInfoList);
+ ENUM_TO_CSTR(HandleOperationList);
+ ENUM_TO_CSTR(Token);
+ ENUM_TO_CSTR(JavascriptData);
+ ENUM_TO_CSTR(SystemMemoryInfo);
+ ENUM_TO_CSTR(ProcessVMCounters);
+ ENUM_TO_CSTR(BreakpadInfo);
+ ENUM_TO_CSTR(AssertionInfo);
+ ENUM_TO_CSTR(LinuxCPUInfo);
+ ENUM_TO_CSTR(LinuxProcStatus);
+ ENUM_TO_CSTR(LinuxLSBRelease);
+ ENUM_TO_CSTR(LinuxCMDLine);
+ ENUM_TO_CSTR(LinuxEnviron);
+ ENUM_TO_CSTR(LinuxAuxv);
+ ENUM_TO_CSTR(LinuxMaps);
+ ENUM_TO_CSTR(LinuxDSODebug);
+ ENUM_TO_CSTR(LinuxProcStat);
+ ENUM_TO_CSTR(LinuxProcUptime);
+ ENUM_TO_CSTR(LinuxProcFD);
+ }
+ return "???";
+}
+
+void MinidumpParser::ForEachStreamType(Callback const &callback) const {
+ for (auto const &pair: m_directory_map) {
+ if (!callback(pair.first, pair.second))
+ break;
+ }
+}
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits