linux切换root段错误,Linux addr2line调试段错误

调试zSeries上的Linux应用程序类似于调试其他体系结构上的Linux应用程序。对于有经验的Linux开发人员,最大的挑战是理解新的

系统体系结构。对于刚接触Linux的大型机开发人员,掌握新的调试工具似乎是一项令人畏惧的任务。不要害怕。本文将提供Linux

addr2line一些有用的提示来帮助您入门。

UserDebug日志记录

调试一个崩溃的程序的第一步是弄清哪里出了错。zSeries上的Linux内核具有这样一个内置特性,它在用户进程崩溃时记录一些基本的调试信息。要启用这个特性,请以root用户身份执行如下命令:

echo1>>/proc/sys/kernel/userprocess_debug

当某个进程崩溃时,日志文件(/var/log/messages)中就会给出附加的信息,包括程序终止原因、故障地址,以及包含程序状态字(PSW)、通用寄存器和访问寄存器的简要寄存器转储。

Mar3111:34:28l02kernel:Userprocessfault:interruptioncode0x10

Mar3111:34:28l02kernel:failingaddress:0

Mar3111:34:28l02kernel:CPU:1

Mar3111:34:28l02kernel:Processsimple(pid:30122,stackpage=05889000)

Mar3111:34:28l02kernel:

Mar3111:34:28l02kernel:UserPSW:070dc000c00ab738

Mar3111:34:28l02kernel:task:05888000ksp:05889f08pt_regs:05889f68

Mar3111:34:28l02kernel:UserGPRS:Mar3111:34:28l02kernel:00000000004019a0004019a000000000

Mar3111:34:28l02kernel:00000003c00ab732004008f800400338

Mar3111:34:28l02kernel:40018ffc0040061c40018e347ffff800

Mar3111:34:28l02kernel:00400434804006248040066e7ffff800

Mar3111:34:28l02kernel:UserACRS:

Mar3111:34:28l02kernel:00000000000000000000000000000000

Mar3111:34:28l02kernel:00000001000000000000000000000000

Mar3111:34:28l02kernel:00000000000000000000000000000000

Mar3111:34:28l02kernel:00000000000000000000000000000000

Mar3111:34:28l02kernel:UserCode:

Mar3111:34:28l02kernel:4440500007fea74a0001185418431835a8240000

上面表明程序(名为“simple”)以一个程序中断代码0x10终止(操作系统原理表明这是一个段转换错误),而故障地址为0。毫无疑问,有人使用了空指针。现在我们知道发生了什么,下面需要弄清它发生在何处。

Linux addr2line基本的诊断

UserDebug日志条目所提供的信息可用于确定程序的崩溃位置。一些可用的工具可帮助解决您可能会遇到的各种程序终止问题。我们将在本文中逐步介绍那些工具。

首先,让我们检查一下该日志条目中的用户PSW。该PSW包含指令地址、状态码以及关于机器状态的其他信息。眼下,我们仅关心指令地址(第33至第

63位)。为简化起见,让我们假设用户PSW是070dc00080400618。记住,我们是在考察一个ESA/390(31位寻址)PSW。第32位

不是指令地址的一部分,它是指示31位寻址模式的标志,但是在研究PSW值时必须处理它。为了获得实际的指令指针,可把PSW的第二个字减去

0x80000000。结果是一个指令地址0x400618。为了定位代码,您需要可执行文件中的一些信息。首先使用readelf来打印一些程序头信

息。

ElffiletypeisEXEC(Executablefile)Entrypoint0x400474Thereare6programheaders,startingatoffset52ProgramHeaders:

TypeOffsetVirtAddrPhysAddrFileSizMemSizFlgAlign

PHDR0x0000340x004000340x004000340x000c00x000c0RE0x4

INTERP0x0000f40x004000f40x004000f40x0000d0x0000dR0x1[Requestingprograminterpreter:/lib/ld.so.1]

LOAD0x0000000x004000000x004000000x009900x00990RE0x1000

LOAD0x0009900x004019900x004019900x000fc0x00114RW0x1000

DYNAMIC0x0009ac0x004019ac0x004019ac0x000a00x000a0RW0x4

NOTE0x0001040x004001040x004001040x000200x00020R0x4

SectiontoSegmentmapping:SegmentSections...

00

01.interp

02.interp.note.ABI-tag.hash.dynsym.dynstr.gnu.version

.gnu.version_r.rela.got.rela.plt.init.plt.text.fini.rodata

03.data.eh_frame.dynamic.ctors.dtors.got.bss

04.dynamic

05.note.ABI-tag

上述显示了readelf-lsimple的结果(记住“simple”是我们的测试程序的名称)。在ProgramHeaders部分,第一个

LOAD行提供了关于程序从哪里加载的信息。在Flg列,该段被标记为R(read)E(executable)。VirtAddr是程序开始加载的地

址。MemSiz是正在被加载到这个段中的代码长度。把它加到VirtAddr上,这个程序的基本地址范围就是0x400000-0x400990。程序

发生崩溃的指令地址为0x400618,在程序的加载范围之内。现在我们知道了问题直接发生在代码中。

如果可执行文件包括调试符号,那么确定哪一行代码导致了问题是可以做到的。对该地址和可执行文件使用addr2line程序,如下所示:

addr2line-esimple0x400618

将返回:

