tools/elf4rom/libs/dwarf-20071209/dwarfdump/print_reloc.c
changeset 34 92d87f2e53c2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/elf4rom/libs/dwarf-20071209/dwarfdump/print_reloc.c	Fri Jan 15 09:07:44 2010 +0000
@@ -0,0 +1,512 @@
+/* 
+  Copyright (C) 2000,2004,2005 Silicon Graphics, Inc.  All Rights Reserved.
+  Portions Copyright (C) 2007 David Anderson. 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.
+
+  Contact information:  Silicon Graphics, Inc., 1500 Crittenden Lane,
+  Mountain View, CA 94043, or:
+
+  http://www.sgi.com
+
+  For further information regarding this notice, see:
+
+  http://oss.sgi.com/projects/GenInfo/NoticeExplan
+
+
+
+$Header: /plroot/cmplrs.src/v7.4.5m/.RCS/PL/dwarfdump/RCS/print_reloc.c,v 1.11 2005/08/04 05:09:37 davea Exp $ */
+
+/* The address of the Free Software Foundation is
+   Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 
+   Boston, MA 02110-1301, USA.
+   SGI has moved from the Crittenden Lane address.
+*/
+
+
+
+
+#include "globals.h"
+
+
+#define DW_SECTION_REL_DEBUG_INFO    0
+#define DW_SECTION_REL_DEBUG_LINE    1
+#define DW_SECTION_REL_DEBUG_PUBNAME 2
+#define DW_SECTION_REL_DEBUG_ABBREV  3
+#define DW_SECTION_REL_DEBUG_ARANGES 4
+#define DW_SECTION_REL_DEBUG_FRAME   5
+#define DW_SECTION_REL_DEBUG_NUM     6
+
+#define DW_SECTNAME_REL_DEBUG_INFO    ".rel.debug_info"
+#define DW_SECTNAME_REL_DEBUG_LINE    ".rel.debug_line"
+#define DW_SECTNAME_REL_DEBUG_PUBNAME ".rel.debug_pubname"
+#define DW_SECTNAME_REL_DEBUG_ABBREV  ".rel.debug_abbrev"
+#define DW_SECTNAME_REL_DEBUG_ARANGES ".rel.debug_aranges"
+#define DW_SECTNAME_REL_DEBUG_FRAME   ".rel.debug_frame"
+
+#define STRING_FOR_DUPLICATE " duplicate"
+#define STRING_FOR_NULL      " null"
+
+static char *sectnames[] = {
+    DW_SECTNAME_REL_DEBUG_INFO,
+    DW_SECTNAME_REL_DEBUG_LINE,
+    DW_SECTNAME_REL_DEBUG_PUBNAME,
+    DW_SECTNAME_REL_DEBUG_ABBREV,
+    DW_SECTNAME_REL_DEBUG_ARANGES,
+    DW_SECTNAME_REL_DEBUG_FRAME,
+};
+
+static char *error_msg_duplicate[] = {
+    DW_SECTNAME_REL_DEBUG_INFO STRING_FOR_DUPLICATE,
+    DW_SECTNAME_REL_DEBUG_LINE STRING_FOR_DUPLICATE,
+    DW_SECTNAME_REL_DEBUG_PUBNAME STRING_FOR_DUPLICATE,
+    DW_SECTNAME_REL_DEBUG_ABBREV STRING_FOR_DUPLICATE,
+    DW_SECTNAME_REL_DEBUG_ARANGES STRING_FOR_DUPLICATE,
+    DW_SECTNAME_REL_DEBUG_FRAME STRING_FOR_DUPLICATE,
+};
+
+static char *error_msg_null[] = {
+    DW_SECTNAME_REL_DEBUG_INFO STRING_FOR_NULL,
+    DW_SECTNAME_REL_DEBUG_LINE STRING_FOR_NULL,
+    DW_SECTNAME_REL_DEBUG_PUBNAME STRING_FOR_NULL,
+    DW_SECTNAME_REL_DEBUG_ABBREV STRING_FOR_NULL,
+    DW_SECTNAME_REL_DEBUG_ARANGES STRING_FOR_NULL,
+    DW_SECTNAME_REL_DEBUG_FRAME STRING_FOR_NULL,
+};
+
+#define SECT_DATA_SET(x) { \
+	    if (sect_data[(x)].buf != NULL) { \
+		print_error(dbg, error_msg_duplicate[(x)],DW_DLV_OK, err); \
+	    } \
+            if ((data = elf_getdata(scn, 0)) == NULL || data->d_size == 0) { \
+		print_error(dbg, error_msg_null[(x)],DW_DLV_OK, err); \
+	    } \
+	    sect_data[(x)].buf = data -> d_buf; \
+	    sect_data[(x)].size = data -> d_size; \
+	    }
+
+static char *reloc_type_names[] = {
+    "R_MIPS_NONE", "R_MIPS_16", "R_MIPS_32", "R_MIPS_REL32",
+    "R_MIPS_26", "R_MIPS_HI16", "R_MIPS_LO16", "R_MIPS_GPREL16",
+    "R_MIPS_LITERAL", "R_MIPS_GOT16", "R_MIPS_PC16", "R_MIPS_CALL16",
+    "R_MIPS_GPREL32",		/* 12 */
+    "reloc type 13?", "reloc type 14?", "reloc type 15?",
+    "R_MIPS_SHIFT5",		/* 16 */
+    "R_MIPS_SHIFT6",		/* 17 */
+    "R_MIPS_64",		/* 18 */
+    "R_MIPS_GOT_DISP",		/* 19 */
+    "R_MIPS_GOT_PAGE",		/* 20 */
+    "R_MIPS_GOT_OFST",		/* 21 */
+    "R_MIPS_GOT_HI16",		/* 22 */
+    "R_MIPS_GOT_LO16",		/* 23 */
+    "R_MIPS_SUB",		/* 24 */
+    "R_MIPS_INSERT_A",		/* 25 */
+    "R_MIPS_INSERT_B",		/* 26 */
+    "R_MIPS_DELETE",		/* 27 */
+    "R_MIPS_HIGHER",		/* 28 */
+    "R_MIPS_HIGHEST",		/* 29 */
+    "R_MIPS_CALL_HI16",		/* 30 */
+    "R_MIPS_CALL_LO16",		/* 31 */
+    "R_MIPS_SCN_DISP",		/* 32 */
+    "R_MIPS_REL16",		/* 33 */
+    "R_MIPS_ADD_IMMEDIATE",	/* 34 */
+};
+
+/*
+	return valid reloc type names. 
+	if buf is used, it is static, so beware it
+	will be overrwritten by the next call.
+*/
+static char *
+get_reloc_type_names(int index)
+{
+    static char buf[100];
+    int arysiz = sizeof(reloc_type_names) / sizeof(char *);
+    char *retval;
+
+    if (index < 0 || index >= arysiz) {
+	sprintf(buf, "reloc type %d unknown", (int) index);
+	retval = buf;
+    } else {
+	retval = reloc_type_names[index];
+    }
+    return retval;
+}
+
+
+static struct {
+    Dwarf_Small *buf;
+    Dwarf_Unsigned size;
+} sect_data[DW_SECTION_REL_DEBUG_NUM];
+
+#ifndef HAVE_ELF64_GETEHDR
+#define Elf64_Addr  long
+#define Elf64_Word  unsigned long
+#define Elf64_Xword unsigned long
+#define Elf64_Sym   long
+#endif
+
+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);
+static void print_reloc_information_32(int section_no,
+				       Dwarf_Small * buf,
+				       Dwarf_Unsigned size);
+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;
+
+void
+print_relocinfo(Dwarf_Debug dbg)
+{
+    Elf *elf;
+    char *endr_ident;
+    int is_64bit;
+    int res;
+    int i;
+    Elf32_Sym *sym = 0;
+
+    for (i = 0; i < DW_SECTION_REL_DEBUG_NUM; i++) {
+	sect_data[i].buf = 0;
+	sect_data[i].size = 0;
+    }
+    res = dwarf_get_elf(dbg, &elf, &err);
+    if (res != DW_DLV_OK) {
+	print_error(dbg, "dwarf_get_elf error", res, err);
+    }
+    if ((endr_ident = elf_getident(elf, NULL)) == NULL) {
+	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;
+    Elf_Data *data;
+    Elf64_Ehdr *ehdr64;
+    Elf64_Shdr *shdr64;
+    char *scn_name;
+    int i;
+    Elf64_Sym *sym_64 = 0;
+
+    if ((ehdr64 = elf64_getehdr(elf)) == NULL) {
+	print_error(dbg, "DW_ELF_GETEHDR_ERROR", DW_DLV_OK, err);
+    }
+
+    while ((scn = elf_nextscn(elf, scn)) != NULL) {
+
+	if ((shdr64 = elf64_getshdr(scn)) == NULL) {
+	    print_error(dbg, "DW_ELF_GETSHDR_ERROR", DW_DLV_OK, err);
+	}
+	if ((scn_name =
+	     elf_strptr(elf, ehdr64->e_shstrndx, shdr64->sh_name))
+	    == NULL) {
+	    print_error(dbg, "DW_ELF_STRPTR_ERROR", DW_DLV_OK, err);
+	}
+	if (shdr64->sh_type == SHT_SYMTAB) {
+	    size_t sym_size = 0;
+	    size_t count = 0;
+
+	    if ((sym_64 =
+		 (Elf64_Sym *) get_scndata(scn, &sym_size)) == NULL) {
+		print_error(dbg, "no symbol table data", DW_DLV_OK,
+			    err);
+	    }
+	    count = sym_size / sizeof(Elf64_Sym);
+	    sym_64++;
+            free(sym_data_64);
+	    sym_data_64 = read_64_syms(sym_64, count, elf, shdr64->sh_link);
+	    if (sym_data_64  == NULL) {
+		print_error(dbg, "problem reading symbol table data",
+			    DW_DLV_OK, err);
+	    }
+	} else if (strncmp(scn_name, ".rel.debug_", 11))
+	    continue;
+	else if (strcmp(scn_name, ".rel.debug_info") == 0) {
+	    SECT_DATA_SET(DW_SECTION_REL_DEBUG_INFO)
+	} else if (strcmp(scn_name, ".rel.debug_line") == 0) {
+	    SECT_DATA_SET(DW_SECTION_REL_DEBUG_LINE)
+	} else if (strcmp(scn_name, ".rel.debug_pubname") == 0) {
+	    SECT_DATA_SET(DW_SECTION_REL_DEBUG_PUBNAME)
+	} else if (strcmp(scn_name, ".rel.debug_aranges") == 0) {
+	    SECT_DATA_SET(DW_SECTION_REL_DEBUG_ARANGES)
+	} else if (strcmp(scn_name, ".rel.debug_abbrev") == 0) {
+	    SECT_DATA_SET(DW_SECTION_REL_DEBUG_ABBREV)
+	} else if (strcmp(scn_name, ".rel.debug_frame") == 0) {
+	    SECT_DATA_SET(DW_SECTION_REL_DEBUG_FRAME)
+	}
+    }				/* while */
+
+    for (i = 0; i < DW_SECTION_REL_DEBUG_NUM; i++) {
+	if (sect_data[i].buf != NULL && sect_data[i].size > 0) {
+	    print_reloc_information_64(i, sect_data[i].buf,
+				       sect_data[i].size);
+	}
+    }
+#endif
+}
+
+static void
+print_relocinfo_32(Dwarf_Debug dbg, Elf * elf)
+{
+    Elf_Scn *scn = NULL;
+    Elf_Data *data;
+    Elf32_Ehdr *ehdr32;
+    Elf32_Shdr *shdr32;
+    char *scn_name;
+    int i;
+    Elf32_Sym  *sym = 0;
+
+    if ((ehdr32 = elf32_getehdr(elf)) == NULL) {
+	print_error(dbg, "DW_ELF_GETEHDR_ERROR", DW_DLV_OK, err);
+    }
+    while ((scn = elf_nextscn(elf, scn)) != NULL) {
+	if ((shdr32 = elf32_getshdr(scn)) == NULL) {
+	    print_error(dbg, "DW_ELF_GETSHDR_ERROR", DW_DLV_OK, err);
+	}
+	if ((scn_name =
+	     elf_strptr(elf, ehdr32->e_shstrndx, shdr32->sh_name)
+	    ) == NULL) {
+	    print_error(dbg, "DW_ELF_STRPTR_ERROR", DW_DLV_OK, err);
+	}
+	if (shdr32->sh_type == SHT_SYMTAB) {
+	    size_t sym_size = 0;
+	    size_t count = 0;
+
+	    if ((sym =
+		 (Elf32_Sym *) get_scndata(scn, &sym_size)) == NULL) {
+		print_error(dbg, "no symbol table data", DW_DLV_OK,
+			    err);
+	    }
+	    sym = (Elf32_Sym *) get_scndata(scn, &sym_size);
+	    count = sym_size / sizeof(Elf32_Sym);
+	    sym++;
+            free(sym_data);
+	    sym_data = readsyms(sym, count, elf, shdr32->sh_link);
+	    if (sym_data  == NULL) {
+		print_error(dbg, "problem reading symbol table data",
+			    DW_DLV_OK, err);
+	    }
+	} else if (strncmp(scn_name, ".rel.debug_", 11))
+	    continue;
+	else if (strcmp(scn_name, ".rel.debug_info") == 0) {
+	    SECT_DATA_SET(DW_SECTION_REL_DEBUG_INFO)
+	} else if (strcmp(scn_name, ".rel.debug_line") == 0) {
+	    SECT_DATA_SET(DW_SECTION_REL_DEBUG_LINE)
+	} else if (strcmp(scn_name, ".rel.debug_pubname") == 0) {
+	    SECT_DATA_SET(DW_SECTION_REL_DEBUG_PUBNAME)
+	} else if (strcmp(scn_name, ".rel.debug_aranges") == 0) {
+	    SECT_DATA_SET(DW_SECTION_REL_DEBUG_ARANGES)
+	} else if (strcmp(scn_name, ".rel.debug_abbrev") == 0) {
+	    SECT_DATA_SET(DW_SECTION_REL_DEBUG_ABBREV)
+	} else if (strcmp(scn_name, ".rel.debug_frame") == 0) {
+	    SECT_DATA_SET(DW_SECTION_REL_DEBUG_FRAME)
+	}
+    }				/* while */
+
+    for (i = 0; i < DW_SECTION_REL_DEBUG_NUM; i++) {
+	if (sect_data[i].buf != NULL && sect_data[i].size > 0) {
+	    print_reloc_information_32(i, sect_data[i].buf,
+				       sect_data[i].size);
+	}
+    }
+}
+
+#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)
+{
+    Dwarf_Unsigned off;
+
+    printf("\n%s:\n", sectnames[section_no]);
+#if HAVE_ELF64_GETEHDR
+    for (off = 0; off < size; off += sizeof(Elf64_Rel)) {
+#if HAVE_ELF64_R_INFO
+	/* This works for the Elf64_Rel in linux */
+	Elf64_Rel *p = (Elf64_Rel *) (buf + off);
+
+	printf("%5lu\t<%3ld> %-34s%s\n",
+	       (unsigned long int) (p->r_offset),
+	       (long)ELF64_R_SYM(p->r_info),
+	       sym_data[ELF64_R_SYM(p->r_info) - 1].name,
+	       get_reloc_type_names(ELF64_R_TYPE(p->r_info)));
+#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);
+
+	printf("%5llu\t<%3d> %-34s%s\n",
+	       (unsigned long long int) (p->r_offset),
+	       (long)p->r_sym, sym_data_64[p->r_sym - 1].name,
+	       get_reloc_type_names(p->r_type));
+#endif
+    }
+#endif /* HAVE_ELF64_GETEHDR */
+}
+
+static void
+print_reloc_information_32(int section_no, Dwarf_Small * buf,
+			   Dwarf_Unsigned size)
+{
+    Dwarf_Unsigned off;
+
+    printf("\n%s:\n", sectnames[section_no]);
+    for (off = 0; off < size; off += sizeof(Elf32_Rel)) {
+	Elf32_Rel *p = (Elf32_Rel *) (buf + off);
+
+	printf("%5lu\t<%3d> %-34s%s\n",
+	       (unsigned long int) (p->r_offset),
+	       ELF32_R_SYM(p->r_info),
+	       sym_data[ELF32_R_SYM(p->r_info) - 1].name,
+	       get_reloc_type_names(ELF32_R_TYPE(p->r_info)));
+    }
+}
+
+static SYM *
+readsyms(Elf32_Sym * data, size_t num, Elf * elf, Elf32_Word link)
+{
+    SYM *s, *buf;
+    indx_type i;
+
+    if ((buf = (SYM *) calloc(num, sizeof(SYM))) == NULL) {
+	return NULL;
+    }
+    s = buf;			/* save pointer to head of array */
+    for (i = 1; 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);
+}
+
+static SYM64 *
+read_64_syms(Elf64_Sym * data, size_t num, Elf * elf, Elf64_Word link)
+{
+#ifdef HAVE_ELF64_GETEHDR
+
+    SYM64 *s, *buf;
+    indx_type i;
+
+    if ((buf = (SYM64 *) calloc(num, sizeof(SYM64))) == NULL) {
+	return NULL;
+    }
+    s = buf;			/* save pointer to head of array */
+    for (i = 1; 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);
+    free(sym_data_64);
+}