php core tool - yaokun123/php-wiki GitHub Wiki

php内核分析-源码分析的环境和工具

一、工具清单

  • PHP7.0.12
  • GDB/LLDB
  • CLion

二、源码下载及安装

  • 2.1、第一步:下载源码:

https://github.com/php/php-src

  • 2.2、第二步:编译:

如何编译PHP请查阅官方文档 编译的时候请添加–debug=1的参数,这样才能更好的调试代码,不加的话,很多地方打断点无效,应该是被编译器优化掉了。

brew install libiconv
#按照提示配置环境变量


$ wget http://php.net/distributions/php-7.0.12.tar.gz
$ tar zxvf php-7.0.12.tar.gz
$ cd php-7.0.12/


修改1:
vim ./main/reentrancy.c
139行修改为readdir_r(dirp, entry, &entry);

$ ./buildconf --force

$ ./configure --prefix=/Users/yaokun/php-private/php-source-code/php7.0.12 --with-iconv=/usr/local/opt/libiconv/ --enable-debug --enable-fpm --without-pear --disable-phar --enable-pdo --with-pdo-mysql --enable-mysqlnd

修改2:
vim Makefile
搜索 EXTRA_LIBS = 这里-liconv替换成/usr/local/opt/libiconv/lib/libiconv.dylib

$ make && sudo make install

三、GDB的安装与调试

3.1 安装

本文介绍两款调试工具,分别是GDB和CLion,前者为命令行调试工具,后者为图形界面调试工具,后者依赖前者。两者的安装都很简单,Clion到官网下载即可,GDB也只需一行命令就可搞定。

yum install gdb

3.2 调试

创建php文件 vim index.php

<?php
    echo "Hello world!";
?>

打开gdb

[root@crm yaok]# gdb php
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-120.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /usr/local/bin/php...done.
(gdb)

调试创建的php文件

(gdb) b main
Breakpoint 1 at 0x43dd30: file /root/php-7.0.7/sapi/cli/php_cli.c, line 1165.
(gdb) run index.php
Starting program: /usr/local/bin/php index.php
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".

Breakpoint 1, main (argc=2, argv=0x7fffffffe2d8) at /root/php-7.0.7/sapi/cli/php_cli.c:1165
1165	{
(gdb)

调试变量技巧

//使用echo
$a = 1;
echo $a;

//gdb中在ZEND_ECHO_SPEC_CV_HANDLER处打断点

关于GDB的具体指令,可以参考官方文档,这里不再一一赘述。

mac下的gdb不好用,用lldb如果在linux下调试代码,请使用gdb。使用教程如下: https://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/gdb.html

php为了方便gdb调试,专门给gdb写了一些便捷的方法,执行gdb的时候source一下就行。文件是: https://github.com/he1016060110/php-src/blob/master/.gdbinit

函数 用法 功能
print_cvs (gdb) print_cvs 打印已编译的变量及其值 它需要传入一个zend_execute_data类型的值。可以先bt看一下调用栈。
- print_cvs [zend_execute_data *] Prints the compiled variables and their values.If a zend_execute_data pointer is set this will print the compiled variables of that scope. If no parameter is used it will use current_execute_data for scope
dump_bt 打印PHP的函数调用栈
- dumps the current execution stack. usage: dump_bt executor_globals.current_execute_data
printzv (gdb) printzv 0x9543f98 打印指定的PHP变量, 需要指定地址
- prints zval contents
print_global_vars 输出全局变量
- Prints the global variables
print_const_table 输出定义的常量
- Dumps elements of Constants HashTable Example: print_const_table executor_globals.zend_constants
print_ht 输出HashTable
- dumps elements of HashTable made of zval
print_htptr 和 print_ht 类似,它输出的是zval的地址不是zval的值
- dumps elements of HashTable made of pointers
print_htstr print_ht 类似,只是HashTable中存的不是zval 而是c char,但是这种情况在源码中好像很少见了,大部分存字符串的情况会直接用zend string,我找了一圈在php_cli_server_mime_type_ctor有一处使用
- dumps elements of HashTable made of strings
print_ft 和 print_ht 类似,只是HashTable中存的是zend_function的地址
- dumps a function table (HashTable)
print_inh 输出class相关信息
print_pi 输出对象中属性相关信息,它需要传入一个zend_property_info类型的地址,在zend_object_handlers.c:492中有使用,php中可以用get_object_vars($e) 触发。
- print_pi Takes a pointer to an object's property and prints the property information
printzn printzn &opline->op1 print type and content of znode.
printzops dump operands of the current opline
print_zstr print_zstr [max length] print the length and contents of a zend string
zbacktrace 同dump_bt
lookup_root lookup_root [ptr]. lookup a refcounted in root

详细使用:https://www.163.com/dy/article/GAPL8R8L0518R7MO.html

四、CLion的配置与调试

4.1 配置

CLion的安装就不再赘述了,下面我来讲述一下CLion是如何配置的。打开CLion,选中菜单栏中的File -> Import Project...,选择下载的PHP源码包,如图所示,点击确定。

导入之后,打开项目根目录的CMakeLists.txt文件,将该文件替换为以下内容,注意版本、源码目录要根据实际情况做调整

cmake_minimum_required(VERSION 3.13)
project(makefile)

set(CMAKE_CXX_STANDARD 11)

set(PHP_SOURCE /Users/enoch/Documents/source/php-7.3.4)
include_directories(${PHP_SOURCE}/main)
include_directories(${PHP_SOURCE}/Zend)
include_directories(${PHP_SOURCE}/sapi)
include_directories(${PHP_SOURCE}/pear)
include_directories(${PHP_SOURCE}/TSRM)
include_directories(${PHP_SOURCE})

add_custom_target(makefile COMMAND make && make install WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})

或者使用如下整理的CMakeLists.txt: https://github.com/he1016060110/php-src/blob/learn/CMakeLists.txt

完成后,打开菜单栏Run -> Edit Configurations...,Target选择makefile、Executable选择PHP的可执行二进制程序、Program arguments填写要执行的脚本名称、Working Directory填写要执行脚本的存放目录

4.2 调试

点击完成,我们来验证一下配置是否成功。先在工作目录创建index.php文件,内容随意输入,只要是PHP代码即可。例如:

<?php
    echo 'Hello world';
?>

回到CLion,打开sapi/cli/php_cli.c文件,在main函数进行断点,如下图:略...

加入断点后,点击菜单Run -> Debug 'makefile',等待IDE编译完成后,若出现下图即大功告成。略...

参考:

https://www.cnblogs.com/pingyeaa/p/9547595.html

https://zhuanlan.zhihu.com/p/78454124

⚠️ **GitHub.com Fallback** ⚠️