From 78373e45c5f29416ce9e2f092f92b57cfefe88ed Mon Sep 17 00:00:00 2001
From: "mkrebs@chromium.org"
 <mkrebs@chromium.org@4c0a9323-5329-0410-9bdc-e9ce6186880e>
Date: Fri, 30 Mar 2012 23:53:32 +0000
Subject: Fix for putting main module as first one in minidump

The first module in a minidump is expected to be for the main executable.
We used to assume that /proc/<pid>/maps always showed that one first, but in
some cases that is no longer true (see comment #7 of the bug).  So this
change makes use of the entry point stored in auxv to make sure we put the
correct module first.

BUG=chromium-os:25355
TEST=Ran Breakpad tests
Review URL: https://breakpad.appspot.com/366002

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@942 4c0a9323-5329-0410-9bdc-e9ce6186880e
---
 src/client/linux/minidump_writer/linux_dumper.cc | 52 +++++++++++++++++++++++-
 src/client/linux/minidump_writer/linux_dumper.h  |  4 +-
 2 files changed, 53 insertions(+), 3 deletions(-)

(limited to 'src/client')

diff --git a/src/client/linux/minidump_writer/linux_dumper.cc b/src/client/linux/minidump_writer/linux_dumper.cc
index 2cf1b40f..e9d211ec 100644
--- a/src/client/linux/minidump_writer/linux_dumper.cc
+++ b/src/client/linux/minidump_writer/linux_dumper.cc
@@ -132,7 +132,7 @@ LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping,
 }
 
 void*
-LinuxDumper::FindBeginningOfLinuxGateSharedLibrary(const pid_t pid) const {
+LinuxDumper::FindBeginningOfLinuxGateSharedLibrary(pid_t pid) const {
   char auxv_path[NAME_MAX];
   if (!BuildProcPath(auxv_path, pid, "auxv"))
     return NULL;
@@ -159,6 +159,32 @@ LinuxDumper::FindBeginningOfLinuxGateSharedLibrary(const pid_t pid) const {
   return NULL;
 }
 
+void*
+LinuxDumper::FindEntryPoint(pid_t pid) const {
+  char auxv_path[NAME_MAX];
+  if (!BuildProcPath(auxv_path, pid, "auxv"))
+    return NULL;
+
+  int fd = sys_open(auxv_path, O_RDONLY, 0);
+  if (fd < 0) {
+    return NULL;
+  }
+
+  // Find the AT_ENTRY entry
+  elf_aux_entry one_aux_entry;
+  while (sys_read(fd,
+                  &one_aux_entry,
+                  sizeof(elf_aux_entry)) == sizeof(elf_aux_entry) &&
+         one_aux_entry.a_type != AT_NULL) {
+    if (one_aux_entry.a_type == AT_ENTRY) {
+      close(fd);
+      return reinterpret_cast<void*>(one_aux_entry.a_un.a_val);
+    }
+  }
+  close(fd);
+  return NULL;
+}
+
 bool LinuxDumper::EnumerateMappings() {
   char maps_path[NAME_MAX];
   if (!BuildProcPath(maps_path, pid_, "maps"))
@@ -171,6 +197,10 @@ bool LinuxDumper::EnumerateMappings() {
   // of mappings.
   const void* linux_gate_loc;
   linux_gate_loc = FindBeginningOfLinuxGateSharedLibrary(pid_);
+  // Although the initial executable is usually the first mapping, it's not
+  // guaranteed (see http://crosbug.com/25355); therefore, try to use the
+  // actual entry point to find the mapping.
+  const void* entry_point_loc = FindEntryPoint(pid_);
 
   const int fd = sys_open(maps_path, O_RDONLY, 0);
   if (fd < 0)
@@ -219,7 +249,25 @@ bool LinuxDumper::EnumerateMappings() {
             if (l < sizeof(module->name))
               memcpy(module->name, name, l);
           }
-          mappings_.push_back(module);
+          // If this is the entry-point mapping, and it's not already the
+          // first one, then we need to make it be first.  This is because
+          // the minidump format assumes the first module is the one that
+          // corresponds to the main executable (as codified in
+          // processor/minidump.cc:MinidumpModuleList::GetMainModule()).
+          if (entry_point_loc &&
+              (entry_point_loc >=
+                  reinterpret_cast<void*>(module->start_addr)) &&
+              (entry_point_loc <
+                  reinterpret_cast<void*>(module->start_addr+module->size)) &&
+              !mappings_.empty()) {
+            // push the module onto the front of the list.
+            mappings_.resize(mappings_.size() + 1);
+            for (size_t idx = mappings_.size() - 1; idx > 0; idx--)
+              mappings_[idx] = mappings_[idx - 1];
+            mappings_[0] = module;
+          } else {
+            mappings_.push_back(module);
+          }
         }
       }
     }
diff --git a/src/client/linux/minidump_writer/linux_dumper.h b/src/client/linux/minidump_writer/linux_dumper.h
index 45779699..42b2a991 100644
--- a/src/client/linux/minidump_writer/linux_dumper.h
+++ b/src/client/linux/minidump_writer/linux_dumper.h
@@ -178,7 +178,9 @@ class LinuxDumper {
   // [vdso], but we can't guarantee that it's the only virtual dynamic
   // shared object.  Parsing the auxilary vector for AT_SYSINFO_EHDR
   // is the safest way to go.)
-  void* FindBeginningOfLinuxGateSharedLibrary(const pid_t pid) const;
+  void* FindBeginningOfLinuxGateSharedLibrary(pid_t pid) const;
+  // Utility method to find the entry point location.
+  void* FindEntryPoint(pid_t pid) const;
 
   uintptr_t crash_address() const { return crash_address_; }
   void set_crash_address(uintptr_t crash_address) {
-- 
cgit v1.2.1