Gdb调试内核的宏
程序员文章站
2022-03-08 08:04:43
...
“I don’t think any new thoughts. I think thoughts that other people have thought, and I rearrange them.” – Linus Torvalds
Linus说他把调试器当反汇编器使用,其实查看宏也是蛮方便的。
打开内核的调试选项CONFIG_DEBUG_INFO,修改内核编译选项。
--- a/Makefile
+++ b/Makefile
@@ -620,7 +620,7 @@ endif
endif
ifdef CONFIG_DEBUG_INFO
-KBUILD_CFLAGS += -g
+KBUILD_CFLAGS += -ggdb3
KBUILD_AFLAGS += -gdwarf-2
endif
这样内核就含有宏调试信息了,调试宏常用的几个命令有:
macro expand expr. 展开宏expr.
info macro -a expr. 查看宏expr定义的地方
macro expand-once
只将嵌套宏最外层展开,但在我的gdb-7.6.1却提示还没实现。
譬如想查看一下"kexec.c"SYSCALL_DEFINE4的宏。
(gdb) list kexec.c:1
(gdb) macro expand SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments,
struct kexec_segment __user *, segments, unsigned long, flags)
static const char *types__kexec_load[] = { "unsigned long", "unsigned long", "struct kexec_segment *", "unsigned long" };
static const char *args__kexec_load[] = { "entry", "nr_segments", "segments", "flags" };
static struct syscall_metadata __syscall_meta__kexec_load;
static struct ftrace_event_call __attribute__((__used__)) event_enter__kexec_load = { .name = "sys_enter""_kexec_load", .class = &event_class_syscall_enter, .event.funcs = &enter_syscall_print_funcs, .data = (void *)&__syscall_meta__kexec_load, .flags = TRACE_EVENT_FL_CAP_ANY, };
static struct ftrace_event_call __attribute__((__used__)) __attribute__((section("_ftrace_events"))) *__event_enter__kexec_load = &event_enter__kexec_load;;
static struct syscall_metadata __syscall_meta__kexec_load;
static struct ftrace_event_call __attribute__((__used__)) event_exit__kexec_load = { .name = "sys_exit""_kexec_load", .class = &event_class_syscall_exit, .event.funcs = &exit_syscall_print_funcs, .data = (void *)&__syscall_meta__kexec_load, .flags = TRACE_EVENT_FL_CAP_ANY, };
static struct ftrace_event_call __attribute__((__used__)) __attribute__((section("_ftrace_events"))) *__event_exit__kexec_load = &event_exit__kexec_load;;
static struct syscall_metadata __attribute__((__used__)) __syscall_meta__kexec_load = {
.name = "sys""_kexec_load", .syscall_nr = -1, .nb_args = 4, .types = 4 ? types__kexec_load : ((void *)0), .args = 4 ? args__kexec_load : ((void *)0), .enter_event = &event_enter__kexec_load, .exit_event = &event_exit__kexec_load, .enter_fields = {
&(__syscall_meta__kexec_load.enter_fields), &(__syscall_meta__kexec_load.enter_fields) },
};
static struct syscall_metadata __attribute__((__used__)) __attribute__((section("__syscalls_metadata"))) *__p_syscall_meta__kexec_load = &__syscall_meta__kexec_load;
long sys_kexec_load(unsigned long entry, unsigned long nr_segments, struct kexec_segment * segments, unsigned long flags) __attribute__((alias("SyS_kexec_load")));
static inline __attribute__((always_inline)) __attribute__((no_instrument_function)) long SYSC_kexec_load(unsigned long entry, unsigned long nr_segments, struct kexec_segment * segments, unsigned long flags);
long SyS_kexec_load(__typeof(__builtin_choose_expr((__builtin_types_compatible_p(typeof((unsigned long)0), typeof(0LL)) || __builtin_types_compatible_p(typeof((unsigned long)0), typeof(0ULL))), 0LL, 0L)) entry, __typeof(__builtin_choose_expr((__builtin_types_compatible_p(typeof((unsigned long)0), typeof(0LL)) || __builtin_types_compatible_p(typeof((unsigned long)0), typeof(0ULL))), 0LL, 0L)) nr_segments, __typeof(__builtin_choose_expr((__builtin_types_compatible_p(typeof((struct kexec_segment *)0), typeof(0LL)) || __builtin_types_compatible_p(typeof((struct kexec_segment *)0), typeof(0ULL))), 0LL, 0L)) segments, __typeof(__builtin_choose_expr((__builtin_types_compatible_p(typeof((unsigned long)0), typeof(0LL)) || __builtin_types_compatible_p(typeof((unsigned long)0), typeof(0ULL))), 0LL, 0L)) flags);
long SyS_kexec_load(__typeof(__builtin_choose_expr((__builtin_types_compatible_p(typeof((unsigned long)0), typeof(0LL)) || __builtin_types_compatible_p(typeof((unsigned long)0), typeof(0ULL))), 0LL, 0L)) entry, __typeof(__builtin_choose_expr((__builtin_types_compatible_p(typeof((unsigned long)0), typeof(0LL)) || __builtin_types_compatible_p(typeof((unsigned long)0), typeof(0ULL))), 0LL, 0L)) nr_segments, __typeof(__builtin_choose_expr((__builtin_types_compatible_p(typeof((struct kexec_segment *)0), typeof(0LL)) || __builtin_types_compatible_p(typeof((struct kexec_segment *)0), typeof(0ULL))), 0LL, 0L)) segments, __typeof(__builtin_choose_expr((__builtin_types_compatible_p(typeof((unsigned long)0), typeof(0LL)) || __builtin_types_compatible_p(typeof((unsigned long)0), typeof(0ULL))), 0LL, 0L)) flags)
{
long ret = SYSC_kexec_load((unsigned long) entry, (unsigned long) nr_segments, (struct kexec_segment *) segments, (unsigned long) flags);
(void)(sizeof(struct { int:-!!(!(__builtin_types_compatible_p(typeof((unsigned long)0), typeof(0LL)) || __builtin_types_compatible_p(typeof((unsigned long)0), typeof(0ULL))) && sizeof(unsigned long) > sizeof(long));
})),
(void)(sizeof(struct { int:-!!(!(__builtin_types_compatible_p(typeof((unsigned long)0), typeof(0LL)) || __builtin_types_compatible_p(typeof((unsigned long)0), typeof(0ULL))) && sizeof(unsigned long) > sizeof(long));
})),
(void)(sizeof(struct { int:-!!(!(__builtin_types_compatible_p(typeof((struct kexec_segment *)0), typeof(0LL)) || __builtin_types_compatible_p(typeof((struct kexec_segment *)0), typeof(0ULL))) && sizeof(struct kexec_segment *) > sizeof(long));
})),
(void)(sizeof(struct { int:-!!(!(__builtin_types_compatible_p(typeof((unsigned long)0), typeof(0LL)) || __builtin_types_compatible_p(typeof((unsigned long)0), typeof(0ULL))) && sizeof(unsigned long) > sizeof(long));
}));
do { } while (0);
return ret;
}
static inline __attribute__((always_inline)) __attribute__((no_instrument_function)) long SYSC_kexec_load(unsigned long entry, unsigned long nr_segments, struct kexec_segment * segments, unsigned long flags)
信息量好大,上面的输出还是手动格式化了一下,不知道有什么好的 pretty-printer自动格式化输出. 其实这些宏主要就是将一些符号放到特定的段 (ftrace)。再利用CPP的__builtin_types_compatible_p __builtin_choose_expr声明参数类型,不过这样做是为了防止编译器警告?还是防范 可能的溢出呢?不明觉厉。
上一篇: 队列的概念及其接口实现