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
elfedit_modified_ehdr(elfedit_obj_state_t * obj_state)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
elfedit_modified_phdr(elfedit_obj_state_t * obj_state)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
elfedit_modified_shdr(elfedit_section_t * s)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
elfedit_modified_data(elfedit_section_t * s)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
elfedit_dyn_elt_init(elfedit_dyn_elt_t * elt)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
elfedit_dyn_elt_save(elfedit_dyn_elt_t * elt,Word ndx,Dyn * dyn)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
elfedit_name_to_shndx(elfedit_obj_state_t * obj_state,const char * shnam)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
elfedit_type_to_shndx(elfedit_obj_state_t * obj_state,Word shtype)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
elfedit_name_to_symndx(elfedit_section_t * symsec,elfedit_section_t * strsec,const char * name,elfedit_msg_t msg_type,Word * ret_symndx)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 *
elfedit_shndx_to_name(elfedit_obj_state_t * obj_state,Word shndx)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 *
elfedit_sec_get(elfedit_obj_state_t * obj_state,Word shndx)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
elfedit_test_osabi(elfedit_obj_state_t * obj_state,uchar_t osabi,int issue_err)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 *
elfedit_sec_getcap(elfedit_obj_state_t * obj_state,Cap ** cap,Word * num)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 *
elfedit_sec_getdyn(elfedit_obj_state_t * obj_state,Dyn ** dyn,Word * num)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 *
elfedit_sec_getsyminfo(elfedit_obj_state_t * obj_state,Syminfo ** syminfo,Word * num)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
elfedit_sec_issymtab(elfedit_obj_state_t * obj_state,elfedit_section_t * sec,int issue_err,elfedit_atoui_sym_t ** atoui_list)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 *
elfedit_sec_getsymtab(elfedit_obj_state_t * obj_state,int by_index,Word index,const char * name,Sym ** sym,Word * num,elfedit_symtab_t ** aux_info)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 *
elfedit_sec_getxshndx(elfedit_obj_state_t * obj_state,elfedit_section_t * symsec,Word ** xshndx,Word * num)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 *
elfedit_sec_getversym(elfedit_obj_state_t * obj_state,elfedit_section_t * symsec,Versym ** versym,Word * num)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 *
elfedit_sec_getstr(elfedit_obj_state_t * obj_state,Word shndx,int allow_shflags)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
elfedit_sec_findstr(elfedit_section_t * sec,Word tail_ign,const char * str,Word * ret_offset)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
elfedit_dynstr_getpad(elfedit_obj_state_t * obj_state,elfedit_section_t * dynsec,elfedit_dyn_elt_t * dyn_strpad)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
elfedit_dynstr_insert(elfedit_section_t * dynsec,elfedit_section_t * strsec,elfedit_dyn_elt_t * dyn_strpad,const char * str)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
elfedit_strtab_insert_test(elfedit_obj_state_t * obj_state,elfedit_section_t * strsec,elfedit_section_t * dynsec,const char * str)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
elfedit_strtab_insert(elfedit_obj_state_t * obj_state,elfedit_section_t * strsec,elfedit_section_t * dynsec,const char * str)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 *
elfedit_offset_to_str(elfedit_section_t * strsec,Word offset,elfedit_msg_t msg_type,int debug_msg)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 *
elfedit_dyn_offset_to_str(elfedit_section_t * strsec,elfedit_dyn_elt_t * dynelt)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 *
elfedit_sec_msgprefix(elfedit_section_t * sec)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