1 | /******************************************************************* |
---|
2 | * File: omTrack.c |
---|
3 | * Purpose: routines for getting Backtraces of stack |
---|
4 | * Author: obachman (Olaf Bachmann) |
---|
5 | * Created: 11/99 |
---|
6 | * Version: $Id: omTrack.c,v 1.2 1999-11-22 18:13:00 obachman Exp $ |
---|
7 | *******************************************************************/ |
---|
8 | #include <limits.h> |
---|
9 | |
---|
10 | #include "omConfig.h" |
---|
11 | #include "omFindExec.h" |
---|
12 | #include "omPrivate.h" |
---|
13 | |
---|
14 | #ifndef MAXPATHLEN |
---|
15 | #define MAXPATHLEN 1024 |
---|
16 | #endif |
---|
17 | |
---|
18 | /* This is for nice alignment of omPrintBackTrace */ |
---|
19 | #define OM_MAX_PROC_NAME_LENGTH 20 |
---|
20 | /* if you make this larger than 11, extend OM_GET_RETURN_ADDR and |
---|
21 | OM_GET_FRAME_ADDR */ |
---|
22 | #define OM_MAX_BT_FRAMES 11 |
---|
23 | |
---|
24 | #ifdef OM_RETURN_ADDR_RVALUE |
---|
25 | #define OM_GET_RETURN_ADDR OM_RETURN_ADDR |
---|
26 | #else |
---|
27 | #define OM_GET_RETURN_ADDR(addr, i) \ |
---|
28 | switch(i) \ |
---|
29 | { \ |
---|
30 | case 0: \ |
---|
31 | addr = OM_RETURN_ADDR(0); break; \ |
---|
32 | case 1: \ |
---|
33 | addr = OM_RETURN_ADDR(1); break; \ |
---|
34 | case 2: \ |
---|
35 | addr = OM_RETURN_ADDR(2); break; \ |
---|
36 | case 3: \ |
---|
37 | addr = OM_RETURN_ADDR(3); break; \ |
---|
38 | case 4: \ |
---|
39 | addr = OM_RETURN_ADDR(4); break; \ |
---|
40 | case 5: \ |
---|
41 | addr = OM_RETURN_ADDR(5); break; \ |
---|
42 | case 6: \ |
---|
43 | addr = OM_RETURN_ADDR(6); break; \ |
---|
44 | case 7: \ |
---|
45 | addr = OM_RETURN_ADDR(7); break; \ |
---|
46 | case 8: \ |
---|
47 | addr = OM_RETURN_ADDR(8); break; \ |
---|
48 | case 9: \ |
---|
49 | addr = OM_RETURN_ADDR(9); break; \ |
---|
50 | case 10: \ |
---|
51 | addr = OM_RETURN_ADDR(10); break; \ |
---|
52 | default: \ |
---|
53 | addr = NULL; \ |
---|
54 | } |
---|
55 | #endif /* OM_RETURN_ADDR_RVALUE */ |
---|
56 | |
---|
57 | #ifdef OM_FRAME_ADDR_RVALUE |
---|
58 | #define OM_GET_FRAME_ADDR OM_FRAME_ADDR |
---|
59 | #else |
---|
60 | #define OM_GET_FRAME_ADDR(addr, i) \ |
---|
61 | switch(i) \ |
---|
62 | { \ |
---|
63 | case 0: \ |
---|
64 | addr = OM_FRAME_ADDR(0); break; \ |
---|
65 | case 1: \ |
---|
66 | addr = OM_FRAME_ADDR(1); break; \ |
---|
67 | case 2: \ |
---|
68 | addr = OM_FRAME_ADDR(2); break; \ |
---|
69 | case 3: \ |
---|
70 | addr = OM_FRAME_ADDR(3); break; \ |
---|
71 | case 4: \ |
---|
72 | addr = OM_FRAME_ADDR(4); break; \ |
---|
73 | case 5: \ |
---|
74 | addr = OM_FRAME_ADDR(5); break; \ |
---|
75 | case 6: \ |
---|
76 | addr = OM_FRAME_ADDR(6); break; \ |
---|
77 | case 7: \ |
---|
78 | addr = OM_FRAME_ADDR(7); break; \ |
---|
79 | case 8: \ |
---|
80 | addr = OM_FRAME_ADDR(8); break; \ |
---|
81 | case 9: \ |
---|
82 | addr = OM_FRAME_ADDR(9); break; \ |
---|
83 | case 10: \ |
---|
84 | addr = OM_FRAME_ADDR(10); break; \ |
---|
85 | default: \ |
---|
86 | addr = NULL; \ |
---|
87 | } |
---|
88 | #endif /* OM_FRAME_ADDR_RVALUE */ |
---|
89 | |
---|
90 | static char* om_this_prog = NULL; |
---|
91 | static void* om_this_main_frame_addr = NULL; |
---|
92 | static void* om_this_prog_min_return_addr = ((void*) 1023); |
---|
93 | static void* om_this_prog_max_return_addr = ((void*) ULONG_MAX -1); |
---|
94 | |
---|
95 | |
---|
96 | void omInitTrack(const char* argv0) |
---|
97 | { |
---|
98 | char buf[MAXPATHLEN]; |
---|
99 | |
---|
100 | if (argv0 != NULL && omFindExec(argv0, buf)) |
---|
101 | { |
---|
102 | __omTypeAllocChunk(char*, om_this_prog, strlen(buf)); |
---|
103 | strcpy(om_this_prog, buf); |
---|
104 | } |
---|
105 | #if defined(OM_FRAME_ADDR_WORKS) |
---|
106 | om_this_main_frame_addr = OM_FRAME_ADDR(1); |
---|
107 | #endif |
---|
108 | #if defined(OM_PROG_NM) && defined(HAVE_POPEN) |
---|
109 | if (om_this_prog != NULL) |
---|
110 | { |
---|
111 | char command[MAXPATHLEN + 30]; |
---|
112 | FILE *pipe; |
---|
113 | sprintf(command, "%s -n %s", OM_PROG_NM, om_this_prog); |
---|
114 | |
---|
115 | pipe = popen(command, "r"); |
---|
116 | if (pipe != NULL) |
---|
117 | { |
---|
118 | /* serach for first address */ |
---|
119 | int c; |
---|
120 | void* nm_addr; |
---|
121 | while ( (c=fgetc(pipe)) != EOF) |
---|
122 | { |
---|
123 | if (c == '\n') |
---|
124 | { |
---|
125 | if (fscanf(pipe, "%p", &nm_addr) && |
---|
126 | (unsigned long) nm_addr > |
---|
127 | (unsigned long) om_this_prog_min_return_addr) |
---|
128 | { |
---|
129 | om_this_prog_min_return_addr = nm_addr; |
---|
130 | break; |
---|
131 | } |
---|
132 | } |
---|
133 | } |
---|
134 | om_this_prog_max_return_addr = nm_addr; |
---|
135 | while ( (c=fgetc(pipe)) != EOF) |
---|
136 | { |
---|
137 | if (c == '\n') |
---|
138 | { |
---|
139 | if (fscanf(pipe, "%p", &nm_addr) && nm_addr != NULL && |
---|
140 | (unsigned long) nm_addr > |
---|
141 | (unsigned long) om_this_prog_max_return_addr) |
---|
142 | { |
---|
143 | om_this_prog_max_return_addr = nm_addr; |
---|
144 | } |
---|
145 | } |
---|
146 | } |
---|
147 | pclose(pipe); |
---|
148 | } |
---|
149 | } |
---|
150 | #endif /* defined(OM_NM) && defined(HAVE_POPEN) */ |
---|
151 | } |
---|
152 | |
---|
153 | |
---|
154 | int omGetCurrentBackTrace(void** addr, int max_frames) |
---|
155 | { |
---|
156 | int i = 0; |
---|
157 | #if defined(OM_RETURN_ADDR_WORKS) |
---|
158 | #if defined(OM_FRAME_ADDR_WORKS) |
---|
159 | if (om_this_main_frame_addr != NULL) |
---|
160 | { |
---|
161 | void* this_frame = OM_FRAME_ADDR(0); |
---|
162 | if (this_frame == 0) return 0; |
---|
163 | else |
---|
164 | { |
---|
165 | #endif /* ! defined(OM_RETURN_ADDR_WORKS) */ |
---|
166 | void* r_addr; |
---|
167 | if (max_frames > OM_MAX_BT_FRAMES) max_frames = OM_MAX_BT_FRAMES; |
---|
168 | for (i=0; i< max_frames; i++) |
---|
169 | { |
---|
170 | OM_GET_RETURN_ADDR(r_addr, i); |
---|
171 | if (r_addr > om_this_prog_min_return_addr && |
---|
172 | r_addr < om_this_prog_max_return_addr) |
---|
173 | addr[i] = r_addr; |
---|
174 | else |
---|
175 | { |
---|
176 | addr[i] = NULL; |
---|
177 | return i; |
---|
178 | } |
---|
179 | #ifdef OM_FRAME_ADDR_WORKS |
---|
180 | OM_GET_FRAME_ADDR(r_addr, i + 1); |
---|
181 | /* check that next frame is in really between main and this_frame */ |
---|
182 | if ((r_addr >= om_this_main_frame_addr && |
---|
183 | om_this_main_frame_addr >= this_frame) || |
---|
184 | (r_addr <= om_this_main_frame_addr && |
---|
185 | om_this_main_frame_addr <= this_frame)) |
---|
186 | { |
---|
187 | if (i+1 < max_frames) addr[i+1] = NULL; |
---|
188 | return i + 1; |
---|
189 | } |
---|
190 | } |
---|
191 | } |
---|
192 | #endif /* OM_FRAME_ADDR_WORKS */ |
---|
193 | } |
---|
194 | #endif /* defined(OM_RETURN_ADDR_WORKS) */ |
---|
195 | return i; |
---|
196 | } |
---|
197 | |
---|
198 | int omPrintBackTrace(void** addr, int max_frames, FILE* fd) |
---|
199 | { |
---|
200 | int i = 0; |
---|
201 | if (max_frames > OM_MAX_BT_FRAMES) max_frames = OM_MAX_BT_FRAMES; |
---|
202 | #if defined(HAVE_POPEN) && defined(OM_PROG_ADDR2LINE) |
---|
203 | if (om_this_prog != NULL) |
---|
204 | { |
---|
205 | char command[2*MAXPATHLEN + 15 + OM_MAX_BT_FRAMES*(2*SIZEOF_VOIDP + 4)]; |
---|
206 | FILE *pipe; |
---|
207 | int l; |
---|
208 | l = sprintf(command, "%s -s -C -f -e %s", |
---|
209 | OM_PROG_ADDR2LINE, om_this_prog); |
---|
210 | |
---|
211 | while (i<max_frames && addr[i] != NULL) |
---|
212 | { |
---|
213 | l += sprintf(&command[l], " %p", addr[i]); |
---|
214 | i++; |
---|
215 | } |
---|
216 | |
---|
217 | if (i > 0) |
---|
218 | { |
---|
219 | pipe = popen(command, "r"); |
---|
220 | if (pipe != NULL) |
---|
221 | { |
---|
222 | int nl = 0; |
---|
223 | int j = 0; |
---|
224 | int k=0; |
---|
225 | while ((l=fgetc(pipe)) != EOF) |
---|
226 | { |
---|
227 | if (nl == 0) |
---|
228 | { |
---|
229 | fprintf(fd, " #%d %p in ", j, addr[j]); |
---|
230 | nl = 1; |
---|
231 | j++; |
---|
232 | k=0; |
---|
233 | } |
---|
234 | if (l == '\n') |
---|
235 | { |
---|
236 | if (nl == 1) |
---|
237 | { |
---|
238 | while (k<OM_MAX_PROC_NAME_LENGTH) |
---|
239 | { |
---|
240 | fprintf(fd, " "); |
---|
241 | k++; |
---|
242 | } |
---|
243 | fprintf(fd, " at "); |
---|
244 | nl = 2; |
---|
245 | } |
---|
246 | else |
---|
247 | { |
---|
248 | fputc('\n', fd); |
---|
249 | nl = 0; |
---|
250 | } |
---|
251 | } |
---|
252 | else |
---|
253 | { |
---|
254 | k++; |
---|
255 | fputc(l, fd); |
---|
256 | } |
---|
257 | } |
---|
258 | pclose(pipe); |
---|
259 | fflush(fd); |
---|
260 | return i; |
---|
261 | } |
---|
262 | i=0; |
---|
263 | } |
---|
264 | } |
---|
265 | #endif |
---|
266 | #if OM_RETURN_ADDR_WORKS |
---|
267 | while (i<max_frames && addr[i] != NULL) |
---|
268 | { |
---|
269 | fprintf(fd, " #%d %p in ??\n", i, addr[i]); |
---|
270 | i++; |
---|
271 | } |
---|
272 | #endif |
---|
273 | if (i == 0) |
---|
274 | { |
---|
275 | fprintf(fd, "??"); |
---|
276 | fputc('\n', fd); |
---|
277 | } |
---|
278 | fflush(fd); |
---|
279 | return i; |
---|
280 | } |
---|
281 | |
---|
282 | int omPrintCurrentBackTrace(int from_frame, int max_frames, FILE *fd) |
---|
283 | { |
---|
284 | void* addr[OM_MAX_BT_FRAMES]; |
---|
285 | int got_frames = omGetCurrentBackTrace(addr, from_frame + max_frames + 1); |
---|
286 | return omPrintBackTrace(&addr[from_frame + 1], |
---|
287 | got_frames - from_frame + 1, fd); |
---|
288 | } |
---|
289 | |
---|
290 | |
---|
291 | |
---|
292 | |
---|
293 | |
---|
294 | |
---|
295 | |
---|
296 | |
---|