mirror of
https://git.suyu.dev/suyu/breakpad.git
synced 2026-03-10 04:06:26 +00:00
Change MDCVInfoELF into something usable.
This patch changes MDCVInfoELF (which is currently unused, apparently a vestigal bit of code landed as part of Solaris support) into a supported CodeView format that simply contains a build id as raw bytes. Modern ELF toolchains support build ids nicely: https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Developer_Guide/compiling-build-id.html It would be useful to have the original build ids of loaded modules in Linux minidumps, since tools like Fedora's darkserver allow querying by build id and the current Breakpad code truncates the build id to the size of a GUID, which loses information: https://darkserver.fedoraproject.org/ A follow-up patch will change the Linux minidump generation code to produce MDCVInfoELF in minidumps instead of MDCVInfoPDB70. This patch should be landed first to ensure that crash processors are able to handle this format before dumps are generated containing it. The full build id is exposed as the return value of Minidump::code_identifier(), which currently just returns "id" for modules in Linux dumps. For backwards-compatibility, Minidump::debug_identifier() continues to treat the build id as a GUID, so debug identifiers for existing modules will not change. BUG= R=mark@chromium.org Review URL: https://codereview.chromium.org/1675413002 .
This commit is contained in:
@@ -1853,11 +1853,30 @@ string MinidumpModule::code_identifier() const {
|
||||
break;
|
||||
}
|
||||
|
||||
case MD_OS_ANDROID:
|
||||
case MD_OS_LINUX: {
|
||||
// If ELF CodeView data is present, return the debug id.
|
||||
if (cv_record_ && cv_record_signature_ == MD_CVINFOELF_SIGNATURE) {
|
||||
const MDCVInfoELF* cv_record_elf =
|
||||
reinterpret_cast<const MDCVInfoELF*>(&(*cv_record_)[0]);
|
||||
assert(cv_record_elf->cv_signature == MD_CVINFOELF_SIGNATURE);
|
||||
|
||||
for (unsigned int build_id_index = 0;
|
||||
build_id_index < (cv_record_->size() - MDCVInfoELF_minsize);
|
||||
++build_id_index) {
|
||||
char hexbyte[3];
|
||||
snprintf(hexbyte, sizeof(hexbyte), "%02x",
|
||||
cv_record_elf->build_id[build_id_index]);
|
||||
identifier += hexbyte;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Otherwise fall through to the case below.
|
||||
}
|
||||
|
||||
case MD_OS_MAC_OS_X:
|
||||
case MD_OS_IOS:
|
||||
case MD_OS_SOLARIS:
|
||||
case MD_OS_ANDROID:
|
||||
case MD_OS_LINUX:
|
||||
case MD_OS_NACL:
|
||||
case MD_OS_PS3: {
|
||||
// TODO(mmentovai): support uuid extension if present, otherwise fall
|
||||
@@ -1908,6 +1927,14 @@ string MinidumpModule::debug_file() const {
|
||||
|
||||
// GetCVRecord guarantees pdb_file_name is null-terminated.
|
||||
file = reinterpret_cast<const char*>(cv_record_20->pdb_file_name);
|
||||
} else if (cv_record_signature_ == MD_CVINFOELF_SIGNATURE) {
|
||||
// It's actually an MDCVInfoELF structure.
|
||||
const MDCVInfoELF* cv_record_elf =
|
||||
reinterpret_cast<const MDCVInfoELF*>(&(*cv_record_)[0]);
|
||||
assert(cv_record_elf->cv_signature == MD_CVINFOELF_SIGNATURE);
|
||||
|
||||
// For MDCVInfoELF, the debug file is the code file.
|
||||
file = *name_;
|
||||
}
|
||||
|
||||
// If there's a CodeView record but it doesn't match a known signature,
|
||||
@@ -1959,6 +1986,25 @@ string MinidumpModule::debug_file() const {
|
||||
return file;
|
||||
}
|
||||
|
||||
static string guid_and_age_to_debug_id(const MDGUID& guid,
|
||||
uint32_t age) {
|
||||
char identifier_string[41];
|
||||
snprintf(identifier_string, sizeof(identifier_string),
|
||||
"%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X%x",
|
||||
guid.data1,
|
||||
guid.data2,
|
||||
guid.data3,
|
||||
guid.data4[0],
|
||||
guid.data4[1],
|
||||
guid.data4[2],
|
||||
guid.data4[3],
|
||||
guid.data4[4],
|
||||
guid.data4[5],
|
||||
guid.data4[6],
|
||||
guid.data4[7],
|
||||
age);
|
||||
return identifier_string;
|
||||
}
|
||||
|
||||
string MinidumpModule::debug_identifier() const {
|
||||
if (!valid_) {
|
||||
@@ -1981,22 +2027,8 @@ string MinidumpModule::debug_identifier() const {
|
||||
|
||||
// Use the same format that the MS symbol server uses in filesystem
|
||||
// hierarchies.
|
||||
char identifier_string[41];
|
||||
snprintf(identifier_string, sizeof(identifier_string),
|
||||
"%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X%x",
|
||||
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],
|
||||
cv_record_70->signature.data4[2],
|
||||
cv_record_70->signature.data4[3],
|
||||
cv_record_70->signature.data4[4],
|
||||
cv_record_70->signature.data4[5],
|
||||
cv_record_70->signature.data4[6],
|
||||
cv_record_70->signature.data4[7],
|
||||
cv_record_70->age);
|
||||
identifier = identifier_string;
|
||||
identifier = guid_and_age_to_debug_id(cv_record_70->signature,
|
||||
cv_record_70->age);
|
||||
} else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) {
|
||||
// It's actually an MDCVInfoPDB20 structure.
|
||||
const MDCVInfoPDB20* cv_record_20 =
|
||||
@@ -2009,6 +2041,21 @@ string MinidumpModule::debug_identifier() const {
|
||||
snprintf(identifier_string, sizeof(identifier_string),
|
||||
"%08X%x", cv_record_20->signature, cv_record_20->age);
|
||||
identifier = identifier_string;
|
||||
} else if (cv_record_signature_ == MD_CVINFOELF_SIGNATURE) {
|
||||
// It's actually an MDCVInfoELF structure.
|
||||
const MDCVInfoELF* cv_record_elf =
|
||||
reinterpret_cast<const MDCVInfoELF*>(&(*cv_record_)[0]);
|
||||
assert(cv_record_elf->cv_signature == MD_CVINFOELF_SIGNATURE);
|
||||
|
||||
// For backwards-compatibility, stuff as many bytes as will fit into
|
||||
// a MDGUID and use the MS symbol server format as MDCVInfoPDB70 does
|
||||
// with age = 0. Historically Breakpad would do this during dump
|
||||
// writing to fit the build id data into a MDCVInfoPDB70 struct.
|
||||
// The full build id is available by calling code_identifier.
|
||||
MDGUID guid = {0};
|
||||
memcpy(&guid, &cv_record_elf->build_id,
|
||||
cv_record_->size() - MDCVInfoELF_minsize);
|
||||
identifier = guid_and_age_to_debug_id(guid, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2167,6 +2214,15 @@ const uint8_t* MinidumpModule::GetCVRecord(uint32_t* size) {
|
||||
"0-terminated";
|
||||
return NULL;
|
||||
}
|
||||
} else if (signature == MD_CVINFOELF_SIGNATURE) {
|
||||
// Now that the structure type is known, recheck the size.
|
||||
if (MDCVInfoELF_minsize > module_.cv_record.data_size) {
|
||||
BPLOG(ERROR) << "MinidumpModule CodeViewELF record size mismatch, " <<
|
||||
MDCVInfoELF_minsize << " > " <<
|
||||
module_.cv_record.data_size;
|
||||
return NULL;
|
||||
}
|
||||
// There's nothing to swap in CVInfoELF, it's just raw bytes.
|
||||
}
|
||||
|
||||
// If the signature doesn't match something above, it's not something
|
||||
@@ -2367,6 +2423,20 @@ void MinidumpModule::Print() {
|
||||
cv_record_20->age);
|
||||
printf(" (cv_record).pdb_file_name = \"%s\"\n",
|
||||
cv_record_20->pdb_file_name);
|
||||
} else if (cv_record_signature_ == MD_CVINFOELF_SIGNATURE) {
|
||||
const MDCVInfoELF* cv_record_elf =
|
||||
reinterpret_cast<const MDCVInfoELF*>(cv_record);
|
||||
assert(cv_record_elf->cv_signature == MD_CVINFOELF_SIGNATURE);
|
||||
|
||||
printf(" (cv_record).cv_signature = 0x%x\n",
|
||||
cv_record_elf->cv_signature);
|
||||
printf(" (cv_record).build_id = ");
|
||||
for (unsigned int build_id_index = 0;
|
||||
build_id_index < (cv_record_size - MDCVInfoELF_minsize);
|
||||
++build_id_index) {
|
||||
printf("%02x", cv_record_elf->build_id[build_id_index]);
|
||||
}
|
||||
printf("\n");
|
||||
} else {
|
||||
printf(" (cv_record) = ");
|
||||
for (unsigned int cv_byte_index = 0;
|
||||
|
||||
Reference in New Issue
Block a user