用systemtap跟蹤打印動態鏈接庫的所有c++函數調用過程


 

 http://gmd20.blog.163.com/blog/static/168439232015475525227/

 
 
 
 
 

用systemtap跟蹤打印動態鏈接庫的所有c++函數調用過程
=================================================

1. ltrace 的問題
---------------
用ltrace 可以打印所有的so文件調用了。但上次試過如果so是自己用dlopen來加載的。
就是在elf結構里面沒有對應的依賴項的情況下,ltrace好像是沒有做對應的調用了。
用systemtap的就沒有這個問題,打印輸出也更靈活一些。

2. systemtap的解析c++ 函數問題
------------------------------
systemtap的 probe point 指定函數名,是支持c++ 方式指定名字的。
但默認的打印輸出卻只能輸出函數名,不包含c++ 類名。

c++ 的函數符號是經過修飾的,比如用 nm *.so 查看就可以看到 _Z開頭一大堆函數名字。

# c++filt _ZZN9log4cplus19initializeLog4cplusEvE11initialized
log4cplus::initializeLog4cplus()::initialized

systemtap的 ppfunc () 函數只輸出"initialized"
systemtap的 probefunc () 函數輸出 "_ZZN9log4cplus19initializeLog4cplusEvE11initialized"
其實我們想要的是 “log4cplus::initializeLog4cplus()::initialized”
但看一下文件是沒有這個tapset函數的,估計的自己寫一個才行。

還好有c++filt 這個命令,可以做c++ 函數名的demangle。 我們就可以簡單用probefunc 打印
然后在自己用c++filt 命令來轉換一下好了。


3. systemtap的函數調用跟蹤
---------------------------
systemtap的資料就有一個 para-callgraph.stp ,根據自己的要求做修改吧。

我是這樣用的,打印所有libTest.so 源碼文件 *.hpp *.cpp 的所有函數,
也就是只有c++的函數。 其實用來跟蹤c函數調用那些用起來更好用吧,都不用做c++
函數名轉換了。根據自己要求來設置跟蹤哪些函數吧。
stap para-callgraph.stp 'process("/usr/lib/libTest.so").function("*@*pp")' 'process("/usr/lib/libTest.so").function("Init")' > trace_file.txt


```
#! /usr/bin/env stap

function trace(entry_p, extra) {
/* %( $# > 1 %? if (tid() in trace) %) */
%( $# > 1 %? if (2 > 1) %)
printf("%s%s%s %s\n",
thread_indent (entry_p),
(entry_p>0?"->":"<-"),
/* ppfunc (), 只有函數名,沒有包含類名*/
probefunc (),
extra)
}


%( $# > 1 %?
global trace
probe $2.call {
trace[tid()] = 1
}
probe $2.return {
delete trace[tid()]
}
%)

probe $1.call { trace(1, $$parms) }
probe $1.return { trace(-1, $$return) }

// 第一個參數是跟蹤的打印的函數,第二個參數是觸發記錄的函數。
// https://sourceware.org/systemtap/langref/Probe_points.html#SECTION00051300000000000000
// probe_point = <function name@filename:line_number>
// stap para-callgraph.stp 'kernel.function("*@fs/*.c")' 'kernel.function("sys_read")':
// stap para-callgraph.stp 'process("/usr/lib/libtest.so").function("*")' 'process("/usr/lib/libtest.so").function("TestInit")'
// stap para-callgraph.stp 'process("/usr/lib/libtest.so").function("*@*cpp")' 'process("/usr/lib/libtest.so").function("TestInit")'
// stap para-callgraph.stp 'process("/usr/lib/libtest.so").function("*@*cpp:*")' 'process("/usr/lib/libtest.so").function("TestInit")'
// stap para-callgraph.stp 'process("/usr/lib/libtest.so").function("*@*cpp:1-200")' 'process("/usr/lib/libtest.so").function("TestInit")'

```


4. 寫個簡單的perl腳本來調用c++filt 來做函數名轉換
----------------------------------------------

```
#!/usr/bin/perl -w
use strict;


open(INFILE, "trace_file.txt");
open(OUTFILE, ">trace_file_2.txt");

my $line;
while ($line = <INFILE>){
if ($line =~ /boost|Trace/) {
next;
}
if ($line =~ /(.*)(_Z\S+)(.*)/) {
my $function_name = `c++filt $2`;

chomp($function_name);
print OUTFILE $1, $function_name, $3, "\n";
} else {
print OUTFILE $line;
}
}

close INFILE;
close OUTFILE;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM