プログラミング

【C言語】デバッグのテクニック(標準関数のスタブ作成、動的ライブラリのデバッグ方法)

【※ 当記事は2020年6月29日時点の情報です】

ペイヴメント(@pavement1234)です。

エンジニア
エンジニア
「標準関数のスタブ作成」「動的ライブラリのデバッグ方法」など。
中級向けC言語のデバッグテクニックを知りたい。

バージョン情報
Windows10 Home(64bit)1903
VMware Player 15 もしくは Virtual Box 6.1 で動くUbuntu18.04

標準関数のスタブ作成方法がわかる

インターポジショニング(関数の上書き)

やり直しC言語:インターポジショニングによるtime(3)のスタブ化を参考にしました。
time関数(実行する度に結果が変わる関数)を題材にしています。
まずこういうコードを単体試験しようとすると、
時間が毎回変わるので一定の結果は得られません。

コンパイルして実行。
現在のUNIX時間(数値)が表示されます。

$ gcc -g -o main main.c
$
$ ./main
$ 1555888123

常に0を返すtime関数のスタブを作ってみました。

コンパイルして実行。
常に0が返ります。

$ gcc -g -o main2 main2.c
$
$ ./main2
$ 0

main.cとstub.cを分離します。

stub.cを共有ライブラリとしてビルドして、main.cと動的リンクさせます。
しかしこのまま実行すると共有ライブラリが見つからないというエラーが出ます。

$ gcc -shared -fPIC -o libstub.so stub.c
$ gcc -I./ -L./ -g -o main main.c -lstub
$ ./main
$ ./main: error while loading shared libraries: libstub.so: cannot open shared object file: No such file or directory

LD_LIBRARY‗PATHに、libstub.soのあるパスを指定することで、
無事スタブ共有ライブラリを見つけることが出来ました。

$ export LD_LIBRARY_PATH=<libstub.soがあるディレクトリ>
$ ./main
$ 0

標準関数をローカル関数で再定義することをインターポジショニングと呼ぶそうです。
単体試験に使えそうですね。
余談ですがUNIX時間(数値)を年月日時分秒に変換できる
UNIX時間変換ツール
が便利です。

動的ライブラリ(*.so)のデバッグ手法

デバッグ対象の動的ライブラリ(*.so)を構築

まずプログラムはこんな感じ。

コンパイルはこう(-sharedで共有ライブラリ指定。
-fPICでPosition Independent Codeを指定)。

$ gcc -shared -fPIC -o libdltest.so dltest.c

デバッグ用ドライバー(呼び出しプログラム)の作成

こんな感じです。
Man page of DLOPEN
などを見ると色々オプションがありますが今日は深く考えない。
ポイントはシンボル名を指定してdlsymを呼ぶと関数ポインタが得られるということ。

コンパイルはこう(-ldlでlibdl.soをリンクします)。

$ gcc -g -o main main.c -ldl

実行する。

$ ./main
$ func1
$ func2(123)
$ func3(abcde)

関数ポインタ

久々に関数ポインタを使いました。
忘れないように覚え書きしておきます。

関数プロトタイプのようにも見えますが
あくまでも関数ポインタ変数の定義です。
変数名はfunc1、
戻り値と引数を定義します。

int( *func1 )( void );

dlsymの戻り値(関数ポインタ)をfunc1に代入するときは、
このようにキャストします。

func1 = ( int (*)( void ) )dlsym( handle, “func1” );

呼び出しはこんな感じ。
func1();でも呼べるけど、
関数ポインタであることを明示しておいた方がいいです。

( *func1 )();

応用編ですが関数ポインタは配列にできます。

コンパイルして実行するとこんな感じ。

$ gcc -g -o func_ptr_array func_ptr_array.c
$ ./func_ptr_array
$ test1
$ test2
$ test3

まとめ

C言語のデバッグテクニックとして
「標準関数のスタブ作成」
「動的ライブラリのデバッグ方法」をご紹介しました。
最近プログラムをたくさん書いてなかったので、
デバッグの効率化のテクニックを忘れ始めてました。
ちょこちょこ自分で手を動かして、カンを鈍らせないようにしたいと思います。

ABOUT ME
ペイヴメント
ペイヴメントのエンジニア塾(当ブログ)では20年以上の経験から得られたプログラミング系ノウハウについてベテランにも満足して頂けるような内容の濃いコンテンツを初心者にも分かりやすい形で日々発信しています。【経歴】ベンチャーのソフトハウスで4年勤務後、精密機器メーカーのソフト開発部門に勤務し今に至ります。
error: Content is protected !!