diff mbox

gdbserver: linux_low: elf_64_file_p cache results

Message ID 1503525413-14843-1-git-send-email-jon@ringle.org
State New
Headers show

Commit Message

jon@ringle.org Aug. 23, 2017, 9:56 p.m. UTC
From: Jon Ringle <jringle@gridpoint.com>

I was debugging a systemd service that would drop root privileges, and
found that I was unable to debug it properly because gdb could not resolve
any symbols. The gdbserver on my arm target would report:

  gdbserver: Corrupted shared library list: 0x0 != 0xe2822038

Prior to getting the above message, symbols could be resolved successfully.
I finally determined that the problem was that in linux_low.c in function
linux_qxfer_libraries_svr4() the is_elf64 variable was causing the wrong
lmo and ptr_size to get used. Here's that code snippet:

7136 static int
7137 linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
7138                             unsigned const char *writebuf,
7139                             CORE_ADDR offset, int len)
7140 {
7141   char *document;
7142   unsigned document_len;
7143   struct process_info_private *const priv = current_process ()->priv;
7144   char filename[PATH_MAX];
7145   int pid, is_elf64;
7146
7147   static const struct link_map_offsets lmo_32bit_offsets =
7148     {
7149       0,     /* r_version offset. */
7150       4,     /* r_debug.r_map offset.  */
7151       0,     /* l_addr offset in link_map.  */
7152       4,     /* l_name offset in link_map.  */
7153       8,     /* l_ld offset in link_map.  */
7154       12,    /* l_next offset in link_map.  */
7155       16     /* l_prev offset in link_map.  */
7156     };
7157
7158   static const struct link_map_offsets lmo_64bit_offsets =
7159     {
7160       0,     /* r_version offset. */
7161       8,     /* r_debug.r_map offset.  */
7162       0,     /* l_addr offset in link_map.  */
7163       8,     /* l_name offset in link_map.  */
7164       16,    /* l_ld offset in link_map.  */
7165       24,    /* l_next offset in link_map.  */
7166       32     /* l_prev offset in link_map.  */
7167     };
7168   const struct link_map_offsets *lmo;
7169   unsigned int machine;
7170   int ptr_size;
7171   CORE_ADDR lm_addr = 0, lm_prev = 0;
7172   int allocated = 1024;
7173   char *p;
7174   CORE_ADDR l_name, l_addr, l_ld, l_next, l_prev;
7175   int header_done = 0;
7176
7177   if (writebuf != NULL)
7178     return -2;
7179   if (readbuf == NULL)
7180     return -1;
7181
7182   pid = lwpid_of (current_thread);
7183   xsnprintf (filename, sizeof filename, "/proc/%d/exe", pid);
7184   is_elf64 = elf_64_file_p (filename, &machine);
7185   lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets;
7186   ptr_size = is_elf64 ? 8 : 4;

The problem lied in the fact that the function elf_64_file_p() was
returning -1 because it could not open the file (with errno set to EACCESS)
This was because the inferior's code was dropping root privileges and no
longer was able to read the file.

This patch implements a cache per file in the elf_64_file_p() function so
that it remembers the results of a previous query for the same filename.

Since it seems that c++ is now accepted, it was implemented using std::map

Signed-off-by: Jon Ringle <jringle@gridpoint.com>
---
 gdb/gdbserver/linux-low.c | 24 ++++++++++++++++++------
 1 file changed, 18 insertions(+), 6 deletions(-)
diff mbox

Patch

diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index e27cbf825a5b..0b1c7e089227 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -47,6 +47,8 @@ 
 #include "tracepoint.h"
 #include "hostio.h"
 #include <inttypes.h>
+#include <map>
+
 #ifndef ELFMAG0
 /* Don't include <linux/elf.h> here.  If it got included by gdb_proc_service.h
    then ELFMAG0 will have been defined.  If it didn't get included by
@@ -370,24 +372,34 @@  elf_64_header_p (const Elf64_Ehdr *header, unsigned int *machine)
    zero if the file is not a 64-bit ELF file,
    and -1 if the file is not accessible or doesn't exist.  */
 
+static std::map<const char*, std::pair<int, unsigned int>> is_elf64_cache;
+
 static int
 elf_64_file_p (const char *file, unsigned int *machine)
 {
   Elf64_Ehdr header;
   int fd;
+  int is_elf64 = 0;
+
+  auto iter = is_elf64_cache.find(file);
+  if (iter != is_elf64_cache.end())
+    {
+      *machine = iter->second.second;
+      return iter->second.first;
+    }
 
   fd = open (file, O_RDONLY);
   if (fd < 0)
     return -1;
 
-  if (read (fd, &header, sizeof (header)) != sizeof (header))
-    {
-      close (fd);
-      return 0;
-    }
+  if (read (fd, &header, sizeof (header)) == sizeof (header))
+    is_elf64 = elf_64_header_p (&header, machine);
+
   close (fd);
 
-  return elf_64_header_p (&header, machine);
+  is_elf64_cache.emplace(file, std::make_pair(is_elf64, *machine));
+
+  return is_elf64;
 }
 
 /* Accepts an integer PID; Returns true if the executable PID is