<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></title> 
<link>https://jackxiang.com/index.php</link> 
<description><![CDATA[赢在IT，Playin' with IT,Focus on Killer Application,Marketing Meets Technology.]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></copyright>
<item>
<link>https://jackxiang.com/post//</link>
<title><![CDATA[善用backtrace解决大问题]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[WEB2.0]]></category>
<pubDate>Sun, 04 Oct 2009 04:49:21 +0000</pubDate> 
<guid>https://jackxiang.com/post//</guid> 
<description>
<![CDATA[ 
	程序在得到一个Segmentation fault这样的错误信息毫无保留地就跳出来了，遇到这样的问题让人很痛苦，查找问题不亚于你N多天辛苦劳累编写代码的难度。那么有没有更好的方法可以在产生SIGSEGV信号的时候得到调试可用的信息呢？看看下面的例程吧！<br/><br/>sigsegv.h<br/><br/>#ifndef __sigsegv_h__#define __sigsegv_h__#ifdef __cplusplusextern &quot;C&quot; {#endif&nbsp;&nbsp;int setup_sigsegv();#ifdef __cplusplus}#endif#endif /* __sigsegv_h__ */<br/><br/>sigsegv.c<br/><br/>#define _GNU_SOURCE#include &lt;memory.h&gt;#include &lt;stdlib.h&gt;#include &lt;stdio.h&gt;#include &lt;signal.h&gt;#include &lt;ucontext.h&gt;#include &lt;dlfcn.h&gt;#include &lt;execinfo.h&gt;#ifndef NO_CPP_DEMANGLE#include &lt;cxxabi.h&gt;#endif#if defined(REG_RIP)# define SIGSEGV_STACK_IA64# define REGFORMAT &quot;%016lx&quot;#elif defined(REG_EIP)# define SIGSEGV_STACK_X86# define REGFORMAT &quot;%08x&quot;#else# define SIGSEGV_STACK_GENERIC# define REGFORMAT &quot;%x&quot;#endifstatic void signal_segv(int signum, siginfo_t* info, void*ptr) {&nbsp;&nbsp;static const char *si_codes[3] = {&quot;&quot;, &quot;SEGV_MAPERR&quot;, &quot;SEGV_ACCERR&quot;};&nbsp;&nbsp;size_t i;&nbsp;&nbsp;ucontext_t *ucontext = (ucontext_t*)ptr;#if defined(SIGSEGV_STACK_X86) &#124;&#124; defined(SIGSEGV_STACK_IA64)&nbsp;&nbsp;int f = 0;&nbsp;&nbsp;Dl_info dlinfo;&nbsp;&nbsp;void **bp = 0;&nbsp;&nbsp;void *ip = 0;#else&nbsp;&nbsp;void *bt[20];&nbsp;&nbsp;char **strings;&nbsp;&nbsp;size_t sz;#endif&nbsp;&nbsp;fprintf(stderr, &quot;Segmentation Fault!&#92;n&quot;);&nbsp;&nbsp;fprintf(stderr, &quot;info.si_signo = %d&#92;n&quot;, signum);&nbsp;&nbsp;fprintf(stderr, &quot;info.si_errno = %d&#92;n&quot;, info-&gt;si_errno);&nbsp;&nbsp;fprintf(stderr, &quot;info.si_code&nbsp;&nbsp;= %d (%s)&#92;n&quot;, info-&gt;si_code, si_codes[info-&gt;si_code]);&nbsp;&nbsp;fprintf(stderr, &quot;info.si_addr&nbsp;&nbsp;= %p&#92;n&quot;, info-&gt;si_addr);&nbsp;&nbsp;for(i = 0; i &amp;lt; NGREG; i++)&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, &quot;reg[%02d]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0x&quot; REGFORMAT &quot;&#92;n&quot;, i, ucontext-&gt;uc_mcontext.gregs[i]);#if defined(SIGSEGV_STACK_X86) &#124;&#124; defined(SIGSEGV_STACK_IA64)# if defined(SIGSEGV_STACK_IA64)&nbsp;&nbsp;ip = (void*)ucontext-&gt;uc_mcontext.gregs[REG_RIP];&nbsp;&nbsp;bp = (void**)ucontext-&gt;uc_mcontext.gregs[REG_RBP];# elif defined(SIGSEGV_STACK_X86)&nbsp;&nbsp;ip = (void*)ucontext-&gt;uc_mcontext.gregs[REG_EIP];&nbsp;&nbsp;bp = (void**)ucontext-&gt;uc_mcontext.gregs[REG_EBP];# endif&nbsp;&nbsp;fprintf(stderr, &quot;Stack trace:&#92;n&quot;);&nbsp;&nbsp;while(bp &amp;&amp; ip) {&nbsp;&nbsp;&nbsp;&nbsp;if(!dladdr(ip, &amp;dlinfo))&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;&nbsp;&nbsp;&nbsp;&nbsp;const char *symname = dlinfo.dli_sname;#ifndef NO_CPP_DEMANGLE&nbsp;&nbsp;&nbsp;&nbsp;int status;&nbsp;&nbsp;&nbsp;&nbsp;char *tmp = __cxa_demangle(symname, NULL, 0, &amp;status);&nbsp;&nbsp;&nbsp;&nbsp;if(status == 0 &amp;&amp; tmp)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;symname = tmp;#endif&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, &quot;% 2d: %p &lt;%s+%u&gt; (%s)&#92;n&quot;,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;++f,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ip,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;symname,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(unsigned)(ip - dlinfo.dli_saddr),&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dlinfo.dli_fname);#ifndef NO_CPP_DEMANGLE&nbsp;&nbsp;&nbsp;&nbsp;if(tmp)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;free(tmp);#endif&nbsp;&nbsp;&nbsp;&nbsp;if(dlinfo.dli_sname &amp;&amp; !strcmp(dlinfo.dli_sname, &quot;main&quot;))&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;&nbsp;&nbsp;&nbsp;&nbsp;ip = bp[1];&nbsp;&nbsp;&nbsp;&nbsp;bp = (void**)bp[0];&nbsp;&nbsp;}#else&nbsp;&nbsp;fprintf(stderr, &quot;Stack trace (non-dedicated):&#92;n&quot;);&nbsp;&nbsp;sz = backtrace(bt, 20);&nbsp;&nbsp;strings = backtrace_symbols(bt, sz);&nbsp;&nbsp;for(i = 0; i &lt; sz; ++i)&nbsp;&nbsp;&nbsp;&nbsp;fprintf(stderr, &quot;%s&#92;n&quot;, strings[i]);#endif&nbsp;&nbsp;fprintf(stderr, &quot;End of stack trace&#92;n&quot;);&nbsp;&nbsp;exit (-1);}int setup_sigsegv() {&nbsp;&nbsp;struct sigaction action;&nbsp;&nbsp;memset(&amp;action, 0, sizeof(action));&nbsp;&nbsp;action.sa_sigaction = signal_segv;&nbsp;&nbsp;action.sa_flags = SA_SIGINFO;&nbsp;&nbsp;if(sigaction(SIGSEGV, &amp;action, NULL) &lt; 0) {&nbsp;&nbsp;&nbsp;&nbsp;perror(&quot;sigaction&quot;);&nbsp;&nbsp;&nbsp;&nbsp;return 0;&nbsp;&nbsp;}&nbsp;&nbsp;return 1;}#ifndef SIGSEGV_NO_AUTO_INITstatic void __attribute((constructor)) init(void) {&nbsp;&nbsp;setup_sigsegv();}#endif<br/><br/>main.c<br/><br/>#include &quot;sigsegv.h&quot;#include &lt;string.h&gt;int die() {&nbsp;&nbsp;char *err = NULL;&nbsp;&nbsp;strcpy(err, &quot;gonner&quot;);&nbsp;&nbsp;return 0;}int main() {&nbsp;&nbsp;return die();}<br/><br/>下面来编译上面的main.c程序看看将会产生什么样的信息呢，不过要注意的就是如果要在你的程序里引用sigsegv.h、sigsegv.c得到堆栈信息的话记得加上-rdynamic -ldl参数。<br/><br/>/data/codes/c/test/backtraces $ gcc -o test -rdynamic -ldl -ggdb -g sigsegv.c main.c/data/codes/c/test/backtraces $ ./testSegmentation Fault!info.si_signo = 11info.si_errno = 0info.si_code&nbsp;&nbsp;= 1 (SEGV_MAPERR)info.si_addr&nbsp;&nbsp;= (nil)reg[00]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0x00000033reg[01]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0x00000000reg[02]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0xc010007breg[03]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0x0000007breg[04]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0x00000000reg[05]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0xb7fc8ca0reg[06]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0xbff04c2creg[07]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0xbff04c1creg[08]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0xb7f8cff4reg[09]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0x00000001reg[10]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0xbff04c50reg[11]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0x00000000reg[12]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0x0000000ereg[13]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0x00000006reg[14]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0x080489ecreg[15]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0x00000073reg[16]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0x00010282reg[17]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0xbff04c1creg[18]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 0x0000007bStack trace: 1: 0x80489ec &lt;die+16&gt; (/data/codes/c/test/backtraces/test) 2: 0x8048a16 &lt;main+19&gt; (/data/codes/c/test/backtraces/test)End of stack trace/data/codes/c/test/backtraces $ <br/><br/>下面用gdb来看看出错的地方左右的代码：<br/><br/>/data/codes/c/test/backtraces $ gdb ./testgdb&gt; disassemble die+16Dump of assembler code for function die:0x080489dc &lt;die+0&gt;:&nbsp;&nbsp;&nbsp;&nbsp; push&nbsp;&nbsp; %ebp0x080489dd &lt;die+1&gt;:&nbsp;&nbsp;&nbsp;&nbsp; mov&nbsp;&nbsp;&nbsp;&nbsp;%esp,%ebp0x080489df &lt;die+3&gt;:&nbsp;&nbsp;&nbsp;&nbsp; sub&nbsp;&nbsp;&nbsp;&nbsp;$0x10,%esp0x080489e2 &lt;die+6&gt;:&nbsp;&nbsp;&nbsp;&nbsp; movl&nbsp;&nbsp; $0x0,0xfffffffc(%ebp)0x080489e9 &lt;die+13&gt;:&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;0xfffffffc(%ebp),%eax0x080489ec &lt;die+16&gt;:&nbsp;&nbsp;&nbsp;&nbsp;movl&nbsp;&nbsp; $0x6e6e6f67,(%eax)0x080489f2 &lt;die+22&gt;:&nbsp;&nbsp;&nbsp;&nbsp;movw&nbsp;&nbsp; $0x7265,0x4(%eax)0x080489f8 &lt;die+28&gt;:&nbsp;&nbsp;&nbsp;&nbsp;movb&nbsp;&nbsp; $0x0,0x6(%eax)0x080489fc &lt;die+32&gt;:&nbsp;&nbsp;&nbsp;&nbsp;mov&nbsp;&nbsp;&nbsp;&nbsp;$0x0,%eax0x08048a01 &lt;die+37&gt;:&nbsp;&nbsp;&nbsp;&nbsp;leave&nbsp;&nbsp;0x08048a02 &lt;die+38&gt;:&nbsp;&nbsp;&nbsp;&nbsp;ret&nbsp;&nbsp;&nbsp;&nbsp;End of assembler dump.gdb&amp;gt; <br/><br/>也可以直接break *die+16进行调试，看看在出错之前的堆栈情况，那么下面我们再来看看代码问题到底出在什么地方了。<br/><br/>/data/codes/c/test/backtraces $ gdb ./testgdb&gt; break *die+16Breakpoint 1 at 0x80489f2: file main.c, line 6.gdb&amp;gt; list *die+160x80489f2 is in die (main.c:6).1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #include &quot;sigsegv.h&quot;2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #include &lt;string.h&gt;3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int die() {5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char *err = NULL;6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; strcpy(err, &quot;gonner&quot;);7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int main() {gdb&gt; <br/><br/>现在看看定位错误将会多么方便，上面的调试指令中list之前break不是必须的，只是让你可以看到break其实就已经指出了哪一行代码导致 Segmentation fault了。如果你要发布你的程序你一般会为了减少体积不会附带调试信息的(也就是不加-ggdb -g参数)，不过没关系，你一样可以得到上面stack-trace信息，然后你调试之前只要加上调试信息即可。 
]]>
</description>
</item><item>
<link>https://jackxiang.com/post//#blogcomment</link>
<title><![CDATA[[评论] 善用backtrace解决大问题]]></title> 
<author> &lt;user@domain.com&gt;</author>
<category><![CDATA[评论]]></category>
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate> 
<guid>https://jackxiang.com/post//#blogcomment</guid> 
<description>
<![CDATA[ 
	
]]>
</description>
</item>
</channel>
</rss>