util.c revision 5088:26c540f30cd3
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 */
86const char *
87elfedit_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}
99const char *
100elfedit_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}
112const char *
113elfedit_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 */
133static int
134atoi_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}
160static int
161atoui_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 */
193void
194elfedit_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}
199void
200elfedit_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}
205void
206elfedit_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 */
237int
238elfedit_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}
253elfedit_atoi_t
254elfedit_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}
262int
263elfedit_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}
279elfedit_atoui_t
280elfedit_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}
288int
289elfedit_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}
294elfedit_atoui_t
295elfedit_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 */
328int
329elfedit_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}
335elfedit_atoi_t
336elfedit_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}
347int
348elfedit_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}
354elfedit_atoui_t
355elfedit_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}
366int
367elfedit_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}
373elfedit_atoui_t
374elfedit_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 */
386int
387elfedit_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 */
411elfedit_atoui_t
412elfedit_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 */
433int
434elfedit_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 */
464void
465elfedit_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 */
501elfedit_getopt_ret_t *
502elfedit_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 */
700int
701elfedit_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 */
733void
734elfedit_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 */
807void
808elfedit_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