英文原文: http://sourceware.org/systemtap/langref/Language_elements.html
译者:林永听
注:本系列文章为作者连载作品,请勿转载,否则视为侵权。
5 语言元素
5.1 标识符
标识符用于命名变量和函数。它是一个字母和数字组成的串,可以包含下划线(_) 和美元符号($) 。除了美元符号作为合法字符外,它和C 标识符的语法一样。以美元符号开头的标识符解释为目标软件变量的引用,而不是SystemTap 脚本变量。标识符不能以数字开始。
5.2 数据类型
SystemTap 语言仅有数种数据类型,均不需要类型声明。变量的类型可从它的使用环境中推导出来。为了支持类型推导,转换器强制要求函数的参数和返回值,数组下标和值在使用时要保证类型一致。字符串和整数之间不存在隐式类型转换。标识符在使用时,类型不一致的相关使用都会产生一个错误信号。
5.2.1 字面值
字面值有两种,分别是字符串和整数。字面值可以是十进制,八进制或十六进制,遵照C 语言的标记法,不需要指定类型后缀(如L 或U )。
5.2.2 整数
整数可以是十进制, 十六进制, 或者八进制, 和C 语言标记法相同。整数是一个64 位有符号变量,尽管分析器可以接受(同时会回 卷 )大于2^63 且小于2^64 的整数(译者注:一个64 位有符号整型可以储存的整数范围是[-2^63,2^63 ),因此大于2^63 且小于2^64 的整数会回 卷成相应的负数 )。
5.2.3 字符串
字符串被括在引号(”” )内,反斜杠转义码均按标准C 的转义字符进行解释。字符的长度不能超过MAXSTRINGLEN ,关于字符串长度或其它限制,请参阅1.6 节。
5.2.4 关联数组
请参阅7 节。
5.2.5 统计变量
请参阅8 节。
5.3 分号
分号是一个条空语句,即什么事情也不做。分号是可选的,用作语句的分隔符,通常有助于检查语法错误和消除语法的二义性。
5.4 注释
SystemTap 脚本支持下述三种注释:
# ... shell style, to the end of line
// ... C++ style, to the end of line
/* ... C style ... */
5.5 空白符
正如C 一样,空格,制表符,回车,换行和注释均被视为空白,分析器直接忽略。
5.6 表达式
SystemTap 提供大量的运算符,并且它的用法,语义和优先级均与C 和awk 相同。算术运算符按C 语言中的有符号整数运算规则执行。如果分析器检测到除数为0 或发生溢出,将产生一个错误。这些运算符(分类)罗列在下述各子章节。
5.6.1 二元数值运算符
* / % + - >> << & ^ | && ||
5.6.2 二元字符串运算符
. ( 字符串串接)
5.6.3 数值赋值运算符
= *= /= %= += -= >>= <<= &= ^= |=
5.6.4 字符串赋值运算符
= .=
5.6.5 一元数值运算符
+ - ! ~ ++ -
5.6.6 二元数值/ 字符串比较运行算
< > <= >= == !=
5.6.7 三元运算符
cond ? exp1 : exp2
5.6.8 组合运算符
( exp )
5.6.9 函数调用
函数调用的语法形式如下:
fn ([ arg1, arg2, ... ])
5.6.10 $ptr->member
Ptr 是探测下文中的变量,一个内核指针。
5.6.11 <value> in <array_name>
如果数组包含指定下标的元素,那么上述表达式求值结果为真。
5.6.12 [ <value>, ... ] in <array_name>
下标的个数必须与数组定义时指定的下标个数一致。
5.7 stap 命令行传递过来的字面值
字符值要么是由引号包含的字符串,要么是整数。关于整数的信息,请参阅5.2.2 节,而字符串的信息,请参阅5.2.3 节。
命令行后面的脚本参数被扩展为字面值,可将它用于所有接受字面值的上下文中,但引用不存在的参数编号将引致错误。
5.7.1 $1 ... $<NN> 将参数转换成整数
使用$1 ... $<NN> 将命令行参数转换成整数字面值。
5.7.2 @1 ... @<NN> 将参数转换成字符串
使用@1 ... @<NN> 将命令行参数转换成字符串字面值。
5.7.3 例子
以下述为例,假定该脚本的名字为example.stp
probe begin { printf("%d, %s/n", $1, @2) }
运行如下:
# stap example.stp 10 mystring
那么,$1 会被替换成10 ,而@2 会被替换成"mystring" ,结果输出:
10, mystring
5.8 条件编译
5.8.1 条件
词法分析工作包含简单的条件预处理阶段,它的语法形式类似于三元运算符(5.6.7 节),如下:
%( CONDITION %? TRUE-TOKENS %)
%( CONDITION %? TRUE-TOKENS %: FALSE-TOKENS %)
CONDITION 是一个有限表达式(limited expression ),它的语法格式由它的第一个关键字决定,下述是它的一般语法格式:
%( <condition> %? <code> [ %: <code> ] %)
5.8.2 基于内核版本号的条件: kernel_v 和kernel_vr
此种条件表达式的第一部分是标识符kernel_v 或kernel_vr ,第二部分是六个标准数值比较运算符``<'', ``<='', ``=='', ``!='', ``>'', or ``>='' 之一,第三部分字符串字面值,一个RPM 形式的版本- 发布号值。如果目标内核的版本(可使用-r 选项来重写该版本号)与给定的版本字符串匹配,那么该条件返回真,其中比较操作是由glibc 的strverscmp 函数来实行的。
kernel_v 仅引用内核版本号数值,如"2.6.13" 。
而kernel_vr 除于引用内核版本号数值外,还包含发布号后缀,如 “2.6.13-1.322FC3smp” 。
5.8.3 基于架构的条件:arch
这种条件表达式的第一部分是标识符arch ,它引用处理器架构类型,第二部分是字符串比较运算符”==” 或”!=” ,第三部分字符串字面值。比较结果是简单的字符串相等和不相等。目前所支持的架构字符串分别有:i386 ,i686 ,x86_64 ,ia64 ,s390 和ppc64 。
5.8.4 TRUN-TOKENS 和FALSE-TOKENS
TRUE-TOKENS 和FALSE-TOKENS 是零个或多个语法单元(parser tokens ),可以包含嵌套的预处理条件。如果条件为真,则传递TRUE-TOKENS 到分析器的输入流,否则传递TRUE-TOKENS 。例如,下述例子中除非目标内核版本新于2.6.5 ,否则产生一个语法分析错误。
%( kernel_v <= "2.6.5" %? **ERROR** %) # invalid token sequence
下述代码可适合在不同的内核版本上运行。
probe kernel.function (
%( kernel_v <= "2.6.12" %? "__mm_do_fault" %:
%( kernel_vr == "2.6.13-1.8273FC3smp" %? "do_page_fault" %: UNSUPPORTED %)
%)) { /* ... */ }
%( arch == "ia64" %?
probe syscall.vliw = kernel.function("vliw_widget") {}
%)
下述代码适用于打开内核CONFIG_UTRACR 选( 译者注:原文是CONFIG ,估计是笔误) 。
%( CONFIG_UTRACE == "y" %?
probe process.syscall {}
%)