2231 lines
66 KiB
C
Vendored
2231 lines
66 KiB
C
Vendored
/* Copyright 2018 David Anderson. All rights reserved.
|
|
|
|
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 reads elf headers and creates generic-elf
|
|
structures containing the Elf headers.
|
|
|
|
These two enums used for type safety in passing
|
|
values. See dwarf_elfread.h
|
|
|
|
enum RelocRela
|
|
enum RelocOffsetSize
|
|
|
|
dwarf_elfread.c
|
|
calls
|
|
_dwarf_load_elf_relx(intfc,i,...,enum RelocRela,errcode)
|
|
calls _dwarf_elf_load_a_relx_batch(ep,...enum RelocRela,
|
|
enum RelocOffsetSize,errcode)
|
|
which calls generic_rel_from_rela32(ep,gsh,relp,grel
|
|
or calls generic_rel_from_rela64(ep,gsh,relp,grel
|
|
or calls generic_rel_from_rel32(ep,gsh,relp,grel...
|
|
or calls generic_rel_from_rel64(ep,gsh,relp,grel...
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <stddef.h> /* size_t */
|
|
#include <stdlib.h> /* calloc() free() malloc() */
|
|
#include <string.h> /* memcpy() strcmp() strdup()
|
|
strlen() strncmp() */
|
|
|
|
/* Windows specific header files */
|
|
#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() */
|
|
#endif /* _WIN32 */
|
|
#ifdef HAVE_FCNTL_H
|
|
#include <fcntl.h> /* open() O_RDONLY */
|
|
#endif /* HAVE_FCNTL_H */
|
|
|
|
#include "dwarf.h"
|
|
#include "libdwarf.h"
|
|
#include "libdwarf_private.h"
|
|
#include "dwarf_base_types.h"
|
|
#include "dwarf_opaque.h"
|
|
#include "dwarf_memcpy_swap.h"
|
|
#include "dwarf_reading.h"
|
|
#include "dwarf_elf_defines.h"
|
|
#include "dwarf_elfstructs.h"
|
|
#include "dwarf_elfread.h"
|
|
#include "dwarf_object_detector.h"
|
|
#include "dwarf_object_read_common.h"
|
|
#include "dwarf_util.h"
|
|
#include "dwarf_secname_ck.h"
|
|
|
|
#ifndef O_BINARY
|
|
#define O_BINARY 0
|
|
#endif /* O_BINARY */
|
|
#ifndef O_CLOEXEC
|
|
#define O_CLOEXEC 0
|
|
#endif /* O_CLOEXEC */
|
|
|
|
#if 0
|
|
/* One example of calling this.
|
|
place just before DW_DLE_SECTION_SIZE_OR_OFFSET_LARGE
|
|
dumpsizes(__LINE__,strsectlength,strpsh->gh_offset,
|
|
ep->f_filesize);
|
|
*/
|
|
static void
|
|
dumpsizes(int line,Dwarf_Unsigned s,
|
|
Dwarf_Unsigned o,
|
|
Dwarf_Unsigned fsz)
|
|
{
|
|
Dwarf_Unsigned tlen = s + o;
|
|
printf("Size Error DEBUGONLY sz 0x%llx off 0x%llx fsx 0x%llx "
|
|
"sum 0x%llx line %d \n",
|
|
s,o,fsz,tlen,line);
|
|
}
|
|
#endif /*0*/
|
|
|
|
int nibblecounts[16] = {
|
|
0,1,1,2,
|
|
1,2,2,3,
|
|
2,2,2,3,
|
|
2,3,3,4
|
|
};
|
|
|
|
static int
|
|
getbitsoncount(Dwarf_Unsigned v_in)
|
|
{
|
|
int bitscount = 0;
|
|
Dwarf_Unsigned v = v_in;
|
|
|
|
while (v) {
|
|
unsigned int nibble = v & 0xf;
|
|
bitscount += nibblecounts[nibble];
|
|
v >>= 4;
|
|
}
|
|
return bitscount;
|
|
}
|
|
|
|
static int
|
|
_dwarf_load_elf_section_is_dwarf(const char *sname,
|
|
int *is_rela,int *is_rel)
|
|
{
|
|
*is_rel = FALSE;
|
|
*is_rela = FALSE;
|
|
if (_dwarf_ignorethissection(sname)) {
|
|
return FALSE;
|
|
}
|
|
if (!strncmp(sname,".rel",4)) {
|
|
if (!strncmp(sname,".rela.",6)) {
|
|
*is_rela = TRUE;
|
|
return TRUE;
|
|
}
|
|
if (!strncmp(sname,".rel.",5)) {
|
|
*is_rela = TRUE;
|
|
return TRUE;
|
|
}
|
|
/* Else something is goofy/Impossible */
|
|
return FALSE;
|
|
}
|
|
if (!strncmp(sname,".debug_",7)) {
|
|
return TRUE;
|
|
}
|
|
if (!strncmp(sname,".zdebug_",8)) {
|
|
return TRUE;
|
|
}
|
|
if (!strcmp(sname,".eh_frame")) {
|
|
return TRUE;
|
|
}
|
|
if (!strncmp(sname,".gdb_index",10)) {
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static int
|
|
is_empty_section(Dwarf_Unsigned type)
|
|
{
|
|
if (type == SHT_NOBITS) {
|
|
return TRUE;
|
|
}
|
|
if (type == SHT_NULL) {
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static int
|
|
generic_ehdr_from_32(dwarf_elf_object_access_internals_t *ep,
|
|
struct generic_ehdr *ehdr, dw_elf32_ehdr *e,
|
|
int *errcode)
|
|
{
|
|
int i = 0;
|
|
|
|
for (i = 0; i < EI_NIDENT; ++i) {
|
|
ehdr->ge_ident[i] = e->e_ident[i];
|
|
}
|
|
ASNAR(ep->f_copy_word,ehdr->ge_type,e->e_type);
|
|
ASNAR(ep->f_copy_word,ehdr->ge_machine,e->e_machine);
|
|
ASNAR(ep->f_copy_word,ehdr->ge_version,e->e_version);
|
|
ASNAR(ep->f_copy_word,ehdr->ge_entry,e->e_entry);
|
|
ASNAR(ep->f_copy_word,ehdr->ge_phoff,e->e_phoff);
|
|
ASNAR(ep->f_copy_word,ehdr->ge_shoff,e->e_shoff);
|
|
ASNAR(ep->f_copy_word,ehdr->ge_flags,e->e_flags);
|
|
ASNAR(ep->f_copy_word,ehdr->ge_ehsize,e->e_ehsize);
|
|
ASNAR(ep->f_copy_word,ehdr->ge_phentsize,e->e_phentsize);
|
|
ASNAR(ep->f_copy_word,ehdr->ge_phnum,e->e_phnum);
|
|
ASNAR(ep->f_copy_word,ehdr->ge_shentsize,e->e_shentsize);
|
|
ASNAR(ep->f_copy_word,ehdr->ge_shnum,e->e_shnum);
|
|
ASNAR(ep->f_copy_word,ehdr->ge_shstrndx,e->e_shstrndx);
|
|
if (ehdr->ge_shoff < sizeof(dw_elf32_ehdr)) {
|
|
/* zero or offset is inside the header! */
|
|
*errcode = DW_DLE_TOO_FEW_SECTIONS;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (ehdr->ge_shstrndx == SHN_XINDEX) {
|
|
ehdr->ge_strndx_extended = TRUE;
|
|
} else {
|
|
ehdr->ge_strndx_in_strndx = TRUE;
|
|
if (ehdr->ge_shstrndx < 1) {
|
|
*errcode = DW_DLE_NO_SECT_STRINGS;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
}
|
|
/* If !ge_strndx_extended && !ehdr->ge_shnum
|
|
this is a very unusual case. */
|
|
if (!ehdr->ge_shnum) {
|
|
ehdr->ge_shnum_extended = TRUE;
|
|
} else {
|
|
ehdr->ge_shnum_in_shnum = TRUE;
|
|
if (ehdr->ge_shnum < 3) {
|
|
*errcode = DW_DLE_TOO_FEW_SECTIONS;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
}
|
|
if (ehdr->ge_shnum_in_shnum &&
|
|
ehdr->ge_strndx_in_strndx &&
|
|
(ehdr->ge_shstrndx >= ehdr->ge_shnum)) {
|
|
*errcode = DW_DLE_NO_SECT_STRINGS;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
ep->f_machine = (unsigned int)ehdr->ge_machine;
|
|
ep->f_ehdr = ehdr;
|
|
ep->f_loc_ehdr.g_name = "Elf File Header";
|
|
ep->f_loc_ehdr.g_offset = 0;
|
|
ep->f_loc_ehdr.g_count = 1;
|
|
ep->f_loc_ehdr.g_entrysize = sizeof(dw_elf32_ehdr);
|
|
ep->f_loc_ehdr.g_totalsize = sizeof(dw_elf32_ehdr);
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
static int
|
|
generic_ehdr_from_64(dwarf_elf_object_access_internals_t* ep,
|
|
struct generic_ehdr *ehdr, dw_elf64_ehdr *e,
|
|
int *errcode)
|
|
{
|
|
int i = 0;
|
|
|
|
for (i = 0; i < EI_NIDENT; ++i) {
|
|
ehdr->ge_ident[i] = e->e_ident[i];
|
|
}
|
|
ASNAR(ep->f_copy_word,ehdr->ge_type,e->e_type);
|
|
ASNAR(ep->f_copy_word,ehdr->ge_machine,e->e_machine);
|
|
ASNAR(ep->f_copy_word,ehdr->ge_version,e->e_version);
|
|
ASNAR(ep->f_copy_word,ehdr->ge_entry,e->e_entry);
|
|
ASNAR(ep->f_copy_word,ehdr->ge_phoff,e->e_phoff);
|
|
ASNAR(ep->f_copy_word,ehdr->ge_shoff,e->e_shoff);
|
|
ASNAR(ep->f_copy_word,ehdr->ge_flags,e->e_flags);
|
|
ASNAR(ep->f_copy_word,ehdr->ge_ehsize,e->e_ehsize);
|
|
ASNAR(ep->f_copy_word,ehdr->ge_phentsize,e->e_phentsize);
|
|
ASNAR(ep->f_copy_word,ehdr->ge_phnum,e->e_phnum);
|
|
ASNAR(ep->f_copy_word,ehdr->ge_shentsize,e->e_shentsize);
|
|
ASNAR(ep->f_copy_word,ehdr->ge_shnum,e->e_shnum);
|
|
ASNAR(ep->f_copy_word,ehdr->ge_shstrndx,e->e_shstrndx);
|
|
if (ehdr->ge_shoff < sizeof(dw_elf64_ehdr)) {
|
|
/* zero or offset is inside the header! */
|
|
*errcode = DW_DLE_TOO_FEW_SECTIONS;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (ehdr->ge_shstrndx == SHN_XINDEX) {
|
|
ehdr->ge_strndx_extended = TRUE;
|
|
} else {
|
|
ehdr->ge_strndx_in_strndx = TRUE;
|
|
if (ehdr->ge_shstrndx < 1) {
|
|
*errcode = DW_DLE_NO_SECT_STRINGS;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
}
|
|
if (!ehdr->ge_shnum) {
|
|
ehdr->ge_shnum_extended = TRUE;
|
|
} else {
|
|
ehdr->ge_shnum_in_shnum = TRUE;
|
|
if (ehdr->ge_shnum < 3) {
|
|
*errcode = DW_DLE_TOO_FEW_SECTIONS;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
}
|
|
if (ehdr->ge_shnum_in_shnum &&
|
|
ehdr->ge_strndx_in_strndx &&
|
|
(ehdr->ge_shstrndx >= ehdr->ge_shnum)) {
|
|
*errcode = DW_DLE_NO_SECT_STRINGS;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
ep->f_machine = (unsigned int)ehdr->ge_machine;
|
|
ep->f_ehdr = ehdr;
|
|
ep->f_loc_ehdr.g_name = "Elf File Header";
|
|
ep->f_loc_ehdr.g_offset = 0;
|
|
ep->f_loc_ehdr.g_count = 1;
|
|
ep->f_loc_ehdr.g_entrysize = sizeof(dw_elf64_ehdr);
|
|
ep->f_loc_ehdr.g_totalsize = sizeof(dw_elf64_ehdr);
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
#if 0 /* not used */
|
|
static int
|
|
generic_phdr_from_phdr32(dwarf_elf_object_access_internals_t* ep,
|
|
struct generic_phdr **phdr_out,
|
|
Dwarf_Unsigned * count_out,
|
|
Dwarf_Unsigned offset,
|
|
Dwarf_Unsigned entsize,
|
|
Dwarf_Unsigned count,
|
|
int *errcode)
|
|
{
|
|
dw_elf32_phdr *pph =0;
|
|
dw_elf32_phdr *orig_pph =0;
|
|
struct generic_phdr *gphdr =0;
|
|
struct generic_phdr *orig_gphdr =0;
|
|
Dwarf_Unsigned i = 0;
|
|
int res = 0;
|
|
|
|
*count_out = 0;
|
|
pph = (dw_elf32_phdr *)calloc(count , entsize);
|
|
if (pph == 0) {
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
gphdr = (struct generic_phdr *)calloc(count,sizeof(*gphdr));
|
|
if (gphdr == 0) {
|
|
free(pph);
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
orig_pph = pph;
|
|
orig_gphdr = gphdr;
|
|
res = RRMOA(ep->f_fd,pph,offset,count*entsize,
|
|
ep->f_filesize,errcode);
|
|
if (res != DW_DLV_OK) {
|
|
free(pph);
|
|
free(gphdr);
|
|
return res;
|
|
}
|
|
for ( i = 0; i < count;
|
|
++i, pph++,gphdr++) {
|
|
ASNAR(ep->f_copy_word,gphdr->gp_type,pph->p_type);
|
|
ASNAR(ep->f_copy_word,gphdr->gp_offset,pph->p_offset);
|
|
ASNAR(ep->f_copy_word,gphdr->gp_vaddr,pph->p_vaddr);
|
|
ASNAR(ep->f_copy_word,gphdr->gp_paddr,pph->p_paddr);
|
|
ASNAR(ep->f_copy_word,gphdr->gp_filesz,pph->p_filesz);
|
|
ASNAR(ep->f_copy_word,gphdr->gp_memsz,pph->p_memsz);
|
|
ASNAR(ep->f_copy_word,gphdr->gp_flags,pph->p_flags);
|
|
ASNAR(ep->f_copy_word,gphdr->gp_align,pph->p_align);
|
|
}
|
|
free(orig_pph);
|
|
*phdr_out = orig_gphdr;
|
|
*count_out = count;
|
|
ep->f_phdr = orig_gphdr;
|
|
ep->f_loc_phdr.g_name = "Program Header";
|
|
ep->f_loc_phdr.g_offset = offset;
|
|
ep->f_loc_phdr.g_count = count;
|
|
ep->f_loc_phdr.g_entrysize = sizeof(dw_elf32_phdr);
|
|
ep->f_loc_phdr.g_totalsize = sizeof(dw_elf32_phdr)*count;
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
static int
|
|
generic_phdr_from_phdr64(dwarf_elf_object_access_internals_t* ep,
|
|
struct generic_phdr **phdr_out,
|
|
Dwarf_Unsigned * count_out,
|
|
Dwarf_Unsigned offset,
|
|
Dwarf_Unsigned entsize,
|
|
Dwarf_Unsigned count,
|
|
int *errcode)
|
|
{
|
|
dw_elf64_phdr *pph =0;
|
|
dw_elf64_phdr *orig_pph =0;
|
|
struct generic_phdr *gphdr =0;
|
|
struct generic_phdr *orig_gphdr =0;
|
|
int res = 0;
|
|
Dwarf_Unsigned i = 0;
|
|
|
|
*count_out = 0;
|
|
pph = (dw_elf64_phdr *)calloc(count , entsize);
|
|
if (pph == 0) {
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
gphdr = (struct generic_phdr *)calloc(count,sizeof(*gphdr));
|
|
if (gphdr == 0) {
|
|
free(pph);
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
orig_pph = pph;
|
|
orig_gphdr = gphdr;
|
|
res = RRMOA(ep->f_fd,pph,offset,count*entsize,
|
|
ep->f_filesize,errcode);
|
|
if (res != DW_DLV_OK) {
|
|
free(pph);
|
|
free(gphdr);
|
|
return res;
|
|
}
|
|
for ( i = 0; i < count;
|
|
++i, pph++,gphdr++) {
|
|
ASNAR(ep->f_copy_word,gphdr->gp_type,pph->p_type);
|
|
ASNAR(ep->f_copy_word,gphdr->gp_offset,pph->p_offset);
|
|
ASNAR(ep->f_copy_word,gphdr->gp_vaddr,pph->p_vaddr);
|
|
ASNAR(ep->f_copy_word,gphdr->gp_paddr,pph->p_paddr);
|
|
ASNAR(ep->f_copy_word,gphdr->gp_filesz,pph->p_filesz);
|
|
ASNAR(ep->f_copy_word,gphdr->gp_memsz,pph->p_memsz);
|
|
ASNAR(ep->f_copy_word,gphdr->gp_flags,pph->p_flags);
|
|
ASNAR(ep->f_copy_word,gphdr->gp_align,pph->p_align);
|
|
}
|
|
free(orig_pph);
|
|
*phdr_out = orig_gphdr;
|
|
*count_out = count;
|
|
ep->f_phdr = orig_gphdr;
|
|
ep->f_loc_phdr.g_name = "Program Header";
|
|
ep->f_loc_phdr.g_offset = offset;
|
|
ep->f_loc_phdr.g_count = count;
|
|
ep->f_loc_phdr.g_entrysize = sizeof(dw_elf64_phdr);
|
|
ep->f_loc_phdr.g_totalsize = sizeof(dw_elf64_phdr)*count;
|
|
return DW_DLV_OK;
|
|
}
|
|
#endif /*0*/
|
|
|
|
static void
|
|
copysection32(
|
|
dwarf_elf_object_access_internals_t *ep,
|
|
struct generic_shdr *gshdr,
|
|
dw_elf32_shdr *psh)
|
|
{
|
|
ASNAR(ep->f_copy_word,gshdr->gh_name,psh->sh_name);
|
|
ASNAR(ep->f_copy_word,gshdr->gh_type,psh->sh_type);
|
|
ASNAR(ep->f_copy_word,gshdr->gh_flags,psh->sh_flags);
|
|
ASNAR(ep->f_copy_word,gshdr->gh_addr,psh->sh_addr);
|
|
ASNAR(ep->f_copy_word,gshdr->gh_offset,psh->sh_offset);
|
|
ASNAR(ep->f_copy_word,gshdr->gh_size,psh->sh_size);
|
|
ASNAR(ep->f_copy_word,gshdr->gh_link,psh->sh_link);
|
|
ASNAR(ep->f_copy_word,gshdr->gh_info,psh->sh_info);
|
|
ASNAR(ep->f_copy_word,gshdr->gh_addralign,psh->sh_addralign);
|
|
ASNAR(ep->f_copy_word,gshdr->gh_entsize,psh->sh_entsize);
|
|
}
|
|
|
|
static int
|
|
generic_shdr_from_shdr32(dwarf_elf_object_access_internals_t *ep,
|
|
Dwarf_Unsigned * count_out,
|
|
Dwarf_Unsigned offset,
|
|
Dwarf_Unsigned entsize,
|
|
Dwarf_Unsigned count,
|
|
int *errcode)
|
|
{
|
|
dw_elf32_shdr *psh =0;
|
|
dw_elf32_shdr *orig_psh =0;
|
|
struct generic_ehdr *ehdr = ep->f_ehdr;
|
|
struct generic_shdr *gshdr =0;
|
|
struct generic_shdr *orig_gshdr =0;
|
|
Dwarf_Unsigned i = 0;
|
|
int res = 0;
|
|
|
|
*count_out = 0;
|
|
psh = (dw_elf32_shdr *)calloc(count , entsize);
|
|
if (!psh) {
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
gshdr = (struct generic_shdr *)calloc(count,sizeof(*gshdr));
|
|
if (!gshdr) {
|
|
free(psh);
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
orig_psh = psh;
|
|
orig_gshdr = gshdr;
|
|
res = RRMOA(ep->f_fd,psh,offset,count*entsize,
|
|
ep->f_filesize,errcode);
|
|
if (res != DW_DLV_OK) {
|
|
free(orig_psh);
|
|
free(orig_gshdr);
|
|
return res;
|
|
}
|
|
for (i = 0; i < count;
|
|
++i, psh++,gshdr++) {
|
|
int isempty = FALSE;
|
|
int bitsoncount = 0;
|
|
|
|
gshdr->gh_secnum = i;
|
|
copysection32(ep,gshdr,psh);
|
|
#if 1
|
|
if (gshdr->gh_size >= ep->f_filesize &&
|
|
gshdr->gh_type != SHT_NOBITS) {
|
|
free(orig_psh);
|
|
free(orig_gshdr);
|
|
*errcode = DW_DLE_SECTION_SIZE_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
#endif /* 0 */
|
|
isempty = is_empty_section(gshdr->gh_type);
|
|
if (i == 0) {
|
|
Dwarf_Unsigned shnum = 0;
|
|
Dwarf_Unsigned shstrx = 0;
|
|
|
|
/* Catch errors asap */
|
|
if (!ehdr->ge_shnum_extended) {
|
|
shnum = gshdr->gh_size;
|
|
}
|
|
if (!ehdr->ge_strndx_extended) {
|
|
shstrx = gshdr->gh_link;
|
|
}
|
|
/* We require that section zero be 'empty'
|
|
per the Elf ABI.
|
|
gh_link and gh_size are sometimes used
|
|
with the elf header, so we do not check
|
|
them here. */
|
|
if (!isempty || gshdr->gh_name || gshdr->gh_flags ||
|
|
shnum || shstrx ||
|
|
gshdr->gh_addr ||
|
|
gshdr->gh_info) {
|
|
free(orig_psh);
|
|
free(orig_gshdr);
|
|
*errcode = DW_DLE_IMPROPER_SECTION_ZERO;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
}
|
|
bitsoncount = getbitsoncount(gshdr->gh_flags);
|
|
if (bitsoncount > 8) {
|
|
free(orig_psh);
|
|
free(orig_gshdr);
|
|
*errcode = DW_DLE_BAD_SECTION_FLAGS;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
if (gshdr->gh_type == SHT_REL || gshdr->gh_type == SHT_RELA){
|
|
gshdr->gh_reloc_target_secnum = gshdr->gh_info;
|
|
}
|
|
}
|
|
free(orig_psh);
|
|
*count_out = count;
|
|
ep->f_shdr = orig_gshdr;
|
|
ep->f_loc_shdr.g_name = "Section Header";
|
|
ep->f_loc_shdr.g_count = count;
|
|
ep->f_loc_shdr.g_offset = offset;
|
|
ep->f_loc_shdr.g_entrysize = sizeof(dw_elf32_shdr);
|
|
ep->f_loc_shdr.g_totalsize = sizeof(dw_elf32_shdr)*count;
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
static void
|
|
copysection64(
|
|
dwarf_elf_object_access_internals_t *ep,
|
|
struct generic_shdr *gshdr,
|
|
dw_elf64_shdr *psh)
|
|
{
|
|
ASNAR(ep->f_copy_word,gshdr->gh_name,psh->sh_name);
|
|
ASNAR(ep->f_copy_word,gshdr->gh_type,psh->sh_type);
|
|
ASNAR(ep->f_copy_word,gshdr->gh_flags,psh->sh_flags);
|
|
ASNAR(ep->f_copy_word,gshdr->gh_addr,psh->sh_addr);
|
|
ASNAR(ep->f_copy_word,gshdr->gh_offset,psh->sh_offset);
|
|
ASNAR(ep->f_copy_word,gshdr->gh_size,psh->sh_size);
|
|
ASNAR(ep->f_copy_word,gshdr->gh_link,psh->sh_link);
|
|
ASNAR(ep->f_copy_word,gshdr->gh_info,psh->sh_info);
|
|
ASNAR(ep->f_copy_word,gshdr->gh_addralign,psh->sh_addralign);
|
|
ASNAR(ep->f_copy_word,gshdr->gh_entsize,psh->sh_entsize);
|
|
}
|
|
|
|
static int
|
|
generic_shdr_from_shdr64(dwarf_elf_object_access_internals_t *ep,
|
|
Dwarf_Unsigned * count_out,
|
|
Dwarf_Unsigned offset,
|
|
Dwarf_Unsigned entsize,
|
|
Dwarf_Unsigned count,
|
|
int *errcode)
|
|
{
|
|
dw_elf64_shdr *psh =0;
|
|
dw_elf64_shdr *orig_psh =0;
|
|
struct generic_shdr *gshdr =0;
|
|
struct generic_shdr *orig_gshdr =0;
|
|
struct generic_ehdr *ehdr = ep->f_ehdr;
|
|
Dwarf_Unsigned i = 0;
|
|
int res = 0;
|
|
|
|
*count_out = 0;
|
|
psh = (dw_elf64_shdr *)calloc(count , entsize);
|
|
if (!psh) {
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
gshdr = (struct generic_shdr *)calloc(count,sizeof(*gshdr));
|
|
if (gshdr == 0) {
|
|
free(psh);
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
orig_psh = psh;
|
|
orig_gshdr = gshdr;
|
|
res = RRMOA(ep->f_fd,psh,offset,count*entsize,
|
|
ep->f_filesize,errcode);
|
|
if (res != DW_DLV_OK) {
|
|
free(orig_psh);
|
|
free(orig_gshdr);
|
|
return res;
|
|
}
|
|
for ( i = 0; i < count;
|
|
++i, psh++,gshdr++) {
|
|
int bitsoncount = 0;
|
|
int isempty = FALSE;
|
|
|
|
gshdr->gh_secnum = i;
|
|
copysection64(ep,gshdr,psh);
|
|
if (gshdr->gh_size >= ep->f_filesize &&
|
|
gshdr->gh_type != SHT_NOBITS) {
|
|
free(orig_psh);
|
|
free(orig_gshdr);
|
|
*errcode = DW_DLE_SECTION_SIZE_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
isempty = is_empty_section(gshdr->gh_type);
|
|
if (i == 0) {
|
|
Dwarf_Unsigned shnum = 0;
|
|
Dwarf_Unsigned shstrx = 0;
|
|
|
|
/* Catch errors asap */
|
|
if (!ehdr->ge_shnum_extended) {
|
|
shnum = gshdr->gh_size;
|
|
}
|
|
if (!ehdr->ge_strndx_extended) {
|
|
shstrx = gshdr->gh_link;
|
|
}
|
|
/* We require that section zero be 'empty'
|
|
per the Elf ABI.
|
|
But gh_link and gh_size might be used for
|
|
ge_shstrndx and ge_shnum, respectively*/
|
|
if (!isempty || gshdr->gh_name || gshdr->gh_flags ||
|
|
shnum || shstrx ||
|
|
gshdr->gh_addr ||
|
|
gshdr->gh_info) {
|
|
free(orig_psh);
|
|
free(orig_gshdr);
|
|
*errcode = DW_DLE_IMPROPER_SECTION_ZERO;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
}
|
|
bitsoncount = getbitsoncount(gshdr->gh_flags);
|
|
if (bitsoncount > 8) {
|
|
free(orig_psh);
|
|
free(orig_gshdr);
|
|
*errcode = DW_DLE_BAD_SECTION_FLAGS;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
if (gshdr->gh_type == SHT_REL ||
|
|
gshdr->gh_type == SHT_RELA){
|
|
gshdr->gh_reloc_target_secnum = gshdr->gh_info;
|
|
}
|
|
}
|
|
free(orig_psh);
|
|
*count_out = count;
|
|
ep->f_shdr = orig_gshdr;
|
|
ep->f_loc_shdr.g_name = "Section Header";
|
|
ep->f_loc_shdr.g_count = count;
|
|
ep->f_loc_shdr.g_offset = offset;
|
|
ep->f_loc_shdr.g_entrysize = sizeof(dw_elf64_shdr);
|
|
ep->f_loc_shdr.g_totalsize = sizeof(dw_elf64_shdr)*count;
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
static int
|
|
_dwarf_generic_elf_load_symbols32(
|
|
dwarf_elf_object_access_internals_t *ep,
|
|
struct generic_symentry **gsym_out,
|
|
Dwarf_Unsigned offset,Dwarf_Unsigned size,
|
|
Dwarf_Unsigned *count_out,int *errcode)
|
|
{
|
|
Dwarf_Unsigned ecount = 0;
|
|
Dwarf_Unsigned size2 = 0;
|
|
Dwarf_Unsigned i = 0;
|
|
dw_elf32_sym *psym = 0;
|
|
dw_elf32_sym *orig_psym = 0;
|
|
struct generic_symentry * gsym = 0;
|
|
struct generic_symentry * orig_gsym = 0;
|
|
int res = 0;
|
|
|
|
ecount = (long)(size/sizeof(dw_elf32_sym));
|
|
size2 = ecount * sizeof(dw_elf32_sym);
|
|
if (size != size2) {
|
|
*errcode = DW_DLE_SYMBOL_SECTION_SIZE_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (size >= ep->f_filesize ) {
|
|
*errcode = DW_DLE_SYMBOL_SECTION_SIZE_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
psym = calloc(ecount,sizeof(dw_elf32_sym));
|
|
if (!psym) {
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
gsym = calloc(ecount,sizeof(struct generic_symentry));
|
|
if (!gsym) {
|
|
free(psym);
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
res = RRMOA(ep->f_fd,psym,offset,size,
|
|
ep->f_filesize,errcode);
|
|
if (res!= DW_DLV_OK) {
|
|
free(psym);
|
|
free(gsym);
|
|
return res;
|
|
}
|
|
orig_psym = psym;
|
|
orig_gsym = gsym;
|
|
for ( i = 0; i < ecount; ++i,++psym,++gsym) {
|
|
Dwarf_Unsigned bind = 0;
|
|
Dwarf_Unsigned type = 0;
|
|
|
|
ASNAR(ep->f_copy_word,gsym->gs_name,psym->st_name);
|
|
ASNAR(ep->f_copy_word,gsym->gs_value,psym->st_value);
|
|
ASNAR(ep->f_copy_word,gsym->gs_size,psym->st_size);
|
|
ASNAR(ep->f_copy_word,gsym->gs_info,psym->st_info);
|
|
ASNAR(ep->f_copy_word,gsym->gs_other,psym->st_other);
|
|
ASNAR(ep->f_copy_word,gsym->gs_shndx,psym->st_shndx);
|
|
bind = gsym->gs_info >> 4;
|
|
type = gsym->gs_info & 0xf;
|
|
gsym->gs_bind = bind;
|
|
gsym->gs_type = type;
|
|
}
|
|
*count_out = ecount;
|
|
*gsym_out = orig_gsym;
|
|
free(orig_psym);
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
static int
|
|
_dwarf_generic_elf_load_symbols64(
|
|
dwarf_elf_object_access_internals_t *ep,
|
|
struct generic_symentry **gsym_out,
|
|
Dwarf_Unsigned offset,Dwarf_Unsigned size,
|
|
Dwarf_Unsigned *count_out,int *errcode)
|
|
{
|
|
Dwarf_Unsigned ecount = 0;
|
|
Dwarf_Unsigned size2 = 0;
|
|
Dwarf_Unsigned i = 0;
|
|
dw_elf64_sym *psym = 0;
|
|
dw_elf64_sym *orig_psym = 0;
|
|
struct generic_symentry * gsym = 0;
|
|
struct generic_symentry * orig_gsym = 0;
|
|
int res = 0;
|
|
|
|
ecount = (long)(size/sizeof(dw_elf64_sym));
|
|
size2 = ecount * sizeof(dw_elf64_sym);
|
|
if (size != size2) {
|
|
*errcode = DW_DLE_SYMBOL_SECTION_SIZE_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (size >= ep->f_filesize ) {
|
|
*errcode = DW_DLE_SYMBOL_SECTION_SIZE_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
psym = calloc(ecount,sizeof(dw_elf64_sym));
|
|
if (!psym) {
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
gsym = calloc(ecount,sizeof(struct generic_symentry));
|
|
if (!gsym) {
|
|
free(psym);
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
res = RRMOA(ep->f_fd,psym,offset,size,
|
|
ep->f_filesize,errcode);
|
|
if (res!= DW_DLV_OK) {
|
|
free(psym);
|
|
free(gsym);
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return res;
|
|
}
|
|
orig_psym = psym;
|
|
orig_gsym = gsym;
|
|
for ( i = 0; i < ecount; ++i,++psym,++gsym) {
|
|
Dwarf_Unsigned bind = 0;
|
|
Dwarf_Unsigned type = 0;
|
|
|
|
ASNAR(ep->f_copy_word,gsym->gs_name,psym->st_name);
|
|
ASNAR(ep->f_copy_word,gsym->gs_value,psym->st_value);
|
|
ASNAR(ep->f_copy_word,gsym->gs_size,psym->st_size);
|
|
ASNAR(ep->f_copy_word,gsym->gs_info,psym->st_info);
|
|
ASNAR(ep->f_copy_word,gsym->gs_other,psym->st_other);
|
|
ASNAR(ep->f_copy_word,gsym->gs_shndx,psym->st_shndx);
|
|
bind = gsym->gs_info >> 4;
|
|
type = gsym->gs_info & 0xf;
|
|
gsym->gs_bind = bind;
|
|
gsym->gs_type = type;
|
|
}
|
|
*count_out = ecount;
|
|
*gsym_out = orig_gsym;
|
|
free(orig_psym);
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
static int
|
|
_dwarf_generic_elf_load_symbols(
|
|
dwarf_elf_object_access_internals_t *ep,
|
|
Dwarf_Unsigned secnum,
|
|
struct generic_shdr *psh,
|
|
struct generic_symentry **gsym_out,
|
|
Dwarf_Unsigned *count_out,int *errcode)
|
|
{
|
|
int res = 0;
|
|
struct generic_symentry *gsym = 0;
|
|
Dwarf_Unsigned count = 0;
|
|
|
|
if (!secnum) {
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
if (psh->gh_size > ep->f_filesize) {
|
|
*errcode = DW_DLE_SECTION_SIZE_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (ep->f_offsetsize == 32) {
|
|
res = _dwarf_generic_elf_load_symbols32(ep,
|
|
&gsym,
|
|
psh->gh_offset,psh->gh_size,
|
|
&count,errcode);
|
|
} else if (ep->f_offsetsize == 64) {
|
|
res = _dwarf_generic_elf_load_symbols64(ep,
|
|
&gsym,
|
|
psh->gh_offset,psh->gh_size,
|
|
&count,errcode);
|
|
} else {
|
|
*errcode = DW_DLE_OFFSET_SIZE;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (res == DW_DLV_OK) {
|
|
*gsym_out = gsym;
|
|
*count_out = count;
|
|
}
|
|
return res;
|
|
}
|
|
#if 0 /* not needed */
|
|
int
|
|
dwarf_load_elf_dynsym_symbols(
|
|
dwarf_elf_object_access_internals_t *ep, int*errcode)
|
|
{
|
|
int res = 0;
|
|
struct generic_symentry *gsym = 0;
|
|
Dwarf_Unsigned count = 0;
|
|
Dwarf_Unsigned secnum = ep->f_dynsym_sect_index;
|
|
struct generic_shdr * psh = 0;
|
|
|
|
if (!secnum) {
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
psh = ep->f_shdr + secnum;
|
|
if we ever use this... gh_size big?
|
|
res = _dwarf_generic_elf_load_symbols(ep,
|
|
secnum,
|
|
psh,
|
|
&gsym,
|
|
&count,errcode);
|
|
if (res == DW_DLV_OK) {
|
|
ep->f_dynsym = gsym;
|
|
ep->f_loc_dynsym.g_count = count;
|
|
}
|
|
return res;
|
|
}
|
|
#endif /*0*/
|
|
|
|
int
|
|
_dwarf_load_elf_symtab_symbols(
|
|
dwarf_elf_object_access_internals_t *ep, int*errcode)
|
|
{
|
|
int res = 0;
|
|
struct generic_symentry *gsym = 0;
|
|
Dwarf_Unsigned count = 0;
|
|
Dwarf_Unsigned secnum = ep->f_symtab_sect_index;
|
|
struct generic_shdr * psh = 0;
|
|
|
|
if (!secnum) {
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
psh = ep->f_shdr + secnum;
|
|
if (psh->gh_size > ep->f_filesize) {
|
|
*errcode = DW_DLE_SECTION_SIZE_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
res = _dwarf_generic_elf_load_symbols(ep,
|
|
secnum,
|
|
psh,
|
|
&gsym,
|
|
&count,errcode);
|
|
if (res == DW_DLV_OK) {
|
|
ep->f_symtab = gsym;
|
|
ep->f_loc_symtab.g_count = count;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
static int
|
|
generic_rel_from_rela32(
|
|
dwarf_elf_object_access_internals_t *ep,
|
|
struct generic_shdr * gsh,
|
|
dw_elf32_rela *relp,
|
|
struct generic_rela *grel,
|
|
int *errcode)
|
|
{
|
|
Dwarf_Unsigned ecount = 0;
|
|
Dwarf_Unsigned size = gsh->gh_size;
|
|
Dwarf_Unsigned size2 = 0;
|
|
Dwarf_Unsigned i = 0;
|
|
|
|
ecount = size/sizeof(dw_elf32_rela);
|
|
size2 = ecount * sizeof(dw_elf32_rela);
|
|
if (size >= ep->f_filesize) {
|
|
*errcode = DW_DLE_RELOCATION_SECTION_SIZE_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (size != size2) {
|
|
*errcode = DW_DLE_RELOCATION_SECTION_SIZE_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
for ( i = 0; i < ecount; ++i,++relp,++grel) {
|
|
ASNAR(ep->f_copy_word,grel->gr_offset,relp->r_offset);
|
|
ASNAR(ep->f_copy_word,grel->gr_info,relp->r_info);
|
|
/* addend signed */
|
|
ASNAR(ep->f_copy_word,grel->gr_addend,relp->r_addend);
|
|
SIGN_EXTEND(grel->gr_addend,sizeof(relp->r_addend));
|
|
grel->gr_sym = grel->gr_info>>8; /* ELF32_R_SYM */
|
|
grel->gr_type = grel->gr_info & 0xff;
|
|
grel->gr_is_rela = TRUE;
|
|
}
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
static int
|
|
generic_rel_from_rela64(
|
|
dwarf_elf_object_access_internals_t *ep,
|
|
struct generic_shdr * gsh,
|
|
dw_elf64_rela *relp,
|
|
struct generic_rela *grel, int *errcode)
|
|
{
|
|
Dwarf_Unsigned ecount = 0;
|
|
Dwarf_Unsigned size = gsh->gh_size;
|
|
Dwarf_Unsigned size2 = 0;
|
|
Dwarf_Unsigned i = 0;
|
|
int objlittleendian = (ep->f_endian == DW_END_little);
|
|
int ismips64 = (ep->f_machine == EM_MIPS);
|
|
int issparcv9 = (ep->f_machine == EM_SPARCV9);
|
|
|
|
ecount = size/sizeof(dw_elf64_rela);
|
|
size2 = ecount * sizeof(dw_elf64_rela);
|
|
if (size >= ep->f_filesize) {
|
|
*errcode = DW_DLE_RELOCATION_SECTION_SIZE_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (size != size2) {
|
|
*errcode = DW_DLE_RELOCATION_SECTION_SIZE_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
for ( i = 0; i < ecount; ++i,++relp,++grel) {
|
|
ASNAR(ep->f_copy_word,grel->gr_offset,relp->r_offset);
|
|
ASNAR(ep->f_copy_word,grel->gr_info,relp->r_info);
|
|
ASNAR(ep->f_copy_word,grel->gr_addend,relp->r_addend);
|
|
SIGN_EXTEND(grel->gr_addend,sizeof(relp->r_addend));
|
|
if (ismips64 && objlittleendian ) {
|
|
char realsym[4];
|
|
|
|
memcpy(realsym,&relp->r_info,sizeof(realsym));
|
|
ASNAR(ep->f_copy_word,grel->gr_sym,realsym);
|
|
grel->gr_type = relp->r_info[7];
|
|
grel->gr_type2 = relp->r_info[6];
|
|
grel->gr_type3 = relp->r_info[5];
|
|
} else if (issparcv9) {
|
|
/* Always Big Endian? */
|
|
char realsym[4];
|
|
|
|
memcpy(realsym,&relp->r_info,sizeof(realsym));
|
|
ASNAR(ep->f_copy_word,grel->gr_sym,realsym);
|
|
grel->gr_type = relp->r_info[7];
|
|
} else {
|
|
grel->gr_sym = grel->gr_info >> 32;
|
|
grel->gr_type = grel->gr_info & 0xffffffff;
|
|
}
|
|
grel->gr_is_rela = TRUE;
|
|
}
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
static int
|
|
generic_rel_from_rel32(
|
|
dwarf_elf_object_access_internals_t *ep,
|
|
struct generic_shdr * gsh,
|
|
dw_elf32_rel *relp,
|
|
struct generic_rela *grel,int *errcode)
|
|
{
|
|
Dwarf_Unsigned ecount = 0;
|
|
Dwarf_Unsigned size = gsh->gh_size;
|
|
Dwarf_Unsigned size2 = 0;
|
|
Dwarf_Unsigned i = 0;
|
|
|
|
ecount = size/sizeof(dw_elf32_rel);
|
|
size2 = ecount * sizeof(dw_elf32_rel);
|
|
if (size >= ep->f_filesize) {
|
|
*errcode = DW_DLE_RELOCATION_SECTION_SIZE_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (size != size2) {
|
|
*errcode = DW_DLE_RELOCATION_SECTION_SIZE_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
for ( i = 0; i < ecount; ++i,++relp,++grel) {
|
|
ASNAR(ep->f_copy_word,grel->gr_offset,relp->r_offset);
|
|
ASNAR(ep->f_copy_word,grel->gr_info,relp->r_info);
|
|
grel->gr_addend = 0; /* Unused for plain .rel */
|
|
grel->gr_sym = grel->gr_info >>8; /* ELF32_R_SYM */
|
|
grel->gr_is_rela = FALSE;
|
|
grel->gr_type = grel->gr_info & 0xff;
|
|
}
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
static int
|
|
generic_rel_from_rel64(
|
|
dwarf_elf_object_access_internals_t *ep,
|
|
struct generic_shdr * gsh,
|
|
dw_elf64_rel *relp,
|
|
struct generic_rela *grel,int *errcode)
|
|
{
|
|
Dwarf_Unsigned ecount = 0;
|
|
Dwarf_Unsigned size = gsh->gh_size;
|
|
Dwarf_Unsigned size2 = 0;
|
|
Dwarf_Unsigned i = 0;
|
|
int objlittleendian = (ep->f_endian == DW_END_little);
|
|
int ismips64 = (ep->f_machine == EM_MIPS);
|
|
int issparcv9 = (ep->f_machine == EM_SPARCV9);
|
|
|
|
ecount = size/sizeof(dw_elf64_rel);
|
|
size2 = ecount * sizeof(dw_elf64_rel);
|
|
if (size >= ep->f_filesize) {
|
|
*errcode = DW_DLE_RELOCATION_SECTION_SIZE_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (size != size2) {
|
|
*errcode = DW_DLE_RELOCATION_SECTION_SIZE_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
for ( i = 0; i < ecount; ++i,++relp,++grel) {
|
|
ASNAR(ep->f_copy_word,grel->gr_offset,relp->r_offset);
|
|
ASNAR(ep->f_copy_word,grel->gr_info,relp->r_info);
|
|
grel->gr_addend = 0; /* Unused for plain .rel */
|
|
if (ismips64 && objlittleendian ) {
|
|
char realsym[4];
|
|
|
|
memcpy(realsym,&relp->r_info,sizeof(realsym));
|
|
ASNAR(ep->f_copy_word,grel->gr_sym,realsym);
|
|
grel->gr_type = relp->r_info[7];
|
|
grel->gr_type2 = relp->r_info[6];
|
|
grel->gr_type3 = relp->r_info[5];
|
|
} else if (issparcv9) {
|
|
/* Always Big Endian? */
|
|
char realsym[4];
|
|
|
|
memcpy(realsym,&relp->r_info,sizeof(realsym));
|
|
ASNAR(ep->f_copy_word,grel->gr_sym,realsym);
|
|
grel->gr_type = relp->r_info[7];
|
|
} else {
|
|
grel->gr_sym = grel->gr_info >>32;
|
|
grel->gr_type = grel->gr_info & 0xffffffff;
|
|
}
|
|
grel->gr_is_rela = FALSE;
|
|
}
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
#if 0 /* not needed */
|
|
int
|
|
dwarf_load_elf_dynstr(
|
|
dwarf_elf_object_access_internals_t *ep, int *errcode)
|
|
{
|
|
struct generic_shdr *strpsh = 0;
|
|
int res = 0;
|
|
Dwarf_Unsigned strsectindex =0;
|
|
Dwarf_Unsigned strsectlength = 0;
|
|
|
|
if (!ep->f_dynsym_sect_strings_sect_index) {
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
strsectindex = ep->f_dynsym_sect_strings_sect_index;
|
|
strsectlength = ep->f_dynsym_sect_strings_max;
|
|
strpsh = ep->f_shdr + strsectindex;
|
|
/* Alloc an extra byte as a guaranteed NUL byte
|
|
at the end of the strings in case the section
|
|
is corrupted and lacks a NUL at end. */
|
|
ep->f_dynsym_sect_strings = calloc(1,strsectlength+1);
|
|
if (!ep->f_dynsym_sect_strings) {
|
|
ep->f_dynsym_sect_strings = 0;
|
|
ep->f_dynsym_sect_strings_max = 0;
|
|
ep->f_dynsym_sect_strings_sect_index = 0;
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
res = RRMOA(ep->f_fd,ep->f_dynsym_sect_strings,
|
|
strpsh->gh_offset,
|
|
strsectlength,
|
|
ep->f_filesize,errcode);
|
|
if (res != DW_DLV_OK) {
|
|
ep->f_dynsym_sect_strings = 0;
|
|
ep->f_dynsym_sect_strings_max = 0;
|
|
ep->f_dynsym_sect_strings_sect_index = 0;
|
|
return res;
|
|
}
|
|
return DW_DLV_OK;
|
|
}
|
|
#endif /*0*/
|
|
|
|
int
|
|
_dwarf_load_elf_symstr(
|
|
dwarf_elf_object_access_internals_t *ep, int *errcode)
|
|
{
|
|
struct generic_shdr *strpsh = 0;
|
|
int res = 0;
|
|
Dwarf_Unsigned strsectindex =0;
|
|
Dwarf_Unsigned strsectlength = 0;
|
|
|
|
if (!ep->f_symtab_sect_strings_sect_index) {
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
strsectindex = ep->f_symtab_sect_strings_sect_index;
|
|
strsectlength = ep->f_symtab_sect_strings_max;
|
|
strpsh = ep->f_shdr + strsectindex;
|
|
/* Alloc an extra byte as a guaranteed NUL byte
|
|
at the end of the strings in case the section
|
|
is corrupted and lacks a NUL at end. */
|
|
if (strsectlength > ep->f_filesize ||
|
|
strpsh->gh_offset >ep->f_filesize ||
|
|
(strsectlength + strpsh->gh_offset) >
|
|
ep->f_filesize) {
|
|
*errcode = DW_DLE_SECTION_SIZE_OR_OFFSET_LARGE;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
ep->f_symtab_sect_strings = calloc(1,strsectlength+1);
|
|
if (!ep->f_symtab_sect_strings) {
|
|
ep->f_symtab_sect_strings = 0;
|
|
ep->f_symtab_sect_strings_max = 0;
|
|
ep->f_symtab_sect_strings_sect_index = 0;
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
res = RRMOA(ep->f_fd,ep->f_symtab_sect_strings,
|
|
strpsh->gh_offset,
|
|
strsectlength,
|
|
ep->f_filesize,errcode);
|
|
if (res != DW_DLV_OK) {
|
|
free(ep->f_symtab_sect_strings);
|
|
ep->f_symtab_sect_strings = 0;
|
|
ep->f_symtab_sect_strings_max = 0;
|
|
ep->f_symtab_sect_strings_sect_index = 0;
|
|
return res;
|
|
}
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
static int
|
|
_dwarf_elf_load_sectstrings(
|
|
dwarf_elf_object_access_internals_t *ep,
|
|
Dwarf_Unsigned stringsection,
|
|
int *errcode)
|
|
{
|
|
int res = 0;
|
|
struct generic_shdr *psh = 0;
|
|
Dwarf_Unsigned secoffset = 0;
|
|
|
|
ep->f_elf_shstrings_length = 0;
|
|
if (stringsection >= ep->f_ehdr->ge_shnum) {
|
|
*errcode = DW_DLE_SECTION_INDEX_BAD;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
psh = ep->f_shdr + stringsection;
|
|
secoffset = psh->gh_offset;
|
|
if (is_empty_section(psh->gh_type)) {
|
|
*errcode = DW_DLE_ELF_STRING_SECTION_MISSING;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (secoffset >= ep->f_filesize ||
|
|
psh->gh_size > ep->f_filesize ||
|
|
(secoffset + psh->gh_size) >
|
|
ep->f_filesize) {
|
|
*errcode = DW_DLE_SECTION_SIZE_OR_OFFSET_LARGE;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (psh->gh_size > ep->f_elf_shstrings_max) {
|
|
free(ep->f_elf_shstrings_data);
|
|
ep->f_elf_shstrings_data = (char *)malloc(psh->gh_size);
|
|
ep->f_elf_shstrings_max = psh->gh_size;
|
|
if (!ep->f_elf_shstrings_data) {
|
|
ep->f_elf_shstrings_max = 0;
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
}
|
|
ep->f_elf_shstrings_length = psh->gh_size;
|
|
res = RRMOA(ep->f_fd,ep->f_elf_shstrings_data,secoffset,
|
|
psh->gh_size,
|
|
ep->f_filesize,errcode);
|
|
return res;
|
|
}
|
|
|
|
static const dw_elf32_shdr shd32zero;
|
|
static const struct generic_shdr shdgzero;
|
|
|
|
/* Has a side effect of setting count, number
|
|
in the ehdr ep points to. */
|
|
static int
|
|
get_counts_from_sec32_zero(
|
|
dwarf_elf_object_access_internals_t * ep,
|
|
Dwarf_Unsigned offset,
|
|
Dwarf_Bool *have_shdr_count,
|
|
Dwarf_Unsigned *shdr_count,
|
|
Dwarf_Bool *have_shstrndx_number,
|
|
Dwarf_Unsigned *shstrndx_number,
|
|
int *errcode)
|
|
{
|
|
dw_elf32_shdr shd32;
|
|
struct generic_shdr shdg;
|
|
int res = 0;
|
|
Dwarf_Unsigned size = sizeof(shd32);
|
|
struct generic_ehdr * geh = ep->f_ehdr;
|
|
|
|
shd32 = shd32zero;
|
|
shdg = shdgzero;
|
|
res = RRMOA(ep->f_fd,&shd32,offset,size,
|
|
ep->f_filesize,errcode);
|
|
if (res != DW_DLV_OK) {
|
|
return res;
|
|
}
|
|
copysection32(ep,&shdg,&shd32);
|
|
if (geh->ge_shnum_extended) {
|
|
geh->ge_shnum = shdg.gh_size;
|
|
geh->ge_shnum_in_shnum = TRUE;
|
|
if (geh->ge_shnum < 3) {
|
|
*errcode = DW_DLE_TOO_FEW_SECTIONS;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
}
|
|
*have_shdr_count = TRUE;
|
|
*shdr_count = geh->ge_shnum;
|
|
if (geh->ge_strndx_extended) {
|
|
geh->ge_shstrndx = shdg.gh_link;
|
|
geh->ge_strndx_in_strndx = TRUE;
|
|
}
|
|
if (geh->ge_shnum_in_shnum &&
|
|
geh->ge_strndx_in_strndx&&
|
|
(geh->ge_shstrndx >= geh->ge_shnum)) {
|
|
*errcode = DW_DLE_NO_SECT_STRINGS;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
*have_shstrndx_number = TRUE;
|
|
*shstrndx_number = geh->ge_shstrndx;
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
static int
|
|
elf_load_sectheaders32(
|
|
dwarf_elf_object_access_internals_t *ep,
|
|
Dwarf_Unsigned offset,
|
|
Dwarf_Unsigned entsize,
|
|
Dwarf_Unsigned count,
|
|
int *errcode)
|
|
{
|
|
Dwarf_Unsigned generic_count = 0;
|
|
Dwarf_Unsigned shdr_count = 0;
|
|
Dwarf_Bool have_shdr_count = FALSE;
|
|
Dwarf_Unsigned shstrndx_number = 0;
|
|
Dwarf_Bool have_shstrndx_number = FALSE;
|
|
struct generic_ehdr *ehp = 0;
|
|
int res = 0;
|
|
|
|
if (entsize < sizeof(dw_elf32_shdr)) {
|
|
*errcode = DW_DLE_SECTION_SIZE_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
ehp = ep->f_ehdr;
|
|
if (!ehp->ge_shnum_in_shnum || !ehp->ge_strndx_in_strndx) {
|
|
res = get_counts_from_sec32_zero(ep,offset,
|
|
&have_shdr_count,&shdr_count,
|
|
&have_shstrndx_number,&shstrndx_number,
|
|
errcode);
|
|
if (res != DW_DLV_OK) {
|
|
return res;
|
|
}
|
|
if (have_shdr_count) {
|
|
count = shdr_count;
|
|
}
|
|
}
|
|
if (count == 0) {
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
if ((offset > ep->f_filesize)||
|
|
(entsize > 200)||
|
|
(count > ep->f_filesize) ||
|
|
((count *entsize +offset) > ep->f_filesize)) {
|
|
*errcode = DW_DLE_SECTION_SIZE_OR_OFFSET_LARGE;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
res = generic_shdr_from_shdr32(ep,&generic_count,
|
|
offset,entsize,count,errcode);
|
|
if (res != DW_DLV_OK) {
|
|
return res;
|
|
}
|
|
if (generic_count != count) {
|
|
*errcode = DW_DLE_ELF_SECTION_COUNT_MISMATCH;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
return DW_DLV_OK;
|
|
}
|
|
static const dw_elf64_shdr shd64zero;
|
|
/* Has a side effect of setting count, number
|
|
in the ehdr ep points to. */
|
|
static int
|
|
get_counts_from_sec64_zero(
|
|
dwarf_elf_object_access_internals_t * ep,
|
|
Dwarf_Unsigned offset,
|
|
Dwarf_Bool *have_shdr_count,
|
|
Dwarf_Unsigned *shdr_count,
|
|
Dwarf_Bool *have_shstrndx_number,
|
|
Dwarf_Unsigned *shstrndx_number,
|
|
int *errcode)
|
|
{
|
|
dw_elf64_shdr shd64;
|
|
struct generic_shdr shdg;
|
|
int res = 0;
|
|
Dwarf_Unsigned size = sizeof(shd64);
|
|
struct generic_ehdr * geh = ep->f_ehdr;
|
|
|
|
shd64 = shd64zero;
|
|
shdg = shdgzero;
|
|
res = RRMOA(ep->f_fd,&shd64,offset,size,
|
|
ep->f_filesize,errcode);
|
|
if (res != DW_DLV_OK) {
|
|
return res;
|
|
}
|
|
copysection64(ep,&shdg,&shd64);
|
|
if (geh->ge_shnum_extended) {
|
|
geh->ge_shnum = shdg.gh_size;
|
|
geh->ge_shnum_in_shnum = TRUE;
|
|
if (geh->ge_shnum < 3) {
|
|
*errcode = DW_DLE_TOO_FEW_SECTIONS;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
}
|
|
*have_shdr_count = TRUE;
|
|
*shdr_count = geh->ge_shnum;
|
|
if (geh->ge_strndx_extended) {
|
|
geh->ge_shstrndx = shdg.gh_link;
|
|
geh->ge_strndx_in_strndx = TRUE;
|
|
}
|
|
if (geh->ge_shnum_in_shnum &&
|
|
geh->ge_strndx_in_strndx &&
|
|
(geh->ge_shstrndx >= geh->ge_shnum)) {
|
|
*errcode = DW_DLE_NO_SECT_STRINGS;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
*have_shstrndx_number = TRUE;
|
|
*shstrndx_number = geh->ge_shstrndx;
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
static int
|
|
elf_load_sectheaders64(
|
|
dwarf_elf_object_access_internals_t *ep,
|
|
Dwarf_Unsigned offset,Dwarf_Unsigned entsize,
|
|
Dwarf_Unsigned count,int*errcode)
|
|
{
|
|
Dwarf_Unsigned generic_count = 0;
|
|
Dwarf_Unsigned shdr_count = 0;
|
|
Dwarf_Bool have_shdr_count = FALSE;
|
|
Dwarf_Unsigned shstrndx_number = 0;
|
|
Dwarf_Bool have_shstrndx_number = FALSE;
|
|
struct generic_ehdr *ehp = 0;
|
|
int res = 0;
|
|
|
|
ehp = ep->f_ehdr;
|
|
if (!ehp->ge_shnum_in_shnum || !ehp->ge_strndx_in_strndx ) {
|
|
res = get_counts_from_sec64_zero(ep,offset,
|
|
&have_shdr_count,&shdr_count,
|
|
&have_shstrndx_number,&shstrndx_number,
|
|
errcode);
|
|
if (res != DW_DLV_OK) {
|
|
return res;
|
|
}
|
|
if (have_shdr_count) {
|
|
count = shdr_count;
|
|
}
|
|
}
|
|
if (count == 0) {
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
if (entsize < sizeof(dw_elf64_shdr)) {
|
|
*errcode = DW_DLE_SECTION_SIZE_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if ((offset > ep->f_filesize)||
|
|
(entsize > 200)||
|
|
(count > ep->f_filesize) ||
|
|
((count *entsize +offset) > ep->f_filesize)) {
|
|
*errcode = DW_DLE_SECTION_SIZE_OR_OFFSET_LARGE;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
res = generic_shdr_from_shdr64(ep,&generic_count,
|
|
offset,entsize,count,errcode);
|
|
if (res != DW_DLV_OK) {
|
|
return res;
|
|
}
|
|
if (generic_count != count) {
|
|
*errcode = DW_DLE_ELF_SECTION_COUNT_MISMATCH;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
static int
|
|
_dwarf_elf_load_a_relx_batch(
|
|
dwarf_elf_object_access_internals_t *ep,
|
|
struct generic_shdr * gsh,
|
|
struct generic_rela ** grel_out,
|
|
Dwarf_Unsigned *count_out,
|
|
enum RelocRela localrela,
|
|
enum RelocOffsetSize localoffsize,
|
|
int *errcode)
|
|
{
|
|
Dwarf_Unsigned count = 0;
|
|
Dwarf_Unsigned size = 0;
|
|
Dwarf_Unsigned size2 = 0;
|
|
Dwarf_Unsigned sizeg = 0;
|
|
Dwarf_Unsigned offset = 0;
|
|
int res = 0;
|
|
Dwarf_Unsigned object_reclen = 0;
|
|
struct generic_rela *grel = 0;
|
|
|
|
/* ASSERT: Caller guarantees localoffsetsize
|
|
is a valid 4 or 8. */
|
|
/* ASSERT: Caller guarantees localrela is one
|
|
of the 2 valid values 1 or 2 */
|
|
|
|
offset = gsh->gh_offset;
|
|
size = gsh->gh_size;
|
|
if (size == 0) {
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
if ((offset > ep->f_filesize)||
|
|
(size > ep->f_filesize) ||
|
|
((size +offset) > ep->f_filesize)) {
|
|
*errcode = DW_DLE_SECTION_SIZE_OR_OFFSET_LARGE;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (localoffsize == RelocOffset32) {
|
|
if (localrela == RelocIsRela) {
|
|
object_reclen = sizeof(dw_elf32_rela);
|
|
count = (long)(size/object_reclen);
|
|
size2 = count * object_reclen;
|
|
if (size != size2) {
|
|
*errcode = DW_DLE_SECTION_SIZE_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
} else {
|
|
object_reclen = sizeof(dw_elf32_rel);
|
|
count = (long)(size/object_reclen);
|
|
size2 = count * object_reclen;
|
|
if (size != size2) {
|
|
*errcode = DW_DLE_SECTION_SIZE_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
}
|
|
} else {
|
|
if (localrela == RelocIsRela) {
|
|
object_reclen = sizeof(dw_elf64_rela);
|
|
count = (long)(size/object_reclen);
|
|
size2 = count * object_reclen;
|
|
if (size != size2) {
|
|
*errcode = DW_DLE_SECTION_SIZE_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
} else {
|
|
object_reclen = sizeof(dw_elf64_rel);
|
|
count = (long)(size/object_reclen);
|
|
size2 = count * object_reclen;
|
|
if (size != size2) {
|
|
*errcode = DW_DLE_SECTION_SIZE_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
}
|
|
}
|
|
sizeg = count*sizeof(struct generic_rela);
|
|
grel = (struct generic_rela *)malloc(sizeg);
|
|
if (!grel) {
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (localoffsize == RelocOffset32) {
|
|
if (localrela == RelocIsRela) {
|
|
dw_elf32_rela *relp = 0;
|
|
relp = (dw_elf32_rela *)malloc(size);
|
|
if (!relp) {
|
|
free(grel);
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
res = RRMOA(ep->f_fd,relp,offset,size,
|
|
ep->f_filesize,errcode);
|
|
if (res != DW_DLV_OK) {
|
|
free(relp);
|
|
free(grel);
|
|
return res;
|
|
}
|
|
res = generic_rel_from_rela32(ep,gsh,relp,grel,errcode);
|
|
free(relp);
|
|
} else {
|
|
dw_elf32_rel *relp = 0;
|
|
relp = (dw_elf32_rel *)malloc(size);
|
|
if (!relp) {
|
|
free(grel);
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
res = RRMOA(ep->f_fd,relp,offset,size,
|
|
ep->f_filesize,errcode);
|
|
if (res != DW_DLV_OK) {
|
|
free(relp);
|
|
free(grel);
|
|
return res;
|
|
}
|
|
res = generic_rel_from_rel32(ep,gsh,relp,grel,errcode);
|
|
free(relp);
|
|
}
|
|
} else {
|
|
if (localrela == RelocIsRela) {
|
|
dw_elf64_rela *relp = 0;
|
|
relp = (dw_elf64_rela *)malloc(size);
|
|
if (!relp) {
|
|
free(grel);
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
res = RRMOA(ep->f_fd,relp,offset,size,
|
|
ep->f_filesize,errcode);
|
|
if (res != DW_DLV_OK) {
|
|
free(relp);
|
|
free(grel);
|
|
return res;
|
|
}
|
|
res = generic_rel_from_rela64(ep,gsh,relp,grel,errcode);
|
|
free(relp);
|
|
} else {
|
|
dw_elf64_rel *relp = 0;
|
|
relp = (dw_elf64_rel *)malloc(size);
|
|
if (!relp) {
|
|
free(grel);
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
res = RRMOA(ep->f_fd,relp,offset,size,
|
|
ep->f_filesize,errcode);
|
|
if (res != DW_DLV_OK) {
|
|
free(relp);
|
|
free(grel);
|
|
return res;
|
|
}
|
|
res = generic_rel_from_rel64(ep,gsh,relp,grel,errcode);
|
|
free(relp);
|
|
}
|
|
}
|
|
if (res == DW_DLV_OK) {
|
|
gsh->gh_relcount = count;
|
|
gsh->gh_rels = grel;
|
|
*count_out = count;
|
|
*grel_out = grel;
|
|
return res;
|
|
}
|
|
/* Some sort of issue */
|
|
count_out = 0;
|
|
free(grel);
|
|
return res;
|
|
}
|
|
|
|
/* Is this rel/rela section related to dwarf at all?
|
|
set oksecnum zero if not. Else set targ secnum.
|
|
Never returns DW_DLV_NO_ENTRY. */
|
|
static int
|
|
this_rel_is_a_section_dwarf_related(
|
|
dwarf_elf_object_access_internals_t *ep,
|
|
struct generic_shdr *gshdr,
|
|
unsigned *oksecnum_out,
|
|
int *errcode)
|
|
{
|
|
Dwarf_Unsigned oksecnum = 0;
|
|
struct generic_shdr *gstarg = 0;
|
|
|
|
if (gshdr->gh_type != SHT_RELA &&
|
|
gshdr->gh_type != SHT_REL) {
|
|
*oksecnum_out = 0;
|
|
return DW_DLV_OK;
|
|
}
|
|
oksecnum = gshdr->gh_reloc_target_secnum;
|
|
if (oksecnum >= ep->f_loc_shdr.g_count) {
|
|
*oksecnum_out = 0;
|
|
*errcode = DW_DLE_ELF_SECTION_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
gstarg = ep->f_shdr+oksecnum;
|
|
if (!gstarg->gh_is_dwarf) {
|
|
*oksecnum_out = 0; /* no reloc needed. */
|
|
return DW_DLV_OK;
|
|
}
|
|
*oksecnum_out = (unsigned)oksecnum;
|
|
return DW_DLV_OK;
|
|
}
|
|
/* Secnum here is the secnum of rela. Not
|
|
the target of the relocations.
|
|
This also loads .rel. */
|
|
int
|
|
_dwarf_load_elf_relx(
|
|
dwarf_elf_object_access_internals_t *ep,
|
|
Dwarf_Unsigned secnum,
|
|
enum RelocRela localr,
|
|
int *errcode)
|
|
{
|
|
struct generic_shdr *gshdr = 0;
|
|
Dwarf_Unsigned seccount = 0;
|
|
unsigned offsetsize = 0;
|
|
struct generic_rela *grp = 0;
|
|
Dwarf_Unsigned count_read = 0;
|
|
int res = 0;
|
|
unsigned oksec = 0;
|
|
enum RelocOffsetSize localoffsize = RelocOffset32;
|
|
|
|
/* ASSERT: Caller guarantees localr is
|
|
a valid RelocRela */
|
|
if (!ep) {
|
|
*errcode = DW_DLE_INTERNAL_NULL_POINTER;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
offsetsize = ep->f_offsetsize;
|
|
seccount = ep->f_loc_shdr.g_count;
|
|
if (secnum >= seccount) {
|
|
*errcode = DW_DLE_ELF_SECTION_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
gshdr = ep->f_shdr +secnum;
|
|
if (is_empty_section(gshdr->gh_type)) {
|
|
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
|
|
res = this_rel_is_a_section_dwarf_related(ep,gshdr,
|
|
&oksec,errcode);
|
|
if (res == DW_DLV_ERROR) {
|
|
return res;
|
|
}
|
|
if (!oksec) {
|
|
return DW_DLV_OK;
|
|
}
|
|
/* We will actually read these relocations. */
|
|
if (offsetsize == 64) {
|
|
localoffsize = RelocOffset64;
|
|
} else if (offsetsize == 32) {
|
|
localoffsize = RelocOffset32;
|
|
} else {
|
|
*errcode = DW_DLE_OFFSET_SIZE;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
/* ASSERT: localoffsize is now a valid enum value,
|
|
one of the two defined. */
|
|
res = _dwarf_elf_load_a_relx_batch(ep,
|
|
gshdr,&grp,&count_read,localr,localoffsize,errcode);
|
|
if (res == DW_DLV_ERROR) {
|
|
return res;
|
|
}
|
|
if (res == DW_DLV_NO_ENTRY) {
|
|
return res;
|
|
}
|
|
gshdr->gh_rels = grp;
|
|
gshdr->gh_relcount = count_read;
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
static int
|
|
validate_section_name_string(Dwarf_Unsigned section_length,
|
|
Dwarf_Unsigned string_loc_index,
|
|
const char * strings_start,
|
|
int * errcode)
|
|
{
|
|
const char *endpoint = strings_start + section_length;
|
|
const char *cur = 0;
|
|
|
|
if (section_length <= string_loc_index) {
|
|
*errcode = DW_DLE_SECTION_STRING_OFFSET_BAD;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
cur = string_loc_index+strings_start;
|
|
for ( ; cur < endpoint;++cur) {
|
|
if (!*cur) {
|
|
return DW_DLV_OK;
|
|
}
|
|
}
|
|
*errcode = DW_DLE_SECTION_STRING_OFFSET_BAD;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
/* Without proper section names in place nothing
|
|
is going to work in reading DWARF sections. */
|
|
static int
|
|
_dwarf_elf_load_sect_namestring(
|
|
dwarf_elf_object_access_internals_t *ep,
|
|
int *errcode)
|
|
{
|
|
struct generic_shdr *gshdr = 0;
|
|
Dwarf_Unsigned generic_count = 0;
|
|
Dwarf_Unsigned i = 1;
|
|
const char *stringsecbase = 0;
|
|
|
|
stringsecbase = ep->f_elf_shstrings_data;
|
|
gshdr = ep->f_shdr;
|
|
generic_count = ep->f_loc_shdr.g_count;
|
|
for (i = 0; i < generic_count; i++, ++gshdr) {
|
|
const char *namestr =
|
|
"<No valid Elf section strings exist>";
|
|
int res = 0;
|
|
|
|
if (!ep->f_ehdr->ge_shstrndx || !stringsecbase) {
|
|
gshdr->gh_namestring = namestr;
|
|
continue;
|
|
}
|
|
namestr = "<Invalid sh_name value. Corrupt Elf.>";
|
|
res = validate_section_name_string(ep->f_elf_shstrings_length,
|
|
gshdr->gh_name, stringsecbase,
|
|
errcode);
|
|
if (res != DW_DLV_OK) {
|
|
gshdr->gh_namestring = namestr;
|
|
if (res == DW_DLV_ERROR) {
|
|
return res;
|
|
}
|
|
/* no entry, missing strings. */
|
|
*errcode = DW_DLE_NO_SECT_STRINGS;
|
|
return DW_DLV_ERROR;
|
|
} else {
|
|
gshdr->gh_namestring = stringsecbase + gshdr->gh_name;
|
|
}
|
|
}
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
/* The C standard ensures these are all appropriate
|
|
zero bits. */
|
|
static const dw_elf32_ehdr eh32_zero;
|
|
static const dw_elf64_ehdr eh64_zero;
|
|
|
|
static int
|
|
elf_load_elf_header32(
|
|
dwarf_elf_object_access_internals_t *ep,int *errcode)
|
|
{
|
|
int res = 0;
|
|
dw_elf32_ehdr ehdr32;
|
|
struct generic_ehdr *ehdr = 0;
|
|
|
|
ehdr32 = eh32_zero;
|
|
res = RRMOA(ep->f_fd,&ehdr32,0,sizeof(ehdr32),
|
|
ep->f_filesize,errcode);
|
|
if (res != DW_DLV_OK) {
|
|
return res;
|
|
}
|
|
ehdr = (struct generic_ehdr *)calloc(1,
|
|
sizeof(struct generic_ehdr));
|
|
if (!ehdr) {
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
res = generic_ehdr_from_32(ep,ehdr,&ehdr32,errcode);
|
|
if (res != DW_DLV_OK) {
|
|
free(ehdr);
|
|
}
|
|
return res;
|
|
}
|
|
static int
|
|
elf_load_elf_header64(
|
|
dwarf_elf_object_access_internals_t *ep,int *errcode)
|
|
{
|
|
int res = 0;
|
|
dw_elf64_ehdr ehdr64;
|
|
struct generic_ehdr *ehdr = 0;
|
|
|
|
ehdr64 = eh64_zero;
|
|
res = RRMOA(ep->f_fd,&ehdr64,0,sizeof(ehdr64),
|
|
ep->f_filesize,errcode);
|
|
if (res != DW_DLV_OK) {
|
|
return res;
|
|
}
|
|
ehdr = (struct generic_ehdr *)calloc(1,
|
|
sizeof(struct generic_ehdr));
|
|
if (!ehdr) {
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
res = generic_ehdr_from_64(ep,ehdr,&ehdr64,errcode);
|
|
if (res != DW_DLV_OK) {
|
|
free(ehdr);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
int
|
|
_dwarf_load_elf_header(
|
|
dwarf_elf_object_access_internals_t *ep,int*errcode)
|
|
{
|
|
unsigned offsetsize = ep->f_offsetsize;
|
|
int res = 0;
|
|
|
|
if (offsetsize == 32) {
|
|
res = elf_load_elf_header32(ep,errcode);
|
|
} else if (offsetsize == 64) {
|
|
if (sizeof(Dwarf_Unsigned) < 8) {
|
|
*errcode = DW_DLE_INTEGER_TOO_SMALL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
res = elf_load_elf_header64(ep,errcode);
|
|
} else {
|
|
*errcode = DW_DLE_OFFSET_SIZE;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
static int
|
|
validate_links(
|
|
dwarf_elf_object_access_internals_t *ep,
|
|
Dwarf_Unsigned knownsect,
|
|
Dwarf_Unsigned string_sect,
|
|
int *errcode)
|
|
{
|
|
struct generic_shdr* pshk = 0;
|
|
|
|
if (!knownsect) {
|
|
return DW_DLV_OK;
|
|
}
|
|
if (!string_sect) {
|
|
*errcode = DW_DLE_ELF_STRING_SECTION_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
pshk = ep->f_shdr + knownsect;
|
|
if (string_sect != pshk->gh_link) {
|
|
*errcode = DW_DLE_ELF_SECTION_LINK_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
static int
|
|
string_endswith(const char *n,const char *q)
|
|
{
|
|
size_t len = strlen(n);
|
|
size_t qlen = strlen(q);
|
|
const char *startpt = 0;
|
|
|
|
if ( len < qlen) {
|
|
return FALSE;
|
|
}
|
|
startpt = n + (len-qlen);
|
|
if (strcmp(startpt,q)) {
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/* We are allowing either SHT_GROUP or .group to indicate
|
|
a group section, but really one should have both
|
|
or neither! */
|
|
static int
|
|
elf_sht_groupsec(Dwarf_Unsigned type, const char *sname)
|
|
{
|
|
/* ARM compilers name SHT group "__ARM_grp<long name here>"
|
|
not .group */
|
|
if ((type == SHT_GROUP) || (!strcmp(sname,".group"))){
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static int
|
|
elf_flagmatches(Dwarf_Unsigned flagsword,Dwarf_Unsigned flag)
|
|
{
|
|
if ((flagsword&flag) == flag) {
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/* For SHT_GROUP sections.
|
|
A group section starts with a 32bit flag
|
|
word with value 1.
|
|
32bit section numbers of the sections
|
|
in the group follow the flag field. */
|
|
static int
|
|
read_gs_section_group(
|
|
dwarf_elf_object_access_internals_t *ep,
|
|
struct generic_shdr* psh,
|
|
int *errcode)
|
|
{
|
|
Dwarf_Unsigned i = 0;
|
|
int res = 0;
|
|
|
|
if (!psh->gh_sht_group_array) {
|
|
Dwarf_Unsigned seclen = psh->gh_size;
|
|
char *data = 0;
|
|
char *dp = 0;
|
|
Dwarf_Unsigned* grouparray = 0;
|
|
char dblock[4];
|
|
Dwarf_Unsigned va = 0;
|
|
Dwarf_Unsigned count = 0;
|
|
Dwarf_Unsigned groupmallocsize = 0;
|
|
int foundone = 0;
|
|
|
|
if (seclen >= ep->f_filesize) {
|
|
*errcode = DW_DLE_ELF_SECTION_GROUP_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (seclen < DWARF_32BIT_SIZE) {
|
|
*errcode = DW_DLE_ELF_SECTION_GROUP_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
data = malloc(seclen);
|
|
if (!data) {
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
dp = data;
|
|
if (psh->gh_entsize != DWARF_32BIT_SIZE) {
|
|
*errcode = DW_DLE_ELF_SECTION_GROUP_ERROR;
|
|
free(data);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (!psh->gh_entsize) {
|
|
free(data);
|
|
*errcode = DW_DLE_ELF_SECTION_GROUP_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
count = seclen/psh->gh_entsize;
|
|
if (count >= ep->f_loc_shdr.g_count) {
|
|
/* Impossible */
|
|
free(data);
|
|
*errcode = DW_DLE_ELF_SECTION_GROUP_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
res = RRMOA(ep->f_fd,data,psh->gh_offset,seclen,
|
|
ep->f_filesize,errcode);
|
|
if (res != DW_DLV_OK) {
|
|
free(data);
|
|
return res;
|
|
}
|
|
groupmallocsize = count * sizeof(Dwarf_Unsigned);
|
|
if (groupmallocsize >= ep->f_filesize) {
|
|
free(data);
|
|
*errcode = DW_DLE_ELF_SECTION_GROUP_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
grouparray = malloc(groupmallocsize);
|
|
if (!grouparray) {
|
|
free(data);
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
memcpy(dblock,dp,DWARF_32BIT_SIZE);
|
|
ASNAR(memcpy,va,dblock);
|
|
/* There is ambiguity on the endianness of this stuff. */
|
|
if (va != 1 && va != 0x1000000) {
|
|
/* Could be corrupted elf object. */
|
|
*errcode = DW_DLE_ELF_SECTION_GROUP_ERROR;
|
|
free(data);
|
|
free(grouparray);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
grouparray[0] = 1;
|
|
/* A .group section will have 0 to G sections
|
|
listed */
|
|
dp = dp + DWARF_32BIT_SIZE;
|
|
for ( i = 1; i < count; ++i,dp += DWARF_32BIT_SIZE) {
|
|
Dwarf_Unsigned gseca = 0;
|
|
Dwarf_Unsigned gsecb = 0;
|
|
struct generic_shdr* targpsh = 0;
|
|
|
|
memcpy(dblock,dp,DWARF_32BIT_SIZE);
|
|
ASNAR(memcpy,gseca,dblock);
|
|
ASNAR(_dwarf_memcpy_swap_bytes,gsecb,dblock);
|
|
if (!gseca) {
|
|
free(data);
|
|
free(grouparray);
|
|
*errcode = DW_DLE_ELF_SECTION_GROUP_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
grouparray[i] = gseca;
|
|
if (gseca >= ep->f_loc_shdr.g_count) {
|
|
/* Might be confused endianness by
|
|
the compiler generating the SHT_GROUP.
|
|
This is pretty horrible. */
|
|
|
|
if (gsecb >= ep->f_loc_shdr.g_count) {
|
|
*errcode = DW_DLE_ELF_SECTION_GROUP_ERROR;
|
|
free(data);
|
|
free(grouparray);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
/* Ok. Yes, ugly. */
|
|
gseca = gsecb;
|
|
grouparray[i] = gseca;
|
|
}
|
|
targpsh = ep->f_shdr + gseca;
|
|
if (_dwarf_ignorethissection(targpsh->gh_namestring)){
|
|
continue;
|
|
}
|
|
if (targpsh->gh_section_group_number) {
|
|
/* multi-assignment to groups. Oops. */
|
|
free(data);
|
|
free(grouparray);
|
|
*errcode = DW_DLE_ELF_SECTION_GROUP_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
targpsh->gh_section_group_number =
|
|
ep->f_sg_next_group_number;
|
|
foundone = 1;
|
|
}
|
|
if (foundone) {
|
|
++ep->f_sg_next_group_number;
|
|
++ep->f_sht_group_type_section_count;
|
|
}
|
|
free(data);
|
|
psh->gh_sht_group_array = grouparray;
|
|
psh->gh_sht_group_array_count = count;
|
|
}
|
|
return DW_DLV_OK;
|
|
}
|
|
/* Does related things.
|
|
A) Counts the number of SHT_GROUP
|
|
and for each builds an array of the sections in the group
|
|
(which we expect are all DWARF-related)
|
|
and sets the group number in each mentioned section.
|
|
B) Counts the number of SHF_GROUP flags.
|
|
C) If gnu groups:
|
|
ensure all the DWARF sections marked with right group
|
|
based on A(we will mark unmarked as group 1,
|
|
DW_GROUPNUMBER_BASE).
|
|
D) If arm groups (SHT_GROUP zero, SHF_GROUP non-zero):
|
|
Check the relocations of all SHF_GROUP section
|
|
FIXME: algorithm needed.
|
|
|
|
If SHT_GROUP and SHF_GROUP this is GNU groups.
|
|
If no SHT_GROUP and have SHF_GROUP this is
|
|
arm cc groups and we must use relocation information
|
|
to identify the group members.
|
|
|
|
It seems(?) impossible for an object to have both
|
|
dwo sections and (SHF_GROUP or SHT_GROUP), but
|
|
we do not rule that out here. */
|
|
static int
|
|
_dwarf_elf_setup_all_section_groups(
|
|
dwarf_elf_object_access_internals_t *ep,
|
|
int *errcode)
|
|
{
|
|
struct generic_shdr* psh = 0;
|
|
Dwarf_Unsigned i = 0;
|
|
Dwarf_Unsigned count = 0;
|
|
int res = 0;
|
|
|
|
count = ep->f_loc_shdr.g_count;
|
|
psh = ep->f_shdr;
|
|
|
|
/* Does step A and step B */
|
|
for (i = 0; i < count; ++psh,++i) {
|
|
const char *name = psh->gh_namestring;
|
|
|
|
if (is_empty_section(psh->gh_type)) {
|
|
/* No data here. */
|
|
continue;
|
|
}
|
|
if (!elf_sht_groupsec(psh->gh_type,name)) {
|
|
/* Step B */
|
|
if (elf_flagmatches(psh->gh_flags,SHF_GROUP)) {
|
|
ep->f_shf_group_flag_section_count++;
|
|
}
|
|
continue;
|
|
}
|
|
/* Looks like a section group. Do Step A. */
|
|
res =read_gs_section_group(ep,psh,errcode);
|
|
if (res != DW_DLV_OK) {
|
|
return res;
|
|
}
|
|
}
|
|
/* Any sections not marked above or here are in
|
|
grep DW_GROUPNUMBER_BASE (1).
|
|
Section C. */
|
|
psh = ep->f_shdr;
|
|
for (i = 0; i < count; ++psh,++i) {
|
|
const char *name = psh->gh_namestring;
|
|
int is_rel = FALSE;
|
|
int is_rela = FALSE;
|
|
|
|
if (is_empty_section(psh->gh_type)) {
|
|
/* No data here. */
|
|
continue;
|
|
}
|
|
if (elf_sht_groupsec(psh->gh_type,name)) {
|
|
continue;
|
|
}
|
|
/* Not a section group */
|
|
if (string_endswith(name,".dwo")) {
|
|
if (psh->gh_section_group_number) {
|
|
/* multi-assignment to groups. Oops. */
|
|
*errcode = DW_DLE_ELF_SECTION_GROUP_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
psh->gh_is_dwarf = TRUE;
|
|
psh->gh_section_group_number = DW_GROUPNUMBER_DWO;
|
|
ep->f_dwo_group_section_count++;
|
|
} else if (_dwarf_load_elf_section_is_dwarf(name,
|
|
&is_rela,&is_rel)) {
|
|
if (!psh->gh_section_group_number) {
|
|
psh->gh_section_group_number = DW_GROUPNUMBER_BASE;
|
|
}
|
|
psh->gh_is_dwarf = TRUE;
|
|
} else {
|
|
/* Do nothing. */
|
|
}
|
|
}
|
|
if (ep->f_sht_group_type_section_count) {
|
|
/* Not ARM. Done. */
|
|
}
|
|
if (!ep->f_shf_group_flag_section_count) {
|
|
/* Nothing more to do. */
|
|
return DW_DLV_OK;
|
|
}
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
static int
|
|
_dwarf_elf_find_sym_sections(
|
|
dwarf_elf_object_access_internals_t *ep,
|
|
int *errcode)
|
|
{
|
|
struct generic_shdr* psh = 0;
|
|
Dwarf_Unsigned i = 0;
|
|
Dwarf_Unsigned count = 0;
|
|
int res = 0;
|
|
|
|
count = ep->f_loc_shdr.g_count;
|
|
psh = ep->f_shdr;
|
|
for (i = 0; i < count; ++psh,++i) {
|
|
const char *name = psh->gh_namestring;
|
|
if (is_empty_section(psh->gh_type)) {
|
|
/* No data here. */
|
|
continue;
|
|
}
|
|
if (!strcmp(name,".dynsym")) {
|
|
ep->f_dynsym_sect_index = i;
|
|
ep->f_loc_dynsym.g_offset = psh->gh_offset;
|
|
} else if (!strcmp(name,".dynstr")) {
|
|
ep->f_dynsym_sect_strings_sect_index = i;
|
|
ep->f_dynsym_sect_strings_max = psh->gh_size;
|
|
} else if (!strcmp(name,".symtab")) {
|
|
ep->f_symtab_sect_index = i;
|
|
ep->f_loc_symtab.g_offset = psh->gh_offset;
|
|
} else if (!strcmp(name,".strtab")) {
|
|
ep->f_symtab_sect_strings_sect_index = i;
|
|
ep->f_symtab_sect_strings_max = psh->gh_size;
|
|
} else if (!strcmp(name,".dynamic")) {
|
|
ep->f_dynamic_sect_index = i;
|
|
ep->f_loc_dynamic.g_offset = psh->gh_offset;
|
|
}
|
|
}
|
|
res = validate_links(ep,ep->f_symtab_sect_index,
|
|
ep->f_symtab_sect_strings_sect_index,errcode);
|
|
if (res!= DW_DLV_OK) {
|
|
return res;
|
|
}
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
int
|
|
_dwarf_load_elf_sectheaders(
|
|
dwarf_elf_object_access_internals_t *ep,int*errcode)
|
|
{
|
|
int res = 0;
|
|
|
|
if (ep->f_offsetsize == 32) {
|
|
res = elf_load_sectheaders32(ep,ep->f_ehdr->ge_shoff,
|
|
ep->f_ehdr->ge_shentsize,
|
|
ep->f_ehdr->ge_shnum,errcode);
|
|
} else if (ep->f_offsetsize == 64) {
|
|
res = elf_load_sectheaders64(ep,ep->f_ehdr->ge_shoff,
|
|
ep->f_ehdr->ge_shentsize,
|
|
ep->f_ehdr->ge_shnum,errcode);
|
|
} else {
|
|
*errcode = DW_DLE_OFFSET_SIZE;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (res != DW_DLV_OK) {
|
|
return res;
|
|
}
|
|
res = _dwarf_elf_load_sectstrings(ep,
|
|
ep->f_ehdr->ge_shstrndx,errcode);
|
|
if (res != DW_DLV_OK) {
|
|
return res;
|
|
}
|
|
res = _dwarf_elf_load_sect_namestring(ep,errcode);
|
|
if (res != DW_DLV_OK) {
|
|
return res;
|
|
}
|
|
res = _dwarf_elf_find_sym_sections(ep,errcode);
|
|
if (res != DW_DLV_OK) {
|
|
return res;
|
|
}
|
|
res = _dwarf_elf_setup_all_section_groups(ep,errcode);
|
|
return res;
|
|
}
|