Validate symbol file using build-id
[deliverable/binutils-gdb.git] / gdb / solib-svr4.c
index 2143021af3217ccd11106b59b24a551a60663f10..71522c6122d4f0962a2d0094ef61ece162f3da39 100644 (file)
@@ -45,6 +45,9 @@
 #include "auxv.h"
 #include "gdb_bfd.h"
 #include "probe.h"
+#include "rsp-low.h"
+
+#define NOTE_GNU_BUILD_ID_NAME  ".note.gnu.build-id"
 
 static struct link_map_offsets *svr4_fetch_link_map_offsets (void);
 static int svr4_have_link_map_offsets (void);
@@ -874,14 +877,18 @@ solib_svr4_r_map (struct svr4_info *info)
   struct link_map_offsets *lmo = svr4_fetch_link_map_offsets ();
   struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
   CORE_ADDR addr = 0;
-  volatile struct gdb_exception ex;
 
-  TRY_CATCH (ex, RETURN_MASK_ERROR)
+  TRY
     {
       addr = read_memory_typed_address (info->debug_base + lmo->r_map_offset,
                                         ptr_type);
     }
-  exception_print (gdb_stderr, ex);
+  CATCH (ex, RETURN_MASK_ERROR)
+    {
+      exception_print (gdb_stderr, ex);
+    }
+  END_CATCH
+
   return addr;
 }
 
@@ -906,13 +913,22 @@ solib_svr4_r_ldsomap (struct svr4_info *info)
   struct link_map_offsets *lmo = svr4_fetch_link_map_offsets ();
   struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
   enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
-  ULONGEST version;
+  ULONGEST version = 0;
+
+  TRY
+    {
+      /* Check version, and return zero if `struct r_debug' doesn't have
+        the r_ldsomap member.  */
+      version
+       = read_memory_unsigned_integer (info->debug_base + lmo->r_version_offset,
+                                       lmo->r_version_size, byte_order);
+    }
+  CATCH (ex, RETURN_MASK_ERROR)
+    {
+      exception_print (gdb_stderr, ex);
+    }
+  END_CATCH
 
-  /* Check version, and return zero if `struct r_debug' doesn't have
-     the r_ldsomap member.  */
-  version
-    = read_memory_unsigned_integer (info->debug_base + lmo->r_version_offset,
-                                   lmo->r_version_size, byte_order);
   if (version < 2 || lmo->r_ldsomap_offset == -1)
     return 0;
 
@@ -957,6 +973,64 @@ svr4_keep_data_in_core (CORE_ADDR vaddr, unsigned long size)
   return (name_lm >= vaddr && name_lm < vaddr + size);
 }
 
+/* Validate SO by comparing build-id from the associated bfd and
+   corresponding build-id from target memory.  Return NULL for success
+   or a string for error.  Caller must call xfree for the error string.  */
+
+static char *
+svr4_validate (const struct so_list *const so)
+{
+  const bfd_byte *local_id;
+  size_t local_idsz;
+
+  gdb_assert (so != NULL);
+
+  /* Target doesn't support reporting the build ID or the remote shared library
+     does not have build ID.  */
+  if (so->build_id == NULL)
+    return NULL;
+
+  /* Build ID may be present in the local file, just GDB is unable to retrieve
+     it.  As it has been reported by gdbserver it is not FSF gdbserver.  */
+  if (so->abfd == NULL
+      || !bfd_check_format (so->abfd, bfd_object))
+    return NULL;
+
+  /* GDB has verified the local file really does not contain the build ID.  */
+  if (so->abfd->build_id == NULL)
+    {
+      char *remote_hex;
+
+      remote_hex = alloca (so->build_idsz * 2 + 1);
+      bin2hex (so->build_id, remote_hex, so->build_idsz);
+
+      return xstrprintf (_("remote build ID is %s "
+                          "but local file does not have build ID"),
+                        remote_hex);
+    }
+
+  local_id = so->abfd->build_id->data;
+  local_idsz = so->abfd->build_id->size;
+
+  if (so->build_idsz != local_idsz
+      || memcmp (so->build_id, local_id, so->build_idsz) != 0)
+    {
+      char *remote_hex, *local_hex;
+
+      remote_hex = alloca (so->build_idsz * 2 + 1);
+      bin2hex (so->build_id, remote_hex, so->build_idsz);
+      local_hex = alloca (local_idsz * 2 + 1);
+      bin2hex (local_id, local_hex, local_idsz);
+
+      return xstrprintf (_("remote build ID %s "
+                          "does not match local build ID %s"),
+                        remote_hex, local_hex);
+    }
+
+  /* Both build IDs are present and they match.  */
+  return NULL;
+}
+
 /* Implement the "open_symbol_file_object" target_so_ops method.
 
    If no open symbol file, attempt to locate and open the main symbol
@@ -1095,6 +1169,12 @@ svr4_copy_library_list (struct so_list *src)
       newobj->lm_info = xmalloc (sizeof (struct lm_info));
       memcpy (newobj->lm_info, src->lm_info, sizeof (struct lm_info));
 
+      if (newobj->build_id != NULL)
+       {
+         newobj->build_id = xmalloc (src->build_idsz);
+         memcpy (newobj->build_id, src->build_id, src->build_idsz);
+       }
+
       newobj->next = NULL;
       *link = newobj;
       link = &newobj->next;
@@ -1122,6 +1202,9 @@ library_list_start_library (struct gdb_xml_parser *parser,
   ULONGEST *lmp = xml_find_attribute (attributes, "lm")->value;
   ULONGEST *l_addrp = xml_find_attribute (attributes, "l_addr")->value;
   ULONGEST *l_ldp = xml_find_attribute (attributes, "l_ld")->value;
+  const struct gdb_xml_value *const att_build_id
+    = xml_find_attribute (attributes, "build-id");
+  const char *const hex_build_id = att_build_id ? att_build_id->value : NULL;
   struct so_list *new_elem;
 
   new_elem = XCNEW (struct so_list);
@@ -1133,6 +1216,37 @@ library_list_start_library (struct gdb_xml_parser *parser,
   strncpy (new_elem->so_name, name, sizeof (new_elem->so_name) - 1);
   new_elem->so_name[sizeof (new_elem->so_name) - 1] = 0;
   strcpy (new_elem->so_original_name, new_elem->so_name);
+  if (hex_build_id != NULL)
+    {
+      const size_t hex_build_id_len = strlen (hex_build_id);
+
+      if (hex_build_id_len == 0)
+       warning (_("Shared library \"%s\" received empty build-id "
+                  "from gdbserver"), new_elem->so_original_name);
+      else if ((hex_build_id_len & 1U) != 0)
+       warning (_("Shared library \"%s\" received odd number "
+                  "of build-id \"%s\" hex characters from gdbserver"),
+                new_elem->so_original_name, hex_build_id);
+      else
+       {
+         const size_t build_idsz = hex_build_id_len / 2;
+
+         new_elem->build_id = xmalloc (build_idsz);
+         new_elem->build_idsz = hex2bin (hex_build_id, new_elem->build_id,
+                                         build_idsz);
+         if (new_elem->build_idsz != build_idsz)
+           {
+             warning (_("Shared library \"%s\" received invalid "
+                        "build-id \"%s\" hex character at encoded byte "
+                        "position %s (first as 0) from gdbserver"),
+                      new_elem->so_original_name, hex_build_id,
+                      pulongest (new_elem->build_idsz));
+             xfree (new_elem->build_id);
+             new_elem->build_id = NULL;
+             new_elem->build_idsz = 0;
+           }
+       }
+    }
 
   *list->tailp = new_elem;
   list->tailp = &new_elem->next;
@@ -1167,6 +1281,7 @@ static const struct gdb_xml_attribute svr4_library_attributes[] =
   { "lm", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
   { "l_addr", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
   { "l_ld", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+  { "build-id", GDB_XML_AF_OPTIONAL, NULL, NULL },
   { NULL, GDB_XML_AF_NONE, NULL, NULL }
 };
 
@@ -2266,7 +2381,6 @@ enable_break (struct svr4_info *info, int from_tty)
       struct so_list *so;
       bfd *tmp_bfd = NULL;
       struct target_ops *tmp_bfd_target;
-      volatile struct gdb_exception ex;
 
       sym_addr = 0;
 
@@ -2279,10 +2393,15 @@ enable_break (struct svr4_info *info, int from_tty)
          be trivial on GNU/Linux).  Therefore, we have to try an alternate
          mechanism to find the dynamic linker's base address.  */
 
