On Tue, Aug 23, 2011 at 9:47 AM, Julia Lawall <[email protected]> wrote: > On Tue, 23 Aug 2011, Simon wrote: > > > 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? > > I need to run out now, but I can try to put something together later. > Basically, one could record the position of all of the functions, and then > use python to filter out all but the last one, and then put the next > functions after that one. > > > 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. > > It depends on what kind of filtering you want to do. At worst, I was > thinking that you could specify function name, parameter number, and > treatment in an auxiliary file, and use python/ocaml code to read that in > and decide what to do. > > But function type and argument type don't seem like a problem. You could > for example have a specific treatment for parameters of a certain set of > types, and then have a generic treatment for all other parameters. > > > 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? > > This comes back to the issue that Coccinelle does not interpret > metavariables in added comments. You would have to use the identifier > trick shown in my initial example. >
Sorry, I think I expressed myself badly :-) The idea is that during a first pass then Coccinelle would create all the wrapper functions as in your nice example. However, Coccinelle itself would write comments into the newly added wrapper functions. Then after Coccinelle is done then another completely different tool could read the new C file containing the newly added wrapped functions and search for the comments added by Coccinelle and munge them into code. This would be as secondary processing step. Here I'm assuming that Coccinelle has the ability to write out comments for each function argument type and name. Thanks, Simon Another option is to use macros. If you want to match the macros and > change them to something else, with your script that would be fine. But > generating a macro call would be easier, given the current functionality > of coccinelle, than generating a comment. > > julia >
_______________________________________________ Cocci mailing list [email protected] http://lists.diku.dk/mailman/listinfo/cocci (Web access from inside DIKUs LAN only)
