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