詳解C語言動(dòng)態(tài)跟蹤工具ProbeVue如何調(diào)試Java應(yīng)用程序
在51CTO的Unix操作系統(tǒng)開發(fā)中我們介紹過AIX6 的安全新特性。 AIX 6.1 中引入的 ProbeVue 是一個(gè)動(dòng)態(tài)跟蹤工具。它最初的設(shè)計(jì)目的是動(dòng)態(tài)地跟蹤 C 應(yīng)用程序和系統(tǒng)中的系統(tǒng)調(diào)用。隨著時(shí)間的推移,它現(xiàn)在支持調(diào)試Java應(yīng)用程序,還支持獲取實(shí)時(shí)轉(zhuǎn)儲(chǔ)和基本系統(tǒng)調(diào)用。本文討論 ProbeVue 對(duì) Java 的支持。
ProbeVue 具有以下特性:
◆跟蹤鉤子不需要作為源代碼的組成部分預(yù)先編譯。
◆ProbeVue 適用于 32/64 位內(nèi)核和應(yīng)用程序,不需要做任何修改。
◆在通過 ProbeVue 放置跟蹤鉤子之前,它們并不存在。
◆可以立即查看跟蹤活動(dòng)捕捉的跟蹤數(shù)據(jù),可以作為終端輸出顯示它們,或者保存到文件中供以后查看。
◆跟蹤鉤子可以應(yīng)用于任何函數(shù)的入口或出口(當(dāng)前對(duì)于系統(tǒng)調(diào)用只支持出口探測(cè)點(diǎn))。
◆當(dāng)探測(cè)類型為入口時(shí),可以探測(cè)傳遞給函數(shù)的參數(shù),這要求在 Vue 腳本的開頭或通過頭文件定義函數(shù)原型。
◆通過在出口點(diǎn)應(yīng)用跟蹤鉤子并指定函數(shù)原型,可以探測(cè)函數(shù)的退出/返回值。
◆可以使用 ProbeVue 進(jìn)行性能分析和問題調(diào)試。
使用 ProbeVue 的前提條件
◆AIX V6.10 和更高版本
◆文件集:不需要特殊的文件集,基本操作系統(tǒng)附帶所需的文件集。
◆在嘗試探測(cè)之前需要啟用 ProbeVue 特性,可以使用 SMIT 啟用它。
Vue 腳本語法
◆探測(cè) Java 函數(shù)
- @@uftjava:PID:*:"fully qualified function name":entry
 
◆探測(cè) Java 庫(kù)例程:與 Java 函數(shù)相同。
命令語法
單獨(dú)啟動(dòng) Java 應(yīng)用程序和 ProbeVue
◆Java 應(yīng)用程序
- 對(duì)于 32 位:java -agentlib:probevuejava <additional parameters> myjavaapp
 - 對(duì)于 64 位:java -agentlib:probevuejava64 <additional parameters> myjavaapp
 
◆ProbeVue
- ProbeVue <additional arguments> myscript.e <script arguments>
 
作為 ProbeVue 的子進(jìn)程啟動(dòng) Java 應(yīng)用程序
◆對(duì)于 32 位:probevue -X <path of java> -A "-agentlib:probevuejava <additional parameters> my javaapp" myscript.e
◆對(duì)于 64 位:probevue -X <path of java> -A "-agentlib:probevuejava64 <additional parameters> my javaapp" myscript.e
基本探測(cè)示例
基本探測(cè)示例: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));
 - }
 - }
 - }
 
執(zhí)行基本探測(cè)的 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
 
訪問參數(shù)
除了提供放置探測(cè)的功能之外,ProbeVue 還允許收集傳遞給函數(shù)的參數(shù)值。對(duì)于訪問參數(shù),不需要為 ProbeVue 指定函數(shù)原型。
注意,Java 應(yīng)用程序代碼與前一個(gè)示例相同,也是 myjava.java。
訪問參數(shù)的示例 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
 
注意以下幾點(diǎn):
◆對(duì)于靜態(tài)函數(shù),可以使用 __arg1 訪問函數(shù)的第一個(gè)實(shí)際參數(shù)。
◆對(duì)于非靜態(tài)函數(shù),可以使用 __arg2 訪問函數(shù)的第一個(gè)實(shí)際參數(shù),因?yàn)樽鳛?__arg1 隱式地傳遞 this 指針。
其他要點(diǎn)
◆ProbeVue 腳本可以使用完全限定名(例如 java.lang.Math.PI)讀取 Java 類中的靜態(tài)變量和常量。
◆沒有替代 @@uftjava 的語法。
◆不需要指定函數(shù)原型,也不需要頭文件。
◆不需要通過使用 copy_userdata 訪問基本數(shù)據(jù)類型。
◆Java 的布爾數(shù)據(jù)類型映射到 ProbeVue 的整數(shù)數(shù)據(jù)類型,1 值代表 true,0 值代表 false。
◆Java 的字符串?dāng)?shù)據(jù)類型映射到 ProbeVue 的字符串?dāng)?shù)據(jù)類型。
◆__pname 提供進(jìn)程名稱 "java" 而不是應(yīng)用程序名,比如 myjavaapp。
◆所有其他函數(shù)的使用方法相同。
◆可以用 -agentlib:probevuejava 標(biāo)志啟動(dòng) Java 應(yīng)用程序,但是以后再啟動(dòng) ProbeVue 會(huì)話。
◆可以探測(cè)靜態(tài)和非靜態(tài)函數(shù)。
◆如果在 ProbeVue 命令行上用 -X 選項(xiàng)啟動(dòng) JVM,那么只能探測(cè) Java 類中的 main 函數(shù)。這迫使 JVM 等到 ProbeVue 啟動(dòng)之后才啟動(dòng) Java 應(yīng)用程序。
可能實(shí)現(xiàn)的場(chǎng)景
◆統(tǒng)計(jì)調(diào)用某一函數(shù)的次數(shù)。
◆跟蹤調(diào)用各個(gè)函數(shù)的次序。
◆檢查參數(shù)值是否正確。
限制
◆只支持 JVM V1.5 和更高版本。
◆目前不支持訪問數(shù)組、實(shí)例變量和對(duì)象引用。
◆不支持探測(cè)重載和多態(tài)的函數(shù)。
◆目前不支持 get_function Vue 函數(shù)。
◆不能探測(cè) Java 函數(shù)的出口點(diǎn),因此不能獲取函數(shù)的返回值。
【編輯推薦】















 
 
 



 
 
 
 