Blame libasm/disasm_cb.c

Packit 032894
/* Copyright (C) 2005, 2007, 2008 Red Hat, Inc.
Packit 032894
   This file is part of elfutils.
Packit 032894
   Written by Ulrich Drepper <drepper@redhat.com>, 2005.
Packit 032894
Packit 032894
   This file is free software; you can redistribute it and/or modify
Packit 032894
   it under the terms of either
Packit 032894
Packit 032894
     * the GNU Lesser General Public License as published by the Free
Packit 032894
       Software Foundation; either version 3 of the License, or (at
Packit 032894
       your option) any later version
Packit 032894
Packit 032894
   or
Packit 032894
Packit 032894
     * the GNU General Public License as published by the Free
Packit 032894
       Software Foundation; either version 2 of the License, or (at
Packit 032894
       your option) any later version
Packit 032894
Packit 032894
   or both in parallel, as here.
Packit 032894
Packit 032894
   elfutils is distributed in the hope that it will be useful, but
Packit 032894
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 032894
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 032894
   General Public License for more details.
Packit 032894
Packit 032894
   You should have received copies of the GNU General Public License and
Packit 032894
   the GNU Lesser General Public License along with this program.  If
Packit 032894
   not, see <http://www.gnu.org/licenses/>.  */
Packit 032894
Packit 032894
#ifdef HAVE_CONFIG_H
Packit 032894
# include <config.h>
Packit 032894
#endif
Packit 032894
Packit 032894
#include <string.h>
Packit 032894
Packit 032894
#include "libasmP.h"
Packit 032894
#include "../libebl/libeblP.h"
Packit 032894
Packit 032894
Packit 032894
struct symtoken
Packit 032894
{
Packit 032894
  DisasmCtx_t *ctx;
Packit 032894
  void *symcbarg;
Packit 032894
};
Packit 032894
Packit 032894
Packit 032894
static int
Packit 032894
default_elf_getsym (GElf_Addr addr, Elf32_Word scnndx, GElf_Addr value,
Packit 032894
		    char **buf, size_t *buflen, void *arg)
