关于powerpc处理器,系统崩溃错误定位的问题!
我又回来了,请教大家一个问题,比如说当内核发生崩溃时,我想定位内核错误信息,某些错误的信息可以通过DSISR寄存器能获取到,还有就是想通过栈回溯来获取到发生错误时的寄存器和参数信息,使用栈回溯获得更多的精确信息找到程序流程上具体导致系统崩溃的调用点。为了译码栈回溯,并且想获取到每个函数的函数名信息,知道发生错误的点在哪个函数,在arm底下GCC编译选项有这一项,mpoke-function-name,使得在函数执行的 mov sp,ip之前插入函数名的地址信息。在powerpc底下也有这样的编译选项吗,怎么获取到函数名信息。
不然的话,要通过解析ELF文件和符号表吗?
[ 本帖最后由 bitliu1983 于 2009-10-10 16:42 编辑 ]
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
完全手工的办法是在崩溃的时候检查寄存器PC和r1,然后用objdump反汇编二进制的elf文件,根据PC的值可以指导当前运行在什么地方,你这种情况下应该是出于panic的函数栈里面。然后想办法把内存映像弄出来,根据r1的内容来查找栈,一层层向上查找。
好一点的办法是使用gdb,崩溃的时候如果console有崩溃的log,直接根据call sequence就可以检查是哪些函数除了问题,当然call sequence给出的是函数地址,可以在gdb里用list *addr来找到源文件。如果没有console log,可以在崩溃之后挂上gdb,然后print log_buf。 要是内容太长就先运行set p elements 1000000000000和set p null-stop on
在系统崩溃的情况下,估计楼主只能用objdump了
按照二楼的操作.
嗯,二楼的说的是一种方法,现在我们想要在系统崩溃时,找到出错的函数地址,出错指令,大概的出错原因(非法指令,内存保护等等),在出错时,r1和SRR0分别指向栈顶和出错指令,但是我们系统没有加GDB(不是linux或其它商用),相当于是一个单片机,只是加了mmu和简单的调度程序,所以出错时,我们想回溯整个调用关系链,所以我回溯了调用关系链的函数地址时,怎么获取函数名呢,是不是自己手工查询符号表文件啊,通过GNU工具链的nm或readelf工具生成符号表,然后再对应函数地址,我们想出错时,自动保存函数调用关系链已经错误信息到flash或sram中,以后好查。而不是当下就手工调试。
另外想问下大家,powerpc的ABI说,参数传递通过r3-r10寄存器,那是不是不通过栈传递了,还是说多于8个就用栈,因为回溯函数的时候,我想知道每一级的函数参数,那该怎么办?因为寄存器只能保存最后一次的函数调用参数。或者加什么编译选项使得powerpc的函数参数通过栈而不通过寄存器?用O0选项而不是O2吗?~
各位大大有什么高见~
获取函数名城的方法可以使用objdump,dump出来的文件中含有函数名称和指令对应的地址,通过比较崩溃时候的PC,可以找到对应的指令及所在函数。
关于函数调用的ABI,只有在寄存器不够的时候才使用栈,也就是你理解的超过8个采用栈(有特殊情况,比如浮点)。不过你说的查找每一级参数也确实是个问题,也许gcc里会有这样的编译选项,我也不知道
可以试试下面几个选项,我还不太清楚他们的区别
-mcall-sysv
On System V.4 and embedded PowerPC systems compile code using calling conventions that adheres to the March 1995 draft of the System V Application Binary Interface, PowerPC processor supplement. This is the default unless you configured GCC using `powerpc-*-eabiaix'.
-mcall-sysv-eabi
Specify both -mcall-sysv and -meabi options.
-mcall-sysv-noeabi
保证你编译的时候带有-o2 (即debug版本)
如果是debug版本的话,你用bt就可以都显示出多层的调用关系.
1. 在这种嵌入式应用中,通常要设计自己的“日志系统”,出错之后进行记录。以前我们用过NVRAM,实际上也就是SRMA加上电池,特别是速度非常快,掉电保存;后来用过在SDRAM中保留一段内存,系统启动时不地清除它,用这一段内存进行日志记录,写Flash的话选择系统启动时完成或定时完成。直接写Flash可能太慢了,而且临死时可能在中断或什么状态,在这种复杂情况下一般不能操作Flash。
2. PowerPC的ABI已经固定了,没看到过哪个编译器实现为只利用栈而不用寄存器。你是不是想出错时把参数记录下来?我们以前的选择是记录一部分栈里的数据,同时也记录所有的通用寄存器,到时候可以分析还原,例如前面把参数先保存到r27之类的non-volatile寄存器了,那它它的值还是能找到的;当然有些参数传进来之后只用一次后面可以破坏了,这样就生成信息丢失。
编译为-O0的方式就不要依赖了,因为这种出异常如果是必现,并且不优化也重现,就可以直接在实验室重现分析了;更多要投入精力的是那种设备运行在网上,偶尔出一次问题,找不到规律的情况。此时的记录可以用来分析问题和指导实验室环境中的问题重现。
是的,Cyberman.Wu大侠,我们现在做的一个小型嵌入式系统,就要做一个系统保护与错误追踪模块,以前在ARM版本上我们实现了,当有错误或异常产生时,我们会获取错误信息,有时不用看dump文件,就可以找到错误根源。因为我们调试错误时,不一定是在实验室。我们单位是做工业控制的。当我们的系统运行在现场时,出错时,往往客户或工程人员会复位系统,此时我们记录下当下的错误到sram或flash里,对后续我们系统维护很有用处。
我看了,apple的Mac OS X 操作系统 Darwin系统, 这个系统就做了我们在内核恐慌时,进行错误定位的功能,我们也想实现。但是对应符号表部分,它的内核扩展已经包含了完整的行号和函数名信息,用一个工具 Xcode 进行调试构建生成时进行配置的。然后在它的开发工具用kextload 命令生成符号文件。现在我们做的是,开发板的系统出现错误后,得到函数地址,然后要到上位机去解析elf文件得到函数名,我现在想到的是用nm工具生成一个txt格式的符号表,然后写个小程序每次查询这个txt文件,但感觉比较麻烦。
我们没有使用linux,和gdb。harry_he兄讲的那两个编译选项值得试试。
还有就是,powerpc的abi讲到,每个函数的调用栈帧,当少于8个参数时,用r3-r10传递,多于时才使用栈,我们想回溯每个函数的参数时,都希望通过栈而不是寄存器,这个不知道有什么办法没?
离线分析的话,用nm生成的符号表时排一下序,做一个查询很容易的。不过对于返回地址要注意顶层可能要特殊处理,有可能在LR寄存器中,并没有进栈。所以说寄存器值一定是要记录的。
我没见过哪个编译器在PowerPC上实现为只用栈传参数,这个不是不可以,但有一个ABI约束不能这样。用-O0 -g我印象中是每个函数入口总是先保寄存器参数到栈里的(或者不需要-g,好久不搞这个记不清楚了,-g在我以前用过的GCC2.96中只影响里面的符号,不影响指令),以前用VxWorks的tt时对于C++参显示出参数来前提就是这个,如果优化了虽然也显示“参数”,但实际上多数情况是错的。(至于为什么只有C++才显示,是因为C函数没办法知道参数是什么)。你如果想通过程序自动还原出参数来,除了要知道参数如何进栈之外,还要能分析源代码找到参数类型(主要是大小),也挺麻烦的。
以前我都是通过记录的栈数据手工分析,运气好的时候参数在栈中能找到;运气不好的时候可能找不到。