使用C获取导致核心转储的分段错误的地址

前端之家收集整理的这篇文章主要介绍了使用C获取导致核心转储的分段错误的地址前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在尝试编写一个可以解析核心转储文件的C程序.我的问题是,如何获取导致C中的核心转储的地址?我知道从这个答案可以得到使用gdb的地址:

How can I get GDB to tell me what address caused a segfault?

但是我想直接在C中检索地址.任何信息将被高度赞赏.谢谢!

注意:我知道如何解析核心转储为精灵.但是我不知道如何得到导致segfault的地址.

解决方法

My question is,how can I get the address that caused the core dump
in C?

简答:

有两种方式来解释这个问题.

什么是故障指示的地址?
>超出范围的地址是什么?

精灵核心转储将所有的元信息保留在笔记中
存储在音符段中.票据是不同的类型.

要回答#1,我们需要抓住寄存器.看看elf标题
找到程序头表.步行程序头表找到
记录表(类型PT_NOTE).走笔记表找到一个注释
键入NT_PRSTATUS.这个笔记的有效载荷是一个结构体
elf_prstatus,可以在linux / elfcore.h中找到.其中一个
这个结构的字段是所有通用寄存器.抓
%rip,你完成了.

对于#2,我们做类似的事情.这一次我们正在寻找一个笔记
类型为NT_SIGINFO.此笔记的有效内容是siginfo_t结构
在signal.h中定义.对于适用的信号(SIGILL,SIGFPE,SIGSEGV,
SIGBUS),字段si_addr将包含您尝试的地址
访问但不能.

更多信息如下.在示例核心转储中,rip是0x400560,该指令地址试图进行非法访问.这与其他通用寄存器一起显示.

程序试图访问的内存是0x03.这与信号信息的其余部分一起显示.

长的答案:

我认为BFD已经有25年的时间,所以我不会用它来将一个核心文件内容转储到一个linux盒子上.也许如果你必须编写一些需要使用一些格式的通用代码,但是即使如此,我也不知道今天会怎样.

elf spec写得很好,只需要根据需要浏览程序标头或部分标题表即可.核心文件中的所有进程元信息都包含在PT_NOTE程序段中的一组注释中,可以在几行直接C代码中解析出来.

我写了一个小程序来从x86_68核心文件获取寄存器并打印一些元数据.我把它放在github.获取一个注释有效载荷的逻辑是在这个功能

void *get_note(void *vp,int nt_type){
    Elf64_Ehdr *eh=vp;
    for(int i=0; i<eh->e_phnum; ++i){
        Elf64_Phdr *ph=(vp+eh->e_phoff+i*eh->e_phentsize);
        if(ph->p_type!=PT_NOTE){
            continue;
        }
        void *note_table=(vp + ph->p_offset);
        void *note_table_end=(note_table+ph->p_filesz);
        Elf64_Nhdr *current_note=note_table;
        while(current_note<(Elf64_Nhdr *)note_table_end){
            void *note_end=current_note;
            note_end += 3*sizeof(Elf64_Word);
            note_end += roundup8(current_note->n_namesz);
            if(current_note->n_type==nt_type){
                return note_end;
            }
            note_end += roundup8(current_note->n_descsz);
            current_note=note_end;          
        }
    }
    return 0;
}

函数会传递一个指向elf文件和一个注释类型的指针,并返回指针相关注释的有效内容(如果存在).各种可能的笔记类型在elf.h中.我在机器上核心文件中看到的笔记类型是:

#define NT_PRSTATUS 1       /* Contains copy of prstatus struct */
#define NT_FPREGSET 2       /* Contains copy of fpregset struct */
#define NT_PRPSINFO 3       /* Contains copy of prpsinfo struct */
#define NT_AUXV     6       /* Contains copy of auxv array */
#define NT_X86_XSTATE   0x202       /* x86 extended state using xsave */
#define NT_SIGINFO  0x53494749  /* Contains copy of siginfo_t,size might increase */
#define NT_FILE     0x46494c45  /* Contains information about mapped
                                   files */

这些结构中的大多数都在/usr/include / linux下的头文件中. xsave结构是intel manual第13章中描述的几KB浮点信息.它具有SSE,AVX和MPX,在其中注册.

NT_FILE有效载荷似乎在标题中没有相关联的结构,但在内核注释(fs / binfmt_elf.c)中有描述:

