git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@10001 626c5289-ae23-0410-ae9c-e8d60b6d4f22
428 lines
12 KiB
C
428 lines
12 KiB
C
/* -----------------------------------------------------------------------------
|
|
* elf.c
|
|
*
|
|
* ELF file management. This file contains functions for accessing ELF
|
|
* file data from a raw memory mapped ELF file (as performed by the
|
|
* functions in object.c).
|
|
*
|
|
* Author(s) : David Beazley (beazley@cs.uchicago.edu)
|
|
*
|
|
* Copyright (C) 2000. The University of Chicago.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
* See the file COPYING for a complete copy of the LGPL.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
#include "wad.h"
|
|
|
|
static char cvs[] = "$Id$";
|
|
|
|
#ifdef WAD_SOLARIS
|
|
#include <sys/elf.h>
|
|
#endif
|
|
#ifdef WAD_LINUX
|
|
#include <elf.h>
|
|
#endif
|
|
|
|
/* --- What's needed here (high level interface) :
|
|
- Mapping of addresses to symbols
|
|
- Mapping of symbols to file+line
|
|
*/
|
|
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* wad_elf_check()
|
|
*
|
|
* Checks to see if an object file is an ELF file. Returns 1 on success and
|
|
* changes the type flag of wo to indicate the type of ELF file.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
int
|
|
wad_elf_check(WadObjectFile *wo) {
|
|
if (strncmp((char *)wo->ptr,ELFMAG, SELFMAG) != 0)
|
|
return 0;
|
|
|
|
/* Probably need to put some kind of 32/64 bit check here */
|
|
return 1;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* wad_elf_phdrcnt()
|
|
*
|
|
* Return number of entries in the ELF program header section
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
int
|
|
wad_elf_phdrcnt(WadObjectFile *wo) {
|
|
Elf32_Ehdr *eh;
|
|
|
|
eh = (Elf32_Ehdr *) wo->ptr;
|
|
return eh->e_phnum;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* wad_elf_phdrpos()
|
|
*
|
|
* Return the location of the ELF program header.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void *
|
|
wad_elf_phdrpos(WadObjectFile *wo) {
|
|
Elf32_Ehdr *eh;
|
|
char *c;
|
|
eh = (Elf32_Ehdr *) wo->ptr;
|
|
c = (char *) wo->ptr;
|
|
return (void *) (c+eh->e_phoff);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* wad_elf_shdrcnt()
|
|
*
|
|
* Return number of entries in the ELF section header
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
int
|
|
wad_elf_shdrcnt(WadObjectFile *wo) {
|
|
Elf32_Ehdr *eh;
|
|
|
|
eh = (Elf32_Ehdr *) wo->ptr;
|
|
return eh->e_shnum;
|
|
}
|
|
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* wad_elf_shdrpos()
|
|
*
|
|
* Return the location of the section headers
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void *
|
|
wad_elf_shdrpos(WadObjectFile *wo) {
|
|
Elf32_Ehdr *eh;
|
|
char *c;
|
|
eh = (Elf32_Ehdr *) wo->ptr;
|
|
c = (char *) wo->ptr;
|
|
return (void *) (c+eh->e_shoff);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* wad_elf_section_header()
|
|
*
|
|
* Get a specific section number
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void *wad_elf_section_header(WadObjectFile *wo, int sn) {
|
|
Elf32_Ehdr *eh;
|
|
char *r;
|
|
|
|
eh = (Elf32_Ehdr *) wo->ptr;
|
|
if ((sn < 0) || (sn >= eh->e_shnum)) return 0;
|
|
|
|
r = (char *) wad_elf_shdrpos(wo) + (sn*eh->e_shentsize);
|
|
return (void *) r;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* wad_elf_section_data()
|
|
*
|
|
* Get section data
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void *wad_elf_section_data(WadObjectFile *wo, int sn) {
|
|
Elf32_Shdr *sh;
|
|
char *r;
|
|
|
|
sh = (Elf32_Shdr *) wad_elf_section_header(wo,sn);
|
|
if (!sh) return 0;
|
|
|
|
r = ((char *) wo->ptr) + sh->sh_offset;
|
|
return r;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* wad_elf_section_size()
|
|
* Return section size
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
int wad_elf_section_size(WadObjectFile *wo, int sn) {
|
|
Elf32_Shdr *sh;
|
|
|
|
sh = (Elf32_Shdr *) wad_elf_section_header(wo,sn);
|
|
if (!sh) return -1;
|
|
return sh->sh_size;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* wad_elf_section_name()
|
|
*
|
|
* Returns the name of an ELF section
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
char *wad_elf_section_name(WadObjectFile *wo, int sn) {
|
|
Elf32_Ehdr *eh;
|
|
Elf32_Shdr *sh;
|
|
char *sectionstr;
|
|
|
|
eh = (Elf32_Ehdr *) wo->ptr;
|
|
|
|
/* Get the string table */
|
|
sectionstr = (char *) wad_elf_section_data(wo,eh->e_shstrndx);
|
|
if (!sectionstr) {
|
|
return 0;
|
|
}
|
|
|
|
/* Get the section header for the section */
|
|
sh = (Elf32_Shdr *) wad_elf_section_header(wo,sn);
|
|
if (!sh) return 0;
|
|
return sectionstr + sh->sh_name;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* wad_elf_section_byname()
|
|
*
|
|
* Get section data given a section name
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
int
|
|
wad_elf_section_byname(WadObjectFile *wo, char *name) {
|
|
int i;
|
|
char *sn;
|
|
int n;
|
|
|
|
n = wad_elf_shdrcnt(wo);
|
|
for (i = 0; i <n; i++) {
|
|
sn = wad_elf_section_name(wo,i);
|
|
if (strcmp(sn,name) == 0) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* wad_find_symbol()
|
|
*
|
|
* Tries to find the symbol associated with a given address. base is the
|
|
* base address of the object file.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static
|
|
int elf_search_section_sym(WadFrame *f, char *secname, char *strname) {
|
|
int nsymtab;
|
|
int nstrtab;
|
|
int symtab_size;
|
|
Elf32_Sym *sym;
|
|
int nsym;
|
|
char *str;
|
|
int i;
|
|
unsigned long vaddr, base;
|
|
char *name;
|
|
char *localfile = 0;
|
|
|
|
vaddr = (unsigned long) f->pc;
|
|
base = (unsigned long) f->segment->base;
|
|
|
|
nsymtab = wad_elf_section_byname(f->object,secname);
|
|
if (nsymtab < 0) return 0;
|
|
nstrtab = wad_elf_section_byname(f->object,strname);
|
|
if (nstrtab < 0) return 0;
|
|
|
|
symtab_size = wad_elf_section_size(f->object,nsymtab);
|
|
sym = (Elf32_Sym *) wad_elf_section_data(f->object,nsymtab);
|
|
str = (char *) wad_elf_section_data(f->object,nstrtab);
|
|
|
|
nsym = (symtab_size/sizeof(Elf32_Sym));
|
|
for (i = 0; i < nsym; i++) {
|
|
name = str + sym[i].st_name;
|
|
/* Look for filename in case the symbol maps to a local symbol */
|
|
if (ELF32_ST_TYPE(sym[i].st_info) == STT_FILE) {
|
|
localfile = name;
|
|
}
|
|
if (wad_debug_mode & DEBUG_SYMBOL_SEARCH) {
|
|
wad_printf("%x(%x): %s %x + %x, %x, %x\n", base, vaddr, name, sym[i].st_value, sym[i].st_size, sym[i].st_info, sym[i].st_shndx);
|
|
}
|
|
if (((base + sym[i].st_value) <= vaddr) && (vaddr <= (base+sym[i].st_value + sym[i].st_size))) {
|
|
#ifdef WAD_LINUX
|
|
/* If the section index is 0, the symbol is undefined */
|
|
if (sym[i].st_shndx == 0) continue;
|
|
#endif
|
|
f->sym_name = name;
|
|
f->sym_nlen = strlen(name);
|
|
f->sym_base = base + sym[i].st_value;
|
|
f->sym_size = sym[i].st_size;
|
|
if (ELF32_ST_BIND(sym[i].st_info) == STB_LOCAL) {
|
|
f->sym_file = localfile;
|
|
f->sym_bind = SYM_LOCAL;
|
|
} else {
|
|
f->sym_bind = SYM_GLOBAL;
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
wad_elf_find_symbol(WadFrame *f) {
|
|
/* We simply try a few possible sections */
|
|
if (elf_search_section_sym(f,".symtab",".strtab")) return;
|
|
if (elf_search_section_sym(f,".dynsym",".dynstr")) return;
|
|
|
|
/* Hmmm. No match found. Oh well */
|
|
return;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* wad_elf_debug_info()
|
|
*
|
|
* Gather debugging information about a function (if possible)
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
int
|
|
wad_elf_debug_info(WadFrame *f) {
|
|
int nstab, nstabstr, nstabindex, nstabindexstr, nstabexcl, nstabexclstr;
|
|
int ret;
|
|
void *stab;
|
|
char *stabstr;
|
|
int stabsize;
|
|
|
|
nstab = wad_elf_section_byname(f->object,".stab");
|
|
nstabstr = wad_elf_section_byname(f->object,".stabstr");
|
|
nstabindex = wad_elf_section_byname(f->object,".stab.index");
|
|
nstabindexstr = wad_elf_section_byname(f->object,".stab.indexstr");
|
|
nstabexcl = wad_elf_section_byname(f->object,".stab.excl");
|
|
nstabexclstr = wad_elf_section_byname(f->object,".stab.exclstr");
|
|
|
|
#ifdef DEBUG_DEBUG
|
|
wad_printf("nstab = %d\n", nstab);
|
|
wad_printf("nstabstr = %d\n", nstabstr);
|
|
wad_printf("nstabindex = %d\n", nstabindex);
|
|
wad_printf("nstabindexstr = %d\n", nstabindexstr);
|
|
wad_printf("nstabexcl = %d\n", nstabexcl);
|
|
wad_printf("nstabexclstr = %d\n", nstabexclstr);
|
|
#endif
|
|
|
|
/* Now start searching stabs */
|
|
|
|
/* Look in the .stab section */
|
|
if (nstab > 0) {
|
|
stab = wad_elf_section_data(f->object,nstab);
|
|
stabsize = wad_elf_section_size(f->object,nstab);
|
|
stabstr = (char *) wad_elf_section_data(f->object,nstabstr);
|
|
|
|
|
|
if (wad_search_stab(stab,stabsize,stabstr, f)) return 1;
|
|
}
|
|
|
|
/* Look in the .stab.excl section. A solaris oddity? */
|
|
|
|
if (nstabexcl > 0) {
|
|
stab = wad_elf_section_data(f->object,nstabexcl);
|
|
stabsize = wad_elf_section_size(f->object, nstabexcl);
|
|
stabstr = (char *) wad_elf_section_data(f->object, nstabexclstr);
|
|
|
|
if (wad_search_stab(stab,stabsize,stabstr, f)) return 1;
|
|
}
|
|
|
|
/* Look in the .stab.index section. A Solaris oddity? */
|
|
if (nstabindex > 0) {
|
|
|
|
stab = wad_elf_section_data(f->object,nstabindex);
|
|
stabsize = wad_elf_section_size(f->object, nstabindex);
|
|
stabstr = (char *) wad_elf_section_data(f->object, nstabindexstr);
|
|
|
|
if (wad_search_stab(stab,stabsize,stabstr, f)) {
|
|
/* Hmmm. Might be in a different file */
|
|
WadObjectFile *wo1, *wold;
|
|
char objfile[MAX_PATH];
|
|
/* printf("DEBUG %s\n", f->sym_name); */
|
|
wad_strcpy(objfile, f->loc_objfile);
|
|
wo1 = wad_object_load(objfile);
|
|
if (wo1) {
|
|
wold = f->object;
|
|
f->object = wo1;
|
|
wad_find_debug(f);
|
|
f->object = wold;
|
|
return ret;
|
|
} else {
|
|
/* wad_printf("couldn't load %s\n", objfile); */
|
|
}
|
|
/* if (!ret) return wad_search_stab(stab,stabsize,stabstr,f);*/
|
|
return ret;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* wad_elf_debug()
|
|
*
|
|
* Print some debugging information about an object
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void
|
|
wad_elf_debug(WadObjectFile *wo) {
|
|
int i;
|
|
wad_printf("ELF Debug : obj = %x (%s)\n", wo, wo->path);
|
|
wad_printf(" phdrcnt = %d\n", wad_elf_phdrcnt(wo));
|
|
wad_printf(" phdrpos = %x\n", wad_elf_phdrpos(wo));
|
|
wad_printf(" shdrcnt = %d\n", wad_elf_shdrcnt(wo));
|
|
wad_printf(" shdrpos = %x\n", wad_elf_shdrpos(wo));
|
|
for (i = 0; i < wad_elf_shdrcnt(wo); i++) {
|
|
wad_printf(" section '%s': data = 0x%x, size = %d\n",
|
|
wad_elf_section_name(wo,i),
|
|
wad_elf_section_data(wo,i),
|
|
wad_elf_section_size(wo,i));
|
|
}
|
|
}
|
|
|
|
/* general purpose functions exposed to the outside world */
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* wad_find_symbol()
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void
|
|
wad_find_symbol(WadFrame *f) {
|
|
if (wad_debug_mode & DEBUG_SYMBOL) {
|
|
wad_printf("wad: Searching for 0x%08x --> ", f->pc);
|
|
}
|
|
if (f->object)
|
|
wad_elf_find_symbol(f);
|
|
if (wad_debug_mode & DEBUG_SYMBOL) {
|
|
if (f->sym_name) {
|
|
wad_printf("%s", f->sym_name);
|
|
if (f->sym_file)
|
|
wad_printf(" in '%s'\n", f->sym_file);
|
|
else
|
|
wad_printf("\n");
|
|
} else {
|
|
wad_printf("?\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
wad_find_debug(WadFrame *f) {
|
|
/* if (f->debug_check) return; */
|
|
if (f->object) {
|
|
wad_elf_debug_info(f);
|
|
}
|
|
/* f->debug_check = 1; */
|
|
}
|
|
|
|
|
|
|