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