From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 9586 invoked by alias); 20 Aug 2009 22:42:27 -0000 Received: (qmail 9566 invoked by uid 22791); 20 Aug 2009 22:42:26 -0000 X-SWARE-Spam-Status: No, hits=-1.6 required=5.0 tests=AWL,BAYES_00,J_CHICKENPOX_32,SPF_HELO_PASS,SPF_PASS X-Spam-Check-By: sourceware.org Received: from mx1-old.redhat.com (HELO mx1.redhat.com) (66.187.233.31) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 20 Aug 2009 22:42:17 +0000 Received: from int-mx1.corp.redhat.com (int-mx1.corp.redhat.com [172.16.52.254]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id n7KMgERo002305 for ; Thu, 20 Aug 2009 18:42:14 -0400 Received: from gateway.sf.frob.com (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx1.corp.redhat.com (8.13.1/8.13.1) with ESMTP id n7KMgDSB018711; Thu, 20 Aug 2009 18:42:13 -0400 Received: from magilla.sf.frob.com (magilla.sf.frob.com [198.49.250.228]) by gateway.sf.frob.com (Postfix) with ESMTP id 437D2357B; Thu, 20 Aug 2009 15:42:12 -0700 (PDT) Received: by magilla.sf.frob.com (Postfix, from userid 5281) id 139EF4730F; Thu, 20 Aug 2009 15:42:12 -0700 (PDT) From: Roland McGrath To: Ulrich Drepper Cc: GNU libc hacker Subject: [patch] Improve backtrace_symbols{,_fd} output when missing symbols. Message-Id: <20090820224212.139EF4730F@magilla.sf.frob.com> Date: Thu, 20 Aug 2009 22:42:00 -0000 Mailing-List: contact libc-hacker-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-hacker-owner@sourceware.org X-SW-Source: 2009-08/txt/msg00000.txt.bz2 Users complain about the backtrace_symbols{,_fd} dumps being less helpful than they might be in cases where no symbol is found. I know the memory map dumped for the libc-internal crash cases gives enough info to calculate it all if you try. But it's a hassle, and not in backtrace_symbols{,_fd} for other users anyway. This changes them to print "FILE(+OFFSET)[ADDRESS]" when there is no symbol matched. Here OFFSET is ADDRESS-l_addr (and still omitted when l_addr==0), which is what people are looking for to pass to addr2line -e foo.so et al. (I didn't use dli_fbase i.e. l_map_start because that is far less helpful when the library is prelinked but loaded elsewhere.) This is on the temporary branch roland/backtrace-syms (464dc02). Ok to merge? Thanks, Roland 2009-08-20 Roland McGrath * 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. diff --git a/sysdeps/generic/elf/backtracesyms.c b/sysdeps/generic/elf/backtracesyms.c index b31be6a..319b207 100644 --- a/sysdeps/generic/elf/backtracesyms.c +++ b/sysdeps/generic/elf/backtracesyms.c @@ -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 , 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 - "() [+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 + "(+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]); diff --git a/sysdeps/generic/elf/backtracesymsfd.c b/sysdeps/generic/elf/backtracesymsfd.c index 6754d14..f0ab715 100644 --- a/sysdeps/generic/elf/backtracesymsfd.c +++ b/sysdeps/generic/elf/backtracesymsfd.c @@ -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 , 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; } }