target/arm7_9_common: use coherent syntax in struct initialization
[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 unsigned int dump_swit;
48
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
54 *
55 * NOTE that this specific encoding could be space-optimized; and that
56 * trace data streams could also be history-sensitive.
57 */
58 static void show_task(int port, unsigned data)
59 {
60 unsigned code = data >> 16;
61 char buf[16];
62
63 if (dump_swit)
64 return;
65
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;
83 }
84 printf("TASK %d, pri %d: %s",
85 (data >> 0) & 0xff,
86 (data >> 8) & 0xff,
87 buf);
88 }
89
90 static void show_reserved(FILE *f, char *label, int c)
91 {
92 unsigned i;
93
94 if (dump_swit)
95 return;
96
97 printf("%s - %#02x", label, c);
98
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;
104 }
105 printf(" %#02x", c);
106 }
107
108 printf("\n");
109 }
110
111 static bool read_varlen(FILE *f, int c, unsigned *value)
112 {
113 unsigned size;
114 unsigned char buf[4];
115
116 *value = 0;
117
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;
131 }
132
133 memset(buf, 0, sizeof buf);
134 if (fread(buf, 1, size, f) != size)
135 goto err;
136
137 *value = (buf[3] << 24)
138 + (buf[2] << 16)
139 + (buf[1] << 8)
140 + (buf[0] << 0);
141 return true;
142
143 err:
144 printf("(ERROR %d - %s)\n", errno, strerror(errno));
145 return false;
146 }
147
148 static void show_hard(FILE *f, int c)
149 {
150 unsigned type = c >> 3;
151 unsigned value;
152 char *label;
153
154 if (dump_swit)
155 return;
156
157 printf("DWT - ");
158
159 if (!read_varlen(f, c, &value))
160 return;
161 printf("%#x", value);
162
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;
187 }
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;
224 }
225 break;
226 default:
227 printf("UNDEFINED, rawtype: %x", type);
228 break;
229 }
230
231 printf("\n");
232 return;
233 }
234
235 /*
236 * Table of SWIT (SoftWare InstrumentTation) message dump formats, for
237 * ITM port 0..31 application data.
238 *
239 * Eventually this should be customizable; all usage is application defined.
240 *
241 * REVISIT there can be up to 256 trace ports, via "ITM Extension" packets
242 */
243 struct {
244 int port;
245 void (*show)(int port, unsigned data);
246 } format[] = {
247 { .port = 31, .show = show_task, },
248 };
249
250 static void show_swit(FILE *f, int c)
251 {
252 unsigned port = c >> 3;
253 unsigned value = 0;
254 unsigned i;
255
256 if (port + 1 == dump_swit) {
257 if (!read_varlen(f, c, &value))
258 return;
259 printf("%c", value);
260 return;
261 }
262
263 if (!read_varlen(f, c, &value))
264 return;
265
266 if (dump_swit)
267 return;
268
269 printf("SWIT %u - ", port);
270
271 printf("%#08x", value);
272
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;
278 }
279 }
280
281 printf("\n");
282 return;
283 }
284
285 static void show_timestamp(FILE *f, int c)
286 {
287 unsigned counter = 0;
288 char *label = "";
289 bool delayed = false;
290
291 if (dump_swit)
292 return;
293
294 printf("TIMESTAMP - ");
295
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;
307 }
308 return;
309 }
310
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;
331 }
332
333 c = fgetc(f);
334 if (c == EOF)
335 goto err;
336 counter = c & 0x7f;
337 if (!(c & 0x80))
338 goto done;
339
340 c = fgetc(f);
341 if (c == EOF)
342 goto err;
343 counter |= (c & 0x7f) << 7;
344 if (!(c & 0x80))
345 goto done;
346
347 c = fgetc(f);
348 if (c == EOF)
349 goto err;
350 counter |= (c & 0x7f) << 14;
351 if (!(c & 0x80))
352 goto done;
353
354 c = fgetc(f);
355 if (c == EOF)
356 goto err;
357 counter |= (c & 0x7f) << 21;
358
359 done:
360 /* REVISIT should we try to convert from delta values? */
361 printf("+%u%s\n", counter, label);
362 return;
363
364 err:
365 printf("(ERROR %d - %s) ", errno, strerror(errno));
366 goto done;
367 }
368
369 int main(int argc, char **argv)
370 {
371 FILE *f = stdin;
372 int c;
373
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;
383 }
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;
392 }
393 }
394
395 /* Parse data ... records have a header then data bytes.
396 * NOTE: we assume getc() deals in 8-bit bytes.
397 */
398 bool overflow = false;
399
400 while ((c = getc(f)) != EOF) {
401
402 /* Sync packet ... 7 zeroes, 0x80 */
403 if (c == 0) {
404 int i;
405
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;
412 }
413 c = fgetc(f);
414 if (c == 0x80) {
415 printf("SYNC\n");
416 continue;
417 }
418 bad_sync:
419 printf("BAD SYNC\n");
420 continue;
421 }
422
423 /* Overflow packet */
424 if (c == 0x70) {
425 /* REVISIT later, report just what overflowed!
426 * Timestamp and SWIT can happen. Non-ITM too?
427 */
428 overflow = true;
429 printf("OVERFLOW ...\n");
430 continue;
431 }
432 overflow = false;
433
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;
454 }
455
456 }
457
458 return 0;
459 }

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)