php-src-debug记录

wsl + vscode + qemu + bear 甚至可以调试跨架构的操作系统源码

!前排提醒,你看我的文章进行的操作一定会遇到各种各样的报错,请根据自己的实际情况debug以及查找解决方案!

php-src clone以及编译

https://github.com/php/php-src 请RTFM,很多都可以在mannul找到

  git clone https://github.com/php/php-src.git
  git checkout PHP-8.2
  # 安装一些必要的依赖,based on ubuntu
  sudo apt install -y pkg-config build-essential autoconf bison re2c libxml2-dev libsqlite3-dev
  ./buildconf
  ./configure --disable-all --enable-debug --enable-phar --prefix=/home/yyz/php-src/build/php/
  # 推荐使用bear生成compile_commands.json
  # bear -- make -j8
  make -j8

bear神器

https://github.com/rizsotto/Bear 请RTFM,很多都可以在mannul找到

Bear is a tool that generates a compilation database for clang tooling.

Usage — bear -- <your-build-command>

这个编译出来后会在目录下面生成compile_commands.json,在vscode中实现代码跳转的话需要clangd插件支持,当然在debug的时候本身gdb会自带符号表信息,所以可以不需要这个就可以自动跳转。

vscode-clangd-plugins支持

找到插件后装好即可

注意需要clangd的binary在PATH下面,这样vscode才能找到,但是vscode会自动帮你安装的,如果出错,请看log,或者手动安装。

RTFM

WSL – vscode 远程调试

一些插件

  • WSL
  • C/C++ Extension Pack
  • Native Debug
  • others you like

wsl远程开发环境

WSL2的优点无需多说,yyds

下载插件WSL

找到左侧栏的远程按钮,自己探索一下就知道了

打开你的php-src目录,这样的环境就是vscode远程开发环境了

开始你的调试准备工作

.vscode/launch.json文件 — 控制调试相关

在vscode左侧Run and Debug -> add Configuration可以添加控制当前程序调试的相关配置文件launch.json,你可以设置成这样,相关参数自行搜索了解

 {
     // 使用 IntelliSense 了解相关属性。 
     // 悬停以查看现有属性的描述。
     // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
     "version": "0.2.0",
     "configurations": [
         {
             "name": "debuug php source",
             "type": "cppdbg",
             "request": "launch",
             "program": "/home/yyz/php-src/build/php/bin/php",
             "args": ["-f","/home/yyz/php-src/yyz.php"],
             "stopAtEntry": true,
             "cwd": "${fileDirname}",
             "environment": [],
             "externalConsole": false,
             "MIMode": "gdb"
         }
         
 ​
     ]
 }

.vscode/tasks.json文件 — 控制编译相关

可选,可以知道这个文件配置好的话,可以在debug之前重新编译一下你的binary,这样你可以实时patch代码。

例如,下面是chatgpt为我生成的一个json示例

 {
     // generated by chatgpt3.5
     // 在task中,label可以定义任务的名称,在command中定义重新编译php的命令。在这个例子中,每次重新编译时会先运行make clean来清空之前的编译信息,然后再运行buildconf和configure等命令重新配置和编译php。
     // 此外,还可以在.vscode/tasks.json中配置problemMatcher以捕获编译过程中出现的问题(例如警告和错误),以便能够在输出面板中捕获和解释问题。
     "version": "2.0.0",
     "tasks": [
         {
             "label": "rebuild-php",
             "type": "shell",
             "command": "make clean && ./buildconf && ./configure && make",
             "group": {
                 "kind": "build",
                 "isDefault": true
             },
             "problemMatcher": {
                 "owner": "php",
                 "fileLocation": ["relative", "${workspaceFolder}/"],
                 "pattern": {
                     "regexp": "^(.*)\\((\\d+)\\):\\s+(warning|error):\\s+(.*)$",
                     "file": 1,
                     "line": 2,
                     "severity": 3,
                     "message": 4
                 }
             }
         }
     ]
 }

如果一些准备工作都就绪了,按下f5,程序会停在./sapi/cli/php_cli.c:1161

glibc调试

查看本地glibc源码

其实想要调试libc,可以不看本地的glibc版本号

 ldd --version

下载源码

 git clone https://mirrors.tuna.tsinghua.edu.cn/git/glibc.git
 # 切换分支,如果必要的话
 git branch -r
 git checkout origin/release/2.35/master

编译

参考官方文档:https://sourceware.org/glibc/wiki/Testing/Builds

 mkdir build
 cd build
 ../configure --prefix=/glibc/x64/2.23/ --disable-werror --enable-debug=yes
 make -j8
 sudo make check  // Do not run make install.

vscode或者gdb中添加环境变量配置即可调试时步进到glibc源码

 {
     "version": "0.2.0",
     "configurations": [
         {
             "name": "debuug php source",
             "type": "cppdbg",
             "request": "launch",
             "program": "/home/yyz/php-src/build/php/bin/php",
             "args": ["-f","/home/yyz/php-src/yyz.php"],
             "stopAtEntry": true,
             "cwd": "${fileDirname}",
             "environment": [
                 {
                     "name": "LD_LIBRARY_PATH",
                     "value": "/glibc/x64/2.35/lib"
                 }
             ],
             "externalConsole": false,
             "MIMode": "gdb"
         }
     ]
 }

简单看看base64_decode和system的函数实现

不想写了。。。之前录了个视频给学弟们,应该有简单的提到。直接总结一下吧:

base64_decode

  • 实现了下面的论文描述的base64加解密算法
 // ext/standard/base64.c:793
 /* See: "Faster Base64 Encoding and Decoding using AVX2 Instructions"
 * https://arxiv.org/pdf/1704.00605.pdf */

当时我看base64的算法只是想找到为什么base64_decode的时候会跳过处理一些不属于base64 table里面的字符。

根据论文中描述的可以找到如下说法

然后也确实能在源码中找到跳过不合法字符的算法实现:

 // ext/standard/base64.c:269
 ch = base64_reverse_table[ch];
 if (!strict) {
     /* skip unknown characters and whitespace */
     if (ch < 0) {
         continue;
     }
 } else {
     /* skip whitespace */
     if (ch == -1) {
         continue;
     }
     /* fail on bad characters or if any data follows padding */
     if (ch == -2 || padding) {
         goto fail;
     }
 }

可以自行打断点调试

system

总结:

  • 传入的字符串直接以char * 数组整个传进去
  • 最底层调用了libc中的popen函数
  • popen最底层调用了/bin/sh来传递命令执行的参数
  • clone3系统调用派生新的进程用以执行/bin/sh
    • 跟进__clone_internal即可,代码如下 // /home/yyz/glibc/sysdeps/unix/sysv/linux/spawni.c:388
       new_pid = __clone_internal (&clone_args, __spawni_child, &args);
    • (注意是先尝试调用clone3,并且在ubuntu22上可以直接成功,这一点可以自行源码调试发现)
  • 注意上面的__spawni_child函数的第二个参数__spawni_child是一个函数指针,他会处理子进程的execve的流程
  • 最终调用execve的地方在下面的代码,(与教科书上的描述一致,fork+execve,只不过细微处理上面clone3比fork处理的更好) // /home/yyz/glibc/sysdeps/unix/sysv/linux/spawni.c:290
       args->exec (args->file, args->argv, args->envp);
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