Xcode
Swift
DWARF

SwiftのstructのメモリレイアウトサイズをdSYMから取り出す

More than 1 year has passed since last update.


環境

Xcode 8.3.2 (Swift 3.1)


動機

EXC_BAD_ACCESS on devices if nested structs are used with Xcode 8.3 and Swift 3.1

https://bugs.swift.org/browse/SR-4432

このバグを踏んだ。

コンパイルは通るがランタイムでその周辺を実行したときにクラッシュする系。(さいわい、最適化により回避されるので、デバッグ端末(しかもarm64に限る)でしか発生しない。)

内容は追っていないが、仮説としてstructのサイズが大きくなったとき、というのがあり、実際にBox化などでstructのサイズを減らすことで回避できた。

structサイズがトリガーとなる仮説に基づき、あるアプリで使っているstructを大きい順に並べたい。(4Kを超えているものがあればアプリ実行してみて確認したい)


メモリレイアウトサイズの取り出しかた

dSYMに含まれているDWARFファイルを dwarfdump する。

structのメモリサイズ順に並べる全部入りのワンライナー:

f=path-to-.dSYM/Contents/Resources/DWARF/*; for a in $(dwarfdump -arch arm64 "$f" | grep 'TAG_structure_type' | cut -f1 -d:); do dwarfdump --debug-info=$a $f | grep -E '(AT_name|AT_byte_size)' | paste -d, -s - | awk '{print strtonum($5) "\t" $2}'; done | sort -g | uniq


出力例

:

721 "_TtRTC..."
721 "_TtTC..."
1185 "_TtRTC..."
1185 "_TtTC..."
2134 "..."
2134 "Optional"
2139 "Result"
2139 "_TtRGO..."
4537 "..."
4537 "_TtRV..."

最大で4537バイトのstructがあることがわかる。

(nominal以外の合成型も出現する)


解説

ただのgrep,awk芸だが‥

dwarfdump すると含まれている各 TAG_* が出力される。

struct がほしいので TAG_structure_type だけ取り出す (でいいのか?)。

TAGの行にアドレスがあるので、それを各々 dwarfdump に渡して、 AT_nameAT_byte_size を取り出して1行にして awk 整形、ソートする。


課題

dwarfdumpTAG_structure_type でフィルタしてその AT_nameAT_byte_size だけ取り出したい、みたいなオプションの書き方は分からなかった。


demangle

結果表示のなかでmanglingされている名前を戻したい場合は swift-demangle を使う。

xcrun swift-demangle ...


他の方法


MemoryLayout<T>.size をつかう

なんらかの方法で T を収集し、デバッガで実行すればよいが、import が必要だったり、遅かったり、ある数以上実行すると返ってこなくなったりで、使いづらかった。

コード内で print(MemoryLayout<T>.size) するには、可視性の問題があった。


アプリの実行ファイル・frameworkのバイナリから取り出す

structのメモリレイアウトサイズは、実行バイナリに入っているのだろうか・・・?