linux c/c++ 段错误(Segmentation fault 查找示例2)

来源:互联网 发布:现在淘宝开店赚钱吗 编辑:程序博客网 时间:2024/04/29 19:46

addr.h 

#ifndef __ADDR_H_#define __ADDR_H_#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <fcntl.h>#include <errno.h>#include <netdb.h>#include <stdio.h>#include <stdlib.h>#include <stdint.h>#include <pthread.h>#include <unistd.h>#include <signal.h>#include <sys/time.h>#include <sys/resource.h>typedef enum{    NO,    OK}Status_t;typedef struct{    pthread_t tid;    pthread_mutex_t mutex;    pthread_cond_t cond;    int index;    int i;    char *buf;    char date[12];    Status_t status;}thread_pool_t;void *thread_all(void *arg);int creat_threads(int num, thread_pool_t *pools);thread_pool_t * create_pools(int thread_num);int task_allocation(thread_pool_t * pools, int thread_num, int id);void wait_all_threads_ready(thread_pool_t *pools, int thread_num);#endif

addr.cpp 

#include "addr.h"pthread_attr_t attr;#define THREAD_STACK_SIZE 16*1024void *thread_all(void *arg){    thread_pool_t *worker = (thread_pool_t *)arg;    int b= 5;    while (1)    {        pthread_mutex_lock(&worker->mutex);        while (worker->status == NO)            pthread_cond_wait(&worker->cond, &worker->mutex);        worker->status = NO;        if (!worker->i){            *(worker->buf) = 1;        }else if (worker->i == 1){            //strcpy(worker->date, "hello world");            printf("hello\n");            printf("%s\n", b);        }else if (worker->i == 2){            printf("%s\n", worker->i);        }else            printf("\n%lu i=%d hello world\n", pthread_self(), worker->i);        pthread_mutex_unlock(&worker->mutex);    }}int creat_threads(int num, thread_pool_t *pools){    int i = 0, ret = 0;     pthread_attr_init(&attr);    pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE);        for (i; i < num; i++){        ret = pthread_create(&pools[i].tid, &attr, thread_all, (void *)(pools + i));        if (ret) {            fprintf(stderr, "pthread_create:%s\n", strerror(ret));            return ret;        }    }    return 0;}thread_pool_t * create_pools(int thread_num){    int i = 0;    thread_pool_t * pools = (thread_pool_t *)malloc(sizeof(thread_pool_t)*thread_num);    if (pools == NULL) {        perror("malloc!\n");        return NULL;    }    for (i; i < thread_num; i++){        pthread_mutex_init(&pools[i].mutex, NULL);        pthread_cond_init(&pools[i].cond, NULL);        pools[i].index = i+1;        pools[i].i = 0;        pools[i].buf = NULL;        pools[i].status = NO;    }    return pools;}int task_allocation(thread_pool_t * pools, int i, int id){    pthread_mutex_lock(&pools[i].mutex);    pools[i].status = OK;    pools[i].i = id;    pthread_cond_signal(&pools[i].cond);    pthread_mutex_unlock(&pools[i].mutex);    return 0;}void wait_all_threads_ready(thread_pool_t *pools, int thread_num){    int i, flag;    for (i = 0; i < thread_num; i++) {        flag = 0;        pthread_mutex_lock(&pools[i].mutex);        if (pools[i].status == OK) {            flag = 1;        }        pthread_mutex_unlock(&pools[i].mutex);        if (flag)            i--;     }}

main.cpp 
#include "addr.h"#include <execinfo.h>#include <libunwind.h>#include <dlfcn.h>#include <link.h>#define THREADNUM   10void sigaction_handler(int s, siginfo_t *info, void* cont){    int ret;    void *buf[100];    ret = backtrace(buf, 100);    backtrace_symbols_fd(buf, ret, 1);    printf("the err addr:%#x\n", (size_t)info->si_addr);    void *p = __builtin_return_address(0);     printf("%p\n", p);    p = __builtin_return_address(1);     printf("%p\n", p);    exit(0);}void sigaction_handler1(int s, siginfo_t *info, void* cont){    char name[256];    unw_cursor_t cursor;     unw_context_t uc;    unw_word_t ip, sp, offp;    //Dl_info info;    unw_getcontext(&uc);    unw_init_local(&cursor, &uc);    while (unw_step(&cursor) > 0) {        int line = 0;        name[0] = '\0';        unw_get_proc_name(&cursor, name, 256, &offp);        unw_get_reg(&cursor, UNW_REG_IP, &ip);        unw_get_reg(&cursor, UNW_REG_SP, &sp);        printf ("name = %s, ip = %#x, sp = %#x\n", name, (long) ip, (long) sp);     //   if (dladdr((void *)ip, &info)){       //     printf("%s %#x\n", info.dli_fname, info.dli_fbase);       // }    }    int ret;    void *buf[100];    ret = backtrace(buf, 100);    backtrace_symbols_fd(buf, ret, 1);    exit(0);}static intcallback(struct dl_phdr_info *info, size_t size, void *data){    int j;    printf("name=%s (%d segments)\n", info->dlpi_name,            info->dlpi_phnum);    for (j = 0; j < info->dlpi_phnum; j++)        printf("\t\t header %2d: address=%10p\n", j,                (void *) (info->dlpi_addr + info->dlpi_phdr[j].p_vaddr));    return 0;}int main(int argc, char *argv[]){    int ret, id, i = 0;    char buf[512];    thread_pool_t * pools;    struct sigaction act;    dl_iterate_phdr(callback, NULL);    pools = create_pools(THREADNUM);    if (!pools) {        perror("create_pools!!\n");        return 1;    }    ret = creat_threads(THREADNUM, pools);    if (ret) {        perror("creat_threads!!\n");        return 1;    }    wait_all_threads_ready(pools, THREADNUM);    act.sa_sigaction = sigaction_handler1;    //act.sa_sigaction = sigaction_handler;    sigemptyset(&act.sa_mask);    act.sa_flags = SA_SIGINFO;    //sigaction(SIGSEGV, &act, NULL);    while(1){         printf("please input your id: ");        fflush(stdout);         ret = read(0, buf, sizeof(buf));        buf[ret - 1] = '\0';        id = atoi(buf);        task_allocation(pools, i%THREADNUM, id);        i++;   }    while (1)        pause();    return 0;}

