Improve backtrace_symbols{,_fd} output when missing symbols.
authorRoland McGrath <roland@redhat.com>
Thu, 20 Aug 2009 22:31:08 +0000 (15:31 -0700)
committerRoland McGrath <roland@redhat.com>
Thu, 20 Aug 2009 22:31:08 +0000 (15:31 -0700)
ChangeLog
sysdeps/generic/elf/backtracesyms.c
sysdeps/generic/elf/backtracesymsfd.c

index 39bbb2a..6ace54b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2009-08-20  Roland McGrath  <roland@redhat.com>
+
+       * sysdeps/generic/elf/backtracesyms.c (__backtrace_symbols):
+       Use l_addr instead of l_map_start (dli_fbase).
+       Print "FILE([+-]OFFSET) [ADDRESS]" with the file-relative
+       address when there is no proximate symbol.
+       * sysdeps/generic/elf/backtracesymsfd.c (__backtrace_symbols_fd):
+       Likewise.
+
 2009-08-16  Ulrich Drepper  <drepper@redhat.com>
 
        * scripts/gen-as-const.awk: Fix test for 64-bit platform.
index b31be6a..319b207 100644 (file)
@@ -1,5 +1,5 @@
 /* Return list with names for address in backtrace.
-   Copyright (C) 1998,1999,2000,2001,2003 Free Software Foundation, Inc.
+   Copyright (C) 1998,1999,2000,2001,2003,2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
 
@@ -48,15 +48,22 @@ __backtrace_symbols (array, size)
   /* Fill in the information we can get from `dladdr'.  */
   for (cnt = 0; cnt < size; ++cnt)
     {
-      status[cnt] = _dl_addr (array[cnt], &info[cnt], NULL, NULL);
+      struct link_map *map;
+      status[cnt] = _dl_addr (array[cnt], &info[cnt], &map, NULL);
       if (status[cnt] && info[cnt].dli_fname && info[cnt].dli_fname[0] != '\0')
-       /* We have some info, compute the length of the string which will be
-          "<file-name>(<sym-name>) [+offset].  */
-       total += (strlen (info[cnt].dli_fname ?: "")
-                 + (info[cnt].dli_sname
-                    ? strlen (info[cnt].dli_sname) + 3 + WORD_WIDTH + 3
-                    : 1)
-                 + WORD_WIDTH + 5);
+       {
+         /* We have some info, compute the length of the string which will be
+            "<file-name>(<sym-name>+offset) [address].  */
+         total += (strlen (info[cnt].dli_fname ?: "")
+                   + strlen (info[cnt].dli_sname ?: "")
+                   + 3 + WORD_WIDTH + 3 + WORD_WIDTH + 5);
+
+         /* The load bias is more useful to the user than the load
+            address.  The use of these addresses is to calculate an
+            address in the ELF file, so its prelinked bias is not
+            something we want to subtract out.  */
+         info[cnt].dli_fbase = (void *) map->l_addr;
+       }
       else
        total += 5 + WORD_WIDTH;
     }
