久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

如何理解Linux故障定位技術

194次閱讀
沒有評論

共計 14091 個字符,預計需要花費 36 分鐘才能閱讀完成。

本篇文章為大家展示了如何理解 Linux 故障定位技術,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。

主要是來了解并學習 linux 中故障定位技術的學習,故障定位技術分為在線故障定位和離線故障定位。

1、故障定位 (Debugging) 場景分類

為便于描述問題,將 Linux 上各種軟件故障定位的情形分成兩類

(1)在線故障故障定位

在線故障定位 (online-debugging) 就是在故障發生時, 故障所處的操作系統環境仍然可以訪問,故障處理人員可通過 console, ssh 等方式登錄到操作系統上,在 shell 上執行各種操作命令或測試程序的方式對故障環境進行觀察,分析,測試,以定位出故障發生的原因

(2)離線故障定位

離線故障定位 (offline-debugging) 就是在故障發生時,故障所處的操作系統環境已經無法正常訪問,但故障發生時系統的全部或部分狀態已經被系統本身所固有或事先設定的方式收集起來,故障處理人員可通過對收集到的故障定位狀態信息進行分析,定位出故障發生的原因

2、應用進程故障情形及處理

應用進程的故障一般不會影響操作系統運行環境的正常使用(如果應用代碼的 bug 導致了內核的 crash 或 hang, 則屬于內核存在漏洞),所以可采用在線故障定位的方法,靈活的進行分析. 應用代碼故障的情形有如下幾種:

(1)進程異常終止

很多用戶認為進程異常終止情況無從分析,但實際上進程異常終止情況都是有跡可尋的. 所有的進程異常終止行為,都是通過內核發信號給特定進程或進程組實現的. 可分成幾個類型進行描述:

– SIGKILL. SIGKILL 最特殊,因為該信號不可被捕獲,同時 SIGKILL 不會導致被終止的進程產生 core 文件, 但如果真正的是由內核中發出的 SIGKILL, 則內核一定會在 dmesg 中記錄下信息. 另外在內核中使用 SIGKILL 的地方 ***,如 oom_kill_process()中, 所以通過 dmesg 記錄并且分析內核中使用 SIGKILL 的代碼,并不難分析原因

– SIGQUIT, SIGILL, SIGABRT, SIGBUS, SIGFPE, SIGSEGV. 這幾個信號在保留情況下會終止進程并會產生 core 文件, 用戶根據 core 中的 stack trace 信息,能直接定位出導致終止信號的代碼位置. 另外, SIGQUIT,SIGABRT 一般是由用戶代碼自己使用的,好的代碼一般會記錄日志. SIGILL, SIGBUS, SIGFPE, SIGSEGV, 都是由內核中產生的,搜索內核源碼,不難列出內核中使用這幾個信號的地方, 如 SIGILL 是非法指令,可能是浮點運算產生的代碼被 corrupted 或文本區域的物理內存 corruption; SIGBUS 多由 MCE 故障定位導致; SIGSEGV 多由應用代碼的指針變量被 corrupted 導致. 對于應用的 heap 或 stack 的內存被 corrupted, 可用 valgrind 工具對應用進行 profile, 通常能直接發現導致 corruption 的代碼

– SIGINT, SIGPIPE, SIGALRM, SIGTERM. 這幾個信號在保留情況下終止進程但不會產生 core 文件. 對這幾個信號,建議用戶一定要定義一個 handler, 以記錄產生問題的上下文. 比較容易忽略的是 SIGPIPE, 很多用戶程序在使用 select()或 poll()時只監聽 read/write 描述符,不監聽 exception 描述符,在對方 TCP 已經關閉的情況下,仍然向 socket 中寫入,導致 SIGPIPE.

– 對于惡意的代嗎產生的進程終止行為,如合作的一些進程中,A 向 B 發 SIGKILL, 而沒做日志記錄,或者 B 直接判斷某條件而調用 exit(), 也沒有做日志記錄. 在應用代碼量很大的情況下,通過分析代碼故障定位這種情形也許很難. SystemTap 提供了解決這個問題的一個比較好的方法,就是寫用戶層的 probes, 追蹤進程對 signal(), exit() 等系統調用的使用

