BioErrorLog Tech Blog

試行錯誤の記録

gdbをデフォルトでintel記法にする | 初期化処理の仕組み

gdbシンタックスをデフォルトでintel記法にする方法と、その仕組みを調べます。


はじめに

おはよう。@bioerrorlogです。

GNUデバッガgdbのアセンブラ表記はAT&T記法とintel記法の2つがあり、それぞれ見た目は次のようになっています。

  • AT&T記法
Dump of assembler code for function main:
   0x00000000000006da <+0>:  push   %rbp
   0x00000000000006db <+1>:  mov    %rsp,%rbp
   0x00000000000006de <+4>:  sub    $0x10,%rsp
   0x00000000000006e2 <+8>:  mov    %edi,-0x4(%rbp)
   0x00000000000006e5 <+11>: mov    %rsi,-0x10(%rbp)
   0x00000000000006e9 <+15>: cmpl   $0x2,-0x4(%rbp)


  • intel記法
Dump of assembler code for function main:
   0x00000000000006da <+0>:  push   rbp
   0x00000000000006db <+1>:  mov    rbp,rsp
   0x00000000000006de <+4>:  sub    rsp,0x10
   0x00000000000006e2 <+8>:  mov    DWORD PTR [rbp-0x4],edi
   0x00000000000006e5 <+11>: mov    QWORD PTR [rbp-0x10],rsi
   0x00000000000006e9 <+15>: cmp    DWORD PTR [rbp-0x4],0x2

intel記法のほうが右の部分がスッキリしていて見やすいので、私はintel記法のほうが好きです。

しかし、gdbはデフォルトではAT&T記法に設定されているため、intel記法に変更するには次のコマンドを打つ必要があります1

(gdb) set disassembly-flavor intel

gdbを立ち上げるたびに毎回このコマンドを打つのは面倒です。

そこで、デフォルトでintel記法に設定する方法とその仕組みを調べました。


作業環境

Ubuntu18.04.1 LTS を
Windows10の上に、VMwareによって構築した仮想環境で起動しています。
www.bioerrorlog.work


gdbをデフォルトでintel記法にする

ホームディレクトリ直下で".gdbinit"にコマンドを書き込む

やり方を検索してみると、すでに多くの方々が解決策を示していました。

gdbで初期設定をAT&T記法からIntel記法に変更する方法 | サラリーマンがハッカーを真剣に目指す

ホームディレクトリに".gdbinit"というファイルを作成し、そこに実行させたいコマンドを書き込むだけでいいようです。 さっそく".gdbinit"を作成し、

set disassembly-flavor intel

とだけ書き込みました。 これを保存し、gdbで確認すると、

(gdb) disas main
Dump of assembler code for function main:
   0x00000000000006da <+0>:  push   rbp
   0x00000000000006db <+1>:  mov    rbp,rsp
   0x00000000000006de <+4>:  sub    rsp,0x10
   0x00000000000006e2 <+8>:  mov    DWORD PTR [rbp-0x4],edi
   0x00000000000006e5 <+11>: mov    QWORD PTR [rbp-0x10],rsi
   0x00000000000006e9 <+15>: cmp    DWORD PTR [rbp-0x4],0x2

たしかにデフォルトでintel記法になっており、ひとまず目的を達成しました。

しかし、なぜ".gdbinit"というファイル名が認識され、コマンドが自動で実行されるのでしょうか。

まるで見当がつきません。 ここを調べていきます。


[関連記事] 逆アセンブル解析 - gdb | リバースエンジニアリング入門#2


"."からはじまるドットファイルの意味

まずは、"."からはじまるファイル(ドットファイル)の意味について。

前々から、lsコマンドではドットファイルは表示されず、ls -aとしなければ表示されないことは経験として認識していましたが、その意味はいまいち分かりませんでした。 このドットファイルが隠しファイルである理由については、面白い情報があったので添えておきます。

Unix系の隠しファイルの仕組みは開発者のポカから生まれた悪習だった - Qiita


