summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libasm/ChangeLog6
-rw-r--r--libasm/disasm_cb.c8
-rw-r--r--libasm/libasm.h6
-rw-r--r--libcpu/ChangeLog5
-rw-r--r--libcpu/i386_disasm.c101
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 = &param_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 = &param_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;
}