亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

PHP如何用gdb調試源碼

發布時間:2022-12-29 10:07:21 來源:億速云 閱讀:106 作者:iii 欄目:編程語言

這篇文章主要介紹了PHP如何用gdb調試源碼的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇PHP如何用gdb調試源碼文章都會有所收獲,下面我們一起來看看吧。

php編譯時有一個debug模式,這個模式會關閉內存優化,提示內存泄露,屏蔽調用棧優化可以讓我們看到完整的php c層面的調用棧。

通常我會編譯兩個php版(一個正常,一個打開debug)在不同的目錄,通過export決定使用哪個。

通過php-config命令可以看到configure-options,修改其中的prefix 和 with-config-file-path 到新的目錄,然后添加--enable-debug 命令

yongkbmaster ?  ~ php-config
Usage: /data/env/runtime/php-7.1.33-debug/bin/php-config [OPTION]
Options:
  --prefix            [/data/env/runtime/php-7.1.33-debug]
  --includes          [-I/data/env/runtime/php-7.1.33-debug/include/php -I/data/env/runtime/php-7.1.33-debug/include/php/main -I/data/env/runtime/php-7.1.33-debug/include/php/TSRM -I/data/env/runtime/php-7.1.33-debug/include/php/Zend -I/data/env/runtime/php-7.1.33-debug/include/php/ext -I/data/env/runtime/php-7.1.33-debug/include/php/ext/date/lib]
  --ldflags           []
  --libs              [-lcrypt   -lz -lexslt -lresolv -lcrypt -lrt -lldap -llber -lpng -lz -ljpeg -lcurl -lbz2 -lz -lrt -lm -ldl -lnsl  -lxml2 -lz -lm -ldl -lgssapi_krb5 -lkrb5 -lk5crypto -lcom_err -lssl -lcrypto -lcurl -lxml2 -lz -lm -ldl -lfreetype -lxml2 -lz -lm -ldl -lxml2 -lz -lm -ldl -lcrypt -lxml2 -lz -lm -ldl -lxml2 -lz -lm -ldl -lxml2 -lz -lm -ldl -lxml2 -lz -lm -ldl -lxslt -lxml2 -lz -ldl -lm -lssl -lcrypto -lcrypt ]
  --extension-dir     [/data/env/runtime/php-7.1.33-debug/lib/php/extensions/debug-non-zts-20160303]
  --include-dir       [/data/env/runtime/php-7.1.33-debug/include/php]
  --man-dir           [/data/env/runtime/php-7.1.33-debug/php/man]
  --php-binary        [/data/env/runtime/php-7.1.33-debug/bin/php]
  --php-sapis         [ cli fpm phpdbg cgi]
  --configure-options [--prefix=/data/env/runtime/php-7.1.33-debug --enable-debug --enable-phpdbg-debug --with-config-file-path=/data/env/runtime/php-7.1.33-debug/etc --with-curl --with-freetype-dir --with-gd --with-gettext --with-iconv-dir --with-kerberos --with-libdir=lib64 --with-libxml-dir --with-mysqli --with-openssl --with-pcre-regex --with-pdo-mysql --with-pdo-sqlite --with-pear --with-png-dir --with-jpeg-dir --with-xmlrpc --with-xsl --with-zlib --with-bz2 --with-mhash --enable-fpm --enable-bcmath --enable-libxml --enable-inline-optimization --enable-gd-native-ttf --enable-mbregex --enable-mbstring --enable-opcache --enable-pcntl --enable-shmop --enable-soap --enable-sockets --enable-sysvsem --enable-sysvshm --enable-xml --enable-zip --with-ldap]
  --version           [7.1.33]
  --vernum            [70133]

修改之后大概是這樣子,然后編譯安裝 就可以得到debug版本了

--prefix=/data/env/runtime/php-7.1.33-debug --enable-debug --enable-phpdbg-debug --with-config-file-path=/data/env/runtime/php-7.1.33-debug/etc --with-curl --with-freetype-dir --with-gd --with-gettext --with-iconv-dir --with-kerberos --with-libdir=lib64 --with-libxml-dir --with-mysqli --with-openssl --with-pcre-regex --with-pdo-mysql --with-pdo-sqlite --with-pear --with-png-dir --with-jpeg-dir --with-xmlrpc --with-xsl --with-zlib --with-bz2 --with-mhash --enable-fpm --enable-bcmath --enable-libxml --enable-inline-optimization --enable-gd-native-ttf --enable-mbregex --enable-mbstring --enable-opcache --enable-pcntl --enable-shmop --enable-soap --enable-sockets --enable-sysvsem --enable-sysvshm --enable-xml --enable-zip --with-ldap

php --version中看到DEBUG 就可以了

yongkbmaster ?  ~ /data/env/runtime/php-7.1.33-debug/bin/php --version
PHP 7.1.33 (cli) (built: Dec 29 2020 19:16:50) ( NTS DEBUG )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2018 Zend Technologie

注意:Debug版本的擴展需要再次編譯安裝,不能拷貝正常版本的so,安裝方式和普通擴展一致,一般不需要開額外的debug參數。如果你需要調試擴展比如swoole你需要設置擴展的debug參數,可以參考擴展的./configure文件說明。

gdb使用

這里簡單介紹一下gdb的基本使用,更詳細的使用方法可以自行google。

啟動gdb

捕獲進程

gdb -p {pid}

run 方法啟動

gdb php
run test3.php

通過core 文件

gdb -c core.8451

斷點

break n :在第n行處設置斷點(可以帶上代碼路徑和代碼名稱)

//注意:這里只能斷點c代碼,php文件不行的,var.c:201在php-7.1.33是var_dump的入口
break var.c:201

b fn1 if a>b:條件斷點設置

break func(break縮寫為b):在函數func()的入口處設置斷點

//大部分php的方法在c層面的方法名都是zif_ + php方法名。 例如 var_dump 在c的方法名叫zif_var_dump
break zif_var_dump

delete 斷點號n:刪除第n個斷點

disable 斷點號n:暫停第n個斷點

enable 斷點號n:開啟第n個斷點

clear 行號n:清除第n行的斷點

info b (info breakpoints) :顯示當前程序的斷點設置情況

delete breakpoints:清除所有斷點

其他

  • list (簡寫 l) ,其作用就是列出程序的源代碼,默認每次顯示10行。

  • list 行號:將顯示當前文件以“行號”為中心的前后10行代碼,

  • print a:將顯示 a 的值

  • continue (簡寫c ):繼續執行,到下一個斷點處(或運行結束)。設置斷點后需要按這個。

  • next (簡寫n):當前函數,下一行

  • step (簡寫s):跳入函數內部

  • where/bt :當前運行的堆棧列表;

php gdb 小工具

這里就是本文的重點了php為gdb提供了一組小工具,在源代碼目錄下的.gdbinit文件中,它可以幫助我們更好的gdb php源代碼。

準備

為了更好的演示,我這里準備一個php文件。

<?php
const A = 'test const';
const B = 'test const B';
class B {
        public $a = 'test';
        public function funB() {
                var_dump('test funB');
        }
}
class C extends B {
        public function funC() {
                var_dump('test funC');
        }
}
$a = 'test';
$b = ['a1' => 1, 'a2' => 2];
$c = new B();
$d = [A, B];
$e = new C();
$f = $b;
var_dump($a, $b, $c, $d, $e, $f);
get_object_vars($e);

啟動gdb,設置2個斷點。

gdb php //注意這里要用debug版本的
(gdb) break var.c:211
Breakpoint 1 at 0x76e717: file /data/env/runtime/php-7.1.33-src/ext/standard/var.c, line 211.
(gdb) break zend_object_handlers.c:492
Breakpoint 2 at 0x86ce9d: file /data/env/runtime/php-7.1.33-src/Zend/zend_object_handlers.c, line 492.
(gdb) r test4.php

然后載入小工具

source /data/env/runtime/php-7.1.33-src/.gdbinit

使用

zbacktrace 顯示當前的php調用棧

(gdb) zbacktrace
[0x7ffff1614200] var_dump("test", array(2)[0x7ffff1614260], object[0x7ffff1614270], array(2)[0x7ffff1614280], object[0x7ffff1614290], array(2)[0x7ffff16142a0]) [internal function]
[0x7ffff1614030] (main) /root/test4.php:26

dump_bt 查看當前調用棧 和 zbacktrace 類似

(gdb) dump_bt executor_globals.current_execute_data
[0x7ffff1614200] var_dump("test", array(2)[0x7ffff1614260], object[0x7ffff1614270], array(2)[0x7ffff1614280], object[0x7ffff1614290], array(2)[0x7ffff16142a0]) [internal function]
[0x7ffff1614030] (main) /root/test4.php:26

printzv 輸出zend value 的情況

(gdb) printzv &args[0]
[0x7ffff1614250] (refcount=0) string: test

print_global_vars 輸出全局變量

