diff options
Diffstat (limited to 'src/processor')
-rw-r--r-- | src/processor/minidump.cc | 148 |
1 files changed, 96 insertions, 52 deletions
diff --git a/src/processor/minidump.cc b/src/processor/minidump.cc index d27e14b3..8b8c2b8f 100644 --- a/src/processor/minidump.cc +++ b/src/processor/minidump.cc @@ -48,6 +48,7 @@ typedef SSIZE_T ssize_t; #define O_BINARY 0 #endif // _WIN32 +#include <cassert> #include <map> #include <vector> @@ -1005,6 +1006,7 @@ MinidumpModule::MinidumpModule(Minidump* minidump) module_(), name_(NULL), cv_record_(NULL), + cv_record_signature_(MD_CVINFOUNKNOWN_SIGNATURE), misc_record_(NULL) { } @@ -1022,6 +1024,7 @@ bool MinidumpModule::Read() { name_ = NULL; delete cv_record_; cv_record_ = NULL; + cv_record_signature_ = MD_CVINFOUNKNOWN_SIGNATURE; delete misc_record_; misc_record_ = NULL; @@ -1078,10 +1081,10 @@ bool MinidumpModule::ReadAuxiliaryData() { // CodeView and miscellaneous debug records are only required if the // module indicates that they exist. - if (module_.cv_record.data_size && !GetCVRecord()) + if (module_.cv_record.data_size && !GetCVRecord(NULL)) return false; - if (module_.misc_record.data_size && !GetMiscRecord()) + if (module_.misc_record.data_size && !GetMiscRecord(NULL)) return false; valid_ = true; @@ -1149,24 +1152,26 @@ string MinidumpModule::debug_file() const { string file; // Prefer the CodeView record if present. if (cv_record_) { - const MDCVInfoPDB70* cv_record_70 = - reinterpret_cast<const MDCVInfoPDB70*>(&(*cv_record_)[0]); - if (cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE) { + if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) { + // It's actually an MDCVInfoPDB70 structure. + const MDCVInfoPDB70* cv_record_70 = + reinterpret_cast<const MDCVInfoPDB70*>(&(*cv_record_)[0]); + assert(cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE); + // GetCVRecord guarantees pdb_file_name is null-terminated. file = reinterpret_cast<const char*>(cv_record_70->pdb_file_name); - } else if (cv_record_70->cv_signature == MD_CVINFOPDB20_SIGNATURE) { - // It's actually a MDCVInfoPDB20 structure. + } else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) { + // It's actually an MDCVInfoPDB20 structure. const MDCVInfoPDB20* cv_record_20 = reinterpret_cast<const MDCVInfoPDB20*>(&(*cv_record_)[0]); + assert(cv_record_20->cv_header.signature == MD_CVINFOPDB20_SIGNATURE); // GetCVRecord guarantees pdb_file_name is null-terminated. file = reinterpret_cast<const char*>(cv_record_20->pdb_file_name); } // If there's a CodeView record but it doesn't match a known signature, - // try the miscellaneous record - but it's suspicious because - // GetCVRecord shouldn't have accepted a CodeView record that doesn't - // match a known signature. + // try the miscellaneous record. } if (file.empty()) { @@ -1219,9 +1224,12 @@ string MinidumpModule::debug_identifier() const { // Use the CodeView record if present. if (cv_record_) { - const MDCVInfoPDB70* cv_record_70 = - reinterpret_cast<const MDCVInfoPDB70*>(&(*cv_record_)[0]); - if (cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE) { + if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) { + // It's actually an MDCVInfoPDB70 structure. + const MDCVInfoPDB70* cv_record_70 = + reinterpret_cast<const MDCVInfoPDB70*>(&(*cv_record_)[0]); + assert(cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE); + // Use the same format that the MS symbol server uses in filesystem // hierarchies. char identifier_string[41]; @@ -1240,10 +1248,11 @@ string MinidumpModule::debug_identifier() const { cv_record_70->signature.data4[7], cv_record_70->age); identifier = identifier_string; - } else if (cv_record_70->cv_signature == MD_CVINFOPDB20_SIGNATURE) { - // It's actually a MDCVInfoPDB20 structure. + } else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) { + // It's actually an MDCVInfoPDB20 structure. const MDCVInfoPDB20* cv_record_20 = reinterpret_cast<const MDCVInfoPDB20*>(&(*cv_record_)[0]); + assert(cv_record_20->cv_header.signature == MD_CVINFOPDB20_SIGNATURE); // Use the same format that the MS symbol server uses in filesystem // hierarchies. @@ -1254,7 +1263,7 @@ string MinidumpModule::debug_identifier() const { } } - // TODO(mmentovai): if there's no CodeView record, there might be a + // TODO(mmentovai): if there's no usable CodeView record, there might be a // miscellaneous debug record. It only carries a filename, though, and no // identifier. I'm not sure what the right thing to do for the identifier // is in that case, but I don't expect to find many modules without a @@ -1299,14 +1308,14 @@ const CodeModule* MinidumpModule::Copy() const { } -const u_int8_t* MinidumpModule::GetCVRecord() { +const u_int8_t* MinidumpModule::GetCVRecord(u_int32_t* size) { if (!module_valid_) return NULL; if (!cv_record_) { - // Only check against the smallest possible structure size now - recheck - // if necessary later if the actual structure is larger. - if (sizeof(MDCVInfoPDB20) > module_.cv_record.data_size) + // This just guards against 0-sized CodeView records; more specific checks + // are used when the signature is checked against various structure types. + if (!module_.cv_record.data_size) return NULL; if (!minidump_->SeekSet(module_.cv_record.rva)) @@ -1327,11 +1336,14 @@ const u_int8_t* MinidumpModule::GetCVRecord() { if (!minidump_->ReadBytes(&(*cv_record)[0], module_.cv_record.data_size)) return NULL; - MDCVInfoPDB70* cv_record_70 = - reinterpret_cast<MDCVInfoPDB70*>(&(*cv_record)[0]); - u_int32_t signature = cv_record_70->cv_signature; - if (minidump_->swap()) - Swap(&signature); + u_int32_t signature = MD_CVINFOUNKNOWN_SIGNATURE; + if (module_.cv_record.data_size > sizeof(signature)) { + MDCVInfoPDB70* cv_record_signature = + reinterpret_cast<MDCVInfoPDB70*>(&(*cv_record)[0]); + signature = cv_record_signature->cv_signature; + if (minidump_->swap()) + Swap(&signature); + } if (signature == MD_CVINFOPDB70_SIGNATURE) { // Now that the structure type is known, recheck the size. @@ -1339,16 +1351,26 @@ const u_int8_t* MinidumpModule::GetCVRecord() { return NULL; if (minidump_->swap()) { + MDCVInfoPDB70* cv_record_70 = + reinterpret_cast<MDCVInfoPDB70*>(&(*cv_record)[0]); Swap(&cv_record_70->cv_signature); Swap(&cv_record_70->signature); Swap(&cv_record_70->age); // Don't swap cv_record_70.pdb_file_name because it's an array of 8-bit - // quanities. (It's a path, is it UTF-8?) + // quantities. (It's a path, is it UTF-8?) } + + // The last field of either structure is null-terminated 8-bit character + // data. Ensure that it's null-terminated. + if ((*cv_record)[module_.cv_record.data_size - 1] != '\0') + return NULL; } else if (signature == MD_CVINFOPDB20_SIGNATURE) { + // Now that the structure type is known, recheck the size. + if (sizeof(MDCVInfoPDB20) > module_.cv_record.data_size) + return NULL; if (minidump_->swap()) { MDCVInfoPDB20* cv_record_20 = - reinterpret_cast<MDCVInfoPDB20*>(&(*cv_record)[0]); + reinterpret_cast<MDCVInfoPDB20*>(&(*cv_record)[0]); Swap(&cv_record_20->cv_header.signature); Swap(&cv_record_20->cv_header.offset); Swap(&cv_record_20->signature); @@ -1356,28 +1378,33 @@ const u_int8_t* MinidumpModule::GetCVRecord() { // Don't swap cv_record_20.pdb_file_name because it's an array of 8-bit // quantities. (It's a path, is it UTF-8?) } - } else { - // Some unknown structure type. We don't need to bail out here, but we - // do instead of returning it, because this method guarantees properly - // swapped data, and data in an unknown format can't possibly be swapped. - return NULL; + + // The last field of either structure is null-terminated 8-bit character + // data. Ensure that it's null-terminated. + if ((*cv_record)[module_.cv_record.data_size - 1] != '\0') + return NULL; } - // The last field of either structure is null-terminated 8-bit character - // data. Ensure that it's null-terminated. - if ((*cv_record)[module_.cv_record.data_size - 1] != '\0') - return NULL; + // If the signature doesn't match something above, it's not something + // that Airbag can presently handle directly. Because some modules in + // the wild contain such CodeView records as MD_CVINFOCV50_SIGNATURE, + // don't bail out here - allow the data to be returned to the user, + // although byte-swapping can't be done. // Store the vector type because that's how storage was allocated, but // return it casted to u_int8_t*. cv_record_ = cv_record.release(); + cv_record_signature_ = signature; } + if (size) + *size = module_.cv_record.data_size; + return &(*cv_record_)[0]; } -const MDImageDebugMisc* MinidumpModule::GetMiscRecord() { +const MDImageDebugMisc* MinidumpModule::GetMiscRecord(u_int32_t* size) { if (!module_valid_) return NULL; @@ -1433,6 +1460,9 @@ const MDImageDebugMisc* MinidumpModule::GetMiscRecord() { misc_record_ = misc_record_mem.release(); } + if (size) + *size = module_.misc_record.data_size; + return reinterpret_cast<MDImageDebugMisc*>(&(*misc_record_)[0]); } @@ -1488,31 +1518,37 @@ void MinidumpModule::Print() { printf(" (code_identifier) = \"%s\"\n", code_identifier().c_str()); - const MDCVInfoPDB70* cv_record = - reinterpret_cast<const MDCVInfoPDB70*>(GetCVRecord()); + u_int32_t cv_record_size; + const u_int8_t *cv_record = GetCVRecord(&cv_record_size); if (cv_record) { - if (cv_record->cv_signature == MD_CVINFOPDB70_SIGNATURE) { + if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) { + const MDCVInfoPDB70* cv_record_70 = + reinterpret_cast<const MDCVInfoPDB70*>(cv_record); + assert(cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE); + printf(" (cv_record).cv_signature = 0x%x\n", - cv_record->cv_signature); + cv_record_70->cv_signature); printf(" (cv_record).signature = %08x-%04x-%04x-%02x%02x-", - cv_record->signature.data1, - cv_record->signature.data2, - cv_record->signature.data3, - cv_record->signature.data4[0], - cv_record->signature.data4[1]); + cv_record_70->signature.data1, + cv_record_70->signature.data2, + cv_record_70->signature.data3, + cv_record_70->signature.data4[0], + cv_record_70->signature.data4[1]); for (unsigned int guidIndex = 2; guidIndex < 8; ++guidIndex) { - printf("%02x", cv_record->signature.data4[guidIndex]); + printf("%02x", cv_record_70->signature.data4[guidIndex]); } printf("\n"); printf(" (cv_record).age = %d\n", - cv_record->age); + cv_record_70->age); printf(" (cv_record).pdb_file_name = \"%s\"\n", - cv_record->pdb_file_name); - } else { + cv_record_70->pdb_file_name); + } else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) { const MDCVInfoPDB20* cv_record_20 = - reinterpret_cast<const MDCVInfoPDB20*>(cv_record); + reinterpret_cast<const MDCVInfoPDB20*>(cv_record); + assert(cv_record_20->cv_header.signature == MD_CVINFOPDB20_SIGNATURE); + printf(" (cv_record).cv_header.signature = 0x%x\n", cv_record_20->cv_header.signature); printf(" (cv_record).cv_header.offset = 0x%x\n", @@ -1523,12 +1559,20 @@ void MinidumpModule::Print() { cv_record_20->age); printf(" (cv_record).pdb_file_name = \"%s\"\n", cv_record_20->pdb_file_name); + } else { + printf(" (cv_record) = "); + for (unsigned int cv_byte_index = 0; + cv_byte_index < cv_record_size; + ++cv_byte_index) { + printf("%02x", cv_record[cv_byte_index]); + } + printf("\n"); } } else { printf(" (cv_record) = (null)\n"); } - const MDImageDebugMisc* misc_record = GetMiscRecord(); + const MDImageDebugMisc* misc_record = GetMiscRecord(NULL); if (misc_record) { printf(" (misc_record).data_type = 0x%x\n", misc_record->data_type); |