/* Copyright (C) 2011 Jiri Olsa This file is part of the latrace. The latrace is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. The latrace is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the latrace (file COPYING). If not, see . */ %name-prefix "lt_config_" %{ #include #include #include #include "config.h" #include "lib-include.h" struct lt_include *lt_config_sinc; static struct lt_config_app *scfg; int lt_config_lex(void); void lt_config_error(const char *m); #define ABORT(fmt, args...) \ do { \ char ebuf[1024]; \ sprintf(ebuf, fmt, ## args); \ lt_config_error(ebuf); \ YYERROR; \ } while(0) static LT_LIST_HEAD(opt_list); static struct lt_error_app error_app; static struct lt_error_app_run *error_app_run; static struct lt_error_app_go *error_app_go; static struct lt_error_app_return *error_app_return; #define OPTION_ADD(idx, sval, nval) \ do { \ struct lt_config_opt *opt; \ opt = lt_config_opt_new(scfg, idx, sval, nval); \ if (!opt) \ ABORT("failed to process option\n"); \ lt_list_add_tail(&opt->list, &opt_list); \ } while(0) static struct lt_list_head ln_names; %} %token INCLUDE NAME BOOL VALUE END %token OPTIONS %token OPT_HEADERS OPT_INDENT_SYM OPT_PIPE %token OPT_TIMESTAMP OPT_FRAMESIZE OPT_FRAMESIZE_CHECK %token OPT_HIDE_TID OPT_FOLLOW_FORK OPT_FOLLOW_EXEC %token OPT_DEMANGLE OPT_BRACES OPT_ENABLE_ARGS %token OPT_DETAIL_ARGS OPT_OUTPUT_TTY %token OPT_LIBS OPT_LIBS_TO OPT_LIBS_FROM %token OPT_SYM OPT_SYM_OMIT OPT_SYM_BELOW OPT_SYM_NOEXIT %token OPT_ARGS_STRING_POINTER_LENGTH %token ERROR %token ERR_DO ERR_DIR ERR_RUN ERR_GO ERR_RETURN ERR_N %token ERR_PROG ERR_ARGS ERR_FILTER ERR_SEQ ERR_START %token ERR_SIGSEGV ERR_AUTO ERR_REPLAY ERR_KEEP %token ERR_TYPE %union { char *s; unsigned long l; } %type NAME %type BOOL %type VALUE %% entry: entry include | entry options | entry errors | entry END { if (lt_inc_close(scfg->sh, lt_config_sinc)) return 0; } | /* left blank intentionally */ include: INCLUDE '"' NAME '"' { if (lt_inc_open(scfg->sh, lt_config_sinc, $3)) ABORT("failed to process include"); } options: OPTIONS '{' OPTIONS_DEF '}' { struct lt_config_opt *opt, *opth; if (lt_config_opt_process(scfg, &opt_list)) ABORT("failed to process options"); lt_list_for_each_entry_safe(opt, opth, &opt_list, list) { lt_list_del(&opt->list); free(opt); } } OPTIONS_DEF: OPTIONS_DEF OPT_HEADERS '=' '"' NAME '"' { OPTION_ADD(LT_OPT_HEADERS, $5, -1); } | OPTIONS_DEF OPT_INDENT_SYM '=' VALUE { OPTION_ADD(LT_OPT_INDENT_SYM, NULL, $4); } | OPTIONS_DEF OPT_PIPE '=' BOOL { OPTION_ADD(LT_OPT_PIPE, $4, -1); } | OPTIONS_DEF OPT_TIMESTAMP '=' BOOL { OPTION_ADD(LT_OPT_TIMESTAMP, $4, -1); } | OPTIONS_DEF OPT_FRAMESIZE '=' VALUE { OPTION_ADD(LT_OPT_FRAMESIZE, NULL, $4); } | OPTIONS_DEF OPT_FRAMESIZE_CHECK '=' BOOL { OPTION_ADD(LT_OPT_FRAMESIZE_CHECK, $4, -1); } | OPTIONS_DEF OPT_HIDE_TID '=' BOOL { OPTION_ADD(LT_OPT_HIDE_TID, $4, -1); } | OPTIONS_DEF OPT_FOLLOW_FORK '=' BOOL { OPTION_ADD(LT_OPT_FOLLOW_FORK, $4, -1); } | OPTIONS_DEF OPT_FOLLOW_EXEC '=' BOOL { OPTION_ADD(LT_OPT_FOLLOW_EXEC, $4, -1); } | OPTIONS_DEF OPT_DEMANGLE '=' BOOL { OPTION_ADD(LT_OPT_DEMANGLE, $4, -1); } | OPTIONS_DEF OPT_BRACES '=' BOOL { OPTION_ADD(LT_OPT_BRACES, $4, -1); } | OPTIONS_DEF OPT_ENABLE_ARGS '=' BOOL { OPTION_ADD(LT_OPT_ENABLE_ARGS, $4, -1); } | OPTIONS_DEF OPT_DETAIL_ARGS '=' BOOL { OPTION_ADD(LT_OPT_DETAIL_ARGS, $4, -1); } | OPTIONS_DEF OPT_OUTPUT_TTY '=' '"' NAME '"' { OPTION_ADD(LT_OPT_OUTPUT_TTY, $5, -1); } | OPTIONS_DEF OPT_LIBS '=' list_names_comma { char libs[LT_LIBS_MAXSIZE]; if (lt_config_ln_fill_buf(&ln_names, libs, LT_LIBS_MAXSIZE)) ABORT("failed to process libs option"); OPTION_ADD(LT_OPT_LIBS, libs, -1); } | OPTIONS_DEF OPT_LIBS_TO '=' list_names_comma { char libs_to[LT_LIBS_MAXSIZE]; if (lt_config_ln_fill_buf(&ln_names, libs_to, LT_LIBS_MAXSIZE)) ABORT("failed to process libs_to option"); OPTION_ADD(LT_OPT_LIBS_TO, libs_to, -1); } | OPTIONS_DEF OPT_LIBS_FROM '=' list_names_comma { char libs_from[LT_LIBS_MAXSIZE]; if (lt_config_ln_fill_buf(&ln_names, libs_from, LT_LIBS_MAXSIZE)) ABORT("failed to process libs_from option"); OPTION_ADD(LT_OPT_LIBS_FROM, libs_from, -1); } | OPTIONS_DEF OPT_SYM '=' list_names_comma { char sym[LT_LIBS_MAXSIZE]; if (lt_config_ln_fill_buf(&ln_names, sym, LT_LIBS_MAXSIZE)) ABORT("failed to process sym option"); OPTION_ADD(LT_OPT_SYM, sym, -1); } | OPTIONS_DEF OPT_SYM_OMIT '=' list_names_comma { char sym_omit[LT_SYMBOLS_MAXSIZE]; if (lt_config_ln_fill_buf(&ln_names, sym_omit, LT_SYMBOLS_MAXSIZE)) ABORT("failed to process sym_omit option"); OPTION_ADD(LT_OPT_SYM_OMIT, sym_omit, -1); } | OPTIONS_DEF OPT_SYM_BELOW '=' list_names_comma { char sym_below[LT_SYMBOLS_MAXSIZE]; if (lt_config_ln_fill_buf(&ln_names, sym_below, LT_SYMBOLS_MAXSIZE)) ABORT("failed to process sym_below option"); OPTION_ADD(LT_OPT_SYM_BELOW, sym_below, -1); } | OPTIONS_DEF OPT_SYM_NOEXIT '=' list_names_comma { char sym_noexit[LT_SYMBOLS_MAXSIZE]; if (lt_config_ln_fill_buf(&ln_names, sym_noexit, LT_SYMBOLS_MAXSIZE)) ABORT("failed to process sym_below option"); OPTION_ADD(LT_OPT_SYM_NOEXIT, sym_noexit, -1); } | OPTIONS_DEF OPT_ARGS_STRING_POINTER_LENGTH '=' BOOL { OPTION_ADD(LT_OPT_ARGS_STRING_POINTER_LENGTH, $4, -1); } | /* left blank intentionally */ list_names_comma: list_names_comma ',' NAME { if (lt_config_ln_add(&ln_names, $3, 0, LT_CONFIG_LN_NAME)) ABORT("failed to add list name"); } | NAME { if (lt_config_ln_add(&ln_names, $1, 0, LT_CONFIG_LN_NAME)) ABORT("failed to add list name"); } list_values_comma: list_values_comma ',' VALUE { if (lt_config_ln_add(&ln_names, NULL, $3, LT_CONFIG_LN_VALUE)) ABORT("failed to add list name"); } | VALUE { if (lt_config_ln_add(&ln_names, NULL, $1, LT_CONFIG_LN_VALUE)) ABORT("failed to add list name"); } errors: ERROR NAME '{' error_def '}' { error_app.name = strdup($2); if (lt_error_app(scfg, &error_app)) ABORT("failed to add error"); lt_error_app_init(&error_app); } error_def: error_def error_run { lt_list_add_tail(&error_app_run->list_app, &error_app.head_run); error_app_run = NULL; } | error_def error_go { lt_list_add_tail(&error_app_go->list, &error_app.head_go); error_app_go = NULL; } | error_def error_return { lt_list_add_tail(&error_app_return->list_app, &error_app.head_return); error_app_return = NULL; } | error_def ERR_DIR NAME { error_app.dir = strdup($3); error_app.no_storage = 0; } | error_def ERR_PROG NAME { if (error_app.prog) ABORT("only one PROG clause allowed"); error_app.prog = strdup($3); } | /* left blank intentionally */ error_return: ERR_RETURN NAME '{' error_return_def '}' { error_app_return->name = strdup($2); } error_return_def: error_return_def NAME '=' list_values_comma { if (lt_error_return_ass(scfg, &error_app_return, $2, &ln_names, 0, 0)) ABORT("failed to add symbol to return definition"); } | error_return_def NAME '=' ERR_KEEP { if (lt_error_return_ass(scfg, &error_app_return, $2, NULL, 0, 1)) ABORT("failed to add symbol to return definition"); } | error_return_def NAME '=' list_values_comma ERR_SIGSEGV { if (lt_error_return_ass(scfg, &error_app_return, $2, &ln_names, 1, 0)) ABORT("failed to add symbol to return definition"); } | error_return_def ERR_FILTER ERR_SEQ { if (lt_error_return_filter(scfg, &error_app_return, LT_ERROR_FILTER_TYPE_SEQ, NULL)) ABORT("failed to add filter to return definition"); } | /* left blank intentionally */ error_run: ERR_RUN NAME '{' error_run_def '}' { error_app_run->name = strdup($2); } error_run_def: error_run_def ERR_ARGS list_names_comma { if (lt_error_run_args(scfg, &error_app_run, &ln_names)) ABORT("failed to add run"); } | error_run_def ERR_RETURN list_names_comma { if (lt_error_run_return(scfg, &error_app_run, &error_app, &ln_names)) ABORT("failed to add run"); } | error_run_def ERR_START ERR_N '=' VALUE { error_app_run->start.n = $5; } | error_run_def ERR_TYPE ERR_SEQ { if (lt_error_run_type(scfg, &error_app_run, LT_ERROR_RUN_TYPE_SEQ)) ABORT("failed to add run"); } | error_run_def ERR_TYPE ERR_AUTO { if (lt_error_run_type(scfg, &error_app_run, LT_ERROR_RUN_TYPE_AUTO)) ABORT("failed to add run"); } | error_run_def ERR_TYPE ERR_REPLAY { if (lt_error_run_type(scfg, &error_app_run, LT_ERROR_RUN_TYPE_REPLAY)) ABORT("failed to add run"); } | error_go: ERR_GO NAME list_names_comma { if (lt_error_go(scfg, &error_app_go, &error_app, strdup($2), &ln_names)) ABORT("failed to add go"); } %% int lt_config_parse_init(struct lt_config_app *cfg, struct lt_include *inc) { scfg = cfg; lt_config_sinc = inc; lt_init_list_head(&ln_names); lt_error_app_init(&error_app); error_app_run = NULL; error_app_go = NULL; return 0; }