aboutsummaryrefslogtreecommitdiff
path: root/src/processor/minidump.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/processor/minidump.cc')
-rw-r--r--src/processor/minidump.cc390
1 files changed, 390 insertions, 0 deletions
diff --git a/src/processor/minidump.cc b/src/processor/minidump.cc
index 929913c0..7226d34a 100644
--- a/src/processor/minidump.cc
+++ b/src/processor/minidump.cc
@@ -3510,6 +3510,390 @@ void MinidumpSystemInfo::Print() {
//
+// MinidumpUnloadedModule
+//
+
+
+MinidumpUnloadedModule::MinidumpUnloadedModule(Minidump* minidump)
+ : MinidumpObject(minidump),
+ module_valid_(false),
+ unloaded_module_(),
+ name_(NULL) {
+
+}
+
+MinidumpUnloadedModule::~MinidumpUnloadedModule() {
+ delete name_;
+}
+
+string MinidumpUnloadedModule::code_file() const {
+ if (!valid_) {
+ BPLOG(ERROR) << "Invalid MinidumpUnloadedModule for code_file";
+ return "";
+ }
+
+ return *name_;
+}
+
+string MinidumpUnloadedModule::code_identifier() const {
+ if (!valid_) {
+ BPLOG(ERROR) << "Invalid MinidumpUnloadedModule for code_identifier";
+ return "";
+ }
+
+ MinidumpSystemInfo *minidump_system_info = minidump_->GetSystemInfo();
+ if (!minidump_system_info) {
+ BPLOG(ERROR) << "MinidumpUnloadedModule code_identifier requires "
+ "MinidumpSystemInfo";
+ return "";
+ }
+
+ const MDRawSystemInfo *raw_system_info = minidump_system_info->system_info();
+ if (!raw_system_info) {
+ BPLOG(ERROR) << "MinidumpUnloadedModule code_identifier requires "
+ << "MDRawSystemInfo";
+ return "";
+ }
+
+ string identifier;
+
+ switch (raw_system_info->platform_id) {
+ case MD_OS_WIN32_NT:
+ case MD_OS_WIN32_WINDOWS: {
+ // Use the same format that the MS symbol server uses in filesystem
+ // hierarchies.
+ char identifier_string[17];
+ snprintf(identifier_string, sizeof(identifier_string), "%08X%x",
+ unloaded_module_.time_date_stamp,
+ unloaded_module_.size_of_image);
+ identifier = identifier_string;
+ break;
+ }
+
+ case MD_OS_ANDROID:
+ case MD_OS_LINUX:
+ case MD_OS_MAC_OS_X:
+ case MD_OS_IOS:
+ case MD_OS_SOLARIS:
+ case MD_OS_NACL:
+ case MD_OS_PS3: {
+ // TODO(mmentovai): support uuid extension if present, otherwise fall
+ // back to version (from LC_ID_DYLIB?), otherwise fall back to something
+ // else.
+ identifier = "id";
+ break;
+ }
+
+ default: {
+ // Without knowing what OS generated the dump, we can't generate a good
+ // identifier. Return an empty string, signalling failure.
+ BPLOG(ERROR) << "MinidumpUnloadedModule code_identifier requires known "
+ << "platform, found "
+ << HexString(raw_system_info->platform_id);
+ break;
+ }
+ }
+
+ return identifier;
+}
+
+string MinidumpUnloadedModule::debug_file() const {
+ return ""; // No debug info provided with unloaded modules
+}
+
+string MinidumpUnloadedModule::debug_identifier() const {
+ return ""; // No debug info provided with unloaded modules
+}
+
+string MinidumpUnloadedModule::version() const {
+ return ""; // No version info provided with unloaded modules
+}
+
+CodeModule* MinidumpUnloadedModule::Copy() const {
+ return new BasicCodeModule(this);
+}
+
+uint64_t MinidumpUnloadedModule::shrink_down_delta() const {
+ return 0;
+}
+
+void MinidumpUnloadedModule::SetShrinkDownDelta(uint64_t shrink_down_delta) {
+ // Not implemented
+ assert(false);
+}
+
+bool MinidumpUnloadedModule::Read(uint32_t expected_size) {
+
+ delete name_;
+ valid_ = false;
+
+ if (expected_size < sizeof(unloaded_module_)) {
+ BPLOG(ERROR) << "MinidumpUnloadedModule expected size is less than size "
+ << "of struct " << expected_size << " < "
+ << sizeof(unloaded_module_);
+ return false;
+ }
+
+ if (!minidump_->ReadBytes(&unloaded_module_, sizeof(unloaded_module_))) {
+ BPLOG(ERROR) << "MinidumpUnloadedModule cannot read module";
+ return false;
+ }
+
+ if (expected_size > sizeof(unloaded_module_)) {
+ uint32_t module_bytes_remaining = expected_size - sizeof(unloaded_module_);
+ off_t pos = minidump_->Tell();
+ if (!minidump_->SeekSet(pos + module_bytes_remaining)) {
+ BPLOG(ERROR) << "MinidumpUnloadedModule unable to seek to end of module";
+ return false;
+ }
+ }
+
+ if (minidump_->swap()) {
+ Swap(&unloaded_module_.base_of_image);
+ Swap(&unloaded_module_.size_of_image);
+ Swap(&unloaded_module_.checksum);
+ Swap(&unloaded_module_.time_date_stamp);
+ Swap(&unloaded_module_.module_name_rva);
+ }
+
+ // Check for base + size overflow or undersize.
+ if (unloaded_module_.size_of_image == 0 ||
+ unloaded_module_.size_of_image >
+ numeric_limits<uint64_t>::max() - unloaded_module_.base_of_image) {
+ BPLOG(ERROR) << "MinidumpUnloadedModule has a module problem, " <<
+ HexString(unloaded_module_.base_of_image) << "+" <<
+ HexString(unloaded_module_.size_of_image);
+ return false;
+ }
+
+
+ module_valid_ = true;
+ return true;
+}
+
+bool MinidumpUnloadedModule::ReadAuxiliaryData() {
+ if (!module_valid_) {
+ BPLOG(ERROR) << "Invalid MinidumpUnloadedModule for ReadAuxiliaryData";
+ return false;
+ }
+
+ // Each module must have a name.
+ name_ = minidump_->ReadString(unloaded_module_.module_name_rva);
+ if (!name_) {
+ BPLOG(ERROR) << "MinidumpUnloadedModule could not read name";
+ return false;
+ }
+
+ // At this point, we have enough info for the module to be valid.
+ valid_ = true;
+ return true;
+}
+
+//
+// MinidumpUnloadedModuleList
+//
+
+
+uint32_t MinidumpUnloadedModuleList::max_modules_ = 1024;
+
+
+MinidumpUnloadedModuleList::MinidumpUnloadedModuleList(Minidump* minidump)
+ : MinidumpStream(minidump),
+ range_map_(new RangeMap<uint64_t, unsigned int>()),
+ unloaded_modules_(NULL),
+ module_count_(0) {
+ range_map_->SetEnableShrinkDown(true);
+}
+
+MinidumpUnloadedModuleList::~MinidumpUnloadedModuleList() {
+ delete range_map_;
+ delete unloaded_modules_;
+}
+
+
+bool MinidumpUnloadedModuleList::Read(uint32_t expected_size) {
+ range_map_->Clear();
+ delete unloaded_modules_;
+ unloaded_modules_ = NULL;
+ module_count_ = 0;
+
+ valid_ = false;
+
+ uint32_t size_of_header;
+ if (!minidump_->ReadBytes(&size_of_header, sizeof(size_of_header))) {
+ BPLOG(ERROR) << "MinidumpUnloadedModuleList could not read header size";
+ return false;
+ }
+
+ uint32_t size_of_entry;
+ if (!minidump_->ReadBytes(&size_of_entry, sizeof(size_of_entry))) {
+ BPLOG(ERROR) << "MinidumpUnloadedModuleList could not read entry size";
+ return false;
+ }
+
+ uint32_t number_of_entries;
+ if (!minidump_->ReadBytes(&number_of_entries, sizeof(number_of_entries))) {
+ BPLOG(ERROR) <<
+ "MinidumpUnloadedModuleList could not read number of entries";
+ return false;
+ }
+
+ if (minidump_->swap()) {
+ Swap(&size_of_header);
+ Swap(&size_of_entry);
+ Swap(&number_of_entries);
+ }
+
+ uint32_t header_bytes_remaining = size_of_header - sizeof(size_of_header) -
+ sizeof(size_of_entry) - sizeof(number_of_entries);
+ if (header_bytes_remaining) {
+ off_t pos = minidump_->Tell();
+ if (!minidump_->SeekSet(pos + header_bytes_remaining)) {
+ BPLOG(ERROR) << "MinidumpUnloadedModuleList could not read header sized "
+ << size_of_header;
+ return false;
+ }
+ }
+
+ if (expected_size != size_of_header + (size_of_entry * number_of_entries)) {
+ BPLOG(ERROR) << "MinidumpUnloadedModuleList expected_size mismatch " <<
+ expected_size << " != " << size_of_header << " + (" <<
+ size_of_entry << " * " << number_of_entries << ")";
+ return false;
+ }
+
+ if (number_of_entries > max_modules_) {
+ BPLOG(ERROR) << "MinidumpUnloadedModuleList count " <<
+ number_of_entries << " exceeds maximum " << max_modules_;
+ return false;
+ }
+
+ if (number_of_entries != 0) {
+ scoped_ptr<MinidumpUnloadedModules> modules(
+ new MinidumpUnloadedModules(number_of_entries,
+ MinidumpUnloadedModule(minidump_)));
+
+ for (unsigned int module_index = 0;
+ module_index < number_of_entries;
+ ++module_index) {
+ MinidumpUnloadedModule* module = &(*modules)[module_index];
+
+ if (!module->Read(size_of_entry)) {
+ BPLOG(ERROR) << "MinidumpUnloadedModuleList could not read module " <<
+ module_index << "/" << number_of_entries;
+ return false;
+ }
+ }
+
+ for (unsigned int module_index = 0;
+ module_index < number_of_entries;
+ ++module_index) {
+ MinidumpUnloadedModule* module = &(*modules)[module_index];
+
+ if (!module->ReadAuxiliaryData()) {
+ BPLOG(ERROR) << "MinidumpUnloadedModuleList could not read required "
+ "module auxiliary data for module " <<
+ module_index << "/" << number_of_entries;
+ return false;
+ }
+
+ uint64_t base_address = module->base_address();
+ uint64_t module_size = module->size();
+
+ // Ignore any failures for conflicting address ranges
+ range_map_->StoreRange(base_address, module_size, module_index);
+
+ }
+ unloaded_modules_ = modules.release();
+ }
+
+ module_count_ = number_of_entries;
+ valid_ = true;
+ return true;
+}
+
+const MinidumpUnloadedModule* MinidumpUnloadedModuleList::GetModuleForAddress(
+ uint64_t address) const {
+ if (!valid_) {
+ BPLOG(ERROR)
+ << "Invalid MinidumpUnloadedModuleList for GetModuleForAddress";
+ return NULL;
+ }
+
+ unsigned int module_index;
+ if (!range_map_->RetrieveRange(address, &module_index, NULL /* base */,
+ NULL /* delta */, NULL /* size */)) {
+ BPLOG(INFO) << "MinidumpUnloadedModuleList has no module at "
+ << HexString(address);
+ return NULL;
+ }
+
+ return GetModuleAtIndex(module_index);
+}
+
+const MinidumpUnloadedModule*
+MinidumpUnloadedModuleList::GetMainModule() const {
+ return NULL;
+}
+
+const MinidumpUnloadedModule*
+MinidumpUnloadedModuleList::GetModuleAtSequence(unsigned int sequence) const {
+ if (!valid_) {
+ BPLOG(ERROR)
+ << "Invalid MinidumpUnloadedModuleList for GetModuleAtSequence";
+ return NULL;
+ }
+
+ if (sequence >= module_count_) {
+ BPLOG(ERROR) << "MinidumpUnloadedModuleList sequence out of range: "
+ << sequence << "/" << module_count_;
+ return NULL;
+ }
+
+ unsigned int module_index;
+ if (!range_map_->RetrieveRangeAtIndex(sequence, &module_index,
+ NULL /* base */, NULL /* delta */,
+ NULL /* size */)) {
+ BPLOG(ERROR) << "MinidumpUnloadedModuleList has no module at sequence "
+ << sequence;
+ return NULL;
+ }
+
+ return GetModuleAtIndex(module_index);
+}
+
+const MinidumpUnloadedModule*
+MinidumpUnloadedModuleList::GetModuleAtIndex(
+ unsigned int index) const {
+ if (!valid_) {
+ BPLOG(ERROR) << "Invalid MinidumpUnloadedModuleList for GetModuleAtIndex";
+ return NULL;
+ }
+
+ if (index >= module_count_) {
+ BPLOG(ERROR) << "MinidumpUnloadedModuleList index out of range: "
+ << index << "/" << module_count_;
+ return NULL;
+ }
+
+ return &(*unloaded_modules_)[index];
+}
+
+const CodeModules* MinidumpUnloadedModuleList::Copy() const {
+ return new BasicCodeModules(this);
+}
+
+vector<linked_ptr<const CodeModule>>
+MinidumpUnloadedModuleList::GetShrunkRangeModules() const {
+ return vector<linked_ptr<const CodeModule> >();
+}
+
+bool MinidumpUnloadedModuleList::IsModuleShrinkEnabled() const {
+ return range_map_->IsShrinkDownEnabled();
+}
+
+
+//
// MinidumpMiscInfo
//
@@ -4603,6 +4987,12 @@ MinidumpSystemInfo* Minidump::GetSystemInfo() {
}
+MinidumpUnloadedModuleList* Minidump::GetUnloadedModuleList() {
+ MinidumpUnloadedModuleList* unloaded_module_list;
+ return GetStream(&unloaded_module_list);
+}
+
+
MinidumpMiscInfo* Minidump::GetMiscInfo() {
MinidumpMiscInfo* misc_info;
return GetStream(&misc_info);