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