/*
 * Format of NT_FILE note:
 *
 * long count     -- how many files are mapped
 * long page_size -- units for file_ofs
 * array of [COUNT] elements of
 *   long start
 *   long end
 *   long file_ofs
 * followed by COUNT filenames in ASCII: "FILE1" NUL "FILE2" NUL...
 */

用于解析32位系统的精灵文件的更改很简单.对于可变大小的字段,使用相应的Elf32_XXX结构,并舍入4而不是8.

最近几天我一直在添加这个小程序的东西.目前它的文件头,段头,通用寄存器,程序状态,程序信息和回溯.随着时间的推移,我会补充其余的笔记的支持.这是当前的输出

$./read_pc -biprst core
General Registers: 
r15     0x000000000000000000  r14     0x000000000000000000  
r13     0x0000007ffc20d36a50  r12     0x000000000000400430  
rbp     0x0000007ffc20d36950  rbx     0x000000000000000000  
r11     0x000000000000000246  r10     0x000000000000000000  
r9      0x000000000000000002  r8      0x000000000000000000  
rax     0x000000000000000003  rcx     0x00000000007ffffffe  
rdx     0x0000007f5817523780  rsi     0x000000000000000001  
rdi     0x000000000000000001  ss      0x00000000000000002b  
rip     0x000000000000400560  cs      0x000000000000000033  
eflags  0x000000000000010246  rsp     0x0000007ffc20d36950  
fs_base 0x0000007f5817723700  gs_base 0x000000000000000000  
ds      0x000000000000000000  es      0x000000000000000000  
fs      0x000000000000000000  gs      0x000000000000000000  
orig_rax 0x00ffffffffffffffff  

Program status: 
signo 11 signal code 0 errno 0
cursig 11 sigpend 000000000000000000 sigheld 000000000000000000
pid 27547 ppid 26600 pgrp 27547 sid 26600
utime: 0.000000 stime 0.000000
cutime: 0.000000 cstime 0.000000
fpvalid: 1


Signal Information: 
signo: 11 errno 0 code 1
addr 0x3 addr_lsb 0 addr_bnd ((nil),(nil))


Process Information:
state 0 (R) zombie 0 nice 0 flags 0x400600
uid 1000 gid 1000 pid 27547 ppid 26600 pgrp 27547 sid 26600
fname: foo
args: ./foo 


Backtrace: 
rip = 0x000000000000400560
rip = 0x000000000000400591
rip = 0x0000000000004005a1


Program Headers:
   Type      Offset             Virt Addr          PhysAddr          
             FileSiz            MemSize              Flags  Align    
 NOTE      0x00000000000004a0 0x0000000000000000 0000000000000000
           0x0000000000000b98 0x0000000000000000         0x000000
 LOAD      0x0000000000002000 0x0000000000400000 0000000000000000
           0x0000000000001000 0x0000000000001000 R X     0x001000
 LOAD      0x0000000000003000 0x000000000
void *get_note(void *vp,int nt_type){
    Elf64_Ehdr *eh=vp;
    for(int i=0; i<eh->e_phnum; ++i){
        Elf64_Phdr *ph=(vp+eh->e_phoff+i*eh->e_phentsize);
        if(ph->p_type!=PT_NOTE){
            continue;
        }
        void *note_table=(vp + ph->p_offset);
        void *note_table_end=(note_table+ph->p_filesz);
        Elf64_Nhdr *current_note=note_table;
        while(current_note<(Elf64_Nhdr *)note_table_end){
            void *note_end=current_note;
            note_end += 3*sizeof(Elf64_Word);
            note_end += roundup8(current_note->n_namesz);
            if(current_note->n_type==nt_type){
                return note_end;
            }
            note_end += roundup8(current_note->n_descsz);
            current_note=note_end;          
        }
    }
    return 0;
}

