Update for libswo decoder callback API change.
[swodec.git] / src / main.c
blobf085fe696bd9180b7f21a0d5ec98dd4f6a9a1a76
1 /*
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/>.
20 #include <stdio.h>
21 #include <stdint.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include <glib.h>
26 #include <libswo/libswo.h>
28 #include "config.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)
44 gchar **tokens;
45 unsigned int i;
46 uint16_t tmp;
47 gboolean invert;
49 (void)option_name;
50 (void)data;
51 (void)error;
53 if (!strlen(value))
54 return TRUE;
56 if (value[0] == '~') {
57 value++;
58 invert = TRUE;
59 } else {
60 invert = FALSE;
63 i = 0;
64 tokens = g_strsplit(value, ",", -1);
65 tmp = 0x0000;
67 while (tokens[i]) {
68 g_strstrip(tokens[i]);
70 if (!strlen(tokens[i])) {
71 i++;
72 continue;
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);
96 } else {
97 g_critical("Invalid packet type: %s.", tokens[i]);
98 g_strfreev(tokens);
99 return FALSE;
102 i++;
105 if (invert)
106 tmp = ~tmp;
109 * Apply the packet type filter only if at least one valid packet type
110 * was specified.
112 if (tmp > 0)
113 packet_type_filter = tmp;
115 g_strfreev(tokens);
117 return TRUE;
120 static gboolean parse_inst_filter_option(const gchar *option_name,
121 const gchar *value, gpointer data, GError **error)
123 gchar **tokens;
124 unsigned int i;
125 uint32_t tmp;
126 long int address;
127 char *endptr;
128 gboolean invert;
130 (void)option_name;
131 (void)data;
132 (void)error;
134 if (!strlen(value))
135 return TRUE;
137 if (value[0] == '~') {
138 value++;
139 invert = TRUE;
140 } else {
141 invert = FALSE;
144 i = 0;
145 tokens = g_strsplit(value, ",", -1);
146 tmp = 0x00000000;
148 while (tokens[i]) {
149 g_strstrip(tokens[i]);
151 if (!strlen(tokens[i])) {
152 i++;
153 continue;
156 address = strtoll(tokens[i], &endptr, 10);
158 if (endptr == tokens[i] || *endptr != '\0') {
159 g_critical("Invalid source address: %s.", tokens[i]);
160 g_strfreev(tokens);
161 return FALSE;
164 if (address < 0 || address > 31) {
165 g_critical("Source address out of range: %li.",
166 address);
167 g_strfreev(tokens);
168 return FALSE;
171 tmp |= (1 << address);
172 i++;
175 if (invert)
176 tmp = ~tmp;
179 * Apply the instrumentation source address filter only if at least one
180 * valid source address was specified.
182 if (tmp > 0)
183 inst_address_filter = tmp;
185 g_strfreev(tokens);
187 return TRUE;
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)))
209 return;
211 if (opt_decode_dwt) {
212 dwt_handle_packet(&packet->hw);
213 return;
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)))
223 return;
225 if (!(inst_address_filter & (1 << packet->inst.address)))
226 return;
228 if (opt_dump_inst) {
229 fwrite(packet->inst.payload, packet->inst.size - 1, 1, stdout);
230 fflush(stdout);
231 return;
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)))
242 return;
244 (void)packet;
245 printf("Overflow\n");
248 static void handle_ext_packet(const union libswo_packet *packet)
250 const char *src;
252 if (!(packet_type_filter & (1 << LIBSWO_PACKET_TYPE_EXT)))
253 return;
255 switch (packet->ext.source) {
256 case LIBSWO_EXT_SRC_ITM:
257 src = "ITM";
258 break;
259 case LIBSWO_EXT_SRC_HW:
260 src = "HW";
261 break;
262 default:
263 g_warning("Extension packet with invalid source: %u.",
264 packet->ext.source);
265 return;
268 printf("Extension (source = %s, value = %x)\n", src,
269 packet->ext.value);
272 static void handle_unknown_packet(const union libswo_packet *packet)
274 if (!(packet_type_filter & (1 << LIBSWO_PACKET_TYPE_UNKNOWN)))
275 return;
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)))
283 return;
285 if (packet->sync.size % 8)
286 printf("Synchronization (size = %zu bits)\n",
287 packet->sync.size);
288 else
289 printf("Synchronization (size = %zu bytes)\n",
290 packet->sync.size / 8);
293 static void handle_lts_packet(const union libswo_packet *packet)
295 const char *tc;
297 if (!(packet_type_filter & (1 << LIBSWO_PACKET_TYPE_LTS)))
298 return;
300 switch (packet->lts.relation) {
301 case LIBSWO_LTS_REL_SYNC:
302 tc = "synchronous";
303 break;
304 case LIBSWO_LTS_REL_TS:
305 tc = "timestamp delayed";
306 break;
307 case LIBSWO_LTS_REL_SRC:
308 tc = "data delayed";
309 break;
310 case LIBSWO_LTS_REL_BOTH:
311 tc = "data and timestamp delayed";
312 break;
313 default:
314 g_warning("Local timestamp packet with invalid relation: %u.",
315 packet->lts.relation);
316 return;
319 printf("Local timestamp (relation = %s, value = %x)\n", tc,
320 packet->lts.value);
323 static void handle_gts1_packet(const union libswo_packet *packet)
325 if (!(packet_type_filter & (1 << LIBSWO_PACKET_TYPE_GTS1)))
326 return;
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)))
335 return;
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)
343 (void)ctx;
344 (void)user_data;
346 switch (packet->type) {
347 case LIBSWO_PACKET_TYPE_SYNC:
348 handle_sync_packet(packet);
349 break;
350 case LIBSWO_PACKET_TYPE_INST:
351 handle_inst_packet(packet);
352 break;
353 case LIBSWO_PACKET_TYPE_OVERFLOW:
354 handle_overflow_packet(packet);
355 break;
356 case LIBSWO_PACKET_TYPE_EXT:
357 handle_ext_packet(packet);
358 break;
359 case LIBSWO_PACKET_TYPE_LTS:
360 handle_lts_packet(packet);
361 break;
362 case LIBSWO_PACKET_TYPE_GTS1:
363 handle_gts1_packet(packet);
364 break;
365 case LIBSWO_PACKET_TYPE_GTS2:
366 handle_gts2_packet(packet);
367 break;
368 case LIBSWO_PACKET_TYPE_HW:
369 handle_hw_packet(packet);
370 break;
371 case LIBSWO_PACKET_TYPE_UNKNOWN:
372 handle_unknown_packet(packet);
373 break;
374 default:
375 g_warning("Invalid packet type: %u.", packet->type);
376 break;
379 return TRUE;
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)
390 GError *error;
391 GOptionContext *context;
393 error = NULL;
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);
400 g_error_free(error);
401 g_option_context_free(context);
402 return FALSE;
405 g_option_context_free(context);
407 return TRUE;
410 void log_handler(const gchar *domain, GLogLevelFlags level,
411 const gchar *message, gpointer user_data)
413 (void)domain;
414 (void)level;
415 (void)user_data;
417 fprintf(stderr, "%s\n", message);
418 fflush(stderr);
421 int main(int argc, char **argv)
423 int ret;
424 struct libswo_context *ctx;
425 uint8_t buffer[BUFFER_SIZE];
426 GIOChannel *input;
427 GError *error;
428 GIOStatus iostat;
429 gsize num;
431 g_log_set_default_handler(&log_handler, NULL);
433 opt_version = FALSE;
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))
452 return EXIT_FAILURE;
454 if (opt_version) {
455 show_version();
456 return EXIT_SUCCESS;
459 if (opt_dump_inst)
460 packet_type_filter = (1 << LIBSWO_PACKET_TYPE_INST);
462 error = NULL;
464 if (input_file) {
465 input = g_io_channel_new_file(input_file, "r", &error);
467 if (!input) {
468 g_critical("%s: %s.", input_file, error->message);
469 g_error_free(error);
470 g_free(input_file);
471 return EXIT_FAILURE;
474 g_free(input_file);
475 } else {
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);
484 g_error_free(error);
485 g_io_channel_unref(input);
486 return EXIT_FAILURE;
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);
497 return EXIT_FAILURE;
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);
506 libswo_exit(ctx);
507 return EXIT_FAILURE;
510 while (TRUE) {
511 iostat = g_io_channel_read_chars(input, (gchar *)buffer,
512 BUFFER_SIZE, &num, &error);
514 if (iostat == G_IO_STATUS_ERROR)
515 break;
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);
523 libswo_exit(ctx);
524 return EXIT_FAILURE;
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);
533 libswo_exit(ctx);
534 return EXIT_FAILURE;
537 if (iostat == G_IO_STATUS_EOF)
538 break;
541 if (iostat == G_IO_STATUS_ERROR) {
542 g_critical("%s.", error->message);
543 g_error_free(error);
544 g_io_channel_unref(input);
545 libswo_exit(ctx);
546 return EXIT_FAILURE;
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);
555 libswo_exit(ctx);
556 return EXIT_FAILURE;
559 g_io_channel_unref(input);
560 libswo_exit(ctx);
562 return EXIT_SUCCESS;