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
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.
47 unsigned int dump_swit;
49 /* Example ITM trace word (0xWWXXYYZZ) parsing for task events, sent
50 * on port 31 (Reserved for "the" RTOS in CMSIS v1.30)
51 * WWXX: event code (0..3 pre-assigned, 4..15 reserved)
55 * NOTE that this specific encoding could be space-optimized; and that
56 * trace data streams could also be history-sensitive.
58 static void show_task(int port, unsigned data)
60 unsigned code = data >> 16;
74 strcpy(buf, "create");
77 strcpy(buf, "destroy");
79 /* 4..15 reserved for other infrastructure ops */
81 sprintf(buf, "code %d", code);
84 printf("TASK %d, pri %d: %s",
90 static void show_reserved(FILE *f, char *label, int c)
97 printf("%s - %#02x", label, c);
99 for (i = 0; (c & 0x80) && i < 4; i++) {
102 printf("(ERROR %d - %s) ", errno, strerror(errno));
111 static bool read_varlen(FILE *f, int c, unsigned *value)
114 unsigned char buf[4];
129 printf("INVALID SIZE\n");
133 memset(buf, 0, sizeof buf);
134 if (fread(buf, 1, size, f) != size)
137 *value = (buf[3] << 24)
144 printf("(ERROR %d - %s)\n", errno, strerror(errno));
148 static void show_hard(FILE *f, int c)
150 unsigned type = c >> 3;
159 if (!read_varlen(f, c, &value))
161 printf("%#x", value);
164 case 0: /* event counter wrapping */
165 printf("overflow %s%s%s%s%s%s",
166 (value & (1 << 5)) ? "cyc " : "",
167 (value & (1 << 4)) ? "fold " : "",
168 (value & (1 << 3)) ? "lsu " : "",
169 (value & (1 << 2)) ? "slp " : "",
170 (value & (1 << 1)) ? "exc " : "",
171 (value & (1 << 0)) ? "cpi " : "");
173 case 1: /* exception tracing */
174 switch (value >> 12) {
188 printf("%s exception %d", label, value & 0x1ff);
190 case 2: /* PC sampling */
192 printf("PC - sleep");
194 printf("PC - %#08x", value);
196 case 8: /* data tracing, pc value */
200 printf("Data trace %d, PC %#08x", (c >> 4) & 3, value);
201 /* optionally followed by data value */
203 case 9: /* data tracing, address offset */
207 printf("Data trace %d, address offset %#04x",
208 (c >> 4) & 3, value);
209 /* always followed by data value */
211 case 16 ... 23: /* data tracing, data value */
212 printf("Data trace %d, ", (c >> 4) & 3);
213 label = (c & 0x8) ? "write" : "read";
216 printf("word %s, value %#08x", label, value);
219 printf("halfword %s, value %#04x", label, value);
222 printf("byte %s, value %#02x", label, value);
227 printf("UNDEFINED, rawtype: %x", type);
236 * Table of SWIT (SoftWare InstrumentTation) message dump formats, for
237 * ITM port 0..31 application data.
239 * Eventually this should be customizable; all usage is application defined.
241 * REVISIT there can be up to 256 trace ports, via "ITM Extension" packets
245 void (*show)(int port, unsigned data);
247 { .port = 31, .show = show_task, },
250 static void show_swit(FILE *f, int c)
252 unsigned port = c >> 3;
256 if (port + 1 == dump_swit) {
257 if (!read_varlen(f, c, &value))
263 if (!read_varlen(f, c, &value))
269 printf("SWIT %u - ", port);
271 printf("%#08x", value);
273 for (i = 0; i < sizeof(format) / sizeof(format[0]); i++) {
274 if (format[i].port == port) {
276 format[i].show(port, value);
285 static void show_timestamp(FILE *f, int c)
287 unsigned counter = 0;
289 bool delayed = false;
294 printf("TIMESTAMP - ");
296 /* Format 2: header only */
299 case 0: /* sync packet -- coding error! */
300 case 0x70: /* overflow -- ditto! */
301 printf("ERROR - %#02x\n", c);
304 /* synchronous to ITM */
311 /* Format 1: one to four bytes of data too */
314 label = ", reserved control\n";
317 /* synchronous to ITM */
320 label = ", timestamp delayed";
324 label = ", packet delayed";
328 label = ", packet and timetamp delayed";
343 counter |= (c & 0x7f) << 7;
350 counter |= (c & 0x7f) << 14;
357 counter |= (c & 0x7f) << 21;
360 /* REVISIT should we try to convert from delta values? */
361 printf("+%u%s\n", counter, label);
365 printf("(ERROR %d - %s) ", errno, strerror(errno));
369 int main(int argc, char **argv)
374 /* parse arguments */
375 while ((c = getopt(argc, argv, "f:d:")) != EOF) {
378 /* e.g. from UART connected to /dev/ttyUSB0 */
379 f = fopen(optarg, "r");
386 dump_swit = atoi(optarg);
389 fprintf(stderr, "usage: %s [-f input]",
395 /* Parse data ... records have a header then data bytes.
396 * NOTE: we assume getc() deals in 8-bit bytes.
398 bool overflow = false;
400 while ((c = getc(f)) != EOF) {
402 /* Sync packet ... 7 zeroes, 0x80 */
406 for (i = 0; i < 6; i++) {
419 printf("BAD SYNC\n");
423 /* Overflow packet */
425 /* REVISIT later, report just what overflowed!
426 * Timestamp and SWIT can happen. Non-ITM too?
429 printf("OVERFLOW ...\n");
435 case 0x00: /* Timestamp */
436 show_timestamp(f, c);
438 case 0x04: /* "Reserved" */
439 show_reserved(f, "RESERVED", c);
441 case 0x08: /* ITM Extension */
442 /* FIXME someday, handle these ... */
443 show_reserved(f, "ITM EXT", c);
445 case 0x0c: /* DWT Extension */
446 show_reserved(f, "DWT EXT", c);