#! /bin/sh -e # DP: - Enable support for symbolic tracebacks in exceptions (delete the dummy # DP: convert_addresses from adaint.c, and provide a real one separately.) dir= if [ $# -eq 3 -a "$2" = '-d' ]; then pdir="-d $3" dir="$3/" elif [ $# -ne 1 ]; then echo >&2 "`basename $0`: script expects -patch|-unpatch as argument" exit 1 fi case "$1" in -patch) patch $pdir -f --no-backup-if-mismatch -p0 < $0 ;; -unpatch) patch $pdir -f --no-backup-if-mismatch -R -p0 < $0 ;; *) echo >&2 "`basename $0`: script expects -patch|-unpatch as argument" exit 1 esac exit 0 Ported Jürgen Pfeifer's patch to enable symbolic tracebacks on Debian GNU/Linux. The binary distribution of GNAT 3.15p comes with an old version of binutils that includes a library, libaddr2line.a. This library does not exist in recent versions of binutils. The patch works around this by calling /usr/bin/addr2line (still part of binutils) and parsing the output. See debian/convert_addresses.c for the gory details. I have modified convert_addresses.c to not use a shell script anymore; Debian controls the version of binutils which is installed. Also, I use execve instead of execle. -- Ludovic Brenta. # ' make emacs highlighting happy Index: gcc/ada/Makefile.in =================================================================== --- gcc/ada/Makefile.in.orig 2008-01-13 22:19:26.000000000 +0100 +++ gcc/ada/Makefile.in 2008-01-29 11:56:42.178635045 +0100 @@ -1655,7 +1655,7 @@ a-nucoar.o a-nurear.o i-forbla.o i-forlap.o s-gearop.o GNATRTL_OBJS = $(GNATRTL_NONTASKING_OBJS) $(GNATRTL_TASKING_OBJS) \ - $(GNATRTL_LINEARALGEBRA_OBJS) g-trasym.o memtrack.o + $(GNATRTL_LINEARALGEBRA_OBJS) g-trasym.o memtrack.o convert_addresses.o # Default run time files @@ -1810,7 +1810,6 @@ for file in rts/*.ali; do \ $(INSTALL_DATA_DATE) $$file $(DESTDIR)$(ADA_RTL_OBJ_DIR); \ done - -$(INSTALL_DATA) rts/g-trasym$(objext) $(DESTDIR)$(ADA_RTL_OBJ_DIR) -cd rts; for file in *$(arext);do \ $(INSTALL_DATA) $$file $(DESTDIR)$(ADA_RTL_OBJ_DIR); \ $(RANLIB_FOR_TARGET) $(DESTDIR)$(ADA_RTL_OBJ_DIR)/$$file; \ @@ -1907,7 +1906,7 @@ $(GNATRTL_OBJS) $(RM) rts/libgnat$(arext) rts/libgnarl$(arext) $(AR_FOR_TARGET) $(AR_FLAGS) rts/libgnat$(arext) \ - $(addprefix rts/,$(GNATRTL_NONTASKING_OBJS) $(LIBGNAT_OBJS)) + $(addprefix rts/,$(GNATRTL_NONTASKING_OBJS) $(LIBGNAT_OBJS) g-trasym.o convert_addresses.o) ifneq ($(PREFIX_OBJS),) $(AR_FOR_TARGET) $(AR_FLAGS) rts/libgccprefix$(arext) \ $(PREFIX_OBJS); @@ -1940,6 +1939,7 @@ $(TARGET_LIBGCC2_CFLAGS) \ -o libgnat$(hyphen)$(LIBRARY_VERSION)$(soext) \ $(GNATRTL_NONTASKING_OBJS) $(LIBGNAT_OBJS) \ + g-trasym.o convert_addresses.o \ $(SO_OPTS)libgnat$(hyphen)$(LIBRARY_VERSION)$(soext) \ $(MISCLIB) -lm cd rts; ../../xgcc -B../../ -shared $(GNATLIBCFLAGS) \ @@ -2183,6 +2183,7 @@ sysdep.o : sysdep.c raise-gcc.o : raise-gcc.c raise.h raise.o : raise.c raise.h +convert_addresses.o : convert_addresses.c vx_stack_info.o : vx_stack_info.c gen-soccon: gen-soccon.c gsocket.h Index: gcc/ada/adaint.c =================================================================== --- gcc/ada/adaint.c.orig 2008-01-13 22:19:26.000000000 +0100 +++ gcc/ada/adaint.c 2008-01-29 11:56:06.614450462 +0100 @@ -2852,35 +2852,6 @@ } #endif -#if defined (CROSS_DIRECTORY_STRUCTURE) \ - || (! ((defined (sparc) || defined (i386)) && defined (sun) \ - && defined (__SVR4)) \ - && ! (defined (linux) && (defined (i386) || defined (__x86_64__))) \ - && ! (defined (linux) && defined (__ia64__)) \ - && ! defined (__FreeBSD__) \ - && ! defined (__hpux__) \ - && ! defined (__APPLE__) \ - && ! defined (_AIX) \ - && ! (defined (__alpha__) && defined (__osf__)) \ - && ! defined (VMS) \ - && ! defined (__MINGW32__) \ - && ! (defined (__mips) && defined (__sgi))) - -/* Dummy function to satisfy g-trasym.o. See the preprocessor conditional - just above for a list of native platforms that provide a non-dummy - version of this procedure in libaddr2line.a. */ - -void -convert_addresses (const char *file_name ATTRIBUTE_UNUSED, - void *addrs ATTRIBUTE_UNUSED, - int n_addr ATTRIBUTE_UNUSED, - void *buf ATTRIBUTE_UNUSED, - int *len ATTRIBUTE_UNUSED) -{ - *len = 0; -} -#endif - #if defined (_WIN32) int __gnat_argument_needs_quote = 1; #else Index: gcc/ada/convert_addresses.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gcc/ada/convert_addresses.c 2008-01-29 11:56:06.614450462 +0100 @@ -0,0 +1,157 @@ +/* + Copyright (C) 1999 by Juergen Pfeifer + Ada for Linux Team (ALT) + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, distribute with modifications, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name(s) of the above copyright + holders shall not be used in advertising or otherwise to promote the + sale, use or other dealings in this Software without prior written + authorization. +*/ +#include +#include +#include +#include +#include +#include + +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define MAX_LINE 1024 + +#define CLOSE1 close(fd1[0]); close(fd1[1]) +#define CLOSE2 close(fd2[0]); close(fd2[1]) +#define RESTSIG sigaction(SIGPIPE,&oact,NULL) + +void convert_addresses +( void* addrs[], + int n_addr, + char* buf, + int* len) +{ + int max_len = *len; + pid_t pid = getpid(); + pid_t child; + + struct sigaction act, oact; + + int fd1[2], fd2[2]; + char exe_name[128]; + + *buf = 0; *len = 0; + /* Thanx to the /proc filesystem we can very easily reference our own + executable image:-)*/ + snprintf(exe_name,sizeof(exe_name),"--exe=/proc/%ld/exe", (long)pid); + + act.sa_handler = SIG_IGN; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + if (sigaction(SIGPIPE,&act,&oact) < 0) + return; + + if (pipe(fd1) >= 0) { + if (pipe(fd2)>=0) { + if ((child = fork()) < 0) { + CLOSE1; CLOSE2; RESTSIG; + return; + } + else { + if (0==child) { + close(fd1[1]); + close(fd2[0]); + if (fd1[0] != STDIN_FILENO) { + if (dup2(fd1[0],STDIN_FILENO) != STDIN_FILENO) { + CLOSE1; CLOSE2; + } + close(fd1[0]); + } + if (fd2[1] != STDOUT_FILENO) { + if (dup2(fd2[1],STDOUT_FILENO) != STDOUT_FILENO) { + CLOSE1; CLOSE2; + } + close(fd2[1]); + } + { + /* As pointed out by Florian Weimer to me, it is a + security threat to call the script with a user defined + environment and using the path. That would be Trojans + pleasure. Therefore we use the absolute path to + addr2line and an empty environment. That should be + safe. + */ + char *const argv[] = { "addr2line", + exe_name, + "--demangle=gnat", + "--functions", + "--basenames", + NULL }; + char *const envp[] = { NULL }; + if (execve("/usr/bin/addr2line", argv, envp) < 0) { + CLOSE1; CLOSE2; + } + } + } + else { + int i, n; + char hex[16]; + char line[MAX_LINE + 1]; + char *p; + char *s = buf; + + /* Parent context */ + close(fd1[0]); + close(fd2[1]); + + for(i=0; i < n_addr; i++) { + snprintf(hex,sizeof(hex),"%p\n",addrs[i]); + write(fd1[1],hex,strlen(hex)); + n = read(fd2[0],line,MAX_LINE); + if (n<=0) + break; + line[n]=0; + /* We have approx. 16 additional chars for "%p in " clause. + We use this info to prevent a buffer overrun. + */ + if (n + 16 + (*len) > max_len) + break; + p = strchr(line,'\n'); + if (p) { + if (*(p+1)) { + *p = 0; + *len += snprintf(s, (max_len - (*len)), "%p in %s at %s",addrs[i], line, p+1); + } + else { + *len += snprintf(s, (max_len - (*len)), "%p at %s",addrs[i], line); + } + s = buf + (*len); + } + } + close(fd1[1]); + close(fd2[0]); + } + } + } + else { + CLOSE1; + } + } + RESTSIG; +} Index: gcc/ada/g-trasym.adb =================================================================== --- gcc/ada/g-trasym.adb.orig 2007-04-11 10:18:15.000000000 +0200 +++ gcc/ada/g-trasym.adb 2008-01-29 11:56:06.614450462 +0100 @@ -32,16 +32,16 @@ ------------------------------------------------------------------------------ -- Run-time symbolic traceback support +-- This file has been modified by Juergen Pfeifer (31-Dec-1999) for +-- the purpose to support the Ada for Linux Team implementation of +-- convert_addresses. This implementation has the advantage to run +-- on the binutils as they are deployed on Linux. with System.Soft_Links; with Ada.Exceptions.Traceback; use Ada.Exceptions.Traceback; package body GNAT.Traceback.Symbolic is - pragma Linker_Options ("-laddr2line"); - pragma Linker_Options ("-lbfd"); - pragma Linker_Options ("-liberty"); - package TSL renames System.Soft_Links; -- To perform the raw addresses to symbolic form translation we rely on a @@ -79,9 +79,13 @@ -- raw addresses provided in ADDRS, looked up in debug information from -- FILENAME. LEN is filled with the result length. -- - -- This procedure is provided by libaddr2line on targets that support - -- it. A dummy version is in adaint.c for other targets so that build - -- of shared libraries doesn't generate unresolved symbols. + -- This is the ALT Linux specific version adapted to the binutils + -- deployed with most Linuxes. These binutils already have an + -- addr2line tool that demangles Ada symbolic names, but there are + -- version dependant variants for the option names. Therefore our + -- implementation spawns a shell script that does normalization of + -- the option and then executes addr2line and communicates with it + -- through a bidirectional pipe. -- -- Note that this procedure is *not* thread-safe. @@ -93,8 +97,9 @@ (c_exename : System.Address) return System.Address; pragma Import (C, locate_exec_on_path, "__gnat_locate_exec_on_path"); - Res : String (1 .. 256 * Traceback'Length); - Len : Integer; + B_Size : constant Integer := 256 * Traceback'Length; + Len : Integer := B_Size; + Res : String (1 .. B_Size); use type System.Address;