2017-02-26 14 views
3

レガシーアプリケーションでバグを修正するように言われました。不要なシステムコールで例外を発生させる

私はバグを再現することができますが、pythonのソースコード行がエラーを実行する手がかりがありません。

straceと表示されます。ファイルが開かれますが、開かないはずです。

私は関連するopen()linux-syscallをPythonインタプリタでExceptionを発生させたいと考えています。私の目標:バグを修正できるスタックトレースを見たい。

このようにして、デバッガで多くの行をステップ実行するのを避けることができました。

他の言葉と同じです:syscallが実行されると、straceの出力がopen("/somefile", O_RDONLY) = 4になり、pythonインタプリタはトレースバックで終了する必要があります。

誰か解決策がありますか?

私が探しているものがわからない場合は、コメントを残してください。

+0

一時的に '/ somefile'の名前を変更することは可能でしょうか? (コードがまだファイルの欠落状況を処理していないと仮定します)。 – chepner

+0

いいえ、ファイルの名前を変更することは役に立ちません。 – guettli

答えて

3

あなたはブレークポイントにヒットしたときに、送信、open()システムコールに(条件付き)ブレークポイントを設定し、GDBの下でのpythonを実行します(または、むしろ、それが呼び出されてlibcのスタブ機能)、およびすることができますSIGINTがpythonプロセスにシグナルを送り、それを続けると、pythonスクリプトの実行は、望ましいスタックトレースで中断されます。

以下のシェルスクリプトは、その手順を自動化します。

使用:

stack_trace_on_openfilename-- pythonscript.py[script args]


をstack_trace_on_open:

#!/usr/bin/env bash 

myname="$(basename "$0")" 

if [[ $# -lt 4 || "$2" != '--' ]] 
then 
    echo >&2 "Usage: $myname <filename> -- python <script.py> [script args ...]" 
    exit 1 
fi 

fname=$1 
python_exe="$3" 
shift 3 

gdb -q "$python_exe" <<END 
set breakpoint pending on 
break open 
condition 1 strcmp(\$rdi,"$fname") == 0 
run "[email protected]" 
signal 2 
cont 
quit 
END 

デモンストレーション:それが失敗した試みが開くどんなコールするよう

$ cat test.py 
import ctypes 

clib = ctypes.CDLL(None) 
fd = clib.open("/dev/urandom", 0) 
clib.close(fd) 

$ ./stack_trace_on_open /dev/urandom -- python test.py 
Reading symbols from python...(no debugging symbols found)...done. 
(gdb) (gdb) Function "open" not defined. 
Breakpoint 1 (open) pending. 
(gdb) (gdb) Starting program: /usr/bin/python "test.py" 
[Thread debugging using libthread_db enabled] 
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". 

Breakpoint 1, open64() at ../sysdeps/unix/syscall-template.S:84 
84 ../sysdeps/unix/syscall-template.S: No such file or directory. 
(gdb) Continuing with signal SIGINT. 

Breakpoint 1, open64() at ../sysdeps/unix/syscall-template.S:84 
84 in ../sysdeps/unix/syscall-template.S 
(gdb) Continuing. 
Traceback (most recent call last):    #  <-------- 
    File "test.py", line 4, in <module>    #  <-------- 
    fd = clib.open("/dev/urandom", 0)    #  <-------- 
KeyboardInterrupt 
[Inferior 1 (process 14248) exited with code 01] 
(gdb) 
+0

うわー、素晴らしい作品です。今までは、私はgdbの専門家ではありません(まだ)。私はそれで可能ないくつかの魔法のものがあると思う。あなたは恩恵を受ける。 – guettli

3

ここでは、インポートモジュールの前にopenにパッチを行うことができます例です。test.py

test2.py
def func(): 
    with open('test', 'w') as f: 
     pass 

try: 
    import __builtin__ # for python2 
except ImportError: 
    import builtins as __builtin__ #for python3 

import copy 
import traceback 

orig_open = copy.copy(__builtin__.open) 

def myopen(*args): 
    traceback.print_stack() 
    return orig_open(*args) 

__builtin__.open = myopen 

from test import funC# Note that we import the module after patching on open() 

func() 

func()がで呼ばれていますtest2.py、コールスタックが印刷されます。

$ python test2.py 
    File "test2.py", line 19, in <module> 
    func() 
    File "/tmp/test.py", line 4, in func 
    with open('test', 'w') as f: 
    File "test2.py", line 12, in myopen 
    traceback.print_stack() 
+0

私はこれを試しましたが、これは助けになりません。オープンなsys-callは、従来のc-extensionで起こると思います。 – guettli

+0

@guettliもしあなただったら、ソースコードをダウンロードし、 'grep -R'または' ag'を使って、オープンソースファイルのファイル名をすべてのソースから検索します。オープン操作はバイナリライブラリで発生する可能性があるため、ライブラリがデバッグ情報に準拠していないと、呼び出しスタックを出力することができても、 'open()'が呼び出される特定の場所を見つけることは難しいでしょう。 – zsrkmyn

+0

私は「syscallのStacktrace」というアイデアを持っていたので、この基本的なデバッグツールが役立ついくつかのユースケースが見つかりました。はい、この質問の使用例では、回避策を見つけることができました。 – guettli

関連する問題