X-Git-Url: http://git.liburcu.org/?a=blobdiff_plain;f=contrib%2Ffsm_checker%2FLOCK_CHECK%2Ffsm_locking.c;fp=contrib%2Ffsm_checker%2FLOCK_CHECK%2Ffsm_locking.c;h=510ab820e4fe7d160a172b4e6facb10339119bed;hb=e09e518ebf18d490dbeb72c6358968af7d05d675;hp=0000000000000000000000000000000000000000;hpb=58f53b56557577b64911d0e7a2bba3fbb521d71d;p=lttv.git 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")