add fsm checker by Gabriel Matni
authorGabriel Matni <gabriel.matni@polymtl.ca>
Fri, 14 Aug 2009 19:04:11 +0000 (15:04 -0400)
committerPierre-Marc Fournier <pierre-marc.fournier@polymtl.ca>
Fri, 14 Aug 2009 19:04:11 +0000 (15:04 -0400)
16 files changed:
contrib/fsm_checker/CHROOT_CHECK/chroot_checker.c [new file with mode: 0755]
contrib/fsm_checker/CHROOT_CHECK/chroot_jail.c [new file with mode: 0755]
contrib/fsm_checker/CHROOT_CHECK/chroot_jail.h [new file with mode: 0755]
contrib/fsm_checker/CHROOT_CHECK/chroot_jail.sm [new file with mode: 0755]
contrib/fsm_checker/FD_CHECK/fd.c [new file with mode: 0755]
contrib/fsm_checker/FD_CHECK/fd.h [new file with mode: 0755]
contrib/fsm_checker/FD_CHECK/fd.sm [new file with mode: 0755]
contrib/fsm_checker/FD_CHECK/fd_checker.c [new file with mode: 0755]
contrib/fsm_checker/LOCK_CHECK/fsm_locking.c [new file with mode: 0755]
contrib/fsm_checker/LOCK_CHECK/fsm_locking.sm [new file with mode: 0755]
contrib/fsm_checker/LOCK_CHECK/lockclass.c [new file with mode: 0755]
contrib/fsm_checker/LOCK_CHECK/lockclass.h [new file with mode: 0755]
contrib/fsm_checker/README [new file with mode: 0644]
contrib/fsm_checker/RT_CHECK/realtime.c [new file with mode: 0755]
contrib/fsm_checker/RT_CHECK/realtime.h [new file with mode: 0755]
contrib/fsm_checker/RT_CHECK/rt_checker.c [new file with mode: 0755]

