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 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include	<stdio.h>
28 #include	<strings.h>
29 #include	<_machelf.h>
30 #include	"_conv.h"
31 #include	"globals_msg.h"
32 
33 
34 /*
35  * Map an integer into a descriptive string.
36  *
37  * entry:
38  *	inv_buf - A buffer into which this routine can format
39  *		a result string, if necessary.
40  *	val - The value for which a string is desired.
41  *	flags - CONV_FMT_* values to be passed to conv_invalid_val() if
42  *		necessary. The caller is reponsible for having examined
43  *		the CONV_FMT_ALT_* part of flags and passing the proper
44  *		msg array.
45  *	num_msg - # of Msg entries in msg.
46  *	msg - Array of num_msg Msg items corresponding to the possible
47  *		strings corresponding to val.
48  *	local_sgs_msg - Message string table from module from which
49  *		this function is called.
50  *
51  * exit:
52  *	If val lies in the range [0-(num_msg-1)], then the string
53  *	corresponding to it is returned. If val is outside the range,
54  *	conv_invalid_val() is called to format an ASCII representation
55  *	of it into inv_buf, and that is returned.
56  */
57 /*ARGSUSED5*/
58 static const char *
map_msg2str(Conv_inv_buf_t * inv_buf,Conv_elfvalue_t val,Conv_fmt_flags_t flags,size_t num_msg,const Msg * msg,const char * local_sgs_msg)59 map_msg2str(Conv_inv_buf_t *inv_buf, Conv_elfvalue_t val,
60     Conv_fmt_flags_t flags, size_t num_msg, const Msg *msg,
61     const char *local_sgs_msg)
62 {
63 	if ((val < num_msg) && (msg[val] != 0))
64 		return (MSG_ORIG_STRTAB(msg[val], local_sgs_msg));
65 
66 	/* If we get here, it's an unknown value */
67 	return (conv_invalid_val(inv_buf, val, flags));
68 }
69 
70 /*
71  * Map an integer into a descriptive string from a NULL terminated
72  * array of Val_desc or Val_desc2 descriptors.
73  *
74  * entry:
75  *	inv_buf - A buffer into which this routine can format
76  *		a result string, if necessary.
77  *	osabi,mach (_conv_vd22str only) - The osab/mach under which
78  *		val is to be interpreted. Items with a non-0 osabi or machine
79  *		that do not match are quietly ignored.
80  *	val - The value for which a string is desired.
81  *	flags - CONV_FMT_* values to be passed to conv_invalid_val() if
82  *		necessary. The caller is reponsible for having examined
83  *		the CONV_FMT_ALT_* part of flags and passing the proper
84  *		descriptor array.
85  *	vdp - Pointer to NULL terminated array of Val_desc descriptors.
86  *	local_sgs_msg - Message string table from module from which
87  *		this function is called.
88  *
89  * exit:
90  *	If val is found in the vdp array, and in the osabi version of
91  *	this function if the osabi matches, then the string corresponding
92  *	val is returned. If a string for val is not found, conv_invalid_val()
93  *	is called to format an ASCII representation of it into inv_buf, and
94  *	that is returned.
95  */
96 /*ARGSUSED4*/
97 static const char *
map_vd2str(Conv_inv_buf_t * inv_buf,Conv_elfvalue_t val,Conv_fmt_flags_t flags,const Val_desc * vdp,const char * local_sgs_msg)98 map_vd2str(Conv_inv_buf_t *inv_buf, Conv_elfvalue_t val,
99     Conv_fmt_flags_t flags, const Val_desc *vdp, const char *local_sgs_msg)
100 {
101 	for (; vdp->v_msg; vdp++) {
102 		if (val == vdp->v_val)
103 			return (MSG_ORIG_STRTAB(vdp->v_msg, local_sgs_msg));
104 	}
105 
106 	/* If we get here, it's an unknown value */
107 	return (conv_invalid_val(inv_buf, val, flags));
108 }
109 
110 /*ARGSUSED6*/
111 static const char *
map_vd22str(Conv_inv_buf_t * inv_buf,uchar_t osabi,Half mach,Conv_elfvalue_t val,Conv_fmt_flags_t flags,const Val_desc2 * vdp,const char * local_sgs_msg)112 map_vd22str(Conv_inv_buf_t *inv_buf, uchar_t osabi, Half mach,
113     Conv_elfvalue_t val, Conv_fmt_flags_t flags, const Val_desc2 *vdp,
114     const char *local_sgs_msg)
115 {
116 	for (; vdp->v_msg; vdp++) {
117 		if (CONV_VD2_SKIP(osabi, mach, vdp))
118 			continue;
119 
120 		if (val == vdp->v_val)
121 			return (MSG_ORIG_STRTAB(vdp->v_msg, local_sgs_msg));
122 	}
123 
124 	/* If we get here, it's an unknown value */
125 	return (conv_invalid_val(inv_buf, val, flags));
126 }
127 
128 /*
129  * Process an array of conv_ds_XXX_t structures and call the appropriate
130  * map functions for the format of the strings given.
131  */
132 const char *
_conv_map_ds(uchar_t osabi,Half mach,Conv_elfvalue_t value,const conv_ds_t ** dsp,Conv_fmt_flags_t fmt_flags,Conv_inv_buf_t * inv_buf,const char * local_sgs_msg)133 _conv_map_ds(uchar_t osabi, Half mach, Conv_elfvalue_t value,
134     const conv_ds_t **dsp, Conv_fmt_flags_t fmt_flags, Conv_inv_buf_t *inv_buf,
135     const char *local_sgs_msg)
136 {
137 	const conv_ds_t *ds;
138 
139 	for (ds = *dsp; ds != NULL; ds = *(++dsp)) {
140 		if ((value < ds->ds_baseval) || (value > ds->ds_topval))
141 			continue;
142 
143 		switch (ds->ds_type) {
144 		case CONV_DS_MSGARR:
145 			return (map_msg2str(inv_buf, value - ds->ds_baseval,
146 			    fmt_flags, ds->ds_topval - ds->ds_baseval + 1,
147 			    /*LINTED*/
148 			    ((conv_ds_msg_t *)ds)->ds_msg,
149 			    local_sgs_msg));
150 
151 		case CONV_DS_VD:
152 			return (map_vd2str(inv_buf, value, fmt_flags,
153 			    /*LINTED*/
154 			    ((conv_ds_vd_t *)ds)->ds_vd,
155 			    local_sgs_msg));
156 
157 		case CONV_DS_VD2:
158 			return (map_vd22str(inv_buf, osabi, mach, value,
159 			    fmt_flags,
160 			    /*LINTED*/
161 			    ((conv_ds_vd2_t *)ds)->ds_vd2,
162 			    local_sgs_msg));
163 		}
164 	}
165 
166 	return (conv_invalid_val(inv_buf, value, fmt_flags));
167 }
168 
169 /*
170  * Iterate over every message string in a given array of Msg codes,
171  * calling a user supplied callback for each one.
172  *
173  * entry:
174  *	basevalue - Value corresponding to the first Msg in the array.
175  *	local_sgs_msg - Pointer to the __sgs_msg array for the
176  *		libconv module making the call.
177  *	num_msg - # of items in array referenced by msg
178  *	msg - Array of Msg indexes for the strings to iterate over.
179  *		The value corresponding to each element of msg must be:
180  *			value[i] = basevalue + i
181  *	func, uvalue - User supplied function to be called for each
182  *		string in msg. uvalue is an arbitrary user supplied pointer
183  *		to be passed to func.
184  *	local_sgs_msg - Pointer to the __sgs_msg array for the
185  *		libconv module making the call.
186  *
187  * exit:
188  *	The callback function is called for every non-zero item in
189  *	msg[]. If any callback returns CONV_ITER_DONE, execution stops
190  *	with that item and the function returns immediately. Otherwise,
191  *	it continues to the end of the array.
192  *
193  *	The value from the last callback is returned.
194  */
195 /*ARGSUSED5*/
196 static conv_iter_ret_t
_conv_iter_msgarr(uint32_t basevalue,const Msg * msg,size_t num_msg,conv_iter_cb_t func,void * uvalue,const char * local_sgs_msg)197 _conv_iter_msgarr(uint32_t basevalue, const Msg *msg, size_t num_msg,
198     conv_iter_cb_t func, void *uvalue, const char *local_sgs_msg)
199 {
200 	for (; num_msg-- > 0; basevalue++, msg++) {
201 		if (*msg != 0)
202 			if ((* func)(MSG_ORIG_STRTAB(*msg, local_sgs_msg),
203 			    basevalue, uvalue) == CONV_ITER_DONE)
204 				return (CONV_ITER_DONE);
205 	}
206 
207 	return (CONV_ITER_CONT);
208 }
209 
210 /*
211  * Iterate over every message string in a given array of Val_desc or
212  * Val_desc2 descriptors, calling a user supplied callback for each one.
213  *
214  * entry:
215  *	osabi,mach (_conv_iter_vd2 only) - The osabi/mach for which
216  *		strings are desired. Strings with a non-0 osabi or machine
217  *		that do not match are quietly ignored.
218  *	vdp - Pointer to NULL terminated array of Val_desc descriptors.
219  *	func, uvalue - User supplied function to be called for each
220  *		string in msg. uvalue is an arbitrary user supplied pointer
221  *		to be passed to func.
222  *	local_sgs_msg - Pointer to the __sgs_msg array for the
223  *		libconv module making the call.
224  *
225  * exit:
226  *	The callback function is called for every descriptor referenced by
227  *	vdp. In the case of the OSABI-version of this function, strings from
228  *	the wrong osabi are not used. If any callback returns CONV_ITER_DONE,
229  *	execution stops with that item and the function returns immediately.
230  *	Otherwise, it continues to the end of the array.
231  *
232  *	The value from the last callback is returned.
233  */
234 /*ARGSUSED3*/
235 conv_iter_ret_t
_conv_iter_vd(const Val_desc * vdp,conv_iter_cb_t func,void * uvalue,const char * local_sgs_msg)236 _conv_iter_vd(const Val_desc *vdp, conv_iter_cb_t func, void *uvalue,
237     const char *local_sgs_msg)
238 {
239 	for (; vdp->v_msg; vdp++) {
240 		if ((* func)(MSG_ORIG_STRTAB(vdp->v_msg, local_sgs_msg),
241 		    vdp->v_val, uvalue) == CONV_ITER_DONE)
242 			return (CONV_ITER_DONE);
243 	}
244 
245 	return (CONV_ITER_CONT);
246 }
247 
248 /*ARGSUSED5*/
249 conv_iter_ret_t
_conv_iter_vd2(conv_iter_osabi_t osabi,Half mach,const Val_desc2 * vdp,conv_iter_cb_t func,void * uvalue,const char * local_sgs_msg)250 _conv_iter_vd2(conv_iter_osabi_t osabi, Half mach, const Val_desc2 *vdp,
251     conv_iter_cb_t func, void *uvalue, const char *local_sgs_msg)
252 {
253 	for (; vdp->v_msg; vdp++) {
254 		if (CONV_ITER_VD2_SKIP(osabi, mach, vdp))
255 			continue;
256 
257 		if ((* func)(MSG_ORIG_STRTAB(vdp->v_msg, local_sgs_msg),
258 		    vdp->v_val, uvalue) == CONV_ITER_DONE)
259 			return (CONV_ITER_DONE);
260 	}
261 
262 	return (CONV_ITER_CONT);
263 }
264 
265 /*
266  * Process an array of conv_ds_XXX_t structures and call the appropriate
267  * iteration functions for the format of the strings given.
268  */
269 conv_iter_ret_t
_conv_iter_ds(conv_iter_osabi_t osabi,Half mach,const conv_ds_t ** dsp,conv_iter_cb_t func,void * uvalue,const char * local_sgs_msg)270 _conv_iter_ds(conv_iter_osabi_t osabi, Half mach, const conv_ds_t **dsp,
271     conv_iter_cb_t func, void *uvalue, const char *local_sgs_msg)
272 {
273 	const conv_ds_t *ds;
274 
275 	for (ds = *dsp; ds != NULL; ds = *(++dsp)) {
276 		switch (ds->ds_type) {
277 		case CONV_DS_MSGARR:
278 			if (_conv_iter_msgarr(ds->ds_baseval,
279 			    /*LINTED*/
280 			    ((conv_ds_msg_t *)ds)->ds_msg,
281 			    ds->ds_topval - ds->ds_baseval + 1, func, uvalue,
282 			    local_sgs_msg) == CONV_ITER_DONE)
283 				return (CONV_ITER_DONE);
284 			break;
285 
286 		case CONV_DS_VD:
287 			/*LINTED*/
288 			if (_conv_iter_vd(((conv_ds_vd_t *)ds)->ds_vd,
289 			    func, uvalue, local_sgs_msg) == CONV_ITER_DONE)
290 				return (CONV_ITER_DONE);
291 			break;
292 
293 		case CONV_DS_VD2:
294 			if (_conv_iter_vd2(osabi, mach,
295 			    /*LINTED*/
296 			    ((conv_ds_vd2_t *)ds)->ds_vd2,
297 			    func, uvalue, local_sgs_msg) == CONV_ITER_DONE)
298 				return (CONV_ITER_DONE);
299 			break;
300 		}
301 	}
302 
303 	return (CONV_ITER_CONT);
304 }
305 
306 /*
307  * Initialize the uvalue block prior to use of an interation function
308  * employing conv_iter_strtol().
309  *
310  * entry:
311  *	str - String to be matched to a value
312  *	uvalue - Pointer to uninitialized uvalue block
313  *
314  * exit:
315  *	Initializes the uvalue block for use. Returns True (1) if a non-empty
316  *	string was supplied, and False (0).
317  */
318 int
conv_iter_strtol_init(const char * str,conv_strtol_uvalue_t * uvalue)319 conv_iter_strtol_init(const char *str, conv_strtol_uvalue_t *uvalue)
320 {
321 	const char	*tail;
322 
323 	while (conv_strproc_isspace(*str))
324 		str++;
325 	uvalue->csl_str = str;
326 	uvalue->csl_found = 0;
327 
328 	tail = str + strlen(str);
329 	while ((tail > str) && conv_strproc_isspace(*(tail - 1)))
330 		tail--;
331 	uvalue->csl_strlen = tail - str;
332 
333 	return (uvalue->csl_strlen > 0);
334 }
335 
336 /*
337  * conv_iter_strtol() is used with iteration functions to map a string
338  * to the value of its corresponding ELF constant.
339  *
340  * entry:
341  *	str - String supplied by this iteration
342  *	value - Value of ELF constant corresponding to str
343  *	uvalue - Pointer to conv_strtol_uvalue_t block previously
344  *		initialized by a call to conv_iter_strtol_init().
345  */
346 conv_iter_ret_t
conv_iter_strtol(const char * str,uint32_t value,void * uvalue)347 conv_iter_strtol(const char *str, uint32_t value, void *uvalue)
348 {
349 	conv_strtol_uvalue_t *state = (conv_strtol_uvalue_t *)uvalue;
350 
351 	if ((strlen(str) == state->csl_strlen) &&
352 	    (strncasecmp(str, state->csl_str, state->csl_strlen) == 0)) {
353 		state->csl_found = 1;
354 		state->csl_value = value;
355 		return (CONV_ITER_DONE);	/* Found it. Stop now. */
356 	}
357 
358 	return (CONV_ITER_CONT);		/* Keep looking */
359 }
360