(2)進程阻塞,應用無法正常推進

這種情況,對于單個被阻塞的進程而言,屬于正常狀態,但對于包含多個進程的應用整體而言,屬于異常. 應用無法推進,說明其中某一個進程推進的因素出現了問題,導致其他依賴于它的進程也要等待. 分析這種情形需要分析清楚進程或事件之間的依賴關系,及數據的處理流. 首先要用 gdb -p 的 back trace 功能查出各進程阻塞的執行路徑, 以確定每個進程所處在的狀態機的位置.

通常而言,如果只考慮各個進程的狀態,則進程之間可能形成了一種互相依賴的環形關系,如(P1 發請求 = P2 處理 = P2 發反應 = P1 再請求 = P2 處理 = P2 再發反應), 但應用對 workload, 一般是按一個個的 transaction 或 session 的方式進行處理的, 每個 transaction 都有起點和終點, 我們需要用 strace, tcpdump 等工具以及應用的執行日志進行觀察,分析出當前正被處理的 transaction 所被阻滯的位置,從而找出全部狀態機被阻塞的原因. 導致這種狀態機停止運轉的原因有多個:如和應用通信的遠端出現了問題,后端數據庫 / 目錄等出現了問題,應用的某個進程或線程處于非正常的 blocking 位置或直接終止,不再正常工作.

(3)用戶進程形成死鎖

用戶進程形成死鎖,如果沒有內存上的故障定位,則完全是應用自身的邏輯問題. 死鎖的進程或線程之間由于鎖的互相占有形成了環路。這種情況發生時,用 gdb -p 的 back trace 的功能能直接確定死鎖的進程全部阻塞在 futex()等和鎖相關的系統調用上, 這些調用 futex()的路徑可能是 mutex, semaphore, conditional variable 等鎖函數. 通過分析 call trace 的代碼,能直接確定各進程在執行到該位置時,可能已經持有的全部鎖, 根據這個修改程序的代碼,消除死鎖環路,就可解決問題.

注意,內存故障也可導致假的死鎖的,如物理內存故障可直接導致鎖變量的值為 -1,所以使用該鎖的進程都會阻塞. 如果是代碼的 bug 導致的內存 corruption, 可用 valgrind 工具檢查程序來發現. 但如果是物理內存的故障定位導致的 corruption, 則需要硬件的支持,對于高端的 PC, 如 MCE 功能的機器,當物理內存故障定位時能直接產生異常或報告, 但對于低端 PC 服務器,除了運行 memtest 工具進行檢測外,沒有其他方法

(4)進程長期處于 D (UnInterruptible)狀態沒法退出

這種多是由內核中的故障引起的. 內核在很多執行路徑中會將進程至于 D 的狀態,以確保關鍵的執行路徑不被外部的信號中斷, 導致不必要的內核中數據結構狀態的不一致性. 但一般而言,進程處于 D 狀態的時間不會太久, 因為狀態結束的條件(如 timer 觸發,

IO 操作完成等)很快會將進程喚醒. 當進程長期處于 D , 關鍵是要找出其阻塞的代碼位置,用 sysrq 的 t 鍵功能可直接打印出系統中全部睡眠進程的內核執行堆棧,如 echo t /proc/sysrq-trigger, 其中包括出現 D 狀態的進程的內核態堆棧. 找出代碼位置后,一般可直接分析出 D 狀態不能退出的原因, 如 IO read 操作因硬件或 nfs 故障而不能完成.

有可能導致 D 狀態的原因比較復雜,如 lsquo;D rsquo; 的退出依賴于某變量的值,而該變量的值因某種原因被 ***corrupted 掉了.

3、內核故障情形及處理

(1)內核 panic

panic 是內核最直接的故障定位報告,發生 panic 時,內核已經認為故障定位已經導致操作系統不再具備正常運行的條件了. 當發生 panic 時,Linux 會將所有 CPU 的中斷和進程調度功能都關掉,所以這時系統是沒有任何反應的,如果用戶啟動的是圖形界面,則在屏幕上也看不到任何關于 panic 的信息.

