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_extract.c
Go to the documentation of this file.
1 /*
2  * Extract a BTS trace from a Xen TT event log.
3  */
4 #include <stdio.h>
5 #include <getopt.h>
6 #include <stdlib.h>
7 #include <stdint.h>
8 #include <string.h>
9 #include <assert.h>
10 #include <xen/xen.h>
11 #include <xen/time_travel.h>
12 
13 #include <bts.h>
14 #include <xentt.h>
15 
16 static void bts_dump(const char *infile, char *outfile);
17 static int bts_dump_branch(struct ttd_rec *rec, FILE *fd);
18 
19 struct brctr_val {
20  uint64_t value;
21  uint64_t radius;
22 };
23 
24 int extended = 0;
25 int debug = 0;
26 struct brctr_val startat = { .value = 0, .radius = 0 };
27 struct brctr_val endat = { .value = UINT64_MAX, .radius = 0 };
28 uint64_t loval, hival;
29 
30 static void
31 usage(void)
32 {
33  fprintf(stderr, "Usage: bts-extract [-d] [-S val[:radius]] [-E val[:radius]] [-o outfile] xentt_event_log\n");
34  fprintf(stderr, " Extracts BTS records from a XenTT replay log,\n");
35  fprintf(stderr, " dumping them to stdout or a logfile (-o). Optionally\n");
36  fprintf(stderr, " takes start and end branch counter values to limit\n");
37  fprintf(stderr, " the range of the dumped records.\n");
38  fprintf(stderr, " -d Turn on debugging.\n");
39  fprintf(stderr, " -x Extended format, include brctr.\n");
40  fprintf(stderr, " -S val[:radius] Starting brctr value and optional radius\n");
41  fprintf(stderr, " -E val[:radius] Ending brctr value and optional radius\n");
42  fprintf(stderr, " -o outfile Output file (stdout is default)\n");
43  exit(1);
44 }
45 
46 static int
47 get_brctr(char *arg, struct brctr_val *val)
48 {
49  char *bp = index(arg, ':');
50  if (bp) {
51  bp[0] = '\0';
52  if (bp[1] != '\0')
53  val->radius = strtoull(&bp[1], NULL, 0);
54  }
55  val->value = strtoull(arg, NULL, 0);
56  if (bp)
57  bp[0] = ':';
58 
59  return 0;
60 }
61 
62 /*
63  * XXX doesn't handle overlap of low and high values yet.
64  */
65 static void
66 set_range(void)
67 {
68  if (startat.value > startat.radius)
69  loval = startat.value - startat.radius;
70  else
71  loval = 0;
72 
73  if (endat.value + endat.radius >= endat.value)
74  hival = endat.value + endat.radius;
75  else
76  hival = UINT64_MAX;
77 }
78 
79 int main(int argc, char **argv)
80 {
81  char ch;
82  char *outfile = 0;
83 
84  while ((ch = getopt(argc, argv, "dxS:E:o:")) != -1) {
85  switch(ch) {
86  case 'd':
87  debug++;
88  break;
89  case 'x':
90  extended++;
91  break;
92  case 'S':
93  if (get_brctr(optarg, &startat)) {
94  fprintf(stderr, "invalid brctr value %s\n", optarg);
95  usage();
96  }
97  break;
98  case 'E':
99  if (get_brctr(optarg, &endat)) {
100  fprintf(stderr, "invalid brctr value %s\n", optarg);
101  usage();
102  }
103  break;
104  case 'o':
105  outfile = optarg;
106  break;
107  }
108  }
109  argc -= optind;
110  argv += optind;
111 
112  if (argc != 1)
113  usage();
114 
115  set_range();
116 
117  bts_dump(*argv, outfile);
118  exit(0);
119 }
120 
121 #define NCPU 8
122 static uint64_t curbrctr[NCPU];
123 
124 static void bts_dump(const char *fname, char *outfile)
125 {
126  struct ttd_rec *rec;
127  unsigned long nrec, nbtsrec;
128  uint64_t lofound = UINT64_MAX, hifound = 0;
129  FILE *fd, *ofd;
130 
131  fd = fopen(fname, "r");
132  if (fd == NULL) {
133  fprintf(stderr, "Could not open XenTT log\n");
134  return;
135  }
136 
137  if (outfile) {
138  ofd = fopen(outfile, "w");
139  if (ofd == NULL) {
140  fprintf(stderr, "Could not open output file %s\n", outfile);
141  return;
142  }
143  } else
144  ofd = stdout;
145 
146  if (debug) {
147  fprintf(stderr, "Dumping BTS records from %s", fname);
148  if (loval != 0 || hival != UINT64_MAX) {
149  fprintf(stderr, " in range [%llu-", loval);
150  if (hival == UINT64_MAX)
151  fprintf(stderr, "end]");
152  else
153  fprintf(stderr, "%llu]", hival);
154  }
155  if (extended)
156  fprintf(stderr, " in extended format");
157  fprintf(stderr, " ...\n");
158  }
159 
160  /*
161  * Write a magic record indicating this is an extended dump.
162  */
163  if (extended) {
164  struct bts_rec _rec;
165  _rec.from = _rec.to = _rec.format = UINT64_MAX;
166  fwrite(&_rec, sizeof(_rec), 1, ofd);
167  }
168 
169  nrec = 0;
170  while ((rec = xentt_readlog(fd)) != 0) {
171  if (extended) {
172  assert(rec->vcpu_id < NCPU);
173  curbrctr[rec->vcpu_id] = rec->cpu_state.brctr_virt;
174  }
175  switch (rec->event.event) {
176  case TTD_HW_BRANCHES:
177  case TTD_HW_BRANCHES_64:
178  if (bts_dump_branch(rec, ofd))
179  exit(1);
180  if (debug) {
181  if (rec->cpu_state.brctr_virt < lofound)
182  lofound = rec->cpu_state.brctr_virt;
183  if (rec->cpu_state.brctr_virt > hifound)
184  hifound = rec->cpu_state.brctr_virt;
185  }
186  nrec++;
187  nbtsrec += rec->data_len / sizeof(struct bts_rec);
188  break;
189  default:
190  break;
191  }
192  free(rec);
193  }
194 
195  fclose(fd);
196 
197  if (debug) {
198  fprintf(stderr, "Found %lu log records ", nrec);
199  if (nrec)
200  fprintf(stderr, "with range [%llu-%llu] ", lofound, hifound);
201  if (nbtsrec)
202  fprintf(stderr, "containing %lu BTS records", nbtsrec);
203  fprintf(stderr, "\n");
204  }
205 }
206 
207 static int bts_dump_branch(struct ttd_rec *rec, FILE *ofd)
208 {
209  uint64_t brctr;
210 
211  assert(rec->event.event == TTD_HW_BRANCHES ||
212  rec->event.event == TTD_HW_BRANCHES_64);
213  assert((rec->data_len % sizeof(struct bts_rec)) == 0);
214 
215  brctr = rec->cpu_state.brctr_virt;
216  if (debug > 1) {
217  int nrec = rec->data_len / sizeof(struct bts_rec);
218  fprintf(stderr, "0x%08lx/%012llu: found %d records\n",
219  rec->cpu_state.ip, brctr, nrec);
220  }
221 
222  /*
223  * Stash our value of the branch counter in the otherwise unused
224  * format field.
225  */
226  if (extended) {
227  struct bts_rec *brec = (struct bts_rec *)rec->data;
228  struct bts_rec *erec = (struct bts_rec *)((void *)rec->data + rec->data_len);
229 
230  while (brec < erec) {
231  brec->format = curbrctr[rec->vcpu_id];
232 /* this does not yield a monotonically increasing log */
233 #if 0
234  curbrctr[rec->vcpu_id]++;
235 #endif
236  brec++;
237  }
238  }
239 
240  if (brctr >= loval && brctr <= hival) {
241  if (fwrite(rec->data, rec->data_len, 1, ofd) == 1)
242  return 0;
243  fprintf(stderr, "error writing record\n");
244  }
245 
246  return 1;
247 }
248 
249 /*
250  * Local variables:
251  * mode: C
252  * c-set-style: "BSD"
253  * c-basic-offset: 4
254  * End:
255  */
char * optarg
Definition: bts.h:23
int optind
int extended
Definition: bts_extract.c:24
uint64_t radius
Definition: bts_extract.c:21
struct brctr_val endat
Definition: bts_extract.c:27
#define assert(x)
Definition: dlmalloc.c:1456
void free(void *ptr)
Definition: debugserver.c:207
uint64_t value
Definition: bts_extract.c:20
int debug
Definition: bts_extract.c:25
int main(int argc, char **argv)
Definition: bts_extract.c:79
uint64_t from
Definition: bts.h:24
uint64_t hival
Definition: bts_extract.c:28
uint64_t format
Definition: bts.h:26
struct brctr_val startat
Definition: bts_extract.c:26
#define NCPU
Definition: bts_extract.c:121
uint64_t to
Definition: bts.h:25
uint64_t loval
Definition: bts_extract.c:28