이번 시간에는 wakeup_sources이란 링크드 리스트를 통해 wakelock 디버깅을 합시다.
이전에는 crash-utility를 썻는데 이번에는 Trace32를 쓰겠습니다.
개발자는 다양한 툴을 써야 한 가지 툴에 종속된 노예 개발자가 되는 것을 피할 수 있습니다.
또한 각 툴의 장점을 잘 활용할 수도 있습니다.
먼저, 다음 T32 명령어를 입력해서 offsetof와 container_of 매크로를 생성합시다.
sYmbol.NEW.MACRO offsetof(type,member) ((int)(&((type*)0)->member))
sYmbol.NEW.MACRO container_of(ptr,type,member) ((type *)((char *)(ptr)-offsetof(type,member)))
wakelock을 잡은 모듈들은 wakeup_sources 이란 전역 변수에 등록돼 있습니다.
우선 wakeup_sources 변수를 봅시다.
v.v %h %t wakeup_sources
(static struct list_head) wakeup_sources = (
(struct list_head *) next = 0xFFFFFFC5FD92EA88 -> (
(struct list_head *) next = 0xFFFFFFC5FD92FC88 -> (
(struct list_head *) next = 0xFFFFFFC541226488,
(struct list_head *) prev = 0xFFFFFFC5FD92EA88),
(struct list_head *) prev = 0xFFFFFF97D92B4D00),
(struct list_head *) prev = 0xFFFFFFC62D3EDB88)
계속 struct list_head->next로 리스트들이 연결돼 있습니다.
이제 앞에서 생성한 container_of 매크로를 쓸 순간입니다. 다음과 같이 명령어를 입력합시다.
v.v %h %t %s container_of(0xFFFFFFC5FD92EA88,struct wakeup_source,entry)
(struct wakeup_source *) container_of(0xFFFFFFC5FD92EA88,struct wakeup_source,entry) = 0xFFFFFFC5FD92EA80 -> (
(char *) name = 0xFFFFFFC55DEE3280 -> "ipc00001269_1988_HwBinder:682_1",
(struct list_head) entry = ((struct list_head *) next = 0xFFFFFFC5FD92FC88, (struct list_head *) prev = 0xFFF
(spinlock_t) lock = ((struct raw_spinlock) rlock = ((arch_spinlock_t) raw_lock = ((u16) owner = 0x298F, (u16)
(struct wake_irq *) wakeirq = 0x0,
(struct timer_list) timer = ((struct hlist_node) entry = ((struct hlist_node *) next = 0x0, (struct hlist_nod
(long unsigned int) timer_expires = 0x0,
(ktime_t) total_time = ((s64) tv64 = 0x0),
(ktime_t) max_time = ((s64) tv64 = 0x0),
(ktime_t) last_time = ((s64) tv64 = 0x000040E1FC6B0DF2),
(ktime_t) start_prevent_time = ((s64) tv64 = 0x0),
(ktime_t) prevent_sleep_time = ((s64) tv64 = 0x0),
(long unsigned int) event_count = 0x0,
(long unsigned int) active_count = 0x0,
(long unsigned int) relax_count = 0x0,
(long unsigned int) expire_count = 0x0,
(long unsigned int) wakeup_count = 0x0,
(long unsigned int) pending_count = 0x0,
(bool:1) active = FALSE,
(bool:1) autosleep_enabled = FALSE)
위 멤버 변수 중 active 변수가 FALSE이니 "ipc00001269_1988_HwBinder:682_1"이란 wakeup source가 wakelock을 잡고 있지 않습니다.
v.v %h %t %s container_of(0xFFFFFFC5FD92EA88,struct wakeup_source,entry)
위와 같은 명령어를 쓴 이유는, struct wakeup_source이란 구조체에 entry이란 struct list_head 타입 멤버 변수가
wakeup_sources이란 링크드 리스트 전역 변수 wakeup_sources->next로 등록됐기 때문입니다.
해당 구조체를 봅시다.
struct wakeup_source {
const char *name;
struct list_head entry;
spinlock_t lock;
struct wake_irq *wakeirq;
struct timer_list timer;
unsigned long timer_expires;
ktime_t total_time;
ktime_t max_time;
ktime_t last_time;
ktime_t start_prevent_time;
ktime_t prevent_sleep_time;
unsigned long event_count;
unsigned long active_count;
unsigned long relax_count;
unsigned long expire_count;
unsigned long wakeup_count;
bool active:1;
bool autosleep_enabled:1;
};
쉽게 설명하면 아래 방식으로 wakeup_source가 wakeup_sources 리스트에 등록합니다.
1st wakeup source 등록
wakeup_sources->next = struct wakeup_source->entry
2nd wakeup source등록
wakeup_sources->next->next = struct wakeup_source->entry
개발자분들이여, 임베디드 동네의 최강의 툴인 Trace32를 잘 활용해서 일찍 퇴근합시다.
'[Debugging] Tips' 카테고리의 다른 글
[Kernel][Debug] 런큐에서 CFS 스케쥴러에 큐잉된 프로세스 찾기 (0) | 2023.05.04 |
---|---|
[Trace32] 폰트 색상 변경 - setup.color (0) | 2023.05.04 |
[안드로이드][리눅스커널] 시그널 - 유저 공간 abort(SIGABRT) 시 동작 시 흐름 (0) | 2023.05.04 |
[Crash-Utility] Radix Tree 디버깅: 'tree -t radix -N (struct radix_tree_node *) 구조체 주소' (0) | 2023.05.04 |
[리눅스커널] 안드로이드/라즈베리 파이 부팅 실패 100% 해결하는 디버깅 패치 (0) | 2023.05.04 |