summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Olsa <Jiri Olsa jolsa@redhat.com>2011-10-18 10:00:38 +0200
committerJiri Olsa <Jiri Olsa jolsa@redhat.com>2011-11-13 15:49:02 +0100
commitbf4e90d73c73d645e705d5fca68f9e8a41493784 (patch)
tree3f2db5ee4c50ca615f20e32b74d11d9b877c0b3b
parent0717d984e1c3596a82dcf302a9fd9c74993ee647 (diff)
downloadlatrace-bf4e90d73c73d645e705d5fca68f9e8a41493784.tar.gz
latrace-bf4e90d73c73d645e705d5fca68f9e8a41493784.tar.xz
latrace-bf4e90d73c73d645e705d5fca68f9e8a41493784.zip
error simulation: application part
-rw-r--r--configure.ac9
-rw-r--r--etc/latrace.d/latrace.conf.in69
-rw-r--r--src/Makefile10
-rw-r--r--src/audit-init.c1
-rw-r--r--src/audit.c2
-rw-r--r--src/autoconf.h.in3
-rw-r--r--src/autoconf.make.in2
-rw-r--r--src/config-bison.y170
-rw-r--r--src/config-flex.l36
-rw-r--r--src/config.c44
-rw-r--r--src/config.h21
-rw-r--r--src/error.c660
-rw-r--r--src/error.h171
-rw-r--r--src/fifo.c8
-rw-r--r--src/latrace.c5
-rw-r--r--src/symbol.c2
16 files changed, 1170 insertions, 43 deletions
diff --git a/configure.ac b/configure.ac
index aeb951e..aa80b3a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -103,6 +103,15 @@ else
AC_MSG_WARN([No automated test support])
fi
+# for following architectures we have error simulation support
+if test "$unamem" = "x86_64" -o\
+ "$unamem" = "i686"; then
+ AC_DEFINE(CONFIG_ARCH_HAVE_ERROR_SIM)
+ AC_SUBST(CONFIG_ARCH_HAVE_ERROR_SIM, "y")
+else
+ AC_MSG_WARN([Error simulation support disabled])
+fi
+
AC_SEARCH_LIBS([cplus_demangle], [iberty_pic iberty],
[AC_DEFINE(CONFIG_LIBERTY, 1, "Liberty found.")],
[AC_MSG_WARN([libiberty not found, no demangle support (install binutils-dev)])])
diff --git a/etc/latrace.d/latrace.conf.in b/etc/latrace.d/latrace.conf.in
index 2788b00..80c6247 100644
--- a/etc/latrace.d/latrace.conf.in
+++ b/etc/latrace.d/latrace.conf.in
@@ -96,3 +96,72 @@ OPTIONS {
# function arguments - display string length and pointer value
ARGS_STRING_POINTER_LENGTH = NO
}
+
+# error simulation
+#
+#ERROR krava {
+# DIR /krava/
+# PROG krava
+#
+# RETURN R1 {
+# malloc = 100
+# krava = 1
+# FILTER NTH 10,12,14
+# }
+#
+# RETURN R2 {
+# malloc = 100 FILTER SEQ
+# krava = 1 FILTER NTH 10,1-5
+# }
+#
+# RETURN R3 {
+# malloc = 100
+# krava = 1
+# FILTER STACK stack1
+# }
+#
+# RETURN R3 {
+# malloc = 100
+# krava = 1
+# FILTER ARGS krava ARG a = 10
+# }
+#
+# RETURN R4 {
+# malloc = 100
+# krava = 1
+# FILTER INTERACTIVE
+# }
+#
+# RUN run1 {
+# RETURN R1
+# ARGS
+# }
+#
+# RUN run2 {
+# RETURN R1
+# RETURN R2
+# ARGS
+# }
+#
+# RUN run3 {
+# RETURN R1
+# RETURN R2
+# ARGS a a a
+# }
+#
+# GO go1 N=100 run1,run2
+# GO go2 run3
+#}
+#
+# directory structure
+# -------------------
+# DIR/latrace-PROG
+# - created based on DIR/PROG settings
+# DIR/latrace-PROG/latest
+# - created by latest run instance
+# DIR/latrace-PROG/latest-TIME
+# - moved from current latest dir
+# DIR/latrace-PROG/latest/GO/
+# - created by processed GO
+# DIR/latrace-PROG/latest/GO/RUN-N
+# - created by processed RUN plus N value
diff --git a/src/Makefile b/src/Makefile
index 169a5f3..6b849d3 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -72,13 +72,19 @@ LATRACE_OBJS=\
src/lib-include.o \
src/tty.o
+ifeq ($(CONFIG_ARCH_HAVE_ERROR_SIM),y)
+LATRACE_OBJS+=\
+ src/error.o
+endif
+
OBJS+=$(LATRACE_OBJS)
PROGRAMS+=$(LATRACE_BIN)
CPPFLAGS+=-DCONFIG_LIBDIR=\"$(libdir)\"
CPPFLAGS+=-DLT_CONF_DIR=\"$(sysconfdir)/latrace.d\"
CPPFLAGS+=-DLT_CONF_HEADERS_DIR=\"$(sysconfdir)/latrace.d/headers\"
CPPFLAGS+=-DLT_CONF_HEADERS_FILE=\"$(sysconfdir)/latrace.d/headers/latrace.h\"
-# no dependency for flex and bison definitions
+CPPFLAGS+=-DLT_CONF_ERRORS_DIR=\"$(sysconfdir)/latrace.d/errors\"
+
OBJS_DEPS_OMIT+=\
src/config-bison.o \
src/config-flex.o
@@ -93,4 +99,6 @@ install::
clean::
$(call remove, src/config-bison.[ch] src/config-flex.c)
$(call remove, src/args-bison.[ch] src/args-flex.c)
+ $(call remove, src/audit-bison.[ch] src/audit-flex.c)
$(call remove, src/config-bison.output src/args-bison.output)
+ $(call remove, src/audit-bison.output)
diff --git a/src/audit-init.c b/src/audit-init.c
index f36fee3..c3f96a4 100644
--- a/src/audit-init.c
+++ b/src/audit-init.c
@@ -255,6 +255,7 @@ int audit_init(int argc, char **argv, char **env)
/* enable global symbols if needed */
lt_sh(&cfg, global_symbols) = lt_sh(&cfg, args_enabled);
+
PRINT_VERBOSE(&cfg, 1, "global_symbols %d\n", lt_sh(&cfg, global_symbols));
cfg.init_ok = 1;
diff --git a/src/audit.c b/src/audit.c
index 6f46e22..40e67ee 100644
--- a/src/audit.c
+++ b/src/audit.c
@@ -37,7 +37,7 @@
extern struct lt_config_audit cfg;
-static __thread int pipe_fd = 0;
+__thread int pipe_fd = 0;
static __thread int flow_below_stack = 0;
static __thread int indent_depth = 0;
diff --git a/src/autoconf.h.in b/src/autoconf.h.in
index 6d698a7..d2f53fb 100644
--- a/src/autoconf.h.in
+++ b/src/autoconf.h.in
@@ -30,6 +30,9 @@
/* Argument display support. */
#undef CONFIG_ARCH_HAVE_ARGS
+/* Error simulation support. */
+#undef CONFIG_ARCH_HAVE_ERROR_SIM
+
/* liberty */
#undef CONFIG_LIBERTY
diff --git a/src/autoconf.make.in b/src/autoconf.make.in
index a49c37e..9655f4a 100644
--- a/src/autoconf.make.in
+++ b/src/autoconf.make.in
@@ -47,3 +47,5 @@ CONFIG_SYSDEP_DIR = @CONFIG_SYSDEP_DIR@
CONFIG_VERSION = @CONFIG_VERSION@
CONFIG_ARCH_HAVE_ARGS = @CONFIG_ARCH_HAVE_ARGS@
CONFIG_ARCH_HAVE_TEST = @CONFIG_ARCH_HAVE_TEST@
+
+CONFIG_ARCH_HAVE_ERROR_SIM = @CONFIG_ARCH_HAVE_ERROR_SIM@
diff --git a/src/config-bison.y b/src/config-bison.y
index 944f59b..14ee5a3 100644
--- a/src/config-bison.y
+++ b/src/config-bison.y
@@ -21,8 +21,9 @@
%name-prefix "lt_config_"
%{
-#include <stdlib.h>
+#include <strings.h>
#include <string.h>
+#include <stdlib.h>
#include "config.h"
#include "lib-include.h"
@@ -33,7 +34,7 @@ static struct lt_config_app *scfg;
int lt_config_lex(void);
void lt_config_error(const char *m);
-#define ERROR(fmt, args...) \
+#define ABORT(fmt, args...) \
do { \
char ebuf[1024]; \
sprintf(ebuf, fmt, ## args); \
@@ -42,13 +43,17 @@ do { \
} while(0)
static LT_LIST_HEAD(opt_list);
+static struct lt_error_app error_app;
+static struct lt_error_app_run *error_app_run;
+static struct lt_error_app_go *error_app_go;
+static struct lt_error_app_return *error_app_return;
#define OPTION_ADD(idx, sval, nval) \
do { \
struct lt_config_opt *opt; \
opt = lt_config_opt_new(scfg, idx, sval, nval); \
if (!opt) \
- ERROR("failed to process option\n"); \
+ ABORT("failed to process option\n"); \
lt_list_add_tail(&opt->list, &opt_list); \
} while(0)
@@ -66,6 +71,9 @@ static struct lt_list_head ln_names;
%token OPT_LIBS OPT_LIBS_TO OPT_LIBS_FROM
%token OPT_SYM OPT_SYM_OMIT OPT_SYM_BELOW OPT_SYM_NOEXIT
%token OPT_ARGS_STRING_POINTER_LENGTH
+%token ERROR
+%token ERR_DO ERR_DIR ERR_RUN ERR_GO ERR_RETURN ERR_N
+%token ERR_PROG ERR_ARGS ERR_FILTER ERR_SEQ
%union
{
@@ -79,9 +87,11 @@ static struct lt_list_head ln_names;
%%
entry:
-entry include_def
+entry include
|
-entry options_def
+entry options
+|
+entry errors
|
entry END
{
@@ -91,18 +101,18 @@ entry END
|
/* left blank intentionally */
-include_def: INCLUDE '"' NAME '"'
+include: INCLUDE '"' NAME '"'
{
if (lt_inc_open(scfg->sh, lt_config_sinc, $3))
- ERROR("failed to process include");
+ ABORT("failed to process include");
}
-options_def: OPTIONS '{' OPTIONS_DEF '}'
+options: OPTIONS '{' OPTIONS_DEF '}'
{
struct lt_config_opt *opt, *opth;
if (lt_config_opt_process(scfg, &opt_list))
- ERROR("failed to process options");
+ ABORT("failed to process options");
lt_list_for_each_entry_safe(opt, opth, &opt_list, list) {
lt_list_del(&opt->list);
@@ -185,8 +195,8 @@ OPTIONS_DEF OPT_LIBS '=' list_names_comma
{
char libs[LT_LIBS_MAXSIZE];
- if (lt_config_ln_fill(&ln_names, libs, LT_LIBS_MAXSIZE))
- ERROR("failed to process libs option");
+ if (lt_config_ln_fill_buf(&ln_names, libs, LT_LIBS_MAXSIZE))
+ ABORT("failed to process libs option");
OPTION_ADD(LT_OPT_LIBS, libs, -1);
}
@@ -195,8 +205,8 @@ OPTIONS_DEF OPT_LIBS_TO '=' list_names_comma
{
char libs_to[LT_LIBS_MAXSIZE];
- if (lt_config_ln_fill(&ln_names, libs_to, LT_LIBS_MAXSIZE))
- ERROR("failed to process libs_to option");
+ if (lt_config_ln_fill_buf(&ln_names, libs_to, LT_LIBS_MAXSIZE))
+ ABORT("failed to process libs_to option");
OPTION_ADD(LT_OPT_LIBS_TO, libs_to, -1);
}
@@ -205,8 +215,8 @@ OPTIONS_DEF OPT_LIBS_FROM '=' list_names_comma
{
char libs_from[LT_LIBS_MAXSIZE];
- if (lt_config_ln_fill(&ln_names, libs_from, LT_LIBS_MAXSIZE))
- ERROR("failed to process libs_from option");
+ if (lt_config_ln_fill_buf(&ln_names, libs_from, LT_LIBS_MAXSIZE))
+ ABORT("failed to process libs_from option");
OPTION_ADD(LT_OPT_LIBS_FROM, libs_from, -1);
}
@@ -215,8 +225,8 @@ OPTIONS_DEF OPT_SYM '=' list_names_comma
{
char sym[LT_LIBS_MAXSIZE];
- if (lt_config_ln_fill(&ln_names, sym, LT_LIBS_MAXSIZE))
- ERROR("failed to process sym option");
+ if (lt_config_ln_fill_buf(&ln_names, sym, LT_LIBS_MAXSIZE))
+ ABORT("failed to process sym option");
OPTION_ADD(LT_OPT_SYM, sym, -1);
}
@@ -225,8 +235,8 @@ OPTIONS_DEF OPT_SYM_OMIT '=' list_names_comma
{
char sym_omit[LT_SYMBOLS_MAXSIZE];
- if (lt_config_ln_fill(&ln_names, sym_omit, LT_SYMBOLS_MAXSIZE))
- ERROR("failed to process sym_omit option");
+ if (lt_config_ln_fill_buf(&ln_names, sym_omit, LT_SYMBOLS_MAXSIZE))
+ ABORT("failed to process sym_omit option");
OPTION_ADD(LT_OPT_SYM_OMIT, sym_omit, -1);
}
@@ -235,8 +245,8 @@ OPTIONS_DEF OPT_SYM_BELOW '=' list_names_comma
{
char sym_below[LT_SYMBOLS_MAXSIZE];
- if (lt_config_ln_fill(&ln_names, sym_below, LT_SYMBOLS_MAXSIZE))
- ERROR("failed to process sym_below option");
+ if (lt_config_ln_fill_buf(&ln_names, sym_below, LT_SYMBOLS_MAXSIZE))
+ ABORT("failed to process sym_below option");
OPTION_ADD(LT_OPT_SYM_BELOW, sym_below, -1);
}
@@ -245,8 +255,8 @@ OPTIONS_DEF OPT_SYM_NOEXIT '=' list_names_comma
{
char sym_noexit[LT_SYMBOLS_MAXSIZE];
- if (lt_config_ln_fill(&ln_names, sym_noexit, LT_SYMBOLS_MAXSIZE))
- ERROR("failed to process sym_below option");
+ if (lt_config_ln_fill_buf(&ln_names, sym_noexit, LT_SYMBOLS_MAXSIZE))
+ ABORT("failed to process sym_below option");
OPTION_ADD(LT_OPT_SYM_NOEXIT, sym_noexit, -1);
}
@@ -262,21 +272,125 @@ list_names_comma:
list_names_comma ',' NAME
{
if (lt_config_ln_add(&ln_names, $3))
- ERROR("failed to add list name");
+ ABORT("failed to add list name");
}
|
NAME
{
if (lt_config_ln_add(&ln_names, $1))
- ERROR("failed to add list name");
+ ABORT("failed to add list name");
+}
+
+errors: ERROR NAME '{' error_def '}'
+{
+ error_app.name = strdup($2);
+
+ if (lt_error_app(scfg, &error_app))
+ ABORT("failed to add error");
+
+ lt_error_app_init(&error_app);
+}
+
+error_def:
+error_def error_run
+{
+ lt_list_add_tail(&error_app_run->list_app, &error_app.head_run);
+ error_app_run = NULL;
+}
+|
+error_def error_go
+{
+ lt_list_add_tail(&error_app_go->list, &error_app.head_go);
+ error_app_go = NULL;
+}
+|
+error_def error_return
+{
+ lt_list_add_tail(&error_app_return->list_app, &error_app.head_return);
+ error_app_return = NULL;
+}
+|
+error_def ERR_DIR NAME
+{
+ error_app.dir = strdup($3);
+}
+|
+error_def ERR_PROG NAME
+{
+ if (error_app.prog)
+ ABORT("only one PROG clause allowed");
+
+ error_app.prog = strdup($3);
+}
+|
+/* left blank intentionally */
+
+
+error_return: ERR_RETURN NAME '{' error_return_def '}'
+{
+ error_app_return->name = strdup($2);
+}
+
+error_return_def:
+error_return_def NAME '=' VALUE
+{
+ if (lt_error_return_ass(scfg, &error_app_return, $2, $4))
+ ABORT("failed to add symbol to return definition");
+}
+|
+error_return_def ERR_FILTER ERR_SEQ
+{
+ if (lt_error_return_filter(scfg, &error_app_return,
+ LT_ERROR_FILTER_TYPE_SEQ, NULL))
+ ABORT("failed to add filter to return definition");
+}
+|
+/* left blank intentionally */
+
+
+error_run: ERR_RUN NAME '{' error_run_def '}'
+{
+ error_app_run->name = strdup($2);
+}
+
+error_run_def:
+error_run_def ERR_ARGS list_names_comma
+{
+ if (lt_error_run_args(scfg, &error_app_run, &ln_names))
+ ABORT("failed to add run");
+}
+|
+error_run_def ERR_RETURN list_names_comma
+{
+ if (lt_error_run_return(scfg, &error_app_run, &error_app, &ln_names))
+ ABORT("failed to add run");
+}
+|
+
+error_go:
+ERR_GO NAME list_names_comma
+{
+ if (lt_error_go(scfg, &error_app_go, &error_app,
+ strdup($2), 1, &ln_names))
+ ABORT("failed to add go");
+}
+|
+ERR_GO NAME ERR_N '=' VALUE list_names_comma
+{
+ if (lt_error_go(scfg, &error_app_go, &error_app,
+ strdup($2), $5, &ln_names))
+ ABORT("failed to add go");
}
%%
int lt_config_parse_init(struct lt_config_app *cfg, struct lt_include *inc)
{
- scfg = cfg;
- lt_config_sinc = inc;
+ scfg = cfg;
+ lt_config_sinc = inc;
lt_init_list_head(&ln_names);
- return 0;
+ lt_error_app_init(&error_app);
+ error_app_run = NULL;
+ error_app_go = NULL;
+ return 0;
}
diff --git a/src/config-flex.l b/src/config-flex.l
index 433992f..3b761d7 100644
--- a/src/config-flex.l
+++ b/src/config-flex.l
@@ -30,6 +30,7 @@
extern struct lt_include *lt_config_sinc;
+static int block_cnt;
#define NEW_LINE() \
do { \
@@ -46,6 +47,17 @@ do { \
lt_config_lval.l = atol(lt_config_text); return token; \
} while(0)
+#define BLOCK_BEGIN() \
+do { \
+ block_cnt++; \
+} while(0)
+
+#define BLOCK_END() \
+do { \
+ if (!--block_cnt) \
+ BEGIN(INITIAL); \
+} while(0)
+
%}
num [-0-9]
@@ -54,7 +66,7 @@ name ([-0-9a-zA-Z\./_\-\*])+
bool YES|NO
comment ^([\s\t])*#.*
-%x comment include options
+%x comment include options error
%%
@@ -106,6 +118,28 @@ OPTIONS { BEGIN(options); return OPTIONS; }
<options>"\n" { NEW_LINE(); }
<options>. { ; }
+ERROR { BEGIN(error); return ERROR; }
+<error>DIR { return ERR_DIR; }
+<error>RUN { return ERR_RUN; }
+<error>GO { return ERR_GO; }
+<error>RETURN { return ERR_RETURN; }
+<error>PROG { return ERR_PROG; }
+<error>ARGS { return ERR_ARGS; }
+<error>N { return ERR_N; }
+<error>FILTER { return ERR_FILTER; }
+<error>SEQ { return ERR_SEQ; }
+
+<error>{value} { RETURN_LONG(VALUE); }
+<error>{name} { RETURN_STR(NAME); }
+<error>{comment} { ; }
+<error>"}" { BLOCK_END(); return '}'; }
+<error>"{" { BLOCK_BEGIN(); return '{'; }
+<error>"=" { return '='; }
+<error>"\"" { return '"'; }
+<error>"\\" { ; }
+<error>"," { return ','; }
+<error>"\n" { NEW_LINE(); }
+<error>. { ; }
%%
#ifndef yywrap
diff --git a/src/config.c b/src/config.c
index 9fea08b..b04ec2c 100644
--- a/src/config.c
+++ b/src/config.c
@@ -87,6 +87,8 @@ static void usage()
printf(" -R, --ctl-config controled config\n");
printf(" -q, --disable disable auditing\n");
printf("\n");
+ printf(" -e, --error error set error simulation\n");
+ printf("\n");
printf(" -v, --verbose verbose output\n");
printf(" -V, --version display version\n");
printf(" -h, --help display help\n");
@@ -392,7 +394,7 @@ int lt_config_ln_add(struct lt_list_head *head, char *name)
return 0;
}
-int lt_config_ln_fill(struct lt_list_head *head, char *buf, int size)
+int lt_config_ln_fill_buf(struct lt_list_head *head, char *buf, int size)
{
struct lt_config_ln *ln, *n;
int first = 1;
@@ -422,6 +424,30 @@ int lt_config_ln_fill(struct lt_list_head *head, char *buf, int size)
return 0;
}
+char **lt_config_ln_fill_array(struct lt_list_head *head)
+{
+ struct lt_config_ln *ln, *n;
+ char **array = NULL;
+ int i = 0;
+
+ lt_list_for_each_entry_safe(ln, n, head, list) {
+
+ /* starting from zero index and keeping NULL
+ * at the end of the args array*/
+ array = realloc(array, sizeof(*array) * (i + 2));
+ if (!array)
+ return NULL;
+
+ array[i++] = ln->name;
+ array[i] = NULL;
+
+ lt_list_del(&ln->list);
+ free(ln);
+ }
+
+ return array;
+}
+
int lt_config(struct lt_config_app *cfg, int argc, char **argv)
{
memset(cfg, 0, sizeof(*cfg));
@@ -439,6 +465,7 @@ int lt_config(struct lt_config_app *cfg, int argc, char **argv)
cfg->csort = LT_CSORT_CALL;
cfg->fstat = stdout;
cfg->output_tty_fd = -1;
+ lt_init_list_head(&cfg->error_apps);
lt_init_list_head(&cfg->process_funcs);
@@ -480,12 +507,13 @@ int lt_config(struct lt_config_app *cfg, int argc, char **argv)
{"no-follow-exec", no_argument, 0, 'E'},
{"disable", no_argument, 0, 'q'},
{"ctl-config", no_argument, 0, 'R'},
+ {"error", required_argument, 0, 'e'},
{"version", no_argument, 0, 'V'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
};
- c = getopt_long(argc, argv, "+s:n:l:t:f:vhi:BdISb:cC:y:YL:po:a:N:ADVTFERq",
+ c = getopt_long(argc, argv, "+s:n:l:t:f:vhi:BdISb:cC:y:YL:po:a:N:ADVTFERe:q",
long_options, &option_index);
if (c == -1)
@@ -643,6 +671,16 @@ int lt_config(struct lt_config_app *cfg, int argc, char **argv)
lt_sh(cfg, ctl_config) = 1;
break;
+ #ifndef CONFIG_ARCH_HAVE_ERROR_SIM
+ case 'e':
+ printf("Error simulation support not compiled in");
+ #else
+ case 'e':
+ if (lt_error_set(cfg, optarg))
+ usage();
+ #endif /* CONFIG_ARCH_HAVE_ERROR_SIM */
+ break;
+
case 'V':
version();
break;
@@ -667,7 +705,7 @@ int lt_config(struct lt_config_app *cfg, int argc, char **argv)
cfg->arg_num = i_arg;
}
- if (!cfg->prog) {
+ if ((!cfg->prog) && (!lt_sh(cfg, error_sim))) {
printf("failed: no program specified\n");
usage();
}
diff --git a/src/config.h b/src/config.h
index 4ab0886..a47a4da 100644
--- a/src/config.h
+++ b/src/config.h
@@ -31,6 +31,7 @@
#include "audit.h"
#include "list.h"
+#include "error.h"
#ifdef CONFIG_ARCH_HAVE_ARGS
#include "args.h"
@@ -152,10 +153,14 @@ struct lt_config_shared {
int framesize_check;
unsigned int framesize;
int global_symbols;
+ int error_sim;
/* for 'not_follow_fork' */
pid_t pid;
+ /* error definition (error_sim = 1) */
+ struct lt_error_def error_def;
+
/* XXX feel like an idiot.. find another way!!! */
struct lt_config_shared *sh;
};
@@ -187,6 +192,11 @@ struct lt_config_app {
int notify_fd_watch;
struct lt_list_head process_funcs;
+
+ /* current error */
+ struct lt_error_app *error_app;
+ /* list of defined errors */
+ struct lt_list_head error_apps;
};
struct lt_config_ctl {
@@ -325,7 +335,8 @@ struct lt_thread {
};
struct lt_symbol {
- struct lt_args_sym *args;
+ struct lt_args_sym *args;
+ struct lt_error_sym *error;
/* symbol name */
const char *name;
@@ -406,7 +417,8 @@ struct lt_config_opt *lt_config_opt_new(struct lt_config_app *cfg,
int idx, char *sval, long nval);
int lt_config_opt_process(struct lt_config_app *cfg, struct lt_list_head *list);
int lt_config_ln_add(struct lt_list_head *head, char *name);
-int lt_config_ln_fill(struct lt_list_head *head, char *buf, int size);
+int lt_config_ln_fill_buf(struct lt_list_head *head, char *buf, int size);
+char **lt_config_ln_fill_array(struct lt_list_head *head);
/* tty */
int tty_master(struct lt_config_app *cfg);
@@ -418,6 +430,11 @@ void tty_close(struct lt_config_app *cfg);
/* process functions registration */
int lt_process_register(struct lt_config_app *cfg, lt_process_cb cb);
+/* error simulation app */
+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);
+
#define PRINT(fmt, args...) \
do { \
char lpbuf[1024]; \
diff --git a/src/error.c b/src/error.c
new file mode 100644
index 0000000..68cf302
--- /dev/null
+++ b/src/error.c
@@ -0,0 +1,660 @@
+
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "config.h"
+
+int lt_error_app(struct lt_config_app *cfg, struct lt_error_app *error_app)
+{
+ struct lt_error_app *app;
+ struct lt_error_app_go *go, *g;
+ struct lt_error_app_run *run, *r;
+
+ if (!error_app->prog ||
+ !error_app->dir)
+ return -EINVAL;
+
+ app = malloc(sizeof(*app));
+ if (!app)
+ return -ENOMEM;
+
+ /* XXX Just copy whatever we got from the bison app object,
+ * but afterwards we need to reinit all the lists, since
+ * it's based on the bison object.
+ * There's probably more sane way to have the app object
+ * dynamically allocated from the start.. let's wait for
+ * someone smart to do that ;) */
+
+ *app = *error_app;
+
+ lt_init_list_head(&app->head_run);
+ lt_init_list_head(&app->head_go);
+ lt_init_list_head(&app->list);
+
+ lt_list_for_each_entry_safe(run, r, &error_app->head_run, list_app) {
+ lt_list_del(&run->list_app);
+ lt_list_add_tail(&run->list_app, &app->head_run);
+ }
+
+ lt_list_for_each_entry_safe(go, g, &error_app->head_go, list) {
+ lt_list_del(&go->list);
+ lt_list_add_tail(&go->list, &app->head_go);
+ }
+
+ lt_list_add_tail(&app->list, &cfg->error_apps);
+
+ return 0;
+}
+
+int lt_error_set(struct lt_config_app *cfg, char *error)
+{
+ struct lt_error_app *app;
+ int found = 0;
+
+ lt_list_for_each_entry(app, &cfg->error_apps, list) {
+ if (!strcmp(error, app->name)) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ return -EINVAL;
+
+ lt_sh(cfg, error_sim) = 1;
+ cfg->error_app = app;
+ return 0;
+}
+
+#define LT_DIR_PERM (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)
+
+static int dir_get(struct lt_config_app *cfg, char *dir, int exist_check)
+{
+ struct stat st;
+
+ PRINT_VERBOSE(cfg, 1, "exist_check %d, dir '%s'\n", exist_check, dir);
+
+ if (!stat(dir, &st)) {
+ if (exist_check) {
+ printf("failed: directory already exists '%s'\n", dir);
+ return -EEXIST;
+ }
+
+ /* TODO permission check */
+ return 0;
+ }
+
+ if (mkdir(dir, LT_DIR_PERM)) {
+ PRINT_VERBOSE(cfg, 1, "failed to create directory '%s'\n",
+ dir);
+ /* XXX some sensiblle return value ;) */
+ return -1;
+ }
+
+ return 0;
+}
+
+static int dir_base_name(struct lt_config_app *cfg,
+ char *buf, int len,
+ char *dir, char *prog)
+{
+ char file[LT_MAXFILE];
+ char *last_bs;
+ int size;
+
+ PRINT_VERBOSE(cfg, 1, "dir '%s', prog '%s'\n", dir, prog);
+
+ last_bs = strrchr(prog, '/');
+ if (last_bs) {
+ /* move behind '/' */
+ last_bs++;
+
+ /* endup with '/' isnt nice */
+ if (!strlen(last_bs))
+ return 0;
+
+ size = snprintf(file, LT_MAXFILE, "%s", last_bs);
+ } else
+ size = snprintf(file, LT_MAXFILE, "%s", prog);
+
+ PRINT_VERBOSE(cfg, 1, "file '%s'\n", file);
+
+ if (size == LT_MAXFILE)
+ return 0;
+
+ size = snprintf(buf, len, "%s/latrace-%s/", dir, file);
+ if (size == len)
+ return 0;
+
+ PRINT_VERBOSE(cfg, 1, "main dir '%s'\n", buf);
+ return size;
+}
+
+static int dir_base(struct lt_config_app *cfg, struct lt_error_app *app, char *dir)
+{
+ int size;
+ int ret;
+
+ /* We dont create parents, just one level..
+ * whatever pass mkdir ;) */
+ if (dir_get(cfg, app->dir, 0))
+ return -1;
+
+ size = dir_base_name(cfg, dir, LT_MAXFILE, app->dir, app->prog);
+ if (!size)
+ return -1;
+
+ if (dir_get(cfg, dir, 0))
+ return -1;
+
+ size = snprintf(dir + size , LT_MAXFILE, "latest");
+ if (size == LT_MAXFILE)
+ return -1;
+
+ ret = dir_get(cfg, dir, 1);
+ if (ret == -EEXIST) {
+ /* TODO move latest */
+ return -1;
+ } else if (ret != 0) {
+ return ret;
+ }
+
+ return 0;
+}
+
+static int dir_go(struct lt_config_app *cfg,
+ char *dir, char *dir_base,
+ struct lt_error_app_go *go)
+{
+ int size;
+
+ size = snprintf(dir, LT_MAXFILE, "%s/GO-%s/", dir_base, go->name);
+ if (size == LT_MAXFILE)
+ return -1;
+
+ if (dir_get(cfg, dir, 0))
+ return -1;
+
+ return 0;
+}
+
+static int dir_run(struct lt_config_app *cfg,
+ char *dir, char *dir_base,
+ struct lt_error_app_run *run, int n)
+{
+ int size;
+
+ size = snprintf(dir, LT_MAXFILE, "%s/RUN-%s-%05d/", dir_base, run->name, n);
+ if (size == LT_MAXFILE)
+ return -1;
+
+ if (dir_get(cfg, dir, 0))
+ return -1;
+
+ return 0;
+}
+
+static int prepare_config_trace(struct lt_config_app *cfg, char *dir)
+{
+ FILE *f;
+
+ snprintf(lt_sh(cfg, output), LT_MAXFILE, "%s/trace", dir);
+
+ PRINT_VERBOSE(cfg, 1, "trace file %s\n", lt_sh(cfg, output));
+
+ /* If the pipe mode is on, the latrace itself is doing the
+ * the trace output to the file, we need to open the output
+ * file each run */
+ if (lt_sh(cfg, pipe)) {
+
+ f = fopen(lt_sh(cfg, output), "w");
+ if (!f) {
+ perror("pipe mode: failed to open output file");
+ return -1;
+ }
+
+ lt_sh(cfg, fout) = f;
+ PRINT_VERBOSE(cfg, 1, "trace file pipe enabled\n");
+ }
+
+ return 0;
+}
+
+static int prepare_config_stat(struct lt_config_app *cfg, char *dir)
+{
+ char stat_file[LT_MAXFILE];
+ FILE *f;
+
+ snprintf(stat_file, LT_MAXFILE, "%s/stat", dir);
+ f = fopen(stat_file, "w");
+ if (!f) {
+ perror("failed to open stat file");
+ return -1;
+ }
+
+ cfg->fstat = f;
+
+ PRINT_VERBOSE(cfg, 1, "stat file %s\n", stat_file);
+ return 0;
+}
+
+static int prepare_config_tty(struct lt_config_app *cfg, char *dir)
+{
+ cfg->output_tty = 1;
+ cfg->output_tty_fd = -1;
+ snprintf(cfg->output_tty_file, LT_MAXFILE, "%s/tty-output", dir);
+
+ PRINT_VERBOSE(cfg, 1, "tty output file %s\n", cfg->output_tty_file);
+ return 0;
+}
+
+static int prepare_config_args(struct lt_config_app *cfg,
+ struct lt_error_app *app,
+ struct lt_error_app_run *run)
+{
+ int i = 1, size;
+ char **arg = run->args;
+#define BUFSIZE 4096
+ char buf[BUFSIZE];
+
+ cfg->prog = app->prog;
+ cfg->arg[0] = app->prog;
+
+ size = snprintf(buf, BUFSIZE, "%s", app->prog);
+
+ while(arg && *arg && (i < LT_NUM_ARG)) {
+ PRINT_VERBOSE(cfg, 1, "arg: %s\n", *arg);
+ size += snprintf(buf + size, BUFSIZE, " %s", *arg);
+ cfg->arg[i++] = *arg++;
+ }
+
+ PRINT_VERBOSE(cfg, 1, "args: %s\n", buf);
+ return 0;
+}
+
+static int prepare_config_error(struct lt_config_app *cfg,
+ struct lt_error_app_run *run,
+ int n)
+{
+ struct lt_error_app_return *ret;
+ struct lt_error_def *error_def = &lt_sh(cfg, error_def);
+ int i = 0;
+
+ bzero(error_def, sizeof(struct lt_error_def));
+
+ lt_list_for_each_entry(ret, &run->head_return, list_run) {
+ struct lt_error_app_return_sym *sym;
+
+ lt_list_for_each_entry(sym, &ret->head_sym, list) {
+ struct lt_error_def_sym *sym_def;
+
+ sym_def = &error_def->sym[i];
+ strncpy(sym_def->symbol, sym->name, LT_MAXNAME);
+ sym_def->ret = sym->val;
+ sym_def->filter.type = ret->filter.type;
+
+ PRINT_VERBOSE(cfg, 1, "symbol %s, ret %s\n",
+ sym->name, sym->val);
+
+ if (i++ >= LT_ERROR_MAXSYM)
+ return -1;
+ }
+ }
+
+ lt_sh(cfg, error_def.n) = n;
+ PRINT_VERBOSE(cfg, 1, "N = %d\n", n);
+ return 0;
+}
+
+static int prepare_config(struct lt_config_app *cfg, char *dir,
+ struct lt_error_app *app,
+ struct lt_error_app_run *run, int n)
+{
+ PRINT_VERBOSE(cfg, 1, "dir '%s'\n", dir);
+
+ if (prepare_config_trace(cfg, dir))
+ return -1;
+
+ if (prepare_config_stat(cfg, dir))
+ return -1;
+
+ if (prepare_config_tty(cfg, dir))
+ return -1;
+
+ if (prepare_config_args(cfg, app, run))
+ return -1;
+
+ if (prepare_config_error(cfg, run, n))
+ return -1;
+
+ return 0;
+}
+
+static void post_config(struct lt_config_app *cfg)
+{
+ if ((lt_sh(cfg, pipe)) && (*lt_sh(cfg, output)))
+ fclose(lt_sh(cfg, fout));
+
+ fclose(cfg->fstat);
+}
+
+static int process_run(struct lt_config_app *cfg,
+ char *dir_base,
+ struct lt_error_app *app,
+ struct lt_error_app_go *go,
+ struct lt_error_app_run *run,
+ int n)
+{
+ static char dir[LT_MAXFILE];
+
+ if (dir_run(cfg, dir, dir_base, run, n))
+ return -1;
+
+ PRINT_VERBOSE(cfg, 1, "dir '%s'\n", dir);
+
+ if (prepare_config(cfg, dir, app, run, n))
+ return -1;
+
+ lt_run(cfg);
+
+ post_config(cfg);
+
+ return 0;
+}
+
+static int process_go(struct lt_config_app *cfg, char *dir_base,
+ struct lt_error_app *app,
+ struct lt_error_app_go *go)
+{
+ static char dir[LT_MAXFILE];
+ int i;
+
+ if (dir_go(cfg, dir, dir_base, go))
+ return -1;
+
+ PRINT_VERBOSE(cfg, 1, "dir '%s'\n", dir);
+
+ for(i = 0; i < go->n; i++) {
+ struct lt_error_app_run *run;
+
+ lt_list_for_each_entry(run, &go->head_run, list_go)
+ if (process_run(cfg, dir, app, go, run, i))
+ return -1;
+ }
+
+ return 0;
+}
+
+int lt_error_run(struct lt_config_app *cfg)
+{
+ struct lt_error_app *app = cfg->error_app;
+ struct lt_error_app_go *go;
+ static char dir[LT_MAXFILE];
+
+ printf("latrace error simulation [%s]\n", app->name);
+
+ if (dir_base(cfg, app, dir))
+ return -1;
+
+ PRINT_VERBOSE(cfg, 1, "dir '%s'\n", dir);
+
+ lt_list_for_each_entry(go, &app->head_go, list) {
+ if (process_go(cfg, dir, app, go))
+ return -1;
+ }
+
+ return 0;
+}
+
+static struct lt_error_app_run *app_run_get(struct lt_config_app *cfg,
+ struct lt_error_app_run **run)
+{
+
+ PRINT_VERBOSE(cfg, 1, "run %p\n", *run);
+
+ if (!*run) {
+ struct lt_error_app_run *app_run;
+
+ app_run = malloc(sizeof(*app_run));
+ if (!app_run)
+ return NULL;
+
+ bzero(app_run, sizeof(*app_run));
+ lt_init_list_head(&app_run->head_return);
+ lt_init_list_head(&app_run->list_go);
+ lt_init_list_head(&app_run->list_app);
+
+ *run = app_run;
+ PRINT_VERBOSE(cfg, 1, "new %p\n", *run);
+ }
+
+ return *run;
+}
+
+static struct lt_error_app_return*
+find_return(struct lt_config_app *cfg,
+ struct lt_error_app *error_app,
+ char *name)
+{
+ struct lt_error_app_return *ret;
+
+ PRINT_VERBOSE(cfg, 1, "looking for %s\n", name);
+
+ lt_list_for_each_entry(ret, &error_app->head_return, list_app) {
+
+ PRINT_VERBOSE(cfg, 2, "got %s\n", ret->name);
+
+ if (!strcmp(name, ret->name)) {
+ PRINT_VERBOSE(cfg, 2, "FOUND\n");
+ return ret;
+ }
+ }
+
+ PRINT_VERBOSE(cfg, 1, "NOT FOUND\n");
+ return NULL;
+}
+
+int lt_error_run_return(struct lt_config_app *cfg,
+ struct lt_error_app_run **run,
+ struct lt_error_app *error_app,
+ struct lt_list_head *rets)
+{
+ struct lt_error_app_run *app_run = app_run_get(cfg, run);
+ struct lt_config_ln *ln, *h;
+
+ if (!app_run)
+ return -ENOMEM;
+
+ PRINT_VERBOSE(cfg, 1, "run %s\n", app_run->name);
+
+ lt_list_for_each_entry_safe(ln, h, rets, list) {
+ struct lt_error_app_return *ret;
+
+ ret = find_return(cfg, error_app, ln->name);
+ if (!ret)
+ return -EINVAL;
+
+ PRINT_VERBOSE(cfg, 1, "return %s, empty %d\n",
+ ret->name, lt_list_empty(&ret->list_run));
+
+ /* TODO Allow more than 1 RUN assignment to GO,
+ * so far only one assignment is allowed. */
+ if (!lt_list_empty(&ret->list_run))
+ return -EINVAL;
+
+ lt_list_add_tail(&ret->list_run, &app_run->head_return);
+
+ lt_list_del(&ln->list);
+ free(ln->name);
+ free(ln);
+ }
+
+ return 0;
+}
+
+int lt_error_run_args(struct lt_config_app *cfg,
+ struct lt_error_app_run **run,
+ struct lt_list_head *head)
+{
+ struct lt_error_app_run *app_run = app_run_get(cfg, run);
+ char **args = NULL;
+
+ if (!app_run)
+ return -ENOMEM;
+
+ /* only one ARGS definition perf RUN */
+ if (app_run->args)
+ return -EINVAL;
+
+ args = lt_config_ln_fill_array(head);
+ if (!args)
+ return -ENOMEM;
+
+ PRINT_VERBOSE(cfg, 1, "args %p\n", args);
+
+ app_run->args = args;
+ return 0;
+}
+
+static struct lt_error_app_run *find_run(struct lt_config_app *cfg,
+ struct lt_error_app *error_app,
+ char *name)
+{
+ struct lt_error_app_run *run;
+
+ PRINT_VERBOSE(cfg, 1, "looking for %s\n", name);
+
+ lt_list_for_each_entry(run, &error_app->head_run, list_app) {
+
+ PRINT_VERBOSE(cfg, 2, "got %s\n", run->name);
+
+ if (!strcmp(name, run->name)) {
+ PRINT_VERBOSE(cfg, 2, "FOUND\n");
+ return run;
+ }
+ }
+
+ PRINT_VERBOSE(cfg, 1, "NOT FOUND\n");
+ return NULL;
+}
+
+int lt_error_go(struct lt_config_app *cfg,
+ struct lt_error_app_go **go,
+ struct lt_error_app *error_app,
+ char *name, int n,
+ struct lt_list_head *runs)
+{
+ struct lt_error_app_go *app_go = *go;
+ struct lt_config_ln *ln, *h;
+
+ if (app_go)
+ return -EINVAL;
+
+ app_go = malloc(sizeof(*app_go));
+ bzero(app_go, sizeof(*app_go));
+ lt_init_list_head(&app_go->head_run);
+ lt_init_list_head(&app_go->list);
+
+ app_go->n = n;
+ app_go->name = name;
+
+ lt_list_for_each_entry_safe(ln, h, runs, list) {
+ struct lt_error_app_run *run;
+
+ run = find_run(cfg, error_app, ln->name);
+ if (!run)
+ return -EINVAL;
+
+ PRINT_VERBOSE(cfg, 1, "run %s, empty %d\n",
+ run->name, lt_list_empty(&run->list_go));
+
+ /* TODO Allow more than 1 RUN assignment to GO,
+ * so far only one assignment is allowed. */
+ if (!lt_list_empty(&run->list_go))
+ return -EINVAL;
+
+ lt_list_add_tail(&run->list_go, &app_go->head_run);
+
+ lt_list_del(&ln->list);
+ free(ln->name);
+ free(ln);
+ }
+
+ *go = app_go;
+ return 0;
+}
+
+static struct lt_error_app_return*
+app_return_get(struct lt_config_app *cfg, struct lt_error_app_return **ret)
+{
+ if (!*ret) {
+ struct lt_error_app_return *app_return;
+
+ app_return = malloc(sizeof(*app_return));
+ if (!app_return)
+ return NULL;
+
+ bzero(app_return, sizeof(*app_return));
+ lt_init_list_head(&app_return->head_sym);
+ lt_init_list_head(&app_return->list_app);
+ lt_init_list_head(&app_return->list_run);
+
+ *ret = app_return;
+ PRINT_VERBOSE(cfg, 1, "new %p\n", *ret);
+ }
+
+ return *ret;
+}
+
+int lt_error_return_ass(struct lt_config_app *cfg,
+ struct lt_error_app_return **ret,
+ char *name, unsigned long val)
+{
+ struct lt_error_app_return *app_ret = app_return_get(cfg, ret);
+ struct lt_error_app_return_sym *sym;
+
+ if (!app_ret)
+ return -ENOMEM;
+
+ sym = malloc(sizeof(*sym));
+ if (!sym)
+ return -ENOMEM;
+
+ sym->name = strdup(name);
+ sym->val = val;
+
+ PRINT_VERBOSE(cfg, 1, "%s = %ld\n", sym->name, val);
+
+ lt_list_add_tail(&sym->list, &app_ret->head_sym);
+ return 0;
+}
+
+int lt_error_return_filter(struct lt_config_app *cfg,
+ struct lt_error_app_return **ret,
+ int type, void *data)
+{
+ struct lt_error_app_return *app_ret = app_return_get(cfg, ret);
+
+ if (!app_ret)
+ return -ENOMEM;
+
+ app_ret->filter.type = type;
+ PRINT_VERBOSE(cfg, 1, "type %d\n", type);
+ return 0;
+}
+
+
+int lt_error_app_init(struct lt_error_app *app)
+{
+ bzero(app, sizeof(*app));
+ lt_init_list_head(&app->head_run);
+ lt_init_list_head(&app->head_go);
+ lt_init_list_head(&app->head_return);
+ lt_init_list_head(&app->list);
+ return 0;
+}
diff --git a/src/error.h b/src/error.h
new file mode 100644
index 0000000..5c44633
--- /dev/null
+++ b/src/error.h
@@ -0,0 +1,171 @@
+#ifndef ERROR_H
+#define ERROR_H
+
+enum {
+ LT_ERROR_FILTER_TYPE_NTH,
+ LT_ERROR_FILTER_TYPE_SEQ,
+ LT_ERROR_FILTER_TYPE_STACK,
+ LT_ERROR_FILTER_TYPE_INTERACTIVE,
+};
+
+struct lt_error_def_filter {
+ int type;
+};
+
+struct lt_error_def_sym {
+#define LT_MAXNAME 20
+ char symbol[LT_MAXNAME];
+ long ret;
+ struct lt_error_def_filter filter;
+};
+
+struct lt_error_def {
+#define LT_ERROR_MAXSYM 50
+ struct lt_error_def_sym sym[LT_ERROR_MAXSYM];
+
+ /* call number */
+ unsigned long n;
+};
+
+struct lt_error_audit_filter {
+ int type;
+ union {
+ int **nth;
+ };
+};
+
+struct lt_error_sym {
+ char *name;
+ unsigned long ret;
+ unsigned long call;
+ struct lt_error_audit_filter filter;
+
+ struct lt_list_head list;
+};
+
+struct lt_error_app_return_sym {
+ char *name;
+ long val;
+
+ struct lt_list_head list;
+};
+
+struct lt_error_app_filter {
+ int type;
+};
+
+struct lt_error_app_return {
+ char *name;
+ struct lt_error_app_filter filter;
+
+ struct lt_list_head head_sym;
+ struct lt_list_head list_app;
+ struct lt_list_head list_run;
+};
+
+struct lt_error_app_run {
+ char *name;
+ char **args;
+
+ struct lt_list_head head_return;
+ struct lt_list_head list_go;
+ struct lt_list_head list_app;
+};
+
+struct lt_error_app_go {
+ int n;
+ char *name;
+
+ struct lt_list_head head_run;
+ struct lt_list_head list;
+};
+
+struct lt_error_app {
+ char *name;
+ char *dir;
+ char *prog;
+
+ struct lt_list_head head_run;
+ struct lt_list_head head_go;
+ struct lt_list_head head_return;
+ struct lt_list_head list;
+};
+
+struct lt_config_app;
+
+#ifdef CONFIG_ARCH_HAVE_ERROR_SIM
+int lt_error_app(struct lt_config_app *cfg,
+ struct lt_error_app *error_app);
+int lt_error_go(struct lt_config_app *cfg,
+ struct lt_error_app_go **go,
+ struct lt_error_app *error_app,
+ char *name, int n,
+ struct lt_list_head *runs);
+int lt_error_run_return(struct lt_config_app *cfg,
+ struct lt_error_app_run **run,
+ struct lt_error_app *error_app,
+ struct lt_list_head *ret);
+int lt_error_run_args(struct lt_config_app *cfg,
+ struct lt_error_app_run **run,
+ struct lt_list_head *args);
+int lt_error_return_ass(struct lt_config_app *cfg,
+ struct lt_error_app_return **ret,
+ char *name, unsigned long val);
+int lt_error_return_filter(struct lt_config_app *cfg,
+ struct lt_error_app_return **ret,
+ int type, void *data);
+
+int lt_error_app_init(struct lt_error_app *app);
+#else
+static inline int lt_error_app(struct lt_config_app *cfg,
+ struct lt_error_app *error_app)
+{
+ return -1;
+}
+
+static inline int lt_error_go(struct lt_config_app *cfg,
+ struct lt_error_app_go **go,
+ struct lt_error_app *error_app,
+ char *name, int n,
+ struct lt_list_head *runs)
+{
+ return -1;
+}
+
+static inline int lt_error_run_return(struct lt_config_app *cfg,
+ struct lt_error_app_run **run,
+ struct lt_error_app *error_app,
+ struct lt_list_head *ret)
+{
+ return -1;
+}
+
+static inline int lt_error_run_args(struct lt_config_app *cfg,
+ struct lt_error_app_run **run,
+ struct lt_list_head *args)
+{
+ return -1;
+}
+
+static inline int lt_error_app_init(struct lt_error_app *app)
+{
+ return -1;
+}
+
+static inline int lt_error_return_ass(struct lt_config_app *cfg,
+ struct lt_error_app_return **ret,
+ char *name, unsigned long val)
+{
+ return -1;
+}
+
+static inline int lt_error_return_filter(struct lt_config_app *cfg,
+ struct lt_error_app_return **ret,
+ int type, void *data)
+{
+ return -1;
+}
+
+#endif
+
+#endif /* ERROR_H */
diff --git a/src/fifo.c b/src/fifo.c
index 7e726f2..c586fa1 100644
--- a/src/fifo.c
+++ b/src/fifo.c
@@ -29,6 +29,7 @@
#include <fcntl.h>
#include <string.h>
#include <sys/inotify.h>
+#include <errno.h>
#include "config.h"
@@ -36,17 +37,12 @@
static char *get_notify_dir(char *dir)
{
static char notify_dir[LT_MAXFILE];
- static int initialized = 0;
int s;
- if (initialized)
- return notify_dir;
-
s = snprintf(notify_dir, LT_MAXFILE, "%s/fifo", dir);
if (s >= LT_MAXFILE)
return NULL;
- initialized = 1;
return notify_dir;
}
@@ -93,7 +89,7 @@ int lt_fifo_notify_init(struct lt_config_app *cfg, char *dir)
struct stat st;
if (stat(notify_dir, &st)) {
- if (mkdir(notify_dir, S_IRWXU)) {
+ if (mkdir(notify_dir, S_IRWXU) && (errno != EEXIST)) {
perror("mkdir failed");
return -1;
}
diff --git a/src/latrace.c b/src/latrace.c
index 6c45338..19d0bfd 100644
--- a/src/latrace.c
+++ b/src/latrace.c
@@ -71,6 +71,11 @@ static int main_latrace(int argc, char **argv)
if (-1 == lt_config(&cfg, argc, argv))
return -1;
+#ifdef CONFIG_ARCH_HAVE_ERROR_SIM
+ if (lt_sh(&cfg, error_sim))
+ return lt_error_run(&cfg);
+#endif
+
ret = lt_run(&cfg);
if ((lt_sh(&cfg, pipe)) && (*lt_sh(&cfg, output)))
diff --git a/src/symbol.c b/src/symbol.c
index df7d169..f10045a 100644
--- a/src/symbol.c
+++ b/src/symbol.c
@@ -73,7 +73,7 @@ static int compare(const void *a, const void *b)
static int symbol_init(struct lt_config_shared *cfg,
struct lt_symbol *sym, const char *name)
{
- struct lt_args_sym* a = NULL;
+ struct lt_args_sym *a = NULL;
if (lt_sh(cfg, args_enabled)) {
a = lt_args_sym_get(cfg, name);