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 #define ELF_TARGET_AMD64 /* SHN_AMD64_LCOMMON */
28
29 #include <stdio.h>
30 #include <unistd.h>
31 #include <elfedit.h>
32 #include <strings.h>
33 #include <debug.h>
34 #include <conv.h>
35 #include <sym_msg.h>
36
37
38
39
40 #define MAXNDXSIZE 10
41
42
43
44 /*
45 * This module uses shared code for several of the commands.
46 * It is sometimes necessary to know which specific command
47 * is active.
48 */
49 typedef enum {
50 SYM_CMD_T_DUMP = 0, /* sym:dump */
51
52 SYM_CMD_T_ST_BIND = 1, /* sym:st_bind */
53 SYM_CMD_T_ST_INFO = 2, /* sym:st_info */
54 SYM_CMD_T_ST_NAME = 3, /* sym:st_name */
55 SYM_CMD_T_ST_OTHER = 4, /* sym:st_other */
56 SYM_CMD_T_ST_SHNDX = 5, /* sym:st_shndx */
57 SYM_CMD_T_ST_SIZE = 6, /* sym:st_size */
58 SYM_CMD_T_ST_TYPE = 7, /* sym:st_type */
59 SYM_CMD_T_ST_VALUE = 8, /* sym:st_value */
60 SYM_CMD_T_ST_VISIBILITY = 9 /* sym:st_visibility */
61 } SYM_CMD_T;
62
63
64
65 /*
66 * ELFCLASS-specific definitions
67 */
68 #ifdef _ELF64
69
70 #define MSG_FMT_XWORDVALNL MSG_FMT_XWORDVALNL_64
71
72 #else
73
74 #define MSG_FMT_XWORDVALNL MSG_FMT_XWORDVALNL_32
75
76 /*
77 * We supply this function for the msg module. Only one copy is needed.
78 */
79 const char *
_sym_msg(Msg mid)80 _sym_msg(Msg mid)
81 {
82 return (gettext(MSG_ORIG(mid)));
83 }
84
85 #endif
86
87
88
89 /*
90 * This function is supplied to elfedit through our elfedit_module_t
91 * definition. It translates the opaque elfedit_i18nhdl_t handles
92 * in our module interface into the actual strings for elfedit to
93 * use.
94 *
95 * note:
96 * This module uses Msg codes for its i18n handle type.
97 * So the translation is simply to use MSG_INTL() to turn
98 * it into a string and return it.
99 */
100 static const char *
mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl)101 mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl)
102 {
103 Msg msg = (Msg)hdl;
104
105 return (MSG_INTL(msg));
106 }
107
108
109
110 /*
111 * The sym_opt_t enum specifies a bit value for every optional
112 * argument allowed by a command in this module.
113 */
114 typedef enum {
115 SYM_OPT_F_XSHINDEX = 1, /* -e: Force shndx update to extended */
116 /* index section */
117 SYM_OPT_F_NAMOFFSET = 2, /* -name_offset: sym:st_name name arg */
118 /* is numeric offset */
119 /* rather than ASCII string */
120 SYM_OPT_F_SECSHNDX = 4, /* -secshndx: Section arg is */
121 /* section index, not name */
122 SYM_OPT_F_SECSHTYP = 8, /* -secshtyp: Section arg is */
123 /* section type, not name */
124 SYM_OPT_F_SHNAME = 16, /* -shnam name: section spec. by name */
125 SYM_OPT_F_SHNDX = 32, /* -shndx ndx: section spec. by index */
126 SYM_OPT_F_SHTYP = 64, /* -shtyp type: section spec. by type */
127 SYM_OPT_F_SYMNDX = 128 /* -symndx: Sym specified by index */
128 } sym_opt_t;
129
130
131 /*
132 * A variable of type ARGSTATE is used by each command to maintain
133 * the overall state for a given set of arguments and the symbol tables
134 * being managed.
135 *
136 * The state for each symbol table and the auxiliary sections that are
137 * related to it are kept in a SYMSTATE sub-struct.
138 *
139 * One benefit of ARGSTATE is that it helps us to ensure that we only
140 * fetch each section a single time:
141 * - More efficient
142 * - Prevents multiple ELFEDIT_MSG_DEBUG messages from
143 * being produced for a given section.
144 *
145 * note: The symstate array in ARGSTATE is defined as having one
146 * element, but in reality, we allocate enough room for
147 * the number of elements defined in the numsymstate field.
148 */
149 typedef struct {
150 Word ndx; /* If argstate.argc > 0, this is the table index */
151 struct { /* Symbol table */
152 elfedit_section_t *sec;
153 Sym *data;
154 Word n;
155 } sym;
156 struct { /* String table */
157 elfedit_section_t *sec;
158 } str;
159 struct { /* Versym */
160 Word shndx;
161 elfedit_section_t *sec;
162 Versym *data;
163 Word n;
164 } versym;
165 struct { /* Extended section indices */
166 Word shndx;
167 elfedit_section_t *sec;
168 Word *data;
169 Word n;
170 } xshndx;
171 } SYMSTATE;
172 typedef struct {
173 elfedit_obj_state_t *obj_state;
174 sym_opt_t optmask; /* Mask of options used */
175 int argc; /* # of plain arguments */
176 const char **argv; /* Plain arguments */
177 int numsymstate; /* # of items in symstate[] */
178 SYMSTATE symstate[1]; /* Symbol tables to process */
179 } ARGSTATE;
180
181
182 /*
183 * We maintain the state of each symbol table and related associated
184 * sections in a SYMSTATE structure . We don't look those auxiliary
185 * things up unless we actually need them, both to be efficient,
186 * and to prevent duplicate ELFEDIT_MSG_DEBUG messages from being
187 * issued as they are located. Hence, process_args() is used to
188 * initialize the state block with just the symbol table, and then one
189 * of the argstate_add_XXX() functions is used as needed
190 * to fetch the additional sections.
191 *
192 * entry:
193 * argstate - Overall state block
194 * symstate - State block for current symbol table.
195 *
196 * exit:
197 * If the needed auxiliary section is not found, an error is
198 * issued and the argstate_add_XXX() routine does not return.
199 * Otherwise, the fields in argstate have been filled in, ready
200 * for use.
201 *
202 */
203 static void
symstate_add_str(ARGSTATE * argstate,SYMSTATE * symstate)204 symstate_add_str(ARGSTATE *argstate, SYMSTATE *symstate)
205 {
206 if (symstate->str.sec != NULL)
207 return;
208
209 symstate->str.sec = elfedit_sec_getstr(argstate->obj_state,
210 symstate->sym.sec->sec_shdr->sh_link, 0);
211 }
212 static void
symstate_add_versym(ARGSTATE * argstate,SYMSTATE * symstate)213 symstate_add_versym(ARGSTATE *argstate, SYMSTATE *symstate)
214 {
215 if (symstate->versym.sec != NULL)
216 return;
217
218 symstate->versym.sec = elfedit_sec_getversym(argstate->obj_state,
219 symstate->sym.sec, &symstate->versym.data, &symstate->versym.n);
220 }
221 static void
symstate_add_xshndx(ARGSTATE * argstate,SYMSTATE * symstate)222 symstate_add_xshndx(ARGSTATE *argstate, SYMSTATE *symstate)
223 {
224 if (symstate->xshndx.sec != NULL)
225 return;
226
227 symstate->xshndx.sec = elfedit_sec_getxshndx(argstate->obj_state,
228 symstate->sym.sec, &symstate->xshndx.data, &symstate->xshndx.n);
229 }
230
231
232
233 /*
234 * Display symbol table entries in the style used by elfdump.
235 *
236 * entry:
237 * argstate - Overall state block
238 * symstate - State block for current symbol table.
239 * ndx - Index of first symbol to display
240 * cnt - Number of symbols to display
241 */
242 static void
dump_symtab(ARGSTATE * argstate,SYMSTATE * symstate,Word ndx,Word cnt)243 dump_symtab(ARGSTATE *argstate, SYMSTATE *symstate, Word ndx, Word cnt)
244 {
245 char index[MAXNDXSIZE];
246 Word shndx;
247 const char *shndx_name;
248 elfedit_section_t *symsec;
249 elfedit_section_t *strsec;
250 Sym *sym;
251 elfedit_obj_state_t *obj_state = argstate->obj_state;
252 uchar_t osabi = obj_state->os_ehdr->e_ident[EI_OSABI];
253 Half mach = obj_state->os_ehdr->e_machine;
254 const char *symname;
255 Versym versym;
256
257 symsec = symstate->sym.sec;
258 sym = symstate->sym.data + ndx;
259
260 symstate_add_str(argstate, symstate);
261 strsec = symstate->str.sec;
262
263 /* If there is a versym index section, fetch it */
264 if (symstate->versym.shndx != SHN_UNDEF)
265 symstate_add_versym(argstate, symstate);
266
267 /* If there is an extended index section, fetch it */
268 if (symstate->xshndx.shndx != SHN_UNDEF)
269 symstate_add_xshndx(argstate, symstate);
270
271 elfedit_printf(MSG_INTL(MSG_FMT_SYMTAB), symsec->sec_name);
272 Elf_syms_table_title(0, ELF_DBG_ELFDUMP);
273 for (; cnt-- > 0; ndx++, sym++) {
274 (void) snprintf(index, MAXNDXSIZE,
275 MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(ndx));
276 versym = (symstate->versym.sec == NULL) ? 0 :
277 symstate->versym.data[ndx];
278 symname = elfedit_offset_to_str(strsec, sym->st_name,
279 ELFEDIT_MSG_DEBUG, 0);
280 shndx = sym->st_shndx;
281 if ((shndx == SHN_XINDEX) && (symstate->xshndx.sec != NULL))
282 shndx = symstate->xshndx.data[ndx];
283 shndx_name = elfedit_shndx_to_name(obj_state, shndx);
284 Elf_syms_table_entry(NULL, ELF_DBG_ELFDUMP, index, osabi, mach,
285 sym, versym, 0, shndx_name, symname);
286 }
287 }
288
289
290
291 /*
292 * Called by print_sym() to determine if a given symbol has the same
293 * display value for the current command in every symbol table.
294 *
295 * entry:
296 * cmd - SYM_CMD_T_* value giving identify of caller
297 * argstate - Overall state block
298 * outstyle - Output style to use
299 */
300 static int
all_same(SYM_CMD_T cmd,ARGSTATE * argstate,elfedit_outstyle_t outstyle)301 all_same(SYM_CMD_T cmd, ARGSTATE *argstate, elfedit_outstyle_t outstyle)
302 {
303 Word tblndx;
304 SYMSTATE *symstate1, *symstate2;
305 Sym *sym1, *sym2;
306
307 symstate1 = argstate->symstate;
308 for (tblndx = 0; tblndx < (argstate->numsymstate - 1);
309 tblndx++, symstate1++) {
310 symstate2 = symstate1 + 1;
311 sym1 = &symstate1->sym.data[symstate1->ndx];
312 sym2 = &symstate2->sym.data[symstate2->ndx];
313
314 switch (cmd) {
315 case SYM_CMD_T_DUMP:
316 /* sym:dump should always show everything */
317 return (0);
318
319 case SYM_CMD_T_ST_BIND:
320 if (ELF_ST_BIND(sym1->st_info) !=
321 ELF_ST_BIND(sym2->st_info))
322 return (0);
323 break;
324
325 case SYM_CMD_T_ST_INFO:
326 if (sym1->st_info != sym2->st_info)
327 return (0);
328 break;
329
330 case SYM_CMD_T_ST_NAME:
331 /*
332 * In simple output mode, we show the string. In
333 * numeric mode, we show the string table offset.
334 */
335 if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
336 const char *n1, *n2;
337
338 symstate_add_str(argstate, symstate1);
339 symstate_add_str(argstate, symstate2);
340 n1 = elfedit_offset_to_str(symstate1->str.sec,
341 sym1->st_name, ELFEDIT_MSG_DEBUG, 0);
342 n2 = elfedit_offset_to_str(symstate2->str.sec,
343 sym2->st_name, ELFEDIT_MSG_DEBUG, 0);
344 if (strcmp(n1, n2) != 0)
345 return (0);
346 } else {
347 if (sym1->st_name != sym2->st_name)
348 return (0);
349 }
350 break;
351
352 case SYM_CMD_T_ST_OTHER:
353 if (sym1->st_other != sym2->st_other)
354 return (0);
355 break;
356
357 case SYM_CMD_T_ST_SHNDX:
358 {
359 Word ndx1, ndx2;
360
361 ndx1 = sym1->st_shndx;
362 if ((ndx1 == SHN_XINDEX) &&
363 (symstate1->xshndx.shndx != SHN_UNDEF)) {
364 symstate_add_xshndx(argstate,
365 symstate1);
366 ndx1 = symstate1->xshndx.
367 data[symstate1->ndx];
368 }
369 ndx2 = sym2->st_shndx;
370 if ((ndx2 == SHN_XINDEX) &&
371 (symstate2->xshndx.shndx != SHN_UNDEF)) {
372 symstate_add_xshndx(argstate,
373 symstate2);
374 ndx2 = symstate2->xshndx.
375 data[symstate2->ndx];
376 }
377 if (ndx1 != ndx2)
378 return (0);
379 }
380 break;
381
382 case SYM_CMD_T_ST_SIZE:
383 if (sym1->st_size != sym2->st_size)
384 return (0);
385 break;
386
387 case SYM_CMD_T_ST_TYPE:
388 if (ELF_ST_TYPE(sym1->st_info) !=
389 ELF_ST_TYPE(sym2->st_info))
390 return (0);
391 break;
392
393 case SYM_CMD_T_ST_VALUE:
394 if (sym1->st_value != sym2->st_value)
395 return (0);
396 break;
397
398 case SYM_CMD_T_ST_VISIBILITY:
399 if (ELF_ST_VISIBILITY(sym1->st_info) !=
400 ELF_ST_VISIBILITY(sym2->st_info))
401 return (0);
402 break;
403 }
404 }
405
406 /* If we got here, there are no differences (or maybe only 1 table */
407 return (1);
408 }
409
410
411 /*
412 * Called by print_sym() to display values for a single symbol table.
413 *
414 * entry:
415 * autoprint - If True, output is only produced if the elfedit
416 * autoprint flag is set. If False, output is always produced.
417 * cmd - SYM_CMD_T_* value giving identify of caller
418 * argstate - Overall state block
419 * symstate - State block for current symbol table.
420 * ndx - Index of first symbol to display
421 * cnt - Number of symbols to display
422 */
423 static void
print_symstate(SYM_CMD_T cmd,ARGSTATE * argstate,SYMSTATE * symstate,elfedit_outstyle_t outstyle,Word ndx,Word cnt)424 print_symstate(SYM_CMD_T cmd, ARGSTATE *argstate, SYMSTATE *symstate,
425 elfedit_outstyle_t outstyle, Word ndx, Word cnt)
426 {
427 Word value;
428 Sym *sym;
429
430 /*
431 * If doing default output, use elfdump style where we
432 * show all symbol attributes. In this case, the command
433 * that called us doesn't matter
434 */
435 if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) {
436 dump_symtab(argstate, symstate, ndx, cnt);
437 return;
438 }
439
440 sym = symstate->sym.data;
441
442 switch (cmd) {
443 case SYM_CMD_T_ST_BIND:
444 {
445 Conv_inv_buf_t inv_buf;
446
447 for (sym += ndx; cnt--; sym++) {
448 value = ELF_ST_BIND(sym->st_info);
449 if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
450 elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
451 conv_sym_info_bind(value,
452 CONV_FMT_ALT_CF, &inv_buf));
453 } else {
454 elfedit_printf(
455 MSG_ORIG(MSG_FMT_WORDVALNL),
456 EC_WORD(value));
457 }
458 }
459 }
460 return;
461
462 case SYM_CMD_T_ST_INFO:
463 for (sym += ndx; cnt-- > 0; sym++)
464 elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL),
465 EC_WORD(sym->st_info));
466 return;
467
468 case SYM_CMD_T_ST_NAME:
469 /*
470 * In simple output mode, we show the string. In numeric
471 * mode, we show the string table offset.
472 */
473 if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
474 symstate_add_str(argstate, symstate);
475 for (sym += ndx; cnt--; sym++) {
476 elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
477 elfedit_offset_to_str(symstate->str.sec,
478 sym->st_name, ELFEDIT_MSG_ERR, 0));
479 }
480 } else {
481 for (; cnt--; sym++)
482 elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL),
483 EC_WORD(sym->st_name));
484 }
485 return;
486
487 case SYM_CMD_T_ST_OTHER:
488 for (sym += ndx; cnt-- > 0; sym++)
489 elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL),
490 EC_WORD(sym->st_other));
491 return;
492
493 case SYM_CMD_T_ST_SHNDX:
494 /* If there is an extended index section, fetch it */
495 if (symstate->xshndx.shndx != SHN_UNDEF)
496 symstate_add_xshndx(argstate, symstate);
497
498 for (; cnt--; ndx++) {
499 value = sym[ndx].st_shndx;
500 if ((value == SHN_XINDEX) &&
501 (symstate->xshndx.sec != NULL))
502 value = symstate->xshndx.data[ndx];
503
504 if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
505 elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
506 elfedit_shndx_to_name(argstate->obj_state,
507 value));
508 } else {
509 elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL),
510 EC_WORD(value));
511 }
512 }
513 return;
514
515 case SYM_CMD_T_ST_SIZE:
516 /*
517 * machine word width integers displayed in fixed width
518 * 0-filled hex format.
519 */
520 for (sym += ndx; cnt--; sym++)
521 elfedit_printf(MSG_ORIG(MSG_FMT_XWORDVALNL),
522 sym->st_size);
523 return;
524
525 case SYM_CMD_T_ST_TYPE:
526 {
527 Half mach = argstate->obj_state->os_ehdr->e_machine;
528 Conv_inv_buf_t inv_buf;
529
530 for (sym += ndx; cnt--; sym++) {
531 value = ELF_ST_TYPE(sym->st_info);
532 if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
533 elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
534 conv_sym_info_type(mach, value,
535 CONV_FMT_ALT_CF, &inv_buf));
536 } else {
537 elfedit_printf(
538 MSG_ORIG(MSG_FMT_WORDVALNL),
539 EC_WORD(value));
540 }
541 }
542 }
543 return;
544
545 case SYM_CMD_T_ST_VALUE:
546 /*
547 * machine word width integers displayed in fixed width
548 * 0-filled hex format.
549 */
550 for (sym += ndx; cnt--; sym++)
551 elfedit_printf(MSG_ORIG(MSG_FMT_XWORDVALNL),
552 sym->st_value);
553 return;
554
555 case SYM_CMD_T_ST_VISIBILITY:
556 {
557 Conv_inv_buf_t inv_buf;
558
559 for (sym += ndx; cnt--; sym++) {
560 value = ELF_ST_VISIBILITY(sym->st_other);
561 if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
562 elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
563 conv_sym_other_vis(value,
564 CONV_FMT_ALT_CF, &inv_buf));
565 } else {
566 elfedit_printf(
567 MSG_ORIG(MSG_FMT_WORDVALNL),
568 EC_WORD(value));
569 }
570 }
571 }
572 return;
573
574 }
575 }
576
577
578 /*
579 * Print symbol values, taking the calling command, and output style
580 * into account.
581 *
582 * entry:
583 * autoprint - If True, output is only produced if the elfedit
584 * autoprint flag is set. If False, output is always produced.
585 * cmd - SYM_CMD_T_* value giving identify of caller
586 * argstate - Overall state block
587 * symstate - State block for current symbol table.
588 * ndx - Index of first symbol to display
589 * cnt - Number of symbols to display
590 */
591 static void
print_sym(SYM_CMD_T cmd,int autoprint,ARGSTATE * argstate)592 print_sym(SYM_CMD_T cmd, int autoprint, ARGSTATE *argstate)
593 {
594 Word ndx, tblndx;
595 Word cnt;
596 elfedit_outstyle_t outstyle;
597 SYMSTATE *symstate;
598 int only_one;
599
600 if ((autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0)))
601 return;
602
603 /*
604 * Pick an output style. sym:dump is required to use the default
605 * style. The other commands use the current output style.
606 */
607 outstyle = (cmd == SYM_CMD_T_DUMP) ?
608 ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle();
609
610 /*
611 * This is a nicity: Force any needed auxiliary sections to be
612 * fetched here before any output is produced. This will put all
613 * of the debug messages right at the top in a single cluster.
614 */
615 symstate = argstate->symstate;
616 for (tblndx = 0; tblndx < argstate->numsymstate; tblndx++, symstate++) {
617 if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) {
618 symstate_add_str(argstate, symstate);
619 if (symstate->versym.shndx != SHN_UNDEF)
620 symstate_add_versym(argstate, symstate);
621 if (symstate->xshndx.shndx != SHN_UNDEF)
622 symstate_add_xshndx(argstate, symstate);
623 continue;
624 }
625
626 if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
627 switch (cmd) {
628 case SYM_CMD_T_ST_NAME:
629 symstate_add_str(argstate, symstate);
630 break;
631
632 case SYM_CMD_T_ST_SHNDX:
633 if (symstate->xshndx.shndx != SHN_UNDEF)
634 symstate_add_xshndx(argstate, symstate);
635 break;
636 }
637 }
638 }
639
640 /*
641 * If there is more than one table, we are displaying a single
642 * item, we are not using the default "elfdump" style, and all
643 * the symbols have the same value for the thing we intend to
644 * display, then we only want to display it once.
645 */
646 only_one = (argstate->numsymstate > 1) && (argstate->argc > 0) &&
647 (outstyle != ELFEDIT_OUTSTYLE_DEFAULT) &&
648 all_same(cmd, argstate, outstyle);
649
650 /* Run through the tables and display from each one */
651 symstate = argstate->symstate;
652 for (tblndx = 0; tblndx < argstate->numsymstate; tblndx++, symstate++) {
653 if (argstate->argc == 0) {
654 ndx = 0;
655 cnt = symstate->sym.n;
656 } else {
657 ndx = symstate->ndx;
658 cnt = 1;
659 }
660
661 if ((tblndx > 0) && ((argstate->argc == 0) ||
662 (outstyle == ELFEDIT_OUTSTYLE_DEFAULT)))
663 elfedit_printf(MSG_ORIG(MSG_STR_NL));
664
665 print_symstate(cmd, argstate, symstate, outstyle, ndx, cnt);
666 if (only_one)
667 break;
668 }
669 }
670
671
672 /*
673 * The cmd_body_set_st_XXX() functions are for use by cmd_body().
674 * They handle the case where the second plain argument is
675 * a value to be stored in the symbol.
676 *
677 * entry:
678 * argstate - Overall state block
679 * symstate - State block for current symbol table.
680 */
681 static elfedit_cmdret_t
cmd_body_set_st_bind(ARGSTATE * argstate,SYMSTATE * symstate)682 cmd_body_set_st_bind(ARGSTATE *argstate, SYMSTATE *symstate)
683 {
684 elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE;
685 Sym *sym = &symstate->sym.data[symstate->ndx];
686 Word gbl_ndx;
687 uchar_t bind, type, old_bind;
688 Word symndx;
689 Conv_inv_buf_t inv_buf1, inv_buf2;
690
691 /*
692 * Use the ELF_ST_BIND() macro to access the defined bits
693 * of the st_info field related to symbol binding.
694 * Accepts STB_ symbolic names as well as integers.
695 */
696 bind = elfedit_atoconst_range(argstate->argv[1],
697 MSG_INTL(MSG_ARG_SYMBIND), 0, 15, ELFEDIT_CONST_STB);
698 old_bind = ELF_ST_BIND(sym->st_info);
699 type = ELF_ST_TYPE(sym->st_info);
700
701 if (old_bind == bind) {
702 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_OK),
703 symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
704 EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_BIND),
705 conv_sym_info_bind(bind, CONV_FMT_ALT_CF, &inv_buf1));
706 } else {
707 /*
708 * The sh_info field of the symbol table section header
709 * gives the index of the first non-local symbol in
710 * the table. Issue warnings if the binding we set
711 * contradicts this.
712 */
713 gbl_ndx = symstate->sym.sec->sec_shdr->sh_info;
714 symndx = symstate->sym.sec->sec_shndx;
715 if ((bind == STB_LOCAL) && (symstate->ndx >= gbl_ndx))
716 elfedit_msg(ELFEDIT_MSG_DEBUG,
717 MSG_INTL(MSG_DEBUG_LBINDGSYM),
718 EC_WORD(symndx), symstate->sym.sec->sec_name,
719 symstate->ndx, EC_WORD(symndx), gbl_ndx);
720 if ((bind != STB_LOCAL) && (symstate->ndx < gbl_ndx))
721 elfedit_msg(ELFEDIT_MSG_DEBUG,
722 MSG_INTL(MSG_DEBUG_GBINDLSYM),
723 EC_WORD(symndx), symstate->sym.sec->sec_name,
724 symstate->ndx, EC_WORD(symndx), gbl_ndx);
725
726 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_CHG),
727 symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
728 EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_BIND),
729 conv_sym_info_bind(old_bind, CONV_FMT_ALT_CF,
730 &inv_buf1),
731 conv_sym_info_bind(bind, CONV_FMT_ALT_CF, &inv_buf2));
732 ret = ELFEDIT_CMDRET_MOD;
733 sym->st_info = ELF_ST_INFO(bind, type);
734 }
735
736 return (ret);
737 }
738
739 static elfedit_cmdret_t
cmd_body_set_st_name(ARGSTATE * argstate,SYMSTATE * symstate)740 cmd_body_set_st_name(ARGSTATE *argstate, SYMSTATE *symstate)
741 {
742 elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE;
743 Sym *sym = &symstate->sym.data[symstate->ndx];
744 Word str_offset;
745
746 /*
747 * If -n was specified, this is an offset into the string
748 * table. Otherwise it is a string we need to turn into
749 * an offset
750 */
751 symstate_add_str(argstate, symstate);
752 if (argstate->optmask & SYM_OPT_F_NAMOFFSET) {
753 str_offset = elfedit_atoui(argstate->argv[1], NULL);
754 /* Warn if the offset is out of range */
755 (void) elfedit_offset_to_str(symstate->str.sec,
756 str_offset, ELFEDIT_MSG_DEBUG, 1);
757 } else {
758 str_offset = elfedit_strtab_insert(argstate->obj_state,
759 symstate->str.sec, NULL, argstate->argv[1]);
760 }
761
762 if (sym->st_name == str_offset) {
763 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_D_OK),
764 symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
765 EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_NAME),
766 EC_WORD(sym->st_name));
767 } else {
768 /*
769 * Warn the user: Changing the name of a symbol in the dynsym
770 * will break the hash table in this object.
771 */
772 if (symstate->sym.sec->sec_shdr->sh_type == SHT_DYNSYM)
773 elfedit_msg(ELFEDIT_MSG_DEBUG,
774 MSG_INTL(MSG_DEBUG_DYNSYMNAMCHG),
775 EC_WORD(symstate->sym.sec->sec_shndx),
776 symstate->sym.sec->sec_name,
777 EC_WORD(symstate->ndx));
778
779 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_D_CHG),
780 symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
781 EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_NAME),
782 EC_WORD(sym->st_name),
783 EC_WORD(str_offset));
784 ret = ELFEDIT_CMDRET_MOD;
785 sym->st_name = str_offset;
786 }
787
788 return (ret);
789 }
790
791 static elfedit_cmdret_t
cmd_body_set_st_shndx(ARGSTATE * argstate,SYMSTATE * symstate)792 cmd_body_set_st_shndx(ARGSTATE *argstate, SYMSTATE *symstate)
793 {
794 elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE;
795 Sym *sym = &symstate->sym.data[symstate->ndx];
796 Word shndx, st_shndx, xshndx;
797 int use_xshndx;
798 int shndx_chg, xshndx_chg;
799
800
801 /*
802 * By default, the sec argument is a section name. If -secshndx was
803 * specified, it is a section index, and if -secshtyp is specified,
804 * it is a section type.
805 */
806 if (argstate->optmask & SYM_OPT_F_SECSHNDX)
807 shndx = elfedit_atoshndx(argstate->argv[1],
808 argstate->obj_state->os_shnum);
809 else if (argstate->optmask & SYM_OPT_F_SECSHTYP)
810 shndx = elfedit_type_to_shndx(argstate->obj_state,
811 elfedit_atoconst(argstate->argv[1], ELFEDIT_CONST_SHT));
812 else
813 shndx = elfedit_name_to_shndx(argstate->obj_state,
814 argstate->argv[1]);
815
816 /*
817 * We want to use an extended index section if the index is too
818 * large to be represented otherwise, or if the caller specified
819 * the -e option to make us do it anyway. However, we cannot
820 * do this if the index is in the special reserved range between
821 * SHN_LORESERVE and SHN_HIRESERVE.
822 */
823 use_xshndx = (shndx > SHN_HIRESERVE) ||
824 ((shndx < SHN_LORESERVE) &&
825 (argstate->optmask & SYM_OPT_F_XSHINDEX));
826
827 /*
828 * There are two cases where we have to touch the extended
829 * index section:
830 *
831 * 1) We have determined that we need to, as determined above.
832 * 2) We do not require it, but the file has an extended
833 * index section, in which case we should set the slot
834 * in that extended section to SHN_UNDEF (0).
835 *
836 * Fetch the extended section as required, and determine the values
837 * for st_shndx and the extended section slot.
838 */
839 if (use_xshndx) {
840 /* We must have an extended index section, or error out */
841 symstate_add_xshndx(argstate, symstate);
842
843 /* Set symbol to SHN_XINDEX, put index in the extended sec. */
844 st_shndx = SHN_XINDEX;
845 xshndx = shndx;
846 } else {
847 st_shndx = shndx;
848 xshndx = SHN_UNDEF;
849 if (symstate->xshndx.shndx != SHN_UNDEF)
850 use_xshndx = 1;
851 }
852 if (use_xshndx)
853 symstate_add_xshndx(argstate, symstate);
854 shndx_chg = (sym->st_shndx != st_shndx);
855 xshndx_chg = use_xshndx &&
856 (symstate->xshndx.data[symstate->ndx] != xshndx);
857
858
859 /* If anything is going to change, issue appropiate warnings */
860 if (shndx_chg || xshndx_chg) {
861 /*
862 * Setting the first symbol to anything other than SHN_UNDEF
863 * produces a bad ELF file.
864 */
865 if ((symstate->ndx == 0) && (shndx != SHN_UNDEF))
866 elfedit_msg(ELFEDIT_MSG_DEBUG,
867 MSG_INTL(MSG_DEBUG_SHNDX_UNDEF0));
868
869 /*
870 * Setting SHN_XINDEX directly, instead of providing
871 * an extended index and letting us decide to use
872 * SHN_XINDEX to implement it, is probably a mistake.
873 * Issue a warning, but go ahead and follow the directions
874 * we've been given.
875 */
876 if (shndx == SHN_XINDEX)
877 elfedit_msg(ELFEDIT_MSG_DEBUG,
878 MSG_INTL(MSG_DEBUG_SHNDX_XINDEX));
879
880 /*
881 * If the section index can fit in the symbol, but
882 * -e is being used to force it into the extended
883 * index section, issue a warning.
884 */
885 if (use_xshndx && (shndx < SHN_LORESERVE) &&
886 (st_shndx == SHN_XINDEX))
887 elfedit_msg(ELFEDIT_MSG_DEBUG,
888 MSG_INTL(MSG_DEBUG_SHNDX_EFORCE),
889 EC_WORD(symstate->sym.sec->sec_shndx),
890 symstate->sym.sec->sec_name, EC_WORD(symstate->ndx),
891 EC_WORD(shndx));
892 }
893
894 if (shndx_chg) {
895 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_CHG),
896 symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
897 EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_SHNDX),
898 elfedit_shndx_to_name(argstate->obj_state,
899 sym->st_shndx),
900 elfedit_shndx_to_name(argstate->obj_state, st_shndx));
901 ret = ELFEDIT_CMDRET_MOD;
902 sym->st_shndx = st_shndx;
903 } else {
904 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_OK),
905 symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
906 EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_SHNDX),
907 elfedit_shndx_to_name(argstate->obj_state, st_shndx));
908 }
909
910 if (use_xshndx) {
911 if (xshndx_chg) {
912 elfedit_msg(ELFEDIT_MSG_DEBUG,
913 MSG_INTL(MSG_DEBUG_EXT_S_CHG),
914 symstate->xshndx.sec->sec_shndx,
915 symstate->xshndx.sec->sec_name,
916 EC_WORD(symstate->ndx),
917 elfedit_shndx_to_name(argstate->obj_state,
918 symstate->xshndx.data[symstate->ndx]),
919 elfedit_shndx_to_name(argstate->obj_state, xshndx));
920 ret = ELFEDIT_CMDRET_MOD;
921 symstate->xshndx.data[symstate->ndx] = xshndx;
922 elfedit_modified_data(symstate->xshndx.sec);
923 } else {
924 elfedit_msg(ELFEDIT_MSG_DEBUG,
925 MSG_INTL(MSG_DEBUG_EXT_S_OK),
926 symstate->xshndx.sec->sec_shndx,
927 symstate->xshndx.sec->sec_name,
928 EC_WORD(symstate->ndx),
929 elfedit_shndx_to_name(argstate->obj_state, xshndx));
930 }
931 }
932
933 return (ret);
934 }
935
936 static elfedit_cmdret_t
cmd_body_set_st_type(ARGSTATE * argstate,SYMSTATE * symstate)937 cmd_body_set_st_type(ARGSTATE *argstate, SYMSTATE *symstate)
938 {
939 elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE;
940 Conv_inv_buf_t inv_buf1, inv_buf2;
941 Half mach = argstate->obj_state->os_ehdr->e_machine;
942 Sym *sym = &symstate->sym.data[symstate->ndx];
943 uchar_t bind, type, old_type;
944
945 /*
946 * Use the ELF_ST_TYPE() macro to access the defined bits
947 * of the st_info field related to symbol type.
948 * Accepts STT_ symbolic names as well as integers.
949 */
950 bind = ELF_ST_BIND(sym->st_info);
951 type = elfedit_atoconst_range(argstate->argv[1],
952 MSG_INTL(MSG_ARG_SYMBIND), 0, 15, ELFEDIT_CONST_STT);
953 old_type = ELF_ST_TYPE(sym->st_info);
954
955 if (old_type == type) {
956 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_OK),
957 symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
958 EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_TYPE),
959 conv_sym_info_type(mach, type, CONV_FMT_ALT_CF,
960 &inv_buf1));
961 } else {
962 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_CHG),
963 symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
964 EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_TYPE),
965 conv_sym_info_type(mach, old_type, CONV_FMT_ALT_CF,
966 &inv_buf1),
967 conv_sym_info_type(mach, type, CONV_FMT_ALT_CF,
968 &inv_buf2));
969 ret = ELFEDIT_CMDRET_MOD;
970 sym->st_info = ELF_ST_INFO(bind, type);
971 }
972
973 return (ret);
974 }
975
976 static elfedit_cmdret_t
cmd_body_set_st_visibility(ARGSTATE * argstate,SYMSTATE * symstate)977 cmd_body_set_st_visibility(ARGSTATE *argstate, SYMSTATE *symstate)
978 {
979 elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE;
980 Conv_inv_buf_t inv_buf1, inv_buf2;
981 Sym *sym = &symstate->sym.data[symstate->ndx];
982 uchar_t st_other = sym->st_other;
983 uchar_t vis, old_vis;
984
985 /*
986 * Use the ELF_ST_VISIBILITY() macro to access the
987 * defined bits of the st_other field related to symbol
988 * visibility. Accepts STV_ symbolic names as well as integers.
989 */
990 vis = elfedit_atoconst_range(argstate->argv[1],
991 MSG_INTL(MSG_ARG_SYMVIS), 0, STV_ELIMINATE, ELFEDIT_CONST_STV);
992 old_vis = st_other & MSK_SYM_VISIBILITY;
993
994 if (old_vis == vis) {
995 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_OK),
996 symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
997 EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_VISIBILITY),
998 conv_sym_other_vis(old_vis, CONV_FMT_ALT_CF,
999 &inv_buf1));
1000 } else {
1001 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_CHG),
1002 symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
1003 EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_VISIBILITY),
1004 conv_sym_other_vis(old_vis, CONV_FMT_ALT_CF,
1005 &inv_buf1),
1006 conv_sym_other_vis(vis, CONV_FMT_ALT_CF, &inv_buf2));
1007 ret = ELFEDIT_CMDRET_MOD;
1008 st_other = (st_other & ~MSK_SYM_VISIBILITY) |
1009 ELF_ST_VISIBILITY(vis);
1010 sym->st_other = st_other;
1011 }
1012
1013 return (ret);
1014 }
1015
1016
1017 /*
1018 * Standard argument processing for sym module
1019 *
1020 * entry
1021 * obj_state, argc, argv - Standard command arguments
1022 * optmask - Mask of allowed optional arguments.
1023 * symstate - State block for current symbol table.
1024 * argstate - Address of ARGSTATE block to be initialized
1025 *
1026 * exit:
1027 * On success, *argstate is initialized. On error,
1028 * an error is issued and this routine does not return.
1029 *
1030 * note:
1031 * Only the basic symbol table is initially referenced by
1032 * argstate. Use the argstate_add_XXX() routines below to
1033 * access any auxiliary sections needed.
1034 */
1035 static ARGSTATE *
process_args(elfedit_obj_state_t * obj_state,int argc,const char * argv[],SYM_CMD_T cmd)1036 process_args(elfedit_obj_state_t *obj_state, int argc, const char *argv[],
1037 SYM_CMD_T cmd)
1038 {
1039 /*
1040 * We reuse this same argstate, resizing it to the required
1041 * number of symbol tables on the first call, and as necessary.
1042 */
1043 static ARGSTATE *argstate;
1044 static int argstate_size = 0;
1045
1046 elfedit_getopt_state_t getopt_state;
1047 elfedit_getopt_ret_t *getopt_ret;
1048 elfedit_symtab_t *symtab;
1049 int explicit = 0;
1050 int got_sym = 0;
1051 Word index;
1052 Word tblndx;
1053 size_t size;
1054 SYMSTATE *symstate;
1055
1056 /* If there are no symbol tables, we can't do a thing */
1057 if (obj_state->os_symtabnum == 0)
1058 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSYMTAB));
1059
1060 /* Calulate required size of argstate and realloc as necessary */
1061 size = sizeof (ARGSTATE) +
1062 ((obj_state->os_symtabnum - 1) * sizeof (SYMSTATE));
1063 if (argstate_size != size) {
1064 argstate = elfedit_realloc(MSG_INTL(MSG_ALLOC_ARGSTATE),
1065 argstate, size);
1066 argstate_size = size;
1067 }
1068 bzero(argstate, argstate_size);
1069 argstate->obj_state = obj_state;
1070
1071 elfedit_getopt_init(&getopt_state, &argc, &argv);
1072 while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL) {
1073 argstate->optmask |= getopt_ret->gor_idmask;
1074 switch (getopt_ret->gor_idmask) {
1075 case SYM_OPT_F_SHNAME: /* -shnam name */
1076 index = elfedit_name_to_shndx(obj_state,
1077 getopt_ret->gor_value);
1078 explicit = 1;
1079 break;
1080
1081 case SYM_OPT_F_SHNDX: /* -shndx index */
1082 index = elfedit_atoui_range(getopt_ret->gor_value,
1083 MSG_INTL(MSG_ARG_SECNDX), 1,
1084 obj_state->os_shnum - 1, NULL);
1085 explicit = 1;
1086 break;
1087
1088 case SYM_OPT_F_SHTYP: /* -shtyp type */
1089 index = elfedit_type_to_shndx(obj_state,
1090 elfedit_atoconst(getopt_ret->gor_value,
1091 ELFEDIT_CONST_SHT));
1092 explicit = 1;
1093 break;
1094 }
1095 }
1096
1097 /*
1098 * Usage error if there are too many plain arguments. sym:dump accepts
1099 * a single argument, while the others accept 2.
1100 */
1101 if (((cmd == SYM_CMD_T_DUMP) && (argc > 1)) || (argc > 2))
1102 elfedit_command_usage();
1103
1104 /*
1105 * If the -symndx option was specified, the sym arg is an index
1106 * into the symbol table. In this case, the symbol table must be
1107 * explicitly specified (-shnam, -shndx, or -shtype).
1108 */
1109 if ((argstate->optmask & SYM_OPT_F_SYMNDX) && !explicit)
1110 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NEEDEXPSYMTAB));
1111
1112 /*
1113 * If a section was explicitly specified, it must be a symbol table.
1114 */
1115 if (explicit)
1116 (void) elfedit_sec_issymtab(obj_state,
1117 &obj_state->os_secarr[index], 1, NULL);
1118
1119 /* If there may be an arbitrary amount of output, use a pager */
1120 if (argc == 0)
1121 elfedit_pager_init();
1122
1123 /* Return the updated values of argc/argv */
1124 argstate->argc = argc;
1125 argstate->argv = argv;
1126
1127 /*
1128 * Decide which symbol table(s) to use. Set up the symstate
1129 * array to contain them:
1130 * - If a symbol table was explicitly specified, we use
1131 * it, and only it.
1132 * - If no symbol table is explicitly specified, and the symbol
1133 * is given by name, we use all symbol tables that
1134 * contain a symbol with that name, throwing an error
1135 * if there isn't at least 1 such table.
1136 * - If no symbol table is specified, and no symbol is specified,
1137 * we use all the tables.
1138 */
1139 symtab = obj_state->os_symtab;
1140 symstate = argstate->symstate;
1141 for (tblndx = 0; tblndx < obj_state->os_symtabnum;
1142 tblndx++, symtab++) {
1143 /*
1144 * If an explicit table is specified, only that table is
1145 * considered.
1146 *
1147 * If no explicit table is specified, verify that table
1148 * is considered to be a symbol table by the current osabi,
1149 * and quietly skip it if not.
1150 */
1151 if (explicit) {
1152 if (symtab->symt_shndx != index)
1153 continue;
1154 } else if (elfedit_sec_issymtab(obj_state,
1155 &obj_state->os_secarr[symtab->symt_shndx], 0, NULL) == 0) {
1156 continue;
1157 }
1158
1159 symstate->sym.sec = elfedit_sec_getsymtab(obj_state, 1,
1160 symtab->symt_shndx, NULL, &symstate->sym.data,
1161 &symstate->sym.n, &symtab);
1162 symstate->versym.shndx = symtab->symt_versym;
1163 symstate->xshndx.shndx = symtab->symt_xshndx;
1164 if (argc > 0) {
1165 if (argstate->optmask & SYM_OPT_F_SYMNDX) {
1166 symstate->ndx = elfedit_atoui_range(
1167 argstate->argv[0], MSG_INTL(MSG_ARG_SYM), 0,
1168 symstate->sym.n - 1, NULL);
1169 } else {
1170 /*
1171 * arg is a symbol name. Use the index of
1172 * the first symbol that matches
1173 */
1174
1175 /*
1176 * We will use debug messages for failure up
1177 * until we run out of symbol tables. If we
1178 * don't find a table with the desired symbol
1179 * before the last table, we switch to error
1180 * messages. Hence, we will jump with an error
1181 * if no table will work.
1182 */
1183 int err_type = (!got_sym &&
1184 ((tblndx + 1) == obj_state->os_symtabnum)) ?
1185 ELFEDIT_MSG_ERR : ELFEDIT_MSG_DEBUG;
1186
1187 symstate_add_str(argstate, symstate);
1188
1189 /*
1190 * If the symbol table doesn't have this
1191 * symbol, then forget it.
1192 */
1193 if (elfedit_name_to_symndx(symstate->sym.sec,
1194 symstate->str.sec, argstate->argv[0],
1195 err_type, &symstate->ndx) == 0) {
1196 bzero(symstate, sizeof (*symstate));
1197 continue;
1198 }
1199 }
1200 }
1201 argstate->numsymstate++;
1202 symstate++;
1203 /*
1204 * If the symbol table was given explicitly, and
1205 * we've just taken it, then there is no reason to
1206 * continue searching.
1207 */
1208 if (explicit)
1209 break;
1210 }
1211
1212 return (argstate);
1213 }
1214
1215
1216
1217 /*
1218 * Called by cmd_body() to handle the value change for a single
1219 * symbol table.
1220 *
1221 * entry:
1222 * cmd - One of the SYM_CMD_T_* constants listed above, specifying
1223 * which command to implement.
1224 * argstate - Overall state block
1225 * symstate - State block for current symbol table.
1226 */
1227 static elfedit_cmdret_t
symstate_cmd_body(SYM_CMD_T cmd,ARGSTATE * argstate,SYMSTATE * symstate)1228 symstate_cmd_body(SYM_CMD_T cmd, ARGSTATE *argstate, SYMSTATE *symstate)
1229 {
1230 elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE;
1231 Sym *sym = &symstate->sym.data[symstate->ndx];
1232
1233 /* You're not supposed to change the value of symbol [0] */
1234 if (symstate->ndx == 0)
1235 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CHGSYMELT0),
1236 EC_WORD(symstate->sym.sec->sec_shndx),
1237 symstate->sym.sec->sec_name, EC_WORD(symstate->ndx));
1238
1239 /* The second value is an integer giving a new value */
1240 switch (cmd) {
1241 /*
1242 * SYM_CMD_T_DUMP can't get here: It never has more than
1243 * one argument, and is handled above.
1244 */
1245
1246 case SYM_CMD_T_ST_BIND:
1247 ret = cmd_body_set_st_bind(argstate, symstate);
1248 break;
1249
1250 case SYM_CMD_T_ST_INFO:
1251 {
1252 /* Treat st_info as a raw integer field */
1253 uchar_t st_info =
1254 elfedit_atoui(argstate->argv[1], NULL);
1255
1256 if (sym->st_info == st_info) {
1257 elfedit_msg(ELFEDIT_MSG_DEBUG,
1258 MSG_INTL(MSG_DEBUG_D_OK),
1259 symstate->sym.sec->sec_shndx,
1260 symstate->sym.sec->sec_name,
1261 EC_WORD(symstate->ndx),
1262 MSG_ORIG(MSG_CMD_ST_INFO),
1263 EC_WORD(sym->st_info));
1264 } else {
1265 elfedit_msg(ELFEDIT_MSG_DEBUG,
1266 MSG_INTL(MSG_DEBUG_D_CHG),
1267 symstate->sym.sec->sec_shndx,
1268 symstate->sym.sec->sec_name,
1269 EC_WORD(symstate->ndx),
1270 MSG_ORIG(MSG_CMD_ST_INFO),
1271 EC_WORD(sym->st_info), EC_WORD(st_info));
1272 ret = ELFEDIT_CMDRET_MOD;
1273 sym->st_info = st_info;
1274 }
1275 }
1276 break;
1277
1278 case SYM_CMD_T_ST_NAME:
1279 ret = cmd_body_set_st_name(argstate, symstate);
1280 break;
1281
1282 case SYM_CMD_T_ST_OTHER:
1283 {
1284 /* Treat st_other as a raw integer field */
1285 uchar_t st_other =
1286 elfedit_atoui(argstate->argv[1], NULL);
1287
1288 if (sym->st_other == st_other) {
1289 elfedit_msg(ELFEDIT_MSG_DEBUG,
1290 MSG_INTL(MSG_DEBUG_D_OK),
1291 symstate->sym.sec->sec_shndx,
1292 symstate->sym.sec->sec_name,
1293 EC_WORD(symstate->ndx),
1294 MSG_ORIG(MSG_CMD_ST_OTHER),
1295 EC_WORD(sym->st_other));
1296 } else {
1297 elfedit_msg(ELFEDIT_MSG_DEBUG,
1298 MSG_INTL(MSG_DEBUG_D_CHG),
1299 symstate->sym.sec->sec_shndx,
1300 symstate->sym.sec->sec_name,
1301 EC_WORD(symstate->ndx),
1302 MSG_ORIG(MSG_CMD_ST_OTHER),
1303 EC_WORD(sym->st_other), EC_WORD(st_other));
1304 ret = ELFEDIT_CMDRET_MOD;
1305 sym->st_other = st_other;
1306 }
1307 }
1308 break;
1309
1310 case SYM_CMD_T_ST_SHNDX:
1311 ret = cmd_body_set_st_shndx(argstate, symstate);
1312 break;
1313
1314 case SYM_CMD_T_ST_SIZE:
1315 {
1316 Xword st_size = elfedit_atoui(argstate->argv[1], NULL);
1317
1318 if (sym->st_size == st_size) {
1319 elfedit_msg(ELFEDIT_MSG_DEBUG,
1320 MSG_INTL(MSG_DEBUG_LLX_OK),
1321 symstate->sym.sec->sec_shndx,
1322 symstate->sym.sec->sec_name,
1323 EC_WORD(symstate->ndx),
1324 MSG_ORIG(MSG_CMD_ST_SIZE),
1325 EC_XWORD(sym->st_size));
1326 } else {
1327 elfedit_msg(ELFEDIT_MSG_DEBUG,
1328 MSG_INTL(MSG_DEBUG_LLX_CHG),
1329 symstate->sym.sec->sec_shndx,
1330 symstate->sym.sec->sec_name,
1331 EC_WORD(symstate->ndx),
1332 MSG_ORIG(MSG_CMD_ST_SIZE),
1333 EC_XWORD(sym->st_size), EC_XWORD(st_size));
1334 ret = ELFEDIT_CMDRET_MOD;
1335 sym->st_size = st_size;
1336 }
1337 }
1338 break;
1339
1340 case SYM_CMD_T_ST_TYPE:
1341 ret = cmd_body_set_st_type(argstate, symstate);
1342 break;
1343
1344 case SYM_CMD_T_ST_VALUE:
1345 {
1346 Addr st_value = elfedit_atoui(argstate->argv[1], NULL);
1347
1348 if (sym->st_value == st_value) {
1349 elfedit_msg(ELFEDIT_MSG_DEBUG,
1350 MSG_INTL(MSG_DEBUG_LLX_OK),
1351 symstate->sym.sec->sec_shndx,
1352 symstate->sym.sec->sec_name,
1353 EC_WORD(symstate->ndx),
1354 MSG_ORIG(MSG_CMD_ST_VALUE),
1355 EC_ADDR(sym->st_value));
1356 } else {
1357 elfedit_msg(ELFEDIT_MSG_DEBUG,
1358 MSG_INTL(MSG_DEBUG_LLX_CHG),
1359 symstate->sym.sec->sec_shndx,
1360 symstate->sym.sec->sec_name,
1361 EC_WORD(symstate->ndx),
1362 MSG_ORIG(MSG_CMD_ST_VALUE),
1363 EC_ADDR(sym->st_value),
1364 EC_ADDR(st_value));
1365 ret = ELFEDIT_CMDRET_MOD;
1366 ret = ELFEDIT_CMDRET_MOD;
1367 sym->st_value = st_value;
1368 }
1369 }
1370 break;
1371
1372 case SYM_CMD_T_ST_VISIBILITY:
1373 ret = cmd_body_set_st_visibility(argstate, symstate);
1374 break;
1375 }
1376
1377 /*
1378 * If we modified the symbol table, tell libelf.
1379 * Any other modified sections are the responsibility
1380 * of the cmd_body_set_st_*() function that did it, but
1381 * everyone modifies the table itself, so we handle that here.
1382 */
1383 if (ret == ELFEDIT_CMDRET_MOD)
1384 elfedit_modified_data(symstate->sym.sec);
1385
1386 return (ret);
1387 }
1388
1389
1390
1391
1392 /*
1393 * Common body for the sym: module commands. These commands
1394 * share a large amount of common behavior, so it is convenient
1395 * to centralize things and use the cmd argument to handle the
1396 * small differences.
1397 *
1398 * entry:
1399 * cmd - One of the SYM_CMD_T_* constants listed above, specifying
1400 * which command to implement.
1401 * obj_state, argc, argv - Standard command arguments
1402 */
1403 static elfedit_cmdret_t
cmd_body(SYM_CMD_T cmd,elfedit_obj_state_t * obj_state,int argc,const char * argv[])1404 cmd_body(SYM_CMD_T cmd, elfedit_obj_state_t *obj_state,
1405 int argc, const char *argv[])
1406 {
1407 elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE;
1408 ARGSTATE *argstate;
1409 SYMSTATE *symstate;
1410 Word tblndx;
1411
1412 argstate = process_args(obj_state, argc, argv, cmd);
1413
1414 /*
1415 * If there are not 2 arguments, then this is a display request.
1416 * If no arguments are present, the full table (or tables) is
1417 * dumped. If there is one argument, then the specified item is shown.
1418 */
1419 if (argstate->argc < 2) {
1420 print_sym(cmd, 0, argstate);
1421 return (ELFEDIT_CMDRET_NONE);
1422 }
1423
1424 /*
1425 * When processing multiple symbol tables, it is important that
1426 * any failure happen before anything is changed. Otherwise, you
1427 * can end up in a situation where things are left in an inconsistent
1428 * half done state. sym:st_name has that issue when the -name_offset
1429 * option is used, because the string may be insertable into some
1430 * (dynstr) string tables, but not all of them. So, do the tests
1431 * up front, and refuse to continue if any string insertions would
1432 * fail.
1433 */
1434 if ((cmd == SYM_CMD_T_ST_NAME) && (argstate->numsymstate > 1) &&
1435 ((argstate->optmask & SYM_OPT_F_NAMOFFSET) == 0)) {
1436 symstate = argstate->symstate;
1437 for (tblndx = 0; tblndx < argstate->numsymstate;
1438 tblndx++, symstate++)
1439 elfedit_strtab_insert_test(obj_state, symstate->str.sec,
1440 NULL, argstate->argv[1]);
1441 }
1442
1443
1444 /* Loop over the table(s) and make the specified value change */
1445 symstate = argstate->symstate;
1446 for (tblndx = 0; tblndx < argstate->numsymstate; tblndx++, symstate++)
1447 if (symstate_cmd_body(cmd, argstate, symstate) ==
1448 ELFEDIT_CMDRET_MOD)
1449 ret = ELFEDIT_CMDRET_MOD;
1450
1451 /* Do autoprint */
1452 print_sym(cmd, 1, argstate);
1453
1454 return (ret);
1455 }
1456
1457
1458
1459
1460 /*
1461 * Command completion functions for the various commands
1462 */
1463
1464 /*
1465 * Handle filling in the values for -shnam, -shndx, and -shtyp options.
1466 */
1467 /*ARGSUSED*/
1468 static void
cpl_sh_opt(elfedit_obj_state_t * obj_state,void * cpldata,int argc,const char * argv[],int num_opt)1469 cpl_sh_opt(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1470 const char *argv[], int num_opt)
1471 {
1472 enum { NAME, INDEX, TYPE } op;
1473 elfedit_symtab_t *symtab;
1474 Word tblndx;
1475
1476 if ((argc != num_opt) || (argc < 2))
1477 return;
1478
1479 if (strcmp(argv[argc - 2], MSG_ORIG(MSG_STR_MINUS_SHNAM)) == 0) {
1480 op = NAME;
1481 } else if (strcmp(argv[argc - 2], MSG_ORIG(MSG_STR_MINUS_SHNDX)) == 0) {
1482 op = INDEX;
1483
1484 } else if (strcmp(argv[argc - 2], MSG_ORIG(MSG_STR_MINUS_SHTYP)) == 0) {
1485 op = TYPE;
1486 if (obj_state == NULL) /* No object available */
1487 elfedit_cpl_atoconst(cpldata,
1488 ELFEDIT_CONST_SHT_ALLSYMTAB);
1489 } else {
1490 return;
1491 }
1492
1493 if (obj_state == NULL) /* No object available */
1494 return;
1495
1496 /*
1497 * Loop over the symbol tables and supply command completion
1498 * for the items in the file.
1499 */
1500 symtab = obj_state->os_symtab;
1501 for (tblndx = 0; tblndx < obj_state->os_symtabnum;
1502 tblndx++, symtab++) {
1503 elfedit_section_t *sec =
1504 &obj_state->os_secarr[symtab->symt_shndx];
1505
1506 switch (op) {
1507 case NAME:
1508 elfedit_cpl_match(cpldata, sec->sec_name, 0);
1509 break;
1510 case INDEX:
1511 elfedit_cpl_ndx(cpldata, symtab->symt_shndx);
1512 break;
1513 case TYPE:
1514 {
1515 elfedit_atoui_sym_t *cpl_list;
1516
1517 (void) elfedit_sec_issymtab(obj_state,
1518 sec, 1, &cpl_list);
1519 elfedit_cpl_atoui(cpldata, cpl_list);
1520 }
1521 break;
1522 }
1523 }
1524 }
1525
1526 /*ARGSUSED*/
1527 static void
cpl_st_bind(elfedit_obj_state_t * obj_state,void * cpldata,int argc,const char * argv[],int num_opt)1528 cpl_st_bind(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1529 const char *argv[], int num_opt)
1530 {
1531 /* Handle -shXXX options */
1532 cpl_sh_opt(obj_state, cpldata, argc, argv, num_opt);
1533
1534 /* The second argument can be an STB_ value */
1535 if (argc == (num_opt + 2))
1536 elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_STB);
1537 }
1538
1539 /*ARGSUSED*/
1540 static void
cpl_st_shndx(elfedit_obj_state_t * obj_state,void * cpldata,int argc,const char * argv[],int num_opt)1541 cpl_st_shndx(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1542 const char *argv[], int num_opt)
1543 {
1544 elfedit_section_t *sec;
1545 enum { NAME, INDEX, TYPE } op;
1546 Word ndx;
1547
1548 /* Handle -shXXX options */
1549 cpl_sh_opt(obj_state, cpldata, argc, argv, num_opt);
1550
1551 /*
1552 * The second argument can be a section name, a section
1553 * index (-secshndx), or a section type (-secshtyp). We
1554 * can do completions for each of these.
1555 */
1556 if (argc != (num_opt + 2))
1557 return;
1558
1559 op = NAME;
1560 for (ndx = 0; ndx < num_opt; ndx++) {
1561 if (strcmp(argv[ndx], MSG_ORIG(MSG_STR_MINUS_SECSHNDX)) == 0)
1562 op = INDEX;
1563 else if (strcmp(argv[ndx],
1564 MSG_ORIG(MSG_STR_MINUS_SECSHTYP)) == 0)
1565 op = TYPE;
1566 }
1567
1568 switch (op) {
1569 case NAME:
1570 if (obj_state == NULL)
1571 break;
1572 sec = obj_state->os_secarr;
1573 for (ndx = 0; ndx < obj_state->os_shnum; ndx++, sec++)
1574 elfedit_cpl_match(cpldata, sec->sec_name, 0);
1575 break;
1576
1577 case INDEX:
1578 elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SHN);
1579 break;
1580
1581 case TYPE:
1582 elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SHT);
1583 break;
1584 }
1585 }
1586
1587 /*ARGSUSED*/
1588 static void
cpl_st_type(elfedit_obj_state_t * obj_state,void * cpldata,int argc,const char * argv[],int num_opt)1589 cpl_st_type(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1590 const char *argv[], int num_opt)
1591 {
1592 /* Handle -shXXX options */
1593 cpl_sh_opt(obj_state, cpldata, argc, argv, num_opt);
1594
1595 /* The second argument can be an STT_ value */
1596 if (argc == (num_opt + 2))
1597 elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_STT);
1598 }
1599
1600 /*ARGSUSED*/
1601 static void
cpl_st_visibility(elfedit_obj_state_t * obj_state,void * cpldata,int argc,const char * argv[],int num_opt)1602 cpl_st_visibility(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1603 const char *argv[], int num_opt)
1604 {
1605 /* Handle -shXXX options */
1606 cpl_sh_opt(obj_state, cpldata, argc, argv, num_opt);
1607
1608 /* The second argument can be an STV_ value */
1609 if (argc == (num_opt + 2))
1610 elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_STV);
1611 }
1612
1613
1614
1615 /*
1616 * Implementation functions for the commands
1617 */
1618 static elfedit_cmdret_t
cmd_dump(elfedit_obj_state_t * obj_state,int argc,const char * argv[])1619 cmd_dump(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1620 {
1621 return (cmd_body(SYM_CMD_T_DUMP, obj_state, argc, argv));
1622 }
1623
1624
1625 static elfedit_cmdret_t
cmd_st_bind(elfedit_obj_state_t * obj_state,int argc,const char * argv[])1626 cmd_st_bind(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1627 {
1628 return (cmd_body(SYM_CMD_T_ST_BIND, obj_state, argc, argv));
1629 }
1630
1631
1632 static elfedit_cmdret_t
cmd_st_info(elfedit_obj_state_t * obj_state,int argc,const char * argv[])1633 cmd_st_info(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1634 {
1635 return (cmd_body(SYM_CMD_T_ST_INFO, obj_state, argc, argv));
1636 }
1637
1638 static elfedit_cmdret_t
cmd_st_name(elfedit_obj_state_t * obj_state,int argc,const char * argv[])1639 cmd_st_name(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1640 {
1641 return (cmd_body(SYM_CMD_T_ST_NAME, obj_state, argc, argv));
1642 }
1643
1644 static elfedit_cmdret_t
cmd_st_other(elfedit_obj_state_t * obj_state,int argc,const char * argv[])1645 cmd_st_other(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1646 {
1647 return (cmd_body(SYM_CMD_T_ST_OTHER, obj_state, argc, argv));
1648 }
1649
1650 static elfedit_cmdret_t
cmd_st_shndx(elfedit_obj_state_t * obj_state,int argc,const char * argv[])1651 cmd_st_shndx(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1652 {
1653 return (cmd_body(SYM_CMD_T_ST_SHNDX, obj_state, argc, argv));
1654 }
1655
1656 static elfedit_cmdret_t
cmd_st_size(elfedit_obj_state_t * obj_state,int argc,const char * argv[])1657 cmd_st_size(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1658 {
1659 return (cmd_body(SYM_CMD_T_ST_SIZE, obj_state, argc, argv));
1660 }
1661
1662 static elfedit_cmdret_t
cmd_st_type(elfedit_obj_state_t * obj_state,int argc,const char * argv[])1663 cmd_st_type(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1664 {
1665 return (cmd_body(SYM_CMD_T_ST_TYPE, obj_state, argc, argv));
1666 }
1667
1668 static elfedit_cmdret_t
cmd_st_value(elfedit_obj_state_t * obj_state,int argc,const char * argv[])1669 cmd_st_value(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1670 {
1671 return (cmd_body(SYM_CMD_T_ST_VALUE, obj_state, argc, argv));
1672 }
1673
1674 static elfedit_cmdret_t
cmd_st_visibility(elfedit_obj_state_t * obj_state,int argc,const char * argv[])1675 cmd_st_visibility(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1676 {
1677 return (cmd_body(SYM_CMD_T_ST_VISIBILITY, obj_state, argc, argv));
1678 }
1679
1680
1681
1682 /*ARGSUSED*/
1683 elfedit_module_t *
elfedit_init(elfedit_module_version_t version)1684 elfedit_init(elfedit_module_version_t version)
1685 {
1686 /* Multiple commands accept only the standard set of options */
1687 static elfedit_cmd_optarg_t opt_std[] = {
1688 { MSG_ORIG(MSG_STR_MINUS_SHNAM),
1689 /* MSG_INTL(MSG_OPTDESC_SHNAM) */
1690 ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE,
1691 SYM_OPT_F_SHNAME, SYM_OPT_F_SHNDX | SYM_OPT_F_SHTYP },
1692 { MSG_ORIG(MSG_STR_NAME), 0, 0 },
1693 { MSG_ORIG(MSG_STR_MINUS_SHNDX),
1694 /* MSG_INTL(MSG_OPTDESC_SHNDX) */
1695 ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE,
1696 SYM_OPT_F_SHNDX, SYM_OPT_F_SHNAME | SYM_OPT_F_SHTYP },
1697 { MSG_ORIG(MSG_STR_INDEX), 0, 0 },
1698 { MSG_ORIG(MSG_STR_MINUS_SHTYP),
1699 /* MSG_INTL(MSG_OPTDESC_SHTYP) */
1700 ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE,
1701 SYM_OPT_F_SHTYP, SYM_OPT_F_SHNAME | SYM_OPT_F_SHNDX },
1702 { MSG_ORIG(MSG_STR_TYPE), 0, 0 },
1703 { MSG_ORIG(MSG_STR_MINUS_SYMNDX),
1704 /* MSG_INTL(MSG_OPTDESC_SYMNDX) */
1705 ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0, SYM_OPT_F_SYMNDX },
1706 { ELFEDIT_STDOA_OPT_O, 0,
1707 ELFEDIT_CMDOA_F_INHERIT, 0 },
1708 { NULL }
1709 };
1710
1711 /* sym:dump */
1712 static const char *name_dump[] = {
1713 MSG_ORIG(MSG_CMD_DUMP),
1714 MSG_ORIG(MSG_STR_EMPTY), /* "" makes this the default command */
1715 NULL
1716 };
1717 static elfedit_cmd_optarg_t opt_dump[] = {
1718 { MSG_ORIG(MSG_STR_MINUS_SHNAM),
1719 /* MSG_INTL(MSG_OPTDESC_SHNAM) */
1720 ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE,
1721 SYM_OPT_F_SHNAME, SYM_OPT_F_SHNDX | SYM_OPT_F_SHTYP },
1722 { MSG_ORIG(MSG_STR_NAME), 0, 0 },
1723 { MSG_ORIG(MSG_STR_MINUS_SHNDX),
1724 /* MSG_INTL(MSG_OPTDESC_SHNDX) */
1725 ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE,
1726 SYM_OPT_F_SHNDX, SYM_OPT_F_SHNAME | SYM_OPT_F_SHTYP },
1727 { MSG_ORIG(MSG_STR_INDEX), 0, 0 },
1728 { MSG_ORIG(MSG_STR_MINUS_SHTYP),
1729 /* MSG_INTL(MSG_OPTDESC_SHTYP) */
1730 ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE,
1731 SYM_OPT_F_SHTYP, SYM_OPT_F_SHNAME | SYM_OPT_F_SHNDX },
1732 { MSG_ORIG(MSG_STR_TYPE), 0, 0 },
1733 { MSG_ORIG(MSG_STR_MINUS_SYMNDX),
1734 /* MSG_INTL(MSG_OPTDESC_SYMNDX) */
1735 ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0, SYM_OPT_F_SYMNDX },
1736 { NULL }
1737 };
1738 static elfedit_cmd_optarg_t arg_dump[] = {
1739 { MSG_ORIG(MSG_STR_SYM),
1740 /* MSG_INTL(MSG_A1_SYM) */
1741 ELFEDIT_I18NHDL(MSG_A1_SYM),
1742 ELFEDIT_CMDOA_F_OPT },
1743 { NULL }
1744 };
1745
1746 /* sym:st_bind */
1747 static const char *name_st_bind[] = {
1748 MSG_ORIG(MSG_CMD_ST_BIND), NULL };
1749 static elfedit_cmd_optarg_t arg_st_bind[] = {
1750 { MSG_ORIG(MSG_STR_SYM),
1751 /* MSG_INTL(MSG_A1_SYM) */
1752 ELFEDIT_I18NHDL(MSG_A1_SYM),
1753 ELFEDIT_CMDOA_F_OPT },
1754 { MSG_ORIG(MSG_STR_VALUE),
1755 /* MSG_INTL(MSG_A2_DESC_ST_BIND) */
1756 ELFEDIT_I18NHDL(MSG_A2_DESC_ST_BIND),
1757 ELFEDIT_CMDOA_F_OPT },
1758 { NULL }
1759 };
1760
1761 /* sym:st_info */
1762 static const char *name_st_info[] = {
1763 MSG_ORIG(MSG_CMD_ST_INFO), NULL };
1764 static elfedit_cmd_optarg_t arg_st_info[] = {
1765 { MSG_ORIG(MSG_STR_SYM),
1766 /* MSG_INTL(MSG_A1_SYM) */
1767 ELFEDIT_I18NHDL(MSG_A1_SYM),
1768 ELFEDIT_CMDOA_F_OPT },
1769 { MSG_ORIG(MSG_STR_VALUE),
1770 /* MSG_INTL(MSG_A2_DESC_ST_INFO) */
1771 ELFEDIT_I18NHDL(MSG_A2_DESC_ST_INFO),
1772 ELFEDIT_CMDOA_F_OPT },
1773 { NULL }
1774 };
1775
1776 /* sym:st_name */
1777 static const char *name_st_name[] = {
1778 MSG_ORIG(MSG_CMD_ST_NAME), NULL };
1779 static elfedit_cmd_optarg_t opt_st_name[] = {
1780 { MSG_ORIG(MSG_STR_MINUS_SHNAM),
1781 /* MSG_INTL(MSG_OPTDESC_SHNAM) */
1782 ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE,
1783 SYM_OPT_F_SHNAME, SYM_OPT_F_SHNDX | SYM_OPT_F_SHTYP },
1784 { MSG_ORIG(MSG_STR_NAME), 0, 0, 0 },
1785 { MSG_ORIG(MSG_STR_MINUS_SHNDX),
1786 /* MSG_INTL(MSG_OPTDESC_SHNDX) */
1787 ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE,
1788 SYM_OPT_F_SHNDX, SYM_OPT_F_SHNAME | SYM_OPT_F_SHTYP },
1789 { MSG_ORIG(MSG_STR_INDEX), 0, 0, 0 },
1790 { MSG_ORIG(MSG_STR_MINUS_SHTYP),
1791 /* MSG_INTL(MSG_OPTDESC_SHTYP) */
1792 ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE,
1793 SYM_OPT_F_SHTYP, SYM_OPT_F_SHNAME | SYM_OPT_F_SHNDX },
1794 { MSG_ORIG(MSG_STR_TYPE), 0, 0, 0 },
1795 { MSG_ORIG(MSG_STR_MINUS_SYMNDX),
1796 /* MSG_INTL(MSG_OPTDESC_SYMNDX) */
1797 ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0,
1798 SYM_OPT_F_SYMNDX, 0 },
1799 { MSG_ORIG(MSG_STR_MINUS_NAME_OFFSET),
1800 /* MSG_INTL(MSG_OPTDESC_NAME_OFFSET) */
1801 ELFEDIT_I18NHDL(MSG_OPTDESC_NAME_OFFSET), 0,
1802 SYM_OPT_F_NAMOFFSET, 0 },
1803 { ELFEDIT_STDOA_OPT_O, 0,
1804 ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
1805 { NULL }
1806 };
1807 static elfedit_cmd_optarg_t arg_st_name[] = {
1808 { MSG_ORIG(MSG_STR_SYM),
1809 /* MSG_INTL(MSG_A1_SYM) */
1810 ELFEDIT_I18NHDL(MSG_A1_SYM),
1811 ELFEDIT_CMDOA_F_OPT },
1812 { MSG_ORIG(MSG_STR_NAME),
1813 /* MSG_INTL(MSG_A2_DESC_ST_NAME) */
1814 ELFEDIT_I18NHDL(MSG_A2_DESC_ST_NAME),
1815 ELFEDIT_CMDOA_F_OPT },
1816 { NULL }
1817 };
1818
1819 /* sym:st_other */
1820 static const char *name_st_other[] = {
1821 MSG_ORIG(MSG_CMD_ST_OTHER), NULL };
1822 static elfedit_cmd_optarg_t arg_st_other[] = {
1823 { MSG_ORIG(MSG_STR_SYM),
1824 /* MSG_INTL(MSG_A1_SYM) */
1825 ELFEDIT_I18NHDL(MSG_A1_SYM),
1826 ELFEDIT_CMDOA_F_OPT },
1827 { MSG_ORIG(MSG_STR_VALUE),
1828 /* MSG_INTL(MSG_A2_DESC_ST_OTHER) */
1829 ELFEDIT_I18NHDL(MSG_A2_DESC_ST_OTHER),
1830 ELFEDIT_CMDOA_F_OPT },
1831 { NULL }
1832 };
1833
1834 /* sym:st_shndx */
1835 static const char *name_st_shndx[] = {
1836 MSG_ORIG(MSG_CMD_ST_SHNDX), NULL };
1837 static elfedit_cmd_optarg_t opt_st_shndx[] = {
1838 { MSG_ORIG(MSG_STR_MINUS_E),
1839 /* MSG_INTL(MSG_OPTDESC_E) */
1840 ELFEDIT_I18NHDL(MSG_OPTDESC_E), 0, SYM_OPT_F_XSHINDEX, 0 },
1841 { MSG_ORIG(MSG_STR_MINUS_SHNAM),
1842 /* MSG_INTL(MSG_OPTDESC_SHNAM) */
1843 ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE,
1844 SYM_OPT_F_SHNAME, SYM_OPT_F_SHNDX | SYM_OPT_F_SHTYP },
1845 { MSG_ORIG(MSG_STR_NAME), 0, 0, 0 },
1846 { MSG_ORIG(MSG_STR_MINUS_SHNDX),
1847 /* MSG_INTL(MSG_OPTDESC_SHNDX) */
1848 ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE,
1849 SYM_OPT_F_SHNDX, SYM_OPT_F_SHNAME | SYM_OPT_F_SHTYP },
1850 { MSG_ORIG(MSG_STR_INDEX), 0, 0, 0 },
1851 { MSG_ORIG(MSG_STR_MINUS_SHTYP),
1852 /* MSG_INTL(MSG_OPTDESC_SHTYP) */
1853 ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE,
1854 SYM_OPT_F_SHTYP, SYM_OPT_F_SHNAME | SYM_OPT_F_SHNDX },
1855 { MSG_ORIG(MSG_STR_TYPE), 0, 0, 0 },
1856 { MSG_ORIG(MSG_STR_MINUS_SYMNDX),
1857 /* MSG_INTL(MSG_OPTDESC_SYMNDX) */
1858 ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0,
1859 SYM_OPT_F_SYMNDX, 0 },
1860 { ELFEDIT_STDOA_OPT_O, 0,
1861 ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
1862 { MSG_ORIG(MSG_STR_MINUS_SECSHNDX),
1863 /* MSG_INTL(MSG_OPTDESC_SECSHNDX) */
1864 ELFEDIT_I18NHDL(MSG_OPTDESC_SECSHNDX),
1865 0, SYM_OPT_F_SECSHNDX, SYM_OPT_F_SECSHTYP },
1866 { MSG_ORIG(MSG_STR_MINUS_SECSHTYP),
1867 /* MSG_INTL(MSG_OPTDESC_SECSHTYP) */
1868 ELFEDIT_I18NHDL(MSG_OPTDESC_SECSHTYP),
1869 0, SYM_OPT_F_SECSHTYP, SYM_OPT_F_SECSHNDX },
1870 { NULL }
1871 };
1872 static elfedit_cmd_optarg_t arg_st_shndx[] = {
1873 { MSG_ORIG(MSG_STR_SYM),
1874 /* MSG_INTL(MSG_A1_SYM) */
1875 ELFEDIT_I18NHDL(MSG_A1_SYM),
1876 ELFEDIT_CMDOA_F_OPT },
1877 { MSG_ORIG(MSG_STR_SEC),
1878 /* MSG_INTL(MSG_A2_DESC_ST_SEC) */
1879 ELFEDIT_I18NHDL(MSG_A2_DESC_ST_SEC),
1880 ELFEDIT_CMDOA_F_OPT },
1881 { NULL }
1882 };
1883
1884 /* sym:st_size */
1885 static const char *name_st_size[] = {
1886 MSG_ORIG(MSG_CMD_ST_SIZE), NULL };
1887 static elfedit_cmd_optarg_t arg_st_size[] = {
1888 { MSG_ORIG(MSG_STR_SYM),
1889 /* MSG_INTL(MSG_A1_SYM) */
1890 ELFEDIT_I18NHDL(MSG_A1_SYM),
1891 ELFEDIT_CMDOA_F_OPT },
1892 { MSG_ORIG(MSG_STR_VALUE),
1893 /* MSG_INTL(MSG_A2_DESC_ST_SIZE) */
1894 ELFEDIT_I18NHDL(MSG_A2_DESC_ST_SIZE),
1895 ELFEDIT_CMDOA_F_OPT },
1896 { NULL }
1897 };
1898
1899 /* sym:st_type */
1900 static const char *name_st_type[] = {
1901 MSG_ORIG(MSG_CMD_ST_TYPE), NULL };
1902 static elfedit_cmd_optarg_t arg_st_type[] = {
1903 { MSG_ORIG(MSG_STR_SYM),
1904 /* MSG_INTL(MSG_A1_SYM) */
1905 ELFEDIT_I18NHDL(MSG_A1_SYM),
1906 ELFEDIT_CMDOA_F_OPT },
1907 { MSG_ORIG(MSG_STR_VALUE),
1908 /* MSG_INTL(MSG_A2_DESC_ST_TYPE) */
1909 ELFEDIT_I18NHDL(MSG_A2_DESC_ST_TYPE),
1910 ELFEDIT_CMDOA_F_OPT },
1911 { NULL }
1912 };
1913
1914 /* sym:st_value */
1915 static const char *name_st_value[] = {
1916 MSG_ORIG(MSG_CMD_ST_VALUE), NULL };
1917 static elfedit_cmd_optarg_t arg_st_value[] = {
1918 { MSG_ORIG(MSG_STR_SYM),
1919 /* MSG_INTL(MSG_A1_SYM) */
1920 ELFEDIT_I18NHDL(MSG_A1_SYM),
1921 ELFEDIT_CMDOA_F_OPT },
1922 { MSG_ORIG(MSG_STR_VALUE),
1923 /* MSG_INTL(MSG_A2_DESC_ST_VALUE) */
1924 ELFEDIT_I18NHDL(MSG_A2_DESC_ST_VALUE),
1925 ELFEDIT_CMDOA_F_OPT },
1926 { NULL }
1927 };
1928
1929 /* sym:st_visibility */
1930 static const char *name_st_visibility[] = {
1931 MSG_ORIG(MSG_CMD_ST_VISIBILITY), NULL };
1932 static elfedit_cmd_optarg_t arg_st_visibility[] = {
1933 { MSG_ORIG(MSG_STR_SYM),
1934 /* MSG_INTL(MSG_A1_SYM) */
1935 ELFEDIT_I18NHDL(MSG_A1_SYM),
1936 ELFEDIT_CMDOA_F_OPT },
1937 { MSG_ORIG(MSG_STR_VALUE),
1938 /* MSG_INTL(MSG_A2_DESC_ST_VISIBILITY) */
1939 ELFEDIT_I18NHDL(MSG_A2_DESC_ST_VISIBILITY),
1940 ELFEDIT_CMDOA_F_OPT },
1941 { NULL }
1942 };
1943
1944 static elfedit_cmd_t cmds[] = {
1945 /* sym:dump */
1946 { cmd_dump, cpl_sh_opt, name_dump,
1947 /* MSG_INTL(MSG_DESC_DUMP) */
1948 ELFEDIT_I18NHDL(MSG_DESC_DUMP),
1949 /* MSG_INTL(MSG_HELP_DUMP) */
1950 ELFEDIT_I18NHDL(MSG_HELP_DUMP),
1951 opt_dump, arg_dump },
1952
1953 /* sym:st_bind */
1954 { cmd_st_bind, cpl_st_bind, name_st_bind,
1955 /* MSG_INTL(MSG_DESC_ST_BIND) */
1956 ELFEDIT_I18NHDL(MSG_DESC_ST_BIND),
1957 /* MSG_INTL(MSG_HELP_ST_BIND) */
1958 ELFEDIT_I18NHDL(MSG_HELP_ST_BIND),
1959 opt_std, arg_st_bind },
1960
1961 /* sym:st_info */
1962 { cmd_st_info, cpl_sh_opt, name_st_info,
1963 /* MSG_INTL(MSG_DESC_ST_INFO) */
1964 ELFEDIT_I18NHDL(MSG_DESC_ST_INFO),
1965 /* MSG_INTL(MSG_HELP_ST_INFO) */
1966 ELFEDIT_I18NHDL(MSG_HELP_ST_INFO),
1967 opt_std, arg_st_info },
1968
1969 /* sym:st_name */
1970 { cmd_st_name, cpl_sh_opt, name_st_name,
1971 /* MSG_INTL(MSG_DESC_ST_NAME) */
1972 ELFEDIT_I18NHDL(MSG_DESC_ST_NAME),
1973 /* MSG_INTL(MSG_HELP_ST_NAME) */
1974 ELFEDIT_I18NHDL(MSG_HELP_ST_NAME),
1975 opt_st_name, arg_st_name },
1976
1977 /* sym:st_other */
1978 { cmd_st_other, cpl_sh_opt, name_st_other,
1979 /* MSG_INTL(MSG_DESC_ST_OTHER) */
1980 ELFEDIT_I18NHDL(MSG_DESC_ST_OTHER),
1981 /* MSG_INTL(MSG_HELP_ST_OTHER) */
1982 ELFEDIT_I18NHDL(MSG_HELP_ST_OTHER),
1983 opt_std, arg_st_other },
1984
1985 /* sym:st_shndx */
1986 { cmd_st_shndx, cpl_st_shndx, name_st_shndx,
1987 /* MSG_INTL(MSG_DESC_ST_SHNDX) */
1988 ELFEDIT_I18NHDL(MSG_DESC_ST_SHNDX),
1989 /* MSG_INTL(MSG_HELP_ST_SHNDX) */
1990 ELFEDIT_I18NHDL(MSG_HELP_ST_SHNDX),
1991 opt_st_shndx, arg_st_shndx },
1992
1993 /* sym:st_size */
1994 { cmd_st_size, cpl_sh_opt, name_st_size,
1995 /* MSG_INTL(MSG_DESC_ST_SIZE) */
1996 ELFEDIT_I18NHDL(MSG_DESC_ST_SIZE),
1997 /* MSG_INTL(MSG_HELP_ST_SIZE) */
1998 ELFEDIT_I18NHDL(MSG_HELP_ST_SIZE),
1999 opt_std, arg_st_size },
2000
2001 /* sym:st_type */
2002 { cmd_st_type, cpl_st_type, name_st_type,
2003 /* MSG_INTL(MSG_DESC_ST_TYPE) */
2004 ELFEDIT_I18NHDL(MSG_DESC_ST_TYPE),
2005 /* MSG_INTL(MSG_HELP_ST_TYPE) */
2006 ELFEDIT_I18NHDL(MSG_HELP_ST_TYPE),
2007 opt_std, arg_st_type },
2008
2009 /* sym:st_value */
2010 { cmd_st_value, cpl_sh_opt, name_st_value,
2011 /* MSG_INTL(MSG_DESC_ST_VALUE) */
2012 ELFEDIT_I18NHDL(MSG_DESC_ST_VALUE),
2013 /* MSG_INTL(MSG_HELP_ST_VALUE) */
2014 ELFEDIT_I18NHDL(MSG_HELP_ST_VALUE),
2015 opt_std, arg_st_value },
2016
2017 /* sym:st_visibility */
2018 { cmd_st_visibility, cpl_st_visibility, name_st_visibility,
2019 /* MSG_INTL(MSG_DESC_ST_VISIBILITY) */
2020 ELFEDIT_I18NHDL(MSG_DESC_ST_VISIBILITY),
2021 /* MSG_INTL(MSG_HELP_ST_VISIBILITY) */
2022 ELFEDIT_I18NHDL(MSG_HELP_ST_VISIBILITY),
2023 opt_std, arg_st_visibility },
2024
2025 { NULL }
2026 };
2027
2028 static elfedit_module_t module = {
2029 ELFEDIT_VER_CURRENT, MSG_ORIG(MSG_MOD_NAME),
2030 /* MSG_INTL(MSG_MOD_DESC) */
2031 ELFEDIT_I18NHDL(MSG_MOD_DESC),
2032 cmds, mod_i18nhdl_to_str };
2033
2034 return (&module);
2035 }
2036