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