使用vscode调试PHP底层C源码

打印 上一主题 下一主题

主题 644|帖子 644|积分 1932

使用vscode调试PHP底层C源码

一直想着有机会调试一下php底层代码来着,这周正好心血来潮,就跟着教程配置了一下。本篇文章是基于macOS,可能在编译php源码之前的步骤对使用windows的师傅没啥可参考的。
windows下比较麻烦,主要是在编译php源码这一步,最方便的办法是用docker来远程调试。具体可以参考这篇文章vscode远程调试php底层代码。使用p牛的dockerfile来自己建一个调试用docker。
说回mac下调试PHP源码需要的准备
下载并编译PHP

使用git来下载源码,这样切换PHP版本会较为方便。(不过我现在应该不会这么做,因为下载下来的源码并不能直接编译成功,需要自己修改。改完的源码不舍得切换了)
  1. git clone https://github.com/php/php-src
  2. cd php-src/
  3. git checkout PHP-7.3.67
复制代码
当然,不排除个人环境的原因,通过checkout切换分支,重新编译一下还是很方便的,如果编译不出错的话。
如果是mac,编译PHP前需要安装一下最新版的bison,mac自带的版本太老。
  1. brew install bison
  2. # bison的具体路径可以通过brew list bison来查看
  3. export PATH=/opt/homebrew/Cellar/bison/3.8.2/bin:$PATH
复制代码
编译需要调试的PHP。像我这里就开启了debug模式,开启了phar扩展,如果需要开启别的扩展,需要再./configure命令后面自行指定。
  1. ./buildconf
  2. ./configure --disable-all --enable-debug --enable-phar --prefix=/source/php7.3.6/
  3. make
  4. make install
复制代码
编译完后,编译结果都在/source/php7.3.6/文件夹下,/source/php7.3.6/bin/php为可执行文件。
编译好的PHP,执行./php -v 会显示NTS DEBUG。

编译过程中的错误

在进行make编译的时候,碰到了两次报错。
第一个报错:
  1. /Users/niushaogang/jkbPhpPackage/php-5.4.45/main/reentrancy.c:139:23: error: too few arguments to function call, expected 3, have 2
  2.         readdir_r(dirp, entry);
  3.         ~~~~~~~~~            ^
  4. /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/dirent.h:110:5: note: 'readdir_r' declared here
  5. int readdir_r(DIR *, struct dirent *, struct dirent **) __DARWIN_INODE64(readdir_r);
  6.     ^
  7. 1 error generated.
  8. make: *** [main/reentrancy.lo] Error 1
复制代码
根据网上的教程,了解到这是php源码调用readdir_r函数的时候少传了一个参数。
查看php-src/main/reentrancy.c
函数定义:
​    int readdir_r(DIR *, struct dirent *, struct dirent **)
php调用:
​    readdir_r(dirp, entry)
readdir_r(dirp, entry) 修改为 readdir_r(dirp, entry,&entry)即可编译通过

第二个报错:
  1. /Users/dre0m1/CTF/学习笔记/PHP源码/php-src/Zend/zend_language_parser.y:1317:5: error: implicit declaration of function 'yystpcpy' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
  2.                                 yystpcpy(yyres, "end of file");
  3.                                 ^
  4. /Users/dre0m1/CTF/学习笔记/PHP源码/php-src/Zend/zend_language_parser.y:1317:5: note: did you mean 'stpcpy'?
  5. /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/string.h:130:7: note: 'stpcpy' declared here
  6. char    *stpcpy(char *__dst, const char *__src);
  7.          ^
  8. /Users/dre0m1/CTF/学习笔记/PHP源码/php-src/Zend/zend_language_parser.y:1324:29: error: implicit declaration of function 'yystrlen' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
  9.                 yystr_len = (unsigned int)yystrlen(yystr);
  10.                                           ^
  11. /Users/dre0m1/CTF/学习笔记/PHP源码/php-src/Zend/zend_language_parser.y:1324:29: note: did you mean 'strlen'?
  12. /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/string.h:82:9: note: 'strlen' declared here
  13. size_t   strlen(const char *__s);
  14.          ^
  15. /Users/dre0m1/CTF/学习笔记/PHP源码/php-src/Zend/zend_language_parser.y:1345:4: error: implicit declaration of function 'yystpcpy' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
  16.                         yystpcpy(yyres, buffer);
  17.                         ^
  18. /Users/dre0m1/CTF/学习笔记/PHP源码/php-src/Zend/zend_language_parser.y:1352:10: error: implicit declaration of function 'yystrlen' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
  19.                 return yystrlen(yystr) - (*yystr == '"' ? 2 : 0);
  20.                        ^
  21. /Users/dre0m1/CTF/学习笔记/PHP源码/php-src/Zend/zend_language_parser.y:1365:2: error: implicit declaration of function 'yystpcpy' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
  22.         yystpcpy(yyres, yystr);
  23.         ^
  24. 5 errors generated.
  25. make: *** [Zend/zend_language_parser.lo] Error 1
复制代码
报错内容较多,出现在Zend/zend_language_parser.lo位置。当时查找了好久的资料,都没有找到相关的内容。只知道implicit declaration of function 'yystrlen' is invalid in C99这种报错类型是因为缺少相应的定义,由报错中的提示可以看出应该是缺少了yystpcpy这个函数。
访问文件php-src/Zend/zend_language_parser.c,可以看到这样一段代码

格式和yystpcpy还有yystrlen异常的统一,我当时就怀疑应该是在这个c文件中进行了函数重命名。
代码中出现yystpcpy函数的位置一共有三处:
  1. if (yyres) {
  2.                                 yystpcpy(yyres, "end of file");
  3.                         }
  4.                         return sizeof("end of file")-1;
  5.                 }
  6. yystpcpy(yyres, buffer);
  7. yystpcpy(yyres, yystr);
复制代码
看样子应该就是stpcpy函数没错了,试着在上面的#define处加入yystpcpy与yystrlen的定义:
  1. #define yystpcpy     zendstpcpy
  2. #define yystrlen     zenddtrlen
复制代码
依旧报错,这边是我没动脑子了,光想着和上面的define内容结构统一,但是strlen和stpcpy这两个函数前面其实是不需要zend前缀的。

修改之后重新编译,make成功。
vscode调试

用vscode打开PHP源码,增加一个调试的配置:

选择环境c++(GDB/LLDB)-> Default Configuration,然后会生成一个配置文件:
  1. {
  2.     // 使用 IntelliSense 了解相关属性。
  3.     // 悬停以查看现有属性的描述。
  4.     // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
  5.     "version": "0.2.0",
  6.     "configurations": [
  7.         {
  8.             "name": "debuug php source",
  9.             "type": "cppdbg",
  10.             "request": "launch",
  11.             "program": "/Users/dre0m1/CTF/学习笔记/PHP源码/source/bin/php",
  12.             "args": ["-f","/Users/dre0m1/CTF/学习笔记/PHP源码/1.php"],
  13.             "stopAtEntry": true,
  14.             "cwd": "${fileDirname}",
  15.             "environment": [],
  16.             "externalConsole": false,
  17.             "MIMode": "lldb"
  18.         }
  19.         
  20.     ]
  21. }
复制代码
参数详解:

  • program 可执行的PHP文件的路径(编译生成的php文件)
  • args 传给php的参数列表,像我上面所填写的执行的就是php -f /Users/dre0m1/CTF/学习笔记/PHP源码/1.php
  • cwd 当前目录,如果调试web应用,可以改成web根目录的路径
  • stopAtEntry 是否在main函数的时候断下
之后就可以正常调试了。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

没腿的鸟

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表