diff options
-rw-r--r-- | libasm/ChangeLog | 6 | ||||
-rw-r--r-- | libasm/disasm_cb.c | 8 | ||||
-rw-r--r-- | libasm/libasm.h | 6 | ||||
-rw-r--r-- | libcpu/ChangeLog | 5 | ||||
-rw-r--r-- | libcpu/i386_disasm.c | 101 |
5 files changed, 85 insertions, 41 deletions
diff --git a/libasm/ChangeLog b/libasm/ChangeLog index 1fe67565..2894970e 100644 --- a/libasm/ChangeLog +++ b/libasm/ChangeLog @@ -1,3 +1,9 @@ +2008-01-11 Ulrich Drepper <drepper@redhat.com> + + * libasm.h (DisasmGetSymCB_t): Change type of fourth and fifth + parameter. + * disasm_cb.c: Adjust accordingly. + 2008-01-08 Roland McGrath <roland@redhat.com> * Makefile.am (euinclude): Variable removed. diff --git a/libasm/disasm_cb.c b/libasm/disasm_cb.c index a0441621..56101258 100644 --- a/libasm/disasm_cb.c +++ b/libasm/disasm_cb.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2005, 2007 Red Hat, Inc. +/* Copyright (C) 2005, 2007, 2008 Red Hat, Inc. This file is part of Red Hat elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 2005. @@ -42,7 +42,7 @@ struct symtoken static int default_elf_getsym (GElf_Addr addr, Elf32_Word scnndx, GElf_Addr value, - char *buf, size_t buflen, void *arg) + char **buf, size_t *buflen, void *arg) { struct symtoken *symtoken = (struct symtoken *) arg; @@ -140,8 +140,8 @@ 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)), + char **buf __attribute__ ((unused)), + size_t *buflen __attribute__ ((unused)), void *arg __attribute__ ((unused))) { return -1; diff --git a/libasm/libasm.h b/libasm/libasm.h index 8a005f1c..307c7349 100644 --- a/libasm/libasm.h +++ b/libasm/libasm.h @@ -1,5 +1,5 @@ /* Interface for libasm. - Copyright (C) 2002, 2005 Red Hat, Inc. + Copyright (C) 2002, 2005, 2008 Red Hat, Inc. This file is part of Red Hat elfutils. Red Hat elfutils is free software; you can redistribute it and/or modify @@ -52,8 +52,8 @@ typedef struct DisasmCtx DisasmCtx_t; 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 *); +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 *); diff --git a/libcpu/ChangeLog b/libcpu/ChangeLog index 4790dd12..cbfcd755 100644 --- a/libcpu/ChangeLog +++ b/libcpu/ChangeLog @@ -1,3 +1,8 @@ +2008-01-11 Ulrich Drepper <drepper@redhat.com> + + * i386_disasm.c (i386_disasm): Resize output buffer if necessary. + Optimize output_data initialization. Free buffers before return. + 2008-01-10 Ulrich Drepper <drepper@redhat.com> * i386_data.h (FCT_crdb): New function. diff --git a/libcpu/i386_disasm.c b/libcpu/i386_disasm.c index acd2d443..dd7bfca4 100644 --- a/libcpu/i386_disasm.c +++ b/libcpu/i386_disasm.c @@ -234,17 +234,33 @@ i386_disasm (const uint8_t **startp, const uint8_t *end, GElf_Addr addr, void *outcbarg, void *symcbarg) { const char *save_fmt = fmt; + char *labelbuf = NULL; + //size_t labelbufsize = 0; +#define BUFSIZE 512 + char initbuf[BUFSIZE]; + int prefixes; + size_t bufcnt; + size_t bufsize = BUFSIZE; + char *buf = initbuf; + const uint8_t *param_start; + + struct output_data output_data = + { + .prefixes = &prefixes, + .bufp = buf, + .bufsize = bufsize, + .bufcntp = &bufcnt, + .param_start = ¶m_start, + .end = end, + .symcb = symcb, + .symcbarg = symcbarg + }; + + int retval = 0; while (1) { -#define BUFSIZE 512 - const size_t bufsize = BUFSIZE; - char initbuf[BUFSIZE]; - char *buf = initbuf; - size_t bufcnt = 0; - - int prefixes = 0; - int last_prefix_bit = 0; + prefixes = 0; const uint8_t *data = *startp; const uint8_t *begin = data; @@ -252,6 +268,7 @@ i386_disasm (const uint8_t **startp, const uint8_t *end, GElf_Addr addr, fmt = save_fmt; /* Recognize all prefixes. */ + int last_prefix_bit = 0; while (data < end) { unsigned int i; @@ -271,20 +288,41 @@ i386_disasm (const uint8_t **startp, const uint8_t *end, GElf_Addr addr, prefixes |= ((*data++) & 0xf) | has_rex; #endif + const uint8_t *curr = match_data; + const uint8_t *const match_end = match_data + sizeof (match_data); + assert (data <= end); if (data == end) { if (prefixes != 0) goto print_prefix; - return -1; + retval = -1; + goto do_ret; } - const uint8_t *curr = match_data; - const uint8_t *const match_end = match_data + sizeof (match_data); + if (0) + { + /* Resize the buffer. */ + char *oldbuf; + enomem: + oldbuf = buf; + if (buf == initbuf) + buf = malloc (2 * bufsize); + else + buf = realloc (buf, 2 * bufsize); + if (buf == NULL) + { + buf = oldbuf; + retval = ENOMEM; + goto do_ret; + } + bufsize *= 2; - enomem: - ; + output_data.bufp = buf; + output_data.bufsize = bufsize; + } + bufcnt = 0; size_t cnt = 0; while (curr < match_end) @@ -326,7 +364,7 @@ i386_disasm (const uint8_t **startp, const uint8_t *end, GElf_Addr addr, --avail; if (codep == end && avail > 0) - return 0; + goto do_ret; } while (avail > 0); @@ -342,7 +380,7 @@ i386_disasm (const uint8_t **startp, const uint8_t *end, GElf_Addr addr, /* There is not enough data for the entire instruction. The caller can figure this out by looking at the pointer into the input data. */ - return 0; + goto do_ret; assert (correct_prefix == 0 || (prefixes & correct_prefix) != 0); @@ -437,7 +475,7 @@ i386_disasm (const uint8_t **startp, const uint8_t *end, GElf_Addr addr, /* We have a match. First determine how many bytes are needed for the adressing mode. */ - const uint8_t *param_start = codep; + param_start = codep; if (instrtab[cnt].modrm) { uint_fast8_t modrm = codep[-1]; @@ -470,19 +508,8 @@ i386_disasm (const uint8_t **startp, const uint8_t *end, GElf_Addr addr, goto not; } - struct output_data output_data = - { - .addr = addr + (data - begin), - .prefixes = &prefixes, - .bufp = buf, - .bufcntp = &bufcnt, - .bufsize = bufsize, - .data = data, - .param_start = ¶m_start, - .end = end, - .symcb = symcb, - .symcbarg = symcbarg - }; + output_data.addr = addr + (data - begin); + output_data.data = data; unsigned long string_end_idx = 0; while (*fmt != '\0') @@ -523,7 +550,8 @@ i386_disasm (const uint8_t **startp, const uint8_t *end, GElf_Addr addr, break; default: - return EINVAL; + retval = EINVAL; + goto do_ret; } } ADD_CHAR (ch); @@ -813,10 +841,15 @@ i386_disasm (const uint8_t **startp, const uint8_t *end, GElf_Addr addr, out: *startp = data; - int res = outcb (buf, strlen (buf), outcbarg); - if (res != 0) - return res; + retval = outcb (buf, strlen (buf), outcbarg); + if (retval != 0) + goto do_ret; } - return 0; + do_ret: + free (labelbuf); + if (buf != initbuf) + free (buf); + + return retval; } |