2116 lines
60 KiB
C
2116 lines
60 KiB
C
/*
|
|
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. */
|
|
|
|
|
|
#include "config.h"
|
|
#include <stdio.h>
|
|
#include <string.h> /* For memcpy etc */
|
|
#include <stdlib.h>
|
|
#include <stddef.h>
|
|
#include <sys/types.h> /* for open() */
|
|
#include <sys/stat.h> /* for open() */
|
|
#include <fcntl.h> /* for open() */
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h> /* lseek read close */
|
|
#elif defined(_WIN32) && defined(_MSC_VER)
|
|
#include <io.h>
|
|
#endif /* HAVE_UNISTD_H */
|
|
|
|
/* Windows specific header files */
|
|
#if defined(_WIN32) && defined(HAVE_STDAFX_H)
|
|
#include "stdafx.h"
|
|
#endif /* HAVE_STDAFX_H */
|
|
|
|
#include "libdwarfdefs.h"
|
|
#include "dwarf.h"
|
|
#include "libdwarf.h"
|
|
#include "dwarf_base_types.h"
|
|
#include "dwarf_opaque.h"
|
|
#include "memcpy_swap.h"
|
|
#include "dwarf_elfstructs.h"
|
|
#include "dwarf_reading.h"
|
|
#include "dwarf_elf_defines.h"
|
|
#include "dwarf_elfread.h"
|
|
#include "dwarf_object_detector.h"
|
|
#include "dwarf_object_read_common.h"
|
|
#include "dwarf_util.h"
|
|
|
|
#ifndef O_BINARY
|
|
#define O_BINARY 0
|
|
#endif /* O_BINARY */
|
|
|
|
#ifdef HAVE_UNUSED_ATTRIBUTE
|
|
#define UNUSEDARG __attribute__ ((unused))
|
|
#else
|
|
#define UNUSEDARG
|
|
#endif
|
|
#define TRUE 1
|
|
#define FALSE 0
|
|
|
|
#ifdef WORDS_BIGENDIAN
|
|
#define ASNAR(func,t,s) \
|
|
do { \
|
|
unsigned tbyte = sizeof(t) - sizeof(s); \
|
|
t = 0; \
|
|
func(((char *)&t)+tbyte ,&s[0],sizeof(s)); \
|
|
} while (0)
|
|
#else /* LITTLE ENDIAN */
|
|
#define ASNAR(func,t,s) \
|
|
do { \
|
|
t = 0; \
|
|
func(&t,&s[0],sizeof(s)); \
|
|
} while (0)
|
|
#endif /* end LITTLE- BIG-ENDIAN */
|
|
|
|
static int
|
|
_dwarf_load_elf_section_is_dwarf(const char *sname)
|
|
{
|
|
if (!strncmp(sname,".rel",4)) {
|
|
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;
|
|
}
|
|
|
|
#if 0
|
|
int
|
|
dwarf_construct_elf_access_path(const char *path,
|
|
dwarf_elf_object_access_internals_t **mp,int *errcode)
|
|
{
|
|
int fd = -1;
|
|
int res = 0;
|
|
dwarf_elf_object_access_internals_t *mymp = 0;
|
|
|
|
fd = open(path, O_RDONLY|O_BINARY);
|
|
if (fd < 0) {
|
|
*errcode = DW_DLE_PATH_SIZE_TOO_SMALL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
res = dwarf_construct_elf_access(fd,
|
|
path,&mymp,errcode);
|
|
if (res != DW_DLV_OK) {
|
|
close(fd);
|
|
return res;
|
|
}
|
|
mymp->f_destruct_close_fd = TRUE;
|
|
*mp = mymp;
|
|
return res;
|
|
}
|
|
#endif /* 0 */
|
|
|
|
/* Here path is not essential. Pass in with "" if unknown. */
|
|
int
|
|
dwarf_construct_elf_access(int fd,
|
|
const char *path,
|
|
dwarf_elf_object_access_internals_t **mp,int *errcode)
|
|
{
|
|
unsigned ftype = 0;
|
|
unsigned endian = 0;
|
|
unsigned offsetsize = 0;
|
|
Dwarf_Unsigned filesize = 0;
|
|
dwarf_elf_object_access_internals_t *mfp = 0;
|
|
int res = 0;
|
|
|
|
res = dwarf_object_detector_fd(fd,
|
|
&ftype,&endian,&offsetsize, &filesize, errcode);
|
|
if (res != DW_DLV_OK) {
|
|
return res;
|
|
}
|
|
|
|
mfp = calloc(1,sizeof(dwarf_elf_object_access_internals_t));
|
|
if (!mfp) {
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
/* For non-libelf Elf, call it 'F'. Libelf Elf uses 'E' */
|
|
mfp->f_ident[0] = 'F';
|
|
mfp->f_ident[1] = 1;
|
|
mfp->f_fd = fd;
|
|
mfp->f_destruct_close_fd = FALSE;
|
|
mfp->f_is_64bit = ((offsetsize==64)?TRUE:FALSE);
|
|
mfp->f_filesize = filesize;
|
|
mfp->f_offsetsize = offsetsize;
|
|
mfp->f_pointersize = offsetsize;
|
|
mfp->f_endian = endian;
|
|
mfp->f_ftype = ftype;
|
|
mfp->f_path = strdup(path);
|
|
|
|
*mp = mfp;
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
/* Caller must zero the passed in pointer
|
|
after this returns to remind
|
|
the caller to avoid use of the pointer. */
|
|
int
|
|
dwarf_destruct_elf_access(dwarf_elf_object_access_internals_t* ep,
|
|
UNUSEDARG int *errcode)
|
|
{
|
|
struct generic_shdr *shp = 0;
|
|
Dwarf_Unsigned shcount = 0;
|
|
Dwarf_Unsigned i = 0;
|
|
|
|
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);
|
|
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);
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
generic_ehdr_from_32(dwarf_elf_object_access_internals_t *ep,
|
|
struct generic_ehdr *ehdr, dw_elf32_ehdr *e,
|
|
UNUSEDARG 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);
|
|
ep->f_machine = 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,
|
|
UNUSEDARG 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);
|
|
ep->f_machine = 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 /* not used */
|
|
|
|
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_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(psh);
|
|
free(gshdr);
|
|
return res;
|
|
}
|
|
for(i = 0; i < count;
|
|
++i, psh++,gshdr++) {
|
|
gshdr->gh_secnum = i;
|
|
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);
|
|
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 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;
|
|
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(psh);
|
|
free(gshdr);
|
|
return res;
|
|
}
|
|
for( i = 0; i < count;
|
|
++i, psh++,gshdr++) {
|
|
gshdr->gh_secnum = i;
|
|
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);
|
|
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_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_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,
|
|
int 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 (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
|
|
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;
|
|
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;
|
|
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 != size2) {
|
|
*errcode = DW_DLE_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_isrela = TRUE;
|
|
grel->gr_sym = grel->gr_info>>8; /* ELF32_R_SYM */
|
|
grel->gr_type = grel->gr_info & 0xff;
|
|
}
|
|
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_OBJECT_LSB);
|
|
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 != size2) {
|
|
*errcode = DW_DLE_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_isrela = TRUE;
|
|
}
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
#if 0
|
|
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 != size2) {
|
|
*errcode = DW_DLE_SECTION_SIZE_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
for ( i = 0; i < ecount; ++i,++relp,++grel) {
|
|
grel->gr_isrela = 0;
|
|
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_isrela = FALSE;
|
|
grel->gr_type = grel->gr_info & 0xff;
|
|
}
|
|
return DW_DLV_OK;
|
|
}
|
|
#endif /* 0 */
|
|
|
|
#if 0
|
|
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_OBJECT_LSB);
|
|
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 != size2) {
|
|
*errcode = DW_DLE_SECTION_SIZE_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
for ( i = 0; i < ecount; ++i,++relp,++grel) {
|
|
grel->gr_isrela = 0;
|
|
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_isrela = FALSE;
|
|
|
|
}
|
|
return DW_DLV_OK;
|
|
}
|
|
#endif /* 0 */
|
|
|
|
#if 0
|
|
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. */
|
|
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(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 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;
|
|
int res = 0;
|
|
|
|
|
|
if(count == 0) {
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
if(entsize < sizeof(dw_elf32_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_FILE_OFFSET_BAD;
|
|
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 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;
|
|
int res = 0;
|
|
|
|
|
|
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_FILE_OFFSET_BAD;
|
|
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_rela_32(
|
|
dwarf_elf_object_access_internals_t *ep,
|
|
struct generic_shdr * gsh,
|
|
struct generic_rela ** grel_out,
|
|
Dwarf_Unsigned *count_out, 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;
|
|
dw_elf32_rela *relp = 0;
|
|
Dwarf_Unsigned object_reclen = sizeof(dw_elf32_rela);
|
|
struct generic_rela *grel = 0;
|
|
|
|
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_FILE_OFFSET_BAD;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
count = (long)(size/object_reclen);
|
|
size2 = count * object_reclen;
|
|
if(size != size2) {
|
|
*errcode = DW_DLE_SECTION_SIZE_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
relp = (dw_elf32_rela *)malloc(size);
|
|
if(!relp) {
|
|
*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);
|
|
return res;
|
|
}
|
|
sizeg = count*sizeof(struct generic_rela);
|
|
grel = (struct generic_rela *)malloc(sizeg);
|
|
if (!grel) {
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
res = generic_rel_from_rela32(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;
|
|
}
|
|
|
|
#if 0
|
|
static int
|
|
_dwarf_elf_load_rel_32(
|
|
dwarf_elf_object_access_internals_t *ep,
|
|
struct generic_shdr * gsh,struct generic_rela ** grel_out,
|
|
Dwarf_Unsigned *count_out,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;
|
|
dw_elf32_rel* relp = 0;
|
|
Dwarf_Unsigned object_reclen = sizeof(dw_elf32_rel);
|
|
struct generic_rela *grel = 0;
|
|
|
|
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_FILE_OFFSET_BAD;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
count = size/object_reclen;
|
|
size2 = count * object_reclen;
|
|
if(size != size2) {
|
|
*errcode = DW_DLE_SECTION_SIZE_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
relp = (dw_elf32_rel *)malloc(size);
|
|
if(!relp) {
|
|
*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);
|
|
return res;
|
|
}
|
|
sizeg = count *sizeof(struct generic_rela);
|
|
grel = (struct generic_rela *)malloc(sizeg);
|
|
if (!grel) {
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
res = generic_rel_from_rel32(ep,gsh,relp,grel,errcode);
|
|
free(relp);
|
|
if (res == DW_DLV_OK) {
|
|
*count_out = count;
|
|
*grel_out = grel;
|
|
return res;
|
|
}
|
|
/* Some sort of error */
|
|
count_out = 0;
|
|
free (grel);
|
|
return res;
|
|
}
|
|
#endif /* 0 */
|
|
|
|
#if 0
|
|
static int
|
|
_dwarf_elf_load_rel_64(
|
|
dwarf_elf_object_access_internals_t *ep,
|
|
struct generic_shdr * gsh,struct generic_rela ** grel_out,
|
|
Dwarf_Unsigned *count_out,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;
|
|
dw_elf64_rel* relp = 0;
|
|
Dwarf_Unsigned object_reclen = sizeof(dw_elf64_rel);
|
|
struct generic_rela *grel = 0;
|
|
|
|
offset = gsh->gh_offset;
|
|
size = gsh->gh_size;
|
|
if(size == 0) {
|
|
*errcode = DW_DLE_SECTION_SIZE_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if ((offset > ep->f_filesize)||
|
|
(size > ep->f_filesize) ||
|
|
((size +offset) > ep->f_filesize)) {
|
|
*errcode = DW_DLE_FILE_OFFSET_BAD;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
count = size/object_reclen;
|
|
size2 = count * object_reclen;
|
|
if(size != size2) {
|
|
*errcode = DW_DLE_SECTION_SIZE_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
relp = (dw_elf64_rel *)malloc(size);
|
|
if(!relp) {
|
|
*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);
|
|
return res;
|
|
}
|
|
sizeg = count*sizeof(struct generic_rela);
|
|
grel = (struct generic_rela *)malloc(sizeg);
|
|
if (!grel) {
|
|
free(relp);
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
res = generic_rel_from_rel64(ep,gsh,relp,grel,errcode);
|
|
free(relp);
|
|
if (res == DW_DLV_OK) {
|
|
*count_out = count;
|
|
*grel_out = grel;
|
|
return res;
|
|
}
|
|
/* Some sort of error */
|
|
count_out = 0;
|
|
free (grel);
|
|
return res;
|
|
}
|
|
#endif /* 0 */
|
|
|
|
|
|
static int
|
|
_dwarf_elf_load_rela_64(
|
|
dwarf_elf_object_access_internals_t *ep,
|
|
struct generic_shdr * gsh,
|
|
struct generic_rela ** grel_out,
|
|
Dwarf_Unsigned *count_out,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;
|
|
dw_elf64_rela *relp = 0;
|
|
Dwarf_Unsigned object_reclen = sizeof(dw_elf64_rela);
|
|
struct generic_rela *grel = 0;
|
|
|
|
offset = gsh->gh_offset;
|
|
size = gsh->gh_size;
|
|
if(size == 0) {
|
|
*errcode = DW_DLE_SECTION_SIZE_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if ((offset > ep->f_filesize)||
|
|
(size > ep->f_filesize) ||
|
|
((size +offset) > ep->f_filesize)) {
|
|
*errcode = DW_DLE_FILE_OFFSET_BAD;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
count = (long)(size/object_reclen);
|
|
size2 = count * object_reclen;
|
|
if(size != size2) {
|
|
*errcode = DW_DLE_SECTION_SIZE_ERROR;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
/* Here want native rela size from the file */
|
|
relp = (dw_elf64_rela *)malloc(size);
|
|
if(!relp) {
|
|
*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);
|
|
return res;
|
|
}
|
|
sizeg = count*sizeof(struct generic_rela);
|
|
/* Here want generic-record size from the file */
|
|
grel = (struct generic_rela *)malloc(sizeg);
|
|
if (!grel) {
|
|
free(relp);
|
|
*errcode = DW_DLE_ALLOC_FAIL;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
res = generic_rel_from_rela64(ep,gsh,relp,grel,errcode);
|
|
free(relp);
|
|
if (res == DW_DLV_OK) {
|
|
*count_out = count;
|
|
*grel_out = grel;
|
|
return res;
|
|
}
|
|
/* Some sort of error */
|
|
count_out = 0;
|
|
free (grel);
|
|
return res;
|
|
}
|
|
|
|
/* Is this 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_is_a_section_dwarf_related(
|
|
dwarf_elf_object_access_internals_t *ep,
|
|
struct generic_shdr *gshdr,
|
|
unsigned *oksecnum_out,
|
|
int *errcode)
|
|
{
|
|
unsigned oksecnum = 0;
|
|
struct generic_shdr *gstarg = 0;
|
|
|
|
if (gshdr->gh_type != SHT_RELA ) {
|
|
*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 = oksecnum;
|
|
return DW_DLV_OK;
|
|
}
|
|
/* Secnum here is the secnum of rela. Not
|
|
the target of the relocations. */
|
|
int
|
|
_dwarf_load_elf_rela(
|
|
dwarf_elf_object_access_internals_t *ep,
|
|
Dwarf_Unsigned secnum,
|
|
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;
|
|
|
|
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_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.
|
|
Others get ignored. */
|
|
if (offsetsize == 32) {
|
|
res = _dwarf_elf_load_rela_32(ep,
|
|
gshdr,&grp,&count_read,errcode);
|
|
} else if (offsetsize == 64) {
|
|
res = _dwarf_elf_load_rela_64(ep,
|
|
gshdr,&grp,&count_read,errcode);
|
|
} else {
|
|
*errcode = DW_DLE_OFFSET_SIZE;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
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;
|
|
}
|
|
#if 0
|
|
int
|
|
_dwarf_load_elf_rel(
|
|
dwarf_elf_object_access_internals_t *ep,
|
|
Dwarf_Unsigned secnum, int *errcode)
|
|
{
|
|
struct generic_shdr *gshdr = 0;
|
|
Dwarf_Unsigned generic_count = 0;
|
|
unsigned offsetsize = 0;
|
|
struct generic_rela *grp = 0;
|
|
Dwarf_Unsigned count_read = 0;
|
|
int res = 0;
|
|
|
|
if (!ep) {
|
|
*errcode = DW_DLE_INTERNAL_NULL_POINTER;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
offsetsize = ep->f_offsetsize;
|
|
generic_count = ep->f_loc_shdr.g_count;
|
|
if (secnum >= generic_count) {
|
|
*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;
|
|
}
|
|
if (offsetsize == 32) {
|
|
res = _dwarf_elf_load_rel_32(ep,
|
|
gshdr,&grp,&count_read,errcode);
|
|
} else if (offsetsize == 64) {
|
|
res = _dwarf_elf_load_rel_64(ep,
|
|
gshdr,&grp,&count_read,errcode);
|
|
} else {
|
|
*errcode = DW_DLE_OFFSET_SIZE;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
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;
|
|
}
|
|
#endif /* 0 */
|
|
|
|
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;
|
|
}
|
|
|
|
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 =
|
|
"<Invalid sh_name value. Corrupt Elf.>";
|
|
int res = 0;
|
|
|
|
res = validate_section_name_string(ep->f_elf_shstrings_length,
|
|
gshdr->gh_name, stringsecbase,
|
|
errcode);
|
|
if (res != DW_DLV_OK) {
|
|
gshdr->gh_namestring = namestr;
|
|
return res;
|
|
}
|
|
gshdr->gh_namestring = stringsecbase + gshdr->gh_name;
|
|
}
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
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);
|
|
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;
|
|
|
|
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);
|
|
return res;
|
|
}
|
|
|
|
static int
|
|
validate_struct_sizes(
|
|
#ifdef HAVE_ELF_H
|
|
int*errcode
|
|
#else
|
|
UNUSEDARG int*errcode
|
|
#endif
|
|
)
|
|
{
|
|
#ifdef HAVE_ELF_H
|
|
/* This is a sanity check when we have an elf.h
|
|
to check against. */
|
|
if (sizeof(Elf32_Ehdr) != sizeof(dw_elf32_ehdr)) {
|
|
*errcode = DW_DLE_BAD_TYPE_SIZE;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (sizeof(Elf64_Ehdr) != sizeof(dw_elf64_ehdr)) {
|
|
*errcode = DW_DLE_BAD_TYPE_SIZE;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (sizeof(Elf32_Shdr) != sizeof(dw_elf32_shdr)) {
|
|
*errcode = DW_DLE_BAD_TYPE_SIZE;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (sizeof(Elf64_Shdr) != sizeof(dw_elf64_shdr)) {
|
|
*errcode = DW_DLE_BAD_TYPE_SIZE;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (sizeof(Elf32_Phdr) != sizeof(dw_elf32_phdr)) {
|
|
*errcode = DW_DLE_BAD_TYPE_SIZE;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (sizeof(Elf64_Phdr) != sizeof(dw_elf64_phdr)) {
|
|
*errcode = DW_DLE_BAD_TYPE_SIZE;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (sizeof(Elf32_Rel) != sizeof(dw_elf32_rel)) {
|
|
*errcode = DW_DLE_BAD_TYPE_SIZE;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (sizeof(Elf64_Rel) != sizeof(dw_elf64_rel)) {
|
|
*errcode = DW_DLE_BAD_TYPE_SIZE;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (sizeof(Elf32_Rela) != sizeof(dw_elf32_rela)) {
|
|
*errcode = DW_DLE_BAD_TYPE_SIZE;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (sizeof(Elf64_Rela) != sizeof(dw_elf64_rela)) {
|
|
*errcode = DW_DLE_BAD_TYPE_SIZE;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (sizeof(Elf32_Sym) != sizeof(dw_elf32_sym)) {
|
|
*errcode = DW_DLE_BAD_TYPE_SIZE;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (sizeof(Elf64_Sym) != sizeof(dw_elf64_sym)) {
|
|
*errcode = DW_DLE_BAD_TYPE_SIZE;
|
|
return DW_DLV_ERROR;
|
|
}
|
|
#endif /* HAVE_ELF_H */
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
int
|
|
_dwarf_load_elf_header(
|
|
dwarf_elf_object_access_internals_t *ep,int*errcode)
|
|
{
|
|
unsigned offsetsize = ep->f_offsetsize;
|
|
int res = 0;
|
|
|
|
res = validate_struct_sizes(errcode);
|
|
if (res != DW_DLV_OK) {
|
|
return res;
|
|
}
|
|
|
|
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)
|
|
{
|
|
unsigned long len = strlen(n);
|
|
unsigned long 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. */
|
|
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;
|
|
int foundone = 0;
|
|
|
|
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;
|
|
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;
|
|
}
|
|
|
|
if (psh->gh_entsize != DWARF_32BIT_SIZE) {
|
|
*errcode = DW_DLE_ELF_SECTION_GROUP_ERROR;
|
|
free(data);
|
|
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;
|
|
}
|
|
grouparray = malloc(count * sizeof(Dwarf_Unsigned));
|
|
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;
|
|
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 (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;
|
|
|
|
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)) {
|
|
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;
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
res = validate_links(ep,ep->f_dynsym_sect_index,
|
|
ep->f_dynsym_sect_strings_sect_index,errcode);
|
|
if (res!= DW_DLV_OK) {
|
|
return res;
|
|
}
|
|
#endif /* 0 */
|
|
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;
|
|
}
|