aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/linux/microdump_writer/microdump_writer.cc2
-rw-r--r--src/client/linux/minidump_writer/linux_core_dumper.cc5
-rw-r--r--src/client/linux/minidump_writer/linux_core_dumper.h4
-rw-r--r--src/client/linux/minidump_writer/linux_core_dumper_unittest.cc10
-rw-r--r--src/client/linux/minidump_writer/linux_dumper.cc48
-rw-r--r--src/client/linux/minidump_writer/linux_dumper.h22
-rw-r--r--src/client/linux/minidump_writer/minidump_writer.cc2
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);