diff options
author | jolsa@redhat.com <jolsa@redhat.com> | 2011-10-21 11:10:51 +0200 |
---|---|---|
committer | Jiri Olsa <Jiri Olsa jolsa@redhat.com> | 2011-11-24 21:20:27 +0100 |
commit | 8967d2b09abc5f3e2bace9f6f14e1cfef8e47030 (patch) | |
tree | f5d4a59b81327608e08c4f1d7b386b5e81e93ff8 /src | |
parent | 27b90e3d32a6c311fca017f55d0fb8e2a1bd451e (diff) | |
download | latrace-8967d2b09abc5f3e2bace9f6f14e1cfef8e47030.tar.gz latrace-8967d2b09abc5f3e2bace9f6f14e1cfef8e47030.tar.xz latrace-8967d2b09abc5f3e2bace9f6f14e1cfef8e47030.zip |
error simulation: automation application part
Diffstat (limited to 'src')
-rw-r--r-- | src/config-bison.y | 36 | ||||
-rw-r--r-- | src/config-flex.l | 3 | ||||
-rw-r--r-- | src/config.c | 2 | ||||
-rw-r--r-- | src/config.h | 13 | ||||
-rw-r--r-- | src/error.c | 206 | ||||
-rw-r--r-- | src/error.h | 48 | ||||
-rw-r--r-- | src/list.h | 7 | ||||
-rw-r--r-- | src/run.c | 28 |
8 files changed, 288 insertions, 55 deletions
diff --git a/src/config-bison.y b/src/config-bison.y index c9512ac..db1d6bc 100644 --- a/src/config-bison.y +++ b/src/config-bison.y @@ -74,7 +74,7 @@ static struct lt_list_head ln_names; %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 +%token ERR_SIGSEGV ERR_AUTOMATED ERR_REPLAY ERR_KEEP %union { @@ -347,15 +347,21 @@ error_return: ERR_RETURN NAME '{' error_return_def '}' } error_return_def: -error_return_def NAME '=' VALUE +error_return_def NAME '=' list_values_comma { - if (lt_error_return_ass(scfg, &error_app_return, $2, $4, 0)) + 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 '=' VALUE ERR_SIGSEGV +error_return_def NAME '=' ERR_KEEP { - if (lt_error_return_ass(scfg, &error_app_return, $2, $4, 1)) + 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"); } | @@ -392,21 +398,35 @@ error_go: ERR_GO NAME list_names_comma { if (lt_error_go(scfg, &error_app_go, &error_app, - strdup($2), 0, 1, &ln_names)) + strdup($2), 0, 1, 0, 0, &ln_names)) + ABORT("failed to add go"); +} +| +ERR_GO NAME ERR_AUTOMATED list_names_comma +{ + if (lt_error_go(scfg, &error_app_go, &error_app, + strdup($2), 0, 1, 1, 0, &ln_names)) + ABORT("failed to add go"); +} +| +ERR_GO NAME ERR_REPLAY list_names_comma +{ + if (lt_error_go(scfg, &error_app_go, &error_app, + strdup($2), 0, 1, 1, 1, &ln_names)) ABORT("failed to add go"); } | ERR_GO NAME ERR_N '=' VALUE list_names_comma { if (lt_error_go(scfg, &error_app_go, &error_app, - strdup($2), 0, $5, &ln_names)) + strdup($2), 0, $5, 0, 0, &ln_names)) ABORT("failed to add go"); } | ERR_GO NAME ERR_START '=' VALUE ERR_N '=' VALUE list_names_comma { if (lt_error_go(scfg, &error_app_go, &error_app, - strdup($2), $5, $8, &ln_names)) + strdup($2), $5, $8, 0, 0, &ln_names)) ABORT("failed to add go"); } diff --git a/src/config-flex.l b/src/config-flex.l index 5f86b9f..03d7a1b 100644 --- a/src/config-flex.l +++ b/src/config-flex.l @@ -130,6 +130,9 @@ ERROR { BEGIN(error); return ERROR; } <error>FILTER { return ERR_FILTER; } <error>SEQ { return ERR_SEQ; } <error>SIGSEGV { return ERR_SIGSEGV; } +<error>AUTOMATED { return ERR_AUTOMATED; } +<error>REPLAY { return ERR_REPLAY; } +<error>KEEP { return ERR_KEEP; } <error>{value} { RETURN_LONG(VALUE); } <error>{name} { RETURN_STR(NAME); } diff --git a/src/config.c b/src/config.c index 7b6ecef..9bde8a4 100644 --- a/src/config.c +++ b/src/config.c @@ -479,6 +479,8 @@ int lt_config(struct lt_config_app *cfg, int argc, char **argv) lt_init_list_head(&cfg->error_apps); lt_init_list_head(&cfg->process_funcs); + lt_init_list_head(&cfg->error_symbols_all); + lt_init_list_head(&cfg->error_symbols_current); /* read the default config file first */ if (read_config(cfg, LT_CONF_DIR "/latrace.conf")) { diff --git a/src/config.h b/src/config.h index 379c7b8..5e44935 100644 --- a/src/config.h +++ b/src/config.h @@ -158,9 +158,6 @@ struct lt_config_shared { /* for 'not_follow_fork' */ pid_t pid; - /* error definition (error_sim = 1) */ - struct lt_error_def error_def; - /* XXX feel like an idiot.. find another way!!! */ struct lt_config_shared *sh; }; @@ -197,6 +194,12 @@ struct lt_config_app { struct lt_error_app *error_app; /* list of defined errors */ struct lt_list_head error_apps; + + /* error definition (error_sim = 1 in shared config) */ + struct lt_error_config *error_config; + + struct lt_list_head error_symbols_all; + struct lt_list_head error_symbols_current; }; struct lt_config_ctl { @@ -255,6 +258,9 @@ struct lt_config_audit { char *dir; int init_ok; + + /* error definition (error_sim = 1 in shared config) */ + struct lt_error_config *error_config; }; enum { @@ -438,6 +444,7 @@ void tty_close(struct lt_config_app *cfg); /* process functions registration */ int lt_process_register(struct lt_config_app *cfg, lt_process_cb cb); +int lt_process_unregister(struct lt_config_app *cfg, lt_process_cb cb); /* error simulation app */ int lt_error_app(struct lt_config_app *cfg, struct lt_error_app *error_app); diff --git a/src/error.c b/src/error.c index fc13cad..6698ff8 100644 --- a/src/error.c +++ b/src/error.c @@ -6,6 +6,7 @@ #include <fcntl.h> #include <errno.h> #include <stdlib.h> +#include <limits.h> #include "config.h" @@ -281,33 +282,46 @@ static int prepare_config_error(struct lt_config_app *cfg, int n) { struct lt_error_app_return *ret; - struct lt_error_def *error_def = <_sh(cfg, error_def); - int i = 0; + struct lt_error_config *cfg_err; + int sym_cnt = 0; - bzero(error_def, sizeof(struct lt_error_def)); + /* get the nymber of configured symbols */ + lt_list_for_each_entry(ret, &run->head_return, list_run) { + struct lt_error_app_return_sym *sym; + lt_list_for_each_entry(sym, &ret->head_sym, list) + sym_cnt++; + } + + PRINT_VERBOSE(cfg, 1, "number of symbols %d\n", sym_cnt); + + cfg_err = malloc(sizeof(*cfg_err) + + sym_cnt * sizeof(struct lt_error_config_sym)); + if (!cfg_err) + return -ENOMEM; + + cfg_err->sym_cnt = sym_cnt; + cfg_err->n = n; + + sym_cnt = 0; lt_list_for_each_entry(ret, &run->head_return, list_run) { struct lt_error_app_return_sym *sym; lt_list_for_each_entry(sym, &ret->head_sym, list) { - struct lt_error_def_sym *sym_def; + struct lt_error_config_sym *cfg_sym; - sym_def = &error_def->sym[i]; - strncpy(sym_def->symbol, sym->name, LT_MAXNAME); - sym_def->ret = sym->val; - sym_def->filter.type = ret->filter.type; - sym_def->handle_sigsegv = sym->handle_sigsegv; + cfg_sym = &cfg_err->sym[sym_cnt++]; + strncpy(cfg_sym->symbol, sym->name, LT_MAXNAME); + cfg_sym->ret = sym->val; + cfg_sym->filter.type = ret->filter.type; + cfg_sym->handle_sigsegv = sym->handle_sigsegv; PRINT_VERBOSE(cfg, 1, "symbol %s, ret %s\n", sym->name, sym->val); - - if (i++ >= LT_ERROR_MAXSYM) - return -1; } } - lt_sh(cfg, error_def.n) = n; - PRINT_VERBOSE(cfg, 1, "N = %d\n", n); + cfg->error_config = cfg_err; return 0; } @@ -376,18 +390,82 @@ static int process_run(struct lt_config_app *cfg, return 0; } -static int process_go(struct lt_config_app *cfg, char *dir_base, - struct lt_error_app *app, - struct lt_error_app_go *go) +static int process_automated_cb(struct lt_config_app *cfg, + struct lt_thread *t, + struct lt_fifo_mbase *mbase) { - static char dir[LT_MAXFILE]; - int i; + return 0; +} - if (!app->no_storage && - dir_go(cfg, dir, dir_base, go)) +static int automated_get_all_syms(struct lt_config_app *cfg, + struct lt_error_app_go *go) +{ + struct lt_list_head *sym_all = &cfg->error_symbols_all; + struct lt_error_app_run *run; + int count = 0; + + lt_list_for_each_entry(run, &go->head_run, list_go) { + struct lt_error_app_return *ret; + + lt_list_for_each_entry(ret, &run->head_return, list_run) { + struct lt_error_app_return_sym *sym; + + lt_list_for_each_entry(sym, &ret->head_sym, list) { + lt_list_move_tail(&sym->list, sym_all); + count++; + } + } + } + + return count; +} + +static int process_go_automated(struct lt_config_app *cfg, char *dir, + struct lt_error_app *app, + struct lt_error_app_go *go) +{ + int ret = 0; + + if (lt_process_register(cfg, process_automated_cb)) return -1; - PRINT_VERBOSE(cfg, 1, "dir '%s'\n", dir); + if (!automated_get_all_syms(cfg, go)) { + PRINT_VERBOSE(cfg, 1, "no symbols defined\n"); + return -1; + } + + /* TODO + * 1) first run with no symbols + * 2) after each run add new symbol to the 'cur' list from global 'all' list + * 3) 'cur' list has fresh reallocated symbols giving the position and return + * for each symbol occurence + * 4) each 'cur' list symbol moves to new return value if all symbols 'below' it + * has changed all their return values + * 5) finish when first symbol cycles its all return values + * 6) repeating till there are new symbols (from 'all' list) visible + * + */ + + BUG_ON(lt_process_unregister(cfg, process_automated_cb)); + + return ret; +} + +static int process_go_replay(struct lt_config_app *cfg, char *dir, + struct lt_error_app *app, + struct lt_error_app_go *go) +{ + return 0; +} + +static int process_go_configured(struct lt_config_app *cfg, char *dir, + struct lt_error_app *app, + struct lt_error_app_go *go) +{ + int i; + + PRINT_VERBOSE(cfg, 1, "dir '%s', name %s, start %d, n %d\n", + dir, go->name, go->start, go->n); for(i = go->start; i < (go->start + go->n); i++) { struct lt_error_app_run *run; @@ -400,6 +478,28 @@ static int process_go(struct lt_config_app *cfg, char *dir_base, return 0; } +static int process_go(struct lt_config_app *cfg, char *dir_base, + struct lt_error_app *app, + struct lt_error_app_go *go) +{ + static char dir[LT_MAXFILE]; + + if (!app->no_storage && + dir_go(cfg, dir, dir_base, go)) + return -1; + + /* automated processing.. God save us */ + if (go->automated) + return process_go_automated(cfg, dir, app, go); + + /* exact symbols return replay */ + if (go->replay) + return process_go_replay(cfg, dir, app, go); + + /* Whatever user configuration wants.. */ + return process_go_configured(cfg, dir, app, go); +} + int lt_error_run(struct lt_config_app *cfg) { struct lt_error_app *app = cfg->error_app; @@ -493,7 +593,7 @@ int lt_error_run_return(struct lt_config_app *cfg, PRINT_VERBOSE(cfg, 1, "return %s, empty %d\n", ret->name, lt_list_empty(&ret->list_run)); - /* TODO Allow more than 1 RUN assignment to GO, + /* TODO Allow more than 1 RETURN assignment to RUN, * so far only one assignment is allowed. */ if (!lt_list_empty(&ret->list_run)) return -EINVAL; @@ -558,6 +658,7 @@ int lt_error_go(struct lt_config_app *cfg, struct lt_error_app_go **go, struct lt_error_app *error_app, char *name, int start, int n, + int automated, int replay, struct lt_list_head *runs) { struct lt_error_app_go *app_go = *go; @@ -574,6 +675,8 @@ int lt_error_go(struct lt_config_app *cfg, app_go->n = n; app_go->start = start; app_go->name = name; + app_go->automated = automated; + app_go->replay = replay; lt_list_for_each_entry_safe(ln, h, runs, list) { struct lt_error_app_run *run; @@ -625,11 +728,13 @@ app_return_get(struct lt_config_app *cfg, struct lt_error_app_return **ret) int lt_error_return_ass(struct lt_config_app *cfg, struct lt_error_app_return **ret, - char *name, unsigned long val, - int handle_sigsegv) + char *name, struct lt_list_head *list_vals, + int handle_sigsegv, int keep) { struct lt_error_app_return *app_ret = app_return_get(cfg, ret); struct lt_error_app_return_sym *sym; + struct lt_config_ln *ln, *h; + int vals_cnt = 0; if (!app_ret) return -ENOMEM; @@ -639,11 +744,41 @@ int lt_error_return_ass(struct lt_config_app *cfg, return -ENOMEM; sym->name = strdup(name); - sym->val = val; sym->handle_sigsegv = handle_sigsegv; + sym->keep = keep; - PRINT_VERBOSE(cfg, 1, "%s = %ld\n", sym->name, val); + /* process return values name list */ + lt_list_for_each_entry_safe(ln, h, list_vals, list) { + if (vals_cnt == LT_MAX_SYM_RETURNS) { + PRINT_VERBOSE(cfg, 1, + "failed: too many return values for (%d allowed) for symbol %s\n", + LT_MAX_SYM_RETURNS, name); + return -1; + } + + BUG_ON(ln->type != LT_CONFIG_LN_VALUE); + + sym->vals[vals_cnt++] = ln->val; + + lt_list_del(&ln->list); + free(ln); + } + + PRINT_VERBOSE(cfg, 1, "%s = %ld, handle_sigsegv = %d, keep %d\n", + sym->name, sym->val, handle_sigsegv, keep); + + if (vals_cnt > 1) { + int i; + + for(i = 0; i < vals_cnt; i++) + PRINT_VERBOSE(cfg, 1, + "\tret[%d] = %lu\n", + i, sym->vals[i]); + } + + /* It's essential we keep the user + * defined sequenece of symbols. */ lt_list_add_tail(&sym->list, &app_ret->head_sym); return 0; } @@ -673,3 +808,20 @@ int lt_error_app_init(struct lt_error_app *app) app->no_storage = 1; return 0; } + +int lt_error_config_write(struct lt_config_app *cfg, int fd) +{ + struct lt_error_config *cfg_err = cfg->error_config; + int size = sizeof(struct lt_error_config); + + BUG_ON(!cfg_err); + + size += cfg_err->sym_cnt * sizeof(struct lt_error_config_sym); + + if (size != write(fd, cfg_err, size)) { + perror("write failed"); + return -1; + } + + return 0; +} diff --git a/src/error.h b/src/error.h index 2486549..d22ba4f 100644 --- a/src/error.h +++ b/src/error.h @@ -8,24 +8,25 @@ enum { LT_ERROR_FILTER_TYPE_INTERACTIVE, }; -struct lt_error_def_filter { +struct lt_error_config_filter { int type; }; -struct lt_error_def_sym { +struct lt_error_config_sym { #define LT_MAXNAME 20 char symbol[LT_MAXNAME]; +#define LT_MAXRET 20 long ret; + struct lt_error_config_filter filter; + int handle_sigsegv; - struct lt_error_def_filter filter; + int keep; }; -struct lt_error_def { -#define LT_ERROR_MAXSYM 50 - struct lt_error_def_sym sym[LT_ERROR_MAXSYM]; - - /* call number */ +struct lt_error_config { unsigned long n; + int sym_cnt; + struct lt_error_config_sym sym[0]; }; struct lt_error_audit_filter { @@ -47,8 +48,18 @@ struct lt_error_sym { struct lt_error_app_return_sym { char *name; - long val; + +#define LT_MAX_SYM_RETURNS 10 + union { + long val; + long vals[LT_MAX_SYM_RETURNS]; + }; + + /* When the symbol return is changed, + * set SIGSEGV handlers. */ int handle_sigsegv; + /* Do not change the return value. */ + int keep; struct lt_list_head list; }; @@ -78,6 +89,8 @@ struct lt_error_app_run { struct lt_error_app_go { int n; int start; + int automated; + int replay; char *name; struct lt_list_head head_run; @@ -97,6 +110,7 @@ struct lt_error_app { }; struct lt_config_app; +struct lt_config_audit; #ifdef CONFIG_ARCH_HAVE_ERROR_SIM int lt_error_app(struct lt_config_app *cfg, @@ -105,6 +119,7 @@ int lt_error_go(struct lt_config_app *cfg, struct lt_error_app_go **go, struct lt_error_app *error_app, char *name, int start, int n, + int automated, int replay, struct lt_list_head *runs); int lt_error_run_return(struct lt_config_app *cfg, struct lt_error_app_run **run, @@ -115,13 +130,14 @@ int lt_error_run_args(struct lt_config_app *cfg, struct lt_list_head *args); int lt_error_return_ass(struct lt_config_app *cfg, struct lt_error_app_return **ret, - char *name, unsigned long val, - int handle_sigsegv); + char *name, struct lt_list_head *list_vals, + int handle_sigsegv, int keep); int lt_error_return_filter(struct lt_config_app *cfg, struct lt_error_app_return **ret, int type, void *data); - int lt_error_app_init(struct lt_error_app *app); +int lt_error_config_write(struct lt_config_app *cfg, int fd); +int lt_error_config_read(struct lt_config_audit *cfg, int fd); #else static inline int lt_error_app(struct lt_config_app *cfg, struct lt_error_app *error_app) @@ -133,6 +149,7 @@ static inline int lt_error_go(struct lt_config_app *cfg, struct lt_error_app_go **go, struct lt_error_app *error_app, char *name, int start, int n, + int automated, int replay, struct lt_list_head *runs) { return -1; @@ -160,7 +177,8 @@ static inline int lt_error_app_init(struct lt_error_app *app) static inline int lt_error_return_ass(struct lt_config_app *cfg, struct lt_error_app_return **ret, - char *name, unsigned long val) + char *name, struct lt_list_head *list_vals, + int handle_sigsegv, int keep) { return -1; } @@ -172,6 +190,10 @@ static inline int lt_error_return_filter(struct lt_config_app *cfg, return -1; } +static inline int lt_error_config_write(struct lt_config_app *cfg, int fd) +{ + return 0; +} #endif #endif /* ERROR_H */ @@ -62,6 +62,13 @@ static inline void lt_list_del(struct lt_list_head *obj) obj->prev->next = obj->next; } +static inline void lt_list_move_tail(struct lt_list_head *list, + struct lt_list_head *head) +{ + lt_list_del(list); + lt_list_add_tail(list, head); +} + static inline int lt_list_empty(struct lt_list_head *head) { return head->next == head; @@ -70,6 +70,10 @@ static int store_config(struct lt_config_app *cfg, char *file) return -1; } + if (lt_sh(cfg, error_sim) && + lt_error_config_write(cfg, fd)) + return -1; + close(fd); return 0; @@ -210,10 +214,6 @@ static int process(struct lt_config_app *cfg, struct lt_process_args *pa) PRINT_VERBOSE(cfg, 1, "doing pipe\n"); FD_SET(fd_notify, &cfg_set); max_fd = fd_notify; - - /* default fifo processing callback */ - if (lt_process_register(cfg, process_fifo_cb)) - return -1; } if (cfg->output_tty) { @@ -487,6 +487,10 @@ int lt_run(struct lt_config_app *cfg) if (get_config_dir(pa.dir, LT_MAXFILE)) return -1; + /* default fifo processing callback */ + if (lt_process_register(cfg, process_fifo_cb)) + return -1; + do { int status; @@ -524,6 +528,7 @@ int lt_run(struct lt_config_app *cfg) ret = WEXITSTATUS(status); } while(0); + BUG_ON(lt_process_unregister(cfg, process_fifo_cb)); run_cleanup(cfg, &pa); return ret; } @@ -540,3 +545,18 @@ int lt_process_register(struct lt_config_app *cfg, lt_process_cb cb) func->cb = cb; return 0; } + +int lt_process_unregister(struct lt_config_app *cfg, lt_process_cb cb) +{ + struct lt_process_func *func; + + lt_list_for_each_entry(func, &cfg->process_funcs, list) { + if (cb == func->cb) { + lt_list_del(&func->list); + free(func); + return 0; + } + } + + return -EINVAL; +} |