我們通常遇到的,機器沒反應,ping 不通的情況,絕大部分都是 panic. Panic 發生時,內核直接在 console 上打印導致 panic 的代碼位置的調用堆棧, 傳統的用戶用串口連接到機器上來收集 console 上的打印信息, 但串口這種方式,顯然用起來不方便, 現在的 Linux, 如 RHEL5,RHEL6,都采用 kdump 的方法來收集 panic 時的信息. 在配置好 kdump 的情況下,panic 時系統會用 kexec 加載并切換到一個新的內核上(放置在預先分配的內存位置),并用磁盤或網絡等將系統的全部或部分內存數據保存起來.

用 kdump 收集到 panic 的數據后,用戶用 crash 工具就能直接查看導致 panic 的代碼路徑.

panic 一般是很直觀的,panic 的堆棧信息能直接反映出導致 bug 的原因,如 MCE 故障,NMI 故障, 數據結構分配失敗等. 但有時 panic 是因為內核主動發現了關鍵的數據結構不一致性,這種不一致性是什么時候,什么代碼導致的,并不清楚,可能還需要多次測試用 SystemTap 這樣的工具進行捕捉

(2)多處理機環境內核執行路徑產生的死鎖

內核死鎖和 panic 不一樣,產生死鎖時,內核并不主動的使自己處于掛起狀態. 但內核死鎖發生時,兩個以上的 CPU 的執行路徑在內核態不能推進了,處于互相阻塞狀態, 而且是 100% 的占用 CPU(用的 spin-lock),直接或間接的導致全部 CPU 上的進程無法調度. 內核死鎖又分兩種情況:

– 涉及到中斷上下文的死鎖. 這種情況的死鎖,最少一個 CPU 上的中斷被屏蔽了. 系統可能沒法響應 ping 請求. 由于有一個 CPU 已經沒法響應中斷,其上的 local APIC 定時中斷沒法工作,可以用 NMI Watchdog 的方法來檢測出來(檢查 local APIC handler 維護的計數器變量),NMI Watchdog 可以在其處理程序中調用 panic(), 用戶就可以用 kdump 收集內存信息,從而分析各死鎖 CPU 上的調用堆棧,查處導致死鎖的邏輯原因.

– 不涉及中斷上下文的死鎖. 這種情況的死鎖,各 CPU 上的中斷都是正常的,系統能對 ping 請求作出反應,這時 NMI Watchdog 無法被觸發. 在 2.6.16 之前的內核中, 并沒有一種很好的方法來處理這種情形. 在 RHEL5, RHEL6 內核中,每個 CPU 上提供了一個 watchdog 內核線程,在死鎖出現的情況下,死鎖 CPU 上的 watchdog 內核線程沒法被調度(即使它是 *** 優先級的實時進程), 它就沒法 update 相應的 counter 變量,各 CPU 的 NMI Watchdog 中斷會周期性的檢查其 CPU 對應的 counter, 發現沒有 updated, 會調用 panic(),用戶就可用 kdump 收集內存信息,分析各死鎖 CPU 上的調用堆棧,查處導致死鎖的邏輯原因.

(3)內核的 oops 或 warning

oops 和 warning 和 panic 類似的地方是,他們都是因內核發現了不一致而主動報告的異常. 但 oops 和 warning 導致的問題嚴重程度要比 panic 輕很多,以致于內核處理該問題時不需要使系統掛起. 產生 oops 和 warning, 內核通常已經在 dmesg 中記錄了相當的信息,特別是 oops, 至少會打印出現故障的地方的 call trace. Oops 也可轉換成 panic/kdump 來進行 offline-debugging, 只要將 /proc/sys/kernel 下的 panic_on_oops 變量設置為 1 就行了.

產生 oops 和 warning 的直接原因有很多,如內核中的 segment fault, 或內核發現的某數據結構的 counter 值不對, 而 segment fault 和 counter 值的變化還有更深層次的原因,通常并不能從內核 dmesg 的信息中看出來,解決這種問題的是要用 SystemTap 進行 probe, 如發現某 counter 的值不對,就用 SystemTap 做一個 probe 來記錄所有代碼對該 counter 的訪問, 然后再進行分析.

定位 oops 和 warning 會比定位應用程序的內存訪問故障定位困難很多,因為在內核并不能象用 valgrind 去 trace 應用程序一樣跟蹤數據結構的分配和使用情況.

2、其他 (硬件相關) 故障

機器自動重啟是一種常見的故障情形,一般是由硬件如物理內存故障引起的,軟件的故障只會導致死鎖或 panic, 內核中幾乎沒有代碼在發現問題的情況下去 reboot 機器. 在 /proc/sys/kernel 目錄下有個參數“panic”, 其值如果設置為非 0,則在 panic 發生若干秒后,內核會重啟機器. 現在高端的 PC 服務器,都在努力用軟件來處理物理內存故障,如 MCA 的“HWPoison”方法會將故障的物理頁隔離起來,Kill 掉故障頁所在的進程就可以了,RHEL6 現在已經支持“HWPoison”. 那些不具備 MCA 能力的機器,物理內存故障時,不會產生 MCE 異常,直接由硬件機制 reboot 機器

4、RHEL6 上的 Debugging 技術介紹

(1)Kdump 故障定位收集和 crash 分析

kdump 就是用來在內核 panic 的情況下收集系統內存信息的, 用戶也可在 online 情況下用 sysrq 的 c 鍵觸發. Kdump 采用沒有污染的內核來執行 dump 工作,所以其比以前的 diskdump, lkcd 方法更可靠. 使用 kdump,用戶可選擇將數據 dump 到本地盤或網絡上,也可通過定義 makedumpfile 的參數過濾要收集的內存信息,已減少 kdump 所需要的停機時間

Crash 就是對 kdump 的信息進行分析的工具. 其實際就是 gdb 的一個 wrapper. 使用 crash 時,*** 安裝 kernel-debuginfo 包,這樣能解析 kdump 收集的內核數據的符號信息. 用 crash 來定位問題的能力,完全取決于用戶對內核代碼的理解和分析能力

參考“# man kdump.conf”,“# man crash”,“# man makedumpfile”學習怎樣使用 kdump 和 crash. 訪問 http://ftp.redhat.com 可下載 debuginfo 文件

(2)用 systemTap 定位 bug

systemtap 屬于 probe 類的定位工具, 它能對內核或用戶代碼的指定位置進行 probe, 當執行到指定位置或訪問指定位置的數據時,用戶定義的 probe 函數自動執行,可打印出該位置的調用堆棧,參數值,變量值等信息. systemtap 選擇進行 probe 的位置很靈活,這是 systemtap 的強大功能所在. Systemtap 的 probe 點可包括如下幾個方面:

– 內核中全部系統調用,內核及模塊中全部函數的入口或出口點

– 自定義的定時器 probe 點

– 內核中任意指定的代碼或數據訪問位置

– 特定用戶進程中任意制定的代碼或數據訪問位置

– 各個功能子系統預先設置的若干 probe 點,如 tcp,udp,nfs,signal 各子系統都預先設置了很多探測點

systemTap 的腳本用 stap 腳本語言來編寫,腳本代碼中調用 stap 提供的 API 進行統計,打印數據等工作,關于 stap 語言提供的 API 函數,參考“# man stapfuncs”. 關于 systemTap 的功能和使用可參考“# man stap”,“# man stapprobes”

(3)ftrace

ftrace 是 linux 內核中利用 tracepoints 基礎設施實現的事件追蹤機制,它的作用在于能比較清楚的給出在一定時間內系統或進程所執行的活動,如函數調用路徑,進程切換流等. Ftrace 可用于觀察系統各部分的 latency, 以便進行實時應用的優化;它也可以通過記錄一段時間內的內核活動來幫助故障定位. 如用以下方法可 trace 某個進程在一端時間的函數調用情況

#  echo “function”   /sys/kernel/debug/tracing/current_tracer #  echo “xxx”   /sys/kernel/debug/tracing/set_ftrace_pid #  echo 1   /sys/kernel/debug/tracing/tracing_enabled

除 tracing 函數調用外,ftrace 還可 tracing 系統的進程切換,喚醒,塊設備訪問,內核數據結構分配等活動. 注意,tracing 和 profile 是不同的,tracing 記錄的是一段時間內的全部活動,而不是統計信息,用戶可以通過 /sys/kernel/debug/tracing 下的 buffer_size_kb 設置緩沖區的大小, 以記錄更長時間的數據.

關于 ftrace 的具體使用可參考內核源碼 Documenation/trace 下的內容

(4)oprofile 和 perf

oprofile 和 perf 都是對系統進行 profile(抽樣,統計)的工具,它們主要用來解決系統和應用的性能問題. perf 功能更強大,更全面, 同時 perf 的用戶空間工具和內核源碼一起維護和發布,讓用戶能及時的享受 perf 內核新增加的特征. Perf 是在 RHEL6 中才有,RHEL5 中沒有 Perf. Oprofile 和 perf 都使用現代 CPU 中具有的硬件計數器進行統計工作,但 perf 還可以使用內核中定義的“software counter”及“trace points”, 所以能做更多的工作. Oprofile 的抽樣工作利用 CPU 的 NMI 中斷來進行,而 perf 既可以利用 NMI 中斷也可利用硬件計數器提供的周期性中斷. 用戶能很容易用 perf 來 oprofile 一個進程或系統的執行時間分布,如

#  perf top -f 1000 -p

還可以利用系統定義的“software counter”和各子系統的“trace points”對子系統進行分析, 如

# perf stat -a -e kmem:mm_page_alloc -e kmem:mm_page_free_direct -e kmem:mm_pagevec_free sleep 6

能統計 6 秒內 kmem 子系統的活動 (這一點實際是利用 ftrace 提供的 tracepoints 來實現)

我認為有了 perf, 用戶就沒必要使用 oprofile 了

5、用 kdump 工具內核故障定位實例

A) 部署 Kdump

部署 kdump 收集故障信息的步驟如下:

(1)設置好相關的內核啟動參數

在 /boot/grub/menu.lst 中加入如下內容

crashkernel=128M@16M nmi_watchdog=1

其中 crashkernel 參數是用來為 kdump 的內核預留內存的; nmi_watchdog=1 是用來激活 NMI 中斷的, 我們在未確定故障是否關閉了中斷的情況下, 需要部署 NMI watchdog 才能確保觸發 panic. 重啟系統確保設置生效

(2)設置好相關的 sysctl 內核參數

在 /etc/sysctl.conf 中 *** 加入一行

kernel.softlookup_panic = 1

該設置確保 softlock 發生時會調用 panic, 從而觸發 kdump 行為執行 # sysctl -p 確保設置生效

(3)配置 /etc/kdump.conf

在 /etc/kdump.conf 中加入如下幾行內容

ext3 /dev/sdb1 core-collector makedumpfile -c  ndash;message-level 7 -d 31 -i /mnt/vmcoreinfo path /var/crash default reboot

其中 /dev/sdb1 是用于放置 dumpfile 的文件系統, dumpfile 文件放置在 /var/crash 下,要事先在 /dev/sdb1 分區下創建 /var/crash 目錄.“-d 31”指定對 dump 內容的過濾級別,這參數對于 dump 分區放不下全部內存內容或用戶不想讓 dumping 中斷業務太長時間時很重要. vmcoreinfo 文件放置在 /dev/sdb1 分區的 / 目錄下, 需要使用如下命令產生:

# makedumpfile -g //vmcoreinfo -x /usr/lib/debug/lib/modules/2.6.18-128.el5.x86_64/vmlinux

“vmlinux”文件是由 kernel-debuginfo 包提供的,在運行 makedumpfile 之前需要安裝相應內核的 kernel-debuginfo 和 kernel-debuginfo-common 兩個包,該兩個包需從 http://ftp.redhat.com 下載.“default reboot”用來告訴 kdump, 收集完 dump 信息后重啟系統

(4)激活 kdump

運行 # service kdump start 命令,你會看到,在成功完成的情況下會在 /boot/ 目錄下生成一個 initrd-2.6.18-128.el5.x86_64kdump.img 文件,該文件就是 kdump 加載的內核的 initrd 文件,收集 dump 信息的工作就是在該 initrd 的啟動環境下進行的. 查看 /etc/init.d/kdump 腳本的代碼,你可看到其中會調用 mkdumprd 命令創建用于 dump 的 initrd 文件

