xref: /illumos-gate/usr/src/cmd/sgs/libconv/common/elf.c (revision 6a074c93c5dee390d8ca2377f42e55418f0a9eb3)
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 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * String conversion routines for ELF header attributes.
30  */
31 #include	<stdio.h>
32 #include	<string.h>
33 #include	"_conv.h"
34 #include	"elf_msg.h"
35 #include	<sys/elf_SPARC.h>
36 
37 
38 
39 /* Instantiate a local copy of conv_map2str() from _conv.h */
40 DEFINE_conv_map2str
41 
42 
43 
44 const char *
45 conv_ehdr_class(uchar_t class, Conv_fmt_flags_t fmt_flags,
46     Conv_inv_buf_t *inv_buf)
47 {
48 	static const Msg	classes[] = {
49 		MSG_ELFCLASSNONE, MSG_ELFCLASS32, MSG_ELFCLASS64
50 	};
51 	static const Msg	classes_alt[] = {
52 		MSG_ELFCLASSNONE_ALT, MSG_ELFCLASS32_ALT, MSG_ELFCLASS64_ALT
53 	};
54 
55 	/* Use alternative strings? */
56 	switch (CONV_TYPE_FMT_ALT(fmt_flags)) {
57 	case CONV_FMT_ALT_DUMP:
58 	case CONV_FMT_ALT_FILE:
59 		return (conv_map2str(inv_buf, class, fmt_flags,
60 		    ARRAY_NELTS(classes_alt), classes_alt));
61 	}
62 
63 	/* Use default strings */
64 	return (conv_map2str(inv_buf, class, fmt_flags,
65 	    ARRAY_NELTS(classes), classes));
66 }
67 
68 const char *
69 conv_ehdr_data(uchar_t data, Conv_fmt_flags_t fmt_flags,
70     Conv_inv_buf_t *inv_buf)
71 {
72 	static const Msg	datas[] = {
73 		MSG_ELFDATANONE, MSG_ELFDATA2LSB, MSG_ELFDATA2MSB
74 	};
75 	static const Msg	datas_dump[] = {
76 		MSG_ELFDATANONE_ALT, MSG_ELFDATA2LSB_ALT1, MSG_ELFDATA2MSB_ALT1
77 	};
78 	static const Msg	datas_file[] = {
79 		MSG_ELFDATANONE_ALT, MSG_ELFDATA2LSB_ALT2, MSG_ELFDATA2MSB_ALT2
80 	};
81 
82 	/* Use alternative strings? */
83 	switch (CONV_TYPE_FMT_ALT(fmt_flags)) {
84 	case CONV_FMT_ALT_DUMP:
85 		return (conv_map2str(inv_buf, data, fmt_flags,
86 		    ARRAY_NELTS(datas_dump), datas_dump));
87 	case CONV_FMT_ALT_FILE:
88 		return (conv_map2str(inv_buf, data, fmt_flags,
89 		    ARRAY_NELTS(datas_file), datas_file));
90 	}
91 
92 	/* Use default strings */
93 	return (conv_map2str(inv_buf, data, fmt_flags,
94 	    ARRAY_NELTS(datas), datas));
95 }
96 
97 static const Msg machines[EM_NUM] = {
98 	MSG_EM_NONE,		MSG_EM_M32,		MSG_EM_SPARC,
99 	MSG_EM_386,		MSG_EM_68K,		MSG_EM_88K,
100 	MSG_EM_486,		MSG_EM_860,		MSG_EM_MIPS,
101 	MSG_EM_S370,		MSG_EM_MIPS_RS3_LE,	MSG_EM_RS6000,
102 	MSG_EM_UNKNOWN12,	MSG_EM_UNKNOWN13,	MSG_EM_UNKNOWN14,
103 	MSG_EM_PA_RISC,		MSG_EM_nCUBE,		MSG_EM_VPP500,
104 	MSG_EM_SPARC32PLUS,	MSG_EM_960,		MSG_EM_PPC,
105 	MSG_EM_PPC64,		MSG_EM_S390,		MSG_EM_UNKNOWN23,
106 	MSG_EM_UNKNOWN24,	MSG_EM_UNKNOWN25,	MSG_EM_UNKNOWN26,
107 	MSG_EM_UNKNOWN27,	MSG_EM_UNKNOWN28,	MSG_EM_UNKNOWN29,
108 	MSG_EM_UNKNOWN30,	MSG_EM_UNKNOWN31,	MSG_EM_UNKNOWN32,
109 	MSG_EM_UNKNOWN33,	MSG_EM_UNKNOWN34,	MSG_EM_UNKNOWN35,
110 	MSG_EM_V800,		MSG_EM_FR20,		MSG_EM_RH32,
111 	MSG_EM_RCE,		MSG_EM_ARM,		MSG_EM_ALPHA,
112 	MSG_EM_SH,		MSG_EM_SPARCV9,		MSG_EM_TRICORE,
113 	MSG_EM_ARC,		MSG_EM_H8_300,		MSG_EM_H8_300H,
114 	MSG_EM_H8S,		MSG_EM_H8_500,		MSG_EM_IA_64,
115 	MSG_EM_MIPS_X,		MSG_EM_COLDFIRE,	MSG_EM_68HC12,
116 	MSG_EM_MMA,		MSG_EM_PCP,		MSG_EM_NCPU,
117 	MSG_EM_NDR1,		MSG_EM_STARCORE,	MSG_EM_ME16,
118 	MSG_EM_ST100,		MSG_EM_TINYJ,		MSG_EM_AMD64,
119 	MSG_EM_PDSP,		MSG_EM_UNKNOWN64,	MSG_EM_UNKNOWN65,
120 	MSG_EM_FX66,		MSG_EM_ST9PLUS,		MSG_EM_ST7,
121 	MSG_EM_68HC16,		MSG_EM_68HC11,		MSG_EM_68HC08,
122 	MSG_EM_68HC05,		MSG_EM_SVX,		MSG_EM_ST19,
123 	MSG_EM_VAX,		MSG_EM_CRIS,		MSG_EM_JAVELIN,
124 	MSG_EM_FIREPATH,	MSG_EM_ZSP,		MSG_EM_MMIX,
125 	MSG_EM_HUANY,		MSG_EM_PRISM,		MSG_EM_AVR,
126 	MSG_EM_FR30,		MSG_EM_D10V,		MSG_EM_D30V,
127 	MSG_EM_V850,		MSG_EM_M32R,		MSG_EM_MN10300,
128 	MSG_EM_MN10200,		MSG_EM_PJ,		MSG_EM_OPENRISC,
129 	MSG_EM_ARC_A5,		MSG_EM_XTENSA
130 };
131 static const Msg machines_alt[EM_NUM] = {
132 	MSG_EM_NONE_ALT,	MSG_EM_M32_ALT,		MSG_EM_SPARC_ALT,
133 	MSG_EM_386_ALT,		MSG_EM_68K_ALT,		MSG_EM_88K_ALT,
134 	MSG_EM_486_ALT,		MSG_EM_860_ALT,		MSG_EM_MIPS_ALT,
135 	MSG_EM_S370,		MSG_EM_MIPS_RS3_LE_ALT,	MSG_EM_RS6000_ALT,
136 	MSG_EM_UNKNOWN12,	MSG_EM_UNKNOWN13,	MSG_EM_UNKNOWN14,
137 	MSG_EM_PA_RISC_ALT,	MSG_EM_nCUBE_ALT,	MSG_EM_VPP500_ALT,
138 	MSG_EM_SPARC32PLUS_ALT,	MSG_EM_960,		MSG_EM_PPC_ALT,
139 	MSG_EM_PPC64_ALT,	MSG_EM_S390,		MSG_EM_UNKNOWN23,
140 	MSG_EM_UNKNOWN24,	MSG_EM_UNKNOWN25,	MSG_EM_UNKNOWN26,
141 	MSG_EM_UNKNOWN27,	MSG_EM_UNKNOWN28,	MSG_EM_UNKNOWN29,
142 	MSG_EM_UNKNOWN30,	MSG_EM_UNKNOWN31,	MSG_EM_UNKNOWN32,
143 	MSG_EM_UNKNOWN33,	MSG_EM_UNKNOWN34,	MSG_EM_UNKNOWN35,
144 	MSG_EM_V800,		MSG_EM_FR20,		MSG_EM_RH32,
145 	MSG_EM_RCE,		MSG_EM_ARM_ALT,		MSG_EM_ALPHA_ALT,
146 	MSG_EM_SH,		MSG_EM_SPARCV9_ALT,	MSG_EM_TRICORE,
147 	MSG_EM_ARC,		MSG_EM_H8_300,		MSG_EM_H8_300H,
148 	MSG_EM_H8S,		MSG_EM_H8_500,		MSG_EM_IA_64_ALT,
149 	MSG_EM_MIPS_X,		MSG_EM_COLDFIRE,	MSG_EM_68HC12,
150 	MSG_EM_MMA,		MSG_EM_PCP,		MSG_EM_NCPU,
151 	MSG_EM_NDR1,		MSG_EM_STARCORE,	MSG_EM_ME16,
152 	MSG_EM_ST100,		MSG_EM_TINYJ,		MSG_EM_AMD64_ALT,
153 	MSG_EM_PDSP,		MSG_EM_UNKNOWN64,	MSG_EM_UNKNOWN65,
154 	MSG_EM_FX66,		MSG_EM_ST9PLUS,		MSG_EM_ST7,
155 	MSG_EM_68HC16,		MSG_EM_68HC11,		MSG_EM_68HC08,
156 	MSG_EM_68HC05,		MSG_EM_SVX,		MSG_EM_ST19,
157 	MSG_EM_VAX_ALT,		MSG_EM_CRIS,		MSG_EM_JAVELIN,
158 	MSG_EM_FIREPATH,	MSG_EM_ZSP,		MSG_EM_MMIX,
159 	MSG_EM_HUANY,		MSG_EM_PRISM,		MSG_EM_AVR,
160 	MSG_EM_FR30,		MSG_EM_D10V,		MSG_EM_D30V,
161 	MSG_EM_V850,		MSG_EM_M32R,		MSG_EM_MN10300,
162 	MSG_EM_MN10200,		MSG_EM_PJ,		MSG_EM_OPENRISC,
163 	MSG_EM_ARC_A5,		MSG_EM_XTENSA
164 };
165 #if	(EM_NUM != (EM_XTENSA + 1))
166 #error	"EM_NUM has grown"
167 #endif
168 
169 const char *
170 conv_ehdr_mach(Half machine, Conv_fmt_flags_t fmt_flags,
171     Conv_inv_buf_t *inv_buf)
172 {
173 	/* Use alternative strings? */
174 	switch (CONV_TYPE_FMT_ALT(fmt_flags)) {
175 	case CONV_FMT_ALT_DUMP:
176 	case CONV_FMT_ALT_FILE:
177 		return (conv_map2str(inv_buf, machine, fmt_flags,
178 		    ARRAY_NELTS(machines_alt), machines_alt));
179 	}
180 
181 	/* Use default strings */
182 	return (conv_map2str(inv_buf, machine, fmt_flags,
183 	    ARRAY_NELTS(machines), machines));
184 }
185 
186 
187 const char *
188 conv_ehdr_type(Half etype, Conv_fmt_flags_t fmt_flags, Conv_inv_buf_t *inv_buf)
189 {
190 	static const Msg	etypes[] = {
191 		MSG_ET_NONE,		MSG_ET_REL,		MSG_ET_EXEC,
192 		MSG_ET_DYN,		MSG_ET_CORE
193 	};
194 	static const Msg	etypes_alt[] = {
195 		MSG_ET_NONE_ALT,	MSG_ET_REL_ALT,		MSG_ET_EXEC_ALT,
196 		MSG_ET_DYN_ALT,		MSG_ET_CORE_ALT
197 	};
198 
199 	if (etype == ET_SUNWPSEUDO) {
200 		switch (CONV_TYPE_FMT_ALT(fmt_flags)) {
201 		case CONV_FMT_ALT_DUMP:
202 		case CONV_FMT_ALT_FILE:
203 			return (MSG_ORIG(MSG_ET_SUNWPSEUDO_ALT));
204 		default:
205 			return (MSG_ORIG(MSG_ET_SUNWPSEUDO));
206 		}
207 	}
208 
209 	/* Use alternative strings? */
210 	switch (CONV_TYPE_FMT_ALT(fmt_flags)) {
211 	case CONV_FMT_ALT_DUMP:
212 	case CONV_FMT_ALT_FILE:
213 		return (conv_map2str(inv_buf, etype, fmt_flags,
214 		    ARRAY_NELTS(etypes_alt), etypes_alt));
215 	}
216 
217 	/* Use default strings */
218 	return (conv_map2str(inv_buf, etype, fmt_flags,
219 	    ARRAY_NELTS(etypes), etypes));
220 
221 }
222 
223 const char *
224 conv_ehdr_vers(Word version, Conv_fmt_flags_t fmt_flags,
225     Conv_inv_buf_t *inv_buf)
226 {
227 	static const Msg	versions[] = {
228 		MSG_EV_NONE,		MSG_EV_CURRENT
229 	};
230 	static const Msg	versions_alt[] = {
231 		MSG_EV_NONE_ALT,	MSG_EV_CURRENT_ALT
232 	};
233 
234 	/* Use alternative strings? */
235 	switch (CONV_TYPE_FMT_ALT(fmt_flags)) {
236 	case CONV_FMT_ALT_DUMP:
237 	case CONV_FMT_ALT_FILE:
238 		return (conv_map2str(inv_buf, version, fmt_flags,
239 		    ARRAY_NELTS(versions_alt), versions_alt));
240 	}
241 
242 	/* Use default strings */
243 	return (conv_map2str(inv_buf, version, fmt_flags,
244 	    ARRAY_NELTS(versions), versions));
245 }
246 
247 #define	EFLAGSZ	CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
248 		MSG_EF_SPARCV9_TSO_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE +  \
249 		MSG_EF_SPARC_SUN_US1_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE +  \
250 		MSG_EF_SPARC_HAL_R1_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE +  \
251 		MSG_EF_SPARC_SUN_US3_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE +  \
252 		CONV_INV_BUFSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
253 
254 /*
255  * Ensure that Conv_ehdr_flags_buf_t is large enough:
256  *
257  * EFLAGSZ is the real minimum size of the buffer required by conv_ehdr_flags().
258  * However, Conv_ehdr_flags_buf_t uses CONV_EHDR_FLAG_BUFSIZE to set the
259  * buffer size. We do things this way because the definition of EFLAGSZ uses
260  * information that is not available in the environment of other programs
261  * that include the conv.h header file.
262  */
263 #if (CONV_EHDR_FLAGS_BUFSIZE != EFLAGSZ) && !defined(__lint)
264 #define	REPORT_BUFSIZE EFLAGSZ
265 #include "report_bufsize.h"
266 #error "CONV_EHDR_FLAGS_BUFSIZE does not match EFLAGSZ"
267 #endif
268 
269 /*
270  * Make a string representation of the e_flags field.
271  */
272 const char *
273 conv_ehdr_flags(Half mach, Word flags, Conv_fmt_flags_t fmt_flags,
274     Conv_ehdr_flags_buf_t *flags_buf)
275 {
276 	static Val_desc vda[] = {
277 		{ EF_SPARC_32PLUS,	MSG_ORIG(MSG_EF_SPARC_32PLUS) },
278 		{ EF_SPARC_SUN_US1,	MSG_ORIG(MSG_EF_SPARC_SUN_US1) },
279 		{ EF_SPARC_HAL_R1,	MSG_ORIG(MSG_EF_SPARC_HAL_R1) },
280 		{ EF_SPARC_SUN_US3,	MSG_ORIG(MSG_EF_SPARC_SUN_US3) },
281 		{ 0,			0 }
282 	};
283 	static const Msg mm_flags[] = {
284 		MSG_EF_SPARCV9_TSO,	MSG_EF_SPARCV9_PSO,
285 		MSG_EF_SPARCV9_RMO
286 	};
287 	static const char *leading_str_arr[2];
288 	static CONV_EXPN_FIELD_ARG conv_arg = {
289 	    NULL, sizeof (flags_buf->buf), vda, leading_str_arr };
290 
291 	const char **lstr = leading_str_arr;
292 
293 	conv_arg.buf = flags_buf->buf;
294 
295 	/*
296 	 * Non-SPARC architectures presently provide no known flags.
297 	 */
298 	if ((mach == EM_SPARCV9) || (((mach == EM_SPARC) ||
299 	    (mach == EM_SPARC32PLUS)) && flags)) {
300 		/*
301 		 * Valid vendor extension bits for SPARCV9.  These must be
302 		 * updated along with elf_SPARC.h.
303 		 */
304 
305 		conv_arg.oflags = conv_arg.rflags = flags;
306 		if ((mach == EM_SPARCV9) && (flags <= EF_SPARCV9_RMO)) {
307 			*lstr++ = MSG_ORIG(mm_flags[flags & EF_SPARCV9_MM]);
308 			conv_arg.rflags &= ~EF_SPARCV9_MM;
309 		}
310 		*lstr = NULL;
311 
312 		(void) conv_expn_field(&conv_arg, fmt_flags);
313 
314 		return (conv_arg.buf);
315 	}
316 
317 	return (conv_invalid_val(&flags_buf->inv_buf, flags, CONV_FMT_DECIMAL));
318 }
319 
320 /*
321  * Make a string representation of the e_ident[EI_OSABI] field.
322  */
323 const char *
324 conv_ehdr_osabi(uchar_t osabi, Conv_fmt_flags_t fmt_flags,
325     Conv_inv_buf_t *inv_buf)
326 {
327 	static const Msg	osabi_arr[] = {
328 		MSG_OSABI_NONE,		MSG_OSABI_HPUX,
329 		MSG_OSABI_NETBSD,	MSG_OSABI_LINUX,
330 		MSG_OSABI_UNKNOWN4,	MSG_OSABI_UNKNOWN5,
331 		MSG_OSABI_SOLARIS,	MSG_OSABI_AIX,
332 		MSG_OSABI_IRIX,		MSG_OSABI_FREEBSD,
333 		MSG_OSABI_TRU64,	MSG_OSABI_MODESTO,
334 		MSG_OSABI_OPENBSD,	MSG_OSABI_OPENVMS,
335 		MSG_OSABI_NSK,		MSG_OSABI_AROS
336 	};
337 	static const Msg	osabi_arr_alt[] = {
338 		MSG_OSABI_NONE_ALT,	MSG_OSABI_HPUX_ALT,
339 		MSG_OSABI_NETBSD_ALT,	MSG_OSABI_LINUX_ALT,
340 		MSG_OSABI_UNKNOWN4,	MSG_OSABI_UNKNOWN5,
341 		MSG_OSABI_SOLARIS_ALT,	MSG_OSABI_AIX_ALT,
342 		MSG_OSABI_IRIX_ALT,	MSG_OSABI_FREEBSD_ALT,
343 		MSG_OSABI_TRU64_ALT,	MSG_OSABI_MODESTO_ALT,
344 		MSG_OSABI_OPENBSD_ALT,	MSG_OSABI_OPENVMS_ALT,
345 		MSG_OSABI_NSK_ALT,	MSG_OSABI_AROS_ALT
346 	};
347 
348 	const char *str;
349 
350 	switch (osabi) {
351 	case ELFOSABI_ARM:
352 		switch (CONV_TYPE_FMT_ALT(fmt_flags)) {
353 		case CONV_FMT_ALT_DUMP:
354 		case CONV_FMT_ALT_FILE:
355 			str = MSG_ORIG(MSG_OSABI_ARM_ALT);
356 			break;
357 		default:
358 			str = MSG_ORIG(MSG_OSABI_ARM);
359 		}
360 		break;
361 
362 	case ELFOSABI_STANDALONE:
363 		switch (CONV_TYPE_FMT_ALT(fmt_flags)) {
364 		case CONV_FMT_ALT_DUMP:
365 		case CONV_FMT_ALT_FILE:
366 			str = MSG_ORIG(MSG_OSABI_STANDALONE_ALT);
367 			break;
368 		default:
369 			str = MSG_ORIG(MSG_OSABI_STANDALONE);
370 		}
371 		break;
372 
373 	default:
374 		switch (CONV_TYPE_FMT_ALT(fmt_flags)) {
375 		case CONV_FMT_ALT_DUMP:
376 		case CONV_FMT_ALT_FILE:
377 			str = conv_map2str(inv_buf, osabi, fmt_flags,
378 			    ARRAY_NELTS(osabi_arr_alt), osabi_arr_alt);
379 			break;
380 		default:
381 			str = conv_map2str(inv_buf, osabi, fmt_flags,
382 			    ARRAY_NELTS(osabi_arr), osabi_arr);
383 		}
384 		break;
385 	}
386 
387 	return (str);
388 }
389 
390 /*
391  * A generic means of returning additional information for a rejected file in
392  * terms of a string.
393  */
394 const char *
395 conv_reject_desc(Rej_desc * rej, Conv_reject_desc_buf_t *reject_desc_buf)
396 {
397 	ushort_t	type = rej->rej_type;
398 	uint_t		info = rej->rej_info;
399 
400 	if (type == SGS_REJ_MACH)
401 		/* LINTED */
402 		return (conv_ehdr_mach((Half)info, 0,
403 		    &reject_desc_buf->inv_buf));
404 	else if (type == SGS_REJ_CLASS)
405 		/* LINTED */
406 		return (conv_ehdr_class((uchar_t)info, 0,
407 		    &reject_desc_buf->inv_buf));
408 	else if (type == SGS_REJ_DATA)
409 		/* LINTED */
410 		return (conv_ehdr_data((uchar_t)info, 0,
411 		    &reject_desc_buf->inv_buf));
412 	else if (type == SGS_REJ_TYPE)
413 		/* LINTED */
414 		return (conv_ehdr_type((Half)info, 0,
415 		    &reject_desc_buf->inv_buf));
416 	else if ((type == SGS_REJ_BADFLAG) || (type == SGS_REJ_MISFLAG) ||
417 	    (type == SGS_REJ_HAL) || (type == SGS_REJ_US3))
418 		/*
419 		 * Only called from ld.so.1, thus M_MACH is hardcoded.
420 		 */
421 		return (conv_ehdr_flags(M_MACH, (Word)info, 0,
422 		    &reject_desc_buf->flags_buf));
423 	else if (type == SGS_REJ_UNKFILE)
424 		return ((const char *)0);
425 	else if ((type == SGS_REJ_STR) || (type == SGS_REJ_HWCAP_1)) {
426 		if (rej->rej_str)
427 			return ((const char *)rej->rej_str);
428 		else
429 			return (MSG_ORIG(MSG_STR_EMPTY));
430 	} else
431 		return (conv_invalid_val(&reject_desc_buf->inv_buf, info,
432 		    CONV_FMT_DECIMAL));
433 }
434