diff --git a/arch/x86/kernel/gencore.c b/arch/x86/kernel/gencore.c index a2009346..19f05843 100644 --- a/arch/x86/kernel/gencore.c +++ b/arch/x86/kernel/gencore.c @@ -3,8 +3,11 @@ #include #include #include +#include #include +#define align32(x) ((((x) + 3) / 4) * 4) + #define DEBUG_PRINT_GENCORE #ifdef DEBUG_PRINT_GENCORE @@ -21,6 +24,184 @@ * of a chunk and its length. */ +/* ELF header */ + +void fill_elf_header(Elf64_Ehdr *eh, int segs) +{ + eh->e_ident[EI_MAG0] = 0x7f; + eh->e_ident[EI_MAG1] = 'E'; + eh->e_ident[EI_MAG2] = 'L'; + eh->e_ident[EI_MAG3] = 'F'; + eh->e_ident[EI_CLASS] = ELFCLASS64; + eh->e_ident[EI_DATA] = ELFDATA2LSB; + eh->e_ident[EI_VERSION] = El_VERSION; + eh->e_ident[EI_OSABI] = ELFOSABI_NONE; + eh->e_ident[EI_ABIVERSION] = El_ABIVERSION_NONE; + eh->e_type = ET_CORE; + eh->e_machine = EM_K10M; + eh->e_version = EV_CURRENT; + eh->e_entry = 0; /* Do we really need this? */ + eh->e_phoff = 64; /* fixed */ + eh->e_shoff = 0; /* no section header */ + eh->e_flags = 0; + eh->e_ehsize = 64; /* fixed */ + eh->e_phentsize = 56; /* fixed */ + eh->e_phnum = segs; + eh->e_shentsize = 0; + eh->e_shnum = 0; + eh->e_shstrndx = 0; +} + +/* prstatus NOTE */ + +int get_prstatus_size(void) +{ + return sizeof(struct note) + align32(sizeof("CORE")) + + align32(sizeof(struct elf_prstatus64)); +} + +void fill_prstatus(struct note *head, struct process *proc, void *regs0) +{ + void *name; + struct elf_prstatus64 *prstatus; + struct x86_regs *regs = regs0; + register unsigned long _r12 asm("r12"); + register unsigned long _r13 asm("r13"); + register unsigned long _r14 asm("r14"); + register unsigned long _r15 asm("r15"); + + head->namesz = sizeof("CORE"); + head->descsz = sizeof(struct elf_prstatus64); + head->type = NT_PRSTATUS; + name = (void *) (head + 1); + memcpy(name, "CORE", sizeof("CORE")); + prstatus = (struct elf_prstatus64 *)(name + align32(sizeof("CORE"))); + +/* + We ignore following entries for now. + + struct elf_siginfo pr_info; + short int pr_cursig; + a8_uint64_t pr_sigpend; + a8_uint64_t pr_sighold; + pid_t pr_pid; + pid_t pr_ppid; + pid_t pr_pgrp; + pid_t pr_sid; + struct prstatus64_timeval pr_utime; + struct prstatus64_timeval pr_stime; + struct prstatus64_timeval pr_cutime; + struct prstatus64_timeval pr_cstime; + */ + + prstatus->pr_reg[0] = _r15; + prstatus->pr_reg[1] = _r14; + prstatus->pr_reg[2] = _r13; + prstatus->pr_reg[3] = _r12; + prstatus->pr_reg[4] = regs->rbp; + prstatus->pr_reg[5] = regs->rbx; + prstatus->pr_reg[6] = regs->r11; + prstatus->pr_reg[7] = regs->r10; + prstatus->pr_reg[8] = regs->r9; + prstatus->pr_reg[9] = regs->r8; + prstatus->pr_reg[10] = regs->rax; + prstatus->pr_reg[11] = regs->rcx; + prstatus->pr_reg[12] = regs->rdx; + prstatus->pr_reg[13] = regs->rsi; + prstatus->pr_reg[14] = regs->rdi; + prstatus->pr_reg[15] = regs->rax; /* ??? */ + prstatus->pr_reg[16] = regs->rip; + prstatus->pr_reg[17] = regs->cs; + prstatus->pr_reg[18] = regs->rflags; + prstatus->pr_reg[19] = regs->rsp; + prstatus->pr_reg[20] = regs->ss; + prstatus->pr_reg[21] = rdmsr(MSR_FS_BASE); + prstatus->pr_reg[22] = rdmsr(MSR_GS_BASE); + /* There is no ds, es, fs and gs. */ + + prstatus->pr_fpvalid = 0; /* We assume no fp */ +} + +/* prpsinfo NOTE */ + +int get_prpsinfo_size(void) +{ + return sizeof(struct note) + align32(sizeof("CORE")) + + align32(sizeof(struct elf_prpsinfo64)); +} + +void fill_prpsinfo(struct note *head, struct process *proc, void *regs) +{ + void *name; + struct elf_prpsinfo64 *prpsinfo; + + head->namesz = sizeof("CORE"); + head->descsz = sizeof(struct elf_prpsinfo64); + head->type = NT_PRPSINFO; + name = (void *) (head + 1); + memcpy(name, "CORE", sizeof("CORE")); + prpsinfo = (struct elf_prpsinfo64 *)(name + align32(sizeof("CORE"))); + + prpsinfo->pr_state = proc->status; + prpsinfo->pr_pid = proc->pid; + +/* + We leave most of the fields unfilled. + + char pr_state; + char pr_sname; + char pr_zomb; + char pr_nice; + a8_uint64_t pr_flag; + unsigned int pr_uid; + unsigned int pr_gid; + int pr_ppid, pr_pgrp, pr_sid; + char pr_fname[16]; + char pr_psargs[ELF_PRARGSZ]; +*/ +} + +/* auxv NOTE */ + +int get_auxv_size(void) +{ + return sizeof(struct note) + align32(sizeof("CORE")) + + sizeof(unsigned long) * AUXV_LEN; +} + +void fill_auxv(struct note *head, struct process *proc, void *regs) +{ + void *name; + void *auxv; + + head->namesz = sizeof("CORE"); + head->descsz = sizeof(unsigned long) * AUXV_LEN; + head->type = NT_AUXV; + name = (void *) (head + 1); + memcpy(name, "CORE", sizeof("CORE")); + auxv = name + align32(sizeof("CORE")); + memcpy(auxv, proc->saved_auxv, sizeof(unsigned long) * AUXV_LEN); +} + +/* whole NOTE segment */ + +int get_note_size(void) +{ + return get_prstatus_size() + get_prpsinfo_size() + + get_auxv_size(); +} + +void fill_note(void *note, struct process *proc, void *regs) +{ + fill_prstatus(note, proc, regs); + note += get_prstatus_size(); + fill_prpsinfo(note, proc, regs); + note += get_prpsinfo_size(); + fill_auxv(note, proc, regs); +} + +/* whole core image */ + int gencore(struct process *proc, void *regs, struct coretable **coretable, int *chunks) { @@ -30,7 +211,7 @@ int gencore(struct process *proc, void *regs, void *note; struct vm_range *range; struct process_vm *vm = proc->vm; - int segs = 1; /* the first one is for NOTES */ + int segs = 1; /* the first one is for NOTE */ int notesize, phsize; unsigned int offset = 0; int i; @@ -43,10 +224,13 @@ int gencore(struct process *proc, void *regs, list_for_each_entry(range, &vm->vm_range_list, list) { dkprintf("start:%x end:%x flag:%x objoff:%x\n", range->start, range->end, range->flag, range->objoff); - if ((range->flag && VR_RESERVED) == 0) - segs++; + /* We omit reserved areas because they are only for + mckernel's internal use. */ + if ((range->flag && VR_RESERVED) != 0) + continue; + segs++; } - dkprintf("we have %d segs including one for NOTES.\n\n", segs); + dkprintf("we have %d segs including one for NOTE.\n\n", segs); { struct vm_regions region = proc->vm->region; @@ -57,7 +241,6 @@ int gencore(struct process *proc, void *regs, dkprintf("map: %x-%x\n", region.map_start, region.map_end); dkprintf("stack: %x-%x\n", region.stack_start, region.stack_end); dkprintf("user: %x-%x\n\n", region.user_start, region.user_end); - } dkprintf("now generate a core file image\n"); @@ -66,37 +249,18 @@ int gencore(struct process *proc, void *regs, #ifndef DUMMY - /* ELF header */ + offset += sizeof(eh); + fill_elf_header(&eh, segs); - eh.e_ident[EI_MAG0] = 0x7f; - eh.e_ident[EI_MAG1] = 'E'; - eh.e_ident[EI_MAG2] = 'L'; - eh.e_ident[EI_MAG3] = 'F'; - eh.e_ident[EI_CLASS] = ELFCLASS64; - eh.e_ident[EI_DATA] = ELFDATA2LSB; - eh.e_ident[EI_VERSION] = El_VERSION; - eh.e_ident[EI_OSABI] = ELFOSABI_NONE; - eh.e_ident[EI_ABIVERSION] = El_ABIVERSION_NONE; - eh.e_type = ET_CORE; - eh.e_machine = EM_K10M; - eh.e_version = EV_CURRENT; - eh.e_entry = 0; /* Do we really need this? */ - eh.e_phoff = 64; /* fixed */ - eh.e_shoff = 0; /* no section header */ - eh.e_flags = 0; - eh.e_ehsize = 64; /* fixed */ - eh.e_phentsize = 56; /* fixed */ - eh.e_phnum = segs; - eh.e_shentsize = 0; - eh.e_shnum = 0; - eh.e_shstrndx = 0; - - offset += 64; - - notesize = 1024; /* dummy */ + notesize = get_note_size(); + note = kmalloc(notesize, IHK_MC_AP_NOWAIT); + if (note == NULL) { + dkprintf("could not alloc NOTE for core.\n"); + goto fail; + } + fill_note(note, proc, regs); /* program header table */ - phsize = sizeof(Elf64_Phdr) * segs; ph = kmalloc(phsize, IHK_MC_AP_NOWAIT); if (ph == NULL) { @@ -107,7 +271,6 @@ int gencore(struct process *proc, void *regs, offset += phsize; /* prgram header for NOTE segment is exceptional */ - ph[0].p_type = PT_NOTE; ph[0].p_flags = 0; ph[0].p_offset = offset; @@ -123,8 +286,10 @@ int gencore(struct process *proc, void *regs, unsigned long flag = range->flag; unsigned long size = range->end - range->start; + if ((range->flag && VR_RESERVED) != 0) + continue; + ph[i].p_type = PT_LOAD; -/* xxx */ ph[i].p_flags = ((flag & VR_PROT_READ) ? PF_R : 0) | ((flag & VR_PROT_WRITE) ? PF_W : 0) | ((flag & VR_PROT_EXEC) ? PF_X : 0); @@ -138,14 +303,6 @@ int gencore(struct process *proc, void *regs, offset += size; } - /* note */ - - note = kmalloc(notesize, IHK_MC_AP_NOWAIT); - if (note == NULL) { - dkprintf("could not alloc note.\n"); - goto fail; - } - /* coretable to send to host */ ct = kmalloc(sizeof(struct coretable) * (segs + 2), IHK_MC_AP_NOWAIT); if (!ct) { @@ -164,6 +321,8 @@ int gencore(struct process *proc, void *regs, i = 3; /* memory segments */ list_for_each_entry(range, &vm->vm_range_list, list) { + if ((range->flag && VR_RESERVED) != 0) + continue; ct[i].addr = virt_to_phys(range->start); ct[i].len = range->end - range->start; i++; diff --git a/arch/x86/kernel/include/elfcore.h b/arch/x86/kernel/include/elfcore.h index 627c9875..23f61efe 100644 --- a/arch/x86/kernel/include/elfcore.h +++ b/arch/x86/kernel/include/elfcore.h @@ -74,12 +74,18 @@ typedef struct { #define PF_W 2 /* writable bit */ #define PF_R 4 /* readable bit */ -typedef struct note { +struct note { Elf64_Xword namesz; Elf64_Xword descsz; Elf64_Xword type; char *contents; /* name char[namesz] and desc[descsz] */ -} Elf64_Nhdr; +}; + +#define NT_PRSTATUS 1 +#define NT_PRFRPREG 2 +#define NT_PRPSINFO 3 +#define NT_AUXV 6 +#define NT_X86_STATE 0x202 #include "elfcoregpl.h" diff --git a/kernel/include/process.h b/kernel/include/process.h index 5bc99fea..d5a7d319 100644 --- a/kernel/include/process.h +++ b/kernel/include/process.h @@ -86,6 +86,8 @@ #include #include +#define AUXV_LEN 12 + struct vm_range { struct list_head list; unsigned long start, end; @@ -184,6 +186,7 @@ struct process { void *pgio_arg; struct fork_tree_node *ftn; + unsigned long saved_auxv[AUXV_LEN]; }; struct process_vm { diff --git a/kernel/process.c b/kernel/process.c index 1c6f75b2..03a60298 100644 --- a/kernel/process.c +++ b/kernel/process.c @@ -1254,6 +1254,9 @@ int init_process_stack(struct process *process, struct program_load_desc *pn, /* set up initial stack frame */ p = (unsigned long *)(stack + minsz); s_ind = -1; + /* auxiliary vector */ + /* If you add/delete entires, then AUXV_LEN should be + increased/decreased. */ p[s_ind--] = 0; /* AT_NULL */ p[s_ind--] = 0; p[s_ind--] = pn->at_entry; /* AT_ENTRY */ @@ -1266,6 +1269,9 @@ int init_process_stack(struct process *process, struct program_load_desc *pn, p[s_ind--] = AT_PHDR; p[s_ind--] = 4096; /* AT_PAGESZ */ p[s_ind--] = AT_PAGESZ; + /* save auxiliary vector for core dump */ + memcpy(process->saved_auxv, &p[s_ind + 1], + sizeof(process->saved_auxv)); p[s_ind--] = 0; /* envp terminating NULL */ /* envp */ for (arg_ind = envc - 1; arg_ind > -1; --arg_ind) {