在51CTO的Unix操作系统开发中我们介绍过AIX6 的安全新特性。 AIX 6.1 中引入的 ProbeVue 是一个动态跟踪工具。它最初的设计目的是动态地跟踪 C 应用程序和系统中的系统调用。随着时间的推移,它现在支持调试Java应用程序,还支持获取实时转储和基本系统调用。本文讨论 ProbeVue 对 Java 的支持。
ProbeVue 具有以下特性:
◆跟踪钩子不需要作为源代码的组成部分预先编译。
◆ProbeVue 适用于 32/64 位内核和应用程序,不需要做任何修改。
◆在通过 ProbeVue 放置跟踪钩子之前,它们并不存在。
◆可以立即查看跟踪活动捕捉的跟踪数据,可以作为终端输出显示它们,或者保存到文件中供以后查看。
◆跟踪钩子可以应用于任何函数的入口或出口(当前对于系统调用只支持出口探测点)。
◆当探测类型为入口时,可以探测传递给函数的参数,这要求在 Vue 脚本的开头或通过头文件定义函数原型。
◆通过在出口点应用跟踪钩子并指定函数原型,可以探测函数的退出/返回值。
◆可以使用 ProbeVue 进行性能分析和问题调试。
使用 ProbeVue 的前提条件
◆AIX V6.10 和更高版本
◆文件集:不需要特殊的文件集,基本操作系统附带所需的文件集。
◆在尝试探测之前需要启用 ProbeVue 特性,可以使用 SMIT 启用它。
Vue 脚本语法
◆探测 Java 函数
- @@uftjava:PID:*:"fully qualified function name":entry
◆探测 Java 库例程:与 Java 函数相同。
命令语法
单独启动 Java 应用程序和 ProbeVue
◆Java 应用程序
- 对于 32 位:java -agentlib:probevuejava <additional parameters> myjavaapp
- 对于 64 位:java -agentlib:probevuejava64 <additional parameters> myjavaapp
◆ProbeVue
- ProbeVue <additional arguments> myscript.e <script arguments>
作为 ProbeVue 的子进程启动 Java 应用程序
◆对于 32 位:probevue -X <path of java> -A "-agentlib:probevuejava <additional parameters> my javaapp" myscript.e
◆对于 64 位:probevue -X <path of java> -A "-agentlib:probevuejava64 <additional parameters> my javaapp" myscript.e
基本探测示例
基本探测示例:myjava.java
- import java.lang.reflect.*;
- import java.util.*;
- import java.lang.*;
- class myclass1
- {
- int i;
- float f;
- double d;
- boolean b;
- String s;
- public myclass1(int j)
- {
- i=j;
- }
- public void set_i(int j)
- {
- i=j;
- }
- public void set_f(float j)
- {
- f=j;
- }
- public void set_d(double j)
- {
- d=j;
- }
- public void set_b(boolean j)
- {
- b=j;
- }
- public void set_s(String j)
- {
- s=j;
- }
- public void print_i()
- {
- System.out.println("Value of Integer i:"+i);
- System.out.println("Value of Float f:"+f);
- System.out.println("Value of Double d:"+d);
- System.out.println("Value of Boolean b:"+b);
- System.out.println("Value of String s:"+s);
- }
- }
- public class myjava
- {
- public static void main(String args[]) throws java.lang.InterruptedException
- {
- Thread.sleep(60);
- System.out.println("In main");
- myclass1 MC1=new myclass1(20);
- MC1.set_i(10);
- MC1.set_f((float)10.03);
- MC1.set_d(10.1123);
- MC1.set_b(false);
- MC1.set_s("ProbeVue");
- MC1.print_i();
- int [] int1;
- int1 = new int[10];
- for(int i=0;i<10;i++)
- Array.set(int1,i,(int)i);
- for(int i=0;i<10;i++)
- {
- System.out.println(Array.getInt(int1,i));
- }
- }
- }
执行基本探测的 Vue 脚本:basic_probing.e
- @@BEGIN
- {
- // Declare and Initialize the variable to track the number of calls made
- // to Array.set function
- int Number_Of_Calls_Of_Array_set;
- Number_Of_Calls_Of_Array_set=0;
- }
- //Probe String to trace the calls to function myclass1.set_d
- @@uftjava:$__CPID:*:"myclass1.set_d":entry
- {
- //Printing the message for user notification that this function has been called
- //By adding ProbeVue tag to message we can easily filter out the ProbeVue messages only.
- printf("ProbeVue - Entered myclass1.set_d function \n");
- }
- @@uftjava:$__CPID:*:"myclass1.set_f":entry
- {
- printf("ProbeVue - Entered myclass1.set_f function \n");
- }
- @@uftjava:$__CPID:*:"myclass1.set_i":entry
- {
- printf("ProbeVue - Entered myclass1.set_i function \n");
- }
- @@uftjava:$__CPID:*:"myclass1.set_s":entry
- {
- printf("ProbeVue - Entered myclass1.set_s function \n");
- }
- @@uftjava:$__CPID:*:"myclass1.set_b":entry
- {
- printf("ProbeVue - Entered myclass1.set_b function \n");
- }
- @@uftjava:$__CPID:*:"myjava.main":entry
- {
- printf("ProbeVue - Entered myjava.main function \n");
- // Printing the Process Id and Parent Process Id
- printf(" Process Id : %ld\n",__pid);
- printf("Parent Process Id : %ld\n",__ppid);
- }
- @@uftjava:$__CPID:*:"java.lang.reflect.Array.set":entry
- {
- printf("ProbeVue - Entered java.lang.reflect.Array.set function \n");
- // Increment the count whenever the function is called
- Number_Of_Calls_Of_Array_set++;
- }
- @@syscall:$__CPID:exit:entry
- {
- // Exit when the application exits
- exit();
- }
- @@END
- {
- //This is executed when ProbeVue session exits and prints the following message.
- printf("Number Of times function - \"java.lang.reflect.Array.set\" called is
- : %d\n",Number_Of_Calls_Of_Array_set);
- }
输出
- # probevue -X `which java` -A "-agentlib:probevuejava myjava" basic_probing.e
- ProbeVue - Entered myjava.main function
- Process Id : 7209080
- Parent Process Id : 5767168
- In main
- Value of Integer i:10
- ProbeVue - Entered myclass1.set_i function
- ProbeVue - Entered myclass1.set_f function
- ProbeVue - Entered myclass1.set_d function
- ProbeVue - Entered myclass1.set_b function
- ProbeVue - Entered myclass1.set_s function
- Value of Float f:10.03
- Value of Double d:10.1123
- Value of Boolean b:false
- Value of String s:ProbeVue
- 0
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- ProbeVue - Entered java.lang.reflect.Array.set function
- ProbeVue - Entered java.lang.reflect.Array.set function
- ProbeVue - Entered java.lang.reflect.Array.set function
- ProbeVue - Entered java.lang.reflect.Array.set function
- ProbeVue - Entered java.lang.reflect.Array.set function
- ProbeVue - Entered java.lang.reflect.Array.set function
- ProbeVue - Entered java.lang.reflect.Array.set function
- ProbeVue - Entered java.lang.reflect.Array.set function
- ProbeVue - Entered java.lang.reflect.Array.set function
- ProbeVue - Entered java.lang.reflect.Array.set function
- Number Of times function - "java.lang.reflect.Array.set" called is : 10
访问参数
除了提供放置探测的功能之外,ProbeVue 还允许收集传递给函数的参数值。对于访问参数,不需要为 ProbeVue 指定函数原型。
注意,Java 应用程序代码与前一个示例相同,也是 myjava.java。
访问参数的示例 Vue 脚本
- # cat accessing_argument.e
- @@uftjava:$__CPID:*:"myclass1.set_d":entry
- {
- //Declaring Vue variable - d of type double
- double d;
- d=__arg2;
- printf("ProbeVue - Entered myclass1.set_d function with
- argument :%llf\n",__arg2);
- printf("ProbeVue Variable d : %llf\n",d);
- // Above is to demonstrate that argument values could be stored in Vue variables and then
- // either operated and printed or printed directly
- }
- @@uftjava:$__CPID:*:"myclass1.set_f":entry
- {
- printf("ProbeVue - Entered myclass1.set_f function with argument :%f\n",__arg2);
- }
- @@uftjava:$__CPID:*:"myclass1.set_i":entry
- {
- printf("ProbeVue - Entered myclass1.set_i function with argument :%d\n",__arg2);
- }
- @@uftjava:$__CPID:*:"myclass1.set_s":entry
- {
- //Declaring String type Vue variable - s with its size
- String s[100];
- //String type variable of Java can be directly copied to String type variable of Vue
- s=__arg2;
- printf("ProbeVue - Entered myclass1.set_s function with argument :%s\n",__arg2);
- printf("ProbeVue Variable s : %s\n",s);
- }
- @@uftjava:$__CPID:*:"myclass1.set_b":entry
- {
- printf("ProbeVue - Entered myclass1.set_b function with argument :%d\n",__arg2);
- }
- @@uftjava:$__CPID:*:"myjava.main":entry
- {
- printf("ProbeVue - Entered Probed Main\n");
- }
- @@uftjava:$__CPID:*:"java.lang.reflect.Array.set":entry
- {
- printf("ProbeVue - Entered java.lang.reflect.Array.set function with
- 2nd argument as : %d\n",__arg2);
- }
- @@syscall:$__CPID:exit:entry
- {
- exit();
- }
输出
- #probevue -X `which java` -A "-agentlib:probevuejava myjava" accessing_argument.e
- ProbeVue - Entered Probed Main
- In main
- Value of Integer i:10
- ProbeVue - Entered myclass1.set_i function with argument :10
- ProbeVue - Entered myclass1.set_f function with argument :10.030000
- ProbeVue - Entered myclass1.set_d function with argument :10.112300
- ProbeVue Variable d : 10.112300
- ProbeVue - Entered myclass1.set_b function with argument :0
- ProbeVue - Entered myclass1.set_s function with argument :ProbeVue
- ProbeVue Variable s : ProbeVue
- Value of Float f:10.03
- Value of Double d:10.1123
- Value of Boolean b:false
- Value of String s:ProbeVue
- 0
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- ProbeVue - Entered java.lang.reflect.Array.set function with 2nd argument as : 0
- ProbeVue - Entered java.lang.reflect.Array.set function with 2nd argument as : 1
- ProbeVue - Entered java.lang.reflect.Array.set function with 2nd argument as : 2
- ProbeVue - Entered java.lang.reflect.Array.set function with 2nd argument as : 3
- ProbeVue - Entered java.lang.reflect.Array.set function with 2nd argument as : 4
- ProbeVue - Entered java.lang.reflect.Array.set function with 2nd argument as : 5
- ProbeVue - Entered java.lang.reflect.Array.set function with 2nd argument as : 6
- ProbeVue - Entered java.lang.reflect.Array.set function with 2nd argument as : 7
- ProbeVue - Entered java.lang.reflect.Array.set function with 2nd argument as : 8
- ProbeVue - Entered java.lang.reflect.Array.set function with 2nd argument as : 9
注意以下几点:
◆对于静态函数,可以使用 __arg1 访问函数的第一个实际参数。
◆对于非静态函数,可以使用 __arg2 访问函数的第一个实际参数,因为作为 __arg1 隐式地传递 this 指针。
其他要点
◆ProbeVue 脚本可以使用完全限定名(例如 java.lang.Math.PI)读取 Java 类中的静态变量和常量。
◆没有替代 @@uftjava 的语法。
◆不需要指定函数原型,也不需要头文件。
◆不需要通过使用 copy_userdata 访问基本数据类型。
◆Java 的布尔数据类型映射到 ProbeVue 的整数数据类型,1 值代表 true,0 值代表 false。
◆Java 的字符串数据类型映射到 ProbeVue 的字符串数据类型。
◆__pname 提供进程名称 "java" 而不是应用程序名,比如 myjavaapp。
◆所有其他函数的使用方法相同。
◆可以用 -agentlib:probevuejava 标志启动 Java 应用程序,但是以后再启动 ProbeVue 会话。
◆可以探测静态和非静态函数。
◆如果在 ProbeVue 命令行上用 -X 选项启动 JVM,那么只能探测 Java 类中的 main 函数。这迫使 JVM 等到 ProbeVue 启动之后才启动 Java 应用程序。
可能实现的场景
◆统计调用某一函数的次数。
◆跟踪调用各个函数的次序。
◆检查参数值是否正确。
限制
◆只支持 JVM V1.5 和更高版本。
◆目前不支持访问数组、实例变量和对象引用。
◆不支持探测重载和多态的函数。
◆目前不支持 get_function Vue 函数。
◆不能探测 Java 函数的出口点,因此不能获取函数的返回值。
【编辑推荐】