gdbシンタックスをデフォルトでintel記法にする方法と、その仕組みを調べます。
はじめに
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"にコマンドを書き込む
やり方を検索してみると、すでに多くの方々が解決策を示していました。
ホームディレクトリに".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系の隠しファイルの仕組みは開発者のポカから生まれた悪習だった #Linux - Qiita
次に、ドットファイルの役割について調べてみました。 すると、ドットファイルは設定を書き込んで読み込ませるためのファイルとして利用されるようです2。 まさに今回".gdbinit"で行ったような用途で使われるというわけです。
しかし、このドット自体に何か特別な機能が付与されているわけではなく、あくまで設定ファイルを取り扱うための表記のようです。 これだけでは、".gdbinit"というファイルがgdbによって実行される理由にはなりません。
gdbドキュメントから調べる
わからなくなったときは、公式のドキュメントやマニュアルを読むのが結局一番早い、というのが私の経験則です。 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検索でヒットする解決策が概ねひとつの方法に収束されている今回のような場合でも、ドキュメントを辿ってみるとそれ以外の多くのやり方が開発者から用意されている、というのはなかなか奥ゆかしいことです。
とはいえ、多くの方々が実践しているやり方というのが、最も効率的な方法である場合がほとんどでしょう。 効率性と好奇心のバランスを、上手いこと回すのが大切かもしれません。
参考
- Top (Debugging with GDB)
- DotFiles - Debian Wiki
- dotfiles - ArchWiki
- Unix系の隠しファイルの仕組みは開発者のポカから生まれた悪習だった #Linux - Qiita
- 逆アセンブル解析 - gdb | リバースエンジニアリング入門#2 - BioErrorLog Tech Blogも参考に。↩
- DotFiles - Debian Wikiまたはdotfiles - ArchWikiなど↩
- 原文からここで不要と思われる部分をカットして載せています。↩