diff options
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | README | 61 | ||||
-rw-r--r-- | fix-lock.cocci | 159 |
3 files changed, 224 insertions, 0 deletions
@@ -5,3 +5,7 @@ main: main.c clean: rm -f main + +coccicheck: + + pycocci fix-lock.cocci ./ @@ -0,0 +1,61 @@ + cocci-tact: Demo for instrumenting with Coccinelle +==================================================== + +This is a basic demo to show how one can do instrumentation with Coccinelle. + + The problem +============= + +Some Linux kernel debugging features often require adding a lot of debug data +structures to a source code repository, often this is addressed with +CONFIG_DEBUG_* features but sometimes maintaining this upstream on Linux is not +really welcomed due to how intrusive your changes may be or the difficulty +in maintaining it properly. Sometimes such code can simply increase the +complexity of what developers see, and can often riddle developers how to +address its use / extending it / or replacing your instrumentation code. + + Instrumenting with Coccinelle +=============================== + +Coccinelle enables a possible alternative: modify upstream code only when +you need it, for a throw away debugging kernel. Your instrumentation then +can be compartamentalized as much as possible upstream, and changes to +existing code kept separate, outside of what developers see. + +This demo illustrates adding some form of instrumentation basic templates +to code in userspace by trying to take advantage of a simple line which +would be assumed to be upstream: on code pthread_mutex_protects_3(). + +In this case pthread_mutex_protects_3() provides Coccinelle with hints +over what data structures a mutex protects. It is the goal of the +instrumentation mechanisms being developed here to either fix or +debug this code without affecting readability for users or average +developers of the code. + +This demo is written in userspace to help facilitate testing of ideas. +Instrumentation ideas are not yet complete but its the hope this provides +enough examples to show how this sort of work might look like. Locking +would just be one area that could use this. There are obviously other +domains that could benefit from this. + + Requirements +============== + + * Coccinelle >= 1.0.2 + * gcc + * make + + Usage +======= + +To see the problem run: + + make + ./main + +To see what the instrumentation does: + + make coccicheck + git diff + +This doesn't do anything quite useful just yet. diff --git a/fix-lock.cocci b/fix-lock.cocci new file mode 100644 index 0000000..7ea7f7c --- /dev/null +++ b/fix-lock.cocci @@ -0,0 +1,159 @@ +@ find_drv_name @ +identifier drv; +identifier mutex; +@@ + +pthread_mutex_protects_3(&drv->mutex, ...); + +@ find_hint @ +type T; +T *drv; +identifier mutex, item_1, item_2, item_3; +@@ + +pthread_mutex_protects_3(&drv->mutex, drv->item_1, drv->item_2, drv->item_3); + +@ add_instrumentation_vars @ +type find_hint.T; +identifier find_hint.mutex, find_hint.item_1, find_hint.item_2, find_hint.item_3; +type T1, T2; +fresh identifier instr_item_1 = "__instr_" ## item_1; +fresh identifier instr_item_2 = "__instr_" ## item_2; +fresh identifier instr_item_3 = "__instr_" ## item_3; +@@ + +T { + ... ++ int instr_item_1; + T1 item_1; + ... ++ int instr_item_2; + T2 item_2; + ... ++ int instr_item_3; + T2 item_3; + ... +}; + +@ add_counter depends on add_instrumentation_vars @ +type find_hint.T; +identifier find_hint.mutex, find_hint.item_1, find_hint.item_2, find_hint.item_3; +identifier find_drv_name.drv; +fresh identifier fn_instr = "__instr_" ## mutex; +@@ + +#include <string.h> ++ ++T; ++static void fn_instr(T *drv) ++{ ++} ++ + +@ find_pthread_fn depends on find_hint @ +identifier fn, ret; +expression thread, attr, val; +@@ + +ret = pthread_create(thread, attr, fn, val); + +@ check_fn_access @ +identifier find_pthread_fn.fn; +type find_hint.T; +T *drv; +//identifier find_drv_name.drv; +identifier add_counter.fn_instr; +identifier find_hint.mutex; +identifier find_hint.item_1; +identifier find_hint.item_2; +identifier find_hint.item_3; +@@ + +fn (...) +{ + <+... +( + drv->item_1 +| + drv->item_2 +| + drv->item_3 +) + ...+> ++ ++ /* top level routine accesses drv */ ++ fn_instr(drv); ++ +} + +@ check_helpers depends on find_pthread_fn @ +identifier helper; +identifier find_pthread_fn.fn; +identifier find_hint.mutex; +type find_hint.T; +T *drv; +@@ + +fn (...) +{ + <+... when != pthread_mutex_lock(&drv->mutex); ++ /* going to check this routine */ + helper(...); + ...+> +} + +@ helper_accessing_with_lock exists @ +identifier check_helpers.helper; +type find_hint.T; +T *drv; +identifier find_hint.mutex; +identifier find_hint.item_1; +identifier find_hint.item_2; +identifier find_hint.item_3; +position p1, p2; +identifier add_counter.fn_instr; +@@ + +helper(...) +{ + ... + pthread_mutex_lock@p1(&drv->mutex); + <+... +( + drv->item_1 +| + drv->item_2 +| + drv->item_3 +) + ...+> + pthread_mutex_unlock@p2(&drv->mutex); ++ /* routine had a lock */ ++ fn_instr(drv); +} + +@ helper_accessing_without_lock exists @ +identifier check_helpers.helper; +type find_hint.T; +T *drv; +identifier find_hint.mutex; +identifier find_hint.item_1; +identifier find_hint.item_2; +identifier find_hint.item_3; +identifier add_counter.fn_instr; +@@ + +helper(...) +{ + <+... when != pthread_mutex_lock(&drv->mutex); +( + drv->item_1 +| + drv->item_2 +| + drv->item_3 +) + ...+> ++ /* was missing lock */ ++ fn_instr(drv); +} |