i am trying to access kernel linked list, the structure is
struct my_struct {
struct my_hardware_context ahw;
struct net_device *netdev;
struct pci_dev *pdev;
struct list_head mac_list;
struct list_head wait_list;
....
....
};
using gdb, i am able to print this in following way:
(gdb)p *(qlcnic_wait_event_t *)(((struct my_struct *)dev_base->next->priv).wait_list)
Output is:
$17 = {
list = {
next = 0x410026a14ff0,
prev = 0x410026a14ff0
},
comp_id = 0x0,
trigger = 0x0,
active = 0x0,
rsp_word = 0x0 <buses_init at vmkdrivers/src_9/vmklinux_9/linux/drivers/base/bus.c:1061>
}
to iterate the list, i need to go to 'next' of wait_list and using 'container_of', get base the address. so i am using container_of Macro, code is
#!/usr/bin/env python
import gdb
long_type = None
def get_type(type_name):
t = gdb.lookup_type(type_name)
if t == None:
raise gdb.GdbError("cannot resolve type '%s'" % type_name)
return t
def get_long_type():
global long_type
if long_type == None:
long_type = get_type("long")
return long_type
def offset_of(typeobj, field):
element = gdb.Value(0).cast(typeobj)
return int(str(element[field].address), 16)
def container_of(ptr, typeobj, member):
return (ptr.cast(get_long_type()) - offset_of(typeobj, member)).cast(typeobj)
class ContainerOf(gdb.Function):
__doc__ = "Return pointer to containing data structure.\n" \
"\n" \
"$container_of(PTR, \"TYPE\", \"ELEMENT\"): Given PTR, return a pointer to the\n" \
"data structure of the type TYPE in which PTR is the address of ELEMENT.\n" \
"Note that TYPE and ELEMENT have to be quoted as strings."
def __init__(self):
super(ContainerOf, self).__init__("container_of")
def invoke(self, ptr, typename, elementname):
return container_of(ptr,
gdb.lookup_type(typename.string()).pointer(),
elementname.string())
ContainerOf()
ptr = gdb.parse_and_eval('(qlcnic_wait_event_t *)(((struct my_struct *)dev_base->next->priv).wait_list)').address
print '%s'%(ptr)
c = container_of(ptr,"qlcnic_wait_event_t","list")
After doing (gdb) source container_of.py
The output is:
wait_list = {
list = {
next = 0x410026a14ff0,
prev = 0x410026a14ff0
},
comp_id = 0x0,
trigger = 0x0,
active = 0x0,
rsp_word = 0x0 <buses_init at /src_9/linux_9/drivers/base/bus.c:1061>
}
ptr = 0x410026a14ff0
Traceback (most recent call last):
File "container_of.py", line 64, in ?
next = container_of(ptr,"struct qlcnic_wait_event_s","list")
File "container_of.py", line 23, in container_of
return (ptr.cast(get_long_type()) - offset_of(typeobj, member)).cast(typeobj)
File "container_of.py", line 19, in offset_of
element = gdb.Value(0).cast(typeobj)
RuntimeError: Argument must be a type.
why is it not working ?How to implement this container_of ?
The problem with your code is that cast() expects a gdb.Type at this point, not a string. Calling gdb.lookup_type() would fix that part.
Regarding offsetof/container_of: By far the most convenient way to make it work is to use gdb's macro facility. This is just because it's easier to access tha a function or command.
(gdb) macro define offsetof(_type, _memb) \
((long)(&((_type *)0)->_memb))
(gdb) macro define container_of(_ptr, _type, _memb) \
((_type *)((void *)(_ptr) - offsetof(_type, _memb)))
This might go into your .gdbinit.
(gdb) print offsetof(struct foo, bar)
...
To use this in Python, you could reimplement it in the same way you started, using gdb.Type/Field and casting operations, or just rely on the macro definition again:
(gdb) python print gdb.parse_and_eval("offsetof(struct foo, bar)")
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With