summaryrefslogtreecommitdiffstats
path: root/src/audit-error.c
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>2012-01-11 20:06:34 +0100
commitdaafe68255b0fbae2d7c1d4c696538327037b067 (patch)
tree075bf6f26c4464dbd983e240d5d227a7693d95db /src/audit-error.c
parent363e9f3169f985b1ab2d9b22ffca1f2458581dcd (diff)
downloadlatrace-daafe68255b0fbae2d7c1d4c696538327037b067.tar.gz
latrace-daafe68255b0fbae2d7c1d4c696538327037b067.tar.xz
latrace-daafe68255b0fbae2d7c1d4c696538327037b067.zip
error simulation: automated changes
Diffstat (limited to 'src/audit-error.c')
-rw-r--r--src/audit-error.c148
1 files changed, 107 insertions, 41 deletions
diff --git a/src/audit-error.c b/src/audit-error.c
index 3824d18..f6286cd 100644
--- a/src/audit-error.c
+++ b/src/audit-error.c
@@ -19,13 +19,14 @@ extern FILE *lt_audit_in;
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,
+struct lt_error_sym* lt_error_sym_get(struct lt_config_audit *cfg,
const char *name)
{
struct lt_error_sym *sym;
ENTRY e, *ep;
- BUG_ON(!symbol_tab_init);
+ if (!symbol_tab_init)
+ return NULL;
PRINT_VERBOSE(cfg, 1, "request for <%s>\n", name);
@@ -46,7 +47,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 +59,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 no change, ret %p",
+ ret_addr);
+ else
+ snprintf(text, LT_MAXMSG, "ERROR SIMULATION inserted %ld, ret %p",
+ ret, ret_addr);
if (lt_sh(cfg, pipe)) {
char buf[LT_FIFO_MSG_MAXLEN];
@@ -111,53 +116,86 @@ 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,
+ const char *symname,
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;
+ int handle_sigsegv;
+ long ret;
/* we're not interested in this symbol */
if (!sym || !sym->error)
return -1;
- esym = sym->error;
+ if (cfg_err->type == LT_ERROR_RUN_TYPE_AUTO) {
+ struct lt_error_sym *esym;
- PRINT_VERBOSE(cfg, 1, "symbol %s, call %lu, n %ld\n",
- sym->name, esym->call, cfg_err->n);
+ PRINT_VERBOSE(cfg, 1, "automated_sym_cnt %d, cfg_err->sym_cnt %d\n",
+ automated_sym_cnt, cfg_err->sym_cnt);
- /* we are not interested in this call number */
- if (esym->call++ != cfg_err->n)
- return -1;
+ if (automated_sym_cnt >= cfg_err->sym_cnt)
+ return -1;
+
+ esym = &cfg_err->sym[automated_sym_cnt];
+ ret = esym->ret;
+ keep = esym->keep;
+ handle_sigsegv = esym->handle_sigsegv;
+
+ *info = automated_sym_cnt++;
+ } else {
+
+ esym = sym->error;
+
+ PRINT_VERBOSE(cfg, 1, "symbol %s, call %lu, n %ld\n",
+ sym->name, esym->call_configured, cfg_err->n);
- PRINT_VERBOSE(cfg, 1, "changing retval to %lu\n",
- esym->ret);
+ /* we are not interested in this call number */
+ if (esym->call_current++ != esym->call_configured)
+ return -1;
+
+ ret = esym->ret;
+ handle_sigsegv = esym->handle_sigsegv;
+ }
+
+ 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))
+ if (handle_sigsegv && install_sigsegv(cfg->sh))
PRINT_VERBOSE(cfg, 1, "failed to install SIGSEGV handler\n");
return 0;
}
static int symbol_add(struct lt_config_audit *cfg,
- struct lt_error_config_sym *cfg_sym)
+ struct lt_error_config *cfg_err,
+ struct lt_error_sym *sym)
{
ENTRY e, *ep;
- struct lt_error_sym *sym;
PRINT_VERBOSE(cfg, 1, "symbol %s, ret %ld\n",
- cfg_sym->symbol, cfg_sym->ret);
+ sym->name.symbol, sym->ret);
/* should be safe, since only one thread
* is doing the initialization */
@@ -170,17 +208,16 @@ static int symbol_add(struct lt_config_audit *cfg,
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;
+ e.key = sym->name.symbol;
+ if (hsearch_r(e, FIND, &ep, &symbol_tab)) {
+ PRINT_VERBOSE(cfg, 1, "symbol %s already in the table\n",
+ sym->name.symbol);
+ /* This is a bug in normal processing,
+ * but completelly ok in automated mode. */
+ return cfg_err->type == LT_ERROR_RUN_TYPE_AUTO? 0 : -1;
}
- sym->name = strdup(cfg_sym->symbol);
- sym->ret = cfg_sym->ret;
- sym->handle_sigsegv = cfg_sym->handle_sigsegv;
-
- e.key = sym->name;
+ e.key = sym->name.symbol;
e.data = sym;
if (!hsearch_r(e, ENTER, &ep, &symbol_tab)) {
@@ -197,19 +234,47 @@ static int symbol_add(struct lt_config_audit *cfg,
return 0;
}
+static void display_error_symbols(struct lt_config_audit *cfg,
+ char *names, int size)
+{
+ char *p;
+
+ PRINT_VERBOSE(cfg, 1, "START size %d\n", size);
+
+ while(size) {
+ PRINT_VERBOSE(cfg, 1, "name %s\n", names);
+ p = memchr(names, 0, size);
+ size -= ++p - names;
+ names = p;
+ }
+
+ PRINT_VERBOSE(cfg, 1, "END\n");
+}
+
int lt_error_init(struct lt_config_audit *cfg)
{
struct lt_error_config *cfg_err = cfg->error_config;
int sym_cnt = cfg_err->sym_cnt, i, ok = 1;
+ char *names;
lt_sh(cfg, error_sim) = 0;
+ names = (char*) (((void*) &cfg_err->sym) +
+ (sym_cnt * sizeof(struct lt_error_sym)));
+
+ display_error_symbols(cfg, names, cfg_err->names_size);
+
for(i = 0; i < sym_cnt; i++) {
- struct lt_error_config_sym *cfg_sym;
+ struct lt_error_sym *sym;
- cfg_sym = &cfg_err->sym[i];
+ sym = &cfg_err->sym[i];
- if (symbol_add(cfg, cfg_sym)) {
+ PRINT_VERBOSE(cfg, 1, "symbol index %d, name %s\n",
+ sym->name.index, names + sym->name.index);
+
+ sym->name.symbol = names + sym->name.index;
+
+ if (symbol_add(cfg, cfg_err, sym)) {
ok = 0;
break;
}
@@ -229,17 +294,19 @@ int lt_error_config_read(struct lt_config_audit *cfg, int fd)
{
int size;
struct lt_error_config *cfg_err, cfg_err_st;
+ ssize_t n;
- if (-1 == read(fd, &cfg_err_st, sizeof(cfg_err_st))) {
+ n = read(fd, &cfg_err_st, sizeof(cfg_err_st));
+ if (n != sizeof(cfg_err_st)) {
perror("read failed");
return -1;
}
- size = cfg_err_st.sym_cnt * sizeof(struct lt_error_config_sym);
- if (size <= 0) {
- PRINT_VERBOSE(cfg, 1, "failed: no error symbols defined\n");
- return -1;
- }
+ size = cfg_err_st.sym_cnt * sizeof(struct lt_error_sym);
+ size += cfg_err_st.names_size;
+
+ PRINT_VERBOSE(cfg, 1, "symbols count %d, names_size %d, total size %d\n",
+ cfg_err_st.sym_cnt, cfg_err_st.names_size, size);
cfg_err = malloc(sizeof(*cfg_err) + size);
if (!cfg_err) {
@@ -249,12 +316,11 @@ int lt_error_config_read(struct lt_config_audit *cfg, int fd)
*cfg_err = cfg_err_st;
- if (size != read(fd, cfg_err->sym, size)) {
+ if (size != read(fd, &cfg_err->sym, size)) {
PRINT_VERBOSE(cfg, 1, "failed: no error symbols defined\n");
return -1;
}
cfg->error_config = cfg_err;
-
- return size + sizeof(cfg_err_st);
+ return 0;
}