diff --git a/contrib/fsm_checker/CHROOT_CHECK/chroot_checker.c b/contrib/fsm_checker/CHROOT_CHECK/chroot_checker.c
new file mode 100755 (executable)
index 0000000..c50eada
--- /dev/null
@@ -0,0 +1,187 @@
+#include <lttv/option.h>
+#include <lttv/module.h>
+#include <lttv/hook.h>
+#include <lttv/attribute.h>
+#include <lttv/iattribute.h>
+#include <lttv/stats.h>
+#include <lttv/filter.h>
+#include <ltt/ltt.h>
+#include <ltt/event.h>
+#include <ltt/trace.h>
+#include <stdio.h>
+#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; i<nb_tracefiles; i++){
+               tfc = &g_array_index(tc->tracefiles, LttvTracefileContext*, i);
+               for(j=0; j<hooks->len; 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 (executable)
index 0000000..1528d78
--- /dev/null
@@ -0,0 +1,34 @@
+#include <glib.h>
+#include <string.h>
+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 (executable)
index 0000000..d402eab
--- /dev/null
@@ -0,0 +1,24 @@
+#include <glib.h>
+
+
+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 (executable)
index 0000000..0579098
--- /dev/null
@@ -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 (executable)
index 0000000..f0df174
--- /dev/null
@@ -0,0 +1,44 @@
+#include "fd.h"
+#include <glib.h>
+
+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 (executable)
index 0000000..12e0605
--- /dev/null
@@ -0,0 +1,18 @@
+#include "fd_sm.h"
+#include <glib.h>
+
+
+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 (executable)
index 0000000..f8603b6
--- /dev/null
@@ -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 (executable)
index 0000000..f026d62
--- /dev/null
@@ -0,0 +1,310 @@
+#include <lttv/lttv.h>
+#include <lttv/option.h>
+#include <lttv/module.h>
+#include <lttv/hook.h>
+#include <lttv/attribute.h>
+#include <lttv/iattribute.h>
+#include <lttv/stats.h>
+#include <lttv/filter.h>
+#include <ltt/ltt.h>
+#include <ltt/event.h>
+#include <ltt/trace.h>
+#include <stdio.h>
+#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; i<nb_tracefiles; i++){
+               tfc = &g_array_index(tc->tracefiles, LttvTracefileContext*, i);
+               for(j=0; j<hooks->len; 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 (executable)
index 0000000..510ab82
--- /dev/null
@@ -0,0 +1,353 @@
+#include <lttv/lttv.h>
+#include <lttv/option.h>
+#include <lttv/module.h>
+#include <lttv/hook.h>
+#include <lttv/attribute.h>
+#include <lttv/iattribute.h>
+#include <lttv/stats.h>
+#include <lttv/filter.h>
+#include <ltt/ltt.h>
+#include <ltt/event.h>
+#include <ltt/trace.h>
+#include <stdio.h>
+#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; i<len; i++){
+               lock = g_array_index(localstack, struct lockstruct *, i);       
+               printlock(lock);
+       }
+}
+void lockclass_schedule_err(struct lockclass *fsm, guint32 pid){
+       printf("process %u was scheduled out\n",pid);
+}
+
+
+static int add_events_by_id_hooks(void *hook_data, void *call_data){
+       LttvTraceContext *tc = (LttvTraceContext *) call_data; 
+       LttTrace *t = tc->t;
+
+       //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; i<nb_tracefiles; i++){
+               tfc = &g_array_index(tc->tracefiles, LttvTracefileContext*, i);
+               //printf("adding hooks for tracefile #%d\n",i);
+               //add all needed hooks
+               for(j=0; j<hooks->len; 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; i<NUM_OF_CPUS; i++){
+               class = lockclass_Init(i);
+               g_array_append_val(fsm_array, class);
+       }
+       locksTable = g_hash_table_new(g_direct_hash, NULL);
+       total_acquire=0;
+}
+//function to be moved to lockclass when testing is done:
+void lockclass_updatelock(struct lockclass *fsm, struct lockstruct *lock, guint32 lock_add, int pid, int hardirqs_off, int hardirq_context){
+       struct lockstruct *temp = g_hash_table_lookup(locksTable,(gconstpointer)lock_add);
+       
+       if(temp==NULL)
+               printf("Attemping to update an uninitialized lock");
+       if(temp!=NULL){
+               temp->pid = 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 (executable)
index 0000000..3f8b1ef
--- /dev/null
@@ -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 (executable)
index 0000000..28e693c
--- /dev/null
@@ -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; i<len; i++)
+       {
+               struct lockstruct *temp = g_array_index(fsm->local_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; i<len; i++)
+       {
+               struct lockstruct *temp=g_array_index(fsm->local_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 (executable)
index 0000000..56f2332
--- /dev/null
@@ -0,0 +1,41 @@
+#include <glib.h>
+#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 (file)
index 0000000..765e29f
--- /dev/null
@@ -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 (executable)
index 0000000..2c60a91
--- /dev/null
@@ -0,0 +1,49 @@
+#include <glib.h>
+#include <string.h>
+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 (executable)
index 0000000..1b890bb
--- /dev/null
@@ -0,0 +1,34 @@
+#include <glib.h>
+#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 (executable)
index 0000000..cec1782
--- /dev/null
@@ -0,0 +1,179 @@
+#include <lttv/option.h>
+#include <lttv/module.h>
+#include <lttv/hook.h>
+#include <lttv/attribute.h>
+#include <lttv/iattribute.h>
+#include <lttv/stats.h>
+#include <lttv/filter.h>
+#include <ltt/ltt.h>
+#include <ltt/event.h>
+#include <ltt/trace.h>
+#include <stdio.h>
+#include <math.h>
+#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; i<fsm_list->len; 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; i<fsm_list->len; 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; i<nb_tracefiles; i++){
+               tfc = &g_array_index(tc->tracefiles, LttvTracefileContext*, i);
+               for(j=0; j<hooks->len; 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")
+
This page took 0.04025 seconds and 4 git commands to generate.