使用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)相关推荐

  1. 使用MDB查看变量的值

    本节描述使用MDB查看core文件中变量的基本知识 基本概念: 一般程序发生coredump,80%的可能是由于参数的值不对造成的(其他可能是堆栈溢出.多线程等问题造成的).对于可以复现的问题,一般拿 ...

  2. pycharm如何在程序运行后查看变量的值,变量的类型(不通过print和debug的方式)

    文章目录: 1 问题描述 2 ycharm如何在程序运行后查看变量的值,变量的类型 1 问题描述 有时候程序中有很多变量,我们在调试程序的时候需要知道这些变量的的值和变量的类型,如果通过print的方 ...

  3. vs2015自动窗口(查看变量的值)

    问题:在使用vs2015时,调试无法看到变量的值,解决方案如下: 1.启动调试 2.调试-->窗口-->自动窗口(Ctrl+Alt+V,A) 如下图:

  4. S32DS实时查看变量的值

    变量动态监测要求在调试时,点击让CPU全速运行的过程中,能够观察到变量的动态变化.目前只有S32DS for ARM v2.0及更高版本的IDE通过PEMicro提供的Real Time Expres ...

  5. qt5.9.0调试如何查看变量的值_从0开发3D引擎(四):搭建测试环境

    大家好,本文介绍了3D引擎的测试方法,搭建了本地的测试环境. 上一篇博文 wonder-yyc:从0开发3D引擎(三):搭建开发环境​zhuanlan.zhihu.com 下一篇博文 wonder-y ...

  6. qt5.9.0调试如何查看变量的值_深入了解 Java 调试

    Bug(俗称"八阿哥") 是软件开发绕不过的一道坎,因此调试便成了每位程序员一项必备的核心技能.调试不仅有助于理解程序的运行流程,还能改进代码质量,最终提高开发者解决问题的能力以及 ...

  7. 【Keil C51】使用 watch1 来查看变量的值

    在使用Keil C51,进行软件调试时,对变量观察的办法如下: 在变量处单击右键,选择添加至watch1窗口,即可看到R6变量在代码调试运行时,具体的数值变化.

  8. gdb+linux+查看变量,gdb查看变量值

    转贴地址 gdb调试过程中如何查看变量的值?一般说来使用print(p)指令来实现,并有自己很多的输出格式. print和它的显示格式 p /x var #十六进制显示变量. p /d var #十进 ...

  9. keil如何进行软件仿真,以及如何查看变量的实时值

    1.打开工程,点击魔术棒选择芯片和晶振,如下图 2.在Debug里面选择选择Use Simulator-使用软件仿真,勾选上Run to main() 3.点击红色的d符号,即可以进入仿真界面 下面介 ...

最新文章

  1. python中where函数_如何在python中基于Where函数获取两列值
  2. VirtualBox上装CentOS5.8网络不通问题
  3. 双指针 - 四数之和
  4. 关于ORM中只有XML没有映射实体的思考?期待大家的建议
  5. [Winodows图形编程]初识双缓冲技术
  6. STM32H743+CubeMX-定时器TIM输出PWM(PWM Generation模式)+ 中断
  7. 20165237 2017-2018-2 《Java程序设计》第1周学习总结
  8. 运行Java web时遇到的错误
  9. 2020受欢迎的20个JavaScript 库
  10. 《从零开始学Swift》学习笔记(Day 30)——选择类还是结构体呢?
  11. 流水线机制、滑动窗口协议、GBN、SR
  12. 免费的录屏软件,来试试这一款软件吧!
  13. 凤凰系统基于android x x86,凤凰系统X86|Phoenix OS X86 V3.0.8.529官方版
  14. Office | Word中插入参考文献
  15. [swift] UIImage NSImage PNG透明区域填充自定义颜色实现
  16. 小甲鱼Python3学习笔记之第十讲(仅记录学习)
  17. 教你快速使用AD7606的简单驱动方法--并行
  18. 迁移学习(基于ResNet18的蜜蜂和蚂蚁分类)
  19. 梦幻西游 WSG 文件格式分析
  20. cv2.erode函数

热门文章

  1. MacBook 安装7zip
  2. 乐视2017暑期实习生笔试题(二)
  3. 修图软件哪个好android,修图软件哪个好?手机修图软件大盘点
  4. 微信公众号及小程序开发入门(二)
  5. Excel多个工作表合并,如何去除每个工作表中的表头,只保留一个表头
  6. android pwm 唤醒 闪屏,A屏低亮度PWM频闪伤眼?拯救OLED屏伤眼的APP了解下
  7. docker 容器常用命令及基本操作
  8. python大战机器学习——人工神经网络
  9. 如何进入互联网行业,成为产品经理?没有项目经验如何转行当上产品经理?
  10. 关于汽车隔音和音响改装,难听,但确是实话