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