2 * Shows display filter byte-code, for debugging dfilter routines.
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0-or-later
12 #define WS_LOG_DOMAIN LOG_DOMAIN_MAIN
22 #include <ws_exit_codes.h>
24 #include <epan/epan.h>
25 #include <epan/timestamp.h>
26 #include <epan/prefs.h>
27 #include <epan/dfilter/dfilter.h>
28 #include <epan/dfilter/dfilter-macro.h>
31 #include <wsutil/plugins.h>
33 #include <wsutil/filesystem.h>
34 #include <wsutil/privileges.h>
35 #include <wsutil/report_message.h>
36 #include <wsutil/wslog.h>
37 #include <wsutil/ws_getopt.h>
38 #include <wsutil/utf8_entities.h>
40 #include <wiretap/wtap.h>
43 #include "wsutil/cmdarg_err.h"
44 #include "ui/failure_message.h"
45 #include "wsutil/version_info.h"
47 static int opt_verbose
;
48 static int opt_debug_level
; /* currently up to 2 */
51 static int opt_syntax_tree
;
52 static int opt_return_vals
;
54 static long opt_optimize
= 1;
55 static int opt_show_types
;
56 static int opt_dump_refs
;
57 static int opt_dump_macros
;
59 static int64_t elapsed_expand
;
60 static int64_t elapsed_compile
;
63 * Report an error in command-line arguments.
66 dftest_cmdarg_err(const char *fmt
, va_list ap
)
68 fprintf(stderr
, "dftest: ");
69 vfprintf(stderr
, fmt
, ap
);
70 fprintf(stderr
, "\n");
74 * Report additional information for an error in command-line arguments.
77 dftest_cmdarg_err_cont(const char *fmt
, va_list ap
)
79 vfprintf(stderr
, fmt
, ap
);
80 fprintf(stderr
, "\n");
84 putloc(FILE *fp
, df_loc_t loc
)
86 for (long i
= 0; i
< loc
.col_start
; i
++) {
91 for (size_t l
= loc
.col_len
; l
> 1; l
--) {
97 WS_NORETURN
static void
98 print_usage(int status
)
102 fprintf(fp
, "Usage: dftest [OPTIONS] -- EXPRESSION\n");
103 fprintf(fp
, "Options:\n");
104 fprintf(fp
, " -V, --verbose enable verbose mode\n");
105 fprintf(fp
, " -d, --debug[=N] increase or set debug level\n");
106 fprintf(fp
, " -D set maximum debug level\n");
107 fprintf(fp
, " -f, --flex enable Flex debug trace\n");
108 fprintf(fp
, " -l, --lemon enable Lemon debug trace\n");
109 fprintf(fp
, " -s, --syntax print syntax tree\n");
110 fprintf(fp
, " -m --macros print saved macros\n");
111 fprintf(fp
, " -t, --timer print elapsed compilation time\n");
112 fprintf(fp
, " -r --return-vals return field values for the tree root\n");
113 fprintf(fp
, " -0, --optimize=0 do not optimize (check syntax)\n");
114 fprintf(fp
, " --types show field value types\n");
115 /* NOTE: References are loaded during runtime and dftest only does compilation.
116 * Unless some static reference data is hard-coded at compile time during
117 * development the --refs option to dftest is useless because it will just
118 * print empty reference vectors. */
119 fprintf(fp
, " --refs dump some runtime data structures\n");
120 fprintf(fp
, " -h, --help display this help and exit\n");
121 fprintf(fp
, " -v, --version print version\n");
123 ws_log_print_usage(fp
);
128 print_syntax_tree(dfilter_t
*df
)
130 printf("Syntax tree:\n%s\n\n", dfilter_syntax_tree(df
));
136 if (dfilter_macro_table_count() == 0) {
137 printf("Macros: (empty)\n\n");
141 struct dfilter_macro_table_iter iter
;
142 const char *name
, *text
;
144 dfilter_macro_table_iter_init(&iter
);
146 while (dfilter_macro_table_iter_next(&iter
, &name
, &text
)) {
147 printf(" "UTF8_BULLET
" %s:\n", name
);
148 printf(" %s\n", text
);
154 print_warnings(dfilter_t
*df
)
157 GPtrArray
*deprecated
;
160 for (GSList
*l
= dfilter_get_warnings(df
); l
!= NULL
; l
= l
->next
) {
161 printf("\nWarning: %s.", (char *)l
->data
);
165 deprecated
= dfilter_deprecated_tokens(df
);
166 if (deprecated
&& deprecated
->len
) {
167 for (i
= 0; i
< deprecated
->len
; i
++) {
168 const char *token
= g_ptr_array_index(deprecated
, i
);
169 printf("\nWarning: Deprecated token \"%s\".", token
);
182 printf("\nElapsed: %"PRId64
" µs (%"PRId64
" µs + %"PRId64
" µs)\n",
183 elapsed_expand
+ elapsed_compile
,
189 expand_filter(const char *text
)
191 char *expanded
= NULL
;
192 df_error_t
*err
= NULL
;
195 start
= g_get_monotonic_time();
196 expanded
= dfilter_expand(text
, &err
);
197 if (expanded
== NULL
) {
198 fprintf(stderr
, "Error: %s\n", err
->msg
);
201 elapsed_expand
= g_get_monotonic_time() - start
;
206 compile_filter(const char *text
, dfilter_t
**dfp
)
208 unsigned df_flags
= 0;
210 df_error_t
*df_err
= NULL
;
213 if (opt_optimize
> 0)
214 df_flags
|= DF_OPTIMIZE
;
216 df_flags
|= DF_SAVE_TREE
;
218 df_flags
|= DF_DEBUG_FLEX
;
220 df_flags
|= DF_DEBUG_LEMON
;
222 df_flags
|= DF_RETURN_VALUES
;
224 start
= g_get_monotonic_time();
225 ok
= dfilter_compile_full(text
, dfp
, &df_err
, df_flags
, "dftest");
227 fprintf(stderr
, "Error: %s\n", df_err
->msg
);
228 if (df_err
->loc
.col_start
>= 0) {
229 fprintf(stderr
, " %s\n ", text
);
230 putloc(stderr
, df_err
->loc
);
232 df_error_free(&df_err
);
234 elapsed_compile
= g_get_monotonic_time() - start
;
239 optarg_to_digit(const char *arg
)
241 if (strlen(arg
) > 1 || !g_ascii_isdigit(*arg
)) {
242 printf("Error: \"%s\" is not a valid number 0-9\n", arg
);
243 print_usage(WS_EXIT_INVALID_OPTION
);
246 int digit
= (int)strtol(ws_optarg
, NULL
, 10);
248 printf("Error: %s\n", g_strerror(errno
));
249 print_usage(WS_EXIT_INVALID_OPTION
);
255 main(int argc
, char **argv
)
257 char *configuration_init_error
;
259 char *expanded_text
= NULL
;
260 dfilter_t
*df
= NULL
;
261 int exit_status
= EXIT_FAILURE
;
264 * Set the C-language locale to the native environment and set the
265 * code page to UTF-8 on Windows.
268 setlocale(LC_ALL
, ".UTF-8");
270 setlocale(LC_ALL
, "");
273 cmdarg_err_init(dftest_cmdarg_err
, dftest_cmdarg_err_cont
);
275 /* Initialize log handler early for startup. */
276 ws_log_init("dftest", vcmdarg_err
);
278 /* Early logging command-line initialization. */
279 ws_log_parse_args(&argc
, argv
, vcmdarg_err
, 1);
281 ws_noisy("Finished log init and parsing command line log arguments");
283 ws_init_version_info("DFTest", NULL
, NULL
);
285 const char *optstring
= "hvdDflsmrtV0";
286 static struct ws_option long_options
[] = {
287 { "help", ws_no_argument
, 0, 'h' },
288 { "version", ws_no_argument
, 0, 'v' },
289 { "debug", ws_optional_argument
, 0, 'd' },
290 { "flex", ws_no_argument
, 0, 'f' },
291 { "lemon", ws_no_argument
, 0, 'l' },
292 { "syntax", ws_no_argument
, 0, 's' },
293 { "macros", ws_no_argument
, 0, 'm' },
294 { "timer", ws_no_argument
, 0, 't' },
295 { "verbose", ws_no_argument
, 0, 'V' },
296 { "return-vals", ws_no_argument
, 0, 'r' },
297 { "optimize", ws_required_argument
, 0, 1000 },
298 { "types", ws_no_argument
, 0, 2000 },
299 { "refs", ws_no_argument
, 0, 3000 },
305 opt
= ws_getopt_long(argc
, argv
, optstring
, long_options
, NULL
);
315 opt_debug_level
= optarg_to_digit(ws_optarg
);
350 opt_optimize
= optarg_to_digit(ws_optarg
);
363 show_help_header(NULL
);
364 print_usage(EXIT_SUCCESS
);
367 print_usage(EXIT_FAILURE
);
369 ws_assert_not_reached();
373 /* Check for filter on command line. */
374 if (argv
[ws_optind
] == NULL
) {
375 /* If not printing macros we need a filter expression to compile. */
376 if (!opt_dump_macros
) {
377 printf("Error: Missing argument.\n");
378 print_usage(EXIT_FAILURE
);
382 /* Set dfilter domain logging. */
383 if (opt_debug_level
> 1) {
384 ws_log_set_noisy_filter(LOG_DOMAIN_DFILTER
);
386 else if (opt_debug_level
> 0 || opt_flex
|| opt_lemon
) {
387 /* Also enable some dfilter logs with flex/lemon traces for context. */
388 ws_log_set_debug_filter(LOG_DOMAIN_DFILTER
);
392 * Get credential information for later use.
394 init_process_policies();
397 * Attempt to get the pathname of the directory containing the
400 configuration_init_error
= configuration_init(argv
[0], NULL
);
401 if (configuration_init_error
!= NULL
) {
402 fprintf(stderr
, "Error: Can't get pathname of directory containing "
403 "the dftest program: %s.\n",
404 configuration_init_error
);
405 g_free(configuration_init_error
);
408 static const struct report_message_routines dftest_report_routines
= {
411 open_failure_message
,
412 read_failure_message
,
413 write_failure_message
,
414 cfile_open_failure_message
,
415 cfile_dump_open_failure_message
,
416 cfile_read_failure_message
,
417 cfile_write_failure_message
,
418 cfile_close_failure_message
421 init_report_message("dftest", &dftest_report_routines
);
423 timestamp_set_type(TS_RELATIVE
);
424 timestamp_set_seconds_type(TS_SECONDS_DEFAULT
);
427 * Libwiretap must be initialized before libwireshark is, so that
428 * dissection-time handlers for file-type-dependent blocks can
429 * register using the file type/subtype value for the file type.
433 /* Register all dissectors; we must do this before checking for the
434 "-g" flag, as the "-g" flag dumps a list of fields registered
435 by the dissectors, and we must do it before we read the preferences,
436 in case any dissectors register preferences. */
437 if (!epan_init(NULL
, NULL
, true))
440 /* Load libwireshark settings from the current profile. */
441 epan_load_settings();
443 /* notify all registered modules that have had any of their preferences
444 changed either from one of the preferences file or from the command
445 line that its preferences have changed. */
448 if (opt_dump_macros
) {
450 if (argv
[ws_optind
] == NULL
) {
451 /* No filter expression, we're done. */
456 /* Check again for filter on command line */
457 if (argv
[ws_optind
] == NULL
) {
458 printf("Error: Missing argument.\n");
459 print_usage(EXIT_FAILURE
);
462 /* This is useful to prevent confusion with option parsing.
463 * Skips printing options and argv[0]. */
465 for (int i
= ws_optind
; i
< argc
; i
++) {
466 fprintf(stderr
, "argv[%d]: %s\n", i
, argv
[i
]);
468 fprintf(stderr
, "\n");
471 /* Get filter text */
472 text
= get_args_as_string(argc
, argv
, ws_optind
);
474 printf("Filter:\n %s\n\n", text
);
477 expanded_text
= expand_filter(text
);
478 if (expanded_text
== NULL
) {
479 exit_status
= WS_EXIT_INVALID_FILTER
;
483 if (strcmp(text
, expanded_text
) != 0)
484 printf("Filter (after expansion):\n %s\n\n", expanded_text
);
487 if (!compile_filter(expanded_text
, &df
)) {
488 exit_status
= WS_EXIT_INVALID_FILTER
;
492 /* If logging is enabled add an empty line. */
493 if (opt_debug_level
> 0) {
498 printf("Filter is empty.\n");
499 exit_status
= WS_EXIT_INVALID_FILTER
;
504 print_syntax_tree(df
);
506 uint16_t dump_flags
= 0;
508 dump_flags
|= DF_DUMP_SHOW_FTYPE
;
510 dump_flags
|= DF_DUMP_REFERENCES
;
512 dfilter_dump(stdout
, df
, dump_flags
);
525 g_free(expanded_text
);