b06c713d947321238d686eeeb0733f2efa7784c7
[mw/micromonitor-lm32.git] / umon_main / host / src / utils / backtrace.c
1 /* backtrace.c:
2  * This tool takes a list of addresses (as they would be dumped by
3  * a linux crash's call backtrace) and searches for a match in a
4  * sorted symbol list.
5  * To use this, run...
6  *
7  *    nm --numeric-sort {elf-file} >nm.out
8  *
9  * Then, when a crash occurs like the one shown here...
10  *
11 Oops: kernel access of bad area, sig: 11
12 NIP: C0013A4C XER: 00000000 LR: C0013A38 SP: C03D1E90 REGS: c03d1de0 TRAP: 0800
13    Not tainted
14 MSR: 00001030 EE: 0 PR: 0 FP: 0 ME: 1 IR/DR: 11
15 DEAR: FFFFFFFC, ESR: 00000000
16 TASK = c03d0000[7] 'mtdblockd' Last syscall: -1
17 last math 00000000 last altivec 00000000
18 GPR00: 00001030 C03D1E90 C03D0000 00000001 00009030 00000001 C7F7C1FC FFFFFFFF
19 GPR08: FFFFFFFF C0170000 00000034 60000000 C0170000 100CD7B0 00000000 00000000
20 GPR16: 00000000 C014FB54 C03D1F58 C03D8240 C7F7C000 00000000 C03D8240 C0170000
21 GPR24: 00000200 00000200 C0170000 00000003 00000001 C03D8294 00000000 C03D1E90
22 Call backtrace:
23 C00C16EC C00BE13C C00B8BEC C00BB268 C00BB820 C00BB984 C0006CCC
24 Kernel panic: Aiee, killing interrupt handler!
25 In interrupt handler - not syncing
26  <0>Rebooting in 180 seconds..<NULL>
27
28  *
29  * Take the address list dumped after "Call backtrace:" and pass it in as
30  * arguments to this tool (after first specifying the nm.out).
31  * For example, assuming the nm.out file is created and the above crash is
32  * to be analyzed, the command line would be...
33  *
34  * backtrace nm.out C00C16EC C00BE13C C00B8BEC C00BB268 C00BB820 C00BB984 C0006CCC
35  * and the output would be something like this...
36  *
37  c00c1714 t simple_map_copy_to
38  c00be1a4 t cfi_amdstd_secsi_read
39  c00b8c64 t part_point
40  c00bb2e4 t mtdblock_readsect
41  c00bb84c t mtd_blktrans_thread
42  c00bba7c t mtd_blktrans_request
43  c0006cd8 T __main
44  *
45  */
46  
47 #include <stdio.h>
48 #include <ctype.h>
49 #include <sys/stat.h>
50 #include <string.h>
51 #include "utils.h"
52
53 #define LINESIZE 256
54
55 extern  int optind;
56 extern  char *optarg;
57
58 int             debug;
59
60 char *usage_txt[] = {
61         "Usage: backtrace {nm-output-file} {addr} [addr] [addr] ...",
62         " Parse the output of nm --numeric-sort <file>, to symbolically",
63         " resolve the addresses dumped by a linux coredump backtrace output.",
64         "",
65         " Note, to force an inline crash, this usually works...",
66         ""
67         " {",
68         "    void     (*func)(void);",
69         "    func = (void(*)(void))1;",
70         "    func();",
71         " }",
72         "",
73         " Options:",
74         " -V               display version of tool",
75         0,
76 };
77
78 main(int argc,char *argv[])
79 {
80         int opt, i;
81         FILE *symfp;
82         char lastline[LINESIZE], line[LINESIZE];
83         unsigned long addr, addr_in_func;
84
85         while((opt=getopt(argc,argv,"V")) != EOF) {
86                 switch(opt) {
87                 case 'V':
88                         showVersion();
89                         break;
90                 default:
91                         usage(0);
92                 }
93         }
94
95         if (argc < optind+2)
96                 usage(0);
97
98         /* Open the symbol file (built by nm): */
99         if ((symfp = fopen(argv[optind],"r")) == (FILE *)NULL) {
100                 perror(argv[optind]);
101                 usage(0);
102         }
103
104         lastline[0] = 0;
105         for(i=optind+1;i<argc;i++) {
106                 addr_in_func = strtoul(argv[i],0,16);
107
108                 while(1)
109                 {
110                         int     lsize;
111                         char *symbol, *data, outline[LINESIZE];
112                 
113                         if (fgets(line,LINESIZE,symfp) == NULL)
114                                 break;
115                 
116                         /* Assume the first whitespace delimited token is the
117                          * address and as soon as the address in the file is 
118                          * greater than the address on our command line, we print
119                          * the previous line...
120                          */
121                         addr = strtoul(line,0,16);
122                         if (addr_in_func <= addr) {
123                                 printf(" %s",lastline);
124                                 break;
125                         }
126                         strcpy(lastline,line);
127                 }
128                 rewind(symfp);
129         }
130         fclose(symfp);
131         exit(0);
132 }
133