Discussion:
[Cocci] Can the current function name be passed to a Python snippet?
Timur Tabi
2018-11-15 20:58:03 UTC
Permalink
Is it possible for a Python code snippet to be passed the name of the
current function? I already have Python code in my .cocci file that
cleans up the text of some string literals. I want to add more code
that removes the current function name from the beginning of a string
literal. So for instance, If I have

void myfunc(void)
{
...
NV_PRINTF("myfunc: xxx\n");

I want to replace the NV_PRINTF line with:

NV_PRINTF("xxx\n");

To do that, the Python code would need to given "myfunc" as a
parameter of some kind.
Julia Lawall
2018-11-15 21:29:46 UTC
Permalink
Post by Timur Tabi
Is it possible for a Python code snippet to be passed the name of the
current function? I already have Python code in my .cocci file that
cleans up the text of some string literals. I want to add more code
that removes the current function name from the beginning of a string
literal. So for instance, If I have
void myfunc(void)
{
...
NV_PRINTF("myfunc: xxx\n");
NV_PRINTF("xxx\n");
To do that, the Python code would need to given "myfunc" as a
parameter of some kind.
The name of the current function at a given match is available in a
position variable bound as part of that match. A position variable should
have a current_element field.

julia
Timur Tabi
2018-12-04 20:17:33 UTC
Permalink
Post by Julia Lawall
The name of the current function at a given match is available in a
position variable bound as part of that match. A position variable should
have a current_element field.
Unfortunately, I don't understand what you're saying. I see some
examples referencing the "position" in a Python script, but they don't
make any sense to me, e.g.

http://coccinelle.lip6.fr/docs/main_grammar016.html#sec27

The example shows:

@ r exists @
local idexpression struct device_node *n;
position p1, p2;
statement S1,S2;
expression E,E1;

I assume when you say "position parameter", you're talking about the
"position p1, p2;" above. If so, I'm completely confused.
Julia Lawall
2018-12-04 20:25:26 UTC
Permalink
Post by Timur Tabi
Post by Julia Lawall
The name of the current function at a given match is available in a
position variable bound as part of that match. A position variable should
have a current_element field.
Unfortunately, I don't understand what you're saying. I see some
examples referencing the "position" in a Python script, but they don't
make any sense to me, e.g.
http://coccinelle.lip6.fr/docs/main_grammar016.html#sec27
@ r exists @
local idexpression struct device_node *n;
position p1, p2;
statement S1,S2;
expression E,E1;
I assume when you say "position parameter", you're talking about the
"position p1, p2;" above. If so, I'm completely confused.
In the example, p1 will store the position of n. In the python rule, you
can then access p1[0].current_element to get the name of the function in
which n occurs.

julia
Timur Tabi
2018-12-04 22:02:11 UTC
Permalink
Post by Julia Lawall
Post by Timur Tabi
Post by Julia Lawall
The name of the current function at a given match is available in a
position variable bound as part of that match. A position variable should
have a current_element field.
Unfortunately, I don't understand what you're saying. I see some
examples referencing the "position" in a Python script, but they don't
make any sense to me, e.g.
http://coccinelle.lip6.fr/docs/main_grammar016.html#sec27
@ r exists @
local idexpression struct device_node *n;
position p1, p2;
statement S1,S2;
expression E,E1;
I assume when you say "position parameter", you're talking about the
"position p1, p2;" above. If so, I'm completely confused.
In the example, p1 will store the position of n. In the python rule, you
can then access p1[0].current_element to get the name of the function in
which n occurs.
What do you mean by "position of n"?

I managed to figure it out without using positional parameters. It
almost works in that it only does the replacement once:

// Look for NV_PRINTF2 calls that have the function name in the string
@r4 depends on rules@
identifier func;
expression x;
constant char[] c;
@@
func(...) {
...
NV_PRINTF2(x, c, ...)
...
}

// Get rid of the function name at the beginning of the string
@script:python s4@
c << r4.c;
c2;
f << r4.func;
@@
import re
coccinelle.c2 = re.sub('"%s[: ]*' % f, '"', c, 1)

@depends on rules@
expression x;
constant char[] r4.c;
identifier s4.c2;
@@
NV_PRINTF2(x,
-c
+c2
,...);

Based on what I've read, I need to add < > in order for spatch to run
the rule multiple times within a function. But if I change r4 to
this:

@r4 depends on rules@
identifier func;
expression x;
constant char[] c;
@@
func(...) {
<...
NV_PRINTF2(x, c, ...)
...>
}

It doesn't work at all.
Timur Tabi
2018-12-04 22:19:16 UTC
Permalink
Post by Timur Tabi
Based on what I've read, I need to add < > in order for spatch to run
the rule multiple times within a function. But if I change r4 to
@r4 depends on rules@
identifier func;
expression x;
constant char[] c;
@@
func(...) {
<...
NV_PRINTF2(x, c, ...)
...>
}
It doesn't work at all.
Ok, I changed it to

func(...) {
<+...
NV_PRINTF2(x, c, ...)
...+>
}

and now it works. I don't know why I needed the +'s, but at least it
works now. Thanks.
Julia Lawall
2018-12-05 06:35:33 UTC
Permalink
Post by Timur Tabi
Post by Timur Tabi
Based on what I've read, I need to add < > in order for spatch to run
the rule multiple times within a function. But if I change r4 to
@r4 depends on rules@
identifier func;
expression x;
constant char[] c;
@@
func(...) {
<...
NV_PRINTF2(x, c, ...)
...>
}
It doesn't work at all.
Ok, I changed it to
func(...) {
<+...
NV_PRINTF2(x, c, ...)
...+>
}
and now it works. I don't know why I needed the +'s, but at least it
works now. Thanks.
This means that the rule only applies when there is at least one
occurrence of the pattern in between the <+... ...+>.

The previous rule matched all functions.

julia
Timur Tabi
2018-12-05 17:49:16 UTC
Permalink
Post by Julia Lawall
Post by Timur Tabi
and now it works. I don't know why I needed the +'s, but at least it
works now. Thanks.
This means that the rule only applies when there is at least one
occurrence of the pattern in between the <+... ...+>.
Unfortunately, on some files, adding the + significantly slows down
the script. It stalls for about 15-20 seconds a few times during
parsing. Normally the while script takes about 1-2 seconds to run. I
believe coccinelle is having trouble finding the functions because
some my source files abuse C macros.
Julia Lawall
2018-12-05 19:33:56 UTC
Permalink
Post by Timur Tabi
Post by Julia Lawall
Post by Timur Tabi
and now it works. I don't know why I needed the +'s, but at least it
works now. Thanks.
This means that the rule only applies when there is at least one
occurrence of the pattern in between the <+... ...+>.
Unfortunately, on some files, adding the + significantly slows down
the script. It stalls for about 15-20 seconds a few times during
parsing. Normally the while script takes about 1-2 seconds to run. I
believe coccinelle is having trouble finding the functions because
some my source files abuse C macros.
That wouldn't change by using <+... ...+>

Could you send the rule again? I could make another suggestion.

julia
Julia Lawall
2018-12-05 06:34:27 UTC
Permalink
Post by Timur Tabi
Post by Julia Lawall
Post by Timur Tabi
Post by Julia Lawall
The name of the current function at a given match is available in a
position variable bound as part of that match. A position variable should
have a current_element field.
Unfortunately, I don't understand what you're saying. I see some
examples referencing the "position" in a Python script, but they don't
make any sense to me, e.g.
http://coccinelle.lip6.fr/docs/main_grammar016.html#sec27
@ r exists @
local idexpression struct device_node *n;
position p1, p2;
statement S1,S2;
expression E,E1;
I assume when you say "position parameter", you're talking about the
"position p1, p2;" above. If so, I'm completely confused.
In the example, p1 will store the position of n. In the python rule, you
can then access p1[0].current_element to get the name of the function in
which n occurs.
What do you mean by "position of n"?
The code that n matches is in some file, within some function, at some
line number, and at some column offset. All of that information is
collected in p1.
Post by Timur Tabi
I managed to figure it out without using positional parameters. It
// Look for NV_PRINTF2 calls that have the function name in the string
@r4 depends on rules@
identifier func;
expression x;
constant char[] c;
@@
func(...) {
...
NV_PRINTF2(x, c, ...)
...
}
This can work, but as written it requires exactly one call to NV_PRINTF2
on every control-flow path through the function. It also has to trace
through the entire function, which will be expensive.
Post by Timur Tabi
// Get rid of the function name at the beginning of the string
@script:python s4@
c << r4.c;
c2;
f << r4.func;
@@
import re
coccinelle.c2 = re.sub('"%s[: ]*' % f, '"', c, 1)
@depends on rules@
expression x;
constant char[] r4.c;
identifier s4.c2;
@@
NV_PRINTF2(x,
-c
+c2
,...);
Based on what I've read, I need to add < > in order for spatch to run
the rule multiple times within a function. But if I change r4 to
@r4 depends on rules@
identifier func;
expression x;
constant char[] c;
@@
func(...) {
<...
NV_PRINTF2(x, c, ...)
...>
}
It doesn't work at all.
What do you mean by doesn't work at all?

julia
Timur Tabi
2018-12-05 17:57:09 UTC
Permalink
Post by Julia Lawall
Post by Timur Tabi
Post by Julia Lawall
In the example, p1 will store the position of n. In the python rule, you
can then access p1[0].current_element to get the name of the function in
which n occurs.
What do you mean by "position of n"?
The code that n matches is in some file, within some function, at some
line number, and at some column offset. All of that information is
collected in p1.
I'm having trouble figuring out how to access p1[0]. I tried this

// Use Python to clean up the string literals.
// Comments are still C-style though
@r depends on rules@
expression x;
position p1;
constant char[] c;
@@
NV_PRINTF2(x, c, ...)

@script:python s@
c << r.c;
c2;
p1 << r.p1;
@@
import re

print p1

But that gave me this error:

warning: r: metavariable p1 not used in the - or
Timur Tabi
2018-12-05 18:32:05 UTC
Permalink
Another thing that I don't understand is why do I need to have two
rules for every Python script? I've attached my .cocci file. Each
Python script is in between a pair of //---- comments. They all have
the same format:

1. One rule to specify the pattern to match
2. A Python script
3. Another rule to specify how to process the output of the Python script

Can't I combine 1) and 3) into one rule?
Julia Lawall
2018-12-05 19:45:47 UTC
Permalink
Post by Timur Tabi
Another thing that I don't understand is why do I need to have two
rules for every Python script? I've attached my .cocci file. Each
Python script is in between a pair of //---- comments. They all have
1. One rule to specify the pattern to match
2. A Python script
3. Another rule to specify how to process the output of the Python script
Can't I combine 1) and 3) into one rule?
No. It is possible to attach script code to metavariable declarations,
but only to express predicates. For example:

constant c : script:ocaml() { is_less_than_6 c };

is_less_than_6 would be defined in the @initialize:ocaml@ rule, and
takes a string as an argument, which is the potential term to bind to c,
and returns true or false.

julia
Timur Tabi
2018-12-05 19:11:21 UTC
Permalink
Post by Timur Tabi
@script:python s@
c << r.c;
c2;
p1 << r.p1;
@@
import re
print p1
warning: r: metavariable p1 not used in the - or
Never mind, I now understand how the @p1 is supposed to be used. I
have it working now.
Timur Tabi
2018-12-05 23:27:32 UTC
Permalink
Post by Timur Tabi
have it working now.
I spoke too soon, I'm getting a weird error:

rule starting on line 232: already tagged token:
C code context
File "/tmp/cocci_small_output-22474-8398df.c", line 43, column 23,
charpos = 1216
around = '"init_PllId: Error programming clock. Stopping script.\n"',
whole content = "init_PllId: Error
programming clock. Stopping script.\n");

Line 232 is the "depends on rule" in this snippet:

// Get rid of the function name at the beginning of the string
@script:python s4@
c << r4.c;
c2;
p1 << r4.p1;
@@
import re

f = p1[0].current_element
coccinelle.c2 = re.sub('"%s[: ]*' % f, '"', c, 1)

@depends on rules@
expression x;
constant char[] r4.c;
identifier s4.c2;
@@
NV_PRINTF2(x,
-c
+c2
,...);
Julia Lawall
2018-12-06 06:33:50 UTC
Permalink
Post by Timur Tabi
Post by Timur Tabi
have it working now.
C code context
File "/tmp/cocci_small_output-22474-8398df.c", line 43, column 23,
charpos = 1216
around = '"init_PllId: Error programming clock. Stopping script.\n"',
whole content = "init_PllId: Error
programming clock. Stopping script.\n");
// Get rid of the function name at the beginning of the string
@script:python s4@
c << r4.c;
c2;
p1 << r4.p1;
@@
import re
f = p1[0].current_element
coccinelle.c2 = re.sub('"%s[: ]*' % f, '"', c, 1)
@depends on rules@
expression x;
constant char[] r4.c;
identifier s4.c2;
@@
NV_PRINTF2(x,
-c
+c2
,...);
Probably the same string occurs in multiple functions, so you get multiple
new propositions for it. To guard against this, you should reuse the
position variable:

@depends on rules@
expression x;
constant char[] r4.c;
position r4.p1;
identifier s4.c2;
@@
NV_PRINTF2(x,
-***@p1
+c2
,...);

You may need to move the @p1. It should be in the same place that it
appears in r4.

julia

Julia Lawall
2018-12-05 19:32:20 UTC
Permalink
Post by Timur Tabi
Post by Julia Lawall
Post by Timur Tabi
Post by Julia Lawall
In the example, p1 will store the position of n. In the python rule, you
can then access p1[0].current_element to get the name of the function in
which n occurs.
What do you mean by "position of n"?
The code that n matches is in some file, within some function, at some
line number, and at some column offset. All of that information is
collected in p1.
I'm having trouble figuring out how to access p1[0]. I tried this
// Use Python to clean up the string literals.
// Comments are still C-style though
@r depends on rules@
expression x;
position p1;
constant char[] c;
@@
NV_PRINTF2(x, c, ...)
You need to attach p1 to something. For example, you could say ***@p1 or
***@p1 or )@p1

julia
Post by Timur Tabi
@script:python s@
c << r.c;
c2;
p1 << r.p1;
@@
import re
print p1
warning: r: metavariable p1 not used in the - or
Loading...