aboutsummaryrefslogtreecommitdiff
path: root/libasm
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2008-01-02 17:44:39 +0000
committerUlrich Drepper <drepper@redhat.com>2008-01-02 17:44:39 +0000
commit3cbdd387c752999255aea91600b5cfdefbeac7d0 (patch)
tree50c18bd26f8cd31f4c1aa3ce1d78bb98548659ba /libasm
parentad024afc93dcd0f4797b3e80bfb6b80c34da5c12 (diff)
downloadelfutils-3cbdd387c752999255aea91600b5cfdefbeac7d0.tar.gz
propagate from branch 'com.redhat.elfutils.disasm' (head d15b4eb794e81e477f9896fe82a74cb5ecf4514c)
to branch 'com.redhat.elfutils' (head eaacbf01f8cc89d043ec6eca9b5e35cb5c4cde06)
Diffstat (limited to 'libasm')
-rw-r--r--libasm/ChangeLog11
-rw-r--r--libasm/Makefile.am1
-rw-r--r--libasm/asm_error.c1
-rw-r--r--libasm/disasm_begin.c49
-rw-r--r--libasm/disasm_cb.c176
-rw-r--r--libasm/disasm_end.c30
-rw-r--r--libasm/disasm_str.c56
-rw-r--r--libasm/libasm.h33
-rw-r--r--libasm/libasm.map5
-rw-r--r--libasm/libasmP.h24
10 files changed, 386 insertions, 0 deletions
diff --git a/libasm/ChangeLog b/libasm/ChangeLog
index 99fb5e4f..78a895c2 100644
--- a/libasm/ChangeLog
+++ b/libasm/ChangeLog
@@ -1,3 +1,14 @@
+2007-12-20 Ulrich Drepper <drepper@redhat.com>
+
+ * disasm_cb.c: Add initial support to resolve addresses to symbols.
+
+2007-02-05 Ulrich Drepper <drepper@redhat.com>
+
+ * disasm_begin.c: New file.
+ * disasm_cb.c: New file.
+ * disasm_end.c: New file.
+ * disasm_str.c: New file.
+
2006-08-29 Roland McGrath <roland@redhat.com>
* Makefile.am (CLEANFILES): Add libasm.so.$(VERSION).
diff --git a/libasm/Makefile.am b/libasm/Makefile.am
index 3bea3747..95939617 100644
--- a/libasm/Makefile.am
+++ b/libasm/Makefile.am
@@ -59,6 +59,7 @@ libasm_a_SOURCES = asm_begin.c asm_abort.c asm_end.c asm_error.c \
asm_addint32.c asm_adduint32.c \
asm_addint64.c asm_adduint64.c \
asm_adduleb128.c asm_addsleb128.c \
+ disasm_begin.c disasm_cb.c disasm_end.c disasm_str.c \
symbolhash.c
if !MUDFLAP
diff --git a/libasm/asm_error.c b/libasm/asm_error.c
index f91bb78e..29c54cb0 100644
--- a/libasm/asm_error.c
+++ b/libasm/asm_error.c
@@ -126,6 +126,7 @@ static const char *msgs[ASM_E_NUM] =
[ASM_E_DUPLSYM] = N_("duplicate symbol"),
[ASM_E_TYPE] = N_("invalid section type for operation"),
[ASM_E_IOERROR] = N_("error during output of data"),
+ [ASM_E_ENOSUP] = N_("no backend support available"),
};
const char *
diff --git a/libasm/disasm_begin.c b/libasm/disasm_begin.c
new file mode 100644
index 00000000..5cdb5424
--- /dev/null
+++ b/libasm/disasm_begin.c
@@ -0,0 +1,49 @@
+/* Create context descriptor for disassembler.
+ Copyright (C) 2005 Red Hat, Inc.
+ Written by Ulrich Drepper <drepper@redhat.com>, 2005.
+
+ This program is Open Source software; you can redistribute it and/or
+ modify it under the terms of the Open Software License version 1.0 as
+ published by the Open Source Initiative.
+
+ You should have received a copy of the Open Software License along
+ with this program; if not, you may obtain a copy of the Open Software
+ License version 1.0 from http://www.opensource.org/licenses/osl.php or
+ by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
+ 3001 King Ranch Road, Ukiah, CA 95482. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#include "libasmP.h"
+#include "../libebl/libeblP.h"
+
+
+DisasmCtx_t *
+disasm_begin (Ebl *ebl, Elf *elf, DisasmGetSymCB_t symcb)
+{
+ if (ebl == NULL)
+ return NULL;
+
+ if (ebl->disasm == NULL)
+ {
+ __libasm_seterrno (ASM_E_ENOSUP);
+ return NULL;
+ }
+
+ DisasmCtx_t *ctx = (DisasmCtx_t *) malloc (sizeof (DisasmCtx_t));
+ if (ctx == NULL)
+ {
+ __libasm_seterrno (ASM_E_NOMEM);
+ return NULL;
+ }
+
+ ctx->ebl = ebl;
+ ctx->elf = elf;
+ ctx->symcb = symcb;
+
+ return ctx;
+}
diff --git a/libasm/disasm_cb.c b/libasm/disasm_cb.c
new file mode 100644
index 00000000..a0441621
--- /dev/null
+++ b/libasm/disasm_cb.c
@@ -0,0 +1,176 @@
+/* Copyright (C) 2005, 2007 Red Hat, Inc.
+ This file is part of Red Hat elfutils.
+ Written by Ulrich Drepper <drepper@redhat.com>, 2005.
+
+ Red Hat elfutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by the
+ Free Software Foundation; version 2 of the License.
+
+ Red Hat elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Red Hat elfutils; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+ Red Hat elfutils is an included package of the Open Invention Network.
+ An included package of the Open Invention Network is a package for which
+ Open Invention Network licensees cross-license their patents. No patent
+ license is granted, either expressly or impliedly, by designation as an
+ included package. Should you wish to participate in the Open Invention
+ Network licensing program, please visit www.openinventionnetwork.com
+ <http://www.openinventionnetwork.com>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+
+#include "libasmP.h"
+#include "../libebl/libeblP.h"
+
+
+struct symtoken
+{
+ DisasmCtx_t *ctx;
+ void *symcbarg;
+};
+
+
+static int
+default_elf_getsym (GElf_Addr addr, Elf32_Word scnndx, GElf_Addr value,
+ char *buf, size_t buflen, void *arg)
+{
+ struct symtoken *symtoken = (struct symtoken *) arg;
+
+ /* First try the user provided function. */
+ if (symtoken->ctx->symcb != NULL)
+ {
+ int res = symtoken->ctx->symcb (addr, scnndx, value, buf, buflen,
+ symtoken->symcbarg);
+ if (res >= 0)
+ return res;
+ }
+
+ // XXX Look up in ELF file.
+
+ return -1;
+}
+
+
+struct symaddrpair
+{
+ GElf_Addr addr;
+ const char *name;
+};
+
+
+static void
+read_symtab_exec (DisasmCtx_t *ctx)
+{
+ /* We simply use all we can get our hands on. This will produce
+ some duplicate information but this is no problem, we simply
+ ignore the latter definitions. */
+ Elf_Scn *scn= NULL;
+ while ((scn = elf_nextscn (ctx->elf, scn)) != NULL)
+ {
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+ Elf_Data *data;
+ if (shdr == NULL || shdr->sh_type != SHT_SYMTAB
+ || (data = elf_getdata (scn, NULL)) == NULL)
+ continue;
+
+ int xndxscnidx = elf_scnshndx (scn);
+ Elf_Data *xndxdata = NULL;
+ if (xndxscnidx > 0)
+ xndxdata = elf_getdata (elf_getscn (ctx->elf, xndxscnidx), NULL);
+
+ /* Iterate over all symbols. Add all defined symbols. */
+ int nsyms = shdr->sh_size / shdr->sh_entsize;
+ for (int cnt = 1; cnt < nsyms; ++cnt)
+ {
+ Elf32_Word xshndx;
+ GElf_Sym sym_mem;
+ GElf_Sym *sym = gelf_getsymshndx (data, xndxdata, cnt, &sym_mem,
+ &xshndx);
+ if (sym == NULL)
+ continue;
+
+ /* Undefined symbols are useless here. */
+ if (sym->st_shndx == SHN_UNDEF)
+ continue;
+
+
+ }
+ }
+}
+
+
+static void
+read_symtab (DisasmCtx_t *ctx)
+{
+ /* Find the symbol table(s). */
+ GElf_Ehdr ehdr_mem;
+ GElf_Ehdr *ehdr = gelf_getehdr (ctx->elf, &ehdr_mem);
+ if (ehdr == NULL)
+ return;
+
+ switch (ehdr->e_type)
+ {
+ case ET_EXEC:
+ case ET_DYN:
+ read_symtab_exec (ctx);
+ break;
+
+ case ET_REL:
+ // XXX Handle
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+static int
+null_elf_getsym (GElf_Addr addr __attribute__ ((unused)),
+ Elf32_Word scnndx __attribute__ ((unused)),
+ GElf_Addr value __attribute__ ((unused)),
+ char *buf __attribute__ ((unused)),
+ size_t buflen __attribute__ ((unused)),
+ void *arg __attribute__ ((unused)))
+{
+ return -1;
+}
+
+
+int
+disasm_cb (DisasmCtx_t *ctx, const uint8_t **startp, const uint8_t *end,
+ GElf_Addr addr, const char *fmt, DisasmOutputCB_t outcb,
+ void *outcbarg, void *symcbarg)
+{
+ struct symtoken symtoken;
+ DisasmGetSymCB_t getsym = ctx->symcb ?: null_elf_getsym;
+
+ if (ctx->elf != NULL)
+ {
+ /* Read all symbols of the ELF file and stuff them into a hash
+ table. The key is the address and the section index. */
+ read_symtab (ctx);
+
+ symtoken.ctx = ctx;
+ symtoken.symcbarg = symcbarg;
+
+ symcbarg = &symtoken;
+
+ getsym = default_elf_getsym;
+ }
+
+ return ctx->ebl->disasm (startp, end, addr, fmt, outcb, getsym, outcbarg,
+ symcbarg);
+}
+INTDEF (disasm_cb)
diff --git a/libasm/disasm_end.c b/libasm/disasm_end.c
new file mode 100644
index 00000000..3165c2dc
--- /dev/null
+++ b/libasm/disasm_end.c
@@ -0,0 +1,30 @@
+/* Release descriptor for disassembler.
+ Copyright (C) 2005 Red Hat, Inc.
+ Written by Ulrich Drepper <drepper@redhat.com>, 2005.
+
+ This program is Open Source software; you can redistribute it and/or
+ modify it under the terms of the Open Software License version 1.0 as
+ published by the Open Source Initiative.
+
+ You should have received a copy of the Open Software License along
+ with this program; if not, you may obtain a copy of the Open Software
+ License version 1.0 from http://www.opensource.org/licenses/osl.php or
+ by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
+ 3001 King Ranch Road, Ukiah, CA 95482. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#include "libasmP.h"
+
+
+int
+disasm_end (DisasmCtx_t *ctx)
+{
+ free (ctx);
+
+ return 0;
+}
diff --git a/libasm/disasm_str.c b/libasm/disasm_str.c
new file mode 100644
index 00000000..9f407371
--- /dev/null
+++ b/libasm/disasm_str.c
@@ -0,0 +1,56 @@
+/* Copyright (C) 2005 Red Hat, Inc.
+
+ This program is Open Source software; you can redistribute it and/or
+ modify it under the terms of the Open Software License version 1.0 as
+ published by the Open Source Initiative.
+
+ You should have received a copy of the Open Software License along
+ with this program; if not, you may obtain a copy of the Open Software
+ License version 1.0 from http://www.opensource.org/licenses/osl.php or
+ by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
+ 3001 King Ranch Road, Ukiah, CA 95482. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+
+#include "libasmP.h"
+
+
+struct buffer
+{
+ char *buf;
+ size_t len;
+};
+
+
+static int
+buffer_cb (char *str, size_t len, void *arg)
+{
+ struct buffer *buffer = (struct buffer *) arg;
+
+ if (len > buffer->len)
+ /* Return additional needed space. */
+ return len - buffer->len;
+
+ buffer->buf = mempcpy (buffer->buf, str, len);
+ buffer->len = len;
+
+ return 0;
+}
+
+
+int
+disasm_str (DisasmCtx_t *ctx, const uint8_t **startp, const uint8_t *end,
+ GElf_Addr addr, const char *fmt, char **bufp, size_t len,
+ void *symcbarg)
+{
+ struct buffer buffer = { .buf = *bufp, .len = len };
+
+ int res = INTUSE(disasm_cb) (ctx, startp, end, addr, fmt, buffer_cb, &buffer,
+ symcbarg);
+ *bufp = buffer.buf;
+ return res;
+}
diff --git a/libasm/libasm.h b/libasm/libasm.h
index 6daf221e..8a005f1c 100644
--- a/libasm/libasm.h
+++ b/libasm/libasm.h
@@ -45,6 +45,20 @@ typedef struct AsmScnGrp AsmScnGrp_t;
typedef struct AsmSym AsmSym_t;
+/* Opaque type for the disassembler context descriptor. */
+typedef struct DisasmCtx DisasmCtx_t;
+
+/* Type used for callback functions to retrieve symbol name. The
+ symbol reference is in the section designated by the second parameter
+ at an offset described by the first parameter. The value is the
+ third parameter. */
+typedef int (*DisasmGetSymCB_t) (GElf_Addr, Elf32_Word, GElf_Addr, char *,
+ size_t, void *);
+
+/* Output function callback. */
+typedef int (*DisasmOutputCB_t) (char *, size_t, void *);
+
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -159,6 +173,25 @@ extern int asm_errno (void);
string is returned. */
extern const char *asm_errmsg (int __error);
+
+/* Create context descriptor for disassembler. */
+extern DisasmCtx_t *disasm_begin (Ebl *ebl, Elf *elf, DisasmGetSymCB_t symcb);
+
+/* Release descriptor for disassembler. */
+extern int disasm_end (DisasmCtx_t *ctx);
+
+/* Produce of disassembly output for given memory, store text in
+ provided buffer. */
+extern int disasm_str (DisasmCtx_t *ctx, const uint8_t **startp,
+ const uint8_t *end, GElf_Addr addr, const char *fmt,
+ char **bufp, size_t len, void *symcbarg);
+
+/* Produce disassembly output for given memory and output it using the
+ given callback functions. */
+extern int disasm_cb (DisasmCtx_t *ctx, const uint8_t **startp,
+ const uint8_t *end, GElf_Addr addr, const char *fmt,
+ DisasmOutputCB_t outcb, void *outcbarg, void *symcbarg);
+
#ifdef __cplusplus
}
#endif
diff --git a/libasm/libasm.map b/libasm/libasm.map
index b0b5b5b7..a36cdbfe 100644
--- a/libasm/libasm.map
+++ b/libasm/libasm.map
@@ -28,6 +28,11 @@ ELFUTILS_1.0 {
asm_newsym;
asm_scngrp_newsignature;
+ disasm_begin;
+ disasm_cb;
+ disasm_end;
+ disasm_str;
+
local:
*;
};
diff --git a/libasm/libasmP.h b/libasm/libasmP.h
index e6401575..ee7005f5 100644
--- a/libasm/libasmP.h
+++ b/libasm/libasmP.h
@@ -47,6 +47,7 @@ enum
ASM_E_LIBELF, /* Refer to error in libelf. */
ASM_E_TYPE, /* Invalid section type for operation. */
ASM_E_IOERROR, /* Error during output of data. */
+ ASM_E_ENOSUP, /* No backend support. */
ASM_E_NUM /* Keep this entry as the last. */
};
@@ -235,6 +236,21 @@ struct AsmScnGrp
};
+/* Descriptor for disassembler. */
+struct DisasmCtx
+{
+ /* Handle for the backend library with the disassembler routine. */
+ Ebl *ebl;
+
+ /* ELF file containing all the data passed to the function. This
+ allows to look up symbols. */
+ Elf *elf;
+
+ /* Callback function to determine symbol names. */
+ DisasmGetSymCB_t symcb;
+};
+
+
/* The default fill pattern: one zero byte. */
extern const struct FillPattern *__libasm_default_pattern
attribute_hidden;
@@ -269,6 +285,14 @@ extern int __asm_addint64_internal (AsmScn_t *asmscn, int64_t num)
attribute_hidden;
+/* Produce disassembly output for given memory and output it using the
+ given callback functions. */
+extern int __disasm_cb_internal (DisasmCtx_t *ctx, const uint8_t **startp,
+ const uint8_t *end, GElf_Addr addr,
+ const char *fmt, DisasmOutputCB_t outcb,
+ void *outcbarp, void *symcbarg)
+ attribute_hidden;
+
/* Test whether given symbol is an internal symbol and if yes, whether
we should nevertheless emit it in the symbol table. */