aarch64: clean up struct aarch64_common
[openocd.git] / contrib / itmdump.c
blob896389416033ab212ffcc6793d3fdce0c1015f66
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>
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)
52 * YY: task priority
53 * ZZ: task number
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;
61 char buf[16];
63 if (dump_swit)
64 return;
66 switch (code) {
67 case 0:
68 strcpy(buf, "run");
69 break;
70 case 1:
71 strcpy(buf, "block");
72 break;
73 case 2:
74 strcpy(buf, "create");
75 break;
76 case 3:
77 strcpy(buf, "destroy");
78 break;
79 /* 4..15 reserved for other infrastructure ops */
80 default:
81 sprintf(buf, "code %d", code);
82 break;
84 printf("TASK %d, pri %d: %s",
85 (data >> 0) & 0xff,
86 (data >> 8) & 0xff,
87 buf);
90 static void show_reserved(FILE *f, char *label, int c)
92 unsigned i;
94 if (dump_swit)
95 return;
97 printf("%s - %#02x", label, c);
99 for (i = 0; (c & 0x80) && i < 4; i++) {
100 c = fgetc(f);
101 if (c == EOF) {
102 printf("(ERROR %d - %s) ", errno, strerror(errno));
103 break;
105 printf(" %#02x", c);
108 printf("\n");
111 static bool read_varlen(FILE *f, int c, unsigned *value)
113 unsigned size;
114 unsigned char buf[4];
116 *value = 0;
118 switch (c & 3) {
119 case 3:
120 size = 4;
121 break;
122 case 2:
123 size = 2;
124 break;
125 case 1:
126 size = 1;
127 break;
128 default:
129 printf("INVALID SIZE\n");
130 return false;
133 memset(buf, 0, sizeof buf);
134 if (fread(buf, 1, size, f) != size)
135 goto err;
137 *value = (buf[3] << 24)
138 + (buf[2] << 16)
139 + (buf[1] << 8)
140 + (buf[0] << 0);
141 return true;
143 err:
144 printf("(ERROR %d - %s)\n", errno, strerror(errno));
145 return false;
148 static void show_hard(FILE *f, int c)
150 unsigned type = c >> 3;
151 unsigned value;
152 char *label;
154 if (dump_swit)
155 return;
157 printf("DWT - ");
159 if (!read_varlen(f, c, &value))
160 return;
161 printf("%#x", value);
163 switch (type) {
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 " : "");
172 break;
173 case 1: /* exception tracing */
174 switch (value >> 12) {
175 case 1:
176 label = "entry to";
177 break;
178 case 2:
179 label = "exit from";
180 break;
181 case 3:
182 label = "return to";
183 break;
184 default:
185 label = "?";
186 break;
188 printf("%s exception %d", label, value & 0x1ff);
189 break;
190 case 2: /* PC sampling */
191 if (c == 0x15)
192 printf("PC - sleep");
193 else
194 printf("PC - %#08x", value);
195 break;
196 case 8: /* data tracing, pc value */
197 case 10:
198 case 12:
199 case 14:
200 printf("Data trace %d, PC %#08x", (c >> 4) & 3, value);
201 /* optionally followed by data value */
202 break;
203 case 9: /* data tracing, address offset */
204 case 11:
205 case 13:
206 case 15:
207 printf("Data trace %d, address offset %#04x",
208 (c >> 4) & 3, value);
209 /* always followed by data value */
210 break;
211 case 16 ... 23: /* data tracing, data value */
212 printf("Data trace %d, ", (c >> 4) & 3);
213 label = (c & 0x8) ? "write" : "read";
214 switch (c & 3) {
215 case 3:
216 printf("word %s, value %#08x", label, value);
217 break;
218 case 2:
219 printf("halfword %s, value %#04x", label, value);
220 break;
221 case 1:
222 printf("byte %s, value %#02x", label, value);
223 break;
225 break;
226 default:
227 printf("UNDEFINED, rawtype: %x", type);
228 break;
231 printf("\n");
232 return;
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
243 struct {
244 int port;
245 void (*show)(int port, unsigned data);
246 } format[] = {
247 { .port = 31, .show = show_task, },
250 static void show_swit(FILE *f, int c)
252 unsigned port = c >> 3;
253 unsigned value = 0;
254 unsigned i;
256 if (port + 1 == dump_swit) {
257 if (!read_varlen(f, c, &value))
258 return;
259 printf("%c", value);
260 return;
263 if (!read_varlen(f, c, &value))
264 return;
266 if (dump_swit)
267 return;
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) {
275 printf(", ");
276 format[i].show(port, value);
277 break;
281 printf("\n");
282 return;
285 static void show_timestamp(FILE *f, int c)
287 unsigned counter = 0;
288 char *label = "";
289 bool delayed = false;
291 if (dump_swit)
292 return;
294 printf("TIMESTAMP - ");
296 /* Format 2: header only */
297 if (!(c & 0x80)) {
298 switch (c) {
299 case 0: /* sync packet -- coding error! */
300 case 0x70: /* overflow -- ditto! */
301 printf("ERROR - %#02x\n", c);
302 break;
303 default:
304 /* synchronous to ITM */
305 counter = c >> 4;
306 goto done;
308 return;
311 /* Format 1: one to four bytes of data too */
312 switch (c >> 4) {
313 default:
314 label = ", reserved control\n";
315 break;
316 case 0xc:
317 /* synchronous to ITM */
318 break;
319 case 0xd:
320 label = ", timestamp delayed";
321 delayed = true;
322 break;
323 case 0xe:
324 label = ", packet delayed";
325 delayed = true;
326 break;
327 case 0xf:
328 label = ", packet and timetamp delayed";
329 delayed = true;
330 break;
333 c = fgetc(f);
334 if (c == EOF)
335 goto err;
336 counter = c & 0x7f;
337 if (!(c & 0x80))
338 goto done;
340 c = fgetc(f);
341 if (c == EOF)
342 goto err;
343 counter |= (c & 0x7f) << 7;
344 if (!(c & 0x80))
345 goto done;
347 c = fgetc(f);
348 if (c == EOF)
349 goto err;
350 counter |= (c & 0x7f) << 14;
351 if (!(c & 0x80))
352 goto done;
354 c = fgetc(f);
355 if (c == EOF)
356 goto err;
357 counter |= (c & 0x7f) << 21;
359 done:
360 /* REVISIT should we try to convert from delta values? */
361 printf("+%u%s\n", counter, label);
362 return;
364 err:
365 printf("(ERROR %d - %s) ", errno, strerror(errno));
366 goto done;
369 int main(int argc, char **argv)
371 FILE *f = stdin;
372 int c;
374 /* parse arguments */
375 while ((c = getopt(argc, argv, "f:d:")) != EOF) {
376 switch (c) {
377 case 'f':
378 /* e.g. from UART connected to /dev/ttyUSB0 */
379 f = fopen(optarg, "r");
380 if (!f) {
381 perror(optarg);
382 return 1;
384 break;
385 case 'd':
386 dump_swit = atoi(optarg);
387 break;
388 default:
389 fprintf(stderr, "usage: %s [-f input]",
390 basename(argv[0]));
391 return 1;
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 */
403 if (c == 0) {
404 int i;
406 for (i = 0; i < 6; i++) {
407 c = fgetc(f);
408 if (c == EOF)
409 break;
410 if (c != 0)
411 goto bad_sync;
413 c = fgetc(f);
414 if (c == 0x80) {
415 printf("SYNC\n");
416 continue;
418 bad_sync:
419 printf("BAD SYNC\n");
420 continue;
423 /* Overflow packet */
424 if (c == 0x70) {
425 /* REVISIT later, report just what overflowed!
426 * Timestamp and SWIT can happen. Non-ITM too?
428 overflow = true;
429 printf("OVERFLOW ...\n");
430 continue;
432 overflow = false;
434 switch (c & 0x0f) {
435 case 0x00: /* Timestamp */
436 show_timestamp(f, c);
437 break;
438 case 0x04: /* "Reserved" */
439 show_reserved(f, "RESERVED", c);
440 break;
441 case 0x08: /* ITM Extension */
442 /* FIXME someday, handle these ... */
443 show_reserved(f, "ITM EXT", c);
444 break;
445 case 0x0c: /* DWT Extension */
446 show_reserved(f, "DWT EXT", c);
447 break;
448 default:
449 if (c & 4)
450 show_hard(f, c);
451 else
452 show_swit(f, c);
453 break;
458 return 0;