UWelfviewer
/* $Id: UWelfviewer.c,v 1.3 2010/10/20 00:12:43 khorben Exp $ */
/* ELF file parser
* UberWall security team \../. .\../ */
/* Copyright (c) 2010 khorben of UberWall */
/* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* FIXME:
* - list the libraries required, RPATH set, etc */
#include <unistd.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#ifdef _LP64
# define ELFSIZE 64
# define bswap(a) bswap64(a)
#else
# define ELFSIZE 32
# define bswap(a) bswap32(a)
#endif
#include <elf.h>
#include "config.h"
/* SI */
/* protected */
/* types */
typedef struct _SI
{
unsigned long index;
char const * string;
} SI;
/* prototypes */
static char const * _si_get(SI * si, unsigned long index);
/* UWelfviewer */
/* private */
/* variables */
static SI _si_class[] =
{
{ ELFCLASSNONE, "ELFCLASSNONE" },
{ ELFCLASS32, "ELFCLASS32" },
{ ELFCLASS64, "ELFCLASS64" },
{ 0, NULL }
};
static SI _si_data[] =
{
{ ELFDATANONE, "ELFDATANONE" },
{ ELFDATA2LSB, "ELFDATA2LSB" },
{ ELFDATA2MSB, "ELFDATA2MSB" },
{ 0, NULL }
};
static SI _si_type[] =
{
{ 0, "ET_NONE" },
{ 1, "ET_REL" },
{ 2, "ET_EXEC" },
{ 3, "ET_DYN" },
{ 4, "ET_CORE" },
{ 0xff00,"ET_LOPROC" },
{ 0xffff,"ET_HIPROC" },
{ 0, NULL }
};
static SI _si_machine[] =
{
{ 0, "EM_NONE" },
{ 1, "EM_M32" },
{ 2, "EM_SPARC" },
{ 3, "EM_386" },
{ 4, "EM_68K" },
{ 5, "EM_88K" },
{ 7, "EM_860" },
{ 8, "EM_MIPS" },
{ 43, "EM_SPARCV9" },
{ 62, "EM_X86_64" },
{ 0, NULL }
};
static SI _si_version[] =
{
{ 0, "EV_NONE" },
{ 1, "EV_CURRENT" },
{ 0, NULL }
};
static SI _si_ptype[] =
{
{ 0, "PT_NULL" },
{ 1, "PT_LOAD" },
{ 2, "PT_DYNAMIC" },
{ 3, "PT_INTERP" },
{ 4, "PT_NOTE" },
{ 5, "PT_SHLIB" },
{ 6, "PT_PHDR" },
{ 0, NULL }
};
static SI _si_dtag[] =
{
{ 0, "DT_NULL" },
{ 1, "DT_NEEDED" },
{ 2, "DT_PLTRELSZ" },
{ 3, "DT_PLTGOT" },
{ 4, "DT_HASH" },
{ 5, "DT_STRTAB" },
{ 6, "DT_SYMTAB" },
{ 7, "DT_RELA" },
{ 8, "DT_RELASZ" },
{ 9, "DT_RELAENT" },
{ 10, "DT_STRSZ" },
{ 11, "DT_SYMENT" },
{ 12, "DT_INIT" },
{ 13, "DT_FINI" },
{ 14, "DT_SONAME" },
{ 15, "DT_RPATH" },
{ 16, "DT_SYMBOLIC" },
{ 17, "DT_REL" },
{ 18, "DT_RELSZ" },
{ 19, "DT_RELENT" },
{ 20, "DT_PLTREL" },
{ 21, "DT_DEBUG" },
{ 22, "DT_TEXTREL" },
{ 23, "DT_JMPREL" },
{ 24, "DT_BIND_NOW" },
{ 25, "DT_INIT_ARRAY" },
{ 26, "DT_FINI_ARRAY" },
{ 27, "DT_INIT_ARRAYSZ" },
{ 28, "DT_FINI_ARRAYSZ" },
{ 29, "DT_NUM" },
{ 0x60000000, "DT_LOOS" },
{ 0x6ffffff0, "DT_VERSYM" },
{ 0x6ffffffb, "DT_FLAGS_1" },
{ 0x6ffffffc, "DT_VERDEF" },
{ 0x6ffffffd, "DT_VERDEFNUM" },
{ 0x6ffffffe, "DT_VERNEED" },
{ 0x6fffffff, "DT_VERNEEDNUM" },
{ 0x6fffffff, "DT_HIOS" },
{ 0x70000000, "DT_LOPROC" },
{ 0x7fffffff, "DT_HIPROC" },
{ 0, NULL }
};
static SI _si_shtype[] =
{
{ 0, "SHT_NULL" },
{ 1, "SHT_PROGBITS" },
{ 2, "SHT_SYMTAB" },
{ 3, "SHT_STRTAB" },
{ 4, "SHT_RELA" },
{ 5, "SHT_HASH" },
{ 6, "SHT_DYNAMIC" },
{ 7, "SHT_NOTE" },
{ 8, "SHT_NOBITS" },
{ 9, "SHT_REL" },
{ 10, "SHT_SHLIB" },
{ 11, "SHT_DYNSYM" },
{ 0, NULL }
};
static SI _si_symtype[] =
{
{ 0, "STT_NOTYPE" },
{ 1, "STT_OBJECT" },
{ 2, "STT_FUNC" },
{ 3, "STT_SECTION" },
{ 4, "STT_FILE" },
{ 5, "STT_NUM" },
{ 10, "STT_LOOS" },
{ 12, "STT_HIOS" },
{ 13, "STT_LOPROC" },
{ 15, "STT_HIPROC" },
{ 0, NULL }
};
static SI _si_rtype[] =
{
{ 0, "R_386_NONE" },
{ 1, "R_386_32" },
{ 2, "R_386_PC32" },
{ 3, "R_386_GOT32" },
{ 4, "R_386_PLT32" },
{ 5, "R_386_COPY" },
{ 6, "R_386_GLOB_DAT" },
{ 7, "R_386_JMP_SLOT" },
{ 8, "R_386_RELATIVE" },
{ 9, "R_386_GOTOFF" },
{ 9, "R_SPARC_HI22" },
{ 10, "R_386_GOTPC" },
{ 11, "R_386_32PLT" },
{ 19, "R_SPARC_COPY" },
{ 20, "R_SPARC_GLOB_DAT" },
{ 21, "R_SPARC_JMP_SLOT" },
{ 22, "R_SPARC_RELATIVE" },
{ 32, "R_SPARC_64" },
{ 33, "R_SPARC_OLO10" },
{ 46, "R_SPARC_DISP64" },
{ 47, "R_SPARC_PLT64" },
{ 53, "R_SPARC_REGISTER" },
{ 54, "R_SPARC_UA64" },
{ 0, NULL }
};
/* prototypes */
static int _UWelfviewer(char const * pathname);
static int _UWelfviewer_do(FILE * fp, char const * pathname);
static int _UWelfviewer_error(char const * format, ...);
static int _usage(void);
/* SI */
/* protected */
/* functions */
static char const * _si_get(SI * si, unsigned long index)
{
static char buf[32];
if(si != NULL)
for(; si->string != NULL; si++)
if(si->index == index)
return si->string;
snprintf(buf, sizeof(buf), "UNKNOWN (%lu)", index);
return buf;
}
/* UWelfviewer */
/* private */
/* functions */
/* UWelfviewer */
static int _UWelfviewer(char const * pathname)
{
int ret;
FILE * fp;
if((fp = fopen(pathname, "r")) == NULL)
return _UWelfviewer_error("%s: %s", pathname, strerror(errno));
ret = _UWelfviewer_do(fp, pathname);
if(fclose(fp) != 0)
return _UWelfviewer_error("%s: %s", pathname, strerror(errno));
return ret;
}
/* UWelfviewer_error */
static int _UWelfviewer_error(char const * format, ...)
{
va_list ap;
fputs(PACKAGE ": ", stderr);
va_start(ap, format);
vfprintf(stderr, format, ap);
va_end(ap);
fputc('\n', stderr);
return 1;
}
/* UWelfviewer_do */
/* elf header */
static int _do_ehdr(FILE * fp, char const * pathname, Elf_Ehdr * ehdr);
static void _ehdr_print(Elf_Ehdr * ehdr);
/* program table */
static int _do_phdr(FILE * fp, char const * pathname, Elf_Ehdr * ehdr,
Elf_Phdr ** phdr, size_t * phdr_cnt);
static void _phdr_print(Elf_Phdr * phdr);
static void _phdr_dyn_print(FILE * fp, Elf_Phdr * phdr);
static char const * _phdr_flags(uint32_t flags);
/* section table */
static int _do_shdr(FILE * fp, char const * pathname, Elf_Ehdr * ehdr,
Elf_Shdr ** shdr, size_t * shdr_cnt, char ** shstrtab,
size_t * shstrtab_cnt);
static void _shdr_print(Elf_Shdr * shdr, char const * strtab,
size_t strtab_cnt);
static char const * _shdr_flags(uint64_t flags);
/* string sections */
static int _do_strtab(FILE * fp, char const * pathname, Elf_Shdr * shdr,
size_t shdr_cnt, uint16_t ndx, char ** strtab,
size_t * strtab_cnt);
static char const * _strtab_get(char const * strtab, size_t strtab_cnt,
unsigned long ndx);
/* symbol table */
static int _do_symtab(FILE * fp, char const * pathname, Elf_Shdr * shdr,
size_t shdr_cnt, uint16_t ndx, Elf_Sym ** symtab,
size_t * symtab_cnt, char const * shstrtab,
size_t shstrtab_cnt);
static void _symtab_print(Elf_Sym * sym, char const * strtab,
size_t strtab_cnt, Elf_Shdr * shdr, size_t shdr_cnt,
char const * shstrtab, size_t shstrtab_cnt);
/* relocations */
static int _do_rela(FILE * fp, char const * pathname, Elf_Ehdr * ehdr,
Elf_Shdr * shdr, size_t shdr_cnt);
static void _rela_print(Elf_Rela * rela, Elf_Sym * symtab, size_t symtab_cnt,
char const * symstrtab, size_t symstrtab_cnt);
static int _UWelfviewer_do(FILE * fp, char const * pathname)
{
int ret;
Elf_Ehdr ehdr;
Elf_Phdr * phdr = NULL;
size_t phdr_cnt = 0;
Elf_Shdr * shdr = NULL;
size_t shdr_cnt = 0;
char * shstrtab = NULL;
size_t shstrtab_cnt = 0;
uint16_t i;
Elf_Sym * symtab = NULL;
size_t symtab_cnt = 0;
if((ret = _do_ehdr(fp, pathname, &ehdr)) != 0)
return ret;
ret |= _do_phdr(fp, pathname, &ehdr, &phdr, &phdr_cnt);
ret |= _do_shdr(fp, pathname, &ehdr, &shdr, &shdr_cnt, &shstrtab,
&shstrtab_cnt);
for(i = 0; i < shdr_cnt; i++)
if(shdr[i].sh_type == SHT_SYMTAB)
{
ret |= _do_symtab(fp, pathname, shdr, shdr_cnt, i,
&symtab, &symtab_cnt, shstrtab,
shstrtab_cnt);
break;
}
ret |= _do_rela(fp, pathname, &ehdr, shdr, shdr_cnt);
free(phdr);
free(shdr);
free(shstrtab);
free(symtab);
return ret;
}
static int _do_ehdr(FILE * fp, char const * pathname, Elf_Ehdr * ehdr)
{
if(fread(ehdr, sizeof(*ehdr), 1, fp) != 1)
return _UWelfviewer_error("%s: %s", pathname, strerror(errno));
if(memcmp(ehdr->e_ident, ELFMAG, sizeof(ELFMAG) - 1) != 0)
return _UWelfviewer_error("%s: %s", pathname,
"Not an ELF file");
#if _BYTE_ORDER == _LITTLE_ENDIAN
if(ehdr->e_ident[EI_DATA] == ELFDATA2MSB)
#else
if(ehdr->e_ident[EI_DATA] == ELFDATA2LSB)
#endif
{
ehdr->e_type = bswap16(ehdr->e_type);
ehdr->e_machine = bswap16(ehdr->e_machine);
ehdr->e_version = bswap32(ehdr->e_version);
ehdr->e_entry = bswap(ehdr->e_entry);
ehdr->e_phoff = bswap(ehdr->e_phoff);
ehdr->e_ehsize = bswap16(ehdr->e_ehsize);
ehdr->e_phentsize = bswap16(ehdr->e_phentsize);
ehdr->e_phnum = bswap16(ehdr->e_phnum);
ehdr->e_shentsize = bswap16(ehdr->e_shentsize);
ehdr->e_shnum = bswap16(ehdr->e_shnum);
ehdr->e_shstrndx = bswap16(ehdr->e_shstrndx);
}
if(ehdr->e_ehsize != sizeof(*ehdr))
return _UWelfviewer_error("%s: %s", pathname,
"Unexpected ELF header size");
_ehdr_print(ehdr);
return 0;
}
static void _ehdr_print(Elf_Ehdr * ehdr)
{
printf("ELF %s file for %s, %s %s, version %s\n"
"Entrypoint: %010p, %u program table entries"
", %u sections\n",
_si_get(_si_type, ehdr->e_type),
_si_get(_si_machine, ehdr->e_machine),
_si_get(_si_data, ehdr->e_ident[EI_DATA]),
_si_get(_si_class, ehdr->e_ident[EI_CLASS]),
_si_get(_si_version, ehdr->e_version),
(void*)ehdr->e_entry, ehdr->e_phnum, ehdr->e_shnum);
}
static int _do_phdr(FILE * fp, char const * pathname, Elf_Ehdr * ehdr,
Elf_Phdr ** phdr, size_t * phdr_cnt)
{
size_t i;
if(ehdr->e_phnum == 0)
return 0;
if(ehdr->e_phentsize != sizeof(**phdr))
return _UWelfviewer_error("%s: %s", pathname,
"Unexpected program header size");
if(fseek(fp, ehdr->e_phoff, SEEK_SET) != 0)
return _UWelfviewer_error("%s: %s", pathname, strerror(errno));
/* no integer overflow: phentsize and phnum are shorts */
i = ehdr->e_phentsize * ehdr->e_phnum;
if((*phdr = malloc(i)) == NULL)
return _UWelfviewer_error("%s: %s", pathname, strerror(errno));
if(fread(*phdr, sizeof(**phdr), ehdr->e_phnum, fp) != ehdr->e_phnum)
{
free(*phdr);
*phdr = NULL;
return _UWelfviewer_error("%s: %s", pathname, strerror(errno));
}
*phdr_cnt = ehdr->e_phnum;
printf("\nListing program table at 0x%lx:\n"
"%-10s %-5s %-10s %-10s %-10s %-10s\n", ehdr->e_phoff,
"Type", "Flags", "Address", "Offset", "Size",
"Memory size");
for(i = 0; i < *phdr_cnt; i++)
_phdr_print((*phdr) + i);
for(i = 0; i < *phdr_cnt; i++)
if((*phdr)[i].p_type == PT_DYNAMIC)
_phdr_dyn_print(fp, &(*phdr)[i]);
return 0;
}
static void _phdr_print(Elf_Phdr * phdr)
{
unsigned long filesz = phdr->p_filesz;
unsigned long memsz = phdr->p_memsz;
printf("%-10s %-5s %010p %010p 0x%08lx 0x%08lx\n",
_si_get(_si_ptype, phdr->p_type),
_phdr_flags(phdr->p_flags), (void*)phdr->p_vaddr,
(void*)phdr->p_offset, filesz, memsz);
}
static char const * _phdr_flags(uint32_t flags)
{
static char buf[4];
buf[0] = flags & PF_R ? 'r' : '-';
buf[1] = flags & PF_W ? 'w' : '-';
buf[2] = flags & PF_X ? 'x' : '-';
return buf;
}
static void _phdr_dyn_print(FILE * fp, Elf_Phdr * phdr)
{
size_t i;
Elf_Dyn dyn;
if(fseek(fp, phdr->p_offset, SEEK_SET) != 0)
return; /* XXX report error */
printf("\nListing dynamic section at 0x%lx:\n"
"%-12s %-10s\n", phdr->p_offset, "Tag", "Value(s)");
for(i = 1; i < phdr->p_filesz; i+=sizeof(dyn))
{
if(fread(&dyn, sizeof(dyn), 1, fp) != 1)
continue; /* XXX report error */
if(dyn.d_tag == DT_NULL)
break;
printf("%-12s", _si_get(_si_dtag, dyn.d_tag));
switch(dyn.d_tag)
{
case DT_NEEDED:
case DT_PLTRELSZ:
case DT_RELASZ:
case DT_RELAENT:
case DT_STRSZ:
case DT_SYMENT:
case DT_SONAME:
case DT_RPATH:
case DT_RELSZ:
case DT_RELENT:
case DT_PLTREL:
printf(" %-10lu\n", dyn.d_un.d_val);
break;
case DT_PLTGOT:
case DT_HASH:
case DT_STRTAB:
case DT_SYMTAB:
case DT_RELA:
case DT_INIT:
case DT_FINI:
case DT_REL:
case DT_DEBUG:
case DT_JMPREL:
printf(" 0x%08lx\n", dyn.d_un.d_ptr);
break;
case DT_SYMBOLIC:
case DT_TEXTREL:
printf("\n");
break;
case DT_LOPROC:
case DT_HIPROC:
default:
printf(" %-10lu 0x%0lx\n", dyn.d_un.d_val,
dyn.d_un.d_ptr);
break;
}
}
}
static int _do_shdr(FILE * fp, char const * pathname, Elf_Ehdr * ehdr,
Elf_Shdr ** shdr, size_t * shdr_cnt, char ** shstrtab,
size_t * shstrtab_cnt)
{
size_t i;
if(ehdr->e_shnum == 0)
return 0;
if(ehdr->e_shentsize != sizeof(**shdr))
return _UWelfviewer_error("%s: %s", pathname,
"Unexpected section header size");
if(fseek(fp, ehdr->e_shoff, SEEK_SET) != 0)
return _UWelfviewer_error("%s: %s", pathname, strerror(errno));
/* no integer overflow: phentsize and phnum are shorts */
i = ehdr->e_shentsize * ehdr->e_shnum;
if((*shdr = malloc(i)) == NULL)
return _UWelfviewer_error("%s: %s", pathname, strerror(errno));
if(fread(*shdr, sizeof(**shdr), ehdr->e_shnum, fp) != ehdr->e_shnum)
{
free(*shdr);
*shdr = NULL;
return _UWelfviewer_error("%s: %s", pathname, strerror(errno));
}
/* load section name string table */
if(_do_strtab(fp, pathname, *shdr, ehdr->e_shnum, ehdr->e_shstrndx,
shstrtab, shstrtab_cnt) != 0)
{
free(*shdr);
*shdr = NULL;
return 1;
}
*shdr_cnt = ehdr->e_shnum;
printf("\nListing sections at 0x%lx:\n"
"%-19s %-12s %-5s %-10s %-10s %-10s %-4s %-4s %s\n",
ehdr->e_shoff, "Name", "Type", "Flags", "Address",
"Offset", "Size", "Link", "Info", "Entsize");
for(i = 0; i < *shdr_cnt; i++)
_shdr_print((*shdr) + i, *shstrtab, *shstrtab_cnt);
return 0;
}
static void _shdr_print(Elf_Shdr * shdr, char const * strtab, size_t strtab_cnt)
{
unsigned long size = shdr->sh_size;
unsigned long entsize = shdr->sh_entsize;
printf("%-19s %-12s %-5s %010p %010p 0x%08lx %-4u %-4u %lu\n",
_strtab_get(strtab, strtab_cnt, shdr->sh_name),
_si_get(_si_shtype, shdr->sh_type),
_shdr_flags(shdr->sh_flags), (void*)shdr->sh_addr,
(void*)shdr->sh_offset, size, shdr->sh_link,
shdr->sh_info, entsize);
}
static char const * _shdr_flags(uint64_t flags)
{
static char buf[5];
buf[0] = flags & SHF_MASKPROC ? 'm' : '-';
buf[1] = flags & SHF_ALLOC ? 'a' : '-';
buf[2] = flags & SHF_WRITE ? 'w' : '-';
buf[3] = flags & SHF_EXECINSTR ? 'x' : '-';
return buf;
}
static int _do_strtab(FILE * fp, char const * pathname, Elf_Shdr * shdr,
size_t shdr_cnt, uint16_t ndx, char ** strtab,
size_t * strtab_cnt)
{
if(ndx >= shdr_cnt)
return 1;
shdr = &shdr[ndx];
if(fseek(fp, shdr->sh_offset, SEEK_SET) != 0)
return _UWelfviewer_error("%s: %s", pathname, strerror(errno));
if((*strtab = malloc(shdr->sh_size)) == NULL)
return _UWelfviewer_error("%s: %s", pathname, strerror(errno));
if(fread(*strtab, 1, shdr->sh_size, fp) != shdr->sh_size)
{
free(*strtab);
*strtab = NULL;
return _UWelfviewer_error("%s: %s", pathname, strerror(errno));
}
*strtab_cnt = shdr->sh_size;
return 0;
}
static char const * _strtab_get(char const * strtab, size_t strtab_cnt,
unsigned long ndx)
{
static char buf[24];
if(ndx >= strtab_cnt || strtab == NULL || strtab_cnt == 0
|| strtab[strtab_cnt - 1] != '\0')
{
snprintf(buf, sizeof(buf), "UNKNOWN (%lu)", ndx);
return buf;
}
return &strtab[ndx];
}
static int _do_symtab(FILE * fp, char const * pathname, Elf_Shdr * shdr,
size_t shdr_cnt, uint16_t ndx, Elf_Sym ** symtab,
size_t * symtab_cnt, char const * shstrtab, size_t shstrtab_cnt)
{
size_t i;
size_t cnt;
char * strtab = NULL;
size_t strtab_cnt = 0;
if(ndx >= shdr_cnt)
return 1;
if(shdr[ndx].sh_entsize != sizeof(**symtab))
return _UWelfviewer_error("%s: %s", pathname,
"Unexpected symbol size");
if(shdr[ndx].sh_size % sizeof(**symtab) != 0)
return _UWelfviewer_error("%s: %s", pathname,
"Unexpected symbol table size");
cnt = shdr[ndx].sh_size / sizeof(**symtab);
if(fseek(fp, shdr[ndx].sh_offset, SEEK_SET) != 0)
return _UWelfviewer_error("%s: %s", pathname, strerror(errno));
if((*symtab = malloc(shdr[ndx].sh_size)) == NULL)
return _UWelfviewer_error("%s: %s", pathname, strerror(errno));
if(fread(*symtab, shdr[ndx].sh_size, 1, fp) != 1)
{
free(*symtab);
*symtab = NULL;
return _UWelfviewer_error("%s: %s", pathname, strerror(errno));
}
if(shstrtab == NULL)
{
/* XXX ugly hack: do not list anything */
*symtab_cnt = cnt;
return 0;
}
/* load symbol table string table */
if(_do_strtab(fp, pathname, shdr, shdr_cnt, shdr[ndx].sh_link, &strtab,
&strtab_cnt) != 0)
{
free(*symtab);
*symtab = NULL;
return 1;
}
*symtab_cnt = cnt;
printf("\nListing symbols at 0x%lx:\n"
"%-19s %-19s %-11s %-10s %-10s\n", shdr[ndx].sh_offset,
"Name", "Section", "Type", "Value", "Size");
for(i = 0; i < cnt; i++)
_symtab_print((*symtab) + i, strtab, strtab_cnt, shdr, shdr_cnt,
shstrtab, shstrtab_cnt);
free(strtab);
return 0;
}
static void _symtab_print(Elf_Sym * sym, char const * strtab, size_t strtab_cnt,
Elf_Shdr * shdr, size_t shdr_cnt, char const * shstrtab,
size_t shstrtab_cnt)
{
char const * section;
unsigned long size = sym->st_size;
if(sym->st_shndx < shdr_cnt)
section = _strtab_get(shstrtab, shstrtab_cnt,
shdr[sym->st_shndx].sh_name);
else
section = _si_get(NULL, sym->st_shndx);
printf("%-19s %-19s %-11s %010p 0x%08lx\n",
_strtab_get(strtab, strtab_cnt, sym->st_name),
section,
_si_get(_si_symtype, ELF_ST_TYPE(sym->st_info)),
(void*)sym->st_value, size);
}
static int _do_rela(FILE * fp, char const * pathname, Elf_Ehdr * ehdr,
Elf_Shdr * shdr, size_t shdr_cnt)
{
int ret = 0;
size_t i;
size_t j;
size_t cnt;
Elf_Rela rela;
Elf_Sym * symtab = NULL;
size_t symtab_cnt = 0;
char * strtab = NULL;
size_t strtab_cnt = 0;
for(i = 0; i < shdr_cnt; i++)
{
if(shdr[i].sh_type == SHT_RELA)
{
if(shdr[i].sh_entsize != sizeof(rela))
{
_UWelfviewer_error("%s: %s", pathname,
"Unexpected relocation size");
continue;
}
}
else if(shdr[i].sh_type == SHT_REL)
{
if(shdr[i].sh_entsize != sizeof(Elf_Rel))
{
_UWelfviewer_error("%s: %s", pathname,
"Unexpected relocation size");
continue;
}
}
else
continue;
if(shdr[i].sh_size % shdr[i].sh_entsize != 0)
{
_UWelfviewer_error("%s: %s", pathname,
"Unexpected relocation section size");
continue;
}
if(fseek(fp, shdr[i].sh_offset, SEEK_SET) != 0)
{
ret |= _UWelfviewer_error("%s: %s", pathname, strerror(
errno));
continue;
}
/* load symbol table */
if(_do_symtab(fp, pathname, shdr, shdr_cnt, shdr[i].sh_link,
&symtab, &symtab_cnt, NULL, 0) != 0)
break;
/* load symbol table string table */
if(_do_strtab(fp, pathname, shdr, shdr_cnt,
shdr[shdr[i].sh_link].sh_link, &strtab,
&strtab_cnt) != 0)
{
free(symtab);
break;
}
cnt = shdr[i].sh_size / shdr[i].sh_entsize;
printf("\nListing relocations at 0x%lx:\n"
"%-19s %-10s %-19s %s\n", shdr[i].sh_offset,
"Symbol", "Offset", "Type", "Addend");
rela.r_addend = 0;
for(j = 0; j < cnt; j++)
{
if(fread(&rela, shdr[i].sh_entsize, 1, fp) != 1)
{
ret |= _UWelfviewer_error("%s: %s", pathname,
strerror(errno));
break;
}
#if _BYTE_ORDER == _LITTLE_ENDIAN
if(ehdr->e_ident[EI_DATA] == ELFDATA2MSB)
#else
if(ehdr->e_ident[EI_DATA] == ELFDATA2LSB)
#endif
{
rela.r_offset = bswap(rela.r_offset);
rela.r_info = bswap(rela.r_info);
rela.r_addend = bswap32(rela.r_addend);
}
_rela_print(&rela, symtab, symtab_cnt, strtab,
strtab_cnt);
}
free(strtab);
free(symtab);
}
return 0;
}
static void _rela_print(Elf_Rela * rela, Elf_Sym * symtab, size_t symtab_cnt,
char const * symstrtab, size_t symstrtab_cnt)
{
Elf_Sym * sym = NULL;
char const * name = "";
unsigned long addend = rela->r_addend;
if(ELF_R_SYM(rela->r_info) < symtab_cnt)
{
sym = &symtab[ELF_R_SYM(rela->r_info)];
name = _strtab_get(symstrtab, symstrtab_cnt, sym->st_name);
}
printf("%-19s %010p %-19s 0x%08lx\n", name,
(void*)rela->r_offset,
_si_get(_si_rtype, ELF_R_TYPE(rela->r_info)),
addend);
}
/* usage */
static int _usage(void)
{
fputs("Usage: " PACKAGE " filename\n", stderr);
return 1;
}
/* public */
/* functions */
/* main */
int main(int argc, char * argv[])
{
int o;
while((o = getopt(argc, argv, "")) != -1)
return _usage();
if(optind + 1 != argc)
return _usage();
return _UWelfviewer(argv[optind]) == 0 ? 0 : 2;
}