diff options
7 files changed, 58 insertions, 35 deletions
diff --git a/src/client/linux/microdump_writer/microdump_writer.cc b/src/client/linux/microdump_writer/microdump_writer.cc index fc29b714..91697ed8 100644 --- a/src/client/linux/microdump_writer/microdump_writer.cc +++ b/src/client/linux/microdump_writer/microdump_writer.cc @@ -350,7 +350,7 @@ class MicrodumpWriter { char file_name[NAME_MAX]; char file_path[NAME_MAX]; - LinuxDumper::GetMappingEffectiveNameAndPath( + dumper_->GetMappingEffectiveNameAndPath( mapping, file_path, sizeof(file_path), file_name, sizeof(file_name)); LogAppend("M "); diff --git a/src/client/linux/minidump_writer/linux_core_dumper.cc b/src/client/linux/minidump_writer/linux_core_dumper.cc index d7328245..622f0506 100644 --- a/src/client/linux/minidump_writer/linux_core_dumper.cc +++ b/src/client/linux/minidump_writer/linux_core_dumper.cc @@ -49,8 +49,9 @@ namespace google_breakpad { LinuxCoreDumper::LinuxCoreDumper(pid_t pid, const char* core_path, - const char* procfs_path) - : LinuxDumper(pid), + const char* procfs_path, + const char* root_prefix) + : LinuxDumper(pid, root_prefix), core_path_(core_path), procfs_path_(procfs_path), thread_infos_(&allocator_, 8) { diff --git a/src/client/linux/minidump_writer/linux_core_dumper.h b/src/client/linux/minidump_writer/linux_core_dumper.h index 8537896e..8a7c924b 100644 --- a/src/client/linux/minidump_writer/linux_core_dumper.h +++ b/src/client/linux/minidump_writer/linux_core_dumper.h @@ -47,7 +47,9 @@ class LinuxCoreDumper : public LinuxDumper { // its proc files at |procfs_path|. If |procfs_path| is a copy of // /proc/<pid>, it should contain the following files: // auxv, cmdline, environ, exe, maps, status - LinuxCoreDumper(pid_t pid, const char* core_path, const char* procfs_path); + // See LinuxDumper for the purpose of |root_prefix|. + LinuxCoreDumper(pid_t pid, const char* core_path, const char* procfs_path, + const char* root_prefix = ""); // Implements LinuxDumper::BuildProcPath(). // Builds a proc path for a certain pid for a node (/proc/<pid>/<node>). diff --git a/src/client/linux/minidump_writer/linux_core_dumper_unittest.cc b/src/client/linux/minidump_writer/linux_core_dumper_unittest.cc index 8f6a423e..ae0c965b 100644 --- a/src/client/linux/minidump_writer/linux_core_dumper_unittest.cc +++ b/src/client/linux/minidump_writer/linux_core_dumper_unittest.cc @@ -39,6 +39,16 @@ using namespace google_breakpad; +TEST(LinuxCoreDumperTest, GetMappingAbsolutePath) { + const LinuxCoreDumper dumper(getpid(), "core", "/tmp", "/mnt/root"); + const MappingInfo mapping = { 0, 0, 0, false, "/usr/lib/libc.so" }; + + char path[PATH_MAX]; + dumper.GetMappingAbsolutePath(mapping, path); + + EXPECT_STREQ("/mnt/root/usr/lib/libc.so", path); +} + TEST(LinuxCoreDumperTest, BuildProcPath) { const pid_t pid = getpid(); const char procfs_path[] = "/procfs_copy"; diff --git a/src/client/linux/minidump_writer/linux_dumper.cc b/src/client/linux/minidump_writer/linux_dumper.cc index 43b74ad9..8d4df9ad 100644 --- a/src/client/linux/minidump_writer/linux_dumper.cc +++ b/src/client/linux/minidump_writer/linux_dumper.cc @@ -88,14 +88,16 @@ namespace google_breakpad { // All interesting auvx entry types are below AT_SYSINFO_EHDR #define AT_MAX AT_SYSINFO_EHDR -LinuxDumper::LinuxDumper(pid_t pid) +LinuxDumper::LinuxDumper(pid_t pid, const char* root_prefix) : pid_(pid), + root_prefix_(root_prefix), crash_address_(0), crash_signal_(0), crash_thread_(pid), threads_(&allocator_, 8), mappings_(&allocator_), auxv_(&allocator_, AT_MAX + 1) { + assert(root_prefix_ && my_strlen(root_prefix_) < PATH_MAX); // The passed-in size to the constructor (above) is only a hint. // Must call .resize() to do actual initialization of the elements. auxv_.resize(AT_MAX + 1); @@ -139,14 +141,9 @@ LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping, return FileID::ElfFileIdentifierFromMappedFile(linux_gate, identifier); } - char filename[NAME_MAX]; - size_t filename_len = my_strlen(mapping.name); - if (filename_len >= NAME_MAX) { - assert(false); + char filename[PATH_MAX]; + if (!GetMappingAbsolutePath(mapping, filename)) return false; - } - my_memcpy(filename, mapping.name, filename_len); - filename[filename_len] = '\0'; bool filename_modified = HandleDeletedFileInMapping(filename); MemoryMappedFile mapped_file(filename, mapping.offset); @@ -156,13 +153,19 @@ LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping, bool success = FileID::ElfFileIdentifierFromMappedFile(mapped_file.data(), identifier); if (success && member && filename_modified) { - mappings_[mapping_id]->name[filename_len - + mappings_[mapping_id]->name[my_strlen(mapping.name) - sizeof(kDeletedSuffix) + 1] = '\0'; } return success; } +bool LinuxDumper::GetMappingAbsolutePath(const MappingInfo& mapping, + char path[PATH_MAX]) const { + return my_strlcpy(path, root_prefix_, PATH_MAX) < PATH_MAX && + my_strlcat(path, mapping.name, PATH_MAX) < PATH_MAX; +} + namespace { bool ElfFileSoNameFromMappedFile( const void* elf_base, char* soname, size_t soname_size) { @@ -212,23 +215,16 @@ bool ElfFileSoNameFromMappedFile( // 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( +bool ElfFileSoName(const LinuxDumper& dumper, const MappingInfo& mapping, char* soname, size_t soname_size) { if (IsMappedFileOpenUnsafe(mapping)) { // Not safe return false; } - char filename[NAME_MAX]; - size_t filename_len = my_strlen(mapping.name); - if (filename_len >= NAME_MAX) { - assert(false); - // name too long + char filename[PATH_MAX]; + if (!dumper.GetMappingAbsolutePath(mapping, filename)) return false; - } - - my_memcpy(filename, mapping.name, filename_len); - filename[filename_len] = '\0'; MemoryMappedFile mapped_file(filename, mapping.offset); if (!mapped_file.data() || mapped_file.size() < SELFMAG) { @@ -242,7 +238,6 @@ bool ElfFileSoName( } // namespace -// static void LinuxDumper::GetMappingEffectiveNameAndPath(const MappingInfo& mapping, char* file_path, size_t file_path_size, @@ -255,8 +250,10 @@ void LinuxDumper::GetMappingEffectiveNameAndPath(const MappingInfo& mapping, // 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 (mapping.exec && mapping.offset != 0) { + mapped_from_archive = + ElfFileSoName(*this, mapping, file_name, file_name_size); + } if (mapped_from_archive) { // Some tools (e.g., stackwalk) extract the basename from the pathname. In @@ -580,10 +577,13 @@ bool LinuxDumper::HandleDeletedFileInMapping(char* path) const { // Check |path| against the /proc/pid/exe 'symlink'. char exe_link[NAME_MAX]; - char new_path[NAME_MAX]; if (!BuildProcPath(exe_link, pid_, "exe")) return false; - if (!SafeReadLink(exe_link, new_path)) + MappingInfo new_mapping = {0}; + if (!SafeReadLink(exe_link, new_mapping.name)) + return false; + char new_path[PATH_MAX]; + if (!GetMappingAbsolutePath(new_mapping, new_path)) return false; if (my_strcmp(path, new_path) != 0) return false; diff --git a/src/client/linux/minidump_writer/linux_dumper.h b/src/client/linux/minidump_writer/linux_dumper.h index 6a3a100f..f7fe1dd9 100644 --- a/src/client/linux/minidump_writer/linux_dumper.h +++ b/src/client/linux/minidump_writer/linux_dumper.h @@ -72,7 +72,9 @@ const char kLinuxGateLibraryName[] = "linux-gate.so"; class LinuxDumper { public: - explicit LinuxDumper(pid_t pid); + // The |root_prefix| is prepended to mapping paths before opening them, which + // is useful if the crash originates from a chroot. + explicit LinuxDumper(pid_t pid, const char* root_prefix = ""); virtual ~LinuxDumper(); @@ -140,16 +142,21 @@ class LinuxDumper { pid_t crash_thread() const { return crash_thread_; } void set_crash_thread(pid_t crash_thread) { crash_thread_ = crash_thread; } + // Concatenates the |root_prefix_| and |mapping| path. Writes into |path| and + // returns true unless the string is too long. + bool GetMappingAbsolutePath(const MappingInfo& mapping, + char path[PATH_MAX]) const; + // 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); + void GetMappingEffectiveNameAndPath(const MappingInfo& mapping, + char* file_path, + size_t file_path_size, + char* file_name, + size_t file_name_size); protected: bool ReadAuxv(); @@ -172,6 +179,9 @@ class LinuxDumper { // ID of the crashed process. const pid_t pid_; + // Path of the root directory to which mapping paths are relative. + const char* const root_prefix_; + // Virtual address at which the process crashed. uintptr_t crash_address_; diff --git a/src/client/linux/minidump_writer/minidump_writer.cc b/src/client/linux/minidump_writer/minidump_writer.cc index 04327338..3103761f 100644 --- a/src/client/linux/minidump_writer/minidump_writer.cc +++ b/src/client/linux/minidump_writer/minidump_writer.cc @@ -567,7 +567,7 @@ class MinidumpWriter { char file_name[NAME_MAX]; char file_path[NAME_MAX]; - LinuxDumper::GetMappingEffectiveNameAndPath( + dumper_->GetMappingEffectiveNameAndPath( mapping, file_path, sizeof(file_path), file_name, sizeof(file_name)); const size_t file_name_len = my_strlen(file_name); |