Pascal で書かれたスクリプトがあります。この方法でデバッグします。すべての行で停止し、メモリ内のすべての変数の値をダンプして、次の行に進みます。Linux用のgdbまたは他のオープンソースツールでそれを行うことは可能ですか?
4 に答える
オプションでファイルをコンパイルします-g
。
fpc/gpc -g file.pas
gdb
このファイルに対して実行します。
gdb file
必要な変数をすべて設定します。
display first_var
display second_var
...
デバッグを開始します。
start
を押すs
と、次の行に進むことができます。
GDB の Python API を使用してすべての変数をダンプし、(シングル スレッドの) プログラムをステップ実行する概念実証を提示します。
# Usage: gdb -x dump-vars-each-step.py PROGRAM
import gdb
import re
import logging
LOG_LEVEL = logging.INFO
def dump_all_vars(skip_libc_symbols=True):
# gdb calls the source of its debug info an 'objfile'
# libc_objfile_name. e.g. '/usr/lib/debug/lib64/libc-2.16.so.debug'
libc_objfile_name_pattern = r'libc.*\.so'
frame = gdb.newest_frame()
while frame:
symtab = frame.find_sal().symtab
if symtab is not None:
objfile_name = symtab.objfile.filename
else:
objfile_name = ''
logging.debug('F: %s, %s' % (frame, objfile_name))
if skip_libc_symbols and re.match(r'libc.*\.so', os.path.basename(objfile_name)):
return
try:
block = frame.block()
except RuntimeError:
block = None
while block:
logging.debug('B: %s, %s' % (block, block.function))
for symbol in block:
try:
value = frame.read_var(symbol, block)
except gdb.error:
# typedefs etc don't have a value
pass
else:
sys.stdout.write('%s: %s\n' % (symbol, value))
block = block.superblock
frame = frame.newer()
def dump_globals(names):
for i in names:
s = gdb.lookup_global_symbol(i)
if s is not None:
sys.stdout.write('%s: %s\n' % (s, s.value()))
inferior_alive = False
def inferior_exited(e):
global inferior_alive
inferior_alive = False
sys.stdout.write('inferior exited with code: %d\n' % (e.exit_code))
def run_and_dump_vars_each_step():
# precondition: inferior not running
# NOTE: only handles single threaded programs
global inferior_alive
gdb.execute('start')
inferior_alive = True
gdb.events.exited.connect(inferior_exited)
while inferior_alive:
dump_all_vars()
gdb.execute('step')
gdb.execute('quit')
logging.basicConfig(format='%(message)s', level=LOG_LEVEL)
gdb.execute('set pagination no')
gdb.execute('set python print-stack full')
run_and_dump_vars_each_step()
C で次のハノイの塔のプログラムがあるとします。
enum {
N = 2,
};
int peg_positions[N];
static void hanoi(int n, int src, int dst)
{
int tmp = (0 + 1 + 2) - src - dst;
if (n == 0) {
peg_positions[n] = dst;
return;
}
hanoi(n - 1, src, tmp);
peg_positions[n] = dst;
hanoi(n - 1, tmp, dst);
}
int main()
{
hanoi(N - 1, 0, 2);
return 0;
}
実行すると、次のようgcc -g hanoi.c -o hanoi
に gdb -x dump-vars-each-step.py hanoi
出力されます。
Reading symbols from /home/scottt/work/gdb-python-scripts/hanoi...done.
Temporary breakpoint 1 at 0x400400: file hanoi.c, line 21.
Temporary breakpoint 1, main () at hanoi.c:21
21 {
N: N
hanoi: {void (int, int, int)} 0x40050c <hanoi>
main: {int ()} 0x400400 <main>
peg_positions: {0, 0}
22 hanoi(N - 1, 0, 2);
N: N
hanoi: {void (int, int, int)} 0x40050c <hanoi>
main: {int ()} 0x400400 <main>
peg_positions: {0, 0}
hanoi (n=n@entry=1, src=src@entry=0, dst=dst@entry=2) at hanoi.c:8
8 {
n: 1
src: 0
dst: 2
tmp: <optimized out>
N: N
hanoi: {void (int, int, int)} 0x40050c <hanoi>
main: {int ()} 0x400400 <main>
peg_positions: {0, 0}
9 int tmp = (0 + 1 + 2) - src - dst;
n: 1
src: 0
dst: 2
tmp: <optimized out>
N: N
hanoi: {void (int, int, int)} 0x40050c <hanoi>
main: {int ()} 0x400400 <main>
peg_positions: {0, 0}
8 {
n: 1
src: 0
dst: 2
tmp: <optimized out>
N: N
hanoi: {void (int, int, int)} 0x40050c <hanoi>
main: {int ()} 0x400400 <main>
peg_positions: {0, 0}
11 if (n == 0) {
n: 1
src: 0
dst: 2
tmp: 1
N: N
hanoi: {void (int, int, int)} 0x40050c <hanoi>
main: {int ()} 0x400400 <main>
peg_positions: {0, 0}
9 int tmp = (0 + 1 + 2) - src - dst;
n: 1
src: 0
dst: 2
tmp: 1
N: N
hanoi: {void (int, int, int)} 0x40050c <hanoi>
main: {int ()} 0x400400 <main>
peg_positions: {0, 0}
15 hanoi(n - 1, src, tmp);
n: 1
src: 0
dst: 2
tmp: 1
N: N
hanoi: {void (int, int, int)} 0x40050c <hanoi>
main: {int ()} 0x400400 <main>
peg_positions: {0, 0}
9 int tmp = (0 + 1 + 2) - src - dst;
n: 1
src: 0
dst: 2
tmp: 1
N: N
hanoi: {void (int, int, int)} 0x40050c <hanoi>
main: {int ()} 0x400400 <main>
peg_positions: {0, 0}
15 hanoi(n - 1, src, tmp);
n: 1
src: 0
dst: 2
tmp: 1
N: N
hanoi: {void (int, int, int)} 0x40050c <hanoi>
main: {int ()} 0x400400 <main>
peg_positions: {0, 0}
hanoi (n=n@entry=0, src=0, dst=dst@entry=1) at hanoi.c:8
8 {
n: 0
src: 0
dst: 1
tmp: <optimized out>
N: N
hanoi: {void (int, int, int)} 0x40050c <hanoi>
main: {int ()} 0x400400 <main>
peg_positions: {0, 0}
9 int tmp = (0 + 1 + 2) - src - dst;
n: 0
src: 0
dst: 1
tmp: <optimized out>
N: N
hanoi: {void (int, int, int)} 0x40050c <hanoi>
main: {int ()} 0x400400 <main>
peg_positions: {0, 0}
8 {
n: 0
src: 0
dst: 1
tmp: <optimized out>
N: N
hanoi: {void (int, int, int)} 0x40050c <hanoi>
main: {int ()} 0x400400 <main>
peg_positions: {0, 0}
11 if (n == 0) {
n: 0
src: <optimized out>
dst: 1
tmp: 2
N: N
hanoi: {void (int, int, int)} 0x40050c <hanoi>
main: {int ()} 0x400400 <main>
peg_positions: {0, 0}
12 peg_positions[n] = dst;
n: 0
src: <optimized out>
dst: 1
tmp: 2
N: N
hanoi: {void (int, int, int)} 0x40050c <hanoi>
main: {int ()} 0x400400 <main>
peg_positions: {0, 0}
18 }
n: 0
src: <optimized out>
dst: 1
tmp: 2
N: N
hanoi: {void (int, int, int)} 0x40050c <hanoi>
main: {int ()} 0x400400 <main>
peg_positions: {1, 0}
hanoi (n=n@entry=1, src=src@entry=0, dst=dst@entry=2) at hanoi.c:16
16 peg_positions[n] = dst;
n: 1
src: 0
dst: 2
tmp: <optimized out>
N: N
hanoi: {void (int, int, int)} 0x40050c <hanoi>
main: {int ()} 0x400400 <main>
peg_positions: {1, 0}
17 hanoi(n - 1, tmp, dst);
n: 1
src: 0
dst: 2
tmp: <optimized out>
N: N
hanoi: {void (int, int, int)} 0x40050c <hanoi>
main: {int ()} 0x400400 <main>
peg_positions: {1, 2}
11 if (n == 0) {
n: 1
src: 0
dst: 2
tmp: 0
N: N
hanoi: {void (int, int, int)} 0x40050c <hanoi>
main: {int ()} 0x400400 <main>
peg_positions: {1, 2}
12 peg_positions[n] = dst;
n: 1
src: 0
dst: 2
tmp: 0
N: N
hanoi: {void (int, int, int)} 0x40050c <hanoi>
main: {int ()} 0x400400 <main>
peg_positions: {1, 2}
18 }
n: 1
src: 0
dst: 2
tmp: 0
N: N
hanoi: {void (int, int, int)} 0x40050c <hanoi>
main: {int ()} 0x400400 <main>
peg_positions: {2, 2}
main () at hanoi.c:24
24 }
N: N
hanoi: {void (int, int, int)} 0x40050c <hanoi>
main: {int ()} 0x400400 <main>
peg_positions: {2, 2}
__libc_start_main (main=0x400400 <main>, argc=1, ubp_av=0x7fffffffde48, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffde38) at libc-start.c:257
257 exit (result);
__GI_exit (status=0) at exit.c:99
99 __run_exit_handlers (status, &__exit_funcs, true);
98 {
99 __run_exit_handlers (status, &__exit_funcs, true);
__run_exit_handlers (status=0, listp=0x3c777b16a8 <__exit_funcs>, run_list_atexit=run_list_atexit@entry=true) at exit.c:36
36 {
41 while (*listp != NULL)
45 while (cur->idx > 0)
48 &cur->fns[--cur->idx];
47 const struct exit_function *const f =
49 switch (f->flavor)
73 cxafct = f->func.cxa.fn;
77 cxafct (f->func.cxa.arg, status);
75 PTR_DEMANGLE (cxafct);
77 cxafct (f->func.cxa.arg, status);
0x00000000004004c0 in __do_global_dtors_aux ()
Single stepping until exit from function __do_global_dtors_aux,
which has no line number information.
0x0000000000400450 in deregister_tm_clones ()
Single stepping until exit from function deregister_tm_clones,
which has no line number information.
0x00000000004004d2 in __do_global_dtors_aux ()
Single stepping until exit from function __do_global_dtors_aux,
which has no line number information.
0x00000000004005f4 in _fini ()
Single stepping until exit from function _fini,
which has no line number information.
__run_exit_handlers (status=0, listp=0x3c777b16a8 <__exit_funcs>, run_list_atexit=run_list_atexit@entry=true) at exit.c:78
78 break;
45 while (cur->idx > 0)
82 *listp = cur->next;
83 if (*listp != NULL)
82 *listp = cur->next;
83 if (*listp != NULL)
89 if (run_list_atexit)
90 RUN_HOOK (__libc_atexit, ());
_IO_cleanup () at genops.c:1003
1003 {
1006 int result = _IO_flush_all_lockp (0);
1003 {
1015 _IO_unbuffer_write ();
_IO_unbuffer_write () at genops.c:958
958 if (fp->_lock == NULL || _IO_lock_trylock (*fp->_lock) == 0)
_IO_cleanup () at genops.c:1003
1003 {
1006 int result = _IO_flush_all_lockp (0);
_IO_flush_all_lockp (do_lock=do_lock@entry=0) at genops.c:819
819 {
825 __libc_cleanup_region_start (do_lock, flush_cleanup, 0);
819 {
825 __libc_cleanup_region_start (do_lock, flush_cleanup, 0);
831 fp = (_IO_FILE *) _IO_list_all;
832 while (fp != NULL)
830 last_stamp = _IO_list_all_stamp;
832 while (fp != NULL)
836 _IO_flockfile (fp);
835 if (do_lock)
834 run_fp = fp;
835 if (do_lock)
838 if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base)
848 if (do_lock)
852 if (last_stamp != _IO_list_all_stamp)
850 run_fp = NULL;
852 if (last_stamp != _IO_list_all_stamp)
859 fp = fp->_chain;
832 while (fp != NULL)
835 if (do_lock)
834 run_fp = fp;
835 if (do_lock)
838 if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base)
848 if (do_lock)
852 if (last_stamp != _IO_list_all_stamp)
850 run_fp = NULL;
852 if (last_stamp != _IO_list_all_stamp)
859 fp = fp->_chain;
832 while (fp != NULL)
835 if (do_lock)
834 run_fp = fp;
835 if (do_lock)
838 if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base)
848 if (do_lock)
852 if (last_stamp != _IO_list_all_stamp)
850 run_fp = NULL;
852 if (last_stamp != _IO_list_all_stamp)
859 fp = fp->_chain;
832 while (fp != NULL)
863 if (do_lock)
865 __libc_cleanup_region_end (0);
869 }
_IO_cleanup () at genops.c:1015
1015 _IO_unbuffer_write ();
_IO_unbuffer_write () at genops.c:947
947 for (fp = (_IO_FILE *) _IO_list_all; fp; fp = fp->_chain)
_IO_cleanup () at genops.c:1006
1006 int result = _IO_flush_all_lockp (0);
1015 _IO_unbuffer_write ();
_IO_unbuffer_write () at genops.c:947
947 for (fp = (_IO_FILE *) _IO_list_all; fp; fp = fp->_chain)
949 if (! (fp->_flags & _IO_UNBUFFERED)
983 fp->_mode = -1;
947 for (fp = (_IO_FILE *) _IO_list_all; fp; fp = fp->_chain)
949 if (! (fp->_flags & _IO_UNBUFFERED)
951 || (fp->_flags & _IO_IS_APPENDING))
950 && (! (fp->_flags & _IO_NO_WRITES)
953 && fp->_mode != 0)
983 fp->_mode = -1;
947 for (fp = (_IO_FILE *) _IO_list_all; fp; fp = fp->_chain)
949 if (! (fp->_flags & _IO_UNBUFFERED)
951 || (fp->_flags & _IO_IS_APPENDING))
950 && (! (fp->_flags & _IO_NO_WRITES)
983 fp->_mode = -1;
947 for (fp = (_IO_FILE *) _IO_list_all; fp; fp = fp->_chain)
_IO_cleanup () at genops.c:1018
1018 }
__run_exit_handlers (status=0, listp=<optimized out>, run_list_atexit=run_list_atexit@entry=true) at exit.c:92
92 _exit (status);
__GI__exit (status=status@entry=0) at ../sysdeps/unix/sysv/linux/_exit.c:28
28 {
32 INLINE_SYSCALL (exit_group, 1, status);
34 INLINE_SYSCALL (exit, 1, status);
32 INLINE_SYSCALL (exit_group, 1, status);
[Inferior 1 (process 32305) exited normally]
inferior exited with code: 0
ローカル変数が最適化されて表示される場合があることに注意tmp
してsrc
ください。関数の引数がレジスタに渡され、コードで使用されている間にレジスタRに配置されることがある x86-64 を使用していますが、gcc はレジスタRを別の目的で使用する必要があり、値が上書きされます。これは、変数ダンプの品質が、コンパイラが生成するデバッグ情報の品質に依存することを示しています。最近の gcc は C/C++ のかなり良いデバッグ情報を生成しますが、gcc Pascal ポートがどの程度最新のものであるか、または FPC がここでどれほど優れているかはわかりません。tmp
tmp
Pascal でテスト プログラムを作成し、デバッグ情報を使用してコンパイルし (pass -g )、テストすることは、読者の課題として残されています ;)
はいgdb
、PascalコンパイラがDWARFデバッグ情報を提供していれば、Pascalプログラムでデバッガを使用することは可能です。GNU Pascal(つまり)を使用している場合は、を呼び出すときにオプションをgpc
渡します。Free Pascalを使用する場合は、へのオプションも受け入れます。-g
gpc
-g
fpc
デバッグ情報を使用してPascalプログラムをコンパイルしたら、GNUgdbの使用方法を学ぶ必要があります。おそらく、、、、、、、、コマンド(to )などが必要display
です。step
next
break
print
frame
cont
gdb
すべてのグラフィカル IDE サポートはすぐに使用できるため、答えはコマンドライン ツールに引き寄せられるように思われます。
しかし、それが問題ではない場合.. Lazarusはそれを行うことができます。コンパイルし、F7 と F8 を押して LOC にステップ オーバー/ステップ インし、そのスコープ内のすべての変数をインスペクター ウィンドウに表示します。
もう 1 つの IDE は Delphi ですが、これはオープンソース/フリーではありません。