/* * 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 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include #include #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 { STR_CMD_T_DUMP = 0, /* str:dump */ STR_CMD_T_SET = 1, /* str:set */ STR_CMD_T_ADD = 2, /* str:add */ STR_CMD_T_ZERO = 3, /* str:zero */ } STR_CMD_T; #ifndef _ELF64 /* * We supply this function for the msg module. Only one copy is needed. */ const char * _str_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 { STR_OPT_F_END = 1, /* -end: zero to end of strtab */ STR_OPT_F_NOTERM = 2, /* -noterm: str:set won't term string */ STR_OPT_F_SHNAME = 4, /* -shnam name: section spec. by name */ STR_OPT_F_SHNDX = 8, /* -shndx ndx: strtab spec. by index */ STR_OPT_F_SHTYP = 16, /* -shtyp type: section spec. by type */ STR_OPT_F_STRNDX = 32, /* -strndx: String specified by index */ } str_opt_t; /* * A variable of type ARGSTATE is used by each command to maintain * information about the string table section being used, and for any * auxiliary sections that are related to it. */ typedef struct { elfedit_obj_state_t *obj_state; str_opt_t optmask; /* Mask of options used */ int argc; /* # of plain arguments */ const char **argv; /* Plain arguments */ struct { /* String table */ elfedit_section_t *sec; Word ndx; /* Table offset if (argc > 0) */ } str; struct { /* Dynamic section */ elfedit_section_t *sec; Dyn *data; Word n; elfedit_dyn_elt_t strpad; } dyn; } ARGSTATE; /* * Given an ELF SHT_ section type constant, shdr_to_strtab() returns * one of the following */ typedef enum { SHTOSTR_NONE = 0, /* Type can't lead to a string table */ SHTOSTR_STRTAB = 1, /* type is SHT_STRTAB */ SHTOSTR_LINK_STRTAB = 2, /* sh_link for type yields strtab */ SHTOSTR_LINK_SYMTAB = 3, /* sh_link for type yields symtab */ } SHTOSTR_T; static int shtype_to_strtab(Word sh_type) { switch (sh_type) { case SHT_STRTAB: return (SHTOSTR_STRTAB); /* These sections reference a string table via sh_link */ case SHT_DYNAMIC: case SHT_SYMTAB: case SHT_DYNSYM: case SHT_SUNW_LDYNSYM: case SHT_SUNW_verdef: case SHT_SUNW_verneed: return (SHTOSTR_LINK_STRTAB); /* * These sections reference a symbol table via sh_link. * Symbol tables, in turn, reference a string table * via their sh_link. */ case SHT_HASH: case SHT_REL: case SHT_RELA: case SHT_GROUP: case SHT_SYMTAB_SHNDX: case SHT_SUNW_move: case SHT_SUNW_syminfo: case SHT_SUNW_versym: case SHT_SUNW_symsort: case SHT_SUNW_tlssort: return (SHTOSTR_LINK_SYMTAB); } /* Types that lead to string tables were caught above */ return (SHTOSTR_NONE); } /* * Given a section index, attempt to convert it into an index * to a string table section. */ static Word shndx_to_strtab(elfedit_obj_state_t *obj_state, Word ndx) { /* * Locate and validate the string table. In the case where * a non-string table section is given that references a string * table, we will use the referenced table. */ if (ndx < obj_state->os_shnum) { switch (shtype_to_strtab( obj_state->os_secarr[ndx].sec_shdr->sh_type)) { /* Sections that reference a string table via sh_link */ case SHTOSTR_LINK_STRTAB: ndx = obj_state->os_secarr[ndx].sec_shdr->sh_link; break; /* * Sections that reference a symbol tabel via sh_link, * which in turn reference a string table via their sh_link. */ case SHTOSTR_LINK_SYMTAB: ndx = obj_state->os_secarr[ndx].sec_shdr->sh_link; if (ndx < obj_state->os_shnum) ndx = obj_state->os_secarr[ndx].sec_shdr->sh_link; break; } } return (ndx); } /* * Standard argument processing for string table module * * entry * obj_state, argc, argv - Standard command arguments * optmask - Mask of allowed optional arguments. * 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. */ static void process_args(elfedit_obj_state_t *obj_state, int argc, const char *argv[], STR_CMD_T cmd, ARGSTATE *argstate, int *print_only) { elfedit_getopt_state_t getopt_state; elfedit_getopt_ret_t *getopt_ret; Word ndx; int argc_ok; bzero(argstate, sizeof (*argstate)); argstate->obj_state = obj_state; /* * By default, we use the section name string table pointed at * by the ELF header. */ ndx = obj_state->os_ehdr->e_shstrndx; elfedit_getopt_init(&getopt_state, &argc, &argv); /* Add each new option to the options mask */ while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL) { argstate->optmask |= getopt_ret->gor_idmask; switch (getopt_ret->gor_idmask) { case STR_OPT_F_SHNAME: /* -shnam name */ ndx = elfedit_name_to_shndx(obj_state, getopt_ret->gor_value); break; case STR_OPT_F_SHNDX: /* -shndx index */ ndx = elfedit_atoui(getopt_ret->gor_value, NULL); break; case STR_OPT_F_SHTYP: /* -shtyp type */ ndx = elfedit_type_to_shndx(obj_state, elfedit_atoconst(getopt_ret->gor_value, ELFEDIT_CONST_SHT)); break; } } /* * Usage error if there are the wrong number of plain arguments. */ switch (cmd) { case STR_CMD_T_DUMP: argc_ok = (argc == 0) || (argc == 1); *print_only = 1; break; case STR_CMD_T_SET: argc_ok = (argc == 1) || (argc == 2); *print_only = (argc == 1); break; case STR_CMD_T_ADD: argc_ok = (argc == 1); *print_only = 0; break; case STR_CMD_T_ZERO: /* * The second argument (count) and the -end option are * mutally exclusive. */ argc_ok = ((argc == 1) || (argc == 2)) && !((argc == 2) && (argstate->optmask & STR_OPT_F_END)); *print_only = 0; break; default: argc_ok = 0; /* Unknown command? */ break; } if (!argc_ok) elfedit_command_usage(); /* 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; /* * Locate and validate the string table. In the case where * a non-string table section is given that references a string * table, we will use the referenced table. */ ndx = shndx_to_strtab(obj_state, ndx); /* * If ndx is a string table, the following will issue the * proper debug messages. If it is out of range, or of any * other type, an error is issued and it doesn't return. */ argstate->str.sec = elfedit_sec_getstr(obj_state, ndx); /* * If there is a dynamic section, check its sh_link to the * string table index. If these match, then we have the * dynamic string table. In that case, fetch the dynamic * section and locate the DT_SUNW_STRPAD entry, causing * debug messages to be issued. */ argstate->dyn.sec = NULL; elfedit_dyn_elt_init(&argstate->dyn.strpad); if (obj_state->os_dynndx != SHN_UNDEF) { elfedit_section_t *dynsec = &obj_state->os_secarr[obj_state->os_dynndx]; if ((dynsec->sec_shdr->sh_type == SHT_DYNAMIC) && (argstate->str.sec->sec_shndx == dynsec->sec_shdr->sh_link)) { argstate->dyn.sec = elfedit_sec_getdyn(obj_state, &argstate->dyn.data, &argstate->dyn.n); (void) elfedit_dynstr_getpad(dynsec, &argstate->dyn.strpad); /* * Does the pad value make sense? * Issue debug message and ignore it if not. */ if ((argstate->dyn.strpad.dn_seen != 0) && (argstate->dyn.strpad.dn_dyn.d_un.d_val > argstate->str.sec->sec_data->d_size)) { argstate->dyn.strpad.dn_seen = 0; elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_BADSTRPAD), EC_WORD(argstate->str.sec->sec_shndx), argstate->str.sec->sec_name, EC_XWORD(argstate->dyn.strpad.dn_dyn. d_un.d_val), EC_XWORD(argstate->str.sec-> sec_data->d_size)); } } } /* Locate the string table offset if argument is present */ if ((argc > 0) && (cmd != STR_CMD_T_ADD)) { /* * If the -strndx option was specified, arg is an index * into the string table. Otherwise it is a string * to be looked up. */ if (argstate->optmask & STR_OPT_F_STRNDX) { argstate->str.ndx = (elfedit_atoui_range(argv[0], MSG_ORIG(MSG_STR_STRING), 0, argstate->str.sec->sec_data->d_size - 1, NULL)); } else { if (elfedit_sec_findstr(argstate->str.sec, 0, argv[0], &argstate->str.ndx) == 0) elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_STRNOTFND), EC_WORD(argstate->str.sec->sec_shndx), argstate->str.sec->sec_name, argv[0]); } } else { argstate->str.ndx = 0; } } /* * Print string table values, taking 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. * argstate - State block for current symbol table. */ static void print_strtab(int autoprint, ARGSTATE *argstate) { char index[(MAXNDXSIZE * 2) + 4]; elfedit_outstyle_t outstyle; const char *str, *limit, *tbl_limit; Word ndx; if (autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0)) return; outstyle = elfedit_outstyle(); if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) { elfedit_printf(MSG_INTL(MSG_FMT_STRTAB), argstate->str.sec->sec_name); if (argstate->dyn.strpad.dn_seen) elfedit_printf(MSG_INTL(MSG_FMT_DYNSTRPAD), EC_WORD(argstate->str.sec->sec_data->d_size - argstate->dyn.strpad.dn_dyn.d_un.d_val), EC_WORD(argstate->str.sec->sec_data->d_size - 1), EC_WORD(argstate->dyn.strpad.dn_dyn.d_un.d_val)); elfedit_printf(MSG_INTL(MSG_FMT_DUMPTITLE)); } str = argstate->str.sec->sec_data->d_buf; tbl_limit = str + argstate->str.sec->sec_data->d_size; ndx = argstate->str.ndx; if (argstate->argc > 0) { str += ndx; /* * If first byte is NULL and this is the default output style, * then we want to display the range of NULL bytes, and we * push limit out to the last one in the sequence. Otherwise, * just display the string. */ if ((*str == '\0') && (outstyle == ELFEDIT_OUTSTYLE_DEFAULT)) { limit = str; while (((limit + 1) < tbl_limit) && (*(limit + 1) == '\0')) limit++; } else { limit = str + strlen(str) + 1; } } else { /* Display the entire string table */ limit = tbl_limit; } while (str < limit) { Word skip = strlen(str) + 1; Word start_ndx; if (outstyle != ELFEDIT_OUTSTYLE_DEFAULT) { elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), str); str += skip; ndx += skip; continue; } start_ndx = ndx; if (*str == '\0') while (((str + 1) < limit) && (*(str + 1) == '\0')) { ndx++; str++; } if (start_ndx != ndx) { (void) snprintf(index, sizeof (index), MSG_ORIG(MSG_FMT_INDEXRANGE), EC_XWORD(start_ndx), EC_XWORD(ndx)); } else { (void) snprintf(index, sizeof (index), MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(ndx)); } elfedit_printf(MSG_ORIG(MSG_FMT_DUMPENTRY), index, str); str += skip; ndx += skip; } } /* * Command body for str:set, handling the case where the 3rd * argument (new-str) is present. */ static elfedit_cmdret_t cmd_body_set(ARGSTATE *argstate) { elfedit_section_t *strsec = argstate->str.sec; const char *newstr = argstate->argv[1]; Word ndx = argstate->str.ndx; char *oldstr; int i, len, ncp; len = strlen(newstr); ncp = len; if (!(argstate->optmask & STR_OPT_F_NOTERM)) ncp++; /* NULL string with no termination? Nothing to do */ if (ncp == 0) return (ELFEDIT_CMDRET_NONE); /* Does it fit? */ if ((ndx + ncp) > strsec->sec_data->d_size) elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOFIT), EC_WORD(strsec->sec_shndx), strsec->sec_name, EC_WORD(ndx), newstr); /* Does it clobber the final NULL termination? */ if (((ndx + ncp) == strsec->sec_data->d_size) && (argstate->optmask & STR_OPT_F_NOTERM)) elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_FINALNULL), EC_WORD(strsec->sec_shndx), strsec->sec_name, EC_WORD(ndx), newstr); /* * strtab[0] is always supposed to contain a NULL byte. You're not * supposed to mess with it. We will carry out this operation, * but with a debug message indicating that it is unorthodox. */ if ((ndx == 0) && (*newstr != '\0')) elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CHGSTR0), EC_WORD(strsec->sec_shndx), strsec->sec_name, EC_WORD(ndx), newstr); /* Does it alter the existing value? */ oldstr = ndx + (char *)strsec->sec_data->d_buf; for (i = 0; i < ncp; i++) if (newstr[i] != oldstr[i]) break; if (i == ncp) { /* No change */ elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_OK), strsec->sec_shndx, strsec->sec_name, ndx, newstr); return (ELFEDIT_CMDRET_NONE); } /* * If the new string is longer than the old one, then it will * clobber the start of the following string. The resulting * string table is perfectly legal, but issue a debug message * letting the user know. */ i = strlen(oldstr); if (len > i) elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_LONGSTR), EC_WORD(strsec->sec_shndx), strsec->sec_name, EC_WORD(ndx), len, i); /* * If we have strayed into the reserved part of the dynstr, then * update DT_SUNW_STRPAD. */ if (argstate->dyn.strpad.dn_seen) { elfedit_dyn_elt_t *strpad = &argstate->dyn.strpad; Word new_pad_ndx = ndx + len + 1; Word pad_ndx = argstate->str.sec->sec_data->d_size - strpad->dn_dyn.d_un.d_val; if (new_pad_ndx > pad_ndx) { elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_ADDDYNSTR), EC_WORD(strsec->sec_shndx), strsec->sec_name, EC_WORD(ndx), EC_WORD(new_pad_ndx - pad_ndx), EC_WORD(strpad->dn_dyn.d_un.d_val), newstr); strpad->dn_dyn.d_un.d_val = argstate->dyn.data[strpad->dn_ndx].d_un.d_val = (argstate->str.sec->sec_data->d_size - new_pad_ndx); elfedit_modified_data(argstate->dyn.sec); } } elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_CHG), strsec->sec_shndx, strsec->sec_name, ndx, len, oldstr, newstr); bcopy(newstr, oldstr, ncp); return (ELFEDIT_CMDRET_MOD); } /* * Command body for str:zero */ static elfedit_cmdret_t cmd_body_zero(ARGSTATE *argstate) { elfedit_section_t *strsec = argstate->str.sec; Word count; Word ndx = argstate->str.ndx; char *oldstr = ndx + (char *)strsec->sec_data->d_buf; Word i; /* How many bytes to zero? */ if (argstate->optmask & STR_OPT_F_END) count = strsec->sec_data->d_size - argstate->str.ndx; else if (argstate->argc == 2) count = elfedit_atoui_range(argstate->argv[1], MSG_ORIG(MSG_STR_COUNT), 0, argstate->str.sec->sec_data->d_size - argstate->str.ndx, NULL); else count = strlen(oldstr); /* Does it alter the existing value? */ for (i = 0; i < count; i++) if (oldstr[i] != '\0') break; if (i == count) { /* No change */ elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_Z_OK), strsec->sec_shndx, strsec->sec_name, ndx); return (ELFEDIT_CMDRET_NONE); } elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_Z_CHG), strsec->sec_shndx, strsec->sec_name, ndx, count); bzero(oldstr, count); return (ELFEDIT_CMDRET_MOD); } /* * Common body for the str: module commands. * * entry: * cmd - One of the STR_CMD_T_* constants listed above, specifying * which command to implement. * obj_state, argc, argv - Standard command arguments */ static elfedit_cmdret_t cmd_body(STR_CMD_T cmd, elfedit_obj_state_t *obj_state, int argc, const char *argv[]) { ARGSTATE argstate; elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE; int print_only; process_args(obj_state, argc, argv, cmd, &argstate, &print_only); /* * If this call call does not change data, display the current * value(s) and return. */ if (print_only) { print_strtab(0, &argstate); return (ELFEDIT_CMDRET_NONE); } switch (cmd) { /* NOTE: STR_CMD_T_DUMP can't get here --- it's always print_only */ case STR_CMD_T_SET: ret = cmd_body_set(&argstate); break; case STR_CMD_T_ADD: argstate.str.ndx = elfedit_strtab_insert(obj_state, argstate.str.sec, argstate.dyn.sec, argstate.argv[0]); break; case STR_CMD_T_ZERO: ret = cmd_body_zero(&argstate); break; } /* * If we modified the strtab section, tell libelf. */ if (ret == ELFEDIT_CMDRET_MOD) elfedit_modified_data(argstate.str.sec); /* Do autoprint */ print_strtab(1, &argstate); return (ret); } /* * Command completion functions for the various commands */ static void add_shtyp_match(Word sh_type, void *cpldata) { char buf[128]; const char *s; char *s2; s = elfedit_atoconst_value_to_str(ELFEDIT_CONST_SHT, sh_type, 0); elfedit_cpl_match(cpldata, s, 1); /* * To get the informal tag names that are lowercase * and lack the leading SHT_, we copy the string we * have into a buffer and process it. */ if (strlen(s) < 4) return; (void) strlcpy(buf, s + 4, sizeof (buf)); for (s2 = buf; *s2 != '\0'; s2++) if (isupper(*s2)) *s2 = tolower(*s2); elfedit_cpl_match(cpldata, buf, 1); } /* * 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_section_t *sec; Word ndx; 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_atoui_sym_t *atoui_sym; atoui_sym = elfedit_const_to_atoui(ELFEDIT_CONST_SHT); for (; atoui_sym->sym_name != NULL; atoui_sym++) if (shtype_to_strtab(atoui_sym->sym_value) != SHTOSTR_NONE) elfedit_cpl_match(cpldata, atoui_sym->sym_name, 1); } } else { return; } if (obj_state == NULL) /* No object available */ return; /* * Loop over the section headers and supply command completion * for the items in the file that can yield a string table. */ sec = obj_state->os_secarr; for (ndx = 0; ndx < obj_state->os_shnum; ndx++, sec++) { Word sh_type = sec->sec_shdr->sh_type; if (shtype_to_strtab(sh_type) == SHTOSTR_NONE) continue; switch (op) { case NAME: elfedit_cpl_match(cpldata, sec->sec_name, 0); break; case INDEX: { char index[MAXNDXSIZE]; (void) snprintf(index, sizeof (index), MSG_ORIG(MSG_FMT_WORDVAL), sec->sec_shndx); elfedit_cpl_match(cpldata, index, 1); } break; case TYPE: add_shtyp_match(sh_type, cpldata); break; } } } /* * Most of the commands accept an -shXXX option for the string table * and a string first argument. This routine examines which argument * is being processed, and supplies completion for these items. */ static void cpl_sec_str(elfedit_obj_state_t *obj_state, void *cpldata, int argc, const char *argv[], int num_opt) { const char *str, *limit; elfedit_section_t *sec; Word strtab_ndx; Word ndx; /* Handle -shXXX options */ cpl_sh_opt(obj_state, cpldata, argc, argv, num_opt); /* Without object state, there's no data to work from */ if (obj_state == NULL) return; /* If not first plain arg, return */ if (argc != (num_opt + 1)) return; /* * Look at the options, looking for two things: * 1) A -shXXX option specifying a section. If so, turn that * into a section index if possible. * 2) Was -strndx used? If so, we are looking at an integer * value and have nothing to complete. */ strtab_ndx = obj_state->os_ehdr->e_shstrndx; for (ndx = 0; ndx < num_opt; ndx++) { if (strcmp(argv[ndx], MSG_ORIG(MSG_STR_MINUS_STRNDX)) == 0) return; if ((ndx+1) < num_opt) { if (strcmp(argv[ndx], MSG_ORIG(MSG_STR_MINUS_SHNAM)) == 0) { Word i; for (i = 1; i < obj_state->os_shnum; i++) if (strcmp(obj_state->os_secarr[i]. sec_name, argv[ndx+1]) == 0) { strtab_ndx = i; break; } } else if (strcmp(argv[ndx], MSG_ORIG(MSG_STR_MINUS_SHNDX)) == 0) { elfedit_atoui_t val; if (elfedit_atoui2(argv[ndx+1], NULL, &val) != 0) strtab_ndx = val; } else if (strcmp(argv[ndx], MSG_ORIG(MSG_STR_MINUS_SHTYP)) == 0) { elfedit_atoui_t sh_type; Word i; if (elfedit_atoconst2(argv[ndx+1], ELFEDIT_CONST_SHT, &sh_type) == 0) continue; for (i = 1; i < obj_state->os_shnum; i++) if (obj_state->os_secarr[i].sec_shdr-> sh_type == sh_type) { strtab_ndx = i; break; } } } } /* * Locate and validate the string table. In the case where * a non-string table section is given that references a string * table, we will use the referenced table. */ strtab_ndx = shndx_to_strtab(obj_state, strtab_ndx); if ((strtab_ndx >= obj_state->os_shnum) || (obj_state->os_secarr[strtab_ndx].sec_shdr->sh_type != SHT_STRTAB)) return; sec = &obj_state->os_secarr[strtab_ndx]; str = sec->sec_data->d_buf; limit = str + sec->sec_data->d_size; while (str < limit) { if (*str != '\0') elfedit_cpl_match(cpldata, str, 0); str += strlen(str) + 1; } } /* * 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(STR_CMD_T_DUMP, obj_state, argc, argv)); } static elfedit_cmdret_t cmd_set(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) { return (cmd_body(STR_CMD_T_SET, obj_state, argc, argv)); } static elfedit_cmdret_t cmd_add(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) { return (cmd_body(STR_CMD_T_ADD, obj_state, argc, argv)); } static elfedit_cmdret_t cmd_zero(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) { return (cmd_body(STR_CMD_T_ZERO, obj_state, argc, argv)); } /*ARGSUSED*/ elfedit_module_t * elfedit_init(elfedit_module_version_t version) { /* str: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[] = { { ELFEDIT_STDOA_OPT_O, NULL, ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, { MSG_ORIG(MSG_STR_MINUS_SHNAM), /* MSG_INTL(MSG_OPTDESC_SHNAM) */ ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE, STR_OPT_F_SHNAME, STR_OPT_F_SHNDX | STR_OPT_F_SHTYP }, { MSG_ORIG(MSG_STR_NAME), NULL, 0 }, { MSG_ORIG(MSG_STR_MINUS_SHNDX), /* MSG_INTL(MSG_OPTDESC_SHNDX) */ ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE, STR_OPT_F_SHNDX, STR_OPT_F_SHNAME | STR_OPT_F_SHTYP }, { MSG_ORIG(MSG_STR_INDEX), NULL, 0 }, { MSG_ORIG(MSG_STR_MINUS_SHTYP), /* MSG_INTL(MSG_OPTDESC_SHTYP) */ ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE, STR_OPT_F_SHTYP, STR_OPT_F_SHNAME | STR_OPT_F_SHNDX }, { MSG_ORIG(MSG_STR_TYPE), NULL, 0 }, { MSG_ORIG(MSG_STR_MINUS_STRNDX), /* MSG_INTL(MSG_OPTDESC_STRNDX) */ ELFEDIT_I18NHDL(MSG_OPTDESC_STRNDX), 0, STR_OPT_F_STRNDX, 0 }, { NULL } }; static elfedit_cmd_optarg_t arg_dump[] = { { MSG_ORIG(MSG_STR_STRING), /* MSG_INTL(MSG_A1_STRING) */ ELFEDIT_I18NHDL(MSG_A1_STRING), ELFEDIT_CMDOA_F_OPT }, { NULL } }; /* str:set */ static const char *name_set[] = { MSG_ORIG(MSG_CMD_SET), NULL }; static elfedit_cmd_optarg_t opt_set[] = { { ELFEDIT_STDOA_OPT_O, NULL, ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, { MSG_ORIG(MSG_STR_MINUS_NOTERM), /* MSG_INTL(MSG_OPTDESC_NOTERM) */ ELFEDIT_I18NHDL(MSG_OPTDESC_NOTERM), 0, STR_OPT_F_NOTERM, 0 }, { MSG_ORIG(MSG_STR_MINUS_SHNAM), /* MSG_INTL(MSG_OPTDESC_SHNAM) */ ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE, STR_OPT_F_SHNAME, STR_OPT_F_SHNDX | STR_OPT_F_SHTYP }, { MSG_ORIG(MSG_STR_NAME), NULL, 0 }, { MSG_ORIG(MSG_STR_MINUS_SHNDX), /* MSG_INTL(MSG_OPTDESC_SHNDX) */ ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE, STR_OPT_F_SHNDX, STR_OPT_F_SHNAME | STR_OPT_F_SHTYP }, { MSG_ORIG(MSG_STR_INDEX), NULL, 0 }, { MSG_ORIG(MSG_STR_MINUS_SHTYP), /* MSG_INTL(MSG_OPTDESC_SHTYP) */ ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE, STR_OPT_F_SHTYP, STR_OPT_F_SHNAME | STR_OPT_F_SHNDX }, { MSG_ORIG(MSG_STR_TYPE), NULL, 0 }, { MSG_ORIG(MSG_STR_MINUS_STRNDX), /* MSG_INTL(MSG_OPTDESC_STRNDX) */ ELFEDIT_I18NHDL(MSG_OPTDESC_STRNDX), 0, STR_OPT_F_STRNDX, 0 }, { NULL } }; static elfedit_cmd_optarg_t arg_set[] = { { MSG_ORIG(MSG_STR_STRING), /* MSG_INTL(MSG_A1_STRING) */ ELFEDIT_I18NHDL(MSG_A1_STRING), 0 }, { MSG_ORIG(MSG_STR_NEWSTRING), /* MSG_INTL(MSG_A2_NEWSTRING) */ ELFEDIT_I18NHDL(MSG_A2_NEWSTRING), ELFEDIT_CMDOA_F_OPT }, { NULL } }; /* str:add */ static const char *name_add[] = { MSG_ORIG(MSG_CMD_ADD), NULL }; static elfedit_cmd_optarg_t opt_add[] = { { ELFEDIT_STDOA_OPT_O, NULL, ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, { MSG_ORIG(MSG_STR_MINUS_SHNAM), /* MSG_INTL(MSG_OPTDESC_SHNAM) */ ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE, STR_OPT_F_SHNAME, STR_OPT_F_SHNDX | STR_OPT_F_SHTYP }, { MSG_ORIG(MSG_STR_NAME), NULL, 0 }, { MSG_ORIG(MSG_STR_MINUS_SHNDX), /* MSG_INTL(MSG_OPTDESC_SHNDX) */ ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE, STR_OPT_F_SHNDX, STR_OPT_F_SHNAME | STR_OPT_F_SHTYP }, { MSG_ORIG(MSG_STR_INDEX), NULL, 0 }, { MSG_ORIG(MSG_STR_MINUS_SHTYP), /* MSG_INTL(MSG_OPTDESC_SHTYP) */ ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE, STR_OPT_F_SHTYP, STR_OPT_F_SHNAME | STR_OPT_F_SHNDX }, { MSG_ORIG(MSG_STR_TYPE), NULL, 0 }, { NULL } }; static elfedit_cmd_optarg_t arg_add[] = { { MSG_ORIG(MSG_STR_NEWSTRING), /* MSG_INTL(MSG_A1_NEWSTRING) */ ELFEDIT_I18NHDL(MSG_A1_NEWSTRING), 0 }, { NULL } }; /* str:zero */ static const char *name_zero[] = { MSG_ORIG(MSG_CMD_ZERO), NULL }; static elfedit_cmd_optarg_t opt_zero[] = { { ELFEDIT_STDOA_OPT_O, NULL, ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, { MSG_ORIG(MSG_STR_MINUS_SHNAM), /* MSG_INTL(MSG_OPTDESC_SHNAM) */ ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE, STR_OPT_F_SHNAME, STR_OPT_F_SHNDX | STR_OPT_F_SHTYP }, { MSG_ORIG(MSG_STR_NAME), NULL, 0 }, { MSG_ORIG(MSG_STR_MINUS_SHNDX), /* MSG_INTL(MSG_OPTDESC_SHNDX) */ ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE, STR_OPT_F_SHNDX, STR_OPT_F_SHNAME | STR_OPT_F_SHTYP }, { MSG_ORIG(MSG_STR_INDEX), NULL, 0 }, { MSG_ORIG(MSG_STR_MINUS_SHTYP), /* MSG_INTL(MSG_OPTDESC_SHTYP) */ ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE, STR_OPT_F_SHTYP, STR_OPT_F_SHNAME | STR_OPT_F_SHNDX }, { MSG_ORIG(MSG_STR_TYPE), NULL, 0 }, { MSG_ORIG(MSG_STR_MINUS_STRNDX), /* MSG_INTL(MSG_OPTDESC_STRNDX) */ ELFEDIT_I18NHDL(MSG_OPTDESC_STRNDX), 0, STR_OPT_F_STRNDX, 0 }, { MSG_ORIG(MSG_STR_MINUS_END), /* MSG_INTL(MSG_OPTDESC_END) */ ELFEDIT_I18NHDL(MSG_OPTDESC_END), 0, STR_OPT_F_END, 0 }, { NULL } }; static elfedit_cmd_optarg_t arg_zero[] = { { MSG_ORIG(MSG_STR_STRING), /* MSG_INTL(MSG_A1_STRING) */ ELFEDIT_I18NHDL(MSG_A1_STRING), 0 }, { MSG_ORIG(MSG_STR_COUNT), /* MSG_INTL(MSG_A2_COUNT) */ ELFEDIT_I18NHDL(MSG_A2_COUNT), ELFEDIT_CMDOA_F_OPT }, { NULL } }; static elfedit_cmd_t cmds[] = { /* str:dump */ { cmd_dump, cpl_sec_str, 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 }, /* str:set */ { cmd_set, cpl_sec_str, name_set, /* MSG_INTL(MSG_DESC_SET) */ ELFEDIT_I18NHDL(MSG_DESC_SET), /* MSG_INTL(MSG_HELP_SET) */ ELFEDIT_I18NHDL(MSG_HELP_SET), opt_set, arg_set }, /* str:add */ { cmd_add, cpl_sh_opt, name_add, /* MSG_INTL(MSG_DESC_ADD) */ ELFEDIT_I18NHDL(MSG_DESC_ADD), /* MSG_INTL(MSG_HELP_ADD) */ ELFEDIT_I18NHDL(MSG_HELP_ADD), opt_add, arg_add }, /* str:zero */ { cmd_zero, cpl_sec_str, name_zero, /* MSG_INTL(MSG_DESC_ZERO) */ ELFEDIT_I18NHDL(MSG_DESC_ZERO), /* MSG_INTL(MSG_HELP_ZERO) */ ELFEDIT_I18NHDL(MSG_HELP_ZERO), opt_zero, arg_zero }, { 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); }