Deep understanding of PHP: debugging source code with gdb
This article brings you relevant knowledge about PHP, which mainly introduces the relevant content about using gdb to debug source code. Let’s take a look at it together. I hope it will be helpful to everyone.
Recommended study: "PHP Video Tutorial"
There is a debug mode when php is compiled, this mode will turn off memory optimization. Prompt memory leaks, shielding call stack optimization allows us to see the complete PHP C-level call stack.
Usually I compile two php versions (one normal, one with debug enabled) in different directories, and decide which one to use through export.
You can see configure-options through the php-config command, modify the prefix and with-config-file-path to the new directory, and then add the --enable-debug command
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]
After modification, it will probably look like this. Then compile and install to get the debug version.
--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
Just see DEBUG in php --version
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
Note: The debug version of the extension needs to be compiled again. During installation, you cannot copy the normal version of so. The installation method is the same as that of ordinary extensions. Generally, there is no need to open additional debug parameters. If you need to debug an extension such as swoole, you need to set the debug parameters of the extension. You can refer to the ./configure file description of the extension.
gdb usage
Here is a brief introduction to the basic use of gdb. For more detailed usage, you can google it yourself.
Start gdb
Capture process
gdb -p {pid}
run method starts
gdb php run test3.php
Through core file
gdb -c core.8451
Breakpoint
break n: Set a breakpoint at line n (you can bring the code path and code name)
//注意:这里只能断点c代码,php文件不行的,var.c:201在php-7.1.33是var_dump的入口 break var.c:201
b fn1 if a>b: Conditional breakpoint setting
break func (break is abbreviated as b): Set a breakpoint at the entrance of function func()
//大部分php的方法在c层面的方法名都是zif_ + php方法名。 例如 var_dump 在c的方法名叫zif_var_dump break zif_var_dump
delete breakpoint Number n: Delete the nth breakpoint
disable Breakpoint number n: Pause the nth breakpoint
enable Breakpoint number n: Enable the nth breakpoint
clear line number n: Clear the breakpoint on line n
info b (info breakpoints): Display the breakpoint settings of the current program
delete breakpoints: Clear all breakpoints
Others
list (abbreviated as l), its function is to list the source code of the program. By default, 10 lines are displayed at a time .
list line number: will display the 10 lines of code before and after the current file centered on the "line number",
print a: will display The value of a
continue (abbreviated as c): Continue execution to the next breakpoint (or end of the run). You need to press this after setting a breakpoint.
next (abbreviation n): current function, next line
step (abbreviation s): jump into the function
where/bt: currently running stack list;
php gdb gadget
This is the focus of this article. PHP provides gdb A set of small tools, in the .gdbinit file in the source code directory, which can help us make better gdb php source code.
Preparation
For a better demonstration, I will prepare a php file here.
<?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);
Start gdb and set 2 breakpoints.
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
Then load the gadget
source /data/env/runtime/php-7.1.33-src/.gdbinit
Use
zbacktrace to display the current php call stack
(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 View the current call stack and zbacktrace similar to
(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 output zend value
(gdb) printzv &args[0] [0x7ffff1614250] (refcount=0) string: test
print_global_vars output global variables
(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 output defined constants
(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 Output 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 Print compiled variables and their values It needs to pass in a zend_execute_data type value. You can take a look at the call stack first.
(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 Output HashTable. HashTable is an important data structure at the bottom of PHP. It is the implementation of PHP array. You can understand it as C-level PHP array. HashTable is also widely used in PHP source code to store various k v structure or array structure.
(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 is similar to print_ht, it outputs the address of zval instead of the value of zval
(gdb) print_htptr args[1].value Hash(2)[0x7ffff170e300]: { [0] a1 => 0x7ffff1793e20 [1] a2 => 0x7ffff1793e40 }
print_htstr is similar to print_ht, except that the HashTable stores c char instead of zval, but this This situation seems to be rare in the source code. In most cases of storing strings, zend string will be used directly. I searched around and found a place in php_cli_server_mime_type_ctor where
(gdb) print_htstr &server->extension_mime_types Hash(2)[0x11b9228]: { [0] ez => application/andrew-inset [1] aw => application/applixware }
print_ft is similar to print_ht, but it is stored in HashTable. Is the address of zend_function
(gdb) print_ft &args[2].value.obj.ce.function_table Hash(1)[0x7ffff1783210]: { [0] funb => "funB" }
print_inh Outputs class-related information
(gdb) print_inh &args[4].value.obj.ce class C extends B { class B { } }
print_pi Outputs attribute-related information in the object. It needs to pass in an address of zend_property_info type, which is used in zend_object_handlers.c:492 , it can be triggered by get_object_vars($e) in PHP.
(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 }
Recommended learning: "PHP Video Tutorial"
The above is the detailed content of Deep understanding of PHP: debugging source code with gdb. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics



PHP 8.4 brings several new features, security improvements, and performance improvements with healthy amounts of feature deprecations and removals. This guide explains how to install PHP 8.4 or upgrade to PHP 8.4 on Ubuntu, Debian, or their derivati

Visual Studio Code, also known as VS Code, is a free source code editor — or integrated development environment (IDE) — available for all major operating systems. With a large collection of extensions for many programming languages, VS Code can be c

If you are an experienced PHP developer, you might have the feeling that you’ve been there and done that already.You have developed a significant number of applications, debugged millions of lines of code, and tweaked a bunch of scripts to achieve op

This tutorial demonstrates how to efficiently process XML documents using PHP. XML (eXtensible Markup Language) is a versatile text-based markup language designed for both human readability and machine parsing. It's commonly used for data storage an

JWT is an open standard based on JSON, used to securely transmit information between parties, mainly for identity authentication and information exchange. 1. JWT consists of three parts: Header, Payload and Signature. 2. The working principle of JWT includes three steps: generating JWT, verifying JWT and parsing Payload. 3. When using JWT for authentication in PHP, JWT can be generated and verified, and user role and permission information can be included in advanced usage. 4. Common errors include signature verification failure, token expiration, and payload oversized. Debugging skills include using debugging tools and logging. 5. Performance optimization and best practices include using appropriate signature algorithms, setting validity periods reasonably,

A string is a sequence of characters, including letters, numbers, and symbols. This tutorial will learn how to calculate the number of vowels in a given string in PHP using different methods. The vowels in English are a, e, i, o, u, and they can be uppercase or lowercase. What is a vowel? Vowels are alphabetic characters that represent a specific pronunciation. There are five vowels in English, including uppercase and lowercase: a, e, i, o, u Example 1 Input: String = "Tutorialspoint" Output: 6 explain The vowels in the string "Tutorialspoint" are u, o, i, a, o, i. There are 6 yuan in total

Static binding (static::) implements late static binding (LSB) in PHP, allowing calling classes to be referenced in static contexts rather than defining classes. 1) The parsing process is performed at runtime, 2) Look up the call class in the inheritance relationship, 3) It may bring performance overhead.

What are the magic methods of PHP? PHP's magic methods include: 1.\_\_construct, used to initialize objects; 2.\_\_destruct, used to clean up resources; 3.\_\_call, handle non-existent method calls; 4.\_\_get, implement dynamic attribute access; 5.\_\_set, implement dynamic attribute settings. These methods are automatically called in certain situations, improving code flexibility and efficiency.
