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