1. 程式人生 > >GDB除錯原理——ptrace系統呼叫

GDB除錯原理——ptrace系統呼叫

本文由霸氣的菠蘿原創,轉載請註明出處:http://www.cnblogs.com/xsln/p/ptrace.html

引子:

  1. gdb基本上大家都在用,你有沒有想過它的實現原理是什麼?為什麼它可以控制程式執行、中斷、訪問記憶體甚至直接使程式流程改變?
  2. 在使用gdb除錯程式時,程式的程序狀態是”T”,但又似乎並非接到了SIGSTOP訊號,那麼這個”T”是什麼呢?

追根溯源,我們今天來研究一下Linux下這個強大的系統呼叫:ptrace()

首先,linux的程序狀態大體分為以下幾種:

  1. D (TASK_UNINTERRUPTIBLE),不可中斷的睡眠狀態。
  2. R (TASK_RUNNING),程序執行中。
  3. S (TASK_INTERRUPTIBLE),可中斷的睡眠狀態。
  4. T (TASK_STOPPED),暫停狀態。
  5. t (TASK_TRACED),程序被追蹤。
  6. w (TASK_PAGING),程序調頁中,2.6以上版本的核心中已經被移除。
  7. X (TASK_DEAD – EXIT_DEAD),退出狀態,程序即將被銷燬。
  8. Z (TASK_DEAD – EXIT_ZOMBIE),退出狀態,程序成為殭屍程序。

 (以上內容來自ps命令的manual手冊,原文請看↓)

 

其中上面的5就是我們要討論的,gdb除錯程式時的t狀態,程式被追蹤。(關於程序的其他狀態請自行百度)。

請看ptrace系統呼叫手冊↓

 

ptrace的原型可以看到是:

long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);

4個引數的含義分別為:

  1. enum __ptrace_request request:指示了ptrace要執行的命令。
  2. pid_t pid: 指示ptrace要跟蹤的程序。
  3. void *addr: 指示要監控的記憶體地址。
  4. void *data: 存放讀取出的或者要寫入的資料。

描述譯文如下:

ptrace()系統呼叫提供了一個方法,該方法使一個程式(追蹤者)可以觀察和控制另外一個程式(被追蹤者)的執行,並檢查和改變被追蹤者的記憶體及暫存器。它主要用於實現斷點除錯和追蹤系統呼叫。

被追蹤者首先需要被追蹤者attach(這個詞實在不知道咋翻譯了……但是程式設計師應該都懂@[email protected])。該行為以及後續操作是執行緒獨立的:在一個多執行緒的程序中,每一個執行緒可以被一個獨立的(可能是不同的)追蹤者attach,或者乾脆不理會。因此,被追蹤者永遠是“一個執行緒”,而不是一個(可能是多執行緒的)程序。使用ptrace命令的方法是追蹤程式傳送如下命令給被追蹤程式:

ptrace(PTRACE_foo, pid, …)

pid即linux系統分配的執行緒號。

 

當被追蹤時,被追蹤執行緒在接收訊號時會被停止,即使那個訊號是被忽略的也是如此(SIGKILL除外)。追蹤程式會在一個呼叫waitpid(或者其他類wait系統呼叫)時收到通知,該呼叫會返回一個包含被追蹤執行緒停止的原因的狀態值。當被追蹤執行緒停止時,追蹤程式可以使用多種ptrace請求來檢查和編輯被追蹤執行緒。追蹤程式可以讓被追蹤執行緒繼續執行,有選擇地忽略發過來的訊號(甚至可以傳送一個完全不同的訊號給被追蹤執行緒)。

可以看到,ptrace確實是一個強大的系統呼叫;gdb就是基於ptrace這個系統呼叫來做的。其原理是利用ptrace系統呼叫,在被除錯程式和gdb之間建立追蹤關係。然後所有傳送給被除錯程式(被追蹤執行緒)的訊號(除SIGKILL)都會被gdb截獲,gdb根據截獲的訊號,檢視被除錯程式相應的記憶體地址,並控制被除錯的程式繼續執行。GDB常用的使用方法有斷點設定和單步除錯,接下來我們來分析一下他們是如何實現的。

1.建立除錯關係:

用gdb除錯程式有2種模式,包括使用gdb啟動程式,以及attach到現有程序。分別對應下面2種建立除錯關係的方法:

  1)  fork: 利用fork+execve執行被測試的程式,子程序在執行execve之前呼叫ptrace(PTRACE_TRACEME),建立了與父程序(debugger)的跟蹤關係。

  2)  attach: debugger可以呼叫ptrace(PTRACE_ATTACH,pid,...),建立自己與程序號為pid的程序間的跟蹤關係。即利用PTRACE_ATTACH,使自己變成被除錯程式的父程序(用ps可以看到)。用attach建立起來的跟蹤關係,可以呼叫ptrace(PTRACE_DETACH,pid,...)來解除。注意attach程序時的許可權問題,如一個非root許可權的程序是不能attach到一個root程序上的。

