Using smatch.pm!!!There are 2 main parts to a Smatch script: pattern matching in the code and tracing state transitions down the code paths. The smatch.pm module is meant to make tracing the code paths easy. There are not too many functions you need to know about actually. Here is a listing in no particular order:
563~/progs/gcc/cvs/pristine.$ grep sub\ [a-z] smatch.pm
sub get_filename {
sub get_lineno {
sub get_cur_func {
sub get_func_pos {
sub set_state {
sub set_true_path {
sub set_false_path {
sub get_state {
sub get_start_line {
sub state_names {
sub add_merge_function($) {
sub abandon_merge($$$) {
sub get_data {
2. General Purpose Functions Each .sm file is made up of lots of stuff that looks like this:
SM include/asm/bitops.h 43 end_func
For this particular line:
get_data() returns "end_func".get_filename() returns "include/asm/bitops.h". get_lineno() returns 43. get_cur_func() returns "sched_find_first_bit". get_func_pos() returns "sched_find_first_bit(3)". 3. Managing States There are three places of interest when tracing state changes: Normal code, branching code and merging code. If a state change happens in normal code then we use the function set_state() to specify the new state. We can either specify the name of the state that changes or allow smatch.pm to supply a name. The respective formats are:
set_state("foo", "bar");
set_state("baz");
Sometimes the state change happens at a branch
position. For example, if you have code that looks
like this:
if (locked(a)){
Then we might say something like this:
set_true_path("a", "locked");
set_false_path("a", "unlocked");
The if statement may have an else statement or it may not.
Either way smatch.pm takes care of that. While statements
are basically the same as if statements except there is
never an else statement.
Smatch.pm automatically handles merging states and for some cases that is good enough. However there are times when it is nice to specify your own merge rules. To do that create a function that takes three parameters:
sub merger($$$) {
my ($name, $one, $two) = @_;
...[code]...
}
The first parameter is the name of the state, and the other
parameters are the two states to merge. From the last example
it could be something like:
$name: "a"
$one: "locked"
$two: "unlocked"
In that case we would probably want to return "undefined".
Once we written the merge function then we say:
add_merge_function("merger")
The other function to handle merging abandon_merge() is
only meant for libraries and isn't used yet. Don't worry
about it.
Once we have stored some states the function get_state() can tell us what the state currently is. If we have stored a lot of state names then we can get a list of all the state names using the function state_names() The last function used to manage states is get_start_line() which records which line the state was first set. This is usefull information for error messages. 4. Printing Error Messages This is how error messages usually are printed.
sub error_msg($$) {
my $state = shift;
my $msg = shift;
print get_filename(), " ", get_start_line($state), " ", get_lineno(), " ", get_func_pos(), " $msg\n";
}
I normally take a list of error messages only look at error
messages with different starting lines. That cuts down on
duplicate messages for the same error.
get_func_pos() is a type of finger print that can be tracked over different kernel versions. It means that a change in the file can happen but unless something happens in that particular function we can still recognize a bug as one that has been seen before. 5. Conclusion Writing Smatch scripts is pretty easy. Sometimes it's interesting to write silly scripts just to see what sort of results they will find. Don't worry too much about being thorough or avoiding false positives for the first draft; just slap it together and see what happens. If you need help writing scripts or you want features added to Smatch then email smatch-discuss@lists.sf.net |