设为首页 收藏本站
查看: 1060|回复: 0

[经验分享] 在php中使用strace、gdb、tcpdump调试工具

[复制链接]

尚未签到

发表于 2017-12-29 21:32:25 | 显示全部楼层 |阅读模式
[转] http://www.syyong.com/php/Using-strace-GDB-and-tcpdump-debugging-tools-in-PHP.html

  在php中我们最常使用调试方式是输出打印方式,比如通过echo、var_dump输出信息到终端或者通过fwrite、file_put_contents将信息写入到文件中。这种普通方式能帮我们解决绝大部分调试问题。但仍然有些问题是需要借助其他工具来分析的,比如死循环,程序执行时间超预期,占用cpu过高,php内核或者扩展错误等场景,这时如果借助strace、gdb、tcpdump这样的工具就能很好的去帮助我们定位问题。

strace
  strace是Linux环境下的一款程序调试工具,用来监察一个应用程序所使用的系统调用及它所接收的系统信息。
  在Linux中,进程是不能直接去访问硬件设备(比如读取磁盘文件,接收网络数据等等),但可以将用户态模式切换至内核态模式,通过系统调用来访问硬件设备。这时strace就可以跟踪到一个进程产生的系统调用,包括参数,返回值,执行消耗的时间,调用次数,成功和失败的次数。
  比如我们使用strace来跟踪cat查看一个文件做了什么:
  

[iyunv@syyong home]$ strace cat index.php  
execve("/bin/cat", ["cat", "index.php"], [/* 25 vars */]) = 0
  
brk(0)                                  = 0x21b0000
  
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f5fd02fd000
  
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
  
open("/etc/ld.so.cache", O_RDONLY)      = 3
  
fstat(3, {st_mode=S_IFREG|0644, st_size=41783, ...}) = 0
  
mmap(NULL, 41783, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f5fd02f2000
  
close(3)                                = 0
  
open("/lib64/libc.so.6", O_RDONLY)      = 3
  
...
  
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 3), ...}) = 0
  
open("index.php", O_RDONLY)             = 3
  
fstat(3, {st_mode=S_IFREG|0664, st_size=27, ...}) = 0
  
read(3, "<?php\necho 'hello world';\n\n", 32768) = 27
  
write(1, "<?php\necho 'hello world';\n\n", 27<?php
  
echo 'hello world';
  

  
) = 27
  
read(3, "", 32768)                      = 0
  
close(3)                                = 0
  
close(1)                                = 0
  
close(2)                                = 0
  
exit_group(0)                           = ?
  

  

[iyunv@syyong home]$ strace -e read cat index.php  
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0p\356\1\0\0\0\0\0"..., 832) = 832
  
read(3, "<?php\necho 'hello world';\n\n", 32768) = 27
  
<?php
  
echo 'hello world';
  

  
read(3, "", 32768)                      = 0
  
+++ exited with 0 +++
  

  

[iyunv@syyong home]$ strace -c cat index.php  
<?php
  
echo "hello world";
  

  
% time     seconds  usecs/call     calls    errors syscall
  
------ ----------- ----------- --------- --------- ----------------
  0.00    0.000000           0         3           read
  0.00    0.000000           0         1           write
  0.00    0.000000           0         4           open
  0.00    0.000000           0         6           close
  0.00    0.000000           0         5           fstat
  0.00    0.000000           0         9           mmap
  0.00    0.000000           0         3           mprotect
  0.00    0.000000           0         1           munmap
  0.00    0.000000           0         3           brk
  0.00    0.000000           0         1         1 access
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         1           arch_prctl
  
------ ----------- ----------- --------- --------- ----------------
  
100.00    0.000000                    38         1 total
  

  

[iyunv@syyong home]$ strace -T cat index.php 2>&1|grep read  
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0p\356\1\0\0\0\0\0"..., 832) = 832 <0.000015>
  
read(3, "<?php\necho 'hello world';\n\n", 32768) = 27 <0.000019>
  
