1 /* Copyright (C) 2005, 2007, 2008 Red Hat, Inc. 2 This file is part of Red Hat elfutils. 3 Written by Ulrich Drepper <drepper (at) redhat.com>, 2005. 4 5 Red Hat elfutils is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by the 7 Free Software Foundation; version 2 of the License. 8 9 Red Hat elfutils is distributed in the hope that it will be useful, but 10 WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 General Public License for more details. 13 14 You should have received a copy of the GNU General Public License along 15 with Red Hat elfutils; if not, write to the Free Software Foundation, 16 Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. 17 18 Red Hat elfutils is an included package of the Open Invention Network. 19 An included package of the Open Invention Network is a package for which 20 Open Invention Network licensees cross-license their patents. No patent 21 license is granted, either expressly or impliedly, by designation as an 22 included package. Should you wish to participate in the Open Invention 23 Network licensing program, please visit www.openinventionnetwork.com 24 <http://www.openinventionnetwork.com>. */ 25 26 #ifdef HAVE_CONFIG_H 27 # include <config.h> 28 #endif 29 30 #include <string.h> 31 32 #include "libasmP.h" 33 #include "../libebl/libeblP.h" 34 35 36 struct symtoken 37 { 38 DisasmCtx_t *ctx; 39 void *symcbarg; 40 }; 41 42 43 static int 44 default_elf_getsym (GElf_Addr addr, Elf32_Word scnndx, GElf_Addr value, 45 char **buf, size_t *buflen, void *arg) 46 { 47 struct symtoken *symtoken = (struct symtoken *) arg; 48 49 /* First try the user provided function. */ 50 if (symtoken->ctx->symcb != NULL) 51 { 52 int res = symtoken->ctx->symcb (addr, scnndx, value, buf, buflen, 53 symtoken->symcbarg); 54 if (res >= 0) 55 return res; 56 } 57 58 // XXX Look up in ELF file. 59 60 return -1; 61 } 62 63 64 struct symaddrpair 65 { 66 GElf_Addr addr; 67 const char *name; 68 }; 69 70 71 static void 72 read_symtab_exec (DisasmCtx_t *ctx) 73 { 74 /* We simply use all we can get our hands on. This will produce 75 some duplicate information but this is no problem, we simply 76 ignore the latter definitions. */ 77 Elf_Scn *scn= NULL; 78 while ((scn = elf_nextscn (ctx->elf, scn)) != NULL) 79 { 80 GElf_Shdr shdr_mem; 81 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); 82 Elf_Data *data; 83 if (shdr == NULL || shdr->sh_type != SHT_SYMTAB 84 || (data = elf_getdata (scn, NULL)) == NULL) 85 continue; 86 87 int xndxscnidx = elf_scnshndx (scn); 88 Elf_Data *xndxdata = NULL; 89 if (xndxscnidx > 0) 90 xndxdata = elf_getdata (elf_getscn (ctx->elf, xndxscnidx), NULL); 91 92 /* Iterate over all symbols. Add all defined symbols. */ 93 int nsyms = shdr->sh_size / shdr->sh_entsize; 94 for (int cnt = 1; cnt < nsyms; ++cnt) 95 { 96 Elf32_Word xshndx; 97 GElf_Sym sym_mem; 98 GElf_Sym *sym = gelf_getsymshndx (data, xndxdata, cnt, &sym_mem, 99 &xshndx); 100 if (sym == NULL) 101 continue; 102 103 /* Undefined symbols are useless here. */ 104 if (sym->st_shndx == SHN_UNDEF) 105 continue; 106 107 108 } 109 } 110 } 111 112 113 static void 114 read_symtab (DisasmCtx_t *ctx) 115 { 116 /* Find the symbol table(s). */ 117 GElf_Ehdr ehdr_mem; 118 GElf_Ehdr *ehdr = gelf_getehdr (ctx->elf, &ehdr_mem); 119 if (ehdr == NULL) 120 return; 121 122 switch (ehdr->e_type) 123 { 124 case ET_EXEC: 125 case ET_DYN: 126 read_symtab_exec (ctx); 127 break; 128 129 case ET_REL: 130 // XXX Handle 131 break; 132 133 default: 134 break; 135 } 136 } 137 138 139 static int 140 null_elf_getsym (GElf_Addr addr __attribute__ ((unused)), 141 Elf32_Word scnndx __attribute__ ((unused)), 142 GElf_Addr value __attribute__ ((unused)), 143 char **buf __attribute__ ((unused)), 144 size_t *buflen __attribute__ ((unused)), 145 void *arg __attribute__ ((unused))) 146 { 147 return -1; 148 } 149 150 151 int 152 disasm_cb (DisasmCtx_t *ctx, const uint8_t **startp, const uint8_t *end, 153 GElf_Addr addr, const char *fmt, DisasmOutputCB_t outcb, 154 void *outcbarg, void *symcbarg) 155 { 156 struct symtoken symtoken; 157 DisasmGetSymCB_t getsym = ctx->symcb ?: null_elf_getsym; 158 159 if (ctx->elf != NULL) 160 { 161 /* Read all symbols of the ELF file and stuff them into a hash 162 table. The key is the address and the section index. */ 163 read_symtab (ctx); 164 165 symtoken.ctx = ctx; 166 symtoken.symcbarg = symcbarg; 167 168 symcbarg = &symtoken; 169 170 getsym = default_elf_getsym; 171 } 172 173 return ctx->ebl->disasm (startp, end, addr, fmt, outcb, getsym, outcbarg, 174 symcbarg); 175 } 176 INTDEF (disasm_cb) 177