On Mon, Aug 22, 2011 at 11:41 PM, Julia Lawall <[email protected]> wrote:
> For what it is worth, here is a semantic patch that creates the debug
> wrappers of functions like you described. It could be adapted to insert
> other kinds of asserts. I just decided to assert that all pointer-typed
> parameters are not NULL.
>
> Semantic patch:
>
> @r@
> identifier f;
> fresh identifier ff = "_called_function_";
> parameter list pl;
> type T;
> @@
>
> T
> - f
> + ff
> (pl) { ... }
> + T f(pl) { return ff(); }
>
> @script:ocaml s@
> (_,pl) << r.pl;
> ff << r.ff;
> newargs;
> @@
>
> newargs := String.concat ", "
> (List.map
> (function pt ->
> match (Ast_c.unwrap pt).Ast_c.p_namei with
> None -> failwith "bad param"
> | Some nm -> Ast_c.str_of_name nm)
> pl)
>
> @@
> identifier s.newargs;
> identifier r.ff;
> @@
>
> ff(
> + newargs
> )
>
> @t@
> identifier r.ff;
> identifier x;
> type T;
> @@
>
> ff(..., T *x, ...) { ... }
>
> @@
> identifier r.f, r.ff, t.x;
> @@
>
> f(...) {
> ++ assert(x != NULL);
> ...
> return ff(...); // be sure this is the right function
> }
>
> Note that this semantic patch code uses the access to the abstract syntax
> tree like Nicolas described. This is because there is no good way to
> convert a list of parameters to a list of just the declared variable
> names. It could also have been done in a more ad hoc manner by parsing
> the string representing the parameter list in the ocaml (or python, in
> this case) code.
>
> The test program is then as follows:
>
> #ifdef FIRST
> int main (int a, struct foo *b, struct bar *c) {
> a = b->x;
> return c->d;
> }
> #else
> int main (int a, struct foo *xyz) {
> a = xyz->x;
> return xyz->d;
> }
> #endif
>
> And the resulting program is:
>
> #ifdef FIRST
> int _called_function_0 (int a, struct foo *b, struct bar *c) {
> a = b->x;
> return c->d;
> }
>
> int main(int a, struct foo *b, struct bar *c) {
> assert(c != NULL);
> assert(b != NULL);
> return _called_function_0(a, b, c);
> }
> #else
> int _called_function_1 (int a, struct foo *xyz) {
> a = xyz->x;
> return xyz->d;
> }
>
> int main(int a, struct foo *xyz) {
> assert(xyz != NULL);
> return _called_function_1(a, xyz);
> }
> #endif
>
> This, however, changes the line numbers. It could be possible to find the
> last function in the file and put all of the new wrapper functions after
> that one.
>
Thanks, Julia. That's really close to what I want for one of the use cases.
I'm not sure that putting the wrapper functions at the end of the file will
work for all cases. I'll have to think about that. But if it does work for
all cases then how could the patch be changed to place the new functions at
the end of the file?
The other problem is that I still want to add in extra code to each wrapper
function for human readable instrumentation and/or different types of
asserts depending upon the function argument type or types. I'm guessing
that this type of decision making logic is not possible at the patch level.
What about this idea? Is it possible for the patch which generates the
wrapper functions to simply output the different function argument types and
names and also the return type into the newly created wrapper functions as
comments. In this way then a further post-processing script could examine
those comments and replace them with code while making the decisions
necessary as to which code to replace them with?
Thanks,
Simon
julia
>
_______________________________________________
Cocci mailing list
[email protected]
http://lists.diku.dk/mailman/listinfo/cocci
(Web access from inside DIKUs LAN only)