MyUtils

View on GitHub

GDB の使い方& ASSEMBlA

ここでは GDB の使い方,Assembla についてまとめる


GDB の使い方

gdb -q ~.out

# 起動済のプロセスにアタッチする gdb単体で起動後に`attach <PID>`でもOK
gdb --pid <PID>
# breakpointsの確認
info breakpoints  
#無効化
disable [breakpoint no]   
#無効化
enable [breakpoint no]
next # 関数の中までは追わない  
step # 関数内まで追う  
continue #次のbreakまで処理を継続  
finish   #関数の終了進む(一個上のスタックまで戻る)  

処理を飛ばして実行する

こんな感じで実行することで指定行にjumpして処理を継続できる。fileのopenをお試しでcallして成功して以降の処理で際呼び出しをするとエラーが発生するケースなどで使う

jump <行番号>


Coreからバグを調査する

GDBではプログラムが吐いたコアファイルを使ってバグの調査ができる。 ここではそれをまとめる。

# 🌟こんな感じで実行する
gdb <実行ファイル> <coreファイル>
bt
backtrace 
# 問題のフレームへ移動
frame <btで確認したNo>
# 変数の確認
print <var>
# 現在のスタックフレーム上のローカル変数を確認できる。
info locals 

GDBでリモートデバッグする

GDBはリモートで動作している側でgdbserverを立ち上げることでリモートデバッグができる これはシンボルファイルがリモートになくともローカル側で持っていればデバッグが可能となるものである。

# comm :接続方法
#   シリアルポート通信の場合 (ex: /dev/com1)
#   TCP接続 (ex: host:portNo)
# prog : デバッグ対象のプログラム
# args... : progの引数
gdbserver comm prog [args...]

# pid: プロセスIDにアタッチ
gdbserver --attach {comm} {pid}

# 🌟アタッチするプロセス ID を指定せずに "gdbserver" を起動する場合
gdbserver --multi {comm}  
gdb

# gdb起動後、以下のコマンドで接続
target extended-remote {IP}:{Port}

# ファイルを指定して実行する場合
set remote exec-file {ファイル名}
run

# プロセスIDを指定して実行
attach {PID}
continue

参考stackoverflow


thread環境をデバッグする

以下のコマンドで各スレッドが何をしているのかがわかる。(わかると言っても動作中の関数ぐらいのものだが、、)

info threads

他のスレッドに移ってスタックを確認するには以下のコマンドで切り替えることができる。

thread <スレッドID>

(gdb) info threads
  Id   Target Id                                  Frame 
* 1    Thread 0x7f1127df2740 (LWP 584) "main.out" 0x00005571e4c5c4d6 in main ()
(gdb) 

🌟 '*'がついている箇所が現在実行しているスレッドになる。
🌟 他のスレッドに移りたい場合はthread <スレッドId>で移動する

他いろいろ

gcc -g ~.c
(gdb) list
1   #include <stdio.h>
2
3   int main(){
4       for(int i =0 ; i < 5;i++){
5           printf("hello world\n");
6       }
7   }
8

GDBでint以外の関数を使う

print cos(0.0) #だめ
print (double)cos(0.0) #だめ

# 以下のようにすることで使える
set $p = (double (*)(double)) cos #1 cos関数を$pの変数で定義
ptype $p # 型確認コマンド(不要)
p $p(3.14159265) #ここで実行

GDBではsignalをハンドリングしている処理を扱う必要がある

こんな感じ ただし、本当に発生するシグナルも見落とすことになるので注意

# no~~ にどれぐらい種類があるのかは不明
handle SIGSEGV nostop noprint

GUIなどのウィンドウで動作するプログラムをデバッグする

courseで動作するプログラムのデバッグを想定する。 🚨先に起動したプロセスにattachする場合はいらない

