我有一个用帕斯卡写的脚本。 我会这样debugging它:停在每一行,转储内存中所有variables的值,并转到下一行。 是否有可能使用gdb或其他一些开放源码的Linux工具?
如何使backtrace()/ backtrace_symbols()打印函数名?
ASLR和地址
windbg:是否可以在我自己的程序中embeddedWindgb引擎?
MINIDUMP_TYPE枚举值的什么组合会给我最“完整的”迷你转储?
如何将Visual Studio的“输出”窗口redirect到DebugView?
用选项-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. eg '/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: %sn' % (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: %sn' % (s,s.value())) inferior_alive = False def inferior_exited(e): global inferior_alive inferior_alive = False sys.stdout.write('inferior exited with code: %dn' % (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,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,2); N: N hanoi: {void (int,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,0} 9 int tmp = (0 + 1 + 2) - src - dst; n: 1 src: 0 dst: 2 tmp: <optimized out> N: N hanoi: {void (int,0} 8 { n: 1 src: 0 dst: 2 tmp: <optimized out> N: N hanoi: {void (int,0} 11 if (n == 0) { n: 1 src: 0 dst: 2 tmp: 1 N: N hanoi: {void (int,0} 9 int tmp = (0 + 1 + 2) - src - dst; n: 1 src: 0 dst: 2 tmp: 1 N: N hanoi: {void (int,0} 15 hanoi(n - 1,tmp); n: 1 src: 0 dst: 2 tmp: 1 N: N hanoi: {void (int,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,0} 9 int tmp = (0 + 1 + 2) - src - dst; n: 0 src: 0 dst: 1 tmp: <optimized out> N: N hanoi: {void (int,0} 8 { n: 0 src: 0 dst: 1 tmp: <optimized out> N: N hanoi: {void (int,0} 11 if (n == 0) { n: 0 src: <optimized out> dst: 1 tmp: 2 N: N hanoi: {void (int,0} 12 peg_positions[n] = dst; n: 0 src: <optimized out> dst: 1 tmp: 2 N: N hanoi: {void (int,0} 18 } n: 0 src: <optimized out> dst: 1 tmp: 2 N: N hanoi: {void (int,int)} 0x40050c <hanoi> main: {int ()} 0x400400 <main> peg_positions: {1,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,0} 17 hanoi(n - 1,dst); n: 1 src: 0 dst: 2 tmp: <optimized out> N: N hanoi: {void (int,2} 11 if (n == 0) { n: 1 src: 0 dst: 2 tmp: 0 N: N hanoi: {void (int,2} 12 peg_positions[n] = dst; n: 1 src: 0 dst: 2 tmp: 0 N: N hanoi: {void (int,2} 18 } n: 1 src: 0 dst: 2 tmp: 0 N: N hanoi: {void (int,int)} 0x40050c <hanoi> main: {int ()} 0x400400 <main> peg_positions: {2,2} main () at hanoi.c:24 24 } N: N hanoi: {void (int,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,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 @R_725_4045@ion. 0x0000000000400450 in deregister_tm_clones () Single stepping until exit from function deregister_tm_clones,which has no line number @R_725_4045@ion. 0x00000000004004d2 in __do_global_dtors_aux () Single stepping until exit from function __do_global_dtors_aux,which has no line number @R_725_4045@ion. 0x00000000004005f4 in _fini () Single stepping until exit from function _fini,which has no line number @R_725_4045@ion. __run_exit_handlers (status=0,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,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,status); 32 INLINE_SYSCALL (exit_group,status); [Inferior 1 (process 32305) exited normally] inferior exited with code: 0
注意有时候局部变量tmp , src显示为最优化 。 我在x86-64上函数参数传递在寄存器中,有时tmp被放置在寄存器R,而在代码中使用,但是然后gcc想要使用寄存器R的东西和tmp的值被覆盖。 这表明变量转储的质量将取决于编译器生成的调试信息的质量。 最近gcc为C / C ++生成相当不错的调试信息,我不确定最新的gcc Pascal端口是多少,或者FPC在这里有多好。
在Pascal中生成测试程序,用调试信息(pass -g )编译并测试它,这是读者的一个练习;)
是的,可以在Pascal程序上使用gdb调试器,前提是您的Pascal编译器提供了DWARF调试信息。 如果使用GNU Pascal (即gpc ), 则在调用gpc时要传递-g选项 。 如果您使用Free Pascal,则它也接受 fpc 的-g选项 。
一旦你编译了你的Pascal程序和调试信息,你需要学习如何使用GNU gdb 。 你可能需要display , step , next , break , print , frame , cont命令(到gdb )等等。
因为每个图形化的IDE都支持这个功能,所以答案似乎更倾向于命令行工具,假设你不用什么IDE。
但是,如果这没有问题, 拉撒路可以做到这一点。 您只需编译,按F7和F8跳过/进入LOC,并在巡视窗口中查看该范围内的所有变量。
另一个IDE是Delphi,但那不是开源/免费的。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。