88099040a6dcb24bf0c67c38303ef7263d4e9927
[openocd.git] / contrib / itmdump.c
1 /*
2 * Copyright (C) 2010 by David Brownell
3 *
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.
8 *
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.
13 *
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/>.
16 */
17
18 /*
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.
23 *
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:
26 *
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.
31 *
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.
35 *
36 * The trace data has two encodings. The working assumption is that data
37 * gets into this program using the UART encoding.
38 */
39
40 #include <errno.h>
41 #include <libgen.h>
42 #include <stdbool.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
47
48 unsigned int dump_swit;
49
50 /* Example ITM trace word (0xWWXXYYZZ) parsing for task events, sent
51 * on port 31 (Reserved for "the" RTOS in CMSIS v1.30)
52 * WWXX: event code (0..3 pre-assigned, 4..15 reserved)
53 * YY: task priority
54 * ZZ: task number
55 *
56 * NOTE that this specific encoding could be space-optimized; and that
57 * trace data streams could also be history-sensitive.
58 */
59 static void show_task(int port, unsigned data)
60 {
61 unsigned code = data >> 16;
62 char buf[16];
63
64 if (dump_swit)
65 return;
66
67 switch (code) {
68 case 0:
69 strcpy(buf, "run");
70 break;
71 case 1:
72 strcpy(buf, "block");
73 break;
74 case 2:
75 strcpy(buf, "create");
76 break;
77 case 3:
78 strcpy(buf, "destroy");
79 break;
80 /* 4..15 reserved for other infrastructure ops */
81 default:
82 sprintf(buf, "code %d", code);
83 break;
84 }
85 printf("TASK %d, pri %d: %s",
86 (data >> 0) & 0xff,
87 (data >> 8) & 0xff,
88 buf);
89 }
90
91 static void show_reserved(FILE *f, char *label, int c)
92 {
93 unsigned i;
94
95 if (dump_swit)
96 return;
97
98 printf("%s - %#02x", label, c);
99
100 for (i = 0; (c & 0x80) && i < 4; i++) {
101 c = fgetc(f);
102 if (c == EOF) {
103 printf("(ERROR %d - %s) ", errno, strerror(errno));
104 break;
105 }
106 printf(" %#02x", c);
107 }
108
109 printf("\n");
110 }
111
112 static bool read_varlen(FILE *f, int c, unsigned *value)
113 {
114 unsigned size;
115 unsigned char buf[4];
116
117 *value = 0;
118
119 switch (c & 3) {
120 case 3:
121 size = 4;
122 break;
123 case 2:
124 size = 2;
125 break;
126 case 1:
127 size = 1;
128 break;
129 default:
130 printf("INVALID SIZE\n");
131 return false;
132 }
133
134 memset(buf, 0, sizeof buf);
135 if (fread(buf, 1, size, f) != size)
136 goto err;
137
138 *value = (buf[3] << 24)
139 + (buf[2] << 16)
140 + (buf[1] << 8)
141 + (buf[0] << 0);
142 return true;
143
144 err:
145 printf("(ERROR %d - %s)\n", errno, strerror(errno));
146 return false;
147 }
148
149 static void show_hard(FILE *f, int c)
150 {
151 unsigned type = c >> 3;
152 unsigned value;
153 char *label;
154
155 if (dump_swit)
156 return;
157
158 printf("DWT - ");
159
160 if (!read_varlen(f, c, &value))
161 return;
162 printf("%#x", value);
163
164 switch (type) {
165 case 0: /* event counter wrapping */
166 printf("overflow %s%s%s%s%s%s",
167 (value & (1 << 5)) ? "cyc " : "",
168 (value & (1 << 4)) ? "fold " : "",
169 (value & (1 << 3)) ? "lsu " : "",
170 (value & (1 << 2)) ? "slp " : "",
171 (value & (1 << 1)) ? "exc " : "",
172 (value & (1 << 0)) ? "cpi " : "");
173 break;
174 case 1: /* exception tracing */
175 switch (value >> 12) {
176 case 1:
177 label = "entry to";
178 break;
179 case 2:
180 label = "exit from";
181 break;
182 case 3:
183 label = "return to";
184 break;
185 default:
186 label = "?";
187 break;
188 }
189 printf("%s exception %d", label, value & 0x1ff);
190 break;
191 case 2: /* PC sampling */
192 if (c == 0x15)
193 printf("PC - sleep");
194 else
195 printf("PC - %#08x", value);
196 break;
197 case 8: /* data tracing, pc value */
198 case 10:
199 case 12:
200 case 14:
201 printf("Data trace %d, PC %#08x", (c >> 4) & 3, value);
202 /* optionally followed by data value */
203 break;
204 case 9: /* data tracing, address offset */
205 case 11:
206 case 13:
207 case 15:
208 printf("Data trace %d, address offset %#04x",
209 (c >> 4) & 3, value);
210 /* always followed by data value */
211 break;
212 case 16 ... 23: /* data tracing, data value */
213 printf("Data trace %d, ", (c >> 4) & 3);
214 label = (c & 0x8) ? "write" : "read";
215 switch (c & 3) {
216 case 3:
217 printf("word %s, value %#08x", label, value);
218 break;
219 case 2:
220 printf("halfword %s, value %#04x", label, value);
221 break;
222 case 1:
223 printf("byte %s, value %#02x", label, value);
224 break;
225 }
226 break;
227 default:
228 printf("UNDEFINED, rawtype: %x", type);
229 break;
230 }
231
232 printf("\n");
233 return;
234 }
235
236 /*
237 * Table of SWIT (SoftWare InstrumentTation) message dump formats, for
238 * ITM port 0..31 application data.
239 *
240 * Eventually this should be customizable; all usage is application defined.
241 *
242 * REVISIT there can be up to 256 trace ports, via "ITM Extension" packets
243 */
244 struct {
245 int port;
246 void (*show)(int port, unsigned data);
247 } format[] = {
248 { .port = 31, .show = show_task, },
249 };
250
251 static void show_swit(FILE *f, int c)
252 {
253 unsigned port = c >> 3;
254 unsigned value = 0;
255 unsigned i;
256
257 if (port + 1 == dump_swit) {
258 if (!read_varlen(f, c, &value))
259 return;
260 printf("%c", value);
261 return;
262 }
263
264 if (!read_varlen(f, c, &value))
265 return;
266
267 if (dump_swit)
268 return;
269
270 printf("SWIT %u - ", port);
271
272 printf("%#08x", value);
273
274 for (i = 0; i < sizeof(format) / sizeof(format[0]); i++) {
275 if (format[i].port == port) {
276 printf(", ");
277 format[i].show(port, value);
278 break;
279 }
280 }
281
282 printf("\n");
283 return;
284 }
285
286 static void show_timestamp(FILE *f, int c)
287 {
288 unsigned counter = 0;
289 char *label = "";
290 bool delayed = false;
291
292 if (dump_swit)
293 return;
294
295 printf("TIMESTAMP - ");
296
297 /* Format 2: header only */
298 if (!(c & 0x80)) {
299 switch (c) {
300 case 0: /* sync packet -- coding error! */
301 case 0x70: /* overflow -- ditto! */
302 printf("ERROR - %#02x\n", c);
303 break;
304 default:
305 /* synchronous to ITM */
306 counter = c >> 4;
307 goto done;
308 }
309 return;
310 }
311
312 /* Format 1: one to four bytes of data too */
313 switch (c >> 4) {
314 default:
315 label = ", reserved control\n";
316 break;
317 case 0xc:
318 /* synchronous to ITM */
319 break;
320 case 0xd:
321 label = ", timestamp delayed";
322 delayed = true;
323 break;
324 case 0xe:
325 label = ", packet delayed";
326 delayed = true;
327 break;
328 case 0xf:
329 label = ", packet and timestamp delayed";
330 delayed = true;
331 break;
332 }
333
334 c = fgetc(f);
335 if (c == EOF)
336 goto err;
337 counter = c & 0x7f;
338 if (!(c & 0x80))
339 goto done;
340
341 c = fgetc(f);
342 if (c == EOF)
343 goto err;
344 counter |= (c & 0x7f) << 7;
345 if (!(c & 0x80))
346 goto done;
347
348 c = fgetc(f);
349 if (c == EOF)
350 goto err;
351 counter |= (c & 0x7f) << 14;
352 if (!(c & 0x80))
353 goto done;
354
355 c = fgetc(f);
356 if (c == EOF)
357 goto err;
358 counter |= (c & 0x7f) << 21;
359
360 done:
361 /* REVISIT should we try to convert from delta values? */
362 printf("+%u%s\n", counter, label);
363 return;
364
365 err:
366 printf("(ERROR %d - %s) ", errno, strerror(errno));
367 goto done;
368 }
369
370 int main(int argc, char **argv)
371 {
372 FILE *f = stdin;
373 int c;
374
375 /* parse arguments */
376 while ((c = getopt(argc, argv, "f:d:")) != EOF) {
377 switch (c) {
378 case 'f':
379 /* e.g. from UART connected to /dev/ttyUSB0 */
380 f = fopen(optarg, "r");
381 if (!f) {
382 perror(optarg);
383 return 1;
384 }
385 break;
386 case 'd':
387 dump_swit = atoi(optarg);
388 break;
389 default:
390 fprintf(stderr, "usage: %s [-f input]",
391 basename(argv[0]));
392 return 1;
393 }
394 }
395
396 /* Parse data ... records have a header then data bytes.
397 * NOTE: we assume getc() deals in 8-bit bytes.
398 */
399 bool overflow = false;
400
401 while ((c = getc(f)) != EOF) {
402
403 /* Sync packet ... 7 zeroes, 0x80 */
404 if (c == 0) {
405 int i;
406
407 for (i = 0; i < 6; i++) {
408 c = fgetc(f);
409 if (c == EOF)
410 break;
411 if (c != 0)
412 goto bad_sync;
413 }
414 c = fgetc(f);
415 if (c == 0x80) {
416 printf("SYNC\n");
417 continue;
418 }
419 bad_sync:
420 printf("BAD SYNC\n");
421 continue;
422 }
423
424 /* Overflow packet */
425 if (c == 0x70) {
426 /* REVISIT later, report just what overflowed!
427 * Timestamp and SWIT can happen. Non-ITM too?
428 */
429 overflow = true;
430 printf("OVERFLOW ...\n");
431 continue;
432 }
433 overflow = false;
434
435 switch (c & 0x0f) {
436 case 0x00: /* Timestamp */
437 show_timestamp(f, c);
438 break;
439 case 0x04: /* "Reserved" */
440 show_reserved(f, "RESERVED", c);
441 break;
442 case 0x08: /* ITM Extension */
443 /* FIXME someday, handle these ... */
444 show_reserved(f, "ITM EXT", c);
445 break;
446 case 0x0c: /* DWT Extension */
447 show_reserved(f, "DWT EXT", c);
448 break;
449 default:
450 if (c & 4)
451 show_hard(f, c);
452 else
453 show_swit(f, c);
454 break;
455 }
456
457 }
458
459 return 0;
460 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)