(base)root@9ea233d8d241:~/Desktop/MyUtils# tty 
/dev/pts/1 # 🌟この出力をコピペしておく
(base)root@9ea233d8d241:~/Desktop/MyUtils# 
# 🌟 ttyコマンドで入出力先のコンソールを指定する
(gdb) tty /dev/pts/1 
(gdb) break main
(gdb) run
# 🌟printfコマンドを使えば出力先のコンソールに出力されることが確認できる
# プログラムの標準入力/出力も同様となる
(gdb) print printf("hello world\n") 
$3 = 12
(gdb) 

strace,ltraceを使ってみる

strace:システムコールに関して引数と返り値を表示してくれる
ltrace:ライブラリ関数の呼び出しについて表示してくれる

strace ./a.out
strace ./a.out -o <logfile> # logfileに出力してくれる
strace ./a.out -o <logfile> -ff # forkした子プロセスごとに logfile.xxxでプロセス番号付きで表示してくれる

マクロ/関数を定義する

マクロを定義する

define function1 //こんな感じでマクロを定義できる
printf $arg0,$arg1 //引数に最大10個まで取れる
continue
end

ブレークポイント・コマンドリスト

commands <breakpoint No>
silent // 余計な出力を減らせる
コマンド(printfや自作の関数など 基本的にC言語と同様に動く)
continue // breakで止まった後で再度動かしてくれる
end

.gdbinitファイルでマクロ、breakpoint設定を使い回す

gdb実行時に特定の初期化ファイルを指定するには

gdb -command=[初期化ファイル] [実行ファイル]

# コマンド履歴を保存する(~/.gdbinitに置くと自動で読み込まれる)
set history save on
set history size 10000
set history filename ~/.gdb_history

# 🌟1 .gdbinitに以下のようにブレークポイントを書いたり
break g

# 🌟2 .gdbinitに以下のようにマクロを書いたり。。
define function1 //こんな感じでマクロを定義できる
printf $arg0,$arg1 //引数に最大10個まで取れる
continue
end


アセンブラ関連

GDB_コマンドリスト



Assembla

機能名 レジスタ名(x86) レジスタ名(x64) 詳細
インストラクションポインタ eip rip プロセッサによって実行されようとしている現在の命令が格納されているアドレス
スタックポインタ esp rsp おそらくスタックフレームと対応するポインタ(引数の先頭?(いや、末尾か?))、スタックフレームの末端のポインタを格納する。
ベースポインタ ebp rbp 局所変数を参照するためのポインタ(stack フレームに格納された変数を参照するために使われる。)
ソースインデックス esi rsi  
ディティネーションインデックス edi    
アキュミュレータ eax    
カウンタ ecx    
データレジスタ edx    
ベースレジスタ ebx    


アセンブラ記法

;Intel記法
命令語 <操作対象>, <参照元>

;AT&T記法
;(数値であることを示すのに$,レジスタを示すのに%のプレフィックスをつける。)
命令語 <参照元>, <操作対象> 
;Intel記法
mov  ebx , eax ; eaxの値をebxに書き込む
mov [ebx], eax ; eaxの値をebxのアドレスの先に書き込む
mov [ebx+4], eax ; eaxの値を(ebx)のアドレス+4のアドレスに書き込む

;バイト数を指定して数値を扱う
; WORD(2byte) -> DWORD(4byte)
mov DWORD PTR eax , 0 ; eaxを(DWORD(4byte)で0にする)
;AT&T記法
mov %eax, %ebx  ; eaxの値をebxに書き込む
mov %eax, (%ebx); eaxの値をebxのアドレスの先に書き込む
mov %eax,4(%ebx); eaxの値をebxのアドレス+4のアドレスに書き込む

;バイト数を指定して数値を扱う
movl $5, %eax ; movlのlはlongを意味する。
addl   $0x1,-0x4(%rbp)

現在の実行位置を知るためのコマンド

 info registers rip
 i r rip

格納されたポインタの中身を表示する方法

表示内容 コマンド コマンド例
文字列表示 x/s <ポインタ> x/s x/s $rbp-0x20
プログラム上の変数表示 x/s <変数名> x/s str