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 #include	<stdlib.h>
     28 #include	<stdio.h>
     29 #include	<unistd.h>
     30 #include	<libintl.h>
     31 #include	<_machelf.h>
     32 #include	<libelf.h>
     33 #include	<link.h>
     34 #include	<strings.h>
     35 #include	<ctype.h>
     36 #include	"msg.h"
     37 #include	<elfedit.h>
     38 #include	<conv.h>
     39 #include	<sys/elf_SPARC.h>
     40 #include	<sys/elf_amd64.h>
     41 
     42 
     43 
     44 /*
     45  * ELFCLASS specific code that would otherwise be found in util.c
     46  */
     47 
     48 
     49 
     50 
     51 /*
     52  * When you modify ELF constructs, you need to tell libelf that you've
     53  * done so. Otherwise, the changes may not be flushed back to the
     54  * output file.
     55  *
     56  * The elfedit_modified_*() functions exist to simplify the calls to
     57  * the underlying elf_flag*() functions.
     58  */
     59 void
     60 elfedit_modified_ehdr(elfedit_obj_state_t *obj_state)
     61 {
     62 	(void) elf_flagehdr(obj_state->os_elf, ELF_C_SET, ELF_F_DIRTY);
     63 }
     64 
     65 void
     66 elfedit_modified_phdr(elfedit_obj_state_t *obj_state)
     67 {
     68 	(void) elf_flagphdr(obj_state->os_elf, ELF_C_SET, ELF_F_DIRTY);
     69 }
     70 
     71 void
     72 elfedit_modified_shdr(elfedit_section_t *s)
     73 {
     74 	(void) elf_flagshdr(s->sec_scn, ELF_C_SET, ELF_F_DIRTY);
     75 }
     76 
     77 void
     78 elfedit_modified_data(elfedit_section_t *s)
     79 {
     80 	(void) elf_flagdata(s->sec_data, ELF_C_SET, ELF_F_DIRTY);
     81 }
     82 
     83 
     84 
     85 /*
     86  * Prepare an elfedit_dyn_elt_t structure for use.
     87  */
     88 void
     89 elfedit_dyn_elt_init(elfedit_dyn_elt_t *elt)
     90 {
     91 	elt->dn_seen = 0;
     92 }
     93 
     94 /*
     95  * Given a dynamic section item, save it in the given elfedit_dyn_elt_t
     96  * structure and mark that structure to show that it is present.
     97  */
     98 void
     99 elfedit_dyn_elt_save(elfedit_dyn_elt_t *elt, Word ndx, Dyn *dyn)
    100 {
    101 	elt->dn_seen = 1;
    102 	elt->dn_ndx = ndx;
    103 	elt->dn_dyn = *dyn;
    104 }
    105 
    106 
    107 /*
    108  * Return the index of the first section that has the given name.
    109  *
    110  * entry:
    111  *	obj_state - Object state.
    112  *	shnam - Name of desired section
    113  *
    114  * exit:
    115  *	On success, returns the section index. On failure, an error
    116  *	is issued, and this routine does not return to the caller.
    117  */
    118 Word
    119 elfedit_name_to_shndx(elfedit_obj_state_t *obj_state, const char *shnam)
    120 {
    121 	elfedit_section_t *sec = obj_state->os_secarr;
    122 	Word	ndx;
    123 	Word	shnum = obj_state->os_shnum;
    124 
    125 	for (ndx = 0; ndx < shnum; ndx++, sec++) {
    126 		if (strcmp(shnam, sec->sec_name) == 0) {
    127 			elfedit_msg(ELFEDIT_MSG_DEBUG,
    128 			    MSG_INTL(MSG_DEBUG_SHNAM2NDX),
    129 			    EC_WORD(sec->sec_shndx), sec->sec_name, shnam);
    130 			return (ndx);
    131 		}
    132 	}
    133 
    134 	/* If didn't return in loop above, the name doesn't match */
    135 	elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSECNAM), shnam);
    136 	/*NOTREACHED*/
    137 	return (SHN_UNDEF);
    138 }
    139 
    140 
    141 
    142 /*
    143  * Return the index of the first section that has the given type.
    144  *
    145  * entry:
    146  *	obj_state - Object state.
    147  *	shtype - Type of desired section
    148  *
    149  * exit:
    150  *	On success, returns the section index. On failure, an error
    151  *	is issued, and this routine does not return to the caller.
    152  */
    153 Word
    154 elfedit_type_to_shndx(elfedit_obj_state_t *obj_state, Word shtype)
    155 {
    156 	Conv_inv_buf_t inv_buf;
    157 	elfedit_section_t *sec = obj_state->os_secarr;
    158 	Word	ndx;
    159 	Word	shnum = obj_state->os_shnum;
    160 
    161 	for (ndx = 0; ndx < shnum; ndx++, sec++) {
    162 		if (shtype == sec->sec_shdr->sh_type) {
    163 			elfedit_msg(ELFEDIT_MSG_DEBUG,
    164 			    MSG_INTL(MSG_DEBUG_SHNAM2NDX),
    165 			    EC_WORD(sec->sec_shndx), sec->sec_name,
    166 			    conv_sec_type(
    167 			    obj_state->os_ehdr->e_ident[EI_OSABI],
    168 			    obj_state->os_ehdr->e_machine,
    169 			    shtype, 0, &inv_buf));
    170 			return (ndx);
    171 		}
    172 	}
    173 
    174 	/* If didn't return in loop above, the name doesn't match */
    175 	elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSECTYP),
    176 	    conv_sec_type(obj_state->os_ehdr->e_ident[EI_OSABI],
    177 	    obj_state->os_ehdr->e_machine, shtype, 0, &inv_buf));
    178 	/*NOTREACHED*/
    179 	return (SHN_UNDEF);
    180 }
    181 
    182 
    183 
    184 /*
    185  * Locate the index of the first symbol that has the given name
    186  *
    187  * entry:
    188  *	obj_state - Object state.
    189  *	symsec - Symbol section
    190  *	strsec = String section
    191  *	name - String giving name of symbol to lookup
    192  *	msg_type - ELFEDIT_MSG_ type code to use with message
    193  *		issued if name does not exist in symbol table.
    194  *	ret_symndx - Address of variable to receive index.
    195  *
    196  * exit:
    197  *	On success, issues debug message, sets *ret_symndx, and returns
    198  *	True (1).
    199  *
    200  *	On failure, issues a message using msg_type to determine
    201  *	the type of message sent. If the message does not take control away
    202  *	from the caller, False (0) is returned.
    203  *
    204  * note:
    205  *	Although the string table is referenced by the sh_link field of
    206  *	the symbol table, we require the user to supply it rather than
    207  *	look it up. The reason for this is that the caller will usually
    208  *	have looked it up, and we wish to avoid multiple debug messages
    209  *	from being issued to that effect.
    210  */
    211 int
    212 elfedit_name_to_symndx(elfedit_section_t *symsec, elfedit_section_t *strsec,
    213     const char *name, elfedit_msg_t msg_type, Word *ret_symndx)
    214 
    215 {
    216 	Sym	*sym = (Sym *) symsec->sec_data->d_buf;
    217 	Word	cnt = symsec->sec_shdr->sh_size / symsec->sec_shdr->sh_entsize;
    218 	Word	ndx, offset;
    219 	const char	*curname;
    220 
    221 	for (ndx = 0; ndx < cnt; ndx++) {
    222 		offset = sym[ndx].st_name;
    223 
    224 		curname = elfedit_offset_to_str(strsec, offset,
    225 		    ELFEDIT_MSG_ERR, 0);
    226 		if (strcmp(curname, name) == 0) {
    227 			elfedit_msg(ELFEDIT_MSG_DEBUG,
    228 			    MSG_INTL(MSG_DEBUG_SYMNAM2NDX),
    229 			    EC_WORD(symsec->sec_shndx),
    230 			    symsec->sec_name, EC_WORD(ndx), name);
    231 			*ret_symndx = ndx;
    232 			return (1);
    233 		}
    234 	}
    235 
    236 	/* If didn't return in loop above, the name doesn't match */
    237 	elfedit_msg(msg_type, MSG_INTL(MSG_ERR_NOSYM),
    238 	    EC_WORD(symsec->sec_shndx), symsec->sec_name, name);
    239 	/*NOTREACHED*/
    240 	return (0);		/* lint */
    241 }
    242 
    243 
    244 /*
    245  * Given a section index, turn it into a descriptive string.
    246  *	- If it is one of the special reserved indexes, the
    247  *		symbolic name is returned.
    248  *	- If it is a regular section, in range for the file,
    249  *		the name associated with the section is returned.
    250  *	- Otherwise, the number is formatted as numeric ASCII.
    251  *
    252  * exit:
    253  *	A pointer to the static buffer containing the name is
    254  *	returned. This pointer is valid until the next call
    255  *	to elfedit_shndx_to_name(), and which point it may
    256  *	be overwritten.
    257  */
    258 const char *
    259 elfedit_shndx_to_name(elfedit_obj_state_t *obj_state, Word shndx)
    260 {
    261 	/*
    262 	 * This routine can be called twice within a single C statement,
    263 	 * so we use alternating buffers on each call to allow this
    264 	 * without requiring the caller to supply a buffer (the size of
    265 	 * which they don't know).
    266 	 */
    267 	static Conv_inv_buf_t	buf1, buf2;
    268 	static Conv_inv_buf_t	*buf;
    269 
    270 	/*
    271 	 * If it is outside of the reserved area, and inside the
    272 	 * range of section indexes in the ELF file, then show
    273 	 * the section name.
    274 	 */
    275 	if ((shndx < obj_state->os_shnum) &&
    276 	    ((shndx < SHN_LORESERVE) || (shndx > SHN_HIRESERVE)) &&
    277 	    (shndx != SHN_UNDEF))
    278 		return (obj_state->os_secarr[shndx].sec_name);
    279 
    280 	/*
    281 	 * Anything else is handled by libconv. It will return standard
    282 	 * names for known items, or format as a number otherwise.
    283 	 */
    284 	buf = (buf == &buf1) ? &buf2 : &buf1;	/* Switch buffers */
    285 	return (conv_sym_shndx(obj_state->os_ehdr->e_ident[EI_OSABI],
    286 	    obj_state->os_ehdr->e_machine, shndx,
    287 	    CONV_FMT_ALT_CF | CONV_FMT_DECIMAL, buf));
    288 }
    289 
    290 
    291 /*
    292  * Locate the arbitrary section specified by shndx for this object.
    293  *
    294  * exit:
    295  *	Returns section descriptor on success. On failure, does not return.
    296  */
    297 elfedit_section_t *
    298 elfedit_sec_get(elfedit_obj_state_t *obj_state, Word shndx)
    299 {
    300 	elfedit_section_t *sec;
    301 
    302 	if ((shndx == 0) || (shndx >= obj_state->os_shnum))
    303 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADSECNDX),
    304 		    EC_WORD(shndx), EC_WORD(obj_state->os_shnum - 1));
    305 
    306 	sec = &obj_state->os_secarr[shndx];
    307 
    308 	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDSEC),
    309 	    EC_WORD(shndx), sec->sec_name);
    310 	return (sec);
    311 }
    312 
    313 
    314 
    315 /*
    316  * Compare the a specified osabi with that of the current object.
    317  *
    318  * entry:
    319  *	obj_state - Object state for open object to query.
    320  *	issue_err - True if this routine should issue an error and
    321  *		not return to the caller if osabi is not native.
    322  *
    323  * exit:
    324  *	If current osabi is the one specified, True (1) is returned.
    325  *
    326  *	Otherwise, if issue_err is True, an error is issued and this
    327  *	routine does not return to the caller. If issue_err is False,
    328  *	False (0) is returned.
    329  *
    330  * note:
    331  *	ELFOSABI_NONE is considered to be equivalent to ELFOSABI_SOLARIS.
    332  */
    333 int
    334 elfedit_test_osabi(elfedit_obj_state_t *obj_state, uchar_t osabi,
    335     int issue_err)
    336 {
    337 	uchar_t		obj_osabi = obj_state->os_ehdr->e_ident[EI_OSABI];
    338 	Conv_inv_buf_t	inv_buf;
    339 
    340 	if (obj_osabi == ELFOSABI_NONE)
    341 		obj_osabi = ELFOSABI_SOLARIS;
    342 
    343 	if (osabi == obj_osabi)
    344 		return (1);
    345 
    346 	if (issue_err)
    347 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADOSABI),
    348 		    conv_ehdr_osabi(osabi, 0, &inv_buf));
    349 	return (0);
    350 }
    351 
    352 /*
    353  * Locate the capabilities section for this object
    354  *
    355  * entry:
    356  *	obj_state - Object state for open object to query.
    357  *	cap - Address of variable to recieve pointer to capabilities
    358  *		section data buffer.
    359  *	num - Address of variable to receive number of items
    360  *		referenced by cap.
    361  *
    362  * exit:
    363  *	On success, returns section descriptor, and sets the
    364  *	variables referenced by cap and num.  On failure,
    365  *	does not return.
    366  */
    367 elfedit_section_t *
    368 elfedit_sec_getcap(elfedit_obj_state_t *obj_state, Cap **cap, Word *num)
    369 {
    370 	Word cnt;
    371 	elfedit_section_t *cache;
    372 
    373 	(void) elfedit_test_osabi(obj_state, ELFOSABI_SOLARIS, 1);
    374 
    375 	for (cnt = 1; cnt < obj_state->os_shnum; cnt++) {
    376 		cache = &obj_state->os_secarr[cnt];
    377 		if (cache->sec_shdr->sh_type == SHT_SUNW_cap) {
    378 			elfedit_msg(ELFEDIT_MSG_DEBUG,
    379 			    MSG_INTL(MSG_DEBUG_FNDCAP),
    380 			    EC_WORD(cnt), cache->sec_name);
    381 			*cap = (Cap *) cache->sec_data->d_buf;
    382 			*num = cache->sec_shdr->sh_size /
    383 			    cache->sec_shdr->sh_entsize;
    384 			return (cache);
    385 		}
    386 	}
    387 
    388 	/* If here, this object has no capabilities section */
    389 	elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOCAP));
    390 
    391 	/*NOTREACHED*/
    392 	return (NULL);
    393 }
    394 
    395 
    396 /*
    397  * Locate the dynamic section for this object
    398  *
    399  * entry:
    400  *	obj_state - Object state for open object to query.
    401  *	dyn - Address of variable to recieve pointer to dynamic
    402  *		section data buffer.
    403  *	numdyn - Address of variable to receive number of items
    404  *		referenced by dyn.
    405  *
    406  * exit:
    407  *	On success, returns section descriptor, and sets the
    408  *	variables referenced by dyn and numdyn.  On failure,
    409  *	does not return.
    410  */
    411 elfedit_section_t *
    412 elfedit_sec_getdyn(elfedit_obj_state_t *obj_state, Dyn **dyn, Word *num)
    413 {
    414 	elfedit_section_t *cache;
    415 
    416 	if (obj_state->os_dynndx != SHN_UNDEF) {
    417 		cache = &obj_state->os_secarr[obj_state->os_dynndx];
    418 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDDYN),
    419 		    EC_WORD(cache->sec_shndx), cache->sec_name);
    420 		*dyn = (Dyn *) cache->sec_data->d_buf;
    421 		*num = cache->sec_shdr->sh_size / cache->sec_shdr->sh_entsize;
    422 		return (cache);
    423 	}
    424 
    425 	/* If here, this object has no dynamic section */
    426 	elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NODYN));
    427 
    428 	/*NOTREACHED*/
    429 	return (NULL);
    430 }
    431 
    432 
    433 /*
    434  * Locate the syminfo section for this object
    435  *
    436  * entry:
    437  *	obj_state - Object state for open object to query.
    438  *	syminfo - Address of variable to recieve pointer to syminfo
    439  *		section data buffer.
    440  *	num - Address of variable to receive number of items
    441  *		referenced by syminfo.
    442  *
    443  * exit:
    444  *	On success, returns section descriptor, and sets the
    445  *	variables referenced by syminfo and num.  On failure,
    446  *	does not return.
    447  */
    448 elfedit_section_t *
    449 elfedit_sec_getsyminfo(elfedit_obj_state_t *obj_state, Syminfo **syminfo,
    450     Word *num)
    451 {
    452 	Word cnt;
    453 	elfedit_section_t *cache;
    454 
    455 	for (cnt = 1; cnt < obj_state->os_shnum; cnt++) {
    456 		cache = &obj_state->os_secarr[cnt];
    457 		if (cache->sec_shdr->sh_type == SHT_SUNW_syminfo) {
    458 			elfedit_msg(ELFEDIT_MSG_DEBUG,
    459 			    MSG_INTL(MSG_DEBUG_FNDSYMINFO),
    460 			    EC_WORD(cnt), cache->sec_name);
    461 			*syminfo = (Syminfo *) cache->sec_data->d_buf;
    462 			*num = cache->sec_shdr->sh_size /
    463 			    cache->sec_shdr->sh_entsize;
    464 			return (cache);
    465 		}
    466 	}
    467 
    468 	/* If here, this object has no syminfo section */
    469 	elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSYMINFO));
    470 
    471 	/*NOTREACHED*/
    472 	return (NULL);
    473 }
    474 
    475 
    476 /*
    477  * Check the given section to see if it is a known symbol table type.
    478  *
    479  * entry:
    480  *	obj_state - Object state for open object to query.
    481  *	sec - Section to check
    482  *	issue_err - True if this routine should issue an error and
    483  *		not return to the caller if sec is not a symbol table.
    484  *	atoui_list - NULL, or address of variable to receive a pointer to
    485  *		an array of elfedit_atoui_sym_t items describing the
    486  *		type of symbol table found. This array is useful for
    487  *		doing command completion.
    488  *
    489  * exit:
    490  *	If sec is a symbol table:
    491  *		- If atoui_list is non-NULL, *atoui_list is set to the
    492  *		  appropriate ELFEDIT_CONST_xx list of items.
    493  *		- True (1) is returned
    494  *	If sec is not a symbol table and issue_err is True:
    495  *		- An error is issued, and this routine does not
    496  *			return to the caller.
    497  *	Otherwise:
    498  *		- If atoui_list is non-NULL, *atoui_list is set to NULL.
    499  *		- False (0) is returned
    500  */
    501 int
    502 elfedit_sec_issymtab(elfedit_obj_state_t *obj_state, elfedit_section_t *sec,
    503     int issue_err, elfedit_atoui_sym_t **atoui_list)
    504 {
    505 	elfedit_const_t		const_type;
    506 	int			ret = 1;
    507 
    508 	/* Is the section a symbol table? */
    509 	switch (sec->sec_shdr->sh_type) {
    510 	case SHT_SYMTAB:
    511 		const_type = ELFEDIT_CONST_SHT_SYMTAB;
    512 		break;
    513 	case SHT_DYNSYM:
    514 		const_type = ELFEDIT_CONST_SHT_DYNSYM;
    515 		break;
    516 	case SHT_SUNW_LDYNSYM:
    517 		/*
    518 		 * These sections are only known to be symbol tables
    519 		 * if the osabi is Solaris.
    520 		 */
    521 		if (elfedit_test_osabi(obj_state, ELFOSABI_SOLARIS, 0)) {
    522 			const_type = ELFEDIT_CONST_SHT_LDYNSYM;
    523 			break;
    524 		}
    525 		/*FALLTHROUGH*/
    526 	default:
    527 		if (issue_err)
    528 			elfedit_msg(ELFEDIT_MSG_ERR,
    529 			    MSG_INTL(MSG_ERR_NOTSYMTAB),
    530 			    EC_WORD(sec->sec_shndx), sec->sec_name);
    531 		ret = 0;
    532 		break;
    533 	}
    534 
    535 	if (atoui_list != NULL)
    536 		*atoui_list = (ret == 0) ? NULL :
    537 		    elfedit_const_to_atoui(const_type);
    538 
    539 	return (ret);
    540 }
    541 
    542 
    543 
    544 /*
    545  * Locate a symbol table section for this object
    546  *
    547  * entry:
    548  *	obj_state - Object state for open object to query.
    549  *	by_index - If True, we want to locate the section with the
    550  *		section index given by index. If False, we return
    551  *		the section with the name given by name.
    552  *	index, name - Key to search for. See by_index.
    553  *	sym - Address of variable to recieve pointer to symbol
    554  *		section data buffer.
    555  *	numsym - Address of variable to receive number of symbols
    556  *		referenced by sym.
    557  *	aux_info - Address of variable to receive pointer to the
    558  *		elfedit_symtab_t struct that ties the symbol table and
    559  *		its related auxiliary sections together. NULL if this
    560  *		information is not required.
    561  *
    562  * exit:
    563  *	On success, returns section descriptor, and sets the
    564  *	variables referenced by sym, and numsym. On failure,
    565  *	does not return.
    566  */
    567 elfedit_section_t *
    568 elfedit_sec_getsymtab(elfedit_obj_state_t *obj_state, int by_index,
    569     Word index, const char *name, Sym **sym, Word *num,
    570     elfedit_symtab_t **aux_info)
    571 {
    572 	Word			ndx;
    573 	elfedit_section_t	*symsec = NULL;
    574 	elfedit_symtab_t	*symtab;
    575 	const char 		*type_name;
    576 
    577 	/* If looking it up by index, make sure the index is in range */
    578 	if (by_index && (index >= obj_state->os_shnum))
    579 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADSECNDX),
    580 		    EC_WORD(index), EC_WORD(obj_state->os_shnum - 1));
    581 
    582 	/*
    583 	 * Look at each known symbol table in turn until the desired
    584 	 * one is hit, or there are no more.
    585 	 */
    586 	symtab = obj_state->os_symtab;
    587 	for (ndx = 0; ndx < obj_state->os_symtabnum; ndx++, symtab++) {
    588 		elfedit_section_t *s =
    589 		    &obj_state->os_secarr[symtab->symt_shndx];
    590 
    591 		if ((by_index && (symtab->symt_shndx == index)) ||
    592 		    (!by_index && (strcmp(s->sec_name, name) == 0))) {
    593 				symsec = s;
    594 				break;
    595 		}
    596 	}
    597 
    598 	/* Did we get a section? */
    599 	if (symsec == NULL)
    600 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSYMTAB));
    601 
    602 	/* Got it. Report to the user and return the necessary data */
    603 	(void) elfedit_sec_issymtab(obj_state, symsec, 1, NULL);
    604 	type_name = elfedit_atoconst_value_to_str(ELFEDIT_CONST_SHT_ALLSYMTAB,
    605 	    symsec->sec_shdr->sh_type, 1);
    606 	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDSYMTAB),
    607 	    EC_WORD(symsec->sec_shndx), symsec->sec_name, type_name);
    608 	*sym = (Sym *) symsec->sec_data->d_buf;
    609 	*num = symsec->sec_shdr->sh_size / symsec->sec_shdr->sh_entsize;
    610 	if (aux_info != NULL)
    611 		*aux_info = symtab;
    612 	return (symsec);
    613 }
    614 
    615 
    616 
    617 /*
    618  * Locate the extended symbol index section associated with a symbol
    619  * table section.
    620  *
    621  * entry:
    622  *	obj_state - Object state for open object to query.
    623  *	symsec - Symbol table section for which extended index
    624  *		index section is required.
    625  *	xshndx - Address of variable to recieve pointer to section index
    626  *		array data buffer.
    627  *	numxshndx - Address of variable to receive number of indices
    628  *		referenced by ndx.
    629  *
    630  * exit:
    631  *	On success, returns extended index section descriptor, and sets the
    632  *	variables referenced by xshndx, and numxshndx. On failure,
    633  *	does not return.
    634  *
    635  * note:
    636  *	Since the extended section index is found in the sec_xshndx field
    637  *	of the elfedit_section_t, the caller may be tempted to bypass this
    638  *	routine and access it directly. That temptation should be resisted,
    639  *	as this routine performs useful error checking, and also handles
    640  *	the issuing of the standard MSG_DEBUG messages.
    641  */
    642 elfedit_section_t *
    643 elfedit_sec_getxshndx(elfedit_obj_state_t *obj_state,
    644     elfedit_section_t *symsec, Word **xshndx, Word *num)
    645 {
    646 	elfedit_section_t	*xshndxsec;
    647 	elfedit_symtab_t	*symtab;
    648 	Word			ndx;
    649 
    650 	/* Sanity check: symsec must be a symbol table */
    651 	(void) elfedit_sec_issymtab(obj_state, symsec, 1, NULL);
    652 
    653 	symtab = obj_state->os_symtab;
    654 	for (ndx = 0; ndx < obj_state->os_symtabnum; ndx++, symtab++)
    655 		if (symsec->sec_shndx == symtab->symt_shndx)
    656 			break;
    657 
    658 	/*
    659 	 * Issue error if the symbol table lacks an extended index section.
    660 	 * The caller won't ask unless they encounter an SHN_XINDEX value,
    661 	 * in which case the lack of the index section denotes a corrupt
    662 	 * ELF file.
    663 	 */
    664 	if ((ndx == obj_state->os_symtabnum) ||
    665 	    (symtab->symt_xshndx == SHN_UNDEF))
    666 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOXSHSEC),
    667 		    EC_WORD(symsec->sec_shndx), symsec->sec_name);
    668 
    669 	/* Got it. Report to the user and return the necessary data */
    670 	xshndxsec = &obj_state->os_secarr[symtab->symt_xshndx];
    671 	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDXSHNDX),
    672 	    EC_WORD(symsec->sec_shndx), symsec->sec_name,
    673 	    EC_WORD(xshndxsec->sec_shndx), xshndxsec->sec_name);
    674 	*xshndx = (Word *) xshndxsec->sec_data->d_buf;
    675 	*num = xshndxsec->sec_shdr->sh_size / xshndxsec->sec_shdr->sh_entsize;
    676 	return (xshndxsec);
    677 }
    678 
    679 
    680 
    681 /*
    682  * Locate the versym section associated with a symbol table section.
    683  *
    684  * entry:
    685  *	obj_state - Object state for open object to query.
    686  *	symsec - Symbol table section for which extended index
    687  *		index section is required.
    688  *	versym - Address of variable to recieve pointer to section index
    689  *		array data buffer.
    690  *	numversym - Address of variable to receive number of indices
    691  *		referenced by ndx.
    692  *
    693  * exit:
    694  *	On success, returns versym section descriptor, and sets the
    695  *	variables referenced by versym, and numversym. On failure,
    696  *	does not return.
    697  *
    698  * note:
    699  *	Since the versym section index is found in the sec_versym field
    700  *	of the elfedit_section_t, the caller may be tempted to bypass this
    701  *	routine and access it directly. That temptation should be resisted,
    702  *	as this routine performs useful error checking, and also handles
    703  *	the issuing of the standard MSG_DEBUG messages.
    704  */
    705 elfedit_section_t *
    706 elfedit_sec_getversym(elfedit_obj_state_t *obj_state,
    707     elfedit_section_t *symsec, Versym **versym, Word *num)
    708 {
    709 	elfedit_section_t	*versymsec;
    710 	elfedit_symtab_t	*symtab;
    711 	Word			ndx;
    712 
    713 	/* Sanity check: symsec must be a symbol table */
    714 	(void) elfedit_sec_issymtab(obj_state, symsec, 1, NULL);
    715 
    716 	symtab = obj_state->os_symtab;
    717 	for (ndx = 0; ndx < obj_state->os_symtabnum; ndx++, symtab++)
    718 		if (symsec->sec_shndx == symtab->symt_shndx)
    719 			break;
    720 	/*
    721 	 * Issue error if the symbol table lacks a versym section.
    722 	 * The caller won't ask unless they see a non-null
    723 	 * aux.symtab.sec_versym, so this should not be a problem.
    724 	 */
    725 	if ((ndx == obj_state->os_symtabnum) ||
    726 	    (symtab->symt_versym == SHN_UNDEF))
    727 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOVERSYMSEC),
    728 		    EC_WORD(symsec->sec_shndx), symsec->sec_name);
    729 
    730 	/* Got it. Report to the user and return the necessary data */
    731 	versymsec = &obj_state->os_secarr[symtab->symt_versym];
    732 	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDVERSYM),
    733 	    EC_WORD(symsec->sec_shndx), symsec->sec_name,
    734 	    EC_WORD(versymsec->sec_shndx), versymsec->sec_name);
    735 	*versym = (Versym *) versymsec->sec_data->d_buf;
    736 	*num = versymsec->sec_shdr->sh_size / versymsec->sec_shdr->sh_entsize;
    737 	return (versymsec);
    738 }
    739 
    740 
    741 
    742 /*
    743  * Locate the string table specified by shndx for this object.
    744  *
    745  * entry:
    746  *	obj_state - Object state.
    747  *	shndx - Section index for string table section
    748  *	allow_shflags - If False (0), only sections of type SHT_STRTAB
    749  *		are accepted as being string tables, and any other type
    750  *		will fail. If True (1), non-stringtable sections with
    751  *		their SHF_STRINGS flag set are also accepted.
    752  *
    753  * exit:
    754  *	Returns section descriptor on success. On failure, does not return.
    755  *
    756  * note:
    757  *	At this time, we can only support SHF_STRINGS sections that
    758  *	use single byte characters and which do not require alignment >1.
    759  *	SHF_STRINGS sections that have multi-byte characters or alignment
    760  *	are not currently supported and will draw an error even if
    761  *	allow_shflags is True.
    762  */
    763 elfedit_section_t *
    764 elfedit_sec_getstr(elfedit_obj_state_t *obj_state, Word shndx,
    765     int allow_shflags)
    766 {
    767 	elfedit_section_t *strsec;
    768 
    769 	if ((shndx == 0) || (shndx >= obj_state->os_shnum))
    770 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_STRSHNDX),
    771 		    EC_WORD(shndx), EC_WORD(obj_state->os_shnum - 1));
    772 
    773 	strsec = &obj_state->os_secarr[shndx];
    774 	if (strsec->sec_shdr->sh_type == SHT_STRTAB) {
    775 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDSTRTAB),
    776 		    EC_WORD(shndx), strsec->sec_name);
    777 	} else if (allow_shflags &&
    778 	    ((strsec->sec_shdr->sh_flags & SHF_STRINGS) != 0) &&
    779 	    (strsec->sec_shdr->sh_entsize <= 1) &&
    780 	    (strsec->sec_shdr->sh_addralign <= 1)) {
    781 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDSTRTABFL),
    782 		    EC_WORD(shndx), strsec->sec_name);
    783 	} else {
    784 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOTSTRSH),
    785 		    EC_WORD(shndx), strsec->sec_name);
    786 	}
    787 
    788 	return (strsec);
    789 }
    790 
    791 
    792 /*
    793  * Returns the offset of the specified string from within
    794  * the given section.
    795  *
    796  * entry:
    797  *	sec - Descriptor for section
    798  *	tail_ign - If non-zero, the # of characters at the end of the
    799  *		section that should be ignored and not searched.
    800  *	str - String we are looking for.
    801  *	ret_offset - Address of variable to receive result
    802  *
    803  * exit:
    804  *	Returns 1 for success, and 0 for failure. If successful, *ret_offset
    805  *	is set to the offset of the found string within the section.
    806  */
    807 int
    808 elfedit_sec_findstr(elfedit_section_t *sec, Word tail_ign,
    809     const char *str, Word *ret_offset)
    810 {
    811 	int		str_fch = *str;	/* First character in str */
    812 	Word		len;		/* # characters in table */
    813 	char		*s;		/* ptr to strings within table */
    814 	const char	*tail;		/* 1 past final character of table */
    815 
    816 
    817 	/* Size of the section, minus the reserved part (if any) at the end */
    818 	len = sec->sec_shdr->sh_size - tail_ign;
    819 
    820 	/*
    821 	 * Move through the section character by character looking for
    822 	 * a match. Moving character by character instead of skipping
    823 	 * from NULL terminated string to string allows us to use
    824 	 * the tails longer strings (i.e. we want "bar", and "foobar" exists).
    825 	 * We look at the first character manually before calling strcmp()
    826 	 * to lower the cost of this approach.
    827 	 */
    828 	s = (char *)sec->sec_data->d_buf;
    829 	tail = s + len;
    830 	for (; s <= tail; s++) {
    831 		if ((*s == str_fch) && (strcmp(s, str) == 0)) {
    832 			*ret_offset = s - (char *)sec->sec_data->d_buf;
    833 			elfedit_msg(ELFEDIT_MSG_DEBUG,
    834 			    MSG_INTL(MSG_DEBUG_EXISTSTR),
    835 			    EC_WORD(sec->sec_shndx), sec->sec_name,
    836 			    EC_WORD(*ret_offset), s);
    837 			return (1);
    838 		}
    839 	}
    840 
    841 	/* Didn't find it. Report failure */
    842 	return (0);
    843 }
    844 
    845 
    846 /*
    847  * Locate the DT_SUNW_STRPAD element of the given dynamic section if
    848  * it exists.
    849  *
    850  * entry:
    851  *	obj_state - Object state for open object to query.
    852  *	dynsec - Dynamic section descriptor
    853  *	dyn_strpad - Address of variable to receive the results.
    854  *		The caller is responsible for calling elfedit_dyn_elt_init()
    855  *		on this variable beforehand.
    856  *
    857  * exit:
    858  *	The dynamic section is searched, and if a DT_SUNW_STRPAD element
    859  *	is found, dyn_strpad is updated via elfedit_dyn_elt_save() to
    860  *	reference it.
    861  *
    862  *	Returns the final value of dyn_strpad->dn_seen.
    863  */
    864 int
    865 elfedit_dynstr_getpad(elfedit_obj_state_t *obj_state, elfedit_section_t *dynsec,
    866     elfedit_dyn_elt_t *dyn_strpad)
    867 {
    868 	Word numdyn = dynsec->sec_shdr->sh_size / dynsec->sec_shdr->sh_entsize;
    869 	Dyn	*dyn = (Dyn *) dynsec->sec_data->d_buf;
    870 	Word	i;
    871 
    872 	/*
    873 	 * DT_SUNW_STRPAD is specific to the Solaris OSABI.
    874 	 * If the object is tagged otherwise, don't even look.
    875 	 */
    876 	if (!elfedit_test_osabi(obj_state, ELFOSABI_SOLARIS, 0))
    877 		return (dyn_strpad->dn_seen);
    878 
    879 	/* Go through dynamic section tags and find the STRPAD entry */
    880 	for (i = 0; i < numdyn; i++) {
    881 		if (dyn[i].d_tag == DT_SUNW_STRPAD) {
    882 			elfedit_dyn_elt_save(dyn_strpad, i, &dyn[i]);
    883 			break;
    884 		}
    885 	}
    886 
    887 	return (dyn_strpad->dn_seen);
    888 }
    889 
    890 
    891 
    892 /*
    893  * Given references to the dynamic section, its string table,
    894  * and the DT_SUNW_STRPAD entry of the dynamic section, returns
    895  * the offset of the specified string from within the given string table,
    896  * adding it if possible.
    897  *
    898  * entry:
    899  *	dynsec - Dynamic section descriptor
    900  *	strsec - Descriptor for string table assocated with dynamic section
    901  *	dyn_strpad - DT_SUNW_STRPAD element from dynamic section
    902  *	str - String we are looking for.
    903  *
    904  * exit:
    905  *	On success, the offset of the given string within the string
    906  *	table is returned. If the string does not exist within the table,
    907  *	but there is a valid DT_SUNW_STRPAD reserved section, then we
    908  *	add the string, and update the dynamic section STRPAD element
    909  *	to reflect the space we use.
    910  *
    911  *	This routine does not return on failure.
    912  */
    913 Word
    914 elfedit_dynstr_insert(elfedit_section_t *dynsec, elfedit_section_t *strsec,
    915     elfedit_dyn_elt_t *dyn_strpad, const char *str)
    916 {
    917 	Word	ins_off;	/* Table offset to 1st reserved byte */
    918 	char	*s;		/* ptr to strings within table */
    919 	Word	len;		/* Length of str inc. NULL byte */
    920 	Word	tail_ign;	/* # reserved bytes at end of strtab */
    921 
    922 
    923 	tail_ign = dyn_strpad->dn_seen ? dyn_strpad->dn_dyn.d_un.d_val : 0;
    924 
    925 	/* Does the string already existin the string table? */
    926 	if (elfedit_sec_findstr(strsec, tail_ign, str, &len))
    927 		return (len);
    928 
    929 	/*
    930 	 * The desired string does not already exist. Do we have
    931 	 * room to add it?
    932 	 */
    933 	len = strlen(str) + 1;
    934 	if (!dyn_strpad->dn_seen || (len > dyn_strpad->dn_dyn.d_un.d_val))
    935 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSTRPAD),
    936 		    EC_WORD(strsec->sec_shdr->sh_link),
    937 		    strsec->sec_name);
    938 
    939 
    940 	/*
    941 	 * We will add the string at the first byte of the reserved NULL
    942 	 * area at the end. The DT_SUNW_STRPAD dynamic element gives us
    943 	 * the size of that reserved space.
    944 	 */
    945 	ins_off = strsec->sec_shdr->sh_size - tail_ign;
    946 	s = ((char *)strsec->sec_data->d_buf) + ins_off;
    947 
    948 	/* Announce the operation */
    949 	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_ADDSTR),
    950 	    EC_WORD(strsec->sec_shndx), strsec->sec_name,
    951 	    EC_WORD(ins_off), EC_WORD(len),
    952 	    EC_WORD(dyn_strpad->dn_dyn.d_un.d_val), str);
    953 
    954 	/*
    955 	 * Copy the string into the pad area at the end, and
    956 	 * mark the data area as dirty so libelf will flush our
    957 	 * changes to the string data.
    958 	 */
    959 	(void) strncpy(s, str, dyn_strpad->dn_dyn.d_un.d_val);
    960 	elfedit_modified_data(strsec);
    961 
    962 	/* Update the DT_STRPAD dynamic entry */
    963 	dyn_strpad->dn_dyn.d_un.d_val -= len;
    964 	((Dyn *) dynsec->sec_data->d_buf)[dyn_strpad->dn_ndx] =
    965 	    dyn_strpad->dn_dyn;
    966 	elfedit_modified_data(dynsec);
    967 
    968 	return (ins_off);
    969 }
    970 
    971 
    972 /*
    973  * Test to see if a call to elfedit_strtab_insert() will succeed.
    974  *
    975  * entry:
    976  *	obj_state - Object state for open object to query.
    977  *	strsec - Descriptor for string table
    978  *	dynsec - NULL, or descriptor for dynamic section. Providing
    979  *		a non-NULL value here will prevent elfedit_strtab_insert()
    980  *		from looking it up, and the duplicate debug message that
    981  *		would result.
    982  *	str - String we are looking for.
    983  *
    984  * exit:
    985  *	If the string exists within the string table, or if an attempt
    986  *	to insert it will be successful, quietly return. Otherwise, throw
    987  *	the error elfedit_strtab_insert() would throw under the
    988  *	same circumstances.
    989  *
    990  */
    991 void
    992 elfedit_strtab_insert_test(elfedit_obj_state_t *obj_state,
    993     elfedit_section_t *strsec, elfedit_section_t *dynsec, const char *str)
    994 {
    995 	Word	len;		/* Length of str inc. NULL byte */
    996 	int			is_dynstr = 0;
    997 	Word			tail_ign = 0;
    998 
    999 
   1000 	/*
   1001 	 * The dynstr is a special case, because we can add strings
   1002 	 * to it under certain circumstances. So, we look for the
   1003 	 * dynamic section, and if it exists, compare its sh_link to
   1004 	 * the string section index. If they match, it is the dynstr,
   1005 	 * and we use elfedit_dynstr_insert() to do the work.
   1006 	 */
   1007 	if (dynsec == NULL) {
   1008 		if (obj_state->os_dynndx != SHN_UNDEF) {
   1009 			dynsec = &obj_state->os_secarr[obj_state->os_dynndx];
   1010 			if ((dynsec->sec_shdr->sh_type == SHT_DYNAMIC) &&
   1011 			    (strsec->sec_shndx == dynsec->sec_shdr->sh_link)) {
   1012 				is_dynstr = 1;
   1013 				elfedit_msg(ELFEDIT_MSG_DEBUG,
   1014 				    MSG_INTL(MSG_DEBUG_FNDDYN),
   1015 				    EC_WORD(dynsec->sec_shndx),
   1016 				    dynsec->sec_name);
   1017 			}
   1018 		}
   1019 	} else {
   1020 		if (strsec->sec_shndx == dynsec->sec_shdr->sh_link)
   1021 			is_dynstr = 1;
   1022 	}
   1023 
   1024 
   1025 	if (is_dynstr) {
   1026 		elfedit_dyn_elt_t dyn_strpad;
   1027 
   1028 		/* Determine the size of the STRPAD area, if any */
   1029 		elfedit_dyn_elt_init(&dyn_strpad);
   1030 		if (elfedit_dynstr_getpad(obj_state, dynsec, &dyn_strpad) != 0)
   1031 			tail_ign = dyn_strpad.dn_dyn.d_un.d_val;
   1032 	}
   1033 
   1034 	/*
   1035 	 * If the string is already in the string table, we
   1036 	 * can't fail.
   1037 	 */
   1038 	if (elfedit_sec_findstr(strsec, tail_ign, str, &len) != 0)
   1039 		return;
   1040 
   1041 	/*
   1042 	 * It's not in the table, but if this is the dynstr, and
   1043 	 * there is enough room, we will be able to add it.
   1044 	 */
   1045 	if (is_dynstr && (tail_ign > strlen(str)))
   1046 		return;
   1047 
   1048 	/* Can't do it. Issue error */
   1049 	elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSTRPAD),
   1050 	    EC_WORD(strsec->sec_shdr->sh_link), strsec->sec_name);
   1051 }
   1052 
   1053 
   1054 /*
   1055  * Returns the offset of the specified string from within
   1056  * the given string table, adding it if possible.
   1057  *
   1058  * entry:
   1059  *	obj_state - Object state for open object to query.
   1060  *	strsec - Descriptor for string table
   1061  *	dynsec - NULL, or descriptor for dynamic section. Providing
   1062  *		a non-NULL value here will prevent elfedit_strtab_insert()
   1063  *		from looking it up, and the duplicate debug message that
   1064  *		would result.
   1065  *	str - String we are looking for.
   1066  *
   1067  * exit:
   1068  *	On success, the offset of the given string within the string
   1069  *	table is returned. If the string does not exist within the table,
   1070  *	and it is possible to add it, elfedit_strtab_insert() will
   1071  *	add the string, and then return the offset.
   1072  *
   1073  *	If the string does not exist in the string table, and cannot
   1074  *	be added, this routine issues an error message and does not
   1075  *	return to the caller.
   1076  */
   1077 Word
   1078 elfedit_strtab_insert(elfedit_obj_state_t *obj_state, elfedit_section_t *strsec,
   1079     elfedit_section_t *dynsec, const char *str)
   1080 {
   1081 	Word	len;		/* Length of str inc. NULL byte */
   1082 	int			is_dynstr = 0;
   1083 	elfedit_dyn_elt_t	dyn_strpad;
   1084 
   1085 
   1086 	/*
   1087 	 * The dynstr is a special case, because we can add strings
   1088 	 * to it under certain circumstances. So, we look for the
   1089 	 * dynamic section, and if it exists, compare its sh_link to
   1090 	 * the string section index. If they match, it is the dynstr,
   1091 	 * and we use elfedit_dynstr_insert() to do the work.
   1092 	 */
   1093 	if (dynsec == NULL) {
   1094 		if (obj_state->os_dynndx != SHN_UNDEF) {
   1095 			dynsec = &obj_state->os_secarr[obj_state->os_dynndx];
   1096 			if ((dynsec->sec_shdr->sh_type == SHT_DYNAMIC) &&
   1097 			    (strsec->sec_shndx == dynsec->sec_shdr->sh_link)) {
   1098 				is_dynstr = 1;
   1099 				elfedit_msg(ELFEDIT_MSG_DEBUG,
   1100 				    MSG_INTL(MSG_DEBUG_FNDDYN),
   1101 				    EC_WORD(dynsec->sec_shndx),
   1102 				    dynsec->sec_name);
   1103 			}
   1104 		}
   1105 	} else {
   1106 		if (strsec->sec_shndx == dynsec->sec_shdr->sh_link)
   1107 			is_dynstr = 1;
   1108 	}
   1109 
   1110 	if (is_dynstr) {
   1111 		elfedit_dyn_elt_init(&dyn_strpad);
   1112 		(void) elfedit_dynstr_getpad(obj_state, dynsec, &dyn_strpad);
   1113 		return (elfedit_dynstr_insert(dynsec, strsec,
   1114 		    &dyn_strpad, str));
   1115 	}
   1116 
   1117 	/*
   1118 	 * This is not the dynstr, so we are limited to strings that
   1119 	 * already exist within it. Try to find one.
   1120 	 */
   1121 	if (elfedit_sec_findstr(strsec, 0, str, &len))
   1122 		return (len);
   1123 
   1124 	/* Can't do it. Issue error */
   1125 	elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSTRPAD),
   1126 	    EC_WORD(strsec->sec_shdr->sh_link), strsec->sec_name);
   1127 	/*NOTREACHED*/
   1128 
   1129 	return (0);
   1130 }
   1131 
   1132 
   1133 /*
   1134  * Return the string found at the given offset within the specified
   1135  * string table.
   1136  *
   1137  * entry:
   1138  *	strsec - Section descriptor for string table section
   1139  *	offset - Offset of desired string in string table
   1140  *	msg_type - ELFEDIT_MSG_ type code to use with message
   1141  *		issued if offset is out of range for the symbol table.
   1142  *	debug_msg - True if should issue debug message for string found.
   1143  *
   1144  * exit:
   1145  *	If the offset is within the section, the string pointer
   1146  *	is returned. Otherwise an error is issued using msg_type
   1147  *	to determine the type of message. If this routine retains
   1148  *	control after the message is issued, a safe string is returned.
   1149  */
   1150 const char *
   1151 elfedit_offset_to_str(elfedit_section_t *strsec, Word offset,
   1152     elfedit_msg_t msg_type, int debug_msg)
   1153 {
   1154 	const char *str;
   1155 
   1156 	/* Make sure it is a string table section */
   1157 	if (strsec->sec_shdr->sh_type != SHT_STRTAB)
   1158 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOTSTRSH),
   1159 		    EC_WORD(strsec->sec_shndx), strsec->sec_name);
   1160 
   1161 	/* Ensure the offset is in range */
   1162 	if (offset >= strsec->sec_data->d_size) {
   1163 		elfedit_msg(msg_type, MSG_INTL(MSG_ERR_BADSTROFF),
   1164 		    EC_WORD(strsec->sec_shndx), strsec->sec_name,
   1165 		    EC_WORD(offset), EC_WORD(strsec->sec_data->d_size - 1));
   1166 		/*
   1167 		 * If the msg_type is a type that returns, give the
   1168 		 * user a safe string to use.
   1169 		 */
   1170 		str = MSG_INTL(MSG_BADSYMOFFSETNAM);
   1171 	} else {
   1172 		/* Return the string */
   1173 		str = ((const char *)strsec->sec_data->d_buf) + offset;
   1174 	}
   1175 
   1176 	if (debug_msg)
   1177 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDSTR),
   1178 		    EC_WORD(strsec->sec_shndx), strsec->sec_name,
   1179 		    EC_WORD(offset), str);
   1180 	return (str);
   1181 }
   1182 
   1183 
   1184 /*
   1185  * Given a string table section, and a dynamic section entry
   1186  * that supplies a string offset, return the string found at
   1187  * the given offset. This routine is a convenience wrapper on
   1188  * elfedit_offset_to_str().
   1189  *
   1190  * exit:
   1191  *	As per elfedit_offset_to_str().
   1192  */
   1193 const char *
   1194 elfedit_dyn_offset_to_str(elfedit_section_t *strsec, elfedit_dyn_elt_t *dynelt)
   1195 {
   1196 	return (elfedit_offset_to_str(strsec, dynelt->dn_dyn.d_un.d_val,
   1197 	    ELFEDIT_MSG_ERR, 0));
   1198 }
   1199 
   1200 
   1201 /*
   1202  * Given a section, fabricate a string for the form:
   1203  *
   1204  *	"[#: name]"
   1205  *
   1206  * as used at the beginning of debug messages. A pointer to static
   1207  * memory is returned, and is good until the next such call.
   1208  */
   1209 const char *
   1210 elfedit_sec_msgprefix(elfedit_section_t *sec)
   1211 {
   1212 	static char	*buf;
   1213 	static size_t	bufsize;
   1214 
   1215 	size_t		need;
   1216 
   1217 	need = 64 + strlen(sec->sec_name);
   1218 	if (need > bufsize) {
   1219 		buf = elfedit_realloc(MSG_INTL(MSG_ALLOC_SECMSGPRE), buf, need);
   1220 		bufsize = need;
   1221 	}
   1222 
   1223 	(void) snprintf(buf, bufsize, MSG_ORIG(MSG_FMT_SECMSGPRE),
   1224 	    EC_WORD(sec->sec_shndx), sec->sec_name);
   1225 
   1226 	return (buf);
   1227 }
   1228