|  | @@ -42,11 +42,14 @@ typedef Elf32_Off	Elf_Off;
 | 
		
	
		
			
			| 42 | 42 |   *
 | 
		
	
		
			
			| 43 | 43 |   * @v image		ELF file
 | 
		
	
		
			
			| 44 | 44 |   * @v phdr		ELF program header
 | 
		
	
		
			
			|  | 45 | + * @v ehdr		ELF executable header
 | 
		
	
		
			
			| 45 | 46 |   * @ret rc		Return status code
 | 
		
	
		
			
			| 46 | 47 |   */
 | 
		
	
		
			
			| 47 |  | -static int elf_load_segment ( struct image *image, Elf_Phdr *phdr ) {
 | 
		
	
		
			
			|  | 48 | +static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
 | 
		
	
		
			
			|  | 49 | +			      Elf_Ehdr *ehdr ) {
 | 
		
	
		
			
			| 48 | 50 |  	physaddr_t dest;
 | 
		
	
		
			
			| 49 | 51 |  	userptr_t buffer;
 | 
		
	
		
			
			|  | 52 | +	unsigned long e_offset;
 | 
		
	
		
			
			| 50 | 53 |  	int rc;
 | 
		
	
		
			
			| 51 | 54 |  
 | 
		
	
		
			
			| 52 | 55 |  	/* Do nothing for non-PT_LOAD segments */
 | 
		
	
	
		
			
			|  | @@ -55,7 +58,7 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr ) {
 | 
		
	
		
			
			| 55 | 58 |  
 | 
		
	
		
			
			| 56 | 59 |  	/* Check segment lies within image */
 | 
		
	
		
			
			| 57 | 60 |  	if ( ( phdr->p_offset + phdr->p_filesz ) > image->len ) {
 | 
		
	
		
			
			| 58 |  | -		DBG ( "ELF segment outside ELF file\n" );
 | 
		
	
		
			
			|  | 61 | +		DBGC ( image, "ELF %p segment outside image\n", image );
 | 
		
	
		
			
			| 59 | 62 |  		return -ENOEXEC;
 | 
		
	
		
			
			| 60 | 63 |  	}
 | 
		
	
		
			
			| 61 | 64 |  
 | 
		
	
	
		
			
			|  | @@ -67,26 +70,43 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr ) {
 | 
		
	
		
			
			| 67 | 70 |  	if ( ! dest )
 | 
		
	
		
			
			| 68 | 71 |  		dest = phdr->p_vaddr;
 | 
		
	
		
			
			| 69 | 72 |  	if ( ! dest ) {
 | 
		
	
		
			
			| 70 |  | -		DBG ( "ELF segment loads to physical address 0\n" );
 | 
		
	
		
			
			|  | 73 | +		DBGC ( image, "ELF %p segment loads to physical address 0\n",
 | 
		
	
		
			
			|  | 74 | +		       image );
 | 
		
	
		
			
			| 71 | 75 |  		return -ENOEXEC;
 | 
		
	
		
			
			| 72 | 76 |  	}
 | 
		
	
		
			
			| 73 | 77 |  	buffer = phys_to_user ( dest );
 | 
		
	
		
			
			| 74 | 78 |  
 | 
		
	
		
			
			| 75 |  | -	DBG ( "ELF loading segment [%x,%x) to [%x,%x,%x)\n",
 | 
		
	
		
			
			| 76 |  | -	      phdr->p_offset, ( phdr->p_offset + phdr->p_filesz ),
 | 
		
	
		
			
			| 77 |  | -	      phdr->p_paddr, ( phdr->p_paddr + phdr->p_filesz ),
 | 
		
	
		
			
			| 78 |  | -	      ( phdr->p_paddr + phdr->p_memsz ) );
 | 
		
	
		
			
			|  | 79 | +	DBGC ( image, "ELF %p loading segment [%x,%x) to [%x,%x,%x)\n", image,
 | 
		
	
		
			
			|  | 80 | +	       phdr->p_offset, ( phdr->p_offset + phdr->p_filesz ),
 | 
		
	
		
			
			|  | 81 | +	       phdr->p_paddr, ( phdr->p_paddr + phdr->p_filesz ),
 | 
		
	
		
			
			|  | 82 | +	       ( phdr->p_paddr + phdr->p_memsz ) );
 | 
		
	
		
			
			| 79 | 83 |  
 | 
		
	
		
			
			| 80 | 84 |  	/* Verify and prepare segment */
 | 
		
	
		
			
			| 81 | 85 |  	if ( ( rc = prep_segment ( buffer, phdr->p_filesz,
 | 
		
	
		
			
			| 82 | 86 |  				   phdr->p_memsz ) ) != 0 ) {
 | 
		
	
		
			
			| 83 |  | -		DBG ( "ELF could not prepare segment: %s\n", strerror ( rc ) );
 | 
		
	
		
			
			|  | 87 | +		DBGC ( image, "ELF %p could not prepare segment: %s\n",
 | 
		
	
		
			
			|  | 88 | +		       image, strerror ( rc ) );
 | 
		
	
		
			
			| 84 | 89 |  		return rc;
 | 
		
	
		
			
			| 85 | 90 |  	}
 | 
		
	
		
			
			| 86 | 91 |  
 | 
		
	
		
			
			| 87 | 92 |  	/* Copy image to segment */
 | 
		
	
		
			
			| 88 | 93 |  	memcpy_user ( buffer, 0, image->data, phdr->p_offset, phdr->p_filesz );
 | 
		
	
		
			
			| 89 | 94 |  
 | 
		
	
		
			
			|  | 95 | +	/* Set execution address, if it lies within this segment */
 | 
		
	
		
			
			|  | 96 | +	if ( ( e_offset = ( ehdr->e_entry - dest ) ) < phdr->p_filesz ) {
 | 
		
	
		
			
			|  | 97 | +		image->priv.phys = ehdr->e_entry;
 | 
		
	
		
			
			|  | 98 | +		DBGC ( image, "ELF %p found physical entry point at %lx\n",
 | 
		
	
		
			
			|  | 99 | +		       image, image->priv.phys );
 | 
		
	
		
			
			|  | 100 | +	} else if ( ( e_offset = ( ehdr->e_entry - phdr->p_vaddr ) )
 | 
		
	
		
			
			|  | 101 | +		    < phdr->p_filesz ) {
 | 
		
	
		
			
			|  | 102 | +		if ( ! image->priv.phys ) {
 | 
		
	
		
			
			|  | 103 | +			image->priv.phys = ( dest + e_offset );
 | 
		
	
		
			
			|  | 104 | +			DBGC ( image, "ELF %p found virtual entry point at %lx"
 | 
		
	
		
			
			|  | 105 | +			       " (virt %lx)\n", image, image->priv.phys,
 | 
		
	
		
			
			|  | 106 | +			       ( ( unsigned long ) ehdr->e_entry ) );
 | 
		
	
		
			
			|  | 107 | +		}
 | 
		
	
		
			
			|  | 108 | +	}
 | 
		
	
		
			
			|  | 109 | +
 | 
		
	
		
			
			| 90 | 110 |  	return 0;
 | 
		
	
		
			
			| 91 | 111 |  }
 | 
		
	
		
			
			| 92 | 112 |  
 | 
		
	
	
		
			
			|  | @@ -109,25 +129,32 @@ int elf_load ( struct image *image ) {
 | 
		
	
		
			
			| 109 | 129 |  	/* Read ELF header */
 | 
		
	
		
			
			| 110 | 130 |  	copy_from_user ( &ehdr, image->data, 0, sizeof ( ehdr ) );
 | 
		
	
		
			
			| 111 | 131 |  	if ( memcmp ( &ehdr.e_ident[EI_MAG0], ELFMAG, SELFMAG ) != 0 ) {
 | 
		
	
		
			
			| 112 |  | -		DBG ( "Invalid ELF signature\n" );
 | 
		
	
		
			
			|  | 132 | +		DBGC ( image, "ELF %p has invalid signature\n", image );
 | 
		
	
		
			
			| 113 | 133 |  		return -ENOEXEC;
 | 
		
	
		
			
			| 114 | 134 |  	}
 | 
		
	
		
			
			| 115 | 135 |  
 | 
		
	
		
			
			|  | 136 | +	/* Invalidate execution address */
 | 
		
	
		
			
			|  | 137 | +	image->priv.phys = 0;
 | 
		
	
		
			
			|  | 138 | +
 | 
		
	
		
			
			| 116 | 139 |  	/* Read ELF program headers */
 | 
		
	
		
			
			| 117 | 140 |  	for ( phoff = ehdr.e_phoff , phnum = ehdr.e_phnum ; phnum ;
 | 
		
	
		
			
			| 118 | 141 |  	      phoff += ehdr.e_phentsize, phnum-- ) {
 | 
		
	
		
			
			| 119 | 142 |  		if ( phoff > image->len ) {
 | 
		
	
		
			
			| 120 |  | -			DBG ( "ELF program header %d outside ELF image\n",
 | 
		
	
		
			
			| 121 |  | -			      phnum );
 | 
		
	
		
			
			|  | 143 | +			DBGC ( image, "ELF %p program header %d outside "
 | 
		
	
		
			
			|  | 144 | +			       "image\n", image, phnum );
 | 
		
	
		
			
			| 122 | 145 |  			return -ENOEXEC;
 | 
		
	
		
			
			| 123 | 146 |  		}
 | 
		
	
		
			
			| 124 | 147 |  		copy_from_user ( &phdr, image->data, phoff, sizeof ( phdr ) );
 | 
		
	
		
			
			| 125 |  | -		if ( ( rc = elf_load_segment ( image, &phdr ) ) != 0 )
 | 
		
	
		
			
			|  | 148 | +		if ( ( rc = elf_load_segment ( image, &phdr, &ehdr ) ) != 0 )
 | 
		
	
		
			
			| 126 | 149 |  			return rc;
 | 
		
	
		
			
			| 127 | 150 |  	}
 | 
		
	
		
			
			| 128 | 151 |  
 | 
		
	
		
			
			| 129 |  | -	/* Record execution entry point in image private data field */
 | 
		
	
		
			
			| 130 |  | -	image->priv.phys = ehdr.e_entry;
 | 
		
	
		
			
			|  | 152 | +	/* Check for a valid execution address */
 | 
		
	
		
			
			|  | 153 | +	if ( ! image->priv.phys ) {
 | 
		
	
		
			
			|  | 154 | +		DBGC ( image, "ELF %p entry point %lx outside image\n",
 | 
		
	
		
			
			|  | 155 | +		       image, ( ( unsigned long ) ehdr.e_entry ) );
 | 
		
	
		
			
			|  | 156 | +		return -ENOEXEC;
 | 
		
	
		
			
			|  | 157 | +	}
 | 
		
	
		
			
			| 131 | 158 |  
 | 
		
	
		
			
			| 132 | 159 |  	return 0;
 | 
		
	
		
			
			| 133 | 160 |  }
 |