(gdb) print_global_vars
Hash(13)[0x11bf0d0]: {
  [0] _GET => [0x7ffff1657100] (refcount=2) array:
  [1] _POST => [0x7ffff1657120] (refcount=2) array:
  [2] _COOKIE => [0x7ffff1657140] (refcount=2) array:
  [3] _FILES => [0x7ffff1657160] (refcount=2) array:
  [4] argv => [0x7ffff1657180] (refcount=2) array:
  [5] argc => [0x7ffff16571a0] long: 1
  [6] _SERVER => [0x7ffff16571c0] (refcount=2) array:
  [7] a => [0x7ffff16571e0] indirect: [0x7ffff1613080] (refcount=0) string: test
  [8] b => [0x7ffff1657200] indirect: [0x7ffff1613090] (refcount=5) array:
  [9] c => [0x7ffff1657220] indirect: [0x7ffff16130a0] (refcount=2) object(B) #2
  [10] d => [0x7ffff1657240] indirect: [0x7ffff16130b0] (refcount=2) array:
  [11] e => [0x7ffff1657260] indirect: [0x7ffff16130c0] (refcount=2) object(C) #3
  [12] f => [0x7ffff1657280] indirect: [0x7ffff16130d0] (refcount=5) array:

print_const_table 輸出定義的常量

(gdb) print_const_table executor_globals.zend_constants
[0x14e8380] {
  Hash(2340)[0x14e8380]: {
    [0] E_ERROR => [0x14fd660] long: 1
    [1] E_RECOVERABLE_ERROR => [0x14fe8a0] long: 4096
    [2] E_WARNING => [0x14fe900] long: 2
    [3] E_PARSE => [0x14fe960] long: 4
    [4] E_NOTICE => [0x14fe9c0] long: 8
    [5] E_STRICT => [0x14fea20] long: 2048
    [6] E_DEPRECATED => [0x14fea80] long: 8192
    [7] E_CORE_ERROR => [0x14feae0] long: 16
    [8] E_CORE_WARNING => [0x14feb40] long: 32
    [9] E_COMPILE_ERROR => [0x14feba0] long: 64
    [10] E_COMPILE_WARNING => [0x14fec10] long: 128
    [11] E_USER_ERROR => [0x14fec70] long: 256
    [12] E_USER_WARNING => [0x14fecd0] long: 512
    [13] E_USER_NOTICE => [0x14fed30] long: 1024
    [14] E_USER_DEPRECATED => [0x14feda0] long: 16384
    [15] E_ALL => [0x14fee00] long: 32767
    [16] DEBUG_BACKTRACE_PROVIDE_OBJECT => [0x14fee70] long: 1
    [17] DEBUG_BACKTRACE_IGNORE_ARGS => [0x14feee0] long: 2
    [18] true => [0x14fef70] bool: true
    [19] false => [0x14ff000] bool: false
    [20] ZEND_THREAD_SAFE => [0x14ff070] bool: false
    [21] ZEND_DEBUG_BUILD => [0x14ff0e0] bool: true
    [22] null => [0x14ff170] NULL
    [23] PHP_VERSION => [0x1500380] (refcount=1) string: 7.1.33
 ......

print_zstr 輸出zend string

(gdb) print_zstr args[0]
string(4) "test"
(gdb) print_zstr args[0] 2
string(4) "te..."
(gdb) print_zstr args[0] 4
string(4) "test"

print_cvs 打印已編譯的變量及其值 它需要傳入一個 zend_execute_data 類型的值。可以先bt看一下調用棧。

(gdb) bt //這里看到 #2 層這里是 zend_vm_execute 的執行入口,這里有zend_execute_data 類型的值。
#0  zif_var_dump (execute_data=0x7ffff1614120, return_value=0x7fffffffa9b0) at /data/env/runtime/php-7.1.33-src/ext/standard/var.c:209
#1  0x0000000000ab08d4 in ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER () at /data/env/runtime/php-7.1.33-src/Zend/zend_vm_execute.h:628
#2  0x0000000000ab01c3 in execute_ex (ex=0x7ffff1614030) at /data/env/runtime/php-7.1.33-src/Zend/zend_vm_execute.h:429
#3  0x0000000000ab02d5 in zend_execute (op_array=0x7ffff1672d00, return_value=0x0) at /data/env/runtime/php-7.1.33-src/Zend/zend_vm_execute.h:474
#4  0x0000000000a510f9 in zend_execute_scripts (type=8, retval=0x0, file_count=3) at /data/env/runtime/php-7.1.33-src/Zend/zend.c:1482
#5  0x00000000009c02f4 in php_execute_script (primary_file=0x7fffffffdf30) at /data/env/runtime/php-7.1.33-src/main/main.c:2577
#6  0x0000000000b31387 in do_cli (argc=2, argv=0x14e7f30) at /data/env/runtime/php-7.1.33-src/sapi/cli/php_cli.c:993
#7  0x0000000000b32346 in main (argc=2, argv=0x14e7f30) at /data/env/runtime/php-7.1.33-src/sapi/cli/php_cli.c:1381
(gdb) f 2 //跳到#2 這一層
#2  0x0000000000ab01c3 in execute_ex (ex=0x7ffff1614030) at /data/env/runtime/php-7.1.33-src/Zend/zend_vm_execute.h:429
429                     ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
(gdb) print_cvs ex //輸出
Compiled variables count: 6
[0] 'a'
[0x7ffff1614080] (refcount=0) string: test
[1] 'b'
[0x7ffff1614090] (refcount=5) array:     Hash(2)[0x7ffff170e300]: {
      [0] a1 => [0x7ffff1793e20] long: 1
      [1] a2 => [0x7ffff1793e40] long: 2
}
[2] 'c'
[0x7ffff16140a0] (refcount=2) object(B) #2
Properties     Hash(1)[0x7ffff170e480]: {
      [0] a => [0x7ffff1793f60] indirect: [0x7ffff170e388] (refcount=4) string: test
}
[3] 'd'
[0x7ffff16140b0] (refcount=2) array:     Packed(2)[0x7ffff170e3c0]: {
      [0] 0 => [0x7ffff1793688] (refcount=1) string: test const
      [1] 1 => [0x7ffff17936a8] (refcount=1) string: test const B
}
[4] 'e'
[0x7ffff16140c0] (refcount=2) object(C) #3
Properties     Hash(1)[0x7ffff170e4e0]: {
      [0] a => [0x7ffff17940a0] indirect: [0x7ffff170e448] (refcount=4) string: test
}
[5] 'f'
[0x7ffff16140d0] (refcount=5) array:     Hash(2)[0x7ffff170e300]: {
      [0] a1 => [0x7ffff1793e20] long: 1
      [1] a2 => [0x7ffff1793e40] long: 2
}

print_ht 輸出HashTable, HashTable是php底層一個重要的數據結構是php array的實現方式,你可以理解為是C層面的php array,在php源碼中也大量使用HashTable存儲各類k v結構或數組結構。

(gdb) print_ht args[1].value
Hash(2)[0x7ffff170e300]: {
  [0] a1 => [0x7ffff1793e20] long: 1
  [1] a2 => [0x7ffff1793e40] long: 2
}
(gdb) print_ht args[3].value
Packed(2)[0x7ffff170e3c0]: {
  [0] 0 => [0x7ffff1793688] (refcount=1) string: test const
  [1] 1 => [0x7ffff17936a8] (refcount=1) string: test const B
}

print_htptr 和 print_ht 類似,它輸出的是zval的地址不是zval的值

(gdb) print_htptr args[1].value
Hash(2)[0x7ffff170e300]: {
  [0] a1 => 0x7ffff1793e20
  [1] a2 => 0x7ffff1793e40
}

print_htstr 和 print_ht 類似,只是HashTable中存的不是zval 而是c char,但是這種情況在源碼中好像很少見了,大部分存字符串的情況會直接用zend string,我找了一圈在  php_cli_server_mime_type_ctor 有一處使用

(gdb) print_htstr &server->extension_mime_types
Hash(2)[0x11b9228]: {
  [0] ez => application/andrew-inset
  [1] aw => application/applixware
}

print_ft 和 print_ht 類似,只是HashTable中存的是  zend_function 的地址

(gdb) print_ft &args[2].value.obj.ce.function_table
Hash(1)[0x7ffff1783210]: {
  [0] funb => "funB"
}

print_inh 輸出class相關信息

(gdb) print_inh &args[4].value.obj.ce
class C extends B {
 class B {
 }
}

print_pi 輸出對象中屬性相關信息,它需要傳入一個zend_property_info類型的地址,在zend_object_handlers.c:492中有使用,php中可以用get_object_vars($e) 觸發。

(gdb) c
Continuing.
Breakpoint 2, zend_check_property_access (zobj=0x7ffff170e420, prop_info_name=0x7ffff173c2c0) at /data/env/runtime/php-7.1.33-src/Zend/zend_object_handlers.c:492
492             zend_string_release(member);
(gdb) print_pi property_info
[0x7ffff17833c8] {
    offset = 0x28
    ce = [0x7ffff17831d0] B
    flags = 0x100 (ZEND_ACC_PUBLIC)
    name  = string(1) "a"
    default value: [0x7ffff17690c0] (refcount=4) string: test
}

關于“PHP如何用gdb調試源碼”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“PHP如何用gdb調試源碼”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

凤翔县| 崇州市| 喀喇沁旗| 美姑县| 特克斯县| 渝中区| 武乡县| 穆棱市| 锦屏县| 河源市| 繁昌县| 东乌珠穆沁旗| 阿城市| 柳河县| 石嘴山市| 琼海市| 黑山县| 年辖:市辖区| 桐乡市| 青铜峡市| 平原县| 宜城市| 循化| 诏安县| 奎屯市| 武隆县| 察隅县| 珠海市| 清徐县| 台江县| 庆阳市| 合江县| 靖安县| 沙湾县| 安福县| 台江县| 盘锦市| 双峰县| 邻水| 桦川县| 新宁县|