生成一个gdb回溯调试php内核及扩展的方法

注意到PHP崩溃

没有绝对的方法知道PHP正在崩溃,但是可能有一些迹象。通常情况下,如果你访问一个总是应该生成输出的页面(例如,有一个前导HTML块),并且突然从浏览器中获得“Document contains no data”,这可能意味着PHP在执行脚本。另一种告诉PHP崩溃的方法是查看Apache错误日志,寻找SEGV(Apache 1.2)或Segmentation Fault(Apache 1.3)。

重要!

要获得正确信息的回溯,您必须将PHP配置为enable-debug!

如果你还没有核心文件:

  • 在shell中删除对内核转储大小的限制:
    • tcsh: 无限coredumpsize
    • bash/sh: ulimit -c unlimited 无限制
  • 确保运行PHP的目录或启用PHP的httpd对运行PHP的用户具有写权限。
  • 导致PHP崩溃:
    • PHP的CGI:只需运行PHP的脚本,崩溃它
    • PHP的Apache模块:运行httpd -X,并访问崩溃PHP的脚本

在Linux上获得core的通用方法

  • 设置core模式(以root身份运行此命令):
    • echo “这里是输出coredump目录/core-%e.%p” > /proc/sys/kernel/core_pattern
    • 确保coredump目录是可写的PHP目录
  • 设置ulimit(请参阅上面的操作方法)。
  • 重启PHP-FPM。
    之后,系统中所有崩溃的进程(包括PHP)都将其核心文件保留在您在core_pattern中指定的目录中。

拥有core文件后:

  • 使用指向PHP或启用PHP的httpd二进制文件的路径以及核心文件的路径运行gdb。一些例子:

    • gdb /usr/local/apache/sbin/httpd /usr/local/apache/sbin/core
    • gdb /home/user/dev/php-snaps/sapi/cli/php /home/user/dev/testing/core
    • gdb /usr/local/php-debug/sbin/php-fpm /usr/local/php-debug/var/coredump/core-php-fpm.10930
  • 在gdb提示符下运行:

    • (gdb) bt

如果无法core核心文件:

  • 在gdb下运行httpd -X,如下所示:

    • gdb /usr/local/apache/sbin/httpd
    • (gdb) run -X
  • 然后,使用Web浏览器并访问服务器以强制崩溃。您应该看到gdb提示符出现,并且一些消息表明发生了崩溃。在此gdb提示符下,键入:

(gdb) bt
  • 或者从命令行运行
gdb /home/user/dev/php-snaps/sapi/cli/php
(gdb) run /path/to/script.php
(gdb) bt

这将生成回溯记录,您应在错误报告中提交该回溯记录,以及您可以向我们提供的有关设置和令人讨厌的脚本的任何其他详细信息。

查找哪个函数调用导致了段错误:

您可以使用gdb轻松找到导致段错误的函数调用。首先,您需要一个核心文件或如上所述在gdb下生成segfault。
在PHP中,每个函数都由称为的内部函数执行, execute()并具有自己的堆栈。该bt命令生成的每一行 代表一个函数调用堆栈。通常,您execute()在发出时会看到几行 bt。您对最后一个execute()堆栈(即最小的帧号)感兴趣 。您可以使用移动当前正在工作的堆叠up,down或 frame命令。下面是一个示例gdb会话,可用作有关如何处理段错误的指南。

  • 示例gdb会话
(gdb) bt
#0  0x080ca21b in _efree (ptr=0xbfffdb9b) at zend_alloc.c:240
#1  0x080d691a in _zval_dtor (zvalue=0x8186b94) at zend_variables.c:44
#2  0x080cfab3 in _zval_ptr_dtor (zval_ptr=0xbfffdbfc) at zend_execute_API.c:274
#3  0x080f1cc4 in execute (op_array=0x816c670) at ./zend_execute.c:1605
#4  0x080f1e06 in execute (op_array=0x816c530) at ./zend_execute.c:1638
#5  0x080f1e06 in execute (op_array=0x816c278) at ./zend_execute.c:1638
#6  0x080f1e06 in execute (op_array=0x8166eec) at ./zend_execute.c:1638
#7  0x080d7b93 in zend_execute_scripts (type=8, retval=0x0, file_count=3) at zend.c:810
#8  0x0805ea75 in php_execute_script (primary_file=0xbffff650) at main.c:1310
#9  0x0805cdb3 in main (argc=2, argv=0xbffff6fc) at cgi_main.c:753
#10 0x400c91be in __libc_start_main (main=0x805c580 
, argc=2, ubp_av=0xbffff6fc,
               init=0x805b080 <_init>, fini=0x80f67b4 <_fini>, rtld_fini=0x4000ddd0 <_dl_fini>,
               stack_end=0xbffff6ec) at ../sysdeps/generic/libc-start.c:129
(gdb) frame 3
#3  0x080f1cc4 in execute (op_array=0x816c670) at ./zend_execute.c:1605
(gdb) print (char *)(executor_globals.function_state_ptr->function)->common.function_name
$14 = 0x80fa6fa "pg_result_error"
(gdb) print (char *)executor_globals.active_op_array->function_name
$15 = 0x816cfc4 "result_error"
(gdb) print (char *)executor_globals.active_op_array->filename
$16 = 0x816afbc "/home/yohgaki/php/DEV/segfault.php"
(gdb) 

在此会话中,帧3是最后一个调用execute()。该 帧3命令将当前工作堆栈移动到适当的帧。 打印函数名称。在示例gdb会话中,该调用导致了段错误。如果您知道内部数据结构,则可以打印任何您喜欢的内部数据。请不要问如何使用gdb或关于内部数据结构。有关gdb的用法,请参见gdb手册;有关内部数据结构,请参见PHP源代码。

print (char *)(executor_globals.function_state_ptr->function)->common.function_name
pg_result_error()

execute如果不调用任何函数,可能看不到段错误是否发生。
原文地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章