diff options
author | jolsa@redhat.com <jolsa@redhat.com> | 2011-06-20 16:14:11 +0200 |
---|---|---|
committer | Jiri Olsa <Jiri Olsa jolsa@redhat.com> | 2011-11-24 21:20:27 +0100 |
commit | d4d4ddd698f1378649e33aa58b7e3b687a2e6c3d (patch) | |
tree | e3748aa5978ca912c964f4f50defe3b3b4740a52 | |
parent | 2d6cc3704e7affeb56c798b39a942daca95385dc (diff) | |
download | latrace-d4d4ddd698f1378649e33aa58b7e3b687a2e6c3d.tar.gz latrace-d4d4ddd698f1378649e33aa58b7e3b687a2e6c3d.tar.xz latrace-d4d4ddd698f1378649e33aa58b7e3b687a2e6c3d.zip |
error simulation: library part
-rw-r--r-- | src/Makefile | 7 | ||||
-rw-r--r-- | src/audit-error.c | 166 | ||||
-rw-r--r-- | src/audit-init.c | 14 | ||||
-rw-r--r-- | src/audit.c | 3 | ||||
-rw-r--r-- | src/config.h | 11 | ||||
-rw-r--r-- | src/symbol.c | 15 | ||||
-rw-r--r-- | src/sysdeps/i686/error.c | 15 | ||||
-rw-r--r-- | src/sysdeps/x86_64/error.c | 15 |
8 files changed, 239 insertions, 7 deletions
diff --git a/src/Makefile b/src/Makefile index 6b849d3..e009358 100644 --- a/src/Makefile +++ b/src/Makefile @@ -40,6 +40,13 @@ AUDIT_OBJS+=\ src/sysdeps/$(CONFIG_SYSDEP_DIR)/stack.o endif +# TODO make this for all error simulation objects +ifeq ($(CONFIG_ARCH_HAVE_ERROR_SIM),y) +AUDIT_OBJS+=\ + src/sysdeps/$(CONFIG_SYSDEP_DIR)/error.o \ + src/audit-error.o +endif + OBJS+=$(AUDIT_OBJS) PROGRAMS+= $(AUDIT_BIN) # no dependency for flex and bison definitions diff --git a/src/audit-error.c b/src/audit-error.c new file mode 100644 index 0000000..6a9bc50 --- /dev/null +++ b/src/audit-error.c @@ -0,0 +1,166 @@ + +#include <stdio.h> +#include <search.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/syscall.h> +#include <strings.h> +#include <string.h> + +#include "config.h" + +int lt_audit_parse_init(struct lt_config_shared *cfg); +int lt_audit_parse(); +extern FILE *lt_audit_in; + +#define SYMBOL_TAB_SIZE 100 +static struct hsearch_data symbol_tab; +static int symbol_tab_init = 0; + +struct lt_error_sym* lt_error_sym_get(struct lt_config_shared *cfg, + const char *name) +{ + struct lt_error_sym *sym; + ENTRY e, *ep; + + BUG_ON(!symbol_tab_init); + + PRINT_VERBOSE(cfg, 1, "request for <%s>\n", name); + + e.key = (char*) name; + hsearch_r(e, FIND, &ep, &symbol_tab); + + if (!ep) { + PRINT_VERBOSE(cfg, 1, "failed to find <%s>\n", name); + return NULL; + } + + sym = (struct lt_error_sym*) ep->data; + + PRINT_VERBOSE(cfg, 1, "found %p <%s>\n", sym, sym->name); + return sym; +} + +extern __thread int pipe_fd; + +int lt_error_sym_exit(struct lt_config_audit *cfg, + struct lt_symbol *sym, + struct timeval *tv, + La_retval *outregs) +{ + struct lt_error_sym *esym; +#define LT_MAXMSG 100 + char text[LT_MAXMSG]; + + /* we're not interested in this symbol */ + if (!sym || !sym->error) + return -1; + + esym = sym->error; + + PRINT_VERBOSE(cfg, 1, "symbol %s, call %lu, n %ld\n", + sym->name, esym->call, lt_sh(cfg, error_def.n)); + + /* we are not interested in this call number */ + if (esym->call++ != lt_sh(cfg, error_def.n)) + return -1; + + PRINT_VERBOSE(cfg, 1, "changing retval to %lu\n", + esym->ret); + + /* The fun begins right now.. let's change the return + * value for the symbol */ + + lt_error_set_retval(cfg, esym->ret, outregs); + + snprintf(text, LT_MAXMSG, "ERROR SIMULATION inserted %ld", + esym->ret); + + if (lt_sh(cfg, pipe)) { + char buf[LT_FIFO_MSG_MAXLEN]; + int len; + + len = lt_fifo_mtext_get(cfg, buf, tv, text); + return lt_fifo_send(cfg, pipe_fd, buf, len); + } + + lt_out_text(cfg->sh, tv, syscall(SYS_gettid), text); + return 0; +} + +static int symbol_add(struct lt_config_audit *cfg, + struct lt_error_def_sym *def_sym) +{ + ENTRY e, *ep; + struct lt_error_sym *sym; + + PRINT_VERBOSE(cfg, 1, "symbol %s, ret %ld\n", + def_sym->symbol, def_sym->ret); + + /* should be safe, since only one thread + * is doing the initialization */ + if (!symbol_tab_init) { + if (!hcreate_r(SYMBOL_TAB_SIZE, &symbol_tab)) { + perror("failed to create hash table"); + return -1; + } + symbol_tab_init = 1; + PRINT_VERBOSE(cfg, 1, "symbol table initialized\n"); + } + + sym = malloc(sizeof(*sym)); + if (!sym) { + PRINT_VERBOSE(cfg, 1, "failed to allocate error symbol\n"); + return -1; + } + + sym->name = strdup(def_sym->symbol); + sym->ret = def_sym->ret; + + e.key = sym->name; + e.data = sym; + + if (!hsearch_r(e, ENTER, &ep, &symbol_tab)) { + perror("hsearch_r failed"); + free(sym); + + PRINT_VERBOSE(cfg, 3, + "reached the error symbol limit %d\n", + SYMBOL_TAB_SIZE); + return -1; + } + + PRINT_VERBOSE(cfg, 1, "ok\n"); + return 0; +} + +int lt_error_init(struct lt_config_audit *cfg) +{ + struct lt_error_def *error_def = <_sh(cfg, error_def); + int i = 0, ok = 1; + + lt_sh(cfg, error_sim) = 0; + + + for(i = 0; (i < LT_ERROR_MAXSYM); i++) { + struct lt_error_def_sym *sym_def; + + sym_def = &error_def->sym[i]; + if (!*sym_def->symbol) + break; + + if (symbol_add(cfg, sym_def)) { + ok = 0; + break; + } + } + + if (!ok) { + if (symbol_tab_init) + hdestroy_r(&symbol_tab); + return -1; + } + + lt_sh(cfg, error_sim) = 1; + return 0; +} diff --git a/src/audit-init.c b/src/audit-init.c index c3f96a4..092bb0c 100644 --- a/src/audit-init.c +++ b/src/audit-init.c @@ -253,8 +253,18 @@ int audit_init(int argc, char **argv, char **env) if (lt_sh(&cfg, not_follow_fork)) lt_sh(&cfg, pid) = getpid(); - /* enable global symbols if needed */ - lt_sh(&cfg, global_symbols) = lt_sh(&cfg, args_enabled); + /* error simulation */ + if (lt_sh(&cfg, error_sim)) + lt_error_init(&cfg); + + /* + enable global symbols if + - we need to display arguments + - we do the error simulation + */ + lt_sh(&cfg, global_symbols) = \ + lt_sh(&cfg, args_enabled) || + lt_sh(&cfg, error_sim); PRINT_VERBOSE(&cfg, 1, "global_symbols %d\n", lt_sh(&cfg, global_symbols)); diff --git a/src/audit.c b/src/audit.c index 40e67ee..3adfa3e 100644 --- a/src/audit.c +++ b/src/audit.c @@ -149,6 +149,9 @@ static int sym_exit(const char *symname, void *ptr, if (lt_sh(&cfg, global_symbols)) sym = lt_symbol_get(cfg.sh, ptr, symname); + if (lt_sh(&cfg, error_sim)) + lt_error_sym_exit(&cfg, sym, &tv, outregs); + #ifdef CONFIG_ARCH_HAVE_ARGS argret = lt_sh(&cfg, args_enabled) ? lt_args_sym_exit(cfg.sh, sym, diff --git a/src/config.h b/src/config.h index a47a4da..b2dc73a 100644 --- a/src/config.h +++ b/src/config.h @@ -435,6 +435,17 @@ int lt_error_app(struct lt_config_app *cfg, struct lt_error_app *error_app); int lt_error_set(struct lt_config_app *cfg, char *error); int lt_error_run(struct lt_config_app *cfg); +/* error simulation lib */ +int lt_error_init(struct lt_config_audit *cfg); +struct lt_error_sym* lt_error_sym_get(struct lt_config_shared *cfg, + const char *name); +int lt_error_sym_exit(struct lt_config_audit *cfg, + struct lt_symbol *sym, + struct timeval *tv, + La_retval *outregs); +int lt_error_set_retval(struct lt_config_audit *cfg, + unsigned long ret, La_retval *outregs); + #define PRINT(fmt, args...) \ do { \ char lpbuf[1024]; \ diff --git a/src/symbol.c b/src/symbol.c index f10045a..707fbf6 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -74,14 +74,19 @@ static int symbol_init(struct lt_config_shared *cfg, struct lt_symbol *sym, const char *name) { struct lt_args_sym *a = NULL; + struct lt_error_sym *e = NULL; - if (lt_sh(cfg, args_enabled)) { + if (lt_sh(cfg, args_enabled)) a = lt_args_sym_get(cfg, name); - if (!a) - return -1; - } - sym->args = a; + if (lt_sh(cfg, error_sim)) + e = lt_error_sym_get(cfg, name); + + if (!a && !e) + return -1; + + sym->args = a; + sym->error = e; PRINT_VERBOSE(cfg, 1, "ok name %s, ptr %p, sym %p\n", name, sym->ptr, sym); diff --git a/src/sysdeps/i686/error.c b/src/sysdeps/i686/error.c new file mode 100644 index 0000000..fd675a5 --- /dev/null +++ b/src/sysdeps/i686/error.c @@ -0,0 +1,15 @@ + +#include <strings.h> + +#include "config.h" + +int lt_error_set_retval(struct lt_config_audit *cfg, + unsigned long ret, La_retval *outregs) +{ + bzero(outregs, sizeof(*outregs)); + + outregs->lrv_edx = 0; + outregs->lrv_eax = (uint32_t) ret; + + return 0; +} diff --git a/src/sysdeps/x86_64/error.c b/src/sysdeps/x86_64/error.c new file mode 100644 index 0000000..36784cd --- /dev/null +++ b/src/sysdeps/x86_64/error.c @@ -0,0 +1,15 @@ + +#include <strings.h> + +#include "config.h" + +int lt_error_set_retval(struct lt_config_audit *cfg, + unsigned long ret, La_retval *outregs) +{ + bzero(outregs, sizeof(*outregs)); + + outregs->lrv_rdx = 0; + outregs->lrv_rax = (uint32_t) ret; + + return 0; +} |