[RFA/Darwin] Fix section relocation addresses when base address is not 0.

Message ID 1520239994-15165-1-git-send-email-roirand@adacore.com
State New, archived
Headers

Commit Message

Xavier Roirand March 5, 2018, 8:53 a.m. UTC
  When using "info sharedlibrary" on Darwin, the start & end addresses
may be wrong if the shared objects relocation address is not 0 because
section relocation adresses does not take in account base address
when this one is different from 0.

This patch fixes it.

gdb/ChangeLog:

        * solib-darwin.c (struct lm_info): Add lm_base and base_set
        fields.
        (darwin_current_sos): Add detail in comment.  Set addr_low.
        (darwin_relocate_section_addresses): Use base address to
        relocate a section.
---
 ChangeLog          |  5 +++++
 gdb/solib-darwin.c | 25 +++++++++++++++++--------
 2 files changed, 22 insertions(+), 8 deletions(-)
  

Comments

Pedro Alves March 26, 2018, 6:05 p.m. UTC | #1
On 03/05/2018 08:53 AM, Xavier Roirand wrote:
> When using "info sharedlibrary" on Darwin, the start & end addresses
> may be wrong if the shared objects relocation address is not 0 because
> section relocation adresses does not take in account base address
> when this one is different from 0.
> 
> This patch fixes it.
> 
> gdb/ChangeLog:
> 
>         * solib-darwin.c (struct lm_info): Add lm_base and base_set
>         fields.
>         (darwin_current_sos): Add detail in comment.  Set addr_low.
>         (darwin_relocate_section_addresses): Use base address to
>         relocate a section.

I don't know much about Darwin, but this sounds reasonable to me,
at least.

> --- a/ChangeLog
> +++ b/ChangeLog
> @@ -1,3 +1,8 @@
> +2018-03-02  Tristan Gingold  <gingold@adacore.com>

Please remember to preserve Tristan as git author, then.

Thanks,
Pedro Alves
  

Patch

diff --git a/ChangeLog b/ChangeLog
index 03e1852114..5c749fb887 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@ 
+2018-03-02  Tristan Gingold  <gingold@adacore.com>
+
+	* Fix solib addr_low & addr_high addresses when base
+	address is not 0.
+
 2018-02-13  Maciej W. Rozycki  <macro@mips.com>
 
 	* configure.ac <wasm32-*-*> (noconfigdirs): Add `ld'.
diff --git a/gdb/solib-darwin.c b/gdb/solib-darwin.c
index cf15148c36..1b43da88b4 100644
--- a/gdb/solib-darwin.c
+++ b/gdb/solib-darwin.c
@@ -157,6 +157,10 @@  struct lm_info_darwin : public lm_info_base
 {
   /* The target location of lm.  */
   CORE_ADDR lm_addr = 0;
+
+  /* Dylib base address.  */
+  CORE_ADDR lm_base;
+  unsigned char base_set;
 };
 
 /* Lookup the value for a specific symbol.  */
@@ -273,7 +277,7 @@  darwin_current_sos (void)
       load_addr = extract_typed_address (buf, ptr_type);
       path_addr = extract_typed_address (buf + ptr_len, ptr_type);
 
-      /* Read Mach-O header from memory.  */
+      /* Read Mach-O header from memory (except the reserved field).  */
       if (target_read_memory (load_addr, (gdb_byte *) &hdr, sizeof (hdr) - 4))
 	break;
       /* Discard wrong magic numbers.  Shouldn't happen.  */
@@ -303,6 +307,8 @@  darwin_current_sos (void)
       newobj->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
       strcpy (newobj->so_original_name, newobj->so_name);
       xfree (file_path);
+      newobj->addr_low = load_addr;
+      newobj->addr_high = load_addr;
       li->lm_addr = load_addr;
 
       if (head == NULL)
@@ -592,16 +598,19 @@  darwin_relocate_section_addresses (struct so_list *so,
 {
   lm_info_darwin *li = (lm_info_darwin *) so->lm_info;
 
-  sec->addr += li->lm_addr;
-  sec->endaddr += li->lm_addr;
+  /* Read base address.  */
+  if (!li->base_set)
+    {
+      li->lm_base = bfd_mach_o_get_base_address (so->abfd);
+      li->base_set = 1;
+    }
+
+  /* Relocate section.  */
+  sec->addr += li->lm_addr - li->lm_base;
+  sec->endaddr += li->lm_addr - li->lm_base;
 
   /* Best effort to set addr_high/addr_low.  This is used only by
      'info sharedlibary'.  */
-  if (so->addr_high == 0)
-    {
-      so->addr_low = sec->addr;
-      so->addr_high = sec->endaddr;
-    }
   if (sec->endaddr > so->addr_high)
     so->addr_high = sec->endaddr;
   if (sec->addr < so->addr_low)