xref: /onnv-gate/usr/src/cmd/sgs/elfedit/common/util_machelf.c (revision 6206:6b0ed502a8e7)
15088Sab196087 /*
25088Sab196087  * CDDL HEADER START
35088Sab196087  *
45088Sab196087  * The contents of this file are subject to the terms of the
55088Sab196087  * Common Development and Distribution License (the "License").
65088Sab196087  * You may not use this file except in compliance with the License.
75088Sab196087  *
85088Sab196087  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95088Sab196087  * or http://www.opensolaris.org/os/licensing.
105088Sab196087  * See the License for the specific language governing permissions
115088Sab196087  * and limitations under the License.
125088Sab196087  *
135088Sab196087  * When distributing Covered Code, include this CDDL HEADER in each
145088Sab196087  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155088Sab196087  * If applicable, add the following below this CDDL HEADER, with the
165088Sab196087  * fields enclosed by brackets "[]" replaced with your own identifying
175088Sab196087  * information: Portions Copyright [yyyy] [name of copyright owner]
185088Sab196087  *
195088Sab196087  * CDDL HEADER END
205088Sab196087  */
215088Sab196087 
225088Sab196087 /*
235892Sab196087  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
245088Sab196087  * Use is subject to license terms.
255088Sab196087  */
265088Sab196087 #pragma ident	"%Z%%M%	%I%	%E% SMI"
275088Sab196087 
285088Sab196087 #include	<stdlib.h>
295088Sab196087 #include	<stdio.h>
305088Sab196087 #include	<unistd.h>
315088Sab196087 #include	<libintl.h>
32*6206Sab196087 #include	<_machelf.h>
335088Sab196087 #include	<libelf.h>
345088Sab196087 #include	<link.h>
355088Sab196087 #include	<strings.h>
365088Sab196087 #include	<ctype.h>
375088Sab196087 #include	"msg.h"
385088Sab196087 #include	<elfedit.h>
395088Sab196087 #include	<conv.h>
405088Sab196087 #include	<sys/elf_SPARC.h>
415088Sab196087 #include	<sys/elf_amd64.h>
425088Sab196087 
435088Sab196087 
445088Sab196087 
455088Sab196087 /*
465088Sab196087  * ELFCLASS specific code that would otherwise be found in util.c
475088Sab196087  */
485088Sab196087 
495088Sab196087 
505088Sab196087 
515088Sab196087 
525088Sab196087 /*
535088Sab196087  * When you modify ELF constructs, you need to tell libelf that you've
545088Sab196087  * done so. Otherwise, the changes may not be flushed back to the
555088Sab196087  * output file.
565088Sab196087  *
575088Sab196087  * The elfedit_modified_*() functions exist to simplify the calls to
585088Sab196087  * the underlying elf_flag*() functions.
595088Sab196087  */
605088Sab196087 void
615088Sab196087 elfedit_modified_ehdr(elfedit_obj_state_t *obj_state)
625088Sab196087 {
635088Sab196087 	(void) elf_flagehdr(obj_state->os_elf, ELF_C_SET, ELF_F_DIRTY);
645088Sab196087 }
655088Sab196087 
665088Sab196087 void
675088Sab196087 elfedit_modified_phdr(elfedit_obj_state_t *obj_state)
685088Sab196087 {
695088Sab196087 	(void) elf_flagphdr(obj_state->os_elf, ELF_C_SET, ELF_F_DIRTY);
705088Sab196087 }
715088Sab196087 
725088Sab196087 void
735088Sab196087 elfedit_modified_shdr(elfedit_section_t *s)
745088Sab196087 {
755088Sab196087 	(void) elf_flagshdr(s->sec_scn, ELF_C_SET, ELF_F_DIRTY);
765088Sab196087 }
775088Sab196087 
785088Sab196087 void
795088Sab196087 elfedit_modified_data(elfedit_section_t *s)
805088Sab196087 {
815088Sab196087 	(void) elf_flagdata(s->sec_data, ELF_C_SET, ELF_F_DIRTY);
825088Sab196087 }
835088Sab196087 
845088Sab196087 
855088Sab196087 
865088Sab196087 /*
875088Sab196087  * Prepare an elfedit_dyn_elt_t structure for use.
885088Sab196087  */
895088Sab196087 void
905088Sab196087 elfedit_dyn_elt_init(elfedit_dyn_elt_t *elt)
915088Sab196087 {
925088Sab196087 	elt->dn_seen = 0;
935088Sab196087 }
945088Sab196087 
955088Sab196087 /*
965088Sab196087  * Given a dynamic section item, save it in the given elfedit_dyn_elt_t
975088Sab196087  * structure and mark that structure to show that it is present.
985088Sab196087  */
995088Sab196087 void
1005088Sab196087 elfedit_dyn_elt_save(elfedit_dyn_elt_t *elt, Word ndx, Dyn *dyn)
1015088Sab196087 {
1025088Sab196087 	elt->dn_seen = 1;
1035088Sab196087 	elt->dn_ndx = ndx;
1045088Sab196087 	elt->dn_dyn = *dyn;
1055088Sab196087 }
1065088Sab196087 
1075088Sab196087 
1085088Sab196087 /*
1095088Sab196087  * Return the index of the first section that has the given name.
1105088Sab196087  *
1115088Sab196087  * entry:
1125088Sab196087  *	obj_state - Object state.
1135088Sab196087  *	shnam - Name of desired section
1145088Sab196087  *
1155088Sab196087  * exit:
1165088Sab196087  *	On success, returns the section index. On failure, an error
1175088Sab196087  *	is issued, and this routine does not return to the caller.
1185088Sab196087  */
1195088Sab196087 Word
1205088Sab196087 elfedit_name_to_shndx(elfedit_obj_state_t *obj_state, const char *shnam)
1215088Sab196087 {
1225088Sab196087 	elfedit_section_t *sec = obj_state->os_secarr;
1235088Sab196087 	Word	ndx;
1245088Sab196087 	Word	shnum = obj_state->os_shnum;
1255088Sab196087 
1265088Sab196087 	for (ndx = 0; ndx < shnum; ndx++, sec++) {
1275088Sab196087 		if (strcmp(shnam, sec->sec_name) == 0) {
1285088Sab196087 			elfedit_msg(ELFEDIT_MSG_DEBUG,
1295088Sab196087 			    MSG_INTL(MSG_DEBUG_SHNAM2NDX),
1305088Sab196087 			    EC_WORD(sec->sec_shndx), sec->sec_name, shnam);
1315088Sab196087 			return (ndx);
1325088Sab196087 		}
1335088Sab196087 	}
1345088Sab196087 
1355088Sab196087 	/* If didn't return in loop above, the name doesn't match */
1365088Sab196087 	elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSECNAM), shnam);
1375088Sab196087 	/*NOTREACHED*/
1385088Sab196087 	return (SHN_UNDEF);
1395088Sab196087 }
1405088Sab196087 
1415088Sab196087 
1425088Sab196087 
1435088Sab196087 /*
1445088Sab196087  * Return the index of the first section that has the given type.
1455088Sab196087  *
1465088Sab196087  * entry:
1475088Sab196087  *	obj_state - Object state.
1485088Sab196087  *	shtype - Type of desired section
1495088Sab196087  *
1505088Sab196087  * exit:
1515088Sab196087  *	On success, returns the section index. On failure, an error
1525088Sab196087  *	is issued, and this routine does not return to the caller.
1535088Sab196087  */
1545088Sab196087 Word
1555088Sab196087 elfedit_type_to_shndx(elfedit_obj_state_t *obj_state, Word shtype)
1565088Sab196087 {
1575088Sab196087 	Conv_inv_buf_t inv_buf;
1585088Sab196087 	elfedit_section_t *sec = obj_state->os_secarr;
1595088Sab196087 	Word	ndx;
1605088Sab196087 	Word	shnum = obj_state->os_shnum;
1615088Sab196087 
1625088Sab196087 	for (ndx = 0; ndx < shnum; ndx++, sec++) {
1635088Sab196087 		if (shtype == sec->sec_shdr->sh_type) {
1645088Sab196087 			elfedit_msg(ELFEDIT_MSG_DEBUG,
1655088Sab196087 			    MSG_INTL(MSG_DEBUG_SHNAM2NDX),
1665088Sab196087 			    EC_WORD(sec->sec_shndx), sec->sec_name,
1675088Sab196087 			    conv_sec_type(obj_state->os_ehdr->e_machine,
1685088Sab196087 			    shtype, 0, &inv_buf));
1695088Sab196087 			return (ndx);
1705088Sab196087 		}
1715088Sab196087 	}
1725088Sab196087 
1735088Sab196087 	/* If didn't return in loop above, the name doesn't match */
1745088Sab196087 	elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSECTYP),
1755088Sab196087 	    conv_sec_type(obj_state->os_ehdr->e_machine, shtype, 0, &inv_buf));
1765088Sab196087 	/*NOTREACHED*/
1775088Sab196087 	return (SHN_UNDEF);
1785088Sab196087 }
1795088Sab196087 
1805088Sab196087 
1815088Sab196087 
1825088Sab196087 /*
1835088Sab196087  * Locate the index of the first symbol that has the given name
1845088Sab196087  *
1855088Sab196087  * entry:
1865088Sab196087  *	obj_state - Object state.
1875088Sab196087  *	symsec - Symbol section
1885088Sab196087  *	strsec = String section
1895088Sab196087  *	name - String giving name of symbol to lookup
1905088Sab196087  *	msg_type - ELFEDIT_MSG_ type code to use with message
1915088Sab196087  *		issued if name does not exist in symbol table.
1925088Sab196087  *	ret_symndx - Address of variable to receive index.
1935088Sab196087  *
1945088Sab196087  * exit:
1955088Sab196087  *	On success, issues debug message, sets *ret_symndx, and returns
1965088Sab196087  *	True (1).
1975088Sab196087  *
1985088Sab196087  *	On failure, issues a message using msg_type to determine
1995088Sab196087  *	the type of message sent. If the message does not take control away
2005088Sab196087  *	from the caller, False (0) is returned.
2015088Sab196087  *
2025088Sab196087  * note:
2035088Sab196087  *	Although the string table is referenced by the sh_link field of
2045088Sab196087  *	the symbol table, we require the user to supply it rather than
2055088Sab196087  *	look it up. The reason for this is that the caller will usually
2065088Sab196087  *	have looked it up, and we wish to avoid multiple debug messages
2075088Sab196087  *	from being issued to that effect.
2085088Sab196087  */
2095088Sab196087 int
2105088Sab196087 elfedit_name_to_symndx(elfedit_section_t *symsec, elfedit_section_t *strsec,
2115088Sab196087     const char *name, elfedit_msg_t msg_type, Word *ret_symndx)
2125088Sab196087 
2135088Sab196087 {
2145088Sab196087 	Sym	*sym = (Sym *) symsec->sec_data->d_buf;
2155088Sab196087 	Word	cnt = symsec->sec_shdr->sh_size / symsec->sec_shdr->sh_entsize;
2165088Sab196087 	Word	ndx, offset;
2175088Sab196087 	const char	*curname;
2185088Sab196087 
2195088Sab196087 	for (ndx = 0; ndx < cnt; ndx++) {
2205088Sab196087 		offset = sym[ndx].st_name;
2215088Sab196087 
2225088Sab196087 		curname = elfedit_offset_to_str(strsec, offset,
2235088Sab196087 		    ELFEDIT_MSG_ERR, 0);
2245088Sab196087 		if (strcmp(curname, name) == 0) {
2255088Sab196087 			elfedit_msg(ELFEDIT_MSG_DEBUG,
2265088Sab196087 			    MSG_INTL(MSG_DEBUG_SYMNAM2NDX),
2275088Sab196087 			    EC_WORD(symsec->sec_shndx),
2285088Sab196087 			    symsec->sec_name, EC_WORD(ndx), name);
2295088Sab196087 			*ret_symndx = ndx;
2305088Sab196087 			return (1);
2315088Sab196087 		}
2325088Sab196087 	}
2335088Sab196087 
2345088Sab196087 	/* If didn't return in loop above, the name doesn't match */
2355088Sab196087 	elfedit_msg(msg_type, MSG_INTL(MSG_ERR_NOSYM),
2365088Sab196087 	    EC_WORD(symsec->sec_shndx), symsec->sec_name, name);
2375088Sab196087 	/*NOTREACHED*/
2385088Sab196087 	return (0);		/* lint */
2395088Sab196087 }
2405088Sab196087 
2415088Sab196087 
2425088Sab196087 /*
2435088Sab196087  * Given a section index, turn it into a descriptive string.
2445088Sab196087  *	- If it is one of the special reserved indexes, the
2455088Sab196087  *		symbolic name is returned.
2465088Sab196087  *	- If it is a regular section, in range for the file,
2475088Sab196087  *		the name associated with the section is returned.
2485088Sab196087  *	- Otherwise, the number is formatted as numeric ASCII.
2495088Sab196087  *
2505088Sab196087  * exit:
2515088Sab196087  *	A pointer to the static buffer containing the name is
2525088Sab196087  *	returned. This pointer is valid until the next call
2535088Sab196087  *	to elfedit_shndx_to_name(), and which point it may
2545088Sab196087  *	be overwritten.
2555088Sab196087  */
2565088Sab196087 const char *
2575088Sab196087 elfedit_shndx_to_name(elfedit_obj_state_t *obj_state, Word shndx)
2585088Sab196087 {
2595088Sab196087 	/*
2605088Sab196087 	 * This routine can be called twice within a single C statement,
2615088Sab196087 	 * so we use alternating buffers on each call to allow this
2625088Sab196087 	 * without requiring the caller to supply a buffer (the size of
2635088Sab196087 	 * which they don't know).
2645088Sab196087 	 */
2655088Sab196087 	static char buf1[64], buf2[64];
2665088Sab196087 	static char *buf;
2675088Sab196087 
2685088Sab196087 	if ((obj_state->os_ehdr->e_machine == EM_AMD64) &&
2695088Sab196087 	    (shndx == SHN_AMD64_LCOMMON))
2705088Sab196087 		return (MSG_ORIG(MSG_SHN_AMD64_LCOMMON));
2715088Sab196087 
2725088Sab196087 	switch (shndx) {
2735088Sab196087 	case SHN_UNDEF:
2745088Sab196087 		return (MSG_ORIG(MSG_SHN_UNDEF));
2755088Sab196087 	case SHN_SUNW_IGNORE:
2765088Sab196087 		return (MSG_ORIG(MSG_SHN_SUNW_IGNORE));
2775088Sab196087 	case SHN_BEFORE:
2785088Sab196087 		return (MSG_ORIG(MSG_SHN_BEFORE));
2795088Sab196087 	case SHN_AFTER:
2805088Sab196087 		return (MSG_ORIG(MSG_SHN_AFTER));
2815088Sab196087 	case SHN_AMD64_LCOMMON:
2825088Sab196087 		if (obj_state->os_ehdr->e_machine == EM_AMD64)
2835088Sab196087 			return (MSG_ORIG(MSG_SHN_AMD64_LCOMMON));
2845088Sab196087 		break;
2855088Sab196087 	case SHN_ABS:
2865088Sab196087 		return (MSG_ORIG(MSG_SHN_ABS));
2875088Sab196087 	case SHN_COMMON:
2885088Sab196087 		return (MSG_ORIG(MSG_SHN_COMMON));
2895088Sab196087 	case SHN_XINDEX:
2905088Sab196087 		return (MSG_ORIG(MSG_SHN_XINDEX));
2915088Sab196087 	}
2925088Sab196087 
2935088Sab196087 
2945088Sab196087 	/*
2955088Sab196087 	 * If it is outside of the reserved area, and inside the
2965088Sab196087 	 * range of section indexes in the ELF file, then show
2975088Sab196087 	 * the section name.
2985088Sab196087 	 */
2995088Sab196087 	if ((shndx < obj_state->os_shnum) &&
3005088Sab196087 	    ((shndx < SHN_LORESERVE) || (shndx > SHN_HIRESERVE)))
3015088Sab196087 		return (obj_state->os_secarr[shndx].sec_name);
3025088Sab196087 
3035088Sab196087 	/* Switch buffers */
3045088Sab196087 	buf = (buf == buf1) ? buf2 : buf1;
3055088Sab196087 
3065088Sab196087 	/*
3075088Sab196087 	 * If we haven't identified it by now, format the
3085088Sab196087 	 * number in a static buffer and return that.
3095088Sab196087 	 */
3105088Sab196087 	(void) snprintf(buf, sizeof (buf1),
3115088Sab196087 	    MSG_ORIG(MSG_FMT_WORDVAL), shndx);
3125088Sab196087 	return (buf);
3135088Sab196087 }
3145088Sab196087 
3155088Sab196087 
3165088Sab196087 /*
3175892Sab196087  * Locate the arbitrary section specified by shndx for this object.
3185892Sab196087  *
3195892Sab196087  * exit:
3205892Sab196087  *	Returns section descriptor on success. On failure, does not return.
3215892Sab196087  */
3225892Sab196087 elfedit_section_t *
3235892Sab196087 elfedit_sec_get(elfedit_obj_state_t *obj_state, Word shndx)
3245892Sab196087 {
3255892Sab196087 	elfedit_section_t *sec;
3265892Sab196087 
3275892Sab196087 	if ((shndx == 0) || (shndx >= obj_state->os_shnum))
3285892Sab196087 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADSECNDX),
3295892Sab196087 		    EC_WORD(shndx), EC_WORD(obj_state->os_shnum - 1));
3305892Sab196087 
3315892Sab196087 	sec = &obj_state->os_secarr[shndx];
3325892Sab196087 
3335892Sab196087 	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDSEC),
3345892Sab196087 	    EC_WORD(shndx), sec->sec_name);
3355892Sab196087 	return (sec);
3365892Sab196087 }
3375892Sab196087 
3385892Sab196087 
3395892Sab196087 /*
3405088Sab196087  * Locate the capabilities section for this object
3415088Sab196087  *
3425088Sab196087  * entry:
3435088Sab196087  *	obj_state - Object state for open object to query.
3445088Sab196087  *	cap - Address of variable to recieve pointer to capabilities
3455088Sab196087  *		section data buffer.
3465088Sab196087  *	num - Address of variable to receive number of items
3475088Sab196087  *		referenced by cap.
3485088Sab196087  *
3495088Sab196087  * exit:
3505088Sab196087  *	On success, returns section descriptor, and sets the
3515088Sab196087  *	variables referenced by cap and num.  On failure,
3525088Sab196087  *	does not return.
3535088Sab196087  */
3545088Sab196087 elfedit_section_t *
3555088Sab196087 elfedit_sec_getcap(elfedit_obj_state_t *obj_state, Cap **cap, Word *num)
3565088Sab196087 {
3575088Sab196087 	Word cnt;
3585088Sab196087 	elfedit_section_t *cache;
3595088Sab196087 
3605088Sab196087 	for (cnt = 1; cnt < obj_state->os_shnum; cnt++) {
3615088Sab196087 		cache = &obj_state->os_secarr[cnt];
3625088Sab196087 		if (cache->sec_shdr->sh_type == SHT_SUNW_cap) {
3635088Sab196087 			elfedit_msg(ELFEDIT_MSG_DEBUG,
3645088Sab196087 			    MSG_INTL(MSG_DEBUG_FNDCAP),
3655088Sab196087 			    EC_WORD(cnt), cache->sec_name);
3665088Sab196087 			*cap = (Cap *) cache->sec_data->d_buf;
3675088Sab196087 			*num = cache->sec_shdr->sh_size /
3685088Sab196087 			    cache->sec_shdr->sh_entsize;
3695088Sab196087 			return (cache);
3705088Sab196087 		}
3715088Sab196087 	}
3725088Sab196087 
3735088Sab196087 	/* If here, this object has no capabilities section */
3745088Sab196087 	elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOCAP));
3755088Sab196087 
3765088Sab196087 	/*NOTREACHED*/
3775088Sab196087 	return (NULL);
3785088Sab196087 }
3795088Sab196087 
3805088Sab196087 
3815088Sab196087 /*
3825088Sab196087  * Locate the dynamic section for this object
3835088Sab196087  *
3845088Sab196087  * entry:
3855088Sab196087  *	obj_state - Object state for open object to query.
3865088Sab196087  *	dyn - Address of variable to recieve pointer to dynamic
3875088Sab196087  *		section data buffer.
3885088Sab196087  *	numdyn - Address of variable to receive number of items
3895088Sab196087  *		referenced by dyn.
3905088Sab196087  *
3915088Sab196087  * exit:
3925088Sab196087  *	On success, returns section descriptor, and sets the
3935088Sab196087  *	variables referenced by dyn and numdyn.  On failure,
3945088Sab196087  *	does not return.
3955088Sab196087  */
3965088Sab196087 elfedit_section_t *
3975088Sab196087 elfedit_sec_getdyn(elfedit_obj_state_t *obj_state, Dyn **dyn, Word *num)
3985088Sab196087 {
3995088Sab196087 	elfedit_section_t *cache;
4005088Sab196087 
4015088Sab196087 	if (obj_state->os_dynndx != SHN_UNDEF) {
4025088Sab196087 		cache = &obj_state->os_secarr[obj_state->os_dynndx];
4035088Sab196087 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDDYN),
4045088Sab196087 		    EC_WORD(cache->sec_shndx), cache->sec_name);
4055088Sab196087 		*dyn = (Dyn *) cache->sec_data->d_buf;
4065088Sab196087 		*num = cache->sec_shdr->sh_size / cache->sec_shdr->sh_entsize;
4075088Sab196087 		return (cache);
4085088Sab196087 	}
4095088Sab196087 
4105088Sab196087 	/* If here, this object has no dynamic section */
4115088Sab196087 	elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NODYN));
4125088Sab196087 
4135088Sab196087 	/*NOTREACHED*/
4145088Sab196087 	return (NULL);
4155088Sab196087 }
4165088Sab196087 
4175088Sab196087 
4185088Sab196087 /*
4195088Sab196087  * Locate the syminfo section for this object
4205088Sab196087  *
4215088Sab196087  * entry:
4225088Sab196087  *	obj_state - Object state for open object to query.
4235088Sab196087  *	syminfo - Address of variable to recieve pointer to syminfo
4245088Sab196087  *		section data buffer.
4255088Sab196087  *	num - Address of variable to receive number of items
4265088Sab196087  *		referenced by syminfo.
4275088Sab196087  *
4285088Sab196087  * exit:
4295088Sab196087  *	On success, returns section descriptor, and sets the
4305088Sab196087  *	variables referenced by syminfo and num.  On failure,
4315088Sab196087  *	does not return.
4325088Sab196087  */
4335088Sab196087 elfedit_section_t *
4345088Sab196087 elfedit_sec_getsyminfo(elfedit_obj_state_t *obj_state, Syminfo **syminfo,
4355088Sab196087     Word *num)
4365088Sab196087 {
4375088Sab196087 	Word cnt;
4385088Sab196087 	elfedit_section_t *cache;
4395088Sab196087 
4405088Sab196087 	for (cnt = 1; cnt < obj_state->os_shnum; cnt++) {
4415088Sab196087 		cache = &obj_state->os_secarr[cnt];
4425088Sab196087 		if (cache->sec_shdr->sh_type == SHT_SUNW_syminfo) {
4435088Sab196087 			elfedit_msg(ELFEDIT_MSG_DEBUG,
4445088Sab196087 			    MSG_INTL(MSG_DEBUG_FNDSYMINFO),
4455088Sab196087 			    EC_WORD(cnt), cache->sec_name);
4465088Sab196087 			*syminfo = (Syminfo *) cache->sec_data->d_buf;
4475088Sab196087 			*num = cache->sec_shdr->sh_size /
4485088Sab196087 			    cache->sec_shdr->sh_entsize;
4495088Sab196087 			return (cache);
4505088Sab196087 		}
4515088Sab196087 	}
4525088Sab196087 
4535088Sab196087 	/* If here, this object has no syminfo section */
4545088Sab196087 	elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSYMINFO));
4555088Sab196087 
4565088Sab196087 	/*NOTREACHED*/
4575088Sab196087 	return (NULL);
4585088Sab196087 }
4595088Sab196087 
4605088Sab196087 
4615088Sab196087 /*
4625088Sab196087  * Check the given section to see if it is a known symbol table type.
4635088Sab196087  *
4645088Sab196087  * entry:
4655088Sab196087  *	sec - Section to check
4665088Sab196087  *	issue_err - True if this routine should issue an error and
4675088Sab196087  *		not return to the caller if sec is not a symbol table.
4685088Sab196087  *	atoui_list - NULL, or address of variable to receive a pointer to
4695088Sab196087  *		an array of elfedit_atoui_sym_t items describing the
4705088Sab196087  *		type of symbol table found. This array is useful for
4715088Sab196087  *		doing command completion.
4725088Sab196087  *
4735088Sab196087  * exit:
4745088Sab196087  *	If sec is a symbol table:
4755088Sab196087  *		- If atoui_list is non-NULL, *atoui_list is set to the
4765088Sab196087  *		  appropriate ELFEDIT_CONST_xx list of items.
4775088Sab196087  *		- True (1) is returned
4785088Sab196087  *	If sec is not a symbol table and issue_err is True:
4795088Sab196087  *		- An error is issued, and this routine does not
4805088Sab196087  *			return to the caller.
4815088Sab196087  *	Otherwise:
4825088Sab196087  *		- If atoui_list is non-NULL, *atoui_list is set to NULL.
4835088Sab196087  *		- False (0) is returned
4845088Sab196087  */
4855088Sab196087 int
4865088Sab196087 elfedit_sec_issymtab(elfedit_section_t *sec, int issue_err,
4875088Sab196087     elfedit_atoui_sym_t **atoui_list)
4885088Sab196087 {
4895088Sab196087 	elfedit_const_t		const_type;
4905088Sab196087 	int			ret = 1;
4915088Sab196087 
4925088Sab196087 	/* Is the section a symbol table? */
4935088Sab196087 	switch (sec->sec_shdr->sh_type) {
4945088Sab196087 	case SHT_SYMTAB:
4955088Sab196087 		const_type = ELFEDIT_CONST_SHT_SYMTAB;
4965088Sab196087 		break;
4975088Sab196087 	case SHT_DYNSYM:
4985088Sab196087 		const_type = ELFEDIT_CONST_SHT_DYNSYM;
4995088Sab196087 		break;
5005088Sab196087 	case SHT_SUNW_LDYNSYM:
5015088Sab196087 		const_type = ELFEDIT_CONST_SHT_LDYNSYM;
5025088Sab196087 		break;
5035088Sab196087 	default:
5045088Sab196087 		if (issue_err)
5055088Sab196087 			elfedit_msg(ELFEDIT_MSG_ERR,
5065088Sab196087 			    MSG_INTL(MSG_ERR_NOTSYMTAB),
5075088Sab196087 			    EC_WORD(sec->sec_shndx), sec->sec_name);
5085088Sab196087 		ret = 0;
5095088Sab196087 		break;
5105088Sab196087 	}
5115088Sab196087 
5125088Sab196087 	if (atoui_list != NULL)
5135088Sab196087 		*atoui_list = (ret == 0) ? NULL :
5145088Sab196087 		    elfedit_const_to_atoui(const_type);
5155088Sab196087 
5165088Sab196087 	return (ret);
5175088Sab196087 }
5185088Sab196087 
5195088Sab196087 
5205088Sab196087 
5215088Sab196087 /*
5225088Sab196087  * Locate a symbol table section for this object
5235088Sab196087  *
5245088Sab196087  * entry:
5255088Sab196087  *	obj_state - Object state for open object to query.
5265088Sab196087  *	by_index - If True, we want to locate the section with the
5275088Sab196087  *		section index given by index. If False, we return
5285088Sab196087  *		the section with the name given by name.
5295088Sab196087  *	index, name - Key to search for. See by_index.
5305088Sab196087  *	sym - Address of variable to recieve pointer to symbol
5315088Sab196087  *		section data buffer.
5325088Sab196087  *	numsym - Address of variable to receive number of symbols
5335088Sab196087  *		referenced by sym.
5345088Sab196087  *	aux_info - Address of variable to receive pointer to the
5355088Sab196087  *		elfedit_symtab_t struct that ties the symbol table and
5365088Sab196087  *		its related auxiliary sections together. NULL if this
5375088Sab196087  *		information is not required.
5385088Sab196087  *
5395088Sab196087  * exit:
5405088Sab196087  *	On success, returns section descriptor, and sets the
5415088Sab196087  *	variables referenced by sym, and numsym. On failure,
5425088Sab196087  *	does not return.
5435088Sab196087  */
5445088Sab196087 elfedit_section_t *
5455088Sab196087 elfedit_sec_getsymtab(elfedit_obj_state_t *obj_state, int by_index,
5465088Sab196087     Word index, const char *name, Sym **sym, Word *num,
5475088Sab196087     elfedit_symtab_t **aux_info)
5485088Sab196087 {
5495088Sab196087 	Word			ndx;
5505088Sab196087 	elfedit_section_t	*symsec = NULL;
5515088Sab196087 	elfedit_symtab_t	*symtab;
5525088Sab196087 	const char 		*type_name;
5535088Sab196087 
5545088Sab196087 	/* If looking it up by index, make sure the index is in range */
5555088Sab196087 	if (by_index && (index >= obj_state->os_shnum))
5565088Sab196087 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADSECNDX),
5575088Sab196087 		    EC_WORD(index), EC_WORD(obj_state->os_shnum - 1));
5585088Sab196087 
5595088Sab196087 	/*
5605088Sab196087 	 * Look at each known symbol table in turn until the desired
5615088Sab196087 	 * one is hit, or there are no more.
5625088Sab196087 	 */
5635088Sab196087 	symtab = obj_state->os_symtab;
5645088Sab196087 	for (ndx = 0; ndx < obj_state->os_symtabnum; ndx++, symtab++) {
5655088Sab196087 		elfedit_section_t *s =
5665088Sab196087 		    &obj_state->os_secarr[symtab->symt_shndx];
5675088Sab196087 
5685088Sab196087 		if ((by_index && (symtab->symt_shndx == index)) ||
5695088Sab196087 		    (!by_index && (strcmp(s->sec_name, name) == 0))) {
5705088Sab196087 				symsec = s;
5715088Sab196087 				break;
5725088Sab196087 		}
5735088Sab196087 	}
5745088Sab196087 
5755088Sab196087 	/* Did we get a section? */
5765088Sab196087 	if (symsec == NULL)
5775088Sab196087 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSYMTAB));
5785088Sab196087 
5795088Sab196087 	/* Got it. Report to the user and return the necessary data */
5805088Sab196087 	(void) elfedit_sec_issymtab(symsec, 1, NULL);
5815088Sab196087 	type_name = elfedit_atoconst_value_to_str(ELFEDIT_CONST_SHT_ALLSYMTAB,
5825088Sab196087 	    symsec->sec_shdr->sh_type, 1);
5835088Sab196087 	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDSYMTAB),
5845088Sab196087 	    EC_WORD(symsec->sec_shndx), symsec->sec_name, type_name);
5855088Sab196087 	*sym = (Sym *) symsec->sec_data->d_buf;
5865088Sab196087 	*num = symsec->sec_shdr->sh_size / symsec->sec_shdr->sh_entsize;
5875088Sab196087 	if (aux_info != NULL)
5885088Sab196087 		*aux_info = symtab;
5895088Sab196087 	return (symsec);
5905088Sab196087 }
5915088Sab196087 
5925088Sab196087 
5935088Sab196087 
5945088Sab196087 /*
5955088Sab196087  * Locate the extended symbol index section associated with a symbol
5965088Sab196087  * table section.
5975088Sab196087  *
5985088Sab196087  * entry:
5995088Sab196087  *	obj_state - Object state for open object to query.
6005088Sab196087  *	symsec - Symbol table section for which extended index
6015088Sab196087  *		index section is required.
6025088Sab196087  *	xshndx - Address of variable to recieve pointer to section index
6035088Sab196087  *		array data buffer.
6045088Sab196087  *	numxshndx - Address of variable to receive number of indices
6055088Sab196087  *		referenced by ndx.
6065088Sab196087  *
6075088Sab196087  * exit:
6085088Sab196087  *	On success, returns extended index section descriptor, and sets the
6095088Sab196087  *	variables referenced by xshndx, and numxshndx. On failure,
6105088Sab196087  *	does not return.
6115088Sab196087  *
6125088Sab196087  * note:
6135088Sab196087  *	Since the extended section index is found in the sec_xshndx field
6145088Sab196087  *	of the elfedit_section_t, the caller may be tempted to bypass this
6155088Sab196087  *	routine and access it directly. That temptation should be resisted,
6165088Sab196087  *	as this routine performs useful error checking, and also handles
6175088Sab196087  *	the issuing of the standard MSG_DEBUG messages.
6185088Sab196087  */
6195088Sab196087 elfedit_section_t *
6205088Sab196087 elfedit_sec_getxshndx(elfedit_obj_state_t *obj_state,
6215088Sab196087     elfedit_section_t *symsec, Word **xshndx, Word *num)
6225088Sab196087 {
6235088Sab196087 	elfedit_section_t	*xshndxsec;
6245088Sab196087 	elfedit_symtab_t	*symtab;
6255088Sab196087 	Word			ndx;
6265088Sab196087 
6275088Sab196087 	/* Sanity check: symsec must be a symbol table */
6285088Sab196087 	(void) elfedit_sec_issymtab(symsec, 1, NULL);
6295088Sab196087 
6305088Sab196087 	symtab = obj_state->os_symtab;
6315088Sab196087 	for (ndx = 0; ndx < obj_state->os_symtabnum; ndx++, symtab++)
6325088Sab196087 		if (symsec->sec_shndx == symtab->symt_shndx)
6335088Sab196087 			break;
6345088Sab196087 
6355088Sab196087 	/*
6365088Sab196087 	 * Issue error if the symbol table lacks an extended index section.
6375088Sab196087 	 * The caller won't ask unless they encounter an SHN_XINDEX value,
6385088Sab196087 	 * in which case the lack of the index section denotes a corrupt
6395088Sab196087 	 * ELF file.
6405088Sab196087 	 */
6415088Sab196087 	if ((ndx == obj_state->os_symtabnum) ||
6425088Sab196087 	    (symtab->symt_xshndx == SHN_UNDEF))
6435088Sab196087 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOXSHSEC),
6445088Sab196087 		    EC_WORD(symsec->sec_shndx), symsec->sec_name);
6455088Sab196087 
6465088Sab196087 	/* Got it. Report to the user and return the necessary data */
6475088Sab196087 	xshndxsec = &obj_state->os_secarr[symtab->symt_xshndx];
6485088Sab196087 	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDXSHNDX),
6495088Sab196087 	    EC_WORD(symsec->sec_shndx), symsec->sec_name,
6505088Sab196087 	    EC_WORD(xshndxsec->sec_shndx), xshndxsec->sec_name);
6515088Sab196087 	*xshndx = (Word *) xshndxsec->sec_data->d_buf;
6525088Sab196087 	*num = xshndxsec->sec_shdr->sh_size / xshndxsec->sec_shdr->sh_entsize;
6535088Sab196087 	return (xshndxsec);
6545088Sab196087 }
6555088Sab196087 
6565088Sab196087 
6575088Sab196087 
6585088Sab196087 /*
6595088Sab196087  * Locate the versym section associated with a symbol table section.
6605088Sab196087  *
6615088Sab196087  * entry:
6625088Sab196087  *	obj_state - Object state for open object to query.
6635088Sab196087  *	symsec - Symbol table section for which extended index
6645088Sab196087  *		index section is required.
6655088Sab196087  *	versym - Address of variable to recieve pointer to section index
6665088Sab196087  *		array data buffer.
6675088Sab196087  *	numversym - Address of variable to receive number of indices
6685088Sab196087  *		referenced by ndx.
6695088Sab196087  *
6705088Sab196087  * exit:
6715088Sab196087  *	On success, returns versym section descriptor, and sets the
6725088Sab196087  *	variables referenced by versym, and numversym. On failure,
6735088Sab196087  *	does not return.
6745088Sab196087  *
6755088Sab196087  * note:
6765088Sab196087  *	Since the versym section index is found in the sec_versym field
6775088Sab196087  *	of the elfedit_section_t, the caller may be tempted to bypass this
6785088Sab196087  *	routine and access it directly. That temptation should be resisted,
6795088Sab196087  *	as this routine performs useful error checking, and also handles
6805088Sab196087  *	the issuing of the standard MSG_DEBUG messages.
6815088Sab196087  */
6825088Sab196087 elfedit_section_t *
6835088Sab196087 elfedit_sec_getversym(elfedit_obj_state_t *obj_state,
6845088Sab196087     elfedit_section_t *symsec, Versym **versym, Word *num)
6855088Sab196087 {
6865088Sab196087 	elfedit_section_t	*versymsec;
6875088Sab196087 	elfedit_symtab_t	*symtab;
6885088Sab196087 	Word			ndx;
6895088Sab196087 
6905088Sab196087 	/* Sanity check: symsec must be a symbol table */
6915088Sab196087 	(void) elfedit_sec_issymtab(symsec, 1, NULL);
6925088Sab196087 
6935088Sab196087 	symtab = obj_state->os_symtab;
6945088Sab196087 	for (ndx = 0; ndx < obj_state->os_symtabnum; ndx++, symtab++)
6955088Sab196087 		if (symsec->sec_shndx == symtab->symt_shndx)
6965088Sab196087 			break;
6975088Sab196087 	/*
6985088Sab196087 	 * Issue error if the symbol table lacks a versym section.
6995088Sab196087 	 * The caller won't ask unless they see a non-null
7005088Sab196087 	 * aux.symtab.sec_versym, so this should not be a problem.
7015088Sab196087 	 */
7025088Sab196087 	if ((ndx == obj_state->os_symtabnum) ||
7035088Sab196087 	    (symtab->symt_versym == SHN_UNDEF))
7045088Sab196087 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOVERSYMSEC),
7055088Sab196087 		    EC_WORD(symsec->sec_shndx), symsec->sec_name);
7065088Sab196087 
7075088Sab196087 	/* Got it. Report to the user and return the necessary data */
7085088Sab196087 	versymsec = &obj_state->os_secarr[symtab->symt_versym];
7095088Sab196087 	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDVERSYM),
7105088Sab196087 	    EC_WORD(symsec->sec_shndx), symsec->sec_name,
7115088Sab196087 	    EC_WORD(versymsec->sec_shndx), versymsec->sec_name);
7125088Sab196087 	*versym = (Versym *) versymsec->sec_data->d_buf;
7135088Sab196087 	*num = versymsec->sec_shdr->sh_size / versymsec->sec_shdr->sh_entsize;
7145088Sab196087 	return (versymsec);
7155088Sab196087 }
7165088Sab196087 
7175088Sab196087 
7185088Sab196087 
7195088Sab196087 /*
7205088Sab196087  * Locate the string table specified by shndx for this object.
7215088Sab196087  *
7225088Sab196087  * exit:
7235088Sab196087  *	Returns section descriptor on success. On failure, does not return.
7245088Sab196087  */
7255088Sab196087 elfedit_section_t *
7265088Sab196087 elfedit_sec_getstr(elfedit_obj_state_t *obj_state, Word shndx)
7275088Sab196087 {
7285088Sab196087 	elfedit_section_t *strsec;
7295088Sab196087 
7305088Sab196087 	if ((shndx == 0) || (shndx >= obj_state->os_shnum))
7315088Sab196087 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_STRSHNDX),
7325892Sab196087 		    EC_WORD(shndx), EC_WORD(obj_state->os_shnum - 1));
7335088Sab196087 
7345088Sab196087 	strsec = &obj_state->os_secarr[shndx];
7355088Sab196087 	if (strsec->sec_shdr->sh_type != SHT_STRTAB)
7365088Sab196087 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOTSTRSH),
7375088Sab196087 		    EC_WORD(shndx), strsec->sec_name);
7385088Sab196087 
7395088Sab196087 	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDSTRTAB),
7405088Sab196087 	    EC_WORD(shndx), strsec->sec_name);
7415088Sab196087 	return (strsec);
7425088Sab196087 }
7435088Sab196087 
7445088Sab196087 
7455088Sab196087 /*
7465088Sab196087  * Returns the offset of the specified string from within
7475088Sab196087  * the given section.
7485088Sab196087  *
7495088Sab196087  * entry:
7505088Sab196087  *	sec - Descriptor for section
7515088Sab196087  *	tail_ign - If non-zero, the # of characters at the end of the
7525088Sab196087  *		section that should be ignored and not searched.
7535088Sab196087  *	str - String we are looking for.
7545088Sab196087  *	ret_offset - Address of variable to receive result
7555088Sab196087  *
7565088Sab196087  * exit:
7575088Sab196087  *	Returns 1 for success, and 0 for failure. If successful, *ret_offset
7585088Sab196087  *	is set to the offset of the found string within the section.
7595088Sab196087  */
7605088Sab196087 int
7615088Sab196087 elfedit_sec_findstr(elfedit_section_t *sec, Word tail_ign,
7625088Sab196087     const char *str, Word *ret_offset)
7635088Sab196087 {
7645088Sab196087 	int		str_fch = *str;	/* First character in str */
7655088Sab196087 	Word		len;		/* # characters in table */
7665088Sab196087 	char		*s;		/* ptr to strings within table */
7675088Sab196087 	const char	*tail;		/* 1 past final character of table */
7685088Sab196087 
7695088Sab196087 
7705088Sab196087 	/* Size of the section, minus the reserved part (if any) at the end */
7715088Sab196087 	len = sec->sec_shdr->sh_size - tail_ign;
7725088Sab196087 
7735088Sab196087 	/*
7745088Sab196087 	 * Move through the section character by character looking for
7755088Sab196087 	 * a match. Moving character by character instead of skipping
7765088Sab196087 	 * from NULL terminated string to string allows us to use
7775088Sab196087 	 * the tails longer strings (i.e. we want "bar", and "foobar" exists).
7785088Sab196087 	 * We look at the first character manually before calling strcmp()
7795088Sab196087 	 * to lower the cost of this approach.
7805088Sab196087 	 */
7815088Sab196087 	s = (char *)sec->sec_data->d_buf;
7825088Sab196087 	tail = s + len;
7835088Sab196087 	for (; s <= tail; s++) {
7845088Sab196087 		if ((*s == str_fch) && (strcmp(s, str) == 0)) {
7855088Sab196087 			*ret_offset = s - (char *)sec->sec_data->d_buf;
7865088Sab196087 			elfedit_msg(ELFEDIT_MSG_DEBUG,
7875088Sab196087 			    MSG_INTL(MSG_DEBUG_EXISTSTR),
7885088Sab196087 			    EC_WORD(sec->sec_shndx), sec->sec_name,
7895088Sab196087 			    EC_WORD(*ret_offset), s);
7905088Sab196087 			return (1);
7915088Sab196087 		}
7925088Sab196087 	}
7935088Sab196087 
7945088Sab196087 	/* Didn't find it. Report failure */
7955088Sab196087 	return (0);
7965088Sab196087 }
7975088Sab196087 
7985088Sab196087 
7995088Sab196087 /*
8005088Sab196087  * Locate the DT_SUNW_STRPAD element of the given dynamic section if
8015088Sab196087  * it exists.
8025088Sab196087  *
8035088Sab196087  * entry:
8045088Sab196087  *	dynsec - Dynamic section descriptor
8055088Sab196087  *	dyn_strpad - Address of variable to receive the results.
8065088Sab196087  *		The caller is responsible for calling elfedit_dyn_elt_init()
8075088Sab196087  *		on this variable beforehand.
8085088Sab196087  *
8095088Sab196087  * exit:
8105088Sab196087  *	The dynamic section is searched, and if a DT_SUNW_STRPAD element
8115088Sab196087  *	is found, dyn_strpad is updated via elfedit_dyn_elt_save() to
8125088Sab196087  *	reference it.
8135088Sab196087  *
8145088Sab196087  *	Returns the final value of dyn_strpad->dn_seen.
8155088Sab196087  */
8165088Sab196087 int
8175088Sab196087 elfedit_dynstr_getpad(elfedit_section_t *dynsec, elfedit_dyn_elt_t *dyn_strpad)
8185088Sab196087 {
8195088Sab196087 	Dyn	*dyn = (Dyn *) dynsec->sec_data->d_buf;
8205088Sab196087 	Word numdyn = dynsec->sec_shdr->sh_size / dynsec->sec_shdr->sh_entsize;
8215088Sab196087 	Word i;
8225088Sab196087 
8235088Sab196087 	/* Go through dynamic section tags and find the STRPAD entry */
8245088Sab196087 	for (i = 0; i < numdyn; i++) {
8255088Sab196087 		if (dyn[i].d_tag == DT_SUNW_STRPAD) {
8265088Sab196087 			elfedit_dyn_elt_save(dyn_strpad, i, &dyn[i]);
8275088Sab196087 			break;
8285088Sab196087 		}
8295088Sab196087 	}
8305088Sab196087 
8315088Sab196087 	return (dyn_strpad->dn_seen);
8325088Sab196087 }
8335088Sab196087 
8345088Sab196087 
8355088Sab196087 
8365088Sab196087 /*
8375088Sab196087  * Given references to the dynamic section, its string table,
8385088Sab196087  * and the DT_SUNW_STRPAD entry of the dynamic section, returns
8395088Sab196087  * the offset of the specified string from within the given string table,
8405088Sab196087  * adding it if possible.
8415088Sab196087  *
8425088Sab196087  * entry:
8435088Sab196087  *	dynsec - Dynamic section descriptor
8445088Sab196087  *	strsec - Descriptor for string table assocated with dynamic section
8455088Sab196087  *	dyn_strpad - DT_SUNW_STRPAD element from dynamic section
8465088Sab196087  *	str - String we are looking for.
8475088Sab196087  *
8485088Sab196087  * exit:
8495088Sab196087  *	On success, the offset of the given string within the string
8505088Sab196087  *	table is returned. If the string does not exist within the table,
8515088Sab196087  *	but there is a valid DT_SUNW_STRPAD reserved section, then we
8525088Sab196087  *	add the string, and update the dynamic section STRPAD element
8535088Sab196087  *	to reflect the space we use.
8545088Sab196087  *
8555088Sab196087  *	This routine does not return on failure.
8565088Sab196087  */
8575088Sab196087 Word
8585088Sab196087 elfedit_dynstr_insert(elfedit_section_t *dynsec, elfedit_section_t *strsec,
8595088Sab196087     elfedit_dyn_elt_t *dyn_strpad, const char *str)
8605088Sab196087 {
8615088Sab196087 	Word	ins_off;	/* Table offset to 1st reserved byte */
8625088Sab196087 	char	*s;		/* ptr to strings within table */
8635088Sab196087 	Word	len;		/* Length of str inc. NULL byte */
8645088Sab196087 	Word	tail_ign;	/* # reserved bytes at end of strtab */
8655088Sab196087 
8665088Sab196087 
8675088Sab196087 	tail_ign = dyn_strpad->dn_seen ? dyn_strpad->dn_dyn.d_un.d_val : 0;
8685088Sab196087 
8695088Sab196087 	/* Does the string already existin the string table? */
8705088Sab196087 	if (elfedit_sec_findstr(strsec, tail_ign, str, &len))
8715088Sab196087 		return (len);
8725088Sab196087 
8735088Sab196087 	/*
8745088Sab196087 	 * The desired string does not already exist. Do we have
8755088Sab196087 	 * room to add it?
8765088Sab196087 	 */
8775088Sab196087 	len = strlen(str) + 1;
8785088Sab196087 	if (!dyn_strpad->dn_seen || (len > dyn_strpad->dn_dyn.d_un.d_val))
8795088Sab196087 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSTRPAD),
8805088Sab196087 		    EC_WORD(strsec->sec_shdr->sh_link),
8815088Sab196087 		    strsec->sec_name);
8825088Sab196087 
8835088Sab196087 
8845088Sab196087 	/*
8855088Sab196087 	 * We will add the string at the first byte of the reserved NULL
8865088Sab196087 	 * area at the end. The DT_SUNW_STRPAD dynamic element gives us
8875088Sab196087 	 * the size of that reserved space.
8885088Sab196087 	 */
8895088Sab196087 	ins_off = strsec->sec_shdr->sh_size - tail_ign;
8905088Sab196087 	s = ((char *)strsec->sec_data->d_buf) + ins_off;
8915088Sab196087 
8925088Sab196087 	/* Announce the operation */
8935088Sab196087 	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_ADDSTR),
8945088Sab196087 	    EC_WORD(strsec->sec_shndx), strsec->sec_name,
8955088Sab196087 	    EC_WORD(ins_off), EC_WORD(len),
8965088Sab196087 	    EC_WORD(dyn_strpad->dn_dyn.d_un.d_val), str);
8975088Sab196087 
8985088Sab196087 	/*
8995088Sab196087 	 * Copy the string into the pad area at the end, and
9005088Sab196087 	 * mark the data area as dirty so libelf will flush our
9015088Sab196087 	 * changes to the string data.
9025088Sab196087 	 */
9035088Sab196087 	(void) strncpy(s, str, dyn_strpad->dn_dyn.d_un.d_val);
9045088Sab196087 	elfedit_modified_data(strsec);
9055088Sab196087 
9065088Sab196087 	/* Update the DT_STRPAD dynamic entry */
9075088Sab196087 	dyn_strpad->dn_dyn.d_un.d_val -= len;
9085088Sab196087 	((Dyn *) dynsec->sec_data->d_buf)[dyn_strpad->dn_ndx] =
9095088Sab196087 	    dyn_strpad->dn_dyn;
9105088Sab196087 	elfedit_modified_data(dynsec);
9115088Sab196087 
9125088Sab196087 	return (ins_off);
9135088Sab196087 }
9145088Sab196087 
9155088Sab196087 
9165088Sab196087 /*
9175088Sab196087  * Test to see if a call to elfedit_strtab_insert() will succeed.
9185088Sab196087  *
9195088Sab196087  * entry:
9205088Sab196087  *	obj_state - Object state for open object to query.
9215088Sab196087  *	strsec - Descriptor for string table
9225088Sab196087  *	dynsec - NULL, or descriptor for dynamic section. Providing
9235088Sab196087  *		a non-NULL value here will prevent elfedit_strtab_insert()
9245088Sab196087  *		from looking it up, and the duplicate debug message that
9255088Sab196087  *		would result.
9265088Sab196087  *	str - String we are looking for.
9275088Sab196087  *
9285088Sab196087  * exit:
9295088Sab196087  *	If the string exists within the string table, or if an attempt
9305088Sab196087  *	to insert it will be successful, quietly return. Otherwise, throw
9315088Sab196087  *	the error elfedit_strtab_insert() would throw under the
9325088Sab196087  *	same circumstances.
9335088Sab196087  *
9345088Sab196087  */
9355088Sab196087 void
9365088Sab196087 elfedit_strtab_insert_test(elfedit_obj_state_t *obj_state,
9375088Sab196087     elfedit_section_t *strsec, elfedit_section_t *dynsec, const char *str)
9385088Sab196087 {
9395088Sab196087 	Word	len;		/* Length of str inc. NULL byte */
9405088Sab196087 	int			is_dynstr = 0;
9415088Sab196087 	Word			tail_ign = 0;
9425088Sab196087 
9435088Sab196087 
9445088Sab196087 	/*
9455088Sab196087 	 * The dynstr is a special case, because we can add strings
9465088Sab196087 	 * to it under certain circumstances. So, we look for the
9475088Sab196087 	 * dynamic section, and if it exists, compare its sh_link to
9485088Sab196087 	 * the string section index. If they match, it is the dynstr,
9495088Sab196087 	 * and we use elfedit_dynstr_insert() to do the work.
9505088Sab196087 	 */
9515088Sab196087 	if (dynsec == NULL) {
9525088Sab196087 		if (obj_state->os_dynndx != SHN_UNDEF) {
9535088Sab196087 			dynsec = &obj_state->os_secarr[obj_state->os_dynndx];
9545088Sab196087 			if ((dynsec->sec_shdr->sh_type == SHT_DYNAMIC) &&
9555088Sab196087 			    (strsec->sec_shndx == dynsec->sec_shdr->sh_link)) {
9565088Sab196087 				is_dynstr = 1;
9575088Sab196087 				elfedit_msg(ELFEDIT_MSG_DEBUG,
9585088Sab196087 				    MSG_INTL(MSG_DEBUG_FNDDYN),
9595088Sab196087 				    EC_WORD(dynsec->sec_shndx),
9605088Sab196087 				    dynsec->sec_name);
9615088Sab196087 			}
9625088Sab196087 		}
9635088Sab196087 	} else {
9645088Sab196087 		if (strsec->sec_shndx == dynsec->sec_shdr->sh_link)
9655088Sab196087 			is_dynstr = 1;
9665088Sab196087 	}
9675088Sab196087 
9685088Sab196087 
9695088Sab196087 	if (is_dynstr) {
9705088Sab196087 		elfedit_dyn_elt_t dyn_strpad;
9715088Sab196087 
9725088Sab196087 		/* Determine the size of the STRPAD area, if any */
9735088Sab196087 		elfedit_dyn_elt_init(&dyn_strpad);
9745088Sab196087 		if (elfedit_dynstr_getpad(dynsec, &dyn_strpad) != 0)
9755088Sab196087 			tail_ign = dyn_strpad.dn_dyn.d_un.d_val;
9765088Sab196087 	}
9775088Sab196087 
9785088Sab196087 	/*
9795088Sab196087 	 * If the string is already in the string table, we
9805088Sab196087 	 * can't fail.
9815088Sab196087 	 */
9825088Sab196087 	if (elfedit_sec_findstr(strsec, tail_ign, str, &len) != 0)
9835088Sab196087 		return;
9845088Sab196087 
9855088Sab196087 	/*
9865088Sab196087 	 * It's not in the table, but if this is the dynstr, and
9875088Sab196087 	 * there is enough room, we will be able to add it.
9885088Sab196087 	 */
9895088Sab196087 	if (is_dynstr && (tail_ign > strlen(str)))
9905088Sab196087 		return;
9915088Sab196087 
9925088Sab196087 	/* Can't do it. Issue error */
9935088Sab196087 	elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSTRPAD),
9945088Sab196087 	    EC_WORD(strsec->sec_shdr->sh_link), strsec->sec_name);
9955088Sab196087 }
9965088Sab196087 
9975088Sab196087 
9985088Sab196087 /*
9995088Sab196087  * Returns the offset of the specified string from within
10005088Sab196087  * the given string table, adding it if possible.
10015088Sab196087  *
10025088Sab196087  * entry:
10035088Sab196087  *	obj_state - Object state for open object to query.
10045088Sab196087  *	strsec - Descriptor for string table
10055088Sab196087  *	dynsec - NULL, or descriptor for dynamic section. Providing
10065088Sab196087  *		a non-NULL value here will prevent elfedit_strtab_insert()
10075088Sab196087  *		from looking it up, and the duplicate debug message that
10085088Sab196087  *		would result.
10095088Sab196087  *	str - String we are looking for.
10105088Sab196087  *
10115088Sab196087  * exit:
10125088Sab196087  *	On success, the offset of the given string within the string
10135088Sab196087  *	table is returned. If the string does not exist within the table,
10145088Sab196087  *	and it is possible to add it, elfedit_strtab_insert() will
10155088Sab196087  *	add the string, and then return the offset.
10165088Sab196087  *
10175088Sab196087  *	If the string does not exist in the string table, and cannot
10185088Sab196087  *	be added, this routine issues an error message and does not
10195088Sab196087  *	return to the caller.
10205088Sab196087  */
10215088Sab196087 Word
10225088Sab196087 elfedit_strtab_insert(elfedit_obj_state_t *obj_state, elfedit_section_t *strsec,
10235088Sab196087     elfedit_section_t *dynsec, const char *str)
10245088Sab196087 {
10255088Sab196087 	Word	len;		/* Length of str inc. NULL byte */
10265088Sab196087 	int			is_dynstr = 0;
10275088Sab196087 	elfedit_dyn_elt_t	dyn_strpad;
10285088Sab196087 
10295088Sab196087 
10305088Sab196087 	/*
10315088Sab196087 	 * The dynstr is a special case, because we can add strings
10325088Sab196087 	 * to it under certain circumstances. So, we look for the
10335088Sab196087 	 * dynamic section, and if it exists, compare its sh_link to
10345088Sab196087 	 * the string section index. If they match, it is the dynstr,
10355088Sab196087 	 * and we use elfedit_dynstr_insert() to do the work.
10365088Sab196087 	 */
10375088Sab196087 	if (dynsec == NULL) {
10385088Sab196087 		if (obj_state->os_dynndx != SHN_UNDEF) {
10395088Sab196087 			dynsec = &obj_state->os_secarr[obj_state->os_dynndx];
10405088Sab196087 			if ((dynsec->sec_shdr->sh_type == SHT_DYNAMIC) &&
10415088Sab196087 			    (strsec->sec_shndx == dynsec->sec_shdr->sh_link)) {
10425088Sab196087 				is_dynstr = 1;
10435088Sab196087 				elfedit_msg(ELFEDIT_MSG_DEBUG,
10445088Sab196087 				    MSG_INTL(MSG_DEBUG_FNDDYN),
10455088Sab196087 				    EC_WORD(dynsec->sec_shndx),
10465088Sab196087 				    dynsec->sec_name);
10475088Sab196087 			}
10485088Sab196087 		}
10495088Sab196087 	} else {
10505088Sab196087 		if (strsec->sec_shndx == dynsec->sec_shdr->sh_link)
10515088Sab196087 			is_dynstr = 1;
10525088Sab196087 	}
10535088Sab196087 
10545088Sab196087 	if (is_dynstr) {
10555088Sab196087 		elfedit_dyn_elt_init(&dyn_strpad);
10565088Sab196087 		(void) elfedit_dynstr_getpad(dynsec, &dyn_strpad);
10575088Sab196087 		return (elfedit_dynstr_insert(dynsec, strsec,
10585088Sab196087 		    &dyn_strpad, str));
10595088Sab196087 	}
10605088Sab196087 
10615088Sab196087 	/*
10625088Sab196087 	 * This is not the dynstr, so we are limited to strings that
10635088Sab196087 	 * already exist within it. Try to find one.
10645088Sab196087 	 */
10655088Sab196087 	if (elfedit_sec_findstr(strsec, 0, str, &len))
10665088Sab196087 		return (len);
10675088Sab196087 
10685088Sab196087 	/* Can't do it. Issue error */
10695088Sab196087 	elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSTRPAD),
10705088Sab196087 	    EC_WORD(strsec->sec_shdr->sh_link), strsec->sec_name);
10715088Sab196087 	/*NOTREACHED*/
10725088Sab196087 
10735088Sab196087 	return (0);
10745088Sab196087 }
10755088Sab196087 
10765088Sab196087 
10775088Sab196087 /*
10785088Sab196087  * Return the string found at the given offset within the specified
10795088Sab196087  * string table.
10805088Sab196087  *
10815088Sab196087  * entry:
10825088Sab196087  *	strsec - Section descriptor for string table section
10835088Sab196087  *	offset - Offset of desired string in string table
10845088Sab196087  *	msg_type - ELFEDIT_MSG_ type code to use with message
10855088Sab196087  *		issued if offset is out of range for the symbol table.
10865088Sab196087  *	debug_msg - True if should issue debug message for string found.
10875088Sab196087  *
10885088Sab196087  * exit:
10895088Sab196087  *	If the offset is within the section, the string pointer
10905088Sab196087  *	is returned. Otherwise an error is issued using msg_type
10915088Sab196087  *	to determine the type of message. If this routine retains
10925088Sab196087  *	control after the message is issued, a safe string is returned.
10935088Sab196087  */
10945088Sab196087 const char *
10955088Sab196087 elfedit_offset_to_str(elfedit_section_t *strsec, Word offset,
10965088Sab196087     elfedit_msg_t msg_type, int debug_msg)
10975088Sab196087 {
10985088Sab196087 	const char *str;
10995088Sab196087 
11005088Sab196087 	/* Make sure it is a string table section */
11015088Sab196087 	if (strsec->sec_shdr->sh_type != SHT_STRTAB)
11025088Sab196087 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOTSTRSH),
11035088Sab196087 		    EC_WORD(strsec->sec_shndx), strsec->sec_name);
11045088Sab196087 
11055088Sab196087 	/* Ensure the offset is in range */
11065088Sab196087 	if (offset >= strsec->sec_data->d_size) {
11075088Sab196087 		elfedit_msg(msg_type, MSG_INTL(MSG_ERR_BADSTROFF),
11085088Sab196087 		    EC_WORD(strsec->sec_shndx), strsec->sec_name,
11095088Sab196087 		    EC_WORD(offset), EC_WORD(strsec->sec_data->d_size - 1));
11105088Sab196087 		/*
11115088Sab196087 		 * If the msg_type is a type that returns, give the
11125088Sab196087 		 * user a safe string to use.
11135088Sab196087 		 */
11145088Sab196087 		str = MSG_INTL(MSG_BADSYMOFFSETNAM);
11155088Sab196087 	} else {
11165088Sab196087 		/* Return the string */
11175088Sab196087 		str = ((const char *)strsec->sec_data->d_buf) + offset;
11185088Sab196087 	}
11195088Sab196087 
11205088Sab196087 	if (debug_msg)
11215088Sab196087 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDSTR),
11225088Sab196087 		    EC_WORD(strsec->sec_shndx), strsec->sec_name,
11235088Sab196087 		    EC_WORD(offset), str);
11245088Sab196087 	return (str);
11255088Sab196087 }
11265088Sab196087 
11275088Sab196087 
11285088Sab196087 /*
11295088Sab196087  * Given a string table section, and a dynamic section entry
11305088Sab196087  * that supplies a string offset, return the string found at
11315088Sab196087  * the given offset. This routine is a convenience wrapper on
11325088Sab196087  * elfedit_offset_to_str().
11335088Sab196087  *
11345088Sab196087  * exit:
11355088Sab196087  *	As per elfedit_offset_to_str().
11365088Sab196087  */
11375088Sab196087 const char *
11385088Sab196087 elfedit_dyn_offset_to_str(elfedit_section_t *strsec, elfedit_dyn_elt_t *dynelt)
11395088Sab196087 {
11405088Sab196087 	return (elfedit_offset_to_str(strsec, dynelt->dn_dyn.d_un.d_val,
11415088Sab196087 	    ELFEDIT_MSG_ERR, 0));
11425088Sab196087 }
11435088Sab196087 
11445088Sab196087 
11455088Sab196087 /*
11465088Sab196087  * Given a section, fabricate a string for the form:
11475088Sab196087  *
11485088Sab196087  *	"[#: name]"
11495088Sab196087  *
11505088Sab196087  * as used at the beginning of debug messages. A pointer to static
11515088Sab196087  * memory is returned, and is good until the next such call.
11525088Sab196087  */
11535088Sab196087 const char *
11545088Sab196087 elfedit_sec_msgprefix(elfedit_section_t *sec)
11555088Sab196087 {
11565088Sab196087 	static char	*buf;
11575088Sab196087 	static size_t	bufsize;
11585088Sab196087 
11595088Sab196087 	size_t		need;
11605088Sab196087 
11615088Sab196087 	need = 64 + strlen(sec->sec_name);
11625088Sab196087 	if (need > bufsize) {
11635088Sab196087 		buf = elfedit_realloc(MSG_INTL(MSG_ALLOC_SECMSGPRE), buf, need);
11645088Sab196087 		bufsize = need;
11655088Sab196087 	}
11665088Sab196087 
11675088Sab196087 	(void) snprintf(buf, bufsize, MSG_ORIG(MSG_FMT_SECMSGPRE),
11685088Sab196087 	    EC_WORD(sec->sec_shndx), sec->sec_name);
11695088Sab196087 
11705088Sab196087 	return (buf);
11715088Sab196087 }
1172