2.斷點原理:

  1)    斷點的實現原理,就是在指定的位置插入斷點指令,當被除錯的程式執行到斷點的時候,產生SIGTRAP訊號。該訊號被gdb捕獲並進行斷點命中判定,當gdb判斷出這次SIGTRAP是斷點命中之後就會轉入等待使用者輸入進行下一步處理,否則繼續。 

  2)    斷點的設定原理: 在程式中設定斷點,就是先將該位置的原來的指令儲存,然後向該位置寫入int 3。當執行到int 3的時候,發生軟中斷,核心會給子程序發出SIGTRAP訊號,當然這個訊號會被轉發給父程序。然後用儲存的指令替換int3,等待恢復執行。

  3)    斷點命中判定:gdb把所有的斷點位置都存放在一個連結串列中,命中判定即把被除錯程式當前停止的位置和連結串列中的斷點位置進行比較,看是斷點產生的訊號,還是無關訊號。

  4)    條件斷點的判定:原理同3),只是恢復斷點處的指令後,再多加一步條件判斷。若表示式為真,則觸發斷點。由於需要判斷一次,因此加入條件斷點後,不管有沒有觸發到條件斷點,都會影響效能。在x86平臺,某些硬體支援硬體斷點,在條件斷點處不插入int    3,而是插入一個其他指令,當程式走到這個地址的時候,不發出int 3訊號,而是先去比較一下特定暫存器和某個地址的內容,再決定是否傳送int 3。因此,當你的斷點的位置會被程式頻繁地“路過”時,儘量使用硬體斷點,會對提高效能有幫助

3.單步跟蹤原理:

這個最簡單,因為ptrace本身支援單步功能,呼叫ptrace(PTRACE_SINGLESTEP,pid,...)即可,如下圖說明:

 

相關推薦

GDB除錯原理——ptrace系統呼叫

本文由霸氣的菠蘿原創,轉載請註明出處:http://www.cnblogs.com/xsln/p/ptrace.html 引子: gdb基本上大家都在用,你有沒有想過它的實現原理是什麼?為什麼它可以控制程式執行、中斷、訪問記憶體甚至直接使程式流程改變? 在使用gdb除錯程式時,程式的程序狀態是”

使用gdb跟蹤分析一個系統呼叫核心函式

“郭孟琦 + 原創作品轉載請註明出處 + 《Linux核心分析》MOOC課程http://mooc.study.163.com/course/USTC-1000029000 ” 繼續上週的內容,首先利用gdb跟蹤系統呼叫system_call的處理過程。 這裡我繼續使用上

嵌入式Linux——應用除錯:自制系統呼叫,並編寫程序檢視器

簡介:     本文主要講解在ARM Linux中系統呼叫的原理,並根據這些原理在系統中新增自制的系統呼叫函式,最後我們還將通過自制的系統呼叫函式來檢視應用程式指定位置的資訊,用此方法實現應用程式的除錯。  Linux核心:linux-2.6.22.6  所用開發板

Golang原始碼學習:使用gdb除錯探究Golang函式呼叫棧結構

本文所使用的golang為1.14,gdb為8.1。 一直以來對於函式呼叫都僅限於函式呼叫棧這個概念上,但對於其中的詳細結構卻瞭解不多。所以用gdb除錯一個簡單的例子,一探究竟。 ## 函式呼叫棧的結構(以下簡稱棧) 棧包含以下作用: - 儲存函式返回地址。 - 儲存呼叫者的rbp。 - 儲存區域性變數。

gdb除錯linux系統呼叫

