📄 binfmt_elf.c
字号:
if (k > elf_bss)
elf_bss = k;
padzero(elf_bss);
len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr + ELF_MIN_ALIGN - 1);
bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
if (bss > len)
do_brk(len, bss - len);
error = 0;
out_free_ph:
kfree(elf_phdata);
out:
return error;
}
/*
* Note that some platforms still use traditional core dumps and not
* the ELF core dump. Each platform can select it as appropriate.
*/
#ifdef USE_ELF_CORE_DUMP
/*
* ELF core dumper
*
* Modelled on fs/exec.c:aout_core_dump()
* Jeremy Fitzhardinge <jeremy@sw.oz.au>
*/
/*
* These are the only things you should do on a core-file: use only these
* functions to write out all the necessary info.
*/
static int dump_write(struct file *file, const void *addr, int nr)
{
return file->f_op->write(file, addr, nr, &file->f_pos) == nr;
}
static int dump_seek(struct file *file, off_t off)
{
if (file->f_op->llseek) {
if (file->f_op->llseek(file, off, 0) != off)
return 0;
} else
file->f_pos = off;
return 1;
}
/*
* Decide whether a segment is worth dumping; default is yes to be
* sure (missing info is worse than too much; etc).
* Personally I'd include everything, and use the coredump limit...
*
* I think we should skip something. But I am not sure how. H.J.
*/
static inline int maydump(struct vm_area_struct *vma)
{
if (!(vma->vm_flags & (VM_READ|VM_WRITE|VM_EXEC)))
return 0;
/* Do not dump I/O mapped devices! -DaveM */
if(vma->vm_flags & VM_IO)
return 0;
#if 1
if (vma->vm_flags & (VM_WRITE|VM_GROWSUP|VM_GROWSDOWN))
return 1;
if (vma->vm_flags & (VM_READ|VM_EXEC|VM_EXECUTABLE|VM_SHARED))
return 0;
#endif
return 1;
}
#define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
/* An ELF note in memory */
struct memelfnote
{
const char *name;
int type;
unsigned int datasz;
void *data;
};
static int notesize(struct memelfnote *en)
{
int sz;
sz = sizeof(struct elf_note);
sz += roundup(strlen(en->name), 4);
sz += roundup(en->datasz, 4);
return sz;
}
/* #define DEBUG */
#ifdef DEBUG
static void dump_regs(const char *str, elf_greg_t *r)
{
int i;
static const char *regs[] = { "ebx", "ecx", "edx", "esi", "edi", "ebp",
"eax", "ds", "es", "fs", "gs",
"orig_eax", "eip", "cs",
"efl", "uesp", "ss"};
printk("Registers: %s\n", str);
for(i = 0; i < ELF_NGREG; i++)
{
unsigned long val = r[i];
printk(" %-2d %-5s=%08lx %lu\n", i, regs[i], val, val);
}
}
#endif
#define DUMP_WRITE(addr, nr) \
do { if (!dump_write(file, (addr), (nr))) return 0; } while(0)
#define DUMP_SEEK(off) \
do { if (!dump_seek(file, (off))) return 0; } while(0)
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;
}
#undef DUMP_WRITE
#undef DUMP_SEEK
#define DUMP_WRITE(addr, nr) \
if ((size += (nr)) > limit || !dump_write(file, (addr), (nr))) \
goto end_coredump;
#define DUMP_SEEK(off) \
if (!dump_seek(file, (off))) \
goto end_coredump;
/*
* 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 */
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;
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);
/*
* 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->nice;
psinfo.pr_flag = current->flags;
psinfo.pr_uid = NEW_TO_OLD_UID(current->uid);
psinfo.pr_gid = NEW_TO_OLD_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; 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;
set_fs(fs);
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 %lx\n", addr, len);
#endif
for (addr = vma->vm_start;
addr < vma->vm_end;
addr += PAGE_SIZE) {
pgd_t *pgd;
pmd_t *pmd;
pte_t *pte;
pgd = pgd_offset(vma->vm_mm, addr);
pmd = pmd_alloc(pgd, addr);
if (!pmd)
goto end_coredump;
pte = pte_alloc(pmd, addr);
if (!pte)
goto end_coredump;
if (!pte_present(*pte) &&
pte_none(*pte)) {
DUMP_SEEK (file->f_pos + PAGE_SIZE);
} else {
DUMP_WRITE((void*)addr, PAGE_SIZE);
}
}
}
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;
}
#endif /* USE_ELF_CORE_DUMP */
static int __init init_elf_binfmt(void)
{
return register_binfmt(&elf_format);
}
static void __exit exit_elf_binfmt(void)
{
/* Remove the COFF and ELF loaders. */
unregister_binfmt(&elf_format);
}
module_init(init_elf_binfmt)
module_exit(exit_elf_binfmt)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -