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 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <msg.h>
31 #include <_elfdump.h>
32 #include <struct_layout.h>
33 #include <conv.h>
34 
35 
36 /*
37  * Functions for extracting and formatting numeric values from
38  * structure data.
39  */
40 
41 
42 
43 
44 /*
45  * Extract the integral field into the value union given and
46  * perform any necessary byte swapping to make the result readable
47  * on the elfdump host.
48  */
49 void
sl_extract_num_field(const char * data,int do_swap,const sl_field_t * fdesc,sl_data_t * field_data)50 sl_extract_num_field(const char *data, int do_swap, const sl_field_t *fdesc,
51     sl_data_t *field_data)
52 {
53 	/* Copy the value bytes into our union */
54 	(void) memcpy(field_data, data + fdesc->slf_offset,
55 	    fdesc->slf_eltlen);
56 
57 	/* Do byte swapping as necessary */
58 	if (do_swap) {
59 		switch (fdesc->slf_eltlen) {
60 		case 2:
61 			field_data->sld_ui16 = BSWAP_HALF(field_data->sld_ui16);
62 			break;
63 
64 		case 4:
65 			field_data->sld_ui32 = BSWAP_WORD(field_data->sld_ui32);
66 			break;
67 
68 		case 8:
69 			field_data->sld_ui64 =
70 			    BSWAP_LWORD(field_data->sld_ui64);
71 			break;
72 		}
73 	}
74 }
75 
76 /*
77  * Extract the given integer field, and return its value, cast
78  * to Word. Note that this operation must not be used on values
79  * that can be negative, or larger than 32-bits, as information
80  * can be lost.
81  */
82 Word
sl_extract_as_word(const char * data,int do_swap,const sl_field_t * fdesc)83 sl_extract_as_word(const char *data, int do_swap, const sl_field_t *fdesc)
84 {
85 	sl_data_t	v;
86 
87 	/* Extract the value from the raw data */
88 	sl_extract_num_field(data, do_swap, fdesc, &v);
89 
90 	if (fdesc->slf_sign) {
91 		switch (fdesc->slf_eltlen) {
92 			case 1:
93 				return ((Word) v.sld_i8);
94 			case 2:
95 				return ((Word) v.sld_i16);
96 			case 4:
97 				return ((Word) v.sld_i32);
98 			case 8:
99 				return ((Word) v.sld_i64);
100 		}
101 	} else {
102 		switch (fdesc->slf_eltlen) {
103 			case 1:
104 				return ((Word) v.sld_ui8);
105 			case 2:
106 				return ((Word) v.sld_ui16);
107 			case 4:
108 				return ((Word) v.sld_ui32);
109 			case 8:
110 				return ((Word) v.sld_ui64);
111 		}
112 	}
113 
114 	/* This should not be reached */
115 	assert(0);
116 	return (0);
117 }
118 
119 
120 /*
121  * Extract the given integer field, and return its value, cast
122  * to Lword. Note that this operation must not be used on values
123  * that can be negative, as information can be lost.
124  */
125 Lword
sl_extract_as_lword(const char * data,int do_swap,const sl_field_t * fdesc)126 sl_extract_as_lword(const char *data, int do_swap, const sl_field_t *fdesc)
127 {
128 	sl_data_t	v;
129 
130 	/* Extract the value from the raw data */
131 	sl_extract_num_field(data, do_swap, fdesc, &v);
132 
133 	if (fdesc->slf_sign) {
134 		switch (fdesc->slf_eltlen) {
135 			case 1:
136 				return ((Lword) v.sld_i8);
137 			case 2:
138 				return ((Lword) v.sld_i16);
139 			case 4:
140 				return ((Lword) v.sld_i32);
141 			case 8:
142 				return ((Lword) v.sld_i64);
143 		}
144 	} else {
145 		switch (fdesc->slf_eltlen) {
146 			case 1:
147 				return ((Lword) v.sld_ui8);
148 			case 2:
149 				return ((Lword) v.sld_ui16);
150 			case 4:
151 				return ((Lword) v.sld_ui32);
152 			case 8:
153 				return ((Lword) v.sld_ui64);
154 		}
155 	}
156 
157 	/* This should not be reached */
158 	assert(0);
159 	return (0);
160 }
161 
162 
163 /*
164  * Extract the given integer field, and return its value, cast
165  * to int32_t. Note that this operation must not be used on unsigned
166  * values larger than 31-bits, or on signed values larger than 32-bits,
167  * as information can be lost.
168  */
169 Sword
sl_extract_as_sword(const char * data,int do_swap,const sl_field_t * fdesc)170 sl_extract_as_sword(const char *data, int do_swap, const sl_field_t *fdesc)
171 {
172 	sl_data_t	v;
173 
174 	/* Extract the value from the raw data */
175 	sl_extract_num_field(data, do_swap, fdesc, &v);
176 
177 	if (fdesc->slf_sign) {
178 		switch (fdesc->slf_eltlen) {
179 			case 1:
180 				return ((Sword)v.sld_i8);
181 			case 2:
182 				return ((Sword)v.sld_i16);
183 			case 4:
184 				return ((Sword)v.sld_i32);
185 			case 8:
186 				return ((Sword)v.sld_i64);
187 		}
188 	} else {
189 		switch (fdesc->slf_eltlen) {
190 			case 1:
191 				return ((Sword)v.sld_ui8);
192 			case 2:
193 				return ((Sword)v.sld_ui16);
194 			case 4:
195 				return ((Sword)v.sld_ui32);
196 			case 8:
197 				return ((Sword)v.sld_ui64);
198 		}
199 	}
200 
201 	/* This should not be reached */
202 	assert(0);
203 	return (0);
204 }
205 
206 
207 /*
208  * Extract the integral field and format it into the supplied buffer.
209  */
210 const char *
sl_fmt_num(const char * data,int do_swap,const sl_field_t * fdesc,sl_fmt_num_t fmt_type,sl_fmtbuf_t buf)211 sl_fmt_num(const char *data, int do_swap, const sl_field_t *fdesc,
212     sl_fmt_num_t fmt_type, sl_fmtbuf_t buf)
213 {
214 	/*
215 	 * These static arrays are indexed by [fdesc->slf_sign][fmt_type]
216 	 * to get a format string to use for the specified combination.
217 	 */
218 	static const char *fmt_i8[2][3] = {
219 		{
220 			MSG_ORIG(MSG_CNOTE_FMT_U),
221 			MSG_ORIG(MSG_CNOTE_FMT_X),
222 			MSG_ORIG(MSG_CNOTE_FMT_Z2X)
223 		},
224 		{
225 			MSG_ORIG(MSG_CNOTE_FMT_D),
226 			MSG_ORIG(MSG_CNOTE_FMT_X),
227 			MSG_ORIG(MSG_CNOTE_FMT_Z2X)
228 		}
229 	};
230 	static const char *fmt_i16[2][3] = {
231 		{
232 			MSG_ORIG(MSG_CNOTE_FMT_U),
233 			MSG_ORIG(MSG_CNOTE_FMT_X),
234 			MSG_ORIG(MSG_CNOTE_FMT_Z4X)
235 		},
236 		{
237 			MSG_ORIG(MSG_CNOTE_FMT_D),
238 			MSG_ORIG(MSG_CNOTE_FMT_X),
239 			MSG_ORIG(MSG_CNOTE_FMT_Z4X)
240 		}
241 	};
242 	static const char *fmt_i32[2][3] = {
243 		{
244 			MSG_ORIG(MSG_CNOTE_FMT_U),
245 			MSG_ORIG(MSG_CNOTE_FMT_X),
246 			MSG_ORIG(MSG_CNOTE_FMT_Z8X)
247 		},
248 		{
249 			MSG_ORIG(MSG_CNOTE_FMT_D),
250 			MSG_ORIG(MSG_CNOTE_FMT_X),
251 			MSG_ORIG(MSG_CNOTE_FMT_Z8X)
252 		}
253 	};
254 	static const char *fmt_i64[2][3] = {
255 		{
256 			MSG_ORIG(MSG_CNOTE_FMT_LLU),
257 			MSG_ORIG(MSG_CNOTE_FMT_LLX),
258 			MSG_ORIG(MSG_CNOTE_FMT_Z16LLX)
259 		},
260 		{
261 			MSG_ORIG(MSG_CNOTE_FMT_LLD),
262 			MSG_ORIG(MSG_CNOTE_FMT_LLX),
263 			MSG_ORIG(MSG_CNOTE_FMT_Z16LLX)
264 		}
265 	};
266 
267 	sl_data_t	v;
268 
269 	/* Extract the value from the raw data */
270 	sl_extract_num_field(data, do_swap, fdesc, &v);
271 
272 	/*
273 	 * Format into the buffer. Note that we depend on the signed
274 	 * and unsigned versions of each width being equivalent as long
275 	 * as the format specifies the proper formatting.
276 	 */
277 	switch (fdesc->slf_eltlen) {
278 	case 1:
279 		(void) snprintf(buf, sizeof (sl_fmtbuf_t),
280 		    fmt_i8[fdesc->slf_sign][fmt_type], (uint32_t)v.sld_ui8);
281 		break;
282 
283 	case 2:
284 		(void) snprintf(buf, sizeof (sl_fmtbuf_t),
285 		    fmt_i16[fdesc->slf_sign][fmt_type], (uint32_t)v.sld_ui16);
286 		break;
287 
288 	case 4:
289 		(void) snprintf(buf, sizeof (sl_fmtbuf_t),
290 		    fmt_i32[fdesc->slf_sign][fmt_type], v.sld_ui32);
291 		break;
292 
293 	case 8:
294 		(void) snprintf(buf, sizeof (sl_fmtbuf_t),
295 		    fmt_i64[fdesc->slf_sign][fmt_type], v.sld_ui64);
296 		break;
297 	}
298 
299 	return (buf);
300 }
301 
302 /*
303  * Return structure layout definition for the given machine type,
304  * or NULL if the specified machine is not supported.
305  */
306 const sl_arch_layout_t	*
sl_mach(Half mach)307 sl_mach(Half mach)
308 {
309 	switch (mach) {
310 	case EM_386:
311 		return (struct_layout_i386());
312 
313 	case EM_AMD64:
314 		return (struct_layout_amd64());
315 
316 	case EM_SPARC:
317 	case EM_SPARC32PLUS:
318 		return (struct_layout_sparc());
319 
320 	case EM_SPARCV9:
321 		return (struct_layout_sparcv9());
322 	}
323 
324 	/* Unsupported architecture */
325 	return (NULL);
326 }
327