Packit 032894
{
Packit 032894
  struct symtoken *symtoken = (struct symtoken *) arg;
Packit 032894
Packit 032894
  /* First try the user provided function.  */
Packit 032894
  if (symtoken->ctx->symcb != NULL)
Packit 032894
    {
Packit 032894
      int res = symtoken->ctx->symcb (addr, scnndx, value, buf, buflen,
Packit 032894
				      symtoken->symcbarg);
Packit 032894
      if (res >= 0)
Packit 032894
	return res;
Packit 032894
    }
Packit 032894
Packit 032894
  // XXX Look up in ELF file.
Packit 032894
Packit 032894
  return -1;
Packit 032894
}
Packit 032894
Packit 032894
Packit 032894
struct symaddrpair
Packit 032894
{
Packit 032894
  GElf_Addr addr;
Packit 032894
  const char *name;
Packit 032894
};
Packit 032894
Packit 032894
Packit 032894
static void
Packit 032894
read_symtab_exec (DisasmCtx_t *ctx)
Packit 032894
{
Packit 032894
  /* We simply use all we can get our hands on.  This will produce
Packit 032894
     some duplicate information but this is no problem, we simply
Packit 032894
     ignore the latter definitions.  */
Packit 032894
  Elf_Scn *scn= NULL;
Packit 032894
  while ((scn = elf_nextscn (ctx->elf, scn)) != NULL)
Packit 032894
    {
Packit 032894
      GElf_Shdr shdr_mem;
Packit 032894
      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
Packit 032894
      Elf_Data *data;
Packit 032894
      if (shdr == NULL || shdr->sh_type != SHT_SYMTAB
Packit 032894
	  || (data = elf_getdata (scn, NULL)) == NULL)
Packit 032894
	continue;
Packit 032894
Packit 032894
      int xndxscnidx = elf_scnshndx (scn);
Packit 032894
      Elf_Data *xndxdata = NULL;
Packit 032894
      if (xndxscnidx > 0)
Packit 032894
	xndxdata = elf_getdata (elf_getscn (ctx->elf, xndxscnidx), NULL);
Packit 032894
Packit 032894
      /* Iterate over all symbols.  Add all defined symbols.  */
Packit 032894
      if (shdr->sh_entsize == 0)
Packit 032894
	continue;
Packit 032894
      int nsyms = shdr->sh_size / shdr->sh_entsize;
Packit 032894
      for (int cnt = 1; cnt < nsyms; ++cnt)
Packit 032894
	{
Packit 032894
	  Elf32_Word xshndx;
Packit 032894
	  GElf_Sym sym_mem;
Packit 032894
	  GElf_Sym *sym = gelf_getsymshndx (data, xndxdata, cnt, &sym_mem,
Packit 032894
					    &xshndx);
Packit 032894
	  if (sym == NULL)
Packit 032894
	    continue;
Packit 032894
Packit 032894
	  /* Undefined symbols are useless here.  */
Packit 032894
	  if (sym->st_shndx == SHN_UNDEF)
Packit 032894
	    continue;
Packit 032894
Packit 032894
Packit 032894
	}
Packit 032894
    }
Packit 032894
}
Packit 032894
Packit 032894
Packit 032894
static void
Packit 032894
read_symtab (DisasmCtx_t *ctx)
Packit 032894
{
Packit 032894
  /* Find the symbol table(s).  */
Packit 032894
  GElf_Ehdr ehdr_mem;
Packit 032894
  GElf_Ehdr *ehdr = gelf_getehdr (ctx->elf, &ehdr_mem);
Packit 032894
  if (ehdr == NULL)
Packit 032894
    return;
Packit 032894
Packit 032894
  switch (ehdr->e_type)
Packit 032894
    {
Packit 032894
    case ET_EXEC:
Packit 032894
    case ET_DYN:
Packit 032894
      read_symtab_exec (ctx);
Packit 032894
      break;
Packit 032894
Packit 032894
    case ET_REL:
Packit 032894
      // XXX  Handle
Packit 032894
      break;
Packit 032894
Packit 032894
    default:
Packit 032894
      break;
Packit 032894
    }
Packit 032894
}
Packit 032894
Packit 032894
Packit 032894
static int
Packit 032894
null_elf_getsym (GElf_Addr addr __attribute__ ((unused)),
Packit 032894
		 Elf32_Word scnndx __attribute__ ((unused)),
Packit 032894
		 GElf_Addr value __attribute__ ((unused)),
Packit 032894
		 char **buf __attribute__ ((unused)),
Packit 032894
		 size_t *buflen __attribute__ ((unused)),
Packit 032894
		 void *arg __attribute__ ((unused)))
Packit 032894
{
Packit 032894
  return -1;
Packit 032894
}
Packit 032894
Packit 032894
Packit 032894
int
Packit 032894
disasm_cb (DisasmCtx_t *ctx, const uint8_t **startp, const uint8_t *end,
Packit 032894
	   GElf_Addr addr, const char *fmt, DisasmOutputCB_t outcb,
Packit 032894
	   void *outcbarg, void *symcbarg)
Packit 032894
{
Packit 032894
  struct symtoken symtoken;
Packit 032894
  DisasmGetSymCB_t getsym = ctx->symcb ?: null_elf_getsym;
Packit 032894
Packit 032894
  if (ctx->elf != NULL)
Packit 032894
    {
Packit 032894
      /* Read all symbols of the ELF file and stuff them into a hash
Packit 032894
	 table.  The key is the address and the section index.  */
Packit 032894
      read_symtab (ctx);
Packit 032894
Packit 032894
      symtoken.ctx = ctx;
Packit 032894
      symtoken.symcbarg = symcbarg;
Packit 032894
Packit 032894
      symcbarg = &symtoken;
Packit 032894
Packit 032894
      getsym = default_elf_getsym;
Packit 032894
    }
Packit 032894
Packit 032894
  return ctx->ebl->disasm (ctx->ebl, startp, end, addr, fmt, outcb,
Packit 032894
			   getsym, outcbarg, symcbarg);
Packit 032894
}
Packit 032894
INTDEF (disasm_cb)