diff options
author | Roland McGrath <roland@redhat.com> | 2010-06-29 13:19:26 -0700 |
---|---|---|
committer | Roland McGrath <roland@redhat.com> | 2011-01-05 10:54:36 -0800 |
commit | 264e372b3a27747823b0ef5aea388750f45e4baa (patch) | |
tree | 574fca3fc597002dad9e7dc01cb5ede03d7e57d9 | |
parent | 2167f54e91fec095b5dd443432687e1d253033dd (diff) | |
download | elfutils-roland/relocate-cfi-tmp.tar.gz |
unfinished cfi relocatableroland/relocate-cfi-tmp
-rw-r--r-- | libdw/cfi.c | 26 | ||||
-rw-r--r-- | libdw/cfi.h | 17 | ||||
-rw-r--r-- | libdw/dwarf_getcfi.c | 2 | ||||
-rw-r--r-- | libdw/dwarf_getcfi_elf.c | 45 | ||||
-rw-r--r-- | libdw/encoded-value.h | 2 | ||||
-rw-r--r-- | libdw/fde.c | 115 | ||||
-rw-r--r-- | libdw/frame-cache.c | 7 |
7 files changed, 154 insertions, 60 deletions
diff --git a/libdw/cfi.c b/libdw/cfi.c index 7dacfc8b..9a67c378 100644 --- a/libdw/cfi.c +++ b/libdw/cfi.c @@ -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, diff --git a/libdw/cfi.h b/libdw/cfi.h index 357a8e6f..b1c07d36 100644 --- a/libdw/cfi.h +++ b/libdw/cfi.h @@ -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; diff --git a/libdw/dwarf_getcfi.c b/libdw/dwarf_getcfi.c index 91e179f3..ed983ed2 100644 --- a/libdw/dwarf_getcfi.c +++ b/libdw/dwarf_getcfi.c @@ -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; diff --git a/libdw/dwarf_getcfi_elf.c b/libdw/dwarf_getcfi_elf.c index 50015202..2c4ed5fa 100644 --- a/libdw/dwarf_getcfi_elf.c +++ b/libdw/dwarf_getcfi_elf.c @@ -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); } } diff --git a/libdw/encoded-value.h b/libdw/encoded-value.h index ee8a6f31..5c87a68a 100644 --- a/libdw/encoded-value.h +++ b/libdw/encoded-value.h @@ -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)) diff --git a/libdw/fde.c b/libdw/fde.c index 44a39ccd..bdb55fe5 100644 --- a/libdw/fde.c +++ b/libdw/fde.c @@ -57,34 +57,52 @@ #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; } diff --git a/libdw/frame-cache.c b/libdw/frame-cache.c index f4876638..37d49b32 100644 --- a/libdw/frame-cache.c +++ b/libdw/frame-cache.c @@ -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); } |