diff options
author | jolsa@redhat.com <jolsa@redhat.com> | 2011-11-01 16:37:03 +0100 |
---|---|---|
committer | Jiri Olsa <Jiri Olsa jolsa@redhat.com> | 2012-01-11 20:06:34 +0100 |
commit | daafe68255b0fbae2d7c1d4c696538327037b067 (patch) | |
tree | 075bf6f26c4464dbd983e240d5d227a7693d95db /src/audit-error.c | |
parent | 363e9f3169f985b1ab2d9b22ffca1f2458581dcd (diff) | |
download | latrace-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.c | 148 |
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; } |