/*
* 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
* 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.
*/
#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
#include <elfedit.h>
#include <strings.h>
#include <debug.h>
#include <conv.h>
#include <str_msg.h>
/*
* 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;
#ifndef _ELF64
/*
* We supply this function for the msg module. Only one copy is needed.
*/
const char *
{
}
#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 *
{
}
/*
* The sym_opt_t enum specifies a bit value for every optional
* argument allowed by a command in this module.
*/
typedef enum {
} 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 {
struct { /* String table */
} str;
struct { /* Dynamic section */
Word n;
} dyn;
} ARGSTATE;
/*
* Given an ELF SHT_ section type constant, shndx_to_strtab() returns
* one of the following
*/
typedef enum {
} SHTOSTR_T;
static SHTOSTR_T
{
/*
* A string table section always leads to itself. A
* non-string table that has it's SHF_STRINGS section flag
* set trumps anything else.
*/
if (sh_type == SHT_STRTAB)
return (SHTOSTR_STRTAB);
if (sh_flags & SHF_STRINGS)
return (SHTOSTR_SHF_STRINGS);
/*
* Look at non-stringtable section types that can lead to
* string tables via sh_link.
*/
switch (sh_type) {
/* 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
{
/*
* 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.
*/
/* Sections that reference a string table via sh_link */
case SHTOSTR_LINK_STRTAB:
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 =
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
{
int argc_ok;
/*
* By default, we use the section name string table pointed at
* by the ELF header.
*/
/* Add each new option to the options mask */
switch (getopt_ret->gor_idmask) {
case STR_OPT_F_SHNAME: /* -shnam name */
break;
case STR_OPT_F_SHNDX: /* -shndx index */
break;
case STR_OPT_F_SHTYP: /* -shtyp type */
break;
}
}
/*
* Usage error if there are the wrong number of plain arguments.
*/
switch (cmd) {
case STR_CMD_T_DUMP:
*print_only = 1;
break;
case STR_CMD_T_SET:
break;
case STR_CMD_T_ADD:
*print_only = 0;
break;
case STR_CMD_T_ZERO:
/*
* The second argument (count) and the -end option are
* mutally exclusive.
*/
*print_only = 0;
break;
default:
argc_ok = 0; /* Unknown command? */
break;
}
if (!argc_ok)
/* If there may be an arbitrary amount of output, use a pager */
if (argc == 0)
/* Take the arbitrary section */
} else {
/*
* 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 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.
*/
}
/*
* 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.
*/
/*
* Does the pad value make sense?
* Issue debug message and ignore it if not.
*/
}
}
}
/* Locate the string table offset if argument is present */
/*
* If the -strndx option was specified, arg is an index
* into the string table. Otherwise it is a string
* to be looked up.
*/
MSG_ORIG(MSG_STR_STRING), 0,
} else {
}
} else {
}
}
/*
* 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
{
return;
outstyle = elfedit_outstyle();
if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) {
}
/*
* 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.
*/
limit++;
} else {
}
} else {
/* Display the entire string table */
}
if (outstyle != ELFEDIT_OUTSTYLE_DEFAULT) {
continue;
}
if (*str == '\0')
ndx++;
str++;
}
} else {
}
}
}
/*
* Command body for str:set, handling the case where the 3rd
* argument (new-str) is present.
*/
static elfedit_cmdret_t
{
char *oldstr;
ncp++;
/* NULL string with no termination? Nothing to do */
if (ncp == 0)
return (ELFEDIT_CMDRET_NONE);
/* Does it fit? */
/* Does it clobber the final NULL termination? */
/*
* 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.
*/
/* Does it alter the existing value? */
for (i = 0; i < ncp; i++)
break;
if (i == ncp) { /* No change */
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.
*/
if (len > i)
/*
* If we have strayed into the reserved part of the dynstr, then
* update DT_SUNW_STRPAD.
*/
if (new_pad_ndx > pad_ndx) {
newstr);
}
}
return (ELFEDIT_CMDRET_MOD);
}
/*
* Command body for str:zero
*/
static elfedit_cmdret_t
{
Word i;
/* How many bytes to zero? */
MSG_ORIG(MSG_STR_COUNT), 0,
NULL);
else
/* Does it alter the existing value? */
for (i = 0; i < count; i++)
if (oldstr[i] != '\0')
break;
if (i == count) { /* No change */
return (ELFEDIT_CMDRET_NONE);
}
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
{
int 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:
break;
case STR_CMD_T_ADD:
break;
case STR_CMD_T_ZERO:
break;
}
/*
* If we modified the strtab section, tell libelf.
*/
if (ret == ELFEDIT_CMDRET_MOD)
/* Do autoprint */
return (ret);
}
/*
* Command completion functions for the various commands
*/
static void
{
const char *s;
char *s2;
/*
* 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;
}
/*
* Handle filling in the values for -shnam, -shndx, and -shtyp options.
*/
/*ARGSUSED*/
static void
{
return;
}
} else {
return;
}
return;
/*
* Loop over the section headers and supply command completion
* for the items in the file that can yield a string table.
*/
if (shtostr_type == SHTOSTR_NONE)
continue;
switch (op) {
case NAME:
break;
case INDEX:
break;
case TYPE:
if (shtostr_type != SHTOSTR_SHF_STRINGS)
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
{
/* Handle -shXXX options */
/* Without object state, there's no data to work from */
return;
/* If not first plain arg, return */
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.
*/
return;
MSG_ORIG(MSG_STR_MINUS_SHNAM)) == 0) {
Word i;
strtab_ndx = i;
break;
}
MSG_ORIG(MSG_STR_MINUS_SHNDX)) == 0) {
&val) != 0)
strtab_ndx = val;
MSG_ORIG(MSG_STR_MINUS_SHTYP)) == 0) {
Word i;
ELFEDIT_CONST_SHT, &sh_type) == 0)
continue;
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.
*/
return;
if (*str != '\0')
}
}
/*
* Implementation functions for the commands
*/
static elfedit_cmdret_t
{
}
static elfedit_cmdret_t
{
}
static elfedit_cmdret_t
{
}
static elfedit_cmdret_t
{
}
/*ARGSUSED*/
{
/* str:dump */
static const char *name_dump[] = {
};
/* MSG_INTL(MSG_OPTDESC_ANY) */
STR_OPT_F_ANY, 0 },
ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
/* MSG_INTL(MSG_OPTDESC_SHNAM) */
/* MSG_INTL(MSG_OPTDESC_SHNDX) */
/* MSG_INTL(MSG_OPTDESC_SHTYP) */
/* MSG_INTL(MSG_OPTDESC_STRNDX) */
STR_OPT_F_STRNDX, 0 },
{ NULL }
};
/* MSG_INTL(MSG_A1_STRING) */
{ NULL }
};
/* str:set */
static const char *name_set[] = {
/* MSG_INTL(MSG_OPTDESC_ANY) */
STR_OPT_F_ANY, 0 },
ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
/* MSG_INTL(MSG_OPTDESC_NOTERM) */
STR_OPT_F_NOTERM, 0 },
/* MSG_INTL(MSG_OPTDESC_SHNAM) */
/* MSG_INTL(MSG_OPTDESC_SHNDX) */
/* MSG_INTL(MSG_OPTDESC_SHTYP) */
/* MSG_INTL(MSG_OPTDESC_STRNDX) */
STR_OPT_F_STRNDX, 0 },
{ NULL }
};
/* MSG_INTL(MSG_A1_STRING) */
0 },
/* MSG_INTL(MSG_A2_NEWSTRING) */
{ NULL }
};
/* str:add */
static const char *name_add[] = {
ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
/* MSG_INTL(MSG_OPTDESC_SHNAM) */
/* MSG_INTL(MSG_OPTDESC_SHNDX) */
/* MSG_INTL(MSG_OPTDESC_SHTYP) */
{ NULL }
};
/* MSG_INTL(MSG_A1_NEWSTRING) */
0 },
{ NULL }
};
/* str:zero */
static const char *name_zero[] = {
/* MSG_INTL(MSG_OPTDESC_ANY) */
STR_OPT_F_ANY, 0 },
ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
/* MSG_INTL(MSG_OPTDESC_SHNAM) */
/* MSG_INTL(MSG_OPTDESC_SHNDX) */
/* MSG_INTL(MSG_OPTDESC_SHTYP) */
/* MSG_INTL(MSG_OPTDESC_STRNDX) */
STR_OPT_F_STRNDX, 0 },
/* MSG_INTL(MSG_OPTDESC_END) */
STR_OPT_F_END, 0 },
{ NULL }
};
/* MSG_INTL(MSG_A1_STRING) */
0 },
/* MSG_INTL(MSG_A2_COUNT) */
{ NULL }
};
/* str:dump */
/* MSG_INTL(MSG_DESC_DUMP) */
/* MSG_INTL(MSG_HELP_DUMP) */
/* str:set */
/* MSG_INTL(MSG_DESC_SET) */
/* MSG_INTL(MSG_HELP_SET) */
/* str:add */
/* MSG_INTL(MSG_DESC_ADD) */
/* MSG_INTL(MSG_HELP_ADD) */
/* str:zero */
/* MSG_INTL(MSG_DESC_ZERO) */
/* MSG_INTL(MSG_HELP_ZERO) */
{ NULL }
};
/* MSG_INTL(MSG_MOD_DESC) */
return (&module);
}