1 /* akbox.c - Application Black (K) Box Decoder
2 * Copyright (c) 2006,2012 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.
3 * This is confidential unpublished proprietary source code of the author.
4 * NO WARRANTY, not even implied warranties. Contains trade secrets.
5 * Distribution prohibited unless authorized in writing. See file COPYING.
6 * Special grant: akbox.h may be used with zxid open source project under
7 * same licensing terms as zxid itself.
8 * $Id$
9 *
10 * Application Black Box provides a lock-less logging facility
11 * using a circular memory buffer per thread. These buffers will
12 * hold recent history of application and will be part of any core
13 * dump that may happen, facilitating interpretation of such core.
14 * This is a simple log analysis program for figuring out such cores.
15 * There may exist other more full-fledged tools for this task.
16 *
17 * Bad compile:
18 * export PATH=/apps/gcc/3.3.3/bin:/apps/binutils/2.14.90.0.4.1/bin:$PATH
19 * gcc -g -O -Wall -fmessage-length=0 -Wno-unused-label -Wno-unknown-pragmas -fno-strict-aliasing -D_REENTRANT -o akbox akbox.c -lpthread -lcrypto -lbfd -liberty
20 *
21 * Good compile:
22 * export PATH=/apps/gcc/3.3.3/bin:/usr/bin:$PATH
23 * gcc -g -O -Wall -fmessage-length=0 -Wno-unused-label -Wno-unknown-pragmas -fno-strict-aliasing -D_REENTRANT -o akbox akbox.c akboxlog.c -lpthread -lcrypto -lbfd
24 *
25 * Unfortunately there are several different versions of bfd.h and presumably
26 * the library. They are not compatible. One tell tale sign in _raw_size vs. rawsize.
27 *
28 * TO DO
29 * - use bfd to implement live snooping
30 * - use symbolic thread indications in brief mode
31 * - compute how much of each buffer was consumed (if not wrapped around)
32 *
33 * See also: objdump -afph core2
34 * See also: ak-lock.pl -w 1000 <ak.out
35 */
36
37 #include "platform.h"
38 #include "errmac.h"
39 #include "akbox.h"
40
41 #include <errno.h>
42 #include <sys/types.h>
43 #include <string.h>
44 #include <stdarg.h>
45 #include <sys/time.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <sys/stat.h>
49 #include <fcntl.h>
50 #include <unistd.h>
51 #include <limits.h>
52 #include <time.h>
53 //#include <sys/ptrace.h> /* see also /proc/pid , Not needed*/
54 #include <bfd.h> /* -lbfd */
55
56 #define AKBOX_RELEASE REL " - akbox -"
57
58 /* Called by: add_password, main x18 */
usage(char * err)59 void usage(char* err) {
60 fputs(err, stderr);
61 fputs(
62 "Application Blak Box Decoder, Rel " AKBOX_RELEASE "\n"
63 "Copyright (c) 2006,2012 Sampo Kellomaki (sampo@iki.fi), All Rights Reserved.\n"
64 "NO WARRANTY. Not even implied warranty of any kind.\n"
65 "Send well researched bug reports to sampo@zxid.org\n"
66 "$Id$\n\n"
67 "Usage: akbox [options] bin.exe core # analyze a core wrt binary\n"
68 " akbox [options] -p pid # attach to live process and analyze it\n"
69 " akbox [options] -f pid # attach to process, follow continuously\n"
70 " akbox [options] -r funcno [n] # resolve function number to name and file\n"
71 " akbox [options] -e errno # Show errno as string\n"
72 " akbox [options] -x bin.exe # extract function names from binary\n"
73 " akbox [options] -y core >exe # extract an executable from core\n"
74 " akbox [options] -z p sigma >v.gz # Extract checksum and version info\n"
75 " akbox [options] -t # Show table of known function numbers.\n"
76 " akbox [options] -T # Show table of known targets.\n"
77 " -s nn Use swimlane view to visualize activity in each thread where\n"
78 " each thread column is nn characters wide.\n"
79 " -2 Use 2 swimlanes: 1st is main thread and 2nd is all worker threads.\n"
80 " -c nn Use swimlane view to visualize activity of each\n"
81 " connection. Each lane is nn characters wide and two sublanes are\n"
82 " used for main thread and all other threads. Lane width is nn.\n"
83 " -b Brief. Omit time stamps and other info.\n"
84 " -m msec Fuzz factor in millisec for simultaneous events in lane views.\n"
85 " -n nn Only mmap nn first bytes of core (used for analyzing huge cores).\n"
86 " -g file Produce GraphViz output (see \n"
87 " http://www.research.att.com/sw/tools/graphviz/download.html)\n"
88 "\n"
89 "The default view is a simple time ordered listing of all activity with\n"
90 "one event per line, irrespective of line width.\n"
91 "You can further analyze the log with ak-lock.pl -w 1000 <ak.out\n"
92 , stderr);
93 exit(1);
94 }
95
96 /* Called by: ak_gviz, anal_live x3, extract_a_sym x2, extract_exe, extract_syms, open_obj x6 */
die(char * why)97 void die(char* why) {
98 perror(why); exit(2);
99 }
100 /* Called by: extract_a_sym x2, locate_buffers x2, resolve */
die2(char * why)101 void die2(char* why) {
102 fprintf(stderr, "%s\n", why); exit(3);
103 }
104 /* Called by: locate_buffers, main x2 */
warning(char * why)105 void warning(char* why) {
106 fprintf(stderr, "%s\n", why);
107 }
108
109 void akbox_gviz(char* file);
110
111 pthread_mutexattr_t MUTEXATTR_DECL;
112 unsigned long max_size = ULONG_MAX; /* max size of mmap, e.g. core file */
113 int adhoc = 1;
114 int leak_free = 0;
115 int assert_nonfatal = 0;
116 int lane_width = 80;
117 int fuzz_usec = 0;
118 int brief = 0;
119 char* format = "full";
120 char* gviz = 0; /* File where graphviz output should be dumped */
121 int swimlane = 0;
122 int siz, n_thr; /* size of mmap'd core image, number of buffers */
123 unsigned char* base; /* base of mmap'd core image */
124 unsigned char* ebase = 0; /* base of mmap'd executable binary image */
125 int esiz = 0;
126
127 struct ak_master_rec* mr;
128 struct ak_buf* b[AK_MAX_BUFS];
129 struct ak_ts* pp[AK_MAX_BUFS]; /* original "point" */
130 struct ak_ts* p[AK_MAX_BUFS]; /* working point */
131 struct ak_ts* lim[AK_MAX_BUFS]; /* end of buffer */
132 struct ak_ts* start[AK_MAX_BUFS]; /* start of buffer */
133 int seen[AK_MAX_BUFS]; /* Used to determine when HOSTART has happened. */
134
135 char* file[65536]; /* Function number to file mapping */
136 char* func[65536]; /* Function number to function name mapping */
137 extern const_str sev[];
138
139 bfd* ebfd = 0; /* Binary File Descriptor for the executable binary, if any. */
140 bfd* cbfd = 0; /* Binary File Descriptor for the core, if any. */
141 /* Called by: anal_live, extract_a_sym x3, extract_syms x3, open_obj x2 */
die_bfd(char * why)142 void die_bfd(char* why) {
143 bfd_perror(why);
144 exit(4);
145 }
146
147 #define BFD_DEBUG(x)
148 #define BFD_DEBUG_ON(x) x
149
150 /* Called by: */
zx_memmem(CU8 * haystack,int haystacklen,CU8 * needle,int needlelen)151 CU8* zx_memmem(CU8* haystack, int haystacklen, CU8* needle, int needlelen)
152 {
153 CU8* p = haystack;
154 CU8* lim = haystack + haystacklen - needlelen + 1;
155
156 while ((p < lim) && (p = memchr(p, needle[0], lim-p))) {
157 if (!memcmp(p, needle, needlelen)) return p;
158 ++p;
159 }
160 return 0;
161 }
162
163
164 /* Look up an address in BFD aware way from core or executable sections. */
165 /* Called by: amap x2 */
map_in_bfd(bfd * abfd,char * x)166 static char* map_in_bfd(bfd* abfd, char* x)
167 {
168 bfd_size_type siz;
169 char* cont;
170 char* vma;
171 char* vma_lim;
172 asection* s;
173 for (s = abfd->sections; s; s = s->next) {
174 vma = (char*)bfd_get_section_vma(abfd, s);
175 siz = bfd_section_size(abfd, s);
176 vma_lim = (char*)( bfd_get_section_vma(abfd, s) + siz );
177 if (x >= vma && x < vma_lim) {
178 BFD_DEBUG(fprintf(stderr, "addr %p [%p..%p] in %s section %s\n", x, (char*)s->vma, (char*)s->vma + s->rawsize, what, bfd_get_section_name(abfd, s)));
179 if (!(s->flags & SEC_HAS_CONTENTS))
180 continue;
181 cont = x - (int)s->vma + (int)s->contents;
182 BFD_DEBUG(fprintf(stderr, "map_in_bfd(%s, %p) returns %p (s->contents=%p, s->vma=%p s->filepos=%d)\n", what, x, cont, s->contents, (char*)s->vma, (int)s->filepos));
183 return cont;
184 }
185 }
186 return 0;
187 }
188
189 /* Called by: extract_exe, locate_buffers x7, print_trace */
amap(char * x)190 static char* amap(char* x)
191 {
192 char* y;
193 if (!x) return "(null)";
194 /* *** do endianness check and adjust as needed */
195 y = map_in_bfd(cbfd, x);
196 if (y) {
197 if (y >= (char*)base + siz)
198 return "(core-truncated)";
199 return y;
200 }
201 if (ebase) {
202 y = map_in_bfd(ebfd, x);
203 if (y) {
204 if (y >= (char*)ebase + esiz)
205 return "(exec-truncated)";
206 return y;
207 }
208 }
209 fprintf(stderr, "addr %p not found in any section\n", x);
210 return "(not-found)";
211 }
212
213 #define LK_FMT "%s"
214 #define lkmap(lk) amap(lk)
215
216 #if 0
217
218 /* Called by: print_io x4 */
219 static char* proto_map(int proto, char* proto_buf)
220 {
221 switch (proto) {
222 case SG_PROTO_LDAP: return "LDAP";
223 case SG_PROTO_LDAPS: return "LDAPS";
224 case SG_PROTO_HTTP: return "HTTP";
225 case SG_PROTO_HTTP11: return "HTTP11";
226 case SG_PROTO_HTTPS: return "HTTPS";
227 case SG_PROTO_HTTP11S: return "HTTP11S";
228 case SG_PROTO_MM1: return "MM1";
229 case SG_PROTO_SNMP: return "SNMP";
230 case SG_PROTO_RADIUS: return "RADIUS";
231 case SG_PROTO_SIP_TCP: return "SIP_TCP";
232 case SG_PROTO_SIPS: return "SIPS";
233 case SG_PROTO_SIP_UDP: return "SIP_UDP";
234 case SG_PROTO_UHAP_UDP: return "UHAP_UDP";
235 case SG_PROTO_UHAP: return "UHAP";
236 case SG_PROTO_UHAPS: return "UHAPS";
237 case SG_PROTO_RAWTCP_STREAM: return "RAWTCPSTREAM";
238 case SG_PROTO_RAWTCP_STREAMS: return "RAWTCPSTREAMS";
239 case SG_PROTO_RAWTCP: return "RAWTCP";
240 case SG_PROTO_RAWSSL: return "RAWSSL";
241 case SG_PROTO_LINETCP: return "LINETCP";
242 case SG_PROTO_LINESSL: return "LINESSL";
243 case SG_PROTO_RAWUDP: return "RAWUDP";
244 default:
245 sprintf(proto_buf, "proto%d", proto);
246 return proto_buf;
247 }
248 }
249
250 /* Called by: print_io x6 */
251 static char* flags_map(unsigned char flags, char* flags_buf){
252 if (flags & IO_CLOSED) flags_buf[0] = 'C'; else flags_buf[0] = '-';
253 if (flags & IO_HTTP_EOF) flags_buf[1] = 'H'; else flags_buf[1] = '-';
254 if (flags & IO_ENQUEUED) flags_buf[2] = 'Q'; else flags_buf[2] = '-';
255 if (flags & IO_INUSE) flags_buf[3] = 'U'; else flags_buf[3] = '-';
256 if (flags & IO_CLOSING) flags_buf[4] = 'I'; else flags_buf[4] = '-';
257 if (flags & IO_MISSING) flags_buf[5] = 'M'; else flags_buf[5] = '-';
258 if (flags & IO_MISSPOLL) flags_buf[6] = 'S'; else flags_buf[6] = '-';
259 flags_buf[7] = '\0';
260 return flags_buf;
261 }
262
263 /* Called by: print_line */
264 static void print_io(int i, char* raz)
265 {
266 char proto_buf[16];
267 char flags_buf[8];
268 struct ak_io* io = ((struct ak_io*)(p[i]));
269 switch (io->role) {
270 case IO_ROLE_FE: /* 0 */
271 printf("%s(%x.%p)\t%s_FE (%s) req_head(%p) req_tail(%p) (%.28s) [" LK_FMT "]\n", raz,
272 io->fd, io->io, proto_map(io->proto, proto_buf), flags_map(io->flags, flags_buf), io->req_head, io->req_tail,
273 io->msg, lkmap(p[i]->h.logkey));
274 break;
275 case IO_ROLE_BE: /* 1 */
276 printf("%s(%x.%p)\t%s_BE (%s) (%.28s) [" LK_FMT "]\n", raz,
277 io->fd, io->io, proto_map(io->proto, proto_buf), flags_map(io->flags, flags_buf), io->msg, lkmap(p[i]->h.logkey));
278 break;
279 case IO_ROLE_LISTENER: /* 2 */
280 printf("%s(%x.%p)\t%s_LISTENER (%s) (%.28s) [" LK_FMT "]\n", raz,
281 io->fd, io->io, proto_map(io->proto, proto_buf), flags_map(io->flags, flags_buf), io->msg, lkmap(p[i]->h.logkey));
282 break;
283 case IO_ROLE_UDP_LISTENER: /* 3 */
284 printf("%s(%x.%p)\t%s_UDP_LISTENER (%s) (%.28s) [" LK_FMT "]\n", raz,
285 io->fd, io->io, proto_map(io->proto, proto_buf), flags_map(io->flags, flags_buf), io->msg, lkmap(p[i]->h.logkey));
286 break;
287 case IO_ROLE_HOPELESS: /* 5 */
288 printf("%s(%x.%p)\tHOPELESS_BE (%s) (%.28s) [" LK_FMT "]\n", raz,
289 io->fd, io->io, flags_map(io->flags, flags_buf), io->msg, lkmap(p[i]->h.logkey));
290 break;
291 case IO_ROLE_SUPERVISOR: /* 4 */
292 default:
293 printf("%s(%x.%p)\trole=%d proto=%d (%s) req_head(%p) req_tail(%p) (%.28s) [" LK_FMT "]\n", raz,
294 io->fd, io->io, io->role, io->proto, flags_map(io->flags, flags_buf), io->req_head, io->req_tail,
295 io->msg, lkmap(p[i]->h.logkey));
296 }
297 }
298
299 /* Called by: print_line */
300 static void print_mem(int i, char* raz)
301 {
302 struct ak_mem* r = ((struct ak_mem*)(p[i]));
303 printf("%s(%p)\tlen=%d pool=%p p_b=%d (%.32s) [" LK_FMT "]\n", raz,
304 r->mem, r->len, r->pool, r->pool_blocks, r->msg, lkmap(p[i]->h.logkey));
305 }
306
307 /* Called by: decode_pdu_flags x4 */
308 static char* map_inthr(int x) {
309 switch (x & 0x7) {
310 case 0: return "0"; /* not in thread */
311 case 1: return "T"; /* inthread any prio */
312 case 2: return "I"; /* inthread */
313 case 3: return "A"; /* aborted */
314 case 4: return "W"; /* in write */
315 case 5: return "R"; /* run (actively running) */
316 case 6: return "S"; /* suspended */
317 case 7: return "E"; /* enqueued */
318 default: return "?";
319 }
320 }
321
322 /* Called by: print_pdu x4, print_pdu2 x4, print_pdu_arg x4, print_pdu_lite, print_run */
323 static char* decode_pdu_flags(char* buf, int flags)
324 {
325 #define FL(bit,name) (flags & bit ? name : "-")
326 switch (flags & 0x30) {
327 case 0x00: sprintf(buf, "REQ(%s,%s,%s,%s)", FL(0x08,"all_seen"), FL(0x80,"D"),
328 FL(0x40,"synth_done"), map_inthr(flags)); break;
329 case 0x10: sprintf(buf, "RESP(%s,%s,%s,%s)", FL(0x08,"all_seen"), FL(0x80,"D"),
330 FL(0x40,"synth_done"), map_inthr(flags)); break;
331 case 0x20: sprintf(buf, "SUBREQ(%s,%s,%s,%s)", FL(0x08,"all_seen"), FL(0x80,"D"),
332 FL(0x40,"synth_done"), map_inthr(flags)); break;
333 case 0x30: sprintf(buf, "SUBRESP(%s,%s,%s,%s)", FL(0x08,"all_seen"), FL(0x80,"D"),
334 FL(0x40,"synth_done"), map_inthr(flags)); break;
335 }
336 return buf;
337 }
338
339 /* Called by: print_line */
340 static void print_run(int i, char* raz)
341 {
342 char buf[128];
343 struct ak_run* r = ((struct ak_run*)(p[i]));
344 if (r->run) {
345 if (r->ph.pdu)
346 printf("%s(%x:%p)\t%s\tmid=%d run=%p (%.32s) [" LK_FMT "]\n", raz,
347 r->ph.pdu_op, r->ph.pdu, decode_pdu_flags(buf, r->ph.pdu_flags),
348 r->ph.pdu_mid, r->run, r->msg, lkmap(p[i]->h.logkey));
349 else
350 printf("%s nopdu run=%p (%.32s) [" LK_FMT "]\n", raz,
351 r->run, r->msg, lkmap(p[i]->h.logkey));
352 }
353 else
354 printf("%s norun (%.32s) [" LK_FMT "]\n", raz,
355 r->msg, lkmap(p[i]->h.logkey));
356 }
357
358 /* Called by: print_line */
359 static void print_pdu_lite(int i, char* raz)
360 {
361 char buf[128];
362 struct ak_pdu_lite* pdu = ((struct ak_pdu_lite*)(p[i]));
363 printf("%s(%x:%p)\t%s\tmid=%d (%.36s) [" LK_FMT "]\n", raz,
364 pdu->ph.pdu_op, pdu->ph.pdu, decode_pdu_flags(buf, pdu->ph.pdu_flags),
365 pdu->ph.pdu_mid, pdu->msg, lkmap(p[i]->h.logkey));
366 }
367
368 /* Called by: print_line */
369 static void print_pdu(int i, char* raz)
370 {
371 char buf[128];
372 struct ak_pdu* pdu = ((struct ak_pdu*)(p[i]));
373 if (pdu->pduparent) {
374 if (pdu->pdureq) {
375 printf("%s(%x:%p)\t%s\tmid=%d fe(%p) req(%p) parent(%p) nx(%p) pr(%p) wnx(%p) deps=%d (%.4s) [" LK_FMT "]\n", raz,
376 pdu->ph.pdu_op, pdu->ph.pdu, decode_pdu_flags(buf, pdu->ph.pdu_flags),
377 pdu->ph.pdu_mid, pdu->pdufe, pdu->pdureq, pdu->pduparent, pdu->pdunext,
378 pdu->pduprev, pdu->writenext, pdu->pdu_deps,
379 pdu->msg, lkmap(p[i]->h.logkey));
380
381 } else {
382 printf("%s(%x:%p)\t%s\tmid=%d fe(%p) parent(%p) nx(%p) pr(%p) wnx(%p) deps=%d (%.4s) [" LK_FMT "]\n", raz,
383 pdu->ph.pdu_op, pdu->ph.pdu, decode_pdu_flags(buf, pdu->ph.pdu_flags),
384 pdu->ph.pdu_mid, pdu->pdufe, pdu->pduparent, pdu->pdunext,
385 pdu->pduprev, pdu->writenext, pdu->pdu_deps,
386 pdu->msg, lkmap(p[i]->h.logkey));
387 }
388 } else {
389 if (pdu->pdureq) {
390 printf("%s(%x:%p)\t%s\tmid=%d fe(%p) req(%p) nx(%p) pr(%p) wnx(%p) deps=%d (%.4s) [" LK_FMT "]\n", raz,
391 pdu->ph.pdu_op, pdu->ph.pdu, decode_pdu_flags(buf, pdu->ph.pdu_flags),
392 pdu->ph.pdu_mid, pdu->pdufe, pdu->pdureq, pdu->pdunext,
393 pdu->pduprev, pdu->writenext, pdu->pdu_deps,
394 pdu->msg, lkmap(p[i]->h.logkey));
395 } else {
396 printf("%s(%x:%p)\t%s\tmid=%d fe(%p) nx(%p) pr(%p) wnx(%p) deps=%d (%.4s) [" LK_FMT "]\n", raz,
397 pdu->ph.pdu_op, pdu->ph.pdu, decode_pdu_flags(buf, pdu->ph.pdu_flags),
398 pdu->ph.pdu_mid, pdu->pdufe, pdu->pdunext,
399 pdu->pduprev, pdu->writenext, pdu->pdu_deps,
400 pdu->msg, lkmap(p[i]->h.logkey));
401 }
402 }
403 }
404
405 /* Called by: print_line */
406 static void print_pdu_arg(int i, char* raz)
407 {
408 char buf[128];
409 struct ak_pdu_arg* pdu = ((struct ak_pdu_arg*)(p[i]));
410 if (pdu->pduparent) {
411 if (pdu->pdureq) {
412 printf("%s(%x:%p)\t%s\tmid=%d fe(%p) req(%p) parent(%p) nx(%p) pr(%p) wnx(%p) deps=%d (0x%x) [" LK_FMT "]\n", raz,
413 pdu->ph.pdu_op, pdu->ph.pdu, decode_pdu_flags(buf, pdu->ph.pdu_flags),
414 pdu->ph.pdu_mid, pdu->pdufe, pdu->pdureq, pdu->pduparent, pdu->pdunext,
415 pdu->pduprev, pdu->writenext, pdu->pdu_deps,
416 pdu->arg, lkmap(p[i]->h.logkey));
417 } else {
418 printf("%s(%x:%p)\t%s\tmid=%d fe(%p) parent(%p) nx(%p) pr(%p) wnx(%p) deps=%d (0x%x) [" LK_FMT "]\n", raz,
419 pdu->ph.pdu_op, pdu->ph.pdu, decode_pdu_flags(buf, pdu->ph.pdu_flags),
420 pdu->ph.pdu_mid, pdu->pdufe, pdu->pduparent, pdu->pdunext,
421 pdu->pduprev, pdu->writenext, pdu->pdu_deps,
422 pdu->arg, lkmap(p[i]->h.logkey));
423 }
424 } else {
425 if (pdu->pdureq) {
426 printf("%s(%x:%p)\t%s\tmid=%d fe(%p) req(%p) nx(%p) pr(%p) wnx(%p) deps=%d (0x%x) [" LK_FMT "]\n", raz,
427 pdu->ph.pdu_op, pdu->ph.pdu, decode_pdu_flags(buf, pdu->ph.pdu_flags),
428 pdu->ph.pdu_mid, pdu->pdufe, pdu->pdureq, pdu->pdunext,
429 pdu->pduprev, pdu->writenext, pdu->pdu_deps,
430 pdu->arg, lkmap(p[i]->h.logkey));
431 } else {
432 printf("%s(%x:%p)\t%s\tmid=%d fe(%p) nx(%p) pr(%p) wnx(%p) deps=%d (0x%x) [" LK_FMT "]\n", raz,
433 pdu->ph.pdu_op, pdu->ph.pdu, decode_pdu_flags(buf, pdu->ph.pdu_flags),
434 pdu->ph.pdu_mid, pdu->pdufe, pdu->pdunext,
435 pdu->pduprev, pdu->writenext, pdu->pdu_deps,
436 pdu->arg, lkmap(p[i]->h.logkey));
437 }
438 }
439 }
440
441 /* Called by: print_line */
442 static void print_pdu2(int i, char* raz)
443 {
444 char buf[128];
445 struct ak_pdu* pdu = ((struct ak_pdu*)(p[i]));
446 if (pdu->pduparent) {
447 if (pdu->pdureq) {
448 printf("%s(%x:%p)\t%s\tmid=%d fe(%p) req(%p) parent(%p) nx(%p) pr(%p) wnx(%p) deps=%d (%.4s) [%p]\n", raz,
449 pdu->ph.pdu_op, pdu->ph.pdu, decode_pdu_flags(buf, pdu->ph.pdu_flags),
450 pdu->ph.pdu_mid, pdu->pdufe, pdu->pdureq, pdu->pduparent, pdu->pdunext,
451 pdu->pduprev, pdu->writenext, pdu->pdu_deps,
452 pdu->msg, p[i]->h.logkey); /* msg is func called, logkey is really nargs */
453 } else {
454 printf("%s(%x:%p)\t%s\tmid=%d fe(%p) parent(%p) nx(%p) pr(%p) wnx(%p) deps=%d (%.4s) [%p]\n", raz,
455 pdu->ph.pdu_op, pdu->ph.pdu, decode_pdu_flags(buf, pdu->ph.pdu_flags),
456 pdu->ph.pdu_mid, pdu->pdufe, pdu->pduparent, pdu->pdunext,
457 pdu->pduprev, pdu->writenext, pdu->pdu_deps,
458 pdu->msg, p[i]->h.logkey); /* msg is func called, logkey is really nargs */
459 }
460 } else {
461 if (pdu->pdureq) {
462 printf("%s(%x:%p)\t%s\tmid=%d fe(%p) req(%p) nx(%p) pr(%p) wnx(%p) deps=%d (%.4s) [%p]\n", raz,
463 pdu->ph.pdu_op, pdu->ph.pdu, decode_pdu_flags(buf, pdu->ph.pdu_flags),
464 pdu->ph.pdu_mid, pdu->pdufe, pdu->pdureq, pdu->pdunext,
465 pdu->pduprev, pdu->writenext, pdu->pdu_deps,
466 pdu->msg, p[i]->h.logkey); /* msg is func called, logkey is really nargs */
467 } else {
468 printf("%s(%x:%p)\t%s\tmid=%d fe(%p) nx(%p) pr(%p) wnx(%p) deps=%d (%.4s) [%p]\n", raz,
469 pdu->ph.pdu_op, pdu->ph.pdu, decode_pdu_flags(buf, pdu->ph.pdu_flags),
470 pdu->ph.pdu_mid, pdu->pdufe, pdu->pdunext,
471 pdu->pduprev, pdu->writenext, pdu->pdu_deps,
472 pdu->msg, p[i]->h.logkey); /* msg is func called, logkey is really nargs */
473 }
474 }
475 }
476 #endif
477
478
479 /* Called by: print_line */
print_report(int i,char * raz)480 static void print_report(int i, char* raz)
481 {
482 struct ak_report* r = ((struct ak_report*)(p[i]));
483 printf("%s " LK_FMT "\tblock_size=%d, blks from pool: %d/%d; from malloc: %d/%d %d bytes (%.16s)\n", raz, lkmap(p[i]->h.logkey), r->block_size, r->blocks_out, r->n_blocks, r->malloc_cnt_bal, r->malloc_cnt, r->malloc_vol_bal, r->msg);
484 }
485
486 /* Called by: print_line */
print_ini(int i,char * raz)487 static void print_ini(int i, char* raz)
488 {
489 struct ak_ini* inc = ((struct ak_ini*)(p[i]));
490 printf("%s F:%s S:%d Bytes M:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x [%s]\n", raz, inc->msg, inc->size, inc->md5val[0], inc->md5val[1], inc->md5val[2], inc->md5val[3], inc->md5val[4], inc->md5val[5], inc->md5val[6], inc->md5val[7], inc->md5val[8], inc->md5val[9], inc->md5val[10], inc->md5val[11], inc->md5val[12], inc->md5val[13], inc->md5val[14], inc->md5val[15], lkmap(p[i]->h.logkey));
491 }
492
493 /* Called by: print_line x2 */
print_ts(int i,char * raz)494 static void print_ts(int i, char* raz)
495 {
496 printf(raz, p[i]->msg, lkmap(p[i]->h.logkey));
497 }
498
499 /* Called by: print_line */
print_tsa(int i,char * raz)500 static void print_tsa(int i, char* raz)
501 {
502 struct ak_tsa* r = ((struct ak_tsa*)(p[i]));
503 printf(raz, r->msg, r->arg, lkmap(p[i]->h.logkey));
504 }
505
506 /* Called by: print_line x6 */
print_trace(int i,char * raz)507 static void print_trace(int i, char* raz)
508 {
509 struct _binid* cur_func;
510 struct ak_disasm* di = ((struct ak_disasm*)(p[i]));
511 cur_func = (struct _binid*)amap((char*)di->cur_func);
512 printf("%s(%s)\n", raz, lkmap((char *)cur_func->key));
513 }
514
515 #ifdef SUNOS
516
517 struct split_ll{
518 union{
519 struct{
520 unsigned long high;
521 unsigned long low;
522 };
523 unsigned long long full;
524 };
525 };
526
527 /* Called by: get_low */
am_big_endian()528 int am_big_endian()
529 {
530 long one= 1;
531 return !(*((char *)(&one)));
532 }
533
534 /* Called by: get_nano, get_secs */
get_low(unsigned long long num)535 unsigned long get_low (unsigned long long num){
536 struct split_ll ll;
537 ll.full = num;
538 if (am_big_endian())
539 return ll.low;
540 else
541 return ll.high;
542 }
543
544 /* Called by: print_line x2 */
get_secs(ak_time act_tick)545 int get_secs (ak_time act_tick){
546 unsigned long a;
547 a = get_low ((act_tick - mr->first_tick)/1000000000.0);
548 return (int)(a);
549 }
550
551 /* Called by: print_line x2 */
get_nano(ak_time act_tick)552 unsigned long get_nano (ak_time act_tick){
553 ak_time rest;
554 rest = ((act_tick - mr->first_tick)%1000000000);
555 return get_low(rest);
556 }
557 #endif
558
559 #ifdef MINGW
560 /* Called by: print_line x2 */
get_secs(ak_time act_tick)561 int get_secs (ak_time act_tick){
562 return (int)((act_tick.QuadPart - mr->first_tick.QuadPart)/mr->ticksPerSecond.QuadPart);
563 }
564
565 /* Called by: print_line x2 */
get_nano(ak_time act_tick)566 unsigned long get_nano (ak_time act_tick){
567 ak_time rest;
568 double ticksPerNano;
569 ticksPerNano = (mr->ticksPerSecond.QuadPart/1000000000.0);
570 rest.QuadPart = ((act_tick.QuadPart - mr->first_tick.QuadPart)%mr->ticksPerSecond.QuadPart);
571 rest.QuadPart = (rest.QuadPart/ticksPerNano);
572 return (unsigned long)rest.LowPart;
573 }
574 #endif
575
576 /* You need to teach this function about every possible message type. When (if) swimlanes
577 * are implemented, this function probably needs to be aware of them. */
578
579 /* Called by: print_buffers x3 */
print_line(int i)580 static void print_line(int i)
581 {
582 int seve;
583 struct tm t;
584
585 #ifdef MINGW
586 unsigned int secs = mr->first_sec + get_secs(p[i]->h.tv);
587 GMTIME(secs, t);
588 printf("%c%-2d %04d%02d%02d %02d%02d%02d.%09lu %15s:%-4d %20s():\t",
589 b[i]->comment[0], i-1, t.tm_year+1900, t.tm_mon+1, t.tm_mday,
590 t.tm_hour, t.tm_min, t.tm_sec, get_nano (p[i]->h.tv),
591 file[p[i]->h.func], p[i]->h.line, func[p[i]->h.func]);
592 #endif
593 #ifdef SUNOS
594 unsigned int secs = mr->first_sec + get_secs(p[i]->h.tv);
595 GMTIME(secs, t);
596 printf("%c%-2d %04d%02d%02d %02d%02d%02d.%09lu %15s:%-4d %20s():\t",
597 b[i]->comment[0], i-1, t.tm_year+1900, t.tm_mon+1, t.tm_mday,
598 t.tm_hour, t.tm_min, t.tm_sec, get_nano (p[i]->h.tv),
599 file[p[i]->h.func], p[i]->h.line, func[p[i]->h.func]);
600 #endif
601 #if (!defined(SUNOS)&&!defined(MINGW))
602 if (brief) {
603 printf("%c%-2d %03ld.%06ld %10.10s:%-3d ", b[i]->comment[0], i-1,
604 p[i]->h.tv.tv_sec % 1000, p[i]->h.tv.tv_usec,
605 func[p[i]->h.func], p[i]->h.line);
606 } else {
607 GMTIME(p[i]->h.tv.tv_sec, t);
608 printf("%c%-2d %04d%02d%02d %02d%02d%02d.%06ld %15s:%-4d %20s():\t",
609 b[i]->comment[0], i-1, t.tm_year+1900, t.tm_mon+1, t.tm_mday,
610 t.tm_hour, t.tm_min, t.tm_sec, p[i]->h.tv.tv_usec,
611 file[p[i]->h.func], p[i]->h.line, func[p[i]->h.func]);
612 }
613 #endif
614
615 switch (p[i]->raz) {
616
617 #define AK_RAZ_INI(sym,code,desc) case AK_ ## sym ## _RAZ: print_ini(i, #sym ); break;
618 #define AK_RAZ_TS(sym,code,desc) case AK_ ## sym ## _RAZ: print_ts(i, #sym " (%s) [" LK_FMT "]\n"); break;
619 #define AK_RAZ_TS2(sym,code,desc) case AK_ ## sym ## _RAZ: print_ts(i, #sym " (%s) [%p]\n"); break;
620 #define AK_RAZ_TSA(sym,code,desc) case AK_ ## sym ## _RAZ: print_tsa(i, #sym " (%s) arg=%p [" LK_FMT "]\n"); break;
621 #define AK_RAZ_MEM(sym,code,desc) case AK_ ## sym ## _RAZ: print_mem(i, #sym); break;
622 #define AK_RAZ_RUN(sym,code,desc) case AK_ ## sym ## _RAZ: print_run(i, #sym); break;
623 #define AK_RAZ_PDU(sym,code,desc) case AK_ ## sym ## _RAZ: print_pdu(i, #sym); break;
624 #define AK_RAZ_PDU2(sym,code,desc) case AK_ ## sym ## _RAZ: print_pdu2(i, #sym); break;
625 #define AK_RAZ_LITE(sym,code,desc) case AK_ ## sym ## _RAZ: print_pdu_lite(i, #sym); break;
626 #define AK_RAZ_ARG(sym,code,desc) case AK_ ## sym ## _RAZ: print_pdu_arg(i, #sym); break;
627 #define AK_RAZ_IO(sym,code,desc) case AK_ ## sym ## _RAZ: print_io(i, #sym); break;
628 #define AK_RAZ_REPORT(sym,code,desc) case AK_ ## sym ## _RAZ: print_report(i, #sym); break;
629 #define AK_RAZ_SPEC(sym,code,desc)
630
631 #include "aktab.h"
632
633 case AK_ERR_RAZ:
634 seve = ((struct ak_err*)p[i])->severity;
635 printf("ERR %s %s %d (%s) [" LK_FMT "]\n",
636 map_error(((struct ak_err*)p[i])->error_code),
637 (seve>=0) && (seve < 8) ? sev[seve] : "***UNKWN_SEV",
638 ((struct ak_err*)p[i])->action,
639 ((struct ak_err*)p[i])->msg, lkmap(p[i]->h.logkey)); break;
640 case AK_ASSERT_RAZ: /* ASSERT or CHK macro, logkey is condition */
641 printf("ASSERT(" LK_FMT ") [%s]\n", lkmap(p[i]->h.logkey), p[i]->msg); break;
642 case AK_ASSERTOP_RAZ: /* ASSERTOP macro, logkey is value a, msg is condition */
643 printf("ASSERTOP(" LK_FMT ") [%s]\n", lkmap(p[i]->h.logkey), p[i]->msg); break;
644 case AK_FAIL_RAZ: /* FAIL macro logkey: val (e.g. failed magic), msg: why */
645 printf("FAIL(%s) [%p]\n", p[i]->msg, p[i]->h.logkey); break;
646 case AK_FAILS_RAZ: /* FAIL_PDU macro logkey: str (e.g. function name), msg: why */
647 printf("FAIL(%s) [" LK_FMT "]\n", p[i]->msg, lkmap(p[i]->h.logkey)); break;
648 case AK_TRACE_VMENTRY_RAZ: print_trace(i, "VMENTRY"); break;
649 case AK_TRACE_CALL_RAZ: print_trace(i, "CALL"); break;
650 case AK_TRACE_RET_RAZ: print_trace(i, "RET"); break;
651 case AK_TRACE_NATCALL_RAZ: print_trace(i, "NATCALL"); break;
652 case AK_TRACE_NATRET_RAZ: print_trace(i, "NATRET"); break;
653 case AK_TRACE_RAZ: print_trace(i, "TRACE"); break;
654
655 default:
656 printf("unknown_reason %x [" LK_FMT "]\n", p[i]->raz, lkmap(p[i]->h.logkey));
657 }
658 ++(p[i]); /* Advance to next line */
659 /*printf("adv. to next p=%p pp=%p lim=%p\n", p[i], pp[i], lim[i]);*/
660 }
661
662 #ifdef MINGW
663 /* Called by: anal_core, anal_live */
print_buffers()664 static void print_buffers()
665 {
666 unsigned long long old_tv;
667 int oldest,i,j, wrapped_seen = 0;
668 printf("COLDSTART\n");
669 while (1) {
670 /* Find oldest (that has not run around buffer yet) */
671 oldest = -1; /* none */
672 old_tv = ULLONG_MAX;
673 for (i = 0; i <= n_thr; ++i) /* Number of threads + 1 static */
674 if ((p[i] != pp[i]) && /* must not have wrapped around back to the point */
675 (p[i]->h.tv.QuadPart < old_tv)) {
676 oldest = i;
677 old_tv = p[i]->h.tv.QuadPart;
678 }
679 if (oldest == -1) break; /* nothing more to print */
680
681 i = oldest;
682 while ((p[i] != pp[i]) && /* must not have wrapped around back to the point */
683 (p[i]->h.tv.QuadPart <= old_tv)) {
684 if (!seen[i]) {
685 seen[i] = 1;
686 for (j = 0; j < n_thr; ++j)
687 if (!seen[j])
688 break;
689 if (!wrapped_seen && b[i]->wrap_around) {
690 printf("FIRSTWRAP\n");
691 wrapped_seen = 1;
692 }
693 if (j == n_thr)
694 printf("ALLSEEN\n");
695 }
696 print_line(i);
697 if (p[i] >= lim[i])
698 p[i] = start[i];
699 }
700 }
701 }
702 #endif
703 #ifdef SUNOS
704 /* Called by: anal_core, anal_live */
print_buffers()705 static void print_buffers()
706 {
707 unsigned long long old_tv;
708 int oldest,i,j, wrapped_seen = 0;
709 printf("COLDSTART\n");
710 while (1) {
711 /* Find oldest (that has not run around buffer yet) */
712 oldest = -1; /* none */
713 old_tv = ULLONG_MAX;
714 for (i = 0; i <= n_thr; ++i) /* Number of threads + 1 static */
715 if ((p[i] != pp[i]) && /* must not have wrapped around back to the point */
716 (p[i]->h.tv < old_tv)) {
717 oldest = i;
718 old_tv = p[i]->h.tv;
719 }
720 if (oldest == -1) break; /* nothing more to print */
721
722 i = oldest;
723 while ((p[i] != pp[i]) && /* must not have wrapped around back to the point */
724 (p[i]->h.tv <= old_tv)) {
725 if (!seen[i]) {
726 seen[i] = 1;
727 for (j = 0; j < n_thr; ++j)
728 if (!seen[j])
729 break;
730 if (!wrapped_seen && b[i]->wrap_around) {
731 printf("FIRSTWRAP\n");
732 wrapped_seen = 1;
733 }
734 if (j == n_thr)
735 printf("ALLSEEN\n");
736 }
737 print_line(i);
738 if (p[i] >= lim[i])
739 p[i] = start[i];
740 }
741 }
742 }
743 #endif
744 #if (!defined(SUNOS)&&!defined(MINGW))
745 /* Called by: anal_core, anal_live */
print_buffers()746 static void print_buffers()
747 {
748 /*unsigned long long end_slice_usec;*/
749 struct timeval old_tv;
750 int oldest,i,j, wrapped_seen = 0;
751
752 printf("COLDSTART\n");
753
754 while (1) {
755 /* Find oldest (that has not run around buffer yet) */
756 oldest = -1; /* none */
757 old_tv.tv_sec = LONG_MAX;
758 old_tv.tv_usec = LONG_MAX;
759 for (i = 0; i <= n_thr; ++i) /* Number of threads + 1 static */
760 if ((p[i] != pp[i]) && /* must not have wrapped around back to the point */
761 ((p[i]->h.tv.tv_sec < old_tv.tv_sec)
762 || ((p[i]->h.tv.tv_sec == old_tv.tv_sec)
763 && (p[i]->h.tv.tv_usec < old_tv.tv_usec)))) {
764 oldest = i;
765 old_tv = p[i]->h.tv;
766 }
767 if (oldest == -1) break; /* nothing more to print */
768
769 /* Print as many lines from selected buffer as fuzz_usec permits. Note: handing 64
770 * bit ints on 32 bit arcitecture proves to be tricky and gdb, for example, apparently
771 * gets it wrong, thus we do the comparisons by parts here. */
772 /*end_slice_usec = old_tv.tv_sec * 1000000L + old_tv.tv_usec + fuzz_usec;*/
773 old_tv.tv_usec += fuzz_usec;
774 if (old_tv.tv_usec > 1000000) {
775 old_tv.tv_sec += old_tv.tv_usec / 1000000;
776 old_tv.tv_usec += old_tv.tv_usec % 1000000;
777 }
778 i = oldest;
779 while ((p[i] != pp[i])
780 /*&& ((p[i]->h.tv.tv_sec * 1000000L + p[i]->h.tv.tv_usec) <= end_slice_usec)*/
781 && ((p[i]->h.tv.tv_sec < old_tv.tv_sec)
782 || ((p[i]->h.tv.tv_sec == old_tv.tv_sec)
783 && (p[i]->h.tv.tv_usec <= old_tv.tv_usec)))
784 )
785 {
786 if (!seen[i]) {
787 seen[i] = 1;
788 for (j = 0; j < n_thr; ++j)
789 if (!seen[j])
790 break;
791 if (!wrapped_seen && b[i]->wrap_around) {
792 printf("FIRSTWRAP\n");
793 wrapped_seen = 1;
794 }
795 if (j == n_thr)
796 printf("ALLSEEN\n");
797 }
798 print_line(i);
799 if (p[i] >= lim[i])
800 p[i] = start[i];
801 }
802 }
803 }
804 #endif
805
806 /* Called by: anal_core, anal_live, extract_exe */
locate_buffers(FILE * file)807 static void locate_buffers(FILE* file)
808 {
809 int i;
810 char* lkmark;
811 char stamp[16];
812
813 /* Find master block */
814
815 mr = (struct ak_master_rec*)base;
816 while (mr) {
817 mr = (struct ak_master_rec*)zx_memmem((U8*)mr, siz - ((unsigned char*)mr - base),
818 (U8*)AK_MASTER_STAMP, sizeof(AK_MASTER_STAMP));
819 if (!mr) die2("AK master magic stamp (" AK_MASTER_STAMP ") not found in core.");
820 if (mr->endian_mark == AK_ENDIAN_MARK) break;
821 ++mr;
822 }
823
824 if (ebase) {
825 lkmark = (char*)zx_memmem(ebase, esiz, (U8*)AK_LOGKEY_MARK, sizeof(AK_LOGKEY_MARK));
826 /* It seems that windows exe does not have the lkmark, but dll has, take a look at this */
827 #if !defined(MINGW)
828 if (!lkmark) die2("AK log key mark (" AK_LOGKEY_MARK ") not found in executable.");
829 #endif
830 }
831 if (n_thr > AK_MAX_BUFS) warning("n_threads exceeds limit");
832
833 fprintf(file, "Summary\n");
834 fprintf(file, " bin date: %s %s\n", mr->date, mr->time);
835 fprintf(file, " n_threads: %d\n", n_thr);
836
837 #if !defined(INTERIXOS)
838 #if !defined(MINGW)
839 fprintf(file, " Proc Number: %d\n", mr->ProcNum);
840 fprintf(file, " Host Id: %x\n", (unsigned int)mr->HostId);
841 fprintf(file, " Sys Name: %s\n", mr->sysname);
842 fprintf(file, " Node Name: %s\n", mr->nodename);
843 fprintf(file, " OS Release: %s\n", mr->os_release);
844 fprintf(file, " OS Version: %s\n", mr->os_version);
845 fprintf(file, " Machine: %s\n", mr->machine);
846 #else /** MINGW **/
847 fprintf(file, " Proc Number: %d\n", mr->ProcNum);
848 fprintf(file, " Sys Name: %s\n", mr->sysname);
849 fprintf(file, " OS Version: %s\n", mr->os_version);
850 #endif
851 #endif
852 fprintf(file, " core command line: %s\n", bfd_core_file_failing_command(cbfd));
853 if (ebase) {
854 fprintf(file, " core signal : %d\n", bfd_core_file_failing_signal(cbfd));
855 if (!core_file_matches_executable_p(cbfd, ebfd)) {
856 fprintf(stderr, "WARNING: core does not match executable. logkey information may be unreliable.\n");
857 fprintf(file, "WARNING: core does not match executable. logkey information may be unreliable.\n");
858 }
859 fprintf(file, " bin arch : %s\n", bfd_printable_name(ebfd));
860 }
861 fprintf(file, " core arch : %s\n", bfd_printable_name(cbfd));
862 fprintf(file, " exe realpath : %s\n", mr->realpath);
863
864 fprintf(file, "END_PREAMBLE\n");
865
866 /** This ASSERT causes some problems in AIX **/
867 #if !defined(AIXOS)
868 ASSERTOP(((char*)(mr)),==,amap((char*)(mr->self)),mr);
869 #endif
870 n_thr = mr->n_threads;
871 fprintf(file, "Master record found\n");
872 fprintf(file, " endian_mark: 0x%x\n", mr->endian_mark);
873 fprintf(file, " mr address: %p\n", mr);
874
875 #if !defined(INTERIXOS)
876 fprintf(file, "Machine info\n");
877
878 #if !defined(MINGW)
879 #ifdef AIXOS
880 fprintf(file, " Proc Arch: %d\n", mr->ProcArch);
881 fprintf(file, " Proc Imp: %d\n", mr->ProcImp);
882 fprintf(file, " Proc Ver: %d\n", mr->ProcVer);
883 fprintf(file, " Width(bits): %d\n", mr->Width);
884 fprintf(file, " Max Memory: %ld\n", mr->MaxMem);
885 #else
886 fprintf(file, " Model Name: %s\n", mr->ModelName); /* Not completed for AIX*/
887 #endif
888 # if defined(LINUX) /** For the moment only works for LINUX **/
889 fprintf(file, " Max Memory: %ld\n", mr->MaxMem);
890 fprintf(file, " Max Swap: %ld\n", mr->MaxSwap);
891 fprintf(file, " Mem Unit: %ld\n", mr->MemUnit);
892 # endif
893 #else /** MINGW **/
894 fprintf(file, " Proc Arch: %d\n", mr->ProcArch);
895 fprintf(file, " Proc Type: %d\n", mr->ProcType);
896 fprintf(file, " Proc Level: %d\n", mr->ProcLevel);
897 fprintf(file, " Proc Revision: %d\n", mr->ProcRev);
898 #endif
899 #endif
900
901 fprintf(file, "Stat info\n");
902 fprintf(file, " exe size : %d\n", (int)mr->binary_st.st_size);
903 fprintf(file, " exe mode : %o\n", (unsigned int)mr->binary_st.st_mode);
904 fprintf(file, " exe uid : %d\n", (int)mr->binary_st.st_uid);
905 fprintf(file, " exe gid : %d\n", (int)mr->binary_st.st_gid);
906 fprintf(file, " exe nlink : %d\n", (int)mr->binary_st.st_nlink);
907 fprintf(file, " exe access time : %d\n", (int)mr->binary_st.st_atime);
908 fprintf(file, " exe modify time : %d\n", (int)mr->binary_st.st_mtime);
909 fprintf(file, " exe status time : %d\n", (int)mr->binary_st.st_ctime);
910 fprintf(file, " exe dev : %d\n", (int)mr->binary_st.st_dev);
911 fprintf(file, " exe inode : %d\n", (int)mr->binary_st.st_ino);
912
913 /* Locate other blocks */
914
915 fprintf(file, "BUFSPEC\n");
916
917 /* First static buffer */
918 b[0] = (struct ak_buf*)amap((char*)(mr->st_buf));
919 sprintf(stamp, AK_ST_BUFFER_STAMP);
920 if (strcmp(stamp, b[0]->stamp))
921 fprintf(stderr, "WARNING: st_buf has bad stamp (%s) mapped=%p\n", b[0]->stamp, b[0]);
922 pp[0] = (struct ak_ts*)amap((char*)(b[0]->p));
923 lim[0] = (struct ak_ts*)amap((char*)(b[0]->lim));
924 start[0] = b[0]->start;
925 p[0] = b[0]->wrap_around ? pp[0]+1 : start[0];
926 if (p[0] >= lim[0])
927 p[0] = start[0];
928 fprintf(file, "Static Buffer comment(%s) tid=%d wrap_around=%d start=%p lim=%p pp=%p p=%p\n",
929 b[0]->comment, b[0]->tid, b[0]->wrap_around, start[0], lim[0], pp[0], p[0]);
930
931 for (i = 1; i <= n_thr; ++i) {
932 b[i] = (struct ak_buf*)amap((char*)(mr->bufs[i-1]));
933 sprintf(stamp, AK_BUFFER_STAMP, i);
934 if (strcmp(stamp, b[i]->stamp))
935 fprintf(stderr, "WARNING: buf[%d] has bad stamp (%s) mapped=%p\n", i, b[i]->stamp, b[i]);
936 pp[i] = (struct ak_ts*)amap((char*)(b[i]->p));
937 lim[i] = (struct ak_ts*)amap((char*)(b[i]->lim));
938 start[i] = b[i]->start;
939 p[i] = b[i]->wrap_around ? pp[i]+1 : start[i];
940 if (p[i] >= lim[i])
941 p[i] = start[i];
942 fprintf(file, "Buffer %c%-2d comment(%s) tid=%d wrap_around=%d start=%p lim=%p pp=%p p=%p mem_pool=%p\n",
943 b[i]->comment[0], i-1, b[i]->comment, b[i]->tid,
944 b[i]->wrap_around, start[i], lim[i], pp[i], p[i], (void *)b[i]->mem_pool);
945 }
946 }
947
948 /* ----------------------------------------------------------------- */
949
950 /* Called by: anal_core x2, extract_a_sym, extract_exe */
open_obj(char * filename,int * size,bfd ** abfd,bfd_format format)951 static char* open_obj(char* filename, int* size, bfd** abfd, bfd_format format) {
952 asection* s;
953 char* base_ptr;
954 fdtype fd;
955 struct stat st;
956 fd = openfile_ro(filename);
957 if (fd == BADFD) die(filename);
958 #ifdef MINGW
959 DWORD filesize;
960 // change this to GetFileSizeEx()
961 if ((filesize = GetFileSize(fd, 0)) == INVALID_FILE_SIZE) die("GetFileSize() failed....");
962 st.st_size = filesize;
963 #else
964 if (fstat(fd, &st) == -1) die("stat(2)");
965 #endif
966 if ((unsigned int)st.st_size > max_size) {
967 fprintf(stderr, "mmap of %s truncated to %lu bytes due to -n flag or max_size limit (the size would have been %lu bytes).\n", filename, max_size, (long unsigned int)st.st_size);
968 *size = max_size;
969 } else
970 *size = st.st_size;
971 #ifdef MINGW
972 HANDLE fM;
973 if ((fM = CreateFileMapping(fd, 0, PAGE_READONLY, 0, 0, 0)) == 0) {
974 errno = GetLastError();
975 die("mmap");
976 }
977 if ((base_ptr = MapViewOfFile(fM, FILE_MAP_READ, 0, 0, *size)) == 0) {
978 errno = GetLastError();
979 die("mmap");
980 }
981 #else
982 base_ptr = mmap(0, *size, PROT_READ, MAP_SHARED|MAP_NORESERVE, fd, 0);
983 if (!base_ptr || base_ptr == MAP_FAILED) die("mmap");
984 #endif
985 #ifdef MINGW
986 *abfd = bfd_openr(filename, "pei-i386");
987 #else
988 *abfd = bfd_openr(filename, "default");
989 #endif
990 if (!*abfd) die_bfd("bfd_fdopenr");
991 if (!bfd_check_format(*abfd, format))
992 die_bfd("Not a recognized BFD file format.");
993
994 for (s = (*abfd)->sections; s; s = s->next) {
995 if (!(s->flags & SEC_HAS_CONTENTS)) /* often crashes here with s == 0xfe9, fix is to compile as in comment in the beginning. This is some mixed library or library versioning issue. --Sampo */
996 continue;
997 s->contents = (U8*)(base_ptr + s->filepos);
998 s->flags |= SEC_IN_MEMORY;
999 }
1000 return base_ptr;
1001 }
1002
1003 /* Called by: main */
anal_core(char * bin,char * core)1004 static void anal_core(char* bin, char* core)
1005 {
1006 printf("PREAMBLE %s " AK_RELEASE "\n"
1007 "Subject to change without notice.\n\n"
1008 "Looking at core file %s generated by %s\n", format, core, bin);
1009 base = (U8*)open_obj(core, &siz, &cbfd, bfd_core);
1010 ebase = (U8*)open_obj(bin, &esiz, &ebfd, bfd_object);
1011 locate_buffers(stdout);
1012 print_buffers();
1013 /*if (gviz) ak_gviz(gviz); */
1014 }
1015
1016 /* Called by: main x2 */
anal_live(int pid)1017 static void anal_live(int pid)
1018 {
1019 fdtype fd;
1020 struct stat st;
1021 char path[1024];
1022 sprintf(path, "/proc/%d/as", pid);
1023 printf("ak - DirectoryScript Application Flight Recorder analysis " AK_RELEASE "\n"
1024 "Looking at live core image of pid %d at %s\n", pid, path);
1025
1026 /* *** use ptrace() to attach to inferior first, otherwise its memory can not be opened. */
1027
1028 /* Open the core. Not being able to open this is fatal. */
1029
1030 fd=openfile_ro(path);
1031 if (fd == BADFD) {
1032 sprintf(path, "/proc/%d/mem", pid);
1033 printf("first image does not exist (%d), trying again at %s\n", errno, path);
1034 fd=openfile_ro(path);
1035 }
1036 if (fd == BADFD) die("Can not read memory image");
1037 if (fstat(fd, &st) == -1) die("stat(2) failed on core file");
1038 siz = st.st_size;
1039 base = (U8*)mmap(0, siz, PROT_READ, MAP_SHARED|MAP_NORESERVE, fd, 0);
1040 if (!base || base == MAP_FAILED) die("mmapping core file failed");
1041 cbfd = bfd_openr(path, 0);
1042 if (!cbfd) die_bfd("bfd_fdopenr");
1043
1044 locate_buffers(stdout);
1045 print_buffers();
1046 /* if (gviz) ak_gviz(gviz);*/
1047 }
1048
1049 /* Called by: main x2, show_tab */
resolve(int funcno)1050 static void resolve(int funcno)
1051 {
1052 if (funcno < 0 || funcno > 65535) die2("Function number must been in range 0..65535");
1053 printf("funcno 0x%x (%d) file: %s\tfunction: %s\n", funcno, funcno, file[funcno], func[funcno]);
1054 }
1055
1056 /* Called by: main */
show_tab()1057 static void show_tab()
1058 {
1059 int x;
1060 for (x=0; x < 65536; ++x) {
1061 if (!memcmp(func[x], "unknown_func", sizeof("unknown_func")-1))
1062 continue;
1063 resolve(x);
1064 }
1065 }
1066
1067 /* Called by: main */
extract_syms(char * bin)1068 static void extract_syms(char* bin)
1069 {
1070 int n;
1071 asymbol** symtab;
1072 asymbol** s;
1073 ebfd = bfd_openr(bin, 0);
1074 if (!ebfd) die_bfd("bfd_fdopenr");
1075 if (!bfd_check_format (ebfd, bfd_object))
1076 die_bfd("Executable is not in a recognized BFD file format.");
1077 n = bfd_get_symtab_upper_bound(ebfd);
1078 if (n <= 0) die_bfd("bfd_get_symtab_upper_bound");
1079 symtab = (asymbol**)malloc(n);
1080 if (!symtab) die("malloc");
1081 bfd_canonicalize_symtab(ebfd, symtab);
1082 for (s = symtab; *s; ++s)
1083 printf("%s %s: base=%p value=%p\n", bfd_get_section_name(ebfd, bfd_get_section(*s)),
1084 bfd_asymbol_name(*s), (char*)bfd_asymbol_base(*s), (char*)bfd_asymbol_value(*s));
1085 }
1086
1087 /* Called by: main */
extract_a_sym(char * bin,char * sym)1088 static void extract_a_sym(char* bin, char* sym)
1089 {
1090 char* sym_data;
1091 char* sym_end;
1092
1093 fprintf(stderr, "ak - DirectoryScript Application Flight Recorder(tm) " AK_RELEASE "\n"
1094 "Extracting symbol %s from binary exectuable file %s\n", sym, bin);
1095
1096 ebase = (U8*)open_obj(bin, &esiz, &ebfd, bfd_object);
1097
1098 #if 0
1099 int n;
1100 asymbol** symtab;
1101 asymbol** s;
1102
1103 ebfd = bfd_openr(bin, 0);
1104 if (!ebfd) die_bfd("bfd_fdopenr");
1105 if (!bfd_check_format (ebfd, bfd_object))
1106 die_bfd("Executable is not in a recognized BFD file format.");
1107 n = bfd_get_symtab_upper_bound(ebfd);
1108 if (n <= 0) die_bfd("bfd_get_symtab_upper_bound");
1109 symtab = (asymbol**)malloc(n);
1110 if (!symtab) die("malloc");
1111 bfd_canonicalize_symtab(ebfd, symtab);
1112 for (s = symtab; *s; ++s) {
1113 if (!strcmp(bfd_asymbol_name(*s), sym)) {
1114 fprintf(stderr, "Found! %s %s: base=%p value=%p\n",
1115 bfd_get_section_name(ebfd, bfd_get_section(*s)),
1116 bfd_asymbol_name(*s), (char*)bfd_asymbol_base(*s), (char*)bfd_asymbol_value(*s));
1117 bfd_print_symbol (ebfd, stderr, *s, bfd_print_symbol_all);
1118 sym_data = s->section ? s->value + s->section->vma : s->value;
1119 fwrite(sym_data, 1, , stdout);
1120 exit(0);
1121 }
1122 }
1123 #else
1124 sym_data = (char*)zx_memmem(ebase, esiz, (U8*)"sigmAsigmA", sizeof("sigmAsigmA")-1);
1125 if (!sym_data) die2("version data magic stamp not found in executable.");
1126 sym_data += sizeof("sigmAsigmA")-1;
1127 sym_end = (char*)zx_memmem(sym_data, esiz - (sym_data - (char*)ebase),
1128 "SigmaSigmaSigma", sizeof("SigmaSigmaSigma")-1);
1129 if (!sym_end) die2("version data end stamp not found in executable.");
1130 fprintf(stderr, "Found! at %p, length %d\n", sym_data, sym_end - sym_data);
1131 fwrite(sym_data, 1, sym_end - sym_data, stdout);
1132 exit(0);
1133 #endif
1134 die("Symbol not found.\n");
1135 }
1136
1137 /* Called by: main */
extract_exe(char * core)1138 static void extract_exe(char* core)
1139 {
1140 fprintf(stderr, "ak - DirectoryScript Application Flight Recorder(tm) " AK_RELEASE "\n"
1141 "Extracting binary from core file %s\n", core);
1142 base = (U8*)open_obj(core, &siz, &cbfd, bfd_core);
1143 locate_buffers(stderr);
1144 if (!mr->binary) die("No binary found in core.\n");
1145 fwrite(amap(mr->binary), 1, mr->binary_st.st_size, stdout);
1146 }
1147
1148 /* Called by: main */
init_func(int x,char * funcname,char * filename)1149 static void init_func(int x, char* funcname, char* filename)
1150 {
1151 char* c;
1152 if (func[x]) {
1153 c = malloc(strlen(funcname)+strlen(func[x])+2);
1154 strcpy(c, func[x]);
1155 strcat(c, "|");
1156 strcat(c, funcname);
1157 func[x] = c;
1158 } else {
1159 func[x] = funcname;
1160 file[x] = filename;
1161 }
1162 }
1163
1164 /* Called by: */
main(int argc,char ** argv)1165 int main(int argc, char** argv)
1166 {
1167 char** cc;
1168 char* q;
1169 int x;
1170 /* Populate table with known functions and their files. function.list was produced by
1171 * call-anal.pl which eats callgraph.files (see top Makefile callgraph target). */
1172 #define AK_FUNC_DEF(f,fil) init_func(AK_FUNCNO(f), f, fil);
1173 #include "../function.list"
1174 for (x=0; x < 65536; ++x) {
1175 if (func[x]) continue;
1176 q = malloc(20);
1177 sprintf(q, "unknown_func_%x", x);
1178 func[x] = q;
1179 q = malloc(20);
1180 sprintf(q, "unknown_file_%x", x);
1181 file[x] = q;
1182 }
1183
1184 bfd_init();
1185
1186 while (argc>1) {
1187 ++argv; --argc;
1188 if (argv[0][0] != '-') {
1189 if (argc < 1) usage("must supply both executable binary and the core\n");
1190 anal_core(argv[0], argv[1]);
1191 exit(0);
1192 }
1193 switch (argv[0][1]) {
1194 case 'p': if (argc < 2) usage("missing pid arg\n"); anal_live(atoi(argv[1])); exit(0);
1195 case 'f': if (argc < 2) usage("missing pid arg\n"); anal_live(atoi(argv[1])); exit(0);
1196 case 'r': if (argc < 2) usage("missing funcno arg\n");
1197 if (strchr(argv[1], ':')) { /* file:line format */
1198 char buf[64];
1199 buf[0] = '0';
1200 buf[1] = 'x';
1201 strncpy(buf+2, argv[1], sizeof(buf));
1202 q = strchr(buf+2, ':');
1203 *q = 0;
1204 sscanf(buf, "%i", &x);
1205 resolve(x);
1206 *q = 'x';
1207 q[-1] = '0';
1208 sscanf(q-1, "%i", &x);
1209 printf("0x%x == %d\n", x, x);
1210 exit(0);
1211 }
1212 sscanf(argv[1], "%i", &x);
1213 resolve(x);
1214 if (argc >= 2) {
1215 sscanf(argv[2], "%i", &x);
1216 printf("0x%x == %d\n", x, x);
1217 }
1218 exit(0);
1219 case 'e': if (argc < 2) usage("missing errno arg\n");
1220 ++argv; --argc;
1221 sscanf(argv[0], "%i", &x);
1222 printf("0x%x == %d ==> %s\n", x, x, STRERROR(x));
1223 exit(0);
1224 case 'x': if (argc < 2) usage("missing executable arg\n");
1225 extract_syms(argv[1]); exit(0);
1226 case 'z': if (argc < 3) usage("missing executable or symbol arg\n");
1227 extract_a_sym(argv[1], argv[2]); exit(0);
1228 case 'y': if (argc < 2) usage("missing core arg\n");
1229 extract_exe(argv[1]); exit(0);
1230 case 't': show_tab(); exit(0);
1231 case 'n': if (argc < 2) usage("missing max core size nn arg\n");
1232 ++argv; --argc; sscanf(argv[0], "%li", &max_size); break;
1233 case 's': if (argc < 2) usage("missing lane width nn arg\n");
1234 ++argv; --argc; swimlane = 1; lane_width = atoi(argv[0]); break;
1235 case '2': swimlane = 2; warning("not implemented yet"); break;
1236 case 'c': if (argc < 2) usage("missing lane width nn arg\n");
1237 ++argv; --argc; swimlane = 3; lane_width = atoi(argv[0]);
1238 warning("not implemented yet"); break;
1239 case 'b': ++brief; format="brief"; break;
1240 case 'g': if (argc < 2) usage("missing gviz file name arg\n");
1241 ++argv; --argc; gviz = argv[0]; break;
1242 case 'm': if (argc < 2) usage("missing fuzz in millisec arg\n");
1243 ++argv; --argc; fuzz_usec = 1000 * atoi(argv[0]); break;
1244 case 'T': for (cc = (char**)bfd_target_list(); *cc; ++cc)
1245 printf("%s\n", *cc);
1246 exit(0);
1247 default: usage("unknown option\n");
1248 }
1249 }
1250 return 0;
1251 }
1252
1253 /* EOF - ak.c */
1254