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 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <unistd.h>
31 #include <libintl.h>
32 #include <libelf.h>
33 #include <sys/machelf.h>
34 #include <link.h>
35 #include <strings.h>
36 #include <ctype.h>
37 #include <elfedit.h>
38 #include <_elfedit.h>
39 #include <sys/elf_SPARC.h>
40 #include <sys/elf_amd64.h>
41 #include <msg.h>
42
43
44
45 /*
46 * This file contains utility functions that are of general use
47 * to different elfedit modules for solving common problems.
48 * The functions in this file are not ELFCLASS specific. Those
49 * functions are found in util_machelf.c
50 *
51 * NOTE: This module contains functions with names
52 * elfedit_atoi, and elfedit_atoui, that are otherwise identical.
53 * These functions are for signed, and unsigned integers, respectively.
54 * In general, I supply one comment header for each such pair,
55 * and put their implementations together.
56 *
57 * There are also functions with names elfedit_atoconst. These are
58 * convenience wrappers that use the corresponding elfedit_atoui()
59 * function to process an array of symbolic names provided by a call
60 * elfedit_const_to_atoui().
61 */
62
63
64
65
66 /*
67 * Given a value and an array of elfedit_ato[u]i items, return a pointer
68 * to the symbolic name for the value.
69 *
70 * entry:
71 * sym - NULL terminated array of name->value mappings.
72 * value - Value to be found
73 * required - If True, and value is not found, an error is issued.
74 * Callers should only set required to True when they know
75 * a priori that the value will be found --- the error
76 * is reported as an internal programming error.
77 *
78 * exit:
79 * If the array contains an entry with the given value, the
80 * name for the first such entry will be returned.
81 *
82 * If no entry is found: If required is True (1), an error is
83 * issued and this routine does not return to the caller. If required
84 * is False (0), then NULL is returned.
85 */
86 const char *
elfedit_atoi_value_to_str(const elfedit_atoi_sym_t * sym,elfedit_atoi_t value,int required)87 elfedit_atoi_value_to_str(const elfedit_atoi_sym_t *sym, elfedit_atoi_t value,
88 int required)
89 {
90 for (; sym->sym_name != NULL; sym++)
91 if (value == sym->sym_value)
92 return (sym->sym_name);
93
94 /* Value did not match any of the entries */
95 if (required)
96 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADGETVAL));
97 return (NULL);
98 }
99 const char *
elfedit_atoui_value_to_str(const elfedit_atoui_sym_t * sym,elfedit_atoui_t value,int required)100 elfedit_atoui_value_to_str(const elfedit_atoui_sym_t *sym,
101 elfedit_atoui_t value, int required)
102 {
103 for (; sym->sym_name != NULL; sym++)
104 if (value == sym->sym_value)
105 return (sym->sym_name);
106
107 /* Value did not match any of the entries */
108 if (required)
109 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADGETVAL));
110 return (NULL);
111 }
112 const char *
elfedit_atoconst_value_to_str(elfedit_const_t const_type,elfedit_atoui_t value,int required)113 elfedit_atoconst_value_to_str(elfedit_const_t const_type, elfedit_atoui_t value,
114 int required)
115 {
116 return (elfedit_atoui_value_to_str(elfedit_const_to_atoui(const_type),
117 value, required));
118 }
119
120
121 /*
122 * Process the symbolic name to value mappings passed to the
123 * atoi and atoui functions.
124 *
125 * entry:
126 * sym - NULL terminated array of name->value mappings.
127 * value - Address of variable to recieve corresponding value.
128 *
129 * exit:
130 * If a mapping is found, *value is set to it, and True is returned.
131 * Otherwise False is returned.
132 */
133 static int
atoi_sym_process(const char * str,const elfedit_atoi_sym_t * sym,elfedit_atoi_t * value)134 atoi_sym_process(const char *str, const elfedit_atoi_sym_t *sym,
135 elfedit_atoi_t *value)
136 {
137 size_t cmp_len;
138 const char *tail;
139
140 while (isspace(*str))
141 str++;
142
143 tail = str + strlen(str);
144 while ((tail > str) && isspace(*(tail - 1)))
145 tail--;
146
147 cmp_len = tail - str;
148
149 for (; sym->sym_name != NULL; sym++) {
150 if ((strlen(sym->sym_name) == cmp_len) &&
151 (strncasecmp(sym->sym_name, str, cmp_len) == 0)) {
152 *value = sym->sym_value;
153 return (1);
154 }
155 }
156
157 /* No symbolic mapping was found */
158 return (0);
159 }
160 static int
atoui_sym_process(const char * str,const elfedit_atoui_sym_t * sym,elfedit_atoui_t * value)161 atoui_sym_process(const char *str, const elfedit_atoui_sym_t *sym,
162 elfedit_atoui_t *value)
163 {
164 size_t cmp_len;
165 const char *tail;
166
167 while (isspace(*str))
168 str++;
169
170 tail = str + strlen(str);
171 while ((tail > str) && isspace(*(tail - 1)))
172 tail--;
173
174 cmp_len = tail - str;
175
176 for (; sym->sym_name != NULL; sym++) {
177 if ((strlen(sym->sym_name) == cmp_len) &&
178 (strncasecmp(sym->sym_name, str, cmp_len) == 0)) {
179 *value = sym->sym_value;
180 return (1);
181 }
182 }
183
184 /* No symbolic mapping was found */
185 return (0);
186 }
187
188
189
190 /*
191 * A command completion function for atoi and atoui mappings.
192 */
193 void
elfedit_cpl_atoi(void * cpldata,const elfedit_atoi_sym_t * sym)194 elfedit_cpl_atoi(void *cpldata, const elfedit_atoi_sym_t *sym)
195 {
196 for (; sym->sym_name != NULL; sym++)
197 elfedit_cpl_match(cpldata, sym->sym_name, 1);
198 }
199 void
elfedit_cpl_atoui(void * cpldata,const elfedit_atoui_sym_t * sym)200 elfedit_cpl_atoui(void *cpldata, const elfedit_atoui_sym_t *sym)
201 {
202 for (; sym->sym_name != NULL; sym++)
203 elfedit_cpl_match(cpldata, sym->sym_name, 1);
204 }
205 void
elfedit_cpl_atoconst(void * cpldata,elfedit_const_t const_type)206 elfedit_cpl_atoconst(void *cpldata, elfedit_const_t const_type)
207 {
208 elfedit_cpl_atoui(cpldata, elfedit_const_to_atoui(const_type));
209 }
210
211
212
213
214
215 /*
216 * Convert a string to a numeric value. Strings starting with '0'
217 * are taken to be octal, those staring with '0x' are hex, and all
218 * others are decimal.
219 *
220 * entry:
221 * str - String to be converted
222 * sym - NULL, or NULL terminated array of name/value pairs.
223 *
224 * [elfedit_atoi2() and elfedit_atoui2() only]
225 * v - Address of variable to receive resulting value.
226 *
227 * exit:
228 * elfedit_atoi2() and elfedit_atoui2():
229 * On success, returns True (1) and *v is set to the value.
230 * On failure, returns False (0) and *v is undefined.
231 *
232 * elfedit_atoi() and elfedit_atoui():
233 * If the string is convertable, the value is returned.
234 * Otherwise an error is issued and this routine does
235 * not return to the caller.
236 */
237 int
elfedit_atoi2(const char * str,const elfedit_atoi_sym_t * sym,elfedit_atoi_t * v)238 elfedit_atoi2(const char *str, const elfedit_atoi_sym_t *sym, elfedit_atoi_t *v)
239 {
240 char *endptr;
241
242 if (sym && atoi_sym_process(str, sym, v))
243 return (1);
244
245 *v = strtoll(str, &endptr, 0);
246
247 /* If the left over part contains anything but whitespace, fail */
248 for (; *endptr; endptr++)
249 if (!isspace(*endptr))
250 return (0);
251 return (1);
252 }
253 elfedit_atoi_t
elfedit_atoi(const char * str,const elfedit_atoi_sym_t * sym)254 elfedit_atoi(const char *str, const elfedit_atoi_sym_t *sym)
255 {
256 elfedit_atoi_t v;
257 if (elfedit_atoi2(str, sym, &v) == 0)
258 elfedit_msg(ELFEDIT_MSG_ERR,
259 MSG_INTL(MSG_ERR_BADATOISTR), str);
260 return (v);
261 }
262 int
elfedit_atoui2(const char * str,const elfedit_atoui_sym_t * sym,elfedit_atoui_t * v)263 elfedit_atoui2(const char *str, const elfedit_atoui_sym_t *sym,
264 elfedit_atoui_t *v)
265 {
266 char *endptr;
267
268 if (sym && atoui_sym_process(str, sym, v))
269 return (1);
270
271 *v = strtoull(str, &endptr, 0);
272
273 /* If the left over part contains anything but whitespace, fail */
274 for (; *endptr; endptr++)
275 if (!isspace(*endptr))
276 return (0);
277 return (1);
278 }
279 elfedit_atoui_t
elfedit_atoui(const char * str,const elfedit_atoui_sym_t * sym)280 elfedit_atoui(const char *str, const elfedit_atoui_sym_t *sym)
281 {
282 elfedit_atoui_t v;
283 if (elfedit_atoui2(str, sym, &v) == 0)
284 elfedit_msg(ELFEDIT_MSG_ERR,
285 MSG_INTL(MSG_ERR_BADATOISTR), str);
286 return (v);
287 }
288 int
elfedit_atoconst2(const char * str,elfedit_const_t const_type,elfedit_atoui_t * v)289 elfedit_atoconst2(const char *str, elfedit_const_t const_type,
290 elfedit_atoui_t *v)
291 {
292 return (elfedit_atoui2(str, elfedit_const_to_atoui(const_type), v));
293 }
294 elfedit_atoui_t
elfedit_atoconst(const char * str,elfedit_const_t const_type)295 elfedit_atoconst(const char *str, elfedit_const_t const_type)
296 {
297 return (elfedit_atoui(str, elfedit_const_to_atoui(const_type)));
298 }
299
300 /*
301 * Convert a string to a numeric value using elfedit_ato[u]i and
302 * ensure that the resulting value lies within a given range.
303 * elfedit_ato[u]i_range() requires values to be in the range
304 * (min <= value <= max).
305 *
306 * entry:
307 * str - String to be converted
308 * min, max - If check_range is true, the allowed range that the
309 * resulting value must lie in.
310 * sym - NULL, or NULL terminated array of name/value pairs.
311 *
312 * entry [elfedit_atoi_range() and elfedit_atoui_range() only]:
313 * item_name - String describing item for which value is being read.
314 *
315 * entry [elfedit_atoi_range2() and elfedit_atoui_range2() only]:
316 * v - Address of variable to receive resulting value.
317 *
318 * exit:
319 * elfedit_atoi_range2() and elfedit_atoui_range2():
320 * On success, returns True (1) and *v is set to the value.
321 * On failure, returns False (0) and *v is undefined.
322 *
323 * elfedit_atoi_range() and elfedit_atoui_range():
324 * If the string is convertable, the value is returned.
325 * Otherwise an error is issued and this routine does
326 * not return to the caller.
327 */
328 int
elfedit_atoi_range2(const char * str,elfedit_atoi_t min,elfedit_atoi_t max,const elfedit_atoi_sym_t * sym,elfedit_atoi_t * v)329 elfedit_atoi_range2(const char *str, elfedit_atoi_t min, elfedit_atoi_t max,
330 const elfedit_atoi_sym_t *sym, elfedit_atoi_t *v)
331 {
332 return ((elfedit_atoi2(str, sym, v) != 0) &&
333 (*v >= min) && (*v <= max));
334 }
335 elfedit_atoi_t
elfedit_atoi_range(const char * str,const char * item_name,elfedit_atoi_t min,elfedit_atoi_t max,const elfedit_atoi_sym_t * sym)336 elfedit_atoi_range(const char *str, const char *item_name,
337 elfedit_atoi_t min, elfedit_atoi_t max, const elfedit_atoi_sym_t *sym)
338 {
339 elfedit_atoi_t v = elfedit_atoi(str, sym);
340
341 if ((v < min) || (v > max))
342 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_ATOIRANGE),
343 item_name, EC_XWORD(min), EC_XWORD(max), EC_XWORD(v));
344
345 return (v);
346 }
347 int
elfedit_atoui_range2(const char * str,elfedit_atoui_t min,elfedit_atoui_t max,const elfedit_atoui_sym_t * sym,elfedit_atoui_t * v)348 elfedit_atoui_range2(const char *str, elfedit_atoui_t min, elfedit_atoui_t max,
349 const elfedit_atoui_sym_t *sym, elfedit_atoui_t *v)
350 {
351 return ((elfedit_atoui2(str, sym, v) != 0) &&
352 (*v >= min) && (*v <= max));
353 }
354 elfedit_atoui_t
elfedit_atoui_range(const char * str,const char * item_name,elfedit_atoui_t min,elfedit_atoui_t max,const elfedit_atoui_sym_t * sym)355 elfedit_atoui_range(const char *str, const char *item_name,
356 elfedit_atoui_t min, elfedit_atoui_t max, const elfedit_atoui_sym_t *sym)
357 {
358 elfedit_atoui_t v = elfedit_atoui(str, sym);
359
360 if ((v < min) || (v > max))
361 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_ATOUIRANGE),
362 item_name, EC_XWORD(min), EC_XWORD(max), EC_XWORD(v));
363
364 return (v);
365 }
366 int
elfedit_atoconst_range2(const char * str,elfedit_atoui_t min,elfedit_atoui_t max,elfedit_const_t const_type,elfedit_atoui_t * v)367 elfedit_atoconst_range2(const char *str, elfedit_atoui_t min,
368 elfedit_atoui_t max, elfedit_const_t const_type, elfedit_atoui_t *v)
369 {
370 return (elfedit_atoui_range2(str, min, max,
371 elfedit_const_to_atoui(const_type), v));
372 }
373 elfedit_atoui_t
elfedit_atoconst_range(const char * str,const char * item_name,elfedit_atoui_t min,elfedit_atoui_t max,elfedit_const_t const_type)374 elfedit_atoconst_range(const char *str, const char *item_name,
375 elfedit_atoui_t min, elfedit_atoui_t max, elfedit_const_t const_type)
376 {
377 return (elfedit_atoui_range(str, item_name, min, max,
378 elfedit_const_to_atoui(const_type)));
379 }
380
381
382 /*
383 * Convenience wrapper on elfedit_atoui_range() that expects to see
384 * boolean values. Returns 1 for true, and 0 for false.
385 */
386 int
elfedit_atobool(const char * str,const char * item_name)387 elfedit_atobool(const char *str, const char *item_name)
388 {
389
390 return (elfedit_atoconst_range(str, item_name, 0, 1,
391 ELFEDIT_CONST_BOOL) != 0);
392 }
393
394
395
396 /*
397 * Convenience wrapper on elfedit_atoui() to read a section index
398 * that understands the special SHN_ names.
399 *
400 * entry:
401 * str - String to process
402 * shnum - Number of sections in the ELF file
403 *
404 * exit:
405 * If it is possible to convert str to a number, that value
406 * is returned. If the value is out of range for the file,
407 * a warning message to that effect is issued. On failure,
408 * an error is issued and this routine does not return to
409 * the caller.
410 */
411 elfedit_atoui_t
elfedit_atoshndx(const char * str,size_t shnum)412 elfedit_atoshndx(const char *str, size_t shnum)
413 {
414 elfedit_atoui_t ndx;
415
416 ndx = elfedit_atoconst(str, ELFEDIT_CONST_SHN);
417 if ((ndx >= shnum) && ((ndx < SHN_LORESERVE) || (ndx > SHN_HIRESERVE)))
418 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_SHNDX_RANGE),
419 EC_WORD(ndx), EC_WORD(shnum-1));
420
421 return (ndx);
422 }
423
424
425
426 /*
427 * Convert an output style string into it's integer constant. This
428 * routine reports success/failure via the return value rather than
429 * by throwing errors so that it can be used to process command
430 * line options at program startup, before
431 * the elfedit framework is initialized.
432 */
433 int
elfedit_atooutstyle(const char * str,elfedit_outstyle_t * outstyle)434 elfedit_atooutstyle(const char *str, elfedit_outstyle_t *outstyle)
435 {
436 int ret;
437 elfedit_atoui_t value;
438
439 ret = atoui_sym_process(str,
440 elfedit_const_to_atoui(ELFEDIT_CONST_OUTSTYLE), &value);
441 if (ret != 0)
442 *outstyle = value;
443 return (ret);
444 }
445
446
447
448
449 /*
450 * Initialize a state block for processing by elfedit_getopt().
451 *
452 * entry:
453 * state - State block to initialize
454 * cmd_name - NULL, or name of command for which we are processing
455 * options.
456 * argc, argv - Address of variables giving number of options and
457 * access to the option strings.
458 *
459 * note:
460 * cmd_name can only be set to NULL when this routine is called
461 * by, or below, a currently active command. Otherwise, results
462 * are undefined (crashing or corruption) if there isn't one.
463 */
464 void
elfedit_getopt_init(elfedit_getopt_state_t * state,int * argc,const char ** argv[])465 elfedit_getopt_init(elfedit_getopt_state_t *state,
466 int *argc, const char **argv[])
467 {
468 elfeditGC_cmd_t *cmd = elfedit_curcmd();
469
470 state->go_argc = argc;
471 state->go_argv = argv;
472 state->go_optarg = cmd->cmd_opt;
473 state->go_idmask = 0;
474 state->go_done = 0;
475 state->go_sglgrp = NULL;
476 }
477
478
479
480 /*
481 * elfedit-centric version of getopt()
482 *
483 * entry:
484 * state - Getopt state, which must have been previously initialized
485 * via a call to elfedit_getopt_init.
486 *
487 * exit:
488 * If an option is matched, this routine returns a pointer to an
489 * elfedit_getopt_ret_t buffer (which comes from the storage used
490 * for state). If there are no more options to process, NULL is returned.
491 *
492 * Syntax errors are reported via elfedit_command_usage(), and this
493 * routine does not return to the caller.
494 *
495 * note:
496 * - The caller should not access the contents of state directly.
497 * Those contents are private, and subject to change.
498 * - Once a call to this routine returns NULL, the argc/argv have
499 * have been ajusted so that they reference the plain arguments.
500 */
501 elfedit_getopt_ret_t *
elfedit_getopt(elfedit_getopt_state_t * state)502 elfedit_getopt(elfedit_getopt_state_t *state)
503 {
504 elfedit_cmd_optarg_t *optarg;
505 const char *argstr;
506 int argc = *(state->go_argc);
507 const char **argv = *(state->go_argv);
508 elfedit_optarg_item_t item;
509 struct {
510 int valid;
511 int is_outstyle;
512 elfedit_getopt_ret_t ret;
513 elfedit_cmd_oa_mask_t excmask;
514 } sgl_with_value;
515
516 if (state->go_sglgrp == NULL) {
517 /*
518 * Reasons to bail out immediately:
519 * - The command does not accept options
520 * - We've already reported the final option.
521 * - There are no more arguments.
522 * - The next argument does not start with '-'
523 */
524 if ((state->go_optarg == NULL) || state->go_done ||
525 (argc <= 0) || (*(argv[0]) != '-')) {
526 state->go_done = 1;
527 return (NULL);
528 }
529
530 argstr = argv[0];
531
532 /* A '-' by itself is a syntax error */
533 if (argstr[1] == '\0')
534 elfedit_command_usage();
535
536 /* A '--' option means we should stop at this point */
537 if ((argstr[1] == '-') && (argstr[2] == '\0')) {
538 (*state->go_argc)--;
539 (*state->go_argv)++;
540 return (NULL);
541 }
542
543 /*
544 * We have a string that starts with a '-'.
545 * Does it match an option?
546 */
547 sgl_with_value.valid = 0;
548 for (optarg = state->go_optarg; optarg->oa_name != NULL; ) {
549 int is_outstyle =
550 (optarg->oa_flags & ELFEDIT_CMDOA_F_INHERIT) &&
551 (optarg->oa_name == ELFEDIT_STDOA_OPT_O);
552 int need_value;
553
554 elfedit_next_optarg(&optarg, &item);
555 need_value = item.oai_flags & ELFEDIT_CMDOA_F_VALUE;
556
557 /*
558 * If the option is a single letter that accepts
559 * a value, then we allow the combined syntax
560 * -ovalue, where no space is reqired between the
561 * option flag and the value string.
562 */
563 if ((item.oai_name[2] == '\0') && need_value &&
564 (argstr[1] == item.oai_name[1]) &&
565 (argstr[2] != '\0')) {
566 /*
567 * We have a match. However, there may also
568 * be a straightforward match that we have
569 * not yet found. If so, we want to prefer that
570 * case over this one. So rather than return
571 * it immediately, we capture the information
572 * and keep looking. If nothing else surfaces,
573 * we'll use this later.
574 */
575 sgl_with_value.valid = 1;
576 sgl_with_value.ret.gor_idmask = item.oai_idmask;
577 sgl_with_value.excmask = item.oai_excmask;
578 sgl_with_value.ret.gor_value = argstr + 2;
579 sgl_with_value.is_outstyle = is_outstyle;
580 continue;
581 }
582
583 /* Try for a straightforward match */
584 if (strcmp(argstr, item.oai_name) == 0) {
585 (*state->go_argc) = --argc;
586 (*state->go_argv) = ++argv;
587
588 /* Mutually exclusive option already seen? */
589 if (item.oai_excmask & state->go_idmask)
590 elfedit_command_usage();
591
592 /* Return the match */
593 state->go_idmask |= item.oai_idmask;
594 state->go_ret.gor_idmask = item.oai_idmask;
595 if (need_value) {
596 /* If out of args, syntax error */
597 if (argc <= 0)
598 elfedit_command_usage();
599 state->go_ret.gor_value = argv[0];
600 (*state->go_argc)--;
601 (*state->go_argv)++;
602 } else {
603 state->go_ret.gor_value = NULL;
604 }
605 if (is_outstyle)
606 elfedit_set_cmd_outstyle(
607 state->go_ret.gor_value);
608 return (&state->go_ret);
609 }
610 }
611
612 /*
613 * No straightforward matches: Did we get a match with
614 * the special single letter and combined value? If so
615 * return that now.
616 */
617 if (sgl_with_value.valid) {
618 (*state->go_argc)--;
619 (*state->go_argv)++;
620
621 /* Mutually exclusive option already seen? */
622 if (sgl_with_value.excmask & state->go_idmask)
623 elfedit_command_usage();
624
625 state->go_idmask |= sgl_with_value.ret.gor_idmask;
626 state->go_ret = sgl_with_value.ret;
627 if (sgl_with_value.is_outstyle)
628 elfedit_set_cmd_outstyle(
629 state->go_ret.gor_value);
630
631 return (&state->go_ret);
632 }
633
634 /*
635 * If nothing above matched, make this option the single
636 * group string and see if the characters in it all match
637 * as single letter options without values.
638 */
639 state->go_sglgrp = argstr + 1; /* Skip '-' */
640 }
641
642 /*
643 * If there is a single group string, take the first character
644 * and try to match it to an 1-letter option that does not
645 * require a value.
646 */
647 if (state->go_sglgrp != NULL) {
648 int ch = *state->go_sglgrp++;
649
650 /* If that is the last character, clear single group mode */
651 if (*state->go_sglgrp == '\0') {
652 (*state->go_argc)--;
653 (*state->go_argv)++;
654 state->go_sglgrp = NULL;
655 }
656
657 for (optarg = state->go_optarg; optarg->oa_name != NULL; ) {
658 elfedit_next_optarg(&optarg, &item);
659
660 if ((item.oai_name[2] == '\0') &&
661 (ch == item.oai_name[1])) {
662 /*
663 * It matches. If the option requires a value
664 * then it cannot be in a group.
665 */
666 if (item.oai_flags & ELFEDIT_CMDOA_F_VALUE)
667 elfedit_command_usage();
668
669 /* Mutually exclusive option already seen? */
670 if (item.oai_excmask & state->go_idmask)
671 elfedit_command_usage();
672
673 /* Return the match */
674 state->go_idmask |= item.oai_idmask;
675 state->go_ret.gor_idmask = item.oai_idmask;
676 state->go_ret.gor_value = NULL;
677 return (&state->go_ret);
678 }
679 }
680 }
681
682 /* Nothing matched. We have a syntax error */
683 elfedit_command_usage();
684 /*NOTREACHED*/
685 return (NULL);
686 }
687
688
689 /*
690 * Return the count of non-zero bits in the value v.
691 *
692 * entry:
693 * v - Value to test
694 * sizeof_orig_v - The result of using the sizeof operator
695 * on the original value of v. The value received
696 * by this routine has been cast to an unsigned 64-bit
697 * integer, so having the caller use sizeof allows us to
698 * avoid testing bits that were not in the original.
699 */
700 int
elfedit_bits_set(u_longlong_t v,int sizeof_orig_v)701 elfedit_bits_set(u_longlong_t v, int sizeof_orig_v)
702 {
703 int nbits = sizeof_orig_v * 8;
704 int mask;
705 int cnt = 0;
706
707 for (mask = 1; (nbits-- > 0) && (cnt < 2); mask *= 2)
708 if (v & mask)
709 cnt++;
710
711 return (cnt);
712 }
713
714
715 /*
716 * "delete" items in an array by copying the following items up
717 * over the "deleted" items and then zero filling the vacated
718 * slots at the bottom.
719 *
720 * entry:
721 * name_str - Array identification prefix to use for debug message
722 * data_start - Address of 1st byte in array
723 * entsize - sizeof a single element of the array
724 * num_ent - # of elements in array
725 * start_ndx - Index of first item to be deleted
726 * cnt - # of items to delete
727 *
728 * exit:
729 * Any errors are issued and control does not return to the
730 * caller. On success, the items have been removed, zero filling
731 * has been done, and debug messages issued.
732 */
733 void
elfedit_array_elts_delete(const char * name_str,void * data_start,size_t entsize,size_t num_ent,size_t start_ndx,size_t cnt)734 elfedit_array_elts_delete(const char *name_str, void *data_start,
735 size_t entsize, size_t num_ent, size_t start_ndx, size_t cnt)
736 {
737 char *data = data_start;
738
739 /* The specified index and range must be in bounds */
740 if ((start_ndx + cnt) > num_ent)
741 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_ARRBNDS),
742 name_str, EC_WORD(num_ent), EC_WORD(num_ent - 1));
743
744 /*
745 * Everything below the deleted items moves up.
746 * Note that bcopy() is documented to handle overlapping
747 * src/dst correctly, so we make no effort to handle this
748 * element by element, but issue a single operation.
749 *
750 * If we're doing the last element, there is nothing to
751 * move up, and we skip this step, moving on to the zeroing below.
752 */
753 if (start_ndx < (num_ent - 1)) {
754 size_t ncpy = num_ent - (start_ndx + cnt);
755
756 bcopy(data + ((start_ndx + cnt) * entsize),
757 data + (start_ndx * entsize), ncpy * entsize);
758 if (ncpy == 1) {
759 elfedit_msg(ELFEDIT_MSG_DEBUG,
760 MSG_INTL(MSG_DEBUG_ARRCPY_1), name_str,
761 EC_WORD(start_ndx + cnt), EC_WORD(start_ndx));
762 } else {
763 elfedit_msg(ELFEDIT_MSG_DEBUG,
764 MSG_INTL(MSG_DEBUG_ARRCPY_N), name_str,
765 EC_WORD(start_ndx + cnt),
766 EC_WORD(start_ndx + cnt + ncpy - 1),
767 EC_WORD(start_ndx),
768 EC_WORD(start_ndx + ncpy - 1));
769 }
770 }
771
772 /* Zero out the vacated elements at the end */
773 bzero(data + ((num_ent - cnt) * entsize), entsize * cnt);
774
775 if (cnt == 1) {
776 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_ARRZERO_1),
777 name_str, EC_WORD(num_ent - 1));
778 } else {
779 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_ARRZERO_N),
780 name_str, EC_WORD(num_ent - cnt),
781 EC_WORD(num_ent - 1), EC_WORD(cnt));
782 }
783 }
784
785
786 /*
787 * move the location of items in an array by shifting the surround
788 * items into the vacated hole and them putting the values into
789 * the new location.
790 *
791 * entry:
792 * name_str - Array identification prefix to use for debug message
793 * data_start - Address of 1st byte in array
794 * entsize - sizeof a single element of the array
795 * num_ent - # of elements in array
796 * start_ndx - Index of first item to be moved
797 * dst_ndx - Index to receive the moved block
798 * cnt - # of items to move
799 * scr_item - Space allocated by the caller sufficient to hold
800 * one item from the array. Used to swap elements.
801 *
802 * exit:
803 * Any errors are issued and control does not return to the
804 * caller. On success, the items have been moved, and debug
805 * messages issued.
806 */
807 void
elfedit_array_elts_move(const char * name_str,void * data_start,size_t entsize,size_t num_ent,size_t srcndx,size_t dstndx,size_t cnt,void * scr_item)808 elfedit_array_elts_move(const char *name_str, void *data_start,
809 size_t entsize, size_t num_ent, size_t srcndx,
810 size_t dstndx, size_t cnt, void *scr_item)
811 {
812 char *data = data_start;
813
814 /* The specified source and destination ranges must be in bounds */
815 if (((srcndx + cnt) > num_ent) || ((dstndx + cnt) > num_ent))
816 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_ARRBNDS),
817 name_str, EC_WORD(num_ent), EC_WORD(num_ent - 1));
818
819 /* If source and destination are same, there's nothing to do */
820 if (srcndx == dstndx)
821 return;
822
823 /*
824 * It is meaningless to do a move where the source and destination
825 * are overlapping, because this "move" amounts to shifting
826 * the existing items around into a new position. If there is
827 * more than one element, then overlap is possible and we need
828 * to test for it.
829 */
830 if (cnt > 1) {
831 size_t low, hi;
832
833 if (srcndx > dstndx) {
834 low = dstndx;
835 hi = srcndx;
836 } else {
837 low = srcndx;
838 hi = dstndx;
839 }
840 /* Ensure that the src and dst don't overlap */
841 if ((low + cnt) > hi)
842 elfedit_msg(ELFEDIT_MSG_ERR,
843 MSG_INTL(MSG_ERR_ARRMVOVERLAP), name_str,
844 EC_WORD(srcndx), EC_WORD(srcndx + cnt - 1),
845 EC_WORD(dstndx), EC_WORD(dstndx + cnt - 1));
846 }
847
848 if (cnt == 1)
849 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_ARRMOVE_1),
850 name_str, EC_WORD(srcndx), EC_WORD(dstndx));
851 else
852 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_ARRMOVE_N),
853 name_str, EC_WORD(cnt),
854 EC_WORD(srcndx), EC_WORD(srcndx + cnt - 1),
855 EC_WORD(dstndx), EC_WORD(dstndx + cnt - 1));
856
857 if (srcndx < dstndx) {
858 srcndx += cnt - 1;
859 dstndx += cnt - 1;
860 for (; cnt-- > 0; srcndx--, dstndx--) {
861 /*
862 * Copy item at srcndx to scratch location
863 *
864 * save = dyn[srcndx];
865 */
866 bcopy(data + (srcndx * entsize), scr_item, entsize);
867
868 /*
869 * Shift items after source up through destination
870 * to source. bcopy() handles overlapped copies.
871 *
872 * for (i = srcndx; i < dstndx; i++)
873 * dyn[i] = dyn[i + 1];
874 */
875 bcopy(data + ((srcndx + 1) * entsize),
876 data + (srcndx * entsize),
877 (dstndx - srcndx) * entsize);
878
879 /*
880 * Copy saved item into destination slot
881 *
882 * dyn[dstndx] = save;
883 */
884 bcopy(scr_item, data + (dstndx * entsize), entsize);
885 }
886 } else {
887 for (; cnt-- > 0; srcndx++, dstndx++) {
888 /*
889 * Copy item at srcndx to scratch location
890 *
891 * save = dyn[srcndx];
892 */
893 bcopy(data + (srcndx * entsize), scr_item, entsize);
894
895 /*
896 * Shift items from destination through item below
897 * source up one. bcopy() handles overlapped copies.
898 *
899 * for (i = srcndx; i > dstndx; i--)
900 * dyn[i] = dyn[i - 1];
901 */
902 bcopy(data + (dstndx * entsize),
903 data + ((dstndx + 1) * entsize),
904 (srcndx - dstndx) * entsize);
905
906 /*
907 * Copy saved item into destination slot
908 *
909 * dyn[dstndx] = save;
910 */
911 bcopy(scr_item, data + (dstndx * entsize), entsize);
912 }
913 }
914 }
915