read(3, "", 32768)                      = 0 <0.000014>
  

  

  默认返回的结果每一行代表一条系统调用,规则为“系统调用的函数名及其参数=函数返回值”。也可以外加一些条件比如:-e指定返回的调用函数,-c对结果进行统计,-T查看绝对耗时,-p通过pid附着(attach)到任何运行的进程等等。
  strace的使用方法这里就不做具体介绍了,可以通过strace --help去详细了解使用方法。
  那么通过strace拿到了所有程序去调用系统过程所产生的痕迹后,我们能用来定位哪些问题呢?


  • 调试性能问题,查看系统调用的频率,找出耗时的程序段
  • 查看程序读取的是哪些文件从而定位比如配置文件加载错误问题
  • 查看某个php脚本长时间运行“假死”情况
  • 当程序出现“Out of memory”时被系统发出的SIGKILL信息所kill
  另外因为strace拿到的是系统调用相关信息,一般也即是IO操作信息,这个对于排查比如cpu占用100%问题是无能为力的。这个时候就可以使用GDB工具了。
  phptrace
  因为strace只能追踪到系统调用信息,而拿不到php代码层的调用信息。phptrace扩展就是为了解决这个问题,phptrace包含两个功能:1. 打印当前PHP调用栈,2. 实时追踪PHP调用。这样就能更方便我们去查看到我们需要的信息。phptrace wiki➫

GDB
  gdb是一个由GNU开源组织发布运行在UNIX/LINUX操作系统下功能强大的程序调试工具。使用gdb可以在程序运行时观察程序的内部结构和内存的使用情况,当程序dump时还可以通过gdb观察到程序dump前发生了什么。主要来说gdb具有以下2个功能:


  • 跟踪和变更执行计算机程序
  • 断点功能
  因为php语言是c写的,那么使用gdb也就能很方便的去调试php代码。举例,我们通过gdb来调试一个简单的php程序index.php:
  

// 程序代码:  
<?php
  
for ($i = 0; $i < 3; $i ++) {
  echo $i . PHP_EOL;
  if ($i == 2) {
  $j = $i + 1;
  var_dump($j);
  }
  sleep(1);
  
}
  

  

  gdb开始调试:
  

[iyunv@syyong home]$ sudo gdb php  

  

(gdb)run index.php  
...
  
0
  
1
  
2
  
int(3)
  
[Inferior 1 (process 577) exited normally]
  

  

  注:如果mac下使用gdb时报:“...please check gdb is codesigned - see taskgated(8)...”时可参考https://leandre.cn/search/gdb/➫。gdb在调试程序时,如果ulimit打开则会把错误信息打印到当前目录下的core.*文件中。ulimit -c如果为0则表示没打开,可以执行ulimit -c unlimited或者ulimit -c 大于0的数字。

常用命令:


  • p:print,打印C变量的值
  • c:continue,继续运行被中止的程序
  • b:breakpoint,设置断点,可以按照函数名设置,如b zif_php_function,也可以按照源代码的行数指定断点,如b src/networker/Server.c:1000
  • t:thread,切换线程,如果进程拥有多个线程,可以使用t指令,切换到不同的线程
  • ctrl + c:中断当前正在运行的程序,和c指令配合使用
  • n:next,执行下一行,单步调试
  • info threads:查看运行的所有线程
  • l:list,查看源码,可以使用l 函数名 或者 l 行号
  • bt:backtrace,查看运行时的函数调用栈。当程序出错后用于查看调用栈信息
  • finish:完成当前函数
  • f:frame,与bt配合使用,可以切换到函数调用栈的某一层
  • r:run,运行程序
  使用.gdbinit脚本:
  除了在gdb shell里输入命令,也可以预先编写好脚本让gdb执行。当gdb启动的时候会在当前目录下查找“.gdbinit”文件并加载,作为gdb命令进行执行。这样就可以不用在命令行中做一些重复的事,比如设定多个断点等操作。另外在gdb运行时也可以通过执行“(gdb) source [-s] [-v] filename”来解释gdb命令脚本文件。一个.gdbinit文件例子:
  