-      TRY_CATCH (ex, RETURN_MASK_ALL)
+      TRY
         {
          tmp_bfd = solib_bfd_open (interp_name);
        }
+      CATCH (ex, RETURN_MASK_ALL)
+       {
+       }
+      END_CATCH
+
       if (tmp_bfd == NULL)
        goto bkpt_at_symbol;
 
@@ -2543,7 +2662,7 @@ svr4_exec_displacement (CORE_ADDR *displacementp)
 {
   /* ENTRY_POINT is a possible function descriptor - before
      a call to gdbarch_convert_from_func_ptr_addr.  */
-  CORE_ADDR entry_point, displacement;
+  CORE_ADDR entry_point, exec_displacement;
 
   if (exec_bfd == NULL)
     return 0;
@@ -2558,9 +2677,9 @@ svr4_exec_displacement (CORE_ADDR *displacementp)
   if (target_auxv_search (&current_target, AT_ENTRY, &entry_point) <= 0)
     return 0;
 
-  displacement = entry_point - bfd_get_start_address (exec_bfd);
+  exec_displacement = entry_point - bfd_get_start_address (exec_bfd);
 
-  /* Verify the DISPLACEMENT candidate complies with the required page
+  /* Verify the EXEC_DISPLACEMENT candidate complies with the required page
      alignment.  It is cheaper than the program headers comparison below.  */
 
   if (bfd_get_flavour (exec_bfd) == bfd_target_elf_flavour)
@@ -2572,7 +2691,7 @@ svr4_exec_displacement (CORE_ADDR *displacementp)
           p_offset % p_align == p_vaddr % p_align
         Kernel is free to load the executable with lower alignment.  */
 
-      if ((displacement & (elf->minpagesize - 1)) != 0)
+      if ((exec_displacement & (elf->minpagesize - 1)) != 0)
        return 0;
     }
 
@@ -2893,11 +3012,11 @@ svr4_exec_displacement (CORE_ADDR *displacementp)
 
       printf_unfiltered (_("Using PIE (Position Independent Executable) "
                           "displacement %s for \"%s\".\n"),
-                        paddress (target_gdbarch (), displacement),
+                        paddress (target_gdbarch (), exec_displacement),
                         bfd_get_filename (exec_bfd));
     }
 
-  *displacementp = displacement;
+  *displacementp = exec_displacement;
   return 1;
 }
 
@@ -3241,4 +3360,5 @@ _initialize_svr4_solib (void)
   svr4_so_ops.keep_data_in_core = svr4_keep_data_in_core;
   svr4_so_ops.update_breakpoints = svr4_update_solib_event_breakpoints;
   svr4_so_ops.handle_event = svr4_handle_solib_event;
+  svr4_so_ops.validate = svr4_validate;
 }
This page took 0.030385 seconds and 4 git commands to generate.