使用MDB查看变量的值(2)
使用MDB查看变量的值(2)
LW1A2@163.COM
本节描述使用MDB查看core文件中STL变量的知识
一、目的
在《使用MDB查看变量的值(1)》中,我们 探讨了查看变量值的一般方法,但是对于复杂的对象,一点一点的查看内存太麻烦,MDB提供一种机制,可以自己实现插件来解析内存中的变量。
二、原理
在《Solaris 模块调试器指南(819–7055–10)》的第十章详细的介绍了编写插件的方法。这里只简单介绍下几个重要的函数。
1) const mdb_modinfo_t *_mdb_init(void);
mdb插件的初始化函数,返回一个mdb_modinfo_t结构的指针,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表示版本号,应该始终设置为MDB_API_VERSION
l mi_dcmds指向自定义dcmd命令的数组
l mi_walkers指向自定义walker命令的数组。
mi_dcmds的例子:
static const mdb_dcmd_t mi_dcmds [] = {
{ "plist", NULL, "print list", plist }, //自定义dcmd命令plist
{ NULL }
};
注:本文只介绍自定义dcmd命令的实现
2) void _mdb_fini(void);
自定义插件卸载时(::unload)执行的操作。
3) int dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv);
自定义dcmd命令的实现:
例如上面的mi_dcmds的例子中,就需要定义应该这样的函数:
int plist (uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv);
l addr:0x804792c::plist,这样调用plist时,addr就等于0x804792c
l flags:标志位,其中flags & DCMD_ADDRSPEC为真时,表示以addr::plist这样的形式调用自定义dcmd
l argc:参数个数,如0x804792c::plist int,参数个数就为1
l argv:参数值,如0x804792c::plist int,参数值就为int
4) ssize_t mdb_vread(void *buf, size_t nbytes, uintptr_t addr);
从给定的目标虚拟地址addr开始,取长度为nbytes的一块内存值,将其赋给buf。例如:
0x804792c/D对应的mdb_vread为mdb_vread(buf, sizeof(int), 0x804792c)
5) ssize_t mdb_readstr(char *s, size_t nbytes, uintptr_t addr);
从给定的目标虚拟地址addr开始,以空字符结尾的C 字符串读入由s 寻址的缓冲区中。主要用来读取内存中的字符串,例如:
0x804792c/s对应的mdb_readstr为mdb_readstr(s, 255, 0x804792c),其中255为缓冲区最大值。
6) void mdb_printf(const char *format, ...);
类似于printf,将计算完的值格式化打印到屏幕上。
三、实例
OS:Solaris10(x86)
编译器:Sun Studio 11
在/usr/demo/mdb下有一个MDB插件的例子,本实例根据这个例子改编而来,实现了查看std::list、std::vector、std::map、std::set的值。对于以上四种stl容器,除了可以以地址形式打印成员变量外,还支持以int、long long、string这三种类型来打印成员变量。
完整代码:
http://download.csdn.net/source/2002961
四、详细说明
1) list
stl的list使用双向链表来实现,通过dbx的print –r,可以显示出list的结构,其伪结构如下(每个变量都是指针):
{
__buffer_size,
__buffer_list,
__free_list,
__next_avail,
__last,
__node, //指向list的node的指针
__length //list含有的成员个数
}
list由多个__node组成,__node的伪结构:
{
next, //双向链表中,指向下一个节点的指针
prev, //双向链表中,指向上一个节点的指针
data //指向list成员的指针,本程序就是打印这个指针
}
假设程序里list变量的地址为0x804792c,则:
l __length的地址为0x804792c+sizeof(uintptr_t)*6,由此可以计算出list成员的个数;
l __node的地址为0x804792c+sizeof(uintptr_t)*5,由此可以计算出每个list成员的地址。__node伪结构中的data即为每个成员的值(或指针)。通过next指针,可以遍历整个双向链表。
使用方法:
将上面的压缩包解压开,执行make,solaris会根据系统的CPU编译不同的动态库,笔者的系统是x86系统,所有会在i386目录下生成printstl.so。可以将这个动态库复制到/usr/lib/mdb/proc/目录下(MDB插件默认目录),然后在mdb中使用::load printstl.so加载插件,使用::unload printstl.so卸载插件。如果不将动态库复制到插件的默认目录,则需要使用绝对路径加载插件:::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
stl的vector中的成员保存在一块连续的内存中,如果能得到成员变量的开始地址、结束地址和成员的大小,就能确定每个成员的地址。通过dbx的print –r,可以显示出vector的结构,其伪结构如下(每个变量都是指针):
{
__buffer_size,
__start, //成员变量的开始地址
__finish, //成员变量的结束地址
__end_of_storage
}
假设程序里vector变量的地址为0x8047900,则:
l __start的地址为0x8047900+sizeof(uintptr_t);
l __finish的地址为0x8047900+sizeof(uintptr_t)*2。
使用方法同list。
注:若无法确定成员的大小,则只能打印出开始地址和结束地址。
3) map
stl的map内部使用红黑树实现。通过dbx的print –r,可以显示出map的结构,其伪结构如下(每个变量都是指针):
{
__buffer_size,
__buffer_list,
__free_list,
__next_avail,
__last,
__header, //指向红黑树的head的指针
__node_count, //含有的成员个数
__insert_always,
__key_compare
}
map节点,伪结构如下:
{
color_field,
parent_link,
left_link.
right_link,
first, //map中的key,
second //map中的value
}
假设程序里map变量的地址为0x8047830,则:
l __node_count的地址为0x8047830+sizeof(uintptr_t)*6;
l __header的地址为0x8047830+sizeof(uintptr_t)*5,之后就可以得到first和second;
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
stl的set内部也是使用红黑树实现,只不过set节点的结构有所不同:
{
color_field,
parent_link,
left_link,
right_link,
value_field //set中的key
}
set中只有一个key,其他的地方都和map相同。
使用方法同list
五、参考资料:
《Solaris 模块调试器指南(819–7055–10)》
《STL源码剖析》
使用MDB查看变量的值(2)相关推荐
- 使用MDB查看变量的值
本节描述使用MDB查看core文件中变量的基本知识 基本概念: 一般程序发生coredump,80%的可能是由于参数的值不对造成的(其他可能是堆栈溢出.多线程等问题造成的).对于可以复现的问题,一般拿 ...
- pycharm如何在程序运行后查看变量的值,变量的类型(不通过print和debug的方式)
文章目录: 1 问题描述 2 ycharm如何在程序运行后查看变量的值,变量的类型 1 问题描述 有时候程序中有很多变量,我们在调试程序的时候需要知道这些变量的的值和变量的类型,如果通过print的方 ...
- vs2015自动窗口(查看变量的值)
问题:在使用vs2015时,调试无法看到变量的值,解决方案如下: 1.启动调试 2.调试-->窗口-->自动窗口(Ctrl+Alt+V,A) 如下图:
- S32DS实时查看变量的值
变量动态监测要求在调试时,点击让CPU全速运行的过程中,能够观察到变量的动态变化.目前只有S32DS for ARM v2.0及更高版本的IDE通过PEMicro提供的Real Time Expres ...
- qt5.9.0调试如何查看变量的值_从0开发3D引擎(四):搭建测试环境
大家好,本文介绍了3D引擎的测试方法,搭建了本地的测试环境. 上一篇博文 wonder-yyc:从0开发3D引擎(三):搭建开发环境zhuanlan.zhihu.com 下一篇博文 wonder-y ...
- qt5.9.0调试如何查看变量的值_深入了解 Java 调试
Bug(俗称"八阿哥") 是软件开发绕不过的一道坎,因此调试便成了每位程序员一项必备的核心技能.调试不仅有助于理解程序的运行流程,还能改进代码质量,最终提高开发者解决问题的能力以及 ...
- 【Keil C51】使用 watch1 来查看变量的值
在使用Keil C51,进行软件调试时,对变量观察的办法如下: 在变量处单击右键,选择添加至watch1窗口,即可看到R6变量在代码调试运行时,具体的数值变化.
- gdb+linux+查看变量,gdb查看变量值
转贴地址 gdb调试过程中如何查看变量的值?一般说来使用print(p)指令来实现,并有自己很多的输出格式. print和它的显示格式 p /x var #十六进制显示变量. p /d var #十进 ...
- keil如何进行软件仿真,以及如何查看变量的实时值
1.打开工程,点击魔术棒选择芯片和晶振,如下图 2.在Debug里面选择选择Use Simulator-使用软件仿真,勾选上Run to main() 3.点击红色的d符号,即可以进入仿真界面 下面介 ...
最新文章
- python中where函数_如何在python中基于Where函数获取两列值
- VirtualBox上装CentOS5.8网络不通问题
- 双指针 - 四数之和
- 关于ORM中只有XML没有映射实体的思考?期待大家的建议
- [Winodows图形编程]初识双缓冲技术
- STM32H743+CubeMX-定时器TIM输出PWM(PWM Generation模式)+ 中断
- 20165237 2017-2018-2 《Java程序设计》第1周学习总结
- 运行Java web时遇到的错误
- 2020受欢迎的20个JavaScript 库
- 《从零开始学Swift》学习笔记(Day 30)——选择类还是结构体呢?
- 流水线机制、滑动窗口协议、GBN、SR
- 免费的录屏软件,来试试这一款软件吧!
- 凤凰系统基于android x x86,凤凰系统X86|Phoenix OS X86 V3.0.8.529官方版
- Office | Word中插入参考文献
- [swift] UIImage NSImage PNG透明区域填充自定义颜色实现
- 小甲鱼Python3学习笔记之第十讲(仅记录学习)
- 教你快速使用AD7606的简单驱动方法--并行
- 迁移学习(基于ResNet18的蜜蜂和蚂蚁分类)
- 梦幻西游 WSG 文件格式分析
- cv2.erode函数