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/>.
26 #include <libswo/libswo.h>
30 #define BUFFER_SIZE 1024
32 static gboolean opt_version
;
33 static gchar
*input_file
= NULL
;
34 static uint16_t packet_type_filter
;
35 static uint32_t inst_address_filter
;
36 static gboolean opt_dump_inst
;
37 static gboolean opt_decode_dwt
;
39 void dwt_handle_packet(const struct libswo_packet_hw
*packet
);
41 static gboolean
parse_filter_option(const gchar
*option_name
,
42 const gchar
*value
, gpointer data
, GError
**error
)
56 if (value
[0] == '~') {
64 tokens
= g_strsplit(value
, ",", -1);
68 g_strstrip(tokens
[i
]);
70 if (!strlen(tokens
[i
])) {
75 if (!g_ascii_strcasecmp(tokens
[i
], "sync")) {
76 tmp
|= (1 << LIBSWO_PACKET_TYPE_SYNC
);
77 } else if (!g_ascii_strcasecmp(tokens
[i
], "of")) {
78 tmp
|= (1 << LIBSWO_PACKET_TYPE_OVERFLOW
);
79 } else if (!g_ascii_strcasecmp(tokens
[i
], "lts")) {
80 tmp
|= (1 << LIBSWO_PACKET_TYPE_LTS
);
81 } else if (!g_ascii_strcasecmp(tokens
[i
], "gts")) {
82 tmp
|= (1 << LIBSWO_PACKET_TYPE_GTS1
);
83 tmp
|= (1 << LIBSWO_PACKET_TYPE_GTS2
);
84 } else if (!g_ascii_strcasecmp(tokens
[i
], "gts1")) {
85 tmp
|= (1 << LIBSWO_PACKET_TYPE_GTS1
);
86 } else if (!g_ascii_strcasecmp(tokens
[i
], "gts2")) {
87 tmp
|= (1 << LIBSWO_PACKET_TYPE_GTS2
);
88 } else if (!g_ascii_strcasecmp(tokens
[i
], "ext")) {
89 tmp
|= (1 << LIBSWO_PACKET_TYPE_EXT
);
90 } else if (!g_ascii_strcasecmp(tokens
[i
], "inst")) {
91 tmp
|= (1 << LIBSWO_PACKET_TYPE_INST
);
92 } else if (!g_ascii_strcasecmp(tokens
[i
], "hw")) {
93 tmp
|= (1 << LIBSWO_PACKET_TYPE_HW
);
94 } else if (!g_ascii_strcasecmp(tokens
[i
], "unknown")) {
95 tmp
|= (1 << LIBSWO_PACKET_TYPE_UNKNOWN
);
97 g_critical("Invalid packet type: %s.", tokens
[i
]);
109 * Apply the packet type filter only if at least one valid packet type
113 packet_type_filter
= tmp
;
120 static gboolean
parse_inst_filter_option(const gchar
*option_name
,
121 const gchar
*value
, gpointer data
, GError
**error
)
137 if (value
[0] == '~') {
145 tokens
= g_strsplit(value
, ",", -1);
149 g_strstrip(tokens
[i
]);
151 if (!strlen(tokens
[i
])) {
156 address
= strtoll(tokens
[i
], &endptr
, 10);
158 if (endptr
== tokens
[i
] || *endptr
!= '\0') {
159 g_critical("Invalid source address: %s.", tokens
[i
]);
164 if (address
< 0 || address
> 31) {
165 g_critical("Source address out of range: %li.",
171 tmp
|= (1 << address
);
179 * Apply the instrumentation source address filter only if at least one
180 * valid source address was specified.
183 inst_address_filter
= tmp
;
190 static GOptionEntry entries
[] = {
191 {"version", 'V', 0, G_OPTION_ARG_NONE
, &opt_version
,
192 "Show version information", NULL
},
193 {"input-file", 'i', 0, G_OPTION_ARG_FILENAME
, &input_file
,
194 "Load trace data from file", NULL
},
195 {"filter", 'f', 0, G_OPTION_ARG_CALLBACK
, &parse_filter_option
,
196 "Filter for packet types", NULL
},
197 {"filter-inst", 0, 0, G_OPTION_ARG_CALLBACK
, &parse_inst_filter_option
,
198 "Filter for instrumentation source addresses", NULL
},
199 {"dump-inst", 0, 0, G_OPTION_ARG_NONE
, &opt_dump_inst
,
200 "Dump instrumentation payload", NULL
},
201 {"dwt", 0, 0, G_OPTION_ARG_NONE
, &opt_decode_dwt
,
202 "Enable DWT decoder", NULL
},
203 {NULL
, 0, 0, 0, NULL
, NULL
, NULL
}
206 static void handle_hw_packet(const union libswo_packet
*packet
)
208 if (!(packet_type_filter
& (1 << LIBSWO_PACKET_TYPE_HW
)))
211 if (opt_decode_dwt
) {
212 dwt_handle_packet(&packet
->hw
);
216 printf("Hardware source (address = %u, value = %x, size = %zu bytes)\n",
217 packet
->hw
.address
, packet
->hw
.value
, packet
->hw
.size
- 1);
220 static void handle_inst_packet(const union libswo_packet
*packet
)
222 if (!(packet_type_filter
& (1 << LIBSWO_PACKET_TYPE_INST
)))
225 if (!(inst_address_filter
& (1 << packet
->inst
.address
)))
229 fwrite(packet
->inst
.payload
, packet
->inst
.size
- 1, 1, stdout
);
234 printf("Instrumentation (address = %u, value = %x, size = %zu bytes)\n",
235 packet
->inst
.address
, packet
->inst
.value
,
236 packet
->inst
.size
- 1);
239 static void handle_overflow_packet(const union libswo_packet
*packet
)
241 if (!(packet_type_filter
& (1 << LIBSWO_PACKET_TYPE_OVERFLOW
)))
245 printf("Overflow\n");
248 static void handle_ext_packet(const union libswo_packet
*packet
)
252 if (!(packet_type_filter
& (1 << LIBSWO_PACKET_TYPE_EXT
)))
255 switch (packet
->ext
.source
) {
256 case LIBSWO_EXT_SRC_ITM
:
259 case LIBSWO_EXT_SRC_HW
:
263 g_warning("Extension packet with invalid source: %u.",
268 printf("Extension (source = %s, value = %x)\n", src
,
272 static void handle_unknown_packet(const union libswo_packet
*packet
)
274 if (!(packet_type_filter
& (1 << LIBSWO_PACKET_TYPE_UNKNOWN
)))
277 printf("Unknown data (size = %zu bytes)\n", packet
->unknown
.size
);
280 static void handle_sync_packet(const union libswo_packet
*packet
)
282 if (!(packet_type_filter
& (1 << LIBSWO_PACKET_TYPE_SYNC
)))
285 if (packet
->sync
.size
% 8)
286 printf("Synchronization (size = %zu bits)\n",
289 printf("Synchronization (size = %zu bytes)\n",
290 packet
->sync
.size
/ 8);
293 static void handle_lts_packet(const union libswo_packet
*packet
)
297 if (!(packet_type_filter
& (1 << LIBSWO_PACKET_TYPE_LTS
)))
300 switch (packet
->lts
.relation
) {
301 case LIBSWO_LTS_REL_SYNC
:
304 case LIBSWO_LTS_REL_TS
:
305 tc
= "timestamp delayed";
307 case LIBSWO_LTS_REL_SRC
:
310 case LIBSWO_LTS_REL_BOTH
:
311 tc
= "data and timestamp delayed";
314 g_warning("Local timestamp packet with invalid relation: %u.",
315 packet
->lts
.relation
);
319 printf("Local timestamp (relation = %s, value = %x)\n", tc
,
323 static void handle_gts1_packet(const union libswo_packet
*packet
)
325 if (!(packet_type_filter
& (1 << LIBSWO_PACKET_TYPE_GTS1
)))
328 printf("Global timestamp (GTS1) (wrap = %u, clkch = %u, value = %x)\n",
329 packet
->gts1
.wrap
, packet
->gts1
.clkch
, packet
->gts1
.value
);
332 static void handle_gts2_packet(const union libswo_packet
*packet
)
334 if (!(packet_type_filter
& (1 << LIBSWO_PACKET_TYPE_GTS2
)))
337 printf("Global timestamp (GTS2) (value = %x)\n", packet
->gts2
.value
);
340 static int packet_cb(struct libswo_context
*ctx
,
341 const union libswo_packet
*packet
, void *user_data
)
346 switch (packet
->type
) {
347 case LIBSWO_PACKET_TYPE_SYNC
:
348 handle_sync_packet(packet
);
350 case LIBSWO_PACKET_TYPE_INST
:
351 handle_inst_packet(packet
);
353 case LIBSWO_PACKET_TYPE_OVERFLOW
:
354 handle_overflow_packet(packet
);
356 case LIBSWO_PACKET_TYPE_EXT
:
357 handle_ext_packet(packet
);
359 case LIBSWO_PACKET_TYPE_LTS
:
360 handle_lts_packet(packet
);
362 case LIBSWO_PACKET_TYPE_GTS1
:
363 handle_gts1_packet(packet
);
365 case LIBSWO_PACKET_TYPE_GTS2
:
366 handle_gts2_packet(packet
);
368 case LIBSWO_PACKET_TYPE_HW
:
369 handle_hw_packet(packet
);
371 case LIBSWO_PACKET_TYPE_UNKNOWN
:
372 handle_unknown_packet(packet
);
375 g_warning("Invalid packet type: %u.", packet
->type
);
382 static void show_version(void)
384 printf("%s\n", PACKAGE_STRING
);
385 printf("Using libswo %s\n", libswo_version_package_get_string());
388 static int parse_options(int *argc
, char ***argv
)
391 GOptionContext
*context
;
395 context
= g_option_context_new(NULL
);
396 g_option_context_add_main_entries(context
, entries
, NULL
);
398 if (!g_option_context_parse(context
, argc
, argv
, &error
)) {
399 g_critical("%s.", error
->message
);
401 g_option_context_free(context
);
405 g_option_context_free(context
);
410 void log_handler(const gchar
*domain
, GLogLevelFlags level
,
411 const gchar
*message
, gpointer user_data
)
417 fprintf(stderr
, "%s\n", message
);
421 int main(int argc
, char **argv
)
424 struct libswo_context
*ctx
;
425 uint8_t buffer
[BUFFER_SIZE
];
431 g_log_set_default_handler(&log_handler
, NULL
);
434 opt_dump_inst
= FALSE
;
435 opt_decode_dwt
= FALSE
;
437 /* Disable packet filtering for all packet types by default. */
438 packet_type_filter
= (1 << LIBSWO_PACKET_TYPE_SYNC
) | \
439 (1 << LIBSWO_PACKET_TYPE_OVERFLOW
) | \
440 (1 << LIBSWO_PACKET_TYPE_LTS
) | \
441 (1 << LIBSWO_PACKET_TYPE_GTS1
) | \
442 (1 << LIBSWO_PACKET_TYPE_GTS2
) | \
443 (1 << LIBSWO_PACKET_TYPE_EXT
) | \
444 (1 << LIBSWO_PACKET_TYPE_INST
) | \
445 (1 << LIBSWO_PACKET_TYPE_HW
) | \
446 (1 << LIBSWO_PACKET_TYPE_UNKNOWN
);
448 /* Disable instrumentation source address filtering by default. */
449 inst_address_filter
= 0xffffffff;
451 if (!parse_options(&argc
, &argv
))
460 packet_type_filter
= (1 << LIBSWO_PACKET_TYPE_INST
);
465 input
= g_io_channel_new_file(input_file
, "r", &error
);
468 g_critical("%s: %s.", input_file
, error
->message
);
476 input
= g_io_channel_unix_new(STDIN_FILENO
);
479 /* Set encoding to binary (default is UTF-8). */
480 iostat
= g_io_channel_set_encoding(input
, NULL
, &error
);
482 if (iostat
!= G_IO_STATUS_NORMAL
) {
483 g_critical("%s.", error
->message
);
485 g_io_channel_unref(input
);
489 g_io_channel_set_buffered(input
, FALSE
);
491 ret
= libswo_init(&ctx
, NULL
, BUFFER_SIZE
* 2);
493 if (ret
!= LIBSWO_OK
) {
494 g_critical("libswo_init() failed: %s.",
495 libswo_strerror_name(ret
));
496 g_io_channel_unref(input
);
500 ret
= libswo_set_callback(ctx
, &packet_cb
, NULL
);
502 if (ret
!= LIBSWO_OK
) {
503 g_critical("libswo_set_callback() failed: %s.",
504 libswo_strerror_name(ret
));
505 g_io_channel_unref(input
);
511 iostat
= g_io_channel_read_chars(input
, (gchar
*)buffer
,
512 BUFFER_SIZE
, &num
, &error
);
514 if (iostat
== G_IO_STATUS_ERROR
)
517 ret
= libswo_feed(ctx
, buffer
, num
);
519 if (ret
!= LIBSWO_OK
) {
520 g_critical("libswo_feed() failed: %s.",
521 libswo_strerror_name(ret
));
522 g_io_channel_unref(input
);
527 ret
= libswo_decode(ctx
, 0, 0);
529 if (ret
< LIBSWO_OK
) {
530 g_critical("libswo_decode() failed: %s.",
531 libswo_strerror_name(ret
));
532 g_io_channel_unref(input
);
537 if (iostat
== G_IO_STATUS_EOF
)
541 if (iostat
== G_IO_STATUS_ERROR
) {
542 g_critical("%s.", error
->message
);
544 g_io_channel_unref(input
);
549 ret
= libswo_decode(ctx
, 0, LIBSWO_DF_EOS
);
551 if (ret
< LIBSWO_OK
) {
552 g_critical("libswo_decode() failed: %s.",
553 libswo_strerror_name(ret
));
554 g_io_channel_unref(input
);
559 g_io_channel_unref(input
);