summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorjolsa@redhat.com <jolsa@redhat.com>2011-11-01 16:37:03 +0100
committerJiri Olsa <Jiri Olsa jolsa@redhat.com>2011-11-13 11:06:37 +0100
commit78a2fe366cf23632dd561e34d849e7fceaefd017 (patch)
tree2e7d692053cb9305262d9058b029aff6547e502b /src
parentbd92a1f2212b5f5cfbc69971067e8d1116e59add (diff)
downloadlatrace-78a2fe366cf23632dd561e34d849e7fceaefd017.tar.gz
latrace-78a2fe366cf23632dd561e34d849e7fceaefd017.tar.xz
latrace-78a2fe366cf23632dd561e34d849e7fceaefd017.zip
error simulation: automated changes
Diffstat (limited to 'src')
-rw-r--r--src/audit-error.c63
-rw-r--r--src/audit.c7
-rw-r--r--src/config.c2
-rw-r--r--src/config.h8
-rw-r--r--src/error.c289
-rw-r--r--src/error.h4
-rw-r--r--src/fifo.c4
-rw-r--r--src/list.h3
8 files changed, 334 insertions, 46 deletions
diff --git a/src/audit-error.c b/src/audit-error.c
index 3824d18..2ece447 100644
--- a/src/audit-error.c
+++ b/src/audit-error.c
@@ -46,7 +46,7 @@ struct lt_error_sym* lt_error_sym_get(struct lt_config_shared *cfg,
extern __thread int pipe_fd;
static void share_info(struct lt_config_audit *cfg,
- struct lt_error_sym *esym,
+ long ret, int keep,
struct timeval *tv,
struct link_map *lr,
const La_regs *inregs)
@@ -58,8 +58,12 @@ static void share_info(struct lt_config_audit *cfg,
lt_error_get_retaddr(cfg, &ret_addr, inregs);
ret_addr -= lr->l_addr;
- snprintf(text, LT_MAXMSG, "ERROR SIMULATION inserted %ld, ret %p",
- esym->ret, ret_addr);
+ if (keep)
+ snprintf(text, LT_MAXMSG, "ERROR SIMULATION inserted %ld, ret %p",
+ ret, ret_addr);
+ else
+ snprintf(text, LT_MAXMSG, "ERROR SIMULATION no change, ret %p",
+ ret_addr);
if (lt_sh(cfg, pipe)) {
char buf[LT_FIFO_MSG_MAXLEN];
@@ -111,15 +115,20 @@ static int install_sigsegv(struct lt_config_shared *cfg)
return sigaction(SIGSEGV, &act, NULL);
}
+static __thread unsigned long automated_sym_cnt = 0;
+
int lt_error_sym_exit(struct lt_config_audit *cfg,
struct lt_symbol *sym,
struct timeval *tv,
struct link_map *lr,
const La_regs *inregs,
- La_retval *outregs)
+ La_retval *outregs,
+ long *info)
{
struct lt_error_sym *esym;
struct lt_error_config *cfg_err = cfg->error_config;
+ int keep = 0;
+ long ret;
/* we're not interested in this symbol */
if (!sym || !sym->error)
@@ -130,19 +139,39 @@ int lt_error_sym_exit(struct lt_config_audit *cfg,
PRINT_VERBOSE(cfg, 1, "symbol %s, call %lu, n %ld\n",
sym->name, esym->call, cfg_err->n);
- /* we are not interested in this call number */
- if (esym->call++ != cfg_err->n)
- return -1;
+ if (cfg_err->automated) {
+ struct lt_error_config_sym *cfg_sym;
+
+ if (automated_sym_cnt >= cfg_err->sym_cnt)
+ return -1;
+
+ cfg_sym = &cfg_err->sym[automated_sym_cnt];
+ ret = cfg_sym->ret;
+ keep = cfg_sym->keep;
- PRINT_VERBOSE(cfg, 1, "changing retval to %lu\n",
- esym->ret);
+ *info = automated_sym_cnt++;
+ } else {
+ /* we are not interested in this call number */
+ if (esym->call++ != cfg_err->n)
+ return -1;
+
+ ret = esym->ret;
+ }
+
+ if (keep)
+ PRINT_VERBOSE(cfg, 1, "keeping the return value\n",
+ ret);
+ else
+ PRINT_VERBOSE(cfg, 1, "changing retval to %lu\n",
+ ret);
/* The fun begins right now.. let's change the return
* value for the symbol ... */
- lt_error_set_retval(cfg, esym->ret, outregs);
+ if (!keep)
+ lt_error_set_retval(cfg, ret, outregs);
/* and share some info about the sinner */
- share_info(cfg, esym, tv, lr, inregs);
+ share_info(cfg, ret, keep, tv, lr, inregs);
if (esym->handle_sigsegv && install_sigsegv(cfg->sh))
PRINT_VERBOSE(cfg, 1, "failed to install SIGSEGV handler\n");
@@ -151,6 +180,7 @@ int lt_error_sym_exit(struct lt_config_audit *cfg,
}
static int symbol_add(struct lt_config_audit *cfg,
+ struct lt_error_config *cfg_err,
struct lt_error_config_sym *cfg_sym)
{
ENTRY e, *ep;
@@ -170,6 +200,15 @@ static int symbol_add(struct lt_config_audit *cfg,
PRINT_VERBOSE(cfg, 1, "symbol table initialized\n");
}
+ e.key = cfg_sym->symbol;
+ if (!hsearch_r(e, FIND, &ep, &symbol_tab)) {
+ PRINT_VERBOSE(cfg, 1, "symbol %s already in the table\n",
+ cfg_sym->symbol);
+ /* This is a bug in normal processing,
+ * but completelly ok in automated mode. */
+ return cfg_err->automated ? 0 : -1;
+ }
+
sym = malloc(sizeof(*sym));
if (!sym) {
PRINT_VERBOSE(cfg, 1, "failed to allocate error symbol\n");
@@ -209,7 +248,7 @@ int lt_error_init(struct lt_config_audit *cfg)
cfg_sym = &cfg_err->sym[i];
- if (symbol_add(cfg, cfg_sym)) {
+ if (symbol_add(cfg, cfg_err, cfg_sym)) {
ok = 0;
break;
}
diff --git a/src/audit.c b/src/audit.c
index 7a83b56..4488d24 100644
--- a/src/audit.c
+++ b/src/audit.c
@@ -114,7 +114,7 @@ static int sym_entry(const char *symname, void *ptr,
pipe_fd = lt_fifo_create(cfg.sh, cfg.dir);
len = lt_fifo_msym_get(cfg.sh, buf, LT_FIFO_MTYPE_ENTRY, &tv,
- (char*) symname, lib_to, argbuf, argdbuf);
+ (char*) symname, lib_to, argbuf, argdbuf, 0);
free_argbuf(argret, argbuf, argdbuf);
return lt_fifo_send(cfg.sh, pipe_fd, buf, len);
@@ -141,6 +141,7 @@ static int sym_exit(const char *symname, void *ptr,
char *argbuf = "", *argdbuf = "";
struct timeval tv;
struct lt_symbol *sym = NULL;
+ long info = -1;
PRINT_VERBOSE(&cfg, 2, "%s@%s\n", symname, lib_to);
@@ -155,7 +156,7 @@ static int sym_exit(const char *symname, void *ptr,
#ifdef CONFIG_ARCH_HAVE_ERROR_SIM
if (lt_sh(&cfg, error_sim))
- lt_error_sym_exit(&cfg, sym, &tv, lr, inregs, outregs);
+ lt_error_sym_exit(&cfg, sym, &tv, lr, inregs, outregs, &info);
#endif
#ifdef CONFIG_ARCH_HAVE_ARGS
@@ -169,7 +170,7 @@ static int sym_exit(const char *symname, void *ptr,
int len;
len = lt_fifo_msym_get(cfg.sh, buf, LT_FIFO_MTYPE_EXIT, &tv,
- (char*) symname, lib_to, argbuf, argdbuf);
+ (char*) symname, lib_to, argbuf, argdbuf, info);
free_argbuf(argret, argbuf, argdbuf);
return lt_fifo_send(cfg.sh, pipe_fd, buf, len);
diff --git a/src/config.c b/src/config.c
index 9bde8a4..868f260 100644
--- a/src/config.c
+++ b/src/config.c
@@ -478,9 +478,11 @@ int lt_config(struct lt_config_app *cfg, int argc, char **argv)
cfg->output_tty_fd = -1;
lt_init_list_head(&cfg->error_apps);
+#ifdef CONFIG_ARCH_HAVE_ERROR_SIM
lt_init_list_head(&cfg->process_funcs);
lt_init_list_head(&cfg->error_symbols_all);
lt_init_list_head(&cfg->error_symbols_current);
+#endif
/* 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 32d6511..ab71324 100644
--- a/src/config.h
+++ b/src/config.h
@@ -197,6 +197,8 @@ struct lt_config_app {
struct lt_list_head error_symbols_all;
struct lt_list_head error_symbols_current;
+ int error_automated_finished;
+ int error_automated_symbol_index;
};
struct lt_config_ctl {
@@ -297,6 +299,7 @@ struct lt_fifo_mbase {
struct lt_fifo_msym {
struct lt_fifo_mbase h;
+ long info;
int sym;
int lib;
int arg;
@@ -381,7 +384,7 @@ int lt_fifo_recv(struct lt_config_shared *cfg, struct lt_thread *t,
void *buf, int bufsize);
int lt_fifo_msym_get(struct lt_config_shared *cfg, char *buf, int type,
struct timeval *tv, char *symname, char *libto,
- char *arg, char *argd);
+ char *arg, char *argd, long info);
int lt_fifo_mtext_get(struct lt_config_shared *cfg, char *buf,
struct timeval *tv, char *text);
@@ -456,7 +459,8 @@ int lt_error_sym_exit(struct lt_config_audit *cfg,
struct timeval *tv,
struct link_map *lr,
const La_regs *inregs,
- La_retval *outregs);
+ La_retval *outregs,
+ long *info);
int lt_error_set_retval(struct lt_config_audit *cfg,
unsigned long ret, La_retval *outregs);
void lt_error_get_retaddr(struct lt_config_audit *cfg,
diff --git a/src/error.c b/src/error.c
index 6698ff8..ec457be 100644
--- a/src/error.c
+++ b/src/error.c
@@ -390,23 +390,22 @@ static int process_run(struct lt_config_app *cfg,
return 0;
}
-static int process_automated_cb(struct lt_config_app *cfg,
- struct lt_thread *t,
- struct lt_fifo_mbase *mbase)
-{
- return 0;
-}
-
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;
+ int count = 0, runs = 1;
lt_list_for_each_entry(run, &go->head_run, list_go) {
struct lt_error_app_return *ret;
+ if (!runs--) {
+ PRINT_VERBOSE(cfg, 1,
+ "failed: supporting only single RUN within AUTOMATED go\n");
+ return -1;
+ }
+
lt_list_for_each_entry(ret, &run->head_return, list_run) {
struct lt_error_app_return_sym *sym;
@@ -417,38 +416,270 @@ static int automated_get_all_syms(struct lt_config_app *cfg,
}
}
+ PRINT_VERBOSE(cfg, 1, "got %d symbols\n", 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)
+long automated_get_index(struct lt_config_app *cfg,
+ struct lt_fifo_mbase *mbase)
+{
+ struct lt_fifo_msym *msym = (struct lt_fifo_msym*) mbase;
+ return msym->info;
+}
+
+static char *automated_get_symname(struct lt_config_app *cfg,
+ struct lt_fifo_mbase *mbase)
+{
+ struct lt_fifo_msym *msym = (struct lt_fifo_msym*) mbase;
+ return msym->data + msym->sym;
+}
+
+static struct lt_error_app_return_sym*
+automated_find_symbol_all(struct lt_config_app *cfg, char *symname)
+{
+ struct lt_error_app_return_sym *sym;
+ struct lt_list_head *sym_all = &cfg->error_symbols_all;
+
+ /* TODO hash, hash, hash... and hash again .. pleaeease ;) hash! */
+ lt_list_for_each_entry(sym, sym_all, list)
+ if (!strcmp(sym->name, symname))
+ return sym;
+
+ return NULL;
+}
+
+static int automated_add_symbol_current(struct lt_config_app *cfg,
+ struct lt_error_app_return_sym *sym_orig)
+{
+ struct lt_error_app_return_sym *sym;
+
+ sym = malloc(sizeof(*sym));
+ if (!sym)
+ return -1;
+
+ *sym = *sym_orig;
+
+ sym->keep = 1;
+ sym->val_idx = 0;
+
+ lt_list_add_tail(&sym->list, &cfg->error_symbols_current);
+ return 0;
+}
+
+static int process_run_automated_cb(struct lt_config_app *cfg,
+ struct lt_thread *t,
+ struct lt_fifo_mbase *mbase)
+{
+ struct lt_error_app_return_sym *sym;
+ struct lt_error_config *error_config;
+ char *symname;
+ long index;
+
+ if (mbase->type != LT_FIFO_MTYPE_EXIT)
+ return 0;
+
+ index = automated_get_index(cfg, mbase);
+ error_config = cfg->error_config;
+
+ if (cfg->error_automated_symbol_index < error_config->sym_cnt) {
+ if (index != -1)
+ BUG_ON((cfg->error_automated_symbol_index + 1) != index);
+ cfg->error_automated_symbol_index = index;
+ return 0;
+ }
+
+ symname = automated_get_symname(cfg, mbase);
+ sym = automated_find_symbol_all(cfg, symname);
+ if (!sym)
+ return 0;
+
+ if (automated_add_symbol_current(cfg, sym))
+ return -1;
+
+ return 0;
+}
+
+static int prepare_config_symbols_automated(struct lt_config_app *cfg)
+{
+ struct lt_list_head *sym_current = &cfg->error_symbols_current;
+
+ while (!lt_list_empty(sym_current)) {
+ struct lt_error_app_return_sym *last;
+
+ last = lt_list_last_entry(sym_current,
+ struct lt_error_app_return_sym,
+ list);
+
+ PRINT_VERBOSE(cfg, 1, "last %s\n", last->name);
+
+ if (last->keep) {
+ int idx = last->val_idx;
+ last->keep = 0;
+
+ PRINT_VERBOSE(cfg, 1, "from keep to vals[%d] = %llu\n",
+ idx, last->vals[idx]);
+ break;
+ } else {
+ int idx = last->val_idx + 1;
+
+ if (idx < last->val_cnt) {
+ last->val_idx = idx;
+
+ PRINT_VERBOSE(cfg, 1, "from vals[%d] = %llu to vals[%d] = %llu\n",
+ idx - 1, last->vals[idx - 1],
+ idx, last->vals[idx]);
+ break;
+ }
+
+ PRINT_VERBOSE(cfg, 1, "removing\n");
+ lt_list_del(&last->list);
+ }
+ }
+
+ /* nothing more to try, we are done */
+ if (lt_list_empty(sym_current)) {
+ PRINT_VERBOSE(cfg, 1, "FINISHED\n");
+ cfg->error_automated_finished = 1;
+ return 0;
+ }
+
+ return 0;
+}
+
+static int prepare_config_error_automated(struct lt_config_app *cfg,
+ struct lt_error_app_run *run)
{
- int ret = 0;
+ struct lt_list_head *sym_current = &cfg->error_symbols_current;
+ struct lt_error_app_return_sym *sym;
+ struct lt_error_config *cfg_err;
+ int sym_cnt = 0;
+
+ lt_list_for_each_entry(sym, sym_current, list)
+ sym_cnt++;
+
+ BUG_ON(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->automated = 1;
+
+ sym_cnt = 0;
+
+ lt_list_for_each_entry(sym, sym_current, list) {
+ struct lt_error_config_sym *cfg_sym;
+
+ cfg_sym = &cfg_err->sym[sym_cnt++];
+ strncpy(cfg_sym->symbol, sym->name, LT_MAXNAME);
+ cfg_sym->ret = sym->vals[sym->val_idx];
+ cfg_sym->keep = sym->keep;
+ cfg_sym->handle_sigsegv = sym->handle_sigsegv;
- if (lt_process_register(cfg, process_automated_cb))
+ PRINT_VERBOSE(cfg, 1, "symbol %s, ret %s\n",
+ sym->name, cfg_sym->ret);
+ }
+
+ cfg->error_config = cfg_err;
+ return 0;
+}
+
+static int prepare_config_automated(struct lt_config_app *cfg,
+ char *dir,
+ struct lt_error_app *app,
+ struct lt_error_app_run *run,
+ int n)
+{
+ if (prepare_config_trace(cfg, dir))
+ return -1;
+
+ if (prepare_config_stat(cfg, dir))
return -1;
- if (!automated_get_all_syms(cfg, go)) {
- PRINT_VERBOSE(cfg, 1, "no symbols defined\n");
+ if (prepare_config_tty(cfg, dir))
return -1;
+
+ if (prepare_config_args(cfg, app, run))
+ return -1;
+
+ /* omit the first run */
+ if (n && prepare_config_symbols_automated(cfg))
+ return -1;
+
+ if (prepare_config_error_automated(cfg, run))
+ return -1;
+
+ return 0;
+}
+
+static void automated_dump_config(struct lt_config_app *cfg,
+ struct lt_error_app *app,
+ char *dir)
+{
+ /* dump config to be replayed with REPLAY */
+}
+
+static void post_config_automated(struct lt_config_app *cfg,
+ struct lt_error_app *app,
+ char *dir)
+{
+ post_config(cfg, app);
+ automated_dump_config(cfg, app, dir);
+ free(cfg->error_config);
+}
+
+static int process_run_automated(struct lt_config_app *cfg,
+ char *dir_base,
+ struct lt_error_app *app,
+ struct lt_error_app_run *run)
+{
+ static char dir[LT_MAXFILE];
+ int n = 0;
+
+ if (lt_process_register(cfg, process_run_automated_cb))
+ return -1;
+
+ while(1) {
+ if (dir_run(cfg, dir, dir_base, run, n))
+ break;
+
+ if (prepare_config_automated(cfg, dir, app, run, n))
+ break;
+
+ if (cfg->error_automated_finished)
+ break;
+
+ lt_run(cfg);
+
+ post_config_automated(cfg, app, dir);
+
+ n++;
}
- /* 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_run_automated_cb));
+
+ return cfg->error_automated_finished ? 0 : -1;
+}
+
+static int process_go_automated(struct lt_config_app *cfg, char *dir,
+ struct lt_error_app *app,
+ struct lt_error_app_go *go)
+{
+ struct lt_error_app_run *run;
+
+ if (!automated_get_all_syms(cfg, go) <= 0)
+ return -1;
+
+ run = lt_list_first_entry(&go->head_run, struct lt_error_app_run, list_go);
- BUG_ON(lt_process_unregister(cfg, process_automated_cb));
+ if (process_run_automated(cfg, dir, app, run))
+ PRINT_VERBOSE(cfg, 1, "failed: AUTOMATED run %s\n", run->name);
- return ret;
+ return 0;
}
static int process_go_replay(struct lt_config_app *cfg, char *dir,
@@ -765,6 +996,8 @@ int lt_error_return_ass(struct lt_config_app *cfg,
free(ln);
}
+ sym->val_cnt = vals_cnt;
+
PRINT_VERBOSE(cfg, 1, "%s = %ld, handle_sigsegv = %d, keep %d\n",
sym->name, sym->val, handle_sigsegv, keep);
diff --git a/src/error.h b/src/error.h
index d22ba4f..e60ef5b 100644
--- a/src/error.h
+++ b/src/error.h
@@ -25,6 +25,7 @@ struct lt_error_config_sym {
struct lt_error_config {
unsigned long n;
+ int automated;
int sym_cnt;
struct lt_error_config_sym sym[0];
};
@@ -55,6 +56,9 @@ struct lt_error_app_return_sym {
long vals[LT_MAX_SYM_RETURNS];
};
+ int val_idx;
+ int val_cnt;
+
/* When the symbol return is changed,
* set SIGSEGV handlers. */
int handle_sigsegv;
diff --git a/src/fifo.c b/src/fifo.c
index 776cd28..632bf91 100644
--- a/src/fifo.c
+++ b/src/fifo.c
@@ -172,7 +172,7 @@ int lt_fifo_recv(struct lt_config_shared *cfg, struct lt_thread *t, void *buf,
int lt_fifo_msym_get(struct lt_config_shared *cfg, char *buf, int type,
struct timeval *tv, char *symname, char *libto,
- char *arg, char *argd)
+ char *arg, char *argd, long info)
{
struct lt_fifo_msym *m = (struct lt_fifo_msym*) buf;
int len_data, len = sizeof(struct lt_fifo_msym);
@@ -182,6 +182,8 @@ int lt_fifo_msym_get(struct lt_config_shared *cfg, char *buf, int type,
m->h.tid = (pid_t) syscall(SYS_gettid);
m->h.tv = *tv;
+ m->info = info;
+
m->sym = 0;
m->lib = strlen(symname);
m->arg = m->lib + strlen(libto) + 1;
diff --git a/src/list.h b/src/list.h
index 027fcdc..a683346 100644
--- a/src/list.h
+++ b/src/list.h
@@ -93,6 +93,9 @@ static inline int lt_list_empty(struct lt_list_head *head)
#define lt_list_first_entry(head, type, member) \
lt_list_entry((head)->next, type, member)
+#define lt_list_last_entry(head, type, member) \
+ lt_list_entry((head)->prev, type, member)
+
#define lt_list_for_each_entry(pos, head, member) \
for (pos = lt_list_entry((head)->next, typeof(*pos), member); \
&(pos)->member != (head); \