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
3 changed files with 70 additions and 54 deletions
|
@ -184,10 +184,12 @@ bool ElfFileSoNameFromMappedFile(
|
|||
// Did not find SONAME
|
||||
return false;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
bool LinuxDumper::ElfFileSoName(
|
||||
// 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.
|
||||
bool ElfFileSoName(
|
||||
const MappingInfo& mapping, char* soname, size_t soname_size) {
|
||||
if (IsMappedFileOpenUnsafe(mapping)) {
|
||||
// Not safe
|
||||
|
@ -214,6 +216,44 @@ bool LinuxDumper::ElfFileSoName(
|
|||
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() {
|
||||
char auxv_path[NAME_MAX];
|
||||
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;
|
||||
|
||||
// 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 member,
|
||||
unsigned int mapping_id,
|
||||
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_; }
|
||||
void set_crash_address(uintptr_t crash_address) {
|
||||
crash_address_ = crash_address;
|
||||
|
@ -135,6 +129,17 @@ class LinuxDumper {
|
|||
pid_t crash_thread() const { return 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:
|
||||
bool ReadAuxv();
|
||||
|
||||
|
|
|
@ -540,49 +540,9 @@ class MinidumpWriter {
|
|||
|
||||
mod.base_of_image = mapping.start_addr;
|
||||
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_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;
|
||||
my_memcpy(cv_ptr, &cv_signature, sizeof(cv_signature));
|
||||
|
@ -593,20 +553,31 @@ class MinidumpWriter {
|
|||
// GUID was provided by caller.
|
||||
my_memcpy(signature, identifier, sizeof(MDGUID));
|
||||
} else {
|
||||
// Note: ElfFileIdentifierForMapping() can manipulate the |mapping.name|.
|
||||
dumper_->ElfFileIdentifierForMapping(mapping, member,
|
||||
mapping_id, signature);
|
||||
}
|
||||
my_memset(cv_ptr, 0, sizeof(uint32_t)); // Set age to 0 on Linux.
|
||||
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
|
||||
my_memcpy(cv_ptr, filename_ptr, filename_len + 1);
|
||||
cv.Copy(cv_buf, MDCVInfoPDB70_minsize + filename_len + 1);
|
||||
my_memcpy(cv_ptr, file_name, file_name_len + 1);
|
||||
cv.Copy(cv_buf, MDCVInfoPDB70_minsize + file_name_len + 1);
|
||||
|
||||
mod.cv_record = cv.location();
|
||||
|
||||
MDLocationDescriptor ld;
|
||||
if (!minidump_writer_.WriteString(filepath_ptr, filepath_len, &ld))
|
||||
if (!minidump_writer_.WriteString(file_path, my_strlen(file_path), &ld))
|
||||
return false;
|
||||
mod.module_name_rva = ld.rva;
|
||||
return true;
|
||||
|
|
Loading…
Reference in a new issue