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