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.

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)

Reply via email to