Home  >  Article  >  php教程  >  gdb方式遍历EG(symbol_table) 哈希表的key

gdb方式遍历EG(symbol_table) 哈希表的key

WBOY
WBOYOriginal
2016-06-13 10:46:001306browse

 

Sara Golemon写过一篇文章,里面提到:“是否存在特别的地方可以找到GLOBALS数组?”答案是“存在”,就是EG(symbol_table)-Executor Globals结构,她也给出了找的具体实例,如下

 

PHP_FUNCTION(confirm_getGlobal_compiled) {

    char *varname;

    int varname_len;

    zval **varvalue;

 

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &varname, &varname_len) == FAILURE) {

        RETURN_NULL();

    }

 

    if (zend_hash_find(&EG(symbol_table), varname, varname_len + 1, (void**)&varvalue) == FAILURE) {

        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Undefined variable: %s", varname);

        RETURN_NULL();

    }

 

    *return_value = **varvalue;

    zval_copy_ctor(return_value);

}

 

编译成so加载后,编写php测试代码

 

$abc = 'string';

$def = 'string2';

 

var_dump(confirm_getGlobal_compiled('abc'));

 

执行结果

 

string(6) "string"

 

大家可能感觉奇怪,为什么多写了一个def变量,这就是下面要进行的,一起来看下EG这个hashtable

 

gdb --args bin/php -c php.ini a.php

 

调试代码如下

(gdb) b renzhi.c : 301     //在写的扩展地方加上断点

No source file named renzhi.c.

Make breakpoint pending on future shared library load? (y or [n]) y

Breakpoint 1 (renzhi.c : 301) pending.

(gdb) r   //运行到断点处

Starting program: /root/php-src-5.3/bin/php -c php.ini ceshi.php

warning: .dynamic section for "/lib/libc.so.6" is not at the expected address

warning: difference appears to be caused by prelink, adjusting expectations

[Thread debugging using libthread_db enabled]

 

Breakpoint 1, zif_confirm_getGlobal_compiled (ht=1, return_value=0x837a43c, return_value_ptr=0x0, this_ptr=0x0, return_value_used=1)

    at /root/php-src-5.3/ext/renzhi/renzhi.c:305

