如何使用GDB调试PHP程序
一般来说,GDB主要完成下面四个方面的功能:
(1)启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。
(2)可让被调试的程序在你所指定的调置的断点处停住。(断点可以是条件表达式)
(3)当程序被停住时,可以检查此时你的程序中所发生的事。
(4)动态的改变你程序的执行环境。
1、简介
GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具。如果你是在UNIX平台下做软件,你会发现GDB这个调试工具有比VC、BCB的图形化调试器更强大的功能。同时GDB也具有例如ddd这样的图形化的调试端。
2、调试C/C++程序
直接上代码了
#include<iostream> usingnamespacestd; longfactorial(intn); intmain() { intn(0); cin>>n; longval=factorial(n); cout<<val<<endl; cin.get(); return0; } longfactorial(intn) { longresult(1); while(n--) { result*=n; } returnresult; }
编译
1
g++k.cpp-g-Wall-Werror-omain
开始调试
[root@localhostcode]#gdb./main GNUgdb(GDB)RedHatEnterpriseLinux(7.2-83.el6) Copyright(C)2010FreeSoftwareFoundation,Inc. LicenseGPLv3+:GNUGPLversion3orlater<http://gnu.org/licenses/gpl.html> Thisisfreesoftware:youarefreetochangeandredistributeit. ThereisNOWARRANTY,totheextentpermittedbylaw.Type"showcopying" and"showwarranty"fordetails. ThisGDBwasconfiguredas"i686-redhat-linux-gnu". Forbugreportinginstructions,pleasesee: <http://www.gnu.org/software/gdb/bugs/>... Readingsymbolsfrom/code/main...done. (gdb)l warning:Sourcefileismorerecentthanexecutable. 1#include<iostream> 2usingnamespacestd; 3longfactorial(intn); 4 5intmain() 6{ 7intn(0); 8cin>>n; 9longval=factorial(n); 10cout<<val<<endl; (gdb)
设置断点breaklinenumber
(gdb)b9 Breakpoint1at0x80486f9:filek.cpp,line9. (gdb)r Startingprogram:/code/main 4 Breakpoint1,main()atk.cpp:9 9longval=factorial(n);
设置观察点watchvar
(gdb)s factorial(n=4)atk.cpp:17 17longresult(1); (gdb)l 12return0; 13} 14 15longfactorial(intn) 16{ 17longresult(1); 18while(n--) 19{ 20result*=n; 21} (gdb)watchn Hardwarewatchpoint2:n (gdb)watchresult Hardwarewatchpoint3:result (gdb)c Continuing. Hardwarewatchpoint3:result Oldvalue=0 Newvalue=1 factorial(n=4)atk.cpp:18 18while(n--) (gdb) Continuing. Hardwarewatchpoint2:n Oldvalue=4 Newvalue=3 0x08048764infactorial(n=3)atk.cpp:18 18while(n--) (gdb) Continuing. Hardwarewatchpoint3:result Oldvalue=1 Newvalue=3 factorial(n=3)atk.cpp:18 18while(n--) (gdb) Continuing. Hardwarewatchpoint2:n Oldvalue=3 Newvalue=2 0x08048764infactorial(n=2)atk.cpp:18 18while(n--) (gdb) Continuing. Hardwarewatchpoint3:result Oldvalue=3 Newvalue=6 factorial(n=2)atk.cpp:18 18while(n--) (gdb) Continuing. Hardwarewatchpoint2:n Oldvalue=2 Newvalue=1 0x08048764infactorial(n=1)atk.cpp:18 18while(n--) (gdb) Continuing. Hardwarewatchpoint2:n Oldvalue=1 Newvalue=0 0x08048764infactorial(n=0)atk.cpp:18 18while(n--) (gdb) Continuing. Watchpoint2deletedbecausetheprogramhaslefttheblockin whichitsexpressionisvalid. Watchpoint3deletedbecausetheprogramhaslefttheblockin whichitsexpressionisvalid. 0x08048705inmain()atk.cpp:9 9longval=factorial(n); (gdb)pval $1=11476980 (gdb)
可以看到是while那里,导致n越界了,fix
while(n>0)//doesn'tletnreach0 { result*=n; n--;//decrementsonlyaftertheevaluation }
一些快捷命令
l–list
p–printprint{variable}
c–continue
s–step
b-breakbreakline_number/break[file_name]:line_number/break[file_name]:func_name
r-run
set<var>=<value>
watch<var>
ENTER:pressingenterkeywouldexecutethepreviouslyexecutedcommandagain.
c/n/s的区别
•corcontinue:Debuggerwillcontinueexecutinguntilthenextbreakpoint.
•nornext:Debuggerwillexecutethenextlineassingleinstruction.
•sorstep:Sameasnext,butdoesnottreatsfunctionasasingleinstruction,insteadgoesintothefunctionandexecutesitlinebyline
3、调试PHP程序
PHP代码
<?php. for($i=0;$i<10;$i++){ echo$i."\n"; sleep(3); if(in_array($i,[1,9,20])){ print_r($i*$i); var_dump($i*$i); print$i*$i; } }
开始调试,加上断点
[root@localhostcode]#gdbphp GNUgdb(GDB)RedHatEnterpriseLinux(7.2-83.el6) Copyright(C)2010FreeSoftwareFoundation,Inc. LicenseGPLv3+:GNUGPLversion3orlater<http://gnu.org/licenses/gpl.html> Thisisfreesoftware:youarefreetochangeandredistributeit. ThereisNOWARRANTY,totheextentpermittedbylaw.Type"showcopying" and"showwarranty"fordetails. ThisGDBwasconfiguredas"i686-redhat-linux-gnu". Forbugreportinginstructions,pleasesee: <http://www.gnu.org/software/gdb/bugs/>... Readingsymbolsfrom/usr/bin/php...done. (gdb)bzif_sleep Breakpoint1at0x8435180:file/usr/local/src/php-5.5.23/ext/standard/basic_functions.c,line4449. (gdb)bzif_in_array Breakpoint2at0x8426923:file/usr/local/src/php-5.5.23/ext/standard/array.c,line1215. (gdb)bzif_print_r Breakpoint3at0x8438273:file/usr/local/src/php-5.5.23/ext/standard/basic_functions.c,line5553. (gdb)bzif_var_dump Breakpoint4at0x847d296:file/usr/local/src/php-5.5.23/ext/standard/var.c,line178. (gdb)bzif_printf Function"zif_printf"notdefined. Makebreakpointpendingonfuturesharedlibraryload?(yor[n])n (gdb)bzif_sprintf Function"zif_sprintf"notdefined. Makebreakpointpendingonfuturesharedlibraryload?(yor[n])n (gdb)bprintf Breakpoint5at0x806a390 (gdb)bmemcpy Breakpoint6at0x8069390 (gdb)bzif_print Function"zif_print"notdefined. Makebreakpointpendingonfuturesharedlibraryload?(yor[n])n (gdb)bzif_echo Function"zif_echo"notdefined. Makebreakpointpendingonfuturesharedlibraryload?(yor[n])n (gdb)infob NumTypeDispEnbAddressWhat 1breakpointkeepy0x08435180inzif_sleepat/usr/local/src/php-5.5.23/ext/standard/basic_functions.c:4449 2breakpointkeepy0x08426923inzif_in_arrayat/usr/local/src/php-5.5.23/ext/standard/array.c:1215 3breakpointkeepy0x08438273inzif_print_rat/usr/local/src/php-5.5.23/ext/standard/basic_functions.c:5553 4breakpointkeepy0x0847d296inzif_var_dumpat/usr/local/src/php-5.5.23/ext/standard/var.c:178 5breakpointkeepy0x0806a390<printf@plt> 6breakpointkeepy0x08069390<memcpy@plt> (gdb)
加几个断点测试一下syntax:break[file_name]:func_name,这里大致可以看一下echoprint等不是函数了
然后开始调试
(gdb)p*return_value $1={value={lval=1515870810,dval=1.7838867517321418e+127,str={val=0x5a5a5a5a<Address0x5a5a5a5aoutofbounds>, len=1515870810},ht=0x5a5a5a5a,obj={handle=1515870810,handlers=0x5a5a5a5a}},refcount__gc=1,type=0'\000',is_ref__gc=0'\000'} (gdb)preturn_value->value $2={lval=1515870810,dval=1.7838867517321418e+127,str={val=0x5a5a5a5a<Address0x5a5a5a5aoutofbounds>, len=1515870810},ht=0x5a5a5a5a,obj={handle=1515870810,handlers=0x5a5a5a5a}} (gdb)preturn_value->value->lval $3=1515870810
我们还可以使用内置的gdbinit来调试
(gdb)source/usr/local/src/php-5.5.23/.gdbinit (gdb)zbacktrace [0xb7fa1144]sleep(3)/code/kk.php:4
查看当前堆栈,PHP内核的执行过程
(gdb)bt #0zif_sleep(ht=1,return_value=0xb7fbd6f0,return_value_ptr=0x0,this_ptr=0x0,return_value_used=0) at/usr/local/src/php-5.5.23/ext/standard/basic_functions.c:4449 #10x085f6870inexecute_internal(execute_data_ptr=0xb7fa1144,fci=0x0,return_value_used=0) at/usr/local/src/php-5.5.23/Zend/zend_execute.c:1484 #20x085aea5findtrace_execute_internal(execute_data_ptr=0xb7fa1144,fci=0x0,return_value_used=0) at/usr/local/src/php-5.5.23/Zend/zend_dtrace.c:97 #30x00935c33inpt_execute_core(internal=1,execute_data=0xb7fa1144,fci=0x0,rvu=0) at/usr/local/src/trace-0.3.0/extension/trace.c:941 #40x00935e49inpt_execute_internal(execute_data=0xb7fa1144,fci=0x0,return_value_used=0) at/usr/local/src/trace-0.3.0/extension/trace.c:1005 #50x085f7523inzend_do_fcall_common_helper_SPEC(execute_data=0xb7fa1144)at/usr/local/src/php-5.5.23/Zend/zend_vm_execute.h:552 #60x085fb2a9inZEND_DO_FCALL_SPEC_CONST_HANDLER(execute_data=0xb7fa1144)at/usr/local/src/php-5.5.23/Zend/zend_vm_execute.h:2332 #70x085f6debinexecute_ex(execute_data=0xb7fa1144)at/usr/local/src/php-5.5.23/Zend/zend_vm_execute.h:363 #80x085ae9dcindtrace_execute_ex(execute_data=0xb7fa1144)at/usr/local/src/php-5.5.23/Zend/zend_dtrace.c:73 #90x00935c5einpt_execute_core(internal=0,execute_data=0xb7fa1144,fci=0x0,rvu=0) at/usr/local/src/trace-0.3.0/extension/trace.c:946 #100x00935e10inpt_execute_ex(execute_data=0xb7fa1144)at/usr/local/src/trace-0.3.0/extension/trace.c:1000 #110x085f6e4ainzend_execute(op_array=0xb7fbc7b4)at/usr/local/src/php-5.5.23/Zend/zend_vm_execute.h:388 #120x085c1cf2inzend_execute_scripts(type=8,retval=0x0,file_count=3)at/usr/local/src/php-5.5.23/Zend/zend.c:1327 #130x085470f9inphp_execute_script(primary_file=0xbffff4a4)at/usr/local/src/php-5.5.23/main/main.c:2525 #140x0865af46indo_cli(argc=2,argv=0x8b9b908)at/usr/local/src/php-5.5.23/sapi/cli/php_cli.c:994 #150x0865bff3inmain(argc=2,argv=0x8b9b908)at/usr/local/src/php-5.5.23/sapi/cli/php_cli.c:1378
查看代码段
(gdb)l 4444Delayforagivennumberofseconds*/ 4445PHP_FUNCTION(sleep) 4446{ 4447longnum; 4448 4449if(zend_parse_parameters(ZEND_NUM_ARGS()TSRMLS_CC,"l",&num)==FAILURE){ 4450RETURN_FALSE; 4451} 4452if(num<0){ 4453php_error_docref(NULLTSRMLS_CC,E_WARNING,"Numberofsecondsmustbegreaterthanorequalto0"); (gdb)l4450 4445PHP_FUNCTION(sleep) 4446{ 4447longnum; 4448 4449if(zend_parse_parameters(ZEND_NUM_ARGS()TSRMLS_CC,"l",&num)==FAILURE){ 4450RETURN_FALSE; 4451} 4452if(num<0){ 4453php_error_docref(NULLTSRMLS_CC,E_WARNING,"Numberofsecondsmustbegreaterthanorequalto0"); 4454RETURN_FALSE; (gdb)lzif_usleep 4463/*}}}*/ 4464 4465/*{{{protovoidusleep(intmicro_seconds) 4466Delayforagivennumberofmicroseconds*/ 4467PHP_FUNCTION(usleep) 4468{ 4469#ifHAVE_USLEEP 4470longnum; 4471 4472if(zend_parse_parameters(ZEND_NUM_ARGS()TSRMLS_CC,"l",&num)==FAILURE){
继续执行
(gdb)n 4452if(num<0){ (gdb)pnum $6=3 (gdb)n 4457RETURN_LONG(php_sleep(num)); (gdb)n 4462} (gdb)n execute_internal(execute_data_ptr=0xb7fa1144,fci=0x0,return_value_used=0)at/usr/local/src/php-5.5.23/Zend/zend_execute.c:1488 1488}
到了execute_internal,可以查看一下当前函数的一个状态
(gdb)pexecute_data_ptr $7=(zend_execute_data*)0xb7fa1144 (gdb)p*execute_data_ptr $8={opline=0xb7fbcacc,function_state={function=0x8bcf3e8,arguments=0xb7fa119c},op_array=0xb7fbc7b4,object=0x0, symbol_table=0x8b99cdc,prev_execute_data=0x0,old_error_reporting=0x0,nested=0'\000', original_return_value=0x38b4ac9,current_scope=0x49,current_called_scope=0x45,current_this=0x0,fast_ret=0x0, call_slots=0xb7fa1188,call=0xb7fa1188} (gdb)p*execute_data_ptr->function_state.function->common->function_name $9=115's' (gdb)pexecute_data_ptr->function_state.function->common->function_name $10=0x8af03c9"sleep" (gdb)pexecute_data_ptr->op_array->filename $11=0xb7fbc8e8"/code/kk.php"
查看当前hashtable
(gdb)p*execute_data_ptr->symbol_table $={nTableSize=,nTableMask=,nNumOfElements=,nNextFreeElement=,pInternalPointer=xbfbc, pListHead=xbfbc,pListTail=xbfbd,arBuckets=xbfb,pDestructor=xbff<_zval_ptr_dtor_wrapper>, persistent='\',nApplyCount='\',bApplyProtection='\',inconsistent=}
继续执行输出c之后,回车即可,同样可以看到in_array的执行信息
(gdb)p*execute_data_ptr->function_state.function $24={type=1'\001',common={type=1'\001',function_name=0x8af1841"in_array",scope=0x0,fn_flags=256, prototype=0x0,num_args=3,required_num_args=2,arg_info=0x8ae7554},op_array={type=1'\001', function_name=0x8af1841"in_array",scope=0x0,fn_flags=256,prototype=0x0,num_args=3,required_num_args=2, arg_info=0x8ae7554,refcount=0x842691d,opcodes=0x8bcf120,last=0,vars=0x0,last_var=0,T=1, nested_calls=3086618796,used_stack=0,brk_cont_array=0x0,last_brk_cont=1,try_catch_array=0xb7fa10dd, last_try_catch=96,has_finally_block=160'\240',static_variables=0x0,this_var=11482064, filename=0xaf1ff4"|\035\257",line_start=11482016,line_end=146381272, doc_comment=0xbffff238"x\362\377\277\244\aY\b\021",doc_comment_len=10305959,early_binding=11085989, literals=0x8b7a0a0,last_literal=140062666,run_time_cache=0xb7fa10d4,last_cache_slot=90,reserved={0x9,0x8b5f7ac, 0x796,0x0}},internal_function={type=1'\001',function_name=0x8af1841"in_array",scope=0x0,fn_flags=256, prototype=0x0,num_args=3,required_num_args=2,arg_info=0x8ae7554,handler=0x842691d<zif_in_array>, module=0x8bcf120}} (gdb)pexecute_data_ptr->function_state.function->common->function_name $26=0x8af1841"in_array" (gdb)pexecute_data_ptr->op_array->filename $27=0xb7fbc8e8"/code/kk.php"
还可以加一下监控watch、设置一些调试变量set等等
其他的调试工具还有strace查看系统调用、ltrace查看类库的调用、vld查看opcode。
以上内容是小编给大家分享的关于如何使用GDB调试PHP程序的全部内容,希望大家喜欢。