#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <libintl.h>
#include <libelf.h>
#include <sys/machelf.h>
#include <link.h>
#include <strings.h>
#include <ctype.h>
#include <elfedit.h>
#include <_elfedit.h>
#include <sys/elf_SPARC.h>
#include <sys/elf_amd64.h>
#include <msg.h>
const char *
elfedit_atoi_value_to_str(const elfedit_atoi_sym_t *sym, elfedit_atoi_t value,
int required)
{
for (; sym->sym_name != NULL; sym++)
if (value == sym->sym_value)
return (sym->sym_name);
if (required)
elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADGETVAL));
return (NULL);
}
const char *
elfedit_atoui_value_to_str(const elfedit_atoui_sym_t *sym,
elfedit_atoui_t value, int required)
{
for (; sym->sym_name != NULL; sym++)
if (value == sym->sym_value)
return (sym->sym_name);
if (required)
elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADGETVAL));
return (NULL);
}
const char *
elfedit_atoconst_value_to_str(elfedit_const_t const_type, elfedit_atoui_t value,
int required)
{
return (elfedit_atoui_value_to_str(elfedit_const_to_atoui(const_type),
value, required));
}
static int
atoi_sym_process(const char *str, const elfedit_atoi_sym_t *sym,
elfedit_atoi_t *value)
{
size_t cmp_len;
const char *tail;
while (isspace(*str))
str++;
tail = str + strlen(str);
while ((tail > str) && isspace(*(tail - 1)))
tail--;
cmp_len = tail - str;
for (; sym->sym_name != NULL; sym++) {
if ((strlen(sym->sym_name) == cmp_len) &&
(strncasecmp(sym->sym_name, str, cmp_len) == 0)) {
*value = sym->sym_value;
return (1);
}
}
return (0);
}
static int
atoui_sym_process(const char *str, const elfedit_atoui_sym_t *sym,
elfedit_atoui_t *value)
{
size_t cmp_len;
const char *tail;
while (isspace(*str))
str++;
tail = str + strlen(str);
while ((tail > str) && isspace(*(tail - 1)))
tail--;
cmp_len = tail - str;
for (; sym->sym_name != NULL; sym++) {
if ((strlen(sym->sym_name) == cmp_len) &&
(strncasecmp(sym->sym_name, str, cmp_len) == 0)) {
*value = sym->sym_value;
return (1);
}
}
return (0);
}
void
elfedit_cpl_atoi(void *cpldata, const elfedit_atoi_sym_t *sym)
{
for (; sym->sym_name != NULL; sym++)
elfedit_cpl_match(cpldata, sym->sym_name, 1);
}
void
elfedit_cpl_atoui(void *cpldata, const elfedit_atoui_sym_t *sym)
{
for (; sym->sym_name != NULL; sym++)
elfedit_cpl_match(cpldata, sym->sym_name, 1);
}
void
elfedit_cpl_atoconst(void *cpldata, elfedit_const_t const_type)
{
elfedit_cpl_atoui(cpldata, elfedit_const_to_atoui(const_type));
}
int
elfedit_atoi2(const char *str, const elfedit_atoi_sym_t *sym, elfedit_atoi_t *v)
{
char *endptr;
if (sym && atoi_sym_process(str, sym, v))
return (1);
*v = strtoll(str, &endptr, 0);
for (; *endptr; endptr++)
if (!isspace(*endptr))
return (0);
return (1);
}
elfedit_atoi_t
elfedit_atoi(const char *str, const elfedit_atoi_sym_t *sym)
{
elfedit_atoi_t v;
if (elfedit_atoi2(str, sym, &v) == 0)
elfedit_msg(ELFEDIT_MSG_ERR,
MSG_INTL(MSG_ERR_BADATOISTR), str);
return (v);
}
int
elfedit_atoui2(const char *str, const elfedit_atoui_sym_t *sym,
elfedit_atoui_t *v)
{
char *endptr;
if (sym && atoui_sym_process(str, sym, v))
return (1);
*v = strtoull(str, &endptr, 0);
for (; *endptr; endptr++)
if (!isspace(*endptr))
return (0);
return (1);
}
elfedit_atoui_t
elfedit_atoui(const char *str, const elfedit_atoui_sym_t *sym)
{
elfedit_atoui_t v;
if (elfedit_atoui2(str, sym, &v) == 0)
elfedit_msg(ELFEDIT_MSG_ERR,
MSG_INTL(MSG_ERR_BADATOISTR), str);
return (v);
}
int
elfedit_atoconst2(const char *str, elfedit_const_t const_type,
elfedit_atoui_t *v)
{
return (elfedit_atoui2(str, elfedit_const_to_atoui(const_type), v));
}
elfedit_atoui_t
elfedit_atoconst(const char *str, elfedit_const_t const_type)
{
return (elfedit_atoui(str, elfedit_const_to_atoui(const_type)));
}
int
elfedit_atoi_range2(const char *str, elfedit_atoi_t min, elfedit_atoi_t max,
const elfedit_atoi_sym_t *sym, elfedit_atoi_t *v)
{
return ((elfedit_atoi2(str, sym, v) != 0) &&
(*v >= min) && (*v <= max));
}
elfedit_atoi_t
elfedit_atoi_range(const char *str, const char *item_name,
elfedit_atoi_t min, elfedit_atoi_t max, const elfedit_atoi_sym_t *sym)
{
elfedit_atoi_t v = elfedit_atoi(str, sym);
if ((v < min) || (v > max))
elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_ATOIRANGE),
item_name, EC_XWORD(min), EC_XWORD(max), EC_XWORD(v));
return (v);
}
int
elfedit_atoui_range2(const char *str, elfedit_atoui_t min, elfedit_atoui_t max,
const elfedit_atoui_sym_t *sym, elfedit_atoui_t *v)
{
return ((elfedit_atoui2(str, sym, v) != 0) &&
(*v >= min) && (*v <= max));
}
elfedit_atoui_t
elfedit_atoui_range(const char *str, const char *item_name,
elfedit_atoui_t min, elfedit_atoui_t max, const elfedit_atoui_sym_t *sym)
{
elfedit_atoui_t v = elfedit_atoui(str, sym);
if ((v < min) || (v > max))
elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_ATOUIRANGE),
item_name, EC_XWORD(min), EC_XWORD(max), EC_XWORD(v));
return (v);
}
int
elfedit_atoconst_range2(const char *str, elfedit_atoui_t min,
elfedit_atoui_t max, elfedit_const_t const_type, elfedit_atoui_t *v)
{
return (elfedit_atoui_range2(str, min, max,
elfedit_const_to_atoui(const_type), v));
}
elfedit_atoui_t
elfedit_atoconst_range(const char *str, const char *item_name,
elfedit_atoui_t min, elfedit_atoui_t max, elfedit_const_t const_type)
{
return (elfedit_atoui_range(str, item_name, min, max,
elfedit_const_to_atoui(const_type)));
}
int
elfedit_atobool(const char *str, const char *item_name)
{
return (elfedit_atoconst_range(str, item_name, 0, 1,
ELFEDIT_CONST_BOOL) != 0);
}
elfedit_atoui_t
elfedit_atoshndx(const char *str, size_t shnum)
{
elfedit_atoui_t ndx;
ndx = elfedit_atoconst(str, ELFEDIT_CONST_SHN);
if ((ndx >= shnum) && ((ndx < SHN_LORESERVE) || (ndx > SHN_HIRESERVE)))
elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_SHNDX_RANGE),
EC_WORD(ndx), EC_WORD(shnum-1));
return (ndx);
}
int
elfedit_atooutstyle(const char *str, elfedit_outstyle_t *outstyle)
{
int ret;
elfedit_atoui_t value;
ret = atoui_sym_process(str,
elfedit_const_to_atoui(ELFEDIT_CONST_OUTSTYLE), &value);
if (ret != 0)
*outstyle = value;
return (ret);
}
void
elfedit_getopt_init(elfedit_getopt_state_t *state,
int *argc, const char **argv[])
{
elfeditGC_cmd_t *cmd = elfedit_curcmd();
state->go_argc = argc;
state->go_argv = argv;
state->go_optarg = cmd->cmd_opt;
state->go_idmask = 0;
state->go_done = 0;
state->go_sglgrp = NULL;
}
elfedit_getopt_ret_t *
elfedit_getopt(elfedit_getopt_state_t *state)
{
elfedit_cmd_optarg_t *optarg;
const char *argstr;
int argc = *(state->go_argc);
const char **argv = *(state->go_argv);
elfedit_optarg_item_t item;
struct {
int valid;
int is_outstyle;
elfedit_getopt_ret_t ret;
elfedit_cmd_oa_mask_t excmask;
} sgl_with_value;
if (state->go_sglgrp == NULL) {
if ((state->go_optarg == NULL) || state->go_done ||
(argc <= 0) || (*(argv[0]) != '-')) {
state->go_done = 1;
return (NULL);
}
argstr = argv[0];
if (argstr[1] == '\0')
elfedit_command_usage();
if ((argstr[1] == '-') && (argstr[2] == '\0')) {
(*state->go_argc)--;
(*state->go_argv)++;
return (NULL);
}
sgl_with_value.valid = 0;
for (optarg = state->go_optarg; optarg->oa_name != NULL; ) {
int is_outstyle =
(optarg->oa_flags & ELFEDIT_CMDOA_F_INHERIT) &&
(optarg->oa_name == ELFEDIT_STDOA_OPT_O);
int need_value;
elfedit_next_optarg(&optarg, &item);
need_value = item.oai_flags & ELFEDIT_CMDOA_F_VALUE;
if ((item.oai_name[2] == '\0') && need_value &&
(argstr[1] == item.oai_name[1]) &&
(argstr[2] != '\0')) {
sgl_with_value.valid = 1;
sgl_with_value.ret.gor_idmask = item.oai_idmask;
sgl_with_value.excmask = item.oai_excmask;
sgl_with_value.ret.gor_value = argstr + 2;
sgl_with_value.is_outstyle = is_outstyle;
continue;
}
if (strcmp(argstr, item.oai_name) == 0) {
(*state->go_argc) = --argc;
(*state->go_argv) = ++argv;
if (item.oai_excmask & state->go_idmask)
elfedit_command_usage();
state->go_idmask |= item.oai_idmask;
state->go_ret.gor_idmask = item.oai_idmask;
if (need_value) {
if (argc <= 0)
elfedit_command_usage();
state->go_ret.gor_value = argv[0];
(*state->go_argc)--;
(*state->go_argv)++;
} else {
state->go_ret.gor_value = NULL;
}
if (is_outstyle)
elfedit_set_cmd_outstyle(
state->go_ret.gor_value);
return (&state->go_ret);
}
}
if (sgl_with_value.valid) {
(*state->go_argc)--;
(*state->go_argv)++;
if (sgl_with_value.excmask & state->go_idmask)
elfedit_command_usage();
state->go_idmask |= sgl_with_value.ret.gor_idmask;
state->go_ret = sgl_with_value.ret;
if (sgl_with_value.is_outstyle)
elfedit_set_cmd_outstyle(
state->go_ret.gor_value);
return (&state->go_ret);
}
state->go_sglgrp = argstr + 1;
}
if (state->go_sglgrp != NULL) {
int ch = *state->go_sglgrp++;
if (*state->go_sglgrp == '\0') {
(*state->go_argc)--;
(*state->go_argv)++;
state->go_sglgrp = NULL;
}
for (optarg = state->go_optarg; optarg->oa_name != NULL; ) {
elfedit_next_optarg(&optarg, &item);
if ((item.oai_name[2] == '\0') &&
(ch == item.oai_name[1])) {
if (item.oai_flags & ELFEDIT_CMDOA_F_VALUE)
elfedit_command_usage();
if (item.oai_excmask & state->go_idmask)
elfedit_command_usage();
state->go_idmask |= item.oai_idmask;
state->go_ret.gor_idmask = item.oai_idmask;
state->go_ret.gor_value = NULL;
return (&state->go_ret);
}
}
}
elfedit_command_usage();
return (NULL);
}
int
elfedit_bits_set(u_longlong_t v, int sizeof_orig_v)
{
int nbits = sizeof_orig_v * 8;
int mask;
int cnt = 0;
for (mask = 1; (nbits-- > 0) && (cnt < 2); mask *= 2)
if (v & mask)
cnt++;
return (cnt);
}
void
elfedit_array_elts_delete(const char *name_str, void *data_start,
size_t entsize, size_t num_ent, size_t start_ndx, size_t cnt)
{
char *data = data_start;
if ((start_ndx + cnt) > num_ent)
elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_ARRBNDS),
name_str, EC_WORD(num_ent), EC_WORD(num_ent - 1));
if (start_ndx < (num_ent - 1)) {
size_t ncpy = num_ent - (start_ndx + cnt);
bcopy(data + ((start_ndx + cnt) * entsize),
data + (start_ndx * entsize), ncpy * entsize);
if (ncpy == 1) {
elfedit_msg(ELFEDIT_MSG_DEBUG,
MSG_INTL(MSG_DEBUG_ARRCPY_1), name_str,
EC_WORD(start_ndx + cnt), EC_WORD(start_ndx));
} else {
elfedit_msg(ELFEDIT_MSG_DEBUG,
MSG_INTL(MSG_DEBUG_ARRCPY_N), name_str,
EC_WORD(start_ndx + cnt),
EC_WORD(start_ndx + cnt + ncpy - 1),
EC_WORD(start_ndx),
EC_WORD(start_ndx + ncpy - 1));
}
}
bzero(data + ((num_ent - cnt) * entsize), entsize * cnt);
if (cnt == 1) {
elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_ARRZERO_1),
name_str, EC_WORD(num_ent - 1));
} else {
elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_ARRZERO_N),
name_str, EC_WORD(num_ent - cnt),
EC_WORD(num_ent - 1), EC_WORD(cnt));
}
}
void
elfedit_array_elts_move(const char *name_str, void *data_start,
size_t entsize, size_t num_ent, size_t srcndx,
size_t dstndx, size_t cnt, void *scr_item)
{
char *data = data_start;
if (((srcndx + cnt) > num_ent) || ((dstndx + cnt) > num_ent))
elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_ARRBNDS),
name_str, EC_WORD(num_ent), EC_WORD(num_ent - 1));
if (srcndx == dstndx)
return;
if (cnt > 1) {
size_t low, hi;
if (srcndx > dstndx) {
low = dstndx;
hi = srcndx;
} else {
low = srcndx;
hi = dstndx;
}
if ((low + cnt) > hi)
elfedit_msg(ELFEDIT_MSG_ERR,
MSG_INTL(MSG_ERR_ARRMVOVERLAP), name_str,
EC_WORD(srcndx), EC_WORD(srcndx + cnt - 1),
EC_WORD(dstndx), EC_WORD(dstndx + cnt - 1));
}
if (cnt == 1)
elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_ARRMOVE_1),
name_str, EC_WORD(srcndx), EC_WORD(dstndx));
else
elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_ARRMOVE_N),
name_str, EC_WORD(cnt),
EC_WORD(srcndx), EC_WORD(srcndx + cnt - 1),
EC_WORD(dstndx), EC_WORD(dstndx + cnt - 1));
if (srcndx < dstndx) {
srcndx += cnt - 1;
dstndx += cnt - 1;
for (; cnt-- > 0; srcndx--, dstndx--) {
bcopy(data + (srcndx * entsize), scr_item, entsize);
bcopy(data + ((srcndx + 1) * entsize),
data + (srcndx * entsize),
(dstndx - srcndx) * entsize);
bcopy(scr_item, data + (dstndx * entsize), entsize);
}
} else {
for (; cnt-- > 0; srcndx++, dstndx++) {
bcopy(data + (srcndx * entsize), scr_item, entsize);
bcopy(data + (dstndx * entsize),
data + ((dstndx + 1) * entsize),
(srcndx - dstndx) * entsize);
bcopy(scr_item, data + (dstndx * entsize), entsize);
}
}
}