1. 程式人生 > 資訊 >《英雄聯盟手遊》3.0 版不停服優化:輔助玩家評價提升,開啟首選位保護功能

《英雄聯盟手遊》3.0 版不停服優化:輔助玩家評價提升,開啟首選位保護功能

參考及學習文件

2.安裝與啟動gdb

  1. gdb -v 檢查是否安裝成功,未安裝成功則安裝(必須確保編譯器已經安裝,如 gcc) → 可參考(http://c.biancheng.net/view/8130.html)
  2. 啟動 gdb
    1. gdb test_file.exe 來啟動 gdb 除錯, 即直接指定需要除錯的可執行檔名
    2. 直接輸入 gdb 啟動,進入 gdb 之後採用命令 file test_file.exe 來指定檔名
    3. 如果目標執行檔案要求出入引數(如 argv[] 接收引數),則可以通過三種方式指定引數:
      1. 在啟動 gdb 時,gdb --args text_file.exe
      2. 在進入gdb 之後,執行 set args param_1
      3. 在 進入 gdb 除錯以後,run param_1 或者 start para_1

3.常用命令

  • 以下以 test_file.c 作為源程式例子的名字,test_file.exe 作為可執行檔案例子的名字, 以param_1 作為引數的例子的名字。
  • (gdb) 表示是在 gdb 除錯模式下執行
  • 一般常用的方法有兩種,即3.1打斷點除錯3.2單步除錯
  • list(l):
    列出原始碼
  • quit(q): 退出 gdb 除錯模式
  • 進入 gdb 之後,輸入 help 可以檢視所有命令的使用說明

3.1 打斷點除錯

  • 檢視斷點資訊: info breakpoint[n] 或者 info break[n] 用於檢視斷點的資訊, n引數 作為可選引數,為某個斷點的編號,表示檢視指定斷點而非全部斷點。
  • 刪除斷點
    • (gdb) clear location
      • 引數 location 通常為某一行程式碼的行號或者某個具體的函式名。當 location 引數為某個函式的函式名時,表示刪除位於該函式入口處的所有斷點。
    • (gdb) delete [breakpoints] [num]
      • breakpoints 引數可有可無,num 引數為指定斷點的編號,其可以是 delete 刪除某一個斷點,而非全部。
  • 禁用斷點
    • disable [breakpoints] [num...]
      • breakpoints 引數可有可無;num... 表示可以有多個引數,每個引數都為要禁用斷點的編號。如果指定 num...,disable 命令會禁用指定編號的斷點;反之若不設定 num...,則 disable 會禁用當前程式中所有的斷點。
  • 啟用斷點
    • enable [breakpoints] [num...] 啟用用 num... 引數指定的多個斷點,如果不設定 num...,表示啟用所有禁用的斷點
    • enable [breakpoints] once num… 臨時啟用以 num... 為編號的多個斷點,但斷點只能使用 1 次,之後會自動回到禁用狀態
    • enable [breakpoints] count num... 臨時啟用以 num... 為編號的多個斷點,斷點可以使用 count 次,之後進入禁用狀態
    • enable [breakpoints] delete num… 啟用 num.. 為編號的多個斷點,但斷點只能使用 1 次,之後會被永久刪除。

break(b):打的是普通斷點,打斷點有兩種形式

  • (gdb) break location // b location,location 代表打斷點的位置

    linenum linenum 是一個整數,表示要打斷點處程式碼的行號。要知道,程式中各行程式碼都有對應的行號,可通過執行 l(小寫的 L)命令看到。
    filename:linenum filename 表示源程式檔名;linenum 為整數,表示具體行數。整體的意思是在指令檔案 filename 中的第 linenum 行打斷點。
    + offset
    - offset
    offset 為整數(假設值為 2),+offset 表示以當前程式暫停位置(例如第 4 行)為準,向後數 offset 行處(第 6 行)打斷點;-offset 表示以當前程式暫停位置為準,向前數 offset 行處(第 2 行)打斷點。
    function function 表示程式中包含的函式的函式名,即 break 命令會在該函式內部的開頭位置打斷點,程式會執行到該函式第一行程式碼處暫停。
    filename:function filename 表示遠端檔名;function 表示程式中函式的函式名。整體的意思是在指定檔案 filename 中function 函式的開頭位置打斷點。
  • (gdb) break ... if cond // b .. if cond,代表如果 cond 條件為true,則在 “...” 處打斷點
    • 通過藉助 condition 命令為不同型別斷點設定條件表示式,只有當條件表示式成立(值為 True)時,相應的斷點才會觸發從而使程式暫停執行。

tbreak: tbreak 命令可以看到是 break 命令的另一個版本,tbreak 和 break 命令的用法和功能都非常相似,唯一的不同在於,使用 tbreak 命令打的斷點僅會作用 1 次,即使程式暫停之後,該斷點就會自動消失。

rbreak:和 break 和 tbreak 命令不同,rbreak 命令的作用物件是 C、C++ 程式中的函式,它會在指定函式的開頭位置打斷點。

  • (gdb) tbreak regex
    • regex 代表一個正則表示式,會在匹配到的函式的內部的開頭位置打斷點
  • tbreak 命令打的斷點和 break 命令打斷點的效果是一樣的,會一直存在,不會自動消失。

watch: 此命令打的是觀察斷點,可以監控某個變數或者表示式的值。只有當被監控變數(表示式)的值發生改變,程式才會停止執行。

  • (gdb) watch cond
    • cond 代表的就是要監控的變數或者表示式
  • rwatch 命令:只要程式中出現讀取目標變數(表示式)的值的操作,程式就會停止執行;
  • awatch 命令:只要程式中出現讀取目標變數(表示式)的值或者改變值的操作,程式就會停止執行。

catch: 捕捉斷點的作用是,監控程式中某一事件的發生,例如程式發生某種異常時、某一動態庫被載入時等等,一旦目標時間發生,則程式停止執行。

  • (gdb) catch event

    event 事件 含 義
    throw [exception] 當程式中丟擲 exception 指定型別異常時,程式停止執行。如果不指定異常型別(即省略 exception),則表示只要程式發生異常,程式就停止執行。
    catch [exception] 當程式中捕獲到 exception 異常時,程式停止執行。exception 引數也可以省略,表示無論程式中捕獲到哪種異常,程式都暫停執行。
    load [regexp]
    unload [regexp]

    其中,regexp 表示目標動態庫的名稱,load 命令表示當 regexp 動態庫載入時程式停止執行;unload 命令表示當 regexp 動態庫被解除安裝時,程式暫停執行。regexp 引數也可以省略,此時只要程式中某一動態庫被載入或解除安裝,程式就會暫停執行。

    PS: 可以先通過 lld text_file.exe 命令檢視此執行檔案所載入的程式動態庫。

tcatch:tcatch 命令和 catch 命令的用法幾乎相同,唯一不同之處在於,對於目標事件,catch 命令的監控是永久的,而 tcatch 命令只監控一次,也就是說,只有目標時間第一次觸發時,tcath 命令才會捕獲並使程式暫停,之後將失效。

GDB的 condition 命令

  • 針對三種斷點設定條件
  • (gdb) condition bnum expression
    • bnum 表示斷點的編號,expression 表示條件表示式
    • 用於為 bnum 編號的斷點新增或修改 expression 條件表示式
  • (gdb) condition bnum
    • 用於刪除 bnum 編號斷點的條件表示式,使其變成普通的無條件斷點

GDB ignore命令

  • ignore 命令也可以使一個斷點成為條件斷點,但這裡的“條件”並非自定義的表示式,而僅為一個整數,它用來表示該斷點失效的次數。
  • 即,ignore 命令可以使目標斷點暫時失去作用,當斷點失效的次數超過指定次數時,斷點的功能會自動恢復。
  • 語法形式
    • ignore bnum count
      • 引數 bnum 為某個斷點的編號;引數 count 用於指定該斷點失效的次數。

3.2 單步除錯

run(r)

continue(c)

next(n)

  • 命令格式: (gdb) next count
    • count表示單步執行多少行程式碼,預設為 1 行
  • 其最大的特點是當遇到包含呼叫函式的語句時,無論函式內部包含多少行程式碼,next 指令都會一步執行完。也就是說,對於呼叫的函式來說,next 命令只會將其視作一行程式碼

step(s)

  • (gdb) step count
    • 引數 count 表示一次執行的行數,預設為 1 行。
  • 通常情況下,step 命令和 next 命令的功能相同,都是單步執行程式。不同之處在於,當 step 命令所執行的程式碼行中包含函式時,會進入該函式內部,並在函式第一行程式碼處停止執行。

until(u)

  • (gdb) until
    • 不帶引數的 until 命令,可以使 GDB 偵錯程式快速執行完當前的迴圈體,並執行至迴圈體外停止。注意,until 命令並非任何情況下都會發揮這個作用,只有當執行至迴圈體尾部(最後一行程式碼)時,until 命令才會發生此作用;反之,until 命令和 next 命令的功能一樣,只是單步執行程式
  • (gdb) until location
    • 引數 location 為某一行程式碼的行號

3.3 檢視變數的值

print(p)

  • p num_1
    • 引數 num_1 用來代指要檢視或者修改的目標變數或者表示式
  • 它的功能就是在 GDB 除錯程式的過程中,輸出或者修改指定變數或者表示式的值

display

  • (gdb) display expr
  • (gdb) display/fmt expr
    • expr 表示要檢視的目標變數或表示式;引數 fmt 用於指定輸出變數或表示式的格式

      /fmt 功 能
      /x 以十六進位制的形式打印出整數。
      /d 以有符號、十進位制的形式打印出整數。
      /u 以無符號、十進位制的形式打印出整數。
      /o 以八進位制的形式打印出整數。
      /t 以二進位制的形式打印出整數。
      /f 以浮點數的形式列印變數或表示式的值。
      /c 以字元形式列印變數或表示式的值。
  • (gdb) undisplay num...
  • (gdb) delete display num...
    • 引數 num... 表示目標變數或表示式的編號,編號的個數可以是多個
  • (gdb) disable display num...
    • 禁用自動顯示列表中處於啟用狀態下的變數或表示式
  • (gdb) enable display num...
    • 也可以啟用當前處於禁用狀態的變數或表示式
  • 和 print 命令一樣,display 命令也用於除錯階段檢視某個變數或表示式的值
  • 它們的區別是,使用 display 命令檢視變數或表示式的值,每當程式暫停執行(例如單步執行)時,GDB 偵錯程式都會自動幫我們打印出來,而 print 命令則不會

3.4 GDB handle 命令: 訊號處理

→(gdb) handle signal mode

其中,signal 引數表示要設定的目標訊號,它通常為某個訊號的全名(SIGINT)或者簡稱(去除‘SIG’後的部分,如 INT);如果要指定所有訊號,可以用 all 表示。

mode 引數用於明確 GDB 處理該目標資訊的方式,其值可以是如下幾個:

  • nostop:當訊號發生時,GDB 不會暫停程式,其可以繼續執行,但會打印出一條提示資訊,告訴我們訊號已經發生;
  • stop:當訊號發生時,GDB 會暫停程式執行。
  • noprint:當訊號發生時,GDB 不會打印出任何提示資訊;
  • print:當訊號發生時,GDB 會打印出必要的提示資訊;
  • nopass(或者 ignore):GDB 捕獲目標訊號的同時,不允許程式自行處理該訊號;
  • pass(或者 noignore):GDB 除錯在捕獲目標訊號的同時,也允許程式自動處理該訊號。

可以在 gdb 模式下,通過 info signals 或者 info signals <signal_name> (例如 info signals SIGINT) 檢視不同 signal 的資訊。

3.5 GDB frame和backtrace命令:檢視棧資訊

(gdb) frame spec該命令可以將 spec 引數指定的棧幀選定為當前棧幀。spec 引數的值,常用的指定方法有 3 種:

  1. 通過棧幀的編號指定。0 為當前被呼叫函式對應的棧幀號,最大編號的棧幀對應的函式通常就是 main() 主函式;
  2. 藉助棧幀的地址指定。棧幀地址可以通過 info frame 命令(後續會講)打印出的資訊中看到;
  3. 通過函式的函式名指定。注意,如果是類似遞迴函式,其對應多個棧幀的話,通過此方法指定的是編號最小的那個棧幀。

(gdb) info frame我們可以檢視當前棧幀中儲存的資訊

該命令會依次打印出當前棧幀的如下資訊:

  • 當前棧幀的編號,以及棧幀的地址;
  • 當前棧幀對應函式的儲存地址,以及該函式被呼叫時的程式碼儲存的地址
  • 當前函式的呼叫者,對應的棧幀的地址;
  • 編寫此棧幀所用的程式語言;
  • 函式引數的儲存地址以及值;
  • 函式中區域性變數的儲存地址;
  • 棧幀中儲存的暫存器變數,例如指令暫存器(64位環境中用 rip 表示,32為環境中用 eip 表示)、堆疊基指標暫存器(64位環境用 rbp 表示,32位環境用 ebp 表示)等。


除此之外,還可以使用info args命令檢視當前函式各個引數的值;使用info locals命令檢視當前函式中各區域性變數的值。

(gdb) backtrace [-full] [n]用於列印當前除錯環境中所有棧幀的資訊

其中,用 [ ] 括起來的引數為可選項,它們的含義分別為:

  • n:一個整數值,當為正整數時,表示列印最裡層的 n 個棧幀的資訊;n 為負整數時,那麼表示列印最外層 n 個棧幀的資訊;
  • -full:列印棧幀資訊的同時,打印出區域性變數的值。

3.6GDB編輯和搜尋原始碼

GDB edit命令:編輯檔案

  • (gdb) edit [location]
  • (gdb) edit [filename] : [location]
    • location 表示程式中的位置。這個命令表示啟用檔案的指定位置,然後進行編輯。
    • 如果遇到報錯 "bash: /bin/ex: 沒有那個檔案或目錄", 因為 GDB 的預設編輯器是 ex , 則需要指定編輯器,如 export EDITOR=/usr/bin/vim orexport EDITOR=/usr/bin/vi

GDB search命令:搜尋檔案

  • search <regexp>
  • reverse-search <regexp>
    • 第一項命令格式表示從當前行的開始向前搜尋,後一項表示從當前行開始向後搜尋。其中 regexp 就是正則表示式,正則表示式描述了一種字串匹配的模式,可以用來檢查一個串中是否含有某種子串、將匹配的子串替換或者從某個串中取出符合某個條件的子串。很多的程式語言都支援使用正則表示式。