Discussion:
[Cocci] Support for macro expansion
Martijn Coenen
2018-01-12 16:19:16 UTC
Permalink
Hello,

I can't find a clear-cut answer on whether macro expansion is supported in
Coccinelle. There's a "--preprocess" option which says it runs the C
preprocessor before doing the match, but it didn't appear to do anything
when I tried it.

Background: I'm trying to do a semantic patch that is only applied when a
certain function is called or assigned. Unfortunately in some cases, the
function call is embedded in a macro, and so Coccinelle will not find it.
I'm aware I can manually define a macros file and have it expanded this
way, but I want to make this as generic as possible and have it work for
any function in the linux kernel - which means I'd have to put *lots* of
macros in there :)

Any suggestions?

Thanks,
Martijn
Julia Lawall
2018-01-12 18:50:13 UTC
Permalink
Post by Martijn Coenen
Hello,
I can't find a clear-cut answer on whether macro expansion is supported in
Coccinelle. There's a "--preprocess" option which says it runs the C
preprocessor before doing the match, but it didn't appear to do anything
when I tried it.
Background: I'm trying to do a semantic patch that is only applied when a
certain function is called or assigned. Unfortunately in some cases, the
function call is embedded in a macro, and so Coccinelle will not find it.
I'm aware I can manually define a macros file and have it expanded this way,
but I want to make this as generic as possible and have it work for any
function in the linux kernel - which means I'd have to put *lots* of macros
in there :)
Any suggestions?
Is it possible to parse the macro? That is, is the body a legal C
statement or expression?

Normally, macros are only unfolded when doing so is necessary to parse the
context in which the macro occurs. But when a macro is unfolded for that
reason, it is not possible to transform the unfolded code, although it is
possible to match it.

It is indeed possible that the --preprocess argument does not do anything.

julia
Martijn Coenen
2018-01-12 19:10:46 UTC
Permalink
Post by Julia Lawall
Is it possible to parse the macro? That is, is the body a legal C
statement or expression?
The macro I was looking at is module_usb_serial_driver():

https://elixir.free-electrons.com/linux/v4.15-rc7/source/include/linux/usb/serial.h#L433

The macro itself expands to another macro (maybe that is the
problem?), which expands to a few C function definitions. In this case
I was interested in seeing whether a file used the
"usb_serial_register_drivers()" function, which is called in one of
those function definitions.

Thanks,
Martijn
Post by Julia Lawall
Normally, macros are only unfolded when doing so is necessary to parse the
context in which the macro occurs. But when a macro is unfolded for that
reason, it is not possible to transform the unfolded code, although it is
possible to match it.
It is indeed possible that the --preprocess argument does not do anything.
julia
Julia Lawall
2018-01-13 06:46:09 UTC
Permalink
Post by Martijn Coenen
Post by Julia Lawall
Is it possible to parse the macro? That is, is the body a legal C
statement or expression?
https://elixir.free-electrons.com/linux/v4.15-rc7/source/include/linux/usb/serial.h#L433
The macro itself expands to another macro (maybe that is the
problem?), which expands to a few C function definitions. In this case
I was interested in seeing whether a file used the
"usb_serial_register_drivers()" function, which is called in one of
those function definitions.
The easiest thing would be to just extend your semantic patch to look for
uses of module_usb_serial_driver. module_usb_serial_driver however is
called outside of any function. So you need to make a declaration among
the metavariables:

declarer name module_usb_serial_driver;

It doesn't make it ia metavariable, but rather gives some information
about the name so that it will look for this name at top level.

julia
Post by Martijn Coenen
Thanks,
Martijn
Post by Julia Lawall
Normally, macros are only unfolded when doing so is necessary to parse the
context in which the macro occurs. But when a macro is unfolded for that
reason, it is not possible to transform the unfolded code, although it is
possible to match it.
It is indeed possible that the --preprocess argument does not do anything.
julia
Martijn Coenen
2018-01-15 07:54:00 UTC
Permalink
Post by Julia Lawall
declarer name module_usb_serial_driver;
It doesn't make it ia metavariable, but rather gives some information
about the name so that it will look for this name at top level.
Thanks, I'll give this a shot. But say I wanted to do this for any
random function in the linux kernel; in that case I would have to
manually declare all macros that contain any of those functions? In
other words, there's not really a way to write something that works
for any function (passed as a virtual to the .cocci)?

Thanks,
Martijn
Post by Julia Lawall
julia
Post by Martijn Coenen
Thanks,
Martijn
Post by Julia Lawall
Normally, macros are only unfolded when doing so is necessary to parse the
context in which the macro occurs. But when a macro is unfolded for that
reason, it is not possible to transform the unfolded code, although it is
possible to match it.
It is indeed possible that the --preprocess argument does not do anything.
julia
Julia Lawall
2018-01-15 09:14:58 UTC
Permalink
Post by Martijn Coenen
Post by Julia Lawall
declarer name module_usb_serial_driver;
It doesn't make it ia metavariable, but rather gives some information
about the name so that it will look for this name at top level.
Thanks, I'll give this a shot. But say I wanted to do this for any
random function in the linux kernel; in that case I would have to
manually declare all macros that contain any of those functions? In
other words, there's not really a way to write something that works
for any function (passed as a virtual to the .cocci)?
My impression is that the problem arises only rarely.

It's hard for Coccinelle to know what macros you want to be expanded.
Also Coccinelle doesn't necessarily have access to the definitions of the
macros, unless you use eg --recursive-includes, which will massively
increase the amount of code to process and correspondingly degrade the
performance. The idea is that generally it is beneficial to reason about
the code in the way that you see it, ie with the macro calls in the code
as they are.

julia
Post by Martijn Coenen
Thanks,
Martijn
Post by Julia Lawall
julia
Post by Martijn Coenen
Thanks,
Martijn
Post by Julia Lawall
Normally, macros are only unfolded when doing so is necessary to parse the
context in which the macro occurs. But when a macro is unfolded for that
reason, it is not possible to transform the unfolded code, although it is
possible to match it.
It is indeed possible that the --preprocess argument does not do anything.
julia
Martijn Coenen
2018-01-16 08:33:35 UTC
Permalink
Post by Julia Lawall
The idea is that generally it is beneficial to reason about
the code in the way that you see it, ie with the macro calls in the code
as they are.
Yes, I think that makes sense - what I'm trying to do is sort of an
edge case. Thanks for your help.

Martijn
Post by Julia Lawall
julia
Post by Martijn Coenen
Thanks,
Martijn
julia
Post by Martijn Coenen
Thanks,
Martijn
Post by Julia Lawall
Normally, macros are only unfolded when doing so is necessary to parse the
context in which the macro occurs. But when a macro is unfolded for that
reason, it is not possible to transform the unfolded code, although it is
possible to match it.
It is indeed possible that the --preprocess argument does not do anything.
julia
Loading...