file index.php  
set args hello
  
b main
  
b foo
  
r
  

  

  php源码中提供的一个.gdbinit示例➫
  其他gdb常用命令可以参考:


  • http://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/gdb.html➫
  • http://coolshell.cn/articles/3643.html➫
  • http://www.cnblogs.com/xuqiang/archive/2011/05/02/2034583.html
  • http://blog.csdn.net/21cnbao/article/details/7385161➫
  • https://sourceware.org/gdb/current/onlinedocs/gdb/➫
  • 所有gdb命令索引➫
gdb 调试php:
  gdb有3种使用方式:


  • 跟踪正在运行的PHP程序,使用 “gdb -p 进程ID” 进行附加到进程上
  • 运行并调试PHP程序,使用 “gdb php -> run server.php” 进行调试
  • 当PHP程序发生coredump后使用gdb加载core内存镜像进行调试 gdb php core
  php在解释执行过程中,zend引擎用executor_globals变量保存了执行过程中的各种数据,包括执行函数、文件、代码行等。zend虚拟机是使用C编写,gdb来打印PHP的调用栈时,实际是打印的虚拟机的执行信息。

  使用zbacktrace更简单的调试:
  php源代码中还提供了zbacktrace这样的方便的对gdb命令的封装的工具。zbacktrace是PHP源码包提供的一个gdb自定义指令,功能与bt指令类似,与bt不同的是zbacktrace看到的调用栈是PHP函数调用栈,而不是c函数。zbacktrace可以直接看到当前执行函数、文件名和行数,简化了直接使用gdb命令的很多步骤。在php-src➫的根目录中有一个.gdbinit文件,下载后再gdb shell中输入:
  

(gdb) source .gdbinit  
(gdb) zbacktrace
  

  

  基于gdb的功能特点,我们可以使用gdb来排查比如这些问题:


  • 某个php进程占用cpu 100%问题
  • 出现core dump问题,比如“Segmentation fault”
  • php扩展出现错误
  • 死循环问题
  一些使用gdb排查问题例子:


  • 更简单的重现PHP Core的调用栈➫
  • PHP stream未能及时清理现场导致Core的bug➫
  • 一个低概率的PHP Core dump➫
tcpdump
  即dump the traffic on a network,是一个功能强大的,命令行的包分析器。它可以将网络中传送的数据包完全截获下来提供分析。它支持针对网络层、协议、主机、网络或端口的过滤,并提供and、or、not等逻辑语句来帮助去掉无用的信息。这样我们就能详细看到网络通信的过程,能帮助我们解决很多网络问题。比如可以通过tcpdump知道什么时候发起的3次握手什么时候发送FIN包,什么时候发送RST包。
  官方man手册➫
  

命令格式为:
  
tcpdump [-aAbdDefhHIJKlLnNOpqRStuUvxX#] [ -B>
[ -C file_size ] [ -E algo:secret ] [ -F file ] [ -G seconds ]

[ -i interface ] [ -j tstamptype ] [ -M secret ]

[ -Q metadata-filter-expression ]

[ -r file ] [ -s snaplen ] [ -T type ] [ --version ] [ -V file ]

[ -w file ] [ -W filecount ] [ -y datalinktype ] [ -z command ]

[ -Z user ] [ 表达式 ]

  

参考链接


  • https://sourceware.org/gdb/➫
  • http://hilojack.com/p/php-debug➫
  • http://wiki.swoole.com/wiki/page/442.html➫
  • http://www.xuebuyuan.com/73074.html➫
  • http://www.syyong.com/php/Using-strace-GDB-and-tcpdump-debugging-tools-in-PHP.html➫
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-429506-1-1.html 上篇帖子: php 跳转页面session丢失 session机制 下篇帖子: php获取微信的openid
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表