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的專欄