Patch proposal 2/2: allow use of $x and @x identifiers during preprocessing

Benjamin Thery benjamin.thery@bull.net
Tue Apr 3 15:09:00 GMT 2007


Hi,

I'm the aforementioned "colleague".

My request was for a very simple stap script: As I often use Systemtap 
to display backtraces for routines either in the kernel or in modules, 
I wanted a generic script that takes either one or two arguments to 
set the probe (kernelsymbol | modulename modulesymbol).
I didn't want to write a bash wrapper around two stap scripts (too 
much files for such a simple task :) ), so I asked Pierre and he 
developed this small patch. Useful.

The script looks like this:

#! stap
# Trace all execution paths that lead to a given function in the
# kernel or a specified module.
#
# Usage: stap kernel_symbol
#        stap module_name module_symbol

%( $# < 2 %?
probe kernel.function(@1) {
         printf("\n\n---------------------\n")
         print_backtrace()
}
%:
probe module(@1).function(@2) {
         printf("\n\n---------------------\n")
         print_backtrace()
}
%)

Can't be more simple.

Benjamin



Pierre Peiffer wrote:
> 
> Hi again,
> 
>     Here is a second proposal to complete the previous one: this patch 
> allows the use of $x or @x identifiers ($1 ... $n and $#, etc) during 
> the preprocessing (in addition of kernel_v pattern, etc).
>     Again, I originally have written this for a colleague and found this 
> useful.
>     So again:
>> That's why I send it to this list, but just forget this mail if you 
>> don't like it ;-)
> 
> Thanks
> 
> 
> ------------------------------------------------------------------------
> 
> ---
>  ChangeLog |    5 +++++
>  parse.cxx |   51 +++++++++++++++++++++++++++++++++++++++++++++------
>  parse.h   |    4 ++--
>  3 files changed, 52 insertions(+), 8 deletions(-)
> 
> Index: b/parse.cxx
> ===================================================================
> --- a/parse.cxx
> +++ b/parse.cxx
> @@ -146,6 +146,8 @@ parser::last ()
>  // The basic form is %( CONDITION %? THEN-TOKENS %: ELSE-TOKENS %)
>  // where CONDITION is: kernel_v[r] COMPARISON-OP "version-string"
>  //                 or: arch COMPARISON-OP "arch-string"
> +//                 or: "string1" COMPARISON-OP "string2"
> +//                 or: number1 COMPARISON-OP number2
>  // The %: ELSE-TOKENS part is optional.
>  //
>  // e.g. %( kernel_v > "2.5" %? "foo" %: "baz" %)
> @@ -212,14 +214,49 @@ bool eval_pp_conditional (systemtap_sess
>        
>        return result;
>      }  
> +  else if ((l->type == tok_string && r->type == tok_string)
> +	   || (l->type == tok_number && r->type == tok_number))
> +    {
> +      // collect acceptable strverscmp results.
> +      int rvc_ok1, rvc_ok2;
> +      if (op->type == tok_operator && op->content == "<=")
> +        { rvc_ok1 = -1; rvc_ok2 = 0; }
> +      else if (op->type == tok_operator && op->content == ">=")
> +        { rvc_ok1 = 1; rvc_ok2 = 0; }
> +      else if (op->type == tok_operator && op->content == "<")
> +        { rvc_ok1 = -1; rvc_ok2 = -1; }
> +      else if (op->type == tok_operator && op->content == ">")
> +        { rvc_ok1 = 1; rvc_ok2 = 1; }
> +      else if (op->type == tok_operator && op->content == "==")
> +        { rvc_ok1 = 0; rvc_ok2 = 0; }
> +      else if (op->type == tok_operator && op->content == "!=")
> +        { rvc_ok1 = -1; rvc_ok2 = 1; }
> +      else
> +        throw parse_error ("expected comparison operator", op);
> +
> +      int rvc_result = l->content.compare(r->content);
> +
> +      // normalize rvc_result
> +      if (rvc_result < 0) rvc_result = -1;
> +      if (rvc_result > 0) rvc_result = 1;
> +
> +      return (rvc_result == rvc_ok1 || rvc_result == rvc_ok2);
> +    }
> +  else if (l->type == tok_string && r->type == tok_number
> +	    && op->type == tok_operator)
> +    throw parse_error ("expected string literal as right value", r);
> +  else if (l->type == tok_number && r->type == tok_string
> +	    && op->type == tok_operator)
> +    throw parse_error ("expected number as right value", r);
>    // XXX: support other forms?  "CONFIG_SMP" ?
>    else
> -    throw parse_error ("expected 'arch' or 'kernel_v' or 'kernel_vr'", l);
> +    throw parse_error ("expected 'arch' or 'kernel_v' or 'kernel_vr'\n"
> +		       "             or comparison between strings or integers", l);
>  }
>  
>  
>  const token*
> -parser::scan_pp ()
> +parser::scan_pp (bool expand_args)
>  {
>    while (true)
>      {
> @@ -230,7 +267,7 @@ parser::scan_pp ()
>            return t;
>          }
>  
> -      const token* t = input.scan (); // NB: not recursive!
> +      const token* t = input.scan (expand_args); // NB: not recursive!
>        if (t == 0) // EOF
>          return t;
>        
> @@ -262,7 +299,7 @@ parser::scan_pp ()
>        
>        while (true) // consume THEN tokens
>          {
> -          m = scan_pp (); // NB: recursive
> +          m = scan_pp (result); // NB: recursive
>            if (m == 0)
>              throw parse_error ("missing THEN tokens for conditional", t);
>            
> @@ -282,7 +319,7 @@ parser::scan_pp ()
>            delete m; // "%:"
>            while (true)
>              {
> -              m = scan_pp (); // NB: recursive
> +              m = scan_pp (!result); // NB: recursive
>                if (m == 0)
>                  throw parse_error ("missing ELSE tokens for conditional", t);
>                
> @@ -473,7 +510,7 @@ lexer::input_get ()
>  
>  
>  token*
> -lexer::scan ()
> +lexer::scan (bool expand_args)
>  {
>    token* n = new token;
>    n->location.file = input_name;
> @@ -514,6 +551,8 @@ lexer::scan ()
>        // numbers and @1 .. @999 as strings.
>        if (n->content[0] == '@' || n->content[0] == '$')
>          {
> +	  if (!expand_args)
> +	    return n;
>  	  if (n->content[1] == '#')
>  	    {
>  	      stringstream converter;
> Index: b/parse.h
> ===================================================================
> --- a/parse.h
> +++ b/parse.h
> @@ -64,7 +64,7 @@ struct systemtap_session;
>  class lexer
>  {
>  public:
> -  token* scan ();
> +  token* scan (bool expand_args=true);
>    lexer (std::istream&, const std::string&, systemtap_session&);
>  
>  private:
> @@ -124,7 +124,7 @@ private:
>  
>    // preprocessing subordinate
>    std::vector<const token*> enqueued_pp;
> -  const token* scan_pp ();
> +  const token* scan_pp (bool expand_args=true);
>  
>    // scanning state
>    const token* last ();
> Index: b/ChangeLog
> ===================================================================
> --- a/ChangeLog
> +++ b/ChangeLog
> @@ -1,5 +1,10 @@
>  2007-04-03  Pierre Peiffer  <pierre.peiffer@bull.net>
>  
> +	* parse.cxx, parse.h: Allows the use of $x and @x identifier
> +	during the preprocessing.
> +
> +2007-04-03  Pierre Peiffer  <pierre.peiffer@bull.net>
> +
>  	* parse.cxx: Add $# and @# identifiers to access the number
>  	of arguments passed as 'number' or as 'string'.
>  


-- 
B e n j a m i n   T h e r y  - BULL/DT/Open Software R&D

    http://www.bull.com



More information about the Systemtap mailing list