Better symbol retrieval function interface. Allow larger output buffers.
authorUlrich Drepper <drepper@redhat.com>
Fri, 11 Jan 2008 09:35:15 +0000 (09:35 +0000)
committerUlrich Drepper <drepper@redhat.com>
Fri, 11 Jan 2008 09:35:15 +0000 (09:35 +0000)
libasm/ChangeLog
libasm/disasm_cb.c
libasm/libasm.h
libcpu/ChangeLog
libcpu/i386_disasm.c

index 1fe6756..2894970 100644 (file)
@@ -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.
index a044162..5610125 100644 (file)
@@ -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;
index 8a005f1..307c734 100644 (file)
@@ -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 *);
index 4790dd1..cbfcd75 100644 (file)
@@ -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.
index acd2d44..dd7bfca 100644 (file)
@@ -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;
 }