如何在Linux用戶和內核空間中進行動態跟蹤?
你不記得如何在代碼中插入探針點了嗎? 沒問題!了解如何使用uprobe和kprobe來動態插入它們吧。 基本上,程序員需要在源代碼彙編指令的不同位置插入動態探針點。
探針點
探針點是一個調試語句,有助於探索軟體的執行特性(即,執行流程以及當探針語句執行時軟體數據結構的狀態)。printk是探針語句的最簡單形式,也是黑客用於內核攻擊的基礎工具之一。
因為它需要重新編譯源代碼,所以printk插入是靜態的探測方法。內核代碼中重要位置上還有許多其他靜態跟蹤點可以動態啟用或禁用。 Linux內核有一些框架可以幫助程序員探測內核或用戶空間應用程序,而無需重新編譯源代碼。Kprobe是在內核代碼中插入探針點的動態方法之一,並且uprobe在用戶應用程序中執行此操作。
使用uprobe跟蹤用戶空間
可以通過使用thesysfs介面或perf工具將uprobe跟蹤點插入用戶空間代碼。
使用sysfs介面插入uprobe
考慮以下簡單測試代碼,沒有列印語句,我們想在某個指令中插入探針:
[source,c]
.test.c
#include 編譯代碼並找到要探測的指令地址: # gcc -o test test.c 假設我們在ARM64平台上有以下目標代碼: 0000000000400620 並且我們想在偏移量0x620和0x644之間插入探針。執行以下命令: # echo "p:func_2_entry test:0x620" > /sys/kernel/debug/tracing/uprobe_events 在上面的第一個和第二個echo語句中,p告訴我們這是一個簡單的測試。(探測器可以是簡單的或返回的。)func_n_entry是我們在跟蹤輸出中看到的名稱,名稱是可選欄位,如果沒有提供,我們應該期待像p_test_0x644這樣的名字。test 是我們要插入探針的可執行二進位文件。如果test 不在當前目錄中,則需要指定path_to_test / test。 0x620或0x640是從程序啟動開始的指令偏移量。請注意>>在第二個echo語句中,因為我們要再添加一個探針。所以,當我們在前兩個命令中插入探針點之後,我們啟用uprobe跟蹤,當我們寫入events/ uprobes / enable時,它將啟用所有的uprobe事件。程序員還可以通過寫入在該事件目錄中創建的特定事件文件來啟用單個事件。一旦探針點被插入和啟用,每當執行探測指令時,我們可以看到一個跟蹤條目。 讀取跟蹤文件以查看輸出: # cat /sys/kernel/debug/tracing/trace 我們可以看到哪個CPU完成了什麼任務,什麼時候執行了探測指令。 返回探針也可以插入指令。當返回該指令的函數時,將記錄一個條目:
#include
#include
# objdump -d test
# echo "p:func_1_entry test:0x644" >> /sys/kernel/debug/tracing/uprobe_events
# echo 1 > /sys/kernel/debug/tracing/events/uprobes/enable# ./test&
# tracer: nop
#
# entries-in-buffer/entries-written: 8/8
#P:8
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU
# |||| TIMESTAMP FUNCTION# | | | |||| | |
# echo 0 > /sys/kernel/debug/tracing/events/uprobes/enable
# echo "r:func_2_exit test:0x620" >> /sys/kernel/debug/tracing/uprobe_events
# echo "r:func_1_exit test:0x644" >> /sys/kernel/debug/tracing/uprobe_events
# echo 1 > /sys/kernel/debug/tracing/events/uprobes/enable
這裡我們使用r而不是p,所有其他參數是相同的。請注意,如果要插入新的探測點,需要禁用uprobe事件:
test-3009 [002] .... 4813.852674: func_1_entry: (0x400644)
上面的日誌表明,func_1返回到地址0x4006b0,時間戳為4813.852691。
# echo 0 > /sys/kernel/debug/tracing/events/uprobes/enable
# echo "p:func_2_entry test:0x630" > /sys/kernel/debug/tracing/uprobe_events count=%x1
# echo 1 > /sys/kernel/debug/tracing/events/uprobes/enable
# echo > /sys/kernel/debug/tracing/trace# ./test&
當執行偏移量0x630的指令時,將列印ARM64 x1寄存器的值作為count =。
輸出如下所示:
test-3095 [003] .... 7918.629728: func_2_entry: (0x400630) count=0x1
使用perf插入uprobe
找到需要插入探針的指令或功能的偏移量很麻煩,而且需要知道分配給局部變數的CPU寄存器的名稱更為複雜。 perf是一個有用的工具,用於幫助引導探針插入源代碼中。
除了perf,還有一些其他工具,如SystemTap,DTrace和LTTng,可用於內核和用戶空間跟蹤;然而,perf與內核配合完美,所以它受到內核程序員的青睞。
# gcc -g -o test test.c# perf probe -x ./test func_2_entry=func_2
# perf probe -x ./test func_2_exit=func_2%return
# perf probe -x ./test test_15=test.c:15
# perf probe -x ./test test_25=test.c:25 number
# perf record -e probe_test:func_2_entry -e
probe_test:func_2_exit -e probe_test:test_15
-e probe_test:test_25 ./test
如上所示,程序員可以將探針點直接插入函數start和return,源文件的特定行號等。可以獲取列印的局部變數,並擁有許多其他選項,例如調用函數的所有實例。 perf探針用於創建探針點事件,那麼在執行./testexecutable時,可以使用perf記錄來探測這些事件。當創建一個perf探測點時,可以使用其他錄音選項,例如perf stat,可以擁有許多後期分析選項,如perf腳本或perf報告。
使用perf腳本,上面的例子輸出如下:
# perf script
使用kprobe跟蹤內核空間
與uprobe一樣,可以使用sysfs介面或perf工具將kprobe跟蹤點插入到內核代碼中。
使用sysfs介面插入kprobe
程序員可以在/proc/kallsyms中的大多數符號中插入kprobe;其他符號已被列入內核的黑名單。還有一些與kprobe插入不兼容的符號,比如kprobe_events文件中的kprobe插入將導致寫入錯誤。 也可以在符號基礎的某個偏移處插入探針,像uprobe一樣,可以使用kretprobe跟蹤函數的返回,局部變數的值也可以列印在跟蹤輸出中。
以下是如何做:
; disable all events, just to insure that we see only kprobe output in trace.
# echo 0 > /sys/kernel/debug/tracing/events/enable; disable kprobe events until probe points are inseted.
# echo 0 > /sys/kernel/debug/tracing/events/kprobes/enable; clear out all the events from kprobe_events,
to insure that we see output for; only those for which we have enabled
[root@pratyush ~]
# more /sys/kernel/debug/tracing/trace# tracer: nop
#
# entries-in-buffer/entries-written: 9037/9037
#P:8#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq#
|| / _--=> preempt-depth#
||| / delay# TASK-PID CPU#
|||| TIMESTAMP FUNCTION#
| | | |||| | |
使用perf插入kprobe
與uprobe一樣,程序員可以使用perf在內核代碼中插入一個kprobe,可以直接將探針點插入到函數start和return中,源文件的特定行號等。程序員可以向-k選項提供vmlinux,也可以為-s選項提供內核源代碼路徑:
# perf probe -k vmlinux kfree_entry=kfree
# perf probe -k vmlinux kfree_exit=kfree%return
# perf probe -s ./ kfree_mid=mm/slub.c:3408 x
# perf record -e probe:kfree_entry -e probe:kfree_exit -e probe:kfree_mid sleep 10
使用perf腳本,以上示例的輸出:
# perf script
你還有什麼更好的方法嗎?歡迎在評論區留言!
※聽說微軟又有3000人下崗了,老套路劇情是否有反轉?
※連接+應用+構建 PTC Navigate重新定義PLM市場格局
※搭載 Windows 10 系統 新一代商務智能投影新品首發
※不容錯過!Linux發行版最全大集錦(二)
TAG:IT168企業級 |
※如何使用命令行檢查 Linux 上的磁碟空間
※眾創空間獨角獸WeWork的業務是如何運轉的?
※VR應用《Tilt Brush》讓你在三維空間進行創作
※Oculus Quest雖支持大空間追蹤,但不適用於戶外
※Wonderwall迷失在現實生活里的奇妙空間
※藉助新工具,在AltspaceVR中構建您自己的空間
※Signature Group 流動的空間藝術
※用iPhone拍攝的建築與室內空間,Andy Hendrata攝影作品
※在Linux系統上擴展swap空間
※在Linux上增加swap空間的技巧
※IBM Watson不久將飛上國際空間站,太空 AI 助理的能力如何?
※iPhone 總提示「iCloud儲存空間將滿」,如何解決?
※Inblum 閱讀空間的情感
※靈活的運動商店,極富創意的空間——耐克實驗室Chi&NYC
※可在Altspace VR中構建自己的空間丨蛙游網
※Figaro life | 女主人與她們的夢想空間
※Ayd?n Büyükta?:重現盜夢空間中的扭曲世界
※設計|清新現代空間,驚艷時光的Tiffany藍
※Larry Liu:Genaro Network是首條結合存儲的公鏈,基於共享有無限存儲空間
※Paradox老大:付費DLC很棒 但仍有進步空間