Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*
     28  * ELFCLASS specific code for elfedit, built once for each class
     29  */
     30 #include	<stdlib.h>
     31 #include	<stdio.h>
     32 #include	<unistd.h>
     33 #include	<_machelf.h>
     34 #include	<libelf.h>
     35 #include	<strings.h>
     36 #include	<sgs.h>
     37 #include	"msg.h"
     38 #include	"_elfedit.h"
     39 
     40 
     41 
     42 /*
     43  * Look up the elfedit_symtab_t that corresponds to the symbol table
     44  * referenced by the sh_link field of the given auxiliary section.
     45  *
     46  * entry:
     47  *	obj_state - Partially constructed object state from
     48  *		elfedit_init_obj_state().
     49  *	auxsec - Section that is associated with the symbol table section
     50  *
     51  * exit:
     52  *	Returns the pointer to the elfedit_symtab_t entry that is
     53  *	referenced by the auxiliary section. If not found,
     54  *	outputs a debug message, and returns NULL.
     55  */
     56 static elfedit_symtab_t *
     57 get_symtab(elfedit_obj_state_t *obj_state, elfedit_section_t *auxsec)
     58 {
     59 	elfedit_symtab_t *symtab = obj_state->os_symtab;
     60 	Word	sh_link = auxsec->sec_shdr->sh_link;
     61 	Word	i;
     62 
     63 	for (i = 0; i < obj_state->os_symtabnum; i++, symtab++)
     64 		if (symtab->symt_shndx == sh_link)
     65 			return (symtab);
     66 
     67 	/*
     68 	 * If we don't return above, it doesn't reference a valid
     69 	 * symbol table. Issue warning.
     70 	 */
     71 	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_AUX_LINK),
     72 	    EC_WORD(auxsec->sec_shndx), auxsec->sec_name,
     73 	    EC_WORD(sh_link));
     74 
     75 	return (NULL);
     76 }
     77 
     78 
     79 /*
     80  * Fill in state.elf.obj_state with a a dynamically allocated
     81  * elfedit_obj_state_t struct of the appropriate ELFCLASS.
     82  * This pre-chewed form is fed to each command, reducing the amount
     83  * of ELF boilerplate code each command needs to contain.
     84  *
     85  * entry:
     86  *	file - Name of file to process
     87  *	fd - Descriptor of open file which has been successfully
     88  *		processed by elf_begin().
     89  *	elf - Elf handle returned by elf_begin
     90  *
     91  * exit:
     92  *	An elfedit_obj_state_t struct of the appropriate ELFCLASS has
     93  *	been dynamically allocated, and state.elf.obj_state references it.
     94  *	On failure, this routine does not return to the caller.
     95  *
     96  * note: The resulting elfedit_obj_state_t is allocated from a single
     97  *	piece of memory, such that a single call to free() suffices
     98  *	to release it as well as any memory it references.
     99  */
    100 #ifdef _ELF64
    101 void
    102 elfedit64_init_obj_state(const char *file, int fd, Elf *elf)
    103 #else
    104 void
    105 elfedit32_init_obj_state(const char *file, int fd, Elf *elf)
    106 #endif
    107 {
    108 #define	INITIAL_SYMTABNDX_ALLOC	5
    109 
    110 	/*
    111 	 * These macros are used to call functions from libelf.
    112 	 *
    113 	 * LIBELF_FAIL encapsulates the common way in which we handle
    114 	 * all of these errors: libelf_fail_name is set and execution
    115 	 * jumps to the libelf_failure label for handling.
    116 	 *
    117 	 * LIBELF is used for the common case in which the function returns
    118 	 * NULL for failure and something else for success.
    119 	 */
    120 #define	LIBELF_FAIL(_name) { libelf_fail_name = _name; goto libelf_failure; }
    121 #define	LIBELF(_libelf_expr, _name) \
    122 	if ((_libelf_expr) == NULL) \
    123 		LIBELF_FAIL(_name)
    124 
    125 	const char *libelf_fail_name;	/* Used for LIBELF errors */
    126 
    127 	Elf_Scn			*scn;
    128 	Elf_Data		*data;
    129 	uint_t			ndx;
    130 	size_t			len, os_size, secarr_size;
    131 	char			*names = 0;
    132 	size_t			names_len;
    133 	elfedit_section_t	*_cache;
    134 	elfedit_obj_state_t	tstate;
    135 	elfedit_obj_state_t	*obj_state = NULL;
    136 	Word			*symtabndx = NULL;
    137 	Word			symtabndx_size = 0;
    138 	elfedit_symtab_t	*symtab;
    139 
    140 	tstate.os_file = file;
    141 	tstate.os_fd = fd;
    142 	tstate.os_elf = elf;
    143 	tstate.os_dynndx = SHN_UNDEF;
    144 	tstate.os_symtabnum = 0;
    145 
    146 	LIBELF(tstate.os_ehdr = elf_getehdr(tstate.os_elf),
    147 	    MSG_ORIG(MSG_ELF_GETEHDR))
    148 
    149 	/* Program header array count and address */
    150 	if (elf_getphdrnum(tstate.os_elf, &tstate.os_phnum) == -1)
    151 		LIBELF_FAIL(MSG_ORIG(MSG_ELF_GETPHDRNUM))
    152 	if (tstate.os_phnum > 0) {
    153 		LIBELF((tstate.os_phdr = elf_getphdr(tstate.os_elf)),
    154 		    MSG_ORIG(MSG_ELF_GETPHDR))
    155 	} else {
    156 		tstate.os_phdr = NULL;
    157 	}
    158 
    159 	if (elf_getshdrnum(tstate.os_elf, &tstate.os_shnum) == -1)
    160 		LIBELF_FAIL(MSG_ORIG(MSG_ELF_GETSHDRNUM))
    161 
    162 	/*
    163 	 * Obtain the .shstrtab data buffer to provide the required section
    164 	 * name strings.
    165 	 */
    166 	if (elf_getshdrstrndx(tstate.os_elf, &tstate.os_shstrndx) == -1)
    167 		LIBELF_FAIL(MSG_ORIG(MSG_ELF_GETSHDRSTRNDX))
    168 	LIBELF((scn = elf_getscn(tstate.os_elf, tstate.os_shstrndx)),
    169 	    MSG_ORIG(MSG_ELF_GETSCN))
    170 	LIBELF((data = elf_getdata(scn, NULL)), MSG_ORIG(MSG_ELF_GETDATA))
    171 	names = data->d_buf;
    172 	names_len = (names == NULL) ? 0 : data->d_size;
    173 
    174 	/*
    175 	 * Count the number of symbol tables and capture their indexes.
    176 	 * Find the dynamic section.
    177 	 */
    178 	for (ndx = 1, scn = NULL; scn = elf_nextscn(tstate.os_elf, scn);
    179 	    ndx++) {
    180 		Shdr *shdr;
    181 
    182 		LIBELF(shdr = elf_getshdr(scn), MSG_ORIG(MSG_ELF_GETSHDR));
    183 
    184 		switch (shdr->sh_type) {
    185 		case SHT_DYNAMIC:
    186 			/* Save index of dynamic section for use below */
    187 			tstate.os_dynndx = ndx;
    188 			break;
    189 
    190 		case SHT_SYMTAB:
    191 		case SHT_DYNSYM:
    192 		case SHT_SUNW_LDYNSYM:
    193 			if (symtabndx_size <= tstate.os_symtabnum) {
    194 				symtabndx_size = (symtabndx_size == 0) ?
    195 				    INITIAL_SYMTABNDX_ALLOC :
    196 				    (symtabndx_size * 2);
    197 				symtabndx = elfedit_realloc(
    198 				    MSG_INTL(MSG_ALLOC_SYMTABOS), symtabndx,
    199 				    symtabndx_size * sizeof (symtabndx[0]));
    200 			}
    201 			symtabndx[tstate.os_symtabnum++] = ndx;
    202 			break;
    203 		}
    204 	}
    205 
    206 	/*
    207 	 * Allocate space to hold the state. We allocate space for everything
    208 	 * in one chunk to make releasing it easy:
    209 	 *	(1) elfedit_obj_state_t struct
    210 	 *	(2) The array of elfedit_section_t items referenced from
    211 	 *		the elfedit_obj_state_t struct.
    212 	 *	(3) The array of elfedit_symtab_t items referenced from
    213 	 *		the elfedit_obj_state_t struct.
    214 	 *	(4) The file name.
    215 	 *
    216 	 * Note that we round up the size of (1) and (2) to a double boundary
    217 	 * to ensure proper alignment of (2) and (3). (4) can align on any
    218 	 * boundary.
    219 	 */
    220 	os_size = S_DROUND(sizeof (tstate));
    221 	secarr_size = (tstate.os_shnum * sizeof (elfedit_section_t));
    222 	secarr_size = S_DROUND(secarr_size);
    223 	len = strlen(tstate.os_file) + 1;
    224 	obj_state = elfedit_malloc(MSG_INTL(MSG_ALLOC_OBJSTATE),
    225 	    os_size + secarr_size +
    226 	    (tstate.os_symtabnum * sizeof (elfedit_symtab_t)) + len);
    227 	*obj_state = tstate;
    228 
    229 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
    230 	obj_state->os_secarr = (elfedit_section_t *)
    231 	    ((char *)obj_state + os_size);
    232 	if (obj_state->os_symtabnum == 0)
    233 		obj_state->os_symtab = NULL;
    234 	else
    235 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
    236 		obj_state->os_symtab = (elfedit_symtab_t *)
    237 		    ((char *)obj_state->os_secarr + secarr_size);
    238 	obj_state->os_file =
    239 	    (char *)(obj_state->os_symtab + tstate.os_symtabnum);
    240 	(void) strncpy((char *)obj_state->os_file, tstate.os_file, len);
    241 
    242 	/*
    243 	 * Fill in obj_state->os_secarr with information for each section.
    244 	 * At the same time, fill in obj_state->os_symtab with the symbol
    245 	 * table related data.
    246 	 */
    247 	bzero(obj_state->os_secarr, sizeof (obj_state->os_secarr[0]));
    248 	_cache = obj_state->os_secarr;
    249 	LIBELF(scn = elf_getscn(tstate.os_elf, 0),
    250 	    MSG_ORIG(MSG_ELF_GETSCN));
    251 	_cache->sec_scn = scn;
    252 	LIBELF(_cache->sec_shdr = elf_getshdr(scn), MSG_ORIG(MSG_ELF_GETSHDR));
    253 	_cache->sec_name = (_cache->sec_shdr->sh_name < names_len) ?
    254 	    (names + _cache->sec_shdr->sh_name) : MSG_INTL(MSG_UNKNOWNSECNAM);
    255 	_cache++;
    256 
    257 	if (obj_state->os_symtab != NULL) {
    258 		bzero(obj_state->os_symtab,
    259 		    sizeof (obj_state->os_symtab[0]) * obj_state->os_symtabnum);
    260 		for (ndx = 0; ndx < obj_state->os_symtabnum; ndx++)
    261 			obj_state->os_symtab[ndx].symt_shndx = symtabndx[ndx];
    262 		free(symtabndx);
    263 	}
    264 
    265 	for (ndx = 1, scn = NULL; scn = elf_nextscn(tstate.os_elf, scn);
    266 	    ndx++, _cache++) {
    267 		_cache->sec_shndx = ndx;
    268 		_cache->sec_scn = scn;
    269 		LIBELF(_cache->sec_shdr = elf_getshdr(scn),
    270 		    MSG_ORIG(MSG_ELF_GETSHDR))
    271 		_cache->sec_data = elf_getdata(scn, NULL);
    272 		_cache->sec_name = (_cache->sec_shdr->sh_name < names_len) ?
    273 		    (names + _cache->sec_shdr->sh_name) :
    274 		    MSG_INTL(MSG_UNKNOWNSECNAM);
    275 
    276 		switch (_cache->sec_shdr->sh_type) {
    277 		case SHT_SYMTAB_SHNDX:
    278 			symtab = get_symtab(obj_state, _cache);
    279 			symtab->symt_xshndx = ndx;
    280 			break;
    281 
    282 		case SHT_SUNW_syminfo:
    283 			symtab = get_symtab(obj_state, _cache);
    284 			symtab->symt_syminfo = ndx;
    285 			break;
    286 
    287 		case SHT_SUNW_versym:
    288 			symtab = get_symtab(obj_state, _cache);
    289 			symtab->symt_versym = ndx;
    290 			break;
    291 		}
    292 	}
    293 
    294 	/*
    295 	 * Sanity check the symbol tables, and discard any auxiliary
    296 	 * sections without enough elements.
    297 	 */
    298 	symtab = obj_state->os_symtab;
    299 	for (ndx = 0; ndx < obj_state->os_symtabnum; ndx++, symtab++) {
    300 		elfedit_section_t	*symsec;
    301 		Word			symsec_cnt, aux_cnt;
    302 
    303 		symsec = &obj_state->os_secarr[symtab->symt_shndx];
    304 		symsec_cnt = symsec->sec_shdr->sh_size / sizeof (Sym);
    305 
    306 		/* Extended section indexes */
    307 		if (symtab->symt_xshndx != SHN_UNDEF) {
    308 			_cache = &obj_state->os_secarr[symtab->symt_xshndx];
    309 			aux_cnt = _cache->sec_shdr->sh_size / sizeof (Word);
    310 			if (symsec_cnt > aux_cnt)
    311 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    312 				    MSG_INTL(MSG_DEBUG_AUX_SIZE),
    313 				    EC_WORD(ndx), _cache->sec_name,
    314 				    EC_WORD(aux_cnt),
    315 				    EC_WORD(symsec->sec_shndx),
    316 				    symsec->sec_name, EC_WORD(aux_cnt));
    317 		}
    318 
    319 		/* Syminfo */
    320 		if (symtab->symt_syminfo != SHN_UNDEF) {
    321 			_cache = &obj_state->os_secarr[symtab->symt_syminfo];
    322 			aux_cnt = _cache->sec_shdr->sh_size / sizeof (Syminfo);
    323 			if (symsec_cnt > aux_cnt)
    324 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    325 				    MSG_INTL(MSG_DEBUG_AUX_SIZE),
    326 				    EC_WORD(ndx), _cache->sec_name,
    327 				    EC_WORD(aux_cnt),
    328 				    EC_WORD(symsec->sec_shndx),
    329 				    symsec->sec_name, EC_WORD(aux_cnt));
    330 		}
    331 
    332 		/* Versym */
    333 		if (symtab->symt_versym != SHN_UNDEF) {
    334 			_cache = &obj_state->os_secarr[symtab->symt_versym];
    335 			aux_cnt = _cache->sec_shdr->sh_size / sizeof (Versym);
    336 			if (symsec_cnt > aux_cnt)
    337 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    338 				    MSG_INTL(MSG_DEBUG_AUX_SIZE),
    339 				    EC_WORD(ndx), _cache->sec_name,
    340 				    EC_WORD(aux_cnt),
    341 				    EC_WORD(symsec->sec_shndx),
    342 				    symsec->sec_name, EC_WORD(aux_cnt));
    343 		}
    344 	}
    345 
    346 	/*
    347 	 * If this object has a dynsym section with a FLAGS_1 field,
    348 	 * then set the DF_1_EDITED bit. elfedit allows changes that
    349 	 * can break the resulting program, so knowing that a file was
    350 	 * edited can be helpful when encountering a core file or other
    351 	 * unexpected failure in the field. A single bit can't tell you
    352 	 * what was changed, but it will alert you to the possibility that
    353 	 * some additional questions might be in order.
    354 	 */
    355 	if (obj_state->os_dynndx != SHN_UNDEF) {
    356 		Word			i;
    357 		Word			numdyn;
    358 		elfedit_section_t	*dynsec;
    359 		elfedit_dyn_elt_t	flags_1_elt;
    360 		elfedit_dyn_elt_t	null_elt;
    361 		Dyn			*dyn;
    362 
    363 		dynsec = &obj_state->os_secarr[obj_state->os_dynndx];
    364 		dyn = (Dyn *) dynsec->sec_data->d_buf;
    365 		numdyn = dynsec->sec_shdr->sh_size /
    366 		    dynsec->sec_shdr->sh_entsize;
    367 		elfedit_dyn_elt_init(&flags_1_elt);
    368 		elfedit_dyn_elt_init(&null_elt);
    369 		for (i = 0; i < numdyn; i++) {
    370 
    371 			switch (dyn[i].d_tag) {
    372 			case DT_NULL:
    373 				/*
    374 				 * Remember state of the first DT_NULL. If there
    375 				 * are more than one (i.e. the first one is not
    376 				 * in the final spot), and there is no flags1,
    377 				 * then we will turn the first one into a
    378 				 * DT_FLAGS_1.
    379 				 */
    380 				if (!null_elt.dn_seen)
    381 					elfedit_dyn_elt_save(&null_elt, i,
    382 					    &dyn[i]);
    383 				break;
    384 
    385 			case DT_FLAGS_1:
    386 				elfedit_dyn_elt_save(&flags_1_elt, i, &dyn[i]);
    387 				break;
    388 			}
    389 		}
    390 		/* If don't have a flags1 field, can we make one from a NULL? */
    391 		if (!flags_1_elt.dn_seen && null_elt.dn_seen &&
    392 		    (null_elt.dn_ndx < (numdyn - 1))) {
    393 			elfedit_msg(ELFEDIT_MSG_DEBUG,
    394 			    MSG_INTL(MSG_DEBUG_NULL2DYNFL1),
    395 			    EC_WORD(obj_state->os_dynndx),
    396 			    dynsec->sec_name, EC_WORD(null_elt.dn_ndx));
    397 			flags_1_elt.dn_seen = 1;
    398 			flags_1_elt.dn_ndx = null_elt.dn_ndx;
    399 			flags_1_elt.dn_dyn.d_tag = DT_FLAGS_1;
    400 			flags_1_elt.dn_dyn.d_un.d_val = 0;
    401 		}
    402 		/*
    403 		 * If there is a flags 1 field, add the edit flag if
    404 		 * it is not present, and report it's presence otherwise.
    405 		 */
    406 		if (flags_1_elt.dn_seen) {
    407 			if (flags_1_elt.dn_dyn.d_un.d_val & DF_1_EDITED) {
    408 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    409 				    MSG_INTL(MSG_DEBUG_SEEDYNFLG),
    410 				    EC_WORD(obj_state->os_dynndx),
    411 				    dynsec->sec_name,
    412 				    EC_WORD(flags_1_elt.dn_ndx));
    413 			} else {
    414 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    415 				    MSG_INTL(MSG_DEBUG_ADDDYNFLG),
    416 				    EC_WORD(obj_state->os_dynndx),
    417 				    dynsec->sec_name,
    418 				    EC_WORD(flags_1_elt.dn_ndx));
    419 				flags_1_elt.dn_dyn.d_un.d_val |= DF_1_EDITED;
    420 				dyn[flags_1_elt.dn_ndx] = flags_1_elt.dn_dyn;
    421 				elfedit_modified_data(dynsec);
    422 			}
    423 		}
    424 	}
    425 
    426 #ifdef _ELF64
    427 	state.elf.obj_state.s64 = obj_state;
    428 #else
    429 	state.elf.obj_state.s32 = obj_state;
    430 #endif
    431 	return;
    432 
    433 libelf_failure:
    434 	/*
    435 	 * Control comes here if there is an error with LIBELF.
    436 	 *
    437 	 * entry:
    438 	 *	libelf_fail_name - Name of failing libelf function
    439 	 *	tstate.os_file - Name of ELF file being processed
    440 	 *	tstate.os_fd - Descriptor of open ELF file
    441 	 *
    442 	 * exit:
    443 	 *	- dynamic memory is released if necessary
    444 	 *	- The error issued
    445 	 */
    446 	if (obj_state != NULL)
    447 		free(obj_state);
    448 	(void) close(tstate.os_fd);
    449 	elfedit_elferr(tstate.os_file, libelf_fail_name);
    450 #undef INITIAL_SYMTABNDX_ALLOC
    451 #undef LIBELF_FAIL
    452 #undef LIBELF
    453 }
    454