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