arm linux内核调试器--kdb

来源:互联网 发布:三菱plcfx3u编程实例 编辑:程序博客网 时间:2024/05/05 15:22

0x1. 介绍

  kdb是简单主义的shell风格的交互接口,可以借助键盘或者串口在系统终端上使用。你可以用它查看内存,寄存器,进程列表,内核log,甚至设置断点停在某个地方,尽管你可以设置断点并且对内核运行进行简单的控制,但kdb不是源码级的调试器。kdb主要的目标时对内核做一些分析用于辅助开发和诊断内核问题。如果内核编译时选择了CONFIG_KALLSYMS,不管时内建的还是模块编译,都可以通过名称访问内核符号,例如可以通过bp命令传入函数符号设置断点等。

0x2. 优势

  单机调试,嵌入式平台利用调试串口作为kdb I/O driver很方便

0x3. 使用方法

0x31. 配置内核

  为了使能KDB,要先使能KGDB
  CONFIG_KGDB=y

  打开kgdb的时候包含kdb调试器
  CONFIG_KGDB_KDB=y

  CONFIG_DEBUG_RODATA选项会标记某些内存区域为只读属性,影响软件断点的使用,这时候需要关闭。如果处理器支持硬件断点,该选项可以打开
  #CONFIG_DEBUG_RODATA is not set

  CONFIG_FRAME_POINTER选项更好的支持栈回溯,该选项依赖于CONFIG_HAVE_FUNCTION_GRAPH_TRACER
  CONFIG_FRAME_POINTER=y
  CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y

  CONFIG_KGDB_SERIAL_CONSOLE选项确定串口为kdb的I/O driver
  CONFIG_KGDB_SERIAL_CONSOLE=y

0x32. 激活kdb

  内核启动参数:
  kgdboc=,[baud]
  示例1:
  添加到内核引导参数
  kgdboc=ttyAMA0,115200

  或者运行时激活
  echo > /sys/module/kgdboc/parameters/kgdboc
  运行时关闭
  echo “” > /sys/module/kgdboc/parameters/kgdboc
  示例2:
  运行时激活
  echo ttyAMA0 > /sys/module/kgdboc/parameters/kgdboc

0x33. 进入kdb模式

  发生oops或fault触发kdb。或者手动进入kdb shell或,手动进入命令:

echo g > /proc/sysrq-trigger

  使用sysrq的前提是CONFIG_MAGIC_SYSRQ=y
这里写图片描述

图3-1 手动进入出发kdb

0x34. 基本命令

  进入kdb shell后可以使用如下命令:
  lsmod – 显示内核加载的模块
  ps – 显示活动的进程
  ps A – 显示所用的进程
  summary – 显示内核版本信息和内存使用情况
  bt – 调用 dump_stack()函数查看当前进程的回溯信息
  dmesg – 查看内核log
  go – 系统继续执行
  reboot 命令立刻重新引导系统。它并没有彻底关闭系统,因此结果是不可预测的。
  内存操作命令
  md 命令以一个地址/符号和行计数为参数,显示从该地址开始的 line-count 行的内存。
  mm 命令修改内存内容。
这里写图片描述

图3-2 内存操作

常用的断点命令
  bp 命令以一个地址/符号作为参数,它在地址处应用断点
  bd 命令禁用特殊断点,它接收断点号作为参数。该命令不是从断点表中除去断点,而只是禁用它。断点号从 0 开始,根据可用性顺序分配给断点。
  be 命令启用断点。该命令的参数也是断点号
  bl 命令列出当前的断点集。它包含了启用的和禁用的断点。
  bc 清除断点。它以具体的断点号或 * 作为参数,在后一种情况下它将除去所有断点
这里写图片描述
图3-3 软件断点控制

0x44. 调试技巧

0x41. gdb辅助调试

  gdb启动时加载内核符号
  arm-none-linux-gnueabi-gdb vmlinux

  加载模块符号
  add-symbol-file test_panic.ko ADDR_FROM_LSMOD

  查找panic位置
  info line *0xADDR_FROM_BT

  显示panic位置
  list linenum
这里写图片描述

图4-1 gdb辅助调试

0x42. 内核符号与地址

  要在运行时查看内核符号,内核需要配置CONFIG_KALLSYMS=y和CONFIG_KALLSYMS_ALL=y。进入kdb后,输入地址可以获取符号信息,输入符号可以获取地址信息
这里写图片描述

图4-2 内核符号操作

0x5. 测试环境

0x51. 版本信息

  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

0x52. 测试代码

/* * 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");

0x53. qemu参数

qemu-system-arm \ -M vexpress-a9 \ -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 \ -sd ~/src/qemu/image/rootfs.ext4  \ -nographic -append "root=/dev/mmcblk0 rw rootfstype=ext4 rootwait init=/linuxrc rootdelay=3 physmap.enabled=0 console=ttyAMA0 kgdboc=ttyAMA0,115200"

参考资料

https://kgdb.wiki.kernel.org/index.php/Main_Page
https://www.kernel.org/pub/linux/kernel/people/jwessel/kdb/index.html
https://www.kernel.org/pub/linux/kernel/people/jwessel/dbg_webinar/State_Of_kernel_debugging_LinuxCon2014.pdf
https://www.ibm.com/developerworks/cn/linux/l-kdbug/

0 0
原创粉丝点击