00 0000000000000000
0x0000000000001000 0x0000000000001000 X 0x001000
LOAD 0x0000000000004000 0x0000000000601000 0000000000000000
0x0000000000001000 0x0000000000001000 WX 0x001000
LOAD 0x0000000000005000 0x00000000018bf000 0000000000000000
0x0000000000021000 0x0000000000021000 WX 0x001000
LOAD 0x0000000000026000 0x00007f581715e000 0000000000000000
0x0000000000001000 0x00000000001c0000 R X 0x001000
LOAD 0x0000000000027000 0x00007f581731e000 0000000000000000
0x0000000000000000 0x00000000001ff000 0x001000
LOAD 0x0000000000027000 0x00007f581751d000 0000000000000000
0x0000000000004000 0x0000000000004000 X 0x001000
LOAD 0x000000000002b000 0x00007f5817521000 0000000000000000
0x0000000000002000 0x0000000000002000 WX 0x001000
LOAD 0x000000000002d000 0x00007f5817523000 0000000000000000
0x0000000000004000 0x0000000000004000 WX 0x001000
LOAD 0x0000000000031000 0x00007f5817527000 0000000000000000
0x0000000000001000 0x0000000000026000 R X 0x001000
LOAD 0x0000000000032000 0x00007f5817722000 0000000000000000
0x0000000000003000 0x0000000000003000 WX 0x001000
LOAD 0x0000000000035000 0x00007f581774a000 0000000000000000
0x0000000000002000 0x0000000000002000 WX 0x001000
LOAD 0x0000000000037000 0x00007f581774c000 0000000000000000
0x0000000000001000 0x0000000000001000 X 0x001000
LOAD 0x0000000000038000 0x00007f581774d000 0000000000000000
0x0000000000001000 0x0000000000001000 WX 0x001000
LOAD 0x0000000000039000 0x00007f581774e000 0000000000000000
0x0000000000001000 0x0000000000001000 WX 0x001000
LOAD 0x000000000003a000 0x00007ffc20d16000 0000000000000000
0x0000000000022000 0x0000000000022000 WX 0x001000
LOAD 0x000000000005c000 0x00007ffc20d9c000 0000000000000000
0x0000000000002000 0x0000000000002000 X 0x001000
LOAD 0x000000000005e000 0x00007ffc20d9e000 0000000000000000
0x0000000000002000 0x0000000000002000 R X 0x001000
LOAD 0x0000000000

void *get_note(void *vp,int nt_type){
    Elf64_Ehdr *eh=vp;
    for(int i=0; i<eh->e_phnum; ++i){
        Elf64_Phdr *ph=(vp+eh->e_phoff+i*eh->e_phentsize);
        if(ph->p_type!=PT_NOTE){
            continue;
        }
        void *note_table=(vp + ph->p_offset);
        void *note_table_end=(note_table+ph->p_filesz);
        Elf64_Nhdr *current_note=note_table;
        while(current_note<(Elf64_Nhdr *)note_table_end){
            void *note_end=current_note;
            note_end += 3*sizeof(Elf64_Word);
            note_end += roundup8(current_note->n_namesz);
            if(current_note->n_type==nt_type){
                return note_end;
            }
            note_end += roundup8(current_note->n_descsz);
            current_note=note_end;          
        }
    }
    return 0;
}
void *get_note(void *vp,int nt_type){ Elf64_Ehdr *eh=vp; for(int i=0; i<eh->e_phnum; ++i){ Elf64_Phdr *ph=(vp+eh->e_phoff+i*eh->e_phentsize); if(ph->p_type!=PT_NOTE){ continue; } void *note_table=(vp + ph->p_offset); void *note_table_end=(note_table+ph->p_filesz); Elf64_Nhdr *current_note=note_table; while(current_note<(Elf64_Nhdr *)note_table_end){ void *note_end=current_note; note_end += 3*sizeof(Elf64_Word); note_end += roundup8(current_note->n_namesz); if(current_note->n_type==nt_type){ return note_end; } note_end += roundup8(current_note->n_descsz); current_note=note_end; } } return 0; }void *get_note(void *vp,int nt_type){ Elf64_Ehdr *eh=vp; for(int i=0; i<eh->e_phnum; ++i){ Elf64_Phdr *ph=(vp+eh->e_phoff+i*eh->e_phentsize); if(ph->p_type!=PT_NOTE){ continue; } void *note_table=(vp + ph->p_offset); void *note_table_end=(note_table+ph->p_filesz); Elf64_Nhdr *current_note=note_table; while(current_note<(Elf64_Nhdr *)note_table_end){ void *note_end=current_note; note_end += 3*sizeof(Elf64_Word); note_end += roundup8(current_note->n_namesz); if(current_note->n_type==nt_type){ return note_end; } note_end += roundup8(current_note->n_descsz); current_note=note_end; } } return 0; }0 0xffffffffff600000 0000000000000000 0x0000000000001000 0x0000000000001000 R X 0x001000 All worked

猜你在找的C&C++相关文章