aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorthestig@chromium.org <thestig@chromium.org@4c0a9323-5329-0410-9bdc-e9ce6186880e>2010-11-19 19:57:07 +0000
committerthestig@chromium.org <thestig@chromium.org@4c0a9323-5329-0410-9bdc-e9ce6186880e>2010-11-19 19:57:07 +0000
commit3665a7d09bb32ab3939635daec398618dd1ef955 (patch)
treedcafba6bde2e1dd5db7389500654d291d01b43b4
parentAdd specific curl headers to facilitate building on Ubuntu Lucid (diff)
downloadbreakpad-3665a7d09bb32ab3939635daec398618dd1ef955.tar.xz
Linux: Attempt to generate an ELF identifier for deleted running binaries.
Review URL: http://breakpad.appspot.com/228001 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@733 4c0a9323-5329-0410-9bdc-e9ce6186880e
-rw-r--r--src/client/linux/minidump_writer/linux_dumper.cc73
-rw-r--r--src/client/linux/minidump_writer/linux_dumper.h13
2 files changed, 71 insertions, 15 deletions
diff --git a/src/client/linux/minidump_writer/linux_dumper.cc b/src/client/linux/minidump_writer/linux_dumper.cc
index 578b788c..4885136e 100644
--- a/src/client/linux/minidump_writer/linux_dumper.cc
+++ b/src/client/linux/minidump_writer/linux_dumper.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009, Google Inc.
+// Copyright (c) 2010, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -36,7 +36,6 @@
#include <asm/ptrace.h>
#include <assert.h>
-#include <elf.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
@@ -47,7 +46,6 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#include <sys/types.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <unistd.h>
@@ -61,6 +59,7 @@
#include "third_party/lss/linux_syscall_support.h"
static const char kMappedFileUnsafePrefix[] = "/dev/";
+static const char kDeletedSuffix[] = " (deleted)";
// Suspend a thread by attaching to it.
static bool SuspendThread(pid_t pid) {
@@ -200,7 +199,7 @@ LinuxDumper::BuildProcPath(char* path, pid_t pid, const char* node) const {
my_itos(path + 6, pid, pid_len);
memcpy(path + 6 + pid_len, "/", 1);
memcpy(path + 6 + pid_len + 1, node, node_len);
- memcpy(path + total_length, "\0", 1);
+ path[total_length] = '\0';
}
bool
@@ -209,11 +208,20 @@ LinuxDumper::ElfFileIdentifierForMapping(unsigned int mapping_id,
{
assert(mapping_id < mappings_.size());
my_memset(identifier, 0, sizeof(MDGUID));
- const MappingInfo* mapping = mappings_[mapping_id];
- if (IsMappedFileOpenUnsafe(mapping)) {
+ MappingInfo* mapping = mappings_[mapping_id];
+ if (IsMappedFileOpenUnsafe(mapping))
return false;
- }
- int fd = sys_open(mapping->name, O_RDONLY, 0);
+
+ char filename[NAME_MAX];
+ size_t filename_len = my_strlen(mapping->name);
+ assert(filename_len < NAME_MAX);
+ if (filename_len >= NAME_MAX)
+ return false;
+ memcpy(filename, mapping->name, filename_len);
+ filename[filename_len] = '\0';
+ bool filename_modified = HandleDeletedFileInMapping(filename);
+
+ int fd = sys_open(filename, O_RDONLY, 0);
if (fd < 0)
return false;
struct kernel_stat st;
@@ -231,6 +239,8 @@ LinuxDumper::ElfFileIdentifierForMapping(unsigned int mapping_id,
bool success = FileID::ElfFileIdentifierFromMappedFile(base, identifier);
sys_munmap(base, st.st_size);
+ if (success && filename_modified)
+ mapping->name[filename_len - sizeof(kDeletedSuffix) + 1] = '\0';
return success;
}
@@ -428,11 +438,8 @@ bool LinuxDumper::ThreadInfoGet(pid_t tid, ThreadInfo* info) {
#error "This code hasn't been ported to your platform yet."
#endif
- if (!GetStackInfo(&info->stack, &info->stack_len,
- (uintptr_t) stack_pointer))
- return false;
-
- return true;
+ return GetStackInfo(&info->stack, &info->stack_len,
+ (uintptr_t) stack_pointer);
}
// Get information about the stack, given the stack pointer. We don't try to
@@ -447,7 +454,7 @@ bool LinuxDumper::GetStackInfo(const void** stack, size_t* stack_len,
reinterpret_cast<uint8_t*>(int_stack_pointer & ~(page_size - 1));
// The number of bytes of stack which we try to capture.
- static ptrdiff_t kStackToCapture = 32 * 1024;
+ static const ptrdiff_t kStackToCapture = 32 * 1024;
const MappingInfo* mapping = FindMapping(stack_pointer);
if (!mapping)
@@ -493,4 +500,42 @@ const MappingInfo* LinuxDumper::FindMapping(const void* address) const {
return NULL;
}
+bool LinuxDumper::HandleDeletedFileInMapping(char* path) {
+ static const size_t kDeletedSuffixLen = sizeof(kDeletedSuffix) - 1;
+
+ // Check for ' (deleted)' in |path|.
+ // |path| has to be at least as long as "/x (deleted)".
+ const size_t path_len = my_strlen(path);
+ if (path_len < kDeletedSuffixLen + 2)
+ return false;
+ if (my_strncmp(path + path_len - kDeletedSuffixLen, kDeletedSuffix,
+ kDeletedSuffixLen) != 0) {
+ return false;
+ }
+
+ // Check |path| against the /proc/pid/exe 'symlink'.
+ char exe_link[NAME_MAX];
+ char new_path[NAME_MAX];
+ BuildProcPath(exe_link, pid_, "exe");
+ ssize_t new_path_len = sys_readlink(exe_link, new_path, NAME_MAX);
+ if (new_path_len <= 0 || new_path_len == NAME_MAX)
+ return false;
+ new_path[new_path_len] = '\0';
+ if (my_strcmp(path, new_path) != 0)
+ return false;
+
+ // Check to see if someone actually named their executable 'foo (deleted)'.
+ struct kernel_stat exe_stat;
+ struct kernel_stat new_path_stat;
+ if (sys_stat(exe_link, &exe_stat) == 0 &&
+ sys_stat(new_path, &new_path_stat) == 0 &&
+ exe_stat.st_dev == new_path_stat.st_dev &&
+ exe_stat.st_ino == new_path_stat.st_ino) {
+ return false;
+ }
+
+ memcpy(path, exe_link, NAME_MAX);
+ return true;
+}
+
} // namespace google_breakpad
diff --git a/src/client/linux/minidump_writer/linux_dumper.h b/src/client/linux/minidump_writer/linux_dumper.h
index 71d1188f..16b15f3c 100644
--- a/src/client/linux/minidump_writer/linux_dumper.h
+++ b/src/client/linux/minidump_writer/linux_dumper.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009, Google Inc.
+// Copyright (c) 2010, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -165,6 +165,17 @@ class LinuxDumper {
bool EnumerateMappings(wasteful_vector<MappingInfo*>* result) const;
bool EnumerateThreads(wasteful_vector<pid_t>* result) const;
+ // For the case where a running program has been deleted, it'll show up in
+ // /proc/pid/maps as "/path/to/program (deleted)". If this is the case, then
+ // see if '/path/to/program (deleted)' matches /proc/pid/exe and return
+ // /proc/pid/exe in |path| so ELF identifier generation works correctly. This
+ // also checks to see if '/path/to/program (deleted)' exists, so it does not
+ // get fooled by a poorly named binary.
+ // For programs that don't end with ' (deleted)', this is a no-op.
+ // This assumes |path| is a buffer with length NAME_MAX.
+ // Returns true if |path| is modified.
+ bool HandleDeletedFileInMapping(char* path);
+
const pid_t pid_;
mutable PageAllocator allocator_;