arm linux内核源码级调试器kgdb配置与使用
来源:互联网 发布:linux php编译 编辑:程序博客网 时间:2024/06/07 11:55
0x1 介绍
kgdb是源码级调试器,与gdb配合调试linux kenrel,就像使用gdb调试应用程序一样,停止内核运行,可以查看内存,变量和调用栈信息。它可以在源码处设置断点,进行单步调试,函数进入等。
kgdb需要两台机器,目标机和调试主机。调试主机运行gdb时加载含有符号表的vmlinux,调试运行时的目标机内核,gdb指定连接参数连接到kgdb,需要通过目标架构内核中的kgdb I/O modules进行连接,可以是rs232或以太网。
0x2 使用方法
0x21 内核配置
CONFIG_KGDB使能KGDB
Kernel hacking —>
[*] KGDB: kernel debugger —>
CONFIG_KGDB_SERIAL_CONSOLE选项确定串口为KGDB的I/O modules driver
Kernel hacking —>
[*] KGDB: kernel debugger —>
<*> KGDB: use kgdb over the serial console(kgdboc)
CONFIG_DEBUG_RODATA选项会标记某些内存区域为只读属性,影响软件断点的使用,这时候需要关闭。如果处理器支持硬件断点,该选项可以打开
System Type —>
[ ] Make kernel text and rodata read-only
CONFIG_FRAME_POINTER选项更好的支持栈回溯,该选项依赖于CONFIG_HAVE_FUNCTION_GRAPH_TRACER
Kernel hacking —>
[*] Tracers —>
[*] Kernel Function Tracer
[*] Kernel Function Graph Tracer
CONFIG_HAVE_FUNCTION_GRAPH_TRACER选中后CONFIG_FRAME_POINTER默认选中
CONFIG_DEBUG_INFO选项在内核中加入调试信息
Kernel hacking —>
Compile-time checks and compiler options —>
[*] Compile the kernel with debug info
CONFIG_KALLSYMS选项可以在运行时通过name访问符号信息
General setup —>
[*] Configure standard kernel features (expert users) —>
-*- Load all symbols for debugging/ksymoops
#CONFIG_DEBUG_RODATA is not setCONFIG_KGDB=yCONFIG_KGDB_SERIAL_CONSOLE=yCONFIG_HAVE_FUNCTION_GRAPH_TRACER=yCONFIG_FRAME_POINTER=yCONFIG_DEBUG_INFO=yCONFIG_KALLSYMS=y
0x22 激活
内核启动参数:
kgdboc=<tty-device>,[baud]
示例1:
添加到内核引导参数
kgdboc=ttyAMA0,115200
示例2:
运行时激活
echo ttyAMA0 > /sys/module/kgdboc/parameters/kgdboc
运行时关闭
echo "" > /sys/module/kgdboc/parameters/kgdboc
0x23 触发
发生oops或fault触发kgdb。或者手动触发kgdb,手动进入命令:
echo g > /proc/sysrq-trigger
0x3 qemu参数
清单 3-1. qmeu运行时 ttyAMA0作为服务器通信IO,控制台转换为tcp服务器
qemu-system-arm -M vexpress-a9 \ -m 512M -kernel ~/src/linux/kernel/vexpress-a9-linux-4.10.9/arch/arm/boot/zImage \ -dtb ~/src/linux/kernel/vexpress-a9-linux-4.10.9/arch/arm/boot/dts/vexpress-v2p-ca9.dtb \ -nographic \ -append “root=/dev/mmcblk0 console=ttyAMA0 kgdboc=ttyAMA0,115200” \ -sd /home/marquis/src/qemu/image/rootfs.ext4 \ -serial tcp::8181,server,nowait
0x4 代理使用
在uart接口足够多的情况下,调试串口和kgdb I/O串口可以分别占用。如果只有一个调试串口,可以考虑使用代理工具agent-proxy,它是一个tty到tcp的连接,tty是硬件平台的调试终端,tcp做为服务端,允许多个客户端同时程序连接。
通过kgdboc可以连接一个交互telnet客户端和一个调试端口,两种连接方法分别为:
方法一,连接主机到目标机的串口作为服务端:
agent-proxy 2223^2222 0 /dev/ttyS0,115200 &
/dev/ttyS0为PC端串口,115200为波特率
方法二,远程服务器或模拟器的连接方法:
agent-proxy 2223^2222 localhost 8181 &
2223为控制台客户端连接的端口,2222为gdb连接的端口,8181为服务端口(qemu运行时的监听端口),agent-proxy作为客户端连接服务端。
agent-proxy源码下载地址
git clone git://git.kernel.org/pub/scm/utils/kernel/kgdb/agent-proxy.git
编译
cd agent-proxy ;
make
0x5 调试技巧
0x51 agent-proxy的使用
- agent-proxy运行
agent-proxy 2223^2222 localhost 8181 & - 运行qemu
直接执行0x3节( qemu参数)所列出的命令,其中参数-serial tcp::8181,server,nowait创建agent-proxy所连接的服务器,监听端口8181 - 连接console
telnet localhost 2223
Enter - 触发kgdb
echo g > /proc/sysrq-trigger - 连接gdb
加载内核符号表
arm-none-linux-gnueabi-gdb vmlinux
进入gdb后,执行
target remote localhost:2222
图5-1 agent-proxy操作
0x52 模块的符号表加载
- 装载模块
insmod test_panic.ko - 查看代码段和数据段的虚拟地址
cat /sys/module/test_panic/sections/.text
cat /sys/module/test_panic/sections/.bss - gdb加载模块符号表
add-symble-file test_panic.ko ADDR_SEC_TEXT -s .bss ADDR_SEC_BSS
图5-3 加载模块符号表
0x53 断点
- 设置断点
(gdb)break test_proc_write - 查询断点信息
(gdb)info break - 触发断点
控制台执行echo 1 > /proc/test_panic/test - 删除断点
(gdb)delete 1
图5-2 设置断点和删除断点
0x56 kgdb遗留问题
arm kgdb不支持硬件断点,所以无法使用。因为kgdb和kdb使用相同的后端,所以在arm平台kdb也不支持硬件断点。
0x6 KGDB其他
0x61 KGDB与KDB
kgdb和kdb是内核两个不同的调试器前端,如果你恰当的编译和运行linux kernel,两个调试器是可以运行时动态切换的。
0x62 kdb和kgdb互相切换
- kdb到kgdb
进入kdb shell后,gdb内远程连接kgdb,则直接进入kgdb模式。 - kgdb到kdb
退出远程gdb,在调试串口输入”$3#33”。
P.S. 实验的过程中从kgdb切换回kdb会导致系统挂起,没有任何信息,不知道是qemu的问题还是kgdb的问题。
0x63 kgdb现状(不完整,待补充)
- kgdb和kdb使用相同的后端
- kgdboe的方式不可靠
- kgdboc虽然速度慢但是比较可靠
- EHCI debug port是最快的kgdb连接方式
0x7 测试环境
0x71 版本信息
主机系统:ubuntu 14.04
linux版本号: 4.10.9
交叉编译工具版本:
arm-none-linux-gnueabi-gcc (Sourcery CodeBench Lite 2014.05-29) 4.8.3
arm-none-linux-gnueabi-gdb GNU gdb (Sourcery CodeBench Lite 2014.05-29) 7.7.50.20140217-cvs
qemu版本:QEMU emulator version 2.7.1
模拟开发板:arm vexpress a9
0x72 测试代码
清单7-1.
/* * Copyright (c) 2005-2010 Wind River Systems, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. */#include <linux/module.h>#include <linux/delay.h>#include <linux/moduleparam.h>#include <linux/types.h>#include <linux/timer.h>#include <linux/miscdevice.h>#include <linux/watchdog.h>#include <linux/fs.h>#include <linux/notifier.h>#include <linux/reboot.h>#include <linux/init.h>#include <linux/proc_fs.h>#include <linux/sched.h>#include <asm/uaccess.h>#include <linux/slab.h>#define LOCAL_MODULE_VERSION "1.0"#define MODULE_NAME "test_panic"#define DEAD_ADDRESS 0xdeadbeefstatic struct proc_dir_entry *panic_dir;static struct proc_dir_entry *panic_file;static struct proc_dir_entry *test_file;static struct proc_dir_entry *print_file;static int panic_proc_open(struct inode *inode, struct file *file){ int err = 0; if (try_module_get(THIS_MODULE)) { return err; } return -ENODEV;}static int panic_proc_release(struct inode *inode, struct file *file){ module_put(THIS_MODULE); return 0;}static ssize_t panic_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *data){ trace_printk("Starting panic\n"); printk(KERN_INFO "=============Starting panic\n"); panic("test_panic running!\n"); return count;}static int test_aaa = 0;static int *test_addr = NULL;static ssize_t test_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *data){ printk(KERN_INFO "test_aaa = 0x%08x\n", test_aaa); test_addr = &test_aaa; return count;}static ssize_t print_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *data){ printk(KERN_INFO "enter printk\n"); return count;}static const struct file_operations panic_fops = { .owner = THIS_MODULE, .open = panic_proc_open, .write = panic_proc_write, .release = panic_proc_release,};static const struct file_operations test_fops = { .owner = THIS_MODULE, .write = test_proc_write,};static const struct file_operations print_fops = { .owner = THIS_MODULE, .write = print_proc_write,};static int __init test_panic_init(void){ int rc = -ENOMEM; trace_printk("Running test_panic_init()"); /* create directory */ panic_dir = proc_mkdir(MODULE_NAME, NULL); if(!panic_dir) return rc; trace_printk("test_panic: Building panic\n"); panic_file = proc_create("panic", S_IFREG | S_IRUGO | S_IWUSR, panic_dir, &panic_fops); if(!panic_file) goto fail1; test_file = proc_create("test", S_IFREG | S_IRUGO | S_IWUSR, panic_dir, &test_fops); if(!panic_file) goto fail2; print_file = proc_create("print", S_IFREG | S_IRUGO | S_IWUSR, panic_dir, &print_fops); if(!panic_file) goto fail3; trace_printk(KERN_INFO "%s %s initialised\n", MODULE_NAME, LOCAL_MODULE_VERSION); printk(KERN_INFO "%s %s initialised\n", MODULE_NAME, LOCAL_MODULE_VERSION); return 0;fail3: remove_proc_entry("test", panic_dir);fail2: remove_proc_entry("panic", panic_dir);fail1: remove_proc_entry(MODULE_NAME, NULL); return rc;}static void __exit test_panic_exit(void){ remove_proc_entry("panic", panic_dir); remove_proc_entry("test", panic_dir); remove_proc_entry("print", panic_dir); remove_proc_entry(MODULE_NAME, NULL); printk(KERN_INFO "%s %s removed\n", MODULE_NAME, LOCAL_MODULE_VERSION);}module_init(test_panic_init);module_exit(test_panic_exit);MODULE_DESCRIPTION("base on WindRiver code");MODULE_AUTHOR("marquis song");MODULE_LICENSE("GPL v2");
参考资料
https://www.kernel.org/pub/linux/kernel/people/jwessel/kdb/
https://www.kernel.org/pub/linux/kernel/people/jwessel/dbg_webinar/State_Of_kernel_debugging_LinuxCon2014.pdf
- arm linux内核源码级调试器kgdb配置与使用
- ARM-使用KGDB调试内核
- 使用 KGDB 调试 Linux 内核
- 使用 KGDB 调试 Linux 内核
- 使用 KGDB 调试 Linux 内核
- 使用KGDB调试Linux内核
- linux内核调试:kgdb,配置kgdb调试环境
- 在VMWARE中使用KGDB进行源码级Linux内核调试
- linux内核调试(kgdb)
- KGDB调试LINUX内核
- linux内核kgdb调试
- 使用KGDB构建Linux内核调试环境
- 使用kgdb进行Linux内核调试(未完成!)
- 基于at91rm9200的arm平台 kgdb+linux内核调试
- (转载)使用kgdb调试linux内核及内核模块
- (转载)使用kgdb调试linux内核及内核模块
- 使用kgdb调试linux内核及内核模块
- 使用kgdb调试linux内核及内核模块
- 如何设置页面元素的显示和隐藏?
- C语言基础-指针和函数的补充21
- .NET下 JSON 的一些常用操作
- 一文看懂NB-IoT所有猫腻:华为如此青睐的原因?
- Android端上传图片到后台,存储到数据库中 详细代码
- arm linux内核源码级调试器kgdb配置与使用
- [LeetCode]Longest Substring Without Repeating Characters
- DOM模型中的常用对象及其方法?
- 005 使用log4j2输出日志(重构)
- History对象,location对象
- navicat premium连接Oracle几个步骤
- Android代码编写规范
- 字符串函数
- 贪心专题