From 0a5fc5d663054eb836eafc258cc2f6792358e2c9 Mon Sep 17 00:00:00 2001 From: "ted.mielczarek" Date: Wed, 23 Dec 2009 17:09:27 +0000 Subject: Issue 357: New Linux file_id code doesn't persist across strip. r=agl,nealsid at http://breakpad.appspot.com/49008 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@461 4c0a9323-5329-0410-9bdc-e9ce6186880e --- src/client/linux/Makefile | 1 + src/client/linux/minidump_writer/linux_dumper.cc | 29 ++++++++++ src/client/linux/minidump_writer/linux_dumper.h | 5 ++ .../linux/minidump_writer/linux_dumper_unittest.cc | 65 ++++++++++++++++++++++ .../linux/minidump_writer/minidump_writer.cc | 25 ++------- 5 files changed, 105 insertions(+), 20 deletions(-) (limited to 'src/client/linux') diff --git a/src/client/linux/Makefile b/src/client/linux/Makefile index 6f1c24f5..9116fe6f 100644 --- a/src/client/linux/Makefile +++ b/src/client/linux/Makefile @@ -39,6 +39,7 @@ TEST_CC_SRC=handler/exception_handler_unittest.cc \ minidump_writer/line_reader_unittest.cc \ minidump_writer/linux_dumper_unittest.cc \ minidump_writer/minidump_writer_unittest.cc \ + ../../common/linux/file_id.cc \ $(GOOGLETEST_CC_SRC) TEST_CC_OBJ=$(patsubst %.cc, $(OBJ_DIR)/%.o,$(TEST_CC_SRC)) diff --git a/src/client/linux/minidump_writer/linux_dumper.cc b/src/client/linux/minidump_writer/linux_dumper.cc index 28729b34..d752608d 100644 --- a/src/client/linux/minidump_writer/linux_dumper.cc +++ b/src/client/linux/minidump_writer/linux_dumper.cc @@ -42,15 +42,20 @@ #include #include +#include #include #include +#include #include #include #include +#include + #include "client/linux/minidump_writer/directory_reader.h" #include "client/linux/minidump_writer/line_reader.h" +#include "common/linux/file_id.h" #include "common/linux/linux_libc_support.h" #include "common/linux/linux_syscall_support.h" @@ -156,6 +161,30 @@ LinuxDumper::BuildProcPath(char* path, pid_t pid, const char* node) const { memcpy(path + total_length, "\0", 1); } +bool +LinuxDumper::ElfFileIdentifierForMapping(unsigned int mapping_id, + uint8_t identifier[sizeof(MDGUID)]) +{ + assert(mapping_id < mappings_.size()); + const MappingInfo* mapping = mappings_[mapping_id]; + int fd = sys_open(mapping->name, O_RDONLY, 0); + if (fd < 0) + return false; + struct kernel_stat st; + if (sys_fstat(fd, &st) != 0) { + sys_close(fd); + return false; + } + void* base = sys_mmap2(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + sys_close(fd); + if (base == MAP_FAILED) + return false; + + bool success = FileID::ElfFileIdentifierFromMappedFile(base, identifier); + sys_munmap(base, st.st_size); + return success; +} + void* LinuxDumper::FindBeginningOfLinuxGateSharedLibrary(const pid_t pid) const { char auxv_path[80]; diff --git a/src/client/linux/minidump_writer/linux_dumper.h b/src/client/linux/minidump_writer/linux_dumper.h index d8e5e783..3e8869b5 100644 --- a/src/client/linux/minidump_writer/linux_dumper.h +++ b/src/client/linux/minidump_writer/linux_dumper.h @@ -37,6 +37,7 @@ #include #include "common/linux/memory.h" +#include "google_breakpad/common/minidump_format.h" namespace google_breakpad { @@ -122,6 +123,10 @@ class LinuxDumper { // without any slashes. void BuildProcPath(char* path, pid_t pid, const char* node) const; + // Generate a File ID from the .text section of a mapped entry + bool ElfFileIdentifierForMapping(unsigned int mapping_id, + uint8_t identifier[sizeof(MDGUID)]); + // Utility method to find the location of where the kernel has // mapped linux-gate.so in memory(shows up in /proc/pid/maps as // [vdso], but we can't guarantee that it's the only virtual dynamic diff --git a/src/client/linux/minidump_writer/linux_dumper_unittest.cc b/src/client/linux/minidump_writer/linux_dumper_unittest.cc index f5ed914b..e060e53e 100644 --- a/src/client/linux/minidump_writer/linux_dumper_unittest.cc +++ b/src/client/linux/minidump_writer/linux_dumper_unittest.cc @@ -27,13 +27,25 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#include #include #include "client/linux/minidump_writer/linux_dumper.h" +#include "common/linux/file_id.h" #include "breakpad_googletest_includes.h" using namespace google_breakpad; +// This provides a wrapper around system calls which may be +// interrupted by a signal and return EINTR. See man 7 signal. +#define HANDLE_EINTR(x) ({ \ + typeof(x) __eintr_result__; \ + do { \ + __eintr_result__ = x; \ + } while (__eintr_result__ == -1 && errno == EINTR); \ + __eintr_result__;\ +}) + namespace { typedef testing::Test LinuxDumperTest; } @@ -116,3 +128,56 @@ TEST(LinuxDumperTest, MappingsIncludeLinuxGate) { EXPECT_EQ(0, memcmp(linux_gate_loc, ELFMAG, SELFMAG)); } } + +TEST(LinuxDumperTest, FileIDsMatch) { + // Calculate the File ID of our binary using both + // FileID::ElfFileIdentifier and LinuxDumper::ElfFileIdentifierForMapping + // and ensure that we get the same result from both. + char exe_name[PATH_MAX]; + ssize_t len = readlink("/proc/self/exe", exe_name, PATH_MAX - 1); + ASSERT_NE(len, -1); + exe_name[len] = '\0'; + + int fds[2]; + ASSERT_NE(-1, pipe(fds)); + + // fork a child so we can ptrace it + const pid_t child = fork(); + if (child == 0) { + close(fds[1]); + // now wait forever for the parent + char b; + HANDLE_EINTR(read(fds[0], &b, sizeof(b))); + close(fds[0]); + syscall(__NR_exit); + } + close(fds[0]); + + LinuxDumper dumper(child); + ASSERT_TRUE(dumper.Init()); + const wasteful_vector mappings = dumper.mappings(); + bool found_exe = false; + unsigned i; + for (i = 0; i < mappings.size(); ++i) { + const MappingInfo* mapping = mappings[i]; + if (!strcmp(mapping->name, exe_name)) { + found_exe = true; + break; + } + } + ASSERT_TRUE(found_exe); + + uint8_t identifier1[sizeof(MDGUID)]; + uint8_t identifier2[sizeof(MDGUID)]; + EXPECT_TRUE(dumper.ElfFileIdentifierForMapping(i, identifier1)); + FileID fileid(exe_name); + EXPECT_TRUE(fileid.ElfFileIdentifier(identifier2)); + char identifier_string1[37]; + char identifier_string2[37]; + FileID::ConvertIdentifierToString(identifier1, identifier_string1, + 37); + FileID::ConvertIdentifierToString(identifier2, identifier_string2, + 37); + EXPECT_STREQ(identifier_string1, identifier_string2); + close(fds[1]); +} diff --git a/src/client/linux/minidump_writer/minidump_writer.cc b/src/client/linux/minidump_writer/minidump_writer.cc index 09f23723..166b8e5c 100644 --- a/src/client/linux/minidump_writer/minidump_writer.cc +++ b/src/client/linux/minidump_writer/minidump_writer.cc @@ -547,26 +547,11 @@ class MinidumpWriter { const uint32_t cv_signature = MD_CVINFOPDB70_SIGNATURE; memcpy(cv_ptr, &cv_signature, sizeof(cv_signature)); cv_ptr += sizeof(cv_signature); - - { - // We XOR the first page of the file to get a signature for it. - uint8_t xor_buf[sizeof(MDGUID)]; - size_t done = 0; - uint8_t* signature = cv_ptr; - cv_ptr += sizeof(xor_buf); - - my_memset(signature, 0, sizeof(xor_buf)); - while (done < 4096) { - dumper_.CopyFromProcess(xor_buf, crashing_tid_, - (void *) (mod.base_of_image + done), - sizeof(xor_buf)); - for (unsigned i = 0; i < sizeof(xor_buf); ++i) - signature[i] ^= xor_buf[i]; - done += sizeof(xor_buf); - } - my_memset(cv_ptr, 0, sizeof(uint32_t)); // Set age to 0 on Linux. - cv_ptr += sizeof(uint32_t); - } + uint8_t* signature = cv_ptr; + cv_ptr += sizeof(MDGUID); + dumper_.ElfFileIdentifierForMapping(i, signature); + my_memset(cv_ptr, 0, sizeof(uint32_t)); // Set age to 0 on Linux. + cv_ptr += sizeof(uint32_t); // Write pdb_file_name memcpy(cv_ptr, filename_ptr, filename_len + 1); -- cgit v1.2.1