1. 程式人生 > >使用GDB除錯PHP Core Dump

使用GDB除錯PHP Core Dump

注意到PHP崩潰了

沒有絕對的方法可以知道PHP崩潰,但可能有跡象。通常,如果您訪問始終應該生成輸出的頁面(例如,具有前導HTML塊),並且突然從瀏覽器中獲取“文件不包含資料”,則可能意味著PHP在執行時崩潰了某處。指令碼。告訴PHP崩潰的另一種方法是檢視Apache錯誤日誌,並查詢SEGV(Apache 1.2)或Segmentation Fault(Apache 1.3)。

重要!

要獲得具有正確資訊的回溯,您必須使用--enable-debug配置PHP!

如果您還沒有核心檔案:

  • 從shell中刪除對核心轉儲大小的任何限制:

        tcsh:unlimit coredumpsize
        bash / sh:ulimit -c unlimited

  • 確保執行PHP的目錄或啟用PHP的httpd對執行PHP的使用者具有寫許可權。
  • 導致PHP崩潰:

        PHP CGI:只需使用崩潰的指令碼執行php
        PHP Apache模組:執行httpd -X,並訪問崩潰PHP的指令碼

在Linux上獲取核心的通用方法

  • 設定核心模式(以root身份執行此命令):

       echo“<cores dir> /core-%e.%p”> / proc / sys / kernel / core_pattern
       確保該目錄可由PHP寫入

  • 設定ulimit(參見上面的方法)。
  • 重新啟動/重新執行PHP。

之後,系統中崩潰的任何程序(包括PHP)都會將其核心檔案保留在您在core_pattern中指定的目錄中。 

獲得核心檔案後:

  • 執行帶有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提示符下,執行:

(gdb) bt

如果您無法獲得核心檔案:

在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下生成段錯誤。

在PHP中,每個函式都由一個名為execute()的內部函式執行,並有自己的堆疊。 bt命令生成的每一行代表一個函式呼叫堆疊。通常,在發出bt時會看到幾行execute()行。您對最後一個execute()堆疊(即最小幀編號)感興趣。您可以使用向上,向下或幀命令移動當前工作堆疊。下面是一個示例gdb會話,可用作如何處理segfault的指南。

示例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幀是最後一次執行()呼叫。 frame 3命令將當前工作堆疊移動到適當的幀。

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

列印功能名稱。在示例gdb會話中,pg_result_error()呼叫導致segfault。如果您瞭解內部資料結構,則可以列印任何您喜歡的內部資料。請不要問如何使用gdb或內部資料結構。有關gdb用法的資訊,請參閱gdb手冊,有關內部資料結構的資訊,請參閱PHP原始碼。

如果在沒有呼叫任何函式的情況下發生段錯誤,您可能看不到執行。