xref: /illumos-gate/usr/src/cmd/sgs/libconv/common/elf.c (revision 5aefb6555731130ca4fd295960123d71f2d21fe8)
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 const char *
38 conv_ehdr_class(uchar_t class)
39 {
40 	static char		string[CONV_INV_STRSIZE];
41 	static const Msg	classes[] = {
42 		MSG_ELFCLASSNONE,	MSG_ELFCLASS32,		MSG_ELFCLASS64
43 	};
44 
45 	if (class >= ELFCLASSNUM)
46 		return (conv_invalid_val(string, CONV_INV_STRSIZE, class, 0));
47 	else
48 		return (MSG_ORIG(classes[class]));
49 }
50 
51 const char *
52 conv_ehdr_data(uchar_t data)
53 {
54 	static char		string[CONV_INV_STRSIZE];
55 	static const Msg	datas[] = {
56 		MSG_ELFDATANONE,	MSG_ELFDATA2LSB, 	MSG_ELFDATA2MSB
57 	};
58 
59 	if (data >= ELFDATANUM)
60 		return (conv_invalid_val(string, CONV_INV_STRSIZE, data, 0));
61 	else
62 		return (MSG_ORIG(datas[data]));
63 }
64 
65 static const Msg machines[EM_NUM] = {
66 	MSG_EM_NONE,		MSG_EM_M32,		MSG_EM_SPARC,
67 	MSG_EM_386,		MSG_EM_68K,		MSG_EM_88K,
68 	MSG_EM_486,		MSG_EM_860,		MSG_EM_MIPS,
69 	MSG_EM_UNKNOWN9,	MSG_EM_MIPS_RS3_LE,	MSG_EM_RS6000,
70 	MSG_EM_UNKNOWN12,	MSG_EM_UNKNOWN13,	MSG_EM_UNKNOWN14,
71 	MSG_EM_PA_RISC,		MSG_EM_nCUBE,		MSG_EM_VPP500,
72 	MSG_EM_SPARC32PLUS,	MSG_EM_UNKNOWN19,	MSG_EM_PPC,
73 	MSG_EM_PPC64,		MSG_EM_UNKNOWN22,	MSG_EM_UNKNOWN23,
74 	MSG_EM_UNKNOWN24,	MSG_EM_UNKNOWN25,	MSG_EM_UNKNOWN26,
75 	MSG_EM_UNKNOWN27,	MSG_EM_UNKNOWN28,	MSG_EM_UNKNOWN29,
76 	MSG_EM_UNKNOWN30,	MSG_EM_UNKNOWN31,	MSG_EM_UNKNOWN32,
77 	MSG_EM_UNKNOWN33,	MSG_EM_UNKNOWN34,	MSG_EM_UNKNOWN35,
78 	MSG_EM_Y800,		MSG_EM_FR20,		MSG_EM_RH32,
79 	MSG_EM_RCE,		MSG_EM_ARM,		MSG_EM_ALPHA,
80 	MSG_EM_SH,		MSG_EM_SPARCV9,		MSG_EM_TRICORE,
81 	MSG_EM_ARC,		MSG_EM_H8_300,		MSG_EM_H8_300H,
82 	MSG_EM_H8S,		MSG_EM_H8_500,		MSG_EM_IA_64,
83 	MSG_EM_MIPS_X,		MSG_EM_COLDFIRE,	MSG_EM_68HC12,
84 	MSG_EM_MMA,		MSG_EM_PCP,		MSG_EM_NCPU,
85 	MSG_EM_NDR1,		MSG_EM_STARCORE,	MSG_EM_ME16,
86 	MSG_EM_ST100,		MSG_EM_TINYJ,		MSG_EM_AMD64,
87 	MSG_EM_UNKNOWN63,	MSG_EM_UNKNOWN64,	MSG_EM_UNKNOWN65,
88 	MSG_EM_FX66,		MSG_EM_ST9PLUS,		MSG_EM_ST7,
89 	MSG_EM_68HC16,		MSG_EM_68HC11,		MSG_EM_68HC08,
90 	MSG_EM_68HC05,		MSG_EM_SVX,		MSG_EM_ST19,
91 	MSG_EM_VAX,		MSG_EM_CRIS,		MSG_EM_JAVELIN,
92 	MSG_EM_FIREPATH,	MSG_EM_ZSP,		MSG_EM_MMIX,
93 	MSG_EM_HUANY,		MSG_EM_PRISM,		MSG_EM_AVR,
94 	MSG_EM_FR30,		MSG_EM_D10V,		MSG_EM_D30V,
95 	MSG_EM_V850,		MSG_EM_M32R,		MSG_EM_MN10300,
96 	MSG_EM_MN10200,		MSG_EM_PJ,		MSG_EM_OPENRISC,
97 	MSG_EM_ARC_A5,		MSG_EM_XTENSA
98 };
99 #if	(EM_NUM != (EM_XTENSA + 1))
100 #error	"EM_NUM has grown"
101 #endif
102 
103 const char *
104 conv_ehdr_mach(Half machine)
105 {
106 	static char	string[CONV_INV_STRSIZE];
107 
108 	if (machine >= (EM_NUM))
109 		return (conv_invalid_val(string, CONV_INV_STRSIZE, machine, 0));
110 	else
111 		return (MSG_ORIG(machines[machine]));
112 }
113 
114 const char *
115 conv_ehdr_type(Half etype)
116 {
117 	static char		string[CONV_INV_STRSIZE];
118 	static const Msg	etypes[] = {
119 		MSG_ET_NONE,		MSG_ET_REL,		MSG_ET_EXEC,
120 		MSG_ET_DYN,		MSG_ET_CORE
121 	};
122 
123 	if (etype == ET_SUNWPSEUDO)
124 		return (MSG_ORIG(MSG_ET_SUNWPSEUDO));
125 	else if (etype >= ET_NUM)
126 		return (conv_invalid_val(string, CONV_INV_STRSIZE, etype, 0));
127 	else
128 		return (MSG_ORIG(etypes[etype]));
129 }
130 
131 const char *
132 conv_ehdr_vers(Word version)
133 {
134 	static char		string[CONV_INV_STRSIZE];
135 	static const Msg	versions[] = {
136 		MSG_EV_NONE,		MSG_EV_CURRENT
137 	};
138 
139 	if (version >= EV_NUM)
140 		return (conv_invalid_val(string, CONV_INV_STRSIZE, version, 0));
141 	else
142 		return (MSG_ORIG(versions[version]));
143 }
144 
145 #define	EFLAGSZ	MSG_GBL_OSQBRKT_SIZE + \
146 		MSG_EF_SPARCV9_TSO_SIZE + \
147 		MSG_EF_SPARC_SUN_US1_SIZE + \
148 		MSG_EF_SPARC_HAL_R1_SIZE + \
149 		MSG_EF_SPARC_SUN_US3_SIZE + \
150 		CONV_INV_STRSIZE + MSG_GBL_CSQBRKT_SIZE
151 
152 /*
153  * Make a string representation of the e_flags field.
154  */
155 const char *
156 conv_ehdr_flags(Half mach, Word flags)
157 {
158 	static char	string[EFLAGSZ];
159 	static Val_desc vda[] = {
160 		{ EF_SPARC_32PLUS,	MSG_ORIG(MSG_EF_SPARC_32PLUS) },
161 		{ EF_SPARC_SUN_US1,	MSG_ORIG(MSG_EF_SPARC_SUN_US1) },
162 		{ EF_SPARC_HAL_R1,	MSG_ORIG(MSG_EF_SPARC_HAL_R1) },
163 		{ EF_SPARC_SUN_US3,	MSG_ORIG(MSG_EF_SPARC_SUN_US3) },
164 		{ 0,			0 }
165 	};
166 	static const Msg mm_flags[] = {
167 		MSG_EF_SPARCV9_TSO,	MSG_EF_SPARCV9_PSO,
168 		MSG_EF_SPARCV9_RMO
169 	};
170 	Word		_flags = flags;
171 
172 	/*
173 	 * Non-SPARC architectures presently provide no known flags.
174 	 */
175 	if ((mach == EM_SPARCV9) || (((mach == EM_SPARC) ||
176 	    (mach == EM_SPARC32PLUS)) && flags)) {
177 		/*
178 		 * Valid vendor extension bits for SPARCV9.  These must be
179 		 * updated along with elf_SPARC.h.
180 		 */
181 		(void) strcpy(string, MSG_ORIG(MSG_GBL_OSQBRKT));
182 
183 		if ((mach == EM_SPARCV9) && (flags <= EF_SPARCV9_RMO)) {
184 		    if (strlcat(string,
185 			MSG_ORIG(mm_flags[flags & EF_SPARCV9_MM]),
186 			EFLAGSZ) >= EFLAGSZ)
187 			    return (conv_invalid_val(string, EFLAGSZ,
188 				flags, 0));
189 		    _flags &= ~EF_SPARCV9_MM;
190 		}
191 
192 		if (conv_expn_field(string, EFLAGSZ, vda, flags, _flags, 0, 0))
193 			(void) strlcat(string, MSG_ORIG(MSG_GBL_CSQBRKT),
194 			    EFLAGSZ);
195 
196 		return (string);
197 	}
198 	return (conv_invalid_val(string, EFLAGSZ, flags, CONV_INV_DECIMAL));
199 }
200 
201 /*
202  * A generic means of returning additional information for a rejected file in
203  * terms of a string.
204  */
205 const char *
206 conv_reject_desc(Rej_desc * rej)
207 {
208 	static char	string[CONV_INV_STRSIZE];
209 
210 	ushort_t	type = rej->rej_type;
211 	uint_t		info = rej->rej_info;
212 
213 	if (type == SGS_REJ_MACH)
214 		/* LINTED */
215 		return (conv_ehdr_mach((Half)info));
216 	else if (type == SGS_REJ_CLASS)
217 		/* LINTED */
218 		return (conv_ehdr_class((uchar_t)info));
219 	else if (type == SGS_REJ_DATA)
220 		/* LINTED */
221 		return (conv_ehdr_data((uchar_t)info));
222 	else if (type == SGS_REJ_TYPE)
223 		/* LINTED */
224 		return (conv_ehdr_type((Half)info));
225 	else if ((type == SGS_REJ_BADFLAG) || (type == SGS_REJ_MISFLAG) ||
226 	    (type == SGS_REJ_HAL) || (type == SGS_REJ_US3))
227 		/*
228 		 * Only called from ld.so.1, thus M_MACH is hardcoded.
229 		 */
230 		return (conv_ehdr_flags(M_MACH, (Word)info));
231 	else if (type == SGS_REJ_UNKFILE)
232 		return ((const char *)0);
233 	else if ((type == SGS_REJ_STR) || (type == SGS_REJ_HWCAP_1)) {
234 		if (rej->rej_str)
235 			return ((const char *)rej->rej_str);
236 		else
237 			return (MSG_ORIG(MSG_STR_EMPTY));
238 	} else
239 		return (conv_invalid_val(string, CONV_INV_STRSIZE, info,
240 		    CONV_INV_DECIMAL));
241 }
242