如何使用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程序的全部内容,希望大家喜欢。