1
# DP: - Enable support for symbolic tracebacks in exceptions (delete the dummy
2
# DP: convert_addresses from adaint.c, and provide a real one separately.)
4
Ported Jürgen Pfeifer's patch to enable symbolic tracebacks on Debian
7
The binary distribution of GNAT 3.15p comes with an old version of
8
binutils that includes a library, libaddr2line.a. This library does
9
not exist in recent versions of binutils. The patch works around this
10
by calling /usr/bin/addr2line (still part of binutils) and parsing the
11
output. See debian/convert_addresses.c for the gory details.
13
I have modified convert_addresses.c to not use a shell script anymore;
14
Debian controls the version of binutils which is installed. Also, I
15
use execve instead of execle.
20
# ' make emacs highlighting happy
22
Index: b/src/gcc/ada/gcc-interface/Makefile.in
23
===================================================================
24
--- a/src/gcc/ada/gcc-interface/Makefile.in
25
+++ b/src/gcc/ada/gcc-interface/Makefile.in
27
# Both . and srcdir are used, in that order,
28
# so that tm.h and config.h will be found in the compilation
29
# subdirectory rather than in the source directory.
30
-INCLUDES = -I- -I. -I.. -I$(srcdir)/ada -I$(srcdir) -I$(srcdir)/../include $(GMPINC)
31
+INCLUDES = -iquote . -iquote .. -iquote $(srcdir)/ada -iquote$(srcdir) \
32
+ -iquote $(srcdir)/../include $(GMPINC)
34
ADA_INCLUDES = -I- -I. -I$(srcdir)/ada
37
# library. LIBGNAT_OBJS is the list of object files for libgnat.
38
# thread.c is special as put into GNATRTL_TASKING_OBJS by Makefile.rtl
39
LIBGNAT_OBJS = adadecode.o adaint.o argv.o aux-io.o \
40
- cal.o cio.o cstreams.o ctrl_c.o \
41
+ cal.o cio.o convert_addresses.o cstreams.o ctrl_c.o \
42
env.o errno.o exit.o expect.o final.o \
43
init.o initialize.o locales.o mkdir.o \
44
raise.o seh_init.o socket.o sysdep.o \
46
socket.o : socket.c gsocket.h
48
raise.o : raise.c raise.h
49
+convert_addresses.o : convert_addresses.c
50
sigtramp-ppcvxw.o : sigtramp-ppcvxw.c sigtramp.h
51
terminals.o : terminals.c
52
vx_stack_info.o : vx_stack_info.c
53
Index: b/src/gcc/ada/adaint.c
54
===================================================================
55
--- a/src/gcc/ada/adaint.c
56
+++ b/src/gcc/ada/adaint.c
57
@@ -3508,35 +3508,6 @@
61
-#if defined (IS_CROSS) \
62
- || (! ((defined (sparc) || defined (i386)) && defined (sun) \
63
- && defined (__SVR4)) \
64
- && ! (defined (linux) && (defined (i386) || defined (__x86_64__))) \
65
- && ! (defined (linux) && defined (__ia64__)) \
66
- && ! (defined (linux) && defined (powerpc)) \
67
- && ! defined (__FreeBSD__) \
68
- && ! defined (__Lynx__) \
69
- && ! defined (__hpux__) \
70
- && ! defined (__APPLE__) \
71
- && ! defined (_AIX) \
72
- && ! defined (VMS) \
73
- && ! defined (__MINGW32__))
75
-/* Dummy function to satisfy g-trasym.o. See the preprocessor conditional
76
- just above for a list of native platforms that provide a non-dummy
77
- version of this procedure in libaddr2line.a. */
80
-convert_addresses (const char *file_name ATTRIBUTE_UNUSED,
81
- void *addrs ATTRIBUTE_UNUSED,
82
- int n_addr ATTRIBUTE_UNUSED,
83
- void *buf ATTRIBUTE_UNUSED,
84
- int *len ATTRIBUTE_UNUSED)
91
int __gnat_argument_needs_quote = 1;
93
Index: b/src/gcc/ada/convert_addresses.c
94
===================================================================
96
+++ b/src/gcc/ada/convert_addresses.c
99
+ Copyright (C) 1999 by Juergen Pfeifer <juergen.pfeifer@gmx.net>
100
+ Ada for Linux Team (ALT)
102
+ Permission is hereby granted, free of charge, to any person obtaining a
103
+ copy of this software and associated documentation files (the
104
+ "Software"), to deal in the Software without restriction, including
105
+ without limitation the rights to use, copy, modify, merge, publish,
106
+ distribute, distribute with modifications, sublicense, and/or sell
107
+ copies of the Software, and to permit persons to whom the Software is
108
+ furnished to do so, subject to the following conditions:
110
+ The above copyright notice and this permission notice shall be included
111
+ in all copies or substantial portions of the Software.
113
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
114
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
115
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
116
+ IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
117
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
118
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
119
+ THE USE OR OTHER DEALINGS IN THE SOFTWARE.
121
+ Except as contained in this notice, the name(s) of the above copyright
122
+ holders shall not be used in advertising or otherwise to promote the
123
+ sale, use or other dealings in this Software without prior written
126
+#include <sys/types.h>
133
+#define STDIN_FILENO 0
134
+#define STDOUT_FILENO 1
135
+#define MAX_LINE 1024
137
+#define CLOSE1 close(fd1[0]); close(fd1[1])
138
+#define CLOSE2 close(fd2[0]); close(fd2[1])
139
+#define RESTSIG sigaction(SIGPIPE,&oact,NULL)
141
+void convert_addresses
142
+(const char *file_name,
148
+ int max_len = *len;
149
+ pid_t pid = getpid();
152
+ struct sigaction act, oact;
154
+ int fd1[2], fd2[2];
156
+ *buf = 0; *len = 0;
157
+ act.sa_handler = SIG_IGN;
158
+ sigemptyset(&act.sa_mask);
160
+ if (sigaction(SIGPIPE,&act,&oact) < 0)
163
+ if (pipe(fd1) >= 0) {
164
+ if (pipe(fd2)>=0) {
165
+ if ((child = fork()) < 0) {
166
+ CLOSE1; CLOSE2; RESTSIG;
173
+ if (fd1[0] != STDIN_FILENO) {
174
+ if (dup2(fd1[0],STDIN_FILENO) != STDIN_FILENO) {
179
+ if (fd2[1] != STDOUT_FILENO) {
180
+ if (dup2(fd2[1],STDOUT_FILENO) != STDOUT_FILENO) {
186
+ /* As pointed out by Florian Weimer to me, it is a
187
+ security threat to call the script with a user defined
188
+ environment and using the path. That would be Trojans
189
+ pleasure. Therefore we use the absolute path to
190
+ addr2line and an empty environment. That should be
193
+ char *const argv[] = { "addr2line",
200
+ char *const envp[] = { NULL };
201
+ if (execve("/usr/bin/addr2line", argv, envp) < 0) {
209
+ char line[MAX_LINE + 1];
213
+ /* Parent context */
217
+ for(i=0; i < n_addr; i++) {
218
+ snprintf(hex,sizeof(hex),"%p\n",addrs[i]);
219
+ write(fd1[1],hex,strlen(hex));
220
+ n = read(fd2[0],line,MAX_LINE);
224
+ /* We have approx. 16 additional chars for "%p in " clause.
225
+ We use this info to prevent a buffer overrun.
227
+ if (n + 16 + (*len) > max_len)
229
+ p = strchr(line,'\n');
233
+ *len += snprintf(s, (max_len - (*len)), "%p in %s at %s",addrs[i], line, p+1);
236
+ *len += snprintf(s, (max_len - (*len)), "%p at %s",addrs[i], line);
252
Index: b/src/gcc/ada/g-trasym.adb
253
===================================================================
254
--- a/src/gcc/ada/g-trasym.adb
255
+++ b/src/gcc/ada/g-trasym.adb
257
-- is not supported. It returns tracebacks as lists of LF separated strings of
258
-- the form "0x..." corresponding to the addresses.
260
+with System.Soft_Links;
261
with Ada.Exceptions.Traceback; use Ada.Exceptions.Traceback;
262
-with System.Address_Image;
264
package body GNAT.Traceback.Symbolic is
266
+ package TSL renames System.Soft_Links;
268
+ -- To perform the raw addresses to symbolic form translation we rely on a
269
+ -- libaddr2line symbolizer which examines debug info from a provided
270
+ -- executable file name, and an absolute path is needed to ensure the file
271
+ -- is always found. This is "__gnat_locate_exec_on_path (gnat_argv [0])"
272
+ -- for our executable file, a fairly heavy operation so we cache the
275
+ Exename : System.Address;
276
+ -- Pointer to the name of the executable file to be used on all
277
+ -- invocations of the libaddr2line symbolization service.
279
+ Exename_Resolved : Boolean := False;
280
+ -- Flag to indicate whether we have performed the executable file name
281
+ -- resolution already. Relying on a not null Exename for this purpose
282
+ -- would be potentially inefficient as this is what we will get if the
283
+ -- resolution attempt fails.
285
------------------------
286
-- Symbolic_Traceback --
287
------------------------
289
function Symbolic_Traceback (Traceback : Tracebacks_Array) return String is
291
+ procedure convert_addresses
292
+ (filename : System.Address;
293
+ addrs : System.Address;
295
+ buf : System.Address;
296
+ len : System.Address);
297
+ pragma Import (C, convert_addresses, "convert_addresses");
298
+ -- This is the procedure version of the Ada-aware addr2line. It places
299
+ -- in BUF a string representing the symbolic translation of the N_ADDRS
300
+ -- raw addresses provided in ADDRS, looked up in debug information from
301
+ -- FILENAME. LEN points to an integer which contains the size of the
302
+ -- BUF buffer at input and the result length at output.
304
+ -- Note that this procedure is *not* thread-safe.
306
+ type Argv_Array is array (0 .. 0) of System.Address;
307
+ gnat_argv : access Argv_Array;
308
+ pragma Import (C, gnat_argv, "gnat_argv");
310
+ function locate_exec_on_path
311
+ (c_exename : System.Address) return System.Address;
312
+ pragma Import (C, locate_exec_on_path, "__gnat_locate_exec_on_path");
314
+ B_Size : constant Integer := 256 * Traceback'Length;
315
+ Len : Integer := B_Size;
316
+ Res : String (1 .. B_Size);
318
+ use type System.Address;
321
+ -- The symbolic translation of an empty set of addresses is an empty
324
if Traceback'Length = 0 then
330
- Img : String := System.Address_Image (Traceback (Traceback'First));
331
+ -- If our input set of raw addresses is not empty, resort to the
332
+ -- libaddr2line service to symbolize it all.
334
- Result : String (1 .. (Img'Length + 3) * Traceback'Length);
335
- Last : Natural := 0;
336
+ -- Compute, cache and provide the absolute path to our executable file
337
+ -- name as the binary file where the relevant debug information is to be
338
+ -- found. If the executable file name resolution fails, we have no
339
+ -- sensible basis to invoke the symbolizer at all.
341
+ -- Protect all this against concurrent accesses explicitly, as the
342
+ -- underlying services are potentially thread unsafe.
346
+ if not Exename_Resolved then
347
+ Exename := locate_exec_on_path (gnat_argv (0));
348
+ Exename_Resolved := True;
351
+ if Exename /= System.Null_Address then
354
+ (Exename, Traceback'Address, Traceback'Length,
355
+ Res (1)'Address, Len'Address);
358
+ TSL.Unlock_Task.all;
361
- for J in Traceback'Range loop
362
- Img := System.Address_Image (Traceback (J));
363
- Result (Last + 1 .. Last + 2) := "0x";
365
- Result (Last + 1 .. Last + Img'Length) := Img;
366
- Last := Last + Img'Length + 1;
367
- Result (Last) := ASCII.LF;
369
+ -- Return what the addr2line symbolizer has produced if we have called
370
+ -- it (the executable name resolution succeeded), or an empty string
373
- return Result (1 .. Last);
375
+ if Exename /= System.Null_Address then
376
+ return Res (1 .. Len);
381
end Symbolic_Traceback;
383
function Symbolic_Traceback (E : Exception_Occurrence) return String is
384
Index: b/src/gcc/ada/tracebak.c
385
===================================================================
386
--- a/src/gcc/ada/tracebak.c
387
+++ b/src/gcc/ada/tracebak.c
389
/* Starting with GCC 4.6, -fomit-frame-pointer is turned on by default for
390
32-bit x86/Linux as well and DWARF 2 unwind tables are emitted instead.
391
See the x86-64 case below for the drawbacks with this approach. */
392
-#if defined (linux) && (__GNUC__ * 10 + __GNUC_MINOR__ > 45)
393
+#if (defined (linux) || defined(__GNU__)) && (__GNUC__ * 10 + __GNUC_MINOR__ > 45)
394
#define USE_GCC_UNWINDER
396
#define USE_GENERIC_UNWINDER