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