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.
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.
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]
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
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
48 * elfedit output style, with and without leading -o
50 static 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
},
56 static 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
},
67 static 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 },
82 * ELF strings for SHT_STRTAB
84 static elfedit_atoui_sym_t sym_sht_strtab
[] = {
85 { MSG_ORIG(MSG_SHT_STRTAB
), SHT_STRTAB
},
86 { MSG_ORIG(MSG_SHT_STRTAB_ALT1
), SHT_STRTAB
},
93 * Strings for SHT_SYMTAB
95 static elfedit_atoui_sym_t sym_sht_symtab
[] = {
96 { MSG_ORIG(MSG_SHT_SYMTAB
), SHT_SYMTAB
},
97 { MSG_ORIG(MSG_SHT_SYMTAB_ALT1
), SHT_SYMTAB
},
103 * Strings for SHT_DYNSYM
105 static elfedit_atoui_sym_t sym_sht_dynsym
[] = {
106 { MSG_ORIG(MSG_SHT_DYNSYM
), SHT_DYNSYM
},
107 { MSG_ORIG(MSG_SHT_DYNSYM_ALT1
), SHT_DYNSYM
},
113 * Strings for SHT_SUNW_LDYNSYM
115 static 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
},
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.
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. */
138 * Interface of functions called to fill strings from libconv
140 typedef conv_iter_ret_t (* libconv_iter_func_simple_t
)(
141 Conv_fmt_flags_t
, conv_iter_cb_t
, void *);
142 typedef conv_iter_ret_t (* libconv_iter_func_os_t
)(conv_iter_osabi_t
,
143 Conv_fmt_flags_t
, conv_iter_cb_t
, void *);
144 typedef conv_iter_ret_t (* libconv_iter_func_mach_t
)(Half
,
145 Conv_fmt_flags_t
, conv_iter_cb_t
, void *);
146 typedef 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 *);
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
;
156 * State for each type of constant
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 */
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.
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.
181 static 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 */
192 { 0 }, /* 9: SHT_ALLSYMTAB */
195 { 0 }, /* 12: DF_P1 */
196 { 0 }, /* 13: DF_1 */
197 { 0 }, /* 14: DTF_1 */
200 { 0 }, /* 17: ELFCLASS */
201 { 0 }, /* 18: ELFDATA */
205 { 0 }, /* 22: ELFOSABI */
206 { 0 }, /* 23: EAV osabi version */
213 { 0 }, /* 30: SYMINFO_BT */
214 { 0 }, /* 31: SYMINFO_FLG */
217 { 0 }, /* 34: SF1_SUNW */
219 #if ELFEDIT_CONST_NUM != (ELFEDIT_CONST_SF1_SUNW)
220 error
"ELFEDIT_CONST_NUM has grown. Update sym_table[]"
227 * Used to count the number of descriptors that will be needed to hold
228 * strings from libconv.
231 static conv_iter_ret_t
232 libconv_count_cb(const char *str
, Conv_elfvalue_t value
, void *uvalue
)
234 size_t *cnt
= (size_t *)uvalue
;
237 return (CONV_ITER_CONT
);
241 * Used to fill in the descriptors with strings from libconv.
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
;
249 static conv_iter_ret_t
250 libconv_fill_cb(const char *str
, Conv_elfvalue_t value
, void *uvalue
)
252 libconv_fill_state_t
*fill_state
= (libconv_fill_state_t
*)uvalue
;
253 elfedit_atoui_sym_t
*sym
= &fill_state
->desc
[fill_state
->cur
++];
256 sym
->sym_value
= value
;
257 return (CONV_ITER_CONT
);
262 * Call the iteration function using the correct calling sequence for
263 * the libconv routine.
266 libconv_fill_iter(sym_table_ent_t
*sym
, conv_iter_osabi_t osabi
, Half mach
,
267 conv_iter_cb_t func
, void *uvalue
)
269 switch (sym
->ste_type
) {
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
);
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
);
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
);
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
);
301 * Allocate/Fill an atoui array for the specified constant.
304 libconv_fill(sym_table_ent_t
*sym
, conv_iter_osabi_t osabi
, Half mach
)
306 libconv_fill_state_t fill_state
;
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
);
313 * If there is an existing allocation, and it is not large enough,
316 if ((sym
->ste_alloc
!= NULL
) && (fill_state
.cnt
> sym
->ste_nelts
)) {
317 free(sym
->ste_alloc
);
318 sym
->ste_alloc
= NULL
;
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
;
330 fill_state
.desc
= sym
->ste_alloc
;
332 libconv_fill_iter(sym
, osabi
, mach
, libconv_fill_cb
, &fill_state
);
334 /* Add null termination */
335 fill_state
.desc
[fill_state
.cur
].sym_name
= NULL
;
336 fill_state
.desc
[fill_state
.cur
].sym_value
= 0;
338 /* atoui array for this item is now available */
339 sym
->ste_arr
= fill_state
.desc
;
343 * Should be called on first call to elfedit_const_to_atoui(). Does the
344 * runtime initialization of sym_table.
347 init_libconv_strings(conv_iter_osabi_t
*osabi
, Half
*mach
)
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.
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.
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;
369 if (!state
.file
.present
) {
371 * No input file: Supply the maximal set of strings for
372 * all osabi and mach values understood by libconv.
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
;
380 *osabi
= state
.elf
.obj_state
.s64
->os_ehdr
->e_ident
[EI_OSABI
];
381 *mach
= state
.elf
.obj_state
.s64
->os_ehdr
->e_machine
;
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
);
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.
427 invalidate_libconv_strings(conv_iter_osabi_t
*osabi
, Half
*mach
)
431 sym_table_ent_t
*sym
;
432 int osabi_change
, mach_change
;
436 /* Reset the ELF header change notification */
437 state
.elf
.elfconst_ehdr_change
= 0;
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
;
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
;
447 /* What has changed? */
448 mach_change
= *mach
!= cur_mach
;
449 osabi_change
= *osabi
!= cur_osabi
;
450 if (!(mach_change
|| osabi_change
))
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
462 for (i
= 0, sym
= sym_table
;
463 i
< (sizeof (sym_table
) / sizeof (sym_table
[0])); i
++, sym
++) {
464 if (sym
->ste_arr
== NULL
)
467 switch (sym
->ste_type
) {
479 if (osabi_change
|| mach_change
)
492 * Given an elfedit_const_t value, return the array of elfedit_atoui_sym_t
493 * entries that it represents.
495 elfedit_atoui_sym_t
*
496 elfedit_const_to_atoui(elfedit_const_t const_type
)
498 static int first
= 1;
499 static conv_iter_osabi_t osabi
;
502 sym_table_ent_t
*sym
;
505 init_libconv_strings(&osabi
, &mach
);
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
];
515 * If the constant is not STE_STATIC, then we may need to fetch
516 * the strings from libconv.
518 if (sym
->ste_type
!= STE_STATIC
) {
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.
525 if (state
.elf
.elfconst_ehdr_change
)
526 invalidate_libconv_strings(&osabi
, &mach
);
528 /* If we don't already have the strings, get them */
529 if (sym
->ste_arr
== NULL
)
530 libconv_fill(sym
, osabi
, mach
);
533 return (sym
->ste_arr
);