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