この記事は アドベントカレンダー2025 13日目の記事です
こんにちは。24Bの zoi_dayo です。普段はゲームを作ったり競技プログラミングをしたりいろいろしています。
講義の環境構築をしていたところ、変なところで引っかかってしまったので備忘録として残しておきます。 ブログのネタが思いつかなかったとかそういうわけではないです
TL;DR
gdb使用時に Couldn't get registers: Input/output error. のようなエラーが発生する場合、gdbの代わりに以下のシェルスクリプトを利用すると解決する可能性があります。
#!/bin/bash
if [ "$#" -lt 1 ]; then
echo "Usage: $0 <path/to/program> [gdb-args...]" >&2
exit 1
fi
prog="$1"
shift
ROSETTA_DEBUGSERVER_PORT=1234 "$prog" &
/usr/bin/gdb \
-iex "set architecture i386:x86-64" \
-iex "file $prog" \
-iex "target remote localhost:1234" \
-iex "set history save on" \
"$@"
はじめに
皆さんmacbookは使っているでしょうか。
同性能帯のWindows機に比べめちゃくちゃ軽く、また電池持ちが良い気がしている (未検証) ので、毎日大学に持ち運ぶコンピュータとしては最強だと思っています。ディスプレイの発色もいいしキーボードもトラックパッドも使いやすい。
とくに弊学の情報理工学院では少し前まで計算機室がmacであったこと (現在はWindowsとUbuntuのデュアルブートに変更されています) もあり、mac使用率が50%を超えていた記憶があります。
弊学の情報理工学院 情報工学系では、2年次に「アセンブリ言語」という授業を受けることになります。この講義では x86_64 を対象に、最低限アセンブリの読み書きができるようになることを目指します。 (というよりは「根本はこうやって動いているよ」という紹介かもしれませんが)
ここで問題があります。いま流通しているmacbookはarmというシリーズ (アーキテクチャ) のCPUを積んでおり、この上では x86_64 向けのアセンブリ・機械語は動作しません。つまり、手元で動作確認が出来ないということです。これは困ります。
そのため、UTMなどの仮想環境を利用して講義の作業を進めている人が多そうでした。UTMを利用すると x86_64 のエミュレーションを行うことが可能で、これにより通常の x86_64 Linux 環境で作業を進めることが出来ます。
Devcontainerという選択肢
このように仮想環境を立ち上げて作業をしてもよいのですが、僕は以下の理由から仮想環境ではなくdevcontainerを利用して作業を進めることにしました。
- 仮想環境にOSを丸ごと入れるのはディスク容量を食う
- 当時、ディスクの空き容量が10GB以下というギリギリの環境で生活していたため
- Ubuntuのセットアップが面倒
- ユーザー名とかタイムゾーンとかいちいち設定したくない
- 環境がテキストで記述できるため、破壊しても修復しやすい
思いついたらやるだけなので、やります。まず以下のような devcontainer.json を作成し...
{
"name": "Ubuntu",
"build": {
"dockerfile": "Dockerfile"
},
"customizations": {
"vscode": {
"extensions": [
"ms-vscode.cpptools",
"ms-vscode.cpptools-extension-pack"
]
}
}
}
最低限の Dockerfile を書いてあげれば、もう使えるようになっています。
FROM --platform=linux/x86_64 ubuntu:24.04
RUN apt update && apt upgrade -y && apt install -y build-essential gdb git
ポイントはDockerfileの --platform 指定です。ほとんどの人はDocker Desktop経由でDockerを利用していると思いますが、ここでアーキテクチャを指定すると Docker Desktop が勝手にRosetta2を利用して仮想化してくれるんですね。Rosetta2を使っているので動作もサクサクです。
gdbが使えない
作業をしていると、このコンテナ内で gdb a.out が上手く動かないことに気が付きました。 Couldn't get registers: Input/output error. みたいなエラーが出ます。原因はおおよそ自明で、変な環境構築をしているからです。
今回問題になったのは、CPUエミュレーションをRosetta2に任せたところでした。Rosetta2は x86_64 の機械語を実行前/実行中に arm に書き換え、arm cpu上での快適な動作を可能にする技術です。このような仲介を噛ませているので、CPUのレジスタレベルで読み書きをするデバッガとは相性が悪いということだと思います。
色々調べた結果、以下のgithub issueにたどり着きました。
この記事を執筆している時点ではまだOpenなので修正されていないのだと思います。コメントによると、環境変数 ROSETTA_DEBUGSERVER_PORT を指定してあげることで、デバッグ対象のプログラム→Rosetta2→gdb というようにデータが送られるようになり、Rosetta2環境下でもデバッガの実行ができるようです。
まず、そんな環境変数の設定を毎回やるのは面倒なのでシェルスクリプトを作成しましょう。やっと TL;DR の内容になりました。
#!/bin/bash
if [ "$#" -lt 1 ]; then
echo "Usage: $0 <path/to/program> [gdb-args...]" >&2
exit 1
fi
prog="$1"
shift
ROSETTA_DEBUGSERVER_PORT=1234 "$prog" &
/usr/bin/gdb \
-iex "set architecture i386:x86-64" \
-iex "file $prog" \
-iex "target remote localhost:1234" \
-iex "set history save on" \
"$@"
これを gdb.sh というような名前で保存し、 chmod +x ./gdb.sh などとして実行権限を与えておきます。あとはいつも gdb hoge と打っているところを ./gdb.sh hoge に置き換えて実行すればいいだけです。
ただし、target remoteでつなげている関係上、実行開始 (再開?) は run ではなく continue になっています。
これで (少なくとも僕が触ってみた範囲では) それなりにまともに動いていそうです。めでたしめでたし。
おわり
Docker DesktopのVMで利用する仮想化技術は設定から変更できるはずなので、設定をいじっている人はこの記事のとおりには動かないかもです...! すみません
それはそれとして、Rosetta 2とかいう素晴らしい技術なんですがあと1,2年くらいで終了するらしいですね...??? めちゃくちゃお世話になっているので現状のまま置いておいてもらいたい気持ちが強いですが、Intel macがほぼほぼ根絶されたというのもまた事実なのでいつまでも不要なアプリを載せておくわけには行かないという判断なんですかね 悲しい...
明日は @ikura-hamu さん、 @haruka1012 さんの記事が投稿される予定です。たのしみ〜
