xref: /illumos-gate/usr/src/cmd/sgs/libconv/common/elf.c (revision ba4e3c84e6b9390bbf7df80b5f1d11dec34cc525)
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 2006 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, int fmt_flags)
46 {
47 	static char		string[CONV_INV_STRSIZE];
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 	return (conv_map2str(string, sizeof (string), class, fmt_flags,
56 		ARRAY_NELTS(classes), classes, classes_alt, classes_alt));
57 }
58 
59 const char *
60 conv_ehdr_data(uchar_t data, int fmt_flags)
61 {
62 	static char		string[CONV_INV_STRSIZE];
63 	static const Msg	datas[] = {
64 		MSG_ELFDATANONE, MSG_ELFDATA2LSB, MSG_ELFDATA2MSB
65 	};
66 	static const Msg	datas_dump[] = {
67 		MSG_ELFDATANONE_ALT, MSG_ELFDATA2LSB_ALT1, MSG_ELFDATA2MSB_ALT1
68 	};
69 	static const Msg	datas_file[] = {
70 		MSG_ELFDATANONE_ALT, MSG_ELFDATA2LSB_ALT2, MSG_ELFDATA2MSB_ALT2
71 	};
72 
73 	return (conv_map2str(string, sizeof (string), data, fmt_flags,
74 		ARRAY_NELTS(datas), datas, datas_dump, datas_file));
75 }
76 
77 static const Msg machines[EM_NUM] = {
78 	MSG_EM_NONE,		MSG_EM_M32,		MSG_EM_SPARC,
79 	MSG_EM_386,		MSG_EM_68K,		MSG_EM_88K,
80 	MSG_EM_486,		MSG_EM_860,		MSG_EM_MIPS,
81 	MSG_EM_UNKNOWN9,	MSG_EM_MIPS_RS3_LE,	MSG_EM_RS6000,
82 	MSG_EM_UNKNOWN12,	MSG_EM_UNKNOWN13,	MSG_EM_UNKNOWN14,
83 	MSG_EM_PA_RISC,		MSG_EM_nCUBE,		MSG_EM_VPP500,
84 	MSG_EM_SPARC32PLUS,	MSG_EM_UNKNOWN19,	MSG_EM_PPC,
85 	MSG_EM_PPC64,		MSG_EM_UNKNOWN22,	MSG_EM_UNKNOWN23,
86 	MSG_EM_UNKNOWN24,	MSG_EM_UNKNOWN25,	MSG_EM_UNKNOWN26,
87 	MSG_EM_UNKNOWN27,	MSG_EM_UNKNOWN28,	MSG_EM_UNKNOWN29,
88 	MSG_EM_UNKNOWN30,	MSG_EM_UNKNOWN31,	MSG_EM_UNKNOWN32,
89 	MSG_EM_UNKNOWN33,	MSG_EM_UNKNOWN34,	MSG_EM_UNKNOWN35,
90 	MSG_EM_Y800,		MSG_EM_FR20,		MSG_EM_RH32,
91 	MSG_EM_RCE,		MSG_EM_ARM,		MSG_EM_ALPHA,
92 	MSG_EM_SH,		MSG_EM_SPARCV9,		MSG_EM_TRICORE,
93 	MSG_EM_ARC,		MSG_EM_H8_300,		MSG_EM_H8_300H,
94 	MSG_EM_H8S,		MSG_EM_H8_500,		MSG_EM_IA_64,
95 	MSG_EM_MIPS_X,		MSG_EM_COLDFIRE,	MSG_EM_68HC12,
96 	MSG_EM_MMA,		MSG_EM_PCP,		MSG_EM_NCPU,
97 	MSG_EM_NDR1,		MSG_EM_STARCORE,	MSG_EM_ME16,
98 	MSG_EM_ST100,		MSG_EM_TINYJ,		MSG_EM_AMD64,
99 	MSG_EM_UNKNOWN63,	MSG_EM_UNKNOWN64,	MSG_EM_UNKNOWN65,
100 	MSG_EM_FX66,		MSG_EM_ST9PLUS,		MSG_EM_ST7,
101 	MSG_EM_68HC16,		MSG_EM_68HC11,		MSG_EM_68HC08,
102 	MSG_EM_68HC05,		MSG_EM_SVX,		MSG_EM_ST19,
103 	MSG_EM_VAX,		MSG_EM_CRIS,		MSG_EM_JAVELIN,
104 	MSG_EM_FIREPATH,	MSG_EM_ZSP,		MSG_EM_MMIX,
105 	MSG_EM_HUANY,		MSG_EM_PRISM,		MSG_EM_AVR,
106 	MSG_EM_FR30,		MSG_EM_D10V,		MSG_EM_D30V,
107 	MSG_EM_V850,		MSG_EM_M32R,		MSG_EM_MN10300,
108 	MSG_EM_MN10200,		MSG_EM_PJ,		MSG_EM_OPENRISC,
109 	MSG_EM_ARC_A5,		MSG_EM_XTENSA
110 };
111 static const Msg machines_alt[EM_NUM] = {
112 	MSG_EM_NONE_ALT,	MSG_EM_M32_ALT,		MSG_EM_SPARC_ALT,
113 	MSG_EM_386_ALT,		MSG_EM_68K_ALT,		MSG_EM_88K_ALT,
114 	MSG_EM_486_ALT,		MSG_EM_860_ALT,		MSG_EM_MIPS_ALT,
115 	MSG_EM_UNKNOWN9,	MSG_EM_MIPS_RS3_LE_ALT,	MSG_EM_RS6000_ALT,
116 	MSG_EM_UNKNOWN12,	MSG_EM_UNKNOWN13,	MSG_EM_UNKNOWN14,
117 	MSG_EM_PA_RISC_ALT,	MSG_EM_nCUBE_ALT,	MSG_EM_VPP500_ALT,
118 	MSG_EM_SPARC32PLUS_ALT,	MSG_EM_UNKNOWN19,	MSG_EM_PPC_ALT,
119 	MSG_EM_PPC64_ALT,	MSG_EM_UNKNOWN22,	MSG_EM_UNKNOWN23,
120 	MSG_EM_UNKNOWN24,	MSG_EM_UNKNOWN25,	MSG_EM_UNKNOWN26,
121 	MSG_EM_UNKNOWN27,	MSG_EM_UNKNOWN28,	MSG_EM_UNKNOWN29,
122 	MSG_EM_UNKNOWN30,	MSG_EM_UNKNOWN31,	MSG_EM_UNKNOWN32,
123 	MSG_EM_UNKNOWN33,	MSG_EM_UNKNOWN34,	MSG_EM_UNKNOWN35,
124 	MSG_EM_Y800,		MSG_EM_FR20,		MSG_EM_RH32,
125 	MSG_EM_RCE,		MSG_EM_ARM_ALT,		MSG_EM_ALPHA_ALT,
126 	MSG_EM_SH,		MSG_EM_SPARCV9_ALT,	MSG_EM_TRICORE,
127 	MSG_EM_ARC,		MSG_EM_H8_300,		MSG_EM_H8_300H,
128 	MSG_EM_H8S,		MSG_EM_H8_500,		MSG_EM_IA_64_ALT,
129 	MSG_EM_MIPS_X,		MSG_EM_COLDFIRE,	MSG_EM_68HC12,
130 	MSG_EM_MMA,		MSG_EM_PCP,		MSG_EM_NCPU,
131 	MSG_EM_NDR1,		MSG_EM_STARCORE,	MSG_EM_ME16,
132 	MSG_EM_ST100,		MSG_EM_TINYJ,		MSG_EM_AMD64_ALT,
133 	MSG_EM_UNKNOWN63,	MSG_EM_UNKNOWN64,	MSG_EM_UNKNOWN65,
134 	MSG_EM_FX66,		MSG_EM_ST9PLUS,		MSG_EM_ST7,
135 	MSG_EM_68HC16,		MSG_EM_68HC11,		MSG_EM_68HC08,
136 	MSG_EM_68HC05,		MSG_EM_SVX,		MSG_EM_ST19,
137 	MSG_EM_VAX_ALT,		MSG_EM_CRIS,		MSG_EM_JAVELIN,
138 	MSG_EM_FIREPATH,	MSG_EM_ZSP,		MSG_EM_MMIX,
139 	MSG_EM_HUANY,		MSG_EM_PRISM,		MSG_EM_AVR,
140 	MSG_EM_FR30,		MSG_EM_D10V,		MSG_EM_D30V,
141 	MSG_EM_V850,		MSG_EM_M32R,		MSG_EM_MN10300,
142 	MSG_EM_MN10200,		MSG_EM_PJ,		MSG_EM_OPENRISC,
143 	MSG_EM_ARC_A5,		MSG_EM_XTENSA
144 };
145 #if	(EM_NUM != (EM_XTENSA + 1))
146 #error	"EM_NUM has grown"
147 #endif
148 
149 const char *
150 conv_ehdr_mach(Half machine, int fmt_flags)
151 {
152 	static char	string[CONV_INV_STRSIZE];
153 
154 	return (conv_map2str(string, sizeof (string), machine, fmt_flags,
155 		ARRAY_NELTS(machines), machines, machines_alt, machines_alt));
156 }
157 
158 
159 const char *
160 conv_ehdr_type(Half etype, int fmt_flags)
161 {
162 	static char		string[CONV_INV_STRSIZE];
163 	static const Msg	etypes[] = {
164 		MSG_ET_NONE,		MSG_ET_REL,		MSG_ET_EXEC,
165 		MSG_ET_DYN,		MSG_ET_CORE
166 	};
167 	static const Msg	etypes_alt[] = {
168 		MSG_ET_NONE_ALT,	MSG_ET_REL_ALT,		MSG_ET_EXEC_ALT,
169 		MSG_ET_DYN_ALT,		MSG_ET_CORE_ALT
170 	};
171 
172 	if (etype == ET_SUNWPSEUDO) {
173 		return ((fmt_flags & CONV_FMTALTMASK)
174 			? MSG_ORIG(MSG_ET_SUNWPSEUDO_ALT)
175 			: MSG_ORIG(MSG_ET_SUNWPSEUDO));
176 	}
177 
178 	return (conv_map2str(string, sizeof (string), etype, fmt_flags,
179 		ARRAY_NELTS(etypes), etypes, etypes_alt, etypes_alt));
180 
181 }
182 
183 const char *
184 conv_ehdr_vers(Word version, int fmt_flags)
185 {
186 	static char		string[CONV_INV_STRSIZE];
187 	static const Msg	versions[] = {
188 		MSG_EV_NONE,		MSG_EV_CURRENT
189 	};
190 	static const Msg	versions_alt[] = {
191 		MSG_EV_NONE_ALT,	MSG_EV_CURRENT_ALT
192 	};
193 
194 	return (conv_map2str(string, sizeof (string), version, fmt_flags,
195 		ARRAY_NELTS(versions), versions, versions_alt, versions_alt));
196 }
197 
198 #define	EFLAGSZ	CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
199 		MSG_EF_SPARCV9_TSO_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE +  \
200 		MSG_EF_SPARC_SUN_US1_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE +  \
201 		MSG_EF_SPARC_HAL_R1_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE +  \
202 		MSG_EF_SPARC_SUN_US3_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE +  \
203 		CONV_INV_STRSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
204 
205 /*
206  * Make a string representation of the e_flags field.
207  */
208 const char *
209 conv_ehdr_flags(Half mach, Word flags)
210 {
211 	static char	string[EFLAGSZ];
212 	static Val_desc vda[] = {
213 		{ EF_SPARC_32PLUS,	MSG_ORIG(MSG_EF_SPARC_32PLUS) },
214 		{ EF_SPARC_SUN_US1,	MSG_ORIG(MSG_EF_SPARC_SUN_US1) },
215 		{ EF_SPARC_HAL_R1,	MSG_ORIG(MSG_EF_SPARC_HAL_R1) },
216 		{ EF_SPARC_SUN_US3,	MSG_ORIG(MSG_EF_SPARC_SUN_US3) },
217 		{ 0,			0 }
218 	};
219 	static const Msg mm_flags[] = {
220 		MSG_EF_SPARCV9_TSO,	MSG_EF_SPARCV9_PSO,
221 		MSG_EF_SPARCV9_RMO
222 	};
223 	static const char *leading_str_arr[2];
224 	static CONV_EXPN_FIELD_ARG conv_arg = { string, sizeof (string), vda,
225 		leading_str_arr };
226 
227 	const char **lstr = leading_str_arr;
228 
229 	/*
230 	 * Non-SPARC architectures presently provide no known flags.
231 	 */
232 	if ((mach == EM_SPARCV9) || (((mach == EM_SPARC) ||
233 	    (mach == EM_SPARC32PLUS)) && flags)) {
234 		/*
235 		 * Valid vendor extension bits for SPARCV9.  These must be
236 		 * updated along with elf_SPARC.h.
237 		 */
238 
239 		conv_arg.oflags = conv_arg.rflags = flags;
240 		if ((mach == EM_SPARCV9) && (flags <= EF_SPARCV9_RMO)) {
241 			*lstr++ = MSG_ORIG(mm_flags[flags & EF_SPARCV9_MM]);
242 			conv_arg.rflags &= ~EF_SPARCV9_MM;
243 		}
244 		*lstr = NULL;
245 
246 		(void) conv_expn_field(&conv_arg);
247 
248 		return (string);
249 	}
250 	return (conv_invalid_val(string, EFLAGSZ, flags, CONV_FMT_DECIMAL));
251 }
252 
253 /*
254  * A generic means of returning additional information for a rejected file in
255  * terms of a string.
256  */
257 const char *
258 conv_reject_desc(Rej_desc * rej)
259 {
260 	static char	string[CONV_INV_STRSIZE];
261 
262 	ushort_t	type = rej->rej_type;
263 	uint_t		info = rej->rej_info;
264 
265 	if (type == SGS_REJ_MACH)
266 		/* LINTED */
267 		return (conv_ehdr_mach((Half)info, 0));
268 	else if (type == SGS_REJ_CLASS)
269 		/* LINTED */
270 		return (conv_ehdr_class((uchar_t)info, 0));
271 	else if (type == SGS_REJ_DATA)
272 		/* LINTED */
273 		return (conv_ehdr_data((uchar_t)info, 0));
274 	else if (type == SGS_REJ_TYPE)
275 		/* LINTED */
276 		return (conv_ehdr_type((Half)info, 0));
277 	else if ((type == SGS_REJ_BADFLAG) || (type == SGS_REJ_MISFLAG) ||
278 	    (type == SGS_REJ_HAL) || (type == SGS_REJ_US3))
279 		/*
280 		 * Only called from ld.so.1, thus M_MACH is hardcoded.
281 		 */
282 		return (conv_ehdr_flags(M_MACH, (Word)info));
283 	else if (type == SGS_REJ_UNKFILE)
284 		return ((const char *)0);
285 	else if ((type == SGS_REJ_STR) || (type == SGS_REJ_HWCAP_1)) {
286 		if (rej->rej_str)
287 			return ((const char *)rej->rej_str);
288 		else
289 			return (MSG_ORIG(MSG_STR_EMPTY));
290 	} else
291 		return (conv_invalid_val(string, CONV_INV_STRSIZE, info,
292 		    CONV_FMT_DECIMAL));
293 }
294