次に、ドットファイルの役割について調べてみました。 すると、ドットファイルは設定を書き込んで読み込ませるためのファイルとして利用されるようです2。 まさに今回".gdbinit"で行ったような用途で使われるというわけです。

しかし、このドット自体に何か特別な機能が付与されているわけではなく、あくまで設定ファイルを取り扱うための表記のようです。 これだけでは、".gdbinit"というファイルがgdbによって実行される理由にはなりません。

gdbドキュメントから調べる

わからなくなったときは、公式のドキュメントやマニュアルを読むのが結局一番早い、というのが私の経験則です。 gdbについては、オンラインドキュメントがありました。

Debugging with GDB

これを調べてみると、gdbの初期化処理についての記述がありました。 まとめると、次のように39つの初期化処理が順番に実行されるようです。

2.1.3 What GDB Does During Startup
Here’s the description of what GDB does during session startup:

1. Sets up the command interpreter as specified by the command line.
2. Reads the system-wide init file and executes all the commands in that file.
3. Reads the init file in your home directory and executes all the commands in that file.
4. Executes commands and command files specified by the ‘-iex’ and ‘-ix’ options in their specified order.
5. Processes command line options and operands.
6. Reads and executes the commands from init file in the current working directory.
7. If the command line specified a program to debug, or a process to attach to, or a core file, GDB loads any auto-loaded scripts provided for the program or for its loaded shared libraries.
8. Executes commands and command files specified by the ‘-ex’ and ‘-x’ options in their specified order.
9. Reads the command history recorded in the history file.

ここで着目すべきは3番目の処理です。

3. Reads the init file in your home directory and executes all the commands in that file.

ホームディレクトリにある初期化ファイルを読み込み、コマンドをすべて実行する、とあります。 まさしく、今回私は".gdbinit"をホームディレクトリに置いたので、この処理過程において実行されたというのであれば、納得がいきます。 あとは、".gdbinit"が初期化ファイルとしてgdbに認識されていればいい訳です。

初期化ファイルの定義について調べてみると、いくつか記述を見つけました。

2.1.3 What GDB Does During Startup
~
The GDB init files are normally called .gdbinit.

または、

2.1.2 Choosing Modes
~
~/.gdbinit
This is the init file in your home directory.

など。

ここまでわかってくれば、さすがに納得できます。

整理すると以下のようになります。

  • gdb初期化処理は9つのステップが用意されている。
  • そのうち3つ目のステップではホームディレクトリ直下の初期化ファイルが処理される。
  • ホームディレクトリ直下の初期化ファイルは".gdbinit"という名前を持つことになっている。


おわりに

gdbをデフォルトでintel記法にする方法と、その仕組みを記録しました。

今回行った方法はホームディレクトリ直下に".gdbinit"を置くやり方ですが、面白いのはこれ以外にも8つの初期化ステップがgdbに用意されているということです。 Google検索でヒットする解決策が概ねひとつの方法に収束されている今回のような場合でも、ドキュメントを辿ってみるとそれ以外の多くのやり方が開発者から用意されている、というのはなかなか奥ゆかしいことです。

とはいえ、多くの方々が実践しているやり方というのが、最も効率的な方法である場合がほとんどでしょう。 効率性と好奇心のバランスを、上手いこと回すのが大切かもしれません。


参考

Debugging with GDB

DotFiles - Debian Wiki

Dotfiles - ArchWiki

gdbで初期設定をAT&T記法からIntel記法に変更する方法 | サラリーマンがハッカーを真剣に目指す

Unix系の隠しファイルの仕組みは開発者のポカから生まれた悪習だった - Qiita


  1. 逆アセンブル解析 - gdb | リバースエンジニアリング入門#2 - 生物系がゼロから始めるTech Blogも参考に。

  2. DotFiles - Debian WikiまたはDotfiles - ArchWikiなど

  3. 原文からここで不要と思われる部分をカットして載せています。