Fix linux-gate handling in LinuxDumper so it gets a valid debug ID
A=ted R=nealsid at http://breakpad.appspot.com/284001

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@788 4c0a9323-5329-0410-9bdc-e9ce6186880e
diff --git a/src/client/linux/minidump_writer/linux_dumper.cc b/src/client/linux/minidump_writer/linux_dumper.cc
index 76dc4db..ab3a5ea 100644
--- a/src/client/linux/minidump_writer/linux_dumper.cc
+++ b/src/client/linux/minidump_writer/linux_dumper.cc
@@ -213,6 +213,21 @@
   if (IsMappedFileOpenUnsafe(mapping))
     return false;
 
+  // Special-case linux-gate because it's not a real file.
+  if (my_strcmp(mapping.name, kLinuxGateLibraryName) == 0) {
+    const uintptr_t kPageSize = getpagesize();
+    void* linux_gate = NULL;
+    if (pid_ == sys_getpid()) {
+      linux_gate = reinterpret_cast<void*>(mapping.start_addr);
+    } else {
+      linux_gate = allocator_.Alloc(kPageSize);
+      CopyFromProcess(linux_gate, pid_,
+                      reinterpret_cast<const void*>(mapping.start_addr),
+                      kPageSize);
+    }
+    return FileID::ElfFileIdentifierFromMappedFile(linux_gate, identifier);
+  }
+
   char filename[NAME_MAX];
   size_t filename_len = my_strlen(mapping.name);
   assert(filename_len < NAME_MAX);
diff --git a/src/client/linux/minidump_writer/linux_dumper_unittest.cc b/src/client/linux/minidump_writer/linux_dumper_unittest.cc
index c537ce9..1eee9a1 100644
--- a/src/client/linux/minidump_writer/linux_dumper_unittest.cc
+++ b/src/client/linux/minidump_writer/linux_dumper_unittest.cc
@@ -276,6 +276,7 @@
 }
 
 #if !defined(__ARM_EABI__)
+// Ensure that the linux-gate VDSO is included in the mapping list.
 TEST(LinuxDumperTest, MappingsIncludeLinuxGate) {
   LinuxDumper dumper(getpid());
   ASSERT_TRUE(dumper.Init());
@@ -297,6 +298,80 @@
   EXPECT_EQ(linux_gate_loc, reinterpret_cast<void*>(mapping->start_addr));
   EXPECT_EQ(0, memcmp(linux_gate_loc, ELFMAG, SELFMAG));
 }
+
+// Ensure that the linux-gate VDSO can generate a non-zeroed File ID.
+TEST(LinuxDumperTest, LinuxGateMappingID) {
+  LinuxDumper dumper(getpid());
+  ASSERT_TRUE(dumper.Init());
+
+  bool found_linux_gate = false;
+  const wasteful_vector<MappingInfo*> mappings = dumper.mappings();
+  unsigned index = 0;
+  for (unsigned i = 0; i < mappings.size(); ++i) {
+    if (!strcmp(mappings[i]->name, kLinuxGateLibraryName)) {
+      found_linux_gate = true;
+      index = i;
+      break;
+    }
+  }
+  ASSERT_TRUE(found_linux_gate);
+
+  uint8_t identifier[sizeof(MDGUID)];
+  ASSERT_TRUE(dumper.ElfFileIdentifierForMapping(*mappings[index],
+                                                 true,
+                                                 index,
+                                                 identifier));
+  uint8_t empty_identifier[sizeof(MDGUID)];
+  memset(empty_identifier, 0, sizeof(empty_identifier));
+  EXPECT_NE(0, memcmp(empty_identifier, identifier, sizeof(identifier)));
+}
+
+// Ensure that the linux-gate VDSO can generate a non-zeroed File ID
+// from a child process.
+TEST(LinuxDumperTest, LinuxGateMappingIDChild) {
+  int fds[2];
+  ASSERT_NE(-1, pipe(fds));
+
+  // Fork a child so ptrace works.
+  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());
+
+  bool found_linux_gate = false;
+  const wasteful_vector<MappingInfo*> mappings = dumper.mappings();
+  unsigned index = 0;
+  for (unsigned i = 0; i < mappings.size(); ++i) {
+    if (!strcmp(mappings[i]->name, kLinuxGateLibraryName)) {
+      found_linux_gate = true;
+      index = i;
+      break;
+    }
+  }
+  ASSERT_TRUE(found_linux_gate);
+
+  // Need to suspend the child so ptrace actually works.
+  ASSERT_TRUE(dumper.ThreadsSuspend());
+  uint8_t identifier[sizeof(MDGUID)];
+  ASSERT_TRUE(dumper.ElfFileIdentifierForMapping(*mappings[index],
+                                                 true,
+                                                 index,
+                                                 identifier));
+  uint8_t empty_identifier[sizeof(MDGUID)];
+  memset(empty_identifier, 0, sizeof(empty_identifier));
+  EXPECT_NE(0, memcmp(empty_identifier, identifier, sizeof(identifier)));
+  EXPECT_TRUE(dumper.ThreadsResume());
+  close(fds[1]);
+}
 #endif
 
 TEST(LinuxDumperTest, FileIDsMatch) {
@@ -311,11 +386,11 @@
   int fds[2];
   ASSERT_NE(-1, pipe(fds));
 
-  // fork a child so we can ptrace it
+  // Fork a child so ptrace works.
   const pid_t child = fork();
   if (child == 0) {
     close(fds[1]);
-    // now wait forever for the parent
+    // Now wait forever for the parent.
     char b;
     HANDLE_EINTR(read(fds[0], &b, sizeof(b)));
     close(fds[0]);