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

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

内容导读

收集整理的这篇技术教程文章主要介绍了【docker+gdb】调试PHP源码,看strval函数C实现,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含15120字,纯文字阅读大概需要22分钟

内容图文

php strval 函数的作用很简单,就是你给他一个值,他给你返回字符串类型。

算是一个比较简单的函数了,我们来通过 gdb 来一探究竟。

通过本文,你可以窥探下

● gdb 的简单使用

● gdb gui 模式初探

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

● 对使用 gdb 调试 php 代码有个初步了解

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

采购食材

● 电脑一台

● docker 和 docker-compose

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

备菜环节

1、使用 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 driverCreating gdb-php-src ... done

2、进入容器

docker exec -it gdb-php-src bash### 显示下面的东西,表示你已经进入到容器内了 ####root@71a98d1bc1a6:/home#

我们看看容器内的环境(php 以及 gdb)

### 我们在容器内看看环境root@71a98d1bc1a6:/home# lsphp-7.0.0
start.mdroot@71a98d1bc1a6:/home# gdb -vGNU gdb (Debian 7.12-6) 7.12.0.20161007-gitCopyright (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 commands related to "word".root@71a98d1bc1a6:/home# php -vPHP 7.0.0 (cli) (built: Apr 17 2019 13:33:30) ( NTS DEBUG )Copyright (c) 1997-2015 The PHP GroupZend Engine v3.0.0, Copyright (c) 1998-2015 Zend Technologiesroot@71a98d1bc1a6:/home#

开火(请在容器内操作)

1、新建测试文件

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

输入以下内容

<?phpstrval(1234);

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

2、开始调试,进入 gdb

接下来车速较快,各位按步骤跟上

输入 gdb php,开始调试

root@71a98d1bc1a6:/home# gdb phpGNU gdb (Debian 7.12-6) 7.12.0.20161007-gitCopyright (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 commands related to "word"...Reading symbols from php...done.(gdb)

3、打一些断点(敲命令时可以用 tab 补全)

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

这里在关键函数 zend_long_to_str 和 zend_print_ulong_to_buf 打了断点。

b 在 gdb 中是 breakpoint 缩写,后面可以加函数名,或者当前文件的行号都是可以的

4、执行,查看断点值

(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.pyline 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:27432743


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) cContinuing.

显示如下

(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 = '';




















































 │
 │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 '00'



0 '00'



0 '00'



0 '00'0x7fffffffafe8: 0 '00'



65 'A'(gdb)

我们看到,函数返回的 buf 是字符串类型的 '1234'

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

比较有意思的是,buf 初始化的时候指向的是缓冲区的末尾,所以填充的时候高位在最后,然后逐步往前填充低位。

最后结束的时候,buf 就是我们需要的字符串类容了

消化

其实,本文就是使用 gdb 调试了 PHP 代码,仅此而已。

更多的是给大家提供了一个直接上手玩玩的机会,你所需要的只是个 docker,然后动动手调试,很有意思。

动手试试吧,甚至,去看 C 源码吧!

附录

手摸手带你看 strval 函数 C 实现

以上就是【docker+gdb】调试 PHP 源码,看 strval 函数 C 实现的详细内容,更多请关注Gxl网其它相关文章!

内容总结

以上是为您收集整理的【docker+gdb】调试PHP源码,看strval函数C实现全部内容,希望文章能够帮你解决【docker+gdb】调试PHP源码,看strval函数C实现所遇到的程序开发问题。 如果觉得技术教程内容还不错,欢迎将网站推荐给程序员好友。

内容备注

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。


本文关键词:

联系我们

在线咨询:点击这里给我发消息

邮件:w420220301@qq.com