util_machelf.c revision 5088:26c540f30cd3
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 2007 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	<machdep.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 */
60void
61elfedit_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
66void
67elfedit_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
72void
73elfedit_modified_shdr(elfedit_section_t *s)
74{
75	(void) elf_flagshdr(s->sec_scn, ELF_C_SET, ELF_F_DIRTY);
76}
77
78void
79elfedit_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 */
89void
90elfedit_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 */
99void
100elfedit_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 */
119Word
120elfedit_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 */
154Word
155elfedit_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 */
209int
210elfedit_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 */
256const char *
257elfedit_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 capabilities section for this object
318 *
319 * entry:
320 *	obj_state - Object state for open object to query.
321 *	cap - Address of variable to recieve pointer to capabilities
322 *		section data buffer.
323 *	num - Address of variable to receive number of items
324 *		referenced by cap.
325 *
326 * exit:
327 *	On success, returns section descriptor, and sets the
328 *	variables referenced by cap and num.  On failure,
329 *	does not return.
330 */
331elfedit_section_t *
332elfedit_sec_getcap(elfedit_obj_state_t *obj_state, Cap **cap, Word *num)
333{
334	Word cnt;
335	elfedit_section_t *cache;
336
337	for (cnt = 1; cnt < obj_state->os_shnum; cnt++) {
338		cache = &obj_state->os_secarr[cnt];
339		if (cache->sec_shdr->sh_type == SHT_SUNW_cap) {
340			elfedit_msg(ELFEDIT_MSG_DEBUG,
341			    MSG_INTL(MSG_DEBUG_FNDCAP),
342			    EC_WORD(cnt), cache->sec_name);
343			*cap = (Cap *) cache->sec_data->d_buf;
344			*num = cache->sec_shdr->sh_size /
345			    cache->sec_shdr->sh_entsize;
346			return (cache);
347		}
348	}
349
350	/* If here, this object has no capabilities section */
351	elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOCAP));
352
353	/*NOTREACHED*/
354	return (NULL);
355}
356
357
358/*
359 * Locate the dynamic section for this object
360 *
361 * entry:
362 *	obj_state - Object state for open object to query.
363 *	dyn - Address of variable to recieve pointer to dynamic
364 *		section data buffer.
365 *	numdyn - Address of variable to receive number of items
366 *		referenced by dyn.
367 *
368 * exit:
369 *	On success, returns section descriptor, and sets the
370 *	variables referenced by dyn and numdyn.  On failure,
371 *	does not return.
372 */
373elfedit_section_t *
374elfedit_sec_getdyn(elfedit_obj_state_t *obj_state, Dyn **dyn, Word *num)
375{
376	elfedit_section_t *cache;
377
378	if (obj_state->os_dynndx != SHN_UNDEF) {
379		cache = &obj_state->os_secarr[obj_state->os_dynndx];
380		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDDYN),
381		    EC_WORD(cache->sec_shndx), cache->sec_name);
382		*dyn = (Dyn *) cache->sec_data->d_buf;
383		*num = cache->sec_shdr->sh_size / cache->sec_shdr->sh_entsize;
384		return (cache);
385	}
386
387	/* If here, this object has no dynamic section */
388	elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NODYN));
389
390	/*NOTREACHED*/
391	return (NULL);
392}
393
394
395/*
396 * Locate the syminfo section for this object
397 *
398 * entry:
399 *	obj_state - Object state for open object to query.
400 *	syminfo - Address of variable to recieve pointer to syminfo
401 *		section data buffer.
402 *	num - Address of variable to receive number of items
403 *		referenced by syminfo.
404 *
405 * exit:
406 *	On success, returns section descriptor, and sets the
407 *	variables referenced by syminfo and num.  On failure,
408 *	does not return.
409 */
410elfedit_section_t *
411elfedit_sec_getsyminfo(elfedit_obj_state_t *obj_state, Syminfo **syminfo,
412    Word *num)
413{
414	Word cnt;
415	elfedit_section_t *cache;
416
417	for (cnt = 1; cnt < obj_state->os_shnum; cnt++) {
418		cache = &obj_state->os_secarr[cnt];
419		if (cache->sec_shdr->sh_type == SHT_SUNW_syminfo) {
420			elfedit_msg(ELFEDIT_MSG_DEBUG,
421			    MSG_INTL(MSG_DEBUG_FNDSYMINFO),
422			    EC_WORD(cnt), cache->sec_name);
423			*syminfo = (Syminfo *) cache->sec_data->d_buf;
424			*num = cache->sec_shdr->sh_size /
425			    cache->sec_shdr->sh_entsize;
426			return (cache);
427		}
428	}
429
430	/* If here, this object has no syminfo section */
431	elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSYMINFO));
432
433	/*NOTREACHED*/
434	return (NULL);
435}
436
437
438/*
439 * Check the given section to see if it is a known symbol table type.
440 *
441 * entry:
442 *	sec - Section to check
443 *	issue_err - True if this routine should issue an error and
444 *		not return to the caller if sec is not a symbol table.
445 *	atoui_list - NULL, or address of variable to receive a pointer to
446 *		an array of elfedit_atoui_sym_t items describing the
447 *		type of symbol table found. This array is useful for
448 *		doing command completion.
449 *
450 * exit:
451 *	If sec is a symbol table:
452 *		- If atoui_list is non-NULL, *atoui_list is set to the
453 *		  appropriate ELFEDIT_CONST_xx list of items.
454 *		- True (1) is returned
455 *	If sec is not a symbol table and issue_err is True:
456 *		- An error is issued, and this routine does not
457 *			return to the caller.
458 *	Otherwise:
459 *		- If atoui_list is non-NULL, *atoui_list is set to NULL.
460 *		- False (0) is returned
461 */
462int
463elfedit_sec_issymtab(elfedit_section_t *sec, int issue_err,
464    elfedit_atoui_sym_t **atoui_list)
465{
466	elfedit_const_t		const_type;
467	int			ret = 1;
468
469	/* Is the section a symbol table? */
470	switch (sec->sec_shdr->sh_type) {
471	case SHT_SYMTAB:
472		const_type = ELFEDIT_CONST_SHT_SYMTAB;
473		break;
474	case SHT_DYNSYM:
475		const_type = ELFEDIT_CONST_SHT_DYNSYM;
476		break;
477	case SHT_SUNW_LDYNSYM:
478		const_type = ELFEDIT_CONST_SHT_LDYNSYM;
479		break;
480	default:
481		if (issue_err)
482			elfedit_msg(ELFEDIT_MSG_ERR,
483			    MSG_INTL(MSG_ERR_NOTSYMTAB),
484			    EC_WORD(sec->sec_shndx), sec->sec_name);
485		ret = 0;
486		break;
487	}
488
489	if (atoui_list != NULL)
490		*atoui_list = (ret == 0) ? NULL :
491		    elfedit_const_to_atoui(const_type);
492
493	return (ret);
494}
495
496
497
498/*
499 * Locate a symbol table section for this object
500 *
501 * entry:
502 *	obj_state - Object state for open object to query.
503 *	by_index - If True, we want to locate the section with the
504 *		section index given by index. If False, we return
505 *		the section with the name given by name.
506 *	index, name - Key to search for. See by_index.
507 *	sym - Address of variable to recieve pointer to symbol
508 *		section data buffer.
509 *	numsym - Address of variable to receive number of symbols
510 *		referenced by sym.
511 *	aux_info - Address of variable to receive pointer to the
512 *		elfedit_symtab_t struct that ties the symbol table and
513 *		its related auxiliary sections together. NULL if this
514 *		information is not required.
515 *
516 * exit:
517 *	On success, returns section descriptor, and sets the
518 *	variables referenced by sym, and numsym. On failure,
519 *	does not return.
520 */
521elfedit_section_t *
522elfedit_sec_getsymtab(elfedit_obj_state_t *obj_state, int by_index,
523    Word index, const char *name, Sym **sym, Word *num,
524    elfedit_symtab_t **aux_info)
525{
526	Word			ndx;
527	elfedit_section_t	*symsec = NULL;
528	elfedit_symtab_t	*symtab;
529	const char 		*type_name;
530
531	/* If looking it up by index, make sure the index is in range */
532	if (by_index && (index >= obj_state->os_shnum))
533		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADSECNDX),
534		    EC_WORD(index), EC_WORD(obj_state->os_shnum - 1));
535
536	/*
537	 * Look at each known symbol table in turn until the desired
538	 * one is hit, or there are no more.
539	 */
540	symtab = obj_state->os_symtab;
541	for (ndx = 0; ndx < obj_state->os_symtabnum; ndx++, symtab++) {
542		elfedit_section_t *s =
543		    &obj_state->os_secarr[symtab->symt_shndx];
544
545		if ((by_index && (symtab->symt_shndx == index)) ||
546		    (!by_index && (strcmp(s->sec_name, name) == 0))) {
547				symsec = s;
548				break;
549		}
550	}
551
552	/* Did we get a section? */
553	if (symsec == NULL)
554		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSYMTAB));
555
556	/* Got it. Report to the user and return the necessary data */
557	(void) elfedit_sec_issymtab(symsec, 1, NULL);
558	type_name = elfedit_atoconst_value_to_str(ELFEDIT_CONST_SHT_ALLSYMTAB,
559	    symsec->sec_shdr->sh_type, 1);
560	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDSYMTAB),
561	    EC_WORD(symsec->sec_shndx), symsec->sec_name, type_name);
562	*sym = (Sym *) symsec->sec_data->d_buf;
563	*num = symsec->sec_shdr->sh_size / symsec->sec_shdr->sh_entsize;
564	if (aux_info != NULL)
565		*aux_info = symtab;
566	return (symsec);
567}
568
569
570
571/*
572 * Locate the extended symbol index section associated with a symbol
573 * table section.
574 *
575 * entry:
576 *	obj_state - Object state for open object to query.
577 *	symsec - Symbol table section for which extended index
578 *		index section is required.
579 *	xshndx - Address of variable to recieve pointer to section index
580 *		array data buffer.
581 *	numxshndx - Address of variable to receive number of indices
582 *		referenced by ndx.
583 *
584 * exit:
585 *	On success, returns extended index section descriptor, and sets the
586 *	variables referenced by xshndx, and numxshndx. On failure,
587 *	does not return.
588 *
589 * note:
590 *	Since the extended section index is found in the sec_xshndx field
591 *	of the elfedit_section_t, the caller may be tempted to bypass this
592 *	routine and access it directly. That temptation should be resisted,
593 *	as this routine performs useful error checking, and also handles
594 *	the issuing of the standard MSG_DEBUG messages.
595 */
596elfedit_section_t *
597elfedit_sec_getxshndx(elfedit_obj_state_t *obj_state,
598    elfedit_section_t *symsec, Word **xshndx, Word *num)
599{
600	elfedit_section_t	*xshndxsec;
601	elfedit_symtab_t	*symtab;
602	Word			ndx;
603
604	/* Sanity check: symsec must be a symbol table */
605	(void) elfedit_sec_issymtab(symsec, 1, NULL);
606
607	symtab = obj_state->os_symtab;
608	for (ndx = 0; ndx < obj_state->os_symtabnum; ndx++, symtab++)
609		if (symsec->sec_shndx == symtab->symt_shndx)
610			break;
611
612	/*
613	 * Issue error if the symbol table lacks an extended index section.
614	 * The caller won't ask unless they encounter an SHN_XINDEX value,
615	 * in which case the lack of the index section denotes a corrupt
616	 * ELF file.
617	 */
618	if ((ndx == obj_state->os_symtabnum) ||
619	    (symtab->symt_xshndx == SHN_UNDEF))
620		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOXSHSEC),
621		    EC_WORD(symsec->sec_shndx), symsec->sec_name);
622
623	/* Got it. Report to the user and return the necessary data */
624	xshndxsec = &obj_state->os_secarr[symtab->symt_xshndx];
625	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDXSHNDX),
626	    EC_WORD(symsec->sec_shndx), symsec->sec_name,
627	    EC_WORD(xshndxsec->sec_shndx), xshndxsec->sec_name);
628	*xshndx = (Word *) xshndxsec->sec_data->d_buf;
629	*num = xshndxsec->sec_shdr->sh_size / xshndxsec->sec_shdr->sh_entsize;
630	return (xshndxsec);
631}
632
633
634
635/*
636 * Locate the versym section associated with a symbol table section.
637 *
638 * entry:
639 *	obj_state - Object state for open object to query.
640 *	symsec - Symbol table section for which extended index
641 *		index section is required.
642 *	versym - Address of variable to recieve pointer to section index
643 *		array data buffer.
644 *	numversym - Address of variable to receive number of indices
645 *		referenced by ndx.
646 *
647 * exit:
648 *	On success, returns versym section descriptor, and sets the
649 *	variables referenced by versym, and numversym. On failure,
650 *	does not return.
651 *
652 * note:
653 *	Since the versym section index is found in the sec_versym field
654 *	of the elfedit_section_t, the caller may be tempted to bypass this
655 *	routine and access it directly. That temptation should be resisted,
656 *	as this routine performs useful error checking, and also handles
657 *	the issuing of the standard MSG_DEBUG messages.
658 */
659elfedit_section_t *
660elfedit_sec_getversym(elfedit_obj_state_t *obj_state,
661    elfedit_section_t *symsec, Versym **versym, Word *num)
662{
663	elfedit_section_t	*versymsec;
664	elfedit_symtab_t	*symtab;
665	Word			ndx;
666
667	/* Sanity check: symsec must be a symbol table */
668	(void) elfedit_sec_issymtab(symsec, 1, NULL);
669
670	symtab = obj_state->os_symtab;
671	for (ndx = 0; ndx < obj_state->os_symtabnum; ndx++, symtab++)
672		if (symsec->sec_shndx == symtab->symt_shndx)
673			break;
674	/*
675	 * Issue error if the symbol table lacks a versym section.
676	 * The caller won't ask unless they see a non-null
677	 * aux.symtab.sec_versym, so this should not be a problem.
678	 */
679	if ((ndx == obj_state->os_symtabnum) ||
680	    (symtab->symt_versym == SHN_UNDEF))
681		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOVERSYMSEC),
682		    EC_WORD(symsec->sec_shndx), symsec->sec_name);
683
684	/* Got it. Report to the user and return the necessary data */
685	versymsec = &obj_state->os_secarr[symtab->symt_versym];
686	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDVERSYM),
687	    EC_WORD(symsec->sec_shndx), symsec->sec_name,
688	    EC_WORD(versymsec->sec_shndx), versymsec->sec_name);
689	*versym = (Versym *) versymsec->sec_data->d_buf;
690	*num = versymsec->sec_shdr->sh_size / versymsec->sec_shdr->sh_entsize;
691	return (versymsec);
692}
693
694
695
696/*
697 * Locate the string table specified by shndx for this object.
698 *
699 * exit:
700 *	Returns section descriptor on success. On failure, does not return.
701 */
702elfedit_section_t *
703elfedit_sec_getstr(elfedit_obj_state_t *obj_state, Word shndx)
704{
705	elfedit_section_t *strsec;
706
707	if ((shndx == 0) || (shndx >= obj_state->os_shnum))
708		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_STRSHNDX),
709		    EC_WORD(shndx), EC_WORD(1),
710		    EC_WORD(obj_state->os_shnum - 1));
711
712	strsec = &obj_state->os_secarr[shndx];
713	if (strsec->sec_shdr->sh_type != SHT_STRTAB)
714		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOTSTRSH),
715		    EC_WORD(shndx), strsec->sec_name);
716
717	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDSTRTAB),
718	    EC_WORD(shndx), strsec->sec_name);
719	return (strsec);
720}
721
722
723/*
724 * Returns the offset of the specified string from within
725 * the given section.
726 *
727 * entry:
728 *	sec - Descriptor for section
729 *	tail_ign - If non-zero, the # of characters at the end of the
730 *		section that should be ignored and not searched.
731 *	str - String we are looking for.
732 *	ret_offset - Address of variable to receive result
733 *
734 * exit:
735 *	Returns 1 for success, and 0 for failure. If successful, *ret_offset
736 *	is set to the offset of the found string within the section.
737 */
738int
739elfedit_sec_findstr(elfedit_section_t *sec, Word tail_ign,
740    const char *str, Word *ret_offset)
741{
742	int		str_fch = *str;	/* First character in str */
743	Word		len;		/* # characters in table */
744	char		*s;		/* ptr to strings within table */
745	const char	*tail;		/* 1 past final character of table */
746
747
748	/* Size of the section, minus the reserved part (if any) at the end */
749	len = sec->sec_shdr->sh_size - tail_ign;
750
751	/*
752	 * Move through the section character by character looking for
753	 * a match. Moving character by character instead of skipping
754	 * from NULL terminated string to string allows us to use
755	 * the tails longer strings (i.e. we want "bar", and "foobar" exists).
756	 * We look at the first character manually before calling strcmp()
757	 * to lower the cost of this approach.
758	 */
759	s = (char *)sec->sec_data->d_buf;
760	tail = s + len;
761	for (; s <= tail; s++) {
762		if ((*s == str_fch) && (strcmp(s, str) == 0)) {
763			*ret_offset = s - (char *)sec->sec_data->d_buf;
764			elfedit_msg(ELFEDIT_MSG_DEBUG,
765			    MSG_INTL(MSG_DEBUG_EXISTSTR),
766			    EC_WORD(sec->sec_shndx), sec->sec_name,
767			    EC_WORD(*ret_offset), s);
768			return (1);
769		}
770	}
771
772	/* Didn't find it. Report failure */
773	return (0);
774}
775
776
777/*
778 * Locate the DT_SUNW_STRPAD element of the given dynamic section if
779 * it exists.
780 *
781 * entry:
782 *	dynsec - Dynamic section descriptor
783 *	dyn_strpad - Address of variable to receive the results.
784 *		The caller is responsible for calling elfedit_dyn_elt_init()
785 *		on this variable beforehand.
786 *
787 * exit:
788 *	The dynamic section is searched, and if a DT_SUNW_STRPAD element
789 *	is found, dyn_strpad is updated via elfedit_dyn_elt_save() to
790 *	reference it.
791 *
792 *	Returns the final value of dyn_strpad->dn_seen.
793 */
794int
795elfedit_dynstr_getpad(elfedit_section_t *dynsec, elfedit_dyn_elt_t *dyn_strpad)
796{
797	Dyn	*dyn = (Dyn *) dynsec->sec_data->d_buf;
798	Word numdyn = dynsec->sec_shdr->sh_size / dynsec->sec_shdr->sh_entsize;
799	Word i;
800
801	/* Go through dynamic section tags and find the STRPAD entry */
802	for (i = 0; i < numdyn; i++) {
803		if (dyn[i].d_tag == DT_SUNW_STRPAD) {
804			elfedit_dyn_elt_save(dyn_strpad, i, &dyn[i]);
805			break;
806		}
807	}
808
809	return (dyn_strpad->dn_seen);
810}
811
812
813
814/*
815 * Given references to the dynamic section, its string table,
816 * and the DT_SUNW_STRPAD entry of the dynamic section, returns
817 * the offset of the specified string from within the given string table,
818 * adding it if possible.
819 *
820 * entry:
821 *	dynsec - Dynamic section descriptor
822 *	strsec - Descriptor for string table assocated with dynamic section
823 *	dyn_strpad - DT_SUNW_STRPAD element from dynamic section
824 *	str - String we are looking for.
825 *
826 * exit:
827 *	On success, the offset of the given string within the string
828 *	table is returned. If the string does not exist within the table,
829 *	but there is a valid DT_SUNW_STRPAD reserved section, then we
830 *	add the string, and update the dynamic section STRPAD element
831 *	to reflect the space we use.
832 *
833 *	This routine does not return on failure.
834 */
835Word
836elfedit_dynstr_insert(elfedit_section_t *dynsec, elfedit_section_t *strsec,
837    elfedit_dyn_elt_t *dyn_strpad, const char *str)
838{
839	Word	ins_off;	/* Table offset to 1st reserved byte */
840	char	*s;		/* ptr to strings within table */
841	Word	len;		/* Length of str inc. NULL byte */
842	Word	tail_ign;	/* # reserved bytes at end of strtab */
843
844
845	tail_ign = dyn_strpad->dn_seen ? dyn_strpad->dn_dyn.d_un.d_val : 0;
846
847	/* Does the string already existin the string table? */
848	if (elfedit_sec_findstr(strsec, tail_ign, str, &len))
849		return (len);
850
851	/*
852	 * The desired string does not already exist. Do we have
853	 * room to add it?
854	 */
855	len = strlen(str) + 1;
856	if (!dyn_strpad->dn_seen || (len > dyn_strpad->dn_dyn.d_un.d_val))
857		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSTRPAD),
858		    EC_WORD(strsec->sec_shdr->sh_link),
859		    strsec->sec_name);
860
861
862	/*
863	 * We will add the string at the first byte of the reserved NULL
864	 * area at the end. The DT_SUNW_STRPAD dynamic element gives us
865	 * the size of that reserved space.
866	 */
867	ins_off = strsec->sec_shdr->sh_size - tail_ign;
868	s = ((char *)strsec->sec_data->d_buf) + ins_off;
869
870	/* Announce the operation */
871	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_ADDSTR),
872	    EC_WORD(strsec->sec_shndx), strsec->sec_name,
873	    EC_WORD(ins_off), EC_WORD(len),
874	    EC_WORD(dyn_strpad->dn_dyn.d_un.d_val), str);
875
876	/*
877	 * Copy the string into the pad area at the end, and
878	 * mark the data area as dirty so libelf will flush our
879	 * changes to the string data.
880	 */
881	(void) strncpy(s, str, dyn_strpad->dn_dyn.d_un.d_val);
882	elfedit_modified_data(strsec);
883
884	/* Update the DT_STRPAD dynamic entry */
885	dyn_strpad->dn_dyn.d_un.d_val -= len;
886	((Dyn *) dynsec->sec_data->d_buf)[dyn_strpad->dn_ndx] =
887	    dyn_strpad->dn_dyn;
888	elfedit_modified_data(dynsec);
889
890	return (ins_off);
891}
892
893
894/*
895 * Test to see if a call to elfedit_strtab_insert() will succeed.
896 *
897 * entry:
898 *	obj_state - Object state for open object to query.
899 *	strsec - Descriptor for string table
900 *	dynsec - NULL, or descriptor for dynamic section. Providing
901 *		a non-NULL value here will prevent elfedit_strtab_insert()
902 *		from looking it up, and the duplicate debug message that
903 *		would result.
904 *	str - String we are looking for.
905 *
906 * exit:
907 *	If the string exists within the string table, or if an attempt
908 *	to insert it will be successful, quietly return. Otherwise, throw
909 *	the error elfedit_strtab_insert() would throw under the
910 *	same circumstances.
911 *
912 */
913void
914elfedit_strtab_insert_test(elfedit_obj_state_t *obj_state,
915    elfedit_section_t *strsec, elfedit_section_t *dynsec, const char *str)
916{
917	Word	len;		/* Length of str inc. NULL byte */
918	int			is_dynstr = 0;
919	Word			tail_ign = 0;
920
921
922	/*
923	 * The dynstr is a special case, because we can add strings
924	 * to it under certain circumstances. So, we look for the
925	 * dynamic section, and if it exists, compare its sh_link to
926	 * the string section index. If they match, it is the dynstr,
927	 * and we use elfedit_dynstr_insert() to do the work.
928	 */
929	if (dynsec == NULL) {
930		if (obj_state->os_dynndx != SHN_UNDEF) {
931			dynsec = &obj_state->os_secarr[obj_state->os_dynndx];
932			if ((dynsec->sec_shdr->sh_type == SHT_DYNAMIC) &&
933			    (strsec->sec_shndx == dynsec->sec_shdr->sh_link)) {
934				is_dynstr = 1;
935				elfedit_msg(ELFEDIT_MSG_DEBUG,
936				    MSG_INTL(MSG_DEBUG_FNDDYN),
937				    EC_WORD(dynsec->sec_shndx),
938				    dynsec->sec_name);
939			}
940		}
941	} else {
942		if (strsec->sec_shndx == dynsec->sec_shdr->sh_link)
943			is_dynstr = 1;
944	}
945
946
947	if (is_dynstr) {
948		elfedit_dyn_elt_t dyn_strpad;
949
950		/* Determine the size of the STRPAD area, if any */
951		elfedit_dyn_elt_init(&dyn_strpad);
952		if (elfedit_dynstr_getpad(dynsec, &dyn_strpad) != 0)
953			tail_ign = dyn_strpad.dn_dyn.d_un.d_val;
954	}
955
956	/*
957	 * If the string is already in the string table, we
958	 * can't fail.
959	 */
960	if (elfedit_sec_findstr(strsec, tail_ign, str, &len) != 0)
961		return;
962
963	/*
964	 * It's not in the table, but if this is the dynstr, and
965	 * there is enough room, we will be able to add it.
966	 */
967	if (is_dynstr && (tail_ign > strlen(str)))
968		return;
969
970	/* Can't do it. Issue error */
971	elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSTRPAD),
972	    EC_WORD(strsec->sec_shdr->sh_link), strsec->sec_name);
973}
974
975
976/*
977 * Returns the offset of the specified string from within
978 * the given string table, adding it if possible.
979 *
980 * entry:
981 *	obj_state - Object state for open object to query.
982 *	strsec - Descriptor for string table
983 *	dynsec - NULL, or descriptor for dynamic section. Providing
984 *		a non-NULL value here will prevent elfedit_strtab_insert()
985 *		from looking it up, and the duplicate debug message that
986 *		would result.
987 *	str - String we are looking for.
988 *
989 * exit:
990 *	On success, the offset of the given string within the string
991 *	table is returned. If the string does not exist within the table,
992 *	and it is possible to add it, elfedit_strtab_insert() will
993 *	add the string, and then return the offset.
994 *
995 *	If the string does not exist in the string table, and cannot
996 *	be added, this routine issues an error message and does not
997 *	return to the caller.
998 */
999Word
1000elfedit_strtab_insert(elfedit_obj_state_t *obj_state, elfedit_section_t *strsec,
1001    elfedit_section_t *dynsec, const char *str)
1002{
1003	Word	len;		/* Length of str inc. NULL byte */
1004	int			is_dynstr = 0;
1005	elfedit_dyn_elt_t	dyn_strpad;
1006
1007
1008	/*
1009	 * The dynstr is a special case, because we can add strings
1010	 * to it under certain circumstances. So, we look for the
1011	 * dynamic section, and if it exists, compare its sh_link to
1012	 * the string section index. If they match, it is the dynstr,
1013	 * and we use elfedit_dynstr_insert() to do the work.
1014	 */
1015	if (dynsec == NULL) {
1016		if (obj_state->os_dynndx != SHN_UNDEF) {
1017			dynsec = &obj_state->os_secarr[obj_state->os_dynndx];
1018			if ((dynsec->sec_shdr->sh_type == SHT_DYNAMIC) &&
1019			    (strsec->sec_shndx == dynsec->sec_shdr->sh_link)) {
1020				is_dynstr = 1;
1021				elfedit_msg(ELFEDIT_MSG_DEBUG,
1022				    MSG_INTL(MSG_DEBUG_FNDDYN),
1023				    EC_WORD(dynsec->sec_shndx),
1024				    dynsec->sec_name);
1025			}
1026		}
1027	} else {
1028		if (strsec->sec_shndx == dynsec->sec_shdr->sh_link)
1029			is_dynstr = 1;
1030	}
1031
1032	if (is_dynstr) {
1033		elfedit_dyn_elt_init(&dyn_strpad);
1034		(void) elfedit_dynstr_getpad(dynsec, &dyn_strpad);
1035		return (elfedit_dynstr_insert(dynsec, strsec,
1036		    &dyn_strpad, str));
1037	}
1038
1039	/*
1040	 * This is not the dynstr, so we are limited to strings that
1041	 * already exist within it. Try to find one.
1042	 */
1043	if (elfedit_sec_findstr(strsec, 0, str, &len))
1044		return (len);
1045
1046	/* Can't do it. Issue error */
1047	elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSTRPAD),
1048	    EC_WORD(strsec->sec_shdr->sh_link), strsec->sec_name);
1049	/*NOTREACHED*/
1050
1051	return (0);
1052}
1053
1054
1055/*
1056 * Return the string found at the given offset within the specified
1057 * string table.
1058 *
1059 * entry:
1060 *	strsec - Section descriptor for string table section
1061 *	offset - Offset of desired string in string table
1062 *	msg_type - ELFEDIT_MSG_ type code to use with message
1063 *		issued if offset is out of range for the symbol table.
1064 *	debug_msg - True if should issue debug message for string found.
1065 *
1066 * exit:
1067 *	If the offset is within the section, the string pointer
1068 *	is returned. Otherwise an error is issued using msg_type
1069 *	to determine the type of message. If this routine retains
1070 *	control after the message is issued, a safe string is returned.
1071 */
1072const char *
1073elfedit_offset_to_str(elfedit_section_t *strsec, Word offset,
1074    elfedit_msg_t msg_type, int debug_msg)
1075{
1076	const char *str;
1077
1078	/* Make sure it is a string table section */
1079	if (strsec->sec_shdr->sh_type != SHT_STRTAB)
1080		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOTSTRSH),
1081		    EC_WORD(strsec->sec_shndx), strsec->sec_name);
1082
1083	/* Ensure the offset is in range */
1084	if (offset >= strsec->sec_data->d_size) {
1085		elfedit_msg(msg_type, MSG_INTL(MSG_ERR_BADSTROFF),
1086		    EC_WORD(strsec->sec_shndx), strsec->sec_name,
1087		    EC_WORD(offset), EC_WORD(strsec->sec_data->d_size - 1));
1088		/*
1089		 * If the msg_type is a type that returns, give the
1090		 * user a safe string to use.
1091		 */
1092		str = MSG_INTL(MSG_BADSYMOFFSETNAM);
1093	} else {
1094		/* Return the string */
1095		str = ((const char *)strsec->sec_data->d_buf) + offset;
1096	}
1097
1098	if (debug_msg)
1099		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDSTR),
1100		    EC_WORD(strsec->sec_shndx), strsec->sec_name,
1101		    EC_WORD(offset), str);
1102	return (str);
1103}
1104
1105
1106/*
1107 * Given a string table section, and a dynamic section entry
1108 * that supplies a string offset, return the string found at
1109 * the given offset. This routine is a convenience wrapper on
1110 * elfedit_offset_to_str().
1111 *
1112 * exit:
1113 *	As per elfedit_offset_to_str().
1114 */
1115const char *
1116elfedit_dyn_offset_to_str(elfedit_section_t *strsec, elfedit_dyn_elt_t *dynelt)
1117{
1118	return (elfedit_offset_to_str(strsec, dynelt->dn_dyn.d_un.d_val,
1119	    ELFEDIT_MSG_ERR, 0));
1120}
1121
1122
1123/*
1124 * Given a section, fabricate a string for the form:
1125 *
1126 *	"[#: name]"
1127 *
1128 * as used at the beginning of debug messages. A pointer to static
1129 * memory is returned, and is good until the next such call.
1130 */
1131const char *
1132elfedit_sec_msgprefix(elfedit_section_t *sec)
1133{
1134	static char	*buf;
1135	static size_t	bufsize;
1136
1137	size_t		need;
1138
1139	need = 64 + strlen(sec->sec_name);
1140	if (need > bufsize) {
1141		buf = elfedit_realloc(MSG_INTL(MSG_ALLOC_SECMSGPRE), buf, need);
1142		bufsize = need;
1143	}
1144
1145	(void) snprintf(buf, bufsize, MSG_ORIG(MSG_FMT_SECMSGPRE),
1146	    EC_WORD(sec->sec_shndx), sec->sec_name);
1147
1148	return (buf);
1149}
1150