您的位置:首页 > 其它

core文件分析

2015-06-10 19:52 381 查看
刚开通博客,想写博客很久了,今天终于开通了。先把之前写的学习笔记贴上来吧。

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

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



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

下面是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); //获取线程的状态,包括signal和pid等

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

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

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

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文件。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: