1 /*
2 Copyright (C) 1999 by Juergen Pfeifer <juergen.pfeifer@gmx.net>
3 Ada for Linux Team (ALT)
4 Heavily modified by John Marino <http://www.dragonlace.net>
5
6 Permission is hereby granted, free of charge, to any person obtaining a
7 copy of this software and associated documentation files (the
8 "Software"), to deal in the Software without restriction, including
9 without limitation the rights to use, copy, modify, merge, publish,
10 distribute, distribute with modifications, sublicense, and/or sell
11 copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
13
14 The above copyright notice and this permission notice shall be included
15 in all copies or substantial portions of the Software.
16
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
23 THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25 Except as contained in this notice, the name(s) of the above copyright
26 holders shall not be used in advertising or otherwise to promote the
27 sale, use or other dealings in this Software without prior written
28 authorization.
29 */
30
31 #ifdef IS_CROSS
32
33
34 /*
35 * Running addr2line doesn't make sense for cross-compiled objects.
36 * Create a dummy function to satisfy g-trasym.o
37 */
38
39 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)40 convert_addresses (const char *file_name ATTRIBUTE_UNUSED,
41 void *addrs ATTRIBUTE_UNUSED,
42 int n_addr ATTRIBUTE_UNUSED,
43 void *buf ATTRIBUTE_UNUSED,
44 int *len ATTRIBUTE_UNUSED)
45 {
46 *len = 0;
47 }
48
49 #else
50
51
52 /*
53 * use the external program /usr/bin/addr2line to convert addresses
54 * into file names and line numbers
55 */
56
57 #include <sys/types.h>
58 #include <stdlib.h>
59 #include <unistd.h>
60 #include <string.h>
61 #include <signal.h>
62
63 #define CLOSE_SENDPIPE close(sendpipe[0]); close(sendpipe[1])
64 #define CLOSE_READPIPE close(readpipe[0]); close(readpipe[1])
65 #define DUP2CLOSE(oldfd, newfd) dup2(oldfd, newfd); close(oldfd);
66 #define RESTSIG sigaction(SIGPIPE,&oact,NULL)
67
68 #define MAX_LINE 1024
69 #define PARENT_READ readpipe[0]
70 #define CHILD_WRITE readpipe[1]
71 #define CHILD_READ sendpipe[0]
72 #define PARENT_WRITE sendpipe[1]
73
74 #if defined (__sun__)
75 #define ADDR2LINE_PROG "/usr/gnu/bin/addr2line"
76 #else
77 #define ADDR2LINE_PROG "/usr/bin/addr2line"
78 #endif
79
80 void
convert_addresses(const char * file_name,void * addrs,int n_addr,void * buf,int * len)81 convert_addresses (const char *file_name,
82 void *addrs,
83 int n_addr,
84 void *buf,
85 int *len)
86 {
87 int max_len = *len;
88 pid_t childpid;
89
90 struct sigaction act, oact;
91
92 int sendpipe[2] = {-1,-1}, /* parent -> child */
93 readpipe[2] = {-1,-1}; /* parent <- child */
94
95 *len = 0;
96 act.sa_handler = SIG_IGN;
97 sigemptyset(&act.sa_mask);
98 act.sa_flags = 0;
99 if (sigaction(SIGPIPE,&act,&oact) < 0)
100 return;
101
102 if (pipe(sendpipe) < 0) { RESTSIG; return; }
103 if (pipe(readpipe) < 0) { CLOSE_SENDPIPE; RESTSIG; return; }
104 if ((childpid = fork()) < 0) {
105 CLOSE_READPIPE;
106 CLOSE_SENDPIPE;
107 RESTSIG;
108 return;
109 }
110
111 if (childpid == 0) { /* child process */
112 close(PARENT_WRITE);
113 close(PARENT_READ);
114 if ((CHILD_READ != STDIN_FILENO) && (CHILD_WRITE != STDOUT_FILENO)) {
115 if ((CHILD_READ == STDOUT_FILENO) && (CHILD_WRITE == STDIN_FILENO)) {
116 const int temp_fd = dup(CHILD_WRITE);
117 close (CHILD_WRITE);
118 DUP2CLOSE (CHILD_READ, STDIN_FILENO);
119 DUP2CLOSE (temp_fd, STDOUT_FILENO);
120 }
121 else if ((CHILD_READ == STDIN_FILENO) && (CHILD_WRITE > 1)) {
122 DUP2CLOSE (CHILD_WRITE, STDOUT_FILENO);
123 }
124 else if ((CHILD_READ > 1) && (CHILD_WRITE == STDOUT_FILENO)) {
125 DUP2CLOSE (CHILD_READ, STDIN_FILENO);
126 }
127 else if ((CHILD_READ > 1) && (CHILD_WRITE == STDIN_FILENO)) {
128 DUP2CLOSE (CHILD_WRITE, STDOUT_FILENO);
129 DUP2CLOSE (CHILD_READ, STDIN_FILENO);
130 }
131 else {
132 /* CHILD_READ >= 1 and CHILD_WRITE > 1 */
133 DUP2CLOSE (CHILD_READ, STDIN_FILENO);
134 DUP2CLOSE (CHILD_WRITE, STDOUT_FILENO);
135 }
136 }
137 /* As pointed out by Florian Weimer to JP, it is a security threat to call
138 the script with a user defined environment and using the path. That
139 would be Trojans pleasure. Therefore the absolute path to addr2line
140 and an empty environment is used. That should be safe.
141 */
142 char *const argv[] = { "addr2line",
143 "-e", file_name,
144 "--demangle=gnat",
145 "--functions",
146 "--basenames",
147 NULL };
148 char *const envp[] = { NULL };
149 if (execve(ADDR2LINE_PROG, argv, envp) < 0) {
150 close (CHILD_WRITE);
151 close (CHILD_READ);
152 RESTSIG;
153 exit (1);
154 }
155 }
156
157 /* Below this line is parent process */
158 int i, n;
159 char hex[16];
160 char line[MAX_LINE + 1];
161 char *p;
162 char *s = buf;
163 long *trace_address = addrs;
164
165 close(CHILD_WRITE);
166 close(CHILD_READ);
167
168 for(i=0; i < n_addr; i++) {
169 snprintf(hex,sizeof(hex),"%#lx\n",*trace_address);
170 write(PARENT_WRITE,hex,strlen(hex));
171 n = read(PARENT_READ,line,MAX_LINE);
172 if (n<=0)
173 break;
174
175 line[n]=0;
176 /* We have approx. 16 additional chars for "%#lx in " clause.
177 We use this info to prevent a buffer overrun. */
178 if (n + 16 + (*len) > max_len)
179 break;
180
181 p = strchr(line,'\n');
182 if (p) {
183 if (*(p+1)) {
184 *p = 0;
185 *len += snprintf(s, (max_len - (*len)), "%#lx in %s at %s",
186 *trace_address, line, p+1);
187 }
188 else {
189 *len += snprintf(s, (max_len - (*len)), "%#lx at %s",
190 *trace_address, line);
191 }
192 s = buf + (*len);
193 }
194 trace_address += 1;
195 }
196 close (PARENT_WRITE);
197 close (PARENT_READ);
198 RESTSIG;
199 }
200
201 #endif
202