/home/devuser/simple.c:34

要研究该问题,可以检查第34行。

对于Linux

addr2line原始的程序崩溃,PSW为070dc000c00ab738。要获得指令地址,可减去0x80000000。结果为

0x400ab738。这个地址并不准确地落在我们的小程序之内。那么,它是什么呢?是来自共享库的代码。如果对可执行文件运行ldd命令

(lddsimple),将会返回程序运行所需的共享对象的列表,以及该库在那里可用的地址。

libc.so.6=>/lib/libc.so.6(0x40021000)/lib/ld.so.1=>/lib/ld.so.1(0x40000000)

该指令地址对应于加载libc.so.6的地址。在我们的简单测试案例中,只需要两个共享对象。其他应用程序可能需要更多共享对象,这使得ldd的输出更加复杂。我们将以perl作为例子。输入:

ldd/usr/bin/perl

将得到:

libnsl.so.1=>

/lib/libnsl.so.1(0x40021000)libdl.so.2=>

/lib/libdl.so.2(0x40039000)libm.so.6=>

/lib/libm.so.6(0x4003d000)libc.so.6=>

/lib/libc.so.6(0x40064000)libcrypt.so.1=>

/lib/libcrypt.so.1(0x4018f000)/lib/ld.so.1=>

/lib/ld.so.1(0x40000000)

所需要的一切都在那里了,但是我发现对于这个进程,下面的内容读起来更快一点:

ldd/usr/bin/perl|awk‘{print?$4““$3}’

|sort(0x40000000)/lib/ld.so.1(0x40021000)

/lib/libnsl.so.1(0x40039000)

/lib/libdl.so.2(0x4003d000)

/lib/libm.so.6(0x40064000)

/lib/libc.so.6(0x4018f000)

/lib/libcrypt.so.1

现在我们来确定Linux

addr2line崩溃发生在libc中的何处。假设libc.so.6的加载地址是0x40021000,从指令地址0x400ab738减去它,结果

为0x8a738。这是进入libc.so.6的偏移。使用nm命令,从libc.so.6转储符号,然后尝试确定该地址位于哪个函数中。对于

libc.so.6,nm将生成7,000多行输出。通过对计算得出的偏移部分执行grep(正则表达式查找程序)可以削减必须检查的数据量。输入:

nm/lib/libc.so.6|sort|grep0008a

将返回66行,在该输出的中间,我们会发现:

0008a6fcTmemcpy0008a754t_wordcopy_fwd_aligned

该偏移落在memcpy中的某个位置。在此例中,一个空指针被当作目标地址传递给了memcpy。我们在何处调用的memcpy呢?问得好。我们可

以通过检查输出在日志文件中的寄存器转储来确定目标区域。寄存器14包含执行某个函数调用时的返回地址。根据图1,R14是0x8040066e,它在截

去高位之后产生一个地址0x40066e。这个地址落在我们的程序范围之内,因此可以运行addr2line来确定该地址在何处。输入:

addr2line-esimple0x40066e

将返回:

/home/devuser/simple.c:36

这是我们调用memcpy之后的那一行。关于addr2line的一点补充:如果可执行文件中没有包括调试符号,您将获得??:0作为响应。

arm-eabi-addr2line

Usage: arm-eabi-addr2line [option(s)] [addr(s)]

for example:

D:\gat\iBox\TRUNK\lib>arm-eabi-addr2line -e

"D:\*.out.symbols\alps\out\target\product\*\symbols/../../../../../kernel/vmlinux"

c0037aa0

The options are:

@Read options from -b --target=Set the binary file format

-e --exe=Set the input file name (default is a.out)

-i --inlines           Unwind inlined functions

-j --section=Read section-relative offsets instead of addresses

-s --basenames         Strip directory names

-f --functions         Show function names

-C --demangle[=style]  Demangle function names

-h --help              Display this information

-v --version           Display the program's version.

常用-f, -C, -e.

KE debug的方法:

首先在在dump的kernel log中找[<>]这样的东西,然后再通过addr2line在vmlinux中找到其对应的line

有的地址,比如bf开头的是debug不了的,因为3GB-8MB ~ 3GB是kernel module载入的地址,而vmlinux中没有module的symbol table.

NE debug的方法

首先在ne log中找signal 11 (SIGSEGV), fault addr baae8fd1

的东西,找到后

通过分析,如果fault addr 是deaddead,那就表示heap error出现,然后再看是deadadd0,就是heap corruption,如果是deadadd0,就是heap usage error.

然后将heap信息保存下载

然后再通过将signal 11 (SIGSEGV), fault addr baae8fd1中的地址通过addr2line来进行转换得道C库出错的地址

NE的decode是通过

#01  pc 0001cd4a  /system/lib/libc.so

中间后面libc.so的路径,将其加到symbols path后面,然后再通过addr2line来解析出来。

arm-eabi-addr2line -f -C -e

D:\gat\Department\SP_SS\OSS5_ST_Share\GAT\TRUNK\Test_Cases\NE\ztemt73v2_ALPS.GB.p52_eng.out.symbols\alps\out\target\product\ztemt73v2\symbols\system\lib\libc.so

0001cd0e

输出的话就是

__findenv

/alps/GB/Of/alps/bionic/libc/stdlib/getenv.c:90

http://blog.csdn.net/dysh1985/article/details/7558148

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值