/*
       * linux/fs/binfmt_elf.c
       *
       * These are the functions used to load ELF format executables as used
       * on SVr4 machines.  Information on the format may be found in the book
       * "UNIX SYSTEM V RELEASE 4 Programmers Guide: Ansi C and Programming Support
       * Tools".
       *
       * Copyright 1993, 1994: Eric Youngdale (ericy@cais.com).
       */
      
      #include <linux/module.h>
      
      #include <linux/fs.h>
      #include <linux/stat.h>
      #include <linux/sched.h>
      #include <linux/mm.h>
      #include <linux/mman.h>
      #include <linux/a.out.h>
      #include <linux/errno.h>
      #include <linux/signal.h>
      #include <linux/binfmts.h>
      #include <linux/string.h>
      #include <linux/file.h>
      #include <linux/fcntl.h>
      #include <linux/ptrace.h>
      #include <linux/malloc.h>
      #include <linux/shm.h>
      #include <linux/personality.h>
      #include <linux/elfcore.h>
      #include <linux/init.h>
      #include <linux/highuid.h>
      #include <linux/smp_lock.h>
      
      #include <asm/uaccess.h>
      #include <asm/param.h>
      #include <asm/pgalloc.h>
      
      #define DLINFO_ITEMS 13
      
      #include <linux/elf.h>
      
      static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs);
      static int load_elf_library(struct file*);
      static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int);
      extern int dump_fpu (struct pt_regs *, elf_fpregset_t *);
      extern void dump_thread(struct pt_regs *, struct user *);
      
      #ifndef elf_addr_t
      #define elf_addr_t unsigned long
      #define elf_caddr_t char *
      #endif
      
      /*
       * If we don't support core dumping, then supply a NULL so we
       * don't even try.
       */
      #ifdef USE_ELF_CORE_DUMP
      static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file);
      #else
      #define elf_core_dump	NULL
      #endif
      
      #if ELF_EXEC_PAGESIZE > PAGE_SIZE
      # define ELF_MIN_ALIGN	ELF_EXEC_PAGESIZE
      #else
      # define ELF_MIN_ALIGN	PAGE_SIZE
      #endif
      
      #define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_MIN_ALIGN-1))
      #define ELF_PAGEOFFSET(_v) ((_v) & (ELF_MIN_ALIGN-1))
      #define ELF_PAGEALIGN(_v) (((_v) + ELF_MIN_ALIGN - 1) & ~(ELF_MIN_ALIGN - 1))
      
      static struct linux_binfmt elf_format = {
      	NULL, THIS_MODULE, load_elf_binary, load_elf_library, elf_core_dump, ELF_EXEC_PAGESIZE
      };
      
  78  static void set_brk(unsigned long start, unsigned long end)
      {
      	start = ELF_PAGEALIGN(start);
      	end = ELF_PAGEALIGN(end);
  82  	if (end <= start)
  83  		return;
      	do_brk(start, end - start);
      }
      
      
      /* We need to explicitly zero any fractional pages
         after the data section (i.e. bss).  This would
         contain the junk from the file that should not
         be in memory */
      
      
  94  static void padzero(unsigned long elf_bss)
      {
      	unsigned long nbyte;
      
      	nbyte = ELF_PAGEOFFSET(elf_bss);
  99  	if (nbyte) {
      		nbyte = ELF_MIN_ALIGN - nbyte;
      		clear_user((void *) elf_bss, nbyte);
      	}
      }
      
      static elf_addr_t * 
 106  create_elf_tables(char *p, int argc, int envc,
      		  struct elfhdr * exec,
      		  unsigned long load_addr,
      		  unsigned long load_bias,
      		  unsigned long interp_load_addr, int ibcs)
      {
      	elf_caddr_t *argv;
      	elf_caddr_t *envp;
      	elf_addr_t *sp, *csp;
      	char *k_platform, *u_platform;
      	long hwcap;
      	size_t platform_len = 0;
      
      	/*
      	 * Get hold of platform and hardware capabilities masks for
      	 * the machine we are running on.  In some cases (Sparc), 
      	 * this info is impossible to get, in others (i386) it is
      	 * merely difficult.
      	 */
      
      	hwcap = ELF_HWCAP;
      	k_platform = ELF_PLATFORM;
      
 129  	if (k_platform) {
      		platform_len = strlen(k_platform) + 1;
      		u_platform = p - platform_len;
      		__copy_to_user(u_platform, k_platform, platform_len);
 133  	} else
      		u_platform = p;
      
      	/*
      	 * Force 16 byte _final_ alignment here for generality.
      	 * Leave an extra 16 bytes free so that on the PowerPC we
      	 * can move the aux table up to start on a 16-byte boundary.
      	 */
      	sp = (elf_addr_t *)((~15UL & (unsigned long)(u_platform)) - 16UL);
      	csp = sp;
      	csp -= ((exec ? DLINFO_ITEMS*2 : 4) + (k_platform ? 2 : 0));
      	csp -= envc+1;
      	csp -= argc+1;
      	csp -= (!ibcs ? 3 : 1);	/* argc itself */
 147  	if ((unsigned long)csp & 15UL)
      		sp -= ((unsigned long)csp & 15UL) / sizeof(*sp);
      
      	/*
      	 * Put the ELF interpreter info on the stack
      	 */
      #define NEW_AUX_ENT(nr, id, val) \
      	  __put_user ((id), sp+(nr*2)); \
      	  __put_user ((val), sp+(nr*2+1)); \
      
      	sp -= 2;
      	NEW_AUX_ENT(0, AT_NULL, 0);
 159  	if (k_platform) {
      		sp -= 2;
      		NEW_AUX_ENT(0, AT_PLATFORM, (elf_addr_t)(unsigned long) u_platform);
      	}
      	sp -= 3*2;
      	NEW_AUX_ENT(0, AT_HWCAP, hwcap);
      	NEW_AUX_ENT(1, AT_PAGESZ, ELF_EXEC_PAGESIZE);
      	NEW_AUX_ENT(2, AT_CLKTCK, CLOCKS_PER_SEC);
      
 168  	if (exec) {
      		sp -= 10*2;
      
      		NEW_AUX_ENT(0, AT_PHDR, load_addr + exec->e_phoff);
      		NEW_AUX_ENT(1, AT_PHENT, sizeof (struct elf_phdr));
      		NEW_AUX_ENT(2, AT_PHNUM, exec->e_phnum);
      		NEW_AUX_ENT(3, AT_BASE, interp_load_addr);
      		NEW_AUX_ENT(4, AT_FLAGS, 0);
      		NEW_AUX_ENT(5, AT_ENTRY, load_bias + exec->e_entry);
      		NEW_AUX_ENT(6, AT_UID, (elf_addr_t) current->uid);
      		NEW_AUX_ENT(7, AT_EUID, (elf_addr_t) current->euid);
      		NEW_AUX_ENT(8, AT_GID, (elf_addr_t) current->gid);
      		NEW_AUX_ENT(9, AT_EGID, (elf_addr_t) current->egid);
      	}
      #undef NEW_AUX_ENT
      
      	sp -= envc+1;
      	envp = (elf_caddr_t *) sp;
      	sp -= argc+1;
      	argv = (elf_caddr_t *) sp;
 188  	if (!ibcs) {
      		__put_user((elf_addr_t)(unsigned long) envp,--sp);
      		__put_user((elf_addr_t)(unsigned long) argv,--sp);
      	}
      
      	__put_user((elf_addr_t)argc,--sp);
      	current->mm->arg_start = (unsigned long) p;
 195  	while (argc-->0) {
      		__put_user((elf_caddr_t)(unsigned long)p,argv++);
      		p += strlen_user(p);
      	}
      	__put_user(NULL, argv);
      	current->mm->arg_end = current->mm->env_start = (unsigned long) p;
 201  	while (envc-->0) {
      		__put_user((elf_caddr_t)(unsigned long)p,envp++);
      		p += strlen_user(p);
      	}
      	__put_user(NULL, envp);
      	current->mm->env_end = (unsigned long) p;
 207  	return sp;
      }
      
      #ifndef elf_map
      
      static inline unsigned long
 213  elf_map (struct file *filep, unsigned long addr, struct elf_phdr *eppnt, int prot, int type)
      {
      	unsigned long map_addr;
      
      	down(¤t->mm->mmap_sem);
      	map_addr = do_mmap(filep, ELF_PAGESTART(addr),
      			   eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), prot, type,
      			   eppnt->p_offset - ELF_PAGEOFFSET(eppnt->p_vaddr));
      	up(¤t->mm->mmap_sem);
 222  	return(map_addr);
      }
      
      #endif /* !elf_map */
      
      /* This is much more generalized than the library routine read function,
         so we keep this separate.  Technically the library read function
         is only provided so that we can read a.out libraries that have
         an ELF header */
      
 232  static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
      				     struct file * interpreter,
      				     unsigned long *interp_load_addr)
      {
      	struct elf_phdr *elf_phdata;
      	struct elf_phdr *eppnt;
      	unsigned long load_addr = 0;
      	int load_addr_set = 0;
      	unsigned long last_bss = 0, elf_bss = 0;
      	unsigned long error = ~0UL;
      	int retval, i, size;
      
      	/* First of all, some simple consistency checks */
      	if (interp_elf_ex->e_type != ET_EXEC &&
 246  	    interp_elf_ex->e_type != ET_DYN)
 247  		goto out;
 248  	if (!elf_check_arch(interp_elf_ex))
 249  		goto out;
 250  	if (!interpreter->f_op || !interpreter->f_op->mmap)
 251  		goto out;
      
      	/*
      	 * If the size of this structure has changed, then punt, since
      	 * we will be doing the wrong thing.
      	 */
 257  	if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr))
 258  		goto out;
      
      	/* Now read in all of the header information */
      
      	size = sizeof(struct elf_phdr) * interp_elf_ex->e_phnum;
 263  	if (size > ELF_MIN_ALIGN)
 264  		goto out;
      	elf_phdata = (struct elf_phdr *) kmalloc(size, GFP_KERNEL);
 266  	if (!elf_phdata)
 267  		goto out;
      
      	retval = kernel_read(interpreter,interp_elf_ex->e_phoff,(char *)elf_phdata,size);
      	error = retval;
 271  	if (retval < 0)
 272  		goto out_close;
      
      	eppnt = elf_phdata;
 275  	for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
 276  	  if (eppnt->p_type == PT_LOAD) {
      	    int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
      	    int elf_prot = 0;
      	    unsigned long vaddr = 0;
      	    unsigned long k, map_addr;
      
 282  	    if (eppnt->p_flags & PF_R) elf_prot =  PROT_READ;
 283  	    if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
 284  	    if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
      	    vaddr = eppnt->p_vaddr;
 286  	    if (interp_elf_ex->e_type == ET_EXEC || load_addr_set)
      	    	elf_type |= MAP_FIXED;
      
      	    map_addr = elf_map(interpreter, load_addr + vaddr, eppnt, elf_prot, elf_type);
      
 291  	    if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
      		load_addr = map_addr - ELF_PAGESTART(vaddr);
      		load_addr_set = 1;
      	    }
      
      	    /*
      	     * Find the end of the file mapping for this phdr, and keep
      	     * track of the largest address we see for this.
      	     */
      	    k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
 301  	    if (k > elf_bss)
      		elf_bss = k;
      
      	    /*
      	     * Do the same thing for the memory mapping - between
      	     * elf_bss and last_bss is the bss section.
      	     */
      	    k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
 309  	    if (k > last_bss)
      		last_bss = k;
      	  }
      	}
      
      	/* Now use mmap to map the library into memory. */
      
      	/*
      	 * Now fill out the bss section.  First pad the last page up
      	 * to the page boundary, and then perform a mmap to make sure
      	 * that there are zero-mapped pages up to and including the 
      	 * last bss page.
      	 */
      	padzero(elf_bss);
      	elf_bss = ELF_PAGESTART(elf_bss + ELF_MIN_ALIGN - 1);	/* What we have mapped so far */
      
      	/* Map the last of the bss segment */
 326  	if (last_bss > elf_bss)
      		do_brk(elf_bss, last_bss - elf_bss);
      
      	*interp_load_addr = load_addr;
      	error = ((unsigned long) interp_elf_ex->e_entry) + load_addr;
      
      out_close:
      	kfree(elf_phdata);
      out:
 335  	return error;
      }
      
 338  static unsigned long load_aout_interp(struct exec * interp_ex,
      			     struct file * interpreter)
      {
      	unsigned long text_data, elf_entry = ~0UL;
      	char * addr;
      	loff_t offset;
      	int retval;
      
      	current->mm->end_code = interp_ex->a_text;
      	text_data = interp_ex->a_text + interp_ex->a_data;
      	current->mm->end_data = text_data;
      	current->mm->brk = interp_ex->a_bss + text_data;
      
 351  	switch (N_MAGIC(*interp_ex)) {
 352  	case OMAGIC:
      		offset = 32;
      		addr = (char *) 0;
 355  		break;
 356  	case ZMAGIC:
 357  	case QMAGIC:
      		offset = N_TXTOFF(*interp_ex);
      		addr = (char *) N_TXTADDR(*interp_ex);
 360  		break;
 361  	default:
 362  		goto out;
      	}
      
      	do_brk(0, text_data);
      	retval = -ENOEXEC;
 367  	if (!interpreter->f_op || !interpreter->f_op->read)
 368  		goto out;
      	retval = interpreter->f_op->read(interpreter, addr, text_data, &offset);
 370  	if (retval < 0)
 371  		goto out;
 372  	flush_icache_range((unsigned long)addr,
      	                   (unsigned long)addr + text_data);
      
      	do_brk(ELF_PAGESTART(text_data + ELF_MIN_ALIGN - 1),
      		interp_ex->a_bss);
      	elf_entry = interp_ex->a_entry;
      
      out:
 380  	return elf_entry;
      }
      
      /*
       * These are the functions used to load ELF style executables and shared
       * libraries.  There is no binary dependent code anywhere else.
       */
      
      #define INTERPRETER_NONE 0
      #define INTERPRETER_AOUT 1
      #define INTERPRETER_ELF 2
      
      
 393  static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
      {
      	struct file *interpreter = NULL; /* to shut gcc up */
       	unsigned long load_addr = 0, load_bias;
      	int load_addr_set = 0;
      	char * elf_interpreter = NULL;
      	unsigned int interpreter_type = INTERPRETER_NONE;
      	unsigned char ibcs2_interpreter = 0;
      	mm_segment_t old_fs;
      	unsigned long error;
      	struct elf_phdr * elf_ppnt, *elf_phdata;
      	unsigned long elf_bss, k, elf_brk;
      	int elf_exec_fileno;
      	int retval, size, i;
      	unsigned long elf_entry, interp_load_addr = 0;
      	unsigned long start_code, end_code, start_data, end_data;
      	struct elfhdr elf_ex;
      	struct elfhdr interp_elf_ex;
        	struct exec interp_ex;
      	char passed_fileno[6];
      
      	/* Get the exec-header */
      	elf_ex = *((struct elfhdr *) bprm->buf);
      
      	retval = -ENOEXEC;
      	/* First of all, some simple consistency checks */
 419  	if (memcmp(elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
 420  		goto out;
      
 422  	if (elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN)
 423  		goto out;
 424  	if (!elf_check_arch(&elf_ex))
 425  		goto out;
 426  	if (!bprm->file->f_op||!bprm->file->f_op->mmap)
 427  		goto out;
      
      	/* Now read in all of the header information */
      
      	retval = -ENOMEM;
      	size = elf_ex.e_phentsize * elf_ex.e_phnum;
 433  	if (size > 65536)
 434  		goto out;
      	elf_phdata = (struct elf_phdr *) kmalloc(size, GFP_KERNEL);
 436  	if (!elf_phdata)
 437  		goto out;
      
      	retval = kernel_read(bprm->file, elf_ex.e_phoff, (char *) elf_phdata, size);
 440  	if (retval < 0)
 441  		goto out_free_ph;
      
      	retval = get_unused_fd();
 444  	if (retval < 0)
 445  		goto out_free_ph;
      	get_file(bprm->file);
      	fd_install(elf_exec_fileno = retval, bprm->file);
      
      	elf_ppnt = elf_phdata;
      	elf_bss = 0;
      	elf_brk = 0;
      
      	start_code = ~0UL;
      	end_code = 0;
      	start_data = 0;
      	end_data = 0;
      
 458  	for (i = 0; i < elf_ex.e_phnum; i++) {
 459  		if (elf_ppnt->p_type == PT_INTERP) {
      			retval = -EINVAL;
 461  		  	if (elf_interpreter)
 462  				goto out_free_dentry;
      
      			/* This is the program interpreter used for
      			 * shared libraries - for now assume that this
      			 * is an a.out format binary
      			 */
      
      			retval = -ENOMEM;
      			elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz,
      							   GFP_KERNEL);
 472  			if (!elf_interpreter)
 473  				goto out_free_file;
      
      			retval = kernel_read(bprm->file, elf_ppnt->p_offset,
      					   elf_interpreter,
      					   elf_ppnt->p_filesz);
 478  			if (retval < 0)
 479  				goto out_free_interp;
      			/* If the program interpreter is one of these two,
      			 * then assume an iBCS2 image. Otherwise assume
      			 * a native linux image.
      			 */
      			if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
 485  			    strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0)
      				ibcs2_interpreter = 1;
      #if 0
      			printk("Using ELF interpreter %s\n", elf_interpreter);
      #endif
      #ifdef __sparc__
      			if (ibcs2_interpreter) {
      				unsigned long old_pers = current->personality;
      				struct exec_domain *old_domain = current->exec_domain;
      				struct exec_domain *new_domain;
      				struct fs_struct *old_fs = current->fs, *new_fs;
      				get_exec_domain(old_domain);
      				atomic_inc(&old_fs->count);
      
      				set_personality(PER_SVR4);
      				interpreter = open_exec(elf_interpreter);
      
      				new_domain = current->exec_domain;
      				new_fs = current->fs;
      				current->personality = old_pers;
      				current->exec_domain = old_domain;
      				current->fs = old_fs;
      				put_exec_domain(new_domain);
      				put_fs_struct(new_fs);
      			} else
      #endif
      			{
      				interpreter = open_exec(elf_interpreter);
      			}
      			retval = PTR_ERR(interpreter);
 515  			if (IS_ERR(interpreter))
 516  				goto out_free_interp;
      			retval = kernel_read(interpreter, 0, bprm->buf, BINPRM_BUF_SIZE);
 518  			if (retval < 0)
 519  				goto out_free_dentry;
      
      			/* Get the exec headers */
      			interp_ex = *((struct exec *) bprm->buf);
      			interp_elf_ex = *((struct elfhdr *) bprm->buf);
      		}
      		elf_ppnt++;
      	}
      
      	/* Some simple consistency checks for the interpreter */
 529  	if (elf_interpreter) {
      		interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
      
      		/* Now figure out which format our binary is */
      		if ((N_MAGIC(interp_ex) != OMAGIC) &&
      		    (N_MAGIC(interp_ex) != ZMAGIC) &&
 535  		    (N_MAGIC(interp_ex) != QMAGIC))
      			interpreter_type = INTERPRETER_ELF;
      
 538  		if (memcmp(interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
      			interpreter_type &= ~INTERPRETER_ELF;
      
      		retval = -ELIBBAD;
 542  		if (!interpreter_type)
 543  			goto out_free_dentry;
      
      		/* Make sure only one type was selected */
      		if ((interpreter_type & INTERPRETER_ELF) &&
 547  		     interpreter_type != INTERPRETER_ELF) {
      			printk(KERN_WARNING "ELF: Ambiguous type, using ELF\n");
      			interpreter_type = INTERPRETER_ELF;
      		}
      	}
      
      	/* OK, we are done with that, now set up the arg stuff,
      	   and then start this sucker up */
      
 556  	if (!bprm->sh_bang) {
      		char * passed_p;
      
 559  		if (interpreter_type == INTERPRETER_AOUT) {
      		  sprintf(passed_fileno, "%d", elf_exec_fileno);
      		  passed_p = passed_fileno;
      
 563  		  if (elf_interpreter) {
      		    retval = copy_strings_kernel(1,&passed_p,bprm);
 565  			if (retval)
 566  				goto out_free_dentry; 
      		    bprm->argc++;
      		  }
      		}
      	}
      
      	/* Flush all traces of the currently running executable */
      	retval = flush_old_exec(bprm);
 574  	if (retval)
 575  		goto out_free_dentry;
      
      	/* OK, This is the point of no return */
      	current->mm->start_data = 0;
      	current->mm->end_data = 0;
      	current->mm->end_code = 0;
      	current->mm->mmap = NULL;
      	current->flags &= ~PF_FORKNOEXEC;
      	elf_entry = (unsigned long) elf_ex.e_entry;
      
      	/* Do this immediately, since STACK_TOP as used in setup_arg_pages
      	   may depend on the personality.  */
 587  	SET_PERSONALITY(elf_ex, ibcs2_interpreter);
      
      	/* Do this so that we can load the interpreter, if need be.  We will
      	   change some of these later */
      	current->mm->rss = 0;
      	setup_arg_pages(bprm); /* XXX: check error */
      	current->mm->start_stack = bprm->p;
      
      	/* Try and get dynamic programs out of the way of the default mmap
      	   base, as well as whatever program they might try to exec.  This
      	   is because the brk will follow the loader, and is not movable.  */
      
      	load_bias = ELF_PAGESTART(elf_ex.e_type==ET_DYN ? ELF_ET_DYN_BASE : 0);
      
      	/* Now we do a little grungy work by mmaping the ELF image into
      	   the correct location in memory.  At this point, we assume that
      	   the image should be loaded at fixed address, not at a variable
      	   address. */
      
      	old_fs = get_fs();
      	set_fs(get_ds());
 608  	for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
      		int elf_prot = 0, elf_flags;
      		unsigned long vaddr;
      
 612  		if (elf_ppnt->p_type != PT_LOAD)
 613  			continue;
      
 615  		if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
 616  		if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
 617  		if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
      
      		elf_flags = MAP_PRIVATE|MAP_DENYWRITE|MAP_EXECUTABLE;
      
      		vaddr = elf_ppnt->p_vaddr;
 622  		if (elf_ex.e_type == ET_EXEC || load_addr_set) {
      			elf_flags |= MAP_FIXED;
      		}
      
      		error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, elf_prot, elf_flags);
      
 628  		if (!load_addr_set) {
      			load_addr_set = 1;
      			load_addr = (elf_ppnt->p_vaddr - elf_ppnt->p_offset);
 631  			if (elf_ex.e_type == ET_DYN) {
      				load_bias += error -
      				             ELF_PAGESTART(load_bias + vaddr);
      				load_addr += error;
      			}
      		}
      		k = elf_ppnt->p_vaddr;
 638  		if (k < start_code) start_code = k;
 639  		if (start_data < k) start_data = k;
      
      		k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
      
 643  		if (k > elf_bss)
      			elf_bss = k;
 645  		if ((elf_ppnt->p_flags & PF_X) && end_code <  k)
      			end_code = k;
 647  		if (end_data < k)
      			end_data = k;
      		k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
 650  		if (k > elf_brk)
      			elf_brk = k;
      	}
      	set_fs(old_fs);
      
      	elf_entry += load_bias;
      	elf_bss += load_bias;
      	elf_brk += load_bias;
      	start_code += load_bias;
      	end_code += load_bias;
      	start_data += load_bias;
      	end_data += load_bias;
      
 663  	if (elf_interpreter) {
 664  		if (interpreter_type == INTERPRETER_AOUT)
      			elf_entry = load_aout_interp(&interp_ex,
      						     interpreter);
 667  		else
      			elf_entry = load_elf_interp(&interp_elf_ex,
      						    interpreter,
      						    &interp_load_addr);
      
      		allow_write_access(interpreter);
      		fput(interpreter);
      		kfree(elf_interpreter);
      
 676  		if (elf_entry == ~0UL) {
      			printk(KERN_ERR "Unable to load interpreter\n");
      			kfree(elf_phdata);
      			send_sig(SIGSEGV, current, 0);
 680  			return 0;
      		}
      	}
      
      	kfree(elf_phdata);
      
 686  	if (interpreter_type != INTERPRETER_AOUT)
      		sys_close(elf_exec_fileno);
      
      	set_binfmt(&elf_format);
      
      	compute_creds(bprm);
      	current->flags &= ~PF_FORKNOEXEC;
      	bprm->p = (unsigned long)
      	  create_elf_tables((char *)bprm->p,
      			bprm->argc,
      			bprm->envc,
      			(interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
      			load_addr, load_bias,
      			interp_load_addr,
      			(interpreter_type == INTERPRETER_AOUT ? 0 : 1));
      	/* N.B. passed_fileno might not be initialized? */
 702  	if (interpreter_type == INTERPRETER_AOUT)
      		current->mm->arg_start += strlen(passed_fileno) + 1;
      	current->mm->start_brk = current->mm->brk = elf_brk;
      	current->mm->end_code = end_code;
      	current->mm->start_code = start_code;
      	current->mm->start_data = start_data;
      	current->mm->end_data = end_data;
      	current->mm->start_stack = bprm->p;
      
      	/* Calling set_brk effectively mmaps the pages that we need
      	 * for the bss and break sections
      	 */
      	set_brk(elf_bss, elf_brk);
      
      	padzero(elf_bss);
      
      #if 0
      	printk("(start_brk) %lx\n" , (long) current->mm->start_brk);
      	printk("(end_code) %lx\n" , (long) current->mm->end_code);
      	printk("(start_code) %lx\n" , (long) current->mm->start_code);
      	printk("(start_data) %lx\n" , (long) current->mm->start_data);
      	printk("(end_data) %lx\n" , (long) current->mm->end_data);
      	printk("(start_stack) %lx\n" , (long) current->mm->start_stack);
      	printk("(brk) %lx\n" , (long) current->mm->brk);
      #endif
      
 728  	if ( current->personality == PER_SVR4 )
      	{
      		/* Why this, you ask???  Well SVr4 maps page 0 as read-only,
      		   and some applications "depend" upon this behavior.
      		   Since we do not have the power to recompile these, we
      		   emulate the SVr4 behavior.  Sigh.  */
      		/* N.B. Shouldn't the size here be PAGE_SIZE?? */
      		down(¤t->mm->mmap_sem);
      		error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC,
      				MAP_FIXED | MAP_PRIVATE, 0);
      		up(¤t->mm->mmap_sem);
      	}
      
      #ifdef ELF_PLAT_INIT
      	/*
      	 * The ABI may specify that certain registers be set up in special
      	 * ways (on i386 %edx is the address of a DT_FINI function, for
      	 * example.  This macro performs whatever initialization to
      	 * the regs structure is required.
      	 */
 748  	ELF_PLAT_INIT(regs);
      #endif
      
 751  	start_thread(regs, elf_entry, bprm->p);
 752  	if (current->ptrace & PT_PTRACED)
      		send_sig(SIGTRAP, current, 0);
      	retval = 0;
      out:
 756  	return retval;
      
      	/* error cleanup */
      out_free_dentry:
      	allow_write_access(interpreter);
      	fput(interpreter);
      out_free_interp:
 763  	if (elf_interpreter)
      		kfree(elf_interpreter);
      out_free_file:
      	sys_close(elf_exec_fileno);
      out_free_ph:
      	kfree(elf_phdata);
 769  	goto out;
      }
      
      /* This is really simpleminded and specialized - we are loading an
         a.out library that is given an ELF header. */
      
 775  static int load_elf_library(struct file *file)
      {
      	struct elf_phdr *elf_phdata;
      	unsigned long elf_bss = 0, bss, len, k;
      	int retval, error, i, j;
      	struct elfhdr elf_ex;
      
      	error = -ENOEXEC;
      	retval = kernel_read(file, 0, (char *) &elf_ex, sizeof(elf_ex));
 784  	if (retval != sizeof(elf_ex))
 785  		goto out;
      
 787  	if (memcmp(elf_ex.e_ident, ELFMAG, SELFMAG) != 0)
 788  		goto out;
      
      	/* First of all, some simple consistency checks */
      	if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
 792  	   !elf_check_arch(&elf_ex) || !file->f_op || !file->f_op->mmap)
 793  		goto out;
      
      	/* Now read in all of the header information */
      
      	j = sizeof(struct elf_phdr) * elf_ex.e_phnum;
 798  	if (j > ELF_MIN_ALIGN)
 799  		goto out;
      
      	error = -ENOMEM;
      	elf_phdata = (struct elf_phdr *) kmalloc(j, GFP_KERNEL);
 803  	if (!elf_phdata)
 804  		goto out;
      
      	/* N.B. check for error return?? */
      	retval = kernel_read(file, elf_ex.e_phoff, (char *) elf_phdata,
      			   sizeof(struct elf_phdr) * elf_ex.e_phnum);
      
      	error = -ENOEXEC;
 811  	for (j = 0, i = 0; i<elf_ex.e_phnum; i++)
 812  		if ((elf_phdata + i)->p_type == PT_LOAD) j++;
 813  	if (j != 1)
 814  		goto out_free_ph;
      
 816  	while (elf_phdata->p_type != PT_LOAD) elf_phdata++;
      
      	/* Now use mmap to map the library into memory. */
      	down(¤t->mm->mmap_sem);
      	error = do_mmap(file,
      			ELF_PAGESTART(elf_phdata->p_vaddr),
      			(elf_phdata->p_filesz +
      			 ELF_PAGEOFFSET(elf_phdata->p_vaddr)),
      			PROT_READ | PROT_WRITE | PROT_EXEC,
      			MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE,
      			(elf_phdata->p_offset -
      			 ELF_PAGEOFFSET(elf_phdata->p_vaddr)));
      	up(¤t->mm->mmap_sem);
 829  	if (error != ELF_PAGESTART(elf_phdata->p_vaddr))
 830  		goto out_free_ph;
      
      	k = elf_phdata->p_vaddr + elf_phdata->p_filesz;
 833  	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;
 839  	if (bss > len)
      		do_brk(len, bss - len);
      	error = 0;
      
      out_free_ph:
      	kfree(elf_phdata);
      out:
 846  	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.
       */
 865  static int dump_write(struct file *file, const void *addr, int nr)
      {
 867  	return file->f_op->write(file, addr, nr, &file->f_pos) == nr;
      }
      
 870  static int dump_seek(struct file *file, off_t off)
      {
 872  	if (file->f_op->llseek) {
 873  		if (file->f_op->llseek(file, off, 0) != off)
 874  			return 0;
 875  	} else
      		file->f_pos = off;
 877  	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.
       */
 887  static inline int maydump(struct vm_area_struct *vma)
      {
 889  	if (!(vma->vm_flags & (VM_READ|VM_WRITE|VM_EXEC)))
 890  		return 0;
      
      	/* Do not dump I/O mapped devices! -DaveM */
 893  	if(vma->vm_flags & VM_IO)
 894  		return 0;
      #if 1
 896  	if (vma->vm_flags & (VM_WRITE|VM_GROWSUP|VM_GROWSDOWN))
 897  		return 1;
 898  	if (vma->vm_flags & (VM_READ|VM_EXEC|VM_EXECUTABLE|VM_SHARED))
 899  		return 0;
      #endif
 901  	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;
      };
      
 915  static int notesize(struct memelfnote *en)
      {
      	int sz;
      
      	sz = sizeof(struct elf_note);
      	sz += roundup(strlen(en->name), 4);
      	sz += roundup(en->datasz, 4);
      
 923  	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)
      
 951  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;
      
 959  	DUMP_WRITE(&en, sizeof(en));
 960  	DUMP_WRITE(men->name, en.n_namesz);
      	/* XXX - cast from long long to long to avoid need for libgcc.a */
 962  	DUMP_SEEK(roundup((unsigned long)file->f_pos, 4));	/* XXX */
 963  	DUMP_WRITE(men->data, men->datasz);
 964  	DUMP_SEEK(roundup((unsigned long)file->f_pos, 4));	/* XXX */
      
 966  	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.
       */
 984  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;
      
1034  	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;
1104  		if (len >= ELF_PRARGSZ)
      			len = ELF_PRARGSZ-1;
      		copy_from_user(&psinfo.pr_psargs,
      			      (const char *)current->mm->arg_start, len);
1108  		for(i = 0; i < len; i++)
1109  			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);
1124  	if (!prstatus.pr_fpvalid)
      	{
      		numnote--;
      	}
