Stackdb
Stackdb is a stackable, multi-target and -level source debugger and memory forensics library.
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
bts_trace.c
Go to the documentation of this file.
1 /*
2  * Given a BTS trace file, create a control flow trace.
3  */
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <getopt.h>
8 
9 #include <bts.h>
10 
11 static void bts_trace(const char *fname);
12 static void printone(FILE *fd, int depth, char *str, struct bts_rec *rec, int src);
13 static void printboth(FILE *fd, int depth, char *str, struct bts_rec *rec);
14 
15 struct symmap symmap[] = {
16  /* user space */
17  {
18  .symfile = NULL,
19  .prefix = "User:",
20  .loaddr = 0x08000000,
21  .hiaddr = 0xBFFFFFFF
22  },
23  /* Linux kernel */
24  {
25  .symfile = "/boot/vmlinux-syms-2.6.18-xenU",
26  .prefix = "",
27  .loaddr = 0xC0000000,
28  .hiaddr = 0xF67FFFFF
29  },
30  /* Xen */
31  {
32  .symfile = "/boot/xen-syms-3.0-unstable",
33  .prefix = "Xen:",
34  .loaddr = 0xF6800000,
35  .hiaddr = 0xFFFFFFFF
36  }
37 };
38 
39 int debug = 0;
40 int doinlined = 0;
41 char *userbin = NULL;
42 
43 int main(int argc, char **argv)
44 {
45  char ch;
46 
47  while ((ch = getopt(argc, argv, "dIU:")) != -1) {
48  switch(ch) {
49  case 'd':
50  debug++;
51  break;
52  case 'I':
53  doinlined++;
54  break;
55  case 'U':
56  userbin = optarg;
57  break;
58  }
59  }
60  argc -= optind;
61  argv += optind;
62 
63  if (argc < 1) {
64  fprintf(stderr, "Usage: bts-trace [-dI] [-U userbin] filename ...\n");
65  exit(1);
66  }
67 
68  if (userbin)
69  symmap[0].symfile = userbin;
70 
71  /*
72  * Open symbol files.
73  */
74  if (symlist_init(symmap, sizeof(symmap)/sizeof(symmap[0])))
75  exit(1);
76 
77  bts_trace(*argv);
78  exit(0);
79 }
80 
81 #define MAXDEPTH 1024
82 
83 struct funccall {
84  char *name;
85  uint32_t calladdr;
86  uint32_t loaddr;
87  uint32_t hiaddr;
88  int flags;
89 };
90 #define F_IS_INLINED 1
91 
92 static struct funccall callstack[MAXDEPTH];
93 static int depth = 0;
94 static int extended = 0;
95 
96 extern int symlist_isfunc_2(uint32_t addr, char **namep,
97  int *isinlined, uint32_t *lo, uint32_t *hi);
98 
99 static void
100 bts_trace(const char *file)
101 {
102  struct bts_rec recs[1024];
103  int n, i;
104  long long tot = 0;
105  uint32_t curlo = 0, curhi = ~0;
106  int currangedepth = 0;
107 
108  BTSFD fd = bts_open(file);
109  if (fd == 0) {
110  fprintf(stderr, "Could not open stream\n");
111  return;
112  }
113 
114  while (1) {
115  n = bts_read(fd, recs, 1024);
116  if (n == 0)
117  break;
118 
119  i = 0;
120 
121  /* see if this is extended format */
122  if (tot == 0 && recs[0].from == UINT64_MAX &&
123  recs[0].to == UINT64_MAX && recs[0].format == UINT64_MAX) {
124  if (debug)
125  fprintf(stderr, "Dump file in extended format\n");
126  extended++;
127  i++;
128  }
129 
130  callstack[0].name = strdup("<TOP>");
131 
132  while (i < n) {
133  int inlined = 0;
134  uint32_t lo, hi;
135  uint32_t addr = recs[i].to;
136  char *name = NULL;
137 
138  /*
139  * Check it the target of the branch is a function entry point.
140  * If so, push another level on the call stack.
141  */
142  if (symlist_isfunc_2(addr, &name, &inlined, &lo, &hi)) {
143  /* ignore inlined functions */
144  if (inlined && !doinlined) {
145  if (debug) {
146  fprintf(stderr, "[%d]: Ignoring inlined function ",
147  depth);
148  printone(stderr, 0, "", &recs[i], 0);
149  fprintf(stderr, "\n");
150  }
151  } else {
152  if (debug) {
153  fprintf(stderr, "[%d]: Found function ", depth);
154  printone(stderr, 0, "", &recs[i], 0);
155  fprintf(stderr, "\n");
156  }
157  printone(stdout, depth, "Call to ", &recs[i], 0);
158  fprintf(stdout, "\n");
159  callstack[depth].calladdr = recs[i].from;
160  depth++;
161  callstack[depth].name = name;
162  name = NULL;
163  if (lo != 0 || hi != 0) {
164  callstack[depth].loaddr = curlo = lo;
165  callstack[depth].hiaddr = curhi = hi;
166  currangedepth = depth;
167  if (debug) {
168  fprintf(stderr, "[%d]: Range is [0x%x-0x%x]\n",
169  depth, curlo, curhi);
170  }
171  } else {
172  if (debug) {
173  fprintf(stderr,
174  "WARNING: no range info for func@0x%x\n",
175  addr);
176  }
177  }
178  if (inlined)
179  callstack[depth].flags |= F_IS_INLINED;
180  }
181  goto next;
182  }
183 
184  /*
185  * If we are not at the top level, see if the branch might
186  * be a return. A "return" is a branch to anywhere within
187  * 5 bytes following a higher-level call site. We check more
188  * that just one level up to catch tail-call optimization.
189  */
190  if (depth > 0) {
191  int d;
192 
193  /*
194  * See if the destination is on our call stack
195  */
196  if (debug > 1)
197  fprintf(stderr, "Compare 0x%x:\n", addr);
198  for (d = depth - 1; d >= 0; d--) {
199  uint32_t raddr = callstack[d].calladdr;
200  if (debug > 1)
201  fprintf(stderr, " rstack[%d]=0x%x (in %s)\n",
202  d, raddr, callstack[d].name);
203  if (addr > raddr && addr <= raddr+5) {
204  if (debug) {
205  fprintf(stderr, "[%d]: Found return to depth %d (%x in %s) ",
206  depth, d, raddr, callstack[d].name);
207  printone(stderr, 0, "", &recs[i], 0);
208  fprintf(stderr, "\n");
209  }
210  printone(stdout, depth, "Return from ", &recs[i], 1);
211  fprintf(stdout, "\n");
212  while (depth > d) {
213  if (callstack[depth].name)
214  free(callstack[depth].name);
215  depth--;
216  }
217  curlo = callstack[d].loaddr;
218  curhi = callstack[d].hiaddr;
219  currangedepth = d;
220  if (debug > 1)
221  fprintf(stderr, "[%d]: Range is [0x%x-0x%x]\n",
222  depth, curlo, curhi);
223  break;
224  }
225  }
226 
227  /*
228  * Didn't find it, probably just a normal branch.
229  * Make sure it is in-scope for the current call level.
230  */
231  if (d == -1) {
232  if (debug > 1)
233  fprintf(stderr,
234  "[%d]: checking branch 0x%x against range [0x%x-0x%x] (from depth %d (%s))\n",
235  depth, addr, curlo, curhi, currangedepth,
236  callstack[currangedepth].name);
237  if (addr < curlo || addr >= curhi) {
238  printboth(stdout, depth, "*** branch ", &recs[i]);
239  printf(" out of range [0x%x-0x%x]\n", curlo, curhi-1);
240  }
241  }
242  }
243 
244  next:
245  if (name)
246  free(name);
247  i++;
248  }
249  tot += n;
250  }
251 
252  bts_close(fd);
253 }
254 
255 static void
256 printone(FILE *fd, int depth, char *str, struct bts_rec *rec, int src)
257 {
258  char buf[256];
259 
260  if (!doinlined)
261  symlist_gdb_string(src ? rec->from :rec->to, buf, sizeof(buf));
262  else
263  symlist_string(src ? rec->from :rec->to, buf, sizeof(buf));
264  while (depth-- > 0)
265  fprintf(fd, " ");
266  fprintf(fd, "%s%s", str, buf);
267  if (extended)
268  fprintf(fd, " (bctr=%012llu)", rec->format);
269 }
270 
271 static void
272 printboth(FILE *fd, int depth, char *str, struct bts_rec *rec)
273 {
274  char buf1[256], buf2[256];
275 
276  if (!doinlined) {
277  symlist_gdb_string(rec->from, buf1, sizeof(buf1));
278  symlist_gdb_string(rec->to, buf2, sizeof(buf2));
279  } else {
280  symlist_string(rec->from, buf1, sizeof(buf1));
281  symlist_string(rec->to, buf2, sizeof(buf2));
282  }
283  while (depth-- > 0)
284  fprintf(fd, " ");
285  fprintf(fd, "%sfrom %s to %s", str, buf1, buf2);
286  if (extended)
287  fprintf(fd, " (bctr=%012llu)", rec->format);
288 }
289 
290 /*
291  * Local variables:
292  * mode: C
293  * c-set-style: "BSD"
294  * c-basic-offset: 4
295  * End:
296  */
void bts_close(BTSFD)
Definition: io.c:113
void symlist_string(uint32_t, char *, int)
Definition: symbol.c:332
char * optarg
Definition: bts.h:23
int optind
uint32_t hiaddr
Definition: bts_trace.c:87
int flags
Definition: bts_trace.c:88
int extended
Definition: bts_extract.c:24
void * BTSFD
Definition: bts.h:29
static uint64_t unsigned int i
void symlist_gdb_string(uint32_t, char *, int)
Definition: symbol.c:326
uint32_t calladdr
Definition: bts_trace.c:85
void free(void *ptr)
Definition: debugserver.c:207
int bts_read(BTSFD, struct bts_rec *, int)
Definition: io.c:73
int symlist_isfunc_2(uint32_t addr, char **namep, int *isinlined, uint32_t *lo, uint32_t *hi)
Definition: symbol.c:80
char * symfile
Definition: bts.h:8
int doinlined
Definition: bts_trace.c:40
#define MAXDEPTH
Definition: bts_trace.c:81
uint64_t from
Definition: bts.h:24
BTSFD bts_open(const char *)
Definition: io.c:19
uint64_t format
Definition: bts.h:26
char * name
Definition: bts_trace.c:84
int main(int argc, char **argv)
Definition: bts_trace.c:43
uint32_t loaddr
Definition: bts_trace.c:86
#define F_IS_INLINED
Definition: bts_trace.c:90
uint64_t to
Definition: bts.h:25
int symlist_init(struct symmap[], int)
Definition: symbol.c:20
Definition: bts.h:7
char * userbin
Definition: bts_trace.c:41
int debug
Definition: bts_trace.c:39