From: Gabriel Matni Date: Fri, 14 Aug 2009 19:04:11 +0000 (-0400) Subject: add fsm checker by Gabriel Matni X-Git-Tag: v0.12.20~51 X-Git-Url: https://git.lttng.org./?a=commitdiff_plain;h=e09e518ebf18d490dbeb72c6358968af7d05d675;p=lttv.git add fsm checker by Gabriel Matni --- diff --git a/contrib/fsm_checker/CHROOT_CHECK/chroot_checker.c b/contrib/fsm_checker/CHROOT_CHECK/chroot_checker.c new file mode 100755 index 00000000..c50eadab --- /dev/null +++ b/contrib/fsm_checker/CHROOT_CHECK/chroot_checker.c @@ -0,0 +1,187 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "chroot_jail.h" + +GArray *_fsm_list; +struct timeval *tv1, *tv2; +int max_fsms = 0; +static gboolean chroot(void *hook_data, void *call_data){ + LttvTracefileState *s = (LttvTracefileState *) call_data; + LttEvent *e = ltt_tracefile_get_event(s->parent.tf); + LttvTraceHook *th = (LttvTraceHook *)hook_data; + struct marker_field *f = lttv_trace_get_hook_field(th, 0); + + char *rootDirectory = ltt_event_get_string(e, f); + + LttvTracefileState *tfs = (LttvTracefileState *)call_data; + LttvTraceState *ts = (LttvTraceState *) tfs->parent.t_context; + LttvProcessState *process = ts->running_process[tfs->cpu]; + int pid=process->pid; + + //initialize a new finite state machine + struct rootjail *rjstruct = chrootjail_Init(); + //add new fsm to list + g_array_append_val(_fsm_list, rjstruct); + //call corresponding transition + rootjailContext_chroot(&(rjstruct->_fsm), pid, rootDirectory); + + if(max_fsms<_fsm_list->len) + max_fsms=_fsm_list->len; + return FALSE; +} +static gboolean chdir(void *hook_data, void *call_data){ + LttvTracefileState *s = (LttvTracefileState *) call_data; + LttEvent *e = ltt_tracefile_get_event(s->parent.tf); + LttvTraceHook *th = (LttvTraceHook *) hook_data; + + struct marker_field *f = lttv_trace_get_hook_field(th,0); + + LttvTracefileState *tfs = (LttvTracefileState *)call_data; + LttvTraceState *ts = (LttvTraceState *) tfs->parent.t_context; + LttvProcessState *process = ts->running_process[tfs->cpu]; + int pid=process->pid; + + char *newDirectory = ltt_event_get_string(e, f); + + int i; + for(i=0; i<_fsm_list->len; i++){ + struct rootjail *rjstruct = g_array_index(_fsm_list, struct rootjail *, i); + rootjailContext_chdir(&(rjstruct->_fsm), pid, newDirectory); + } + + return FALSE; + +} +static gboolean open(void *hook_data, void *call_data){ + LttvTracefileState *s = (LttvTracefileState *) call_data; + LttEvent *e = ltt_tracefile_get_event(s->parent.tf); + LttvTraceHook *th = (LttvTraceHook *) hook_data; + + struct marker_field *f = lttv_trace_get_hook_field(th,0); + + LttvTracefileState *tfs = (LttvTracefileState *)call_data; + LttvTraceState *ts = (LttvTraceState *) tfs->parent.t_context; + LttvProcessState *process = ts->running_process[tfs->cpu]; + int pid=process->pid; + + int i; + for(i=0; i<_fsm_list->len; i++){ + struct rootjail *rjstruct = g_array_index(_fsm_list, struct rootjail *, i); + rootjailContext_open(&(rjstruct->_fsm), pid); + } + + return FALSE; + +} +int removefsm(struct rootjail *this){ + int i; + for(i=0; i<_fsm_list->len; i++) + { + struct rootjail *rj = g_array_index(_fsm_list, struct rootjail *, i); + if(rj==this) + { + g_array_remove_index(_fsm_list, i); + break; + } + } +} +static int add_events_by_id_hooks(void *hook_data, void *call_data){ + LttvTraceContext *tc = (LttvTraceContext *) call_data; + LttTrace *t = tc->t; + + //EVENT CHROOT + GQuark LTT_FACILITY_FS = g_quark_from_string("fs"); + GQuark LTT_EVENT_CHROOT = g_quark_from_string("chroot"); + //EVENT FIELDS + GQuark LTT_FIELD_ROOT = g_quark_from_string("RootDirectory"); + + + GQuark LTT_EVENT_CHDIR = g_quark_from_string("chdir"); + GQuark LTT_FIELD_DIRECTORY = g_quark_from_string("Directory"); + + GQuark LTT_EVENT_OPEN = g_quark_from_string("open"); + GQuark LTT_FIELD_FD = g_quark_from_string("fd"); + GQuark LTT_FIELD_FILENAME = g_quark_from_string("filename"); + + GArray *hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 3); + + lttv_trace_find_hook(t, LTT_FACILITY_FS, LTT_EVENT_CHROOT, + FIELD_ARRAY(LTT_FIELD_ROOT), + chroot, + NULL, + &hooks); + + lttv_trace_find_hook(t, LTT_FACILITY_FS, LTT_EVENT_CHDIR, + FIELD_ARRAY(LTT_FIELD_DIRECTORY), + chdir, + NULL, + &hooks); + + + lttv_trace_find_hook(t, LTT_FACILITY_FS, LTT_EVENT_OPEN, + FIELD_ARRAY(LTT_FIELD_FD, LTT_FIELD_FILENAME), + open, + NULL, + &hooks); + + int nb_tracefiles = tc->tracefiles->len; +//someting may be missing here... after recovery file got split into 2 parts. + LttvHooks *needed_hooks; + LttvTraceHook *th = (LttvTraceHook *)hook_data; + int i, j; + for(i=0; itracefiles, LttvTracefileContext*, i); + for(j=0; jlen; j++){ + th=&g_array_index(hooks, LttvTraceHook, j); + needed_hooks = lttv_hooks_by_id_find((*tfc)->event_by_id, th->id); + lttv_hooks_add(needed_hooks, th->h, th, LTTV_PRIO_DEFAULT); + } + } +} +static void init(){ + + gboolean result; + + LttvAttributeValue value; + + LttvIAttribute *attributes = LTTV_IATTRIBUTE(lttv_global_attributes()); + + static LttvHooks *before_trace; + + result = lttv_iattribute_find_by_path(attributes, "hooks/trace/before", LTTV_POINTER, &value); + g_assert(result); + before_trace = *(value.v_pointer); + g_assert(before_trace); + + //Register add_events_by_id_hook to be called before starting to read the trace + //This function will be overwritten between checkers + lttv_hooks_add(before_trace, add_events_by_id_hooks, NULL, LTTV_PRIO_DEFAULT); + + //Initialize empty GArray for FSMs + _fsm_list = g_array_new(FALSE, FALSE, sizeof(struct rootjail *)); + + tv1 = (struct timeval *)malloc(sizeof(struct timeval)); + gettimeofday(tv1, NULL); + +} +static void destroy(){ + tv2 = (struct timeval *)malloc(sizeof(struct timeval)); + gettimeofday(tv2, NULL); + int seconds = tv2->tv_sec - tv1->tv_sec; + printf("analysis took: %d seconds \n", seconds); + printf("total number of coexisting fsms is: %d\n",max_fsms); + +} + +LTTV_MODULE("chroot_checker", "Detects improper chroot jailing", + "Catches attempts to open files after calling chroot without calling chdir", + init, destroy, "stats", "batchAnalysis", "option") diff --git a/contrib/fsm_checker/CHROOT_CHECK/chroot_jail.c b/contrib/fsm_checker/CHROOT_CHECK/chroot_jail.c new file mode 100755 index 00000000..1528d78d --- /dev/null +++ b/contrib/fsm_checker/CHROOT_CHECK/chroot_jail.c @@ -0,0 +1,34 @@ +#include +#include +struct rootjail * chrootjail_Init(){ + struct rootjail *this = (struct rootjail *) g_malloc(sizeof(struct rootjail)); + rootjailContext_Init(&this->_fsm, this); + this->pid=-1; + this->newroot = g_string_new(""); + return this; +} +void rootjail_savepid(struct rootjail *this, int pid){ + this->pid=pid; +} +void rootjail_savenewroot(struct rootjail *this, char *newroot){ + g_string_printf(this->newroot, newroot); +} +void rootjail_destroyfsm(struct rootjail *this){ + //remove fsm from fsm_list + removefsm(this); + g_string_free(this->newroot,TRUE); + g_free(this); +} +void rootjail_warning(struct rootjail *this){ + printf("WARNING: pid %d attempted to open a file before calling chdir()\n", this->pid); +} +int checknewdir(char * newdir){ + if(!strcmp(newdir, "/"))//returns 0 when strings are equal + return 1; + return 0; +} +int thisprocess(struct rootjail *this, int pid){ + if(this->pid==pid) + return 1; + return 0; +} diff --git a/contrib/fsm_checker/CHROOT_CHECK/chroot_jail.h b/contrib/fsm_checker/CHROOT_CHECK/chroot_jail.h new file mode 100755 index 00000000..d402eabb --- /dev/null +++ b/contrib/fsm_checker/CHROOT_CHECK/chroot_jail.h @@ -0,0 +1,24 @@ +#include + + +struct rootjail +{ + int pid; + GString *newroot; + struct rootjailContext _fsm; +}; + +struct rootjail * chrootjail_Init(); + +void rootjail_savepid(struct rootjail *, int); + +void rootjail_savenewroot(struct rootjail *, char *); + +void rootjail_destroyfsm(struct rootjail *); + +void rootjail_warning(struct rootjail *); + +int checknewdir(char *); + +int removefsm(struct rootjail *); + diff --git a/contrib/fsm_checker/CHROOT_CHECK/chroot_jail.sm b/contrib/fsm_checker/CHROOT_CHECK/chroot_jail.sm new file mode 100755 index 00000000..0579098e --- /dev/null +++ b/contrib/fsm_checker/CHROOT_CHECK/chroot_jail.sm @@ -0,0 +1,36 @@ +%start Map1::Start +%class rootjail +%header chroot_jail.h + +%map Map1 +%% +//STATE TRANSITION END STATE ACTION(S) + +Start +{ + chroot(pid: int, newroot:char*) Newroot {savepid(pid); savenewroot(newroot);} + Default + Start + {} + +} +Newroot +{ + chdir(pid: int, newdir: char *) + [thisprocess(ctxt, pid)==1 && checknewdir(newdir)==1] Destroy + {destroyfsm();} + chdir(pid: int, newdir: char *) + Newroot + {} + open(pid: int)[thisprocess(ctxt, pid)==1] + Destroy + {warning(); destroyfsm();} + Default + Newroot + {} +} +Destroy +{ + Default Destroy {} +} +%% diff --git a/contrib/fsm_checker/FD_CHECK/fd.c b/contrib/fsm_checker/FD_CHECK/fd.c new file mode 100755 index 00000000..f0df174f --- /dev/null +++ b/contrib/fsm_checker/FD_CHECK/fd.c @@ -0,0 +1,44 @@ +#include "fd.h" +#include + +struct fd * fd_Init(){ + struct fd *this = (struct fd *) g_malloc(sizeof(struct fd)); + fdContext_Init(&this->_fsm, this); + this->pid=-1; + this->fd=-1; + return this; +} + +int test_args(struct fd *this, int pid, int fd){ + if(this->pid==pid && this->fd==fd) + return 1; + return 0; +} + +void fd_save_args(struct fd *this, int pid, int fd){ + this->pid=pid; + this->fd=fd; +} + +int my_process_exit(struct fd *this, int pid){ + if(this->pid==pid) + return 1; + return 0; +} + +void fd_destroy_scenario(struct fd *this, int i){ + //remove fsm from fsm_list... not yet implemented + + removefsm(i); + g_free(this); +} +void fd_skip_FSM(){ + skip_FSM(); +} +void fd_warning(struct fd *this, char *msg){ + printf("%s\n",msg); +} +void fd_print_ts(struct fd *this, long ts_sec, long ts_nsec){ + printf("ts=%ld.%09ld\n", ts_sec, ts_nsec); + +} diff --git a/contrib/fsm_checker/FD_CHECK/fd.h b/contrib/fsm_checker/FD_CHECK/fd.h new file mode 100755 index 00000000..12e06056 --- /dev/null +++ b/contrib/fsm_checker/FD_CHECK/fd.h @@ -0,0 +1,18 @@ +#include "fd_sm.h" +#include + + +struct fd +{ + int pid; + int fd; + struct fdContext _fsm; +}; +struct fd * fd_Init(); +void fd_save_args(struct fd *this, int pid, int fd); +void fd_destroy_scenario(struct fd *, int); +void fd_warning(struct fd *this, char *msg); + +int my_process_exit(struct fd *this, int pid); +int test_args(struct fd *this, int pid, int fd); +void skip_FSM(); diff --git a/contrib/fsm_checker/FD_CHECK/fd.sm b/contrib/fsm_checker/FD_CHECK/fd.sm new file mode 100755 index 00000000..f8603b66 --- /dev/null +++ b/contrib/fsm_checker/FD_CHECK/fd.sm @@ -0,0 +1,65 @@ + + +%start Map1::Start +%class fd +%header fd.h + +%map Map1 +%% +//STATE TRANSITION END STATE ACTION(S) + +Start +{ + fs_close(pid: int, fd: int) + CloseState + {save_args(pid, fd);} + + + process_exit(pid: int, i: int) + [my_process_exit(ctxt, pid) == 1] + ExitState + {destroy_scenario(i);} + + Default + Start + {} + +} + +CloseState +{ + fs_read(pid: int, fd: int, ts_sec: long, ts_nsec: long) + [test_args(ctxt,pid, fd) == 1] + CloseState + {warning("Trying to read from a closed fd");print_ts(ts_sec, ts_nsec); skip_FSM();} + + fs_write(pid: int, fd: int) + [test_args(ctxt,pid, fd) == 1] + CloseState + {warning("Trying to write to a closed fd");skip_FSM();} + + process_exit(pid: int, i: int) + [my_process_exit(ctxt, pid) == 1] + ExitState + {destroy_scenario(i);} + + fs_open(pid: int, fd: int, i: int) + [test_args(ctxt, pid, fd)==1] + ExitState + {destroy_scenario(i);skip_FSM();} + + fs_dup3(pid: int, newfd: int, i: int) + [test_args(ctxt, pid, newfd)==1] + ExitState + {destroy_scenario(i);skip_FSM();} + + Default CloseState {} +} + +ExitState +{ + Default ExitState {} +} + +%% + diff --git a/contrib/fsm_checker/FD_CHECK/fd_checker.c b/contrib/fsm_checker/FD_CHECK/fd_checker.c new file mode 100755 index 00000000..f026d629 --- /dev/null +++ b/contrib/fsm_checker/FD_CHECK/fd_checker.c @@ -0,0 +1,310 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fd.h" + +GArray *_fsm_list; +GArray * _fsms_to_remove; +struct timeval *tv1, *tv2; +int max_fsms = 0; +int total_forks = 0; +int count_events = 0; +int skip=0; + +static gboolean fs_close(void *hook_data, void *call_data){ + count_events++; + LttvTracefileState *s = (LttvTracefileState *) call_data; + LttEvent *e = ltt_tracefile_get_event(s->parent.tf); + LttvTraceHook *th = (LttvTraceHook *)hook_data; + + struct marker_field *f = lttv_trace_get_hook_field(th, 0); + guint32 fd = ltt_event_get_long_unsigned(e, f); + + LttvTracefileState *tfs = (LttvTracefileState *)call_data; + LttvTraceState *ts = (LttvTraceState *) tfs->parent.t_context; + LttvProcessState *process = ts->running_process[tfs->cpu]; + int pid=process->pid; + + //initialize a new finite state machine + struct fd *fdstruct = fd_Init(); + total_forks++; + //add new fsm to list + g_array_append_val(_fsm_list, fdstruct); + //call corresponding transition + fdContext_fs_close(&(fdstruct->_fsm), pid, fd); + + if(max_fsms<_fsm_list->len) + max_fsms=_fsm_list->len; + return FALSE; + +} + +static gboolean fs_open(void *hook_data, void *call_data){ + count_events++; + LttvTracefileState *s = (LttvTracefileState *) call_data; + LttEvent *e = ltt_tracefile_get_event(s->parent.tf); + LttvTraceHook *th = (LttvTraceHook *)hook_data; + + struct marker_field *f = lttv_trace_get_hook_field(th, 0); + guint32 fd = ltt_event_get_long_unsigned(e, f); + + LttvTracefileState *tfs = (LttvTracefileState *)call_data; + LttvTraceState *ts = (LttvTraceState *) tfs->parent.t_context; + LttvProcessState *process = ts->running_process[tfs->cpu]; + int pid=process->pid; + + //for every fsm in the list, call appropriate transition + //index i is sent as an argument in case fsm is to be freed + struct fd *fdstruct; + int i; + for(i=_fsm_list->len-1; i>=0; i--){ + if (skip) + break; + fdstruct = (struct fd *) g_array_index(_fsm_list, struct fdstruct *, i); + fdContext_fs_open(&(fdstruct->_fsm), pid, fd, i); + } + skip=0; + return FALSE; +} + +static gboolean fs_read(void *hook_data, void *call_data){ + count_events++; + LttvTracefileState *s = (LttvTracefileState *) call_data; + LttEvent *e = ltt_tracefile_get_event(s->parent.tf); + LttvTraceHook *th = (LttvTraceHook *)hook_data; + + struct marker_field *f = lttv_trace_get_hook_field(th, 0); + guint32 fd = ltt_event_get_long_unsigned(e, f); + + LttvTracefileState *tfs = (LttvTracefileState *)call_data; + LttvTraceState *ts = (LttvTraceState *) tfs->parent.t_context; + LttvProcessState *process = ts->running_process[tfs->cpu]; + int pid=process->pid; + + LttTime time = ltt_event_time(e); + long ts_nsec, ts_sec; + ts_sec = (long) time.tv_sec; + ts_nsec=(long) time.tv_nsec; + + //for every fsm in the list, call appropriate transition + struct fd *fdstruct; + int i; + for(i=0; i<_fsm_list->len; i++){ + if (skip) + break; + fdstruct = (struct fd *)g_array_index(_fsm_list, struct fd *, i); + fdContext_fs_read(&(fdstruct->_fsm), pid, fd, ts_sec, ts_nsec); + } + + skip=0; + return FALSE; +} +static gboolean fs_write(void *hook_data, void *call_data){ + count_events++; + LttvTracefileState *s = (LttvTracefileState *) call_data; + LttEvent *e = ltt_tracefile_get_event(s->parent.tf); + LttvTraceHook *th = (LttvTraceHook *)hook_data; + + struct marker_field *f = lttv_trace_get_hook_field(th, 0); + guint32 fd = ltt_event_get_long_unsigned(e, f); + + LttvTracefileState *tfs = (LttvTracefileState *)call_data; + LttvTraceState *ts = (LttvTraceState *) tfs->parent.t_context; + LttvProcessState *process = ts->running_process[tfs->cpu]; + int pid=process->pid; + + //for every fsm in the list, call appropriate transition + struct fd *fdstruct; + int i; + for(i=0; i<_fsm_list->len; i++){ + if (skip) + break; + fdstruct = g_array_index(_fsm_list, struct fd *, i); + fdContext_fs_write(&(fdstruct->_fsm), pid, fd); + } + skip=0; + return FALSE; +} +static gboolean process_exit(void *hook_data, void *call_data){ + count_events++; + LttvTracefileState *s = (LttvTracefileState *) call_data; + LttEvent *e = ltt_tracefile_get_event(s->parent.tf); + LttvTraceHook *th = (LttvTraceHook *)hook_data; + + LttvTracefileState *tfs = (LttvTracefileState *)call_data; + LttvTraceState *ts = (LttvTraceState *) tfs->parent.t_context; + LttvProcessState *process = ts->running_process[tfs->cpu]; + int pid=process->pid; + + + //for every fsm in the list, call appropriate transition + struct fd *fdstruct; + int i; + for(i=_fsm_list->len-1; i>=0 ; i--){ + fdstruct =(struct fd *) g_array_index(_fsm_list, struct fd *, i); + fdContext_process_exit(&(fdstruct->_fsm), pid, i); + } + skip=0; + return FALSE; +} +static gboolean fs_dup3(void *hook_data, void *call_data){ + count_events++; + LttvTracefileState *s = (LttvTracefileState *) call_data; + LttEvent *e = ltt_tracefile_get_event(s->parent.tf); + LttvTraceHook *th = (LttvTraceHook *)hook_data; + + LttvTracefileState *tfs = (LttvTracefileState *)call_data; + LttvTraceState *ts = (LttvTraceState *) tfs->parent.t_context; + LttvProcessState *process = ts->running_process[tfs->cpu]; + int pid=process->pid; + + struct marker_field *f = lttv_trace_get_hook_field(th, 1); + guint32 newfd = ltt_event_get_long_unsigned(e, f); + + //for every fsm in the list, call appropriate transition + struct fd *fdstruct; + int i; + for(i=_fsm_list->len-1; i>=0; i--){ + if (skip) + break; + fdstruct =(struct fd *) g_array_index(_fsm_list, struct fd *, i); + fdContext_fs_dup3(&(fdstruct->_fsm), pid, newfd, i); + } + skip=0; + return FALSE; + +} + +void skip_FSM(){ + skip=1; +} + +int removefsm(int i){ + g_array_remove_index(_fsm_list, i); + } +static int add_events_by_id_hooks(void *hook_data, void *call_data){ + LttvTraceContext *tc = (LttvTraceContext *) call_data; + LttTrace *t = tc->t; + + //EVENT CHROOT + GQuark LTT_FACILITY_FS = g_quark_from_string("fs"); + GQuark LTT_FACILITY_KERNEL = g_quark_from_string("kernel"); + + GQuark LTT_EVENT_CLOSE = g_quark_from_string("close"); + //EVENT FIELDS + GQuark LTT_FIELD_FD = g_quark_from_string("fd"); + GQuark LTT_FIELD_OLD_FD = g_quark_from_string("oldfd"); + GQuark LTT_FIELD_NEW_FD = g_quark_from_string("newfd"); + + GQuark LTT_EVENT_OPEN = g_quark_from_string("open"); + + GQuark LTT_EVENT_READ = g_quark_from_string("read"); + + GQuark LTT_EVENT_WRITE = g_quark_from_string("write"); + + GQuark LTT_EVENT_DUP3 = g_quark_from_string("dup3"); + + GQuark LTT_EVENT_PROCESS_EXIT = g_quark_from_string("process_exit"); + + GArray *hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 6); + + lttv_trace_find_hook(t, LTT_FACILITY_FS, LTT_EVENT_CLOSE, + FIELD_ARRAY(LTT_FIELD_FD), + fs_close, + NULL, + &hooks); + + lttv_trace_find_hook(t, LTT_FACILITY_FS, LTT_EVENT_OPEN, + FIELD_ARRAY(LTT_FIELD_FD), + fs_open, + NULL, + &hooks); + + lttv_trace_find_hook(t, LTT_FACILITY_FS, LTT_EVENT_READ, + FIELD_ARRAY(LTT_FIELD_FD), + fs_read, + NULL, + &hooks); + + + lttv_trace_find_hook(t, LTT_FACILITY_FS, LTT_EVENT_WRITE, + FIELD_ARRAY(LTT_FIELD_FD), + fs_write, + NULL, + &hooks); + + lttv_trace_find_hook(t, LTT_FACILITY_KERNEL, LTT_EVENT_PROCESS_EXIT, + NULL, + process_exit, + NULL, + &hooks); + + lttv_trace_find_hook(t, LTT_FACILITY_FS, LTT_EVENT_DUP3, + FIELD_ARRAY(LTT_FIELD_OLD_FD, LTT_FIELD_NEW_FD), + fs_dup3, + NULL, + &hooks); + + int nb_tracefiles = tc->tracefiles->len; + LttvTracefileContext **tfc; + LttvHooks *needed_hooks; + LttvTraceHook *th = (LttvTraceHook *)hook_data; + int i, j; + for(i=0; itracefiles, LttvTracefileContext*, i); + for(j=0; jlen; j++){ + th=&g_array_index(hooks, LttvTraceHook, j); + needed_hooks = lttv_hooks_by_id_find((*tfc)->event_by_id, th->id); + lttv_hooks_add(needed_hooks, th->h, th, LTTV_PRIO_DEFAULT); + } + } +} +static void init(){ + + gboolean result; + + LttvAttributeValue value; + + LttvIAttribute *attributes = LTTV_IATTRIBUTE(lttv_global_attributes()); + + static LttvHooks *before_trace; + + result = lttv_iattribute_find_by_path(attributes, "hooks/trace/before", LTTV_POINTER, &value); + g_assert(result); + before_trace = *(value.v_pointer); + g_assert(before_trace); + + //Register add_events_by_id_hook to be called before starting to read the trace + //This function will be overwritten between checkers + lttv_hooks_add(before_trace, add_events_by_id_hooks, NULL, LTTV_PRIO_DEFAULT); + + //Initialize empty GArray for FSMs + _fsm_list = g_array_new(FALSE, FALSE, sizeof(struct fd *)); + + tv1 = (struct timeval *)malloc(sizeof(struct timeval)); + gettimeofday(tv1, NULL); +} +static void destroy(){ + tv2 = (struct timeval *)malloc(sizeof(struct timeval)); + gettimeofday(tv2, NULL); + int seconds = tv2->tv_sec - tv1->tv_sec; + printf("analysis took: %d seconds \n", seconds); + printf("total number of coexisting fsms is: %d\n",max_fsms); + printf("total number of forked fsms is: %d\n", total_forks); + printf("size of one fsm (in bytes) is: %d\n", sizeof(struct fd)); + printf("total number of pertinent events is %d\n", count_events); + +} + +LTTV_MODULE("fd_checker", "Detects improper fd usage", + "finds read/write access to a closed fd in a trace file", + init, destroy, "stats", "batchAnalysis", "option") diff --git a/contrib/fsm_checker/LOCK_CHECK/fsm_locking.c b/contrib/fsm_checker/LOCK_CHECK/fsm_locking.c new file mode 100755 index 00000000..510ab820 --- /dev/null +++ b/contrib/fsm_checker/LOCK_CHECK/fsm_locking.c @@ -0,0 +1,353 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fsm_locking_sm.h" +#include "lockclass.h" + + +int NUM_OF_CPUS; +//one hashing table for all locks +GHashTable *locksTable; +GArray *fsm_array; +int total_acquire; +//Global timestamps very useful for debugging +long ts_sec; +long ts_ns; + +void lockclass_clearlock(struct lockclass *fsm, struct lockstruct *lock){ + struct lockstruct *temp; + + temp = g_hash_table_lookup(locksTable,(gconstpointer)lock->lock_add); + if(temp!=NULL){ + temp->taken_irqs_on=0; + temp->taken_irqs_off=0; + temp->hardirq_context =0; + } +} + +static gboolean lockdep_init_map(void *hook_data, void *call_data){ + LttvTracefileState *s = (LttvTracefileState *) call_data; + int cpu = s->cpu; + LttEvent *e = ltt_tracefile_get_event(s->parent.tf); + LttvTraceHook *th = (LttvTraceHook *)hook_data; + + struct marker_field *f = lttv_trace_get_hook_field(th, 0); + guint32 lock_add = ltt_event_get_long_unsigned(e, f); + + //TODO:the lock_add being initialized by lockdep should not be present in stack + struct lockclass *fsm = g_array_index(fsm_array,struct lockclass *, cpu); + + struct lockstruct *lock = g_hash_table_lookup(locksTable,(gconstpointer)lock_add); + if(lock==NULL) + return FALSE; + + LttTime time = ltt_event_time(e); + ts_sec=(long)time.tv_sec; + ts_ns=(long)time.tv_nsec; + + lockclassContext_free_lock(&fsm->_fsm, lock); + return FALSE; +} +static gboolean kernel_sched_schedule(void *hook_data, void *call_data){ + LttvTracefileState *s = (LttvTracefileState *) call_data; + //printf("event sched_schedule encountered on cpu: %d\n", s->cpu); + //work should be done per processor + int cpu = s->cpu; + //parse event here + LttEvent *e = ltt_tracefile_get_event(s->parent.tf); + LttvTraceHook *th = (LttvTraceHook *)hook_data; + + struct marker_field *f = lttv_trace_get_hook_field(th, 0); + guint32 prev_pid = ltt_event_get_long_unsigned(e, f); + + f = lttv_trace_get_hook_field(th, 1); + guint32 next_pid = ltt_event_get_long_unsigned(e, f); + + LttTime time = ltt_event_time(e); + ts_sec=(long)time.tv_sec; + ts_ns=(long)time.tv_nsec; + + struct lockclass *fsm = g_array_index(fsm_array,struct lockclass *, cpu); + + lockclassContext_schedule_out(&fsm->_fsm, prev_pid); + return FALSE; +} + + +static gboolean lockdep_lock_acquire(void *hook_data, void *call_data){ + total_acquire++; + LttvTracefileState *s = (LttvTracefileState *) call_data; + int cpu = s->cpu; + + //parse event here + LttEvent *e = ltt_tracefile_get_event(s->parent.tf); + LttvTraceHook *th = (LttvTraceHook *)hook_data; + + struct marker_field *f = lttv_trace_get_hook_field(th, 2); + guint32 lock_add = ltt_event_get_long_unsigned(e, f); + + f= lttv_trace_get_hook_field(th, 5); + int hardirqs_off = ltt_event_get_long_unsigned(e, f); + + f=lttv_trace_get_hook_field(th, 0); + guint32 ret_add = ltt_event_get_long_unsigned(e, f); + + f=lttv_trace_get_hook_field(th,4); + int read = ltt_event_get_long_unsigned(e, f); + + f=lttv_trace_get_hook_field(th, 6); + int hardirq_context = ltt_event_get_long_unsigned(e, f); + + LttvTraceState *ts = (LttvTraceState*) s->parent.t_context; + LttvProcessState *process = ts->running_process[cpu]; + int pid = process->pid; + + LttTime time = ltt_event_time(e); + ts_sec=(long)time.tv_sec; + ts_ns=(long)time.tv_nsec; + + + //filter rwlock_acquire_read and rwsem_acquire_read + if(read==2 || read==1) + return FALSE; + //read needs to be 0: spin_acquire, rwlock_acquire, mutex_acquire, rwsem_acquire & lock_map_acquire + struct lockclass *fsm = g_array_index(fsm_array,struct lockclass *, cpu); + + struct lockstruct *lock = g_hash_table_lookup(locksTable,(gconstpointer)lock_add); + if(lock==NULL){ + lock = lockstruct_Init(lock_add); + //add lock to table + g_hash_table_insert(locksTable, (gpointer)lock_add,lock); + } + //lock->pid = pid;//update pid + lockclassContext_acquire_lock(&fsm->_fsm,lock, lock->lock_add, hardirqs_off, hardirq_context, pid); + + return FALSE; +} +static gboolean lockdep_lock_release(void *hook_data, void *call_data){ + LttvTracefileState *s = (LttvTracefileState *) call_data; + int cpu = s->cpu; + + //parse event here + LttEvent *e = ltt_tracefile_get_event(s->parent.tf); + LttvTraceHook *th = (LttvTraceHook *)hook_data; + struct marker_field *f = lttv_trace_get_hook_field(th, 1); + guint32 lock_add = ltt_event_get_long_unsigned(e, f); + + LttvTraceState *ts = (LttvTraceState*) s->parent.t_context; + LttvProcessState *process = ts->running_process[cpu]; + int pid = process->pid; + + LttTime time = ltt_event_time(e); + ts_sec=(long)time.tv_sec; + ts_ns=(long)time.tv_nsec; + + struct lockstruct *lock = g_hash_table_lookup(locksTable,(gconstpointer)lock_add); + + if(lock==NULL) + return FALSE; + + struct lockclass *fsm = g_array_index(fsm_array,struct lockclass *, cpu); + + lockclassContext_release_lock(&fsm->_fsm, lock); + return FALSE; +} +void printlock(struct lockstruct * lock){ + printf("Lock 0x%x: held_irqs_on: %d held_irqs_off %d irqcontext: %d pid: %u\n", + lock->lock_add, lock->taken_irqs_on, + lock->taken_irqs_off, lock->hardirq_context, + lock->pid); +} + +void lockclass_printstack(struct lockclass *fsm){ + GArray *localstack = fsm->local_stack; + int len = localstack->len; + int i; + struct lockstruct *lock; + for(i=0; it; + + //FIND NUMBER OF CPUS + NUM_OF_CPUS = ltt_trace_get_num_cpu(t); + + // EVENT ***LOCKDEP_LOCK_ACQUIRE*** + GQuark LTT_FACILITY_LOCKDEP = g_quark_from_string("lockdep"); + GQuark LTT_EVENT_LOCK_ACQUIRE = g_quark_from_string("lock_acquire"); + + GQuark LTT_FIELD_RET_ADDRESS = g_quark_from_string("retaddr"); + GQuark LTT_FIELD_SUBCLASS = g_quark_from_string("subclass"); + GQuark LTT_FIELD_LOCK = g_quark_from_string("lock"); + GQuark LTT_FIELD_TRYLOCK = g_quark_from_string("trylock"); + GQuark LTT_FIELD_READ = g_quark_from_string("read"); + GQuark LTT_FIELD_HARD_IRQS_OFF = g_quark_from_string("hardirqs_off"); + GQuark LTT_FIELD_HARDIRQ_CONTEXT = g_quark_from_string("hardirq_context"); + //******************************************************************* + + // EVENT ***KERNEL_SCHED_SCHEDULE + GQuark LTT_FACILITY_KERNEL = g_quark_from_string("kernel"); + GQuark LTT_EVENT_SCHED_SCHEDULE = g_quark_from_string("sched_schedule"); + + GQuark LTT_FIELD_PREV_PID = g_quark_from_string("prev_pid"); + GQuark LTT_FIELD_NEXT_PID = g_quark_from_string("next_pid"); + GQuark LTT_FIELD_PREV_STATE = g_quark_from_string("prev_state"); + //******************************************************************* + // EVENT ***LOCKDEP_LOCK_RELEASE*** + GQuark LTT_EVENT_LOCK_RELEASE = g_quark_from_string("lock_release"); + + GQuark LTT_FIELD_NESTED = g_quark_from_string("nested"); + + //******************************************************************* + // EVENT ***LOCKDEP_INIT_MAP*** + GQuark LTT_EVENT_INIT_MAP = g_quark_from_string("init_map"); + + //******************************************************************* + + // EVENT ***... + + //... + + //******************************************************************* + + //# of hooks to register = # of desired events + GArray *hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 3 ); + + lttv_trace_find_hook(t, LTT_FACILITY_LOCKDEP, LTT_EVENT_LOCK_ACQUIRE, + FIELD_ARRAY(LTT_FIELD_RET_ADDRESS, LTT_FIELD_SUBCLASS, LTT_FIELD_LOCK, LTT_FIELD_TRYLOCK, + LTT_FIELD_READ, LTT_FIELD_HARD_IRQS_OFF, LTT_FIELD_HARDIRQ_CONTEXT), + lockdep_lock_acquire, + NULL, + &hooks); + + lttv_trace_find_hook(t, LTT_FACILITY_KERNEL, LTT_EVENT_SCHED_SCHEDULE, + FIELD_ARRAY(LTT_FIELD_PREV_PID, LTT_FIELD_NEXT_PID, LTT_FIELD_PREV_STATE), + kernel_sched_schedule, + NULL, + &hooks); + + lttv_trace_find_hook(t, LTT_FACILITY_LOCKDEP, LTT_EVENT_LOCK_RELEASE, + FIELD_ARRAY(LTT_FIELD_RET_ADDRESS, LTT_FIELD_LOCK, LTT_FIELD_NESTED), + lockdep_lock_release, + NULL, + &hooks); + + lttv_trace_find_hook(t, LTT_FACILITY_LOCKDEP, LTT_EVENT_INIT_MAP, + FIELD_ARRAY(LTT_FIELD_LOCK), + lockdep_init_map, + NULL, + &hooks); + //find remaining hooks here to fill the hooks array + //... + + //LttvTraceHook *th = &g_array_index(hooks, LttvTraceHook, 0); + + + //Determine id of needed events + GQuark evQuark_lock_acquire = g_quark_try_string("lockdep_lock_acquire"); + struct marker_info *info_lock_acquire = marker_get_info_from_name(t, evQuark_lock_acquire); + int ev_id_lock_acquire = marker_get_id_from_info(t, info_lock_acquire); + + //printf("id of event of interest: %d\n", ev_id_lock_acquire); + + //when multiple tracefiles exists: + int nb_tracefiles = tc->tracefiles->len; + int i, j; + LttvTracefileContext **tfc; + LttvHooks *needed_hooks; + LttvTraceHook *th = (LttvTraceHook *)hook_data; + for(i=0; itracefiles, LttvTracefileContext*, i); + //printf("adding hooks for tracefile #%d\n",i); + //add all needed hooks + for(j=0; jlen; j++) + { + th=&g_array_index(hooks, LttvTraceHook, j); + needed_hooks = lttv_hooks_by_id_find((*tfc)->event_by_id, th->id); + lttv_hooks_add(needed_hooks, th->h, th, LTTV_PRIO_DEFAULT); + //printf("hooked with event id: %d\n", th->id); + } + } + + fsm_array = g_array_sized_new(FALSE, FALSE, sizeof(struct lockclass *), NUM_OF_CPUS); + + struct lockclass *class; + for(i=0; ipid = pid; + if(hardirq_context==1){ + temp->hardirq_context=1; + temp->hardirq_context_ts_sec=ts_sec; + temp->hardirq_context_ts_ns=ts_ns; + } + if(hardirqs_off==1){ + temp->taken_irqs_off=1; + temp->taken_irqs_off_ts_sec=ts_sec; + temp->taken_irqs_off_ts_ns=ts_ns; + } + else if(hardirqs_off==0){ + temp->taken_irqs_on=1; + temp->taken_irqs_on_ts_sec=ts_sec; + temp->taken_irqs_on_ts_ns=ts_ns; + } + + } +} +static void init(){ + + gboolean result; + + LttvAttributeValue value; + + LttvIAttribute *attributes = LTTV_IATTRIBUTE(lttv_global_attributes()); + + static LttvHooks *before_trace; + + result = lttv_iattribute_find_by_path(attributes, "hooks/trace/before", LTTV_POINTER, &value); + g_assert(result); + before_trace = *(value.v_pointer); + g_assert(before_trace); + //Register add_events_by_id_hook to be called before starting to read the trace + lttv_hooks_add(before_trace, add_events_by_id_hooks, NULL, LTTV_PRIO_DEFAULT); + + //****************************************************************** + + +} +static void destroy(){ + printf("total lock_acquire %d\n", total_acquire); + printf("\nEnd of locks analysis.\n"); +} +LTTV_MODULE("fsm_locking", "Detects improper use of kernel locks", \ + "4 scenarios of problematic use of spinlocks are searched for",\ + init, destroy, "stats", "batchAnalysis", "option") diff --git a/contrib/fsm_checker/LOCK_CHECK/fsm_locking.sm b/contrib/fsm_checker/LOCK_CHECK/fsm_locking.sm new file mode 100755 index 00000000..3f8b1ef1 --- /dev/null +++ b/contrib/fsm_checker/LOCK_CHECK/fsm_locking.sm @@ -0,0 +1,60 @@ +%start Map1::S0 +%class lockclass +%header lockclass.h + +%map Map1 +%% + +S0 +{ + acquire_lock(lock: void *, lock_add: guint32, hardirqs_off: int,hardirq_context: int, pid: int) + [irq_check(ctxt, lock, hardirqs_off, hardirq_context)] S0 + {updatelock(lock, lock_add, pid, hardirqs_off, hardirq_context);warning("potential deadlock", lock);pushlock(lock);} + acquire_lock(lock: void *, lock_add: guint32, hardirqs_off: int,hardirq_context: int, pid: int) + Locks_acquired + {updatelock(lock, lock_add, pid, hardirqs_off, hardirq_context);pushlock(lock);} + free_lock(lock: void *) + S0 + {clearlock(lock);} + + Default + S0 + {} +} +Locks_acquired +{ + acquire_lock(lock: void *, lock_add: guint32, hardirqs_off: int,hardirq_context: int, pid: int) + [irq_check(ctxt, lock, hardirqs_off, hardirq_context)] Locks_acquired + {updatelock(lock, lock_add, pid, hardirqs_off, hardirq_context);pushlock(lock);warning("potential deadlock", lock);} + acquire_lock(lock: void *, lock_add: guint32, hardirqs_off: int,hardirq_context: int, pid: int) + Locks_acquired + {updatelock(lock, lock_add, pid, hardirqs_off, hardirq_context);pushlock(lock);} + release_lock(lock: void *) + [empty_stack(ctxt)] S0 + {poplock(lock);} + release_lock(lock: void *) + Locks_acquired + {poplock(lock);} + free_lock(lock: void *) + [lock_held(ctxt, lock)] Locks_acquired + {warning("Lockdep attempting to free a held lock", lock);} + free_lock(lock: void *) + Locks_acquired + {clearlock(lock);} + schedule_out(pid: guint32) + [lock_held_on_behalf(ctxt, pid)] Locks_acquired + // {warning("process... was scheduled out when a lock is being held on its behalf", NULL);printstack(); + // schedule_err(pid);} + {test();} + Default + Locks_acquired + {} +} +Potential_Deadlock +{ + Default Potential_Deadlock {} +} +Error{ + Default Error {} +} +%% diff --git a/contrib/fsm_checker/LOCK_CHECK/lockclass.c b/contrib/fsm_checker/LOCK_CHECK/lockclass.c new file mode 100755 index 00000000..28e693cf --- /dev/null +++ b/contrib/fsm_checker/LOCK_CHECK/lockclass.c @@ -0,0 +1,84 @@ +#include "lockclass.h" + + + +struct lockclass * lockclass_Init(int CPU){ + struct lockclass *this = (struct lockclass *) g_malloc(sizeof(struct lockclass)); + lockclassContext_Init(&this->_fsm, this); + this->cpu = CPU; + this->local_stack = g_array_new(FALSE, FALSE, sizeof(struct lockstruct *)); + return this; +} + +struct lockstruct * lockstruct_Init(guint32 address){ + struct lockstruct *this = (struct lockstruct *) g_malloc(sizeof(struct lockstruct)); + this->lock_add = address; + this->taken_irqs_off=0; + this->taken_irqs_on=0; + this->hardirq_context=0; + return this; +} +int irq_check(struct lockclass *fsm, void *lock, int hardirqs_off, int hardirq_context){ + struct lockstruct *lock_check = (struct lockstruct *)lock; + if(hardirq_context) + lock_check->hardirq_context=hardirq_context; + if(hardirq_context && lock_check->taken_irqs_on) + return 1; + else if(lock_check->hardirq_context && !hardirqs_off) + return 1; + + return 0; +} +int empty_stack(struct lockclass *fsm){ + return fsm->local_stack->len; +} +int lock_held(struct lockclass *fsm, struct lockstruct *lock){ + //loop through stack & return 1 if found, 0 otherwise + int i, len=fsm->local_stack->len; + for(i=0; ilocal_stack, struct lockstruct *, i); + if(temp==lock) + return 1; + } + return 0; +} +int lock_held_on_behalf(struct lockclass *fsm, guint32 pid){ + //loop through stack & return 1 if a lock is being held on behalf of pid + int i, len=fsm->local_stack->len; + for(i=0; ilocal_stack, struct lockstruct *, i); + if(temp->pid==pid){ + return 1; + + } + } + return 0; +} +void lockclass_test(){ + //the smc compiler didn't generate the right code since no action was specified. (only a guard) + return; +} +void lockclass_warning(struct lockclass *fsm, char *msg, struct lockstruct *lock){ + printf("WARNING: %s\n", msg); + if(lock!=NULL) + printf("Lock 0x%x: taken_hard_irqs_on: %d, taken_hard_irqs_off %d, hardirq_context %d\n ", + lock->lock_add, lock->taken_irqs_on, lock->taken_irqs_off, lock->hardirq_context); +} +void lockclass_pushlock(struct lockclass *fsm, struct lockstruct *lock){ + g_array_append_val(fsm->local_stack, lock); +} + +void lockclass_poplock(struct lockclass *fsm, struct lockstruct *lock){ + int i; + struct lockstruct *temp; + for(i=fsm->local_stack->len-1; i>=0; i--){ + temp=g_array_index(fsm->local_stack, struct lockstruct *, i); + if(temp==lock){ + g_array_remove_index(fsm->local_stack, i); + break; + } + } +} + diff --git a/contrib/fsm_checker/LOCK_CHECK/lockclass.h b/contrib/fsm_checker/LOCK_CHECK/lockclass.h new file mode 100755 index 00000000..56f23326 --- /dev/null +++ b/contrib/fsm_checker/LOCK_CHECK/lockclass.h @@ -0,0 +1,41 @@ +#include +#include "fsm_locking_sm.h" +struct lockclass{ + struct lockclassContext _fsm; + int cpu; //one class per CPU + GArray *local_stack; //stack containing held (per CPU) locks +}; + +struct lockstruct{ + guint32 lock_add; + guint32 ret_add; + + int taken_irqs_off; + long taken_irqs_off_ts_sec,taken_irqs_off_ts_ns; + + int taken_irqs_on; + long taken_irqs_on_ts_sec, taken_irqs_on_ts_ns; + + int hardirq_context; //1 if taken inside an irq handler + long hardirq_context_ts_sec, hardirq_context_ts_ns; + + int pid; //pid of the process currently holding the lock + //only valid if lock is present in stack; +}; + + +struct lockclass * lockclass_Init(int CPU); + +struct lockstruct * lockstruct_Init(); +int irq_check(struct lockclass *fsm, void *lock, int hardirqs_off, int hardirq_context); + +int empty_stack(struct lockclass *fsm); +int lock_held(struct lockclass *fsm, struct lockstruct *lock); +int lock_held_on_behalf(struct lockclass *fsm, guint32 pid); +void lockclass_warning(struct lockclass *fsm, char *msg, struct lockstruct *); +void lockclass_printstack(struct lockclass *fsm); +void poplock(struct lockclass *fsm, struct lockstruct *lock); +void pushlock(struct lockclass *fsm, struct lockstruct *lock); +void lockclass_clearlock(struct lockclass *fsm, struct lockstruct *lock); +void lockclass_updatelock(struct lockclass *fsm, struct lockstruct *lock, guint32 lock_add, int pid, int hardirqs_off, int hardirq_context); +void lockclass_test(); diff --git a/contrib/fsm_checker/README b/contrib/fsm_checker/README new file mode 100644 index 00000000..765e29f5 --- /dev/null +++ b/contrib/fsm_checker/README @@ -0,0 +1,5 @@ +This code is Copyright 2009 Gabriel Matni + +Released under the GPL. + +Tested with smc 5.1.0 diff --git a/contrib/fsm_checker/RT_CHECK/realtime.c b/contrib/fsm_checker/RT_CHECK/realtime.c new file mode 100755 index 00000000..2c60a91a --- /dev/null +++ b/contrib/fsm_checker/RT_CHECK/realtime.c @@ -0,0 +1,49 @@ +#include +#include +struct realtime * realtime_Init(int pid, long period_sec, long period_nsec, long running_time_sec, long running_time_nsec){ + struct realtime *this = (struct realtime *) g_malloc(sizeof(struct realtime)); + realtimeContext_Init(&this->_fsm, this); + this->pid = pid; + this->period_sec=period_sec; + this->period_nsec=period_nsec; + this->running_time_sec = running_time_sec; + this->running_time_nsec = running_time_nsec; + this->schedin_ts_sec=0;//needed for first event + this->schedin_ts_nsec=0; + return this; +} +void realtime_destroyfsm(struct realtime *this){ + //remove fsm from fsm_list + removefsm(this); + g_free(this); +} +void realtime_warning(struct realtime *this, long ts_sec, long ts_nsec){ + printf("WARNING: real-time process, pid %d was scheduled in after tolerable period @ %ld.%09ld.\n", this->pid, ts_sec, ts_nsec); +} +void realtime_report_insufficient_scheduling_time(struct realtime *this, long ts_sec, long ts_nsec){ + printf("WARNING: real-time process, pid %d was scheduled out early @%ld.%09ld.\n", this->pid, ts_sec, ts_nsec); +} +int latency(struct realtime *this, long ts_sec, long ts_nsec){ + //2 successive schedin are seperated by more than period + long delta_sec = ts_sec - this->schedin_ts_sec; + long delta_nsec = ts_nsec - this->schedin_ts_nsec; + if(delta_sec < this->period_sec) + return 0;//no latency + else if(delta_sec == this->period_sec) + if(delta_nsec < this->period_nsec) + return 0;//no latency + return 1; +} +int running_enough(struct realtime *this, long ts_sec, long ts_nsec){ + if(ts_sec - this->schedin_ts_sec > this->running_time_sec) + return 1; + else if(ts_sec - this->schedin_ts_sec == this->running_time_sec) + if(ts_nsec - this->running_time_nsec > this->running_time_nsec) + return 1; + return 0; +} +void realtime_save_ts(struct realtime *this, long ts_sec, long ts_nsec){ + this->schedin_ts_sec = ts_sec; + this->schedin_ts_nsec = ts_nsec; +} + diff --git a/contrib/fsm_checker/RT_CHECK/realtime.h b/contrib/fsm_checker/RT_CHECK/realtime.h new file mode 100755 index 00000000..1b890bb8 --- /dev/null +++ b/contrib/fsm_checker/RT_CHECK/realtime.h @@ -0,0 +1,34 @@ +#include +#define DEFAULT_PERIOD_SEC 0 +#define DEFAULT_PERIOD_NSEC 500000000 //500ms + +#define DEFAULT_RUNNING_TIME_SEC 0 +#define DEFAULT_RUNNING_TIME_NSEC 500000000 //500ms + + + +struct realtime{ + int pid; //set by checker + long period_sec; //tolerable period + long period_nsec; + long running_time_sec; //needed time to execute per scheduling cycle + long running_time_nsec; + long schedin_ts_sec; + long schedin_ts_nsec; + struct realtimeContext _fsm; + +}; +struct realtime * realtime_Init(int, long, long, long, long); + +void realtime_warning(struct realtime *, long, long); + +void realtime_report_insufficient_scheduling_time(struct realtime *, long, long); + +void realtime_save_ts(struct realtime *, long, long); + +int latency(struct realtime *, long, long); + +int running_enough(struct realtime *, long, long); + +void removefsm(struct realtime *rtstruct); + diff --git a/contrib/fsm_checker/RT_CHECK/rt_checker.c b/contrib/fsm_checker/RT_CHECK/rt_checker.c new file mode 100755 index 00000000..cec17822 --- /dev/null +++ b/contrib/fsm_checker/RT_CHECK/rt_checker.c @@ -0,0 +1,179 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "realtime.h" + +int application_pid; +long period_sec, period_nsec, running_time_sec, running_time_nsec; +long t2_sec, t2_nsec; +GArray *fsm_list; +struct timeval *tv1, *tv2; + +static gboolean schedule(void *hook_data, void *call_data){ + LttvTracefileState *s = (LttvTracefileState *) call_data; + LttEvent *e = ltt_tracefile_get_event(s->parent.tf); + LttvTraceHook *th = (LttvTraceHook *)hook_data; + + struct marker_field *f = lttv_trace_get_hook_field(th,0); + guint32 prev_pid = ltt_event_get_long_unsigned(e, f); + + f = lttv_trace_get_hook_field(th, 1); + guint32 next_pid = ltt_event_get_long_unsigned(e, f); + + LttTime time = ltt_event_time(e); + t2_sec=(long)time.tv_sec; + t2_nsec=(long)time.tv_nsec; + struct realtime *rtstruct; + if(application_pid==-1){ + //iterate over all fsms + int i, found=0; + + for(i=0; ilen; i++) + { + rtstruct = g_array_index(fsm_list, struct realtime *, i); + if(rtstruct->pid==next_pid){ + found=1; + realtimeContext_schedule_in(&rtstruct->_fsm, t2_sec, t2_nsec); + break; + } + else if(rtstruct->pid==prev_pid){ + found=1; + realtimeContext_schedule_out(&rtstruct->_fsm, t2_sec, t2_nsec); + break; + } + + } + if(!found){ + rtstruct = realtime_Init(next_pid, DEFAULT_PERIOD_SEC, + DEFAULT_PERIOD_NSEC, + DEFAULT_RUNNING_TIME_SEC, + DEFAULT_RUNNING_TIME_NSEC); + g_array_append_val(fsm_list, rtstruct); + //call transition + realtimeContext_schedule_in(&rtstruct->_fsm, t2_sec, t2_nsec); + + } + } + + else//we might have already created the fsm so check @ first + { + if(fsm_list->len==0){ + rtstruct = realtime_Init(application_pid, period_sec, period_nsec, running_time_sec, running_time_nsec); + g_array_append_val(fsm_list, rtstruct); + + } + else + rtstruct = g_array_index(fsm_list, struct realtime *, 0); + + + if(rtstruct->pid==next_pid) + realtimeContext_schedule_in(&rtstruct->_fsm, t2_sec, t2_nsec); + else if(rtstruct->pid==prev_pid) + realtimeContext_schedule_out(&rtstruct->_fsm, t2_sec, t2_nsec); + } + return FALSE; +} +void removefsm(struct realtime *rtstruct){ + int i; + for(i=0; ilen; i++){ + struct realtime *tmp = g_array_index(fsm_list,struct realtime *, i); + if(tmp==rtstruct){ + g_array_remove_index(fsm_list,i); + break; + } + } + +} +static int add_events_by_id_hooks(void *hook_data, void *call_data){ + LttvTraceContext *tc = (LttvTraceContext *) call_data; + LttTrace *t = tc->t; + + //EVENT CHROOT + GQuark LTT_FACILITY_KERNEL = g_quark_from_string("kernel"); + GQuark LTT_EVENT_SCHED_SCHEDULE = g_quark_from_string("sched_schedule"); + //EVENT FIELDS + GQuark LTT_FIELD_PREV_PID = g_quark_from_string("prev_pid"); + GQuark LTT_FIELD_NEXT_PID = g_quark_from_string("next_pid"); + GQuark LTT_FIELD_PREV_STATE = g_quark_from_string("prev_state"); + + + GArray *hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 1); + + lttv_trace_find_hook(t, LTT_FACILITY_KERNEL, LTT_EVENT_SCHED_SCHEDULE, + FIELD_ARRAY(LTT_FIELD_PREV_PID, LTT_FIELD_NEXT_PID, LTT_FIELD_PREV_STATE), + schedule, + NULL, + &hooks); + + int nb_tracefiles = tc->tracefiles->len; + LttvTracefileContext **tfc; + LttvHooks *needed_hooks; + LttvTraceHook *th = (LttvTraceHook *)hook_data; + int i, j; + for(i=0; itracefiles, LttvTracefileContext*, i); + for(j=0; jlen; j++){ + th=&g_array_index(hooks, LttvTraceHook, j); + needed_hooks = lttv_hooks_by_id_find((*tfc)->event_by_id, th->id); + lttv_hooks_add(needed_hooks, th->h, th, LTTV_PRIO_DEFAULT); + } + } +} +static void init(){ + + gboolean result; + + LttvAttributeValue value; + + LttvIAttribute *attributes = LTTV_IATTRIBUTE(lttv_global_attributes()); + + static LttvHooks *before_trace; + + result = lttv_iattribute_find_by_path(attributes, "hooks/trace/before", LTTV_POINTER, &value); + g_assert(result); +before_trace = *(value.v_pointer); +g_assert(before_trace); + + //Register add_events_by_id_hook to be called before starting to read the trace + //This function will be overwritten between checkers + lttv_hooks_add(before_trace, add_events_by_id_hooks, NULL, LTTV_PRIO_DEFAULT); + + printf("Enter your real-time application ip (-1 for all)\n"); + scanf("%d", &application_pid); + if(application_pid!=-1) + { + printf("Enter period_sec, period_nsec, running_time_sec, running_time_nsec:\n"); + //scanf("%ld%ld%ld%ld", &period_sec, &period_nsec, &running_time_sec, &running_time_nsec); + period_sec=1; + period_nsec=0; + running_time_sec=0; + running_time_nsec=500000; + + } + tv1 = (struct timeval *)malloc(sizeof(struct timeval)); + gettimeofday(tv1, NULL); + + fsm_list = g_array_new(FALSE, FALSE, sizeof(struct realtime *)); +} +static void destroy(){ + tv2 = (struct timeval *)malloc(sizeof(struct timeval)); + gettimeofday(tv2, NULL); + int seconds = tv2->tv_sec - tv1->tv_sec; + printf("analysis took: %d seconds \n", seconds); + + +} + +LTTV_MODULE("rt_checker", "Detects scheduling latencies", + "detects latencies", + init, destroy, "stats", "batchAnalysis", "option") +