added stacktrace
[nao-ulib.git] / src / stacktrace.c
blobff119376347d1b740a4e1cb7f63a9d1db975eaed
1 /*
2 * nao-ulib
3 * Copyright 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>
4 * Subject to the GPL.
5 * Nao-Team HTWK,
6 * Faculty of Computer Science, Mathematics and Natural Sciences,
7 * Leipzig University of Applied Sciences (HTWK Leipzig)
8 */
10 #define _GNU_SOURCE
11 #include <string.h>
12 #include <signal.h>
13 #include <unistd.h>
14 #include <limits.h>
15 #include <sys/types.h>
17 #define SYMNAMSIZ 512
18 #define TMPBUFSIZ 512
19 #define ADDRESSLISTSIZ 20
21 #include "comp_x86.h"
22 #include "strlcpy.h"
23 #include "die.h"
24 #include "stacktrace.h"
26 struct faddress {
27 unsigned long real_addr;
28 unsigned long closest_addr;
29 char name[SYMNAMSIZ];
30 char type;
33 static void kill_pipe(int fd, int pid)
35 close(fd);
36 kill(pid, SIGTERM);
39 static int spawn_pipe(const char *cmd, pid_t *pid)
41 int ret, pipefd[2];
43 ret = pipe(pipefd);
44 if (ret < 0)
45 return ret;
47 *pid = fork();
48 switch (*pid) {
49 case -1:
50 close(pipefd[0]);
51 close(pipefd[1]);
52 ret = -EIO;
53 break;
54 case 0:
55 close(pipefd[0]);
56 close(STDOUT_FILENO);
57 close(STDERR_FILENO);
59 dup2(pipefd[1], STDOUT_FILENO);
60 dup2(pipefd[1], STDERR_FILENO);
63 * The System() call assumes that /bin/sh is
64 * always available, and so will we.
66 execl("/bin/sh", "/bin/sh", "-c", cmd, NULL);
67 _die();
68 break;
69 default:
70 close(pipefd[1]);
71 ret = pipefd[0];
72 break;
75 return ret;
78 static int pull_from_pipe(int fd, char *buffer, int max)
80 char c;
81 int i = 0;
83 do {
84 if (read(fd, &c, 1) < 1)
85 return 0;
86 if (i < max)
87 buffer[i++] = c;
88 } while (c != '\n');
89 buffer[i] = 0;
91 return i;
94 void stacktrace(void)
96 void *p;
97 int i, fd, ret;
98 char buffer[TMPBUFSIZ], type;
99 char name[TMPBUFSIZ];
100 struct faddress syms[ADDRESSLISTSIZ + 1];
101 unsigned long addr, hi_addr, lo_addr;
102 pid_t pid = 0;
104 for (i = 0, p = &p; p; ++i) {
106 * This is based on code by Steve Coleman
107 * <steve.colemanjhuapl.edu> __builtin_return_address()
108 * only accepts a constant as argument.
110 switch (i) {
111 case 0:
112 if (__builtin_frame_address(0))
113 p = __builtin_return_address(0);
114 else p = NULL;
115 break;
116 case 1:
117 if (__builtin_frame_address(1))
118 p = __builtin_return_address(1);
119 else p = NULL;
120 break;
121 case 2:
122 if (__builtin_frame_address(2))
123 p = __builtin_return_address(2);
124 else p = NULL;
125 break;
126 case 3:
127 if (__builtin_frame_address(3))
128 p = __builtin_return_address(3);
129 else p = NULL;
130 break;
131 case 4:
132 if (__builtin_frame_address(4))
133 p = __builtin_return_address(4);
134 else p = NULL;
135 break;
136 case 5:
137 if (__builtin_frame_address(5))
138 p = __builtin_return_address(5);
139 else p = NULL;
140 break;
141 case 6:
142 if (__builtin_frame_address(6))
143 p = __builtin_return_address(6);
144 else p = NULL;
145 break;
146 case 7:
147 if (__builtin_frame_address(7))
148 p = __builtin_return_address(7);
149 else p = NULL;
150 break;
151 case 8:
152 if (__builtin_frame_address(8))
153 p = __builtin_return_address(8);
154 else p = NULL;
155 break;
156 case 9:
157 if (__builtin_frame_address(9))
158 p = __builtin_return_address(9);
159 else p = NULL;
160 break;
161 case 10:
162 if (__builtin_frame_address(10))
163 p = __builtin_return_address(10);
164 else p = NULL;
165 break;
166 case 11:
167 if (__builtin_frame_address(11))
168 p = __builtin_return_address(11);
169 else p = NULL;
170 break;
171 case 12:
172 if (__builtin_frame_address(12))
173 p = __builtin_return_address(12);
174 else p = NULL;
175 break;
176 case 13:
177 if (__builtin_frame_address(13))
178 p = __builtin_return_address(13);
179 else p = NULL;
180 break;
181 case 14:
182 if (__builtin_frame_address(14))
183 p = __builtin_return_address(14);
184 else p = NULL;
185 break;
186 case 15:
187 if (__builtin_frame_address(15))
188 p = __builtin_return_address(15);
189 else p = NULL;
190 break;
191 case 16:
192 if (__builtin_frame_address(16))
193 p = __builtin_return_address(16);
194 else p = NULL;
195 break;
196 case 17:
197 if (__builtin_frame_address(17))
198 p = __builtin_return_address(17);
199 else p = NULL;
200 break;
201 case 18:
202 if (__builtin_frame_address(18))
203 p = __builtin_return_address(18);
204 else p = NULL;
205 break;
206 case 19:
207 if (__builtin_frame_address(19))
208 p = __builtin_return_address(19);
209 else p = NULL;
210 break;
211 default:
212 p = NULL;
213 break;
216 if (p && i < ADDRESSLISTSIZ) {
217 syms[i].real_addr = (unsigned long) p;
218 syms[i].closest_addr = 0;
219 syms[i].name[0] = 0;
220 syms[i].type = ' ';
221 } else {
222 syms[i].real_addr = 0;
223 break;
227 strcpy(buffer, "nm -B ");
228 strcat(buffer, TARGETNAME);
230 lo_addr = ULONG_MAX;
231 hi_addr = 0;
233 fd = spawn_pipe(buffer, &pid);
234 if (fd < 0)
235 panic("Cannot spawn pipe to shell!\n");
237 while (pull_from_pipe(fd, buffer, sizeof(buffer))) {
238 if (buffer[0] == '\n')
239 continue;
240 ret = sscanf(buffer, "%lx %c %s", &addr, &type, name);
241 if (ret != 3)
242 continue;
243 if (type != 't' && type != 'T')
244 continue;
245 if (addr == 0)
246 continue;
247 if (addr < lo_addr)
248 lo_addr = addr;
249 if (addr > hi_addr)
250 hi_addr = addr;
251 for (i = 0; syms[i].real_addr != 0; ++i) {
252 if (addr <= syms[i].real_addr &&
253 addr > syms[i].closest_addr) {
254 syms[i].closest_addr = addr;
255 strlcpy(syms[i].name, name, SYMNAMSIZ);
256 syms[i].type = type;
261 kill_pipe(fd, pid);
263 for (i = 0; syms[i].real_addr != 0; ++i) {
264 if (syms[i].name[0] == 0 ||
265 syms[i].real_addr <= lo_addr ||
266 syms[i].real_addr >= hi_addr)
267 sprintf(buffer, "[%d] 0x%08lx ???\n",
268 i, syms[i].real_addr);
269 else
270 sprintf(buffer, "[%d] 0x%08lx <%s+0x%lx> %c\n",
271 i, syms[i].real_addr, syms[i].name,
272 syms[i].real_addr - syms[i].closest_addr,
273 syms[i].type);
274 info(buffer);