1128  	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;
      
1141  		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;
1154  		DUMP_WRITE(&phdr, sizeof(phdr));
      	}
      
      	/* Page-align dumped data */
      	dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
      
      	/* Write program headers for segments dump */
1161  	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;
1175  		if (vma->vm_flags & VM_WRITE) phdr.p_flags |= PF_W;
1176  		if (vma->vm_flags & VM_EXEC) phdr.p_flags |= PF_X;
      		phdr.p_align = ELF_EXEC_PAGESIZE;
      
1179  		DUMP_WRITE(&phdr, sizeof(phdr));
      	}
      
1182  	for(i = 0; i < numnote; i++)
1183  		if (!writenote(¬es[i], file))
1184  			goto end_coredump;
      
      	set_fs(fs);
      
1188  	DUMP_SEEK(dataoff);
      
1190  	for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
      		unsigned long addr;
      
1193  		if (!maydump(vma))
1194  			continue;
      #ifdef DEBUG
      		printk("elf_core_dump: writing %08lx %lx\n", addr, len);
      #endif
      		for (addr = vma->vm_start;
1199  		     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);
      	
1208  			if (!pmd)
1209  				goto end_coredump;
      			pte = pte_alloc(pmd, addr);
1211  			if (!pte)
1212  				goto end_coredump;
      			if (!pte_present(*pte) &&
1214  			    pte_none(*pte)) {
1215  				DUMP_SEEK (file->f_pos + PAGE_SIZE);
1216  			} else {
1217  				DUMP_WRITE((void*)addr, PAGE_SIZE);
      			}
      		}
      	}
      
1222  	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);
1230  	return has_dumped;
      }
      #endif		/* USE_ELF_CORE_DUMP */
      
1234  static int __init init_elf_binfmt(void)
      {
1236  	return register_binfmt(&elf_format);
      }
      
1239  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)