1、測試 Kdump 部署的有效性

為了測試 kdump 部署的有效性,本人寫了如下一個內核模塊,通過 insmod 加載該內核模塊,就能產生一個內核線程,在 10 秒左右后,占據 100% 的 CPU,在 20 秒左右后觸發 kdump. 系統重啟后,檢查 /oracle 分區 /var/crash 目錄下的內容,就能確認 vmcore 文件是否生成.

Zqfthread.c #include #include #include #include #include #include MODULE_AUTHOR(frzhang@redhat.com  MODULE_DESCRIPTION( A module to test ....  MODULE_LICENSE( GPL  static struct task_struct *zqf_thread; static int zqfd_thread(void *data); static int zqfd_thread(void *data) { int i=0; while (!kthread_should_stop()) { i++; if ( i   10 ) { msleep_interruptible(1000); printk(%d seconds\n , i); } if ( i == 1000 ) // Running in the kernel i = 11 ; } return 0; } static int __init zqfinit(void) { struct task_struct *p; p = kthread_create(zqfd_thread, NULL, %s , zqfd  if ( p ) { zqf_thread = p; wake_up_process(zqf_thread); // actually start it up return(0); } return(-1); } static void __exit zqffini(void) { kthread_stop(zqf_thread); } module_init(zqfinit); module_exit(zqffini) Makefile obj-m += zqfthread.o Making #  make -C /usr/src/kernels/2.6.32-71.el6.x86_64/ M=`pwd` modules

2、用 crash 工具分析 vmcore 文件

用 crash 命令分析 vmcore 的命令行格式如下所示. 用 crash 打開 vmcore 后,主要是用 dmesg 及 bt 命令打印出問題的執行路徑的 call trace, 用 dis 反匯編出代碼,最終確認 call trace 對應的 C 源碼中的位置,再進行邏輯分析.

# crash /usr/lib/debug/lib/modules/2.6.18-128.el5.x86_64/vmlinux /boot/System.map-2.6.18-128.el5.x86_64 ./vmcore

6、使用 kprobe 來觀察內核函數的執行實例

kprobe 是 SystemTap 對內核函數進行 probing 的功能在內核中的實現,由于內核中提供了正式的 API 來使用 kprobe, 所以對很多內核程序員來說,也許直接使用 kprobe 比使用 SystemTap 更方便.  內核中提供了三種類型的 kprobe 處理函數,分別是 jprobe, kprobe, kretprobe,  下面的代碼用這三個 probe 觀察在 TCP/IP 的 arp_process 函數執行中對 ip_route_input()調用的返回結果. 這個代碼還展示了在同一個函數 probe 的 Entry handler 和 Ret handler 之間共享參數的方法.  代碼如下:

