doc: Clarify the topic field in the commit comment template
[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 <stdio.h>
43 #include <stdbool.h>
44 #include <string.h>
45 #include <unistd.h>
46
47
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
53 *
54 * NOTE that this specific encoding could be space-optimized; and that
55 * trace data streams could also be history-sensitive.
56 */
57 static void show_task(int port, unsigned data)
58 {
59 unsigned code = data >> 16;
60 char buf[16];
61
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;
79 }
80 printf("TASK %d, pri %d: %s",
81 (data >> 0) & 0xff,
82 (data >> 8) & 0xff,
83 buf);
84 }
85
86 static void show_reserved(FILE *f, char *label, int c)
87 {
88 unsigned i;
89
90 printf("%s - %#02x", label, c);
91
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;
97 }
98 printf(" %#02x", c);
99 }
100
101 printf("\n");
102 }
103
104 static bool read_varlen(FILE *f, int c, unsigned *value)
105 {
106 unsigned size;
107 unsigned char buf[4];
108 unsigned i;
109
110 *value = 0;
111
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;
125 }
126
127 memset(buf, 0, sizeof buf);
128 if (fread(buf, 1, size, f) != size)
129 goto err;
130
131 *value = (buf[3] << 24)
132 + (buf[2] << 16)
133 + (buf[2] << 8)
134 + (buf[0] << 0);
135 return true;
136
137 err:
138 printf("(ERROR %d - %s)\n", errno, strerror(errno));
139 return;
140 }
141
142 static void show_hard(FILE *f, int c)
143 {
144 unsigned type = c >> 3;
145 unsigned value;
146 unsigned size;
147 char *label;
148
149 printf("DWT - ", type);
150
151 if (!read_varlen(f, c, &value))
152 return;
153 printf("%#x", value);
154
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;
179 }
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;
216 }
217 break;
218 default:
219 printf("UNDEFINED");
220 break;
221 }
222
223 printf("\n");
224 return;
225 }
226
227 /*
228 * Table of SWIT (SoftWare InstrumentTation) message dump formats, for
229 * ITM port 0..31 application data.
230 *
231 * Eventually this should be customizable; all usage is application defined.
232 *
233 * REVISIT there can be up to 256 trace ports, via "ITM Extension" packets
234 */
235 struct {
236 int port;
237 void (*show)(int port, unsigned data);
238 } format[] = {
239 { .port = 31, .show = show_task, },
240 };
241
242 static void show_swit(FILE *f, int c)
243 {
244 unsigned size;
245 unsigned port = c >> 3;
246 unsigned char buf[4];
247 unsigned value = 0;
248 unsigned i;
249
250 printf("SWIT %u - ", port);
251
252 if (!read_varlen(f, c, &value))
253 return;
254 printf("%#08x", value);
255
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;
261 }
262 }
263
264 printf("\n");
265 return;
266
267 err:
268 printf("(ERROR %d - %s)\n", errno, strerror(errno));
269 return;
270 }
271
272 static void show_timestamp(FILE *f, int c)
273 {
274 unsigned counter = 0;
275 char *label = "";
276 bool delayed = false;
277
278 printf("TIMESTAMP - ");
279
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;
291 }
292 return;
293 }
294
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;
315 }
316
317 c = fgetc(f);
318 if (c == EOF)
319 goto err;
320 counter = c & 0x7f;
321 if (!(c & 0x80))
322 goto done;
323
324 c = fgetc(f);
325 if (c == EOF)
326 goto err;
327 counter |= (c & 0x7f) << 7;
328 if (!(c & 0x80))
329 goto done;
330
331 c = fgetc(f);
332 if (c == EOF)
333 goto err;
334 counter |= (c & 0x7f) << 14;
335 if (!(c & 0x80))
336 goto done;
337
338 c = fgetc(f);
339 if (c == EOF)
340 goto err;
341 counter |= (c & 0x7f) << 21;
342
343 done:
344 /* REVISIT should we try to convert from delta values? */
345 printf("+%u%s\n", counter, label);
346 return;
347
348 err:
349 printf("(ERROR %d - %s) ", errno, strerror(errno));
350 goto done;
351 }
352
353 int main(int argc, char **argv)
354 {
355 FILE *f = stdin;
356 int c;
357
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;
367 }
368 break;
369 default:
370 usage:
371 fprintf(stderr, "usage: %s [-f input]",
372 basename(argv[0]));
373 return 1;
374 }
375 }
376
377 /* Parse data ... records have a header then data bytes.
378 * NOTE: we assume getc() deals in 8-bit bytes.
379 */
380 bool overflow = false;
381
382 while ((c = getc(f)) != EOF) {
383
384 /* Sync packet ... 7 zeroes, 0x80 */
385 if (c == 0) {
386 int i;
387
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;
394 }
395 c = fgetc(f);
396 if (c == 0x80) {
397 printf("SYNC\n");
398 continue;
399 }
400 bad_sync:
401 printf("BAD SYNC\n");
402 continue;
403 }
404
405 /* Overflow packet */
406 if (c == 0x70) {
407 /* REVISIT later, report just what overflowed!
408 * Timestamp and SWIT can happen. Non-ITM too?
409 */
410 overflow = true;
411 printf("OVERFLOW ...\n");
412 continue;
413 }
414 overflow = false;
415
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;
436 }
437
438 }
439
440 return 0;
441 }

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)