標籤:局部變數 針對 .com 參數 bsp 操作方法 map 打破 情況
使用GDB進行調試
這是編譯ARM二進位檔案和使用GDB進行基本調試的簡單介紹。在您按照教程進行操作時,您可能需要按照自己的習慣使用ARM程式集。在這種情況下,你要麼需要一個備用的ARM裝置,或者你只是按照在這短短的步驟建立自己的實驗室環境中虛擬機器操作方法。
您可以使用第7部分 - 堆棧和函數中的以下代碼來熟悉GDB的基本調試。
.section .text.global _start_開始: 按{r11,lr} / *開始序幕。將幀指標和LR儲存到堆棧* / 添加r11,sp,#0 / *設定堆棧架構的底部* / sub sp,sp,#16 / *序幕結束。在堆棧上分配一些緩衝區* / mov r0,#1 / *設定局部變數(a = 1)。這也可以作為設定最大功能的第一個參數* / mov r1,#2 / *設定局部變數(b = 2)。這也可以作為設定最大功能的第二個參數* / bl最大/ *呼叫/分支功能最大* / sub sp,r11,#0 / *結尾的開始。重新調整堆棧指標* / 流行{r11,pc} / *結語結尾。從堆棧中恢複幀指標,通過直接載入到PC,跳轉到先前儲存的LR * /最大: 按{r11} / *開始序幕。將幀指標儲存到堆棧* / 添加r11,sp,#0 / *設定堆棧架構的底部* / sub sp,sp,#12 / *序幕結束。在堆棧上分配一些緩衝區* / cmp r0,r1 / *執行if(a <b)* / movlt r0,r1 / *如果r0小於r1,將r1存入r0 * / 添加sp,r11,#0 / *結尾的開始。重新調整堆棧指標* / 彈出{r11} / *恢複幀指標* / bx lr / *結語結尾。通過LR寄存器跳回主站* /
就個人而言,我更喜歡使用GEF作為GDB擴充。它給了我一個更好的概述和有用的功能。您可以在這裡試用:GEF - GDB增強功能。
將上面的代碼儲存在一個名為max.s的檔案中,並使用以下命令進行編譯:
$ as max.s -o max.o$ ld max.o -o max
調試器是一個強大的工具,可以:
- 崩潰後載入記憶體轉儲(驗屍調試)
- 附加到正在啟動並執行進程(用於伺服器處理序)
- 啟動一個程式並進行調試
針對二進位檔案,核心檔案或進程ID啟動GDB:
- 附加到進程:$ gdb -pid $(pidof <process>)
- 調試一個二進位檔案:$ gdb ./file
- 檢查核心(崩潰)檔案:$ gdb -c ./core.3243
$ gdb max
如果您安裝了GEF,則會釋放您的gef>提示符。
這是你如何獲得協助:
- (gdb)h
- (gdb)apropos <search-term>
gef> apropos寄存器收集 - 指定要在追蹤點收集的一個或多個資料項目核心檔案 - 使用FILE作為核心轉儲來檢查記憶體和寄存器info all-registers - 所有寄存器及其內容的列表info r - 整數寄存器及其內容的列表資訊寄存器 - 整數寄存器及其內容的列表維護列印烹飪寄存器 - 列印包括烹飪值的內部寄存器配置維護列印原始寄存器 - 列印內部寄存器配置,包括原始值維護列印寄存器 - 列印內部寄存器配置維護列印遠程寄存器 - 列印包括每個寄存器的內部寄存器配置p - 列印EXP運算式的值列印 - 表達EXP的列印值寄存器 - 在一個顯示全部細節設定may-write-registers - 設定寫入寄存器的許可權設定觀察者 - 設定gdb是否在觀察者模式下控制劣勢顯示may-write-registers - 顯示寫入寄存器的許可權顯示觀察者 - 顯示gdb是否在觀察者模式下控制劣勢tui reg float - 僅顯示浮點寄存器tui reg general - 只顯示通用寄存器tui reg system - 只顯示系統寄存器
斷點命令:
- break(或者只是b)<function-name>
- 打破<line-number>
- 打破檔案名稱:功能
- 中斷檔案名稱:行號
- 打破* <地址>
- break + <offset>
- 打破 - <位移>
- tbreak(設定臨時斷點)
- del <number> (刪除斷點編號x)
- 刪除(刪除所有斷點)
- 刪除<range>(刪除斷點範圍)
- 禁用/啟用<斷點編號或範圍>(不刪除斷點,只是啟用/禁用它們)
- 繼續(或只是c) - (繼續執行,直到下一個斷點)
- 繼續<number>(繼續,但是忽略當前的斷點編號時間,對迴圈內的斷點很有用。
- 完成(繼續結束功能)
gef> break _start gef> info breakNum Type Disp Enb Address什麼1個斷點保持y 0x00008054 <_start> 斷點已經達到了一次gef> del 1 gef> break * 0x0000805c斷點2在0x805cgef> break _start
這將刪除第一個斷點並在指定的記憶體位址設定一個斷點。當你運行這個程式時,它會在這個確切的位置中斷。如果不刪除第一個斷點,只是設定一個新斷點並運行,它將在第一個斷點處斷開。
開始和停止:
- 從程式開始處開始執行程式
- 跑
- [R
- 運行<command-line-argument>
- 停止程式執行
- 退出GDB調試器
gef>運行
現在我們的程式正好打破了我們想要的地方,現在是檢查記憶體的時候了。命令“x”以各種格式顯示儲存空間內容。
| 文法:x / < count > < format > < unit > |
| 格式 |
單元 |
| x - 十六進位 |
b - 位元組 |
| d - 十進位 |
h - 半字(2位元組) |
| 我 - 指示 |
w - 字(4位元組) |
| t - 二進位(二) |
g - 巨詞(8位元組) |
| o - 八進位 |
|
| 你 - 無符號 |
|
| s - 字串 |
|
| c - 字元 |
|
gef> x / 10i $ pc=> 0x8054 <_start>:push {r11,lr} 0x8058 <_start + 4>:添加r11,sp,#0 0x805c <_start + 8>:sub sp,sp,#16 0x8060 <_start + 12>:mov r0,#1 0x8064 <_start + 16>:mov r1,#2 0x8068 <_start + 20>:bl 0x8074 <max> 0x806c <_start + 24>:sub sp,r11,#0 0x8070 <_start + 28>:pop {r11,pc} 0x8074 <max>:push {r11} 0x8078 <max + 4>:加上r11,sp,#0gef> x / 16xw $ pc0x8068 <_start + 20>:0xeb000001 0xe24bd000 0xe8bd8800 0xe92d08000x8078 <max + 4>:0xe28db000 0xe24dd00c 0xe1500001 0xb1a000010x8088 <max + 20>:0xe28bd000 0xe8bd0800 0xe12fff1e 0x000017410x8098:0x61656100 0x01006962 0x0000000d 0x01080206
逐步執行代碼的命令:
- 進入下一行代碼。將步入一個功能
- 執行下一行代碼。不會輸入功能
- 繼續處理,直到達到指定的行號,函數名稱,地址,檔案名稱:函數或檔案名稱:行號
- 顯示當前行號和您所在的功能
gef> nexti 5...0x8068 <_start + 20> bl 0x8074 <max> < - $ pc0x806c <_start + 24> sub sp,r11,#00x8070 <_start + 28> pop {r11,pc}0x8074 <max> push {r11}0x8078 <max + 4>添加r11,sp,#00x807c <max + 8> sub sp,sp,#120x8080 <max + 12> cmp r0,r10x8084 <max + 16> movlt r0,r10x8088 <max + 20>添加sp,r11,#0
用資訊寄存器或ir檢查寄存器
gef> info寄存器r0 0x1 1r1 0x2 2r2 0x0 0r3 0x0 0r4 0x0 0r5 0x0 0r6 0x0 0r7 0x0 0r8 0x0 0r9 0x0 0r10 0x0 0r11 0xbefff7e8 3204446184r12 0x0 0sp 0xbefff7d8 0xbefff7d8lr 0x0 0pc 0x8068 0x8068 <_start + 20>cpsr 0x10 16
命令“資訊寄存器”給你當前的寄存器狀態。我們可以看到通用寄存器r0-r12和專用寄存器SP,LR和PC,包括狀態寄存器CPSR。函數的前四個參數通常儲存在r0-r3中。在這種情況下,我們手動將值移到r0和r1。
顯示進程記憶體映射:
gef> info proc map過程10225映射地址空間: 開始地址結束位址大小位移量objfile 0x8000 0x9000 0x1000 0 / home / pi / lab / max 0xb6fff000 0xb7000000 0x1000 0 [sigpage] 0xbefdf000 0xbf000000 0x21000 0 [stack] 0xffff0000 0xffff1000 0x1000 0 [向量]
用“反組譯碼”命令查看max函數的反組譯碼輸出。
gef>反組譯碼max 彙編代碼功能最大的轉儲: 0x00008074 <+0>:push {r11} 0x00008078 <+4>:添加r11,sp,#0 0x0000807c <+8>:sub sp,sp,#12 0x00008080 <+12>:cmp r0,r1 0x00008084 <+16>:movlt r0,r1 0x00008088 <+20>:添加sp,r11,#0 0x0000808c <+24>:pop {r11} 0x00008090 <+28>:bx lr 彙編器轉儲結束。
GEF特定命令(更多命令可以使用命令“gef”查看):
- 將所有載入的ELF映像的所有部分轉儲到進程記憶體中
- proc map的增強版本在映射頁面中包含RWX屬性
- 記憶體屬性在給定的地址
- 檢查內建於運行二進位檔案中的編譯器級保護
gef> xfiles 開始結束名稱檔案0x00008054 0x00008094 .text / home / pi / lab / max0x00008054 0x00008094 .text / home / pi / lab / max0x00008054 0x00008094 .text / home / pi / lab / max0x00008054 0x00008094 .text / home / pi / lab / max0x00008054 0x00008094 .text / home / pi / lab / max0x00008054 0x00008094 .text / home / pi / lab / max0x00008054 0x00008094 .text / home / pi / lab / max0x00008054 0x00008094 .text / home / pi / lab / max0x00008054 0x00008094 .text / home / pi / lab / max0x00008054 0x00008094 .text / home / pi / lab / maxgef> vmmap 開始結束位移Perm路徑0x00008000 0x00009000 0x00000000 rx / home / pi / lab / max0xb6fff000 0xb7000000 0x00000000 rx [sigpage]0xbefdf000 0xbf000000 0x00000000 rwx [stack]0xffff0000 0xffff1000 0x00000000 rx [向量]gef> xinfo 0xbefff7e8---------------------------------------- [xinfo:0xbefff7e8] ----- -----------------------------------找到0xbefff7e8頁面:0xbefdf000 - > 0xbf000000(大小= 0x21000)許可權:rwx路徑名稱:[stack]位移(從頁面):+ 0x207e8Inode:0gef> checksec[+] checksec for‘/ home / pi / lab / max‘金絲雀:沒有NX支援:是的PIE支援:沒有RPATH:沒有RUNPATH:沒有部分RelRO:沒有完整的RelRO:沒有
故障排除
為了使GDB的調試更高效,知道某些分支/跳轉將帶給我們的位置是非常有用的。某些(較新的)GDB版本解析分支指令的地址並向我們顯示目標函數的名稱。例如,GDB的以下輸出缺少這個功能:
...0x000104f8 <+72>:bl 0x103340x000104fc <+76>:mov r0,#80x00010500 <+80>:bl 0x1034c0x00010504 <+84>:mov r3,r0...
這是GDB(native,沒有gef)的輸出,它具有我正在談論的功能:
0x000104f8 <+72>:bl 0x10334 <free @ plt>0x000104fc <+76>:mov r0,#80x00010500 <+80>:bl 0x1034c <malloc @ plt> 0x00010504 <+84>:mov r3,r0
如果你在GDB中沒有這個特性,你可以更新Linux原始碼(並且希望他們的程式碼程式庫中已經有了一個更新的GDB)或者自己編譯一個更新的GDB。如果您選擇自行編譯GDB,則可以使用以下命令:
cd / tmpwget https://ftp.gnu.org/gnu/gdb/gdb-7.12.tar.gztar vxzf gdb-7.12.tar.gzsudo apt-get更新sudo apt-get install libreadline-dev python-dev texinfo -ycd gdb-7.12./configure --prefix = / usr --with-system-readline --with-python && make -j4sudo make -j4 -C gdb / installgdb --version
我用上面提供的命令在Raspbian(jessie)上下載,編譯和運行GDB,沒有任何問題。這些命令也將取代以前的GDB版本。如果你不想要,那麼跳過以install為結尾的命令。而且,我在QEMU中類比Raspbian的時候做了這個,所以花了我很長時間(小時),因為模擬環境中的資源(CPU)有限。我使用GDB版本7.12,但是即使使用更新的版本,您也很有可能成功(請點擊這裡查看其他版本)。
使用GDB和GEF進行調試