810 lines
26 KiB
C
Vendored
810 lines
26 KiB
C
Vendored
/*
|
|
Copyright (c) 2019, David Anderson
|
|
All rights reserved.
|
|
cc
|
|
Redistribution and use in source and binary forms, with
|
|
or without modification, are permitted provided that the
|
|
following conditions are met:
|
|
|
|
Redistributions of source code must retain the above
|
|
copyright notice, this list of conditions and the following
|
|
disclaimer.
|
|
|
|
Redistributions in binary form must reproduce the above
|
|
copyright notice, this list of conditions and the following
|
|
disclaimer in the documentation and/or other materials
|
|
provided with the distribution.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
|
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/* This file reads the parts of an Elf
|
|
file appropriate to reading DWARF debugging data.
|
|
Overview:
|
|
_dwarf_elf_nlsetup() Does all elf setup.
|
|
calls _dwarf_elf_access_init()
|
|
calls _dwarf_elf_object_access_internals_init()
|
|
Creates internals record 'M',
|
|
dwarf_elf_object_access_internals_t
|
|
Sets flags/data in internals record
|
|
Loads elf object data needed later.
|
|
Sets methods struct to access elf object.
|
|
calls _dwarf_object_init_b() Creates Dwarf_Debug, independent
|
|
of any elf code.
|
|
Sets internals record into dbg.
|
|
----------------------
|
|
_dwarf_destruct_elf_nlaccess(). This frees
|
|
the elf internals record created in
|
|
_dwarf_elf_object_access_internals_init()
|
|
in case of errors during setup or when
|
|
dwarf_finish() is called. Works safely for
|
|
partially or fully set-up elf internals record.
|
|
|
|
Other than in _dwarf_elf_nlsetup() the elf code
|
|
knows nothing about Dwarf_Debug, and the rest of
|
|
libdwarf knows nothing about the content of the
|
|
object-type-specific (for Elf here)
|
|
internals record.
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <stddef.h> /* size_t */
|
|
#include <stdlib.h> /* free() malloc() */
|
|
#include <stdio.h> /* debug printf */
|
|
#include <string.h> /* memset() strdup() strncmp() */
|
|
|
|
#ifdef _WIN32
|
|
#ifdef HAVE_STDAFX_H
|
|
#include "stdafx.h"
|
|
#endif /* HAVE_STDAFX_H */
|
|
#include <io.h> /* close() off_t */
|
|
#elif defined HAVE_UNISTD_H
|
|
#include <unistd.h> /* close() off_t */
|
|
#endif /* _WIN32*/
|
|
|
|
#include "dwarf.h"
|
|
#include "libdwarf.h"
|
|
#include "libdwarf_private.h"
|
|
#include "dwarf_base_types.h"
|
|
#include "dwarf_opaque.h"
|
|
#include "dwarf_error.h" /* for _dwarf_error() declaration */
|
|
#include "dwarf_reading.h"
|
|
#include "dwarf_memcpy_swap.h"
|
|
#include "dwarf_object_read_common.h"
|
|
#include "dwarf_object_detector.h"
|
|
#include "dwarf_elfstructs.h"
|
|
#include "dwarf_elf_defines.h"
|
|
#include "dwarf_elf_rel_detector.h"
|
|
#include "dwarf_elfread.h"
|
|
|
|
#ifndef TYP
|
|
#define TYP(n,l) char (n)[(l)]
|
|
#endif /* TYPE */
|
|
|
|
#ifdef WORDS_BIGENDIAN
|
|
#define READ_UNALIGNED_SAFE(dbg,dest, source, length) \
|
|
do { \
|
|
Dwarf_Unsigned _ltmp = 0; \
|
|
(dbg)->de_copy_word( (((char *)(&_ltmp)) + \
|
|
sizeof(_ltmp) - length),(source),(length)); \
|
|
dest = _ltmp; \
|
|
} while (0)
|
|
|
|
#define WRITE_UNALIGNED_LOCAL(dbg,dest,source, srclength,len_out) \
|
|
{ \
|
|
(dbg)->de_copy_word((dest), \
|
|
((char *)(source)) +(srclength)-(len_out), \
|
|
(len_out)) ; \
|
|
}
|
|
#else /* LITTLE ENDIAN */
|
|
#define READ_UNALIGNED_SAFE(dbg,dest, source, srclength) \
|
|
do { \
|
|
Dwarf_Unsigned _ltmp = 0; \
|
|
dbg->de_copy_word( (char *)(&_ltmp), \
|
|
(source), (srclength)) ; \
|
|
dest = _ltmp; \
|
|
} while (0)
|
|
|
|
#define WRITE_UNALIGNED_LOCAL(dbg,dest,source, srclength,len_out) \
|
|
{ \
|
|
dbg->de_copy_word( (dest) , \
|
|
((char *)(source)) , \
|
|
(len_out)) ; \
|
|
}
|
|
#endif /* *-ENDIAN */
|
|
|
|
static int
|
|
_dwarf_elf_object_access_init(
|
|
int fd,
|
|
unsigned ftype,
|
|
unsigned endian,
|
|
unsigned offsetsize,
|
|
size_t filesize,
|
|
Dwarf_Obj_Access_Interface_a **binary_interface,
|
|
int *localerrnum);
|
|
|
|
static Dwarf_Small elf_get_nolibelf_byte_order (void *obj)
|
|
{
|
|
dwarf_elf_object_access_internals_t *elf =
|
|
(dwarf_elf_object_access_internals_t*)(obj);
|
|
return (Dwarf_Small)elf->f_endian;
|
|
}
|
|
|
|
static Dwarf_Small elf_get_nolibelf_length_size (void *obj)
|
|
{
|
|
dwarf_elf_object_access_internals_t *elf =
|
|
(dwarf_elf_object_access_internals_t*)(obj);
|
|
return elf->f_offsetsize/8;
|
|
}
|
|
|
|
static Dwarf_Small elf_get_nolibelf_pointer_size (void *obj)
|
|
{
|
|
dwarf_elf_object_access_internals_t *elf =
|
|
(dwarf_elf_object_access_internals_t*)(obj);
|
|
return elf->f_pointersize/8;
|
|
}
|
|
|
|
static Dwarf_Unsigned elf_get_nolibelf_file_size(void *obj)
|
|
{
|
|
dwarf_elf_object_access_internals_t *elf =
|
|
(dwarf_elf_object_access_internals_t*)(obj);
|
|
return elf->f_filesize;
|
|
}
|
|
|
|
static Dwarf_Unsigned elf_get_nolibelf_section_count (void *obj)
|
|
{
|
|
dwarf_elf_object_access_internals_t *elf =
|
|
(dwarf_elf_object_access_internals_t*)(obj);
|
|
return elf->f_loc_shdr.g_count;
|
|
}
|
|
|
|
static int elf_get_nolibelf_section_info(void *obj,
|
|
Dwarf_Unsigned section_index,
|
|
Dwarf_Obj_Access_Section_a *return_section,
|
|
int *error)
|
|
{
|
|
dwarf_elf_object_access_internals_t *elf =
|
|
(dwarf_elf_object_access_internals_t*)(obj);
|
|
|
|
(void)error;
|
|
if (section_index < elf->f_loc_shdr.g_count) {
|
|
struct generic_shdr *sp = 0;
|
|
|
|
sp = elf->f_shdr + section_index;
|
|
return_section->as_addr = sp->gh_addr;
|
|
return_section->as_type = sp->gh_type;
|
|
return_section->as_size = sp->gh_size;
|
|
return_section->as_name = sp->gh_namestring;
|
|
return_section->as_link = sp->gh_link;
|
|
return_section->as_info = sp->gh_info;
|
|
return_section->as_flags = sp->gh_flags;
|
|
return_section->as_entrysize = sp->gh_entsize;
|
|
return_section->as_offset = sp->gh_offset;
|
|
return DW_DLV_OK;
|
|
}
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
|
|
static int
|
|
elf_load_nolibelf_section (void *obj, Dwarf_Unsigned section_index,
|
|
Dwarf_Small **return_data, int *error)
|
|
{
|
|
/* Linux kernel read size limit 0x7ffff000,
|
|
Without any good reason, limit our reads
|
|
to a bit less. */
|
|
const Dwarf_Unsigned read_size_limit = 0x7ff00000;
|
|
Dwarf_Unsigned read_offset = 0;
|
|
Dwarf_Unsigned read_size = 0;
|
|
Dwarf_Unsigned remaining_bytes = 0;
|
|
Dwarf_Small * read_target = 0;
|
|
dwarf_elf_object_access_internals_t *elf =
|
|
(dwarf_elf_object_access_internals_t*)(obj);
|
|
|
|
if (0 < section_index &&
|
|
section_index < elf->f_loc_shdr.g_count) {
|
|
int res = 0;
|
|
|
|
struct generic_shdr *sp =
|
|
elf->f_shdr + section_index;
|
|
if (sp->gh_content) {
|
|
*return_data = (Dwarf_Small *)sp->gh_content;
|
|
return DW_DLV_OK;
|
|
}
|
|
if (!sp->gh_size) {
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
/* Guarding against bad values and
|
|
against overflow */
|
|
if (sp->gh_size > elf->f_filesize ||
|
|
sp->gh_offset > elf->f_filesize ||
|
|
(sp->gh_size + sp->gh_offset) >
|
|
elf->f_filesize) {
|
|
*error = DW_DLE_ELF_SECTION_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
sp->gh_content = malloc((size_t)sp->gh_size);
|
|
if (!sp->gh_content) {
|
|
*error = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
/* Linux has a 2GB limit on read size.
|
|
So break this into 2gb pieces. */
|
|
remaining_bytes = sp->gh_size;
|
|
read_size = remaining_bytes;
|
|
read_offset = sp->gh_offset;
|
|
read_target = (Dwarf_Small*)sp->gh_content;
|
|
for ( ; remaining_bytes > 0; read_size = remaining_bytes ) {
|
|
if (read_size > read_size_limit) {
|
|
read_size = read_size_limit;
|
|
}
|
|
res = RRMOA(elf->f_fd,
|
|
(void *)read_target, (off_t)read_offset,
|
|
(size_t)read_size,
|
|
(off_t)elf->f_filesize, error);
|
|
if (res != DW_DLV_OK) {
|
|
free(sp->gh_content);
|
|
sp->gh_content = 0;
|
|
return res;
|
|
}
|
|
remaining_bytes -= read_size;
|
|
read_offset += read_size;
|
|
read_target += read_size;
|
|
}
|
|
*return_data = (Dwarf_Small *)sp->gh_content;
|
|
return DW_DLV_OK;
|
|
}
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
|
|
#define MATCH_REL_SEC(i_,s_,r_) \
|
|
if ((i_) == (s_).dss_index) { \
|
|
*(r_) = &(s_); \
|
|
return DW_DLV_OK; \
|
|
}
|
|
|
|
static int
|
|
find_section_to_relocate(Dwarf_Debug dbg,Dwarf_Unsigned section_index,
|
|
struct Dwarf_Section_s **relocatablesec, int *error)
|
|
{
|
|
MATCH_REL_SEC(section_index,dbg->de_debug_info,relocatablesec);
|
|
MATCH_REL_SEC(section_index,dbg->de_debug_abbrev,relocatablesec);
|
|
MATCH_REL_SEC(section_index,dbg->de_debug_line,relocatablesec);
|
|
MATCH_REL_SEC(section_index,dbg->de_debug_loc,relocatablesec);
|
|
MATCH_REL_SEC(section_index,dbg->de_debug_aranges,relocatablesec);
|
|
MATCH_REL_SEC(section_index,dbg->de_debug_macinfo,relocatablesec);
|
|
MATCH_REL_SEC(section_index,dbg->de_debug_pubnames,
|
|
relocatablesec);
|
|
MATCH_REL_SEC(section_index,dbg->de_debug_names,
|
|
relocatablesec);
|
|
MATCH_REL_SEC(section_index,dbg->de_debug_ranges,relocatablesec);
|
|
MATCH_REL_SEC(section_index,dbg->de_debug_frame,
|
|
relocatablesec);
|
|
MATCH_REL_SEC(section_index,dbg->de_debug_frame_eh_gnu,
|
|
relocatablesec);
|
|
MATCH_REL_SEC(section_index,dbg->de_debug_pubtypes,
|
|
relocatablesec);
|
|
MATCH_REL_SEC(section_index,dbg->de_debug_funcnames,
|
|
relocatablesec);
|
|
MATCH_REL_SEC(section_index,dbg->de_debug_typenames,
|
|
relocatablesec);
|
|
MATCH_REL_SEC(section_index,dbg->de_debug_varnames,
|
|
relocatablesec);
|
|
MATCH_REL_SEC(section_index,dbg->de_debug_weaknames,
|
|
relocatablesec);
|
|
MATCH_REL_SEC(section_index,dbg->de_debug_types,relocatablesec);
|
|
MATCH_REL_SEC(section_index,dbg->de_debug_macro,relocatablesec);
|
|
MATCH_REL_SEC(section_index,dbg->de_debug_rnglists,
|
|
relocatablesec);
|
|
MATCH_REL_SEC(section_index,dbg->de_debug_loclists,
|
|
relocatablesec);
|
|
MATCH_REL_SEC(section_index,dbg->de_debug_aranges,
|
|
relocatablesec);
|
|
MATCH_REL_SEC(section_index,dbg->de_debug_sup,
|
|
relocatablesec);
|
|
MATCH_REL_SEC(section_index,dbg->de_debug_str_offsets,
|
|
relocatablesec);
|
|
MATCH_REL_SEC(section_index,dbg->de_debug_addr,relocatablesec);
|
|
MATCH_REL_SEC(section_index,dbg->de_debug_gnu_pubnames,
|
|
relocatablesec);
|
|
MATCH_REL_SEC(section_index,dbg->de_debug_gnu_pubtypes,
|
|
relocatablesec);
|
|
/* dbg-> de_debug_tu_index,reloctablesec); */
|
|
/* dbg-> de_debug_cu_index,reloctablesec); */
|
|
/* dbg-> de_debug_gdbindex,reloctablesec); */
|
|
/* dbg-> de_debug_str,syms); */
|
|
/* de_elf_symtab,syms); */
|
|
/* de_elf_strtab,syms); */
|
|
*error = DW_DLE_RELOC_SECTION_MISMATCH;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
/* Returns DW_DLV_OK if it works, else DW_DLV_ERROR.
|
|
The caller may decide to ignore the errors or report them. */
|
|
static int
|
|
update_entry(Dwarf_Debug dbg,
|
|
dwarf_elf_object_access_internals_t*obj,
|
|
struct generic_rela *rela,
|
|
Dwarf_Small *target_section,
|
|
Dwarf_Unsigned target_section_size,
|
|
int *error)
|
|
{
|
|
unsigned int type = 0;
|
|
unsigned int sym_idx = 0;
|
|
Dwarf_Unsigned offset = 0;
|
|
Dwarf_Signed addend = 0;
|
|
Dwarf_Half reloc_size = 0;
|
|
Dwarf_Half machine = (Dwarf_Half)obj->f_machine;
|
|
struct generic_symentry *symp = 0;
|
|
int is_rela = rela->gr_is_rela;
|
|
|
|
offset = rela->gr_offset;
|
|
addend = rela->gr_addend;
|
|
type = (unsigned int)rela->gr_type;
|
|
sym_idx = (unsigned int)rela->gr_sym;
|
|
if (sym_idx >= obj->f_loc_symtab.g_count) {
|
|
*error = DW_DLE_RELOC_SECTION_SYMBOL_INDEX_BAD;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
symp = obj->f_symtab + sym_idx;
|
|
if (offset >= target_section_size) {
|
|
/* If offset really big, any add will overflow.
|
|
So lets stop early if offset is corrupt. */
|
|
*error = DW_DLE_RELOC_INVALID;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
/* Determine relocation size */
|
|
if (_dwarf_is_32bit_abs_reloc(type, machine)) {
|
|
reloc_size = 4;
|
|
} else if (_dwarf_is_64bit_abs_reloc(type, machine)) {
|
|
reloc_size = 8;
|
|
} else if (!type) {
|
|
/* There is nothing to do. , this is the case such as
|
|
R_AARCH64_NONE and R_X86_64_NONE and the other machine
|
|
cases have it too. Most object files do not have
|
|
any relocation records of type R_<machine>_NONE. */
|
|
return DW_DLV_OK;
|
|
} else {
|
|
*error = DW_DLE_RELOC_SECTION_RELOC_TARGET_SIZE_UNKNOWN;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if ( (offset + reloc_size) < offset) {
|
|
/* Another check for overflow. */
|
|
*error = DW_DLE_RELOC_INVALID;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if ( (offset + reloc_size) > target_section_size) {
|
|
*error = DW_DLE_RELOC_INVALID;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
/* Assuming we do not need to do a READ_UNALIGNED here
|
|
at target_section + offset and add its value to
|
|
outval. Some ABIs say no read (for example MIPS),
|
|
but if some do then which ones? */
|
|
{ /* .rel. (addend is 0), or .rela. */
|
|
Dwarf_Small *targ = target_section+offset;
|
|
Dwarf_Unsigned presentval = 0;
|
|
Dwarf_Unsigned outval = 0;
|
|
|
|
if (!is_rela) {
|
|
READ_UNALIGNED_SAFE(dbg,presentval,
|
|
targ,(unsigned long)reloc_size);
|
|
}
|
|
/* There is no addend in .rel.
|
|
Normally presentval is correct
|
|
and st_value will be zero.
|
|
But a few compilers have
|
|
presentval zero and st_value set. */
|
|
outval = presentval + symp->gs_value + addend;
|
|
WRITE_UNALIGNED_LOCAL(dbg,targ,
|
|
&outval,sizeof(outval),(unsigned long)reloc_size);
|
|
}
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
/* Somewhat arbitrarily, we attempt to apply all the
|
|
relocations we can
|
|
and still notify the caller of at least one error if we found
|
|
any errors. */
|
|
|
|
static int
|
|
apply_rela_entries(
|
|
Dwarf_Debug dbg,
|
|
/* Section_index of the relocation section, .rela entries */
|
|
Dwarf_Unsigned r_section_index,
|
|
dwarf_elf_object_access_internals_t*obj,
|
|
/* relocatablesec is the .debug_info(etc) in Dwarf_Debug */
|
|
struct Dwarf_Section_s * relocatablesec,
|
|
int *error)
|
|
{
|
|
int return_res = DW_DLV_OK;
|
|
struct generic_shdr * rels_shp = 0;
|
|
Dwarf_Unsigned relcount;
|
|
Dwarf_Unsigned i = 0;
|
|
|
|
if (r_section_index >= obj->f_loc_shdr.g_count) {
|
|
*error = DW_DLE_SECTION_INDEX_BAD;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
rels_shp = obj->f_shdr + r_section_index;
|
|
relcount = rels_shp->gh_relcount;
|
|
if (obj->f_ehdr->ge_type != ET_REL) {
|
|
/* No relocations to do */
|
|
return DW_DLV_OK;
|
|
}
|
|
if (!relcount) {
|
|
/* Nothing to do. */
|
|
return DW_DLV_OK;
|
|
}
|
|
if (!rels_shp->gh_rels) {
|
|
/* something wrong. */
|
|
*error = DW_DLE_RELOCS_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
for (i = 0; i < relcount; i++) {
|
|
int res = update_entry(dbg,obj,
|
|
rels_shp->gh_rels+i,
|
|
relocatablesec->dss_data,
|
|
relocatablesec->dss_size,
|
|
error);
|
|
if (res != DW_DLV_OK) {
|
|
/* We try to keep going, not stop. */
|
|
return_res = res;
|
|
}
|
|
}
|
|
return return_res;
|
|
}
|
|
|
|
/* Find the section data in dbg and find all the relevant
|
|
sections. Then do relocations.
|
|
|
|
section_index is the index of a .debug_info (for example)
|
|
so we have to find the section(s) with relocations
|
|
targeting section_index.
|
|
Normally there is exactly one such, though.
|
|
*/
|
|
static int
|
|
elf_relocations_nolibelf(void* obj_in,
|
|
Dwarf_Unsigned section_index,
|
|
Dwarf_Debug dbg,
|
|
int* error)
|
|
{
|
|
int res = DW_DLV_ERROR;
|
|
dwarf_elf_object_access_internals_t*obj = 0;
|
|
struct Dwarf_Section_s * relocatablesec = 0;
|
|
Dwarf_Unsigned section_with_reloc_records = 0;
|
|
|
|
if (section_index == 0) {
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
obj = (dwarf_elf_object_access_internals_t*)obj_in;
|
|
|
|
/* The section to relocate must already be loaded into memory.
|
|
This just turns section_index into a pointer
|
|
to a de_debug_info or other section record in
|
|
Dwarf_Debug. */
|
|
res = find_section_to_relocate(dbg, section_index,
|
|
&relocatablesec, error);
|
|
if (res != DW_DLV_OK) {
|
|
return res;
|
|
}
|
|
/* Now we know the Dwarf_Section_s section
|
|
we need to relocate.
|
|
So lets find the rela section(s) targeting this.
|
|
*/
|
|
|
|
/* Sun and possibly others do not always set
|
|
sh_link in .debug_* sections.
|
|
So we cannot do full consistency checks.
|
|
FIXME: This approach assumes there is only one
|
|
relocation section applying to section section_index! */
|
|
section_with_reloc_records = relocatablesec->dss_reloc_index;
|
|
if (!section_with_reloc_records) {
|
|
/* Something is wrong. */
|
|
*error = DW_DLE_RELOC_SECTION_MISSING_INDEX;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
/* The relocations, if they exist, have been loaded. */
|
|
/* The symtab was already loaded. */
|
|
if (!obj->f_symtab || !obj->f_symtab_sect_strings) {
|
|
*error = DW_DLE_DEBUG_SYMTAB_ERR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (obj->f_symtab_sect_index != relocatablesec->dss_reloc_link) {
|
|
/* Something is wrong. */
|
|
*error = DW_DLE_RELOC_MISMATCH_RELOC_INDEX;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
/* We have all the data we need in memory. */
|
|
/* Now we apply the relocs in section_with_reloc_records to the
|
|
target, relocablesec */
|
|
res = apply_rela_entries(dbg,
|
|
section_with_reloc_records,
|
|
obj, relocatablesec,error);
|
|
return res;
|
|
}
|
|
|
|
void
|
|
_dwarf_destruct_elf_nlaccess(
|
|
struct Dwarf_Obj_Access_Interface_a_s *aip)
|
|
{
|
|
dwarf_elf_object_access_internals_t *ep = 0;
|
|
struct generic_shdr *shp = 0;
|
|
Dwarf_Unsigned shcount = 0;
|
|
Dwarf_Unsigned i = 0;
|
|
|
|
ep = (dwarf_elf_object_access_internals_t *)aip->ai_object;
|
|
free(ep->f_ehdr);
|
|
shp = ep->f_shdr;
|
|
shcount = ep->f_loc_shdr.g_count;
|
|
for (i = 0; i < shcount; ++i,++shp) {
|
|
free(shp->gh_rels);
|
|
shp->gh_rels = 0;
|
|
free(shp->gh_content);
|
|
shp->gh_content = 0;
|
|
free(shp->gh_sht_group_array);
|
|
shp->gh_sht_group_array = 0;
|
|
shp->gh_sht_group_array_count = 0;
|
|
}
|
|
free(ep->f_shdr);
|
|
ep->f_loc_shdr.g_count = 0;
|
|
free(ep->f_phdr);
|
|
free(ep->f_elf_shstrings_data);
|
|
free(ep->f_dynamic);
|
|
free(ep->f_symtab_sect_strings);
|
|
free(ep->f_dynsym_sect_strings);
|
|
free(ep->f_symtab);
|
|
free(ep->f_dynsym);
|
|
|
|
/* if TRUE close f_fd on destruct.*/
|
|
if (ep->f_destruct_close_fd) {
|
|
close(ep->f_fd);
|
|
}
|
|
ep->f_ident[0] = 'X';
|
|
free(ep->f_path);
|
|
free(ep);
|
|
free(aip);
|
|
}
|
|
|
|
int
|
|
_dwarf_elf_nlsetup(int fd,
|
|
char *true_path,
|
|
unsigned ftype,
|
|
unsigned endian,
|
|
unsigned offsetsize,
|
|
size_t filesize,
|
|
unsigned groupnumber,
|
|
Dwarf_Handler errhand,
|
|
Dwarf_Ptr errarg,
|
|
Dwarf_Debug *dbg,Dwarf_Error *error)
|
|
{
|
|
Dwarf_Obj_Access_Interface_a *binary_interface = 0;
|
|
dwarf_elf_object_access_internals_t *intfc = 0;
|
|
int res = DW_DLV_OK;
|
|
int localerrnum = 0;
|
|
|
|
res = _dwarf_elf_object_access_init(
|
|
fd,
|
|
ftype,endian,offsetsize,filesize,
|
|
&binary_interface,
|
|
&localerrnum);
|
|
if (res != DW_DLV_OK) {
|
|
if (res == DW_DLV_NO_ENTRY) {
|
|
return res;
|
|
}
|
|
_dwarf_error(NULL, error, localerrnum);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
/* allocates and initializes Dwarf_Debug,
|
|
generic code */
|
|
res = dwarf_object_init_b(binary_interface, errhand, errarg,
|
|
groupnumber, dbg, error);
|
|
if (res != DW_DLV_OK){
|
|
_dwarf_destruct_elf_nlaccess(binary_interface);
|
|
return res;
|
|
}
|
|
intfc = binary_interface->ai_object;
|
|
intfc->f_path = strdup(true_path);
|
|
return res;
|
|
}
|
|
|
|
/* dwarf_elf_access method table for use with non-libelf.
|
|
See also the methods table in dwarf_elf_access.c for libelf.
|
|
*/
|
|
static Dwarf_Obj_Access_Methods_a const elf_nlmethods = {
|
|
elf_get_nolibelf_section_info,
|
|
elf_get_nolibelf_byte_order,
|
|
elf_get_nolibelf_length_size,
|
|
elf_get_nolibelf_pointer_size,
|
|
elf_get_nolibelf_file_size,
|
|
elf_get_nolibelf_section_count,
|
|
elf_load_nolibelf_section,
|
|
elf_relocations_nolibelf
|
|
};
|
|
|
|
/* On any error this frees internals argument. */
|
|
static int
|
|
_dwarf_elf_object_access_internals_init(
|
|
dwarf_elf_object_access_internals_t * internals,
|
|
int fd,
|
|
unsigned ftype,
|
|
unsigned endian,
|
|
unsigned offsetsize,
|
|
size_t filesize,
|
|
int *errcode)
|
|
{
|
|
dwarf_elf_object_access_internals_t * intfc = internals;
|
|
Dwarf_Unsigned i = 0;
|
|
struct Dwarf_Obj_Access_Interface_a_s *localdoas;
|
|
int res = 0;
|
|
|
|
/* Must malloc as _dwarf_destruct_elf_access()
|
|
forces that due to other uses. */
|
|
localdoas = (struct Dwarf_Obj_Access_Interface_a_s *)
|
|
malloc(sizeof(struct Dwarf_Obj_Access_Interface_a_s));
|
|
if (!localdoas) {
|
|
free(internals);
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
memset(localdoas,0,sizeof(struct Dwarf_Obj_Access_Interface_a_s));
|
|
/* E is used with libelf. F with this elf reader. */
|
|
intfc->f_ident[0] = 'F';
|
|
intfc->f_ident[1] = '1';
|
|
intfc->f_fd = fd;
|
|
intfc->f_is_64bit = ((offsetsize==64)?TRUE:FALSE);
|
|
intfc->f_offsetsize = (Dwarf_Small)offsetsize;
|
|
intfc->f_pointersize = (Dwarf_Small)offsetsize;
|
|
intfc->f_filesize = filesize;
|
|
intfc->f_ftype = ftype;
|
|
intfc->f_destruct_close_fd = FALSE;
|
|
|
|
#ifdef WORDS_BIGENDIAN
|
|
if (endian == DW_END_little ) {
|
|
intfc->f_copy_word = _dwarf_memcpy_swap_bytes;
|
|
intfc->f_endian = DW_END_little;
|
|
} else {
|
|
intfc->f_copy_word = _dwarf_memcpy_noswap_bytes;
|
|
intfc->f_endian = DW_END_big;
|
|
}
|
|
#else /* LITTLE ENDIAN */
|
|
if (endian == DW_END_little ) {
|
|
intfc->f_copy_word = _dwarf_memcpy_noswap_bytes;
|
|
intfc->f_endian = DW_END_little;
|
|
} else {
|
|
intfc->f_copy_word = _dwarf_memcpy_swap_bytes;
|
|
intfc->f_endian = DW_END_big;
|
|
}
|
|
#endif /* LITTLE- BIG-ENDIAN */
|
|
/* The following sets f_machine. */
|
|
res = _dwarf_load_elf_header(intfc,errcode);
|
|
if (res != DW_DLV_OK) {
|
|
localdoas->ai_object = intfc;
|
|
localdoas->ai_methods = 0;
|
|
_dwarf_destruct_elf_nlaccess(localdoas);
|
|
localdoas = 0;
|
|
return res;
|
|
}
|
|
/* Not loading progheaders */
|
|
res = _dwarf_load_elf_sectheaders(intfc,errcode);
|
|
if (res != DW_DLV_OK) {
|
|
localdoas->ai_object = intfc;
|
|
localdoas->ai_methods = 0;
|
|
_dwarf_destruct_elf_nlaccess(localdoas);
|
|
localdoas = 0;
|
|
return res;
|
|
}
|
|
/* We are not looking at symbol strings for now. */
|
|
res = _dwarf_load_elf_symstr(intfc,errcode);
|
|
if (res == DW_DLV_ERROR) {
|
|
localdoas->ai_object = intfc;
|
|
localdoas->ai_methods = 0;
|
|
_dwarf_destruct_elf_nlaccess(localdoas);
|
|
localdoas = 0;
|
|
return res;
|
|
}
|
|
res = _dwarf_load_elf_symtab_symbols(intfc,errcode);
|
|
if (res == DW_DLV_ERROR) {
|
|
localdoas->ai_object = intfc;
|
|
localdoas->ai_methods = 0;
|
|
_dwarf_destruct_elf_nlaccess(localdoas);
|
|
localdoas = 0;
|
|
return res;
|
|
}
|
|
for ( i = 1; i < intfc->f_loc_shdr.g_count; ++i) {
|
|
struct generic_shdr *shp = 0;
|
|
Dwarf_Unsigned section_type = 0;
|
|
enum RelocRela localrel = RelocIsRela;
|
|
|
|
shp = intfc->f_shdr +i;
|
|
section_type = shp->gh_type;
|
|
if (!shp->gh_namestring) {
|
|
/* A serious error which we ignore here
|
|
as it will be caught elsewhere
|
|
if necessary. */
|
|
continue;
|
|
} else if (section_type == SHT_REL ||
|
|
(!strncmp(".rel.",shp->gh_namestring,5))) {
|
|
localrel = RelocIsRel;
|
|
} else if (section_type == SHT_RELA ||
|
|
(!strncmp(".rela.",shp->gh_namestring,6))) {
|
|
localrel = RelocIsRela;
|
|
} else {
|
|
continue;
|
|
}
|
|
/* ASSERT: local rel is either RelocIsRel or
|
|
RelocIsRela. Never any other value. */
|
|
/* Possibly we should check if the target section
|
|
is one we care about before loading rela
|
|
FIXME */
|
|
res = _dwarf_load_elf_relx(intfc,i,localrel,errcode);
|
|
if (res == DW_DLV_ERROR) {
|
|
localdoas->ai_object = intfc;
|
|
localdoas->ai_methods = 0;
|
|
_dwarf_destruct_elf_nlaccess(localdoas);
|
|
localdoas = 0;
|
|
return res;
|
|
}
|
|
}
|
|
free(localdoas);
|
|
localdoas = 0;
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
static int
|
|
_dwarf_elf_object_access_init(
|
|
int fd,
|
|
unsigned ftype,
|
|
unsigned endian,
|
|
unsigned offsetsize,
|
|
size_t filesize,
|
|
Dwarf_Obj_Access_Interface_a **binary_interface,
|
|
int *localerrnum)
|
|
{
|
|
|
|
int res = 0;
|
|
dwarf_elf_object_access_internals_t *internals = 0;
|
|
Dwarf_Obj_Access_Interface_a *intfc = 0;
|
|
|
|
internals = malloc(sizeof(dwarf_elf_object_access_internals_t));
|
|
if (!internals) {
|
|
*localerrnum = DW_DLE_ALLOC_FAIL;
|
|
/* Impossible case, we hope. Give up. */
|
|
return DW_DLV_ERROR;
|
|
}
|
|
memset(internals,0,sizeof(*internals));
|
|
res = _dwarf_elf_object_access_internals_init(internals,
|
|
fd,
|
|
ftype, endian, offsetsize, filesize,
|
|
localerrnum);
|
|
if (res != DW_DLV_OK){
|
|
return res;
|
|
}
|
|
|
|
intfc = malloc(sizeof(Dwarf_Obj_Access_Interface_a));
|
|
if (!intfc) {
|
|
/* Impossible case, we hope. Give up. */
|
|
free(internals);
|
|
*localerrnum = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
/* Initialize the interface struct */
|
|
intfc->ai_object = internals;
|
|
intfc->ai_methods = &elf_nlmethods;
|
|
*binary_interface = intfc;
|
|
return DW_DLV_OK;
|
|
}
|