한 4년 전 인가요? 아래 코드를 열심히 분석 했었어요. 그런데 나중에 알고 보니 CONFIG_KMEMCHECK, CONFIG_LOCKDEP 컨피그 내 코드가 컴파일 되지 않는 죽은 코드라는 걸 알게 되었어요. 그 때 참 머리를 쥐어 뜯으며 자책했죠.
static inline void slab_free_hook(struct kmem_cache *s, void *x)
{
kmemleak_free_recursive(x, s->flags);
/*
* Trouble is that we may no longer disable interrupts in the fast path
* So in order to make the debug calls that expect irqs to be
* disabled we need to disable interrupts temporarily.
*/
#if defined(CONFIG_KMEMCHECK) || defined(CONFIG_LOCKDEP)
{
unsigned long flags;
local_irq_save(flags);
kmemcheck_slab_free(s, x, s->object_size);
debug_check_no_locks_freed(x, s->object_size);
local_irq_restore(flags);
}
#endif
if (!(s->flags & SLAB_DEBUG_OBJECTS))
debug_check_no_obj_freed(x, s->object_size);
kasan_slab_free(s, x);
}
이 사실을 어떻게 알아 냈나면, 전처리 파일을 보고 나서죠.
전처리 파일로 slab_free_hook() 함수 구현부를 보았더니 완전 다른 코드로 바뀌어 있었어요.
SLAB_DEBUG_OBJECTS 매크로가 0x00000000UL로 뒤바꾸어 있네요.
static inline __attribute__((always_inline)) __attribute__((no_instrument_function)) void slab_free_hook(struct kmem_cache *s, void *x)
{
kmemleak_free_recursive(x, s->flags);
# 1314 "/home001/kernel_lover/kernel/mm/slub.c"
if (!(s->flags & 0x00000000UL))
debug_check_no_obj_freed(x, s->object_size);
kasan_slab_free(s, x);
}
다른 예를 살펴볼까요? get_partial_node() 함수 내 너무나도 유명한 list_for_each_entry_safe API가 보이죠.
static void *get_partial_node(struct kmem_cache *s, struct kmem_cache_node *n,
struct kmem_cache_cpu *c, gfp_t flags)
{
struct page *page, *page2;
void *object = NULL;
int available = 0;
int objects;
if (!n || !n->nr_partial)
return NULL;
spin_lock(&n->list_lock);
list_for_each_entry_safe(page, page2, &n->partial, lru) {
void *t;
if (!pfmemalloc_match(page, flags))
continue;
t = acquire_slab(s, n, page, object == NULL, &objects);
//skip
}
spin_unlock(&n->list_lock);
list_for_each_entry_safe 함수를 전처리 파일로 보면 어떨까요?
어라, 참 다르죠.
static void *get_partial_node(struct kmem_cache *s, struct kmem_cache_node *n,
struct kmem_cache_cpu *c, gfp_t flags)
{
struct page *page, *page2;
void *object = ((void *)0);
int available = 0;
int objects;
if (!n || !n->nr_partial)
return ((void *)0);
spin_lock(&n->list_lock);
for (page = ({ const typeof( ((typeof(*page) *)0)->lru ) *__mptr = ((&n->partial)->next); (typeof(*page) *)( (char *)__mptr - __builtin_offsetof(typeof(*page), lru) );}), page2 = ({ const typeof( ((typeof(*(page)) *)0)->lru ) *__mptr = ((page)->lru.next); (typeof(*(page)) *)( (char *)__mptr - __builtin_offsetof(typeof(*(page)), lru) );}); &page->lru != (&n->partial); page = page2, page2 = ({ const typeof( ((typeof(*(page2)) *)0)->lru ) *__mptr = ((page2)->lru.next); (typeof(*(page2)) *)( (char *)__mptr - __builtin_offsetof(typeof(*(page2)), lru) );})) {
void *t;
또 다른 예를 살펴볼까요?
static void init_pwq(struct pool_workqueue *pwq, struct workqueue_struct *wq,
struct worker_pool *pool)
{
BUG_ON((unsigned long)pwq & WORK_STRUCT_FLAG_MASK);
memset(pwq, 0, sizeof(*pwq));
pwq->pool = pool;
역시 전처리 파일 내 함수는 다르게 구현되어 있네요.
static void init_pwq(struct pool_workqueue *pwq, struct workqueue_struct *wq,
struct worker_pool *pool)
{
do { if (__builtin_expect(!!((unsigned long)pwq & WORK_STRUCT_FLAG_MASK), 0)) do { asm volatile(".long " "((0xe7f001f2) & 0xFFFFFFFF)" "\n\t" "\n"); __builtin_unreachable(); } while (0); } while (0);
({ void *__p = (pwq); size_t __n = sizeof(*pwq); if ((__n) != 0) { if (__builtin_constant_p((0)) && (0) == 0) __memzero((__p),(__n)); else memset((__p),(0),(__n)); } (__p); });
pwq->pool = pool;
전처리 파일을 추출은 하는 방법이 뭐냐구요?
아래 패치를 적용하고 커널 컴파일을 하세요. 그럼 리눅스 커널 오브젝트 파일이 생기는 디렉토리에
.tmp_slub.i 형태로 생성되요.
diff --git a/Makefile b/Makefile
index b03ca98..f52240c 100644
--- a/Makefile
+++ b/Makefile
@@ -406,6 +406,7 @@ KBUILD_CFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
-fno-strict-aliasing -fno-common \
-Werror-implicit-function-declaration \
-Wno-format-security \
+ -save-temps=obj \
-std=gnu89
'[Debugging] Tips' 카테고리의 다른 글
TraceStackDumpWithCallstack_64BitARM.cmm (0) | 2023.05.05 |
---|---|
[Linux][Kernel] T32 - 구조체 확인 (v.type) (0) | 2023.05.05 |
[Linux][Kernel] T32 - Linked List 디버깅 cmm Script (0) | 2023.05.04 |
[리눅스커널][디버깅] Red Hat Crash-Utility(크래시 유틸리티) 설치 (0) | 2023.05.04 |
[Linux][Kernel][ARM] char buf[32]; vs char buf[32]={0}; (0) | 2023.05.04 |