kdb 已经和 kgdb 合入到内核的同一个模块,代码已经合并
CONFIG_KGDB_KDB=y
kgdboc=ttyS0,115200
在启动过程中会自动进入
在 挂载 procfs后手动 "echo g > /proc/sysrq-trigger" 进入
// 默认进入kdb
kdb>
进入 kdb 交互式 shell 之后,可以使用 help 命令查看 kdb 支持的调试功能,并尝试使用之。
前面说过 kdb 和 kgdb 可通过交互 shell 自己切换,
kdb 交互式shell下 可以通过 键入kgdb 进入 kgdb // 进入之后就开始等待gdb的连接
kgdb 非交互式shell下 可以通过 键入$3#33 进入 kdb
- 几种调试手段的区别
| JTAG | KGDB | KDB | |
|---|---|---|---|
| 框架 | JTAG+JLINK+JLinkGDBServer+GDB | KGDB+串口+GDB | KDB+串口(只要是输入就可以,例如lcd) |
| 可以调试的对象 | 裸机(包括u-boot) rtos linux | linux | linux |
| 需要的硬件 | JLINK | 串口 | 串口(只要可以输入就可以,不一定是串口) |
| 需要的软件 | JLinkGDBServer+GDB | KGDB+GDB | KDB |
| 调试linux启动的范围 | 大(在stext时,就可以调试) | 小(必须等待KGDB建立后) | 小(必须等待KDB建立后,与KGDB一同建立) |
| linux启动后是否可以调试 | 可以 | 可以 | 可以 |
| 可否调试裸机 | 可以 | 不可以 | 不可以 |
| 用户接口 | GDB | GDB | KDB命令行 |
| 底层实现机制 | 外部JLINK通过JTAG通过DAP访问debug APB总线上的coresight组件 | 代码通过寄存器从系统总线访问 debug APB总线上的coresight组件 | 同KGDB |
实现原理
- 初始化
kdb_init
kdb_inittab
kdb_register_flags("go", kdb_go, "[<vaddr>]", "Continue Execution", 1, KDB_ENABLE_REG_WRITE | KDB_ENABLE_ALWAYS_SAFE_NO_ARGS);
---
kgdb_arch_init
register_undef_hook(&kgdb_brkpt_hook);
register_undef_hook(&kgdb_compiled_brkpt_hook);
static struct undef_hook kgdb_brkpt_hook = {
.instr_mask = 0xffffffff,
.instr_val = KGDB_BREAKINST,
.cpsr_mask = MODE_MASK,
.cpsr_val = SVC_MODE,
.fn = kgdb_brk_fn
};
static struct undef_hook kgdb_compiled_brkpt_hook = {
.instr_mask = 0xffffffff,
.instr_val = KGDB_COMPILED_BREAK,
.cpsr_mask = MODE_MASK,
.cpsr_val = SVC_MODE,
.fn = kgdb_compiled_brk_fn
};
----------------------------------
device_initcall(sysrq_init);
sysrq_init_procfs
proc_create("sysrq-trigger", S_IWUSR, NULL, &sysrq_trigger_proc_ops)
-------------------------------
// 第一种初始化
console_initcall(kgdboc_earlycon_late_init);
kgdboc_earlycon_init(kgdboc_earlycon_param);
// 第二种初始化
early_param("kgdboc_earlycon", kgdboc_earlycon_init); // drivers/tty/serial/kgdboc.c
kgdboc_earlycon_init
kgdb_register_io_module // kernel/debug/debug_core.c
kgdb_register_callbacks
register_sysrq_key // drivers/tty/sysrq.c
__sysrq_swap_key_ops
__sysrq_put_key_op
// 第三种初始化
static struct platform_driver kgdboc_platform_driver = {
.probe = kgdboc_probe,
.driver = {
.name = "kgdboc",
kgdboc_probe //
configure_kgdboc // drivers/tty/serial/kgdboc.c
kgdb_register_io_module // kernel/debug/debug_core.c
kgdb_register_callbacks
register_sysrq_key // drivers/tty/sysrq.c
__sysrq_swap_key_ops
__sysrq_put_key_op
三种初始化相关的 ops
static const struct sysrq_key_op sysrq_dbg_op = {
.handler = sysrq_handle_dbg,
.help_msg = "debug(g)",
.action_msg = "DEBUG",
};
sysrq_handle_dbg
if (!kgdb_connected) {
#ifdef CONFIG_KGDB_KDB
if (!dbg_kdb_mode)
pr_crit("KGDB or $3#33 for KDB\n");
#else
pr_crit("Entering KGDB\n");
#endif
}
kgdb_breakpoint();
asm(__inst_arm(0xe7ffdeff)); // arch/arm/include/asm/kgdb.h
// #define KGDB_COMPILED_BREAK 0xe7ffdeff 非arm定义指令, kgdb会将其视为 断点指令
// #define KGDB_BREAKINST 0xe7ffdefe 非arm定义指令, kgdb会将其视为 下一条指令
- 发生时
drivers/tty/sysrq.c
static const struct proc_ops sysrq_trigger_proc_ops = {
.proc_write = write_sysrq_trigger
write_sysrq_trigger/
__handle_sysrq // sysrq键 调用 __sysrq_swap_key_ops->__handle_sysrq
sysrq_key_table[16]/即sysrq_handle_dbg
kgdb_breakpoint
asm(__inst_arm(0xe7ffdeff)); // 非定义指令,产生非定义指令异常,进入 __und_svc
_und_svc:
...
__und_svc_fault:
bl __und_fault
__und_fault:
ldr r2, [r0, #S_PC]
sub r2, r2, r1
str r2, [r0, #S_PC]
b do_undefinstr
比较 产生异常的指令码 是不是 (0xe7ffdeff或0xe7ffdefe)
如果是,调用 do_undefinstr
如果不是,正常 未定义指令异常 流程
do_undefinstr
call_undef_hook(regs, instr)
list_for_each_entry(hook, &undef_hook, node) fn = hook->fn;
fn ? fn(regs, instr) : 1;/即 kgdb_compiled_brk_fn
kgdb_handle_exception
kgdb_cpu_enter // kernel/debug/debug_core.c
kdb_stub // kernel/debug/kdb/kdb_debugger.c
kdb_main_loop // kernel/debug/kdb/kdb_main.c
kdb_local
while(1){
kdb_getstr // 获取用户输入的字符串
diag = kdb_parse(cmdbuf); // 解析字符串
if (diag == KDB_CMD_GO)
break;
}
或
gdb_serial_stub
版权声明:本文为u011011827原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。