【docker+gdb】调试 PHP 源码,看 strval 函数 C 实现-php教程

资源魔 33 0
php strval 函数的作用很简略,就是你给他一个值,他给你前往字符串类型。

算是一个比拟简略的函数了,咱们来经过 gdb 来一探索竟。

经过本文,你能够窥探下

● gdb 的简略应用

● gdb gui 模式初探

● 看看平常写的 PHP 代码正在 C 言语里的样子

● 对应用 gdb 调试 php 代码有个初步理解

● 对了,文末有一些截图,没有要错过

洽购食材

● 电脑一台

● docker 以及 docker-compose

gdb 也好, PHP 也好,都打包成 docker 镜像啦,开袋即食,甚好。

备菜环节

一、应用 docker 拉取环境

# 拉取预备好的环境
git clone https://github.com/rovast/docker-examples.git
# 进入名目
cd docker-examples/gdb-php-src/
# 启动,会经验一个漫长又没有太漫长的期待,看你网速
docker-compose up -d

对于容器内的环境,各人能够看看 dockerfile

其实很简略,就是基于 gcc 民间镜像构建,而后添加了 vim gdb,而且下载了 php7.0.0 的源码,依照 debug 参数进行编译

显示以下

Creating network "gdb-php-src_default" with the default driver
Creating gdb-php-src ... done

二、进入容器

docker exec -it gdb-php-src bash
### 显示上面的货色,示意你曾经进入到容器内了 ####
root@71a98d1bc1a6:/home#

咱们看看容器内的环境(php 和 gdb)

### 咱们正在容器内看看环境
root@71a98d1bc1a6:/home# ls
php-7.0.0  start.md
root@71a98d1bc1a6:/home# gdb -v
GNU gdb (Debian 7.12-6) 7.12.0.20161007-git
Copyright (C) 2016 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-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for co妹妹ands related to "word".
root@71a98d1bc1a6:/home# php -v
PHP 7.0.0 (cli) (built: Apr 17 2019 13:33:30) ( NTS DEBUG )
Copyright (c) 1997-2015 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2015 Zend Technologies
root@71a98d1bc1a6:/home#

停火(请正在容器内操作)

一、新建测试文件

root@71a98d1bc1a6:/home# vi test.php

输出如下内容

<?php
strval(1234);

这个文件干的事件就比拟简略了,就是把 -1234 [整形] 转换为 -1234 [字符串]

二、开端调试,进入 gdb

接上去车速较快,列位按步骤跟上

输出 gdb php,开端调试

root@71a98d1bc1a6:/home# gdb php
GNU gdb (Debian 7.12-6) 7.12.0.20161007-git
Copyright (C) 2016 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-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for co妹妹ands related to "word"...
Reading symbols from php...done.
(gdb)

三、打一些断点(敲饬令时能够用 tab 补全)

(gdb) b zend_long_to_str
Breakpoint 1 at 0x810423: file /home/php-7.0.0/Zend/zend_operators.c, line 2743.
(gdb) b zend_print_ulong_to_buf
Breakpoint 2 at 0x5f387b: zend_print_ulong_to_buf. (13 locations)
(gdb)

这里正在要害函数 zend_long_to_str 以及 zend_print_ulong_to_buf 打了断点。

b 正在 gdb 中是 breakpoint 缩写,前面能够加函数名,或许以后文件的行号都是能够的

四、执行,查看断点值

(gdb) r test.php # 执行咱们方才的阿谁 PHP 文件
Starting program: /usr/local/bin/php test.php
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
warning: File "/usr/local/lib64/libstdc++.so.6.0.25-gdb.py" auto-loading has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load".
To enable execution of this file add
   add-auto-load-safe-path /usr/local/lib64/libstdc++.so.6.0.25-gdb.py
line to your configuration file "/root/.gdbinit".
To completely disable this security protection add
   set auto-load safe-path /
