/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #define ELF_TARGET_AMD64 /* SHN_AMD64_LCOMMON */ #include #include #include #include #include #include #include #define MAXNDXSIZE 10 /* * This module uses shared code for several of the commands. * It is sometimes necessary to know which specific command * is active. */ typedef enum { SYM_CMD_T_DUMP = 0, /* sym:dump */ SYM_CMD_T_ST_BIND = 1, /* sym:st_bind */ SYM_CMD_T_ST_INFO = 2, /* sym:st_info */ SYM_CMD_T_ST_NAME = 3, /* sym:st_name */ SYM_CMD_T_ST_OTHER = 4, /* sym:st_other */ SYM_CMD_T_ST_SHNDX = 5, /* sym:st_shndx */ SYM_CMD_T_ST_SIZE = 6, /* sym:st_size */ SYM_CMD_T_ST_TYPE = 7, /* sym:st_type */ SYM_CMD_T_ST_VALUE = 8, /* sym:st_value */ SYM_CMD_T_ST_VISIBILITY = 9 /* sym:st_visibility */ } SYM_CMD_T; /* * ELFCLASS-specific definitions */ #ifdef _ELF64 #define MSG_FMT_XWORDVALNL MSG_FMT_XWORDVALNL_64 #else #define MSG_FMT_XWORDVALNL MSG_FMT_XWORDVALNL_32 /* * We supply this function for the msg module. Only one copy is needed. */ const char * _sym_msg(Msg mid) { return (gettext(MSG_ORIG(mid))); } #endif /* * This function is supplied to elfedit through our elfedit_module_t * definition. It translates the opaque elfedit_i18nhdl_t handles * in our module interface into the actual strings for elfedit to * use. * * note: * This module uses Msg codes for its i18n handle type. * So the translation is simply to use MSG_INTL() to turn * it into a string and return it. */ static const char * mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl) { Msg msg = (Msg)hdl; return (MSG_INTL(msg)); } /* * The sym_opt_t enum specifies a bit value for every optional * argument allowed by a command in this module. */ typedef enum { SYM_OPT_F_XSHINDEX = 1, /* -e: Force shndx update to extended */ /* index section */ SYM_OPT_F_NAMOFFSET = 2, /* -name_offset: sym:st_name name arg */ /* is numeric offset */ /* rather than ASCII string */ SYM_OPT_F_SECSHNDX = 4, /* -secshndx: Section arg is */ /* section index, not name */ SYM_OPT_F_SECSHTYP = 8, /* -secshtyp: Section arg is */ /* section type, not name */ SYM_OPT_F_SHNAME = 16, /* -shnam name: section spec. by name */ SYM_OPT_F_SHNDX = 32, /* -shndx ndx: section spec. by index */ SYM_OPT_F_SHTYP = 64, /* -shtyp type: section spec. by type */ SYM_OPT_F_SYMNDX = 128 /* -symndx: Sym specified by index */ } sym_opt_t; /* * A variable of type ARGSTATE is used by each command to maintain * the overall state for a given set of arguments and the symbol tables * being managed. * * The state for each symbol table and the auxiliary sections that are * related to it are kept in a SYMSTATE sub-struct. * * One benefit of ARGSTATE is that it helps us to ensure that we only * fetch each section a single time: * - More efficient * - Prevents multiple ELFEDIT_MSG_DEBUG messages from * being produced for a given section. * * note: The symstate array in ARGSTATE is defined as having one * element, but in reality, we allocate enough room for * the number of elements defined in the numsymstate field. */ typedef struct { Word ndx; /* If argstate.argc > 0, this is the table index */ struct { /* Symbol table */ elfedit_section_t *sec; Sym *data; Word n; } sym; struct { /* String table */ elfedit_section_t *sec; } str; struct { /* Versym */ Word shndx; elfedit_section_t *sec; Versym *data; Word n; } versym; struct { /* Extended section indices */ Word shndx; elfedit_section_t *sec; Word *data; Word n; } xshndx; } SYMSTATE; typedef struct { elfedit_obj_state_t *obj_state; sym_opt_t optmask; /* Mask of options used */ int argc; /* # of plain arguments */ const char **argv; /* Plain arguments */ int numsymstate; /* # of items in symstate[] */ SYMSTATE symstate[1]; /* Symbol tables to process */ } ARGSTATE; /* * We maintain the state of each symbol table and related associated * sections in a SYMSTATE structure . We don't look those auxiliary * things up unless we actually need them, both to be efficient, * and to prevent duplicate ELFEDIT_MSG_DEBUG messages from being * issued as they are located. Hence, process_args() is used to * initialize the state block with just the symbol table, and then one * of the argstate_add_XXX() functions is used as needed * to fetch the additional sections. * * entry: * argstate - Overall state block * symstate - State block for current symbol table. * * exit: * If the needed auxiliary section is not found, an error is * issued and the argstate_add_XXX() routine does not return. * Otherwise, the fields in argstate have been filled in, ready * for use. * */ static void symstate_add_str(ARGSTATE *argstate, SYMSTATE *symstate) { if (symstate->str.sec != NULL) return; symstate->str.sec = elfedit_sec_getstr(argstate->obj_state, symstate->sym.sec->sec_shdr->sh_link, 0); } static void symstate_add_versym(ARGSTATE *argstate, SYMSTATE *symstate) { if (symstate->versym.sec != NULL) return; symstate->versym.sec = elfedit_sec_getversym(argstate->obj_state, symstate->sym.sec, &symstate->versym.data, &symstate->versym.n); } static void symstate_add_xshndx(ARGSTATE *argstate, SYMSTATE *symstate) { if (symstate->xshndx.sec != NULL) return; symstate->xshndx.sec = elfedit_sec_getxshndx(argstate->obj_state, symstate->sym.sec, &symstate->xshndx.data, &symstate->xshndx.n); } /* * Display symbol table entries in the style used by elfdump. * * entry: * argstate - Overall state block * symstate - State block for current symbol table. * ndx - Index of first symbol to display * cnt - Number of symbols to display */ static void dump_symtab(ARGSTATE *argstate, SYMSTATE *symstate, Word ndx, Word cnt) { char index[MAXNDXSIZE]; Word shndx; const char *shndx_name; elfedit_section_t *symsec; elfedit_section_t *strsec; Sym *sym; elfedit_obj_state_t *obj_state = argstate->obj_state; uchar_t osabi = obj_state->os_ehdr->e_ident[EI_OSABI]; Half mach = obj_state->os_ehdr->e_machine; const char *symname; Versym versym; symsec = symstate->sym.sec; sym = symstate->sym.data + ndx; symstate_add_str(argstate, symstate); strsec = symstate->str.sec; /* If there is a versym index section, fetch it */ if (symstate->versym.shndx != SHN_UNDEF) symstate_add_versym(argstate, symstate); /* If there is an extended index section, fetch it */ if (symstate->xshndx.shndx != SHN_UNDEF) symstate_add_xshndx(argstate, symstate); elfedit_printf(MSG_INTL(MSG_FMT_SYMTAB), symsec->sec_name); Elf_syms_table_title(0, ELF_DBG_ELFDUMP); for (; cnt-- > 0; ndx++, sym++) { (void) snprintf(index, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(ndx)); versym = (symstate->versym.sec == NULL) ? 0 : symstate->versym.data[ndx]; symname = elfedit_offset_to_str(strsec, sym->st_name, ELFEDIT_MSG_DEBUG, 0); shndx = sym->st_shndx; if ((shndx == SHN_XINDEX) && (symstate->xshndx.sec != NULL)) shndx = symstate->xshndx.data[ndx]; shndx_name = elfedit_shndx_to_name(obj_state, shndx); Elf_syms_table_entry(NULL, ELF_DBG_ELFDUMP, index, osabi, mach, sym, versym, 0, shndx_name, symname); } } /* * Called by print_sym() to determine if a given symbol has the same * display value for the current command in every symbol table. * * entry: * cmd - SYM_CMD_T_* value giving identify of caller * argstate - Overall state block * outstyle - Output style to use */ static int all_same(SYM_CMD_T cmd, ARGSTATE *argstate, elfedit_outstyle_t outstyle) { Word tblndx; SYMSTATE *symstate1, *symstate2; Sym *sym1, *sym2; symstate1 = argstate->symstate; for (tblndx = 0; tblndx < (argstate->numsymstate - 1); tblndx++, symstate1++) { symstate2 = symstate1 + 1; sym1 = &symstate1->sym.data[symstate1->ndx]; sym2 = &symstate2->sym.data[symstate2->ndx]; switch (cmd) { case SYM_CMD_T_DUMP: /* sym:dump should always show everything */ return (0); case SYM_CMD_T_ST_BIND: if (ELF_ST_BIND(sym1->st_info) != ELF_ST_BIND(sym2->st_info)) return (0); break; case SYM_CMD_T_ST_INFO: if (sym1->st_info != sym2->st_info) return (0); break; case SYM_CMD_T_ST_NAME: /* * In simple output mode, we show the string. In * numeric mode, we show the string table offset. */ if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { const char *n1, *n2; symstate_add_str(argstate, symstate1); symstate_add_str(argstate, symstate2); n1 = elfedit_offset_to_str(symstate1->str.sec, sym1->st_name, ELFEDIT_MSG_DEBUG, 0); n2 = elfedit_offset_to_str(symstate2->str.sec, sym2->st_name, ELFEDIT_MSG_DEBUG, 0); if (strcmp(n1, n2) != 0) return (0); } else { if (sym1->st_name != sym2->st_name) return (0); } break; case SYM_CMD_T_ST_OTHER: if (sym1->st_other != sym2->st_other) return (0); break; case SYM_CMD_T_ST_SHNDX: { Word ndx1, ndx2; ndx1 = sym1->st_shndx; if ((ndx1 == SHN_XINDEX) && (symstate1->xshndx.shndx != SHN_UNDEF)) { symstate_add_xshndx(argstate, symstate1); ndx1 = symstate1->xshndx. data[symstate1->ndx]; } ndx2 = sym2->st_shndx; if ((ndx2 == SHN_XINDEX) && (symstate2->xshndx.shndx != SHN_UNDEF)) { symstate_add_xshndx(argstate, symstate2); ndx2 = symstate2->xshndx. data[symstate2->ndx]; } if (ndx1 != ndx2) return (0); } break; case SYM_CMD_T_ST_SIZE: if (sym1->st_size != sym2->st_size) return (0); break; case SYM_CMD_T_ST_TYPE: if (ELF_ST_TYPE(sym1->st_info) != ELF_ST_TYPE(sym2->st_info)) return (0); break; case SYM_CMD_T_ST_VALUE: if (sym1->st_value != sym2->st_value) return (0); break; case SYM_CMD_T_ST_VISIBILITY: if (ELF_ST_VISIBILITY(sym1->st_info) != ELF_ST_VISIBILITY(sym2->st_info)) return (0); break; } } /* If we got here, there are no differences (or maybe only 1 table */ return (1); } /* * Called by print_sym() to display values for a single symbol table. * * entry: * autoprint - If True, output is only produced if the elfedit * autoprint flag is set. If False, output is always produced. * cmd - SYM_CMD_T_* value giving identify of caller * argstate - Overall state block * symstate - State block for current symbol table. * ndx - Index of first symbol to display * cnt - Number of symbols to display */ static void print_symstate(SYM_CMD_T cmd, ARGSTATE *argstate, SYMSTATE *symstate, elfedit_outstyle_t outstyle, Word ndx, Word cnt) { Word value; Sym *sym; /* * If doing default output, use elfdump style where we * show all symbol attributes. In this case, the command * that called us doesn't matter */ if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) { dump_symtab(argstate, symstate, ndx, cnt); return; } sym = symstate->sym.data; switch (cmd) { case SYM_CMD_T_ST_BIND: { Conv_inv_buf_t inv_buf; for (sym += ndx; cnt--; sym++) { value = ELF_ST_BIND(sym->st_info); if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), conv_sym_info_bind(value, CONV_FMT_ALT_CF, &inv_buf)); } else { elfedit_printf( MSG_ORIG(MSG_FMT_WORDVALNL), EC_WORD(value)); } } } return; case SYM_CMD_T_ST_INFO: for (sym += ndx; cnt-- > 0; sym++) elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL), EC_WORD(sym->st_info)); return; case SYM_CMD_T_ST_NAME: /* * In simple output mode, we show the string. In numeric * mode, we show the string table offset. */ if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { symstate_add_str(argstate, symstate); for (sym += ndx; cnt--; sym++) { elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), elfedit_offset_to_str(symstate->str.sec, sym->st_name, ELFEDIT_MSG_ERR, 0)); } } else { for (; cnt--; sym++) elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL), EC_WORD(sym->st_name)); } return; case SYM_CMD_T_ST_OTHER: for (sym += ndx; cnt-- > 0; sym++) elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL), EC_WORD(sym->st_other)); return; case SYM_CMD_T_ST_SHNDX: /* If there is an extended index section, fetch it */ if (symstate->xshndx.shndx != SHN_UNDEF) symstate_add_xshndx(argstate, symstate); for (; cnt--; ndx++) { value = sym[ndx].st_shndx; if ((value == SHN_XINDEX) && (symstate->xshndx.sec != NULL)) value = symstate->xshndx.data[ndx]; if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), elfedit_shndx_to_name(argstate->obj_state, value)); } else { elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL), EC_WORD(value)); } } return; case SYM_CMD_T_ST_SIZE: /* * machine word width integers displayed in fixed width * 0-filled hex format. */ for (sym += ndx; cnt--; sym++) elfedit_printf(MSG_ORIG(MSG_FMT_XWORDVALNL), sym->st_size); return; case SYM_CMD_T_ST_TYPE: { Half mach = argstate->obj_state->os_ehdr->e_machine; Conv_inv_buf_t inv_buf; for (sym += ndx; cnt--; sym++) { value = ELF_ST_TYPE(sym->st_info); if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), conv_sym_info_type(mach, value, CONV_FMT_ALT_CF, &inv_buf)); } else { elfedit_printf( MSG_ORIG(MSG_FMT_WORDVALNL), EC_WORD(value)); } } } return; case SYM_CMD_T_ST_VALUE: /* * machine word width integers displayed in fixed width * 0-filled hex format. */ for (sym += ndx; cnt--; sym++) elfedit_printf(MSG_ORIG(MSG_FMT_XWORDVALNL), sym->st_value); return; case SYM_CMD_T_ST_VISIBILITY: { Conv_inv_buf_t inv_buf; for (sym += ndx; cnt--; sym++) { value = ELF_ST_VISIBILITY(sym->st_other); if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), conv_sym_other_vis(value, CONV_FMT_ALT_CF, &inv_buf)); } else { elfedit_printf( MSG_ORIG(MSG_FMT_WORDVALNL), EC_WORD(value)); } } } return; } } /* * Print symbol values, taking the calling command, and output style * into account. * * entry: * autoprint - If True, output is only produced if the elfedit * autoprint flag is set. If False, output is always produced. * cmd - SYM_CMD_T_* value giving identify of caller * argstate - Overall state block * symstate - State block for current symbol table. * ndx - Index of first symbol to display * cnt - Number of symbols to display */ static void print_sym(SYM_CMD_T cmd, int autoprint, ARGSTATE *argstate) { Word ndx, tblndx; Word cnt; elfedit_outstyle_t outstyle; SYMSTATE *symstate; int only_one; if ((autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0))) return; /* * Pick an output style. sym:dump is required to use the default * style. The other commands use the current output style. */ outstyle = (cmd == SYM_CMD_T_DUMP) ? ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle(); /* * This is a nicity: Force any needed auxiliary sections to be * fetched here before any output is produced. This will put all * of the debug messages right at the top in a single cluster. */ symstate = argstate->symstate; for (tblndx = 0; tblndx < argstate->numsymstate; tblndx++, symstate++) { if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) { symstate_add_str(argstate, symstate); if (symstate->versym.shndx != SHN_UNDEF) symstate_add_versym(argstate, symstate); if (symstate->xshndx.shndx != SHN_UNDEF) symstate_add_xshndx(argstate, symstate); continue; } if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { switch (cmd) { case SYM_CMD_T_ST_NAME: symstate_add_str(argstate, symstate); break; case SYM_CMD_T_ST_SHNDX: if (symstate->xshndx.shndx != SHN_UNDEF) symstate_add_xshndx(argstate, symstate); break; } } } /* * If there is more than one table, we are displaying a single * item, we are not using the default "elfdump" style, and all * the symbols have the same value for the thing we intend to * display, then we only want to display it once. */ only_one = (argstate->numsymstate > 1) && (argstate->argc > 0) && (outstyle != ELFEDIT_OUTSTYLE_DEFAULT) && all_same(cmd, argstate, outstyle); /* Run through the tables and display from each one */ symstate = argstate->symstate; for (tblndx = 0; tblndx < argstate->numsymstate; tblndx++, symstate++) { if (argstate->argc == 0) { ndx = 0; cnt = symstate->sym.n; } else { ndx = symstate->ndx; cnt = 1; } if ((tblndx > 0) && ((argstate->argc == 0) || (outstyle == ELFEDIT_OUTSTYLE_DEFAULT))) elfedit_printf(MSG_ORIG(MSG_STR_NL)); print_symstate(cmd, argstate, symstate, outstyle, ndx, cnt); if (only_one) break; } } /* * The cmd_body_set_st_XXX() functions are for use by cmd_body(). * They handle the case where the second plain argument is * a value to be stored in the symbol. * * entry: * argstate - Overall state block * symstate - State block for current symbol table. */ static elfedit_cmdret_t cmd_body_set_st_bind(ARGSTATE *argstate, SYMSTATE *symstate) { elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE; Sym *sym = &symstate->sym.data[symstate->ndx]; Word gbl_ndx; uchar_t bind, type, old_bind; Word symndx; Conv_inv_buf_t inv_buf1, inv_buf2; /* * Use the ELF_ST_BIND() macro to access the defined bits * of the st_info field related to symbol binding. * Accepts STB_ symbolic names as well as integers. */ bind = elfedit_atoconst_range(argstate->argv[1], MSG_INTL(MSG_ARG_SYMBIND), 0, 15, ELFEDIT_CONST_STB); old_bind = ELF_ST_BIND(sym->st_info); type = ELF_ST_TYPE(sym->st_info); if (old_bind == bind) { elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_OK), symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name, EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_BIND), conv_sym_info_bind(bind, CONV_FMT_ALT_CF, &inv_buf1)); } else { /* * The sh_info field of the symbol table section header * gives the index of the first non-local symbol in * the table. Issue warnings if the binding we set * contradicts this. */ gbl_ndx = symstate->sym.sec->sec_shdr->sh_info; symndx = symstate->sym.sec->sec_shndx; if ((bind == STB_LOCAL) && (symstate->ndx >= gbl_ndx)) elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_LBINDGSYM), EC_WORD(symndx), symstate->sym.sec->sec_name, symstate->ndx, EC_WORD(symndx), gbl_ndx); if ((bind != STB_LOCAL) && (symstate->ndx < gbl_ndx)) elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_GBINDLSYM), EC_WORD(symndx), symstate->sym.sec->sec_name, symstate->ndx, EC_WORD(symndx), gbl_ndx); elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_CHG), symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name, EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_BIND), conv_sym_info_bind(old_bind, CONV_FMT_ALT_CF, &inv_buf1), conv_sym_info_bind(bind, CONV_FMT_ALT_CF, &inv_buf2)); ret = ELFEDIT_CMDRET_MOD; sym->st_info = ELF_ST_INFO(bind, type); } return (ret); } static elfedit_cmdret_t cmd_body_set_st_name(ARGSTATE *argstate, SYMSTATE *symstate) { elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE; Sym *sym = &symstate->sym.data[symstate->ndx]; Word str_offset; /* * If -n was specified, this is an offset into the string * table. Otherwise it is a string we need to turn into * an offset */ symstate_add_str(argstate, symstate); if (argstate->optmask & SYM_OPT_F_NAMOFFSET) { str_offset = elfedit_atoui(argstate->argv[1], NULL); /* Warn if the offset is out of range */ (void) elfedit_offset_to_str(symstate->str.sec, str_offset, ELFEDIT_MSG_DEBUG, 1); } else { str_offset = elfedit_strtab_insert(argstate->obj_state, symstate->str.sec, NULL, argstate->argv[1]); } if (sym->st_name == str_offset) { elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_D_OK), symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name, EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_NAME), EC_WORD(sym->st_name)); } else { /* * Warn the user: Changing the name of a symbol in the dynsym * will break the hash table in this object. */ if (symstate->sym.sec->sec_shdr->sh_type == SHT_DYNSYM) elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_DYNSYMNAMCHG), EC_WORD(symstate->sym.sec->sec_shndx), symstate->sym.sec->sec_name, EC_WORD(symstate->ndx)); elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_D_CHG), symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name, EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_NAME), EC_WORD(sym->st_name), EC_WORD(str_offset)); ret = ELFEDIT_CMDRET_MOD; sym->st_name = str_offset; } return (ret); } static elfedit_cmdret_t cmd_body_set_st_shndx(ARGSTATE *argstate, SYMSTATE *symstate) { elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE; Sym *sym = &symstate->sym.data[symstate->ndx]; Word shndx, st_shndx, xshndx; int use_xshndx; int shndx_chg, xshndx_chg; /* * By default, the sec argument is a section name. If -secshndx was * specified, it is a section index, and if -secshtyp is specified, * it is a section type. */ if (argstate->optmask & SYM_OPT_F_SECSHNDX) shndx = elfedit_atoshndx(argstate->argv[1], argstate->obj_state->os_shnum); else if (argstate->optmask & SYM_OPT_F_SECSHTYP) shndx = elfedit_type_to_shndx(argstate->obj_state, elfedit_atoconst(argstate->argv[1], ELFEDIT_CONST_SHT)); else shndx = elfedit_name_to_shndx(argstate->obj_state, argstate->argv[1]); /* * We want to use an extended index section if the index is too * large to be represented otherwise, or if the caller specified * the -e option to make us do it anyway. However, we cannot * do this if the index is in the special reserved range between * SHN_LORESERVE and SHN_HIRESERVE. */ use_xshndx = (shndx > SHN_HIRESERVE) || ((shndx < SHN_LORESERVE) && (argstate->optmask & SYM_OPT_F_XSHINDEX)); /* * There are two cases where we have to touch the extended * index section: * * 1) We have determined that we need to, as determined above. * 2) We do not require it, but the file has an extended * index section, in which case we should set the slot * in that extended section to SHN_UNDEF (0). * * Fetch the extended section as required, and determine the values * for st_shndx and the extended section slot. */ if (use_xshndx) { /* We must have an extended index section, or error out */ symstate_add_xshndx(argstate, symstate); /* Set symbol to SHN_XINDEX, put index in the extended sec. */ st_shndx = SHN_XINDEX; xshndx = shndx; } else { st_shndx = shndx; xshndx = SHN_UNDEF; if (symstate->xshndx.shndx != SHN_UNDEF) use_xshndx = 1; } if (use_xshndx) symstate_add_xshndx(argstate, symstate); shndx_chg = (sym->st_shndx != st_shndx); xshndx_chg = use_xshndx && (symstate->xshndx.data[symstate->ndx] != xshndx); /* If anything is going to change, issue appropiate warnings */ if (shndx_chg || xshndx_chg) { /* * Setting the first symbol to anything other than SHN_UNDEF * produces a bad ELF file. */ if ((symstate->ndx == 0) && (shndx != SHN_UNDEF)) elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_SHNDX_UNDEF0)); /* * Setting SHN_XINDEX directly, instead of providing * an extended index and letting us decide to use * SHN_XINDEX to implement it, is probably a mistake. * Issue a warning, but go ahead and follow the directions * we've been given. */ if (shndx == SHN_XINDEX) elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_SHNDX_XINDEX)); /* * If the section index can fit in the symbol, but * -e is being used to force it into the extended * index section, issue a warning. */ if (use_xshndx && (shndx < SHN_LORESERVE) && (st_shndx == SHN_XINDEX)) elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_SHNDX_EFORCE), EC_WORD(symstate->sym.sec->sec_shndx), symstate->sym.sec->sec_name, EC_WORD(symstate->ndx), EC_WORD(shndx)); } if (shndx_chg) { elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_CHG), symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name, EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_SHNDX), elfedit_shndx_to_name(argstate->obj_state, sym->st_shndx), elfedit_shndx_to_name(argstate->obj_state, st_shndx)); ret = ELFEDIT_CMDRET_MOD; sym->st_shndx = st_shndx; } else { elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_OK), symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name, EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_SHNDX), elfedit_shndx_to_name(argstate->obj_state, st_shndx)); } if (use_xshndx) { if (xshndx_chg) { elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_EXT_S_CHG), symstate->xshndx.sec->sec_shndx, symstate->xshndx.sec->sec_name, EC_WORD(symstate->ndx), elfedit_shndx_to_name(argstate->obj_state, symstate->xshndx.data[symstate->ndx]), elfedit_shndx_to_name(argstate->obj_state, xshndx)); ret = ELFEDIT_CMDRET_MOD; symstate->xshndx.data[symstate->ndx] = xshndx; elfedit_modified_data(symstate->xshndx.sec); } else { elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_EXT_S_OK), symstate->xshndx.sec->sec_shndx, symstate->xshndx.sec->sec_name, EC_WORD(symstate->ndx), elfedit_shndx_to_name(argstate->obj_state, xshndx)); } } return (ret); } static elfedit_cmdret_t cmd_body_set_st_type(ARGSTATE *argstate, SYMSTATE *symstate) { elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE; Conv_inv_buf_t inv_buf1, inv_buf2; Half mach = argstate->obj_state->os_ehdr->e_machine; Sym *sym = &symstate->sym.data[symstate->ndx]; uchar_t bind, type, old_type; /* * Use the ELF_ST_TYPE() macro to access the defined bits * of the st_info field related to symbol type. * Accepts STT_ symbolic names as well as integers. */ bind = ELF_ST_BIND(sym->st_info); type = elfedit_atoconst_range(argstate->argv[1], MSG_INTL(MSG_ARG_SYMBIND), 0, 15, ELFEDIT_CONST_STT); old_type = ELF_ST_TYPE(sym->st_info); if (old_type == type) { elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_OK), symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name, EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_TYPE), conv_sym_info_type(mach, type, CONV_FMT_ALT_CF, &inv_buf1)); } else { elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_CHG), symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name, EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_TYPE), conv_sym_info_type(mach, old_type, CONV_FMT_ALT_CF, &inv_buf1), conv_sym_info_type(mach, type, CONV_FMT_ALT_CF, &inv_buf2)); ret = ELFEDIT_CMDRET_MOD; sym->st_info = ELF_ST_INFO(bind, type); } return (ret); } static elfedit_cmdret_t cmd_body_set_st_visibility(ARGSTATE *argstate, SYMSTATE *symstate) { elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE; Conv_inv_buf_t inv_buf1, inv_buf2; Sym *sym = &symstate->sym.data[symstate->ndx]; uchar_t st_other = sym->st_other; uchar_t vis, old_vis; /* * Use the ELF_ST_VISIBILITY() macro to access the * defined bits of the st_other field related to symbol * visibility. Accepts STV_ symbolic names as well as integers. */ vis = elfedit_atoconst_range(argstate->argv[1], MSG_INTL(MSG_ARG_SYMVIS), 0, STV_ELIMINATE, ELFEDIT_CONST_STV); old_vis = st_other & MSK_SYM_VISIBILITY; if (old_vis == vis) { elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_OK), symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name, EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_VISIBILITY), conv_sym_other_vis(old_vis, CONV_FMT_ALT_CF, &inv_buf1)); } else { elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_CHG), symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name, EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_VISIBILITY), conv_sym_other_vis(old_vis, CONV_FMT_ALT_CF, &inv_buf1), conv_sym_other_vis(vis, CONV_FMT_ALT_CF, &inv_buf2)); ret = ELFEDIT_CMDRET_MOD; st_other = (st_other & ~MSK_SYM_VISIBILITY) | ELF_ST_VISIBILITY(vis); sym->st_other = st_other; } return (ret); } /* * Standard argument processing for sym module * * entry * obj_state, argc, argv - Standard command arguments * optmask - Mask of allowed optional arguments. * symstate - State block for current symbol table. * argstate - Address of ARGSTATE block to be initialized * * exit: * On success, *argstate is initialized. On error, * an error is issued and this routine does not return. * * note: * Only the basic symbol table is initially referenced by * argstate. Use the argstate_add_XXX() routines below to * access any auxiliary sections needed. */ static ARGSTATE * process_args(elfedit_obj_state_t *obj_state, int argc, const char *argv[], SYM_CMD_T cmd) { /* * We reuse this same argstate, resizing it to the required * number of symbol tables on the first call, and as necessary. */ static ARGSTATE *argstate; static int argstate_size = 0; elfedit_getopt_state_t getopt_state; elfedit_getopt_ret_t *getopt_ret; elfedit_symtab_t *symtab; int explicit = 0; int got_sym = 0; Word index; Word tblndx; size_t size; SYMSTATE *symstate; /* If there are no symbol tables, we can't do a thing */ if (obj_state->os_symtabnum == 0) elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSYMTAB)); /* Calulate required size of argstate and realloc as necessary */ size = sizeof (ARGSTATE) + ((obj_state->os_symtabnum - 1) * sizeof (SYMSTATE)); if (argstate_size != size) { argstate = elfedit_realloc(MSG_INTL(MSG_ALLOC_ARGSTATE), argstate, size); argstate_size = size; } bzero(argstate, argstate_size); argstate->obj_state = obj_state; elfedit_getopt_init(&getopt_state, &argc, &argv); while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL) { argstate->optmask |= getopt_ret->gor_idmask; switch (getopt_ret->gor_idmask) { case SYM_OPT_F_SHNAME: /* -shnam name */ index = elfedit_name_to_shndx(obj_state, getopt_ret->gor_value); explicit = 1; break; case SYM_OPT_F_SHNDX: /* -shndx index */ index = elfedit_atoui_range(getopt_ret->gor_value, MSG_INTL(MSG_ARG_SECNDX), 1, obj_state->os_shnum - 1, NULL); explicit = 1; break; case SYM_OPT_F_SHTYP: /* -shtyp type */ index = elfedit_type_to_shndx(obj_state, elfedit_atoconst(getopt_ret->gor_value, ELFEDIT_CONST_SHT)); explicit = 1; break; } } /* * Usage error if there are too many plain arguments. sym:dump accepts * a single argument, while the others accept 2. */ if (((cmd == SYM_CMD_T_DUMP) && (argc > 1)) || (argc > 2)) elfedit_command_usage(); /* * If the -symndx option was specified, the sym arg is an index * into the symbol table. In this case, the symbol table must be * explicitly specified (-shnam, -shndx, or -shtype). */ if ((argstate->optmask & SYM_OPT_F_SYMNDX) && !explicit) elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NEEDEXPSYMTAB)); /* * If a section was explicitly specified, it must be a symbol table. */ if (explicit) (void) elfedit_sec_issymtab(obj_state, &obj_state->os_secarr[index], 1, NULL); /* If there may be an arbitrary amount of output, use a pager */ if (argc == 0) elfedit_pager_init(); /* Return the updated values of argc/argv */ argstate->argc = argc; argstate->argv = argv; /* * Decide which symbol table(s) to use. Set up the symstate * array to contain them: * - If a symbol table was explicitly specified, we use * it, and only it. * - If no symbol table is explicitly specified, and the symbol * is given by name, we use all symbol tables that * contain a symbol with that name, throwing an error * if there isn't at least 1 such table. * - If no symbol table is specified, and no symbol is specified, * we use all the tables. */ symtab = obj_state->os_symtab; symstate = argstate->symstate; for (tblndx = 0; tblndx < obj_state->os_symtabnum; tblndx++, symtab++) { /* * If an explicit table is specified, only that table is * considered. * * If no explicit table is specified, verify that table * is considered to be a symbol table by the current osabi, * and quietly skip it if not. */ if (explicit) { if (symtab->symt_shndx != index) continue; } else if (elfedit_sec_issymtab(obj_state, &obj_state->os_secarr[symtab->symt_shndx], 0, NULL) == 0) { continue; } symstate->sym.sec = elfedit_sec_getsymtab(obj_state, 1, symtab->symt_shndx, NULL, &symstate->sym.data, &symstate->sym.n, &symtab); symstate->versym.shndx = symtab->symt_versym; symstate->xshndx.shndx = symtab->symt_xshndx; if (argc > 0) { if (argstate->optmask & SYM_OPT_F_SYMNDX) { symstate->ndx = elfedit_atoui_range( argstate->argv[0], MSG_INTL(MSG_ARG_SYM), 0, symstate->sym.n - 1, NULL); } else { /* * arg is a symbol name. Use the index of * the first symbol that matches */ /* * We will use debug messages for failure up * until we run out of symbol tables. If we * don't find a table with the desired symbol * before the last table, we switch to error * messages. Hence, we will jump with an error * if no table will work. */ int err_type = (!got_sym && ((tblndx + 1) == obj_state->os_symtabnum)) ? ELFEDIT_MSG_ERR : ELFEDIT_MSG_DEBUG; symstate_add_str(argstate, symstate); /* * If the symbol table doesn't have this * symbol, then forget it. */ if (elfedit_name_to_symndx(symstate->sym.sec, symstate->str.sec, argstate->argv[0], err_type, &symstate->ndx) == 0) { bzero(symstate, sizeof (*symstate)); continue; } } } argstate->numsymstate++; symstate++; /* * If the symbol table was given explicitly, and * we've just taken it, then there is no reason to * continue searching. */ if (explicit) break; } return (argstate); } /* * Called by cmd_body() to handle the value change for a single * symbol table. * * entry: * cmd - One of the SYM_CMD_T_* constants listed above, specifying * which command to implement. * argstate - Overall state block * symstate - State block for current symbol table. */ static elfedit_cmdret_t symstate_cmd_body(SYM_CMD_T cmd, ARGSTATE *argstate, SYMSTATE *symstate) { elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE; Sym *sym = &symstate->sym.data[symstate->ndx]; /* You're not supposed to change the value of symbol [0] */ if (symstate->ndx == 0) elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CHGSYMELT0), EC_WORD(symstate->sym.sec->sec_shndx), symstate->sym.sec->sec_name, EC_WORD(symstate->ndx)); /* The second value is an integer giving a new value */ switch (cmd) { /* * SYM_CMD_T_DUMP can't get here: It never has more than * one argument, and is handled above. */ case SYM_CMD_T_ST_BIND: ret = cmd_body_set_st_bind(argstate, symstate); break; case SYM_CMD_T_ST_INFO: { /* Treat st_info as a raw integer field */ uchar_t st_info = elfedit_atoui(argstate->argv[1], NULL); if (sym->st_info == st_info) { elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_D_OK), symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name, EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_INFO), EC_WORD(sym->st_info)); } else { elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_D_CHG), symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name, EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_INFO), EC_WORD(sym->st_info), EC_WORD(st_info)); ret = ELFEDIT_CMDRET_MOD; sym->st_info = st_info; } } break; case SYM_CMD_T_ST_NAME: ret = cmd_body_set_st_name(argstate, symstate); break; case SYM_CMD_T_ST_OTHER: { /* Treat st_other as a raw integer field */ uchar_t st_other = elfedit_atoui(argstate->argv[1], NULL); if (sym->st_other == st_other) { elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_D_OK), symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name, EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_OTHER), EC_WORD(sym->st_other)); } else { elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_D_CHG), symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name, EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_OTHER), EC_WORD(sym->st_other), EC_WORD(st_other)); ret = ELFEDIT_CMDRET_MOD; sym->st_other = st_other; } } break; case SYM_CMD_T_ST_SHNDX: ret = cmd_body_set_st_shndx(argstate, symstate); break; case SYM_CMD_T_ST_SIZE: { Xword st_size = elfedit_atoui(argstate->argv[1], NULL); if (sym->st_size == st_size) { elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_LLX_OK), symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name, EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_SIZE), EC_XWORD(sym->st_size)); } else { elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_LLX_CHG), symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name, EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_SIZE), EC_XWORD(sym->st_size), EC_XWORD(st_size)); ret = ELFEDIT_CMDRET_MOD; sym->st_size = st_size; } } break; case SYM_CMD_T_ST_TYPE: ret = cmd_body_set_st_type(argstate, symstate); break; case SYM_CMD_T_ST_VALUE: { Addr st_value = elfedit_atoui(argstate->argv[1], NULL); if (sym->st_value == st_value) { elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_LLX_OK), symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name, EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_VALUE), EC_ADDR(sym->st_value)); } else { elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_LLX_CHG), symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name, EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_VALUE), EC_ADDR(sym->st_value), EC_ADDR(st_value)); ret = ELFEDIT_CMDRET_MOD; ret = ELFEDIT_CMDRET_MOD; sym->st_value = st_value; } } break; case SYM_CMD_T_ST_VISIBILITY: ret = cmd_body_set_st_visibility(argstate, symstate); break; } /* * If we modified the symbol table, tell libelf. * Any other modified sections are the responsibility * of the cmd_body_set_st_*() function that did it, but * everyone modifies the table itself, so we handle that here. */ if (ret == ELFEDIT_CMDRET_MOD) elfedit_modified_data(symstate->sym.sec); return (ret); } /* * Common body for the sym: module commands. These commands * share a large amount of common behavior, so it is convenient * to centralize things and use the cmd argument to handle the * small differences. * * entry: * cmd - One of the SYM_CMD_T_* constants listed above, specifying * which command to implement. * obj_state, argc, argv - Standard command arguments */ static elfedit_cmdret_t cmd_body(SYM_CMD_T cmd, elfedit_obj_state_t *obj_state, int argc, const char *argv[]) { elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE; ARGSTATE *argstate; SYMSTATE *symstate; Word tblndx; argstate = process_args(obj_state, argc, argv, cmd); /* * If there are not 2 arguments, then this is a display request. * If no arguments are present, the full table (or tables) is * dumped. If there is one argument, then the specified item is shown. */ if (argstate->argc < 2) { print_sym(cmd, 0, argstate); return (ELFEDIT_CMDRET_NONE); } /* * When processing multiple symbol tables, it is important that * any failure happen before anything is changed. Otherwise, you * can end up in a situation where things are left in an inconsistent * half done state. sym:st_name has that issue when the -name_offset * option is used, because the string may be insertable into some * (dynstr) string tables, but not all of them. So, do the tests * up front, and refuse to continue if any string insertions would * fail. */ if ((cmd == SYM_CMD_T_ST_NAME) && (argstate->numsymstate > 1) && ((argstate->optmask & SYM_OPT_F_NAMOFFSET) == 0)) { symstate = argstate->symstate; for (tblndx = 0; tblndx < argstate->numsymstate; tblndx++, symstate++) elfedit_strtab_insert_test(obj_state, symstate->str.sec, NULL, argstate->argv[1]); } /* Loop over the table(s) and make the specified value change */ symstate = argstate->symstate; for (tblndx = 0; tblndx < argstate->numsymstate; tblndx++, symstate++) if (symstate_cmd_body(cmd, argstate, symstate) == ELFEDIT_CMDRET_MOD) ret = ELFEDIT_CMDRET_MOD; /* Do autoprint */ print_sym(cmd, 1, argstate); return (ret); } /* * Command completion functions for the various commands */ /* * Handle filling in the values for -shnam, -shndx, and -shtyp options. */ /*ARGSUSED*/ static void cpl_sh_opt(elfedit_obj_state_t *obj_state, void *cpldata, int argc, const char *argv[], int num_opt) { enum { NAME, INDEX, TYPE } op; elfedit_symtab_t *symtab; Word tblndx; if ((argc != num_opt) || (argc < 2)) return; if (strcmp(argv[argc - 2], MSG_ORIG(MSG_STR_MINUS_SHNAM)) == 0) { op = NAME; } else if (strcmp(argv[argc - 2], MSG_ORIG(MSG_STR_MINUS_SHNDX)) == 0) { op = INDEX; } else if (strcmp(argv[argc - 2], MSG_ORIG(MSG_STR_MINUS_SHTYP)) == 0) { op = TYPE; if (obj_state == NULL) /* No object available */ elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SHT_ALLSYMTAB); } else { return; } if (obj_state == NULL) /* No object available */ return; /* * Loop over the symbol tables and supply command completion * for the items in the file. */ symtab = obj_state->os_symtab; for (tblndx = 0; tblndx < obj_state->os_symtabnum; tblndx++, symtab++) { elfedit_section_t *sec = &obj_state->os_secarr[symtab->symt_shndx]; switch (op) { case NAME: elfedit_cpl_match(cpldata, sec->sec_name, 0); break; case INDEX: elfedit_cpl_ndx(cpldata, symtab->symt_shndx); break; case TYPE: { elfedit_atoui_sym_t *cpl_list; (void) elfedit_sec_issymtab(obj_state, sec, 1, &cpl_list); elfedit_cpl_atoui(cpldata, cpl_list); } break; } } } /*ARGSUSED*/ static void cpl_st_bind(elfedit_obj_state_t *obj_state, void *cpldata, int argc, const char *argv[], int num_opt) { /* Handle -shXXX options */ cpl_sh_opt(obj_state, cpldata, argc, argv, num_opt); /* The second argument can be an STB_ value */ if (argc == (num_opt + 2)) elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_STB); } /*ARGSUSED*/ static void cpl_st_shndx(elfedit_obj_state_t *obj_state, void *cpldata, int argc, const char *argv[], int num_opt) { elfedit_section_t *sec; enum { NAME, INDEX, TYPE } op; Word ndx; /* Handle -shXXX options */ cpl_sh_opt(obj_state, cpldata, argc, argv, num_opt); /* * The second argument can be a section name, a section * index (-secshndx), or a section type (-secshtyp). We * can do completions for each of these. */ if (argc != (num_opt + 2)) return; op = NAME; for (ndx = 0; ndx < num_opt; ndx++) { if (strcmp(argv[ndx], MSG_ORIG(MSG_STR_MINUS_SECSHNDX)) == 0) op = INDEX; else if (strcmp(argv[ndx], MSG_ORIG(MSG_STR_MINUS_SECSHTYP)) == 0) op = TYPE; } switch (op) { case NAME: if (obj_state == NULL) break; sec = obj_state->os_secarr; for (ndx = 0; ndx < obj_state->os_shnum; ndx++, sec++) elfedit_cpl_match(cpldata, sec->sec_name, 0); break; case INDEX: elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SHN); break; case TYPE: elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SHT); break; } } /*ARGSUSED*/ static void cpl_st_type(elfedit_obj_state_t *obj_state, void *cpldata, int argc, const char *argv[], int num_opt) { /* Handle -shXXX options */ cpl_sh_opt(obj_state, cpldata, argc, argv, num_opt); /* The second argument can be an STT_ value */ if (argc == (num_opt + 2)) elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_STT); } /*ARGSUSED*/ static void cpl_st_visibility(elfedit_obj_state_t *obj_state, void *cpldata, int argc, const char *argv[], int num_opt) { /* Handle -shXXX options */ cpl_sh_opt(obj_state, cpldata, argc, argv, num_opt); /* The second argument can be an STV_ value */ if (argc == (num_opt + 2)) elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_STV); } /* * Implementation functions for the commands */ static elfedit_cmdret_t cmd_dump(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) { return (cmd_body(SYM_CMD_T_DUMP, obj_state, argc, argv)); } static elfedit_cmdret_t cmd_st_bind(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) { return (cmd_body(SYM_CMD_T_ST_BIND, obj_state, argc, argv)); } static elfedit_cmdret_t cmd_st_info(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) { return (cmd_body(SYM_CMD_T_ST_INFO, obj_state, argc, argv)); } static elfedit_cmdret_t cmd_st_name(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) { return (cmd_body(SYM_CMD_T_ST_NAME, obj_state, argc, argv)); } static elfedit_cmdret_t cmd_st_other(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) { return (cmd_body(SYM_CMD_T_ST_OTHER, obj_state, argc, argv)); } static elfedit_cmdret_t cmd_st_shndx(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) { return (cmd_body(SYM_CMD_T_ST_SHNDX, obj_state, argc, argv)); } static elfedit_cmdret_t cmd_st_size(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) { return (cmd_body(SYM_CMD_T_ST_SIZE, obj_state, argc, argv)); } static elfedit_cmdret_t cmd_st_type(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) { return (cmd_body(SYM_CMD_T_ST_TYPE, obj_state, argc, argv)); } static elfedit_cmdret_t cmd_st_value(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) { return (cmd_body(SYM_CMD_T_ST_VALUE, obj_state, argc, argv)); } static elfedit_cmdret_t cmd_st_visibility(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) { return (cmd_body(SYM_CMD_T_ST_VISIBILITY, obj_state, argc, argv)); } /*ARGSUSED*/ elfedit_module_t * elfedit_init(elfedit_module_version_t version) { /* Multiple commands accept only the standard set of options */ static elfedit_cmd_optarg_t opt_std[] = { { MSG_ORIG(MSG_STR_MINUS_SHNAM), /* MSG_INTL(MSG_OPTDESC_SHNAM) */ ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE, SYM_OPT_F_SHNAME, SYM_OPT_F_SHNDX | SYM_OPT_F_SHTYP }, { MSG_ORIG(MSG_STR_NAME), 0, 0 }, { MSG_ORIG(MSG_STR_MINUS_SHNDX), /* MSG_INTL(MSG_OPTDESC_SHNDX) */ ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE, SYM_OPT_F_SHNDX, SYM_OPT_F_SHNAME | SYM_OPT_F_SHTYP }, { MSG_ORIG(MSG_STR_INDEX), 0, 0 }, { MSG_ORIG(MSG_STR_MINUS_SHTYP), /* MSG_INTL(MSG_OPTDESC_SHTYP) */ ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE, SYM_OPT_F_SHTYP, SYM_OPT_F_SHNAME | SYM_OPT_F_SHNDX }, { MSG_ORIG(MSG_STR_TYPE), 0, 0 }, { MSG_ORIG(MSG_STR_MINUS_SYMNDX), /* MSG_INTL(MSG_OPTDESC_SYMNDX) */ ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0, SYM_OPT_F_SYMNDX }, { ELFEDIT_STDOA_OPT_O, 0, ELFEDIT_CMDOA_F_INHERIT, 0 }, { NULL } }; /* sym:dump */ static const char *name_dump[] = { MSG_ORIG(MSG_CMD_DUMP), MSG_ORIG(MSG_STR_EMPTY), /* "" makes this the default command */ NULL }; static elfedit_cmd_optarg_t opt_dump[] = { { MSG_ORIG(MSG_STR_MINUS_SHNAM), /* MSG_INTL(MSG_OPTDESC_SHNAM) */ ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE, SYM_OPT_F_SHNAME, SYM_OPT_F_SHNDX | SYM_OPT_F_SHTYP }, { MSG_ORIG(MSG_STR_NAME), 0, 0 }, { MSG_ORIG(MSG_STR_MINUS_SHNDX), /* MSG_INTL(MSG_OPTDESC_SHNDX) */ ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE, SYM_OPT_F_SHNDX, SYM_OPT_F_SHNAME | SYM_OPT_F_SHTYP }, { MSG_ORIG(MSG_STR_INDEX), 0, 0 }, { MSG_ORIG(MSG_STR_MINUS_SHTYP), /* MSG_INTL(MSG_OPTDESC_SHTYP) */ ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE, SYM_OPT_F_SHTYP, SYM_OPT_F_SHNAME | SYM_OPT_F_SHNDX }, { MSG_ORIG(MSG_STR_TYPE), 0, 0 }, { MSG_ORIG(MSG_STR_MINUS_SYMNDX), /* MSG_INTL(MSG_OPTDESC_SYMNDX) */ ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0, SYM_OPT_F_SYMNDX }, { NULL } }; static elfedit_cmd_optarg_t arg_dump[] = { { MSG_ORIG(MSG_STR_SYM), /* MSG_INTL(MSG_A1_SYM) */ ELFEDIT_I18NHDL(MSG_A1_SYM), ELFEDIT_CMDOA_F_OPT }, { NULL } }; /* sym:st_bind */ static const char *name_st_bind[] = { MSG_ORIG(MSG_CMD_ST_BIND), NULL }; static elfedit_cmd_optarg_t arg_st_bind[] = { { MSG_ORIG(MSG_STR_SYM), /* MSG_INTL(MSG_A1_SYM) */ ELFEDIT_I18NHDL(MSG_A1_SYM), ELFEDIT_CMDOA_F_OPT }, { MSG_ORIG(MSG_STR_VALUE), /* MSG_INTL(MSG_A2_DESC_ST_BIND) */ ELFEDIT_I18NHDL(MSG_A2_DESC_ST_BIND), ELFEDIT_CMDOA_F_OPT }, { NULL } }; /* sym:st_info */ static const char *name_st_info[] = { MSG_ORIG(MSG_CMD_ST_INFO), NULL }; static elfedit_cmd_optarg_t arg_st_info[] = { { MSG_ORIG(MSG_STR_SYM), /* MSG_INTL(MSG_A1_SYM) */ ELFEDIT_I18NHDL(MSG_A1_SYM), ELFEDIT_CMDOA_F_OPT }, { MSG_ORIG(MSG_STR_VALUE), /* MSG_INTL(MSG_A2_DESC_ST_INFO) */ ELFEDIT_I18NHDL(MSG_A2_DESC_ST_INFO), ELFEDIT_CMDOA_F_OPT }, { NULL } }; /* sym:st_name */ static const char *name_st_name[] = { MSG_ORIG(MSG_CMD_ST_NAME), NULL }; static elfedit_cmd_optarg_t opt_st_name[] = { { MSG_ORIG(MSG_STR_MINUS_SHNAM), /* MSG_INTL(MSG_OPTDESC_SHNAM) */ ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE, SYM_OPT_F_SHNAME, SYM_OPT_F_SHNDX | SYM_OPT_F_SHTYP }, { MSG_ORIG(MSG_STR_NAME), 0, 0, 0 }, { MSG_ORIG(MSG_STR_MINUS_SHNDX), /* MSG_INTL(MSG_OPTDESC_SHNDX) */ ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE, SYM_OPT_F_SHNDX, SYM_OPT_F_SHNAME | SYM_OPT_F_SHTYP }, { MSG_ORIG(MSG_STR_INDEX), 0, 0, 0 }, { MSG_ORIG(MSG_STR_MINUS_SHTYP), /* MSG_INTL(MSG_OPTDESC_SHTYP) */ ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE, SYM_OPT_F_SHTYP, SYM_OPT_F_SHNAME | SYM_OPT_F_SHNDX }, { MSG_ORIG(MSG_STR_TYPE), 0, 0, 0 }, { MSG_ORIG(MSG_STR_MINUS_SYMNDX), /* MSG_INTL(MSG_OPTDESC_SYMNDX) */ ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0, SYM_OPT_F_SYMNDX, 0 }, { MSG_ORIG(MSG_STR_MINUS_NAME_OFFSET), /* MSG_INTL(MSG_OPTDESC_NAME_OFFSET) */ ELFEDIT_I18NHDL(MSG_OPTDESC_NAME_OFFSET), 0, SYM_OPT_F_NAMOFFSET, 0 }, { ELFEDIT_STDOA_OPT_O, 0, ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, { NULL } }; static elfedit_cmd_optarg_t arg_st_name[] = { { MSG_ORIG(MSG_STR_SYM), /* MSG_INTL(MSG_A1_SYM) */ ELFEDIT_I18NHDL(MSG_A1_SYM), ELFEDIT_CMDOA_F_OPT }, { MSG_ORIG(MSG_STR_NAME), /* MSG_INTL(MSG_A2_DESC_ST_NAME) */ ELFEDIT_I18NHDL(MSG_A2_DESC_ST_NAME), ELFEDIT_CMDOA_F_OPT }, { NULL } }; /* sym:st_other */ static const char *name_st_other[] = { MSG_ORIG(MSG_CMD_ST_OTHER), NULL }; static elfedit_cmd_optarg_t arg_st_other[] = { { MSG_ORIG(MSG_STR_SYM), /* MSG_INTL(MSG_A1_SYM) */ ELFEDIT_I18NHDL(MSG_A1_SYM), ELFEDIT_CMDOA_F_OPT }, { MSG_ORIG(MSG_STR_VALUE), /* MSG_INTL(MSG_A2_DESC_ST_OTHER) */ ELFEDIT_I18NHDL(MSG_A2_DESC_ST_OTHER), ELFEDIT_CMDOA_F_OPT }, { NULL } }; /* sym:st_shndx */ static const char *name_st_shndx[] = { MSG_ORIG(MSG_CMD_ST_SHNDX), NULL }; static elfedit_cmd_optarg_t opt_st_shndx[] = { { MSG_ORIG(MSG_STR_MINUS_E), /* MSG_INTL(MSG_OPTDESC_E) */ ELFEDIT_I18NHDL(MSG_OPTDESC_E), 0, SYM_OPT_F_XSHINDEX, 0 }, { MSG_ORIG(MSG_STR_MINUS_SHNAM), /* MSG_INTL(MSG_OPTDESC_SHNAM) */ ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE, SYM_OPT_F_SHNAME, SYM_OPT_F_SHNDX | SYM_OPT_F_SHTYP }, { MSG_ORIG(MSG_STR_NAME), 0, 0, 0 }, { MSG_ORIG(MSG_STR_MINUS_SHNDX), /* MSG_INTL(MSG_OPTDESC_SHNDX) */ ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE, SYM_OPT_F_SHNDX, SYM_OPT_F_SHNAME | SYM_OPT_F_SHTYP }, { MSG_ORIG(MSG_STR_INDEX), 0, 0, 0 }, { MSG_ORIG(MSG_STR_MINUS_SHTYP), /* MSG_INTL(MSG_OPTDESC_SHTYP) */ ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE, SYM_OPT_F_SHTYP, SYM_OPT_F_SHNAME | SYM_OPT_F_SHNDX }, { MSG_ORIG(MSG_STR_TYPE), 0, 0, 0 }, { MSG_ORIG(MSG_STR_MINUS_SYMNDX), /* MSG_INTL(MSG_OPTDESC_SYMNDX) */ ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0, SYM_OPT_F_SYMNDX, 0 }, { ELFEDIT_STDOA_OPT_O, 0, ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, { MSG_ORIG(MSG_STR_MINUS_SECSHNDX), /* MSG_INTL(MSG_OPTDESC_SECSHNDX) */ ELFEDIT_I18NHDL(MSG_OPTDESC_SECSHNDX), 0, SYM_OPT_F_SECSHNDX, SYM_OPT_F_SECSHTYP }, { MSG_ORIG(MSG_STR_MINUS_SECSHTYP), /* MSG_INTL(MSG_OPTDESC_SECSHTYP) */ ELFEDIT_I18NHDL(MSG_OPTDESC_SECSHTYP), 0, SYM_OPT_F_SECSHTYP, SYM_OPT_F_SECSHNDX }, { NULL } }; static elfedit_cmd_optarg_t arg_st_shndx[] = { { MSG_ORIG(MSG_STR_SYM), /* MSG_INTL(MSG_A1_SYM) */ ELFEDIT_I18NHDL(MSG_A1_SYM), ELFEDIT_CMDOA_F_OPT }, { MSG_ORIG(MSG_STR_SEC), /* MSG_INTL(MSG_A2_DESC_ST_SEC) */ ELFEDIT_I18NHDL(MSG_A2_DESC_ST_SEC), ELFEDIT_CMDOA_F_OPT }, { NULL } }; /* sym:st_size */ static const char *name_st_size[] = { MSG_ORIG(MSG_CMD_ST_SIZE), NULL }; static elfedit_cmd_optarg_t arg_st_size[] = { { MSG_ORIG(MSG_STR_SYM), /* MSG_INTL(MSG_A1_SYM) */ ELFEDIT_I18NHDL(MSG_A1_SYM), ELFEDIT_CMDOA_F_OPT }, { MSG_ORIG(MSG_STR_VALUE), /* MSG_INTL(MSG_A2_DESC_ST_SIZE) */ ELFEDIT_I18NHDL(MSG_A2_DESC_ST_SIZE), ELFEDIT_CMDOA_F_OPT }, { NULL } }; /* sym:st_type */ static const char *name_st_type[] = { MSG_ORIG(MSG_CMD_ST_TYPE), NULL }; static elfedit_cmd_optarg_t arg_st_type[] = { { MSG_ORIG(MSG_STR_SYM), /* MSG_INTL(MSG_A1_SYM) */ ELFEDIT_I18NHDL(MSG_A1_SYM), ELFEDIT_CMDOA_F_OPT }, { MSG_ORIG(MSG_STR_VALUE), /* MSG_INTL(MSG_A2_DESC_ST_TYPE) */ ELFEDIT_I18NHDL(MSG_A2_DESC_ST_TYPE), ELFEDIT_CMDOA_F_OPT }, { NULL } }; /* sym:st_value */ static const char *name_st_value[] = { MSG_ORIG(MSG_CMD_ST_VALUE), NULL }; static elfedit_cmd_optarg_t arg_st_value[] = { { MSG_ORIG(MSG_STR_SYM), /* MSG_INTL(MSG_A1_SYM) */ ELFEDIT_I18NHDL(MSG_A1_SYM), ELFEDIT_CMDOA_F_OPT }, { MSG_ORIG(MSG_STR_VALUE), /* MSG_INTL(MSG_A2_DESC_ST_VALUE) */ ELFEDIT_I18NHDL(MSG_A2_DESC_ST_VALUE), ELFEDIT_CMDOA_F_OPT }, { NULL } }; /* sym:st_visibility */ static const char *name_st_visibility[] = { MSG_ORIG(MSG_CMD_ST_VISIBILITY), NULL }; static elfedit_cmd_optarg_t arg_st_visibility[] = { { MSG_ORIG(MSG_STR_SYM), /* MSG_INTL(MSG_A1_SYM) */ ELFEDIT_I18NHDL(MSG_A1_SYM), ELFEDIT_CMDOA_F_OPT }, { MSG_ORIG(MSG_STR_VALUE), /* MSG_INTL(MSG_A2_DESC_ST_VISIBILITY) */ ELFEDIT_I18NHDL(MSG_A2_DESC_ST_VISIBILITY), ELFEDIT_CMDOA_F_OPT }, { NULL } }; static elfedit_cmd_t cmds[] = { /* sym:dump */ { cmd_dump, cpl_sh_opt, name_dump, /* MSG_INTL(MSG_DESC_DUMP) */ ELFEDIT_I18NHDL(MSG_DESC_DUMP), /* MSG_INTL(MSG_HELP_DUMP) */ ELFEDIT_I18NHDL(MSG_HELP_DUMP), opt_dump, arg_dump }, /* sym:st_bind */ { cmd_st_bind, cpl_st_bind, name_st_bind, /* MSG_INTL(MSG_DESC_ST_BIND) */ ELFEDIT_I18NHDL(MSG_DESC_ST_BIND), /* MSG_INTL(MSG_HELP_ST_BIND) */ ELFEDIT_I18NHDL(MSG_HELP_ST_BIND), opt_std, arg_st_bind }, /* sym:st_info */ { cmd_st_info, cpl_sh_opt, name_st_info, /* MSG_INTL(MSG_DESC_ST_INFO) */ ELFEDIT_I18NHDL(MSG_DESC_ST_INFO), /* MSG_INTL(MSG_HELP_ST_INFO) */ ELFEDIT_I18NHDL(MSG_HELP_ST_INFO), opt_std, arg_st_info }, /* sym:st_name */ { cmd_st_name, cpl_sh_opt, name_st_name, /* MSG_INTL(MSG_DESC_ST_NAME) */ ELFEDIT_I18NHDL(MSG_DESC_ST_NAME), /* MSG_INTL(MSG_HELP_ST_NAME) */ ELFEDIT_I18NHDL(MSG_HELP_ST_NAME), opt_st_name, arg_st_name }, /* sym:st_other */ { cmd_st_other, cpl_sh_opt, name_st_other, /* MSG_INTL(MSG_DESC_ST_OTHER) */ ELFEDIT_I18NHDL(MSG_DESC_ST_OTHER), /* MSG_INTL(MSG_HELP_ST_OTHER) */ ELFEDIT_I18NHDL(MSG_HELP_ST_OTHER), opt_std, arg_st_other }, /* sym:st_shndx */ { cmd_st_shndx, cpl_st_shndx, name_st_shndx, /* MSG_INTL(MSG_DESC_ST_SHNDX) */ ELFEDIT_I18NHDL(MSG_DESC_ST_SHNDX), /* MSG_INTL(MSG_HELP_ST_SHNDX) */ ELFEDIT_I18NHDL(MSG_HELP_ST_SHNDX), opt_st_shndx, arg_st_shndx }, /* sym:st_size */ { cmd_st_size, cpl_sh_opt, name_st_size, /* MSG_INTL(MSG_DESC_ST_SIZE) */ ELFEDIT_I18NHDL(MSG_DESC_ST_SIZE), /* MSG_INTL(MSG_HELP_ST_SIZE) */ ELFEDIT_I18NHDL(MSG_HELP_ST_SIZE), opt_std, arg_st_size }, /* sym:st_type */ { cmd_st_type, cpl_st_type, name_st_type, /* MSG_INTL(MSG_DESC_ST_TYPE) */ ELFEDIT_I18NHDL(MSG_DESC_ST_TYPE), /* MSG_INTL(MSG_HELP_ST_TYPE) */ ELFEDIT_I18NHDL(MSG_HELP_ST_TYPE), opt_std, arg_st_type }, /* sym:st_value */ { cmd_st_value, cpl_sh_opt, name_st_value, /* MSG_INTL(MSG_DESC_ST_VALUE) */ ELFEDIT_I18NHDL(MSG_DESC_ST_VALUE), /* MSG_INTL(MSG_HELP_ST_VALUE) */ ELFEDIT_I18NHDL(MSG_HELP_ST_VALUE), opt_std, arg_st_value }, /* sym:st_visibility */ { cmd_st_visibility, cpl_st_visibility, name_st_visibility, /* MSG_INTL(MSG_DESC_ST_VISIBILITY) */ ELFEDIT_I18NHDL(MSG_DESC_ST_VISIBILITY), /* MSG_INTL(MSG_HELP_ST_VISIBILITY) */ ELFEDIT_I18NHDL(MSG_HELP_ST_VISIBILITY), opt_std, arg_st_visibility }, { NULL } }; static elfedit_module_t module = { ELFEDIT_VER_CURRENT, MSG_ORIG(MSG_MOD_NAME), /* MSG_INTL(MSG_MOD_DESC) */ ELFEDIT_I18NHDL(MSG_MOD_DESC), cmds, mod_i18nhdl_to_str }; return (&module); }