使用vscode除錯PHP底層C原始碼
一直想著有機會除錯一下php底層代碼來著,這周正好心血來潮,就跟著教程配置了一下,本篇文章是基于macOS,可能在編譯php原始碼之前的步驟對使用windows的師傅沒啥可參考的,
windows下比較麻煩,主要是在編譯php原始碼這一步,最方便的辦法是用docker來遠程除錯,具體可以參考這篇文章vscode遠程除錯php底層代碼,使用p牛的dockerfile來自己建一個除錯用docker,
說回mac下除錯PHP原始碼需要的準備
下載并編譯PHP
使用git來下載原始碼,這樣切換PHP版本會較為方便,(不過我現在應該不會這么做,因為下載下來的原始碼并不能直接編譯成功,需要自己修改,改完的原始碼不舍得切換了)
git clone https://github.com/php/php-src
cd php-src/
git checkout PHP-7.3.67
當然,不排除個人環境的原因,通過checkout切換分支,重新編譯一下還是很方便的,如果編譯不出錯的話,
如果是mac,編譯PHP前需要安裝一下最新版的bison,mac自帶的版本太老,
brew install bison
# bison的具體路徑可以通過brew list bison來查看
export PATH=/opt/homebrew/Cellar/bison/3.8.2/bin:$PATH
編譯需要除錯的PHP,像我這里就開啟了debug模式,開啟了phar擴展,如果需要開啟別的擴展,需要再./configure命令后面自行指定,
./buildconf
./configure --disable-all --enable-debug --enable-phar --prefix=/source/php7.3.6/
make
make install
編譯完后,編譯結果都在/source/php7.3.6/檔案夾下,/source/php7.3.6/bin/php為可執行檔案,
編譯好的PHP,執行./php -v 會顯示NTS DEBUG,

編譯程序中的錯誤
在進行make編譯的時候,碰到了兩次報錯,
第一個報錯:
/Users/niushaogang/jkbPhpPackage/php-5.4.45/main/reentrancy.c:139:23: error: too few arguments to function call, expected 3, have 2
readdir_r(dirp, entry);
~~~~~~~~~ ^
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/dirent.h:110:5: note: 'readdir_r' declared here
int readdir_r(DIR *, struct dirent *, struct dirent **) __DARWIN_INODE64(readdir_r);
^
1 error generated.
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)即可編譯通過

第二個報錯:
/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]
yystpcpy(yyres, "end of file");
^
/Users/dre0m1/CTF/學習筆記/PHP原始碼/php-src/Zend/zend_language_parser.y:1317:5: note: did you mean 'stpcpy'?
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/string.h:130:7: note: 'stpcpy' declared here
char *stpcpy(char *__dst, const char *__src);
^
/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]
yystr_len = (unsigned int)yystrlen(yystr);
^
/Users/dre0m1/CTF/學習筆記/PHP原始碼/php-src/Zend/zend_language_parser.y:1324:29: note: did you mean 'strlen'?
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/string.h:82:9: note: 'strlen' declared here
size_t strlen(const char *__s);
^
/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]
yystpcpy(yyres, buffer);
^
/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]
return yystrlen(yystr) - (*yystr == '"' ? 2 : 0);
^
/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]
yystpcpy(yyres, yystr);
^
5 errors generated.
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函式的位置一共有三處:
if (yyres) {
yystpcpy(yyres, "end of file");
}
return sizeof("end of file")-1;
}
yystpcpy(yyres, buffer);
yystpcpy(yyres, yystr);
看樣子應該就是stpcpy函式沒錯了,試著在上面的#define處加入yystpcpy與yystrlen的定義:
#define yystpcpy zendstpcpy
#define yystrlen zenddtrlen
依舊報錯,這邊是我沒動腦子了,光想著和上面的define內容結構統一,但是strlen和stpcpy這兩個函式前面其實是不需要zend前綴的,

修改之后重新編譯,make成功,
vscode除錯
用vscode打開PHP原始碼,增加一個除錯的配置:

選擇環境c++(GDB/LLDB)-> Default Configuration,然后會生成一個組態檔:
{
// 使用 IntelliSense 了解相關屬性,
// 懸停以查看現有屬性的描述,
// 欲了解更多資訊,請訪問: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "debuug php source",
"type": "cppdbg",
"request": "launch",
"program": "/Users/dre0m1/CTF/學習筆記/PHP原始碼/source/bin/php",
"args": ["-f","/Users/dre0m1/CTF/學習筆記/PHP原始碼/1.php"],
"stopAtEntry": true,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "lldb"
}
]
}
引數詳解:
- program 可執行的PHP檔案的路徑(編譯生成的php檔案)
- args 傳給php的引數串列,像我上面所填寫的執行的就是
php -f /Users/dre0m1/CTF/學習筆記/PHP原始碼/1.php - cwd 當前目錄,如果除錯web應用,可以改成web根目錄的路徑
- stopAtEntry 是否在main函式的時候斷下
之后就可以正常除錯了,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/541925.html
標籤:其他
上一篇:學習筆記——Spring簡介;Spring搭建步驟;Spring的特性;Spring中getBean三種方式;Spring中的標簽
下一篇:陣列
