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