Xcode 5のデバッガとして用意されているLLDBですが、実は設定ファイルを書くことで自由にカスタマイズすることが可能になっています。またPythonを使ってより深いLLDB自体の挙動をカスタマイズすることも出来るらしいと最近教えてもらいました。
参考: http://qiita.com/dealforest/items/e3a5284badd17733ccc1
さてこちらの参考記事に、
例えば動的に生成した UIImage をファイルに出力するコマンドとかは便利そうですね。というなかなか夢のある発言があるのですが、残念ながらこちらの記事の中では実際のコードがありません。ということでLLDBの設定の練習がてら、私の方で早速デバッガからUIImageをファイルに書き出すコマンドの作成にチャレンジしてみました。
■実装方針
LLDBを操作するために使用できるPythonモジュールについては、LLDBの公式ページに詳しいドキュメントが揃っています。
http://lldb.llvm.org/python-reference.html (簡単な解説とチュートリアル)
http://lldb.llvm.org/python_reference/ (APIドキュメント)
また既に何人かの方が似たようなことをされた形跡があります。
http://stackoverflow.com/questions/12668815/lldb-python-access-of-ios-variables
http://stackoverflow.com/questions/18468126/pointer-arithmetic-in-lldb-python-scripts
http://lists.cs.uiuc.edu/pipermail/lldb-dev/2011-January/000321.html
これを元にして、以下の様な戦略でいってみます。
冒頭の画像にもあるのですが、Python経由でexprした実行結果を取得する手段がどうにも見つかりません。
うーん。もう少し頑張ったらうまくいきそうな気もするのですが。残念です><
http://lldb.llvm.org/python-reference.html (簡単な解説とチュートリアル)
http://lldb.llvm.org/python_reference/ (APIドキュメント)
また既に何人かの方が似たようなことをされた形跡があります。
http://stackoverflow.com/questions/12668815/lldb-python-access-of-ios-variables
http://stackoverflow.com/questions/18468126/pointer-arithmetic-in-lldb-python-scripts
http://lists.cs.uiuc.edu/pipermail/lldb-dev/2011-January/000321.html
これを元にして、以下の様な戦略でいってみます。
- 引数のUIImageを
UIImagePNGRepresentation
関数を通してNSDataにする。 - ただのUIImageをそのままファイルに書き出しても使えませんので、まず一旦JPEGなりPNGなりに変換する必要があります。ここではObjective-C側に変換してもらうことにします。
- NSData bytesを取得する。
expr (const void *)[(NSData *)UIImagePNGRepresentation(image) bytes]
とか叩けば一発なはずなので、その方針で行きます。- ファイルに書き出す。
- exprの結果をraw dataで取り出せれば、あとは普通にファイルに書き出しておしまいです。簡単そうですね。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 | |
import lldb | |
import commands | |
import os | |
def save_image(debugger, command, result, internal_dict): | |
# Generate a PNG representation NSData of specified UIImage into current frame | |
expr = "(const void *)[(NSData *)UIImagePNGRepresentation("+ command +") bytes]" | |
# Get raw data from current frame | |
# TODO: how can we retrieve the result of commands as variable? | |
# HandleCommand can return SBCommandReturnObject but it doesn't behave as an SBValue | |
# - http://lldb.llvm.org/python_reference/lldb.SBDebugger-class.html | |
# - http://lldb.llvm.org/python_reference/lldb.SBCommandInterpreter-class.html | |
# - http://lldb.llvm.org/python_reference/lldb.SBCommandReturnObject-class.html | |
# If we could retrieve the result of commands as frame.locals, frame.variables or frame.arguments then it's pretty easy to get raw data from it by using lldb.process.ReadMemory | |
# - http://lldb.llvm.org/python_reference/lldb.SBFrame-class.html | |
# - http://lldb.llvm.org/python_reference/lldb.SBValue-class.html | |
# - http://stackoverflow.com/questions/12668815/lldb-python-access-of-ios-variables | |
# - http://stackoverflow.com/questions/18468126/pointer-arithmetic-in-lldb-python-scripts | |
# Perhaps this example, using frame.EvaluateExpression and expression.GetValue(), could help so I'm trying with this method | |
# - http://lldb.llvm.org/python_reference/lldb.SBFrame-class.html#EvaluateExpression | |
# - http://lists.cs.uiuc.edu/pipermail/lldb-dev/2011-January/000321.html | |
print expr | |
val = lldb.frame.EvaluateExpression(expr) | |
err = lldb.SBError() | |
print val | |
print val.addr | |
print val.load_addr | |
print val.size | |
print val.data | |
print val.GetError() | |
print val.GetError().Success() | |
rawdata = val.data.GetString(err, 0) | |
# Save it to disk | |
with open(os.path.expanduser("~/.lldb/saved_image.png"), "wb") as fp: | |
fp.write(rawdata) | |
def __lldb_init_module(debugger,internal_dict): | |
debugger.HandleCommand("command script add -f save_image.save_image save_image") | |
print"save_image command enabled." | |
■しかし
やはりというか落とし穴がorz冒頭の画像にもあるのですが、Python経由でexprした実行結果を取得する手段がどうにも見つかりません。
SBFrame.EvaluateExpression(expr)
の結果がSBValueなんだからそっからデータが引けるだろうと思っていたのですが、何を実行しても壊れたSBValueしか返却されないためどうにもうまくいきません。SBDebuggerやSBCommandInterpreter経由でHandleCommand(expr, result)
する手も考えたのですが、今度はresultから値を取る手段がない(resultをコンソールではなくファイルにリダイレクトする手段しか無い)ためやはり断念です・・・うーん。もう少し頑張ったらうまくいきそうな気もするのですが。残念です><