Coredump Format

Table of Contents

1. Coredump Format

coredump 是一个 elf 文件, 但它并不包含任何 section, 只包含了几个 segment, 用来保存寄存器, vma 等信息.

1.1. Format

它的格式大约是:

Ehdr
  struct Elf32_Ehdr {
    unsigned char e_ident[EI_NIDENT]; // ELF magic
    Elf32_Half	e_type;  // ET_CORE
    Elf32_Half	e_machine;  // EM_ARM ...
    Elf32_Word	e_version;
    Elf32_Addr	e_entry; // elf entry, coredump 不包含该信息, 所以为 0
    Elf32_Off	e_phoff; // 后面 program header 相对于文件的 offset,
                         // 一般来说 program header 紧接在 elf header, 包含多个 program header entry, 所以它的值一般为 sizeof(Elf32_Ehdr)
    Elf32_Off	e_shoff; // coredump 不包含 segment, 所以这里为 0
    Elf32_Word	e_flags;
    Elf32_Half	e_ehsize; // elf header 的大小, 一般为 sizoef(ELf32_Ehdr)
    Elf32_Half	e_phentsize; // 一个 program header entry 的大小, 一般为 sizeof(Elf32_Phdr)
    Elf32_Half	e_phnum;   // 包含多少个 program header entry (即包含多少个 segment)
    Elf32_Half	e_shentsize; // section header 的大小, coredump 中为 0
    Elf32_Half	e_shnum;
    Elf32_Half	e_shstrndx;
  }
------------------------------
Phdr
  // 第一个 program header entry, 一般类型为 PT_NOTE
  typedef struct {
    Elf32_Word	p_type;        // 对应的 segment 的类型, coredump 中一般包含一个 PT_NOTE 类型的 segment 和 N 个 PT_LOAD 类型的 segment
                               // 其中 PT_NOTE segment 用来保存 note 信息 (寄存器, proc 信息, mapping 信息), PT_LOAD 用来 dump vma
    Elf32_Off	p_offset;      // 对应的 segment 相对于文件的 offset, 这个 offset 在 phdr 之后, -------------------------------------------------------------+
                               // 在生成 coredump 时, 对 p_offset 的处理是比较麻烦的地方,                                                                    |
                               // 在计算某个 phdr 的 offset 时, 需要知道前面所有的 segment 的 p_filesz, 以确定它的 offset                                    |
    Elf32_Addr	p_vaddr;       // 对于 PT_LOAD 类型的 segment, p_vaddr 和 p_memsz 表示 vma 在内存中被映射的位置, PT_NOTE 类型的 segment 没有这个信息         |
    Elf32_Addr	p_paddr;                                                                                                                                     |
    Elf32_Word	p_filesz;      // 若 segment 有内容保存在 coredump 中, 则 p_offset 和 p_filesz 表示 segment 在文件中保存的位置, 使用 coredump 时             |
                               // 可以根据这两个值从 coredump 中读取 segment 的内容. PT_NOTE 的内容一定会保存在 coredump 文件中, 但 PT_LOAD 的内容不         |
                               // 一定, 例如, 一般来说, 以 VM_SHARED 方式映射 so 的 vma 是不需要保存在 coredump 中的, 因为可以从原始的 so 获得它的内容,      |
                               // 另外, madvise(DONT_DUMP) 的 vma 也不会保存在 coredump 中                                                                   |
    Elf32_Word	p_memsz;                                                                                                                                     |
    Elf32_Word	p_flags;       // 对于 PT_LOAD, 表示 vma 的权限                                                                                              |
    Elf32_Word	p_align;        // PT_LOAD 类型的 segment header 需要是 PAGE_SIZE align, 所以 p_align 会是 PAGE_SIZE                                         |
  } Elf32_Phdr;                                                                                                                                              |
  // 第二个 program header entry, 一般类型为 PT_LOAD, 对应一个 vma 的信息                                                                                    |
  // 这里要求 PAGE_SIZE 对齐                                                                                                                                 |
  typedef struct {                                                                                                                                           |
    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;                                                                                                                   |                          |
  ...                                                                                                                             |                          |
------------------------------                                                                                                    |                          |
Segment                                                                                                                           |                          |
  note segment    <---------------------------------------------------------------------------------------------------------------+--------------------------+
    // note segment 包含多个 note, 每个 note 包含 Nhdr, name 和 desc                                                              |
    Elf32_Nhdr                                                                                                                    |
      typedef struct {                                                                                                            |
        Elf32_Word n_namesz;  // note 名字的长度, 一般来说均为 name 均为 "CORE", 所以长度为 5                                     |
        Elf32_Word n_descsz;  // note desc 的长度                                                                                 |
        Elf32_Word n_type;    // note 类型, coredump 中一般会用来如下几个类型: NT_PRSTATUS, NT_PRPSINFO, NT_AUXV 和 NT_FILE       |
      } Elf32_Nhdr;                                                                                                               |
      name // 4 bytes 对齐                                                                                                        |
      desc // 4 bytes 对齐                                                                                                        |
    ... // 其它的 note                                                                                                            |
  vma segment 1    <--------------------------------------------------------------------------------------------------------------+

  vma segment 2

  ...

1.2. Note

coredump 中最重要的内容是各种 note 信息

1.2.1. NT_PRSTATUS

NT_PRSTATUS 的 desc 部分的结构与 struct elf_prstatus 一致:

struct elf_prstatus {
    struct elf_siginfo pr_info; /* 产生 coredump 的信号 */
  short int pr_cursig;
    unsigned long int pr_sigpend;
    unsigned long int pr_sighold;
    pid_t pr_pid;               /* tid */
    pid_t pr_ppid;
    pid_t pr_pgrp;
    pid_t pr_sid;
    struct timeval pr_utime;
    struct timeval pr_stime;
    struct timeval pr_cutime;
    struct timeval pr_cstime;
    elf_gregset_t pr_reg;       /* coredump 时各个寄存器的值, 和
                                 * sighandler 的 ucontext 中的值是一致
                                 * 的 */
    int pr_fpvalid;
};

每个 prstatus 表示一个线程的状态, 所以多线程的进程产生的 coredump 会包含多个 prstatus

1.2.2. NT_PRPSINFO

NT_PRPSINFO 的 desc 部分由 struct elf_prpsinfo 表示:

struct elf_prpsinfo {
    char pr_state;
    char pr_sname;
    char pr_zomb;
    char pr_nice;
    unsigned long int pr_flag;
    unsigned int pr_uid;
    unsigned int pr_gid;
    int pr_pid, pr_ppid, pr_pgrp, pr_sid;
    char pr_fname[16];          /* exec 的名字 */
    char pr_psargs[ELF_PRARGSZ]; /* args, 格式为 "argv1[space]argv2[space]..." */
};

1.2.3. NT_AUXV

NT_AUXV 表示 auxiliary vector, 使用 gdb info aux 查看, 其格式为 uintptr_t auxv[], 数组中依次保存着 key1, val1, key2, val2 …

1.2.4. NT_FILE

NT_FILE 保存 mapping 信息, 使用 gdb 的 info proc mapping 可以查看, 其格式为:

long count     -- how many files are mapped
long page_size -- units for file offset
array of [COUNT] elements of
  long start
  long end
  long file offset
followed by COUNT filenames in ASCII: "FILE1" NUL "FILE2" NUL...

1.3. 参考

  1. qemu elfload.c
  2. kernel elf_core_dump

Author: [email protected]
Date: 2017-04-25 Tue 00:00
Last updated: 2022-02-06 Sun 21:58

知识共享许可协议