欧美高清va在线视频

<i id="txlz7"><delect id="txlz7"></delect></i>
<video id="txlz7"><i id="txlz7"></i></video><dl id="txlz7"><i id="txlz7"></i></dl><video id="txlz7"></video><video id="txlz7"></video>
<video id="txlz7"><dl id="txlz7"></dl></video>
<i id="txlz7"><meter id="txlz7"></meter></i>
<video id="txlz7"></video>
<dl id="txlz7"></dl>
<video id="txlz7"><i id="txlz7"><font id="txlz7"></font></i></video><video id="txlz7"></video>
<dl id="txlz7"><dl id="txlz7"><delect id="txlz7"></delect></dl></dl>
<video id="txlz7"><i id="txlz7"><delect id="txlz7"></delect></i></video>
<video id="txlz7"></video>
<dl id="txlz7"></dl><dl id="txlz7"></dl>
<dl id="txlz7"></dl><dl id="txlz7"></dl>
成都志合科技有限公司
服務熱線:18086825958
Banner

聯系我們

成都志合科技有限公司
聯系人:劉經理
聯系電話:18086825958
聯系電話:13378116508
辦公室電話:028-87696337
聯系地址:成都市西三環羊犀立交旁蜀輝路465號3棟1-10-3號

新聞資訊
首頁 > 新聞資訊 > 內容
成都監控SystemTap是一個Linux非常有用的調試
編輯:成都志合科技有限公司   時間:2018-08-11

成都監控SystemTap是一個Linux非常有用的調試


SystemTap是一個Linux非常有用的調試(跟蹤/探測)工具,常用于Linu
定位(內核)函數位置

在網上找了個原理圖:

聽阿里云CDN安防技術專家金九講SystemTap使用技巧

SystemTap的處理流程有5個步驟:解析script文件(parse)、細化(elaborate)、script文件翻譯成C語言代碼(translate)、編譯C語言代碼(生成內核模塊)(build)、加載內核模塊(run)

聽阿里云CDN安防技術專家金九講SystemTap使用技巧

SystemTap依賴的package:

elfutils、gcc、kernel-devel、kernel-debuginfo

如果調用用戶態進程,還需要該程序有調試符號,否則無法調試。

推薦使用最新穩定版的SystemTap,目前最新穩定版為:systemtap-2.9.tar.gz

5.1 stap命令

stap[OPTIONS]FILENAME[ARGUMENTS]

Hello World:

root@j9 ~/stp# cat hello-world.stpprobe begin{ print("===Hello World===\n")

5.2 staprun命令

staprun[OPTIONS]MODULE[MODULE-OPTIONS]

stap命令與staprun命令的區別在于:

stap命令的操作對象是stp文件或script命令等,而staprun命令的操作對象是編譯生成的內核模塊。

6.1 probe

“probe” <=> “探測”, 是SystemTap進行具體地收集數據的關鍵字。

聽阿里云CDN安防技術專家金九講SystemTap使用技巧

“probe point” 是probe動作的時機,也稱探測點。也就是probe程序監視的某事件點,一旦偵測的事件觸發了,則probe將從此處插入內核或者用戶進程中。

“probe handle” 是當probe插入內核或者用戶進程后所做的具體動作。

probe用法:

probe probe-point{ statement }

在Hello World例子中begin和end就是probe-point, statement就是該探測點的處理邏輯,在Hello World例子中statement只有一行print,statement可以是復雜的代碼塊。

探測點語法:

kernel.function(PATTERN)

PATTERN語法為:

func[@file]

例如:

kernel.function("*init*")module("ext3").function("*")kernel.statement("*@kernel/time.c:296")process("/home/admin/tengine/bin/nginx").function("ngx_http_process_request")

在return探測點可以用\$return獲取該函數的返回值。

inline函數無法安裝.return探測點,也無法用$return獲取其返回值。

6.2 基本語法

SystemTap腳本語法比較簡單,與C語言類似,只是每一行結尾";"是可選的。主要語句如下:

if/else、while、for/foreach、break/continue、return、next、delete、try/catch

其中:

next:主要在probe探測點邏輯處理中使用,調用此語句時,立刻從調用函數中退出。不同于exit()的是,next只是退出當前的調用函數,而此SystemTap并沒有終了,但exit()則會終止SystemTap。

6.2.1 變量

不需要明確聲明變量類型,腳本語言會根據函數參數等自動判斷變量是什么類型的。

局部變量:在聲明的probe和block(”{ }“范圍內的部分)內有效。

全局變量:用”global“聲明的變量,在此SystemTap的整個動作過程中都有效。全局變量的聲明位置沒有具體要求。需要注意的是,全局變量默認有鎖保護,使用過多會有性能損失,如果用全局變量保存指針,可能出現指針所指的內容被進程修改,在探測點中拿不到真正的數據。

獲取進程中的變量(全局變量、局部變量、參數)直接在變量名前面加$即可(后面會有例子)

6.2.2 注釋

# ...... : Shell語言風格

6.2.3 操作符

比較運算符、算數運算符基本上與C語言一樣,需要特別指出的是:

(1)、.操作符:連接兩個字符串,類似于php;

(2)、=~和!~:正則匹配和正則不匹配;

6.2.4 函數

函數定義例子:

function indent:string (delta:long){

官方有很多很有用的函數,詳情請參考:https://sourceware.org/systemtap/tapsets/

以及在本機安裝了SystemTap之后在目錄/usr/local/share/systemtap/tapset/下也可以看具體函數的實現以及一些奇特的用法。

7.1 定位函數位置

在一個大型項目中找出函數在哪里定義有時很有用,特別是一些比較難找出在哪里定義的函數,比如內核或者glibc中的某個函數想要看其實現時,首先得找出其在哪個文件的哪一行定義,用SystemTap一行命令就可以搞定。

比如要看printf在glibc中哪里定義的:

root@j9 ~# stap -l 'process("/lib/x86_64-linux-gnu/libc.so.6").function("printf")'

可以看出printf是在printf.c第29行定義的。

再比如要看內核中recv系統的調用是在哪里定義的:

root@j9 ~# stap -l 'kernel.function("sys_recv")'

可以看出recv是在socket.c第1868行定義的。

甚至可以*號來模糊查找:

root@j9 ~# stap -l 'kernel.function("*recv")'

同理,也可以用來定位用戶進程的函數位置:

比如tengine的文件ngx_shmem.c里面為了兼容各個操作系統而實現了三個版本的ngx_shm_alloc,用#if (NGX_HAVE_MAP_ANON)、#elif (NGX_HAVE_MAP_DEVZERO)、#elif (NGX_HAVE_SYSVSHM)、#endif來做條件編譯,那怎么知道編譯出來的是哪個版本呢,用SystemTap的話就很簡單了,否則要去grep一下這幾宏有沒有定義才知道了。

[root@cache4 tengine]# stap -l 'process("/home/admin/tengine/bin/nginx").function("ngx_shm_alloc")'

7.2 查看可用探測點以及該探測點上可用的變量

在一些探測點上能獲取的變量比較有限,這是因為這些變量可能已經被編譯器優化掉了,優化掉的變量就獲取不到了。一般先用-L參數來看看有哪些變量可以直接使用:

[root@cache4 tengine]# stap -L 'process("/home/admin/tengine/bin/nginx").function("ngx_shm_alloc")'

可見在該探測點上可以直接使用$shm這個變量,其類型是ngx_shm_t*。

statement探測點也類似:

[root@cache4 tengine]# stap -L 'process("/home/admin/tengine/bin/nginx").statement("ngx_pcalloc@src/core/ngx_palloc.c:*")' process("/home/admin/tengine/bin/nginx").statement("ngx_pcalloc@src/core/ngx_palloc.c:395") $pool:ngx_pool_t* $size:size_tprocess("/home/admin/tengine/bin/nginx").statement("ngx_pcalloc@src/core/ngx_palloc.c:398") $pool:ngx_pool_t* $size:size_tprocess("/home/admin/tengine/bin/nginx").statement("ngx_pcalloc@src/core/ngx_palloc.c:399") $size:size_tprocess("/home/admin/tengine/bin/nginx").statement("ngx_pcalloc@src/core/ngx_palloc.c:404") $size:size_t $p:void*

7.3 輸出調用堆棧

用戶態探測點堆棧:print_ubacktrace()、sprint_ubacktrace()

內核態探測點堆棧:print_backtrace()、sprint_backtrace()

不帶s和帶s的區別是前者直接輸出,后者是返回堆棧字符串。

這幾個函數非常有用,在排查問題時可以根據一些特定條件來過濾函數被執行時是怎么調用進來的,比如排查tengine返回5xx時的調用堆棧是怎樣的:

#cat debug_tengine_5xx.stp probe process("/home/admin/tengine/bin/nginx").function("ngx_http_finalize_request").call{ if ($rc >= 500){

比如看看內核是怎么收包的:

root@jusse ~# cat netif_receive_skb.stp

7.4 獲取函數參數

一些被編譯器優化掉的函數參數用-L去看的時候沒有找到,這樣的話在探測點里面也不能直接用$方式獲取該參數變量,這時可以使用SystemTap提供的*_arg函數接口,*是根據類型指定的,比如pointer_arg是獲取指針類型參數,int_arg是獲取整型參數,類似的還有long_arg、longlong_arg、uint_arg、ulong_arg、ulonglong_arg、s32_arg、s64_arg、u32_arg、u64_arg:

聽阿里云CDN安防技術專家金九講SystemTap使用技巧

root@j9 ~# stap -L 'kernel.function("sys_open")' kernel.function("SyS_open@/build/buildd/linux-lts-trusty-3.13.0/fs/open.c:1011") $ret:long int

再比如兩個函數的函數參數類型兼容也可以使用這種方法獲?。?/p>

聽阿里云CDN安防技術專家金九講SystemTap使用技巧

這兩個函數的參數完全兼容,只是第二個參數命名不一樣而已,可以像下面這么用:

#cat debug_tengine_5xx.stp probe process("/home/admin/tengine/bin/nginx").function("ngx_http_finalize_request").call, process("/home/admin/tengine/bin/nginx").function("ngx_http_special_response_handler").call{

7.5 獲取全局變量

有時候用$可以直接獲取到全局變量,但有時候又獲取不到,那可以試試@var:

比如獲取nginx的全局變量ngx_cycyle:

root@j9 ~# cat get_ngx_cycle.stpprobe process("/home/admin/tengine/bin/nginx").function("ngx_process_events_and_timers").call{ printf("ngx_cycle->connections: %d\n", $ngx_cycle->connections) exit()

7.6 獲取數據結構成員用法

typedef struct{ size_t len;

上面這個是nginx里面的http請求結構里面的幾個成員,在C語言里,如果r是struct ngx_http_request_t *,那么要獲取uri的data是這樣的:r->uri.data,但在SystemTap里面,不管是指針還是數據結構,都是用->訪問其成員:

#cat get_http_uri.stp

7.7 輸出整個數據結構

SystemTap有兩個語法可以輸出整個數據結構:在變量的后面加一個或者兩個

$即可,例子如下:

#cat get_r_pool.stpprobe process("/home/admin/tengine/bin/nginx").function("ngx_http_process_request").call{

其中r->pool的結構如下:

typedef struct{

ngx_pool_s包含了結構ngx_pool_data_t。變量后面加和$的區別是后者展開了里面的結構而前者不展開,此用法只輸出基本數據類型的值。

7.8 輸出字符串指針

用戶態使用:user_string、user_string_n

內核態使用:kernel_string、kernel_string_n、user_string_quoted

#cat get_http_uri.stp

user_string_quoted是獲取用戶態傳給內核的字符串,代碼中一般有__user宏標記:

聽阿里云CDN安防技術專家金九講SystemTap使用技巧

#cat sys_open.stpprobe kernel.function("sys_open")

7.9 指針類型轉換

SystemTap提供@cast來實現指針類型轉換,比如可以將void *轉成自己需要的類型:

聽阿里云CDN安防技術專家金九講SystemTap使用技巧

聽阿里云CDN安防技術專家金九講SystemTap使用技巧

#cat get_c_fd.stp probe process("/home/admin/tengine/bin/nginx").function("ngx_http_process_request_line").call{ printf("c->fd: %d\n", @cast($rev->data, "ngx_connection_t")->fd)

7.10 定義某個類型的變量

同樣是用@cast,定義一個變量用來保存其轉換后的地址即可,用法如下:

#cat get_c.stp

7.11 多級指針用法

root@j9 ~# cat cc_multi_pointer.c

簡言之:通過[0]去解引用即可。

7.12 遍歷C語言數組

下面是在nginx處理請求關閉時遍歷請求頭的例子:

#cat debug_http_header.stp

7.13 查看函數指針所指的函數名

獲取一個地址所對應的符號:

用戶態:usymname

內核態:symname

#cat get_c_handler.stp

7.14 修改進程中的變量

root@j9 ~# cat stap_set_var.c -n

可以看出在第17行用SystemTap修改后的值在第19行就生效了。

需要注意的是stap要加-g參數在guru模式下才能修改變量的值。

7.15 跟蹤進程執行流程

thread_indent(n): 補充空格

ppfunc(): 當前探測點所在的函數

在call探測點調用thread_indent(4)補充4個空格,在return探測點調用thread_indent(-4)回退4個空格,效果如下:

#cat trace_nginx.stp

7.16 查看代碼執行路徑

pp(): 輸出當前被激活的探測點

#cat ngx_http_process_request.stpprobe process("/home/admin/tengine/bin/nginx").statement("ngx_http_process_request@src/http/ngx_http_request.c:*"){

可以看出該函數哪些行被執行了。

7.17 巧用正則匹配過濾

在排查問題時,可以利用一些正則匹配來獲取自己想要的信息,比如下面是只收集*.j9.com的堆棧:

#cat debug_tengine_5xx.stp

7.18 關聯數組用法

SystemTap的關聯數組必須是全局變量,需要用global進行聲明,其索引可以支持多達9項索引域,各域間以逗號隔開。支持 =, ++ 與 +=操作,其默認的初始值為0。

例如:

root@j9 ~# cat stap_array.stp

也可以用+、-進行排序:

root@j9 ~# cat stap_array.stp

7.19 調試內存泄漏以及內存重復釋放

probe begin{ printf("=============begin============\n")

詳細請看:http://blog.csdn.net/wangzuxi/article/details/44901285

7.20 嵌入C代碼

在進程fork出子進程時打印出進程id和進程名:

root@jusse ~/systemtap# cat copy_process.stp

有三個需要注意的地方:

1)、SystemTap腳本里面嵌入C語言代碼要在每個大括號前加%前綴,是%{…… %}而不是%{ …… }%;

2)、獲取腳本函數參數要用STAP_ARG_前綴;

3)、一般long等返回值用STAP_RETURN,而string類型返回值要用snprintf、strncat等方式把字符串復制到STAP_RETVALUE里面。

7.21 調試內核模塊

這小節就不細講了,這篇博客 (http://blog.chinaunix.net/uid-14528823-id-4726046.html) 寫得很詳細,這里只copy兩個關鍵點過來記錄一下:

要調試自己的內核模塊,需要注意的有兩個關鍵點:

1)、使用SystemTap調試內核模塊,探測點的編寫格式示例為:

module("ext3").function("ext3_*")

2)、需要將自己的模塊cp到/lib/modules/uname -r/extra目錄中,否則找不到符號,如果/lib/modules/uname -r/目錄下沒有extra這個目錄,自己mkdir一下就可以。

7.22 一些錯誤提示及解決辦法

錯誤提示1:

ERROR: MAXACTION exceeded near keyword at debug_connection.stp:86:9ERROR: MAXACTION exceeded near operator '->' at debug_connection.stp:84:30

解決辦法:

加上stap參數:-DMAXACTION=102400,如果還報這種類型的錯誤,只需把102400調成更大的值即可。

錯誤提示2:

WARNING: Number of errors: 0, skipped probes: 82

解決辦法:

加上-DMAXSKIPPED=102400和-DSTP_NO_OVERLOAD參數

還有一些可以去掉限制的宏:

MAXSTRINGLEN:這個宏會影響sprintf的buffer大小,默認為512字節。

MAXTRYLOCK:對全局變量進行try lock操作的次數,超過則次數還拿不到鎖則放棄和跳過該探測點,默認值為1000.全局變量多的時候可以把這個宏開大一點。

成都志合科技有限公司
聯系人:劉經理
聯系電話:18086825958
聯系電話:13378116508
辦公室電話:028-87696337
聯系地址:成都市西三環羊犀立交旁蜀輝路465號3棟1-10-3號
二維碼
欧美高清va在线视频
<i id="txlz7"><delect id="txlz7"></delect></i>
<video id="txlz7"><i id="txlz7"></i></video><dl id="txlz7"><i id="txlz7"></i></dl><video id="txlz7"></video><video id="txlz7"></video>
<video id="txlz7"><dl id="txlz7"></dl></video>
<i id="txlz7"><meter id="txlz7"></meter></i>
<video id="txlz7"></video>
<dl id="txlz7"></dl>
<video id="txlz7"><i id="txlz7"><font id="txlz7"></font></i></video><video id="txlz7"></video>
<dl id="txlz7"><dl id="txlz7"><delect id="txlz7"></delect></dl></dl>
<video id="txlz7"><i id="txlz7"><delect id="txlz7"></delect></i></video>
<video id="txlz7"></video>
<dl id="txlz7"></dl><dl id="txlz7"></dl>
<dl id="txlz7"></dl><dl id="txlz7"></dl>