2013-06-10 3 views
1

내가 커널 연결리스트에 액세스를 시도하고, 구조}container_of 매크로

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; 
.... 
.... 

이다; GDB를 사용

, 내가 방법 다음이를 인쇄 할 수 있어요 :

(gdb)p *(qlcnic_wait_event_t *)(((struct my_struct *)dev_base->next->priv).wait_list)

출력은 다음과 같습니다

$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> 

}

내가 갈 필요가 목록을 반복 wait_list의 'next'로 이동하고 'container_of'를 사용하여 주소를 가져옵니다. ? 왜 작동하지

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. 

방법이 container_of을 구현 : 그래서 난 container_of 매크로를 사용하고, 코드는

#!/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") 

(gdb) source container_of.py

이 출력은 수행 한 후입니까?

+0

안녕하세요, 귀하의 회신을 기다리고 있습니다 ... –

답변

0

어떤 코드가 잘못되었는지 보려면이 코드에 디버깅 인쇄물을 넣어야합니다. 첫 번째 읽기에서는 괜찮은 것처럼 보이지만 "offset_of"로 인쇄하면 "캐스팅"하는 인수의 유형을 쉽게 볼 수 있습니다.

return int(element[field].address) 
+0

나는'int (element [field] .address)'를 시도했지만 같은 오류가 발생했습니다. :-('element = gdb.Value (0) .cast (typeobj)'줄의'offset_of '함수에 문제가있는 것 같지만 정확한 문제를 식별 할 수는 없습니다. –

0

당신이 계산 된 컨테이너 유형에 대한 포인터 타입, 샘플 코드를 제공해야합니다 : 당신은 그냥 대신이 작업을 수행 할 수있는 것처럼

return int(str(element[field].address), 16) 

것 같다 :

나는이 라인이 이상한 줄 알았는데 아이디어를 설명합니다.

# container_of(p, type, field) = (type*) (p - offset_of(type, field) 
# offset_of(type, field) = field.bitpos/8 
container_address = int(str(dev_pointer), 16) - field.bitpos/8 
container_pointer = gdb.Value(container_address).cast(container_type.pointer()) 
0

코드의 문제는 캐스트가() 에서이 시점이 아닌 문자열을 gdb.Type을 기대하고 있다는 것입니다. gdb.lookup_type()을 호출하면 해당 부분이 수정됩니다.

offsetof/container_of 관련 : 가장 편리한 방법 인 을 사용하면 gdb의 매크로 기능을 사용할 수 있습니다. 이는 함수 나 명령에 더 쉽게 액세스 할 수 있기 때문입니다.

(gdb) macro define offsetof(_type, _memb) \ 
     ((long)(&((_type *)0)->_memb)) 
(gdb) macro define container_of(_ptr, _type, _memb) \ 
     ((_type *)((void *)(_ptr) - offsetof(_type, _memb))) 

.gdbinit에 포함될 수 있습니다.

(gdb) print offsetof(struct foo, bar) 
... 

는 작업을 gdb.Type/필드를 사용하여 주조, 시작 같은 방법으로 그것을 구현할 수, 파이썬에서 이것을 사용하려면, 또는 은 다시 매크로 정의에 의존 :

(gdb) python print gdb.parse_and_eval("offsetof(struct foo, bar)") 
...