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 <stdio.h>
28 #include <unistd.h>
29 #include <elfedit.h>
30 #include <strings.h>
31 #include <debug.h>
32 #include <conv.h>
33 #include <syminfo_msg.h>
34
35
36
37 /*
38 * This module uses shared code for several of the commands.
39 * It is sometimes necessary to know which specific command
40 * is active.
41 */
42 typedef enum {
43 SYMINFO_CMD_T_DUMP = 0, /* syminfo:dump */
44
45 SYMINFO_CMD_T_SI_BOUNDTO = 1, /* syminfo:si_boundto */
46 SYMINFO_CMD_T_SI_FLAGS = 2 /* syminfo:si_boundto */
47 } SYMINFO_CMD_T;
48
49
50
51 #ifndef _ELF64
52 /*
53 * We supply this function for the msg module. Only one copy is needed.
54 */
55 const char *
_syminfo_msg(Msg mid)56 _syminfo_msg(Msg mid)
57 {
58 return (gettext(MSG_ORIG(mid)));
59 }
60
61 #endif
62
63
64
65 /*
66 * This function is supplied to elfedit through our elfedit_module_t
67 * definition. It translates the opaque elfedit_i18nhdl_t handles
68 * in our module interface into the actual strings for elfedit to
69 * use.
70 *
71 * note:
72 * This module uses Msg codes for its i18n handle type.
73 * So the translation is simply to use MSG_INTL() to turn
74 * it into a string and return it.
75 */
76 static const char *
mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl)77 mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl)
78 {
79 Msg msg = (Msg)hdl;
80
81 return (MSG_INTL(msg));
82 }
83
84
85
86 /*
87 * The sym_opt_t enum specifies a bit value for every optional
88 * argument allowed by a command in this module.
89 */
90 typedef enum {
91 SYMINFO_OPT_F_AND = 1, /* -and: AND (&) values to dest */
92 SYMINFO_OPT_F_CMP = 2, /* -cmp: Complement (~) values */
93 SYMINFO_OPT_F_NEEDED = 4, /* -needed: arg is name of object to */
94 /* be referenced via DT_NEEDED */
95 /* dynamic entry */
96 SYMINFO_OPT_F_OR = 8, /* -or: OR (|) values to dest */
97 SYMINFO_OPT_F_SYMNDX = 16 /* -symndx: Sym specified by index */
98 } syminfo_opt_t;
99
100
101 /*
102 * A variable of type ARGSTATE is used by each command to maintain
103 * information about the syminfo section being used, as and for any
104 * auxiliary sections that are related to it. This helps us to ensure
105 * that we only fetch each section a single time:
106 * - More efficient
107 * - Prevents multiple ELFEDIT_MSG_DEBUG messages from
108 * being produced for a given section.
109 */
110 typedef struct {
111 elfedit_obj_state_t *obj_state;
112 syminfo_opt_t optmask; /* Mask of options used */
113 int argc; /* # of plain arguments */
114 const char **argv; /* Plain arguments */
115 struct { /* Syminfo */
116 elfedit_section_t *sec;
117 Syminfo *data;
118 Word n;
119 } syminfo;
120 struct { /* Symbol table */
121 elfedit_section_t *sec;
122 Sym *data;
123 Word n;
124 } sym;
125 struct { /* String table */
126 elfedit_section_t *sec;
127 } str;
128 struct { /* Dynamic section */
129 elfedit_section_t *sec;
130 Dyn *data;
131 Word n;
132 } dynamic;
133 } ARGSTATE;
134
135
136
137 /*
138 * Standard argument processing for syminfo module
139 *
140 * entry
141 * obj_state, argc, argv - Standard command arguments
142 * optmask - Mask of allowed optional arguments.
143 * argstate - Address of ARGSTATE block to be initialized
144 *
145 * exit:
146 * On success, *argstate is initialized. On error,
147 * an error is issued and this routine does not return.
148 *
149 * note:
150 * Only the syminfo section is initially referenced by
151 * argstate. Use the argstate_add_XXX() routines below to
152 * access any other sections needed.
153 */
154 static void
process_args(elfedit_obj_state_t * obj_state,int argc,const char * argv[],SYMINFO_CMD_T cmd,ARGSTATE * argstate)155 process_args(elfedit_obj_state_t *obj_state, int argc, const char *argv[],
156 SYMINFO_CMD_T cmd, ARGSTATE *argstate)
157 {
158 elfedit_getopt_state_t getopt_state;
159 elfedit_getopt_ret_t *getopt_ret;
160
161 bzero(argstate, sizeof (*argstate));
162 argstate->obj_state = obj_state;
163
164 elfedit_getopt_init(&getopt_state, &argc, &argv);
165
166 /* Add each new option to the options mask */
167 while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL)
168 argstate->optmask |= getopt_ret->gor_idmask;
169
170 /*
171 * Usage error if there are too many plain arguments.
172 * - syminfo:dump accepts a single argument
173 * - syminfo:si_boundto accepts 2 arguments
174 * - syminfo:si_flags accepts an unbounded number
175 */
176 if (((cmd == SYMINFO_CMD_T_DUMP) && (argc > 1)) ||
177 ((cmd == SYMINFO_CMD_T_SI_BOUNDTO) && (argc > 2)))
178 elfedit_command_usage();
179
180 /* If there may be an arbitrary amount of output, use a pager */
181 if (argc == 0)
182 elfedit_pager_init();
183
184 /* Return the updated values of argc/argv */
185 argstate->argc = argc;
186 argstate->argv = argv;
187
188 /* Locate the syminfo section */
189 argstate->syminfo.sec = elfedit_sec_getsyminfo(obj_state,
190 &argstate->syminfo.data, &argstate->syminfo.n);
191 }
192
193
194
195 /*
196 * We maintain the state of the current syminfo table in a ARGSTATE
197 * structure. A syminfo is related to the dynamic symbol table, and
198 * can reference the dynamic section of the object. We don't look those
199 * things up unless we actually need them, both to be efficient, and
200 * to prevent duplicate ELFEDIT_MSG_DEBUG messages from being issued
201 * as they are located. Hence, process_args() is used to initialze the
202 * state block with just the syminfo section, and then one of the
203 * argstate_add_XXX() functions is used as needed to fetch the
204 * additional sections.
205 *
206 * entry:
207 * argstate - State block for current symbol table.
208 *
209 * exit:
210 * If the needed auxiliary section is not found, an error is
211 * issued and the argstate_add_XXX() routine does not return.
212 * Otherwise, the fields in argstate have been filled in, ready
213 * for use.
214 *
215 */
216 static void
argstate_add_sym(ARGSTATE * argstate)217 argstate_add_sym(ARGSTATE *argstate)
218 {
219 if (argstate->sym.sec != NULL)
220 return;
221
222 argstate->sym.sec = elfedit_sec_getsymtab(argstate->obj_state,
223 1, argstate->syminfo.sec->sec_shdr->sh_link, NULL,
224 &argstate->sym.data, &argstate->sym.n, NULL);
225 }
226 static void
argstate_add_str(ARGSTATE * argstate)227 argstate_add_str(ARGSTATE *argstate)
228 {
229 if (argstate->str.sec != NULL)
230 return;
231
232 argstate_add_sym(argstate);
233 argstate->str.sec = elfedit_sec_getstr(argstate->obj_state,
234 argstate->sym.sec->sec_shdr->sh_link, 0);
235 }
236 static void
argstate_add_dynamic(ARGSTATE * argstate)237 argstate_add_dynamic(ARGSTATE *argstate)
238 {
239 if (argstate->dynamic.sec != NULL)
240 return;
241
242 argstate->dynamic.sec = elfedit_sec_getdyn(argstate->obj_state,
243 &argstate->dynamic.data, &argstate->dynamic.n);
244 }
245
246
247
248 /*
249 * Display syminfo section entries in the style used by elfdump.
250 *
251 * entry:
252 * argstate - State block for current symbol table.
253 * ndx - Index of first symbol to display
254 * cnt - Number of symbols to display
255 */
256 static void
dump_syminfo(ARGSTATE * argstate,Word ndx,Word cnt)257 dump_syminfo(ARGSTATE *argstate, Word ndx, Word cnt)
258 {
259 Syminfo *syminfo;
260 Sym *sym;
261 Dyn *dyn;
262
263 syminfo = argstate->syminfo.data + ndx;
264
265 argstate_add_sym(argstate);
266 sym = argstate->sym.data + ndx;
267
268 argstate_add_str(argstate);
269
270 argstate_add_dynamic(argstate);
271 dyn = argstate->dynamic.data;
272
273 /*
274 * Loop through the syminfo entries.
275 */
276 Elf_syminfo_title(0);
277
278 for (; cnt-- > 0; ndx++, syminfo++, sym++) {
279 const char *needed = NULL, *name;
280
281 name = elfedit_offset_to_str(argstate->str.sec,
282 sym->st_name, ELFEDIT_MSG_ERR, 0);
283
284 if ((syminfo->si_boundto < SYMINFO_BT_LOWRESERVE) &&
285 (syminfo->si_boundto < argstate->dynamic.n) &&
286 ((dyn[syminfo->si_boundto].d_tag == DT_NEEDED) ||
287 (dyn[syminfo->si_boundto].d_tag == DT_USED)))
288 needed = elfedit_offset_to_str(argstate->str.sec,
289 dyn[syminfo->si_boundto].d_un.d_val,
290 ELFEDIT_MSG_ERR, 0);
291 else
292 needed = MSG_ORIG(MSG_STR_EMPTY);
293
294 Elf_syminfo_entry(0, ndx, syminfo, name, needed);
295 }
296 }
297
298
299
300 /*
301 * Print syminfo values, taking the calling command, and output style
302 * into account.
303 *
304 * entry:
305 * cmd - SYMINFO_CMD_T_* value giving identify of caller
306 * autoprint - If True, output is only produced if the elfedit
307 * autoprint flag is set. If False, output is always produced.
308 * argstate - State block for current symbol table.
309 * ndx - Index of first symbol to display
310 * cnt - Number of symbols to display
311 */
312 static void
print_syminfo(SYMINFO_CMD_T cmd,int autoprint,ARGSTATE * argstate,Word ndx,Word cnt)313 print_syminfo(SYMINFO_CMD_T cmd, int autoprint, ARGSTATE *argstate,
314 Word ndx, Word cnt)
315 {
316 elfedit_outstyle_t outstyle;
317 Syminfo *syminfo;
318
319 if ((autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0)) ||
320 (cnt == 0))
321 return;
322
323 /*
324 * Pick an output style. syminfo:dump is required to use the default
325 * style. The other commands use the current output style.
326 */
327 outstyle = (cmd == SYMINFO_CMD_T_DUMP) ?
328 ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle();
329
330 /*
331 * If doing default output, use elfdump style where we
332 * show all symbol attributes. In this case, the command
333 * that called us doesn't matter
334 */
335 if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) {
336 dump_syminfo(argstate, ndx, cnt);
337 return;
338 }
339
340 syminfo = argstate->syminfo.data;
341
342 switch (cmd) {
343 case SYMINFO_CMD_T_SI_BOUNDTO:
344 if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
345 /* Find the dynamic section and string table */
346 argstate_add_dynamic(argstate);
347 argstate_add_str(argstate);
348 }
349
350 for (syminfo += ndx; cnt--; syminfo++) {
351 Half bndto = syminfo->si_boundto;
352
353 if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
354 const char *str = NULL;
355
356 switch (bndto) {
357 case SYMINFO_BT_SELF:
358 str = elfedit_atoconst_value_to_str(
359 ELFEDIT_CONST_SYMINFO_BT,
360 SYMINFO_BT_SELF, 1);
361 break;
362 case SYMINFO_BT_PARENT:
363 str = elfedit_atoconst_value_to_str(
364 ELFEDIT_CONST_SYMINFO_BT,
365 SYMINFO_BT_PARENT, 1);
366 break;
367 case SYMINFO_BT_NONE:
368 str = elfedit_atoconst_value_to_str(
369 ELFEDIT_CONST_SYMINFO_BT,
370 SYMINFO_BT_NONE, 1);
371 break;
372 }
373 if ((str == NULL) &&
374 (bndto < SYMINFO_BT_LOWRESERVE) &&
375 (argstate->dynamic.sec != NULL) &&
376 (bndto < argstate->dynamic.n) &&
377 (argstate->dynamic.data[bndto].d_tag ==
378 DT_NEEDED))
379 str = elfedit_offset_to_str(
380 argstate->str.sec,
381 argstate->dynamic.data[bndto].
382 d_un.d_val, ELFEDIT_MSG_ERR, 0);
383
384 if (str != NULL) {
385 elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
386 str);
387 continue;
388 }
389 }
390
391 /*
392 * If we reach this point, we are either in numeric
393 * mode, or we were unable to find a string above.
394 * In either case, output as integer.
395 */
396 elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL),
397 EC_WORD(bndto));
398 }
399 break;
400
401 case SYMINFO_CMD_T_SI_FLAGS:
402 for (syminfo += ndx; cnt--; syminfo++) {
403 if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
404 Conv_syminfo_flags_buf_t buf;
405
406 elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
407 conv_syminfo_flags(syminfo->si_flags,
408 CONV_FMT_NOBKT, &buf));
409 } else {
410 elfedit_printf(MSG_ORIG(MSG_FMT_HEXNUMNL),
411 EC_WORD(syminfo->si_flags));
412 }
413 }
414 break;
415 }
416 }
417
418
419 /*
420 * Convert the given argument string into a symbol table index.
421 *
422 * entry:
423 * argstate - State block for current symbol table.
424 * arg - String containing symbol index argument.
425 *
426 * exit:
427 * On success, returns the symbol index. On failure, an error
428 * is issued and this routine does not return.
429 */
430 static Word
arg_to_symndx(ARGSTATE * argstate,const char * arg)431 arg_to_symndx(ARGSTATE *argstate, const char *arg)
432 {
433 Word symndx;
434
435 /*
436 * If the -symndx option was specified, arg is an index
437 * into the symbol table.
438 */
439 if (argstate->optmask & SYMINFO_OPT_F_SYMNDX)
440 return (elfedit_atoui_range(arg, MSG_ORIG(MSG_STR_SYM),
441 0, argstate->syminfo.n - 1, NULL));
442
443 /*
444 * arg is a symbol name. Return the index of the first symbol
445 * that matches
446 */
447 argstate_add_sym(argstate);
448 argstate_add_str(argstate);
449
450 (void) elfedit_name_to_symndx(argstate->sym.sec,
451 argstate->str.sec, arg, ELFEDIT_MSG_ERR, &symndx);
452
453 return (symndx);
454 }
455
456
457 /*
458 * Given a string argument representing an object, return the index of
459 * the dynamic section that should be used for the si_boundto value.
460 */
461 static Half
needed_to_boundto(ARGSTATE * argstate,const char * arg)462 needed_to_boundto(ARGSTATE *argstate, const char *arg)
463 {
464 Conv_inv_buf_t inv_buf;
465 elfedit_dyn_elt_t strpad_elt;
466 elfedit_dyn_elt_t null_elt;
467 elfedit_section_t *dynsec;
468 Word null_cnt;
469 Dyn *dyn;
470 Word str_offset, ndx, numdyn;
471 int have_string;
472
473 argstate_add_str(argstate);
474 argstate_add_dynamic(argstate);
475 dynsec = argstate->dynamic.sec;
476 numdyn = argstate->dynamic.n;
477
478 /* Locate DT_SUNW_STRPAD element if present and locate the DT_NULLs */
479 elfedit_dyn_elt_init(&strpad_elt);
480 elfedit_dyn_elt_init(&null_elt);
481 null_cnt = 0;
482 strpad_elt.dn_dyn.d_un.d_val = 0;
483 dyn = argstate->dynamic.data;
484 for (ndx = 0; ndx < numdyn; dyn++, ndx++) {
485 switch (dyn->d_tag) {
486 case DT_NULL:
487 /* Count all the nulls, remember the first one */
488 null_cnt++;
489 if (!null_elt.dn_seen)
490 elfedit_dyn_elt_save(&null_elt, ndx, dyn);
491 break;
492
493 case DT_SUNW_STRPAD:
494 if (elfedit_test_osabi(argstate->obj_state,
495 ELFOSABI_SOLARIS, 0))
496 elfedit_dyn_elt_save(&strpad_elt, ndx, dyn);
497 break;
498 }
499 }
500
501 /*
502 * Look up the string in the string table and get its offset. If
503 * this succeeds, then it is possible that there is a DT_NEEDED
504 * dynamic entry that references it.
505 */
506 have_string = elfedit_sec_findstr(argstate->str.sec,
507 strpad_elt.dn_dyn.d_un.d_val, arg, &str_offset) != 0;
508 if (have_string) {
509 dyn = argstate->dynamic.data;
510 for (ndx = 0; ndx < numdyn; dyn++, ndx++) {
511 if (((dyn->d_tag == DT_NEEDED) ||
512 (dyn->d_tag == DT_USED)) &&
513 (dyn->d_un.d_val == str_offset))
514 goto done;
515 }
516 }
517
518 /*
519 * It doesn't already exist. We might be able to add a DT_NEEDED
520 * to the dynamic section if an extra DT_NULL is available.
521 * Otherwise, we have to fail here.
522 */
523 if (null_cnt < 2)
524 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOEXTRANULL),
525 EC_WORD(dynsec->sec_shndx), dynsec->sec_name);
526
527 /*
528 * If the string is not already in the string table, try to
529 * insert it. If it succeeds, we will convert the DT_NULL.
530 * Otherwise, an error will be issued and control will not
531 * return here.
532 */
533 if (!have_string)
534 str_offset = elfedit_dynstr_insert(dynsec,
535 argstate->str.sec, &strpad_elt, arg);
536
537 /* Convert the extra DT_NULL */
538 ndx = null_elt.dn_ndx;
539 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CONVNULL),
540 EC_WORD(dynsec->sec_shndx), dynsec->sec_name, EC_WORD(ndx),
541 conv_dyn_tag(DT_NEEDED,
542 argstate->obj_state->os_ehdr->e_ident[EI_OSABI],
543 argstate->obj_state->os_ehdr->e_machine,
544 0, &inv_buf));
545 dyn = argstate->dynamic.data + ndx;
546 dyn->d_tag = DT_NEEDED;
547 dyn->d_un.d_val = str_offset;
548 elfedit_modified_data(dynsec);
549
550 done:
551 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDNEEDED),
552 dynsec->sec_shndx, dynsec->sec_name, ndx, arg);
553 return (ndx);
554 }
555
556 /*
557 * Common body for the syminfo: module commands. These commands
558 * share a large amount of common behavior, so it is convenient
559 * to centralize things and use the cmd argument to handle the
560 * small differences.
561 *
562 * entry:
563 * cmd - One of the SYMINFO_CMD_T_* constants listed above, specifying
564 * which command to implement.
565 * obj_state, argc, argv - Standard command arguments
566 */
567 static elfedit_cmdret_t
cmd_body(SYMINFO_CMD_T cmd,elfedit_obj_state_t * obj_state,int argc,const char * argv[])568 cmd_body(SYMINFO_CMD_T cmd, elfedit_obj_state_t *obj_state,
569 int argc, const char *argv[])
570 {
571 ARGSTATE argstate;
572 Word ndx;
573 Syminfo *syminfo;
574 elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE;
575
576 process_args(obj_state, argc, argv, cmd, &argstate);
577
578 /* If there are no arguments, dump the whole table and return */
579 if (argstate.argc == 0) {
580 print_syminfo(cmd, 0, &argstate, 0, argstate.syminfo.n);
581 return (ELFEDIT_CMDRET_NONE);
582 }
583
584 /* The first argument is the symbol name/index */
585 ndx = arg_to_symndx(&argstate, argstate.argv[0]);
586
587 /* If there is a single argument, display that item and return */
588 if (argstate.argc == 1) {
589 print_syminfo(cmd, 0, &argstate, ndx, 1);
590 return (ELFEDIT_CMDRET_NONE);
591 }
592
593 syminfo = &argstate.syminfo.data[ndx];
594
595 /*
596 * Syminfo [0] holds the value SYMINFO_CURRENT, as a versioning
597 * technique. You're not supposed to mess with it.
598 */
599 if (ndx == 0)
600 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CHGSYMINFO0),
601 EC_WORD(argstate.syminfo.sec->sec_shndx),
602 argstate.syminfo.sec->sec_name, EC_WORD(ndx));
603
604 /* The second value supplies a new value for the item */
605 switch (cmd) {
606 /*
607 * SYMINFO_CMD_T_DUMP can't get here: It never has more than
608 * one argument, and is handled above.
609 */
610
611 case SYMINFO_CMD_T_SI_BOUNDTO:
612 {
613 const char *name = MSG_ORIG(MSG_CMD_SI_BOUNDTO);
614 Half boundto;
615
616 if (argstate.optmask & SYMINFO_OPT_F_NEEDED)
617 boundto = needed_to_boundto(&argstate,
618 argstate.argv[1]);
619 else
620 boundto = elfedit_atoconst_range(
621 argstate.argv[1], MSG_ORIG(MSG_STR_VALUE),
622 0, 0xffff, ELFEDIT_CONST_SYMINFO_BT);
623
624 if (syminfo->si_boundto == boundto) {
625 elfedit_msg(ELFEDIT_MSG_DEBUG,
626 MSG_INTL(MSG_DEBUG_X_OK),
627 argstate.syminfo.sec->sec_shndx,
628 argstate.syminfo.sec->sec_name, ndx, name,
629 syminfo->si_boundto);
630 } else {
631 elfedit_msg(ELFEDIT_MSG_DEBUG,
632 MSG_INTL(MSG_DEBUG_X_CHG),
633 argstate.syminfo.sec->sec_shndx,
634 argstate.syminfo.sec->sec_name, ndx, name,
635 syminfo->si_boundto, boundto);
636 ret = ELFEDIT_CMDRET_MOD;
637 syminfo->si_boundto = boundto;
638 }
639 }
640 break;
641
642 case SYMINFO_CMD_T_SI_FLAGS:
643 {
644 Conv_syminfo_flags_buf_t flags_buf1, flags_buf2;
645 const char *name = MSG_ORIG(MSG_CMD_SI_FLAGS);
646 Half flags = 0;
647 int i;
648
649 /* Collect the arguments */
650 for (i = 1; i < argstate.argc; i++)
651 flags |= (Word)
652 elfedit_atoconst(argstate.argv[i],
653 ELFEDIT_CONST_SYMINFO_FLG);
654
655 /* Complement the value? */
656 if (argstate.optmask & SYMINFO_OPT_F_CMP)
657 flags = ~flags;
658
659 /* Perform any requested bit operations */
660 if (argstate.optmask & SYMINFO_OPT_F_AND)
661 flags &= syminfo->si_flags;
662 else if (argstate.optmask & SYMINFO_OPT_F_OR)
663 flags |= syminfo->si_flags;
664
665 /* Set the value */
666 if (syminfo->si_flags == flags) {
667 elfedit_msg(ELFEDIT_MSG_DEBUG,
668 MSG_INTL(MSG_DEBUG_S_OK),
669 argstate.syminfo.sec->sec_shndx,
670 argstate.syminfo.sec->sec_name, ndx, name,
671 conv_syminfo_flags(syminfo->si_flags,
672 0, &flags_buf1));
673 } else {
674 elfedit_msg(ELFEDIT_MSG_DEBUG,
675 MSG_INTL(MSG_DEBUG_S_CHG),
676 argstate.syminfo.sec->sec_shndx,
677 argstate.syminfo.sec->sec_name, ndx, name,
678 conv_syminfo_flags(syminfo->si_flags,
679 0, &flags_buf1),
680 conv_syminfo_flags(flags, 0, &flags_buf2));
681 ret = ELFEDIT_CMDRET_MOD;
682 syminfo->si_flags = flags;
683 }
684 }
685 break;
686 }
687
688 /*
689 * If we modified the syminfo section, tell libelf.
690 */
691 if (ret == ELFEDIT_CMDRET_MOD)
692 elfedit_modified_data(argstate.syminfo.sec);
693
694 /* Do autoprint */
695 print_syminfo(cmd, 1, &argstate, ndx, 1);
696
697 return (ret);
698 }
699
700
701
702
703 /*
704 * Command completion functions for the various commands
705 */
706 /*ARGSUSED*/
707 static void
cpl_si_boundto(elfedit_obj_state_t * obj_state,void * cpldata,int argc,const char * argv[],int num_opt)708 cpl_si_boundto(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
709 const char *argv[], int num_opt)
710 {
711 int i;
712
713 /*
714 * If -needed option is not present, the second argument can be
715 * an SYMINFO_BT_ value.
716 */
717 if (argc != (num_opt + 2))
718 return;
719
720 /* Is -needed there? If so, no completion is possible so return */
721 for (i = 0; i < num_opt; i++)
722 if (strcmp(argv[i], MSG_ORIG(MSG_STR_MINUS_NEEDED)) == 0)
723 return;
724
725 elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SYMINFO_BT);
726 }
727
728 /*ARGSUSED*/
729 static void
cpl_si_flags(elfedit_obj_state_t * obj_state,void * cpldata,int argc,const char * argv[],int num_opt)730 cpl_si_flags(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
731 const char *argv[], int num_opt)
732 {
733 /* The second argument can be an SYMINFO_FLG_ value */
734 if (argc == (num_opt + 2))
735 elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SYMINFO_FLG);
736 }
737
738
739
740 /*
741 * Implementation functions for the commands
742 */
743 static elfedit_cmdret_t
cmd_dump(elfedit_obj_state_t * obj_state,int argc,const char * argv[])744 cmd_dump(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
745 {
746 return (cmd_body(SYMINFO_CMD_T_DUMP, obj_state, argc, argv));
747 }
748
749
750 static elfedit_cmdret_t
cmd_si_boundto(elfedit_obj_state_t * obj_state,int argc,const char * argv[])751 cmd_si_boundto(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
752 {
753 return (cmd_body(SYMINFO_CMD_T_SI_BOUNDTO, obj_state, argc, argv));
754 }
755
756
757 static elfedit_cmdret_t
cmd_si_flags(elfedit_obj_state_t * obj_state,int argc,const char * argv[])758 cmd_si_flags(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
759 {
760 return (cmd_body(SYMINFO_CMD_T_SI_FLAGS, obj_state, argc, argv));
761 }
762
763
764
765
766 /*ARGSUSED*/
767 elfedit_module_t *
elfedit_init(elfedit_module_version_t version)768 elfedit_init(elfedit_module_version_t version)
769 {
770 /* sym:dump */
771 static const char *name_dump[] = {
772 MSG_ORIG(MSG_CMD_DUMP),
773 MSG_ORIG(MSG_STR_EMPTY), /* "" makes this the default command */
774 NULL
775 };
776 static elfedit_cmd_optarg_t opt_dump[] = {
777 { MSG_ORIG(MSG_STR_MINUS_SYMNDX),
778 /* MSG_INTL(MSG_OPTDESC_SYMNDX) */
779 ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0,
780 SYMINFO_OPT_F_SYMNDX, 0 },
781 { NULL }
782 };
783 static elfedit_cmd_optarg_t arg_dump[] = {
784 { MSG_ORIG(MSG_STR_SYM),
785 /* MSG_INTL(MSG_A1_SYM) */
786 ELFEDIT_I18NHDL(MSG_A1_SYM),
787 ELFEDIT_CMDOA_F_OPT },
788 { NULL }
789 };
790
791 /* sym:si_boundto */
792 static const char *name_si_boundto[] = {
793 MSG_ORIG(MSG_CMD_SI_BOUNDTO), NULL };
794 static elfedit_cmd_optarg_t opt_si_boundto[] = {
795 { MSG_ORIG(MSG_STR_MINUS_NEEDED),
796 /* MSG_INTL(MSG_OPTDESC_NEEDED) */
797 ELFEDIT_I18NHDL(MSG_OPTDESC_NEEDED), 0,
798 SYMINFO_OPT_F_NEEDED, 0 },
799 { ELFEDIT_STDOA_OPT_O, NULL,
800 ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
801 { MSG_ORIG(MSG_STR_MINUS_SYMNDX),
802 /* MSG_INTL(MSG_OPTDESC_SYMNDX) */
803 ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0,
804 SYMINFO_OPT_F_SYMNDX, 0 },
805 { NULL }
806 };
807 static elfedit_cmd_optarg_t arg_si_boundto[] = {
808 { MSG_ORIG(MSG_STR_SYM),
809 /* MSG_INTL(MSG_A1_SYM) */
810 ELFEDIT_I18NHDL(MSG_A1_SYM),
811 ELFEDIT_CMDOA_F_OPT },
812 { MSG_ORIG(MSG_STR_VALUE),
813 /* MSG_INTL(MSG_A2_DESC_SI_BOUNDTO) */
814 ELFEDIT_I18NHDL(MSG_A2_DESC_SI_BOUNDTO),
815 ELFEDIT_CMDOA_F_OPT },
816 { NULL }
817 };
818
819 /* sym:si_flags */
820 static const char *name_si_flags[] = {
821 MSG_ORIG(MSG_CMD_SI_FLAGS), NULL };
822 static elfedit_cmd_optarg_t opt_si_flags[] = {
823 { ELFEDIT_STDOA_OPT_AND, NULL, ELFEDIT_CMDOA_F_INHERIT,
824 SYMINFO_OPT_F_AND, SYMINFO_OPT_F_OR },
825 { ELFEDIT_STDOA_OPT_CMP, NULL,
826 ELFEDIT_CMDOA_F_INHERIT, SYMINFO_OPT_F_CMP, 0 },
827 { ELFEDIT_STDOA_OPT_O, NULL,
828 ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
829 { ELFEDIT_STDOA_OPT_OR, NULL, ELFEDIT_CMDOA_F_INHERIT,
830 SYMINFO_OPT_F_OR, SYMINFO_OPT_F_AND },
831 { MSG_ORIG(MSG_STR_MINUS_SYMNDX),
832 /* MSG_INTL(MSG_OPTDESC_SYMNDX) */
833 ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0,
834 SYMINFO_OPT_F_SYMNDX, 0 },
835 { NULL }
836 };
837 static elfedit_cmd_optarg_t arg_si_flags[] = {
838 { MSG_ORIG(MSG_STR_SYM),
839 /* MSG_INTL(MSG_A1_SYM) */
840 ELFEDIT_I18NHDL(MSG_A1_SYM),
841 ELFEDIT_CMDOA_F_OPT },
842 { MSG_ORIG(MSG_STR_VALUE),
843 /* MSG_INTL(MSG_A2_DESC_SI_FLAGS) */
844 ELFEDIT_I18NHDL(MSG_A2_DESC_SI_FLAGS),
845 ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
846 { NULL }
847 };
848
849 static elfedit_cmd_t cmds[] = {
850 /* sym:dump */
851 { cmd_dump, NULL, name_dump,
852 /* MSG_INTL(MSG_DESC_DUMP) */
853 ELFEDIT_I18NHDL(MSG_DESC_DUMP),
854 /* MSG_INTL(MSG_HELP_DUMP) */
855 ELFEDIT_I18NHDL(MSG_HELP_DUMP),
856 opt_dump, arg_dump },
857
858 /* sym:si_boundto */
859 { cmd_si_boundto, cpl_si_boundto, name_si_boundto,
860 /* MSG_INTL(MSG_DESC_SI_BOUNDTO) */
861 ELFEDIT_I18NHDL(MSG_DESC_SI_BOUNDTO),
862 /* MSG_INTL(MSG_HELP_SI_BOUNDTO) */
863 ELFEDIT_I18NHDL(MSG_HELP_SI_BOUNDTO),
864 opt_si_boundto, arg_si_boundto },
865
866 /* sym:si_flags */
867 { cmd_si_flags, cpl_si_flags, name_si_flags,
868 /* MSG_INTL(MSG_DESC_SI_FLAGS) */
869 ELFEDIT_I18NHDL(MSG_DESC_SI_FLAGS),
870 /* MSG_INTL(MSG_HELP_SI_FLAGS) */
871 ELFEDIT_I18NHDL(MSG_HELP_SI_FLAGS),
872 opt_si_flags, arg_si_flags },
873
874 { NULL }
875 };
876
877 static elfedit_module_t module = {
878 ELFEDIT_VER_CURRENT, MSG_ORIG(MSG_MOD_NAME),
879 /* MSG_INTL(MSG_MOD_DESC) */
880 ELFEDIT_I18NHDL(MSG_MOD_DESC),
881 cmds, mod_i18nhdl_to_str };
882
883 return (&module);
884 }
885