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 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <ctype.h>
28 #include <elfedit.h>
29 #include <sys/elf_SPARC.h>
30 #include <strings.h>
31 #include <debug.h>
32 #include <conv.h>
33 #include <dyn_msg.h>
34
35
36 /*
37 * Dynamic section
38 */
39
40 /*
41 * This module uses shared code for several of the commands.
42 * It is sometimes necessary to know which specific command
43 * is active.
44 */
45 typedef enum {
46 /* Dump command, used as module default to display dynamic section */
47 DYN_CMD_T_DUMP = 0, /* dyn:dump */
48
49 /* Commands that do not correspond directly to a specific DT tag */
50 DYN_CMD_T_TAG = 1, /* dyn:tag */
51 DYN_CMD_T_VALUE = 2, /* dyn:value */
52 DYN_CMD_T_DELETE = 3, /* dyn:delete */
53 DYN_CMD_T_MOVE = 4, /* dyn:shift */
54
55 /* Commands that embody tag specific knowledge */
56 DYN_CMD_T_RUNPATH = 5, /* dyn:runpath/rpath */
57 DYN_CMD_T_POSFLAG1 = 6, /* dyn:posflag1 */
58 DYN_CMD_T_FLAGS = 7, /* dyn:flags */
59 DYN_CMD_T_FLAGS1 = 8, /* dyn:flags1 */
60 DYN_CMD_T_FEATURE1 = 9, /* dyn:feature1 */
61 DYN_CMD_T_CHECKSUM = 10, /* dyn:checksum */
62 DYN_CMD_T_SUNW_LDMACH = 11 /* dyn:sunw_ldmach */
63 } DYN_CMD_T;
64
65
66
67 #ifndef _ELF64
68 /*
69 * We supply this function for the msg module
70 */
71 const char *
_dyn_msg(Msg mid)72 _dyn_msg(Msg mid)
73 {
74 return (gettext(MSG_ORIG(mid)));
75 }
76 #endif
77
78
79 /*
80 * This function is supplied to elfedit through our elfedit_module_t
81 * definition. It translates the opaque elfedit_i18nhdl_t handles
82 * in our module interface into the actual strings for elfedit to
83 * use.
84 *
85 * note:
86 * This module uses Msg codes for its i18n handle type.
87 * So the translation is simply to use MSG_INTL() to turn
88 * it into a string and return it.
89 */
90 static const char *
mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl)91 mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl)
92 {
93 Msg msg = (Msg)hdl;
94
95 return (MSG_INTL(msg));
96 }
97
98
99
100 /*
101 * The dyn_opt_t enum specifies a bit value for every optional
102 * argument allowed by a command in this module.
103 */
104 typedef enum {
105 DYN_OPT_F_ADD = 1, /* -add: Add new elt rather than */
106 /* modifying an existing one */
107 DYN_OPT_F_AND = 2, /* -and: AND (&) values to dest */
108 DYN_OPT_F_CMP = 4, /* -cmp: Complement (~) values */
109 DYN_OPT_F_DYNNDX_ELT = 8, /* -dynndx: 1st plain arg is tag */
110 /* index, not name */
111 DYN_OPT_F_DYNNDX_VAL = 16, /* -dynndx ndx: Index is value to */
112 /* option rather than 1st plain */
113 /* arg. Used for dyn:posflag1 */
114 DYN_OPT_F_NEEDED = 32, /* -needed str: Locate DT_POSFLAG_1 */
115 /* relative to DT_NEEDED element */
116 DYN_OPT_F_OR = 64, /* -or: OR (|) values to dest */
117 DYN_OPT_F_STRVAL = 128 /* -s: value is string, not integer */
118 } dyn_opt_t;
119
120
121 /*
122 * A variable of type ARGSTATE is used by each command to maintain
123 * information about the arguments and related things. It is
124 * initialized by process_args(), and used by the other routines.
125 */
126 typedef struct {
127 elfedit_obj_state_t *obj_state;
128 elfedit_section_t *strsec; /* Dynamic string table ref */
129 struct {
130 elfedit_section_t *sec; /* Dynamic section reference */
131 Dyn *data; /* Start dynamic section data */
132 Word num; /* # dynamic elts */
133 Word null_ndx; /* Index of first DT_NULL */
134 Word num_null_ndx; /* # of DT_NULL elements */
135 } dyn;
136 dyn_opt_t optmask; /* Mask of options used */
137 int argc; /* # of plain arguments */
138 const char **argv; /* Plain arguments */
139 const char *dyn_elt_str; /* Value string for */
140 /* DYN_OPT_F_DYNNDX_VAL */
141 /* or DYN_OPT_F_NEEDED */
142 } ARGSTATE;
143
144
145
146 /*
147 * Set argstate null_ndx field for current dynamic area
148 */
149 static void
set_null_ndx(ARGSTATE * argstate)150 set_null_ndx(ARGSTATE *argstate)
151 {
152 Word num, null_ndx;
153
154 num = argstate->dyn.num;
155 argstate->dyn.num_null_ndx = 0;
156 for (null_ndx = 0; null_ndx < num; null_ndx++)
157 if (argstate->dyn.data[null_ndx].d_tag == DT_NULL) {
158 argstate->dyn.num_null_ndx++;
159 break;
160 }
161 argstate->dyn.null_ndx = null_ndx;
162
163 /* Count the number of remaining DT_NULL items */
164 for (; null_ndx < num; null_ndx++)
165 if (argstate->dyn.data[null_ndx].d_tag == DT_NULL)
166 argstate->dyn.num_null_ndx++;
167 }
168
169
170 /*
171 * Convert the first available DT_NULL slot in the dynamic section
172 * into something else.
173 *
174 * entry:
175 * argstate - Argument state block
176 * d_tag, d_val - Values to be set in new element
177 *
178 * exit:
179 * If an extra DT_NULL slot is available, a debug message is
180 * issued, the slot is converted to its new use, and the argstate
181 * block state related to DT_NULL slots is updated.
182 *
183 * if no extra DT_NULL slot is present, an error is issued and
184 * this routine does not return to the caller.
185 */
186 static Word
convert_dt_null(ARGSTATE * argstate,Xword d_tag,Xword d_val)187 convert_dt_null(ARGSTATE *argstate, Xword d_tag, Xword d_val)
188 {
189 Conv_inv_buf_t inv_buf;
190 Word ndx;
191 Dyn *dyn;
192 Ehdr *ehdr;
193
194 /* If we lack an extra element, we can't continue */
195 if (argstate->dyn.num_null_ndx <= 1)
196 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOEXTRANULL),
197 EC_WORD(argstate->dyn.sec->sec_shndx),
198 argstate->dyn.sec->sec_name);
199
200 ehdr = argstate->obj_state->os_ehdr;
201 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CONVNULL),
202 EC_WORD(argstate->dyn.sec->sec_shndx), argstate->dyn.sec->sec_name,
203 EC_WORD(argstate->dyn.null_ndx), conv_dyn_tag(d_tag,
204 ehdr->e_ident[EI_OSABI], ehdr->e_machine, 0, &inv_buf));
205
206 ndx = argstate->dyn.null_ndx;
207 dyn = &argstate->dyn.data[ndx];
208 dyn->d_tag = d_tag;
209 dyn->d_un.d_val = d_val;
210
211 /* Recompute the DT_NULL situation */
212 set_null_ndx(argstate);
213
214 return (ndx);
215 }
216
217
218 /*
219 * Standard argument processing for dyn module
220 *
221 * entry
222 * obj_state, argc, argv - Standard command arguments
223 * argstate - Address of ARGSTATE block to be initialized
224 *
225 * exit:
226 * On success, *argstate is initialized. On error,
227 * an error is issued and this routine does not return.
228 */
229 static void
process_args(elfedit_obj_state_t * obj_state,int argc,const char * argv[],ARGSTATE * argstate)230 process_args(elfedit_obj_state_t *obj_state, int argc, const char *argv[],
231 ARGSTATE *argstate)
232 {
233 elfedit_getopt_state_t getopt_state;
234 elfedit_getopt_ret_t *getopt_ret;
235
236 bzero(argstate, sizeof (*argstate));
237 argstate->obj_state = obj_state;
238
239 elfedit_getopt_init(&getopt_state, &argc, &argv);
240
241 /* Add each new option to the options mask */
242 while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL) {
243 argstate->optmask |= getopt_ret->gor_idmask;
244 switch (getopt_ret->gor_idmask) {
245 case DYN_OPT_F_DYNNDX_VAL:
246 case DYN_OPT_F_NEEDED:
247 argstate->dyn_elt_str = getopt_ret->gor_value;
248 break;
249 }
250 }
251
252 /* If there may be an arbitrary amount of output, use a pager */
253 if (argc == 0)
254 elfedit_pager_init();
255
256 /* Return the updated values of argc/argv */
257 argstate->argc = argc;
258 argstate->argv = argv;
259
260 /* Locate the dynamic section, and the assocated string table */
261 argstate->dyn.sec = elfedit_sec_getdyn(obj_state, &argstate->dyn.data,
262 &argstate->dyn.num);
263 argstate->strsec = elfedit_sec_getstr(obj_state,
264 argstate->dyn.sec->sec_shdr->sh_link, 0);
265
266 /* Index of first DT_NULL */
267 set_null_ndx(argstate);
268 }
269
270 /*
271 * Print ELF header values, taking the calling command, and output style
272 * into account.
273 *
274 * entry:
275 * cmd - DYN_CMD_T_* value giving identify of caller
276 * autoprint - If True, output is only produced if the elfedit
277 * autoprint flag is set. If False, output is always produced.
278 * argstate - Argument state block
279 * print_type - Specifies which dynamic elements to display.
280 * arg - If print_type is PRINT_DYN_T_NDX, displays the index specified.
281 * Otherwise ignored.
282 */
283 typedef enum {
284 PRINT_DYN_T_ALL = 0, /* Show all indexes */
285 PRINT_DYN_T_NDX = 1, /* Show dynamic[arg] only */
286 PRINT_DYN_T_TAG = 2, /* Show all elts with tag type */
287 /* given by arg */
288 PRINT_DYN_T_RUNPATH = 3 /* Show all runpath/rpath elts */
289
290 } PRINT_DYN_T;
291
292 static void
print_dyn(DYN_CMD_T cmd,int autoprint,ARGSTATE * argstate,PRINT_DYN_T print_type,Word arg)293 print_dyn(DYN_CMD_T cmd, int autoprint, ARGSTATE *argstate,
294 PRINT_DYN_T print_type, Word arg)
295 {
296 elfedit_outstyle_t outstyle;
297 Conv_fmt_flags_t flags_fmt_flags;
298 Word end_ndx, ndx, printed = 0;
299 Dyn *dyn;
300 int header_done = 0;
301 Xword last_d_val;
302 int one_shot;
303 int osabi_solaris;
304
305 if (autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0))
306 return;
307
308 osabi_solaris =
309 elfedit_test_osabi(argstate->obj_state, ELFOSABI_SOLARIS, 0);
310
311 /*
312 * Pick an output style. dyn:dump is required to use the default
313 * style. The other commands use the current output style.
314 */
315 outstyle = (cmd == DYN_CMD_T_DUMP) ?
316 ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle();
317
318 /*
319 * When using the simple output style, omit the
320 * brackets from around the values.
321 */
322 flags_fmt_flags = (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) ?
323 CONV_FMT_NOBKT : 0;
324
325 /* Starting index */
326 if (print_type == PRINT_DYN_T_NDX) {
327 if (arg >= argstate->dyn.num)
328 return; /* Out of range */
329 ndx = arg;
330 } else {
331 ndx = 0;
332 }
333
334 /*
335 * one_shot is used by positional elements (e.g. DT_POSFLAG_1)
336 * to get the item following them to be shown even if they
337 * are not of the desired tag type or the count of elements
338 * to be displayed is only 1.
339 */
340 one_shot = 0;
341
342 dyn = &argstate->dyn.data[ndx];
343
344 /*
345 * Loop predicate explanation:
346 * Normally, we want to iterate from the starting index
347 * to the end. However, in the case of PRINT_DYN_T_NDX, we
348 * only want to display one item (ndx == arg) and then quit,
349 * with the exception that if we've been through the loop
350 * and encountered a one_shot situation, we want to continue
351 * iterating until the one-shot situation is cleared.
352 */
353 for (; (ndx < argstate->dyn.num) &&
354 ((print_type != PRINT_DYN_T_NDX) || ((ndx == arg) || one_shot));
355 dyn++, ndx++) {
356 union {
357 Conv_inv_buf_t inv;
358 Conv_dyn_flag_buf_t flag;
359 Conv_dyn_flag1_buf_t flag1;
360 Conv_dyn_posflag1_buf_t posflag1;
361 Conv_dyn_feature1_buf_t feature1;
362 } c_buf;
363 const char *name;
364
365 if (one_shot) {
366 one_shot = 0;
367 } else {
368 /*
369 * If we are only displaying certain tag types and
370 * this isn't one of those, move on to next element.
371 */
372 switch (print_type) {
373 case PRINT_DYN_T_TAG:
374 if (dyn->d_tag != arg)
375 continue;
376 break;
377 case PRINT_DYN_T_RUNPATH:
378 if ((dyn->d_tag != DT_RPATH) &&
379 (dyn->d_tag != DT_RUNPATH))
380 continue;
381 break;
382 }
383 }
384
385 /*
386 * Print the information numerically, and if possible
387 * as a string.
388 */
389 name = NULL;
390 switch (dyn->d_tag) {
391 case DT_NULL:
392 if (!((outstyle == ELFEDIT_OUTSTYLE_DEFAULT) &&
393 (print_type == PRINT_DYN_T_ALL) &&
394 (dyn->d_un.d_val == 0)))
395 break;
396 end_ndx = ndx;
397 /*
398 * Special case: DT_NULLs can come in groups
399 * that we prefer to reduce to a single line.
400 */
401 while ((end_ndx < (argstate->dyn.num - 1)) &&
402 ((dyn + 1)->d_tag == DT_NULL) &&
403 ((dyn + 1)->d_un.d_val == 0)) {
404 dyn++;
405 end_ndx++;
406 }
407 if (header_done == 0) {
408 header_done = 1;
409 Elf_dyn_title(0);
410 }
411 Elf_dyn_null_entry(0, dyn, ndx, end_ndx);
412 ndx = end_ndx;
413 printed = 1;
414 last_d_val = dyn->d_un.d_val;
415 continue;
416
417 /*
418 * Print the information numerically, and if possible
419 * as a string.
420 */
421 case DT_NEEDED:
422 case DT_SONAME:
423 case DT_FILTER:
424 case DT_AUXILIARY:
425 case DT_CONFIG:
426 case DT_RPATH:
427 case DT_RUNPATH:
428 case DT_USED:
429 case DT_DEPAUDIT:
430 case DT_AUDIT:
431 name = elfedit_offset_to_str(argstate->strsec,
432 dyn->d_un.d_val, ELFEDIT_MSG_DEBUG, 0);
433 break;
434 case DT_SUNW_AUXILIARY:
435 case DT_SUNW_FILTER:
436 if (osabi_solaris)
437 name = elfedit_offset_to_str(argstate->strsec,
438 dyn->d_un.d_val, ELFEDIT_MSG_DEBUG, 0);
439 break;
440
441 case DT_FLAGS:
442 name = conv_dyn_flag(dyn->d_un.d_val,
443 flags_fmt_flags, &c_buf.flag);
444 break;
445 case DT_FLAGS_1:
446 name = conv_dyn_flag1(dyn->d_un.d_val,
447 flags_fmt_flags, &c_buf.flag1);
448 break;
449 case DT_POSFLAG_1:
450 /*
451 * If this is dyn:posflag1, and the print_type
452 * is PRINT_DYN_T_TAG, and the -needed option is
453 * used, then don't show any DT_POSFLAG_1 elements
454 * that are not followed by a DT_NEEDED element
455 * that matches the -needed string.
456 */
457 if ((cmd == DYN_CMD_T_POSFLAG1) &&
458 (print_type == PRINT_DYN_T_TAG) &&
459 ((argstate->optmask & DYN_OPT_F_NEEDED) != 0) &&
460 ((ndx + 1) < argstate->dyn.num)) {
461 Dyn *dyn1 = &argstate->dyn.data[ndx + 1];
462
463 if (dyn1->d_tag != DT_NEEDED)
464 continue;
465 name = elfedit_offset_to_str(argstate->strsec,
466 dyn1->d_un.d_val, ELFEDIT_MSG_DEBUG, 0);
467 if (strncmp(name, argstate->dyn_elt_str,
468 strlen(argstate->dyn_elt_str)) != 0)
469 continue;
470 }
471
472 name = conv_dyn_posflag1(dyn->d_un.d_val,
473 flags_fmt_flags, &c_buf.posflag1);
474 /*
475 * DT_POSFLAG_1 is a positional element that affects
476 * the following item. If using the default output
477 * style, then show the following item as well.
478 */
479 one_shot = (outstyle == ELFEDIT_OUTSTYLE_DEFAULT);
480 break;
481 case DT_FEATURE_1:
482 name = conv_dyn_feature1(dyn->d_un.d_val,
483 flags_fmt_flags, &c_buf.feature1);
484 break;
485 case DT_DEPRECATED_SPARC_REGISTER:
486 name = MSG_INTL(MSG_STR_DEPRECATED);
487 break;
488 case DT_SUNW_LDMACH:
489 if (osabi_solaris)
490 name = conv_ehdr_mach((Half)dyn->d_un.d_val, 0,
491 &c_buf.inv);
492 break;
493 }
494
495 if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) {
496 Ehdr *ehdr;
497
498 if (header_done == 0) {
499 header_done = 1;
500 Elf_dyn_title(0);
501 }
502 if (name == NULL)
503 name = MSG_ORIG(MSG_STR_EMPTY);
504 ehdr = argstate->obj_state->os_ehdr;
505 Elf_dyn_entry(0, dyn, ndx, name,
506 ehdr->e_ident[EI_OSABI], ehdr->e_machine);
507 } else {
508 /*
509 * In simple or numeric mode under a print type
510 * that is based on tag type rather than on index,
511 * if there are more than one qualifying tag, we
512 * want to skip printing redundant information.
513 */
514 switch (print_type) {
515 case PRINT_DYN_T_TAG:
516 switch (dyn->d_tag) {
517 case DT_NEEDED:
518 /* Multiple NEEDED entries are normal */
519 break;
520 case DT_POSFLAG_1:
521 /*
522 * Positional flags don't count,
523 * because each one affects a different
524 * item. Don't skip those even if they
525 * have duplicate values.
526 */
527 break;
528 default:
529 /*
530 * Anything else: If we've already
531 * printed this value, don't print
532 * it again.
533 */
534 if (printed &&
535 (last_d_val == dyn->d_un.d_val))
536 continue;
537 }
538 break;
539 case PRINT_DYN_T_RUNPATH:
540 /*
541 * If we've already printed this value,
542 * don't print it again. This commonly
543 * happens when both DT_RPATH and DT_RUNPATH
544 * are present with the same value.
545 */
546 if (printed && (last_d_val == dyn->d_un.d_val))
547 continue;
548 break;
549 }
550
551 if ((name != NULL) &&
552 (outstyle == ELFEDIT_OUTSTYLE_SIMPLE)) {
553 elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), name);
554 } else {
555 elfedit_printf(MSG_ORIG(MSG_FMT_HEXXWORDNL),
556 EC_XWORD(dyn->d_un.d_val));
557 }
558 }
559 printed = 1;
560 last_d_val = dyn->d_un.d_val;
561 }
562
563 /*
564 * If nothing was output under the print types that are
565 * based on tag type, issue an error saying it doesn't exist.
566 */
567 if (!printed) {
568 if (print_type == PRINT_DYN_T_TAG) {
569 Conv_inv_buf_t inv_buf;
570 Ehdr *ehdr = argstate->obj_state->os_ehdr;
571
572 elfedit_msg(ELFEDIT_MSG_ERR,
573 MSG_INTL(MSG_ERR_NODYNELT),
574 EC_WORD(argstate->dyn.sec->sec_shndx),
575 argstate->dyn.sec->sec_name, conv_dyn_tag(arg,
576 ehdr->e_ident[EI_OSABI], ehdr->e_machine,
577 0, &inv_buf));
578 }
579
580 if (print_type == PRINT_DYN_T_RUNPATH)
581 elfedit_msg(ELFEDIT_MSG_ERR,
582 MSG_INTL(MSG_ERR_NORUNPATH),
583 EC_WORD(argstate->dyn.sec->sec_shndx),
584 argstate->dyn.sec->sec_name);
585 }
586 }
587
588
589 /*
590 * Determine the index(s) of the dynamic element(s) to be displayed and/or
591 * manipulated.
592 *
593 * entry:
594 * argstate - Argument state block
595 * arg - If the command being called accepts a first plain argument
596 * named 'elt' which is used to specify the dynamic element,
597 * arg is the value of argv[0] for that command. If the
598 * command does not accept an 'elt' argument and instead
599 * implicitly assumes a tag type, arg is the constant string
600 * for that type (e.g. "DT_POSFLAG_1").
601 * print_request - True if the command is to print the current
602 * value(s) and return without changing anything.
603 * print_type - Address of variable containing PRINT_DYN_T_
604 * code specifying how the elements will be displayed.
605 *
606 * exit:
607 * If print_request is False: This routine always returns the index
608 * of a single dynamic element. *print_type is set to PRINT_DYN_T_NDX.
609 * The 'elt' argument as well as any modifier options (-dynndx, -needed)
610 * are examined to determine this index. If there are no modifier options,
611 * the dynamic section contains no element of the desired type, and there
612 * is an extra DT_NULL element in the section, then a new element of
613 * the desired type is created and its index returned. Otherwise an
614 * error is issued.
615 *
616 * If print_request is True: If a modifier (-dynndx, -needed) was used,
617 * *print_type is set to PRINT_DYN_T_NDX and the index of the
618 * corresponding single dynamic element is returned. If no modifier
619 * was used, *print_type is set to PRINT_DYN_T_TAG, and the tag
620 * type code is returned.
621 */
622 static Word
arg_to_index(ARGSTATE * argstate,const char * arg,int print_request,PRINT_DYN_T * print_type)623 arg_to_index(ARGSTATE *argstate, const char *arg,
624 int print_request, PRINT_DYN_T *print_type)
625 {
626 Word ndx;
627 Xword dt_value;
628 Dyn *dyn;
629
630
631 /* Assume we are returning an index, alter as needed below */
632 *print_type = PRINT_DYN_T_NDX;
633
634 /*
635 * All the commands that accept the DYN_OPT_F_DYNNDX_ELT form
636 * of -dynndx require a plain argument named 'elt' as their first
637 * argument. -dynndx is a modifier that means that 'elt' is a
638 * simple numeric section index. Routines that accept this form
639 * of -dynndx are willing to handle any tag type, so all we need
640 * to check is that the value is in range.
641 */
642 if ((argstate->optmask & DYN_OPT_F_DYNNDX_ELT) != 0)
643 return ((Word) elfedit_atoui_range(arg, MSG_ORIG(MSG_STR_ELT),
644 0, argstate->dyn.num - 1, NULL));
645
646 /* arg is a DT_ tag type, not a numeric index */
647 dt_value = (Word) elfedit_atoconst(arg, ELFEDIT_CONST_DT);
648
649 /*
650 * Commands that accept the DYN_OPT_F_DYNNDX_VAL form of
651 * dynndx do not accept the 'elt' argument. The index is a
652 * value that follows the option, and was saved in argstate by
653 * process_args(). Routines that accept this form of -dynndx
654 * require the specified element to have a specific tag type,
655 * so we test for this as well as for the index being in range.
656 */
657 if ((argstate->optmask & DYN_OPT_F_DYNNDX_VAL) != 0) {
658 ndx = ((Word) elfedit_atoui_range(argstate->dyn_elt_str,
659 MSG_ORIG(MSG_STR_INDEX), 0, argstate->dyn.num - 1, NULL));
660 if (argstate->dyn.data[ndx].d_tag != dt_value) {
661 Ehdr *ehdr = argstate->obj_state->os_ehdr;
662 uchar_t osabi = ehdr->e_ident[EI_OSABI];
663 Half mach = ehdr->e_machine;
664 Conv_inv_buf_t is, want;
665
666 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_WRONGTAG),
667 EC_WORD(argstate->dyn.sec->sec_shndx),
668 argstate->dyn.sec->sec_name, ndx,
669 conv_dyn_tag(dt_value, osabi, mach, 0, &want),
670 conv_dyn_tag(argstate->dyn.data[ndx].d_tag,
671 osabi, mach, 0, &is));
672 }
673 return (ndx);
674 }
675
676 /*
677 * If this is a printing request, then we let print_dyn() show
678 * all the items with this tag type.
679 */
680 if (print_request) {
681 *print_type = PRINT_DYN_T_TAG;
682 return (dt_value);
683 }
684
685 /*
686 * Commands that accept -needed are looking for the dt_value element
687 * (usually DT_POSFLAG_1) that immediately preceeds the DT_NEEDED
688 * element with the string given by argstate->dyn_elt_str.
689 */
690 if ((argstate->optmask & DYN_OPT_F_NEEDED) != 0) {
691 Word retndx = argstate->dyn.num; /* Out of range value */
692 const char *name;
693 size_t len;
694
695 len = strlen(argstate->dyn_elt_str);
696 for (ndx = 0, dyn = argstate->dyn.data;
697 ndx < argstate->dyn.num; dyn++, ndx++) {
698 /*
699 * If the immediately preceeding item has the
700 * tag type we're looking for, and the current item
701 * is a DT_NEEDED with a string that matches,
702 * then the preceeding item is the one we want.
703 */
704 if ((dyn->d_tag == DT_NEEDED) &&
705 (ndx > 0) && (retndx == (ndx - 1))) {
706 name = elfedit_offset_to_str(argstate->strsec,
707 dyn->d_un.d_val, ELFEDIT_MSG_DEBUG, 0);
708
709 if (strncmp(name,
710 argstate->dyn_elt_str, len) == 0)
711 return (retndx);
712 continue;
713 }
714
715 /*
716 * If the current item has the tag type we're
717 * looking for, make it our current candidate.
718 * If the next item is a DT_NEEDED with the right
719 * string value, we'll use it then.
720 */
721 if (dyn->d_tag == dt_value)
722 retndx = ndx;
723 }
724
725 /* If we get here, no matching DT_NEEDED was found */
726 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NEEDEDNOMATCH),
727 EC_WORD(argstate->dyn.sec->sec_shndx),
728 argstate->dyn.sec->sec_name, argstate->dyn_elt_str);
729 }
730
731 /* Locate the first entry with the given tag type */
732 for (ndx = 0; ndx < argstate->dyn.num; ndx++) {
733 if (argstate->dyn.data[ndx].d_tag == dt_value) {
734 elfedit_msg(ELFEDIT_MSG_DEBUG,
735 MSG_INTL(MSG_DEBUG_DT2NDX),
736 EC_WORD(argstate->dyn.sec->sec_shndx),
737 argstate->dyn.sec->sec_name, EC_WORD(ndx), arg);
738 return (ndx);
739 }
740 }
741
742 /* Not found. Can we create one? */
743 if (argstate->dyn.num_null_ndx > 1)
744 return (convert_dt_null(argstate, dt_value, 0));
745
746 /* No room to create one, so we're out of options and must fail */
747 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NODTELT),
748 EC_WORD(argstate->dyn.sec->sec_shndx),
749 argstate->dyn.sec->sec_name, arg);
750
751 /*NOTREACHED*/
752 return (0); /* For lint */
753 }
754
755
756 /*
757 * Called by cmd_body() for dyn:value. Implements the core functionality
758 * for that command.
759 *
760 * This routine expects that both the index and value arguments are
761 * present.
762 */
763 static elfedit_cmdret_t
cmd_body_value(ARGSTATE * argstate,Word * ret_ndx)764 cmd_body_value(ARGSTATE *argstate, Word *ret_ndx)
765 {
766 elfedit_section_t *dynsec = argstate->dyn.sec;
767 elfedit_section_t *strsec = argstate->strsec;
768 elfedit_dyn_elt_t strpad_elt;
769 Word i;
770 Dyn *dyn = argstate->dyn.data;
771 Word numdyn = argstate->dyn.num;
772 int minus_add, minus_s, minus_dynndx;
773 Word tmp_val;
774 Xword arg1, arg2;
775 int arg2_known = 1;
776
777 minus_add = ((argstate->optmask & DYN_OPT_F_ADD) != 0);
778 minus_s = ((argstate->optmask & DYN_OPT_F_STRVAL) != 0);
779 minus_dynndx = ((argstate->optmask & DYN_OPT_F_DYNNDX_ELT) != 0);
780
781 elfedit_dyn_elt_init(&strpad_elt);
782
783 /*
784 * The first argument is an index if -dynndx is used, and is a
785 * tag value otherwise.
786 */
787 arg1 = minus_dynndx ?
788 elfedit_atoui_range(argstate->argv[0], MSG_ORIG(MSG_STR_ELT),
789 0, numdyn - 1, NULL) :
790 elfedit_atoconst(argstate->argv[0], ELFEDIT_CONST_DT);
791
792 if (minus_s) {
793 /*
794 * Don't allow the user to specify -s when manipulating a
795 * DT_SUNW_STRPAD element. Since DT_SUNW_STRPAD is used to
796 * manage the extra space used for strings, this would break
797 * our ability to add the string.
798 */
799 if ((!minus_dynndx && (arg1 == DT_SUNW_STRPAD)) ||
800 (minus_dynndx && (dyn[arg1].d_tag == DT_SUNW_STRPAD)))
801 elfedit_msg(ELFEDIT_MSG_ERR,
802 MSG_INTL(MSG_ERR_STRPADSTRVAL),
803 EC_WORD(dynsec->sec_shndx), dynsec->sec_name);
804
805 /* Locate DT_SUNW_STRPAD element if present */
806 strpad_elt.dn_dyn.d_un.d_val = 0;
807 (void) elfedit_dynstr_getpad(argstate->obj_state,
808 argstate->dyn.sec, &strpad_elt);
809
810 /*
811 * Look up the string: If the user specified the -dynndx
812 * -option, then we will insert it if possible, and
813 * fail with an error if not. However, if they did not
814 * specify -dynndx, we want to look up the string if it is
815 * already there, but defer the insertion. The reason for
816 * this is that we may have to grab an unused DT_NULL element
817 * below, and if there are none available, we won't want
818 * to have modified the string table.
819 *
820 * This isn't a problem, because if the string isn't
821 * in the string table, it can't be used by a dynamic element.
822 * Hence, we don't need to insert it to know that there is
823 * no match.
824 */
825 if (minus_dynndx == 0) {
826 if (elfedit_sec_findstr(strsec,
827 strpad_elt.dn_dyn.d_un.d_val, argstate->argv[1],
828 &tmp_val) == 0) {
829 arg2_known = 0;
830 } else {
831 arg2 = tmp_val;
832 }
833 } else {
834 arg2 = elfedit_dynstr_insert(dynsec, strsec,
835 &strpad_elt, argstate->argv[1]);
836 }
837 } else { /* Argument 2 is an integer */
838 arg2 = elfedit_atoui(argstate->argv[1], NULL);
839 }
840
841
842 if (!minus_dynndx && !(minus_add && !arg2_known)) {
843 /*
844 * Search the dynamic section and see if an item with the
845 * specified tag value already exists. We can reduce this
846 * to a simple update of an existing value if -add is not
847 * specified or the existing d_un value matches the new one.
848 *
849 * In either of these cases, we will change arg1 to be the
850 * index, and set minus_dynndx, causing the simple update to
851 * happen immediately below.
852 */
853 for (i = 0; i < numdyn; i++) {
854 if ((dyn[i].d_tag == arg1) &&
855 (!minus_add || (dyn[i].d_un.d_val == arg2))) {
856 arg1 = i;
857 minus_dynndx = 1;
858 break;
859 }
860 }
861 }
862
863 /*
864 * If -dynndx is used, then this is a relatively simple
865 * operation, as we simply write over the specified index.
866 */
867 if (minus_dynndx) {
868 /*
869 * If we held back from inserting a new string into
870 * the dynstr above, we insert it now, because we
871 * have a slot in the dynamic section, and we need
872 * the string offset ot finish.
873 */
874 if (!arg2_known)
875 arg2 = elfedit_dynstr_insert(dynsec, strsec,
876 &strpad_elt, argstate->argv[1]);
877
878 *ret_ndx = arg1;
879 if (dyn[arg1].d_un.d_val == arg2) {
880 elfedit_msg(ELFEDIT_MSG_DEBUG,
881 MSG_INTL(MSG_DEBUG_X_OK),
882 dynsec->sec_shndx, dynsec->sec_name,
883 EC_WORD(arg1), EC_XWORD(arg2));
884 return (ELFEDIT_CMDRET_NONE);
885 } else {
886 /* Warn if setting DT_NULL value to non-zero */
887 if ((dyn[arg1].d_tag == DT_NULL) && (arg2 != 0))
888 elfedit_msg(ELFEDIT_MSG_DEBUG,
889 MSG_INTL(MSG_DEBUG_DTNULLVALUE),
890 dynsec->sec_shndx, dynsec->sec_name,
891 EC_WORD(arg1), EC_XWORD(arg2));
892
893 elfedit_msg(ELFEDIT_MSG_DEBUG,
894 MSG_INTL(MSG_DEBUG_X_CHG),
895 dynsec->sec_shndx, dynsec->sec_name,
896 EC_WORD(arg1), EC_XWORD(dyn[arg1].d_un.d_val),
897 EC_XWORD(arg2));
898 dyn[arg1].d_un.d_val = arg2;
899 return (ELFEDIT_CMDRET_MOD);
900 }
901 }
902
903 /*
904 * We need a new slot in the dynamic section. If we can't have
905 * one, then we fail.
906 */
907 if (argstate->dyn.num_null_ndx <= 1)
908 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOEXTRANULL),
909 EC_WORD(dynsec->sec_shndx), dynsec->sec_name);
910
911 /*
912 * If we still need to insert a new string into the dynstr,
913 * then it is safe now, because if we succeed, we know that
914 * there is an available slot to receive it. If we fail, we
915 * haven't claimed the extra slot yet, and it will be unharmed.
916 */
917 if (!arg2_known)
918 arg2 = elfedit_dynstr_insert(dynsec, strsec,
919 &strpad_elt, argstate->argv[1]);
920
921 /* Use an extra DT_NULL slot and enter the new element */
922 *ret_ndx = convert_dt_null(argstate, arg1, arg2);
923 return (ELFEDIT_CMDRET_MOD);
924 }
925
926
927
928 /*
929 * Called by cmd_body() for dyn:runpath. Implements the core functionality
930 * for that command.
931 *
932 * History Lesson And Strategy:
933 *
934 * This routine handles both DT_RPATH and DT_RUNPATH entries, altering
935 * either or both if they are present.
936 *
937 * The original SYSV ABI only had DT_RPATH, and the runtime loader used
938 * it to search for things in the following order:
939 *
940 * DT_RPATH, LD_LIBRARY_PATH, defaults
941 *
942 * Solaris did not follow this rule, an extremely rare deviation from
943 * the ABI. Environment variables should supercede everything else,
944 * otherwise they are not very useful. This decision was made at the
945 * very beginning of the SunOS 5.x development, so we have always
946 * deviated from the ABI and and instead search in the order
947 *
948 * LD_LIBRARY_PATH, DT_RPATH, defaults
949 *
950 * Other Unix variants initially followed the ABI, but in recent years
951 * have come to agree with the early Solaris folks that it was a mistake.
952 * Hence, DT_RUNPATH was invented, with the search order:
953 *
954 * LD_LIBRARY_PATH, DT_RUNPATH, defaults
955 *
956 * So for Solaris, DT_RPATH and DT_RUNPATH mean the same thing. If both
957 * are present (which does happen), we set them both to the new
958 * value. If either one is present, we set that one. If neither is
959 * present, and we have a spare DT_NULL slot, we create a DT_RUNPATH, but
960 * not a DT_RPATH, to conserve available slots for other uses.
961 */
962 static elfedit_cmdret_t
cmd_body_runpath(ARGSTATE * argstate)963 cmd_body_runpath(ARGSTATE *argstate)
964 {
965 elfedit_section_t *dynsec = argstate->dyn.sec;
966 elfedit_section_t *strsec = argstate->strsec;
967 elfedit_dyn_elt_t rpath_elt;
968 elfedit_dyn_elt_t runpath_elt;
969 elfedit_dyn_elt_t strpad_elt;
970 Word i;
971 Dyn *dyn = argstate->dyn.data;
972 Word numdyn = argstate->dyn.num;
973
974 /* Go through the tags and gather what we need */
975 elfedit_dyn_elt_init(&rpath_elt);
976 elfedit_dyn_elt_init(&runpath_elt);
977 elfedit_dyn_elt_init(&strpad_elt);
978 for (i = 0; i < numdyn; i++) {
979 switch (dyn[i].d_tag) {
980 case DT_RPATH:
981 elfedit_dyn_elt_save(&rpath_elt, i, &dyn[i]);
982 break;
983
984 case DT_RUNPATH:
985 elfedit_dyn_elt_save(&runpath_elt, i, &dyn[i]);
986 break;
987
988 case DT_SUNW_STRPAD:
989 if (elfedit_test_osabi(argstate->obj_state,
990 ELFOSABI_SOLARIS, 0))
991 elfedit_dyn_elt_save(&strpad_elt, i, &dyn[i]);
992 break;
993 }
994 }
995
996 /* Do we have an available dynamic section entry to use? */
997 if (rpath_elt.dn_seen || runpath_elt.dn_seen) {
998 /*
999 * We have seen a DT_RPATH, or a DT_RUNPATH, or both.
1000 * If all of these have the same string as the desired
1001 * new value, then we don't need to alter anything and can
1002 * simply return. Otherwise, we'll modify them all to have
1003 * the new string (below).
1004 */
1005 if ((!rpath_elt.dn_seen ||
1006 (strcmp(elfedit_dyn_offset_to_str(strsec, &rpath_elt),
1007 argstate->argv[0]) == 0)) &&
1008 (!runpath_elt.dn_seen ||
1009 (strcmp(elfedit_dyn_offset_to_str(strsec, &runpath_elt),
1010 argstate->argv[0]) == 0))) {
1011 if (rpath_elt.dn_seen)
1012 elfedit_msg(ELFEDIT_MSG_DEBUG,
1013 MSG_INTL(MSG_DEBUG_OLDRPATHOK),
1014 EC_WORD(dynsec->sec_shndx),
1015 dynsec->sec_name, EC_WORD(rpath_elt.dn_ndx),
1016 elfedit_atoconst_value_to_str(
1017 ELFEDIT_CONST_DT, DT_RPATH, 1));
1018 if (runpath_elt.dn_seen)
1019 elfedit_msg(ELFEDIT_MSG_DEBUG,
1020 MSG_INTL(MSG_DEBUG_OLDRPATHOK),
1021 EC_WORD(dynsec->sec_shndx),
1022 dynsec->sec_name,
1023 EC_WORD(runpath_elt.dn_ndx),
1024 elfedit_atoconst_value_to_str(
1025 ELFEDIT_CONST_DT, DT_RUNPATH, 1));
1026 return (ELFEDIT_CMDRET_NONE);
1027 }
1028 } else if (argstate->dyn.num_null_ndx <= 1) {
1029 /*
1030 * There is no DT_RPATH or DT_RUNPATH in the dynamic array,
1031 * and there are no extra DT_NULL entries that we can
1032 * convert into one. We cannot proceed.
1033 */
1034 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOEXTRANULL),
1035 EC_WORD(dynsec->sec_shndx), dynsec->sec_name);
1036 }
1037
1038 /* Does the string exist in the table already, or can we add it? */
1039 rpath_elt.dn_dyn.d_un.d_val = runpath_elt.dn_dyn.d_un.d_val =
1040 elfedit_dynstr_insert(dynsec, strsec, &strpad_elt,
1041 argstate->argv[0]);
1042
1043 /* Update DT_RPATH entry if present */
1044 if (rpath_elt.dn_seen) {
1045 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_PREVRPATH),
1046 EC_WORD(dynsec->sec_shndx), dynsec->sec_name,
1047 EC_WORD(rpath_elt.dn_ndx),
1048 elfedit_atoconst_value_to_str(
1049 ELFEDIT_CONST_DT, DT_RPATH, 1),
1050 elfedit_dyn_offset_to_str(strsec, &rpath_elt));
1051 dyn[rpath_elt.dn_ndx] = rpath_elt.dn_dyn;
1052 }
1053
1054 /*
1055 * Update the DT_RUNPATH entry in the dynamic section, if present.
1056 * If one is not present, and there is also no DT_RPATH, then
1057 * we use a spare DT_NULL entry to create a new DT_RUNPATH.
1058 */
1059 if (runpath_elt.dn_seen || !rpath_elt.dn_seen) {
1060 if (runpath_elt.dn_seen) {
1061 elfedit_msg(ELFEDIT_MSG_DEBUG,
1062 MSG_INTL(MSG_DEBUG_PREVRPATH),
1063 EC_WORD(dynsec->sec_shndx), dynsec->sec_name,
1064 EC_WORD(runpath_elt.dn_ndx),
1065 elfedit_atoconst_value_to_str(
1066 ELFEDIT_CONST_DT, DT_RUNPATH, 1),
1067 elfedit_dyn_offset_to_str(strsec, &runpath_elt));
1068 dyn[runpath_elt.dn_ndx] = runpath_elt.dn_dyn;
1069 } else { /* Using a spare DT_NULL entry */
1070 (void) convert_dt_null(argstate, DT_RUNPATH,
1071 runpath_elt.dn_dyn.d_un.d_val);
1072 }
1073 }
1074
1075 return (ELFEDIT_CMDRET_MOD);
1076 }
1077
1078
1079
1080 /*
1081 * Argument processing for the bitmask commands. Convert the arguments
1082 * to integer form, apply -and/-cmp/-or, and return the resulting value.
1083 *
1084 * entry:
1085 * argstate - Argument state block
1086 * orig - Value of original bitmask
1087 * const_type - ELFEDIT_CONST_* value for type of constants
1088 */
1089 static Word
flag_bitop(ARGSTATE * argstate,Word orig,elfedit_const_t const_type)1090 flag_bitop(ARGSTATE *argstate, Word orig, elfedit_const_t const_type)
1091 {
1092 Word flags = 0;
1093 int i;
1094
1095 /* Collect the arguments */
1096 for (i = 0; i < argstate->argc; i++)
1097 flags |= (Word) elfedit_atoconst(argstate->argv[i], const_type);
1098
1099 /* Complement the value? */
1100 if (argstate->optmask & DYN_OPT_F_CMP)
1101 flags = ~flags;
1102
1103 /* Perform any requested bit operations */
1104 if (argstate->optmask & DYN_OPT_F_AND)
1105 flags &= orig;
1106 else if (argstate->optmask & DYN_OPT_F_OR)
1107 flags |= orig;
1108
1109 return (flags);
1110 }
1111
1112
1113
1114 /*
1115 * Common body for the dyn: module commands. These commands
1116 * share a large amount of common behavior, so it is convenient
1117 * to centralize things and use the cmd argument to handle the
1118 * small differences.
1119 *
1120 * entry:
1121 * cmd - One of the DYN_CMD_T_* constants listed above, specifying
1122 * which command to implement.
1123 * obj_state, argc, argv - Standard command arguments
1124 */
1125 static elfedit_cmdret_t
cmd_body(DYN_CMD_T cmd,elfedit_obj_state_t * obj_state,int argc,const char * argv[])1126 cmd_body(DYN_CMD_T cmd, elfedit_obj_state_t *obj_state,
1127 int argc, const char *argv[])
1128 {
1129 ARGSTATE argstate;
1130 Dyn *dyn;
1131 const char *dyn_name;
1132 Word dyn_ndx, dyn_num, null_ndx;
1133 elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE;
1134 PRINT_DYN_T print_type = PRINT_DYN_T_ALL;
1135 Word ndx;
1136 int print_only = 0;
1137 int do_autoprint = 1;
1138
1139 /* Process the optional arguments */
1140 process_args(obj_state, argc, argv, &argstate);
1141
1142 dyn = argstate.dyn.data;
1143 dyn_num = argstate.dyn.num;
1144 dyn_name = argstate.dyn.sec->sec_name;
1145 dyn_ndx = argstate.dyn.sec->sec_shndx;
1146
1147 /* Check number of arguments, gather information */
1148 switch (cmd) {
1149 case DYN_CMD_T_DUMP:
1150 /* dyn:dump can accept an optional index argument */
1151 if (argstate.argc > 1)
1152 elfedit_command_usage();
1153 print_only = 1;
1154 if (argstate.argc == 1)
1155 ndx = arg_to_index(&argstate, argstate.argv[0],
1156 print_only, &print_type);
1157 break;
1158
1159 case DYN_CMD_T_TAG:
1160 print_only = (argstate.argc != 2);
1161 if (argstate.argc > 0) {
1162 if (argstate.argc > 2)
1163 elfedit_command_usage();
1164 ndx = arg_to_index(&argstate, argstate.argv[0],
1165 print_only, &print_type);
1166 }
1167 break;
1168
1169 case DYN_CMD_T_VALUE:
1170 print_only = (argstate.argc != 2);
1171 if (argstate.argc > 2)
1172 elfedit_command_usage();
1173 if (argstate.argc > 0) {
1174 if (print_only) {
1175 ndx = arg_to_index(&argstate, argstate.argv[0],
1176 print_only, &print_type);
1177 } else {
1178 print_type = PRINT_DYN_T_NDX;
1179 }
1180 }
1181 break;
1182
1183 case DYN_CMD_T_DELETE:
1184 if ((argstate.argc < 1) || (argstate.argc > 2))
1185 elfedit_command_usage();
1186 ndx = arg_to_index(&argstate, argstate.argv[0],
1187 0, &print_type);
1188 do_autoprint = 0;
1189 break;
1190
1191 case DYN_CMD_T_MOVE:
1192 if ((argstate.argc < 2) || (argstate.argc > 3))
1193 elfedit_command_usage();
1194 ndx = arg_to_index(&argstate, argstate.argv[0],
1195 0, &print_type);
1196 do_autoprint = 0;
1197 break;
1198
1199 case DYN_CMD_T_RUNPATH:
1200 if (argstate.argc > 1)
1201 elfedit_command_usage();
1202 /*
1203 * dyn:runpath does not accept an explicit index
1204 * argument, so we implicitly only show the DT_RPATH and
1205 * DT_RUNPATH elements.
1206 */
1207 print_type = PRINT_DYN_T_RUNPATH;
1208 print_only = (argstate.argc == 0);
1209 break;
1210
1211 case DYN_CMD_T_POSFLAG1:
1212 print_only = (argstate.argc == 0);
1213 ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
1214 ELFEDIT_CONST_DT, DT_POSFLAG_1, 1),
1215 print_only, &print_type);
1216 break;
1217
1218 case DYN_CMD_T_FLAGS:
1219 print_only = (argstate.argc == 0);
1220 ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
1221 ELFEDIT_CONST_DT, DT_FLAGS, 1),
1222 print_only, &print_type);
1223 break;
1224
1225 case DYN_CMD_T_FLAGS1:
1226 print_only = (argstate.argc == 0);
1227 ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
1228 ELFEDIT_CONST_DT, DT_FLAGS_1, 1),
1229 print_only, &print_type);
1230 break;
1231
1232 case DYN_CMD_T_FEATURE1:
1233 print_only = (argstate.argc == 0);
1234 ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
1235 ELFEDIT_CONST_DT, DT_FEATURE_1, 1),
1236 print_only, &print_type);
1237 break;
1238
1239 case DYN_CMD_T_CHECKSUM:
1240 ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
1241 ELFEDIT_CONST_DT, DT_CHECKSUM, 1),
1242 print_only, &print_type);
1243 break;
1244
1245 case DYN_CMD_T_SUNW_LDMACH:
1246 if (argstate.argc > 1)
1247 elfedit_command_usage();
1248 /* DT_SUNW_LDMACH is an ELFOSABI_SOLARIS feature */
1249 (void) elfedit_test_osabi(argstate.obj_state,
1250 ELFOSABI_SOLARIS, 1);
1251 print_only = (argstate.argc == 0);
1252 ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
1253 ELFEDIT_CONST_DT, DT_SUNW_LDMACH, 1),
1254 print_only, &print_type);
1255 break;
1256
1257 default:
1258 /* Note expected: All commands should have been caught above */
1259 elfedit_command_usage();
1260 break;
1261 }
1262
1263
1264 /* If this is a request to print current values, do it and return */
1265 if (print_only) {
1266 print_dyn(cmd, 0, &argstate, print_type, ndx);
1267 return (ELFEDIT_CMDRET_NONE);
1268 }
1269
1270
1271 switch (cmd) {
1272 /*
1273 * DYN_CMD_T_DUMP can't get here: It is a print-only
1274 * command.
1275 */
1276
1277 case DYN_CMD_T_TAG:
1278 {
1279 Ehdr *ehdr = argstate.obj_state->os_ehdr;
1280 uchar_t osabi = ehdr->e_ident[EI_OSABI];
1281 Half mach = ehdr->e_machine;
1282 Conv_inv_buf_t inv_buf1, inv_buf2;
1283 Xword d_tag = (Xword) elfedit_atoconst(argstate.argv[1],
1284 ELFEDIT_CONST_DT);
1285
1286 if (dyn[ndx].d_tag == d_tag) {
1287 elfedit_msg(ELFEDIT_MSG_DEBUG,
1288 MSG_INTL(MSG_DEBUG_S_OK), dyn_ndx, dyn_name,
1289 EC_WORD(ndx), conv_dyn_tag(d_tag, osabi,
1290 mach, 0, &inv_buf1));
1291 } else {
1292 Xword orig_d_tag = dyn[ndx].d_tag;
1293
1294 ret = ELFEDIT_CMDRET_MOD;
1295 dyn[ndx].d_tag = d_tag;
1296
1297 /*
1298 * Update null termination index. Warn if we
1299 * just clobbered the only DT_NULL termination
1300 * for the array.
1301 */
1302 null_ndx = argstate.dyn.null_ndx;
1303 set_null_ndx(&argstate);
1304 if ((argstate.dyn.null_ndx >=
1305 argstate.dyn.num) &&
1306 (null_ndx != argstate.dyn.null_ndx))
1307 elfedit_msg(ELFEDIT_MSG_DEBUG,
1308 MSG_INTL(MSG_DEBUG_NULLTERM),
1309 dyn_ndx, dyn_name,
1310 EC_WORD(ndx), conv_dyn_tag(d_tag,
1311 osabi, mach, 0, &inv_buf1));
1312
1313 /*
1314 * Warning if
1315 * - Inserting a DT_NULL cuts off following
1316 * non-null elements.
1317 * - Inserting a non-DT_NULL after the
1318 * first null element, will be
1319 * ignored by rtld.
1320 */
1321 if (d_tag == DT_NULL) {
1322 if ((ndx + 1) < null_ndx)
1323 elfedit_msg(ELFEDIT_MSG_DEBUG,
1324 MSG_INTL(MSG_DEBUG_NULCLIP),
1325 dyn_ndx, dyn_name,
1326 EC_WORD(ndx),
1327 conv_dyn_tag(d_tag, osabi,
1328 mach, 0, &inv_buf1));
1329 } else {
1330 if ((ndx + 1) > argstate.dyn.null_ndx)
1331 elfedit_msg(ELFEDIT_MSG_DEBUG,
1332 MSG_INTL(MSG_DEBUG_NULHIDE),
1333 dyn_ndx, dyn_name,
1334 EC_WORD(ndx),
1335 conv_dyn_tag(d_tag, osabi,
1336 mach, 0, &inv_buf1));
1337 }
1338
1339 /* Debug message that we changed it */
1340 elfedit_msg(ELFEDIT_MSG_DEBUG,
1341 MSG_INTL(MSG_DEBUG_S_CHG),
1342 dyn_ndx, dyn_name, EC_WORD(ndx),
1343 conv_dyn_tag(orig_d_tag, osabi, mach, 0,
1344 &inv_buf1),
1345 conv_dyn_tag(d_tag, osabi, mach, 0,
1346 &inv_buf2));
1347 }
1348 }
1349 break;
1350
1351 case DYN_CMD_T_VALUE:
1352 ret = cmd_body_value(&argstate, &ndx);
1353 break;
1354
1355 case DYN_CMD_T_DELETE:
1356 {
1357 Word cnt = (argstate.argc == 1) ? 1 :
1358 (Word) elfedit_atoui_range(argstate.argv[1],
1359 MSG_ORIG(MSG_STR_COUNT), 1, dyn_num - ndx, NULL);
1360 const char *msg_prefix =
1361 elfedit_sec_msgprefix(argstate.dyn.sec);
1362
1363 elfedit_array_elts_delete(msg_prefix, argstate.dyn.data,
1364 sizeof (Dyn), dyn_num, ndx, cnt);
1365 ret = ELFEDIT_CMDRET_MOD;
1366 }
1367 break;
1368
1369 case DYN_CMD_T_MOVE:
1370 {
1371 Dyn save;
1372 Word cnt;
1373 Word dstndx;
1374 const char *msg_prefix =
1375 elfedit_sec_msgprefix(argstate.dyn.sec);
1376
1377 dstndx = (Word)
1378 elfedit_atoui_range(argstate.argv[1],
1379 MSG_ORIG(MSG_STR_DST_INDEX), 0, dyn_num - 1,
1380 NULL);
1381 if (argstate.argc == 2) {
1382 cnt = 1;
1383 } else {
1384 cnt = (Word) elfedit_atoui_range(
1385 argstate.argv[2], MSG_ORIG(MSG_STR_COUNT),
1386 1, dyn_num, NULL);
1387 }
1388 elfedit_array_elts_move(msg_prefix, argstate.dyn.data,
1389 sizeof (save), dyn_num, ndx, dstndx, cnt, &save);
1390 ret = ELFEDIT_CMDRET_MOD;
1391 }
1392 break;
1393
1394
1395 case DYN_CMD_T_RUNPATH:
1396 ret = cmd_body_runpath(&argstate);
1397 break;
1398
1399 case DYN_CMD_T_POSFLAG1:
1400 {
1401 Conv_dyn_posflag1_buf_t buf1, buf2;
1402 Word flags;
1403
1404 flags = flag_bitop(&argstate, dyn[ndx].d_un.d_val,
1405 ELFEDIT_CONST_DF_P1);
1406
1407 /* Set the value */
1408 if (dyn[ndx].d_un.d_val == flags) {
1409 elfedit_msg(ELFEDIT_MSG_DEBUG,
1410 MSG_INTL(MSG_DEBUG_S_OK), dyn_ndx,
1411 dyn_name, EC_WORD(ndx),
1412 conv_dyn_posflag1(dyn[ndx].d_un.d_val, 0,
1413 &buf1));
1414 } else {
1415 elfedit_msg(ELFEDIT_MSG_DEBUG,
1416 MSG_INTL(MSG_DEBUG_S_CHG),
1417 dyn_ndx, dyn_name, EC_WORD(ndx),
1418 conv_dyn_posflag1(dyn[ndx].d_un.d_val, 0,
1419 &buf1),
1420 conv_dyn_posflag1(flags, 0, &buf2));
1421 ret = ELFEDIT_CMDRET_MOD;
1422 dyn[ndx].d_un.d_val = flags;
1423 }
1424 }
1425 break;
1426
1427 case DYN_CMD_T_FLAGS:
1428 {
1429 Conv_dyn_flag_buf_t buf1, buf2;
1430 Word flags;
1431
1432 flags = flag_bitop(&argstate, dyn[ndx].d_un.d_val,
1433 ELFEDIT_CONST_DF);
1434
1435 /* Set the value */
1436 if (dyn[ndx].d_un.d_val == flags) {
1437 elfedit_msg(ELFEDIT_MSG_DEBUG,
1438 MSG_INTL(MSG_DEBUG_S_OK), dyn_ndx,
1439 dyn_name, EC_WORD(ndx),
1440 conv_dyn_flag(dyn[ndx].d_un.d_val, 0,
1441 &buf1));
1442 } else {
1443 elfedit_msg(ELFEDIT_MSG_DEBUG,
1444 MSG_INTL(MSG_DEBUG_S_CHG),
1445 dyn_ndx, dyn_name, EC_WORD(ndx),
1446 conv_dyn_flag(dyn[ndx].d_un.d_val, 0,
1447 &buf1),
1448 conv_dyn_flag(flags, 0, &buf2));
1449 ret = ELFEDIT_CMDRET_MOD;
1450 dyn[ndx].d_un.d_val = flags;
1451 }
1452 }
1453 break;
1454
1455 case DYN_CMD_T_FLAGS1:
1456 {
1457 Conv_dyn_flag1_buf_t buf1, buf2;
1458 Word flags1;
1459
1460 flags1 = flag_bitop(&argstate, dyn[ndx].d_un.d_val,
1461 ELFEDIT_CONST_DF_1);
1462
1463 /* Set the value */
1464 if (dyn[ndx].d_un.d_val == flags1) {
1465 elfedit_msg(ELFEDIT_MSG_DEBUG,
1466 MSG_INTL(MSG_DEBUG_S_OK), dyn_ndx,
1467 dyn_name, EC_WORD(ndx),
1468 conv_dyn_flag1(dyn[ndx].d_un.d_val,
1469 0, &buf1));
1470 } else {
1471 elfedit_msg(ELFEDIT_MSG_DEBUG,
1472 MSG_INTL(MSG_DEBUG_S_CHG),
1473 dyn_ndx, dyn_name, EC_WORD(ndx),
1474 conv_dyn_flag1(dyn[ndx].d_un.d_val,
1475 0, &buf1),
1476 conv_dyn_flag1(flags1, 0, &buf2));
1477 ret = ELFEDIT_CMDRET_MOD;
1478 dyn[ndx].d_un.d_val = flags1;
1479 }
1480 }
1481 break;
1482
1483 case DYN_CMD_T_FEATURE1:
1484 {
1485 Conv_dyn_feature1_buf_t buf1, buf2;
1486 Word flags;
1487
1488 flags = flag_bitop(&argstate, dyn[ndx].d_un.d_val,
1489 ELFEDIT_CONST_DTF_1);
1490
1491 /* Set the value */
1492 if (dyn[ndx].d_un.d_val == flags) {
1493 elfedit_msg(ELFEDIT_MSG_DEBUG,
1494 MSG_INTL(MSG_DEBUG_S_OK), dyn_ndx,
1495 dyn_name, EC_WORD(ndx),
1496 conv_dyn_feature1(dyn[ndx].d_un.d_val, 0,
1497 &buf1));
1498 } else {
1499 elfedit_msg(ELFEDIT_MSG_DEBUG,
1500 MSG_INTL(MSG_DEBUG_S_CHG),
1501 dyn_ndx, dyn_name, EC_WORD(ndx),
1502 conv_dyn_feature1(dyn[ndx].d_un.d_val, 0,
1503 &buf1),
1504 conv_dyn_feature1(flags, 0, &buf2));
1505 ret = ELFEDIT_CMDRET_MOD;
1506 dyn[ndx].d_un.d_val = flags;
1507 }
1508 }
1509 break;
1510
1511 case DYN_CMD_T_CHECKSUM:
1512 {
1513 long checksum = elf_checksum(obj_state->os_elf);
1514
1515 /* Set the value */
1516 if (dyn[ndx].d_un.d_val == checksum) {
1517 elfedit_msg(ELFEDIT_MSG_DEBUG,
1518 MSG_INTL(MSG_DEBUG_X_OK), dyn_ndx,
1519 dyn_name, EC_WORD(ndx), EC_XWORD(checksum));
1520 } else {
1521 elfedit_msg(ELFEDIT_MSG_DEBUG,
1522 MSG_INTL(MSG_DEBUG_X_CHG),
1523 dyn_ndx, dyn_name, EC_WORD(ndx),
1524 EC_XWORD(dyn[ndx].d_un.d_val),
1525 EC_XWORD(checksum));
1526 ret = ELFEDIT_CMDRET_MOD;
1527 dyn[ndx].d_un.d_val = checksum;
1528 }
1529
1530 }
1531 break;
1532
1533 case DYN_CMD_T_SUNW_LDMACH:
1534 {
1535 Conv_inv_buf_t buf1, buf2;
1536 Half ldmach;
1537
1538 ldmach = (Half) elfedit_atoconst(argstate.argv[0],
1539 ELFEDIT_CONST_EM);
1540
1541 /* Set the value */
1542 if (dyn[ndx].d_un.d_val == ldmach) {
1543 elfedit_msg(ELFEDIT_MSG_DEBUG,
1544 MSG_INTL(MSG_DEBUG_S_OK), dyn_ndx,
1545 dyn_name, EC_WORD(ndx),
1546 conv_ehdr_mach(dyn[ndx].d_un.d_val, 0,
1547 &buf1));
1548 } else {
1549 elfedit_msg(ELFEDIT_MSG_DEBUG,
1550 MSG_INTL(MSG_DEBUG_S_CHG),
1551 dyn_ndx, dyn_name, EC_WORD(ndx),
1552 conv_ehdr_mach(dyn[ndx].d_un.d_val, 0,
1553 &buf1),
1554 conv_ehdr_mach(ldmach, 0, &buf2));
1555 ret = ELFEDIT_CMDRET_MOD;
1556 dyn[ndx].d_un.d_val = ldmach;
1557 }
1558 }
1559 break;
1560
1561 }
1562
1563 /*
1564 * If we modified the dynamic section header, tell libelf.
1565 */
1566 if (ret == ELFEDIT_CMDRET_MOD)
1567 elfedit_modified_data(argstate.dyn.sec);
1568
1569 /* Do autoprint */
1570 if (do_autoprint)
1571 print_dyn(cmd, 1, &argstate, print_type, ndx);
1572
1573 return (ret);
1574 }
1575
1576
1577
1578 /*
1579 * Command completion functions for the commands
1580 */
1581
1582 /*
1583 * Command completion for the first argument, which specifies
1584 * the dynamic element to use. Examines the options to see if
1585 * -dynndx is present, and if not, supplies the completion
1586 * strings for argument 1.
1587 */
1588 /*ARGSUSED*/
1589 static void
cpl_eltarg(elfedit_obj_state_t * obj_state,void * cpldata,int argc,const char * argv[],int num_opt)1590 cpl_eltarg(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1591 const char *argv[], int num_opt)
1592 {
1593 elfedit_section_t *cache;
1594 Dyn *dyn;
1595 Word i;
1596 const char *s;
1597 char *s2;
1598 char buf[128];
1599
1600 /* Make sure it's the first argument */
1601 if ((argc - num_opt) != 1)
1602 return;
1603
1604 /* Is -dynndx present? If so, we don't complete tag types */
1605 for (i = 0; i < num_opt; i++)
1606 if (strcmp(argv[i], MSG_ORIG(MSG_STR_MINUS_DYNNDX)) == 0)
1607 return;
1608
1609 /*
1610 * If there is no object, or if there is no dynamic section,
1611 * then supply all possible names.
1612 */
1613 if ((obj_state == NULL) || (obj_state->os_dynndx == SHN_UNDEF)) {
1614 elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DT);
1615 return;
1616 }
1617
1618 /* Supply completions for the tags present in the dynamic section */
1619 cache = &obj_state->os_secarr[obj_state->os_dynndx];
1620 dyn = (Dyn *) cache->sec_data->d_buf;
1621 i = cache->sec_shdr->sh_size / cache->sec_shdr->sh_entsize;
1622 for (; i-- > 0; dyn++) {
1623 s = elfedit_atoconst_value_to_str(ELFEDIT_CONST_DT,
1624 dyn->d_tag, 0);
1625 if (s == NULL)
1626 continue;
1627 elfedit_cpl_match(cpldata, s, 1);
1628
1629 /*
1630 * To get the informal tag names that are lowercase
1631 * and lack the leading DT_, we copy the string we
1632 * have into a buffer and process it.
1633 */
1634 if (strlen(s) < 3)
1635 continue;
1636 (void) strlcpy(buf, s + 3, sizeof (buf));
1637 for (s2 = buf; *s2 != '\0'; s2++)
1638 if (isupper(*s2))
1639 *s2 = tolower(*s2);
1640 elfedit_cpl_match(cpldata, buf, 1);
1641 }
1642 }
1643
1644
1645 /*ARGSUSED*/
1646 static void
cpl_tag(elfedit_obj_state_t * obj_state,void * cpldata,int argc,const char * argv[],int num_opt)1647 cpl_tag(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1648 const char *argv[], int num_opt)
1649 {
1650 /* First argument */
1651 if ((argc - num_opt) == 1) {
1652 cpl_eltarg(obj_state, cpldata, argc, argv, num_opt);
1653 return;
1654 }
1655
1656 /* The second argument is always a tag value */
1657 if ((argc - num_opt) == 2)
1658 elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DT);
1659 }
1660
1661 /*ARGSUSED*/
1662 static void
cpl_posflag1(elfedit_obj_state_t * obj_state,void * cpldata,int argc,const char * argv[],int num_opt)1663 cpl_posflag1(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1664 const char *argv[], int num_opt)
1665 {
1666 /*
1667 * dyn:posflag1 accepts two mutually exclusive options that have
1668 * a corresponding value argument: -dynndx and -needed. If we
1669 * are being called to supply options for the value, handle that here.
1670 */
1671 if ((num_opt > 1) && (argc == num_opt)) {
1672 elfedit_section_t *dynsec, *strsec;
1673 const char *opt = argv[num_opt - 2];
1674 dyn_opt_t type;
1675 Dyn *dyn;
1676 Word i, num;
1677
1678 /*
1679 * If there is no object available, or if the object has no
1680 * dynamic section, then there is nothing to report.
1681 */
1682 if ((obj_state == NULL) || obj_state->os_dynndx == SHN_UNDEF)
1683 return;
1684
1685 /*
1686 * Determine which option it is, bail if it isn't one of
1687 * the ones we are concerned with.
1688 */
1689 if ((strcmp(opt, MSG_ORIG(MSG_STR_MINUS_NEEDED)) == 0))
1690 type = DYN_OPT_F_NEEDED;
1691 else if ((strcmp(opt, MSG_ORIG(MSG_STR_MINUS_DYNNDX)) == 0))
1692 type = DYN_OPT_F_DYNNDX_VAL;
1693 else
1694 return;
1695
1696 dynsec = elfedit_sec_getdyn(obj_state, &dyn, &num);
1697 switch (type) {
1698 case DYN_OPT_F_NEEDED:
1699 strsec = elfedit_sec_getstr(obj_state,
1700 dynsec->sec_shdr->sh_link, 0);
1701 for (; num-- > 0; dyn++)
1702 if (dyn->d_tag == DT_NEEDED)
1703 elfedit_cpl_match(cpldata,
1704 elfedit_offset_to_str(strsec,
1705 dyn->d_un.d_val, ELFEDIT_MSG_DEBUG,
1706 0), 0);
1707 break;
1708
1709 case DYN_OPT_F_DYNNDX_VAL:
1710 for (i = 0; i < num; i++, dyn++)
1711 if (dyn->d_tag == DT_POSFLAG_1)
1712 elfedit_cpl_ndx(cpldata, i);
1713 break;
1714 }
1715 return;
1716 }
1717
1718 /* This routine allows multiple flags to be specified */
1719 elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DF_P1);
1720 }
1721
1722 /*ARGSUSED*/
1723 static void
cpl_flags(elfedit_obj_state_t * obj_state,void * cpldata,int argc,const char * argv[],int num_opt)1724 cpl_flags(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1725 const char *argv[], int num_opt)
1726 {
1727 /* This routine allows multiple flags to be specified */
1728 elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DF);
1729 }
1730
1731 /*ARGSUSED*/
1732 static void
cpl_flags1(elfedit_obj_state_t * obj_state,void * cpldata,int argc,const char * argv[],int num_opt)1733 cpl_flags1(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1734 const char *argv[], int num_opt)
1735 {
1736 /* This routine allows multiple flags to be specified */
1737 elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DF_1);
1738 }
1739
1740 /*ARGSUSED*/
1741 static void
cpl_feature1(elfedit_obj_state_t * obj_state,void * cpldata,int argc,const char * argv[],int num_opt)1742 cpl_feature1(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1743 const char *argv[], int num_opt)
1744 {
1745 /* This routine allows multiple flags to be specified */
1746 elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DTF_1);
1747 }
1748
1749 /*ARGSUSED*/
1750 static void
cpl_sunw_ldmach(elfedit_obj_state_t * obj_state,void * cpldata,int argc,const char * argv[],int num_opt)1751 cpl_sunw_ldmach(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1752 const char *argv[], int num_opt)
1753 {
1754 /*
1755 * This command doesn't accept options, so num_opt should be
1756 * 0. This is a defensive measure, in case that should change.
1757 */
1758 argc -= num_opt;
1759 argv += num_opt;
1760
1761 if (argc == 1)
1762 elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_EM);
1763 }
1764
1765
1766 /*
1767 * Implementation functions for the commands
1768 */
1769 static elfedit_cmdret_t
cmd_dump(elfedit_obj_state_t * obj_state,int argc,const char * argv[])1770 cmd_dump(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1771 {
1772 return (cmd_body(DYN_CMD_T_DUMP, obj_state, argc, argv));
1773 }
1774
1775 static elfedit_cmdret_t
cmd_tag(elfedit_obj_state_t * obj_state,int argc,const char * argv[])1776 cmd_tag(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1777 {
1778 return (cmd_body(DYN_CMD_T_TAG, obj_state, argc, argv));
1779 }
1780
1781 static elfedit_cmdret_t
cmd_value(elfedit_obj_state_t * obj_state,int argc,const char * argv[])1782 cmd_value(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1783 {
1784 return (cmd_body(DYN_CMD_T_VALUE, obj_state, argc, argv));
1785 }
1786
1787 static elfedit_cmdret_t
cmd_delete(elfedit_obj_state_t * obj_state,int argc,const char * argv[])1788 cmd_delete(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1789 {
1790 return (cmd_body(DYN_CMD_T_DELETE, obj_state, argc, argv));
1791 }
1792
1793 static elfedit_cmdret_t
cmd_move(elfedit_obj_state_t * obj_state,int argc,const char * argv[])1794 cmd_move(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1795 {
1796 return (cmd_body(DYN_CMD_T_MOVE, obj_state, argc, argv));
1797 }
1798
1799 static elfedit_cmdret_t
cmd_runpath(elfedit_obj_state_t * obj_state,int argc,const char * argv[])1800 cmd_runpath(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1801 {
1802 return (cmd_body(DYN_CMD_T_RUNPATH, obj_state, argc, argv));
1803 }
1804
1805 static elfedit_cmdret_t
cmd_posflag1(elfedit_obj_state_t * obj_state,int argc,const char * argv[])1806 cmd_posflag1(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1807 {
1808 return (cmd_body(DYN_CMD_T_POSFLAG1, obj_state, argc, argv));
1809 }
1810
1811 static elfedit_cmdret_t
cmd_flags(elfedit_obj_state_t * obj_state,int argc,const char * argv[])1812 cmd_flags(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1813 {
1814 return (cmd_body(DYN_CMD_T_FLAGS, obj_state, argc, argv));
1815 }
1816
1817 static elfedit_cmdret_t
cmd_flags1(elfedit_obj_state_t * obj_state,int argc,const char * argv[])1818 cmd_flags1(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1819 {
1820 return (cmd_body(DYN_CMD_T_FLAGS1, obj_state, argc, argv));
1821 }
1822
1823 static elfedit_cmdret_t
cmd_feature1(elfedit_obj_state_t * obj_state,int argc,const char * argv[])1824 cmd_feature1(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1825 {
1826 return (cmd_body(DYN_CMD_T_FEATURE1, obj_state, argc, argv));
1827 }
1828
1829 static elfedit_cmdret_t
cmd_checksum(elfedit_obj_state_t * obj_state,int argc,const char * argv[])1830 cmd_checksum(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1831 {
1832 return (cmd_body(DYN_CMD_T_CHECKSUM, obj_state, argc, argv));
1833 }
1834
1835 static elfedit_cmdret_t
cmd_sunw_ldmach(elfedit_obj_state_t * obj_state,int argc,const char * argv[])1836 cmd_sunw_ldmach(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1837 {
1838 return (cmd_body(DYN_CMD_T_SUNW_LDMACH, obj_state, argc, argv));
1839 }
1840
1841
1842
1843 /*ARGSUSED*/
1844 elfedit_module_t *
elfedit_init(elfedit_module_version_t version)1845 elfedit_init(elfedit_module_version_t version)
1846 {
1847 /* For commands that only accept -o */
1848 static elfedit_cmd_optarg_t opt_ostyle[] = {
1849 { ELFEDIT_STDOA_OPT_O, NULL,
1850 ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
1851 { NULL }
1852 };
1853
1854 /* For commands that only accept -and, -cmp, -o, -or */
1855 static elfedit_cmd_optarg_t opt_ostyle_bitop[] = {
1856 { ELFEDIT_STDOA_OPT_AND, NULL,
1857 ELFEDIT_CMDOA_F_INHERIT, DYN_OPT_F_AND, DYN_OPT_F_OR },
1858 { ELFEDIT_STDOA_OPT_CMP, NULL,
1859 ELFEDIT_CMDOA_F_INHERIT, DYN_OPT_F_CMP, 0 },
1860 { ELFEDIT_STDOA_OPT_O, NULL,
1861 ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
1862 { ELFEDIT_STDOA_OPT_OR, NULL,
1863 ELFEDIT_CMDOA_F_INHERIT, DYN_OPT_F_OR, DYN_OPT_F_AND },
1864 { NULL }
1865 };
1866
1867 /* For commands that only accept -dynndx */
1868 static elfedit_cmd_optarg_t opt_minus_dynndx[] = {
1869 { MSG_ORIG(MSG_STR_MINUS_DYNNDX),
1870 /* MSG_INTL(MSG_OPTDESC_DYNNDX_ELT) */
1871 ELFEDIT_I18NHDL(MSG_OPTDESC_DYNNDX_ELT), 0,
1872 DYN_OPT_F_DYNNDX_ELT, 0 },
1873 { NULL }
1874 };
1875
1876 /* dyn:dump */
1877 static const char *name_dump[] = {
1878 MSG_ORIG(MSG_CMD_DUMP),
1879 MSG_ORIG(MSG_STR_EMPTY), /* "" makes this the default command */
1880 NULL
1881 };
1882 static elfedit_cmd_optarg_t arg_dump[] = {
1883 { MSG_ORIG(MSG_STR_ELT),
1884 /* MSG_INTL(MSG_ARGDESC_ELT) */
1885 ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
1886 ELFEDIT_CMDOA_F_OPT },
1887 { NULL }
1888 };
1889
1890
1891 /* dyn:tag */
1892 static const char *name_tag[] = { MSG_ORIG(MSG_CMD_TAG), NULL };
1893 static elfedit_cmd_optarg_t opt_tag[] = {
1894 { MSG_ORIG(MSG_STR_MINUS_DYNNDX),
1895 /* MSG_INTL(MSG_OPTDESC_DYNNDX_ELT) */
1896 ELFEDIT_I18NHDL(MSG_OPTDESC_DYNNDX_ELT), 0,
1897 DYN_OPT_F_DYNNDX_ELT, 0 },
1898 { ELFEDIT_STDOA_OPT_O, NULL,
1899 ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
1900 { NULL }
1901 };
1902 static elfedit_cmd_optarg_t arg_tag[] = {
1903 { MSG_ORIG(MSG_STR_ELT),
1904 /* MSG_INTL(MSG_A1_TAG_ELT) */
1905 ELFEDIT_I18NHDL(MSG_A1_TAG_ELT),
1906 ELFEDIT_CMDOA_F_OPT },
1907 { MSG_ORIG(MSG_STR_VALUE),
1908 /* MSG_INTL(MSG_A2_TAG_VALUE) */
1909 ELFEDIT_I18NHDL(MSG_A2_TAG_VALUE),
1910 ELFEDIT_CMDOA_F_OPT },
1911 { NULL }
1912 };
1913
1914
1915 /* dyn:value */
1916 static const char *name_value[] = { MSG_ORIG(MSG_CMD_VALUE), NULL };
1917 static elfedit_cmd_optarg_t opt_value[] = {
1918 { MSG_ORIG(MSG_STR_MINUS_ADD),
1919 /* MSG_INTL(MSG_OPTDESC_ADD) */
1920 ELFEDIT_I18NHDL(MSG_OPTDESC_ADD), 0,
1921 DYN_OPT_F_ADD, DYN_OPT_F_DYNNDX_ELT },
1922 { MSG_ORIG(MSG_STR_MINUS_DYNNDX),
1923 /* MSG_INTL(MSG_OPTDESC_DYNNDX_ELT) */
1924 ELFEDIT_I18NHDL(MSG_OPTDESC_DYNNDX_ELT), 0,
1925 DYN_OPT_F_DYNNDX_ELT, DYN_OPT_F_ADD },
1926 { ELFEDIT_STDOA_OPT_O, NULL,
1927 ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
1928 { MSG_ORIG(MSG_STR_MINUS_S),
1929 /* MSG_INTL(MSG_OPTDESC_S) */
1930 ELFEDIT_I18NHDL(MSG_OPTDESC_S), 0,
1931 DYN_OPT_F_STRVAL, 0 },
1932 { NULL }
1933 };
1934 static elfedit_cmd_optarg_t arg_value[] = {
1935 { MSG_ORIG(MSG_STR_ELT),
1936 /* MSG_INTL(MSG_ARGDESC_ELT) */
1937 ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
1938 ELFEDIT_CMDOA_F_OPT },
1939 { MSG_ORIG(MSG_STR_VALUE),
1940 /* MSG_INTL(MSG_A2_VALUE_VALUE) */
1941 ELFEDIT_I18NHDL(MSG_A2_VALUE_VALUE),
1942 ELFEDIT_CMDOA_F_OPT },
1943 { NULL }
1944 };
1945
1946 /* dyn:delete */
1947 static const char *name_delete[] = { MSG_ORIG(MSG_CMD_DELETE), NULL };
1948 static elfedit_cmd_optarg_t arg_delete[] = {
1949 { MSG_ORIG(MSG_STR_ELT),
1950 /* MSG_INTL(MSG_ARGDESC_ELT) */
1951 ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
1952 0 },
1953 { MSG_ORIG(MSG_STR_COUNT),
1954 /* MSG_INTL(MSG_A2_DELETE_COUNT) */
1955 ELFEDIT_I18NHDL(MSG_A2_DELETE_COUNT),
1956 ELFEDIT_CMDOA_F_OPT },
1957 { NULL }
1958 };
1959
1960 /* dyn:move */
1961 static const char *name_move[] = { MSG_ORIG(MSG_CMD_MOVE), NULL };
1962 static elfedit_cmd_optarg_t arg_move[] = {
1963 { MSG_ORIG(MSG_STR_ELT),
1964 /* MSG_INTL(MSG_ARGDESC_ELT) */
1965 ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
1966 0 },
1967 { MSG_ORIG(MSG_STR_DST_INDEX),
1968 /* MSG_INTL(MSG_A2_MOVE_DST_INDEX) */
1969 ELFEDIT_I18NHDL(MSG_A2_MOVE_DST_INDEX),
1970 0 },
1971 { MSG_ORIG(MSG_STR_COUNT),
1972 /* MSG_INTL(MSG_A3_MOVE_COUNT) */
1973 ELFEDIT_I18NHDL(MSG_A3_MOVE_COUNT),
1974 ELFEDIT_CMDOA_F_OPT },
1975 { NULL }
1976 };
1977
1978 /* dyn:runpath / dyn:rpath */
1979 static const char *name_runpath[] = { MSG_ORIG(MSG_CMD_RUNPATH),
1980 MSG_ORIG(MSG_CMD_RUNPATH_A1), NULL };
1981 static elfedit_cmd_optarg_t arg_runpath[] = {
1982 { MSG_ORIG(MSG_STR_NEWPATH),
1983 /* MSG_INTL(MSG_A1_RUNPATH_NEWPATH) */
1984 ELFEDIT_I18NHDL(MSG_A1_RUNPATH_NEWPATH),
1985 ELFEDIT_CMDOA_F_OPT },
1986 { NULL }
1987 };
1988
1989 /* dyn:posflag1 */
1990 static const char *name_posflag1[] = { MSG_ORIG(MSG_CMD_POSFLAG1),
1991 NULL };
1992 static elfedit_cmd_optarg_t opt_posflag1[] = {
1993 { ELFEDIT_STDOA_OPT_AND, NULL,
1994 ELFEDIT_CMDOA_F_INHERIT, DYN_OPT_F_AND, DYN_OPT_F_OR },
1995 { ELFEDIT_STDOA_OPT_CMP, NULL,
1996 ELFEDIT_CMDOA_F_INHERIT, DYN_OPT_F_CMP, 0 },
1997 { MSG_ORIG(MSG_STR_MINUS_DYNNDX),
1998 /* MSG_INTL(MSG_OPTDESC_DYNNDX_VAL) */
1999 ELFEDIT_I18NHDL(MSG_OPTDESC_DYNNDX_VAL),
2000 ELFEDIT_CMDOA_F_VALUE,
2001 DYN_OPT_F_DYNNDX_VAL, DYN_OPT_F_NEEDED },
2002 { MSG_ORIG(MSG_STR_INDEX), NULL, 0, 0 },
2003 { MSG_ORIG(MSG_STR_MINUS_NEEDED),
2004 /* MSG_INTL(MSG_OPTDESC_NEEDED) */
2005 ELFEDIT_I18NHDL(MSG_OPTDESC_NEEDED),
2006 ELFEDIT_CMDOA_F_VALUE,
2007 DYN_OPT_F_NEEDED, DYN_OPT_F_DYNNDX_VAL },
2008 { MSG_ORIG(MSG_STR_PREFIX), NULL, 0, 0 },
2009 { ELFEDIT_STDOA_OPT_O, NULL,
2010 ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
2011 { ELFEDIT_STDOA_OPT_OR, NULL,
2012 ELFEDIT_CMDOA_F_INHERIT, DYN_OPT_F_OR, DYN_OPT_F_AND },
2013 { NULL }
2014 };
2015 static elfedit_cmd_optarg_t arg_posflag1[] = {
2016 { MSG_ORIG(MSG_STR_VALUE),
2017 /* MSG_INTL(MSG_A1_POSFLAG1_VALUE) */
2018 ELFEDIT_I18NHDL(MSG_A1_POSFLAG1_VALUE),
2019 ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
2020 { NULL }
2021 };
2022
2023 /* dyn:flags */
2024 static const char *name_flags[] = { MSG_ORIG(MSG_CMD_FLAGS), NULL };
2025 static elfedit_cmd_optarg_t arg_flags[] = {
2026 { MSG_ORIG(MSG_STR_VALUE),
2027 /* MSG_INTL(MSG_A1_FLAGS_VALUE) */
2028 ELFEDIT_I18NHDL(MSG_A1_FLAGS_VALUE),
2029 ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
2030 { NULL }
2031 };
2032
2033 /* dyn:flags1 */
2034 static const char *name_flags1[] = { MSG_ORIG(MSG_CMD_FLAGS1), NULL };
2035 static elfedit_cmd_optarg_t arg_flags1[] = {
2036 { MSG_ORIG(MSG_STR_VALUE),
2037 /* MSG_INTL(MSG_A1_FLAGS1_VALUE) */
2038 ELFEDIT_I18NHDL(MSG_A1_FLAGS1_VALUE),
2039 ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
2040 { NULL }
2041 };
2042
2043 /* dyn:feature1 */
2044 static const char *name_feature1[] = { MSG_ORIG(MSG_CMD_FEATURE1),
2045 NULL };
2046 static elfedit_cmd_optarg_t arg_feature1[] = {
2047 { MSG_ORIG(MSG_STR_VALUE),
2048 /* MSG_INTL(MSG_A1_FEATURE1_VALUE) */
2049 ELFEDIT_I18NHDL(MSG_A1_FEATURE1_VALUE),
2050 ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
2051 { NULL }
2052 };
2053
2054 /* dyn:checksum */
2055 static const char *name_checksum[] = { MSG_ORIG(MSG_CMD_CHECKSUM),
2056 NULL };
2057
2058 /* dyn:sunw_ldmach */
2059 static const char *name_sunw_ldmach[] = { MSG_ORIG(MSG_CMD_SUNW_LDMACH),
2060 NULL };
2061 static elfedit_cmd_optarg_t arg_sunw_ldmach[] = {
2062 { MSG_ORIG(MSG_STR_VALUE),
2063 /* MSG_INTL(MSG_A1_SUNW_LDMACH_VALUE) */
2064 ELFEDIT_I18NHDL(MSG_A1_SUNW_LDMACH_VALUE),
2065 ELFEDIT_CMDOA_F_OPT },
2066 { NULL }
2067 };
2068
2069
2070
2071 static elfedit_cmd_t cmds[] = {
2072 /* dyn:dump */
2073 { cmd_dump, cpl_eltarg, name_dump,
2074 /* MSG_INTL(MSG_DESC_DUMP) */
2075 ELFEDIT_I18NHDL(MSG_DESC_DUMP),
2076 /* MSG_INTL(MSG_HELP_DUMP) */
2077 ELFEDIT_I18NHDL(MSG_HELP_DUMP),
2078 opt_minus_dynndx, arg_dump },
2079
2080 /* dyn:tag */
2081 { cmd_tag, cpl_tag, name_tag,
2082 /* MSG_INTL(MSG_DESC_TAG) */
2083 ELFEDIT_I18NHDL(MSG_DESC_TAG),
2084 /* MSG_INTL(MSG_HELP_TAG) */
2085 ELFEDIT_I18NHDL(MSG_HELP_TAG),
2086 opt_tag, arg_tag },
2087
2088 /* dyn:value */
2089 { cmd_value, cpl_eltarg, name_value,
2090 /* MSG_INTL(MSG_DESC_VALUE) */
2091 ELFEDIT_I18NHDL(MSG_DESC_VALUE),
2092 /* MSG_INTL(MSG_HELP_VALUE) */
2093 ELFEDIT_I18NHDL(MSG_HELP_VALUE),
2094 opt_value, arg_value },
2095
2096 /* dyn:delete */
2097 { cmd_delete, cpl_eltarg, name_delete,
2098 /* MSG_INTL(MSG_DESC_DELETE) */
2099 ELFEDIT_I18NHDL(MSG_DESC_DELETE),
2100 /* MSG_INTL(MSG_HELP_DELETE) */
2101 ELFEDIT_I18NHDL(MSG_HELP_DELETE),
2102 opt_minus_dynndx, arg_delete },
2103
2104 /* dyn:move */
2105 { cmd_move, cpl_eltarg, name_move,
2106 /* MSG_INTL(MSG_DESC_MOVE) */
2107 ELFEDIT_I18NHDL(MSG_DESC_MOVE),
2108 /* MSG_INTL(MSG_HELP_MOVE) */
2109 ELFEDIT_I18NHDL(MSG_HELP_MOVE),
2110 opt_minus_dynndx, arg_move },
2111
2112 /* dyn:runpath */
2113 { cmd_runpath, NULL, name_runpath,
2114 /* MSG_INTL(MSG_DESC_RUNPATH) */
2115 ELFEDIT_I18NHDL(MSG_DESC_RUNPATH),
2116 /* MSG_INTL(MSG_HELP_RUNPATH) */
2117 ELFEDIT_I18NHDL(MSG_HELP_RUNPATH),
2118 opt_ostyle, arg_runpath },
2119
2120 /* dyn:posflag1 */
2121 { cmd_posflag1, cpl_posflag1, name_posflag1,
2122 /* MSG_INTL(MSG_DESC_POSFLAG1) */
2123 ELFEDIT_I18NHDL(MSG_DESC_POSFLAG1),
2124 /* MSG_INTL(MSG_HELP_POSFLAG1) */
2125 ELFEDIT_I18NHDL(MSG_HELP_POSFLAG1),
2126 opt_posflag1, arg_posflag1 },
2127
2128 /* dyn:flags */
2129 { cmd_flags, cpl_flags, name_flags,
2130 /* MSG_INTL(MSG_DESC_FLAGS) */
2131 ELFEDIT_I18NHDL(MSG_DESC_FLAGS),
2132 /* MSG_INTL(MSG_HELP_FLAGS) */
2133 ELFEDIT_I18NHDL(MSG_HELP_FLAGS),
2134 opt_ostyle_bitop, arg_flags },
2135
2136 /* dyn:flags1 */
2137 { cmd_flags1, cpl_flags1, name_flags1,
2138 /* MSG_INTL(MSG_DESC_FLAGS1) */
2139 ELFEDIT_I18NHDL(MSG_DESC_FLAGS1),
2140 /* MSG_INTL(MSG_HELP_FLAGS1) */
2141 ELFEDIT_I18NHDL(MSG_HELP_FLAGS1),
2142 opt_ostyle_bitop, arg_flags1 },
2143
2144 /* dyn:feature1 */
2145 { cmd_feature1, cpl_feature1, name_feature1,
2146 /* MSG_INTL(MSG_DESC_FEATURE1) */
2147 ELFEDIT_I18NHDL(MSG_DESC_FEATURE1),
2148 /* MSG_INTL(MSG_HELP_FEATURE1) */
2149 ELFEDIT_I18NHDL(MSG_HELP_FEATURE1),
2150 opt_ostyle_bitop, arg_feature1 },
2151
2152 /* dyn:checksum */
2153 { cmd_checksum, NULL, name_checksum,
2154 /* MSG_INTL(MSG_DESC_CHECKSUM) */
2155 ELFEDIT_I18NHDL(MSG_DESC_CHECKSUM),
2156 /* MSG_INTL(MSG_HELP_CHECKSUM) */
2157 ELFEDIT_I18NHDL(MSG_HELP_CHECKSUM),
2158 NULL, NULL },
2159
2160 /* dyn:sunw_ldmach */
2161 { cmd_sunw_ldmach, cpl_sunw_ldmach, name_sunw_ldmach,
2162 /* MSG_INTL(MSG_DESC_SUNW_LDMACH) */
2163 ELFEDIT_I18NHDL(MSG_DESC_SUNW_LDMACH),
2164 /* MSG_INTL(MSG_HELP_SUNW_LDMACH) */
2165 ELFEDIT_I18NHDL(MSG_HELP_SUNW_LDMACH),
2166 opt_ostyle, arg_sunw_ldmach },
2167
2168 { NULL }
2169 };
2170
2171 static elfedit_module_t module = {
2172 ELFEDIT_VER_CURRENT, MSG_ORIG(MSG_MOD_NAME),
2173 /* MSG_INTL(MSG_MOD_DESC) */
2174 ELFEDIT_I18NHDL(MSG_MOD_DESC), cmds, mod_i18nhdl_to_str };
2175
2176 return (&module);
2177 }
2178