@@ -71,25 +78,39 @@ __backtrace_symbols (array, size)
        {
          result[cnt] = last;
 
-         if (status[cnt] && info[cnt].dli_fname
-             && info[cnt].dli_fname[0] != '\0')
+         if (status[cnt]
+             && info[cnt].dli_fname != NULL && info[cnt].dli_fname[0] != '\0')
            {
-             char buf[20];
+             if (info[cnt].dli_sname == NULL)
+               /* We found no symbol name to use, so describe it as
+                  relative to the file.  */
+               info[cnt].dli_saddr = info[cnt].dli_fbase;
 
-             if (array[cnt] >= (void *) info[cnt].dli_saddr)
-               sprintf (buf, "+%#lx",
-                        (unsigned long)(array[cnt] - info[cnt].dli_saddr));
+             if (info[cnt].dli_sname == NULL && info[cnt].dli_saddr == 0)
+               last += 1 + sprintf (last, "%s(%s) [%p]",
+                                    info[cnt].dli_fname ?: "",
+                                    info[cnt].dli_sname ?: "",
+                                    array[cnt]);
              else
-               sprintf (buf, "-%#lx",
-                        (unsigned long)(info[cnt].dli_saddr - array[cnt]));
-
-             last += 1 + sprintf (last, "%s%s%s%s%s[%p]",
-                                  info[cnt].dli_fname ?: "",
-                                  info[cnt].dli_sname ? "(" : "",
-                                  info[cnt].dli_sname ?: "",
-                                  info[cnt].dli_sname ? buf : "",
-                                  info[cnt].dli_sname ? ") " : " ",
-                                  array[cnt]);
+               {
+                 char sign;
+                 ptrdiff_t offset;
+                 if (array[cnt] >= (void *) info[cnt].dli_saddr)
+                   {
+                     sign = '+';
+                     offset = array[cnt] - info[cnt].dli_saddr;
+                   }
+                 else
+                   {
+                     sign = '-';
+                     offset = info[cnt].dli_saddr - array[cnt];
+                   }
+
+                 last += 1 + sprintf (last, "%s(%s%c%#tx) [%p]",
+                                      info[cnt].dli_fname ?: "",
+                                      info[cnt].dli_sname ?: "",
+                                      sign, offset, array[cnt]);
+               }
            }
          else
            last += 1 + sprintf (last, "[%p]", array[cnt]);
index 6754d14..f0ab715 100644 (file)
@@ -1,5 +1,5 @@
 /* Write formatted list with names for addresses in backtrace to a file.
-   Copyright (C) 1998, 2000, 2003, 2005 Free Software Foundation, Inc.
+   Copyright (C) 1998,2000,2003,2005,2009 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
 
@@ -46,47 +46,63 @@ __backtrace_symbols_fd (array, size, fd)
     {
       char buf[WORD_WIDTH];
       Dl_info info;
+      struct link_map *map;
       size_t last = 0;
 
-      if (_dl_addr (array[cnt], &info, NULL, NULL)
-         && info.dli_fname && info.dli_fname[0] != '\0')
+      if (_dl_addr (array[cnt], &info, &map, NULL)
+         && info.dli_fname != NULL && info.dli_fname[0] != '\0')
        {
          /* Name of the file.  */
          iov[0].iov_base = (void *) info.dli_fname;
          iov[0].iov_len = strlen (info.dli_fname);
          last = 1;
 
-         /* Symbol name.  */
-         if (info.dli_sname != NULL)
+         if (info.dli_sname != NULL || map->l_addr != 0)
            {
              char buf2[WORD_WIDTH];
              size_t diff;
 
-             iov[1].iov_base = (void *) "(";
-             iov[1].iov_len = 1;
-             iov[2].iov_base = (void *) info.dli_sname;
-             iov[2].iov_len = strlen (info.dli_sname);
+             iov[last].iov_base = (void *) "(";
+             iov[last].iov_len = 1;
+             ++last;
+
+             if (info.dli_sname != NULL)
+               {
+                 /* We have a symbol name.  */
+                 iov[last].iov_base = (void *) info.dli_sname;
+                 iov[last].iov_len = strlen (info.dli_sname);
+                 ++last;
+               }
+             else
+               /* We have no symbol, so describe it as relative to the file.
+                  The load bias is more useful to the user than the load
+                  address.  The use of these addresses is to calculate an
+                  address in the ELF file, so its prelinked bias is not
+                  something we want to subtract out.  */
+               info.dli_saddr = (void *) map->l_addr;
 
              if (array[cnt] >= (void *) info.dli_saddr)
                {
-                 iov[3].iov_base = (void *) "+0x";
+                 iov[last].iov_base = (void *) "+0x";
                  diff = array[cnt] - info.dli_saddr;
                }
              else
                {
-                 iov[3].iov_base = (void *) "-0x";
+                 iov[last].iov_base = (void *) "-0x";
                  diff = info.dli_saddr - array[cnt];
                }
-             iov[3].iov_len = 3;
-
-             iov[4].iov_base = _itoa_word ((unsigned long int) diff,
-                                           &buf2[WORD_WIDTH], 16, 0);
-             iov[4].iov_len = &buf2[WORD_WIDTH] - (char *) iov[4].iov_base;
-
-             iov[5].iov_base = (void *) ")";
-             iov[5].iov_len = 1;
-
-             last = 6;
+             iov[last].iov_len = 3;
+             ++last;
+
+             iov[last].iov_base = _itoa_word ((unsigned long int) diff,
+                                              &buf2[WORD_WIDTH], 16, 0);
+             iov[last].iov_len = (&buf2[WORD_WIDTH]
+                                  - (char *) iov[last].iov_base);
+             ++last;
+
+             iov[last].iov_base = (void *) ")";
+             iov[last].iov_len = 1;
+             ++last;
            }
        }