xref: /illumos-gate/usr/src/cmd/sgs/elfedit/common/util.c (revision 0250c53ad267726f2438e3c6556199a0bbf588a2)
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 *
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 *
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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
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
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
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