static int writenote(struct memelfnote *men, struct file *file) { struct elf_note en; en.n_namesz = strlen(men->name); en.n_descsz = men->datasz; en.n_type = men->type; DUMP_WRITE(&en, sizeof(en)); DUMP_WRITE(men->name, en.n_namesz); /* XXX - cast from long long to long to avoid need for libgcc.a */ DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */ DUMP_WRITE(men->data, men->datasz); DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */ return 1; }
/* * Actual dumper * * This is a two-pass process; first we find the offsets of the bits, * and then they are actually written out. If we run out of core limit * we just truncate. */ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file) { int has_dumped = 0; mm_segment_t fs; int segs; size_t size = 0; int i; struct vm_area_struct *vma; struct elfhdr elf; off_t offset = 0, dataoff; unsigned long limit = current->rlim[RLIMIT_CORE].rlim_cur; int numnote = 4; struct memelfnote notes[4]; struct elf_prstatus prstatus; /* NT_PRSTATUS */ elf_fpregset_t fpu; /* NT_PRFPREG */ struct elf_prpsinfo psinfo; /* NT_PRPSINFO */ /* first copy the parameters from user space */ memset(&psinfo, 0, sizeof(psinfo)); { unsigned int i, len; len = current->mm->arg_end - current->mm->arg_start; if (len >= ELF_PRARGSZ) len = ELF_PRARGSZ-1; copy_from_user(&psinfo.pr_psargs, (const char *)current->mm->arg_start, len); for(i = 0; i < len; i++) if (psinfo.pr_psargs[i] == 0) psinfo.pr_psargs[i] = ' '; psinfo.pr_psargs[len] = 0; } memset(&prstatus, 0, sizeof(prstatus)); /* * This transfers the registers from regs into the standard * coredump arrangement, whatever that is. */ #ifdef ELF_CORE_COPY_REGS ELF_CORE_COPY_REGS(prstatus.pr_reg, regs) #else if (sizeof(elf_gregset_t) != sizeof(struct pt_regs)) { printk("sizeof(elf_gregset_t) (%ld) != sizeof(struct pt_regs) (%ld)\n", (long)sizeof(elf_gregset_t), (long)sizeof(struct pt_regs)); } else *(struct pt_regs *)&prstatus.pr_reg = *regs; #endif /* now stop all vm operations */ down_write(¤t->mm->mmap_sem); segs = current->mm->map_count; #ifdef DEBUG printk("elf_core_dump: %d segs %lu limit\n", segs, limit); #endif /* Set up header */ 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; memset(elf.e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD); elf.e_type = ET_CORE; elf.e_machine = ELF_ARCH; elf.e_version = EV_CURRENT; elf.e_entry = 0; elf.e_phoff = sizeof(elf); elf.e_shoff = 0; #ifdef ELF_CORE_EFLAGS elf.e_flags = ELF_CORE_EFLAGS; #else elf.e_flags = 0; #endif elf.e_ehsize = sizeof(elf); elf.e_phentsize = sizeof(struct elf_phdr); elf.e_phnum = segs+1; /* Include notes */ elf.e_shentsize = 0; elf.e_shnum = 0; elf.e_shstrndx = 0; fs = get_fs(); set_fs(KERNEL_DS); has_dumped = 1; current->flags |= PF_DUMPCORE; DUMP_WRITE(&elf, sizeof(elf)); offset += sizeof(elf); /* Elf header */ offset += (segs+1) * sizeof(struct elf_phdr); /* Program headers */ /* * Set up the notes in similar form to SVR4 core dumps made * with info from their /proc. */ notes[0].name = "CORE"; notes[0].type = NT_PRSTATUS; notes[0].datasz = sizeof(prstatus); notes[0].data = &prstatus; prstatus.pr_info.si_signo = prstatus.pr_cursig = signr; prstatus.pr_sigpend = current->pending.signal.sig[0]; prstatus.pr_sighold = current->blocked.sig[0]; psinfo.pr_pid = prstatus.pr_pid = current->pid; psinfo.pr_ppid = prstatus.pr_ppid = current->p_pptr->pid; psinfo.pr_pgrp = prstatus.pr_pgrp = current->pgrp; psinfo.pr_sid = prstatus.pr_sid = current->session; prstatus.pr_utime.tv_sec = CT_TO_SECS(current->times.tms_utime); prstatus.pr_utime.tv_usec = CT_TO_USECS(current->times.tms_utime); prstatus.pr_stime.tv_sec = CT_TO_SECS(current->times.tms_stime); prstatus.pr_stime.tv_usec = CT_TO_USECS(current->times.tms_stime); prstatus.pr_cutime.tv_sec = CT_TO_SECS(current->times.tms_cutime); prstatus.pr_cutime.tv_usec = CT_TO_USECS(current->times.tms_cutime); prstatus.pr_cstime.tv_sec = CT_TO_SECS(current->times.tms_cstime); prstatus.pr_cstime.tv_usec = CT_TO_USECS(current->times.tms_cstime); #ifdef DEBUG dump_regs("Passed in regs", (elf_greg_t *)regs); dump_regs("prstatus regs", (elf_greg_t *)&prstatus.pr_reg); #endif notes[1].name = "CORE"; notes[1].type = NT_PRPSINFO; notes[1].datasz = sizeof(psinfo); notes[1].data = &psinfo; i = current->state ? ffz(~current->state) + 1 : 0; psinfo.pr_state = i; psinfo.pr_sname = (i < 0 || i > 5) ? '.' : "RSDZTD"[i]; psinfo.pr_zomb = psinfo.pr_sname == 'Z'; psinfo.pr_nice = task_nice(current); psinfo.pr_flag = current->flags; psinfo.pr_uid = NEW_TO_OLD_UID(current->uid); psinfo.pr_gid = NEW_TO_OLD_GID(current->gid); strncpy(psinfo.pr_fname, current->comm, sizeof(psinfo.pr_fname)); notes[2].name = "CORE"; notes[2].type = NT_TASKSTRUCT; notes[2].datasz = sizeof(*current); notes[2].data = current; /* Try to dump the FPU. */ prstatus.pr_fpvalid = dump_fpu (regs, &fpu); if (!prstatus.pr_fpvalid) { numnote--; } else { notes[3].name = "CORE"; notes[3].type = NT_PRFPREG; notes[3].datasz = sizeof(fpu); notes[3].data = &fpu; } /* Write notes phdr entry */ { struct elf_phdr phdr; int sz = 0; for(i = 0; i < numnote; i++) sz += notesize(¬es[i]); phdr.p_type = PT_NOTE; phdr.p_offset = offset; phdr.p_vaddr = 0; phdr.p_paddr = 0; phdr.p_filesz = sz; phdr.p_memsz = 0; phdr.p_flags = 0; phdr.p_align = 0; offset += phdr.p_filesz; DUMP_WRITE(&phdr, sizeof(phdr)); } /* Page-align dumped data */ dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); /* Write program headers for segments dump */ for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { struct elf_phdr phdr; size_t sz; sz = vma->vm_end - vma->vm_start; phdr.p_type = PT_LOAD; phdr.p_offset = offset; phdr.p_vaddr = vma->vm_start; phdr.p_paddr = 0; phdr.p_filesz = maydump(vma) ? sz : 0; phdr.p_memsz = sz; offset += phdr.p_filesz; phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; if (vma->vm_flags & VM_WRITE) phdr.p_flags |= PF_W; if (vma->vm_flags & VM_EXEC) phdr.p_flags |= PF_X; phdr.p_align = ELF_EXEC_PAGESIZE; DUMP_WRITE(&phdr, sizeof(phdr)); } for(i = 0; i < numnote; i++) if (!writenote(¬es[i], file)) goto end_coredump; DUMP_SEEK(dataoff); for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { unsigned long addr; if (!maydump(vma)) continue; #ifdef DEBUG printk("elf_core_dump: writing %08lx-%08lx\n", vma->vm_start, vma->vm_end); #endif for (addr = vma->vm_start; addr < vma->vm_end; addr += PAGE_SIZE) { struct page* page; struct vm_area_struct *vma; if (get_user_pages(current, current->mm, addr, 1, 0, 1, &page, &vma) <= 0) { DUMP_SEEK (file->f_pos + PAGE_SIZE); } else { if (page == ZERO_PAGE(addr)) { DUMP_SEEK (file->f_pos + PAGE_SIZE); } else { void *kaddr; flush_cache_page(vma, addr); kaddr = kmap(page); DUMP_WRITE(kaddr, PAGE_SIZE); flush_page_to_ram(page); kunmap(page); } put_page(page); } } } if ((off_t) file->f_pos != offset) { /* Sanity check */ printk("elf_core_dump: file->f_pos (%ld) != offset (%ld)\n", (off_t) file->f_pos, offset); } end_coredump: set_fs(fs); up_write(¤t->mm->mmap_sem); return has_dumped; }
/* Actual dumper. * * This is a two-pass process; first we find the offsets of the bits, * and then they are actually written out. If we run out of core limit * we just truncate. */ static int irix_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit) { int has_dumped = 0; mm_segment_t fs; int segs; int i; size_t size; struct vm_area_struct *vma; struct elfhdr elf; off_t offset = 0, dataoff; int numnote = 3; struct memelfnote notes[3]; struct elf_prstatus prstatus; /* NT_PRSTATUS */ elf_fpregset_t fpu; /* NT_PRFPREG */ struct elf_prpsinfo psinfo; /* NT_PRPSINFO */ /* Count what's needed to dump, up to the limit of coredump size. */ segs = 0; size = 0; for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { if (maydump(vma)) { int sz = vma->vm_end-vma->vm_start; if (size+sz >= limit) break; else size += sz; } segs++; } pr_debug("irix_core_dump: %d segs taking %d bytes\n", segs, size); /* Set up header. */ memcpy(elf.e_ident, ELFMAG, SELFMAG); elf.e_ident[EI_CLASS] = ELFCLASS32; elf.e_ident[EI_DATA] = ELFDATA2LSB; elf.e_ident[EI_VERSION] = EV_CURRENT; elf.e_ident[EI_OSABI] = ELF_OSABI; memset(elf.e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD); elf.e_type = ET_CORE; elf.e_machine = ELF_ARCH; elf.e_version = EV_CURRENT; elf.e_entry = 0; elf.e_phoff = sizeof(elf); elf.e_shoff = 0; elf.e_flags = 0; elf.e_ehsize = sizeof(elf); elf.e_phentsize = sizeof(struct elf_phdr); elf.e_phnum = segs+1; /* Include notes. */ elf.e_shentsize = 0; elf.e_shnum = 0; elf.e_shstrndx = 0; fs = get_fs(); set_fs(KERNEL_DS); has_dumped = 1; current->flags |= PF_DUMPCORE; DUMP_WRITE(&elf, sizeof(elf)); offset += sizeof(elf); /* Elf header. */ offset += (segs+1) * sizeof(struct elf_phdr); /* Program headers. */ /* Set up the notes in similar form to SVR4 core dumps made * with info from their /proc. */ memset(&psinfo, 0, sizeof(psinfo)); memset(&prstatus, 0, sizeof(prstatus)); notes[0].name = "CORE"; notes[0].type = NT_PRSTATUS; notes[0].datasz = sizeof(prstatus); notes[0].data = &prstatus; prstatus.pr_info.si_signo = prstatus.pr_cursig = signr; prstatus.pr_sigpend = current->pending.signal.sig[0]; prstatus.pr_sighold = current->blocked.sig[0]; psinfo.pr_pid = prstatus.pr_pid = task_pid_vnr(current); psinfo.pr_ppid = prstatus.pr_ppid = task_pid_vnr(current->parent); psinfo.pr_pgrp = prstatus.pr_pgrp = task_pgrp_vnr(current); psinfo.pr_sid = prstatus.pr_sid = task_session_vnr(current); if (thread_group_leader(current)) { /* * This is the record for the group leader. Add in the * cumulative times of previous dead threads. This total * won't include the time of each live thread whose state * is included in the core dump. The final total reported * to our parent process when it calls wait4 will include * those sums as well as the little bit more time it takes * this and each other thread to finish dying after the * core dump synchronization phase. */ jiffies_to_timeval(current->utime + current->signal->utime, &prstatus.pr_utime); jiffies_to_timeval(current->stime + current->signal->stime, &prstatus.pr_stime); } else { jiffies_to_timeval(current->utime, &prstatus.pr_utime); jiffies_to_timeval(current->stime, &prstatus.pr_stime); } jiffies_to_timeval(current->signal->cutime, &prstatus.pr_cutime); jiffies_to_timeval(current->signal->cstime, &prstatus.pr_cstime); if (sizeof(elf_gregset_t) != sizeof(struct pt_regs)) { printk("sizeof(elf_gregset_t) (%d) != sizeof(struct pt_regs) " "(%d)\n", sizeof(elf_gregset_t), sizeof(struct pt_regs)); } else { *(struct pt_regs *)&prstatus.pr_reg = *regs; } notes[1].name = "CORE"; notes[1].type = NT_PRPSINFO; notes[1].datasz = sizeof(psinfo); notes[1].data = &psinfo; i = current->state ? ffz(~current->state) + 1 : 0; psinfo.pr_state = i; psinfo.pr_sname = (i < 0 || i > 5) ? '.' : "RSDZTD"[i]; psinfo.pr_zomb = psinfo.pr_sname == 'Z'; psinfo.pr_nice = task_nice(current); psinfo.pr_flag = current->flags; psinfo.pr_uid = current->uid; psinfo.pr_gid = current->gid; { int i, len; set_fs(fs); len = current->mm->arg_end - current->mm->arg_start; len = len >= ELF_PRARGSZ ? ELF_PRARGSZ : len; (void *) copy_from_user(&psinfo.pr_psargs, (const char __user *)current->mm->arg_start, len); for (i = 0; i < len; i++) if (psinfo.pr_psargs[i] == 0) psinfo.pr_psargs[i] = ' '; psinfo.pr_psargs[len] = 0; set_fs(KERNEL_DS); } strlcpy(psinfo.pr_fname, current->comm, sizeof(psinfo.pr_fname)); /* Try to dump the FPU. */ prstatus.pr_fpvalid = dump_fpu(regs, &fpu); if (!prstatus.pr_fpvalid) { numnote--; } else { notes[2].name = "CORE"; notes[2].type = NT_PRFPREG; notes[2].datasz = sizeof(fpu); notes[2].data = &fpu; } /* Write notes phdr entry. */ { struct elf_phdr phdr; int sz = 0; for (i = 0; i < numnote; i++) sz += notesize(¬es[i]); phdr.p_type = PT_NOTE; phdr.p_offset = offset; phdr.p_vaddr = 0; phdr.p_paddr = 0; phdr.p_filesz = sz; phdr.p_memsz = 0; phdr.p_flags = 0; phdr.p_align = 0; offset += phdr.p_filesz; DUMP_WRITE(&phdr, sizeof(phdr)); } /* Page-align dumped data. */ dataoff = offset = roundup(offset, PAGE_SIZE); /* Write program headers for segments dump. */ for (vma = current->mm->mmap, i = 0; i < segs && vma != NULL; vma = vma->vm_next) { struct elf_phdr phdr; size_t sz; i++; sz = vma->vm_end - vma->vm_start; phdr.p_type = PT_LOAD; phdr.p_offset = offset; phdr.p_vaddr = vma->vm_start; phdr.p_paddr = 0; phdr.p_filesz = maydump(vma) ? sz : 0; phdr.p_memsz = sz; offset += phdr.p_filesz; phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; if (vma->vm_flags & VM_WRITE) phdr.p_flags |= PF_W; if (vma->vm_flags & VM_EXEC) phdr.p_flags |= PF_X; phdr.p_align = PAGE_SIZE; DUMP_WRITE(&phdr, sizeof(phdr)); } for (i = 0; i < numnote; i++) if (!writenote(¬es[i], file)) goto end_coredump; set_fs(fs); DUMP_SEEK(dataoff); for (i = 0, vma = current->mm->mmap; i < segs && vma != NULL; vma = vma->vm_next) { unsigned long addr = vma->vm_start; unsigned long len = vma->vm_end - vma->vm_start; if (!maydump(vma)) continue; i++; pr_debug("elf_core_dump: writing %08lx %lx\n", addr, len); DUMP_WRITE((void __user *)addr, len); } if ((off_t) file->f_pos != offset) { /* Sanity check. */ printk("elf_core_dump: file->f_pos (%ld) != offset (%ld)\n", (off_t) file->f_pos, offset); } end_coredump: set_fs(fs); return has_dumped; }
static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file) { mm_segment_t fs; int has_dumped = 0; unsigned long dump_start, dump_size; struct user dump; #if defined(__alpha__) # define START_DATA(u) (u.start_data) #elif defined(__arm__) # define START_DATA(u) ((u.u_tsize << PAGE_SHIFT) + u.start_code) #elif defined(__sparc__) # define START_DATA(u) (u.u_tsize) #elif defined(__i386__) || defined(__mc68000__) || defined(__arch_um__) # define START_DATA(u) (u.u_tsize << PAGE_SHIFT) #endif #ifdef __sparc__ # define START_STACK(u) ((regs->u_regs[UREG_FP]) & ~(PAGE_SIZE - 1)) #else # define START_STACK(u) (u.start_stack) #endif fs = get_fs(); set_fs(KERNEL_DS); has_dumped = 1; current->flags |= PF_DUMPCORE; strncpy(dump.u_comm, current->comm, sizeof(current->comm)); #ifndef __sparc__ dump.u_ar0 = (void *)(((unsigned long)(&dump.regs)) - ((unsigned long)(&dump))); #endif dump.signal = signr; dump_thread(regs, &dump); /* If the size of the dump file exceeds the rlimit, then see what would happen if we wrote the stack, but not the data area. */ #ifdef __sparc__ if ((dump.u_dsize+dump.u_ssize) > current->rlim[RLIMIT_CORE].rlim_cur) dump.u_dsize = 0; #else if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE > current->rlim[RLIMIT_CORE].rlim_cur) dump.u_dsize = 0; #endif /* Make sure we have enough room to write the stack and data areas. */ #ifdef __sparc__ if ((dump.u_ssize) > current->rlim[RLIMIT_CORE].rlim_cur) dump.u_ssize = 0; #else if ((dump.u_ssize+1) * PAGE_SIZE > current->rlim[RLIMIT_CORE].rlim_cur) dump.u_ssize = 0; #endif /* make sure we actually have a data and stack area to dump */ set_fs(USER_DS); #ifdef __sparc__ if (verify_area(VERIFY_READ, (void *) START_DATA(dump), dump.u_dsize)) dump.u_dsize = 0; if (verify_area(VERIFY_READ, (void *) START_STACK(dump), dump.u_ssize)) dump.u_ssize = 0; #else if (verify_area(VERIFY_READ, (void *) START_DATA(dump), dump.u_dsize << PAGE_SHIFT)) dump.u_dsize = 0; if (verify_area(VERIFY_READ, (void *) START_STACK(dump), dump.u_ssize << PAGE_SHIFT)) dump.u_ssize = 0; #endif set_fs(KERNEL_DS); /* struct user */ DUMP_WRITE(&dump,sizeof(dump)); /* Now dump all of the user data. Include malloced stuff as well */ #ifndef __sparc__ DUMP_SEEK(PAGE_SIZE); #endif /* now we start writing out the user space info */ set_fs(USER_DS); /* Dump the data area */ if (dump.u_dsize != 0) { dump_start = START_DATA(dump); #ifdef __sparc__ dump_size = dump.u_dsize; #else dump_size = dump.u_dsize << PAGE_SHIFT; #endif DUMP_WRITE(dump_start,dump_size); } /* Now prepare to dump the stack area */ if (dump.u_ssize != 0) { dump_start = START_STACK(dump); #ifdef __sparc__ dump_size = dump.u_ssize; #else dump_size = dump.u_ssize << PAGE_SHIFT; #endif DUMP_WRITE(dump_start,dump_size); } /* Finally dump the task struct. Not be used by gdb, but could be useful */ set_fs(KERNEL_DS); DUMP_WRITE(current,sizeof(*current)); end_coredump: set_fs(fs); return has_dumped; }
/* * Actual dumper * * This is a two-pass process; first we find the offsets of the bits, * and then they are actually written out. If we run out of core limit * we just truncate. */ static int elf_core_dump(long signr, struct pt_regs * regs) { int has_dumped = 0; struct file file; struct dentry *dentry; struct inode *inode; mm_segment_t fs; char corefile[6+sizeof(current->comm)]; int segs; int i; size_t size; struct vm_area_struct *vma; struct elfhdr elf; off_t offset = 0, dataoff; unsigned long limit = current->rlim[RLIMIT_CORE].rlim_cur; int numnote = 4; struct memelfnote notes[4]; struct elf_prstatus prstatus; /* NT_PRSTATUS */ elf_fpregset_t fpu; /* NT_PRFPREG */ struct elf_prpsinfo psinfo; /* NT_PRPSINFO */ if (!current->dumpable || limit < ELF_EXEC_PAGESIZE || atomic_read(¤t->mm->count) != 1) return 0; current->dumpable = 0; #ifndef CONFIG_BINFMT_ELF MOD_INC_USE_COUNT; #endif /* Count what's needed to dump, up to the limit of coredump size */ segs = 0; size = 0; for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { if (maydump(vma)) { unsigned long sz = vma->vm_end-vma->vm_start; if (size+sz >= limit) break; else size += sz; } segs++; } #ifdef DEBUG printk("elf_core_dump: %d segs taking %d bytes\n", segs, size); #endif /* Set up header */ 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; memset(elf.e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD); elf.e_type = ET_CORE; elf.e_machine = ELF_ARCH; elf.e_version = EV_CURRENT; elf.e_entry = 0; elf.e_phoff = sizeof(elf); elf.e_shoff = 0; elf.e_flags = 0; elf.e_ehsize = sizeof(elf); elf.e_phentsize = sizeof(struct elf_phdr); elf.e_phnum = segs+1; /* Include notes */ elf.e_shentsize = 0; elf.e_shnum = 0; elf.e_shstrndx = 0; fs = get_fs(); set_fs(KERNEL_DS); memcpy(corefile,"core.",5); #if 0 memcpy(corefile+5,current->comm,sizeof(current->comm)); #else corefile[4] = '\0'; #endif dentry = open_namei(corefile, O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600); if (IS_ERR(dentry)) { dentry = NULL; goto end_coredump; } inode = dentry->d_inode; if(inode->i_nlink > 1) goto end_coredump; /* multiple links - don't dump */ if (!S_ISREG(inode->i_mode)) goto end_coredump; if (!inode->i_op || !inode->i_op->default_file_ops) goto end_coredump; if (init_private_file(&file, dentry, 3)) goto end_coredump; if (!file.f_op->write) goto close_coredump; has_dumped = 1; current->flags |= PF_DUMPCORE; DUMP_WRITE(&elf, sizeof(elf)); offset += sizeof(elf); /* Elf header */ offset += (segs+1) * sizeof(struct elf_phdr); /* Program headers */ /* * Set up the notes in similar form to SVR4 core dumps made * with info from their /proc. */ memset(&psinfo, 0, sizeof(psinfo)); memset(&prstatus, 0, sizeof(prstatus)); notes[0].name = "CORE"; notes[0].type = NT_PRSTATUS; notes[0].datasz = sizeof(prstatus); notes[0].data = &prstatus; prstatus.pr_info.si_signo = prstatus.pr_cursig = signr; prstatus.pr_sigpend = current->signal.sig[0]; prstatus.pr_sighold = current->blocked.sig[0]; psinfo.pr_pid = prstatus.pr_pid = current->pid; psinfo.pr_ppid = prstatus.pr_ppid = current->p_pptr->pid; psinfo.pr_pgrp = prstatus.pr_pgrp = current->pgrp; psinfo.pr_sid = prstatus.pr_sid = current->session; prstatus.pr_utime.tv_sec = CT_TO_SECS(current->times.tms_utime); prstatus.pr_utime.tv_usec = CT_TO_USECS(current->times.tms_utime); prstatus.pr_stime.tv_sec = CT_TO_SECS(current->times.tms_stime); prstatus.pr_stime.tv_usec = CT_TO_USECS(current->times.tms_stime); prstatus.pr_cutime.tv_sec = CT_TO_SECS(current->times.tms_cutime); prstatus.pr_cutime.tv_usec = CT_TO_USECS(current->times.tms_cutime); prstatus.pr_cstime.tv_sec = CT_TO_SECS(current->times.tms_cstime); prstatus.pr_cstime.tv_usec = CT_TO_USECS(current->times.tms_cstime); /* * This transfers the registers from regs into the standard * coredump arrangement, whatever that is. */ #ifdef ELF_CORE_COPY_REGS ELF_CORE_COPY_REGS(prstatus.pr_reg, regs) #else if (sizeof(elf_gregset_t) != sizeof(struct pt_regs)) { printk("sizeof(elf_gregset_t) (%ld) != sizeof(struct pt_regs) (%ld)\n", (long)sizeof(elf_gregset_t), (long)sizeof(struct pt_regs)); } else *(struct pt_regs *)&prstatus.pr_reg = *regs; #endif #ifdef DEBUG dump_regs("Passed in regs", (elf_greg_t *)regs); dump_regs("prstatus regs", (elf_greg_t *)&prstatus.pr_reg); #endif notes[1].name = "CORE"; notes[1].type = NT_PRPSINFO; notes[1].datasz = sizeof(psinfo); notes[1].data = &psinfo; i = current->state ? ffz(~current->state) + 1 : 0; psinfo.pr_state = i; psinfo.pr_sname = (i < 0 || i > 5) ? '.' : "RSDZTD"[i]; psinfo.pr_zomb = psinfo.pr_sname == 'Z'; psinfo.pr_nice = current->priority-15; psinfo.pr_flag = current->flags; psinfo.pr_uid = current->uid; psinfo.pr_gid = current->gid; { int i, len; set_fs(fs); len = current->mm->arg_end - current->mm->arg_start; if (len >= ELF_PRARGSZ) len = ELF_PRARGSZ-1; copy_from_user(&psinfo.pr_psargs, (const char *)current->mm->arg_start, len); for(i = 0; i < len; i++) if (psinfo.pr_psargs[i] == 0) psinfo.pr_psargs[i] = ' '; psinfo.pr_psargs[len] = 0; set_fs(KERNEL_DS); } strncpy(psinfo.pr_fname, current->comm, sizeof(psinfo.pr_fname)); notes[2].name = "CORE"; notes[2].type = NT_TASKSTRUCT; notes[2].datasz = sizeof(*current); notes[2].data = current; /* Try to dump the FPU. */ prstatus.pr_fpvalid = dump_fpu (regs, &fpu); if (!prstatus.pr_fpvalid) { numnote--; } else { notes[3].name = "CORE"; notes[3].type = NT_PRFPREG; notes[3].datasz = sizeof(fpu); notes[3].data = &fpu; } /* Write notes phdr entry */ { struct elf_phdr phdr; int sz = 0; for(i = 0; i < numnote; i++) sz += notesize(¬es[i]); phdr.p_type = PT_NOTE; phdr.p_offset = offset; phdr.p_vaddr = 0; phdr.p_paddr = 0; phdr.p_filesz = sz; phdr.p_memsz = 0; phdr.p_flags = 0; phdr.p_align = 0; offset += phdr.p_filesz; DUMP_WRITE(&phdr, sizeof(phdr)); } /* Page-align dumped data */ dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); /* Write program headers for segments dump */ for(vma = current->mm->mmap, i = 0; i < segs && vma != NULL; vma = vma->vm_next) { struct elf_phdr phdr; size_t sz; i++; sz = vma->vm_end - vma->vm_start; phdr.p_type = PT_LOAD; phdr.p_offset = offset; phdr.p_vaddr = vma->vm_start; phdr.p_paddr = 0; phdr.p_filesz = maydump(vma) ? sz : 0; phdr.p_memsz = sz; offset += phdr.p_filesz; phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; if (vma->vm_flags & VM_WRITE) phdr.p_flags |= PF_W; if (vma->vm_flags & VM_EXEC) phdr.p_flags |= PF_X; phdr.p_align = ELF_EXEC_PAGESIZE; DUMP_WRITE(&phdr, sizeof(phdr)); } for(i = 0; i < numnote; i++) if (!writenote(¬es[i], &file)) goto close_coredump; set_fs(fs); DUMP_SEEK(dataoff); for(i = 0, vma = current->mm->mmap; i < segs && vma != NULL; vma = vma->vm_next) { unsigned long addr = vma->vm_start; unsigned long len = vma->vm_end - vma->vm_start; i++; if (!maydump(vma)) continue; #ifdef DEBUG printk("elf_core_dump: writing %08lx %lx\n", addr, len); #endif DUMP_WRITE((void *)addr, len); } if ((off_t) file.f_pos != offset) { /* Sanity check */ printk("elf_core_dump: file.f_pos (%ld) != offset (%ld)\n", (off_t) file.f_pos, offset); } close_coredump: if (file.f_op->release) file.f_op->release(inode,&file); end_coredump: set_fs(fs); dput(dentry); #ifndef CONFIG_BINFMT_ELF MOD_DEC_USE_COUNT; #endif return has_dumped; }
static inline int do_aout_core_dump(long signr, struct pt_regs * regs) { struct inode * inode = NULL; struct file file; unsigned short fs; int has_dumped = 0; char corefile[6+sizeof(current->comm)]; unsigned long dump_start, dump_size; struct user dump; #ifdef __alpha__ # define START_DATA(u) (u.start_data) #elif defined(CONFIG_ARM) # define START_DATA(u) ((u.u_tsize << PAGE_SHIFT) + u.start_code) #else # define START_DATA(u) (u.u_tsize << PAGE_SHIFT) #endif if (!current->dumpable || current->mm->count != 1) return 0; current->dumpable = 0; /* See if we have enough room to write the upage. */ if (current->rlim[RLIMIT_CORE].rlim_cur < PAGE_SIZE) return 0; fs = get_fs(); set_fs(KERNEL_DS); memcpy(corefile,"core.",5); #if 0 memcpy(corefile+5,current->comm,sizeof(current->comm)); #else corefile[4] = '\0'; #endif if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) { inode = NULL; goto end_coredump; } if (!S_ISREG(inode->i_mode)) goto end_coredump; if (!inode->i_op || !inode->i_op->default_file_ops) goto end_coredump; if (get_write_access(inode)) goto end_coredump; file.f_mode = 3; file.f_flags = 0; file.f_count = 1; file.f_inode = inode; file.f_pos = 0; file.f_reada = 0; file.f_op = inode->i_op->default_file_ops; if (file.f_op->open) if (file.f_op->open(inode,&file)) goto done_coredump; if (!file.f_op->write) goto close_coredump; has_dumped = 1; current->flags |= PF_DUMPCORE; strncpy(dump.u_comm, current->comm, sizeof(current->comm)); dump.u_ar0 = (void *)(((unsigned long)(&dump.regs)) - ((unsigned long)(&dump))); dump.signal = signr; dump_thread(regs, &dump); /* If the size of the dump file exceeds the rlimit, then see what would happen if we wrote the stack, but not the data area. */ if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE > current->rlim[RLIMIT_CORE].rlim_cur) dump.u_dsize = 0; /* Make sure we have enough room to write the stack and data areas. */ if ((dump.u_ssize+1) * PAGE_SIZE > current->rlim[RLIMIT_CORE].rlim_cur) dump.u_ssize = 0; /* make sure we actually have a data and stack area to dump */ set_fs(USER_DS); if (verify_area(VERIFY_READ, (void *) START_DATA(dump), dump.u_dsize << PAGE_SHIFT)) dump.u_dsize = 0; if (verify_area(VERIFY_READ, (void *) dump.start_stack, dump.u_ssize << PAGE_SHIFT)) dump.u_ssize = 0; set_fs(KERNEL_DS); /* struct user */ DUMP_WRITE(&dump,sizeof(dump)); /* Now dump all of the user data. Include malloced stuff as well */ DUMP_SEEK(PAGE_SIZE); /* now we start writing out the user space info */ set_fs(USER_DS); /* Dump the data area */ if (dump.u_dsize != 0) { dump_start = START_DATA(dump); dump_size = dump.u_dsize << PAGE_SHIFT; DUMP_WRITE(dump_start,dump_size); } /* Now prepare to dump the stack area */ if (dump.u_ssize != 0) { dump_start = dump.start_stack; dump_size = dump.u_ssize << PAGE_SHIFT; DUMP_WRITE(dump_start,dump_size); } /* Finally dump the task struct. Not be used by gdb, but could be useful */ set_fs(KERNEL_DS); DUMP_WRITE(current,sizeof(*current)); close_coredump: if (file.f_op->release) file.f_op->release(inode,&file); done_coredump: put_write_access(inode); end_coredump: set_fs(fs); iput(inode); return has_dumped; }
/* Actual dumper. * * This is a two-pass process; first we find the offsets of the bits, * and then they are actually written out. If we run out of core limit * we just truncate. */ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file) { int has_dumped = 0; mm_segment_t fs; int segs; int i; size_t size; struct vm_area_struct *vma; struct elfhdr elf; off_t offset = 0, dataoff; int limit = current->rlim[RLIMIT_CORE].rlim_cur; int numnote = 4; struct memelfnote notes[4]; struct elf_prstatus prstatus; /* NT_PRSTATUS */ elf_fpregset_t fpu; /* NT_PRFPREG */ struct elf_prpsinfo psinfo; /* NT_PRPSINFO */ /* Count what's needed to dump, up to the limit of coredump size. */ segs = 0; size = 0; for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { if (maydump(vma)) { int sz = vma->vm_end-vma->vm_start; if (size+sz >= limit) break; else size += sz; } segs++; } #ifdef DEBUG printk("irix_core_dump: %d segs taking %d bytes\n", segs, size); #endif /* Set up header. */ memcpy(elf.e_ident, ELFMAG, SELFMAG); elf.e_ident[EI_CLASS] = ELFCLASS32; elf.e_ident[EI_DATA] = ELFDATA2LSB; elf.e_ident[EI_VERSION] = EV_CURRENT; memset(elf.e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD); elf.e_type = ET_CORE; elf.e_machine = ELF_ARCH; elf.e_version = EV_CURRENT; elf.e_entry = 0; elf.e_phoff = sizeof(elf); elf.e_shoff = 0; elf.e_flags = 0; elf.e_ehsize = sizeof(elf); elf.e_phentsize = sizeof(struct elf_phdr); elf.e_phnum = segs+1; /* Include notes. */ elf.e_shentsize = 0; elf.e_shnum = 0; elf.e_shstrndx = 0; fs = get_fs(); set_fs(KERNEL_DS); has_dumped = 1; current->flags |= PF_DUMPCORE; DUMP_WRITE(&elf, sizeof(elf)); offset += sizeof(elf); /* Elf header. */ offset += (segs+1) * sizeof(struct elf_phdr); /* Program headers. */ /* Set up the notes in similar form to SVR4 core dumps made * with info from their /proc. */ memset(&psinfo, 0, sizeof(psinfo)); memset(&prstatus, 0, sizeof(prstatus)); notes[0].name = "CORE"; notes[0].type = NT_PRSTATUS; notes[0].datasz = sizeof(prstatus); notes[0].data = &prstatus; prstatus.pr_info.si_signo = prstatus.pr_cursig = signr; prstatus.pr_sigpend = current->pending.signal.sig[0]; prstatus.pr_sighold = current->blocked.sig[0]; psinfo.pr_pid = prstatus.pr_pid = current->pid; psinfo.pr_ppid = prstatus.pr_ppid = current->p_pptr->pid; psinfo.pr_pgrp = prstatus.pr_pgrp = current->pgrp; psinfo.pr_sid = prstatus.pr_sid = current->session; prstatus.pr_utime.tv_sec = CT_TO_SECS(current->times.tms_utime); prstatus.pr_utime.tv_usec = CT_TO_USECS(current->times.tms_utime); prstatus.pr_stime.tv_sec = CT_TO_SECS(current->times.tms_stime); prstatus.pr_stime.tv_usec = CT_TO_USECS(current->times.tms_stime); prstatus.pr_cutime.tv_sec = CT_TO_SECS(current->times.tms_cutime); prstatus.pr_cutime.tv_usec = CT_TO_USECS(current->times.tms_cutime); prstatus.pr_cstime.tv_sec = CT_TO_SECS(current->times.tms_cstime); prstatus.pr_cstime.tv_usec = CT_TO_USECS(current->times.tms_cstime); if (sizeof(elf_gregset_t) != sizeof(struct pt_regs)) { printk("sizeof(elf_gregset_t) (%d) != sizeof(struct pt_regs) " "(%d)\n", sizeof(elf_gregset_t), sizeof(struct pt_regs)); } else { *(struct pt_regs *)&prstatus.pr_reg = *regs; } notes[1].name = "CORE"; notes[1].type = NT_PRPSINFO; notes[1].datasz = sizeof(psinfo); notes[1].data = &psinfo; i = current->state ? ffz(~current->state) + 1 : 0; psinfo.pr_state = i; psinfo.pr_sname = (i < 0 || i > 5) ? '.' : "RSDZTD"[i]; psinfo.pr_zomb = psinfo.pr_sname == 'Z'; psinfo.pr_nice = current->nice; psinfo.pr_flag = current->flags; psinfo.pr_uid = current->uid; psinfo.pr_gid = current->gid; { int i, len; set_fs(fs); len = current->mm->arg_end - current->mm->arg_start; len = len >= ELF_PRARGSZ ? ELF_PRARGSZ : len; copy_from_user(&psinfo.pr_psargs, (const char *)current->mm->arg_start, len); for(i = 0; i < len; i++) if (psinfo.pr_psargs[i] == 0) psinfo.pr_psargs[i] = ' '; psinfo.pr_psargs[len] = 0; set_fs(KERNEL_DS); } strncpy(psinfo.pr_fname, current->comm, sizeof(psinfo.pr_fname)); notes[2].name = "CORE"; notes[2].type = NT_TASKSTRUCT; notes[2].datasz = sizeof(*current); notes[2].data = current; /* Try to dump the FPU. */ prstatus.pr_fpvalid = dump_fpu (&fpu); if (!prstatus.pr_fpvalid) { numnote--; } else { notes[3].name = "CORE"; notes[3].type = NT_PRFPREG; notes[3].datasz = sizeof(fpu); notes[3].data = &fpu; } /* Write notes phdr entry. */ { struct elf_phdr phdr; int sz = 0; for(i = 0; i < numnote; i++) sz += notesize(¬es[i]); phdr.p_type = PT_NOTE; phdr.p_offset = offset; phdr.p_vaddr = 0; phdr.p_paddr = 0; phdr.p_filesz = sz; phdr.p_memsz = 0; phdr.p_flags = 0; phdr.p_align = 0; offset += phdr.p_filesz; DUMP_WRITE(&phdr, sizeof(phdr)); } /* Page-align dumped data. */ dataoff = offset = roundup(offset, PAGE_SIZE); /* Write program headers for segments dump. */ for(vma = current->mm->mmap, i = 0; i < segs && vma != NULL; vma = vma->vm_next) { struct elf_phdr phdr; size_t sz; i++; sz = vma->vm_end - vma->vm_start; phdr.p_type = PT_LOAD; phdr.p_offset = offset; phdr.p_vaddr = vma->vm_start; phdr.p_paddr = 0; phdr.p_filesz = maydump(vma) ? sz : 0; phdr.p_memsz = sz; offset += phdr.p_filesz; phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; if (vma->vm_flags & VM_WRITE) phdr.p_flags |= PF_W; if (vma->vm_flags & VM_EXEC) phdr.p_flags |= PF_X; phdr.p_align = PAGE_SIZE; DUMP_WRITE(&phdr, sizeof(phdr)); } for(i = 0; i < numnote; i++) if (!writenote(¬es[i], file)) goto end_coredump; set_fs(fs); DUMP_SEEK(dataoff); for(i = 0, vma = current->mm->mmap; i < segs && vma != NULL; vma = vma->vm_next) { unsigned long addr = vma->vm_start; unsigned long len = vma->vm_end - vma->vm_start; if (!maydump(vma)) continue; i++; #ifdef DEBUG printk("elf_core_dump: writing %08lx %lx\n", addr, len); #endif DUMP_WRITE((void *)addr, len); } if ((off_t) file->f_pos != offset) { /* Sanity check. */ printk("elf_core_dump: file->f_pos (%ld) != offset (%ld)\n", (off_t) file->f_pos, offset); } end_coredump: set_fs(fs); return has_dumped; }