mirror of
https://github.com/yuzu-emu/breakpad.git
synced 2025-07-23 13:28:19 +00:00
Refactor .so name detection logic in minidump/linux_dumper.
This is a refactoring of the logic which determines the module name and path for a given MappingInfo in minidump_writer.cc. Such logic, which will be soon shared also with the upcoming microdump_writer.cc, is simply being moved to linux_dumper.cc, extracting a GetMappingEffectiveNameAndPath method. No behavioral change is intended. BUG=chromium:410294 R=thestig@chromium.org Review URL: https://breakpad.appspot.com/7734002 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1392 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
962f1b0e60
commit
719546275a
|
@ -184,10 +184,12 @@ bool ElfFileSoNameFromMappedFile(
|
||||||
// Did not find SONAME
|
// Did not find SONAME
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} // namespace
|
|
||||||
|
|
||||||
// static
|
// Find the shared object name (SONAME) by examining the ELF information
|
||||||
bool LinuxDumper::ElfFileSoName(
|
// for |mapping|. If the SONAME is found copy it into the passed buffer
|
||||||
|
// |soname| and return true. The size of the buffer is |soname_size|.
|
||||||
|
// The SONAME will be truncated if it is too long to fit in the buffer.
|
||||||
|
bool ElfFileSoName(
|
||||||
const MappingInfo& mapping, char* soname, size_t soname_size) {
|
const MappingInfo& mapping, char* soname, size_t soname_size) {
|
||||||
if (IsMappedFileOpenUnsafe(mapping)) {
|
if (IsMappedFileOpenUnsafe(mapping)) {
|
||||||
// Not safe
|
// Not safe
|
||||||
|
@ -214,6 +216,44 @@ bool LinuxDumper::ElfFileSoName(
|
||||||
return ElfFileSoNameFromMappedFile(mapped_file.data(), soname, soname_size);
|
return ElfFileSoNameFromMappedFile(mapped_file.data(), soname, soname_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
|
// static
|
||||||
|
void LinuxDumper::GetMappingEffectiveNameAndPath(const MappingInfo& mapping,
|
||||||
|
char* file_path,
|
||||||
|
size_t file_path_size,
|
||||||
|
char* file_name,
|
||||||
|
size_t file_name_size) {
|
||||||
|
my_strlcpy(file_path, mapping.name, file_path_size);
|
||||||
|
|
||||||
|
// If an executable is mapped from a non-zero offset, this is likely because
|
||||||
|
// the executable was loaded directly from inside an archive file (e.g., an
|
||||||
|
// apk on Android). We try to find the name of the shared object (SONAME) by
|
||||||
|
// looking in the file for ELF sections.
|
||||||
|
bool mapped_from_archive = false;
|
||||||
|
if (mapping.exec && mapping.offset != 0)
|
||||||
|
mapped_from_archive = ElfFileSoName(mapping, file_name, file_name_size);
|
||||||
|
|
||||||
|
if (mapped_from_archive) {
|
||||||
|
// Some tools (e.g., stackwalk) extract the basename from the pathname. In
|
||||||
|
// this case, we append the file_name to the mapped archive path as follows:
|
||||||
|
// file_name := libname.so
|
||||||
|
// file_path := /path/to/ARCHIVE.APK/libname.so
|
||||||
|
if (my_strlen(file_path) + 1 + my_strlen(file_name) < file_path_size) {
|
||||||
|
my_strlcat(file_path, "/", file_path_size);
|
||||||
|
my_strlcat(file_path, file_name, file_path_size);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Common case:
|
||||||
|
// file_path := /path/to/libname.so
|
||||||
|
// file_name := libname.so
|
||||||
|
const char* basename = my_strrchr(file_path, '/');
|
||||||
|
basename = basename == NULL ? file_path : (basename + 1);
|
||||||
|
my_strlcpy(file_name, basename, file_name_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool LinuxDumper::ReadAuxv() {
|
bool LinuxDumper::ReadAuxv() {
|
||||||
char auxv_path[NAME_MAX];
|
char auxv_path[NAME_MAX];
|
||||||
if (!BuildProcPath(auxv_path, pid_, "auxv")) {
|
if (!BuildProcPath(auxv_path, pid_, "auxv")) {
|
||||||
|
|
|
@ -111,19 +111,13 @@ class LinuxDumper {
|
||||||
virtual bool BuildProcPath(char* path, pid_t pid, const char* node) const = 0;
|
virtual bool BuildProcPath(char* path, pid_t pid, const char* node) const = 0;
|
||||||
|
|
||||||
// Generate a File ID from the .text section of a mapped entry.
|
// Generate a File ID from the .text section of a mapped entry.
|
||||||
// If not a member, mapping_id is ignored.
|
// If not a member, mapping_id is ignored. This method can also manipulate the
|
||||||
|
// |mapping|.name to truncate "(deleted)" from the file name if necessary.
|
||||||
bool ElfFileIdentifierForMapping(const MappingInfo& mapping,
|
bool ElfFileIdentifierForMapping(const MappingInfo& mapping,
|
||||||
bool member,
|
bool member,
|
||||||
unsigned int mapping_id,
|
unsigned int mapping_id,
|
||||||
uint8_t identifier[sizeof(MDGUID)]);
|
uint8_t identifier[sizeof(MDGUID)]);
|
||||||
|
|
||||||
// Find the shared object name (SONAME) by examining the ELF information
|
|
||||||
// for |mapping|. If the SONAME is found copy it into the passed buffer
|
|
||||||
// |soname| and return true. The size of the buffer is |soname_size|.
|
|
||||||
// The SONAME will be truncated if it is too long to fit in the buffer.
|
|
||||||
static bool ElfFileSoName(
|
|
||||||
const MappingInfo& mapping, char* soname, size_t soname_size);
|
|
||||||
|
|
||||||
uintptr_t crash_address() const { return crash_address_; }
|
uintptr_t crash_address() const { return crash_address_; }
|
||||||
void set_crash_address(uintptr_t crash_address) {
|
void set_crash_address(uintptr_t crash_address) {
|
||||||
crash_address_ = crash_address;
|
crash_address_ = crash_address;
|
||||||
|
@ -135,6 +129,17 @@ class LinuxDumper {
|
||||||
pid_t crash_thread() const { return crash_thread_; }
|
pid_t crash_thread() const { return crash_thread_; }
|
||||||
void set_crash_thread(pid_t crash_thread) { crash_thread_ = crash_thread; }
|
void set_crash_thread(pid_t crash_thread) { crash_thread_ = crash_thread; }
|
||||||
|
|
||||||
|
// Extracts the effective path and file name of from |mapping|. In most cases
|
||||||
|
// the effective name/path are just the mapping's path and basename. In some
|
||||||
|
// other cases, however, a library can be mapped from an archive (e.g., when
|
||||||
|
// loading .so libs from an apk on Android) and this method is able to
|
||||||
|
// reconstruct the original file name.
|
||||||
|
static void GetMappingEffectiveNameAndPath(const MappingInfo& mapping,
|
||||||
|
char* file_path,
|
||||||
|
size_t file_path_size,
|
||||||
|
char* file_name,
|
||||||
|
size_t file_name_size);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool ReadAuxv();
|
bool ReadAuxv();
|
||||||
|
|
||||||
|
|
|
@ -540,49 +540,9 @@ class MinidumpWriter {
|
||||||
|
|
||||||
mod.base_of_image = mapping.start_addr;
|
mod.base_of_image = mapping.start_addr;
|
||||||
mod.size_of_image = mapping.size;
|
mod.size_of_image = mapping.size;
|
||||||
const char* filepath_ptr = mapping.name;
|
|
||||||
size_t filepath_len = my_strlen(mapping.name);
|
|
||||||
|
|
||||||
// Figure out file name from path
|
|
||||||
const char* filename_ptr = mapping.name + filepath_len - 1;
|
|
||||||
while (filename_ptr >= mapping.name) {
|
|
||||||
if (*filename_ptr == '/')
|
|
||||||
break;
|
|
||||||
filename_ptr--;
|
|
||||||
}
|
|
||||||
filename_ptr++;
|
|
||||||
|
|
||||||
size_t filename_len = mapping.name + filepath_len - filename_ptr;
|
|
||||||
|
|
||||||
// If an executable is mapped from a non-zero offset, this is likely
|
|
||||||
// because the executable was loaded directly from inside an archive
|
|
||||||
// file. We try to find the name of the shared object (SONAME) by
|
|
||||||
// looking in the file for ELF sections.
|
|
||||||
|
|
||||||
char soname[NAME_MAX];
|
|
||||||
char pathname[NAME_MAX];
|
|
||||||
if (mapping.exec && mapping.offset != 0 &&
|
|
||||||
LinuxDumper::ElfFileSoName(mapping, soname, sizeof(soname))) {
|
|
||||||
filename_ptr = soname;
|
|
||||||
filename_len = my_strlen(soname);
|
|
||||||
|
|
||||||
if (filepath_len + filename_len + 1 < NAME_MAX) {
|
|
||||||
// It doesn't have a real pathname, but tools such as stackwalk
|
|
||||||
// extract the basename, so simulating a pathname is helpful.
|
|
||||||
my_memcpy(pathname, filepath_ptr, filepath_len);
|
|
||||||
pathname[filepath_len] = '/';
|
|
||||||
my_memcpy(pathname + filepath_len + 1, filename_ptr, filename_len);
|
|
||||||
pathname[filepath_len + filename_len + 1] = '\0';
|
|
||||||
filepath_ptr = pathname;
|
|
||||||
filepath_len = filepath_len + filename_len + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t cv_buf[MDCVInfoPDB70_minsize + NAME_MAX];
|
uint8_t cv_buf[MDCVInfoPDB70_minsize + NAME_MAX];
|
||||||
uint8_t* cv_ptr = cv_buf;
|
uint8_t* cv_ptr = cv_buf;
|
||||||
UntypedMDRVA cv(&minidump_writer_);
|
|
||||||
if (!cv.Allocate(MDCVInfoPDB70_minsize + filename_len + 1))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const uint32_t cv_signature = MD_CVINFOPDB70_SIGNATURE;
|
const uint32_t cv_signature = MD_CVINFOPDB70_SIGNATURE;
|
||||||
my_memcpy(cv_ptr, &cv_signature, sizeof(cv_signature));
|
my_memcpy(cv_ptr, &cv_signature, sizeof(cv_signature));
|
||||||
|
@ -593,20 +553,31 @@ class MinidumpWriter {
|
||||||
// GUID was provided by caller.
|
// GUID was provided by caller.
|
||||||
my_memcpy(signature, identifier, sizeof(MDGUID));
|
my_memcpy(signature, identifier, sizeof(MDGUID));
|
||||||
} else {
|
} else {
|
||||||
|
// Note: ElfFileIdentifierForMapping() can manipulate the |mapping.name|.
|
||||||
dumper_->ElfFileIdentifierForMapping(mapping, member,
|
dumper_->ElfFileIdentifierForMapping(mapping, member,
|
||||||
mapping_id, signature);
|
mapping_id, signature);
|
||||||
}
|
}
|
||||||
my_memset(cv_ptr, 0, sizeof(uint32_t)); // Set age to 0 on Linux.
|
my_memset(cv_ptr, 0, sizeof(uint32_t)); // Set age to 0 on Linux.
|
||||||
cv_ptr += sizeof(uint32_t);
|
cv_ptr += sizeof(uint32_t);
|
||||||
|
|
||||||
|
char file_name[NAME_MAX];
|
||||||
|
char file_path[NAME_MAX];
|
||||||
|
LinuxDumper::GetMappingEffectiveNameAndPath(
|
||||||
|
mapping, file_path, sizeof(file_path), file_name, sizeof(file_name));
|
||||||
|
|
||||||
|
const size_t file_name_len = my_strlen(file_name);
|
||||||
|
UntypedMDRVA cv(&minidump_writer_);
|
||||||
|
if (!cv.Allocate(MDCVInfoPDB70_minsize + file_name_len + 1))
|
||||||
|
return false;
|
||||||
|
|
||||||
// Write pdb_file_name
|
// Write pdb_file_name
|
||||||
my_memcpy(cv_ptr, filename_ptr, filename_len + 1);
|
my_memcpy(cv_ptr, file_name, file_name_len + 1);
|
||||||
cv.Copy(cv_buf, MDCVInfoPDB70_minsize + filename_len + 1);
|
cv.Copy(cv_buf, MDCVInfoPDB70_minsize + file_name_len + 1);
|
||||||
|
|
||||||
mod.cv_record = cv.location();
|
mod.cv_record = cv.location();
|
||||||
|
|
||||||
MDLocationDescriptor ld;
|
MDLocationDescriptor ld;
|
||||||
if (!minidump_writer_.WriteString(filepath_ptr, filepath_len, &ld))
|
if (!minidump_writer_.WriteString(file_path, my_strlen(file_path), &ld))
|
||||||
return false;
|
return false;
|
||||||
mod.module_name_rva = ld.rva;
|
mod.module_name_rva = ld.rva;
|
||||||
return true;
|
return true;
|
||||||
|
|
Loading…
Reference in a new issue