[原创]转载请注明来源于CSDN _xiao。
Linux异常时会生成Coredump文件用于调试和分析,Coredump文件在嵌入式工作中对死机问题的帮助是非常大的。网上有很多生成core文件的配置方法,但却很少涉及core文件的数据格式,这里通过linux的源码走读尝试解读Coredump文件的格式。
Coredump文件的整体格式是ELF格式,但在ELF格式定义中对Core子类别的定义是开放的,由各架构自己定义,因此Core文件在不同的体系中格式是有差别的。这里主要说明Linux下生成的Core文件,另外我们在工作中通常接触的指令架构是ARM和MIPS。
Coredump文件按ELF格式组织,不过它只有Executing View,没有Linking View,也就是只有Program Headers,没有Section Heders。所以用readelf命令查看时只能看到Segments而看不到Sections。异常产生时,Linux将死机进程的内存段的内容以Segment的形式保存到Coredump文件中(包括数据区,堆栈区,已分配的堆内容,以及死机时的帧结构数据等),对于代码段(属性为RX,即只读可执行的段),Linux不保存其内容,只保存代码段的地址信息;其它如线程信息、寄存器信息等辅助信息则保存在类型为PT_NOTE的Segment段中。所以使用GDB工具查看时,需要原始的可执行文件来恢复代码区的内容。
Linux生成Coredump的相关代码在3.1.10\fs\binfmt_elf.c中。
从函数elf_core_dump看起。首先申请空间存放elfhdr文件头,然后通过current->mm->map_count得到当前进程已映射的内存段数量,计算core文件中需要生成的segment数量,这里会多保留一个segment供PT_NOTE使用。然后调用fill_note_info填充note段信息。在fill_note_info里,先将所有的task放到info->thread_list链表中,然后遍历该链表,对每一个thread调用elf_dump_thread_status来保存该线程的状态。在elf_dump_thread_status中,先调用fill_prstatus获取线程状态,这包括收到的signal(对死机线程而言就是引起coredump的信号了),pending和hold的signal,线程的pid,pgrp,ppid等各种数据。再调用elf_core_copy_task_regs获取线程的寄存器,这里对ARM和MIPS会调用各自的函数来保存寄存器,例如MIPS会调用3.1.10\arch\mips\kernel\binfmt_elfo32.c里的elf32_core_copy_regs函数来获取MIPS寄存器的内容,再调用elf_core_copy_task_fpregs获取线程的浮点寄存器内容,在获取完信息后都会调用fill_note将这些信息放到类型为memelfnote的notes数组中(后面会利用这个notes数组再将所有信息保存到PT_NOTE段中)。回到elf_core_dump,现在获得了所有的note,所以可以计算出整个note段的大小,以及计算所有Program Header的地址信息了。填充elf头,为所有的Program header申