dis —Pythonバイトコードの逆アセンブラ
ソースコード: :source: `Lib / dis.py`
dis モジュールは、CPython bytecode を逆アセンブルすることで分析をサポートします。 このモジュールが入力として受け取るCPythonバイトコードは、ファイルInclude/opcode.h
で定義され、コンパイラーとインタープリターによって使用されます。
例:関数myfunc()
が与えられた場合:
def myfunc(alist):
return len(alist)
次のコマンドを使用して、myfunc()
の逆アセンブリを表示できます。
>>> dis.dis(myfunc)
2 0 LOAD_GLOBAL 0 (len)
2 LOAD_FAST 0 (alist)
4 CALL_FUNCTION 1
6 RETURN_VALUE
(「2」は行番号です)。
バイトコード分析
バージョン3.4の新機能。
バイトコード分析APIを使用すると、Pythonコードの一部を Bytecode オブジェクトにラップして、コンパイルされたコードの詳細に簡単にアクセスできます。
- class dis.Bytecode(x, *, first_line=None, current_offset=None)
関数、ジェネレーター、非同期ジェネレーター、コルーチン、メソッド、ソースコードの文字列、またはコードオブジェクト( compile()によって返される)に対応するバイトコードを分析します。
これは、 Bytecode インスタンスを反復処理すると、 Instruction インスタンスとしてバイトコード操作が生成されるため、以下にリストされている多くの関数、特に get_instructions()の便利なラッパーです。 。
first_line が
None
でない場合は、逆アセンブルされたコードの最初のソース行について報告する必要がある行番号を示します。 それ以外の場合、ソース行情報(存在する場合)は、逆アセンブルされたコードオブジェクトから直接取得されます。current_offset が
None
でない場合は、逆アセンブルされたコードの命令オフセットを参照します。 これを設定すると、 dis()は、指定されたオペコードに対して「現在の命令」マーカーを表示します。- classmethod from_traceback(tb)
指定されたトレースバックから Bytecode インスタンスを構築し、 current_offset を例外の原因となる命令に設定します。
- codeobj
コンパイルされたコードオブジェクト。
- first_line
コードオブジェクトの最初のソース行(利用可能な場合)
- dis()
バイトコード操作のフォーマットされたビューを返します( dis.dis()によって出力されるのと同じですが、複数行の文字列として返されます)。
- info()
code_info()のように、コードオブジェクトに関する詳細情報を含むフォーマットされた複数行の文字列を返します。
バージョン3.7で変更:これにより、コルーチンおよび非同期ジェネレーターオブジェクトを処理できるようになりました。
例:
>>> bytecode = dis.Bytecode(myfunc)
>>> for instr in bytecode:
... print(instr.opname)
...
LOAD_GLOBAL
LOAD_FAST
CALL_FUNCTION
RETURN_VALUE
分析機能
dis モジュールは、入力を目的の出力に直接変換する次の分析関数も定義します。 これらは、単一の操作のみが実行されている場合に役立つ可能性があるため、中間分析オブジェクトは役に立ちません。
- dis.code_info(x)
提供された関数、ジェネレーター、非同期ジェネレーター、コルーチン、メソッド、ソースコード文字列、またはコードオブジェクトの詳細なコードオブジェクト情報を含む、フォーマットされた複数行の文字列を返します。
コード情報文字列の正確な内容は実装に大きく依存し、PythonVMまたはPythonリリース間で任意に変更される可能性があることに注意してください。
バージョン3.2の新機能。
バージョン3.7で変更:これにより、コルーチンおよび非同期ジェネレーターオブジェクトを処理できるようになりました。
- dis.show_code(x, *, file=None)
提供された関数、メソッド、ソースコード文字列、またはコードオブジェクトの詳細なコードオブジェクト情報をファイル(またはファイルが指定されていない場合は
sys.stdout
)に出力します。これは
print(code_info(x), file=file)
の便利な省略形であり、インタプリタプロンプトでのインタラクティブな探索を目的としています。バージョン3.2の新機能。
バージョン3.4で変更: file パラメーターが追加されました。
- dis.dis(x=None, *, file=None, depth=None)
x オブジェクトを逆アセンブルします。 x は、モジュール、クラス、メソッド、関数、ジェネレーター、非同期ジェネレーター、コルーチン、コードオブジェクト、ソースコードの文字列、または生のバイトコードのバイトシーケンスのいずれかを表すことができます。 モジュールの場合、すべての関数を分解します。 クラスの場合、すべてのメソッド(クラスメソッドと静的メソッドを含む)を分解します。 コードオブジェクトまたは生のバイトコードのシーケンスの場合、バイトコード命令ごとに1行を出力します。 また、ネストされたコードオブジェクト(内包表記、ジェネレータ式、ネストされた関数のコード、およびネストされたクラスの構築に使用されるコード)を再帰的に分解します。 文字列は、最初に compile()組み込み関数を使用してコードオブジェクトにコンパイルされてから、逆アセンブルされます。 オブジェクトが指定されていない場合、この関数は最後のトレースバックを逆アセンブルします。
逆アセンブリは、提供されている場合は指定された file 引数に、そうでない場合は
sys.stdout
にテキストとして書き込まれます。再帰の最大深度は、
None
でない限り、 depth によって制限されます。depth=0
は、再帰がないことを意味します。バージョン3.4で変更: file パラメーターが追加されました。
バージョン3.7で変更:再帰的逆アセンブルを実装し、 depth パラメーターを追加しました。
バージョン3.7で変更:これにより、コルーチンおよび非同期ジェネレーターオブジェクトを処理できるようになりました。
- dis.distb(tb=None, *, file=None)
何も渡されなかった場合は最後のトレースバックを使用して、トレースバックのスタックの最上位関数を逆アセンブルします。 例外の原因となった命令が表示されます。
逆アセンブリは、提供されている場合は指定された file 引数に、そうでない場合は
sys.stdout
にテキストとして書き込まれます。バージョン3.4で変更: file パラメーターが追加されました。
- dis.disassemble(code, lasti=- 1, *, file=None)
dis.disco(code, lasti=- 1, *, file=None) lasti が指定されている場合は、最後の命令を示すコードオブジェクトを逆アセンブルします。 出力は次の列に分割されます。
各行の最初の命令の行番号
-->
として示される現在の命令、>>
で示される、ラベル付きの命令、命令のアドレス、
操作コード名、
動作パラメータ、および
括弧内のパラメーターの解釈。
パラメータの解釈は、ローカルおよびグローバル変数名、定数値、分岐ターゲット、および比較演算子を認識します。
逆アセンブリは、提供されている場合は指定された file 引数に、そうでない場合は
sys.stdout
にテキストとして書き込まれます。バージョン3.4で変更: file パラメーターが追加されました。
- dis.get_instructions(x, *, first_line=None)
提供された関数、メソッド、ソースコード文字列、またはコードオブジェクトの命令に対してイテレータを返します。
イテレータは、提供されたコードの各操作の詳細を示す一連の Instruction 名前付きタプルを生成します。
first_line が
None
でない場合は、逆アセンブルされたコードの最初のソース行について報告する必要がある行番号を示します。 それ以外の場合、ソース行情報(存在する場合)は、逆アセンブルされたコードオブジェクトから直接取得されます。バージョン3.4の新機能。
- dis.findlinestarts(code)
このジェネレーター関数は、コードオブジェクト code の
co_firstlineno
およびco_lnotab
属性を使用して、ソースコードの行の始まりであるオフセットを見つけます。 それらは(offset, lineno)
ペアとして生成されます。co_lnotab
形式とそのデコード方法については、:source: `Objects / lnotab_notes.txt` を参照してください。バージョン3.6で変更:行番号が減少する可能性があります。 以前は、常に増加していました。
- dis.findlabels(code)
- ジャンプターゲットである生のコンパイル済みバイトコード文字列 code 内のすべてのオフセットを検出し、これらのオフセットのリストを返します。
- dis.stack_effect(opcode, oparg=None, *, jump=None)
引数 oparg を使用して opcode の煙突効果を計算します。
コードにジャンプターゲットがあり、 jump が
True
の場合、 stack_effect()はジャンプの煙突効果を返します。 ジャンプがFalse
の場合、ジャンプしないという煙突効果を返します。 また、ジャンプがNone
(デフォルト)の場合、両方の場合の最大の煙突効果を返します。バージョン3.4の新機能。
バージョン3.8で変更: jump パラメーターが追加されました。
Pythonバイトコード命令
get_instructions()関数と Bytecode クラスは、 Instruction インスタンスとしてバイトコード命令の詳細を提供します。
- class dis.Instruction
バイトコード操作の詳細
- opcode
以下にリストされているオペコード値およびオペコードコレクションのバイトコード値に対応する操作用の数値コード。
- opname
操作のための人間が読める名前
- arg
操作に対する数値引数(存在する場合)、それ以外の場合は
None
- argval
解決されたarg値(わかっている場合)、それ以外はargと同じ
- argrepr
人間が読める形式の操作引数の説明
- offset
バイトコードシーケンス内で操作のインデックスを開始します
- starts_line
このオペコード(存在する場合)で始まる行、それ以外の場合は
None
- is_jump_target
True
他のコードがここにジャンプする場合、それ以外の場合はFalse
バージョン3.4の新機能。
Pythonコンパイラは現在、次のバイトコード命令を生成します。
一般的な手順
単項演算
単項演算はスタックの最上位を取り、演算を適用して、結果をスタックにプッシュバックします。
二項演算
二項演算は、スタックの最上位(TOS)と2番目に上位のスタック項目(TOS1)をスタックから削除します。 それらは操作を実行し、結果をスタックに戻します。
インプレース操作
インプレース操作は、TOSとTOS1を削除し、結果をスタックにプッシュバックするという点でバイナリ操作に似ていますが、TOS1がサポートしている場合、操作はインプレースで実行され、結果のTOSは次のようになります(ただし、 )オリジナルのTOS1。
コルーチンオペコード
その他のオペコード
:opcode: `SET_ADD` 、:opcode:` LIST_APPEND` 、:opcode: `MAP_ADD` のすべての命令について、付加値またはキー/ valueペアがポップオフされ、コンテナオブジェクトはスタックに残り、ループのさらなる反復に使用できるようになります。
次のすべてのオペコードは、引数を使用します。
オペコードコレクション
これらのコレクションは、バイトコード命令の自動イントロスペクションのために提供されています。
- dis.opname
- バイトコードを使用して索引付け可能な操作名のシーケンス。
- dis.opmap
- オペレーション名をバイトコードにマッピングする辞書。
- dis.cmp_op
- すべての比較操作名のシーケンス。
- dis.hasconst
- 定数にアクセスするバイトコードのシーケンス。
- dis.hasfree
- 自由変数にアクセスするバイトコードのシーケンス(このコンテキストでの「free」は、内部スコープによって参照される現在のスコープ内の名前、またはこのスコープから参照される外部スコープ内の名前を指すことに注意してください。 グローバルスコープまたは組み込みスコープへの参照は含まれていません。
- dis.hasname
- 名前で属性にアクセスするバイトコードのシーケンス。
- dis.hasjrel
- 相対ジャンプターゲットを持つバイトコードのシーケンス。
- dis.hasjabs
- 絶対ジャンプターゲットを持つバイトコードのシーケンス。
- dis.haslocal
- ローカル変数にアクセスするバイトコードのシーケンス。
- dis.hascompare
- ブール演算のバイトコードのシーケンス。