]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
unfinished cfi relocatable roland/relocate-cfi-tmp
authorRoland McGrath <roland@redhat.com>
Tue, 29 Jun 2010 20:19:26 +0000 (13:19 -0700)
committerRoland McGrath <roland@redhat.com>
Wed, 5 Jan 2011 18:54:36 +0000 (10:54 -0800)
libdw/cfi.c
libdw/cfi.h
libdw/dwarf_getcfi.c
libdw/dwarf_getcfi_elf.c
libdw/encoded-value.h
libdw/fde.c
libdw/frame-cache.c

index 7dacfc8b38026ca35688d2e19e3a634bb3ef794e..9a67c3782f69af34b46375bb6d9cd8a62c2de0e7 100644 (file)
@@ -170,11 +170,11 @@ execute_cfi (Dwarf_CFI *cache,
          goto advance_loc;
 
        case DW_CFA_set_loc:
-         if (likely (!read_encoded_value (cache, cie->fde_encoding,
-                                          &program, &loc)))
-           break;
-         result = INTUSE(dwarf_errno) ();
-         goto out;
+         loc = 0;
+         fs->base_address = program;
+         program += encoded_value_size (&cache->data->d, cie->address_size,
+                                        cie->fde_encoding, program);
+         break;
 
          /* Now all following cases affect this row, but do not touch LOC.
             These cases end with 'continue'.  We only get out of the
@@ -438,9 +438,14 @@ cie_cache_initial_state (Dwarf_CFI *cache, struct dwarf_cie *cie)
   /* Make sure we have a backend handle cached.  */
   if (unlikely (cache->ebl == NULL))
     {
-      cache->ebl = ebl_openbackend (cache->data->s->elf);
-      if (unlikely (cache->ebl == NULL))
-       cache->ebl = (void *) -1l;
+      if (cache->dbg != NULL && cache->dbg->relocate != NULL)
+       cache->ebl = cache->dbg->relocate->ebl;
+      if (cache->ebl == NULL)
+       {
+         cache->ebl = ebl_openbackend (cache->data->s->elf);
+         if (unlikely (cache->ebl == NULL))
+           cache->ebl = (void *) -1l;
+       }
     }
 
   /* Fetch the ABI's default CFI program.  */
@@ -501,8 +506,9 @@ __libdw_frame_at_address (Dwarf_CFI *cache, struct dwarf_fde *fde,
        return DWARF_E_NOMEM;
 
       fs->fde = fde;
-      fs->start = fde->start;
-      fs->end = fde->end;
+      fs->base_address = fde->initial_location;
+      fs->start = 0;
+      fs->end = fde->address_range;
 
       result = execute_cfi (cache, fde->cie, &fs, true,
                            fde->instructions, fde->instructions_end, false,
index 357a8e6fb0a39a4305466d87ed495c3c11427e9c..b1c07d36c6e5d355f9efe5bfefe43be50288d6f1 100644 (file)
@@ -88,9 +88,10 @@ struct dwarf_fde
   struct dwarf_cie *cie;
   struct dwarf_fde *next;      /* Chain from cie->first_fde.  */
 
-  /* This FDE describes PC values in [start, end).  */
-  Dwarf_Addr start;
-  Dwarf_Addr end;
+  /* This is a pointer into the CFI data, which might be relocatable.
+     The length of the range is not allowed to be relocatable.  */
+  const uint8_t *initial_location;
+  Dwarf_Word address_range;
 
   const uint8_t *instructions;
   const uint8_t *instructions_end;
@@ -108,6 +109,9 @@ struct Dwarf_CFI_s
   Elf_Data_Scn *data;
   const unsigned char *e_ident;        /* For EI_DATA and EI_CLASS.  */
 
+  /* Relocation hook for the data.  */
+  struct dwarf_section_reloc *relocate;
+
   Dwarf_Addr frame_vaddr;  /* DW_EH_PE_pcrel, address of frame section.  */
   Dwarf_Addr textrel;          /* DW_EH_PE_textrel base address.  */
   Dwarf_Addr datarel;          /* DW_EH_PE_datarel base address.  */
@@ -187,7 +191,12 @@ struct dwarf_frame_register
    at a particular PC location described by an FDE.  */
 struct Dwarf_Frame_s
 {
-  /* This frame description covers PC values in [start, end).  */
+  /* This frame description covers PC values in [start, end).
+     We track these as offsets relative to the a position
+     indicated by pointer into the CFI data where there might be
+     a relocation, either at fde->initial_location, or at the
+     position of a DW_CFA_set_loc operand.  */
+  const uint8_t *base_address;
   Dwarf_Addr start;
   Dwarf_Addr end;
 
index 91e179f370cf398a6673e1a86bb1214bb9a07bda..ed983ed2937a024c9093cc8c344f9c5466eb15a6 100644 (file)
@@ -68,6 +68,8 @@ dwarf_getcfi (dbg)
 
       cfi->dbg = dbg;
       cfi->data = (Elf_Data_Scn *) dbg->sectiondata[IDX_debug_frame];
+      if (dbg->relocate != NULL)
+       cfi->relocate = dbg->relocate->sectionrel[IDX_debug_frame];
 
       cfi->search_table = NULL;
       cfi->search_table_vaddr = 0;
index 50015202e19fe9bec98482fdd27560dc31851fd4..2c4ed5fad199d7e98febb84b777eb1bce436c459 100644 (file)
@@ -55,7 +55,7 @@
 #include <string.h>
 #include <assert.h>
 
-#include "libdwP.h"
+#include "relocate.h"
 #include "cfi.h"
 #include "encoded-value.h"
 #include <dwarf.h>
@@ -231,7 +231,8 @@ getcfi_phdr (Elf *elf, const GElf_Ehdr *ehdr)
 static Dwarf_CFI *
 getcfi_scn_eh_frame (Elf *elf, const GElf_Ehdr *ehdr,
                     Elf_Scn *scn, GElf_Shdr *shdr,
-                    Elf_Scn *hdr_scn, GElf_Addr hdr_vaddr)
+                    Elf_Scn *hdr_scn, GElf_Addr hdr_vaddr,
+                    Elf_Scn *relscn)
 {
   Elf_Data *data = elf_rawdata (scn, NULL);
   if (data == NULL)
@@ -243,7 +244,18 @@ getcfi_scn_eh_frame (Elf *elf, const GElf_Ehdr *ehdr,
   if (cfi != NULL)
     {
       cfi->data = (Elf_Data_Scn *) data;
-      if (hdr_scn != NULL)
+      if (relscn != NULL)
+       {
+         cfi->relocate = malloc (sizeof *cfi->relocate);
+         if (unlikely (cfi->relocate == NULL))
+           {
+             free (cfi);
+             __libdw_seterrno (DWARF_E_NOMEM);
+             return NULL;
+           }
+         cfi->relocate->scn = relscn;
+       }
+      else if (hdr_scn != NULL)
        {
          Elf_Data *hdr_data = elf_rawdata (hdr_scn, NULL);
          if (hdr_data != NULL)
@@ -303,8 +315,31 @@ getcfi_shdr (Elf *elf, const GElf_Ehdr *ehdr)
              hdr_vaddr = shdr->sh_addr;
            }
          else if (!strcmp (name, ".eh_frame"))
-           return getcfi_scn_eh_frame (elf, ehdr, scn, shdr,
-                                       hdr_scn, hdr_vaddr);
+           break;
+       }
+
+      if (scn != NULL)
+       {
+         Elf_Scn *relscn = NULL;
+
+         if (ehdr->e_type == ET_REL)
+           {
+             relscn = scn;
+             for (int i = 0; i < 2; ++i)
+               while ((relscn = elf_nextscn (elf, relscn)) != NULL)
+                 {
+                   GElf_Shdr shdr_mem;
+                   GElf_Shdr *shdr = gelf_getshdr (relscn, &shdr_mem);
+                   if (shdr != NULL
+                       && (shdr->sh_type == SHT_REL
+                           || shdr->sh_type == SHT_RELA)
+                       && shdr->sh_link == elf_ndxscn (scn))
+                     break;
+                 }
+           }
+
+         return getcfi_scn_eh_frame (elf, ehdr, scn, shdr,
+                                     hdr_scn, hdr_vaddr, relscn);
        }
     }
 
index ee8a6f31a10d403fb27d82404546324625ddd6ec..5c87a68afdc5d333cb9b94bb3d6347f6680c5da5 100644 (file)
@@ -50,9 +50,9 @@
 #ifndef _ENCODED_VALUE_H
 #define _ENCODED_VALUE_H 1
 
+#include "cfi.h"
 #include <dwarf.h>
 #include <stdlib.h>
-#include "libdwP.h"
 
 
 static size_t __attribute__ ((unused))
index 44a39ccd7e3282c2ca9004aac3c09424231ec56c..bdb55fe5c28f1029f42936399b9a7311a044d84e 100644 (file)
 
 #include "encoded-value.h"
 
+struct fde_search
+{
+  struct dwarf_cie *cie;       /* Always NULL, a marker. */
+
+
+}
+
+static int
+compare_fde_1 (const struct dwarf_fde *fde, const struct fde_search *search)
+{
+  if (unlikely (search->initial_location == NULL))
+    ;
+
+  const uint8_t **p = fde->initial_location;
+  Dwarf_Addr start;
+
+  if (unlikely (read_encoded_value (cache, cie->fde_encoding & 0x0f,
+                                   p, &start)))
+      ;
+
+  if (search->start < fde->start)
+    return 1;
+  if (search->start >= fde1->end)
+    return -1;
+
+  return 0;
+}
+
 static int
 compare_fde (const void *a, const void *b)
 {
   const struct dwarf_fde *fde1 = a;
   const struct dwarf_fde *fde2 = b;
 
-  /* Find out which of the two arguments is the search value.
-     It has end offset 0.  */
-  if (fde1->end == 0)
-    {
-      if (fde1->start < fde2->start)
-       return -1;
-      if (fde1->start >= fde2->end)
-       return 1;
-    }
-  else
-    {
-      if (fde2->start < fde1->start)
-       return 1;
-      if (fde2->start >= fde1->end)
-       return -1;
-    }
+  /* Find out which of the two arguments is the search value.  */
+
+  if (fde1->cie == NULL)
+    return compare_fde_1 (fde2, a);
+  else if (fde2->cie == NULL)
+    return compare_fde_1 (fde1, b);
+
 
-  return 0;
 }
 
 static struct dwarf_fde *
-intern_fde (Dwarf_CFI *cache, const Dwarf_FDE *entry)
+intern_fde (Dwarf_CFI *cache, const Dwarf_FDE *entry, Dwarf_address *start)
 {
   /* Look up the new entry's CIE.  */
   struct dwarf_cie *cie = __libdw_find_cie (cache, entry->CIE_pointer);
@@ -102,12 +120,18 @@ intern_fde (Dwarf_CFI *cache, const Dwarf_FDE *entry)
 
   fde->instructions = entry->start;
   fde->instructions_end = entry->end;
-  if (unlikely (read_encoded_value (cache, cie->fde_encoding,
-                                   &fde->instructions, &fde->start))
-      || unlikely (read_encoded_value (cache, cie->fde_encoding & 0x0f,
-                                      &fde->instructions, &fde->end)))
-    return NULL;
-  fde->end += fde->start;
+  fde->initial_location = fde->instructions;
+  fde->instructions += encoded_value_size (&cache->data->d, cie->address_size,
+                                          cie->fde_encoding,
+                                          fde->instructions);
+  if (unlikely (read_encoded_value (cache, cie->fde_encoding & 0x0f,
+                                   &fde->instructions, &fde->address_range))
+      || unlikely (fde->address_range == 0))
+    {
+      free (fde);
+      __libdw_seterrno (DWARF_E_INVALID_DWARF);
+      return NULL;
+    }
 
   fde->cie = cie;
 
@@ -130,11 +154,24 @@ intern_fde (Dwarf_CFI *cache, const Dwarf_FDE *entry)
        We've recorded the number of data bytes in FDEs.  */
     fde->instructions += cie->fde_augmentation_data_size;
 
+  int result = __libdw_relocatable (cu->dbg, sec_idx, valp, width,
+                                   &symndx, addend);
+  if (unlikely (result < 0))
+    {
+      free (fde);
+      return NULL;
+    }
+  if (result == 0)
+    {
+      /* No relocation here.  */
+
+    }
+
   /* Add the new entry to the search tree.  */
   if (tsearch (fde, &cache->fde_tree, &compare_fde) == NULL)
     {
-      free (fde);
       __libdw_seterrno (DWARF_E_NOMEM);
+      free (fde);
       return NULL;
     }
 
@@ -168,17 +205,22 @@ __libdw_fde_by_offset (Dwarf_CFI *cache, Dwarf_Off offset, ptrdiff_t *nextoff)
       if (cache->next_offset == offset)
        cache->next_offset = next_offset;
 
-      offset = next_offset;
-
       if (!dwarf_cfi_cie_p (&entry))
        {
+         offset = next_offset;
          if (nextoff != NULL)
-           *nextoff = next_offset;
+           *nextoff = offset;
          break;
        }
 
       if (nextoff == NULL)
        goto invalid;
+
+      /* This is a CIE, not an FDE.  We eagerly intern these
+        because the next FDE will usually refer to this CIE.  */
+      __libdw_intern_cie (cache, offset, &entry.cie);
+
+      offset = next_offset;
     }
 
   /* We have a new FDE to consider.  */
@@ -276,15 +318,7 @@ __libdw_find_fde (Dwarf_CFI *cache, Dwarf_Addr address)
       Dwarf_Off offset = binary_search_fde (cache, address);
       if (offset == (Dwarf_Off) -1l)
        goto no_match;
-      struct dwarf_fde *fde = __libdw_fde_by_offset (cache, offset, NULL);
-      if (unlikely (fde != NULL)
-         /* Sanity check the address range.  */
-         && unlikely (address < fde->start || address >= fde->end))
-       {
-         __libdw_seterrno (DWARF_E_INVALID_DWARF);
-         return NULL;
-       }
-      return fde;
+      return __libdw_fde_by_offset (cache, offset, NULL);
     }
 
   /* It's not there.  Read more CFI entries until we find it.  */
@@ -316,7 +350,8 @@ __libdw_find_fde (Dwarf_CFI *cache, Dwarf_Addr address)
        }
 
       /* We have a new FDE to consider.  */
-      struct dwarf_fde *fde = intern_fde (cache, &entry.fde);
+      Dwarf_Addr start;
+      struct dwarf_fde *fde = intern_fde (cache, &entry.fde, &start);
 
       if (fde == (void *) -1l) /* Bad FDE, but we can keep looking.  */
        continue;
@@ -324,8 +359,10 @@ __libdw_find_fde (Dwarf_CFI *cache, Dwarf_Addr address)
       if (fde == NULL)         /* Bad data.  */
        return NULL;
 
+      if (read_encoded_value (cache, fde->cie->fde_encoding,
+
       /* Is this the one we're looking for?  */
-      if (fde->start <= address && fde->end > address)
+      if (start <= address && address - start < fde->address_range)
        return fde;
     }
 
index f48766382f1e18f03a36d7ad3748437abb800213..37d49b324b4d2a0ab438f31d3a02c59923523ccf 100644 (file)
@@ -1,5 +1,5 @@
 /* Frame cache handling.
-   Copyright (C) 2009 Red Hat, Inc.
+   Copyright (C) 2009-2010 Red Hat, Inc.
    This file is part of Red Hat elfutils.
 
    Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -54,6 +54,7 @@
 #include "cfi.h"
 #include <search.h>
 #include <stdlib.h>
+#include <libebl.h>
 
 
 static void
@@ -84,4 +85,8 @@ __libdw_destroy_frame_cache (Dwarf_CFI *cache)
   tdestroy (cache->fde_tree, free_fde);
   tdestroy (cache->cie_tree, free_cie);
   tdestroy (cache->expr_tree, free_expr);
+
+  if (cache->dbg == NULL || cache->dbg->relocate == NULL
+      || cache->dbg->relocate->ebl != cache->ebl)
+    ebl_closebackend (cache->ebl);
 }