305         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &varname, &varname_len) == FAILURE) {

(gdb) n

309         if (zend_hash_find(&EG(symbol_table), varname, varname_len + 1, (void**)&varvalue) == FAILURE) {

(gdb) step    //进入zend_hash_find哈希查找函数

zend_hash_find (ht=0x82e3250, arKey=0x837a42c "abc", nKeyLength=4, pData=0xbfffc484) at /root/php-src-5.3/Zend/zend_hash.c:872

 

 

下面看下关键

 

(gdb) p *ht

$9 = {nTableSize = 64, nTableMask = 63, nNumOfElements = 10, nNextFreeElement = 0, pInternalPointer = 0x83edc98, pListHead = 0x83edc98,

  pListTail = 0x837a3fc, arBuckets = 0x83705a8, pDestructor = 0x81923b0 <_zval_ptr_dtor>, persistent = 0 '\000', nApplyCount = 0 '\000',

  bApplyProtection = 1 '\001'}

(gdb) p *ht.pListHead

$2 = {h = 2572561225, nKeyLength = 8, pData = 0x83edca4, pDataPtr = 0x83edc7c, pListNext = 0x8378c4c, pListLast = 0x0, pNext = 0x0, pLast = 0x0,

  arKey = "G"}

(gdb) p *ht.pListHead.pListNext

$3 = {h = 253399445, nKeyLength = 5, pData = 0x8378c58, pDataPtr = 0x8378b60, pListNext = 0x8378c7c, pListLast = 0x83edc98, pNext = 0x0, pLast = 0x0,

  arKey = "a"}

(gdb) p *ht.pListHead.pListNext.pListNext

$4 = {h = 253398818, nKeyLength = 5, pData = 0x8378c88, pDataPtr = 0x8378c30, pListNext = 0x8378d20, pListLast = 0x8378c4c, pNext = 0x0, pLast = 0x0,

  arKey = "a"}

(gdb) p *ht.pListHead.pListNext.pListNext.pListNext

$5 = {h = 3947724458, nKeyLength = 6, pData = 0x8378d2c, pDataPtr = 0x8378cac, pListNext = 0x8378d54, pListLast = 0x8378c7c, pNext = 0x0, pLast = 0x0,

  arKey = "_"}

(gdb) p *ht.pListHead.pListNext.pListNext.pListNext.pListNext

$6 = {h = 249444164, nKeyLength = 5, pData = 0x8378d60, pDataPtr = 0x83edd1c, pListNext = 0x8378d84, pListLast = 0x8378d20, pNext = 0x0, pLast = 0x0,

  arKey = "_"}

(gdb) p *ht.pListHead.pListNext.pListNext.pListNext.pListNext.pListNext

$7 = {h = 195471710, nKeyLength = 8, pData = 0x8378d90, pDataPtr = 0x83edd38, pListNext = 0x8378e2c, pListLast = 0x8378d54, pNext = 0x0, pLast = 0x0,

  arKey = "_"}

(gdb) p *ht.pListHead.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext

$8 = {h = 1027153623, nKeyLength = 7, pData = 0x8378e38, pDataPtr = 0x8378db8, pListNext = 0x8379e8c, pListLast = 0x8378d84, pNext = 0x0, pLast = 0x0,

  arKey = "_"}

(gdb) p *ht.pListHead.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext

$9 = {h = 3291685243, nKeyLength = 8, pData = 0x8379e98, pDataPtr = 0x8378e88, pListNext = 0x837a3cc, pListLast = 0x8378e2c, pNext = 0x0, pLast = 0x0,

  arKey = "_"}

(gdb) p *ht.pListHead.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext

$10 = {h = 2090069483, nKeyLength = 4, pData = 0x837a3d8, pDataPtr = 0x8379ef8, pListNext = 0x837a3fc, pListLast = 0x8379e8c, pNext = 0x0, pLast = 0x0,

  arKey = "a"}

(gdb) p *ht.pListHead.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext

$11 = {h = 2090180660, nKeyLength = 4, pData = 0x837a408, pDataPtr = 0x8379edc, pListNext = 0x0, pListLast = 0x837a3cc, pNext = 0x0, pLast = 0x0,

  arKey = "d"}

 

有点乱,这里第一条就是现实了EG这个hash表里面有nNumOfElements =10个元素

 

这里的

 

(gdb) p *ht.pListHead.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext

$10 = {h = 2090069483, nKeyLength = 4, pData = 0x837a3d8, pDataPtr = 0x8379ef8, pListNext = 0x837a3fc, pListLast = 0x8379e8c, pNext = 0x0, pLast = 0x0,

  arKey = "a"}

(gdb) p *ht.pListHead.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext

$11 = {h = 2090180660, nKeyLength = 4, pData = 0x837a408, pDataPtr = 0x8379edc, pListNext = 0x0, pListLast = 0x837a3cc, pNext = 0x0, pLast = 0x0,

  arKey = "d"}

 

就是测试php代码里面的

 

$abc = 'string';

$def = 'string2';

 

这两个变量名称的具体hash的bucket了

 

(gdb) p *ht.pListHead.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext

$10 = {h = 2090069483, nKeyLength = 4, pData = 0x837a3d8, pDataPtr = 0x8379ef8, pListNext = 0x837a3fc, pListLast = 0x8379e8c, pNext = 0x0, pLast = 0x0,

  arKey = "a"}

 

第一个字符arKey为a,有nKeyLength = 4四个字符长度

 

(gdb) p ht.pListHead.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext.arKey[0]

$10 = 97 'a'

(gdb) p ht.pListHead.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext.arKey[1]

$11 = 98 'b'

(gdb) p ht.pListHead.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext.arKey[2]

$12 = 99 'c'

(gdb) p ht.pListHead.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext.arKey[3]

$13 = 0 '\000'

 

 

如何在gdb方式下拿到指针了,看到对应的执行的zval的内容呢?

 

已经知道了bucket结构体中的pData就执行了内容

(gdb) p ht.pListHead.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext.pData

$19 = (void *) 0x837a3d8

 

但是返回的这个,还不知道如何获得,请高手帮助

 

搞明白了

 

(gdb) p *ht.pListHead.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext.pListNext

$29 = {h = 2090069483, nKeyLength = 4, pData = 0x839fe28, pDataPtr = 0x839f948, pListNext = 0x839fe4c, pListLast = 0x839f8dc, pNext = 0x0, pLast = 0x0,

  arKey = "a"}

(gdb) p *(zval *)$29->pDataPtr

$30 = {value = {lval = 138024112, dval = 1.2800167717828578e-313, str = {val = 0x83a14b0 "string", len = 6}, ht = 0x83a14b0, obj = {handle = 138024112,

      handlers = 0x6}}, refcount__gc = 1, type = 6 '\006', is_ref__gc = 0 '\000'}

 

哈哈,可以看到具体的hash指向的值了

 

但是又有点不明白了pData和pDataPtr到底有啥关系?

 

(gdb) p &$29->pDataPtr

$46 = (void **) 0x839fe28

(gdb) p $29->pData

$47 = (void *) 0x839fe28

 

也就是pData里面存得是pDataPtr的地址

摘自 xiaoq3406的专栏

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Previous article:php文件缓存数据Next article:PHP面向切面编程组件