diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile | 13 | ||||
-rw-r--r-- | src/args-bison.y | 16 | ||||
-rw-r--r-- | src/args-flex.l | 22 | ||||
-rw-r--r-- | src/args.c | 148 | ||||
-rw-r--r-- | src/args.h | 7 | ||||
-rw-r--r-- | src/config-bison.y | 179 | ||||
-rw-r--r-- | src/config-flex.l | 119 | ||||
-rw-r--r-- | src/config.c | 264 | ||||
-rw-r--r-- | src/config.h | 27 | ||||
-rw-r--r-- | src/lib-include.c | 161 | ||||
-rw-r--r-- | src/lib-include.h | 61 | ||||
-rw-r--r-- | src/sysdeps/x86_64/args.h | 4 |
12 files changed, 849 insertions, 172 deletions
diff --git a/src/Makefile b/src/Makefile index 7263eec..dd7b56f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -29,7 +29,8 @@ AUDIT_OBJS=\ src/output.o \ src/objsearch.o \ src/stack.o \ - src/symbol.o + src/symbol.o \ + src/lib-include.o ifeq ($(CONFIG_ARCH_HAVE_ARGS),y) AUDIT_OBJS+=\ @@ -61,13 +62,17 @@ LATRACE_OBJS=\ src/stats.o \ src/fifo.o \ src/thread.o \ - src/output.o + src/output.o \ + src/config-bison.o \ + src/config-flex.o \ + src/lib-include.o OBJS+=$(LATRACE_OBJS) PROGRAMS+=$(LATRACE_BIN) CPPFLAGS+=-DCONFIG_LIBDIR=\"$(libdir)\" -CPPFLAGS+=-DLT_ARGS_DEF_DIR=\"$(confdir)\" -CPPFLAGS+=-DLT_ARGS_DEF_CONF=\"$(sysconfdir)/headers/latrace.h\" +CPPFLAGS+=-DLT_CONF_DIR=\"$(sysconfdir)/latrace.d\" +CPPFLAGS+=-DLT_CONF_HEADERS_DIR=\"$(sysconfdir)/latrace.d/headers\" +CPPFLAGS+=-DLT_CONF_HEADERS_FILE=\"$(sysconfdir)/latrace.d/headers/latrace.h\" $(LATRACE_BIN): $(LATRACE_OBJS) $(QUIET_LD)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(LATRACE_OBJS) $(LATRACE_LIBS) $(LATRACE_LIB) diff --git a/src/args-bison.y b/src/args-bison.y index 1776a1e..fc6787c 100644 --- a/src/args-bison.y +++ b/src/args-bison.y @@ -18,6 +18,7 @@ <http://www.gnu.org/licenses/>. */ +%name-prefix "lt_args_" %{ @@ -27,18 +28,20 @@ #include <string.h> #include "config.h" +#include "lib-include.h" -int yylex (void); -void yyerror(const char *m); +int lt_args_lex(void); +void lt_args_error(const char *m); static struct lt_config_shared *scfg; static int struct_alive = 0; +struct lt_include *lt_args_sinc; #define ERROR(fmt, args...) \ do { \ char ebuf[1024]; \ sprintf(ebuf, fmt, ## args); \ - yyerror(ebuf); \ + lt_args_error(ebuf); \ YYERROR; \ } while(0) @@ -100,7 +103,7 @@ entry include_def | entry END { - if (lt_args_buf_close(scfg)) + if (lt_inc_close(scfg, lt_args_sinc)) return 0; } | @@ -289,14 +292,15 @@ ENUM_REF: /* include definitions */ include_def: INCLUDE '"' FILENAME '"' { - if (lt_args_buf_open(scfg, $3)) + if (lt_inc_open(scfg, lt_args_sinc, $3)) ERROR("failed to process include"); } %% -int lt_args_parse_init(struct lt_config_shared *cfg) +int lt_args_parse_init(struct lt_config_shared *cfg, struct lt_include *inc) { scfg = cfg; + lt_args_sinc = inc; return 0; } diff --git a/src/args-flex.l b/src/args-flex.l index cd68fb3..368e4df 100644 --- a/src/args-flex.l +++ b/src/args-flex.l @@ -18,6 +18,7 @@ <http://www.gnu.org/licenses/>. */ +%option prefix="lt_args_" %{ @@ -25,8 +26,9 @@ #include "config.h" #include "args-bison.h" +#include "lib-include.h" -struct lt_args_include* lt_args_buf_get(void); +extern struct lt_include *lt_args_sinc; %} @@ -40,11 +42,11 @@ filename ([-0-9a-zA-Z\./_])+ "/*" BEGIN(comment); <comment>[^*\n]* /* eat anything that's not a '*' */ <comment>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */ -<comment>\n { lt_args_buf_get()->lineno++; } +<comment>\n { lt_inc_stack(lt_args_sinc)->lineno++; } <comment>"*"+"/" BEGIN(INITIAL); "#include" { BEGIN(include); return INCLUDE; } -<include>{filename} { yylval.s = strdup(yytext); return FILENAME; } +<include>{filename} { lt_args_lval.s = strdup(lt_args_text); return FILENAME; } <include>"\"" { return '"'; } <include>\n { BEGIN(INITIAL); } <include>. { ; } @@ -55,7 +57,7 @@ filename ([-0-9a-zA-Z\./_])+ "struct" { return STRUCT; } "enum" { return ENUM; } "typedef" { return TYPEDEF; } -{name} { yylval.s = strdup(yytext); return NAME; } +{name} { lt_args_lval.s = strdup(lt_args_text); return NAME; } "\*"+ { return POINTER; } ")" { return ')'; } "(" { return '('; } @@ -65,7 +67,7 @@ filename ([-0-9a-zA-Z\./_])+ "," { return ','; } "=" { return '='; } \ { ; } -\n { lt_args_buf_get()->lineno++; } +\n { lt_inc_stack(lt_args_sinc)->lineno++; } . { ; } %% @@ -80,10 +82,10 @@ int yywrap() } #endif -void yyerror(const char *m) +void lt_args_error(const char *m) { - printf("latrace config file [%s] line %d: %s\n", - lt_args_buf_get()->file, - lt_args_buf_get()->lineno, - m); + printf("header file [%s] line %d: %s\n", + lt_inc_stack(lt_args_sinc)->file, + lt_inc_stack(lt_args_sinc)->lineno, + m); } @@ -28,26 +28,26 @@ #include <stdio.h> #include "config.h" +#include "lib-include.h" - -#define YY_BUF_SIZE 16384 -#define MAX_INCLUDE_DEPTH 10 #define LT_EQUAL " = " - extern int errno; +extern FILE *lt_args_in; +int lt_args_parse(); +void lt_args__switch_to_buffer (YY_BUFFER_STATE new_buffer ); +void lt_args__delete_buffer (YY_BUFFER_STATE b ); +YY_BUFFER_STATE lt_args__create_buffer (FILE *file,int size ); + +static struct lt_include inc = { + .create_buffer = lt_args__create_buffer, + .switch_to_buffer = lt_args__switch_to_buffer, + .delete_buffer = lt_args__delete_buffer, + .in = <_args_in, +}; -typedef struct yy_buffer_state *YY_BUFFER_STATE; -YY_BUFFER_STATE yy_create_buffer(FILE *file, int size); -extern FILE *yyin; - -int yyparse(); -void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer); -void yy_delete_buffer(YY_BUFFER_STATE b); +int lt_args_parse_init(struct lt_config_shared *cfg, struct lt_include *inc); -int lt_args_parse_init(struct lt_config_shared *cfg); -static struct lt_args_include include_stack[MAX_INCLUDE_DEPTH]; -static int include_stack_ptr = 0; static int enum_init = 0; @@ -706,7 +706,7 @@ int lt_args_add_typedef(struct lt_config_shared *cfg, char *base, int lt_args_init(struct lt_config_shared *cfg) { - char *file = LT_ARGS_DEF_CONF; + char *file = LT_CONF_HEADERS_FILE; int ret = 0; if (!hcreate_r(LT_ARGS_TAB, &cfg->args_tab)) { @@ -714,38 +714,33 @@ int lt_args_init(struct lt_config_shared *cfg) return -1; } - lt_args_parse_init(cfg); + lt_args_parse_init(cfg, &inc); if (*cfg->args_def) file = cfg->args_def; PRINT_VERBOSE(cfg, 1, "arguments definition file %s\n", file); - if (lt_args_buf_open(cfg, file)) + if (lt_inc_open(cfg, &inc, file)) return -1; - if (yyparse()) { - printf("failed to parse config file %s\n", file); + if (lt_args_parse()) { + printf("failed to header file(s) %s\n", file); ret = -1; } #if defined(LT_ARGS_ARCH_CONF) /* Some architectures provides specific * configuration file. */ - if (lt_args_buf_open(cfg, lt_args_arch_conf(cfg))) + if (lt_inc_open(cfg, &inc, lt_args_arch_conf(cfg))) return -1; - if (yyparse()) { + if (lt_args_parse()) { printf("failed to parse config file %s\n", file); ret = -1; } #endif - if (fclose(yyin)) { - perror("failed to close " LT_ARGS_DEF_CONF); - return -1; - } - return ret; } @@ -976,107 +971,6 @@ static int getargs(struct lt_config_shared *cfg, struct lt_args_sym *asym, return lt_stack_process(cfg, asym, regs, &data); } -static FILE* open_include(struct lt_config_shared *cfg, char *file) -{ - FILE *f; - char fn[LT_MAXFILE]; - - /* we got an absolute path */ - if ((NULL != (f = fopen(file, "r")))) { - PRINT_VERBOSE(cfg, 1, "open ok [%s]\n", file); - return f; - } - - PRINT_VERBOSE(cfg, 1, "open failed [%s]: %s\n", - file, strerror(errno)); - - /* give up if there was already the absolute name */ - if (*file == '/') { - printf("open failed [%s]: %s\n", file, strerror(errno)); - return NULL; - } - - /* not an absolute name, give it a chance - inside of the /etc config directory */ - if (strlen(file) > (LT_MAXFILE - sizeof(LT_ARGS_DEF_DIR))) { - printf("file name length crossed the max %u: %s\n", - (u_int) (LT_MAXFILE - sizeof(LT_ARGS_DEF_DIR)), file); - return NULL; - } - - sprintf(fn, "%s/%s", LT_ARGS_DEF_DIR, file); - - if ((NULL == (f = fopen(fn, "r")))) { - PRINT_VERBOSE(cfg, 1, "open failed [%s]: %s\n", - fn, strerror(errno)); - printf("open failed [%s]: %s\n", file, strerror(errno)); - return NULL; - } - - PRINT_VERBOSE(cfg, 1, "open ok [%s]\n", fn); - return f; -} - -int lt_args_buf_open(struct lt_config_shared *cfg, char *file) -{ - struct lt_args_include *inc; - - PRINT_VERBOSE(cfg, 1, "opening buffer for [%s] depth %d\n", - file, include_stack_ptr); - - if ((include_stack_ptr + 1) == MAX_INCLUDE_DEPTH) { - printf("include depth overstep"); - return -1; - } - - if (NULL == (yyin = open_include(cfg, file))) - return -1; - - inc = &include_stack[include_stack_ptr++]; - memset(inc, 0, sizeof(*inc)); - - inc->yyin = yyin; - inc->file = strdup(file); - inc->lineno = 1; - inc->yybuf = yy_create_buffer(yyin, YY_BUF_SIZE); - - yy_switch_to_buffer(inc->yybuf); - - PRINT_VERBOSE(cfg, 1, "opened buffer for [%s] depth %d\n", - file, include_stack_ptr); - return 0; -} - -int lt_args_buf_close(struct lt_config_shared *cfg) -{ - struct lt_args_include *inc = &include_stack[--include_stack_ptr]; - - PRINT_VERBOSE(cfg, 1, "buffer closed [%s], depth [%d]\n", - inc->file, include_stack_ptr); - - free(inc->file); - - /* EOF with no other includes on stack */ - if (!include_stack_ptr) - return -1; - - /* looks like the base buffer is cleaned up by the - flex itself, so we do the actual cleaning - only for includes */ - yy_delete_buffer(inc->yybuf); - fclose(inc->yyin); - - inc = &include_stack[include_stack_ptr - 1]; - yy_switch_to_buffer(inc->yybuf); - return 0; -} - -struct lt_args_include* lt_args_buf_get(void) -{ - struct lt_args_include *inc = &include_stack[include_stack_ptr - 1]; - return inc; -} - struct lt_args_sym* lt_args_sym_get(struct lt_config_shared *cfg, const char *sym) { @@ -98,13 +98,6 @@ struct lt_args_sym { struct lt_arg **args; }; -struct lt_args_include { - FILE *yyin; - void *yybuf; - char *file; - int lineno; -}; - /* used in lt_args_cb_struct for argument type */ enum { LT_ARGS_STRUCT_ITSELF = 0, diff --git a/src/config-bison.y b/src/config-bison.y new file mode 100644 index 0000000..a544fa7 --- /dev/null +++ b/src/config-bison.y @@ -0,0 +1,179 @@ +/* + Copyright (C) 2011 Jiri Olsa <olsajiri@gmail.com> + + 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 + <http://www.gnu.org/licenses/>. +*/ + +%name-prefix "lt_config_" + +%{ +#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 ERROR(fmt, args...) \ +do { \ + char ebuf[1024]; \ + sprintf(ebuf, fmt, ## args); \ + lt_config_error(ebuf); \ + YYERROR; \ +} while(0) + +static LT_LIST_HEAD(opt_list); + +#define OPTION_ADD(idx, sval, nval) \ +do { \ + struct lt_config_opt *opt; \ + opt = lt_config_opt_new(idx, sval, nval); \ + if (!opt) \ + ERROR("failed to process option\n"); \ + lt_list_add_tail(&opt->list, &opt_list); \ +} while(0) +%} + +%token INCLUDE FILENAME 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 + +%union +{ + char *s; + unsigned long l; +} + +%type <s> FILENAME +%type <s> BOOL +%type <l> VALUE + +%% +entry: +entry include_def +| +entry options_def +| +entry END +{ + if (lt_inc_close(scfg->sh, lt_config_sinc)) + return 0; +} +| +/* left blank intentionally */ + +include_def: INCLUDE '"' FILENAME '"' +{ + if (lt_inc_open(scfg->sh, lt_config_sinc, $3)) + ERROR("failed to process include"); +} + +options_def: OPTIONS '{' OPTIONS_DEF '}' +{ + struct lt_config_opt *opt, *opth; + + if (lt_config_opt_process(scfg, &opt_list)) + ERROR("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 '=' '"' FILENAME '"' +{ + 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); +} +| +/* left blank intentionally */ + +%% + +int lt_config_parse_init(struct lt_config_app *cfg, struct lt_include *inc) +{ + scfg = cfg; + lt_config_sinc = inc; + return 0; +} diff --git a/src/config-flex.l b/src/config-flex.l new file mode 100644 index 0000000..61a775e --- /dev/null +++ b/src/config-flex.l @@ -0,0 +1,119 @@ +/* + Copyright (C) 2011 Jiri Olsa <olsajiri@gmail.com> + + 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 + <http://www.gnu.org/licenses/>. +*/ + +%option prefix="lt_config_" + +%{ + +#include <string.h> + +#include "config.h" +#include "config-bison.h" +#include "lib-include.h" + +extern struct lt_include *lt_config_sinc; + + +#define NEW_LINE() \ +do { \ + lt_inc_stack(lt_config_sinc)->lineno++; \ +} while(0) + +#define RETURN_STR(token) \ +do { \ + lt_config_lval.s = strdup(lt_config_text); return token; \ +} while(0) + +#define RETURN_LONG(token) \ +do { \ + lt_config_lval.l = atol(lt_config_text); return token; \ +} while(0) + +%} + +num [-0-9] +value ({num})+ +alphnum [-0-9a-zA-Z_] +name ({alphnum})+ +filename ([-0-9a-zA-Z\./_])+ +bool YES|NO +comment ^([\s\t])*#.* + +%x comment include options + +%% + +<<EOF>> { return END; } +"\n" { NEW_LINE(); } +{comment} { ; } +. { ; } + +INCLUDE { BEGIN(include); return INCLUDE; } +<include>{filename} { RETURN_STR(FILENAME); } +<include>"\"" { return '"'; } +<include>\n { BEGIN(INITIAL); NEW_LINE(); } +<include>. { ; } + +OPTIONS { BEGIN(options); return OPTIONS; } +<options>HEADERS { return OPT_HEADERS; } +<options>INDENT_SYM { return OPT_INDENT_SYM; } +<options>PIPE { return OPT_PIPE; } +<options>TIMESTAMP { return OPT_TIMESTAMP; } +<options>FRAMESIZE { return OPT_FRAMESIZE; } +<options>FRAMESIZE_CHECK { return OPT_FRAMESIZE_CHECK; } +<options>HIDE_TID { return OPT_HIDE_TID; } +<options>FOLLOW_FORK { return OPT_FOLLOW_FORK; } +<options>FOLLOW_EXEC { return OPT_FOLLOW_EXEC; } +<options>DEMANGLE { return OPT_DEMANGLE; } +<options>BRACES { return OPT_BRACES; } +<options>ENABLE_ARGS { return OPT_ENABLE_ARGS; } +<options>DETAIL_ARGS { return OPT_DETAIL_ARGS; } + +<options>{bool} { RETURN_STR(BOOL); } +<options>{value} { RETURN_LONG(VALUE); } +<options>{filename} { RETURN_STR(FILENAME); } +<options>{comment} { ; } +<options>"}" { BEGIN(INITIAL); return '}'; } +<options>"{" { return '{'; } +<options>"=" { return '='; } +<options>"\"" { return '"'; } +<options>"\\" { ; } +<options>"\n" { NEW_LINE(); } +<options>. { ; } + +%% + +#ifndef yywrap +int yywrap() +{ + return 1; + /* XXX not to get the compiler 'not used' warning */ + yyunput(0, NULL); + input(); +} +#endif + +void lt_config_error(const char *m) +{ + printf("conf file [%s] line %d: %s\n", + lt_inc_stack(lt_config_sinc)->file, + lt_inc_stack(lt_config_sinc)->lineno, + m); +} diff --git a/src/config.c b/src/config.c index 3cf734b..8ba7b0b 100644 --- a/src/config.c +++ b/src/config.c @@ -23,8 +23,26 @@ #include <getopt.h> #include <stdio.h> #include <stdlib.h> +#include <errno.h> #include "config.h" +#include "lib-include.h" + +extern FILE *lt_config_in; +int lt_config_parse(); +void lt_config__switch_to_buffer (YY_BUFFER_STATE new_buffer ); +void lt_config__delete_buffer (YY_BUFFER_STATE b ); +YY_BUFFER_STATE lt_config__create_buffer (FILE *file,int size ); + +static struct lt_include inc = { + .stack_idx = 0, + .create_buffer = lt_config__create_buffer, + .switch_to_buffer = lt_config__switch_to_buffer, + .delete_buffer = lt_config__delete_buffer, + .in = <_config_in, +}; + +int lt_config_parse_init(struct lt_config_app *cfg, struct lt_include *inc); static void usage() NORETURN; static void usage() @@ -46,7 +64,7 @@ static void usage() #ifndef CONFIG_ARCH_HAVE_ARGS printf(" -[ADa] arguments display support not compiled in\n"); #else - printf(" -A, --enable-args enable arguments output (definitions from /etc/latrace.conf)\n"); + printf(" -A, --enable-args enable arguments output (definitions from headers)\n"); printf(" -D, --detail-args display struct arguments in more detail\n"); printf(" -a, --args file arguments definition file, implies \'-A\'\n"); #endif @@ -107,10 +125,204 @@ static int get_type(struct lt_config_app *cfg, struct lt_config_tv *tv, return -1; } +/* read conf file */ +static int read_config(struct lt_config_app *cfg, char *file) +{ + int ret = 0; + lt_config_parse_init(cfg, &inc); + + PRINT_VERBOSE(cfg, 1, "arguments definition file %s\n", file); + + if (lt_inc_open(cfg->sh, &inc, file)) + return -1; + + if (lt_config_parse()) { + printf("failed to parse config file %s\n", file); + ret = -1; + } + + return ret; +} + +#define CHECK_BOOL(str, sval, ival) \ +do { \ + if (ival != -1) \ + val = ival; \ + else if (!strcmp(sval, "YES")) \ + val = 1; \ + else if (!strcmp(sval, "NO")) \ + val = 0; \ + else \ + return -1; \ +} while(0) + +#define CHECK_INT(val, sval, ival) \ +do { \ + val = ival; \ + if (val == -1) \ + val = atoi(sval); \ +} while(0) + +static int process_option_val(struct lt_config_app *cfg, int idx, + char *sval, int ival) +{ + int val; + + PRINT_VERBOSE(cfg, 1, "option idx %d, sval %s, ival %d\n", + idx, sval, ival); + + switch(idx) { + case LT_OPT_HEADERS: + strcpy(lt_sh(cfg, args_def), sval); + + PRINT_VERBOSE(cfg, 1, "HEADERS '%s'\n", + lt_sh(cfg, args_def)); + break; + + case LT_OPT_INDENT_SYM: + CHECK_INT(val, sval, ival); + lt_sh(cfg, indent_size) = val; + + PRINT_VERBOSE(cfg, 1, "INDENT_SYM %d\n", + lt_sh(cfg, indent_size)); + break; + + case LT_OPT_PIPE: + CHECK_BOOL(val, sval, ival); + lt_sh(cfg, pipe) = val; + + PRINT_VERBOSE(cfg, 1, "PIPE %d\n", + lt_sh(cfg, pipe)); + break; + + case LT_OPT_TIMESTAMP: + CHECK_BOOL(val, sval, ival); + lt_sh(cfg, timestamp) = val; + + PRINT_VERBOSE(cfg, 1, "TIMESTAMP %d\n", + lt_sh(cfg, timestamp)); + break; + + case LT_OPT_FRAMESIZE: + CHECK_INT(val, sval, ival); + lt_sh(cfg, framesize) = val; + + PRINT_VERBOSE(cfg, 1, "FRAMESIZE %d\n", + lt_sh(cfg, framesize)); + break; + + case LT_OPT_FRAMESIZE_CHECK: + CHECK_BOOL(val, sval, ival); + lt_sh(cfg, framesize_check) = val; + + PRINT_VERBOSE(cfg, 1, "FRAMESIZE_CHECK %d\n", + lt_sh(cfg, framesize_check)); + break; + + case LT_OPT_HIDE_TID: + CHECK_BOOL(val, sval, ival); + lt_sh(cfg, hide_tid) = val; + + PRINT_VERBOSE(cfg, 1, "HIDE_TID %d\n", + lt_sh(cfg, hide_tid)); + break; + + case LT_OPT_FOLLOW_FORK: + CHECK_BOOL(val, sval, ival); + lt_sh(cfg, not_follow_fork) = !val; + + PRINT_VERBOSE(cfg, 1, "NOT FOLLOW_FORK %d\n", + lt_sh(cfg, not_follow_fork)); + break; + + case LT_OPT_FOLLOW_EXEC: + CHECK_BOOL(val, sval, ival); + lt_sh(cfg, not_follow_exec) = !val; + + PRINT_VERBOSE(cfg, 1, "NOT FOLLOW_EXEC %d\n", + lt_sh(cfg, not_follow_exec)); + break; + + case LT_OPT_DEMANGLE: + CHECK_BOOL(val, sval, ival); + lt_sh(cfg, demangle) = val; + + PRINT_VERBOSE(cfg, 1, "DEMANGLE %d\n", + lt_sh(cfg, demangle)); + break; + + case LT_OPT_BRACES: + CHECK_BOOL(val, sval, ival); + lt_sh(cfg, braces) = val; + + PRINT_VERBOSE(cfg, 1, "BRACES %d\n", + lt_sh(cfg, braces)); + break; + + case LT_OPT_ENABLE_ARGS: + CHECK_BOOL(val, sval, ival); + lt_sh(cfg, args_enabled) = val; + + PRINT_VERBOSE(cfg, 1, "ENABLE_ARGS %d\n", + lt_sh(cfg, args_enabled)); + break; + + case LT_OPT_DETAIL_ARGS: + CHECK_BOOL(val, sval, ival); + lt_sh(cfg, args_detailed) = val; + + PRINT_VERBOSE(cfg, 1, "DETAIL_ARGS %d\n", + lt_sh(cfg, args_detailed)); + break; + + default: + return -1; + } + return 0; +} + +static int process_option(struct lt_config_app *cfg, struct lt_config_opt *opt) +{ + return process_option_val(cfg, opt->idx, opt->sval, opt->nval); +} + +int lt_config_opt_process(struct lt_config_app *cfg, struct lt_list_head *list) +{ + struct lt_config_opt *opt; + + lt_list_for_each_entry(opt, list, list) { + int ret; + + ret = process_option(cfg, opt); + if (ret) + return ret; + } + + return 0; +} + +struct lt_config_opt *lt_config_opt_new(int idx, char *sval, long nval) +{ + struct lt_config_opt *opt; + + opt = malloc(sizeof(*opt)); + if (!opt) + return NULL; + + lt_init_list_head(&opt->list); + opt->idx = idx; + opt->sval = sval ? strdup(sval) : NULL; + opt->nval = nval; + + return opt; +} + int lt_config(struct lt_config_app *cfg, int argc, char **argv) { + char *conf_file = LT_CONF_DIR "/latrace.conf"; + memset(cfg, 0, sizeof(*cfg)); - cfg->sh = &cfg->sh_storage; + cfg->sh = cfg->sh_storage.sh = &cfg->sh_storage; /* default values settings */ lt_sh(cfg, magic) = LT_CONFIG_MAGIC; @@ -123,6 +335,15 @@ int lt_config(struct lt_config_app *cfg, int argc, char **argv) lt_sh(cfg, args_detail_maxlen) = LR_ARGS_DETAIL_MAXLEN; cfg->csort = LT_CSORT_CALL; + + /* read the default config file first */ + if (read_config(cfg, conf_file)) { + printf("failed: read config file '%s'\n", conf_file); + usage(); + } + + conf_file = NULL; + while (1) { int c; int option_index = 0; @@ -142,6 +363,7 @@ int lt_config(struct lt_config_app *cfg, int argc, char **argv) {"sort-counts", required_argument, 0, 'C'}, {"pipe", no_argument, 0, 'p'}, {"output", required_argument, 0, 'o'}, + {"conf", required_argument, 0, 'N'}, {"args", required_argument, 0, 'a'}, {"enable-args", required_argument, 0, 'A'}, {"detail-args", required_argument, 0, 'D'}, @@ -159,7 +381,7 @@ int lt_config(struct lt_config_app *cfg, int argc, char **argv) {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "+s:n:l:t:f:vhi:BdISb:cC:y:YL:po:a:ADVTFERq", + c = getopt_long(argc, argv, "+s:n:l:t:f:vhi:BdISb:cC:y:YL:po:a:N:ADVTFERq", long_options, &option_index); if (c == -1) @@ -213,19 +435,19 @@ int lt_config(struct lt_config_app *cfg, int argc, char **argv) break; case 'S': - lt_sh(cfg, timestamp) = 1; + process_option_val(cfg, LT_OPT_TIMESTAMP, NULL, 1); break; case 'T': - lt_sh(cfg, hide_tid) = 1; + process_option_val(cfg, LT_OPT_HIDE_TID, NULL, 1); break; case 'F': - lt_sh(cfg, not_follow_fork) = 1; + process_option_val(cfg, LT_OPT_FOLLOW_FORK, NULL, 0); break; case 'E': - lt_sh(cfg, not_follow_exec) = 1; + process_option_val(cfg, LT_OPT_FOLLOW_EXEC, NULL, 0); break; case 'i': @@ -233,7 +455,7 @@ int lt_config(struct lt_config_app *cfg, int argc, char **argv) break; case 'B': - lt_sh(cfg, braces) = 1; + process_option_val(cfg, LT_OPT_BRACES, NULL, 0); break; case 'd': @@ -243,7 +465,7 @@ int lt_config(struct lt_config_app *cfg, int argc, char **argv) break; #endif - lt_sh(cfg, demangle) = 1; + process_option_val(cfg, LT_OPT_DEMANGLE, NULL, 0); break; case 'I': @@ -251,11 +473,11 @@ int lt_config(struct lt_config_app *cfg, int argc, char **argv) break; case 'y': - lt_sh(cfg, framesize) = atoi(optarg); + process_option_val(cfg, LT_OPT_FRAMESIZE, optarg, -1); break; case 'Y': - lt_sh(cfg, framesize_check) = 0; + process_option_val(cfg, LT_OPT_FRAMESIZE_CHECK, NULL, 0); break; case 'L': @@ -274,7 +496,7 @@ int lt_config(struct lt_config_app *cfg, int argc, char **argv) lt_sh(cfg, counts) = 1; /* falling through */ case 'p': - lt_sh(cfg, pipe) = 1; + process_option_val(cfg, LT_OPT_PIPE, NULL, 1); break; #ifndef CONFIG_ARCH_HAVE_ARGS @@ -285,18 +507,22 @@ int lt_config(struct lt_config_app *cfg, int argc, char **argv) break; #else case 'a': - strcpy(lt_sh(cfg, args_def), optarg); + process_option_val(cfg, LT_OPT_HEADERS, optarg, -1); + /* falling through */ case 'A': - - lt_sh(cfg, args_enabled) = 1; + process_option_val(cfg, LT_OPT_ENABLE_ARGS, NULL, 1); break; case 'D': - lt_sh(cfg, args_detailed) = 1; + process_option_val(cfg, LT_OPT_DETAIL_ARGS, NULL, 1); break; #endif /* CONFIG_ARCH_HAVE_ARGS */ + case 'N': + conf_file = optarg; + break; + case 'o': strcpy(lt_sh(cfg, output), optarg); break; @@ -332,6 +558,12 @@ int lt_config(struct lt_config_app *cfg, int argc, char **argv) cfg->arg_num = i_arg; } + /* read user-specifide config file */ + if (conf_file && read_config(cfg, conf_file)) { + printf("failed: read config file '%s'\n", conf_file); + usage(); + } + if (!cfg->prog) { printf("failed: no program specified\n"); usage(); diff --git a/src/config.h b/src/config.h index c7f88ee..9bdae88 100644 --- a/src/config.h +++ b/src/config.h @@ -70,6 +70,29 @@ struct lt_config_tv { char *name; }; +enum { + LT_OPT_HEADERS = 1, + LT_OPT_PIPE, + LT_OPT_INDENT_SYM, + LT_OPT_TIMESTAMP, + LT_OPT_FRAMESIZE, + LT_OPT_FRAMESIZE_CHECK, + LT_OPT_HIDE_TID, + LT_OPT_FOLLOW_FORK, + LT_OPT_FOLLOW_EXEC, + LT_OPT_DEMANGLE, + LT_OPT_BRACES, + LT_OPT_ENABLE_ARGS, + LT_OPT_DETAIL_ARGS, +}; + +struct lt_config_opt { + int idx; + char *sval; + unsigned long nval; + struct lt_list_head list; +}; + struct lt_config_shared { #define LT_CONFIG_VERSION 1 #define LT_CONFIG_MAGIC ((LT_CONFIG_VERSION << 16) + 0xdead) @@ -323,6 +346,10 @@ struct lt_symbol* lt_symbol_bind(struct lt_config_shared *cfg, struct lt_symbol* lt_symbol_get(struct lt_config_shared *cfg, void *ptr, const char *name); +/* config options */ +struct lt_config_opt *lt_config_opt_new(int idx, char *sval, long nval); +int lt_config_opt_process(struct lt_config_app *cfg, struct lt_list_head *list); + #define PRINT(fmt, args...) \ do { \ char lpbuf[1024]; \ diff --git a/src/lib-include.c b/src/lib-include.c new file mode 100644 index 0000000..afdabf8 --- /dev/null +++ b/src/lib-include.c @@ -0,0 +1,161 @@ +/* + Copyright (C) 2011 Jiri Olsa <olsajiri@gmail.com> + + 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 + <http://www.gnu.org/licenses/>. +*/ + + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> + +#include "config.h" +#include "lib-include.h" + +#define YY_BUF_SIZE 16384 + +extern int errno; + +static FILE* open_include_dir(struct lt_config_shared *cfg, char *file, + char *dir) +{ + FILE *f; + char fn[LT_MAXFILE]; + int len_file, len_dir; + + len_file = strlen(file); + len_dir = strlen(dir); + + if (len_file > (LT_MAXFILE - len_dir - 1)) { + printf("file name length crossed the max %u: %s\n", + (u_int) (LT_MAXFILE - len_dir), file); + return NULL; + } + + sprintf(fn, "%s/%s", dir, file); + + f = fopen(fn, "r"); + if (f) { + PRINT_VERBOSE(cfg, 1, "open ok [%s]\n", fn); + return f; + } + + PRINT_VERBOSE(cfg, 1, "open failed [%s]: %s\n", + fn, strerror(errno)); + return NULL; +} + +static FILE* open_include(struct lt_config_shared *cfg, char *file) +{ + FILE *f; + + /* we got an absolute path */ + if ((NULL != (f = fopen(file, "r")))) { + PRINT_VERBOSE(cfg, 1, "open ok [%s]\n", file); + return f; + } + + /* give up if there was already the absolute name */ + if (*file == '/') { + printf("open failed [%s]: %s\n", file, strerror(errno)); + return NULL; + } + + PRINT_VERBOSE(cfg, 1, "open failed [%s]: %s\n", + file, strerror(errno)); + + /* not an absolute name, give it a chance + inside of the LT_CONF_DIR directory */ + f = open_include_dir(cfg, file, LT_CONF_DIR); + if (f) + return f; + + /* not in LT_CONF_DIR directory, give it a chance + inside of the LT_CONF_HEADERS_DIR directory */ + f = open_include_dir(cfg, file, LT_CONF_HEADERS_DIR); + if (f) + return f; + + return NULL; +} + +int lt_inc_open(struct lt_config_shared *cfg, struct lt_include *inc, + char *file) +{ + struct lt_include_stack *inc_stack; + FILE *f; + + PRINT_VERBOSE(cfg, 1, "opening buffer for [%s] depth %d\n", + file, inc->stack_idx); + + if ((inc->stack_idx + 1) == MAX_INCLUDE_DEPTH) { + printf("include depth overstep"); + return -1; + } + + if (NULL == (f = open_include(cfg, file))) + return -1; + + *inc->in = f; + + inc_stack = &inc->stack[inc->stack_idx++]; + memset(inc_stack, 0, sizeof(*inc_stack)); + + inc_stack->in = f; + inc_stack->file = strdup(file); + inc_stack->lineno = 1; + inc_stack->buf = inc->create_buffer(f, YY_BUF_SIZE); + + inc->switch_to_buffer(inc_stack->buf); + + PRINT_VERBOSE(cfg, 1, "opened buffer for [%s] depth %d\n", + file, inc->stack_idx); + return 0; +} + +int lt_inc_close(struct lt_config_shared *cfg, struct lt_include *inc) +{ + struct lt_include_stack *inc_stack = &inc->stack[--inc->stack_idx]; + + PRINT_VERBOSE(cfg, 1, "buffer closed [%s], depth [%d]\n", + inc_stack->file, inc->stack_idx); + + free(inc_stack->file); + + /* EOF with no other includes on stack */ + if (!inc->stack_idx) + return -1; + + /* looks like the base buffer is cleaned up by the + flex itself, so we do the actual cleaning + only for includes */ + inc->delete_buffer(inc_stack->buf); + fclose(inc_stack->in); + + inc_stack = &inc->stack[inc->stack_idx - 1]; + inc->switch_to_buffer(inc_stack->buf); + return 0; +} + +struct lt_include_stack* lt_inc_stack(struct lt_include *inc) +{ + struct lt_include_stack *inc_stack = &inc->stack[inc->stack_idx - 1]; + return inc_stack; +} diff --git a/src/lib-include.h b/src/lib-include.h new file mode 100644 index 0000000..e5647fd --- /dev/null +++ b/src/lib-include.h @@ -0,0 +1,61 @@ +/* + Copyright (C) 2011 Jiri Olsa <olsajiri@gmail.com> + + 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 + <http://www.gnu.org/licenses/>. +*/ + + +#ifndef LIB_INCLUDE_H +#define LIB_INCLUDE_H + +#include <stdio.h> +#include "config.h" + +#define MAX_INCLUDE_DEPTH 10 + +struct lt_include_stack { + FILE *in; + void *buf; + char *file; + int lineno; +}; + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +typedef YY_BUFFER_STATE (*yy_create_buffer_t)(FILE*, int); +typedef void (*yy_switch_to_buffer_t)(YY_BUFFER_STATE); +typedef void (*yy_delete_buffer_t)(YY_BUFFER_STATE); + +struct lt_include { + struct lt_include_stack stack[MAX_INCLUDE_DEPTH]; + int stack_idx; + + FILE **in; + yy_create_buffer_t create_buffer; + yy_switch_to_buffer_t switch_to_buffer; + yy_delete_buffer_t delete_buffer; +}; + +int lt_inc_open(struct lt_config_shared *cfg, struct lt_include *inc, + char *file); +int lt_inc_close(struct lt_config_shared *cfg, struct lt_include *inc); +struct lt_include_stack* lt_inc_stack(struct lt_include *inc); + +#endif /* LIB_INCLUDE_H */ diff --git a/src/sysdeps/x86_64/args.h b/src/sysdeps/x86_64/args.h index 125c0a1..caa91a6 100644 --- a/src/sysdeps/x86_64/args.h +++ b/src/sysdeps/x86_64/args.h @@ -31,8 +31,8 @@ char* lt_args_arch_conf(struct lt_config_shared *cfg) static char buf[LT_MAXFILE]; sprintf(buf, "%s/%s", - LT_ARGS_DEF_DIR, - "sysdeps/x86_64/latrace.conf"); + LT_CONF_HEADERS_DIR, + "sysdeps/x86_64/latrace.h"); return buf; } |