cfg: Beaglebone/AM335x refactor
[openocd/andreasf.git] / contrib / itmdump.c
blob1c484d0a4858f822dfac3f8508a929bb2d48153f
1 /*
2 * Copyright (C) 2010 by David Brownell
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or (at
7 * your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 * Simple utility to parse and dump ARM Cortex-M3 SWO trace output. Once the
20 * mechanisms work right, this information can be used for various purposes
21 * including profiling (particularly easy for flat PC-sample profiles) and
22 * for debugging.
24 * SWO is the Single Wire Output found on some ARM cores, most notably on the
25 * Cortex-M3. It combines data from several sources:
27 * - Software trace (ITM): so-called "printf-style" application messaging
28 * using "ITM stimulus ports"; and differential timestamps.
29 * - Hardware trace (DWT): for profiling counters and comparator matches.
30 * - TPIU may issue sync packets.
32 * The trace data format is defined in Appendix E, "Debug ITM and DWT packet
33 * protocol", of the ARMv7-M Architecture Reference Manual (DDI 0403C). It
34 * is a superset of the ITM data format from the Coresight TRM.
36 * The trace data has two encodings. The working assumption is that data
37 * gets into this program using the UART encoding.
40 #include <errno.h>
41 #include <libgen.h>
42 #include <stdio.h>
43 #include <stdbool.h>
44 #include <string.h>
45 #include <unistd.h>
48 /* Example ITM trace word (0xWWXXYYZZ) parsing for task events, sent
49 * on port 31 (Reserved for "the" RTOS in CMSIS v1.30)
50 * WWXX: event code (0..3 pre-assigned, 4..15 reserved)
51 * YY: task priority
52 * ZZ: task number
54 * NOTE that this specific encoding could be space-optimized; and that
55 * trace data streams could also be history-sensitive.
57 static void show_task(int port, unsigned data)
59 unsigned code = data >> 16;
60 char buf[16];
62 switch (code) {
63 case 0:
64 strcpy(buf, "run");
65 break;
66 case 1:
67 strcpy(buf, "block");
68 break;
69 case 2:
70 strcpy(buf, "create");
71 break;
72 case 3:
73 strcpy(buf, "destroy");
74 break;
75 /* 4..15 reserved for other infrastructure ops */
76 default:
77 sprintf(buf, "code %d", code);
78 break;
80 printf("TASK %d, pri %d: %s",
81 (data >> 0) & 0xff,
82 (data >> 8) & 0xff,
83 buf);
86 static void show_reserved(FILE *f, char *label, int c)
88 unsigned i;
90 printf("%s - %#02x", label, c);
92 for (i = 0; (c & 0x80) && i < 4; i++) {
93 c = fgetc(f);
94 if (c == EOF) {
95 printf("(ERROR %d - %s) ", errno, strerror(errno));
96 break;
98 printf(" %#02x", c);
101 printf("\n");
104 static bool read_varlen(FILE *f, int c, unsigned *value)
106 unsigned size;
107 unsigned char buf[4];
108 unsigned i;
110 *value = 0;
112 switch (c & 3) {
113 case 3:
114 size = 4;
115 break;
116 case 2:
117 size = 2;
118 break;
119 case 1:
120 size = 1;
121 break;
122 default:
123 printf("INVALID SIZE\n");
124 return false;
127 memset(buf, 0, sizeof buf);
128 if (fread(buf, 1, size, f) != size)
129 goto err;
131 *value = (buf[3] << 24)
132 + (buf[2] << 16)
133 + (buf[2] << 8)
134 + (buf[0] << 0);
135 return true;
137 err:
138 printf("(ERROR %d - %s)\n", errno, strerror(errno));
139 return;
142 static void show_hard(FILE *f, int c)
144 unsigned type = c >> 3;
145 unsigned value;
146 unsigned size;
147 char *label;
149 printf("DWT - ", type);
151 if (!read_varlen(f, c, &value))
152 return;
153 printf("%#x", value);
155 switch (type) {
156 case 0: /* event counter wrapping */
157 printf("overflow %s%s%s%s%s%s",
158 (value & (1 << 5)) ? "cyc " : "",
159 (value & (1 << 4)) ? "fold " : "",
160 (value & (1 << 3)) ? "lsu " : "",
161 (value & (1 << 2)) ? "slp " : "",
162 (value & (1 << 1)) ? "exc " : "",
163 (value & (1 << 0)) ? "cpi " : "");
164 break;
165 case 1: /* exception tracing */
166 switch (value >> 12) {
167 case 1:
168 label = "entry to";
169 break;
170 case 2:
171 label = "exit from";
172 break;
173 case 3:
174 label = "return to";
175 break;
176 default:
177 label = "?";
178 break;
180 printf("%s exception %d", label, value & 0x1ff);
181 break;
182 case 2: /* PC sampling */
183 if (c == 0x15)
184 printf("PC - sleep");
185 else
186 printf("PC - %#08x", value);
187 break;
188 case 8: /* data tracing, pc value */
189 case 10:
190 case 12:
191 case 14:
192 printf("Data trace %d, PC %#08x", (c >> 4) & 3, value);
193 /* optionally followed by data value */
194 break;
195 case 9: /* data tracing, address offset */
196 case 11:
197 case 13:
198 case 15:
199 printf("Data trace %d, address offset %#04x",
200 (c >> 4) & 3, value);
201 /* always followed by data value */
202 break;
203 case 16 ... 23: /* data tracing, data value */
204 printf("Data trace %d, ", (c >> 4) & 3);
205 label = (c & 0x8) ? "write" : "read";
206 switch (c & 3) {
207 case 3:
208 printf("word %s, value %#08x", label, value);
209 break;
210 case 2:
211 printf("halfword %s, value %#04x", label, value);
212 break;
213 case 1:
214 printf("byte %s, value %#02x", label, value);
215 break;
217 break;
218 default:
219 printf("UNDEFINED");
220 break;
223 printf("\n");
224 return;
228 * Table of SWIT (SoftWare InstrumentTation) message dump formats, for
229 * ITM port 0..31 application data.
231 * Eventually this should be customizable; all usage is application defined.
233 * REVISIT there can be up to 256 trace ports, via "ITM Extension" packets
235 struct {
236 int port;
237 void (*show)(int port, unsigned data);
238 } format[] = {
239 { .port = 31, .show = show_task, },
242 static void show_swit(FILE *f, int c)
244 unsigned size;
245 unsigned port = c >> 3;
246 unsigned char buf[4];
247 unsigned value = 0;
248 unsigned i;
250 printf("SWIT %u - ", port);
252 if (!read_varlen(f, c, &value))
253 return;
254 printf("%#08x", value);
256 for (i = 0; i <= sizeof(format) / sizeof(format[0]); i++) {
257 if (format[i].port == port) {
258 printf(", ");
259 format[i].show(port, value);
260 break;
264 printf("\n");
265 return;
267 err:
268 printf("(ERROR %d - %s)\n", errno, strerror(errno));
269 return;
272 static void show_timestamp(FILE *f, int c)
274 unsigned counter = 0;
275 char *label = "";
276 bool delayed = false;
278 printf("TIMESTAMP - ");
280 /* Format 2: header only */
281 if (!(c & 0x80)) {
282 switch (c) {
283 case 0: /* sync packet -- coding error! */
284 case 0x70: /* overflow -- ditto! */
285 printf("ERROR - %#02x\n", c);
286 break;
287 default:
288 /* synchronous to ITM */
289 counter = c >> 4;
290 goto done;
292 return;
295 /* Format 1: one to four bytes of data too */
296 switch (c) {
297 default:
298 label = ", reserved control\n";
299 break;
300 case 0xc:
301 /* synchronous to ITM */
302 break;
303 case 0xd:
304 label = ", timestamp delayed";
305 delayed = true;
306 break;
307 case 0xe:
308 label = ", packet delayed";
309 delayed = true;
310 break;
311 case 0xf:
312 label = ", packet and timetamp delayed";
313 delayed = true;
314 break;
317 c = fgetc(f);
318 if (c == EOF)
319 goto err;
320 counter = c & 0x7f;
321 if (!(c & 0x80))
322 goto done;
324 c = fgetc(f);
325 if (c == EOF)
326 goto err;
327 counter |= (c & 0x7f) << 7;
328 if (!(c & 0x80))
329 goto done;
331 c = fgetc(f);
332 if (c == EOF)
333 goto err;
334 counter |= (c & 0x7f) << 14;
335 if (!(c & 0x80))
336 goto done;
338 c = fgetc(f);
339 if (c == EOF)
340 goto err;
341 counter |= (c & 0x7f) << 21;
343 done:
344 /* REVISIT should we try to convert from delta values? */
345 printf("+%u%s\n", counter, label);
346 return;
348 err:
349 printf("(ERROR %d - %s) ", errno, strerror(errno));
350 goto done;
353 int main(int argc, char **argv)
355 FILE *f = stdin;
356 int c;
358 /* parse arguments */
359 while ((c = getopt(argc, argv, "f:")) != EOF) {
360 switch (c) {
361 case 'f':
362 /* e.g. from UART connected to /dev/ttyUSB0 */
363 f = fopen(optarg, "r");
364 if (!f) {
365 perror(optarg);
366 return 1;
368 break;
369 default:
370 usage:
371 fprintf(stderr, "usage: %s [-f input]",
372 basename(argv[0]));
373 return 1;
377 /* Parse data ... records have a header then data bytes.
378 * NOTE: we assume getc() deals in 8-bit bytes.
380 bool overflow = false;
382 while ((c = getc(f)) != EOF) {
384 /* Sync packet ... 7 zeroes, 0x80 */
385 if (c == 0) {
386 int i;
388 for (i = 0; i < 6; i++) {
389 c = fgetc(f);
390 if (c == EOF)
391 break;
392 if (c != 0)
393 goto bad_sync;
395 c = fgetc(f);
396 if (c == 0x80) {
397 printf("SYNC\n");
398 continue;
400 bad_sync:
401 printf("BAD SYNC\n");
402 continue;
405 /* Overflow packet */
406 if (c == 0x70) {
407 /* REVISIT later, report just what overflowed!
408 * Timestamp and SWIT can happen. Non-ITM too?
410 overflow = true;
411 printf("OVERFLOW ...\n");
412 continue;
414 overflow = false;
416 switch (c & 0x0f) {
417 case 0x00: /* Timestamp */
418 show_timestamp(f, c);
419 break;
420 case 0x04: /* "Reserved" */
421 show_reserved(f, "RESERVED", c);
422 break;
423 case 0x08: /* ITM Extension */
424 /* FIXME someday, handle these ... */
425 show_reserved(f, "ITM EXT", c);
426 break;
427 case 0x0c: /* DWT Extension */
428 show_reserved(f, "DWT EXT", c);
429 break;
430 default:
431 if (c & 4)
432 show_hard(f, c);
433 else
434 show_swit(f, c);
435 break;
440 return 0;