Makefile 

CC = g++CPPFLAGS = -O0 -g3 -DDEBUG -DUNW_LOCAL_ONLY -D_GNU_SOURCEOBJLIB = libaddr.soaddr: main.cpp $(OBJLIB)$(CC) -rdynamic  -I./ $(CPPFLAGS) -L./ -laddr -lpthread -L/usr/local/lib -lunwind -o $@ main.cpp$(OBJLIB):addr.cpp$(CC)  -rdynamic -I./ $(CPPFLAGS) -fpic -shared -lpthread -o $@ $<.PHONY: cleanclean:rm -f addr $(OBJLIB)


程序采用多线程

ulimit -c 0 (当前shell 中不产生core文件)

第一步将main.cpp 中sigaction(SIGSEGV, &act, NULL); 注释, 这样段错误就会在内核日志产生相应信息

编译生成 addr、libaddr.so

运行./addr

程序打印:

name=libaddr.so (6 segments) header  0: address=  0xa24000 header  1: address=  0xa25000 header  2: address=  0xa25018 header  3: address=  0xa240f4 header  4: address=  0xa24df4 header  5: address=  0xa24000

输入0:

程序段错误结束

grep segfault /var/log/messages 查看

addr[22500]: segfault at 0 ip 00a24a21 sp b7724350 error 6 in libaddr.so[a24000+1000]

程序加载的基地址是0xa24000, crash 发生在进程调用的libaddr.so中

算偏移地址: 0x00a24a21 - 0xa24000 = 0xa21

一: addr2line -e libaddr.so 0xa21

二: objdump -DCl libaddr.so >dump

grep a21 dump  即可找到段错误发生位置

a19: 75 0b                jne    a26 <thread_all(void*)+0x76>
/mnt/hgfs/D/code/vm_proj_saving/myproj/addr2line/addr.cpp:19
 a1b: 8b 45 f0             mov    -0x10(%ebp),%eax
 a1e: 8b 40 54             mov    0x54(%eax),%eax
 a21: c6 00 01             movb   $0x1,(%eax)
 a24: eb 76                jmp    a9c <thread_all(void*)+0xec>

错误发生在addr.cpp 19行


至于捕捉段错误信号将main.cpp 中sigaction(SIGSEGV, &act, NULL);注释去掉

分别act.sa_sigaction 分别赋值sigaction_handler和sigaction_handler1 编译运行体验一下

(注意一旦程序有捕捉这个信号了, 内核日志就不会在打印相印的错误信息了)

这里已sigaction_handler示例

编译运行:

./addr

打印动态库加载信息:

name=libaddr.so (6 segments)
header  0: address=  0xe22000
header  1: address=  0xe23000
header  2: address=  0xe23018
header  3: address=  0xe220f4
header  4: address=  0xe22df4
header  5: address=  0xe22000

输入0

程序段错误打印如下然后结束:

 ./addr(_Z17sigaction_handleriP7siginfoPv+0x1f)[0x8048ba3]
[0xf7440c]
/lib/libc.so.6[0x6a0b5f]
/lib/libc.so.6(_IO_vfprintf+0x3a6f)[0x66b49f]
/lib/libc.so.6(_IO_printf+0x30)[0x672470]
libaddr.so(_Z10thread_allPv+0xc9)[0xe22a79]
/lib/libpthread.so.0[0x7cda49]
/lib/libc.so.6(clone+0x5e)[0x709aae]
the err addr:0x2
0xf7440c
0x672470

libaddr.so(_Z10thread_allPv+0xc9)[0xe22a79]     指令地址0xe22a79

偏移地址: e22a79 - e22000 = a79

addr2line -e libaddr.so a79

得/mnt/hgfs/D/code/vm_proj_saving/myproj/addr2line/addr.cpp:25