/* elf.c
* This file is part of decomp - a disassembler. Here are the routines
* for manipulating ELF32/64 files.
*
* Copyright (C) 2002 Jonathan duSaint <dusaint@earthlink.net>
*
* Started on 30 January 2002.
*/
#include <stdio.h>
#include <string.h>
#include <elf.h>
#include "decomp.h"
/* give these forward references */
int elf_unneeded_section (const char *name);
char *elf_get_flags (unsigned long flags);
enum symbol_type elf_get_symbol_type (struct file_info *fi,unsigned char info);
/* I finally found a problem with C - the lack of dynamic types forces
me to separate elf32/elf64 handling into two virtually identical
largish functions. Of course, that sort of thing would cause a lot
of bloat in the language itself, so I guess I'll live. */
/* ELF32 section */
/* elf32_read_file_header
* Reads the ELF32 file header in the file pointed to by FP and
* populates FILE_HEADER with the information.
*/
void
elf32_read_file_header (Elf32_Ehdr *file_header, FILE *fp)
{
d_read (file_header->e_ident, sizeof (char), EI_NIDENT, fp, 1);
d_read (&file_header->e_type, sizeof (Elf32_Half), 1, fp, 0);
d_read (&file_header->e_machine, sizeof (Elf32_Half), 1, fp, 0);
d_read (&file_header->e_version, sizeof (Elf32_Word), 1, fp, 0);
d_read (&file_header->e_entry, sizeof (Elf32_Addr), 1, fp, 0);
d_read (&file_header->e_phoff, sizeof (Elf32_Off), 1, fp, 0);
d_read (&file_header->e_shoff, sizeof (Elf32_Off), 1, fp, 0);
d_read (&file_header->e_flags, sizeof (Elf32_Word), 1, fp, 0);
d_read (&file_header->e_ehsize, sizeof (Elf32_Half), 1, fp, 0);
d_read (&file_header->e_phentsize, sizeof (Elf32_Half), 1, fp, 0);
d_read (&file_header->e_phnum, sizeof (Elf32_Half), 1, fp, 0);
d_read (&file_header->e_shentsize, sizeof (Elf32_Half), 1, fp, 0);
d_read (&file_header->e_shnum, sizeof (Elf32_Half), 1, fp, 0);
d_read (&file_header->e_shstrndx, sizeof (Elf32_Half), 1, fp, 0);
}
/* elf32_read_section_header
* Reads and ELF32 section header which is pointed to by FP and
* uses the information to populate SH.
*/
void
elf32_read_section_header (Elf32_Shdr *sh, FILE *fp)
{
d_read (&sh->sh_name, sizeof (Elf32_Word), 1, fp, 0);
d_read (&sh->sh_type, sizeof (Elf32_Word), 1, fp, 0);
d_read (&sh->sh_flags, sizeof (Elf32_Word), 1, fp, 0);
d_read (&sh->sh_addr, sizeof (Elf32_Addr), 1, fp, 0);
d_read (&sh->sh_offset, sizeof (Elf32_Off), 1, fp, 0);
d_read (&sh->sh_size, sizeof (Elf32_Word), 1, fp, 0);
d_read (&sh->sh_link, sizeof (Elf32_Word), 1, fp, 0);
d_read (&sh->sh_info, sizeof (Elf32_Word), 1, fp, 0);
d_read (&sh->sh_addralign, sizeof (Elf32_Word), 1, fp, 0);
d_read (&sh->sh_entsize, sizeof (Elf32_Word), 1, fp, 0);
}
/* elf32_get_file_info
* Get the information from an ELF32 file and populate FI with the
* information.
*/
void
elf32_get_file_info (struct file_info *fi)
{
int k, n_data = 0, n_code = 0;
char *shstrtab;
Elf32_Ehdr fh;
Elf32_Shdr sh;
elf32_read_file_header (&fh, fi->fp);
fi->bit_size = BS_32;
fi->load_address = fh.e_entry;
fi->endian = ((fh.e_ident[EI_DATA] == ELFDATA2LSB)
? BO_LITTLE_ENDIAN
: BO_BIG_ENDIAN);
/* do some sanity checks on the header */
if (strncmp (fh.e_ident, ELFMAG, SELFMAG) /* magic - \x7fELF */
|| (fh.e_ident[EI_VERSION] != EV_CURRENT) /* current version */
|| (fh.e_type != ET_REL /* object file */
&& fh.e_type != ET_EXEC /* or executable */
&& fh.e_type != ET_DYN) /* or library */
|| (fh.e_version != EV_CURRENT)) /* current version */
error_out (ERR_INVALID_FILE);
/* only handle IA-32 for now... */
if (fh.e_machine == EM_386)
fi->arch = MT_IA32;
else
fi->arch = MT_UNK;
/* read the section header string table index */
fseek (fi->fp, fh.e_shoff + fh.e_shstrndx * fh.e_shentsize, SEEK_SET);
elf32_read_section_header (&sh, fi->fp);
shstrtab = xmalloc (sh.sh_size);
fseek (fi->fp, sh.sh_offset, SEEK_SET);
/* and then read the section header string table */
fread (shstrtab, sizeof (char), sh.sh_size, fi->fp);
/* read the sections and put them in their proper places */
fi->data_sections = xmalloc ((fh.e_shnum + 1)
* sizeof (struct section_info *));
fi->code_sections = xmalloc ((fh.e_shnum + 1)
* sizeof (struct section_info *));
/* position at start of section headers */
fseek (fi->fp, fh.e_shoff, SEEK_SET);
for (k = 0; k < fh.e_shnum; k++)
{
char *section_name = NULL;
/* read the header */
elf32_read_section_header (&sh, fi->fp);
/* find the name */
section_name = xmalloc (strlen (shstrtab + sh.sh_name) + 1);
strcpy (section_name, shstrtab + sh.sh_name);
if (debug)
printf ("read %s, idx %#x, offset %#x\n", section_name, k,
sh.sh_offset);
/* parse the header into the proper place */
switch (sh.sh_type)
{
case SHT_PROGBITS:
if (sh.sh_flags & SHF_EXECINSTR) /* code section */
{
if (elf_unneeded_section (section_name))
{
xfree (section_name);
continue;
}
fi->code_sections[n_code] = alloc_section_info (section_name,
CODE_SECTION,
sh.sh_offset,
sh.sh_size, 0, k,
sh.sh_addr, NULL,
elf_get_flags (sh.sh_flags),
sh.sh_addralign);
put_data_limits (sh.sh_addr, sh.sh_addr + sh.sh_size);
n_code++;
}
else /* data section */
{
if (elf_unneeded_section (section_name))
{
xfree (section_name);
continue;
}
fi->data_sections[n_data] = alloc_section_info (section_name,
DATA_SECTION,
sh.sh_offset,
sh.sh_size, 0, k,
sh.sh_addr, NULL,
elf_get_flags (sh.sh_flags),
sh.sh_addralign);
put_data_limits (sh.sh_addr, sh.sh_addr + sh.sh_size);
n_data++;
}
break;
case SHT_SYMTAB: /* symbol table */
fi->symtab = alloc_section_info (section_name, OTHER_SECTION,
sh.sh_offset, sh.sh_size,
sh.sh_entsize, k, sh.sh_addr, NULL,
elf_get_flags (sh.sh_flags),
sh.sh_addralign);
break;
case SHT_STRTAB: /* string table */
if (elf_unneeded_section (section_name))
{
xfree (section_name);
continue;
}
if (!strcmp (section_name, ".strtab")) /* the string table */
{
fi->strtab = alloc_section_info (section_name, STRING_SECTION,
sh.sh_offset, sh.sh_size, 0, k,
sh.sh_addr, NULL,
elf_get_flags (sh.sh_flags),
sh.sh_addralign);
}
else /* another table with strings (??) */
{
fi->data_sections[n_data] = alloc_section_info (section_name,
STRING_SECTION,
sh.sh_offset,
sh.sh_size, 0, k,
sh.sh_addr, NULL,
elf_get_flags (sh.sh_flags),
sh.sh_addralign);
put_data_limits (sh.sh_addr, sh.sh_addr + sh.sh_size);
n_data++;
}
break;
/*
I don't think that these two are needed, but they're here
as a reminder, just in case.
case SHT_RELA:
case SHT_HASH:
*/
default:
xfree (section_name);
continue;
}
}
xfree (shstrtab);
}
/* elf32_read_symbol
* Read an Elf32_Sym and store it into SYM.
*/
void
elf32_read_symbol (Elf32_Sym *sym, FILE *fp)
{
d_read (&sym->st_name, sizeof (Elf32_Word), 1, fp, 0);
d_read (&sym->st_value, sizeof (Elf32_Addr), 1, fp, 0);
d_read (&sym->st_size, sizeof (Elf32_Word), 1, fp, 0);
d_read (&sym->st_info, sizeof (unsigned char), 1, fp, 0);
d_read (&sym->st_other, sizeof (unsigned char), 1, fp, 0);
d_read (&sym->st_shndx, sizeof (Elf32_Section), 1, fp, 0);
}
/* elf_32_get_next_symbol
* Read the next symbol from the object file and return it as a struct symtab.
*/
struct symtab *
elf32_get_next_symbol (struct file_info *fi, char *strtab)
{
unsigned long unnamed_index = 0;
char *tmp;
struct symtab *sym;
Elf32_Sym symbol;
elf32_read_symbol (&symbol, fi->fp);
/* ignore symbols with no section */
/* if (symbol.st_shndx == 0xfff1) continue; */
/* ignore unknown symbol types */
/*if (get_symbol_type (symbol.st_info) == UNKNOWN_SYMBOL) continue;*/
/* ignore null-named symbols */
/*if (!strlen (strtab + symbol.st_name)) continue;*/
/* if this symbol references a section or a file, ignore */
if (ELF32_ST_TYPE (symbol.st_info) == STT_SECTION
|| ELF32_ST_TYPE (symbol.st_info) == STT_FILE) return NULL;
if (symbol.st_value == 0) return NULL;
sym = xmalloc (sizeof (struct symtab));
/* if a symbol has no name, make up a (sorta) random name */
if (!strlen (strtab + symbol.st_name))
{
char *tmp_name;
tmp_name = xmalloc (16);
snprintf (tmp_name, 16, "sym_%ld", unnamed_index++);
sym->name = xmalloc (strlen (tmp_name) + 1);
strcpy (sym->name, tmp_name);
xfree (tmp_name);
}
else /* symbol has a name */
{
sym->name = xmalloc (strlen (strtab + symbol.st_name) + 1);
strcpy (sym->name, strtab + symbol.st_name);
}
sym->address = symbol.st_value;
sym->size = symbol.st_size;
sym->idx = symbol.st_shndx;
sym->type = elf_get_symbol_type (fi, symbol.st_info);
if (debug)
printf ("%#lx:%s: size %#lx, info %#02x, other %#02x, idx %#x\n",
(unsigned long)symbol.st_value, sym->name,
(unsigned long)symbol.st_size, symbol.st_info,
symbol.st_other, symbol.st_shndx);
/* if (debug) */
/* printf ("%s: %#lx, %#lx, %#lx, %d\n", sym->name, sym->address, */
/* sym->size, sym->section_index, sym->type); */
/* check for @@foo at the end of a symbol - if it is there, strip it */
if ((tmp = strchr (sym->name, '@')) != NULL) *tmp = '\0';
return sym;
}
/* ELF64 section */
/* elf64_read_file_header
* Reads the ELF64 file header in the file pointed to by FP and
* populates FILE_HEADER with the information.
*/
void
elf64_read_file_header (Elf64_Ehdr *file_header, FILE *fp)
{
d_read (file_header->e_ident, sizeof (char), EI_NIDENT, fp, 1);
d_read (&file_header->e_type, sizeof (Elf64_Half), 1, fp, 0);
d_read (&file_header->e_machine, sizeof (Elf64_Half), 1, fp, 0);
d_read (&file_header->e_version, sizeof (Elf64_Word), 1, fp, 0);
d_read (&file_header->e_entry, sizeof (Elf64_Addr), 1, fp, 0);
d_read (&file_header->e_phoff, sizeof (Elf64_Off), 1, fp, 0);
d_read (&file_header->e_shoff, sizeof (Elf64_Off), 1, fp, 0);
d_read (&file_header->e_flags, sizeof (Elf64_Word), 1, fp, 0);
d_read (&file_header->e_ehsize, sizeof (Elf64_Half), 1, fp, 0);
d_read (&file_header->e_phentsize, sizeof (Elf64_Half), 1, fp, 0);
d_read (&file_header->e_phnum, sizeof (Elf64_Half), 1, fp, 0);
d_read (&file_header->e_shentsize, sizeof (Elf64_Half), 1, fp, 0);
d_read (&file_header->e_shnum, sizeof (Elf64_Half), 1, fp, 0);
d_read (&file_header->e_shstrndx, sizeof (Elf64_Half), 1, fp, 0);
}
/* elf64_read_section_header
* Reads and ELF64 section header which is pointed to by FP and
* uses the information to populate SH.
*/
void
elf64_read_section_header (Elf64_Shdr *sh, FILE *fp)
{
d_read (&sh->sh_name, sizeof (Elf64_Word), 1, fp, 0);
d_read (&sh->sh_type, sizeof (Elf64_Word), 1, fp, 0);
d_read (&sh->sh_flags, sizeof (Elf64_Xword), 1, fp, 0);
d_read (&sh->sh_addr, sizeof (Elf64_Addr), 1, fp, 0);
d_read (&sh->sh_offset, sizeof (Elf64_Off), 1, fp, 0);
d_read (&sh->sh_size, sizeof (Elf64_Xword), 1, fp, 0);
d_read (&sh->sh_link, sizeof (Elf64_Word), 1, fp, 0);
d_read (&sh->sh_info, sizeof (Elf64_Word), 1, fp, 0);
d_read (&sh->sh_addralign, sizeof (Elf64_Xword), 1, fp, 0);
d_read (&sh->sh_entsize, sizeof (Elf64_Xword), 1, fp, 0);
}
/* elf64_get_file_info
* Get the information from an ELF64 file and populate FI with the
* information.
*/
void
elf64_get_file_info (struct file_info *fi)
{
int k, n_data = 0, n_code = 0;
char *shstrtab;
Elf64_Ehdr fh;
Elf64_Shdr sh;
elf64_read_file_header (&fh, fi->fp);
fi->bit_size = BS_64;
fi->load_address = fh.e_entry;
fi->endian = ((fh.e_ident[EI_DATA] == ELFDATA2LSB)
? BO_LITTLE_ENDIAN
: BO_BIG_ENDIAN);
/* do some sanity checks on the header */
if (strncmp (fh.e_ident, ELFMAG, SELFMAG) /* magic - \x7fELF */
|| (fh.e_ident[EI_VERSION] != EV_CURRENT) /* current version */
|| (fh.e_type != ET_REL /* object file */
&& fh.e_type != ET_EXEC /* or executable */
&& fh.e_type != ET_DYN) /* or library */
|| (fh.e_version != EV_CURRENT)) /* current version */
error_out (ERR_INVALID_FILE);
/* only handle IA-32 for now... */
switch (fh.e_machine)
{
case EM_386:
fi->arch = MT_IA32;
break;
default:
fi->arch = MT_UNK;
}
/* read the section header string table index */
fseek (fi->fp, fh.e_shoff + fh.e_shstrndx * fh.e_shentsize, SEEK_SET);
elf64_read_section_header (&sh, fi->fp);
shstrtab = xmalloc (sh.sh_size);
fseek (fi->fp, sh.sh_offset, SEEK_SET);
/* and then read the section header string table */
fread (shstrtab, sizeof (char), sh.sh_size, fi->fp);
/* read the sections and put them in their proper places */
fi->data_sections = xmalloc ((fh.e_shnum + 1)
* sizeof (struct section_info *));
fi->code_sections = xmalloc ((fh.e_shnum + 1)
* sizeof (struct section_info *));
/* position at start of section headers */
fseek (fi->fp, fh.e_shoff, SEEK_SET);
for (k = 0; k < fh.e_shnum; k++)
{
char *section_name = NULL;
/* read the header */
elf64_read_section_header (&sh, fi->fp);
/* find the name */
section_name = xmalloc (strlen (shstrtab + sh.sh_name) + 1);
strcpy (section_name, shstrtab + sh.sh_name);
if (debug)
printf ("read %s, idx %#x, offset %#llx\n", section_name, k,
sh.sh_offset);
/* parse the header into the proper place */
switch (sh.sh_type)
{
case SHT_PROGBITS:
if (sh.sh_flags & SHF_EXECINSTR) /* code section */
{
if (elf_unneeded_section (section_name))
{
xfree (section_name);
continue;
}
fi->code_sections[n_code] = alloc_section_info (section_name,
CODE_SECTION,
sh.sh_offset,
sh.sh_size, 0, k,
sh.sh_addr, NULL,
elf_get_flags (sh.sh_flags),
sh.sh_addralign);
put_data_limits (sh.sh_addr, sh.sh_addr + sh.sh_size);
n_code++;
}
else /* data section */
{
if (elf_unneeded_section (section_name))
{
xfree (section_name);
continue;
}
fi->data_sections[n_data] = alloc_section_info (section_name,
DATA_SECTION,
sh.sh_offset,
sh.sh_size, 0, k,
sh.sh_addr, NULL,
elf_get_flags (sh.sh_flags),
sh.sh_addralign);
put_data_limits (sh.sh_addr, sh.sh_addr + sh.sh_size);
n_data++;
}
break;
case SHT_SYMTAB: /* symbol table */
fi->symtab = alloc_section_info (section_name, OTHER_SECTION,
sh.sh_offset, sh.sh_size,
sh.sh_entsize, k, sh.sh_addr, NULL,
elf_get_flags (sh.sh_flags),
sh.sh_addralign);
break;
case SHT_STRTAB: /* string table */
if (elf_unneeded_section (section_name))
{
xfree (section_name);
continue;
}
if (!strcmp (section_name, ".strtab")) /* the string table */
{
fi->strtab = alloc_section_info (section_name, STRING_SECTION,
sh.sh_offset, sh.sh_size, 0, k,
sh.sh_addr, NULL,
elf_get_flags (sh.sh_flags),
sh.sh_addralign);
}
else /* another table with strings (??) */
{
fi->data_sections[n_data] = alloc_section_info (section_name,
STRING_SECTION,
sh.sh_offset,
sh.sh_size, 0, k,
sh.sh_addr, NULL,
elf_get_flags (sh.sh_flags),
sh.sh_addralign);
put_data_limits (sh.sh_addr, sh.sh_addr + sh.sh_size);
n_data++;
}
break;
/*
I don't think that these two are needed, but they're here
as a reminder, just in case.
case SHT_RELA:
case SHT_HASH:
*/
default:
xfree (section_name);
continue;
}
}
xfree (shstrtab);
}
/* elf64_read_symbol
* Read an Elf64_Sym and store it into SYM.
*/
void
elf64_read_symbol (Elf64_Sym *sym, FILE *fp)
{
d_read (&sym->st_name, sizeof (Elf64_Word), 1, fp, 0);
d_read (&sym->st_info, sizeof (unsigned char), 1, fp, 0);
d_read (&sym->st_other, sizeof (unsigned char), 1, fp, 0);
d_read (&sym->st_shndx, sizeof (Elf64_Section), 1, fp, 0);
d_read (&sym->st_value, sizeof (Elf64_Addr), 1, fp, 0);
d_read (&sym->st_size, sizeof (Elf64_Xword), 1, fp, 0);
}
/* elf64_get_next_symbol
* Read the next symbol from the object file and return it as a struct symtab.
*/
struct symtab *
elf64_get_next_symbol (struct file_info *fi, char *strtab)
{
unsigned long unnamed_index = 0;
char *tmp;
struct symtab *sym;
Elf64_Sym symbol;
elf64_read_symbol (&symbol, fi->fp);
/* ignore symbols with no section */
/* if (symbol.st_shndx == 0xfff1) continue; */
/* ignore unknown symbol types */
/*if (get_symbol_type (symbol.st_info) == UNKNOWN_SYMBOL) continue;*/
/* ignore null-named symbols */
/*if (!strlen (strtab + symbol.st_name)) continue;*/
/* if this symbol references a section or a file, ignore */
if (ELF64_ST_TYPE (symbol.st_info) == STT_SECTION
|| ELF64_ST_TYPE (symbol.st_info) == STT_FILE) return NULL;
if (symbol.st_value == 0) return NULL;
sym = xmalloc (sizeof (struct symtab));
/* if a symbol has no name, make up a (sorta) random name */
if (!strlen (strtab + symbol.st_name))
{
char *tmp_name;
tmp_name = xmalloc (16);
snprintf (tmp_name, 16, "sym_%ld", unnamed_index++);
sym->name = xmalloc (strlen (tmp_name) + 1);
strcpy (sym->name, tmp_name);
xfree (tmp_name);
}
else /* symbol has a name */
{
sym->name = xmalloc (strlen (strtab + symbol.st_name) + 1);
strcpy (sym->name, strtab + symbol.st_name);
}
sym->address = symbol.st_value;
sym->size = symbol.st_size;
sym->idx = symbol.st_shndx;
sym->type = elf_get_symbol_type (fi, symbol.st_info);
if (debug)
printf ("%#lx:%s: size %#lx, info %#02x, other %#02x, idx %#x\n",
(unsigned long)symbol.st_value, sym->name,
(unsigned long)symbol.st_size, symbol.st_info,
symbol.st_other, symbol.st_shndx);
/* if (debug) */
/* printf ("%s: %#lx, %#lx, %#lx, %d\n", sym->name, sym->address, */
/* sym->size, sym->section_index, sym->type); */
/* check for @@foo at the end of a symbol - if it is there, strip it */
if ((tmp = strchr (sym->name, '@')) != NULL) *tmp = '\0';
return sym;
}
/* Generic ELF section */
/* elf_unneeded_section
* If NAME matches one of the names of the unneeded data sections,
* then 1 is returned, otherwise 0 is returned.
*/
int
elf_unneeded_section (const char *name)
{
int k = -1;
char *unneeded[] = { ".interp", ".plt", ".stab", ".comment", ".sbss",
".shstrtab", ".stabstr", ".got", ".dtors", ".dynstr",
".ctors", ".eh_frame", NULL };
while (unneeded[++k] != NULL) if (!strcmp (name, unneeded[k])) return 1;
if (!strncmp (name, ".debug", 6)) return 1;
return 0;
}
char *flag_str_array[] = {
"", /* no flags */
", \"w\"", /* writeable */
", \"a\"", /* occupies memory during execution */
", \"aw\"", /* writeable and occupies memory during execution */
", \"x\"", /* executable */
", \"xw\"", /* executable and writeable */
", \"xa\"", /* executable and occupies memory during execution */
", \"xaw\"", /* executable, occupies memory during execution and writeable */
};
/* elf_get_flags
* Translate the flags from the section header into textual flags that the
* assembler will understand.
*/
char *
elf_get_flags (unsigned long flags)
{
int index;
index = (flags & SHF_WRITE) + (flags & SHF_ALLOC) + (flags & SHF_EXECINSTR);
if (index > 7) index = 0;
return flag_str_array[index];
}
/* elf_get_file_info
* Get the information from the object file and populate FI.
*/
void
elf_get_file_info (struct file_info *fi)
{
int k;
char ident_buffer[EI_NIDENT];
fi->symtab = NULL;
fi->strtab = NULL;
/* read in the first EI_NIDENT chars in to find out if this is ELF32
or ELF64 */
fseek (fi->fp, 0, SEEK_SET);
fread (ident_buffer, sizeof (char), EI_NIDENT, fi->fp);
/* reset the file pointer */
fseek (fi->fp, 0, SEEK_SET);
/* find the target byte order */
if (ident_buffer[EI_DATA] == ELFDATA2LSB) /* little endian */
target_endian = BO_LITTLE_ENDIAN;
else /* big endian */
target_endian = BO_BIG_ENDIAN;
if (ident_buffer[EI_CLASS] == ELFCLASS32)
elf32_get_file_info (fi);
else
elf64_get_file_info (fi);
/* print debug info */
if (debug)
{
k = -1;
printf ("data:\n");
while (fi->data_sections[++k])
{
printf (" %s (%#lx), %d, %#lx, %#lx, %#lx\n",
fi->data_sections[k]->section_name,
fi->data_sections[k]->section_index,
fi->data_sections[k]->section_type,
fi->data_sections[k]->section_offset,
fi->data_sections[k]->section_size,
fi->data_sections[k]->load_address);
}
k = -1;
printf ("code:\n");
while (fi->code_sections[++k])
{
printf (" %s (%#lx), %d, %#lx, %#lx, %#lx\n",
fi->code_sections[k]->section_name,
fi->code_sections[k]->section_index,
fi->code_sections[k]->section_type,
fi->code_sections[k]->section_offset,
fi->code_sections[k]->section_size,
fi->code_sections[k]->load_address);
}
if (fi->symtab != NULL)
printf ("symtab:\n %s (%#lx), %d, %#lx, %#lx, %#lx\n",
fi->symtab->section_name,
fi->symtab->section_index,
fi->symtab->section_type,
fi->symtab->section_offset,
fi->symtab->section_size,
fi->symtab->load_address);
if (fi->strtab != NULL)
printf ("strtab:\n %s (%#lx), %d, %#lx, %#lx, %#lx\n",
fi->strtab->section_name,
fi->strtab->section_index,
fi->strtab->section_type,
fi->strtab->section_offset,
fi->strtab->section_size,
fi->strtab->load_address);
}
}
/* elf_read_strtab
* Read the string table from the object file.
*/
char *
elf_read_strtab (struct file_info *fi)
{
char *strtab;
if (fi->strtab == NULL) return (NULL);
fseek (fi->fp, fi->strtab->section_offset, SEEK_SET);
strtab = xmalloc (fi->strtab->section_size);
d_read (strtab, sizeof (char), fi->strtab->section_size, fi->fp, 1);
return strtab;
}
/* elf_get_symbol_type
* Translate a symbol's type into the internal format.
*/
enum symbol_type
elf_get_symbol_type (struct file_info *fi, unsigned char info)
{
unsigned char bind, type;
enum symbol_type stype = UNKNOWN_SYMBOL;
if (fi->bit_size == BS_32)
{
bind = ELF32_ST_BIND (info);
type = ELF32_ST_TYPE (info);
}
else
{
bind = ELF64_ST_BIND (info);
type = ELF64_ST_TYPE (info);
}
if (bind == STB_LOCAL && type == STT_OBJECT)
stype = LOCAL_DATA;
else if (bind == STB_LOCAL && type == STT_FUNC)
stype = LOCAL_FUNCTION;
else if (bind == STB_GLOBAL && type == STT_OBJECT)
stype = GLOBAL_DATA;
else if (bind == STB_GLOBAL && type == STT_FUNC)
stype = GLOBAL_FUNCTION;
else if (bind == STB_GLOBAL)
stype = GLOBAL_UNKNOWN;
else if (bind == STB_LOCAL)
stype = LOCAL_UNKNOWN;
else if (type == STT_OBJECT)
stype = UNKNOWN_DATA;
else if (type == STT_FUNC)
stype = UNKNOWN_FUNCTION;
else
stype = UNKNOWN_SYMBOL;
return (stype);
}
/* elf_get_next_symbol
* Read the next symbol from the object file and return it as a struct symtab.
*/
struct symtab *
elf_get_next_symbol (struct file_info *fi, char *strtab)
{
if (fi->bit_size == BS_32)
return elf32_get_next_symbol (fi, strtab);
else
return elf64_get_next_symbol (fi, strtab);
}