iOS開発をしていてデバッグする際に、コピーしたり、"を外したりするのが地味にめんどくさいので作ってみました。
今回は、SwiftのStringをopenurl hogeのようなコマンドで開くのを目指します。(Swift以外でもほぼ同じです)
openurlコマンドの作成
コマンドの追加
コマンドの雛形はこちらです。(過去記事: LLDBからRxSwiftのdebugを仕込む - しおメモ)
このopenの中身を実装していきます。
#!/usr/bin/env python3 import lldb def open(debugger, exp, result, dict): # ... def __lldb_init_module(debugger, internal_dict): debugger.HandleCommand('command script add -f openurl.open openurl')
String値をPythonの変数に格納する
まずLLDBのstack frameを取得して、そこで該当の変数を評価してPython側の変数に格納します。
def evaluate(exp): value = ( lldb.debugger.GetSelectedTarget() .GetProcess() .GetSelectedThread() .GetSelectedFrame() .EvaluateExpression(exp) ) return value
ドキュメントを読む限りでは、lldb.frameで一発で取得できそうなのですが、実際にはinteractiveに動かした場合しか取得できなかったので、一つずつたどっています。
SBValueの変換
ここで取得したvalueは、SBValueというtypeなので、扱いやすい文字列に直していきます。
ドキュメントで不足している情報は、script helpで取得できます。
(とくにLLDBのPythonスクリプトに関してはあまり情報がないので、script helpやLLDB自体のドキュメントを見たほうが良いです)
(lldb) script help(lldb.SBValue)
こちらを見ると、GetValue()というchar const *を返すメソッドがあるのですが、こちらを使うと0x0000600000a1e610のような単なるアドレスの文字列が返ってきてしまうので、GetObjectDescription()を利用します。
value = evaluate(exp) url = value.GetObjectDescription().replace('"', '')
SwiftのStringの場合は"がついてしまうので外しておきます。
同様に、型名を取得することもできます。
typename = value.GetTypeName()
こちらはSwift.StringやFoundation.NSMutableStringといった文字列が入ります。
Pythonを利用してURLを開く
あとは、urllibやosなどのPythonの機能を利用します。
ブラウザを開くのに、macOSのopenコマンドを利用しています。
実装例は以下のとおりです。
def open(debugger, exp, result, dict): value = evaluate(exp) typename = value.GetTypeName() if typename not in ['Swift.String', 'Foundation.NSMutableString']: print('Incompatible type: ' + typename) return url = value.GetObjectDescription().replace('"', '') u = urlparse(url) if u.scheme in ['http', 'https']: os.system('open ' + url) else: print('Failed to open: ' + url)
subprocess.runなどではこの場合動かないので、os.systemを利用しています。
LLDB上で実行する
実際にスクリプトをロードして実行してみます。
let urlString: String = "https://www.google.com/"
(lldb) command script import ~/dotfiles/lldb/openurl.py (lldb) openurl urlString
実行すると、ブラウザで該当のURLが開かれます。
余談
StringからもQuick Lookで画像確認したいというモチベーションで、最初はdebugQuickLookObject()というメソッドを利用しようと思ったのですが、@objcが必須っぽかったので、こちらは断念しました。