xref: /titanic_51/usr/src/cmd/sgs/elfedit/common/util_machelf.c (revision cf5b5989488984444a152faba2a8183a71dcf485)
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  */
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 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  */
331 elfedit_section_t *
332 elfedit_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  */
373 elfedit_section_t *
374 elfedit_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  */
410 elfedit_section_t *
411 elfedit_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  */
462 int
463 elfedit_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  */
521 elfedit_section_t *
522 elfedit_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  */
596 elfedit_section_t *
597 elfedit_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  */
659 elfedit_section_t *
660 elfedit_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  */
702 elfedit_section_t *
703 elfedit_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  */
738 int
739 elfedit_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  */
794 int
795 elfedit_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  */
835 Word
836 elfedit_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  */
913 void
914 elfedit_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  */
999 Word
1000 elfedit_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  */
1072 const char *
1073 elfedit_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  */
1115 const char *
1116 elfedit_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  */
1131 const char *
1132 elfedit_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