xref: /titanic_50/usr/src/cmd/sgs/elfedit/common/util.c (revision 2df1fe9ca32bb227b9158c67f5c00b54c20b10fd)
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 *
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 *
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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
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
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
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