core文件分析

来源:互联网 发布:高仿球鞋的淘宝店 编辑:程序博客网 时间:2024/06/18 00:06

刚开通博客,想写博客很久了,今天终于开通了。先把之前写的学习笔记贴上来吧。


在程序运行出现segmentfault后,我们会通过gdb来调试core文件定位问题,下面我们来分析下core文件是什么?

首先需要明确的一点就是core文件也是ELF格式的,ELF的格式如下:

 

ELF文件参与程序的链接和运行,从链接的角度看有上面左边所示的Linking View,从程序运行的角度看为右边所示的Execution View(执行视图)。CoreELF文件格式是按照执行视图的格式组织的。

下面是core文件的ELF头信息


以内核代码elf_core_dump函数为入口分析core文件怎么生成的:

elf_core_dump-àfill_note_info-àfill_elf_header

static void fill_elf_header(struct elfhdr *elf, int segs,

    u16 machine, u32 flags, u8 osabi)

{

memset(elf, 0, sizeof(*elf));

 

memcpy(elf->e_ident, ELFMAG, SELFMAG);

elf->e_ident[EI_CLASS] = ELF_CLASS;

elf->e_ident[EI_DATA] = ELF_DATA;

elf->e_ident[EI_VERSION] = EV_CURRENT;

elf->e_ident[EI_OSABI] = ELF_OSABI;

 

elf->e_type = ET_CORE;

elf->e_machine = machine;

elf->e_version = EV_CURRENT;

elf->e_phoff = sizeof(struct elfhdr);

elf->e_flags = flags;

elf->e_ehsize = sizeof(struct elfhdr);

elf->e_phentsize = sizeof(struct elf_phdr);

elf->e_phnum = segs;

 

return;

这里填入的ELF头信息就是用readelf –h读取到的。下面我们看下生成的core文件


上面表格中是core文件的ELF头的详细信息,分别用不同的颜色表明了不同的成员值。

成员

含义

e_ident

"\177ELF"

magic

0x1

ELF32

0x1

2's complement, little endian

0x1

1 (current)

0

UNIX - System V

0

 

e_type

4

ELF类型,ET_CORE表示为core文件

e_machine

0x28

ELF文件的平台属性

e_version

1

 

e_entry

0

ELF程序的入口虚拟地址

e_phoff

0x34

程序头表的偏移,程序头从0x34开始,紧跟在ELF头后面

e_shoff

0

 

e_flags

0

 

e_ehsize

0x34

ELF文件头本身的大小,52字节

e_phentsize

0x20

每个程序头占用的大小为32字节

e_phnum

0xa1

程序头表的个数,161

e_shentsize

0

段描述符的大小

e_shnum

0

段描述符的个数

e_shstrndx

0


从上面信息可知,core文件程序头表从0x34位置开始,每个程序头表的大小为32字节

下面看下core文件程序头表的信息


截图只是程序头表的部分信息,因为有161个程序头表这里无法全部显示。

typedef struct elf32_phdr{

  Elf32_Word p_type;

  Elf32_Off p_offset;

  Elf32_Addr p_vaddr;

  Elf32_Addr p_paddr;

  Elf32_Word p_filesz;

  Elf32_Word p_memsz;

  Elf32_Word p_flags;

  Elf32_Word p_align;

} Elf32_Phdr;


分析下core文件中第一个程序头表的信息,第一个程序头表的偏移是0x34


上面表格中是第一个程序头表的详细信息,分别用不同的颜色表明了不同的成员值。

成员

含义

p_type

0x4

段的类型,这里为PT_NOTE

p_offset

0x1454

段的位置相对于文件开始的偏移

p_vaddr

0

段在内存中的首字节地址

p_paddr

0

 

p_filesz

0x3904

段在文件映像栈的字节数

p_memsz

0

段在内存映像中的字节数

p_flags

0

 

p_align

0


从上面的程序头表信息可知,第一个段类型为NOTE段,偏移为0x1454,大小为0x3904

PT_NOTE类型的段用于存放线程信息和寄存器信息。由于PT_NOTE段是辅助信息,不存在与内存中。

那么PT_NOTE段信息是怎么存储的呢?

去内核中看下相应代码fill_note_info函数

fill_note_info函数代码片段:

       //首先将所有的线程加入到info-> thread_list

for (ct = current->mm->core_state->dumper.next;

ct; ct = ct->next) {

ets = kzalloc(sizeof(*ets), GFP_KERNEL);

if (!ets)

return 0;

 

ets->thread = ct->task;

list_add(&ets->list, &info->thread_list);

}

        //遍历链表,调用elf_dump_thread_status保存线程的信息

list_for_each(t, &info->thread_list) {

int sz;

 

ets = list_entry(t, struct elf_thread_status, list);

sz = elf_dump_thread_status(signr, ets);

info->thread_status_size += sz;

}


接着分析elf_dump_thread_status函数

elf_dump_thread_status函数代码:

static int elf_dump_thread_status(long signr, struct elf_thread_status *t)

{

int sz = 0;

struct task_struct *p = t->thread;

t->num_notes = 0;

 

fill_prstatus(&t->prstatus, p, signr); //获取线程的状态,包括signalpid

elf_core_copy_task_regs(p, &t->prstatus.pr_reg);  //获取线程的寄存器信息

fill_note(&t->notes[0], "CORE", NT_PRSTATUS, sizeof(t->prstatus),

  &(t->prstatus)); //将信息存入memelfnotenotes数组中

t->num_notes++;

sz += notesize(&t->notes[0]);

return sz;

}


上面就是填充PT_NOTE段的主要代码流程,回过头来我们看下PT_NOTE段的数据结构:


/* Note header in a PT_NOTE section */

typedef struct elf32_note {

  Elf32_Word n_namesz; /* Name size */

  Elf32_Word n_descsz; /* Content size */

  Elf32_Word n_type; /* Content type */

} Elf32_Nhdr;

 

struct elf_note_info {

struct memelfnote *notes;

struct elf_prstatus *prstatus; /* NT_PRSTATUS */

struct elf_prpsinfo *psinfo; /* NT_PRPSINFO */

struct list_head thread_list;

elf_fpregset_t *fpu;

int thread_status_size;

int numnote;

};


下面分析core文件的PT_NOTE段信息:


上面的寄存器信息正好与gdb看到的寄存器信息一致



上面只是分析了PT_NOTE段的一部分,我们定位coredump的问题也不需要这样脑神费力的分析二进制core文件。



0 0
原创粉丝点击