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