]> git.sur5r.net Git - openocd/blob - contrib/itmdump.c
jlink: Use error description in log messages
[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 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 }