转自: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 查看一个文件做了什么:

[root@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) = ?
[root@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 +++
[root@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
[root@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 拿到了所有程序去调用系统过程所产生的痕迹后,我们能用来定位哪些问题呢?

  1. 调试性能问题,查看系统调用的频率,找出耗时的程序段
  2. 查看程序读取的是哪些文件从而定位比如配置文件加载错误问题
  3. 查看某个 php 脚本长时间运行“假死”情况
  4. 当程序出现 “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个功能:

  1. 跟踪和变更执行计算机程序
  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 开始调试:

[root@syyong home]$ sudo gdb php
(gdb)run index.php
... int()
[Inferior (process ) 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 常用命令可以参考:

gdb 调试 php:

gdb 有3种使用方式:

  1. 跟踪正在运行的 PHP 程序,使用 “gdb -p 进程ID” 进行附加到进程上
  2. 运行并调试 PHP 程序,使用 “gdb php -> run server.php” 进行调试
  3. 当 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➫] (https://github.com/php/php-src)的根目录中有一个 .gdbinit 文件,下载后再 gdb shell 中输入:

(gdb) source .gdbinit
(gdb) zbacktrace

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

  1. 某个 php 进程占用 cpu 100% 问题
  2. 出现 core dump 问题,比如“Segmentation fault”
  3. php 扩展出现错误
  4. 死循环问题

一些使用 gdb 排查问题例子:

tcpdump

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

官方man手册➫

命令格式为:
tcpdump [-aAbdDefhHIJKlLnNOpqRStuUvxX#] [ -B size ] [ -c count ]
[ -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 ] [ 表达式 ]

参考链接

在 php 中使用 strace、gdb、tcpdump 调试工具的更多相关文章

  1. 在php中使用strace、gdb、tcpdump调试工具

    [转] http://www.syyong.com/php/Using-strace-GDB-and-tcpdump-debugging-tools-in-PHP.html 在php中我们最常使用调试 ...

  2. Linux GDB程序调试工具使用简单介绍

    GDB概述 GDB是GNU开源组织公布的一个强大的UNIX下的程序调试工具.也许,各位比較喜欢那种图形界面方式的,像VC.BCB等IDE的调试,但假设你是在UNIX平台下做软件,你会发现GDB这个调试 ...

  3. Linux GDB 程序调试工具使用详解

    转自    http://www.codeceo.com/article/linux-gdb-tools.html 整理的挺全的 GDB概述 GDB是GNU开源组织发布的一个强大的UNIX下的程序调试 ...

  4. GDB程序调试工具

    GDB程序调试工具 GDB主要完成下面三个方面的功能: 启动被调试程序 让被调试程序在指定的位置停住 当程序被停住时,可以检查程序状态 GDB快速入门 编译生成可执行文件 gcc -g test.c ...

  5. GIS中的数据库.gdb与.mdb的区别

    gdb是文件地理数据库,mdb是个人地理数据库,都是数据库文件类型. 个人地理数据库,是以access数据库为基础的个人将数据库格式mdb,可以存储不超过2G的文件,只适合Windows系统下: 文件 ...

  6. linux 调试

    strace gdb tcpdump valgrind perf

  7. gdb调试工具学习

    GDB 是GNU开源组织发布的一个强大的UNIX下的程序调试工具.或许,各位比较喜欢那种图形界面方式的,像VC.BCB等IDE的调试,但如果你是在 UNIX平台下做软件,你会发现GDB这个调试工具有比 ...

  8. CentOS 6.4中升级编译安装GCC 4.8.1 + GDB 7.6.1 + Eclipse 以及Kdump配置

    在CentOS 6.4中编译安装GCC 4.8.1 + GDB 7.6.1 + Eclipse 今天在isocpp上看到"GCC 4.8.1 released, C++11 feature ...

  9. 嵌入式arm linux环境中gdb+gdbserver调试

    一.前言嵌入式Linux系统中,应用开发过程中,很多情况下,用户需要对一个应用程序进行反复调试,特别是复杂的程序.采用GDB方法调试,由于嵌入式系统资源有限性,一般不能直接在目标系统上进行调试,通常采 ...

随机推荐

  1. mysql如何按周统计数据?

    转自:https://www.cnblogs.com/wanghetao/p/3920124.html MySql 按周/月/日统计数据的方法 知识关键词:DATE_FORMAT  select DA ...

  2. Oracle Database Memory Structures

    Oracle Database creates and uses memory structures for various purposes. For example, memory stores ...

  3. VMware Authorization Service 未运行怎么解决

    操作步骤如下: 1.按win+r快捷键,输入services.msc,点击确定: 2.服务列表找到VMware Authorization Service 并双击: 3.修改启动类型为自动,点击应用, ...

  4. tensorflow和python操作中的笔记

    前一段时间做了一些项目,把一些笔记放在了txt中,现分享出来,自己也能够时长预习. 1) 读取文件时,将固定的文件地址,采用数组或者字符串的形式,提前表示出来,后期使用时候采用拼接操作 2) # 得到 ...

  5. 分区默认segment大小变化(64k—>8M)

    _partition_large_extents和_index_partition_large_extents 参考: http://www.xifenfei.com/2013/08/%E5%88%8 ...

  6. talib 中文文档(八): Momentum Indicator Functions 动量指标

    Momentum Indicator Functions ADX - Average Directional Movement Index 函数名:ADX 名称:平均趋向指数 简介:使用ADX指标,指 ...

  7. Expedition---poj2431(优先队列-堆的实现)

    题目链接:http://poj.org/problem?id=2431 题意:一辆卡车需要行驶 L 距离,车上油的含量为 P,在行驶的过程中有 n 个加油站 每个加油站到终点的距离是ai,每个加油站最 ...

  8. 301-React Ext-React创建组件的三种方式及其区别

    一.概述 React推出后,出于不同的原因先后出现三种定义react组件的方式,殊途同归:具体的三种方式: 函数式定义的无状态组件 es5原生方式React.createClass定义的组件 es6形 ...

  9. 迅雷7 纯净版v7.9.18.4724

    http://soft2.xzstatic.com/2016/08/Thunder_7.9.13.4666_NoAD_VIP.exe http://www.downza.cn/soft/192064. ...

  10. [RGEOS]空间拓扑关系

    -1.判断两个线段是否平行 inline bool parallel_seg_seg(Segment_2 S1, Segment_2 S2) { Vector_2 u(S1); Vector_2 v( ...