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