下載並編譯核心 首先進行核心編譯,在核心原始碼路徑下執行: sudo apt-get install m4 libncurses5-dev -y make menuconfig(選中 kernel hacking –>

linux系統呼叫原理及實現

linux系統呼叫 系統呼叫是linux核心為使用者態程式提供的主要功能介面。通過系統呼叫,使用者態程序能夠臨時切換到核心態,使用核心態才能訪問的硬體和資源完成特定功能。系統呼叫由linux核心和核心模組實現,核心在處理系統呼叫時還會檢查系統呼叫請求和引數是否正確,保證對特

gdb除錯(1):單步執行和跟蹤函式呼叫

轉發自:http://songjinshan.com/akabook/zh/gdb.html#id1看下面的程式: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18#include <stdio.h> in

系統技術非業餘研究 » 如何用gdb除錯erlang執行期(高階)

前些天在erlang的原始碼裡面閒逛的時候發現了 bin目錄下的cerl,一看原來是個除錯的高階貨。 我之前寫過一篇文章http://mryufeng.javaeye.com/blog/113852 如何除錯erlang 但是這是土八路的方法, cerl才是現代化工業。 # This is a s

系統呼叫 (原理)

// 轉自:https://blog.csdn.net/u012877472/article/details/49907137 “作業系統”通常包含以下兩種含義: 1、表示完整的軟體包,包括用來管理計算機資源的核心層軟體,以及附帶的所有標準軟體工具,諸如命令列

gdb除錯coredump(原理篇)

上一篇部落格裡我們通過3個例子介紹了gdb除錯coredump的時候,比較常用到的一些命令和定位方法。這篇內容裡,我們將嘗試去探討gdb除錯coredump的原理,以及它們背後的一些東西。 Core

【軟體開發底層知識修煉】十七 快速學習GDB除錯四 使用GDB進行函式呼叫棧的檢視

上一篇文章學習瞭如何使用GDB資料斷點進行記憶體監測:【軟體開發底層知識修煉】十五 快速學習GDB除錯三 使用GDB的資料斷點監測變數是否改變 本篇文章繼續上一篇文章的學習:如何使用GDB進行函式呼叫棧的檢視 文章目錄

用Qt 呼叫GDB除錯 Arm程式 詳細步驟----可單步執行每一行

前言本人交叉編譯環境 Ubuntu 10.04(虛擬機器),編譯工具鏈 arm-hisiv100nptl-linux,Qt 4.8.5 ,QtCreator1.3.11、在虛擬機器Ubuntu 10.04上,安裝GDB除錯工具之前,要安裝預處理模組:sudo apt-get

嵌入式系統交叉除錯原理和方法

)的韌體區,對使用使用者不可見;而音樂檔案、電子書等則是存在於外存的使用者區,對使用使用者可見。從中可看成,各個應用程式是分時複用寶貴的記憶體資源。由於成本敏感,記憶體資源的大小是經過精心設計的。對於單個應用程式,也會將程式碼分為常駐記憶體型別和可切換型別。例如,對效能影響比較大的解碼部分程式碼就需要常駐記憶

gdb除錯(四)函式呼叫棧之Backtraces

通過產看棧資訊,我們可以瞭解棧內幀的編號或地址,通過選擇幀我們可以移動到指定的幀內去產看資訊。 1、檢視棧資訊 產看函式呼叫棧的幾個函式 bt     顯示所有的函式呼叫棧幀的資訊,每個幀一行。 bt n     顯示棧定的n個幀資訊。 bt -n     顯示棧底

[原理分析]Linux下的棧溢位案例分析-GDB除錯操練[2]

摘要: 原版本中的問題主要在於除錯過程中,蠻力的痕跡太重,沒有很好地體現常用的除錯準則;本文在原版本的基礎上,融入參考文獻中提及的除錯原則,重新審視和操練該問題,希望儘量體現出除錯中常用的思維法則。 測試的平臺:1.  ubuntu 9;   gcc 4.4.1;   G

64位Linux系統呼叫的新增以及系統呼叫原理

使用者地址空間和核心地址空間 每個程序都會有一個固定大小的虛擬地址空間,大小較固定,視作業系統位數而定(位數同時也決定實體地址的大小)。例如32位作業系統,其實體地址也就是32位,表示的空間也就是2的32次方,即4GB。 大家都知道系統核心事關作業系統的穩定

系統呼叫原理

1什麼是系統呼叫    系統呼叫,顧名思義,說的是作業系統提供給使用者程式呼叫的一組“特殊”介面。使用者程式可以通過這組“特殊”介面來獲得作業系統核心提供的服務,比如使用者可以通過檔案系統相關的呼叫請求系統開啟檔案、關閉檔案或讀寫檔案,可以通過時鐘相關的系統呼叫獲得系統

Linux VFS中write系統呼叫實現原理

目錄 WORD裡面的目錄複製過來似乎不能直接用。。還是放在這裡當主線看吧.. 使用者空間的write函式在核心裡面的服務例程為sys_write [email protected]

linux系統呼叫原理

x86架構 trap_init 在系統啟動的時候start_kernel會呼叫trap_init來初始化異常向量表 start_kernel trap_init set_system_trap_gate(SYSCALL_VE

第三章 第二節 C庫{fread, fwrite}和系統呼叫{read,write}原理

最新我研究了一下fwrite, write,printf的實現原理, 給大家分享一下,給大家展示一下 一. 程式碼片段 #include <stdio.h> #include <unistd.h> #include <string.