1 / 69

The success's road

The success's road. Linux 调试. www.farsight.com.cn. 写在前面. Linux 内核或设备驱动程序的调试远比应用程序的调试繁琐、复杂! 调试内核的关键是对内核的深刻理解 要有汇编基础 ! 要有耐心! 要有好运!. 2.4 内核中对调试的支持. 2.6 内核中对调试的支持. 使用 printk 进行调试. printk 的健壮性. printk 的脆弱性. 随时调用 在中断中调用 在进程上下文中调用 在持有锁时调用 在多处理器上同时使用. 终端启动前无法调用. early_printk ().

ailsa
Download Presentation

The success's road

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. The success's road Linux调试 www.farsight.com.cn

  2. 写在前面 • Linux内核或设备驱动程序的调试远比应用程序的调试繁琐、复杂! • 调试内核的关键是对内核的深刻理解 • 要有汇编基础! • 要有耐心! • 要有好运!

  3. 2.4内核中对调试的支持

  4. 2.6内核中对调试的支持

  5. 使用printk进行调试 printk的健壮性 printk的脆弱性 • 随时调用 • 在中断中调用 • 在进程上下文中调用 • 在持有锁时调用 • 在多处理器上同时使用 • 终端启动前无法调用 early_printk()

  6. printk的记录等级 printk( KERN_WARNING“This is a warning\n”); printk( KERN_DEBUG“This is a warning!\n” ); printk( “No LogLevel is specified!\n” );

  7. 重要性逐渐减弱 可供使用的记录等级 记录等级 说明 0. KERN_EMERG 紧急情况 KERN_ALERT 需要立即被注意到的 KERN_CRIT 临界情况 KERN_ERR 错误 KERN_WARNING 警告 KERN_NOTICE 普通的,可能需要注意 KERN_INFO 非正式的 KERN_DEBUG 一般的调试信息

  8. 用户空间的守护进程--klogd • 用来从记录缓冲区获取内核消息; • 只有日记级别小于console_loglevel,消息才能显示出来, console_loglevel的值可以通过sys_syslogd系统调用进行修改; • 载入klogd时,可以使用-c标志改变终端的记录等级; • 运行klogd后,消息将追加到/var/log/messages; • 没有运行klogd,消息不会传递到用户空间,此时可以查看/proc/kmsg文件。

  9. syslogd进程 • 保存klogd进程获取的内核消息到系统日志文件中; • 默认的文件是/var/log/messages; • 可通过/etc/syslog.conf文件重新配置; • 如果没有运行klogd进程,数据将保留在循环缓冲区中,直到某个进程读取和缓冲区溢出为止。

  10. 调试信息数据流传递流程图 其他应用程序调试信息printf klogd进程 syslog库函数 控制台或log文件 用户空间 syslog进程 内核空间 sys_syslog系统调用 __log_buf循环缓冲区 printk函数

  11. 提高日志级别 • 要查看调试信息,必须提高日志级别; • 读写/proc/sys/kernel/printk文件 • [root@vm-2.6]#cat /proc/sys/kernel/printk • 6 4 1 7 • 设置当前日志级别的命令 • [root@vm-2.6]#echo 8 > /proc/sys/kernel/printk

  12. strace命令 • 显示程序调用的所有系统调用 • 从内核接收信息,而且不需要以任何特殊的方式来构建内核。 • -t:显示调用发生的时间 • -T:显示调用花费的时间 • -e:限定被跟踪的调用类型 • -o:将输出定向到一个文件中 strace cp -o aa

  13. oops • 产生oops的原因: • 内存访问越界 • 非法指令 • 使用了NULL指针 • 使用了不正确的指针值 • oops的内容: • CPU寄存器内容 • 页描述符表的位置 • 其他信息

  14. 有问题的write程序 ssize_t faulty_write ( struct file *filp, const char __user *buf, size_t count, loff_t *pos ) { *(int *)0 = 0; return 0; }

  15. 有问题的read程序 ssize_t faulty_read ( struct file *filp, const char __user *buf, size_t count, loff_t *pos ) { int ret; char stack_buf[4]; memset(stack_buf,0xff,20); if(count > 4) count=4; ret = copy_to_user(buf,stack_buf,count); if(!ret) return count; return ret; }

  16. oops产生时的转储信息 EIP: 0010:[<00000000>] Unable to handle kerel paging request at virtual address ffffffff printing eip: ffffffff Oops: 0000[#5] SMP CPU: 0 EIP: 0060:[<ffffffff>] Not tainted EFLAGS: 00010296 (2.6.6) EIP is at 0xfffffff eax:0000000c ebx:ffffffff ecx:00000000 edx:bfffda7c esi:cf434f00 edi:ffffffff ebp:00002000 esp:c27fff78 ds:007b es:007b ss:0068

  17. oops产生时的转储信息(2) Process Head (pid:2331,threadinfo=c27fe000 task=c3226150) Stack: ffffffff bfffda70 00002000 cf434f20 00000001 00000286 cf434f00 fffffff bfffda70 c27fe000 c0150612 cf434f00 bfffda70 00002000 cf434f20 00000000 00000003 00002000 c0103f8f 00000003 bfffda70 00002000 00002000 bfffda70 Call Trace: [<c0150612>] sys_read + 0x42/0x70 [<c0103f8f>] syscall_call + 0x7/0xb Code: Bad EIP value

  18. oop分析器 • klogd:符号表与当前内核必须匹配。 • ksymoops:查看/proc/modules获得模块的符号信息,从/proc/ksyms中取得内核符号表。 ksymoops filename.oops

  19. 格式化 Oops 消息 错误 代码 oops消息 运行kysmoops 格式化后的 oops消息

  20. oops产生时的转储信息 EIP: 0010:[<00000000>] Unable to handle kerel paging request at virtual address ffffffff printing eip: ffffffff Oops: 0000[#5] SMP CPU: 0 EIP: 0060:[<ffffffff>] Not tainted EFLAGS: 00010296 (2.6.6) EIP is at 0xfffffff eax:0000000c ebx:ffffffff ecx:00000000 edx:bfffda7c esi:cf434f00 edi:ffffffff ebp:00002000 esp:c27fff78 ds:007b es:007b ss:0068

  21. 查看日志获取系统状态 • Linux的3个主要的日志子系统: • 连接时间日志 /var/log/wtmp和/var/run/utmp • 进程统计日志 pacct或acct • 错误日志 由syslogd(8)执行

  22. 常用的日志文件 • access-log --> 记录网络传输 • acct/pacct --> 记录用户命令 • btmp --> 记录失败的记录 • lastlog --> 最后登陆记录 • messages --> 从syslog中记录信息 • sudolog --> sudo发出的命令 • sulog --> su命令的使用 • utmp --> 记录当前登陆用户 • xferlog --> 记录ftp会话

  23. gdb调试器 • 运行程序,给程序加所需的调试条件 • 在给定的条件下让程序停止 • 检查程序停止时的运行状态 • 通过改变数据,更改程序的错误

  24. gdb启动界面

  25. gdb基本命令 • file • quit • run • info • list • break watch print set step next continue help

  26. 远程调试 目标操纵系统初始化到应用程序入口 运行调试器 主动触发异常 指定调试通信端口向目标系统发送消息 异常处理程序转到调试端口进行通信

  27. gdb远程调试环境原理图 应用程序 GDB/XGDB 内核 串口/网络 X Windows 环境 stub程序 本地主机 远程主机

  28. arm-linux-gdb的创建 • download gdb-<version>.tar.bz2 • tar jxvf gdb-<version>.tar.bz2 • ./configure --target = arm-linux --prefix = /usr/local/arm-gdb –v • make • make install

  29. 编译stub程序 • export PATH=$PATH:/usr/local/arm-gdb/bin • ./configure --target=arm-linux --host=arm-linux • 在gdbserver目录运行: • make CC=/usr/local/xxx/bin/arm-linux-gcc • 在gdb目录下生成gdbserver,该程序在开发板上运行 • 建立主机和开发板之间的TCP/IP连接

  30. 建立gdb和gdbserver连接 • 在目标板上运行gdbserver • [root@vm /root]# ./gdbserver 192.168.1.1:2345 hello • Process hello created; pid=1000 • Listening on port 2345 • 将hello程序复制到主机的相应目录,执行arm-linux-gdb: • ./arm-linux-gdb hello • 连接到开发板 • (gdb) target remote 192.168.1.1:2345

  31. KDB介绍 • Linux内核调试器是Linux内核的补丁,提供了一种在系统能运行时对内核内存和数据结构进行检查的办法。 • 不允许进行源代码级别上的调试。 • 可以添加额外的命令,给出该数据结构的标识或地址,这些命令便可以格式化和显示基本的系统数据结构。

  32. KDB允许的内核操作 • 处理器单步执行 • 执行到某条特定指令时停止 • 当存取(或修改)某个特定的虚拟内存位置时停止 • 当存取输入/输出地址空间中的寄存器时停止 对当前活动的任务和所有其它任务进行堆栈回溯跟踪(通过进程 ID) • 对指令进行反汇编 • 追击内存溢出

  33. 配置KDB • tar jxvf linux-xxx.tar.bz2 • bzip2 -d xxx.patch.bz2 • patch -p1 < xxx.patch • 设置CONFIG_KDB选项 • Kernel hacking ->Built-in Kernel Debugger support • 设置CONFIG_FRAME_POINTER选项 • Compile the kernel with frame pointers • 设置CONFIG_KDB_OFF选项 • KDB off by default

  34. 激活KDB • 激活: • echo “1” > /proc/sys/kernel/kdb • 取消激活: • echo “0” > /proc/sys/kernel/kdb

  35. KDB命令(1) • 运行 • go:继续程序执行 • ss:单步执行程序 • ssb:执行到分支或者函数调用时停止

  36. KDB命令(2) • 内存显示和修改 • md :显示内存内容 • mdr :显示原始内存的内容 • mm :修改内存内容 (thinkingmmW) • mds :以符号的方式显示内存的内容 例1: 显示从0x30000000开始的30行内存 [0] kdb > md 0x30000000 15 例2: 修改0x20000000上的内存 [0] kdb > mm 0x20000000 0x33

  37. KDB命令(3) • 寄存器修改和显示 • rd :显示寄存器内容 • rm :修改寄存器的内容 • ef :显示异常帧 例1: 显示通用寄存器组 [0] kdb > rd 例2: 设置eax寄存器内容 [0] kdb > rm %eax,0x22

  38. KDB命令(4) • 断点 • bp/bl :设置或者显示断点 • bc/be :清除/激活断点 • bd :使断点无效 • bpa :设置或者显示全局断点 • bph/bpha:设置硬件断点或者显示所有断点 例1: 为函数设置断点 [0] kdb > bp func_1 例2: 列出断点 [0] kdb > bl 例3: 清楚断点 [0] kdb > bc 1

  39. KDB命令(5) • 堆栈 • bt :显示调用堆栈 • btp :显示进程的堆栈 • bta :显示所有进程的堆栈 • btc :命令对每个活动 CPU 上正在运行的进程执行堆栈回溯 例1: 跟踪当前活动线程的堆栈 [0] kdb > bt 例2: 跟踪某进程的堆栈 [0] kdb > btp 888

  40. KDB命令(6) • 其他数十个命令 • help :获得帮助 • ? :获得帮助 • ……

  41. KGDB 使用两台计算机开发: stty ispeed 115200 ospeed 115200 -F /dev/ttyS0 echo hello > /dev/ttyS0 stty ispeed 115200 ospeed 115200 -F /dev/ttyS1cat /dev/ttyS1

  42. 安装KGDB • 需要软件: • 内核源代码:linux-x.x.x.tar.bz2 • Kgdb补丁:linux-x.x.x-kgdb-1.9.patch • gdbmod-x.x.bz2 • 配置内核 make; make bzImage

More Related