‧ 版權聲明:轉載時請以超鏈結形式標明文章原始出處和作者資訊及本聲明
http://chenzhuoyou.blogbus.com/logs/35484209.html
程式在得到一個Segmentation
fault這樣的錯誤資訊毫無保留地就跳出來了,遇到這樣的問題讓人很痛苦,查找問題不亞於你N多天辛苦勞累編寫代碼的難度。那麼有沒有更好的方法可以在產生SIGSEGV信號的時候得到調試可用的資訊呢?看看下面的常式吧!
sigsegv.h
#ifndef __sigsegv_h__
#define __sigsegv_h__
#ifdef __cplusplus
extern "C" {
#endif
int setup_sigsegv();
#ifdef __cplusplus
}
#endif
#endif /* __sigsegv_h__ */
sigsegv.c
#define _GNU_SOURCE
#include <memory.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <ucontext.h>
#include <dlfcn.h>
#include <execinfo.h>
#ifndef NO_CPP_DEMANGLE
#include <cxxabi.h>
#endif
#if defined(REG_RIP)
# define SIGSEGV_STACK_IA64
# define REGFORMAT "%016lx"
#elif defined(REG_EIP)
# define SIGSEGV_STACK_X86
# define REGFORMAT "%08x"
#else
# define SIGSEGV_STACK_GENERIC
# define REGFORMAT "%x"
#endif
static void signal_segv(int signum, siginfo_t* info, void*ptr) {
static const char *si_codes[3] = {"", "SEGV_MAPERR", "SEGV_ACCERR"};
size_t i;
ucontext_t *ucontext = (ucontext_t*)ptr;
#if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)
int f = 0;
Dl_info dlinfo;
void **bp = 0;
void *ip = 0;
#else
void *bt[20];
char **strings;
size_t sz;
#endif
fprintf(stderr, "Segmentation Fault!\n");
fprintf(stderr, "info.si_signo = %d\n", signum);
fprintf(stderr, "info.si_errno = %d\n", info->si_errno);
fprintf(stderr, "info.si_code = %d (%s)\n", info->si_code, si_codes[info->si_code]);
fprintf(stderr, "info.si_addr = %p\n", info->si_addr);
for(i = 0; i < NGREG; i++)
fprintf(stderr, "reg[%02d] = 0x" REGFORMAT "\n", i, ucontext->uc_mcontext.gregs[i]);
#if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)
# if defined(SIGSEGV_STACK_IA64)
ip = (void*)ucontext->uc_mcontext.gregs[REG_RIP];
bp = (void**)ucontext->uc_mcontext.gregs[REG_RBP];
# elif defined(SIGSEGV_STACK_X86)
ip = (void*)ucontext->uc_mcontext.gregs[REG_EIP];
bp = (void**)ucontext->uc_mcontext.gregs[REG_EBP];
# endif
fprintf(stderr, "Stack trace:\n");
while(bp && ip) {
if(!dladdr(ip, &dlinfo))
break;
const char *symname = dlinfo.dli_sname;
#ifndef NO_CPP_DEMANGLE
int status;
char *tmp = __cxa_demangle(symname, NULL, 0, &status);
if(status == 0 && tmp)
symname = tmp;
#endif
fprintf(stderr, "% 2d: %p <%s+%u> (%s)\n",
++f,
ip,
symname,
(unsigned)(ip - dlinfo.dli_saddr),
dlinfo.dli_fname);
#ifndef NO_CPP_DEMANGLE
if(tmp)
free(tmp);
#endif
if(dlinfo.dli_sname && !strcmp(dlinfo.dli_sname, "main"))
break;
ip = bp[1];
bp = (void**)bp[0];
}
#else
fprintf(stderr, "Stack trace (non-dedicated):\n");
sz = backtrace(bt, 20);
strings = backtrace_symbols(bt, sz);
for(i = 0; i < sz; ++i)
fprintf(stderr, "%s\n", strings[i]);
#endif
fprintf(stderr, "End of stack trace\n");
exit (-1);
}
int setup_sigsegv() {
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_sigaction = signal_segv;
action.sa_flags = SA_SIGINFO;
if(sigaction(SIGSEGV, &action, NULL) < 0) {
perror("sigaction");
return 0;
}
return 1;
}
#ifndef SIGSEGV_NO_AUTO_INIT
static void __attribute((constructor)) init(void) {
setup_sigsegv();
}
#endif
main.c
#include "sigsegv.h"
#include <string.h>
int die() {
char *err = NULL;
strcpy(err, "gonner");
return 0;
}
int main() {
return die();
}
下面來編譯上面的main.c程式看看將會產生什麼樣的資訊呢,不過要注意的就是如果要在你的程式裏引用sigsegv.h、sigsegv.c得到堆疊資訊的話記得加上-rdynamic
-ldl參數。
/data/codes/c/test/backtraces $ gcc -o test -rdynamic -ldl -ggdb -g sigsegv.c
main.c
/data/codes/c/test/backtraces $ ./test
Segmentation Fault!
info.si_signo = 11
info.si_errno = 0
info.si_code = 1 (SEGV_MAPERR)
info.si_addr = (nil)
reg[00] = 0x00000033
reg[01] = 0x00000000
reg[02] = 0xc010007b
reg[03] = 0x0000007b
reg[04] = 0x00000000
reg[05] = 0xb7fc8ca0
reg[06] = 0xbff04c2c
reg[07] = 0xbff04c1c
reg[08] = 0xb7f8cff4
reg[09] = 0x00000001
reg[10] = 0xbff04c50
reg[11] = 0x00000000
reg[12] = 0x0000000e
reg[13] = 0x00000006
reg[14] = 0x080489ec
reg[15] = 0x00000073
reg[16] = 0x00010282
reg[17] = 0xbff04c1c
reg[18] = 0x0000007b
Stack trace:
1: 0x80489ec <die+16> (/data/codes/c/test/backtraces/test)
2: 0x8048a16 <main+19> (/data/codes/c/test/backtraces/test)
End of stack trace
/data/codes/c/test/backtraces $
下面用gdb來看看出錯的地方左右的代碼:
/data/codes/c/test/backtraces $ gdb ./test
gdb> disassemble die+16
Dump of assembler code for function die:
0x080489dc <die+0>: push %ebp
0x080489dd <die+1>: mov %esp,%ebp
0x080489df <die+3>: sub $0x10,%esp
0x080489e2 <die+6>: movl $0x0,0xfffffffc(%ebp)
0x080489e9 <die+13>: mov 0xfffffffc(%ebp),%eax
0x080489ec <die+16>: movl $0x6e6e6f67,(%eax)
0x080489f2 <die+22>: movw $0x7265,0x4(%eax)
0x080489f8 <die+28>: movb $0x0,0x6(%eax)
0x080489fc <die+32>: mov $0x0,%eax
0x08048a01 <die+37>: leave
0x08048a02 <die+38>: ret
End of assembler dump.
gdb>
也可以直接break *die+16進行調試,看看在出錯之前的堆疊情況,那麼下面我們再來看看代碼問題到底出在什麼地方了。
/data/codes/c/test/backtraces $ gdb ./test
gdb> break *die+16
Breakpoint 1 at 0x80489f2: file main.c, line 6.
gdb> list *die+16
0x80489f2 is in die (main.c:6).
1 #include "sigsegv.h"
2 #include <string.h>
3
4 int die() {
5 char *err = NULL;
6 strcpy(err, "gonner");
7 return 0;
8 }
9
10 int main() {
gdb>
現在看看定位錯誤將會多麼方便,上面的調試指令中list之前break不是必須的,只是讓你可以看到break其實就已經指出了哪一行代碼導致
Segmentation fault了。如果你要發佈你的程式你一般會為了減少體積不會附帶調試資訊的(也就是不加-ggdb
-g參數),不過沒關係,你一樣可以得到上面stack-trace資訊,然後你調試之前只要加上調試資訊即可。
2010年9月23日 星期四
Backtrace的方法
2010年9月6日 星期一
SKYPE安裝
Introduction
Skype is proprietary software that allows you to make calls over the Internet using your computer. Skype uses decentralized peer-to-peer technologies, so your calls do not go through a central server, but through distributed servers and other users. It uses its own proprietary communication protocol to achieve this. In addition, all communications are encrypted from end to end so that others cannot listen in. The Skype software is free to use, but it is not free software; the source code is proprietary and not available for modification.
General information about Skype can be found here at, Wikipedia. The official Skype website is Skype.com
SkypeEthics gives information on why some users do not use Skype.
Open alternatives Softphones using open protocols include Ekiga and Twinkle.
You need a working sound input and output configuration in order to use Skype. Most modern computers have sound output out of the box, but you need a microphone (or a headset, while you are out shopping) for the input. In order to broadcast video, you'll need a webcam.
Links to detailed information about Skype issues on Ubuntu can be found in the Resources section below.
Installing Skype
Since Ubuntu 10.04 (Lucid Lynx), Skype is part of the Canonical partner repository. To install Skype add the Canonical Partner Repository and install Skype via the Software-Center or via the Terminal.
sudo apt-get update && sudo apt-get install skype
Installing Skype on older Ubuntu versions.
Skype is not available in any Ubuntu software repository, and therefore cannot be installed with Ubuntu's package management software such as Synaptic or apt-get without adding a repository containing Skype. There is the official Skype repository: Skype Forum
You can add the Apt source like this
echo "deb http://download.skype.com/linux/repos/debian/ stable non-free #Skype" | sudo tee -a /etc/apt/sources.list > /dev/null
Import the Apt key, even it is not used, but may be useful in future:
sudo apt-key adv --keyserver pgp.mit.edu --recv-keys 0xd66b746e
Install Skype:
sudo apt-get update && sudo apt-get install skype
Using a repository, you will automatically receive future updates to the software. Please be aware that the repository is not signed, so when you try to install Skype, you will get a warning.
If you don't want to do that, or can't (for example, if you're on amd64), perhaps the easiest way to install is from the Debian (.deb) package available directly from the Skype website. The downside of this is that you won't automatically get future updates, you will have to download the new versions as they become available.
Debian Package
Download Debian package from Get Skype
- Save and then open the file. It will open with the proper installer by default.
- Click on the install button.
AMD64
For Ubuntu 8.10 (Intrepid Ibex)-Ubuntu 10.04 (Lucid Lynx)
Download http://www.skype.com/download/skype/linux/choose/ (choose your architecture).
- Install it by double-clicking the deb file and clicking "Install Package"
Note : version 2.1 beta will work natively using PulseAudio server
Note 2: For Ubuntu 10.04 you will need the nspluginwrapper package which is available from the multiverse. You can enable the multiverse by going to System > Administration > Software sources and enabling the "multiverse" channel.
For Ubuntu 8.04 (Hardy Heron):
Download Ubuntu 64 bit Skype package
- Install it by double-clicking the deb file and clicking "Install package"
For Ubuntu 6.06 (Dapper Drake):
Download the Debian package (http://skype.com/download/skype/linux/)
Install skype: sudo dpkg -i --force-all
- Determine missing 32bit libs: ldd /usr/bin/skype | grep not
Download the libs (the i386 version of course, hint: the package is named libqt3-mt): http://packages.ubuntu.com/
- mkdir ~/.32bitLibs (or use /lib32 and change last step to this directory)
extract the *.deb files (dpkg-deb --extract
) - copy the necessary library files from the extracted packages to ~/.32bitLibs
create a wrapper script: export LD_LIBRARY_PATH="/home/
/.32bitLibs/";skype
Running Skype
To start Skype, choose Applications->Internet->Skype. It usually takes a minute or two for Skype to get started, and you may think that nothing is happening, so be patient.
When the Skype window finally opens, sign up (if necessary) and log in to your Skype account. Test your configuration by selecting the Echo / Sound Test Service contact (if not there already, add contact echo123) and clicking on the large green button at the bottom of the Skype window. If the connection is made and you hear a voice, your sound configuration is fine. If you cannot hear a voice, see the troubleshooting section below.