2 * This file is part of the swodec project.
4 * Copyright (C) 2014-2015 Marc Schink <swo-dev@marcschink.de>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29 #define BUFFER_SIZE 1024
31 static gboolean opt_version
;
32 static gchar
*input_file
= NULL
;
33 uint16_t packet_type_filter
;
34 static uint32_t inst_address_filter
;
35 static gboolean opt_dump_inst
;
37 static gboolean
parse_filter_option(const gchar
*option_name
,
38 const gchar
*value
, gpointer data
, GError
**error
)
52 if (value
[0] == '~') {
60 tokens
= g_strsplit(value
, ",", -1);
64 g_strstrip(tokens
[i
]);
66 if (!strlen(tokens
[i
])) {
71 if (!g_ascii_strcasecmp(tokens
[i
], "sync")) {
72 tmp
|= (1 << LIBSWO_PACKET_TYPE_SYNC
);
73 } else if (!g_ascii_strcasecmp(tokens
[i
], "of")) {
74 tmp
|= (1 << LIBSWO_PACKET_TYPE_OVERFLOW
);
75 } else if (!g_ascii_strcasecmp(tokens
[i
], "lts")) {
76 tmp
|= (1 << LIBSWO_PACKET_TYPE_LTS
);
77 } else if (!g_ascii_strcasecmp(tokens
[i
], "gts")) {
78 tmp
|= (1 << LIBSWO_PACKET_TYPE_GTS1
);
79 tmp
|= (1 << LIBSWO_PACKET_TYPE_GTS2
);
80 } else if (!g_ascii_strcasecmp(tokens
[i
], "gts1")) {
81 tmp
|= (1 << LIBSWO_PACKET_TYPE_GTS1
);
82 } else if (!g_ascii_strcasecmp(tokens
[i
], "gts2")) {
83 tmp
|= (1 << LIBSWO_PACKET_TYPE_GTS2
);
84 } else if (!g_ascii_strcasecmp(tokens
[i
], "ext")) {
85 tmp
|= (1 << LIBSWO_PACKET_TYPE_EXT
);
86 } else if (!g_ascii_strcasecmp(tokens
[i
], "inst")) {
87 tmp
|= (1 << LIBSWO_PACKET_TYPE_INST
);
88 } else if (!g_ascii_strcasecmp(tokens
[i
], "hw")) {
89 tmp
|= (1 << LIBSWO_PACKET_TYPE_HW
);
90 } else if (!g_ascii_strcasecmp(tokens
[i
], "evcnt")) {
91 tmp
|= (1 << DWT_PACKET_TYPE_EVENT_COUNTER
);
92 } else if (!g_ascii_strcasecmp(tokens
[i
], "exc")) {
93 tmp
|= (1 << DWT_PACKET_TYPE_EXCEPTION_TRACE
);
94 } else if (!g_ascii_strcasecmp(tokens
[i
], "pc")) {
95 tmp
|= (1 << DWT_PACKET_TYPE_PC_SAMPLE
);
96 } else if (!g_ascii_strcasecmp(tokens
[i
], "dtpc")) {
97 tmp
|= (1 << DWT_PACKET_TYPE_DT_PC_VALUE
);
98 } else if (!g_ascii_strcasecmp(tokens
[i
], "dtaddr")) {
99 tmp
|= (1 << DWT_PACKET_TYPE_DT_ADDR_OFFSET
);
100 } else if (!g_ascii_strcasecmp(tokens
[i
], "dtval")) {
101 tmp
|= (1 << DWT_PACKET_TYPE_DT_DATA_VALUE
);
102 } else if (!g_ascii_strcasecmp(tokens
[i
], "unknown")) {
103 tmp
|= (1 << LIBSWO_PACKET_TYPE_UNKNOWN
);
105 g_critical("Invalid packet type: %s.", tokens
[i
]);
117 * Apply the packet type filter only if at least one valid packet type
121 packet_type_filter
= tmp
;
128 static gboolean
parse_inst_filter_option(const gchar
*option_name
,
129 const gchar
*value
, gpointer data
, GError
**error
)
145 if (value
[0] == '~') {
153 tokens
= g_strsplit(value
, ",", -1);
157 g_strstrip(tokens
[i
]);
159 if (!strlen(tokens
[i
])) {
164 address
= strtoll(tokens
[i
], &endptr
, 10);
166 if (endptr
== tokens
[i
] || *endptr
!= '\0') {
167 g_critical("Invalid source address: %s.", tokens
[i
]);
172 if (address
< 0 || address
> 31) {
173 g_critical("Source address out of range: %li.",
179 tmp
|= (1 << address
);
187 * Apply the instrumentation source address filter only if at least one
188 * valid source address was specified.
191 inst_address_filter
= tmp
;
198 static GOptionEntry entries
[] = {
199 {"version", 'V', 0, G_OPTION_ARG_NONE
, &opt_version
,
200 "Show version information", NULL
},
201 {"input-file", 'i', 0, G_OPTION_ARG_FILENAME
, &input_file
,
202 "Load trace data from file", NULL
},
203 {"filter", 'f', 0, G_OPTION_ARG_CALLBACK
, &parse_filter_option
,
204 "Filter for packet types", NULL
},
205 {"filter-inst", 0, 0, G_OPTION_ARG_CALLBACK
, &parse_inst_filter_option
,
206 "Filter for instrumentation source addresses", NULL
},
207 {"dump-inst", 0, 0, G_OPTION_ARG_NONE
, &opt_dump_inst
,
208 "Dump instrumentation payload", NULL
},
209 {NULL
, 0, 0, 0, NULL
, NULL
, NULL
}
212 static void handle_hw_packet(const union libswo_packet
*packet
)
214 if (dwt_handle_packet(&packet
->hw
))
217 if (!(packet_type_filter
& (1 << LIBSWO_PACKET_TYPE_HW
)))
220 printf("Hardware source (address = %u, value = %x, size = %zu bytes)\n",
221 packet
->hw
.address
, packet
->hw
.value
, packet
->hw
.size
- 1);
224 static void handle_inst_packet(const union libswo_packet
*packet
)
226 if (!(packet_type_filter
& (1 << LIBSWO_PACKET_TYPE_INST
)))
229 if (!(inst_address_filter
& (1 << packet
->inst
.address
)))
233 fwrite(packet
->inst
.payload
, packet
->inst
.size
- 1, 1, stdout
);
238 printf("Instrumentation (address = %u, value = %x, size = %zu bytes)\n",
239 packet
->inst
.address
, packet
->inst
.value
,
240 packet
->inst
.size
- 1);
243 static void handle_overflow_packet(const union libswo_packet
*packet
)
245 if (!(packet_type_filter
& (1 << LIBSWO_PACKET_TYPE_OVERFLOW
)))
249 printf("Overflow\n");
252 static void handle_ext_packet(const union libswo_packet
*packet
)
256 if (!(packet_type_filter
& (1 << LIBSWO_PACKET_TYPE_EXT
)))
259 switch (packet
->ext
.source
) {
260 case LIBSWO_EXT_SRC_ITM
:
263 case LIBSWO_EXT_SRC_HW
:
267 g_warning("Extension packet with invalid source: %u.",
272 printf("Extension (source = %s, value = %x)\n", src
,
276 static void handle_unknown_packet(const union libswo_packet
*packet
)
278 if (!(packet_type_filter
& (1 << LIBSWO_PACKET_TYPE_UNKNOWN
)))
281 printf("Unknown data (size = %zu bytes)\n", packet
->unknown
.size
);
284 static void handle_sync_packet(const union libswo_packet
*packet
)
286 if (!(packet_type_filter
& (1 << LIBSWO_PACKET_TYPE_SYNC
)))
289 if (packet
->sync
.size
% 8)
290 printf("Synchronization (size = %zu bits)\n",
293 printf("Synchronization (size = %zu bytes)\n",
294 packet
->sync
.size
/ 8);
297 static void handle_lts_packet(const union libswo_packet
*packet
)
301 if (!(packet_type_filter
& (1 << LIBSWO_PACKET_TYPE_LTS
)))
304 switch (packet
->lts
.relation
) {
305 case LIBSWO_LTS_REL_SYNC
:
308 case LIBSWO_LTS_REL_TS
:
309 tc
= "timestamp delayed";
311 case LIBSWO_LTS_REL_SRC
:
314 case LIBSWO_LTS_REL_BOTH
:
315 tc
= "data and timestamp delayed";
318 g_warning("Local timestamp packet with invalid relation: %u.",
319 packet
->lts
.relation
);
323 printf("Local timestamp (relation = %s, value = %x)\n", tc
,
327 static void handle_gts1_packet(const union libswo_packet
*packet
)
329 if (!(packet_type_filter
& (1 << LIBSWO_PACKET_TYPE_GTS1
)))
332 printf("Global timestamp (GTS1) (wrap = %u, clkch = %u, value = %x)\n",
333 packet
->gts1
.wrap
, packet
->gts1
.clkch
, packet
->gts1
.value
);
336 static void handle_gts2_packet(const union libswo_packet
*packet
)
338 if (!(packet_type_filter
& (1 << LIBSWO_PACKET_TYPE_GTS2
)))
341 printf("Global timestamp (GTS2) (value = %x)\n", packet
->gts2
.value
);
344 static int packet_cb(struct libswo_context
*ctx
,
345 const union libswo_packet
*packet
, void *user_data
)
350 switch (packet
->type
) {
351 case LIBSWO_PACKET_TYPE_SYNC
:
352 handle_sync_packet(packet
);
354 case LIBSWO_PACKET_TYPE_INST
:
355 handle_inst_packet(packet
);
357 case LIBSWO_PACKET_TYPE_OVERFLOW
:
358 handle_overflow_packet(packet
);
360 case LIBSWO_PACKET_TYPE_EXT
:
361 handle_ext_packet(packet
);
363 case LIBSWO_PACKET_TYPE_LTS
:
364 handle_lts_packet(packet
);
366 case LIBSWO_PACKET_TYPE_GTS1
:
367 handle_gts1_packet(packet
);
369 case LIBSWO_PACKET_TYPE_GTS2
:
370 handle_gts2_packet(packet
);
372 case LIBSWO_PACKET_TYPE_HW
:
373 handle_hw_packet(packet
);
375 case LIBSWO_PACKET_TYPE_UNKNOWN
:
376 handle_unknown_packet(packet
);
379 g_warning("Invalid packet type: %u.", packet
->type
);
386 static void show_version(void)
388 printf("%s\n", PACKAGE_STRING
);
389 printf("Using libswo %s\n", libswo_version_package_get_string());
392 static int parse_options(int *argc
, char ***argv
)
395 GOptionContext
*context
;
399 context
= g_option_context_new(NULL
);
400 g_option_context_add_main_entries(context
, entries
, NULL
);
402 if (!g_option_context_parse(context
, argc
, argv
, &error
)) {
403 g_critical("%s.", error
->message
);
405 g_option_context_free(context
);
409 g_option_context_free(context
);
414 static void log_handler(const gchar
*domain
, GLogLevelFlags level
,
415 const gchar
*message
, gpointer user_data
)
421 fprintf(stderr
, "%s\n", message
);
425 int main(int argc
, char **argv
)
428 struct libswo_context
*ctx
;
429 uint8_t buffer
[BUFFER_SIZE
];
435 g_log_set_default_handler(&log_handler
, NULL
);
438 opt_dump_inst
= FALSE
;
440 /* Disable packet filtering for all packet types by default. */
441 packet_type_filter
= (1 << LIBSWO_PACKET_TYPE_SYNC
) | \
442 (1 << LIBSWO_PACKET_TYPE_OVERFLOW
) | \
443 (1 << LIBSWO_PACKET_TYPE_LTS
) | \
444 (1 << LIBSWO_PACKET_TYPE_GTS1
) | \
445 (1 << LIBSWO_PACKET_TYPE_GTS2
) | \
446 (1 << LIBSWO_PACKET_TYPE_EXT
) | \
447 (1 << LIBSWO_PACKET_TYPE_INST
) | \
448 (1 << LIBSWO_PACKET_TYPE_HW
) | \
449 (1 << LIBSWO_PACKET_TYPE_UNKNOWN
) | \
450 (1 << DWT_PACKET_TYPE_EVENT_COUNTER
) | \
451 (1 << DWT_PACKET_TYPE_EXCEPTION_TRACE
) | \
452 (1 << DWT_PACKET_TYPE_PC_SAMPLE
) | \
453 (1 << DWT_PACKET_TYPE_DT_PC_VALUE
) | \
454 (1 << DWT_PACKET_TYPE_DT_ADDR_OFFSET
) | \
455 (1 << DWT_PACKET_TYPE_DT_DATA_VALUE
);
457 /* Disable instrumentation source address filtering by default. */
458 inst_address_filter
= 0xffffffff;
460 if (!parse_options(&argc
, &argv
))
469 packet_type_filter
= (1 << LIBSWO_PACKET_TYPE_INST
);
474 input
= g_io_channel_new_file(input_file
, "r", &error
);
477 g_critical("%s: %s.", input_file
, error
->message
);
485 input
= g_io_channel_unix_new(STDIN_FILENO
);
488 /* Set encoding to binary (default is UTF-8). */
489 iostat
= g_io_channel_set_encoding(input
, NULL
, &error
);
491 if (iostat
!= G_IO_STATUS_NORMAL
) {
492 g_critical("%s.", error
->message
);
494 g_io_channel_unref(input
);
498 g_io_channel_set_buffered(input
, FALSE
);
500 ret
= libswo_init(&ctx
, NULL
, BUFFER_SIZE
* 2);
502 if (ret
!= LIBSWO_OK
) {
503 g_critical("libswo_init() failed: %s.",
504 libswo_strerror_name(ret
));
505 g_io_channel_unref(input
);
509 ret
= libswo_set_callback(ctx
, &packet_cb
, NULL
);
511 if (ret
!= LIBSWO_OK
) {
512 g_critical("libswo_set_callback() failed: %s.",
513 libswo_strerror_name(ret
));
514 g_io_channel_unref(input
);
520 iostat
= g_io_channel_read_chars(input
, (gchar
*)buffer
,
521 BUFFER_SIZE
, &num
, &error
);
523 if (iostat
== G_IO_STATUS_ERROR
)
526 ret
= libswo_feed(ctx
, buffer
, num
);
528 if (ret
!= LIBSWO_OK
) {
529 g_critical("libswo_feed() failed: %s.",
530 libswo_strerror_name(ret
));
531 g_io_channel_unref(input
);
536 ret
= libswo_decode(ctx
, 0);
538 if (ret
!= LIBSWO_OK
) {
539 g_critical("libswo_decode() failed: %s.",
540 libswo_strerror_name(ret
));
541 g_io_channel_unref(input
);
546 if (iostat
== G_IO_STATUS_EOF
)
550 if (iostat
== G_IO_STATUS_ERROR
) {
551 g_critical("%s.", error
->message
);
553 g_io_channel_unref(input
);
558 ret
= libswo_decode(ctx
, LIBSWO_DF_EOS
);
560 if (ret
!= LIBSWO_OK
) {
561 g_critical("libswo_decode() failed: %s.",
562 libswo_strerror_name(ret
));
563 g_io_channel_unref(input
);
568 g_io_channel_unref(input
);