elfconst.c revision 11827:d7ef53deac3f
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 2010 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#include	<stdlib.h>
28#include	<stdio.h>
29#include	<_elfedit.h>
30#include	<conv.h>
31#include	<msg.h>
32
33
34
35/*
36 * This file contains support for mapping well known ELF constants
37 * to their numeric values. It is a layer on top of the elfedit_atoui()
38 * routines defined in util.c. The idea is that centralizing all the
39 * support for such constants will improve consistency between modules,
40 * allow for sharing of commonly needed items, and make the modules
41 * simpler.
42 */
43
44
45
46
47/*
48 * elfedit output style, with and without leading -o
49 */
50static elfedit_atoui_sym_t sym_outstyle[] = {
51	{ MSG_ORIG(MSG_STR_DEFAULT),		ELFEDIT_OUTSTYLE_DEFAULT },
52	{ MSG_ORIG(MSG_STR_SIMPLE),		ELFEDIT_OUTSTYLE_SIMPLE },
53	{ MSG_ORIG(MSG_STR_NUM),		ELFEDIT_OUTSTYLE_NUM },
54	{ NULL }
55};
56static elfedit_atoui_sym_t sym_minus_o_outstyle[] = {
57	{ MSG_ORIG(MSG_STR_MINUS_O_DEFAULT),	ELFEDIT_OUTSTYLE_DEFAULT },
58	{ MSG_ORIG(MSG_STR_MINUS_O_SIMPLE),	ELFEDIT_OUTSTYLE_SIMPLE },
59	{ MSG_ORIG(MSG_STR_MINUS_O_NUM),	ELFEDIT_OUTSTYLE_NUM },
60	{ NULL }
61};
62
63
64/*
65 * Booleans
66 */
67static elfedit_atoui_sym_t sym_bool[] = {
68	{ MSG_ORIG(MSG_STR_T),			1 },
69	{ MSG_ORIG(MSG_STR_F),			0 },
70	{ MSG_ORIG(MSG_STR_TRUE),		1 },
71	{ MSG_ORIG(MSG_STR_FALSE),		0 },
72	{ MSG_ORIG(MSG_STR_ON),			1 },
73	{ MSG_ORIG(MSG_STR_OFF),		0 },
74	{ MSG_ORIG(MSG_STR_YES),		1 },
75	{ MSG_ORIG(MSG_STR_NO),			0 },
76	{ MSG_ORIG(MSG_STR_Y),			1 },
77	{ MSG_ORIG(MSG_STR_N),			0 },
78	{ NULL }
79};
80
81/*
82 * ELF strings for SHT_STRTAB
83 */
84static elfedit_atoui_sym_t sym_sht_strtab[] = {
85	{ MSG_ORIG(MSG_SHT_STRTAB),		SHT_STRTAB },
86	{ MSG_ORIG(MSG_SHT_STRTAB_ALT1),	SHT_STRTAB },
87
88	{ NULL }
89};
90
91
92/*
93 * Strings for SHT_SYMTAB
94 */
95static elfedit_atoui_sym_t sym_sht_symtab[] = {
96	{ MSG_ORIG(MSG_SHT_SYMTAB),		SHT_SYMTAB },
97	{ MSG_ORIG(MSG_SHT_SYMTAB_ALT1),	SHT_SYMTAB },
98
99	{ NULL }
100};
101
102/*
103 * Strings for SHT_DYNSYM
104 */
105static elfedit_atoui_sym_t sym_sht_dynsym[] = {
106	{ MSG_ORIG(MSG_SHT_DYNSYM),		SHT_DYNSYM },
107	{ MSG_ORIG(MSG_SHT_DYNSYM_ALT1),	SHT_DYNSYM },
108
109	{ NULL }
110};
111
112/*
113 * Strings for SHT_SUNW_LDYNSYM
114 */
115static elfedit_atoui_sym_t sym_sht_ldynsym[] = {
116	{ MSG_ORIG(MSG_SHT_SUNW_LDYNSYM),	SHT_SUNW_LDYNSYM },
117	{ MSG_ORIG(MSG_SHT_SUNW_LDYNSYM_ALT1),	SHT_SUNW_LDYNSYM },
118
119	{ NULL }
120};
121
122
123
124/*
125 * Types of items found in sym_table[]. All items other than STE_STATIC
126 * pulls strings from libconv, differing in the interface required by
127 * the libconv iteration function used.
128 */
129typedef enum {
130	STE_STATIC =		0,	/* Constants are statically defined */
131	STE_LC =		1,	/* Libconv, pull once */
132	STE_LC_OS =		2,	/* From libconv, osabi dependency */
133	STE_LC_MACH =		3,	/* From libconv, mach dependency */
134	STE_LC_OS_MACH =	4	/* From libconv, osabi/mach dep. */
135} ste_type_t;
136
137/*
138 * Interface of functions called to fill strings from libconv
139 */
140typedef conv_iter_ret_t	(* libconv_iter_func_simple_t)(
141			    Conv_fmt_flags_t, conv_iter_cb_t, void *);
142typedef conv_iter_ret_t	(* libconv_iter_func_os_t)(conv_iter_osabi_t,
143			    Conv_fmt_flags_t, conv_iter_cb_t, void *);
144typedef conv_iter_ret_t	(* libconv_iter_func_mach_t)(Half,
145			    Conv_fmt_flags_t, conv_iter_cb_t, void *);
146typedef conv_iter_ret_t	(* libconv_iter_func_os_mach_t)(conv_iter_osabi_t, Half,
147			    Conv_fmt_flags_t, conv_iter_cb_t, void *);
148typedef union {
149	libconv_iter_func_simple_t	simple;
150	libconv_iter_func_os_t		osabi;
151	libconv_iter_func_mach_t	mach;
152	libconv_iter_func_os_mach_t	osabi_mach;
153} libconv_iter_func_t;
154
155/*
156 * State for each type of constant
157 */
158typedef struct {
159	ste_type_t		ste_type;	/* Type of entry */
160	elfedit_atoui_sym_t	*ste_arr;	/* NULL, or atoui array */
161	void			*ste_alloc;	/* Current memory allocation */
162	size_t			ste_nelts;	/* # items in ste_alloc */
163	libconv_iter_func_t	ste_conv_func;	/* libconv fill function */
164} sym_table_ent_t;
165
166
167/*
168 * Array of state for each constant type, including the array of atoui
169 * pointers, for each constant type, indexed by elfedit_const_t value.
170 * The number and order of entries in this table must agree with the
171 * definition of elfedit_const_t in elfedit.h.
172 *
173 * note:
174 * -	STE_STATIC items must supply a statically allocated buffer here.
175 * -	The non-STE_STATIC items use libconv strings. These items are
176 *	initialized by init_libconv_strings() at runtime, and are represented
177 *	by a simple { 0 } here. The memory used for these arrays is dynamic,
178 *	and can be released and rebuilt at runtime as necessary to keep up
179 *	with changes in osabi or machine type.
180 */
181static sym_table_ent_t sym_table[ELFEDIT_CONST_NUM] = {
182						/* #: ELFEDIT_CONST_xxx */
183	{ STE_STATIC, sym_outstyle },		/* 0: OUTSTYLE */
184	{ STE_STATIC, sym_minus_o_outstyle },	/* 1: OUTSTYLE_MO */
185	{ STE_STATIC, sym_bool },		/* 2: BOOL */
186	{ STE_STATIC, sym_sht_strtab },		/* 3: SHT_STRTAB */
187	{ STE_STATIC, sym_sht_symtab },		/* 4: SHT_SYMTAB */
188	{ STE_STATIC, sym_sht_dynsym },		/* 5: SHT_DYNSYM */
189	{ STE_STATIC, sym_sht_ldynsym },	/* 6: SHT_LDYNSYM */
190	{ 0 },					/* 7: SHN */
191	{ 0 },					/* 8: SHT */
192	{ 0 },					/* 9: SHT_ALLSYMTAB */
193	{ 0 },					/* 10: DT */
194	{ 0 },					/* 11: DF */
195	{ 0 },					/* 12: DF_P1 */
196	{ 0 },					/* 13: DF_1 */
197	{ 0 },					/* 14: DTF_1 */
198	{ 0 },					/* 15: EI */
199	{ 0 },					/* 16: ET */
200	{ 0 },					/* 17: ELFCLASS */
201	{ 0 },					/* 18: ELFDATA */
202	{ 0 },					/* 19: EF */
203	{ 0 },					/* 20: EV */
204	{ 0 },					/* 21: EM */
205	{ 0 },					/* 22: ELFOSABI */
206	{ 0 },					/* 23: EAV osabi version */
207	{ 0 },					/* 24: PT */
208	{ 0 },					/* 25: PF */
209	{ 0 },					/* 26: SHF */
210	{ 0 },					/* 27: STB */
211	{ 0 },					/* 28: STT */
212	{ 0 },					/* 29: STV */
213	{ 0 },					/* 30: SYMINFO_BT */
214	{ 0 },					/* 31: SYMINFO_FLG */
215	{ 0 },					/* 32: CA */
216	{ 0 },					/* 33: AV */
217	{ 0 },					/* 34: SF1_SUNW */
218};
219#if ELFEDIT_CONST_NUM != (ELFEDIT_CONST_SF1_SUNW)
220error "ELFEDIT_CONST_NUM has grown. Update sym_table[]"
221#endif
222
223
224
225
226/*
227 * Used to count the number of descriptors that will be needed to hold
228 * strings from libconv.
229 */
230/*ARGSUSED*/
231static conv_iter_ret_t
232libconv_count_cb(const char *str, Conv_elfvalue_t value, void *uvalue)
233{
234	size_t *cnt = (size_t *)uvalue;
235
236	(*cnt)++;
237	return (CONV_ITER_CONT);
238}
239
240/*
241 * Used to fill in the descriptors with strings from libconv.
242 */
243typedef struct {
244	size_t			cur;	/* Index of next descriptor */
245	size_t			cnt;	/* # of descriptors */
246	elfedit_atoui_sym_t	*desc;	/* descriptors */
247} libconv_fill_state_t;
248
249static conv_iter_ret_t
250libconv_fill_cb(const char *str, Conv_elfvalue_t value, void *uvalue)
251{
252	libconv_fill_state_t	*fill_state = (libconv_fill_state_t *)uvalue;
253	elfedit_atoui_sym_t	*sym = &fill_state->desc[fill_state->cur++];
254
255	sym->sym_name = str;
256	sym->sym_value = value;
257	return (CONV_ITER_CONT);
258}
259
260
261/*
262 * Call the iteration function using the correct calling sequence for
263 * the libconv routine.
264 */
265static void
266libconv_fill_iter(sym_table_ent_t *sym, conv_iter_osabi_t osabi, Half mach,
267    conv_iter_cb_t func, void *uvalue)
268{
269	switch (sym->ste_type) {
270	case STE_LC:
271		(void) (* sym->ste_conv_func.simple)(
272		    CONV_FMT_ALT_CF, func, uvalue);
273		(void) (* sym->ste_conv_func.simple)(
274		    CONV_FMT_ALT_NF, func, uvalue);
275		break;
276
277	case STE_LC_OS:
278		(void) (* sym->ste_conv_func.osabi)(osabi,
279		    CONV_FMT_ALT_CF, func, uvalue);
280		(void) (* sym->ste_conv_func.osabi)(osabi,
281		    CONV_FMT_ALT_NF, func, uvalue);
282		break;
283
284	case STE_LC_MACH:
285		(void) (* sym->ste_conv_func.mach)(mach,
286		    CONV_FMT_ALT_CF, func, uvalue);
287		(void) (* sym->ste_conv_func.mach)(mach,
288		    CONV_FMT_ALT_NF, func, uvalue);
289		break;
290
291	case STE_LC_OS_MACH:
292		(void) (* sym->ste_conv_func.osabi_mach)(osabi, mach,
293		    CONV_FMT_ALT_CF, func, uvalue);
294		(void) (* sym->ste_conv_func.osabi_mach)(osabi, mach,
295		    CONV_FMT_ALT_NF, func, uvalue);
296		break;
297	}
298}
299
300/*
301 * Allocate/Fill an atoui array for the specified constant.
302 */
303static void
304libconv_fill(sym_table_ent_t *sym, conv_iter_osabi_t osabi, Half mach)
305{
306	libconv_fill_state_t	fill_state;
307
308	/* How many descriptors will we need? */
309	fill_state.cnt = 1;		/* Extra for NULL termination */
310	libconv_fill_iter(sym, osabi, mach, libconv_count_cb, &fill_state.cnt);
311
312	/*
313	 * If there is an existing allocation, and it is not large enough,
314	 * release it.
315	 */
316	if ((sym->ste_alloc != NULL) && (fill_state.cnt > sym->ste_nelts)) {
317		free(sym->ste_alloc);
318		sym->ste_alloc = NULL;
319		sym->ste_nelts = 0;
320	}
321
322	/* Allocate memory if don't already have an allocation */
323	if (sym->ste_alloc == NULL) {
324		sym->ste_alloc = elfedit_malloc(MSG_INTL(MSG_ALLOC_ELFCONDESC),
325		    fill_state.cnt * sizeof (*fill_state.desc));
326		sym->ste_nelts = fill_state.cnt;
327	}
328
329	/* Fill the array */
330	fill_state.desc = sym->ste_alloc;
331	fill_state.cur = 0;
332	libconv_fill_iter(sym, osabi, mach, libconv_fill_cb, &fill_state);
333
334	/* Add null termination */
335	fill_state.desc[fill_state.cur].sym_name = NULL;
336	fill_state.desc[fill_state.cur].sym_value = 0;
337
338	/* atoui array for this item is now available */
339	sym->ste_arr = fill_state.desc;
340}
341
342/*
343 * Should be called on first call to elfedit_const_to_atoui(). Does the
344 * runtime initialization of sym_table.
345 */
346static void
347init_libconv_strings(conv_iter_osabi_t *osabi, Half *mach)
348{
349	/*
350	 * It is critical that the ste_type and ste_conv_func values
351	 * agree. Since the libconv iteration function signatures can
352	 * change (gain or lose an osabi or mach argument), we want to
353	 * ensure that the compiler will catch such changes.
354	 *
355	 * The compiler will catch an attempt to assign a function of
356	 * the wrong type to ste_conv_func. Using these macros, we ensure
357	 * that the ste_type and function assignment happen as a unit.
358	 */
359#define	LC(_ndx, _func) sym_table[_ndx].ste_type = STE_LC; \
360	sym_table[_ndx].ste_conv_func.simple = _func;
361#define	LC_OS(_ndx, _func) sym_table[_ndx].ste_type = STE_LC_OS; \
362	sym_table[_ndx].ste_conv_func.osabi = _func;
363#define	LC_MACH(_ndx, _func) sym_table[_ndx].ste_type = STE_LC_MACH; \
364	sym_table[_ndx].ste_conv_func.mach = _func;
365#define	LC_OS_MACH(_ndx, _func) sym_table[_ndx].ste_type = STE_LC_OS_MACH; \
366	sym_table[_ndx].ste_conv_func.osabi_mach = _func;
367
368
369	if (!state.file.present) {
370		/*
371		 * No input file: Supply the maximal set of strings for
372		 * all osabi and mach values understood by libconv.
373		 */
374		*osabi = CONV_OSABI_ALL;
375		*mach = CONV_MACH_ALL;
376	} else if (state.elf.elfclass == ELFCLASS32) {
377		*osabi = state.elf.obj_state.s32->os_ehdr->e_ident[EI_OSABI];
378		*mach = state.elf.obj_state.s32->os_ehdr->e_machine;
379	} else {
380		*osabi = state.elf.obj_state.s64->os_ehdr->e_ident[EI_OSABI];
381		*mach = state.elf.obj_state.s64->os_ehdr->e_machine;
382	}
383
384	/* Set up non- STE_STATIC libconv fill functions */
385	LC_OS_MACH(ELFEDIT_CONST_SHN,		conv_iter_sym_shndx);
386	LC_OS_MACH(ELFEDIT_CONST_SHT,		conv_iter_sec_type);
387	LC_OS(ELFEDIT_CONST_SHT_ALLSYMTAB,	conv_iter_sec_symtab);
388	LC_OS_MACH(ELFEDIT_CONST_DT,		conv_iter_dyn_tag);
389	LC(ELFEDIT_CONST_DF,			conv_iter_dyn_flag);
390	LC(ELFEDIT_CONST_DF_P1,			conv_iter_dyn_posflag1);
391	LC(ELFEDIT_CONST_DF_1,			conv_iter_dyn_flag1);
392	LC(ELFEDIT_CONST_DTF_1,			conv_iter_dyn_feature1);
393	LC(ELFEDIT_CONST_EI,			conv_iter_ehdr_eident);
394	LC_OS(ELFEDIT_CONST_ET,			conv_iter_ehdr_type);
395	LC(ELFEDIT_CONST_ELFCLASS,		conv_iter_ehdr_class);
396	LC(ELFEDIT_CONST_ELFDATA,		conv_iter_ehdr_data);
397	LC_MACH(ELFEDIT_CONST_EF,		conv_iter_ehdr_flags);
398	LC(ELFEDIT_CONST_EV,			conv_iter_ehdr_vers);
399	LC(ELFEDIT_CONST_EM,			conv_iter_ehdr_mach);
400	LC(ELFEDIT_CONST_ELFOSABI,		conv_iter_ehdr_osabi);
401	LC_OS(ELFEDIT_CONST_EAV,		conv_iter_ehdr_abivers);
402	LC_OS(ELFEDIT_CONST_PT,			conv_iter_phdr_type);
403	LC_OS(ELFEDIT_CONST_PF,			conv_iter_phdr_flags);
404	LC_OS_MACH(ELFEDIT_CONST_SHF,		conv_iter_sec_flags);
405	LC(ELFEDIT_CONST_STB,			conv_iter_sym_info_bind);
406	LC_MACH(ELFEDIT_CONST_STT,		conv_iter_sym_info_type);
407	LC(ELFEDIT_CONST_STV,			conv_iter_sym_other_vis);
408	LC(ELFEDIT_CONST_SYMINFO_BT,		conv_iter_syminfo_boundto);
409	LC(ELFEDIT_CONST_SYMINFO_FLG,		conv_iter_syminfo_flags);
410	LC(ELFEDIT_CONST_CA,			conv_iter_cap_tags);
411	LC_MACH(ELFEDIT_CONST_HW1_SUNW,		conv_iter_cap_val_hw1);
412	LC(ELFEDIT_CONST_SF1_SUNW,		conv_iter_cap_val_sf1);
413	LC_MACH(ELFEDIT_CONST_HW2_SUNW,		conv_iter_cap_val_hw2);
414
415#undef LC
416#undef LC_OS
417#undef LC_MACH
418#undef LC_OS_MACH
419}
420
421/*
422 * If the user has changed the osabi or machine type of the object,
423 * then we need to discard the strings we've loaded from libconv
424 * that are dependent on these values.
425 */
426static void
427invalidate_libconv_strings(conv_iter_osabi_t *osabi, Half *mach)
428{
429	uchar_t		cur_osabi;
430	Half		cur_mach;
431	sym_table_ent_t	*sym;
432	int		osabi_change, mach_change;
433	int		i;
434
435
436	/* Reset the ELF header change notification */
437	state.elf.elfconst_ehdr_change = 0;
438
439	if (state.elf.elfclass == ELFCLASS32) {
440		cur_osabi = state.elf.obj_state.s32->os_ehdr->e_ident[EI_OSABI];
441		cur_mach = state.elf.obj_state.s32->os_ehdr->e_machine;
442	} else {
443		cur_osabi = state.elf.obj_state.s64->os_ehdr->e_ident[EI_OSABI];
444		cur_mach = state.elf.obj_state.s64->os_ehdr->e_machine;
445	}
446
447	/* What has changed? */
448	mach_change = *mach != cur_mach;
449	osabi_change = *osabi != cur_osabi;
450	if (!(mach_change || osabi_change))
451		return;
452
453	/*
454	 * Set the ste_arr pointer to NULL for any items that
455	 * depend on the things that have changed. Note that we
456	 * do not release the allocated memory --- it may turn
457	 * out to be large enough to hold the new strings, so we
458	 * keep the allocation and leave that decision to the fill
459	 * routine, which will run the next time those strings are
460	 * needed.
461	 */
462	for (i = 0, sym = sym_table;
463	    i < (sizeof (sym_table) / sizeof (sym_table[0])); i++, sym++) {
464		if (sym->ste_arr == NULL)
465			continue;
466
467		switch (sym->ste_type) {
468		case STE_LC_OS:
469			if (osabi_change)
470				sym->ste_arr = NULL;
471			break;
472
473		case STE_LC_MACH:
474			if (mach_change)
475				sym->ste_arr = NULL;
476			break;
477
478		case STE_LC_OS_MACH:
479			if (osabi_change || mach_change)
480				sym->ste_arr = NULL;
481			break;
482		}
483	}
484
485	*mach = cur_mach;
486	*osabi = cur_osabi;
487}
488
489
490
491/*
492 * Given an elfedit_const_t value, return the array of elfedit_atoui_sym_t
493 * entries that it represents.
494 */
495elfedit_atoui_sym_t *
496elfedit_const_to_atoui(elfedit_const_t const_type)
497{
498	static int			first = 1;
499	static conv_iter_osabi_t	osabi;
500	static Half			mach;
501
502	sym_table_ent_t	*sym;
503
504	if (first) {
505		init_libconv_strings(&osabi, &mach);
506		first = 0;
507	}
508
509	if ((const_type < 0) ||
510	    (const_type >= (sizeof (sym_table) / sizeof (sym_table[0]))))
511		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADCONST));
512	sym = &sym_table[const_type];
513
514	/*
515	 * If the constant is not STE_STATIC, then we may need to fetch
516	 * the strings from libconv.
517	 */
518	if (sym->ste_type != STE_STATIC) {
519		/*
520		 * If the ELF header has changed since the last
521		 * time we were called, then we need to invalidate any
522		 * strings previously pulled from libconv that have
523		 * an osabi or machine dependency.
524		 */
525		if (state.elf.elfconst_ehdr_change)
526			invalidate_libconv_strings(&osabi, &mach);
527
528		/* If we don't already have the strings, get them */
529		if (sym->ste_arr == NULL)
530			libconv_fill(sym, osabi, mach);
531	}
532
533	return (sym->ste_arr);
534}
535