• 使用GDB调试PHP Core


    使用GDB调试PHP Core

    GDB

    GDB工具的使用方法如下

    简介

    GDB是UNIX下程序调试工具,可以用来调试C/C++开发的程序

    gdb调试是命令行交互式

    使用方法

    gdb使用的3种方式

    • gdb -p 进程ID
      跟踪正在运行的PHP程序,使用gdb -p 进程ID
    • gdb php
      使用gdb运行并调试PHP程序,使用 gdb php -> run server.php 进行调试
    • gdb php core
      PHP程序发生coredump后,使用gdb加载core内存镜像进行调试, gdb php core

    常用命令

    1. p: print,打印c变量的值
    2. c: coninue,继续运行被中止的程序
    3. b: breakpoint,设置断点,可以按照函数名设置,如 b zip_php_function,也可按照源代码的函数指定断点,如 b src/network/Server.c:1000
    4. t: thread,切换线程,如果进程拥有多个线程,可以使用t指令,切换到不同的线程
    5. n: next,执行下一行,单步调试
    6. info thread: 查看运行的所有线程
    7. l: list,查看源码,可以使用l 函数名或者 l 行号
    8. bt: backtrace,查看运行时的函数调用栈
    9. finish: 完成当前函数
    10. f: frame,与bt配合使用,可以切换到函数调用栈的某一层
    11. r: run,运行程序

    php自定义的gdb指令

    • zbacktrace
      zbacktrace是php源码包提供的gdb自定义指令,功能与backtrace指令类似,与bt不同的是zbacktrace看到的调用栈是php函数调用栈,而不是c函数
      在gdb shell中使用
    source .gdbinit
    zbractrace
    

    跟踪调试正在运行的PHP程序

    • 运行php脚本
      准备php脚本
    <?php
    
    class Test {
    }
    
    function a($i) {
        b(new Test, 2.3432, "reader");
    }
    function b($i) {
        c(array(1,2,3));
    }
    function c($i) {
        d(TRUE);
    }
    function d($i) {
        $fp = fopen("/tmp/1.php", "r");
        e($fp);
    }
    
    function e($i) {
        sleep(1000);
    }
    
    a(2);
    

    运行脚本

    root@37abad564db2:/var/www/php/php# /var/www/php/php-7.4.20/sapi/cli/php 1.php
    
    • 查看进程ID
    ps aux | grep php
    

    • 使用gdb跟踪该进程ID
    gdb --pid 46121
    

    • 加载php自定义gdb指令,执行zbacktrace指令
    (gdb) source /var/www/php/php-7.4.20/.gdbinit
    zbacktrace
    

    • 查看array具体元素
    print ((zval *)0x7fd3046121f0)
    printzv $1
    

    • 查看object
    print ((zval *)0x7fd304612160)
    printzv $3
    

    运行并调试php程序

    运行调试流程

    gdb --args /var/www/php/php-7.4.20/sapi/cli/php -r "echo 'hello world';"

    把php命令放在--args 选项后面,表示把 -r "echo 'hello world';" 这个字符串作为要调试的php可执行程序的参数,否则gdb会把它们当做gdb的参数

    运行要调试的程序,执行gdb的run命令,由于此时没有设置断点,程序会运行完成并退出

    run

    设置断点

    break main

    run

    程序在mian函数第一行代码中止

    使用next命令单步执行

    n

    探索zend执行引擎

    准备脚本

    equal.php

    <?php
    
    \$i = 1;
    
    \$j = 1.0;
    
    echo \$i == \$j;
    

    使用gdb调试

    gdb --args /var/www/php/php-7.4.20/sapi/cli/php equal.php

    设置断点

    b ZEND_IS_EQUAL_SPEC_CV_CV_HANDLER

    运行程序

    run

    47265 是这个函数体中的第一行代码

    使用list命令显示这个函数名开始的20行代码

    list 47265,47285

    打印变量值

    • test.php
    <?php
    
    $a = 'hello';
    
    var_dump($a);
    
    • gdb调试
    gdb --args /var/www/php/php-7.4.19/sapi/cli/php 22.php
    
    (gdb) b zif_var_dump
    
    (gdb) run
    Starting program: /var/www/php/php-7.4.19/sapi/cli/php 22.php
    
    Breakpoint 1, zif_var_dump (execute_data=0x801ae7a49db87483, return_value=0x175fffffc83)
        at /var/www/php/php-7.4.19/ext/standard/var.c:218
    
    (gdb) bt
    #0  zif_var_dump (execute_data=0x801ae7a49db87483, return_value=0x175fffffc83) at /var/www/php/php-7.4.19/ext/standard/var.c:218
    #1  0x00005555559a68ef in ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER () at /var/www/php/php-7.4.19/Zend/zend_vm_execute.h:1269
    #2  0x0000555555a10915 in execute_ex (ex=0x7ffff7a13020) at /var/www/php/php-7.4.19/Zend/zend_vm_execute.h:53873
    #3  0x0000555555a158ff in zend_execute (op_array=0x7ffff7a7f300, return_value=0x0)
        at /var/www/php/php-7.4.19/Zend/zend_vm_execute.h:57993
    #4  0x0000555555934149 in zend_execute_scripts (type=8, retval=0x0, file_count=3) at /var/www/php/php-7.4.19/Zend/zend.c:1679
    #5  0x0000555555898fdf in php_execute_script (primary_file=0x7fffffffd350) at /var/www/php/php-7.4.19/main/main.c:2621
    #6  0x0000555555a1845d in do_cli (argc=2, argv=0x555556220b60) at /var/www/php/php-7.4.19/sapi/cli/php_cli.c:964
    #7  0x0000555555a19574 in main (argc=2, argv=0x555556220b60) at /var/www/php/php-7.4.19/sapi/cli/php_cli.c:1359
    
    (gdb) l
    213	/* }}} */
    214
    215	/* {{{ proto void var_dump(mixed var)
    216	   Dumps a string representation of variable to output */
    217	PHP_FUNCTION(var_dump)
    218	{
    219		zval *args;
    220		int argc;
    221		int	i;
    222
    
    (gdb) u 227
    zif_var_dump (execute_data=0x7ffff7a130a0, return_value=0x7fffffffabb0) at /var/www/php/php-7.4.19/ext/standard/var.c:227
    227		for (i = 0; i < argc; i++) {
    (gdb) p args[0].value.str.val@5
    $3 = {"h", "e", "l", "l", "o"}
    (gdb) p args[0].value.str.val
    $4 = "h"
    

    异常处理

    • 使用Docker调试gdb
      • 异常

    Error disabling address space randomization: Operation not permitte

    • 解决方法

    docker run --privileged

    • optimized out
      • 异常
        变量值被编译器优化

    • 解决方法,添加编译参数,启用调试模式

    --enable-debug

    参考

    重现PHP Core调用栈

    gdb使用

    调试PHP源码

    编译和调试php

    GDB工具的使用

  • 相关阅读:
    jQuery 间歇式无缝滚动特效分享(三张图片平行滚动)
    百度网页分享js代码
    如何在linux中搭建JEECMS系统
    Python菜鸟之路:Python基础-类(2)——成员、成员修饰符、异常及其他
    Python菜鸟之路:Python基础-类(1)——概念
    Python菜鸟之路:Python基础-生成器和迭代器、递归
    Python菜鸟之路:Python基础-逼格提升利器:装饰器Decorator
    Python菜鸟之路:Python基础-内置函数补充
    Python菜鸟之路:Python基础——函数
    Python菜鸟之路:Python基础(三)
  • 原文地址:https://www.cnblogs.com/biby/p/16269740.html
Copyright © 2020-2023  润新知