gdb-python:解析结构的每个字段,并使用适当的值打印它们(如果存在) [英] gdb-python : Parsing structure's each field and print them with proper value, if exists
问题描述
我正在编写一个python脚本来自动调试gdb的核心转储。我试图打印包含内核数据结构和列表(例如struct list_head)的数据结构。例如,结构如下所示:
struct my_struct {
struct my_hardware_context ahw;
struct net_device * netdev;
struct pci_dev * pdev;
struct list_head mac_list;
....
....
};
我正在使用以下API tp打印此结构:
gdb.execute('p(*(struct my_struct *)dev_base-> priv)')
所以我可以打印'struct (仅显示地址)my_struct',struct my_hardware_context ahw,但不包含指针和列表的内容(例如struct net_device * netdev,struct pci_dev * pdev,struct list_head mac_list)。那么如何使用gdb-python脚本打印* netdev,* pdev和mac_list的内容?
编辑:使我的问题更清晰
我正在编写一个python脚本来自动调试gdb的核心转储。我试图打印包含内核数据结构和列表(例如struct list_head)的数据结构。例如,结构如下所示:
struct my_struct {
struct my_hardware_context ahw;
struct net_device * netdev;
struct pci_dev * pdev;
struct list_head mac_list;
....
....
};
我正在使用以下API来打印此结构:(可以假定我有正确的核心转储并添加了适当的符号。
main_struct = gdb.execute('p(*(struct my_struct *)dev_base-> priv)') / code>
print main_struct
现在它将打印struct my_struct的所有成员的值,但打印到一个级别,这意味着它将打印struct my_hardware_context ahw的全部内容,因为它是一个实例,但不会打印struct net_device * netdev的内容,struct pci_dev * pdev,struct list_head,mac_list等现在手动我需要像下面这样做:
netdev = gdb.parse_and_eval('*(*( struct my_struct *)dev_base-> next-> priv).netdev')
$ b print netdev < code
pdev = gdb.parse_and_eval('*(*(struct my_struct *)dev_base-> next-> priv ).pdev')
print pdev
所以我想自动执行这些步骤。是否有任何gdb-python API或它可以迭代struct my_struct并自动打印指针,数组和列表值的方式?
谢谢。
struct net_device来自Linux的, struct pci_dev
是用于内核而不是用户空间的代码。它们甚至不会通过使用libc的 make headers_install
获得的已消毒内核头文件导出。
GDB无法打印 struct net_device
, struct pci_dev
,因为它没有描述这些结构定义的调试信息。您的用户空间 struct my_struct
被声明为具有指向这些结构的不透明指针。我不认为你应该这样做。
核心转储澄清后的编辑
诀窍是将调试信息从内核和驱动模块加载到GDB中:
$ b
- 使用debuginfo获取内核( CONFIG_DEBUG_INFO < /强>)。例如对于Centos,从 http:// debuginfo获取匹配的 kernel-debuginfo 包。 。 获取 .text , .data 和通过检查驱动程序模块的 / sys / module / MY-DRIVER / sections / {。text,.data,.bss} 系统在正常操作下运行您的驱动程序。
假设带有调试信息的内核位于 / usr / lib / debug /
$ gdb / usr /lib/debug/lib/modules/3.9.4-200.fc18.x86_64/vmlinux vmcore
(gdb)添加符号文件MY-DRIVER.ko TEXT-ADDR -s .data DATA-ADDR -s .bss BSS-ADDR
同时替换 TEXT-ADDR , DATA-ADDR 和 BSS-ADDR ,其地址来自/ sys / module / MY-D下的文件RIVER /分段/。 (我认为只是撒谎,并使用地址0可能会在这种情况下工作)
验证 ptype struct net_device , ptype struct pci_dev , ptype my_struct 工作。然后在获得 struct * my_struct
的地址之后,您应该能够打印其内容。
在追随指针时遍历结构
print-struct-follow-pointers.py
import gdb
def is_container(v):
c = v.type.code
return(c == gdb.TYPE_CODE_STRUCT或c == gdb.TYPE_CODE_UNION)
def is_pointer(v):
return(v.type.code == gdb.TYPE_CODE_PTR)
def print_struct_follow_pointers( s,level_limit = 3,level = 0):
indent =''* level
如果不是is_container(s):
gdb.write('%s\\\
'%s(s))
返回
if level> = level_limit:
gdb.write('%s {...},\\\
'%( s.type))
返回
对于s.type中的k,gdb.write('%s {\ n'%(s.type,))
。 keys():
v = s [k]
如果is_pointer(v):
gdb.write('%s%s:%s'%(indent,k,v))
try:
v1 = v.dereference()
v1.fetch_lazy()
除了gdb.error:
gdb.write(',\ n')
continue
else:
gdb.write(' - > ')
print_struct_follow_pointers(v1,level_limit,level + 1)
elif is_container(v):
gdb.write('%s%s:'%(indent,k))
print_struct_follow_pointers(v,level_limit,level + 1)
else:
gdb.write('%s%s:%s,\\\
'%(indent,k,v))
gdb.write('%s},\\\
'%(indent,))
$ b $ class PrintStructFollowPointers(gdb.Command):
'''
print- struct-follow-pointers [/ LEVEL_LIMIT] STRUCT-VALUE
'''
def __init __(self):
super(PrintStructFollowPointers,self).__ init __(
'print-struct
gdb.COMMAND_DATA,gdb.COMPLETE_SYMBOL,False)
def invoke(self,arg,from_tty):
s = arg.find('/' )
如果s == -1:
(expr,limit)=(arg,3)
else:
如果arg [:s] .strip():
(expr,limit)=(arg,3 )
else:
i = s + 1
for enumerate(arg [s + 1:],s + 1)中的(i,c):
如果不是c.isdigit ():
break
end = i
digits = arg [s + 1:end]
try:
limit = int(digits)
ValueError:
raise gdb.GdbError(PrintStructFollowPointers .__ doc__)
(expr,limit)=(arg [end:],limit)
try:
v = gdb.parse_and_eval(expr )
除了gdb.error,e:
raise gdb.GdbError(e.message)
print_struct_follow_pointers(v,limit)
PrintStructFollowPointers()
示例会话
(gdb)source print-struct-follow-pointers.py
(gdb)print-struct-follow-pointers * p
您可以限制嵌入的str的级别印刷版:
(gdb)print-struct-follow-pointers / 4 * p
I am writing a python script to automate debugging core dump from gdb. i am trying to print data structure which includes kernel data structures and lists(e.g. struct list_head). For example the structure is something like this:
struct my_struct {
struct my_hardware_context ahw;
struct net_device *netdev;
struct pci_dev *pdev;
struct list_head mac_list;
....
....
};
i am using following API tp print this structure:
gdb.execute('p (*(struct my_struct *)dev_base->priv)')
so i am able to print the content of 'struct my_struct' , struct my_hardware_context ahw, but not the content of pointers and list ( e.g. struct net_device *netdev, struct pci_dev *pdev, struct list_head mac_list) automatically (only address is printed). So how to print the content of *netdev, *pdev and mac_list using gdb-python script?
EDITED : to make my question more clear
I am writing a python script to automate debugging core dump from gdb. i am trying to print data structure which includes kernel data structures and lists(e.g. struct list_head). For example the structure is something like this:
struct my_struct {
struct my_hardware_context ahw;
struct net_device *netdev;
struct pci_dev *pdev;
struct list_head mac_list;
....
....
};
i am using following API to print this structure: (it can be assumed that i have right core dump and added proper symbols.
main_struct = gdb.execute('p (*(struct my_struct *)dev_base->priv)')
print main_struct
Now it will print the values of all members of struct my_struct but upto one level , meaning it will print the whole content of struct my_hardware_context ahw because it is an instance but it will not print the content of struct net_device *netdev, struct pci_dev *pdev, struct list_head mac_list etc. so now manually i need to do it like below:
netdev = gdb.parse_and_eval('*(*(struct my_struct *)dev_base->next->priv).netdev')
print netdev
pdev = gdb.parse_and_eval('*(*(struct my_struct *)dev_base->next->priv).pdev')
print pdev
so i want to automate these steps. Is there any gdb-python API or way by which it can iterate the struct my_struct and print the pointers, arrays and lists values also automatically?
Thanks.
struct net_device
, struct pci_dev
from Linux are meant to be used by kernel and not userspace code. They're not even exported in the sanitized kernel headers you get with make headers_install
for use with libc.
GDB can't print struct net_device
, struct pci_dev
because it doesn't have debug info describing the definition of those structures. Your userspace struct my_struct
is declared to have opaque pointers to those structures. I don't think you should be doing that in the first place.
Edit After Core Dump Clarification
The trick is loading debug info from both the kernel and your driver module into GDB:
- Grab a kernel with debuginfo (CONFIG_DEBUG_INFO). e.g. for Centos, get the matching kernel-debuginfo package from http://debuginfo.centos.org/6/x86_64/.
- Get the .text, .data and .bss load addresses of your driver module by inspecting /sys/module/MY-DRIVER/sections/{.text,.data,.bss} from a system running your driver under normal operation.
Assuming the kernel with debug info is located at /usr/lib/debug/lib/modules/3.9.4-200.fc18.x86_64/vmlinux, run:
$ gdb /usr/lib/debug/lib/modules/3.9.4-200.fc18.x86_64/vmlinux vmcore
(gdb) add-symbol-file MY-DRIVER.ko TEXT-ADDR -s .data DATA-ADDR -s .bss BSS-ADDR
while replacing TEXT-ADDR, DATA-ADDR and BSS-ADDR with the address from the files under /sys/module/MY-DRIVER/sections/. (I think just lying and using an address of 0 would probably work in this case)
Verify that ptype struct net_device, ptype struct pci_dev, ptype my_struct work. Then after obtaining the address of a struct *my_struct
the way you did before you should be able print its contents.
Traversing a Struct While Following Pointers
print-struct-follow-pointers.py
import gdb
def is_container(v):
c = v.type.code
return (c == gdb.TYPE_CODE_STRUCT or c == gdb.TYPE_CODE_UNION)
def is_pointer(v):
return (v.type.code == gdb.TYPE_CODE_PTR)
def print_struct_follow_pointers(s, level_limit = 3, level = 0):
indent = ' ' * level
if not is_container(s):
gdb.write('%s\n' % (s,))
return
if level >= level_limit:
gdb.write('%s { ... },\n' % (s.type,))
return
gdb.write('%s {\n' % (s.type,))
for k in s.type.keys():
v = s[k]
if is_pointer(v):
gdb.write('%s %s: %s' % (indent, k, v))
try:
v1 = v.dereference()
v1.fetch_lazy()
except gdb.error:
gdb.write(',\n')
continue
else:
gdb.write(' -> ')
print_struct_follow_pointers(v1, level_limit, level + 1)
elif is_container(v):
gdb.write('%s %s: ' % (indent, k))
print_struct_follow_pointers(v, level_limit, level + 1)
else:
gdb.write('%s %s: %s,\n' % (indent, k, v))
gdb.write('%s},\n' % (indent,))
class PrintStructFollowPointers(gdb.Command):
'''
print-struct-follow-pointers [/LEVEL_LIMIT] STRUCT-VALUE
'''
def __init__(self):
super(PrintStructFollowPointers, self).__init__(
'print-struct-follow-pointers',
gdb.COMMAND_DATA, gdb.COMPLETE_SYMBOL, False)
def invoke(self, arg, from_tty):
s = arg.find('/')
if s == -1:
(expr, limit) = (arg, 3)
else:
if arg[:s].strip():
(expr, limit) = (arg, 3)
else:
i = s + 1
for (i, c) in enumerate(arg[s+1:], s + 1):
if not c.isdigit():
break
end = i
digits = arg[s+1:end]
try:
limit = int(digits)
except ValueError:
raise gdb.GdbError(PrintStructFollowPointers.__doc__)
(expr, limit) = (arg[end:], limit)
try:
v = gdb.parse_and_eval(expr)
except gdb.error, e:
raise gdb.GdbError(e.message)
print_struct_follow_pointers(v, limit)
PrintStructFollowPointers()
Sample Session
(gdb) source print-struct-follow-pointers.py
(gdb) print-struct-follow-pointers *p
You can limit the levels of embedded structures printed:
(gdb) print-struct-follow-pointers/4 *p
这篇关于gdb-python:解析结构的每个字段,并使用适当的值打印它们(如果存在)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!