diff options
author | Ulrich Drepper <drepper@redhat.com> | 2008-01-02 17:44:39 +0000 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 2008-01-02 17:44:39 +0000 |
commit | 3cbdd387c752999255aea91600b5cfdefbeac7d0 (patch) | |
tree | 50c18bd26f8cd31f4c1aa3ce1d78bb98548659ba /libasm | |
parent | ad024afc93dcd0f4797b3e80bfb6b80c34da5c12 (diff) | |
download | elfutils-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/ChangeLog | 11 | ||||
-rw-r--r-- | libasm/Makefile.am | 1 | ||||
-rw-r--r-- | libasm/asm_error.c | 1 | ||||
-rw-r--r-- | libasm/disasm_begin.c | 49 | ||||
-rw-r--r-- | libasm/disasm_cb.c | 176 | ||||
-rw-r--r-- | libasm/disasm_end.c | 30 | ||||
-rw-r--r-- | libasm/disasm_str.c | 56 | ||||
-rw-r--r-- | libasm/libasm.h | 33 | ||||
-rw-r--r-- | libasm/libasm.map | 5 | ||||
-rw-r--r-- | libasm/libasmP.h | 24 |
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. */ |