#include <stdlib.h>
#include <stdio.h>
#include <_elfedit.h>
#include <conv.h>
#include <msg.h>
static elfedit_atoui_sym_t sym_outstyle[] = {
{ MSG_ORIG(MSG_STR_DEFAULT), ELFEDIT_OUTSTYLE_DEFAULT },
{ MSG_ORIG(MSG_STR_SIMPLE), ELFEDIT_OUTSTYLE_SIMPLE },
{ MSG_ORIG(MSG_STR_NUM), ELFEDIT_OUTSTYLE_NUM },
{ NULL }
};
static elfedit_atoui_sym_t sym_minus_o_outstyle[] = {
{ MSG_ORIG(MSG_STR_MINUS_O_DEFAULT), ELFEDIT_OUTSTYLE_DEFAULT },
{ MSG_ORIG(MSG_STR_MINUS_O_SIMPLE), ELFEDIT_OUTSTYLE_SIMPLE },
{ MSG_ORIG(MSG_STR_MINUS_O_NUM), ELFEDIT_OUTSTYLE_NUM },
{ NULL }
};
static elfedit_atoui_sym_t sym_bool[] = {
{ MSG_ORIG(MSG_STR_T), 1 },
{ MSG_ORIG(MSG_STR_F), 0 },
{ MSG_ORIG(MSG_STR_TRUE), 1 },
{ MSG_ORIG(MSG_STR_FALSE), 0 },
{ MSG_ORIG(MSG_STR_ON), 1 },
{ MSG_ORIG(MSG_STR_OFF), 0 },
{ MSG_ORIG(MSG_STR_YES), 1 },
{ MSG_ORIG(MSG_STR_NO), 0 },
{ MSG_ORIG(MSG_STR_Y), 1 },
{ MSG_ORIG(MSG_STR_N), 0 },
{ NULL }
};
static elfedit_atoui_sym_t sym_sht_strtab[] = {
{ MSG_ORIG(MSG_SHT_STRTAB), SHT_STRTAB },
{ MSG_ORIG(MSG_SHT_STRTAB_ALT1), SHT_STRTAB },
{ NULL }
};
static elfedit_atoui_sym_t sym_sht_symtab[] = {
{ MSG_ORIG(MSG_SHT_SYMTAB), SHT_SYMTAB },
{ MSG_ORIG(MSG_SHT_SYMTAB_ALT1), SHT_SYMTAB },
{ NULL }
};
static elfedit_atoui_sym_t sym_sht_dynsym[] = {
{ MSG_ORIG(MSG_SHT_DYNSYM), SHT_DYNSYM },
{ MSG_ORIG(MSG_SHT_DYNSYM_ALT1), SHT_DYNSYM },
{ NULL }
};
static elfedit_atoui_sym_t sym_sht_ldynsym[] = {
{ MSG_ORIG(MSG_SHT_SUNW_LDYNSYM), SHT_SUNW_LDYNSYM },
{ MSG_ORIG(MSG_SHT_SUNW_LDYNSYM_ALT1), SHT_SUNW_LDYNSYM },
{ NULL }
};
typedef enum {
STE_STATIC = 0,
STE_LC = 1,
STE_LC_OS = 2,
STE_LC_MACH = 3,
STE_LC_OS_MACH = 4
} ste_type_t;
typedef conv_iter_ret_t (* libconv_iter_func_simple_t)(
Conv_fmt_flags_t, conv_iter_cb_t, void *);
typedef conv_iter_ret_t (* libconv_iter_func_os_t)(conv_iter_osabi_t,
Conv_fmt_flags_t, conv_iter_cb_t, void *);
typedef conv_iter_ret_t (* libconv_iter_func_mach_t)(Half,
Conv_fmt_flags_t, conv_iter_cb_t, void *);
typedef conv_iter_ret_t (* libconv_iter_func_os_mach_t)(conv_iter_osabi_t, Half,
Conv_fmt_flags_t, conv_iter_cb_t, void *);
typedef union {
libconv_iter_func_simple_t simple;
libconv_iter_func_os_t osabi;
libconv_iter_func_mach_t mach;
libconv_iter_func_os_mach_t osabi_mach;
} libconv_iter_func_t;
typedef struct {
ste_type_t ste_type;
elfedit_atoui_sym_t *ste_arr;
void *ste_alloc;
size_t ste_nelts;
libconv_iter_func_t ste_conv_func;
} sym_table_ent_t;
static sym_table_ent_t sym_table[ELFEDIT_CONST_NUM] = {
{ STE_STATIC, sym_outstyle },
{ STE_STATIC, sym_minus_o_outstyle },
{ STE_STATIC, sym_bool },
{ STE_STATIC, sym_sht_strtab },
{ STE_STATIC, sym_sht_symtab },
{ STE_STATIC, sym_sht_dynsym },
{ STE_STATIC, sym_sht_ldynsym },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
{ 0 },
};
#if ELFEDIT_CONST_NUM != (ELFEDIT_CONST_SF1_SUNW)
error "ELFEDIT_CONST_NUM has grown. Update sym_table[]"
#endif
static conv_iter_ret_t
libconv_count_cb(const char *str, Conv_elfvalue_t value, void *uvalue)
{
size_t *cnt = (size_t *)uvalue;
(*cnt)++;
return (CONV_ITER_CONT);
}
typedef struct {
size_t cur;
size_t cnt;
elfedit_atoui_sym_t *desc;
} libconv_fill_state_t;
static conv_iter_ret_t
libconv_fill_cb(const char *str, Conv_elfvalue_t value, void *uvalue)
{
libconv_fill_state_t *fill_state = (libconv_fill_state_t *)uvalue;
elfedit_atoui_sym_t *sym = &fill_state->desc[fill_state->cur++];
sym->sym_name = str;
sym->sym_value = value;
return (CONV_ITER_CONT);
}
static void
libconv_fill_iter(sym_table_ent_t *sym, conv_iter_osabi_t osabi, Half mach,
conv_iter_cb_t func, void *uvalue)
{
switch (sym->ste_type) {
case STE_LC:
(void) (* sym->ste_conv_func.simple)(
CONV_FMT_ALT_CF, func, uvalue);
(void) (* sym->ste_conv_func.simple)(
CONV_FMT_ALT_NF, func, uvalue);
break;
case STE_LC_OS:
(void) (* sym->ste_conv_func.osabi)(osabi,
CONV_FMT_ALT_CF, func, uvalue);
(void) (* sym->ste_conv_func.osabi)(osabi,
CONV_FMT_ALT_NF, func, uvalue);
break;
case STE_LC_MACH:
(void) (* sym->ste_conv_func.mach)(mach,
CONV_FMT_ALT_CF, func, uvalue);
(void) (* sym->ste_conv_func.mach)(mach,
CONV_FMT_ALT_NF, func, uvalue);
break;
case STE_LC_OS_MACH:
(void) (* sym->ste_conv_func.osabi_mach)(osabi, mach,
CONV_FMT_ALT_CF, func, uvalue);
(void) (* sym->ste_conv_func.osabi_mach)(osabi, mach,
CONV_FMT_ALT_NF, func, uvalue);
break;
case STE_STATIC:
break;
}
}
static void
libconv_fill(sym_table_ent_t *sym, conv_iter_osabi_t osabi, Half mach)
{
libconv_fill_state_t fill_state;
fill_state.cnt = 1;
libconv_fill_iter(sym, osabi, mach, libconv_count_cb, &fill_state.cnt);
if ((sym->ste_alloc != NULL) && (fill_state.cnt > sym->ste_nelts)) {
free(sym->ste_alloc);
sym->ste_alloc = NULL;
sym->ste_nelts = 0;
}
if (sym->ste_alloc == NULL) {
sym->ste_alloc = elfedit_malloc(MSG_INTL(MSG_ALLOC_ELFCONDESC),
fill_state.cnt * sizeof (*fill_state.desc));
sym->ste_nelts = fill_state.cnt;
}
fill_state.desc = sym->ste_alloc;
fill_state.cur = 0;
libconv_fill_iter(sym, osabi, mach, libconv_fill_cb, &fill_state);
fill_state.desc[fill_state.cur].sym_name = NULL;
fill_state.desc[fill_state.cur].sym_value = 0;
sym->ste_arr = fill_state.desc;
}
static void
init_libconv_strings(conv_iter_osabi_t *osabi, Half *mach)
{
#define LC(_ndx, _func) sym_table[_ndx].ste_type = STE_LC; \
sym_table[_ndx].ste_conv_func.simple = _func;
#define LC_OS(_ndx, _func) sym_table[_ndx].ste_type = STE_LC_OS; \
sym_table[_ndx].ste_conv_func.osabi = _func;
#define LC_MACH(_ndx, _func) sym_table[_ndx].ste_type = STE_LC_MACH; \
sym_table[_ndx].ste_conv_func.mach = _func;
#define LC_OS_MACH(_ndx, _func) sym_table[_ndx].ste_type = STE_LC_OS_MACH; \
sym_table[_ndx].ste_conv_func.osabi_mach = _func;
if (!state.file.present) {
*osabi = CONV_OSABI_ALL;
*mach = CONV_MACH_ALL;
} else if (state.elf.elfclass == ELFCLASS32) {
*osabi = state.elf.obj_state.s32->os_ehdr->e_ident[EI_OSABI];
*mach = state.elf.obj_state.s32->os_ehdr->e_machine;
} else {
*osabi = state.elf.obj_state.s64->os_ehdr->e_ident[EI_OSABI];
*mach = state.elf.obj_state.s64->os_ehdr->e_machine;
}
LC_OS_MACH(ELFEDIT_CONST_SHN, conv_iter_sym_shndx);
LC_OS_MACH(ELFEDIT_CONST_SHT, conv_iter_sec_type);
LC_OS(ELFEDIT_CONST_SHT_ALLSYMTAB, conv_iter_sec_symtab);
LC_OS_MACH(ELFEDIT_CONST_DT, conv_iter_dyn_tag);
LC(ELFEDIT_CONST_DF, conv_iter_dyn_flag);
LC(ELFEDIT_CONST_DF_P1, conv_iter_dyn_posflag1);
LC(ELFEDIT_CONST_DF_1, conv_iter_dyn_flag1);
LC(ELFEDIT_CONST_DTF_1, conv_iter_dyn_feature1);
LC(ELFEDIT_CONST_EI, conv_iter_ehdr_eident);
LC_OS(ELFEDIT_CONST_ET, conv_iter_ehdr_type);
LC(ELFEDIT_CONST_ELFCLASS, conv_iter_ehdr_class);
LC(ELFEDIT_CONST_ELFDATA, conv_iter_ehdr_data);
LC_MACH(ELFEDIT_CONST_EF, conv_iter_ehdr_flags);
LC(ELFEDIT_CONST_EV, conv_iter_ehdr_vers);
LC(ELFEDIT_CONST_EM, conv_iter_ehdr_mach);
LC(ELFEDIT_CONST_ELFOSABI, conv_iter_ehdr_osabi);
LC_OS(ELFEDIT_CONST_EAV, conv_iter_ehdr_abivers);
LC_OS(ELFEDIT_CONST_PT, conv_iter_phdr_type);
LC_OS(ELFEDIT_CONST_PF, conv_iter_phdr_flags);
LC_OS_MACH(ELFEDIT_CONST_SHF, conv_iter_sec_flags);
LC(ELFEDIT_CONST_STB, conv_iter_sym_info_bind);
LC_MACH(ELFEDIT_CONST_STT, conv_iter_sym_info_type);
LC(ELFEDIT_CONST_STV, conv_iter_sym_other_vis);
LC(ELFEDIT_CONST_SYMINFO_BT, conv_iter_syminfo_boundto);
LC(ELFEDIT_CONST_SYMINFO_FLG, conv_iter_syminfo_flags);
LC(ELFEDIT_CONST_CA, conv_iter_cap_tags);
LC_MACH(ELFEDIT_CONST_HW1_SUNW, conv_iter_cap_val_hw1);
LC(ELFEDIT_CONST_SF1_SUNW, conv_iter_cap_val_sf1);
LC_MACH(ELFEDIT_CONST_HW2_SUNW, conv_iter_cap_val_hw2);
LC_MACH(ELFEDIT_CONST_HW3_SUNW, conv_iter_cap_val_hw3);
#undef LC
#undef LC_OS
#undef LC_MACH
#undef LC_OS_MACH
}
static void
invalidate_libconv_strings(conv_iter_osabi_t *osabi, Half *mach)
{
uchar_t cur_osabi;
Half cur_mach;
sym_table_ent_t *sym;
int osabi_change, mach_change;
int i;
state.elf.elfconst_ehdr_change = 0;
if (state.elf.elfclass == ELFCLASS32) {
cur_osabi = state.elf.obj_state.s32->os_ehdr->e_ident[EI_OSABI];
cur_mach = state.elf.obj_state.s32->os_ehdr->e_machine;
} else {
cur_osabi = state.elf.obj_state.s64->os_ehdr->e_ident[EI_OSABI];
cur_mach = state.elf.obj_state.s64->os_ehdr->e_machine;
}
mach_change = *mach != cur_mach;
osabi_change = *osabi != cur_osabi;
if (!(mach_change || osabi_change))
return;
for (i = 0, sym = sym_table;
i < (sizeof (sym_table) / sizeof (sym_table[0])); i++, sym++) {
if (sym->ste_arr == NULL)
continue;
switch (sym->ste_type) {
case STE_STATIC:
case STE_LC:
break;
case STE_LC_OS:
if (osabi_change)
sym->ste_arr = NULL;
break;
case STE_LC_MACH:
if (mach_change)
sym->ste_arr = NULL;
break;
case STE_LC_OS_MACH:
if (osabi_change || mach_change)
sym->ste_arr = NULL;
break;
}
}
*mach = cur_mach;
*osabi = cur_osabi;
}
elfedit_atoui_sym_t *
elfedit_const_to_atoui(elfedit_const_t const_type)
{
static int first = 1;
static conv_iter_osabi_t osabi;
static Half mach;
sym_table_ent_t *sym;
if (first) {
init_libconv_strings(&osabi, &mach);
first = 0;
}
if ((const_type < 0) ||
(const_type >= (sizeof (sym_table) / sizeof (sym_table[0]))))
elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADCONST));
sym = &sym_table[const_type];
if (sym->ste_type != STE_STATIC) {
if (state.elf.elfconst_ehdr_change)
invalidate_libconv_strings(&osabi, &mach);
if (sym->ste_arr == NULL)
libconv_fill(sym, osabi, mach);
}
return (sym->ste_arr);
}