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
/* 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. */
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,
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;
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. */
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;
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;
#include <string.h>
#include <assert.h>
-#include "libdwP.h"
+#include "relocate.h"
#include "cfi.h"
#include "encoded-value.h"
#include <dwarf.h>
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)
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)
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);
}
}
#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))
#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);
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;
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;
}
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. */
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. */
}
/* 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;
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;
}
/* 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
#include "cfi.h"
#include <search.h>
#include <stdlib.h>
+#include <libebl.h>
static void
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);
}