line to your configuration file "/root/.gdbinit".
For more information about this security protection see the
"Auto-loading safe path" section in the GDB manual.  E.g., run from the shell:
   info "(gdb)Auto-loading safe path"
Breakpoint 1, zend_long_to_str (num=-1234) at /home/php-7.0.0/Zend/zend_operators.c:2743
2743      char *res = zend_print_long_to_buf(buf + sizeof(buf) - 1, num);
(gdb)

看的如同没有清楚明了嘛, ctrl + x 后再按 a 进入 gui 模式看看

 ┌──/home/php-7.0.0/Zend/zend_operators.c────────────────────────────────────────────────────────────────────────────────────────────────┐
   │2731    ZEND_API void ZEND_FASTCALL zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC) /* {{{ */                                   │
   │2732    {                                                                                                                              │
   │2733            zend_string *str;                                                                                                      │
   │2734                                                                                                                                   │
   │2735            str = zend_strpprintf(0, "%.*G", (int) EG(precision), (double)Z_DVAL_P(op));                                           │
   │2736            ZVAL_NEW_STR(op, str);                                                                                                 │
   │2737    }                                                                                                                              │
   │2738    /* }}} */                                                                                                                      │
   │2739                                                                                                                                   │
   │2740    ZEND_API zend_string* ZEND_FASTCALL zend_long_to_str(zend_long num) /* {{{ */                                                  │
   │2741    {                                                                                                                              │
   │2742            char buf[MAX_LENGTH_OF_LONG + 1];                                                                                      │
B+>│2743            char *res = zend_print_long_to_buf(buf + sizeof(buf) - 1, num);                                                        │
   │2744            return zend_string_init(res, buf + sizeof(buf) - 1 - res, 0);                                                          │
   │2745    }                                                                                                                              │
   │2746    /* }}} */                                                                                                                      │
   │2747                                                                                                                                   │
   │2748    ZEND_API zend_uchar ZEND_FASTCALL is_numeric_str_function(const zend_string *str, zend_long *lval, double *dval) /* {{{ */ {   │
   │2749        return is_numeric_string_ex(ZSTR_VAL(str), ZSTR_LEN(str), lval, dval, -1, NULL);                                           │
   │2750    }                                                                                                                              │
   │2751    /* }}} */                                                                                                                      │
   │2752                                                                                                                                   │
   │2753    ZEND_API zend_uchar ZEND_FASTCALL _is_numeric_string_ex(const char *str, size_t length, zend_long *lval, double *dval, int allo│
   │2754    {                                                                                                                              │
   │2755            const char *ptr;                                                                                                       │
   │2756            int digits = 0, dp_or_e = 0;                                                                                           │
   │2757            double local_dval = 0.0;                                                                                               │
   └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
multi-thre Thread 0x7ffff7fe37 In: zend_long_to_str                                                                      L2743 PC: 0x810423
(gdb)

有点意义了,函数正在 2743 行断住了,咱们来看看 num 的值

(gdb) p num
$1 = -1234
(gdb)

对嘛,这个就是咱们要解决的值,咱们全速运转到 zend_print_long_to_buf 里看看

(gdb) c
Continuing.

显示以下

(gdb) c
  ┌──/home/php-7.0.0/Zend/zend_operators.h────────────────────────────────────────────────────────────────────────────────────────────────┐
   │781             else                                                                                                   \               │
   │782             ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(opcode)                                                                           │
   │783                                                                                                                                    │
   │784     #define ZEND_TRY_UNARY_OBJECT_OPERATION(opcode)                                                            \                   │
   │785             if (UNEXPECTED(Z_TYPE_P(op1) == IS_OBJECT)                                                             \               │
   │786                     && UNEXPECTED(Z_OBJ_HANDLER_P(op1, do_operation))                                                  \           │
   │787                     && EXPECTED(SUCCESS == Z_OBJ_HANDLER_P(op1, do_operation)(opcode, result, op1, NULL))) { \                     │
   │788                     return SUCCESS;                                                                                    \           │
   │789             }                                                                                                                      │
   │790                                                                                                                                    │
   │791     /* buf points to the END of the buffer */                                                                                      │
   │792     static zend_always_inline char *zend_print_ulong_to_buf(char *buf, zend_ulong num) {                                           │
B+>│793             *buf = '\0';                                                                                                           │
   │794             do {                                                                                                                   │
   │795                     *--buf = (char) (num % 10) + '0';                                                                              │
   │796                     num /= 10;                                                                                                     │
   │797             } while (num > 0);                                                                                                     │
   │798             return buf;                                                                                                            │
   │799     }                                                                                                                              │
   │800                                                                                                                                    │
   │801     /* buf points to the END of the buffer */                                                                                      │
   │802     static zend_always_inline char *zend_print_long_to_buf(char *buf, zend_long num) {                                             │
   │803             if (num < 0) {                                                                                                         │
   │804                 char *result = zend_print_ulong_to_buf(buf, ~((zend_ulong) num) + 1);                                              │
   │805                 *--result = '-';                                                                                                   │
   │806                     return result;                                                                                                 │
   │807             } else {                                                                                                               │
   └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
multi-thre Thread 0x7ffff7fe37 In: zend_print_ulong_to_buf                                                               L793  PC: 0x8041fd

接上去,咱们来进行一些单步伐试,看看内存里的值

Breakpoint 1, zend_long_to_str (num=-1234) at /home/php-7.0.0/Zend/zend_operators.c:2743
(gdb) c  #-------------> 示意持续执行
Continuing.
Breakpoint 2, zend_print_ulong_to_buf (buf=0x7fffffffafe4 "", num=1234) at /home/php-7.0.0/Zend/zend_operators.h:793
(gdb) b 798  #-------------> 798行打个断点
Breakpoint 6 at 0x5f38e2: /home/php-7.0.0/Zend/zend_operators.h:798. (13 locations)
(gdb) c 
Continuing.
Breakpoint 6, zend_print_ulong_to_buf (buf=0x7fffffffafe0 "1234", num=0) at /home/php-7.0.0/Zend/zend_operators.h:798
(gdb) p buf  #-------------> 查看 buf 的值
$2 = 0x7fffffffafe0 "1234"
(gdb) x/10c buf  #-------------> 查看 buf 地位开端,延续 10 个以 char 为单元的内存值
0x7fffffffafe0: 49 '1'  50 '2'  51 '3'  52 '4'  0 '\000'        0 '\000'        0 '\000'        0 '\000'
0x7fffffffafe8: 0 '\000'        65 'A'
(gdb)

咱们看到,函数前往的 buf 是字符串类型的 '1234'

咱们看看函数 zend_print_ulong_to_buf,其实就是从高位到低位,按个取模(除了以 10,取整数局部),而后塞到 buf 缓冲区。

比拟无意思的是,buf 初始化的时分指向的是缓冲区的末尾,以是填充的时分高位正在最初,而后逐渐往前填充低位。

最初完结的时分,buf 就是咱们需求的字符串类容了

消化

其实,本文就是应用 gdb 调试了 PHP 代码,仅此罢了。

更多的是给各人提供了一个间接上手玩玩的机会,你所需求的只是个 docker,而后动入手调试,颇有意义。

入手尝尝吧,乃至,去看 C 源码吧!

附录

手摸手带你看 strval 函数 C 完成

b9fdc5047d5aec46adefdc9a388fb94.png

229a089a607c8d96094012dd1e1b0ad.png

21ba011c493c647b0457b84d41aa538.png

以上就是【docker+gdb】调试 PHP 源码,看 strval 函数 C 完成的具体内容,更多请存眷资源魔其它相干文章!

标签: php开发教程 php开发资料 php开发自学 strval

抱歉,评论功能暂时关闭!