251 lines
8.6 KiB
Diff
251 lines
8.6 KiB
Diff
changeset: 649910:59994b59eb51
|
|
tag: tip
|
|
parent: 649905:058997a8167d
|
|
user: Gabriele Svelto <gsvelto@mozilla.com>
|
|
date: Wed Mar 31 16:25:34 2021 +0200
|
|
summary: Bug 1702043 - Print out the list of unloaded modules when processing a minidump
|
|
|
|
diff --git a/src/google_breakpad/processor/minidump.h b/src/google_breakpad/processor/minidump.h
|
|
--- a/src/google_breakpad/processor/minidump.h
|
|
+++ b/src/google_breakpad/processor/minidump.h
|
|
@@ -792,16 +792,19 @@ class MinidumpUnloadedModule : public Mi
|
|
string debug_file() const override;
|
|
string debug_identifier() const override;
|
|
string version() const override;
|
|
CodeModule* Copy() const override;
|
|
bool is_unloaded() const override { return true; }
|
|
uint64_t shrink_down_delta() const override;
|
|
void SetShrinkDownDelta(uint64_t shrink_down_delta) override;
|
|
|
|
+ // Print a human-readable representation of the object to stdout.
|
|
+ void Print();
|
|
+
|
|
protected:
|
|
explicit MinidumpUnloadedModule(Minidump* minidump);
|
|
|
|
private:
|
|
// These objects are managed by MinidumpUnloadedModuleList
|
|
friend class MinidumpUnloadedModuleList;
|
|
|
|
// This works like MinidumpStream::Read, but is driven by
|
|
@@ -850,16 +853,19 @@ class MinidumpUnloadedModuleList : publi
|
|
const MinidumpUnloadedModule* GetMainModule() const override;
|
|
const MinidumpUnloadedModule*
|
|
GetModuleAtSequence(unsigned int sequence) const override;
|
|
const MinidumpUnloadedModule*
|
|
GetModuleAtIndex(unsigned int index) const override;
|
|
const CodeModules* Copy() const override;
|
|
vector<linked_ptr<const CodeModule>> GetShrunkRangeModules() const override;
|
|
|
|
+ // Print a human-readable representation of the object to stdout.
|
|
+ void Print();
|
|
+
|
|
protected:
|
|
explicit MinidumpUnloadedModuleList(Minidump* minidump_);
|
|
|
|
private:
|
|
friend class Minidump;
|
|
|
|
typedef vector<MinidumpUnloadedModule> MinidumpUnloadedModules;
|
|
|
|
diff --git a/src/processor/minidump.cc b/src/processor/minidump.cc
|
|
--- a/src/processor/minidump.cc
|
|
+++ b/src/processor/minidump.cc
|
|
@@ -3727,16 +3727,46 @@ MinidumpUnloadedModule::MinidumpUnloaded
|
|
name_(NULL) {
|
|
|
|
}
|
|
|
|
MinidumpUnloadedModule::~MinidumpUnloadedModule() {
|
|
delete name_;
|
|
}
|
|
|
|
+void MinidumpUnloadedModule::Print() {
|
|
+ if (!valid_) {
|
|
+ BPLOG(ERROR) << "MinidumpUnloadedModule cannot print invalid data";
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ printf("MDRawUnloadedModule\n");
|
|
+ printf(" base_of_image = 0x%" PRIx64 "\n",
|
|
+ unloaded_module_.base_of_image);
|
|
+ printf(" size_of_image = 0x%x\n",
|
|
+ unloaded_module_.size_of_image);
|
|
+ printf(" checksum = 0x%x\n",
|
|
+ unloaded_module_.checksum);
|
|
+ printf(" time_date_stamp = 0x%x %s\n",
|
|
+ unloaded_module_.time_date_stamp,
|
|
+ TimeTToUTCString(unloaded_module_.time_date_stamp).c_str());
|
|
+ printf(" module_name_rva = 0x%x\n",
|
|
+ unloaded_module_.module_name_rva);
|
|
+
|
|
+ printf(" (code_file) = \"%s\"\n", code_file().c_str());
|
|
+ printf(" (code_identifier) = \"%s\"\n",
|
|
+ code_identifier().c_str());
|
|
+
|
|
+ printf(" (debug_file) = \"%s\"\n", debug_file().c_str());
|
|
+ printf(" (debug_identifier) = \"%s\"\n",
|
|
+ debug_identifier().c_str());
|
|
+ printf(" (version) = \"%s\"\n", version().c_str());
|
|
+ printf("\n");
|
|
+}
|
|
+
|
|
string MinidumpUnloadedModule::code_file() const {
|
|
if (!valid_) {
|
|
BPLOG(ERROR) << "Invalid MinidumpUnloadedModule for code_file";
|
|
return "";
|
|
}
|
|
|
|
return *name_;
|
|
}
|
|
@@ -3911,16 +3941,34 @@ MinidumpUnloadedModuleList::MinidumpUnlo
|
|
range_map_->SetMergeStrategy(MergeRangeStrategy::kTruncateLower);
|
|
}
|
|
|
|
MinidumpUnloadedModuleList::~MinidumpUnloadedModuleList() {
|
|
delete range_map_;
|
|
delete unloaded_modules_;
|
|
}
|
|
|
|
+void MinidumpUnloadedModuleList::Print() {
|
|
+ if (!valid_) {
|
|
+ BPLOG(ERROR) << "MinidumpUnloadedModuleList cannot print invalid data";
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ printf("MinidumpUnloadedModuleList\n");
|
|
+ printf(" module_count = %d\n", module_count_);
|
|
+ printf("\n");
|
|
+
|
|
+ for (unsigned int module_index = 0;
|
|
+ module_index < module_count_;
|
|
+ ++module_index) {
|
|
+ printf("module[%d]\n", module_index);
|
|
+
|
|
+ (*unloaded_modules_)[module_index].Print();
|
|
+ }
|
|
+}
|
|
|
|
bool MinidumpUnloadedModuleList::Read(uint32_t expected_size) {
|
|
range_map_->Clear();
|
|
delete unloaded_modules_;
|
|
unloaded_modules_ = NULL;
|
|
module_count_ = 0;
|
|
|
|
valid_ = false;
|
|
diff --git a/src/processor/minidump_dump.cc b/src/processor/minidump_dump.cc
|
|
--- a/src/processor/minidump_dump.cc
|
|
+++ b/src/processor/minidump_dump.cc
|
|
@@ -40,16 +40,17 @@
|
|
#include "google_breakpad/processor/minidump.h"
|
|
#include "processor/logging.h"
|
|
|
|
namespace {
|
|
|
|
using google_breakpad::Minidump;
|
|
using google_breakpad::MinidumpThreadList;
|
|
using google_breakpad::MinidumpModuleList;
|
|
+using google_breakpad::MinidumpUnloadedModuleList;
|
|
using google_breakpad::MinidumpMemoryInfoList;
|
|
using google_breakpad::MinidumpMemoryList;
|
|
using google_breakpad::MinidumpException;
|
|
using google_breakpad::MinidumpAssertion;
|
|
using google_breakpad::MinidumpSystemInfo;
|
|
using google_breakpad::MinidumpMiscInfo;
|
|
using google_breakpad::MinidumpBreakpadInfo;
|
|
using google_breakpad::MinidumpCrashpadInfo;
|
|
@@ -127,16 +128,25 @@ static bool PrintMinidumpDump(const Opti
|
|
MinidumpModuleList *module_list = minidump.GetModuleList();
|
|
if (!module_list) {
|
|
++errors;
|
|
BPLOG(ERROR) << "minidump.GetModuleList() failed";
|
|
} else {
|
|
module_list->Print();
|
|
}
|
|
|
|
+ MinidumpUnloadedModuleList::set_max_modules(UINT32_MAX);
|
|
+ MinidumpUnloadedModuleList *unloaded_module_list = minidump.GetUnloadedModuleList();
|
|
+ if (!unloaded_module_list) {
|
|
+ ++errors;
|
|
+ BPLOG(ERROR) << "minidump.GetUnloadedModuleList() failed";
|
|
+ } else {
|
|
+ unloaded_module_list->Print();
|
|
+ }
|
|
+
|
|
MinidumpMemoryList *memory_list = minidump.GetMemoryList();
|
|
if (!memory_list) {
|
|
++errors;
|
|
BPLOG(ERROR) << "minidump.GetMemoryList() failed";
|
|
} else {
|
|
memory_list->Print();
|
|
}
|
|
|
|
diff --git a/src/processor/stackwalk_common.cc b/src/processor/stackwalk_common.cc
|
|
--- a/src/processor/stackwalk_common.cc
|
|
+++ b/src/processor/stackwalk_common.cc
|
|
@@ -777,16 +777,46 @@ static void PrintModulesMachineReadable(
|
|
StripSeparator(module->debug_identifier()).c_str(),
|
|
kOutputSeparator, base_address,
|
|
kOutputSeparator, base_address + module->size() - 1,
|
|
kOutputSeparator,
|
|
main_module != NULL && base_address == main_address ? 1 : 0);
|
|
}
|
|
}
|
|
|
|
+// PrintUnloadedModulesMachineReadable outputs a list of loaded modules,
|
|
+// one per line, in the following machine-readable pipe-delimited
|
|
+// text format:
|
|
+// UnloadedModule|{Module Filename}|{Base Address}|{Max Address}|{Main}
|
|
+static void PrintUnloadedModulesMachineReadable(const CodeModules* modules) {
|
|
+ if (!modules)
|
|
+ return;
|
|
+
|
|
+ uint64_t main_address = 0;
|
|
+ const CodeModule* main_module = modules->GetMainModule();
|
|
+ if (main_module) {
|
|
+ main_address = main_module->base_address();
|
|
+ }
|
|
+
|
|
+ unsigned int module_count = modules->module_count();
|
|
+ for (unsigned int module_sequence = 0;
|
|
+ module_sequence < module_count;
|
|
+ ++module_sequence) {
|
|
+ const CodeModule* module = modules->GetModuleAtSequence(module_sequence);
|
|
+ uint64_t base_address = module->base_address();
|
|
+ printf("UnloadedModule%c%s%c0x%08" PRIx64 "%c0x%08" PRIx64 "%c%d\n",
|
|
+ kOutputSeparator,
|
|
+ StripSeparator(PathnameStripper::File(module->code_file())).c_str(),
|
|
+ kOutputSeparator, base_address,
|
|
+ kOutputSeparator, base_address + module->size() - 1,
|
|
+ kOutputSeparator,
|
|
+ main_module != NULL && base_address == main_address ? 1 : 0);
|
|
+ }
|
|
+}
|
|
+
|
|
} // namespace
|
|
|
|
void PrintProcessState(const ProcessState& process_state,
|
|
bool output_stack_contents,
|
|
SourceLineResolverInterface* resolver) {
|
|
// Print OS and CPU information.
|
|
string cpu = process_state.system_info()->cpu;
|
|
string cpu_info = process_state.system_info()->cpu_info;
|
|
@@ -921,16 +951,17 @@ void PrintProcessStateMachineReadable(co
|
|
|
|
if (requesting_thread != -1) {
|
|
printf("%d\n", requesting_thread);
|
|
} else {
|
|
printf("\n");
|
|
}
|
|
|
|
PrintModulesMachineReadable(process_state.modules());
|
|
+ PrintUnloadedModulesMachineReadable(process_state.unloaded_modules());
|
|
|
|
// blank line to indicate start of threads
|
|
printf("\n");
|
|
|
|
// If the thread that requested the dump is known, print it first.
|
|
if (requesting_thread != -1) {
|
|
PrintStackMachineReadable(requesting_thread,
|
|
process_state.threads()->at(requesting_thread));
|
|
|