日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

使用MDB查看变量的值(2)

發(fā)布時間:2023/12/20 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用MDB查看变量的值(2) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

使用MDB查看變量的值(2

LW1A2@163.COM

?

本節(jié)描述使用MDB查看core文件中STL變量的知識

?

一、目的

在《使用MDB查看變量的值(1)》中,我們 探討了查看變量值的一般方法,但是對于復(fù)雜的對象,一點(diǎn)一點(diǎn)的查看內(nèi)存太麻煩,MDB提供一種機(jī)制,可以自己實(shí)現(xiàn)插件來解析內(nèi)存中的變量。

?

二、原理

在《Solaris 模塊調(diào)試器指南(819705510)》的第十章詳細(xì)的介紹了編寫插件的方法。這里只簡單介紹下幾個重要的函數(shù)。

1)? const mdb_modinfo_t *_mdb_init(void);

mdb插件的初始化函數(shù),返回一個mdb_modinfo_t結(jié)構(gòu)的指針,mdb_modinfo_t的定義如下:

typedef struct mdb_modinfo {

??? ushort_t mi_dvers; ????????????? /* Debugger API version number */

??? const mdb_dcmd_t *mi_dcmds; ???? /* NULL-terminated list of dcmds */

??? const mdb_walker_t *mi_walkers; ?/* NULL-terminated list of walks */

} mdb_modinfo_t;

l? mi_dvers表示版本號,應(yīng)該始終設(shè)置為MDB_API_VERSION

l? mi_dcmds指向自定義dcmd命令的數(shù)組

l? mi_walkers指向自定義walker命令的數(shù)組。

mi_dcmds的例子:

static const mdb_dcmd_t mi_dcmds [] = {

{ "plist", NULL, "print list", plist }, //自定義dcmd命令plist

{ NULL }

};

注:本文只介紹自定義dcmd命令的實(shí)現(xiàn)

?

2)? void _mdb_fini(void);

自定義插件卸載時(::unload)執(zhí)行的操作。

?

3)? int dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv);

自定義dcmd命令的實(shí)現(xiàn):

例如上面的mi_dcmds的例子中,就需要定義應(yīng)該這樣的函數(shù):

int plist (uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv);

l? addr0x804792c::plist,這樣調(diào)用plist時,addr就等于0x804792c

l? flags:標(biāo)志位,其中flags & DCMD_ADDRSPEC為真時,表示以addr::plist這樣的形式調(diào)用自定義dcmd

l? argc:參數(shù)個數(shù),如0x804792c::plist int,參數(shù)個數(shù)就為1

l? argv:參數(shù)值,如0x804792c::plist int,參數(shù)值就為int

?

4)? ssize_t mdb_vread(void *buf, size_t nbytes, uintptr_t addr);

從給定的目標(biāo)虛擬地址addr開始,取長度為nbytes的一塊內(nèi)存值,將其賦給buf。例如:

0x804792c/D對應(yīng)的mdb_vreadmdb_vread(buf, sizeof(int), 0x804792c)

?

5)? ssize_t mdb_readstr(char *s, size_t nbytes, uintptr_t addr);

從給定的目標(biāo)虛擬地址addr開始,以空字符結(jié)尾的C 字符串讀入由s 尋址的緩沖區(qū)中。主要用來讀取內(nèi)存中的字符串,例如:

0x804792c/s對應(yīng)的mdb_readstrmdb_readstr(s, 255, 0x804792c),其中255為緩沖區(qū)最大值。

?

6)? void mdb_printf(const char *format, ...);

類似于printf,將計算完的值格式化打印到屏幕上。

?

三、實(shí)例

OSSolaris10x86

編譯器:Sun Studio 11

/usr/demo/mdb下有一個MDB插件的例子,本實(shí)例根據(jù)這個例子改編而來,實(shí)現(xiàn)了查看std::list、std::vector、std::map、std::set的值。對于以上四種stl容器,除了可以以地址形式打印成員變量外,還支持以int、long long、string這三種類型來打印成員變量。

完整代碼:

http://download.csdn.net/source/2002961

?

?

四、詳細(xì)說明

1)? list

stllist使用雙向鏈表來實(shí)現(xiàn),通過dbxprint –r,可以顯示出list的結(jié)構(gòu),其偽結(jié)構(gòu)如下(每個變量都是指針):

?? ?{

??????? __buffer_size,

??????? __buffer_list,

??????? __free_list,

??????? __next_avail,

??????? __last,

??????? __node,?????????????? //指向listnode的指針

??????? __length????????????? //list含有的成員個數(shù)

?? ?}

list由多個__node組成,__node的偽結(jié)構(gòu):

?? ?{

??????? next,???????? //雙向鏈表中,指向下一個節(jié)點(diǎn)的指針

??????? prev,???????? //雙向鏈表中,指向上一個節(jié)點(diǎn)的指針

??????? data????????????????????? //指向list成員的指針,本程序就是打印這個指針

?? ?}