arp_probe.c /* * arp_probe.c, by Qianfeng Zhang (frzhang@redhat.com) */ #include #include #include #include #include #include #include #include MODULE_AUTHOR(frzhang@redhat.com  MODULE_DESCRIPTION( A module to track the call results of ip_route_input() inside arp_process using jprobe and kretprobe  MODULE_LICENSE(GPL  static int j_arp_process(struct sk_buff *skb) { struct net_device *dev = skb-  struct in_device *in_dev; int no_addr, rpf; in_dev = in_dev_get(dev); no_addr = ( in_dev- ifa_list == NULL ); rpf = IN_DEV_RPFILTER(in_dev); in_dev_put(in_dev); printk(\narp_process() is called with interface device %s, in_dev(no_addr=%d,rpf=%d) \n , dev- name, no_addr, rpf); jprobe_return(); return(0); }; static int j_fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, struct net_device *dev, __be32 *spec_dst, u32 *itag, u32 mark) { printk( fib_validate_source() is called with dst=0x%x, oif=%d \n , dst, oif); jprobe_return(); return(0); }; static struct jprobe my_jp1 = { .entry = j_arp_process, .kp.symbol_name =  arp_process  }; static struct jprobe my_jp2 = { .entry = j_fib_validate_source, .kp.symbol_name =  fib_validate_source  }; static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs) { printk( Calling: %s()\n , ri- rp- kp.symbol_name); return(0); }; static int return_handler(struct kretprobe_instance *ri, struct pt_regs *regs) { int eax; eax = regs- ax   0xffff ; printk( Returning: %s() with a return value: 0x%lx(64bit) 0x%x(32bit)\n , ri- rp- kp.symbol_name, regs- ax, eax); return(0); }; static int fib_lookup_entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs) { struct fib_result *resp; resp = (struct fib_result *) regs-  printk(Calling: %s()\n , ri- rp- kp.symbol_name); *((struct fib_result **)ri- data) = resp; return(0); }; static int fib_lookup_return_handler(struct kretprobe_instance *ri, struct pt_regs *regs) { struct fib_result *resp; int eax; eax = regs- ax   0xffff ; resp = *((struct fib_result **) ri- data); printk(Returning: fib_lookup() with a return value: 0x%lx(64bit) 0x%x(32bit), result- type: %d\n , regs- ax, eax, resp- type); return(0); } static struct kretprobe my_rp1 = { .handler = return_handler, .entry_handler = entry_handler, .kp.symbol_name =  ip_route_input_slow  }; static struct kretprobe my_rp2 = { .handler = return_handler, .entry_handler = entry_handler, .kp.symbol_name =  fib_validate_source  }; static struct kretprobe my_rp3 = { .handler = fib_lookup_return_handler, .entry_handler = fib_lookup_entry_handler, .kp.symbol_name =  fib_lookup , .data_size = sizeof(struct fib_result *) }; static int __init init_myprobe(void) { int ret; printk( RTN_UNICAST is %d\n , RTN_UNICAST); if ( (ret = register_jprobe( my_jp1))   0) { printk( register_jprobe %s failed, returned %d\n , my_jp1.kp.symbol_name, ret); return(-1); } if ( (ret = register_jprobe( my_jp2))   0) { printk( register_jprobe %s failed, returned %d\n , my_jp2.kp.symbol_name, ret); return(-1); } if ( (ret = register_kretprobe( my_rp1))   0 ) { printk( register_kretprobe %s failed, returned %d\n , my_rp1.kp.symbol_name, ret); unregister_jprobe(my_jp1); unregister_jprobe(my_jp2); return(-1); } if ( (ret = register_kretprobe( my_rp2))   0 ) { printk( register_kretprobe %s failed, returned %d\n , my_rp2.kp.symbol_name, ret); unregister_jprobe(my_jp1); unregister_jprobe(my_jp2); unregister_kretprobe(my_rp1); return(-1); } if ( (ret = register_kretprobe( my_rp3))   0 ) { printk( register_kretprobe %s failed, returned %d\n , my_rp3.kp.symbol_name, ret); unregister_jprobe(my_jp1); unregister_jprobe(my_jp2); unregister_kretprobe(my_rp1); unregister_kretprobe(my_rp2); return(-1); } return 0; } static void __exit rel_myprobe(void) { unregister_jprobe( my_jp1); unregister_jprobe(my_jp2); unregister_kretprobe(my_rp1); unregister_kretprobe(my_rp2); unregister_kretprobe(my_rp3); } module_init(init_myprobe); module_exit(rel_myprobe); Makefile obj-m += arp_probe.o Making #  make -C /usr/src/kernels/2.6.32-71.el6.x86_64/ M=`pwd` modules

上述內容就是如何理解 Linux 故障定位技術,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注丸趣 TV 行業資訊頻道。

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2023-08-25發表,共計14091字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 宾川县| 明星| 长葛市| 澜沧| 彩票| 山阴县| 锦州市| 巩留县| 昭通市| 雅安市| 济南市| 灵武市| 萍乡市| 拜城县| 依兰县| 渑池县| 云阳县| 称多县| 彩票| 垣曲县| 沁阳市| 融水| 长阳| 玉田县| 隆化县| 平阳县| 调兵山市| 拉萨市| 大竹县| 会泽县| 常宁市| 新邵县| 偏关县| 舒兰市| 昂仁县| 阳信县| 大连市| 镇雄县| 邯郸市| 丰顺县| 赞皇县|