summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjolsa@redhat.com <jolsa@redhat.com>2011-06-20 16:14:11 +0200
committerJiri Olsa <Jiri Olsa jolsa@redhat.com>2011-11-24 21:20:27 +0100
commitd4d4ddd698f1378649e33aa58b7e3b687a2e6c3d (patch)
treee3748aa5978ca912c964f4f50defe3b3b4740a52
parent2d6cc3704e7affeb56c798b39a942daca95385dc (diff)
downloadlatrace-d4d4ddd698f1378649e33aa58b7e3b687a2e6c3d.tar.gz
latrace-d4d4ddd698f1378649e33aa58b7e3b687a2e6c3d.tar.xz
latrace-d4d4ddd698f1378649e33aa58b7e3b687a2e6c3d.zip
error simulation: library part
-rw-r--r--src/Makefile7
-rw-r--r--src/audit-error.c166
-rw-r--r--src/audit-init.c14
-rw-r--r--src/audit.c3
-rw-r--r--src/config.h11
-rw-r--r--src/symbol.c15
-rw-r--r--src/sysdeps/i686/error.c15
-rw-r--r--src/sysdeps/x86_64/error.c15
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 = &lt_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;
+}