找回密码
 注册
搜索
热搜: 回贴
微赢网络技术论坛 门户 服务器 Linux/BSD 查看内容

debug

2009-12-20 13:26| 发布者: admin| 查看: 51| 评论: 0|原作者: 韩菱纱

先看看我用的是个什么机器:
$ uname -a
Linux dev 2.4.21-9.30AXsmp #1 SMP Wed May 26 23:37:09 EDT 2004 i686 i686 i386 GNU/Linux
再看看默认的一些参数,注意core file size是个0,程序出错时不会产生core文件了。
$ ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
file size (blocks, -f) unlimited
max locked memory (kbytes, -l) 4
max memory size (kbytes, -m) unlimited
open files (-n) 2048
pipe size (512 bytes, -p) 8
stack size (kbytes, -s) 10240
cpu time (seconds, -t) unlimited
max user processes (-u) 7168
virtual memory (kbytes, -v) unlimited
写个简单的程序,看看core文件是不是会被产生。
$ more foo.c
#include
static void sub(void);
int main(void)
{
sub();
return 0;
}
static void sub(void)
{
int *p = NULL;
/* derefernce a null pointer, expect core dump. */
printf("%d", *p);
}
$ gcc -Wall -g foo.c
$ ./a.out
Segmentation fault
$ ls -l core.*
ls: core.*: No such file or directory
没有找到core文件,我们改改ulimit的设置,让它产生。1024是随便取的,要是core文件大于1024个块,就产生不出来了。
$ ulimit -c 1024
$ ulimit -a
core file size (blocks, -c) 1024
data seg size (kbytes, -d) unlimited
file size (blocks, -f) unlimited
max locked memory (kbytes, -l) 4
max memory size (kbytes, -m) unlimited
open files (-n) 2048
pipe size (512 bytes, -p) 8
stack size (kbytes, -s) 10240
cpu time (seconds, -t) unlimited
max user processes (-u) 7168
virtual memory (kbytes, -v) unlimited
$ ./a.out
Segmentation fault (core dumped)
$ ls -l core.*
-rw------- 1 uniware uniware 53248 Jun 30 17:10 core.9128
注意看上述的输出信息,多了个(core dumped)。确实产生了一个core文件,9128是该进程的PID。我们用GDB来看看这个core。
$ gdb --core=core.9128
GNU gdb Asianux (6.0post-0.20040223.17.1AX)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-asianux-linux-gnu".
Core was generated by `./a.out'.
Program terminated with signal 11, Segmentation fault.
#0 0x08048373 in ?? ()
(gdb) bt
#0 0x08048373 in ?? ()
#1 0xbfffd8f8 in ?? ()
#2 0x0804839e in ?? ()
#3 0xb74cc6b3 in ?? ()
#4 0x00000000 in ?? ()
此时用bt看不到backtrace,也就是调用堆栈,原来GDB还不知道符号信息在哪里。我们告诉它一下:
(gdb) file ./a.out
Reading symbols from ./a.out...done.
Using host libthread_db library "/lib/tls/libthread_db.so.1".
(gdb) bt
#0 0x08048373 in sub () at foo.c:17
#1 0x08048359 in main () at foo.c:8
此时backtrace出来了。
(gdb) l
8 sub();
9 return 0;
10 }
11
12 static void sub(void)
13 {
14 int *p = NULL;
15
16 /* derefernce a null pointer, expect core dump. */
17 printf("%d", *p);
(gdb)
1.使用gdb调试
* /proc/kcore文件是系统内核运行情况的内存映像
* 如果编译内核的时候增加-g选项,即会在生成的二进制代码vmlinuz或vmlinux中,添加调试相关的数据。
* 以root身份运行
#gdb /usr/src/linux/vmlinux /proc/kcore
* 因为core-file命令是静态的,如果需要查看内核最近的运行情况,需要再次运行core-file将新的/proc/kcore导入,否则就只能是上次使用core-file的情况
# gdb vmlinux
# (gdb) core-file /proc/kcore
# #0 0x0 in ?? ()
# (gdb) p jiffies
# $1 = 29119787
# (gdb) p jiffies
# $2 = 29119787
# (gdb) core-file /proc/kcore
# #0 0x0 in ?? ()
# (gdb) p jiffies
# $3 = 29122291
# (gdb)
2.Core Dump
1>开启系统的Core Dump功能
ulimit -c core_file_size_in_kb
如果要关闭该功能core_file_size_in_kb为0就行了。
ulimit -c 1000
2>设置Core Dump的核心转储文件目录和命名规则
文件的命名规则放在
/proc/sys/kernel/core_name_format文件中
使用sysctl -w "kernel.core_name_format=/coredump/%n.core"
上例的core文件放在/coredump目录下,文件名是进程名 .core
以下是一些命名的格式说明
%P The Process ID (current->pid)
%U The UID of the process (current->uid)
%N The command name of the process (current->comm)
%H The nodename of the system (system_utsname.nodename)
%% A "%"
3.UML调试内核
1>直接使用gdb运行UML内核
root@wangyao-desktop:/usr/src/linux-2.6.24# gdb -q ./linux ubd0=/uml/Debian-4.0-x86-root_fs mem=128M eth0=tuntap,,,192.168.1.11 umid=ubuntu
Excess command line arguments ignored. (mem=128M ...)
Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".
/usr/src/linux-2.6.24/ubd0=/uml/Debian-4.0-x86-root_fs: No such file or directory.
(gdb) b start_kernel
Breakpoint 1 at 0x80493a7: file init/main.c, line 512.
(gdb) r
Starting program: /usr/src/linux-2.6.24/linux
Core dump limits :
soft - 0
hard - NONE
Checking that ptrace can change system call numbers...OK
Checking syscall emulation patch for ptrace...OK
Checking advanced syscall emulation patch for ptrace...OK
Checking for tmpfs mount on /dev/shm...OK
Checking PROT_EXEC mmap in /dev/shm/...OK
Checking for the skas3 patch in the host:
- /proc/mm...not found: No such file or directory
- PTRACE_FAULTINFO...not found
- PTRACE_LDT...not found
UML running in SKAS0 mode
Breakpoint 1, start_kernel () at init/main.c:512
512 smp_setup_processor_id();
2>先运行了UML内核,再通过gdb attach到相应的进程
root@wangyao-desktop:/usr/src/linux-2.6.24# cat ~/.uml/ubuntu/pid
13678
root@wangyao-desktop:/usr/src/linux-2.6.24# gdb -q ./linux 13678
Using host libthread_db library "/lib/tls/i686/cmov/libthread_db.so.1".
Attaching to program: /usr/src/linux-2.6.24/linux, process 13678
Reading symbols from /lib/tls/i686/cmov/libutil.so.1...done.
Loaded symbols for /lib/tls/i686/cmov/libutil.so.1
Reading symbols from /lib/tls/i686/cmov/libc.so.6...done.
Loaded symbols for /lib/tls/i686/cmov/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
0xffffe410 in __kernel_vsyscall ()
(gdb) b do_execve
Breakpoint 1 at 0x80b0491: file fs/exec.c, line 1303.
(gdb) c
Continuing.
3> 调试module
UML# modprobe loop
UML# lsmod
Module Size Used by
loop 12328 0
gdb中调试:
(gdb) p modules
$6 = {next = 0x108030a4, prev = 0x1082a084}
The "next" address is 4 bytes (on x86, 8 on x86_64) into the module structure, so you can print the structure by subtracting that from the address in the modules list_head:
(gdb) p *((struct module *)0x108030a0)
$7 = {state = MODULE_STATE_LIVE, list = {next = 0x1082a084, prev = 0x8206c2c}, name = "loop", '\0' , mkobj = {kobj = {k_name = 0xfed7fa0 "loop", kref = {
refcount = {counter = 4}}, entry = {next = 0x8203884, prev = 0x1082a0d0}, parent = 0x820388c, kset = 0x8203880, ktype = 0x0, sd = 0xfe2d9f8}, mod = 0x108030a0,
drivers_dir = 0x0}, param_attrs = 0x0, modinfo_attrs = 0xfedaf08, version = 0x0, srcversion = 0x0, holders_dir = 0xfed7868, syms = 0x10801d20, num_syms = 2, crcs = 0x0,
gpl_syms = 0x0, num_gpl_syms = 0, gpl_crcs = 0x0, unused_syms = 0x0, num_unused_syms = 0, unused_crcs = 0x0, unused_gpl_syms = 0x0, num_unused_gpl_syms = 0,
unused_gpl_crcs = 0x0, gpl_future_syms = 0x0, num_gpl_future_syms = 0, gpl_future_crcs = 0x0, num_exentries = 0, extable = 0x0, init = 0x10805000, module_init = 0x0,
module_core = 0x10800000, init_size = 0, core_size = 12808, init_text_size = 0, core_text_size = 6909, unwind_info = 0x0, arch = {}, taints = 0, bug_list = {
next = 0x1082a16c, prev = 0x8209d28}, bug_table = 0x0, num_bugs = 0, ref = {{count = {a = {counter = 0}}}}, modules_which_use_me = {next = 0x108031c0, prev = 0x108031c0},
waiter = 0xfd1f040, exit = 0x10801a94, symtab = 0x10801d30, num_symtab = 164, strtab = 0x10802770 "", sect_attrs = 0xfdf68d0, notes_attrs = 0xfe0b5a8, percpu = 0x0,
args = 0xfed76e0 ""}
# Once you find the module structure you're interested in, look at the "module_core" field (0x3502a000 above). Use that as ADDR in this command:
(gdb) add-symbol-file HOST_PATH_TO_KO ADDR
For example, here that command looks like this
(gdb) obj/mods/lib/modules/2.6.18-rc3-mm2/kernel/drivers/block/loop.ko 0x3502a000
To verify that you have done this correctly, you can look at the init function address and see that gdb agrees about its address
(gdb) p loop_init
$5 = {int (void)} 0x3502a000
Now, you can set breakpoints and debug the module.
(gdb) b loop_init
Breakpoint 1 at 0x3502a009: file /home/jdike/linux/2.6/linux-2.6.18-mm/drivers/block/loop.c, line 1242.
(gdb) c
Continuing.
Breakpoint 1, loop_init ()
at /home/jdike/linux/2.6/linux-2.6.18-mm/drivers/block/loop.c:1242
1242 if (max_loop 256) {
(gdb)
http://blog.csdn.net/joshua_yu/archive/2006/02/03/591456.aspx
峥嵘岁月
joshua_yu的网络空间
* 登录
* 注册
*
*
*
* 空间
* 博客
* 好友
* 相册
* 留言
俞峥ID:joshua_yu
共102582次访问,排名849好友5人,关注者14人
人生总有些阶段,新的起点,新的心情,没有好也没有坏,生活总是辩证而真实地存在,感谢所有人!
joshua_yu的文章
原创 45 篇
翻译 2 篇
转载 42 篇
评论 24 篇
joshua的公告
联系方式: QQ:404271575 MSN:joshua_yu@263.net
最近评论
wBlf_www:to ohyeath
怎么解决,能否具体点
ohyeath:需要skd、ddk
老胡:863就是骗钱的。
wBlf_www:驱动运行正常,setipaddrarray程序设置过滤IP地址,经常出现提示WBEM_E_INVALID_CLASS,可能原因是 : Passthru IM driver is not active
这个问题怎么解决。
wBlf_www:上个问题,广播地址不过滤即可。
文章分类
* Linux开发技术(RSS)
* NDIS驱动开发(RSS)
* Windows文件过滤驱动(RSS)
* Windows系统开发(RSS)
* 管理理念与技术趋势(RSS)
* 软件工程和项目管理(RSS)
* 网络安全(RSS)
* 文档安全保护(RSS)
* 我的日记(RSS)
收藏
相册
08年第一期儿子照片
过年
交大新面貌
我的可爱儿子
周末烧烤之众生相
关注的Blog
EVA的回收站
joyfire的space
Kendiv的专栏
PJF的Blog
WebCrazy的Blog
孟言的blog
野路子(http://wulujia.com)
铁卷大成天下
网络收藏夹
China CISSP论坛(文档保护)
China Uniix
developerWorks Linux 专栏
docshow
linux伊甸园
OSR在线论坛
PKI论坛
reactos
rootkit论坛
Sysinternals论坛
中国Linux公社
中国Linux论坛
协议分析网论坛
安全焦点
看雪技术学院论坛
驱动开发网
存档
* 2008年07月(11)
* 2008年05月(2)
* 2008年04月(10)
* 2006年11月(1)
* 2006年10月(1)
* 2006年09月(2)
* 2006年04月(1)
* 2006年03月(11)
* 2006年02月(28)
* 2006年01月(22)
软件项目交易
订阅我的博客
XML聚合 FeedSky
订阅到鲜果
订阅到Google
订阅到抓虾
订阅到BlogLines
订阅到Yahoo
订阅到GouGou
订阅到飞鸽
订阅到Rojo
订阅到newsgator
订阅到netvibes
原创 (转载)Linux 调试技术收藏
新一篇: (转载)使用kgdb调试linux内核及内核模块 | 旧一篇: (转载)Linux 汇编语言开发指南
在 Linux 上找出并解决程序错误的主要方法
Steve Best(sbest@us.ibm.com)
JFS 核心小组成员,IBM
您可以用各种方法来监控运行着的用户空间程序:可以为其运行调试器并单步调试该程序,
添加打印语句,或者添加工具来分析程序。本文描述了几种可以用来调试在 Linux 上运行的
程序的方法。我们将回顾四种调试问题的情况,这些问题包括段错误,内存溢出和泄漏,还
有挂起。
本文讨论了四种调试 Linux 程序的情况。在第 1 种情况中,我们使用了两个有内存分配问
题的样本程序,使用 MEMWATCH 和 Yet Another Malloc Debugger(YAMD)工具来调试它们
。在第 2 种情况中,我们使用了 Linux 中的 strace 实用程序,它能够跟踪系统调用和信
号,从而找出程序发生错误的地方。在第 3 种情况中,我们使用 Linux 内核的 Oops 功能
来解决程序的段错误,并向您展示如何设置内核源代码级调试器(kernel source level de
bugger,kgdb),以使用 GNU 调试器(GNU debugger,gdb)来解决相同的问题;kgdb 程序
是使用串行连接的 Linux 内核远程 gdb。在第 4 种情况中,我们使用 Linux 上提供的魔术
键控顺序(magic key sequence)来显示引发挂起问题的组件的信息。
常见调试方法
当您的程序中包含错误时,很可能在代码中某处有一个条件,您认为它为真(true),但实
际上是假(false)。找出错误的过程也就是在找出错误后推翻以前一直确信为真的某个条件
过程。
以下几个示例是您可能确信成立的条件的一些类型:
在源代码中的某处,某变量有特定的值。
在给定的地方,某个结构已被正确设置。
对于给定的 if-then-else 语句,if 部分就是被执行的路径。
当子例程被调用时,该例程正确地接收到了它的参数。
找出错误也就是要确定上述所有情况是否存在。如果您确信在子例程被调用时某变量应该有
特定的值,那么就检查一下情况是否如此。如果您相信 if 结构会被执行,那么也检查一下
情况是否如此。通常,您的假设都会是正确的,但最终您会找到与假设不符的情况。结果,
您就会找出发生错误的地方。
调试是您无法逃避的任务。进行调试有很多种方法,比如将消息打印到屏幕上、使用调试器
,或只是考虑程序执行的情况并仔细地揣摩问题所在。
在修正问题之前,您必须找出它的源头。举例来说,对于段错误,您需要了解段错误发生在
代码的哪一行。一旦您发现了代码中出错的行,请确定该方法中变量的值、方法被调用的方
式以及关于错误如何发生的详细情况。使用调试器将使找出所有这些信息变得很简单。如果
没有调试器可用,您还可以使用其它的工具。(请注意,产品环境中可能并不提供调试器,
而且 Linux 内核没有内建的调试器。)
实用的内存和内核工具
您可以使用 Linux 上的调试工具,通过各种方式跟踪用户空间和内核问题。请使用下面的工
具和技术来构建和调试您的源代码:
用户空间工具:
内存工具:MEMWATCH 和 YAMD
strace
GNU 调试器(gdb)
魔术键控顺序
内核工具:
内核源代码级调试器(kgdb)
内建内核调试器(kdb)
Oops
本文将讨论一类通过人工检查代码不容易找到的问题,而且此类问题只在很少见的情况下存
在。内存错误通常在多种情况同时存在时出现,而且您有时只能在部署程序之后才能发现内
存错误。
第 1 种情况:内存调试工具
C 语言作为 Linux 系统上标准的编程语言给予了我们对动态内存分配很大的控制权。然而,
这种自由可能会导致严重的内存管理问题,而这些问题可能导致程序崩溃或随时间的推移导
致性能降级。
内存泄漏(即 malloc() 内存在对应的 free() 调用执行后永不被释放)和缓冲区溢出(例
如对以前分配到某数组的内存进行写操作)是一些常见的问题,它们可能很难检测到。这一
部分将讨论几个调试工具,它们极大地简化了检测和找出内存问题的过程。
MEMWATCH
MEMWATCH 由 Johan Lindh 编写,是一个开放源代码 C 语言内存错误检测工具,您可以自己
下载它(请参阅本文后面部分的参考资料)。只要在代码中添加一个头文件并在 gcc 语句中
定义了 MEMWATCH 之后,您就可以跟踪程序中的内存泄漏和错误了。MEMWATCH 支持 ANSI C
,它提供结果日志纪录,能检测双重释放(double-free)、错误释放(erroneous free)、
没有释放的内存(unfreed memory)、溢出和下溢等等。
清单 1. 内存样本(test1.c)
#include
#include
#include "memwatch.h"
int main(void)
{
char *ptr1;
char *ptr2;
ptr1 = malloc(512);
ptr2 = malloc(512);
ptr2 = ptr1;
free(ptr2);
free(ptr1);
}

清单 1 中的代码将分配两个 512 字节的内存块,然后指向第一个内存块的指针被设定为指
向第二个内存块。结果,第二个内存块的地址丢失,从而产生了内存泄漏。
现在我们编译清单 1 的 memwatch.c。下面是一个 makefile 示例:
test1
gcc -DMEMWATCH -DMW_STDIO test1.c memwatch
c -o test1

当您运行 test1 程序后,它会生成一个关于泄漏的内存的报告。清单 2 展示了示例 memwa
tch.log 输出文件。
清单 2. test1 memwatch.log 文件
MEMWATCH 2.67 Copyright (C) 1992-1999 Johan Lindh
...
double-free: test1.c(15), 0x80517b4 was freed from test1.c(14)
...
unfreed: test1.c(11), 512 bytes at 0x80519e4
{FE FE FE FE FE FE FE FE FE FE FE FE ..............}
Memory usage statistics (global):
N)umber of allocations made: 2
L)argest memory usage : 1024
T)otal of all alloc() calls: 1024
U)nfreed bytes totals : 512

MEMWATCH 为您显示真正导致问题的行。如果您释放一个已经释放过的指针,它会告诉您。对
于没有释放的内存也一样。日志结尾部分显示统计信息,包括泄漏了多少内存,使用了多少
内存,以及总共分配了多少内存。
YAMD
YAMD 软件包由 Nate Eldredge 编写,可以查找 C 和 C 中动态的、与内存分配有关的问
题。在撰写本文时,YAMD 的最新版本为 0.32。请下载 yamd-0.32.tar.gz(请参阅参考资料
)。执行 make 命令来构建程序;然后执行 make install 命令安装程序并设置工具。
一旦您下载了 YAMD 之后,请在 test1.c 上使用它。请删除 #include memwatch.h 并对 m
akefile 进行如下小小的修改:
使用 YAMD 的 test1
gcc -g test1.c -o test1

清单 3 展示了来自 test1 上的 YAMD 的输出。
清单 3. 使用 YAMD 的 test1 输出
YAMD version 0.32
Executable: /usr/src/test/yamd-0.32/test1
...
INFO: Normal allocation of this block
Address 0x40025e00, size 512
...
INFO: Normal allocation of this block
Address 0x40028e00, size 512
...
INFO: Normal deallocation of this block
Address 0x40025e00, size 512
...
ERROR: Multiple freeing At
free of pointer already freed
Address 0x40025e00, size 512
...
WARNING: Memory leak
Address 0x40028e00, size 512
WARNING: Total memory leaks:
1 unfreed allocations totaling 512 bytes
*** Finished at Tue ... 10:07:15 2002
Allocated a grand total of 1024 bytes 2 allocations
Average of 512 bytes per allocation
Max bytes allocated at one time: 1024
24 K alloced internally / 12 K mapped now / 8 K max
Virtual program size is 1416 K
End.

YAMD 显示我们已经释放了内存,而且存在内存泄漏。让我们在清单 4 中另一个样本程序上
试试 YAMD。
清单 4. 内存代码(test2.c)
#include
#include
int main(void)
{
char *ptr1;
char *ptr2;
char *chptr;
int i = 1;
ptr1 = malloc(512);
ptr2 = malloc(512);
chptr = (char *)malloc(512);
for (i; i >EIP; c01588fc :
Code; c01588fc /proc/sys/kernel/kdb 回车以后没什么反映,说明启动成功了。
我有个同事运行这个命令以后,提示找不到kdb这个文件,后来我给他调试时发现kdb根本就没安装成功,最后我给他重新安装就没问题了。
按“Pause Break”键,就会出现kdb的使用接口了。如果想退出,就输入go,然后按回车即可。我后来发现通过f1进入系统后,输入go 回车后
怎么也退不出来,在f2进入系统后,输入go 回车后就很顺利的退出了,这个现象非常奇怪,我猜可能跟linux本身有关系。
使用kdb。
谁说kdb不能源码级调试,那时他没真正用过kdb.
其实kdb是可以源码级调试的,在这里的前提是对源码级调试的定义,反正你使用kdb用单步跟踪时是可以看到源码也一行一行的自动走的,对
你怀疑有bug的地方进行查看,非常方便。
关于使用kdb谁说都没用,关键看文档,记住不要看其他任何第三方的文档(有很多误导),就看上面你的Documentation/kdb里的slides等文档,这才是最没有污染和最正宗的文档。





最新评论

QQ|小黑屋|最新主题|手机版|微赢网络技术论坛 ( 苏ICP备08020429号 )

GMT+8, 2024-9-30 05:32 , Processed in 0.136208 second(s), 12 queries , Gzip On, MemCache On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

返回顶部