gdbによるredisソースコードのデバッグと観察
8288 ワード
概要
この文書では、gdbを介してredisのソースコードをデバッグする方法について説明します.ソースコードを表示するだけでなく、gdbを介して実際のシーンでコードがどのように動作するか、メモリがどのように変化するかを観察することは、redis-serverの動作メカニズムを理解するために非常に必要である.redis-serverの一般的なコマンドの実行メカニズムのデバッグを行う場合は、c/c++プログラミングに精通する必要はありません.gdbの基本的なコマンドを知るだけでいいです.
gdb紹介
gdbでredis-serverをデバッグする場合は、基本的なgdbコマンドを知る必要があります.たとえば、ブレークポイントの作成方法、構造体の内容の印刷方法、サブプロセスの実行を追跡する方法などです.このセクションでは、redisの世界に入るための基本的なgdbコマンドについて説明します. gdbを先に起動し、実行コードを指定します(redis-serverは事前にコンパイルされています). $ gdb ./src/redis-server (gdb) gdb は、以下のコマンドで実行する.
コマンド名
機能
r
先ほどロードしたバイナリプログラムを実行し、パラメータを指定できます
b
ブレークポイント、後のパラメータは関数、または行数です.
n
単一ステップで実行しますが、関数には入りません.
s
単一ステップ実行、呼び出し関数へ
bt
現在の呼び出しスタックの表示(関数の呼び出しスタックと現在実行されている場所を表示するのに役立ちます)
l
コードを表示します.パラメータは関数名または行数です.
p
変数または構造体の値を印刷
他のコマンドはgdbマニュアルを表示できます.
gdbでredis-serverをデバッグする
redis-serverソースコードのコンパイル
redis-4.0.9をダウンロードし、解凍してredisディレクトリに入り、次のように直接makeします.
コンパイルされたバイナリはsrcで、redis-4.0.9ディレクトリの下にredisがあることに注意してください.confファイル.redis-serverを実行するときのプロファイルです.
注意:gdbでコードをデバッグする場合は、コンパイル時にgccの後に-g-ggdbというオプションを付ける必要があります.redis-serverのコンパイルオプションではデフォルトで追加されるので、直接makeでいいです.
コンパイルが完了したら、srcの下に、他にもいくつかの実行可能なファイルがコンパイルされているはずです.
本稿では、2つのredis-serverとredis-cliを使用します.
デバッグの開始
コードをコンパイルしてredis-serverのデバッグを始めました
gdbでsetコマンドの実行手順を表示する gdbによりredis-server を起動する
setコマンドの実行手順を表示するには、まずsetコマンドを実行する関数のエントリにブレークポイントを付けます.次に、この処理関数に入り、単一ステップで実行します.server.cコードには、コマンド処理のリスト関数があります.以下のようにします.
以上のコードからsetコマンドの実装関数はsetCommandであり、この関数の入り口にブレークポイントを打つことができます.
この場合、gdbはredis-serverの接続待ち場所をブロックします.redisクライアント接続サービス側がないため、redis-cliを起動し、setコマンドを送信する必要があります. redis-cli を起動
新しい端末を開き、redisをコンパイルしたばかりのディレクトリに入り、redis-cliを起動します. setコマンドの実行メカニズムをgdbのインタフェースで観察すると、コードはsetCommand関数エントリに実行されていることがわかります.gdb端末で実行スタックを表示する:
この関数に入り、次のステップで実行します.
関数の内部に入るには、sコマンドを直接使用します.
変数の値を印刷します.
コマンド処理の全プロセスに至るまで、processCommand関数にブレークポイントを打つことができます.そして、上記と同様にワンステップで実行します.
まとめ
本論文では,gdbを介してredis−serverをデバッグし,redis−serverの内部実行を観察する方法について述べた.しかし、マルチプロセスのデバッグなど、より複雑なgdbのデバッグテクニックについては説明していません.
この文書では、gdbを介してredisのソースコードをデバッグする方法について説明します.ソースコードを表示するだけでなく、gdbを介して実際のシーンでコードがどのように動作するか、メモリがどのように変化するかを観察することは、redis-serverの動作メカニズムを理解するために非常に必要である.redis-serverの一般的なコマンドの実行メカニズムのデバッグを行う場合は、c/c++プログラミングに精通する必要はありません.gdbの基本的なコマンドを知るだけでいいです.
gdb紹介
gdbでredis-serverをデバッグする場合は、基本的なgdbコマンドを知る必要があります.たとえば、ブレークポイントの作成方法、構造体の内容の印刷方法、サブプロセスの実行を追跡する方法などです.このセクションでは、redisの世界に入るための基本的なgdbコマンドについて説明します.
コマンド名
機能
r
先ほどロードしたバイナリプログラムを実行し、パラメータを指定できます
b
ブレークポイント、後のパラメータは関数、または行数です.
n
単一ステップで実行しますが、関数には入りません.
s
単一ステップ実行、呼び出し関数へ
bt
現在の呼び出しスタックの表示(関数の呼び出しスタックと現在実行されている場所を表示するのに役立ちます)
l
コードを表示します.パラメータは関数名または行数です.
p
変数または構造体の値を印刷
他のコマンドはgdbマニュアルを表示できます.
gdbでredis-serverをデバッグする
redis-serverソースコードのコンパイル
redis-4.0.9をダウンロードし、解凍してredisディレクトリに入り、次のように直接makeします.
cd redis-4.0.9
make
コンパイルされたバイナリはsrcで、redis-4.0.9ディレクトリの下にredisがあることに注意してください.confファイル.redis-serverを実行するときのプロファイルです.
注意:gdbでコードをデバッグする場合は、コンパイル時にgccの後に-g-ggdbというオプションを付ける必要があります.redis-serverのコンパイルオプションではデフォルトで追加されるので、直接makeでいいです.
コンパイルが完了したら、srcの下に、他にもいくつかの実行可能なファイルがコンパイルされているはずです.
redis-server: redis
redis-cli : redis
redis-benchmark
redis-sentinel
...
本稿では、2つのredis-serverとredis-cliを使用します.
デバッグの開始
コードをコンパイルしてredis-serverのデバッグを始めました
$ gdb src/redis-server
(gdb)
gdbでsetコマンドの実行手順を表示する
setコマンドの実行手順を表示するには、まずsetコマンドを実行する関数のエントリにブレークポイントを付けます.次に、この処理関数に入り、単一ステップで実行します.server.cコードには、コマンド処理のリスト関数があります.以下のようにします.
struct redisCommand redisCommandTable[] = {
{"module",moduleCommand,-2,"as",0,NULL,0,0,0,0,0},
{"get",getCommand,2,"rF",0,NULL,1,1,1,0,0},
{"set",setCommand,-3,"wm",0,NULL,1,1,1,0,0},
{"setnx",setnxCommand,3,"wmF",0,NULL,1,1,1,0,0},
{"setex",setexCommand,4,"wm",0,NULL,1,1,1,0,0},
... ...
以上のコードからsetコマンドの実装関数はsetCommandであり、この関数の入り口にブレークポイントを打つことができます.
//
(gdb) b setCommand
// redis-server
(gdb) r ./redis.conf
この場合、gdbはredis-serverの接続待ち場所をブロックします.redisクライアント接続サービス側がないため、redis-cliを起動し、setコマンドを送信する必要があります.
新しい端末を開き、redisをコンパイルしたばかりのディレクトリに入り、redis-cliを起動します.
cd redis-4.0.9/src
$ ./redis-cli
127.0.0.1:6379> set k1 "v123"
(gdb) bt
#0 setCommand (c=0x102016000) at t_string.c:102
#1 0x000000010000cd53 in call (c=0x102016000, flags=15) at server.c:2229
#2 0x000000010000d61e in processCommand (c=0x102016000) at server.c:2510
#3 0x000000010001dd76 in processInputBuffer (c=0x5b91a431) at networking.c:1354
#4 0x00000001000051ee in aeProcessEvents (eventLoop=0x1005289b0, flags=11) at ae.c:440
#5 0x000000010000552b in aeMain (eventLoop=0x5b91a431) at ae.c:498
#6 0x0000000100010680 in main (argc=1, argv=0x0) at server.c:3894
この関数に入り、次のステップで実行します.
(gdb) n
138 c->argv[2] = tryObjectEncoding(c->argv[2]); // : string value
関数の内部に入るには、sコマンドを直接使用します.
(gdb) s
tryObjectEncoding (o=0x100306600) at object.c:384
384 serverAssertWithInfo(NULL,o,o->type == OBJ_STRING);
変数の値を印刷します.
(gdb) p o
$1 = (robj *) 0x100306600 // o
//
(gdb) p *o
$2 = {type = 0, encoding = 8, lru = 9544752, refcount = 1, ptr = 0x100306613}
(gdb) p o->type
コマンド処理の全プロセスに至るまで、processCommand関数にブレークポイントを打つことができます.そして、上記と同様にワンステップで実行します.
まとめ
本論文では,gdbを介してredis−serverをデバッグし,redis−serverの内部実行を観察する方法について述べた.しかし、マルチプロセスのデバッグなど、より複雑なgdbのデバッグテクニックについては説明していません.