Gdb调试内核的宏

“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声明参数类型,不过这样做是为了防止编译器警告?还是防范 可能的溢出呢?不明觉厉。

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页