877 lines
27 KiB
C
877 lines
27 KiB
C
|
/*
|
||
|
Copyright (C) 2000,2004,2005 Silicon Graphics, Inc. All Rights Reserved.
|
||
|
Portions Copyright (C) 2007-2012 David Anderson. All Rights Reserved.
|
||
|
Portions Copyright (C) 2011-2012 SN Systems Ltd. All Rights Reserved
|
||
|
|
||
|
This program is free software; you can redistribute it and/or modify it
|
||
|
under the terms of version 2 of the GNU General Public License as
|
||
|
published by the Free Software Foundation.
|
||
|
|
||
|
This program is distributed in the hope that it would be useful, but
|
||
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||
|
|
||
|
Further, this software is distributed without any warranty that it is
|
||
|
free of the rightful claim of any third person regarding infringement
|
||
|
or the like. Any license provided herein, whether implied or
|
||
|
otherwise, applies only to this software file. Patent licenses, if
|
||
|
any, provided herein do not apply to combinations of this program with
|
||
|
other software, or any other product whatsoever.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License along
|
||
|
with this program; if not, write the Free Software Foundation, Inc., 51
|
||
|
Franklin Street - Fifth Floor, Boston MA 02110-1301, USA.
|
||
|
|
||
|
*/
|
||
|
#include "globals.h"
|
||
|
#define DWARF_RELOC_MIPS
|
||
|
#define DWARF_RELOC_PPC
|
||
|
#define DWARF_RELOC_PPC64
|
||
|
#define DWARF_RELOC_ARM
|
||
|
#define DWARF_RELOC_X86_64
|
||
|
#define DWARF_RELOC_386
|
||
|
|
||
|
#include "print_reloc.h"
|
||
|
#include "section_bitmaps.h"
|
||
|
#include "esb.h"
|
||
|
|
||
|
/* Include Section type, to be able to deal with all the
|
||
|
Elf32_Rel, Elf32_Rela, Elf64_Rel, Elf64_Rela relocation types
|
||
|
print_error does not return, so the following esb_destructor()
|
||
|
call is unnecessary but reads well :-) */
|
||
|
#define SECT_DATA_SET(x,t,n,sout,r2) { \
|
||
|
data = elf_getdata(scn, 0); \
|
||
|
if (!data || !data->d_size) { \
|
||
|
struct esb_s data_disaster; \
|
||
|
esb_constructor(&data_disaster); \
|
||
|
esb_append(&data_disaster,(n)); \
|
||
|
esb_append(&data_disaster," null"); \
|
||
|
print_error(dbg,esb_get_string(&data_disaster),DW_DLV_OK, err); \
|
||
|
esb_destructor(&data_disaster); \
|
||
|
} \
|
||
|
sout[(r2)] = sect_data[(x)]; \
|
||
|
sout[(r2)].buf = data->d_buf; \
|
||
|
sout[(r2)].size = data->d_size; \
|
||
|
sout[(r2)].type = (t); \
|
||
|
sout[(r2)].name = (n); \
|
||
|
}
|
||
|
/* Record the relocation table name information */
|
||
|
static const char **reloc_type_names = NULL;
|
||
|
static Dwarf_Small number_of_reloc_type_names = 0;
|
||
|
|
||
|
/* Set the relocation names based on the machine type */
|
||
|
static void
|
||
|
set_relocation_table_names(Dwarf_Small machine_type)
|
||
|
{
|
||
|
reloc_type_names = 0;
|
||
|
number_of_reloc_type_names = 0;
|
||
|
switch (machine_type) {
|
||
|
case EM_MIPS:
|
||
|
#ifdef DWARF_RELOC_MIPS
|
||
|
reloc_type_names = reloc_type_names_MIPS;
|
||
|
number_of_reloc_type_names =
|
||
|
sizeof(reloc_type_names_MIPS) / sizeof(char *);
|
||
|
#endif /* DWARF_RELOC_MIPS */
|
||
|
break;
|
||
|
case EM_PPC:
|
||
|
#ifdef DWARF_RELOC_PPC
|
||
|
reloc_type_names = reloc_type_names_PPC;
|
||
|
number_of_reloc_type_names =
|
||
|
sizeof(reloc_type_names_PPC) / sizeof(char *);
|
||
|
#endif /* DWARF_RELOC_PPC */
|
||
|
break;
|
||
|
case EM_PPC64:
|
||
|
#ifdef DWARF_RELOC_PPC64
|
||
|
reloc_type_names = reloc_type_names_PPC64;
|
||
|
number_of_reloc_type_names =
|
||
|
sizeof(reloc_type_names_PPC64) / sizeof(char *);
|
||
|
#endif /* DWARF_RELOC_PPC64 */
|
||
|
break;
|
||
|
case EM_ARM:
|
||
|
#ifdef DWARF_RELOC_ARM
|
||
|
reloc_type_names = reloc_type_names_ARM;
|
||
|
number_of_reloc_type_names =
|
||
|
sizeof(reloc_type_names_ARM) / sizeof(char *);
|
||
|
#endif /* DWARF_RELOC_ARM */
|
||
|
break;
|
||
|
case EM_386:
|
||
|
#ifdef DWARF_RELOC_386
|
||
|
reloc_type_names = reloc_type_names_386;
|
||
|
number_of_reloc_type_names =
|
||
|
sizeof(reloc_type_names_386) / sizeof(char *);
|
||
|
#endif /* DWARF_RELOC_X86_64 */
|
||
|
break;
|
||
|
case EM_X86_64:
|
||
|
#ifdef DWARF_RELOC_X86_64
|
||
|
reloc_type_names = reloc_type_names_X86_64;
|
||
|
number_of_reloc_type_names =
|
||
|
sizeof(reloc_type_names_X86_64) / sizeof(char *);
|
||
|
#endif /* DWARF_RELOC_X86_64 */
|
||
|
break;
|
||
|
default:
|
||
|
/* We don't have others covered. */
|
||
|
reloc_type_names = 0;
|
||
|
number_of_reloc_type_names = 0;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
Return valid reloc type names.
|
||
|
If buf is used, it is static, so beware: it
|
||
|
will be overwritten by the next call.
|
||
|
*/
|
||
|
static const char *
|
||
|
get_reloc_type_names(int index)
|
||
|
{
|
||
|
static char buf[100];
|
||
|
const char *retval = 0;
|
||
|
|
||
|
if (index < 0 || index >= number_of_reloc_type_names) {
|
||
|
if (number_of_reloc_type_names == 0) {
|
||
|
/* No table provided. */
|
||
|
sprintf(buf, "reloc type %d", (int) index);
|
||
|
} else {
|
||
|
/* Table incomplete? */
|
||
|
sprintf(buf, "reloc type %d unknown", (int) index);
|
||
|
}
|
||
|
retval = buf;
|
||
|
} else {
|
||
|
retval = reloc_type_names[index];
|
||
|
}
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
#ifndef HAVE_ELF64_GETEHDR
|
||
|
#define Elf64_Addr long
|
||
|
#define Elf64_Word unsigned long
|
||
|
#define Elf64_Xword unsigned long
|
||
|
#define Elf64_Sym long
|
||
|
#endif
|
||
|
|
||
|
struct sect_data_s {
|
||
|
Dwarf_Small *buf;
|
||
|
Dwarf_Unsigned size;
|
||
|
Dwarf_Bool display; /* Display reloc if TRUE */
|
||
|
const char *name; /* Section name */
|
||
|
Elf64_Xword type; /* To cover 32 and 64 records types */
|
||
|
};
|
||
|
static struct sect_data_s sect_data[DW_SECTION_REL_ARRAY_SIZE];
|
||
|
|
||
|
|
||
|
typedef size_t indx_type;
|
||
|
|
||
|
typedef struct {
|
||
|
indx_type indx;
|
||
|
char *name;
|
||
|
Elf32_Addr value;
|
||
|
Elf32_Word size;
|
||
|
int type;
|
||
|
int bind;
|
||
|
unsigned char other;
|
||
|
Elf32_Half shndx;
|
||
|
} SYM;
|
||
|
|
||
|
|
||
|
typedef struct {
|
||
|
indx_type indx;
|
||
|
char *name;
|
||
|
Elf64_Addr value;
|
||
|
Elf64_Xword size;
|
||
|
int type;
|
||
|
int bind;
|
||
|
unsigned char other;
|
||
|
unsigned short shndx;
|
||
|
} SYM64;
|
||
|
|
||
|
static void print_reloc_information_64(int section_no,
|
||
|
Dwarf_Small * buf,
|
||
|
Dwarf_Unsigned size,
|
||
|
Elf64_Xword type,
|
||
|
char **scn_names,
|
||
|
int scn_names_count);
|
||
|
static void print_reloc_information_32(int section_no,
|
||
|
Dwarf_Small * buf,
|
||
|
Dwarf_Unsigned size,
|
||
|
Elf64_Xword type,
|
||
|
char **scn_names,
|
||
|
int scn_names_count);
|
||
|
static SYM *readsyms(Elf32_Sym * data, size_t num, Elf * elf,
|
||
|
Elf32_Word link);
|
||
|
static SYM64 *read_64_syms(Elf64_Sym * data, size_t num, Elf * elf,
|
||
|
Elf64_Word link);
|
||
|
static void *get_scndata(Elf_Scn * fd_scn, size_t * scn_size);
|
||
|
static void print_relocinfo_64(Dwarf_Debug dbg, Elf * elf);
|
||
|
static void print_relocinfo_32(Dwarf_Debug dbg, Elf * elf);
|
||
|
|
||
|
static SYM *sym_data;
|
||
|
static SYM64 *sym_data_64;
|
||
|
static unsigned long sym_data_entry_count;
|
||
|
static unsigned long sym_data_64_entry_count;
|
||
|
|
||
|
typedef struct {
|
||
|
indx_type index;
|
||
|
char *name_rel; /* .rel.debug_* names */
|
||
|
char *name_rela; /* .rela.debug_* names */
|
||
|
} REL_INFO;
|
||
|
|
||
|
/* If the incoming scn_name is known, record the name
|
||
|
in our reloc section names table.
|
||
|
For a given (debug) section there can be a .rel or a .rela,
|
||
|
not both.
|
||
|
The name-to-index in this table is fixed, invariant.
|
||
|
|
||
|
*/
|
||
|
static REL_INFO rel_info[DW_SECTION_REL_ARRAY_SIZE] = {
|
||
|
{0,0,0},
|
||
|
{/*1*/ DW_SECTION_REL_DEBUG_INFO,
|
||
|
DW_SECTNAME_REL_DEBUG_INFO,
|
||
|
DW_SECTNAME_RELA_DEBUG_INFO},
|
||
|
|
||
|
{/*2*/ DW_SECTION_REL_DEBUG_LINE,
|
||
|
DW_SECTNAME_REL_DEBUG_LINE,
|
||
|
DW_SECTNAME_RELA_DEBUG_LINE},
|
||
|
|
||
|
{/*3*/ DW_SECTION_REL_DEBUG_PUBNAMES,
|
||
|
DW_SECTNAME_REL_DEBUG_PUBNAMES,
|
||
|
DW_SECTNAME_RELA_DEBUG_PUBNAMES},
|
||
|
|
||
|
{/*4*/ DW_SECTION_REL_DEBUG_ABBREV,
|
||
|
DW_SECTNAME_REL_DEBUG_ABBREV,
|
||
|
DW_SECTNAME_RELA_DEBUG_ABBREV},
|
||
|
|
||
|
{/*5*/ DW_SECTION_REL_DEBUG_ARANGES,
|
||
|
DW_SECTNAME_REL_DEBUG_ARANGES,
|
||
|
DW_SECTNAME_RELA_DEBUG_ARANGES},
|
||
|
|
||
|
{/*6*/ DW_SECTION_REL_DEBUG_FRAME,
|
||
|
DW_SECTNAME_REL_DEBUG_FRAME,
|
||
|
DW_SECTNAME_RELA_DEBUG_FRAME},
|
||
|
|
||
|
{/*7*/ DW_SECTION_REL_DEBUG_LOC,
|
||
|
DW_SECTNAME_REL_DEBUG_LOC,
|
||
|
DW_SECTNAME_RELA_DEBUG_LOC},
|
||
|
|
||
|
{/*8*/ DW_SECTION_REL_DEBUG_LOCLISTS,
|
||
|
DW_SECTNAME_REL_DEBUG_LOCLISTS,
|
||
|
DW_SECTNAME_RELA_DEBUG_LOCLISTS},
|
||
|
|
||
|
{/*9*/ DW_SECTION_REL_DEBUG_RANGES,
|
||
|
DW_SECTNAME_REL_DEBUG_RANGES,
|
||
|
DW_SECTNAME_RELA_DEBUG_RANGES},
|
||
|
|
||
|
{/*10*/ DW_SECTION_REL_DEBUG_RNGLISTS,
|
||
|
DW_SECTNAME_REL_DEBUG_RNGLISTS,
|
||
|
DW_SECTNAME_RELA_DEBUG_RNGLISTS},
|
||
|
|
||
|
{/*11*/ DW_SECTION_REL_DEBUG_TYPES,
|
||
|
DW_SECTNAME_REL_DEBUG_TYPES,
|
||
|
DW_SECTNAME_RELA_DEBUG_TYPES},
|
||
|
|
||
|
{/*12*/ DW_SECTION_REL_DEBUG_STR_OFFSETS,
|
||
|
DW_SECTNAME_REL_DEBUG_STR_OFFSETS,
|
||
|
DW_SECTNAME_RELA_DEBUG_STR_OFFSETS},
|
||
|
|
||
|
{/*13*/ DW_SECTION_REL_DEBUG_PUBTYPES,
|
||
|
DW_SECTNAME_REL_DEBUG_PUBTYPES,
|
||
|
DW_SECTNAME_RELA_DEBUG_PUBTYPES},
|
||
|
|
||
|
{/*14*/ DW_SECTION_REL_GDB_INDEX,
|
||
|
DW_SECTNAME_REL_GDB_INDEX,
|
||
|
DW_SECTNAME_RELA_GDB_INDEX},
|
||
|
|
||
|
{/*15*/ DW_SECTION_REL_EH_FRAME,
|
||
|
DW_SECTNAME_REL_EH_FRAME,
|
||
|
DW_SECTNAME_RELA_EH_FRAME},
|
||
|
|
||
|
{/*16*/ DW_SECTION_REL_DEBUG_SUP,
|
||
|
DW_SECTNAME_REL_DEBUG_SUP,
|
||
|
DW_SECTNAME_RELA_DEBUG_SUP},
|
||
|
|
||
|
{/*17*/ DW_SECTION_REL_DEBUG_MACINFO,
|
||
|
DW_SECTNAME_REL_DEBUG_MACINFO,
|
||
|
DW_SECTNAME_RELA_DEBUG_MACINFO},
|
||
|
|
||
|
{/*18*/ DW_SECTION_REL_DEBUG_MACRO,
|
||
|
DW_SECTNAME_REL_DEBUG_MACRO,
|
||
|
DW_SECTNAME_RELA_DEBUG_MACRO},
|
||
|
|
||
|
{/*19*/ DW_SECTION_REL_DEBUG_NAMES,
|
||
|
DW_SECTNAME_REL_DEBUG_NAMES,
|
||
|
DW_SECTNAME_RELA_DEBUG_NAMES},
|
||
|
};
|
||
|
|
||
|
#ifndef SELFTEST
|
||
|
|
||
|
static void
|
||
|
get_reloc_section(Dwarf_Debug dbg,
|
||
|
Elf_Scn *scn,
|
||
|
char *scn_name,
|
||
|
Elf64_Word sh_type,
|
||
|
struct sect_data_s * printable_sect,
|
||
|
unsigned sectnum)
|
||
|
{
|
||
|
Elf_Data *data;
|
||
|
int index;
|
||
|
/* Check for reloc records we are interested in. */
|
||
|
for (index = 1; index < DW_SECTION_REL_ARRAY_SIZE; ++index) {
|
||
|
const char *n = rel_info[index].name_rel;
|
||
|
const char *na = rel_info[index].name_rela;
|
||
|
Dwarf_Error err = 0;
|
||
|
|
||
|
if (strcmp(scn_name, n) == 0) {
|
||
|
SECT_DATA_SET(rel_info[index].index,sh_type,n,
|
||
|
printable_sect,sectnum)
|
||
|
return;
|
||
|
}
|
||
|
if (strcmp(scn_name, na) == 0) {
|
||
|
SECT_DATA_SET(rel_info[index].index,sh_type,na,
|
||
|
printable_sect,sectnum)
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
print_relocinfo(Dwarf_Debug dbg, char * reloc_map)
|
||
|
{
|
||
|
Elf *elf;
|
||
|
char *endr_ident;
|
||
|
int is_64bit;
|
||
|
int res;
|
||
|
int i;
|
||
|
Dwarf_Error err = 0;
|
||
|
|
||
|
for (i = 1; i < DW_SECTION_REL_ARRAY_SIZE; i++) {
|
||
|
sect_data[i].display = reloc_map[i];
|
||
|
sect_data[i].buf = 0;
|
||
|
sect_data[i].size = 0;
|
||
|
sect_data[i].type = SHT_NULL;
|
||
|
}
|
||
|
res = dwarf_get_elf(dbg, &elf, &err);
|
||
|
if (res != DW_DLV_OK) {
|
||
|
print_error(dbg, "dwarf_get_elf error", res, err);
|
||
|
}
|
||
|
endr_ident = elf_getident(elf, NULL);
|
||
|
if (!endr_ident) {
|
||
|
print_error(dbg, "DW_ELF_GETIDENT_ERROR", res, err);
|
||
|
}
|
||
|
is_64bit = (endr_ident[EI_CLASS] == ELFCLASS64);
|
||
|
if (is_64bit) {
|
||
|
print_relocinfo_64(dbg, elf);
|
||
|
} else {
|
||
|
print_relocinfo_32(dbg, elf);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
print_relocinfo_64(Dwarf_Debug dbg, Elf * elf)
|
||
|
{
|
||
|
#ifdef HAVE_ELF64_GETEHDR
|
||
|
Elf_Scn *scn = NULL;
|
||
|
unsigned sect_number = 0;
|
||
|
Elf64_Ehdr *ehdr64 = 0;
|
||
|
Elf64_Shdr *shdr64 = 0;
|
||
|
char *scn_name = 0;
|
||
|
int i = 0;
|
||
|
Elf64_Sym *sym_64 = 0;
|
||
|
char **scn_names = 0;
|
||
|
struct sect_data_s *printable_sects = 0;
|
||
|
|
||
|
int scn_names_cnt = 0;
|
||
|
Dwarf_Error err = 0;
|
||
|
|
||
|
ehdr64 = elf64_getehdr(elf);
|
||
|
if (ehdr64 == NULL) {
|
||
|
print_error(dbg, "DW_ELF_GETEHDR_ERROR", DW_DLV_OK, err);
|
||
|
}
|
||
|
|
||
|
/* Make the section name array big enough
|
||
|
that we don't need to check for overrun in the loop. */
|
||
|
scn_names_cnt = ehdr64->e_shnum + 1;
|
||
|
scn_names = (char **)calloc(scn_names_cnt, sizeof(char *));
|
||
|
if (!scn_names) {
|
||
|
print_error(dbg, "Out of malloc space in relocation print names",
|
||
|
DW_DLV_OK, err);
|
||
|
}
|
||
|
printable_sects = (struct sect_data_s *)calloc(scn_names_cnt,
|
||
|
sizeof(struct sect_data_s));
|
||
|
if (!printable_sects) {
|
||
|
free(scn_names);
|
||
|
print_error(dbg, "Out of malloc space in relocation print sects",
|
||
|
DW_DLV_OK, err);
|
||
|
}
|
||
|
|
||
|
/* First nextscn returns section 1 */
|
||
|
while ((scn = elf_nextscn(elf, scn)) != NULL) {
|
||
|
++sect_number;
|
||
|
shdr64 = elf64_getshdr(scn);
|
||
|
if (shdr64 == NULL) {
|
||
|
free(scn_names);
|
||
|
free(printable_sects);
|
||
|
print_error(dbg, "DW_ELF_GETSHDR_ERROR", DW_DLV_OK, err);
|
||
|
}
|
||
|
scn_name = elf_strptr(elf, ehdr64->e_shstrndx, shdr64->sh_name);
|
||
|
if (scn_name == NULL) {
|
||
|
print_error(dbg, "DW_ELF_STRPTR_ERROR", DW_DLV_OK, err);
|
||
|
}
|
||
|
/* elf_nextscn() skips section with index '0' */
|
||
|
scn_names[sect_number] = scn_name;
|
||
|
if (shdr64->sh_type == SHT_SYMTAB) {
|
||
|
size_t sym_size = 0;
|
||
|
size_t count = 0;
|
||
|
|
||
|
sym_64 = (Elf64_Sym *) get_scndata(scn, &sym_size);
|
||
|
if (sym_64 == NULL) {
|
||
|
free(scn_names);
|
||
|
free(printable_sects);
|
||
|
print_error(dbg, "no Elf64 symbol table data", DW_DLV_OK,
|
||
|
err);
|
||
|
}
|
||
|
count = sym_size / sizeof(Elf64_Sym);
|
||
|
if(sym_size%sizeof(Elf64_Sym)) {
|
||
|
print_error(dbg, "Elf64 problem reading .symtab data",
|
||
|
DW_DLV_OK, err);
|
||
|
}
|
||
|
sym_64++;
|
||
|
count--;
|
||
|
free(sym_data_64);
|
||
|
sym_data_64 = 0;
|
||
|
sym_data_64 = read_64_syms(sym_64, count, elf, shdr64->sh_link);
|
||
|
sym_data_64_entry_count = count;
|
||
|
if (sym_data_64 == NULL) {
|
||
|
free(scn_names);
|
||
|
free(printable_sects);
|
||
|
print_error(dbg, "problem reading Elf64 symbol table data",
|
||
|
DW_DLV_OK, err);
|
||
|
}
|
||
|
} else {
|
||
|
get_reloc_section(dbg,scn,scn_name,shdr64->sh_type,
|
||
|
printable_sects,sect_number);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Set the relocation names based on the machine type */
|
||
|
set_relocation_table_names(ehdr64->e_machine);
|
||
|
|
||
|
for (i = 1; i < ehdr64->e_shnum + 1; i++) {
|
||
|
if (printable_sects[i].display &&
|
||
|
printable_sects[i].buf != NULL &&
|
||
|
printable_sects[i].size > 0) {
|
||
|
print_reloc_information_64(i,
|
||
|
printable_sects[i].buf,
|
||
|
printable_sects[i].size,
|
||
|
printable_sects[i].type,
|
||
|
scn_names,scn_names_cnt);
|
||
|
}
|
||
|
}
|
||
|
free(printable_sects);
|
||
|
free(scn_names);
|
||
|
scn_names = 0;
|
||
|
scn_names_cnt = 0;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
print_relocinfo_32(Dwarf_Debug dbg, Elf * elf)
|
||
|
{
|
||
|
Elf_Scn *scn = NULL;
|
||
|
Elf32_Ehdr *ehdr32 = 0;
|
||
|
Elf32_Shdr *shdr32 = 0;
|
||
|
unsigned sect_number = 0;
|
||
|
char *scn_name = 0;
|
||
|
int i = 0;
|
||
|
Elf32_Sym *sym = 0;
|
||
|
char **scn_names = 0;
|
||
|
int scn_names_cnt = 0;
|
||
|
Dwarf_Error err = 0;
|
||
|
struct sect_data_s *printable_sects = 0;
|
||
|
|
||
|
ehdr32 = elf32_getehdr(elf);
|
||
|
if (ehdr32 == NULL) {
|
||
|
print_error(dbg, "DW_ELF_GETEHDR_ERROR", DW_DLV_OK, err);
|
||
|
}
|
||
|
|
||
|
/* Make the section name array big enough
|
||
|
that we don't need to check for overrun in the loop. */
|
||
|
scn_names_cnt = ehdr32->e_shnum + 1;
|
||
|
scn_names = (char **)calloc(scn_names_cnt, sizeof(char *));
|
||
|
if (!scn_names) {
|
||
|
print_error(dbg, "Out of malloc space in relocation print names",
|
||
|
DW_DLV_OK, err);
|
||
|
}
|
||
|
printable_sects = (struct sect_data_s *)calloc(scn_names_cnt,
|
||
|
sizeof(struct sect_data_s));
|
||
|
if (!printable_sects) {
|
||
|
free(scn_names);
|
||
|
print_error(dbg, "Out of malloc space in relocation print sects",
|
||
|
DW_DLV_OK, err);
|
||
|
}
|
||
|
|
||
|
while ((scn = elf_nextscn(elf, scn)) != NULL) {
|
||
|
++sect_number;
|
||
|
shdr32 = elf32_getshdr(scn);
|
||
|
if (shdr32 == NULL) {
|
||
|
free(printable_sects);
|
||
|
free(scn_names);
|
||
|
print_error(dbg, "DW_ELF_GETSHDR_ERROR", DW_DLV_OK, err);
|
||
|
}
|
||
|
scn_name = elf_strptr(elf, ehdr32->e_shstrndx, shdr32->sh_name);
|
||
|
if (scn_name == NULL) {
|
||
|
free(printable_sects);
|
||
|
free(scn_names);
|
||
|
print_error(dbg, "DW_ELF_STRPTR_ERROR", DW_DLV_OK, err);
|
||
|
}
|
||
|
|
||
|
scn_names[sect_number] = scn_name;
|
||
|
if (shdr32->sh_type == SHT_SYMTAB) {
|
||
|
size_t sym_size = 0;
|
||
|
size_t count = 0;
|
||
|
|
||
|
sym = (Elf32_Sym *) get_scndata(scn, &sym_size);
|
||
|
if (sym == NULL) {
|
||
|
free(printable_sects);
|
||
|
free(scn_names);
|
||
|
print_error(dbg, "No Elf32 symbol table data", DW_DLV_OK,
|
||
|
err);
|
||
|
}
|
||
|
count = sym_size / sizeof(Elf32_Sym);
|
||
|
if(sym_size%sizeof(Elf32_Sym)) {
|
||
|
print_error(dbg, "Elf32 problem reading .symtab data",
|
||
|
DW_DLV_OK, err);
|
||
|
}
|
||
|
sym++;
|
||
|
count--;
|
||
|
free(sym_data);
|
||
|
sym_data = 0;
|
||
|
sym_data = readsyms(sym, count, elf, shdr32->sh_link);
|
||
|
sym_data_entry_count = count;
|
||
|
if (sym_data == NULL) {
|
||
|
free(printable_sects);
|
||
|
free(scn_names);
|
||
|
print_error(dbg, "problem reading Elf32 symbol table data",
|
||
|
DW_DLV_OK, err);
|
||
|
}
|
||
|
} else {
|
||
|
get_reloc_section(dbg,scn,scn_name,shdr32->sh_type,
|
||
|
printable_sects,sect_number);
|
||
|
}
|
||
|
} /* End while. */
|
||
|
|
||
|
/* Set the relocation names based on the machine type */
|
||
|
set_relocation_table_names(ehdr32->e_machine);
|
||
|
for (i = 1; i < ehdr32->e_shnum + 1; i++) {
|
||
|
if (printable_sects[i].display &&
|
||
|
printable_sects[i].buf != NULL &&
|
||
|
printable_sects[i].size > 0) {
|
||
|
print_reloc_information_32(i,
|
||
|
printable_sects[i].buf,
|
||
|
printable_sects[i].size,
|
||
|
printable_sects[i].type,
|
||
|
scn_names,scn_names_cnt);
|
||
|
}
|
||
|
}
|
||
|
free(printable_sects);
|
||
|
free(scn_names);
|
||
|
scn_names = 0;
|
||
|
scn_names_cnt = 0;
|
||
|
}
|
||
|
|
||
|
#if HAVE_ELF64_R_INFO
|
||
|
#ifndef ELF64_R_TYPE
|
||
|
#define ELF64_R_TYPE(x) 0 /* FIXME */
|
||
|
#endif
|
||
|
#ifndef ELF64_R_SYM
|
||
|
#define ELF64_R_SYM(x) 0 /* FIXME */
|
||
|
#endif
|
||
|
#ifndef ELF64_ST_TYPE
|
||
|
#define ELF64_ST_TYPE(x) 0 /* FIXME */
|
||
|
#endif
|
||
|
#ifndef ELF64_ST_BIND
|
||
|
#define ELF64_ST_BIND(x) 0 /* FIXME */
|
||
|
#endif
|
||
|
#endif /* HAVE_ELF64_R_INFO */
|
||
|
|
||
|
|
||
|
static void
|
||
|
print_reloc_information_64(int section_no, Dwarf_Small * buf,
|
||
|
Dwarf_Unsigned size, Elf64_Xword type,
|
||
|
char **scn_names,int scn_names_count)
|
||
|
{
|
||
|
/* Include support for Elf64_Rel and Elf64_Rela */
|
||
|
Dwarf_Unsigned add = 0;
|
||
|
Dwarf_Half rel_size = SHT_RELA == type ?
|
||
|
sizeof(Elf64_Rela) : sizeof(Elf64_Rel);
|
||
|
Dwarf_Unsigned off = 0;
|
||
|
struct esb_s tempesb;
|
||
|
|
||
|
printf("\n[%3d] %s:\n",section_no, sanitized(scn_names[section_no]));
|
||
|
/* Print some headers and change the order for better reading */
|
||
|
printf("Offset Addend %-26s Index Symbol Name\n","Reloc Type");
|
||
|
|
||
|
#if HAVE_ELF64_GETEHDR
|
||
|
for (off = 0; off < size; off += rel_size) {
|
||
|
#if HAVE_ELF64_R_INFO
|
||
|
/* This works for the Elf64_Rel in linux */
|
||
|
Elf64_Rel *p = (Elf64_Rel *) (buf + off);
|
||
|
char *name = 0;
|
||
|
|
||
|
/* We subtract 1 from sym indexes since we left
|
||
|
symtab entry 0 out of the sym_data[_64] array */
|
||
|
if (sym_data ) {
|
||
|
size_t index = ELF64_R_SYM(p->r_info) - 1;
|
||
|
if (index < sym_data_entry_count) {
|
||
|
name = sym_data[index].name;
|
||
|
}
|
||
|
} else if (sym_data_64) {
|
||
|
size_t index = ELF64_R_SYM(p->r_info) - 1;
|
||
|
if (index < sym_data_64_entry_count) {
|
||
|
name = sym_data_64[index].name;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* When the name is not available, use the
|
||
|
section name as a reference for the name.*/
|
||
|
if (!name || !name[0]) {
|
||
|
size_t index = ELF64_R_SYM(p->r_info) - 1;
|
||
|
if (index < sym_data_64_entry_count) {
|
||
|
SYM64 *sym_64 = &sym_data_64[index];
|
||
|
if (sym_64->type == STT_SECTION &&
|
||
|
sym_64->shndx < scn_names_count) {
|
||
|
name = scn_names[sym_64->shndx];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (!name || !name[0]) {
|
||
|
name = "<no name>";
|
||
|
}
|
||
|
|
||
|
if (SHT_RELA == type) {
|
||
|
Elf64_Rela *pa = (Elf64_Rela *)p;
|
||
|
add = pa->r_addend;
|
||
|
}
|
||
|
esb_constructor(&tempesb);
|
||
|
esb_append(&tempesb,sanitized(
|
||
|
get_reloc_type_names(ELF64_R_TYPE(p->r_info))));
|
||
|
/* sanitized uses a static buffer, call just once here */
|
||
|
printf("0x%08lx 0x%08lx %-26s <%5ld> %s\n",
|
||
|
(unsigned long int) (p->r_offset),
|
||
|
(unsigned long int) (add),
|
||
|
esb_get_string(&tempesb),
|
||
|
(long)ELF64_R_SYM(p->r_info),
|
||
|
sanitized(name));
|
||
|
esb_destructor(&tempesb);
|
||
|
#else
|
||
|
/* sgi/mips -64 does not have r_info in the 64bit relocations,
|
||
|
but seperate fields, with 3 types, actually. Only one of
|
||
|
which prints here, as only one really used with dwarf */
|
||
|
Elf64_Rel *p = (Elf64_Rel *) (buf + off);
|
||
|
char *name = 0;
|
||
|
|
||
|
/* We subtract 1 from sym indexes since we left
|
||
|
symtab entry 0 out of the sym_data[_64] array */
|
||
|
if (sym_data ) {
|
||
|
size_t index = p->r_sym - 1;
|
||
|
if (index < sym_data_entry_count) {
|
||
|
name = sym_data[index].name;
|
||
|
}
|
||
|
} else if (sym_data_64) {
|
||
|
size_t index = p->r_sym - 1;
|
||
|
if (index < sym_data_64_entry_count) {
|
||
|
name = sym_data_64[index].name;
|
||
|
}
|
||
|
}
|
||
|
if (!name || !name[0]) {
|
||
|
name = "<no name>";
|
||
|
}
|
||
|
|
||
|
/* sanitized uses a static buffer, call just once here */
|
||
|
esb_constructor(&tempesb);
|
||
|
esb_append(&tempesb, sanitized(
|
||
|
get_reloc_type_names(p->r_type)));
|
||
|
/* sanitized uses a static buffer, call just once here */
|
||
|
printf("%5" DW_PR_DUu " %-26s <%3ld> %s\n",
|
||
|
(Dwarf_Unsigned) (p->r_offset),
|
||
|
esb_get_string(&tempesb),
|
||
|
(long)p->r_sym,
|
||
|
sanitized(name));
|
||
|
esb_destructor(&tempesb);
|
||
|
#endif
|
||
|
}
|
||
|
#endif /* HAVE_ELF64_GETEHDR */
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
print_reloc_information_32(int section_no, Dwarf_Small * buf,
|
||
|
Dwarf_Unsigned size, Elf64_Xword type, char **scn_names,
|
||
|
int scn_names_count)
|
||
|
{
|
||
|
/* Include support for Elf32_Rel and Elf32_Rela */
|
||
|
Dwarf_Unsigned add = 0;
|
||
|
Dwarf_Half rel_size = SHT_RELA == type ?
|
||
|
sizeof(Elf32_Rela) : sizeof(Elf32_Rel);
|
||
|
Dwarf_Unsigned off = 0;
|
||
|
struct esb_s tempesb;
|
||
|
|
||
|
printf("\n[%3d] %s:\n",section_no, sanitized(scn_names[section_no]));
|
||
|
|
||
|
/* Print some headers and change the order for better reading. */
|
||
|
printf("Offset Addend %-26s Index Symbol Name\n","Reloc Type");
|
||
|
|
||
|
for (off = 0; off < size; off += rel_size) {
|
||
|
Elf32_Rel *p = (Elf32_Rel *) (buf + off);
|
||
|
char *name = 0;
|
||
|
|
||
|
/* We subtract 1 from sym indexes since we left
|
||
|
symtab entry 0 out of the sym_data[_64] array */
|
||
|
if (sym_data) {
|
||
|
size_t index = ELF32_R_SYM(p->r_info) - 1;
|
||
|
if (index < sym_data_entry_count) {
|
||
|
name = sym_data[index].name;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* When the name is not available, use the
|
||
|
section name as a reference for the name. */
|
||
|
if (!name || !name[0]) {
|
||
|
size_t index = ELF32_R_SYM(p->r_info) - 1;
|
||
|
if (index < sym_data_entry_count) {
|
||
|
SYM *sym = &sym_data[index];
|
||
|
if (sym->type == STT_SECTION&&
|
||
|
sym->shndx < scn_names_count) {
|
||
|
name = scn_names[sym->shndx];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (!name || !name[0]) {
|
||
|
name = "<no name>";
|
||
|
}
|
||
|
if (SHT_RELA == type) {
|
||
|
Elf32_Rela *pa = (Elf32_Rela *)p;
|
||
|
add = pa->r_addend;
|
||
|
}
|
||
|
esb_constructor(&tempesb);
|
||
|
esb_append(&tempesb,sanitized(
|
||
|
get_reloc_type_names(ELF32_R_TYPE(p->r_info))));
|
||
|
printf("0x%08lx 0x%08lx %-26s <%5ld> %s\n",
|
||
|
(unsigned long int) (p->r_offset),
|
||
|
(unsigned long int) (add),
|
||
|
esb_get_string(&tempesb),
|
||
|
(long)ELF32_R_SYM(p->r_info),
|
||
|
sanitized(name));
|
||
|
esb_destructor(&tempesb);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* We are only reading and saving syms 1...num-1. */
|
||
|
static SYM *
|
||
|
readsyms(Elf32_Sym * data, size_t num, Elf * elf, Elf32_Word link)
|
||
|
{
|
||
|
SYM *s = 0;
|
||
|
SYM *buf = 0;
|
||
|
indx_type i = 0;
|
||
|
|
||
|
buf = (SYM *) calloc(num, sizeof(SYM));
|
||
|
if (buf == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
s = buf; /* save pointer to head of array */
|
||
|
for (i = 0; i < num; i++, data++, buf++) {
|
||
|
buf->indx = i;
|
||
|
buf->name = (char *) elf_strptr(elf, link, data->st_name);
|
||
|
buf->value = data->st_value;
|
||
|
buf->size = data->st_size;
|
||
|
buf->type = ELF32_ST_TYPE(data->st_info);
|
||
|
buf->bind = ELF32_ST_BIND(data->st_info);
|
||
|
buf->other = data->st_other;
|
||
|
buf->shndx = data->st_shndx;
|
||
|
} /* end for loop */
|
||
|
return (s);
|
||
|
}
|
||
|
|
||
|
/* We are only reading and saving syms 1...num-1. */
|
||
|
static SYM64 *
|
||
|
read_64_syms(Elf64_Sym * data, size_t num, Elf * elf, Elf64_Word link)
|
||
|
{
|
||
|
#ifdef HAVE_ELF64_GETEHDR
|
||
|
|
||
|
SYM64 *s = 0;
|
||
|
SYM64 *buf = 0;
|
||
|
indx_type i = 0;
|
||
|
|
||
|
buf = (SYM64 *) calloc(num, sizeof(SYM64));
|
||
|
if (buf == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
s = buf; /* save pointer to head of array */
|
||
|
for (i = 0; i < num; i++, data++, buf++) {
|
||
|
buf->indx = i;
|
||
|
buf->name = (char *) elf_strptr(elf, link, data->st_name);
|
||
|
buf->value = data->st_value;
|
||
|
buf->size = data->st_size;
|
||
|
buf->type = ELF64_ST_TYPE(data->st_info);
|
||
|
buf->bind = ELF64_ST_BIND(data->st_info);
|
||
|
buf->other = data->st_other;
|
||
|
buf->shndx = data->st_shndx;
|
||
|
} /* end for loop */
|
||
|
return (s);
|
||
|
#else
|
||
|
return 0;
|
||
|
#endif /* HAVE_ELF64_GETEHDR */
|
||
|
}
|
||
|
|
||
|
static void *
|
||
|
get_scndata(Elf_Scn * fd_scn, size_t * scn_size)
|
||
|
{
|
||
|
Elf_Data *p_data;
|
||
|
|
||
|
p_data = 0;
|
||
|
if ((p_data = elf_getdata(fd_scn, p_data)) == 0 ||
|
||
|
p_data->d_size == 0) {
|
||
|
return NULL;
|
||
|
}
|
||
|
*scn_size = p_data->d_size;
|
||
|
return (p_data->d_buf);
|
||
|
}
|
||
|
|
||
|
/* Cleanup of malloc space (some of the pointers will be 0 here)
|
||
|
so dwarfdump looks 'clean' to a malloc checker.
|
||
|
*/
|
||
|
void
|
||
|
clean_up_syms_malloc_data()
|
||
|
{
|
||
|
free(sym_data);
|
||
|
sym_data = 0;
|
||
|
free(sym_data_64);
|
||
|
sym_data_64 = 0;
|
||
|
sym_data_64_entry_count = 0;
|
||
|
sym_data_entry_count = 0;
|
||
|
}
|
||
|
#endif /* !SELFTEST */
|
||
|
|
||
|
#ifdef SELFTEST
|
||
|
/* SELFTEST here is just to check on table
|
||
|
internal consistency. */
|
||
|
int
|
||
|
main()
|
||
|
{
|
||
|
int failcount = 0;
|
||
|
unsigned long i = 1;
|
||
|
for ( ; i < DW_SECTION_REL_ARRAY_SIZE; ++i) {
|
||
|
if (rel_info[i].index != i) {
|
||
|
printf(" FAIL rel_info check, i = %lu vs %lu\n",
|
||
|
i,
|
||
|
(unsigned long)rel_info[i].index);
|
||
|
++failcount;
|
||
|
}
|
||
|
}
|
||
|
if(failcount) {
|
||
|
printf("FAIL print_reloc selftest\n");
|
||
|
exit(1);
|
||
|
}
|
||
|
printf("PASS print_reloc selftest\n");
|
||
|
return 0;
|
||
|
}
|
||
|
#endif /* SELFTEST*/
|