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*/
58static const char *
59map_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*/
97static const char *
98map_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*/
111static const char *
112map_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 */
132const char *
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*/
196static conv_iter_ret_t
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*/
235conv_iter_ret_t
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*/
249conv_iter_ret_t
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 */
269conv_iter_ret_t
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 */
318int
319conv_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 */
346conv_iter_ret_t
347conv_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