tcl: Add default hooks for STM32F3x
[fw/openocd] / 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
109         *value = 0;
110
111         switch (c & 3) {
112         case 3:
113                 size = 4;
114                 break;
115         case 2:
116                 size = 2;
117                 break;
118         case 1:
119                 size = 1;
120                 break;
121         default:
122                 printf("INVALID SIZE\n");
123                 return false;
124         }
125
126         memset(buf, 0, sizeof buf);
127         if (fread(buf, 1, size, f) != size)
128                 goto err;
129
130         *value =  (buf[3] << 24)
131                 + (buf[2] << 16)
132                 + (buf[1] << 8)
133                 + (buf[0] << 0);
134         return true;
135
136 err:
137         printf("(ERROR %d - %s)\n", errno, strerror(errno));
138         return false;
139 }
140
141 static void show_hard(FILE *f, int c)
142 {
143         unsigned type = c >> 3;
144         unsigned value;
145         char *label;
146
147         printf("DWT - ");
148
149         if (!read_varlen(f, c, &value))
150                 return;
151         printf("%#x", value);
152
153         switch (type) {
154         case 0:                         /* event counter wrapping */
155                 printf("overflow %s%s%s%s%s%s",
156                         (value & (1 << 5)) ? "cyc " : "",
157                         (value & (1 << 4)) ? "fold " : "",
158                         (value & (1 << 3)) ? "lsu " : "",
159                         (value & (1 << 2)) ? "slp " : "",
160                         (value & (1 << 1)) ? "exc " : "",
161                         (value & (1 << 0)) ? "cpi " : "");
162                 break;
163         case 1:                         /* exception tracing */
164                 switch (value >> 12) {
165                 case 1:
166                         label = "entry to";
167                         break;
168                 case 2:
169                         label = "exit from";
170                         break;
171                 case 3:
172                         label = "return to";
173                         break;
174                 default:
175                         label = "?";
176                         break;
177                 }
178                 printf("%s exception %d", label, value & 0x1ff);
179                 break;
180         case 2:                         /* PC sampling */
181                 if (c == 0x15)
182                         printf("PC - sleep");
183                 else
184                         printf("PC - %#08x", value);
185                 break;
186         case 8:                         /* data tracing, pc value */
187         case 10:
188         case 12:
189         case 14:
190                 printf("Data trace %d, PC %#08x", (c >> 4) & 3, value);
191                 /* optionally followed by data value */
192                 break;
193         case 9:                         /* data tracing, address offset */
194         case 11:
195         case 13:
196         case 15:
197                 printf("Data trace %d, address offset %#04x",
198                                 (c >> 4) & 3, value);
199                 /* always followed by data value */
200                 break;
201         case 16 ... 23:                 /* data tracing, data value */
202                 printf("Data trace %d, ", (c >> 4) & 3);
203                 label = (c & 0x8) ? "write" : "read";
204                 switch (c & 3) {
205                 case 3:
206                         printf("word %s, value %#08x", label, value);
207                         break;
208                 case 2:
209                         printf("halfword %s, value %#04x", label, value);
210                         break;
211                 case 1:
212                         printf("byte %s, value %#02x", label, value);
213                         break;
214                 }
215                 break;
216         default:
217                 printf("UNDEFINED, rawtype: %x", type);
218                 break;
219         }
220
221         printf("\n");
222         return;
223 }
224
225 /*
226  * Table of SWIT (SoftWare InstrumentTation) message dump formats, for
227  * ITM port 0..31 application data.
228  *
229  * Eventually this should be customizable; all usage is application defined.
230  *
231  * REVISIT there can be up to 256 trace ports, via "ITM Extension" packets
232  */
233 struct {
234         int port;
235         void (*show)(int port, unsigned data);
236 } format[] = {
237         { .port = 31,  .show = show_task, },
238 };
239
240 static void show_swit(FILE *f, int c)
241 {
242         unsigned port = c >> 3;
243         unsigned value = 0;
244         unsigned i;
245
246         printf("SWIT %u - ", port);
247
248         if (!read_varlen(f, c, &value))
249                 return;
250         printf("%#08x", value);
251
252         for (i = 0; i < sizeof(format) / sizeof(format[0]); i++) {
253                 if (format[i].port == port) {
254                         printf(", ");
255                         format[i].show(port, value);
256                         break;
257                 }
258         }
259
260         printf("\n");
261         return;
262 }
263
264 static void show_timestamp(FILE *f, int c)
265 {
266         unsigned counter = 0;
267         char *label = "";
268         bool delayed = false;
269
270         printf("TIMESTAMP - ");
271
272         /* Format 2: header only */
273         if (!(c & 0x80)) {
274                 switch (c) {
275                 case 0:         /* sync packet -- coding error! */
276                 case 0x70:      /* overflow -- ditto! */
277                         printf("ERROR - %#02x\n", c);
278                         break;
279                 default:
280                         /* synchronous to ITM */
281                         counter = c >> 4;
282                         goto done;
283                 }
284                 return;
285         }
286
287         /* Format 1:  one to four bytes of data too */
288         switch (c) {
289         default:
290                 label = ", reserved control\n";
291                 break;
292         case 0xc:
293                 /* synchronous to ITM */
294                 break;
295         case 0xd:
296                 label = ", timestamp delayed";
297                 delayed = true;
298                 break;
299         case 0xe:
300                 label = ", packet delayed";
301                 delayed = true;
302                 break;
303         case 0xf:
304                 label = ", packet and timetamp delayed";
305                 delayed = true;
306                 break;
307         }
308
309         c = fgetc(f);
310         if (c == EOF)
311                 goto err;
312         counter = c & 0x7f;
313         if (!(c & 0x80))
314                 goto done;
315
316         c = fgetc(f);
317         if (c == EOF)
318                 goto err;
319         counter |= (c & 0x7f) << 7;
320         if (!(c & 0x80))
321                 goto done;
322
323         c = fgetc(f);
324         if (c == EOF)
325                 goto err;
326         counter |= (c & 0x7f) << 14;
327         if (!(c & 0x80))
328                 goto done;
329
330         c = fgetc(f);
331         if (c == EOF)
332                 goto err;
333         counter |= (c & 0x7f) << 21;
334
335 done:
336         /* REVISIT should we try to convert from delta values?  */
337         printf("+%u%s\n", counter, label);
338         return;
339
340 err:
341         printf("(ERROR %d - %s) ", errno, strerror(errno));
342         goto done;
343 }
344
345 int main(int argc, char **argv)
346 {
347         FILE *f = stdin;
348         int c;
349
350         /* parse arguments */
351         while ((c = getopt(argc, argv, "f:")) != EOF) {
352                 switch (c) {
353                 case 'f':
354                         /* e.g. from UART connected to /dev/ttyUSB0 */
355                         f = fopen(optarg, "r");
356                         if (!f) {
357                                 perror(optarg);
358                                 return 1;
359                         }
360                         break;
361                 default:
362                         fprintf(stderr, "usage: %s [-f input]",
363                                 basename(argv[0]));
364                         return 1;
365                 }
366         }
367
368         /* Parse data ... records have a header then data bytes.
369          * NOTE: we assume getc() deals in 8-bit bytes.
370          */
371         bool overflow = false;
372
373         while ((c = getc(f)) != EOF) {
374
375                 /* Sync packet ... 7 zeroes, 0x80 */
376                 if (c == 0) {
377                         int i;
378
379                         for (i = 0; i < 6; i++) {
380                                 c = fgetc(f);
381                                 if (c == EOF)
382                                         break;
383                                 if (c != 0)
384                                         goto bad_sync;
385                         }
386                         c = fgetc(f);
387                         if (c == 0x80) {
388                                 printf("SYNC\n");
389                                 continue;
390                         }
391 bad_sync:
392                         printf("BAD SYNC\n");
393                         continue;
394                 }
395
396                 /* Overflow packet */
397                 if (c == 0x70) {
398                         /* REVISIT later, report just what overflowed!
399                          * Timestamp and SWIT can happen.  Non-ITM too?
400                          */
401                         overflow = true;
402                         printf("OVERFLOW ...\n");
403                         continue;
404                 }
405                 overflow = false;
406
407                 switch (c & 0x0f) {
408                 case 0x00:              /* Timestamp */
409                         show_timestamp(f, c);
410                         break;
411                 case 0x04:              /* "Reserved" */
412                         show_reserved(f, "RESERVED", c);
413                         break;
414                 case 0x08:              /* ITM Extension */
415                         /* FIXME someday, handle these ...  */
416                         show_reserved(f, "ITM EXT", c);
417                         break;
418                 case 0x0c:              /* DWT Extension */
419                         show_reserved(f, "DWT EXT", c);
420                         break;
421                 default:
422                         if (c & 4)
423                                 show_hard(f, c);
424                         else
425                                 show_swit(f, c);
426                         break;
427                 }
428
429         }
430
431         return 0;
432 }