假設(shè)程序里list變量的地址為0x804792c,則:

l? __length的地址為0x804792c+sizeof(uintptr_t)*6,由此可以計算出list成員的個數(shù);

l? __node的地址為0x804792c+sizeof(uintptr_t)*5,由此可以計算出每個list成員的地址。__node偽結(jié)構(gòu)中的data即為每個成員的值(或指針)。通過next指針,可以遍歷整個雙向鏈表。

使用方法:

將上面的壓縮包解壓開,執(zhí)行makesolaris會根據(jù)系統(tǒng)的CPU編譯不同的動態(tài)庫,筆者的系統(tǒng)是x86系統(tǒng),所有會在i386目錄下生成printstl.so。可以將這個動態(tài)庫復(fù)制到/usr/lib/mdb/proc/目錄下(MDB插件默認(rèn)目錄),然后在mdb中使用::load printstl.so加載插件,使用::unload printstl.so卸載插件。如果不將動態(tài)庫復(fù)制到插件的默認(rèn)目錄,則需要使用絕對路徑加載插件:::load /XXX/printstl.so。

具體使用方法:

l? 804792c::plist:以指針形式打印list,例:

> 804792c::plist

The list size is: 3

The list member is: ([0]0x8079bf0, [1]0x8099978, [2]0x8099988)

l? 804792c::plist int:知道list里保存的是int類型,打印list,例:

> 804792c::plist int

The list size is: 3

The list member is: ([0]123, [1]456, [2]789)

l? 804792c::plist long long:知道list里保存的是long long類型,打印list,例:

> 804792c::plist long long

The list size is: 3

The list member is: ([0] 9223372036854775807, [1]456, [2]789)

l? 804792c::plist string:知道list里保存的是string類型,打印list,例:

> 8047804::plist string

The list size is: 3

The list member is: ([0]abc, [1]def, [2]Good)

?

2)? vector

stlvector中的成員保存在一塊連續(xù)的內(nèi)存中,如果能得到成員變量的開始地址、結(jié)束地址和成員的大小,就能確定每個成員的地址。通過dbxprint –r,可以顯示出vector的結(jié)構(gòu),其偽結(jié)構(gòu)如下(每個變量都是指針):

?? ?{

??????? __buffer_size,

??????? __start,???????????????????????? //成員變量的開始地址

??????? __finish,??????????????????????? //成員變量的結(jié)束地址

??????? __end_of_storage

? }

假設(shè)程序里vector變量的地址為0x8047900,則:

l? __start的地址為0x8047900+sizeof(uintptr_t)

l? __finish的地址為0x8047900+sizeof(uintptr_t)*2。

使用方法同list

注:若無法確定成員的大小,則只能打印出開始地址和結(jié)束地址。

?

3)? map

stlmap內(nèi)部使用紅黑樹實(shí)現(xiàn)。通過dbxprint –r,可以顯示出map的結(jié)構(gòu),其偽結(jié)構(gòu)如下(每個變量都是指針):

? {

??????? __buffer_size,

??????? __buffer_list,

??????? __free_list,

??????? __next_avail,

??????? __last,

??????? __header,?????????? //指向紅黑樹的head的指針

??????? __node_count,?????? //含有的成員個數(shù)

??????? __insert_always,

??????? __key_compare

? }

map節(jié)點(diǎn),偽結(jié)構(gòu)如下:

? {

??????? color_field,

??????? parent_link,

??????? left_link.

??????? right_link,

??????? first,????? ??//map中的key

??????? second????? //map中的value

? }

假設(shè)程序里map變量的地址為0x8047830,則:

l? __node_count的地址為0x8047830+sizeof(uintptr_t)*6

l? __header的地址為0x8047830+sizeof(uintptr_t)*5,之后就可以得到firstsecond

l? 得到紅黑樹的head指針后,就可以使用遍歷二叉樹的方法來遍歷。使用中序遍歷二叉樹的方法,可以將map中的成員按照從小到大的順序打印出。

使用方法:

l? 8047830::pmap int, int:知道map的定義為map<int,int>,打印map,例:

> 8047830::pmap int, int

The map size is: 3

The map member is: ([0](8,4000), [1](9,2000), [2](1999,2000))

其他使用方法可參考list

?

4)? set

stlset內(nèi)部也是使用紅黑樹實(shí)現(xiàn),只不過set節(jié)點(diǎn)的結(jié)構(gòu)有所不同:

? {

??????? color_field,

??????? parent_link,

??????? left_link,

??????? right_link,

??????? value_field //set中的key

? }

set中只有一個key,其他的地方都和map相同。

使用方法同list

?

五、參考資料:

Solaris 模塊調(diào)試器指南(819705510)》

STL源碼剖析》

總結(jié)

以上是生活随笔為你收集整理的使用MDB查看变量的值(2)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。