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

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*1024

void *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   10


void 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 int
callback(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_SOURCE
OBJLIB = libaddr.so

addr: 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: clean
clean:
	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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值