diff options
author | ab196087 <none@none> | 2007-09-19 08:15:57 -0700 |
---|---|---|
committer | ab196087 <none@none> | 2007-09-19 08:15:57 -0700 |
commit | d29b2c4438482eb00488be49a1f5d6835f455546 (patch) | |
tree | 541f5471fe500cce2429019f17f9f87ddcf80b76 | |
parent | 90685d2c52744c6540828f16cdd2db815d467e37 (diff) | |
download | illumos-joyent-d29b2c4438482eb00488be49a1f5d6835f455546.tar.gz |
PSARC 2007/509 elfedit
6234471 need a way to edit ELF objects
--HG--
rename : usr/src/cmd/sgs/packages/setup_pkg_ext => deleted_files/usr/src/cmd/sgs/packages/setup_pkg_ext
101 files changed, 27156 insertions, 321 deletions
diff --git a/usr/src/cmd/sgs/packages/setup_pkg_ext b/deleted_files/usr/src/cmd/sgs/packages/setup_pkg_ext index 59cab814e1..59cab814e1 100644 --- a/usr/src/cmd/sgs/packages/setup_pkg_ext +++ b/deleted_files/usr/src/cmd/sgs/packages/setup_pkg_ext diff --git a/usr/src/Targetdirs b/usr/src/Targetdirs index 5bdcc521ce..b7d74fa7f7 100644 --- a/usr/src/Targetdirs +++ b/usr/src/Targetdirs @@ -255,6 +255,7 @@ ROOT.BIN= \ /usr/lib/class/TS \ /usr/lib/crypto \ /usr/lib/drv \ + /usr/lib/elfedit \ /usr/lib/font \ /usr/lib/fp \ /usr/lib/fp/libp \ @@ -340,6 +341,7 @@ ROOT.BIN64= \ /usr/ccs/lib/$(MACH64) \ /usr/lib/$(MACH64) \ /usr/lib/$(MACH64)/gss \ + /usr/lib/elfedit/$(MACH64) \ /usr/lib/fm/$(MACH64) \ /usr/lib/fp/libp/$(MACH64) \ /usr/lib/krb5/$(MACH64) \ @@ -464,6 +466,7 @@ SYM.ROOT.BIN= \ /usr/preserve \ /usr/src \ /usr/lib/32 \ + /usr/lib/elfedit/32 \ /usr/lib/libp/32 \ /usr/lib/lwp/32 \ /usr/lib/link_audit/32 \ @@ -482,6 +485,7 @@ SYM.ROOT.BIN64= \ /lib/64 \ /lib/secure/64 \ /usr/lib/64 \ + /usr/lib/elfedit/64 \ /usr/lib/libp/64 \ /usr/lib/link_audit/64 \ /usr/lib/lwp/64 \ @@ -618,6 +622,7 @@ $(ROOT)/usr/spool:= LINKDEST=../var/spool $(ROOT)/usr/tmp:= LINKDEST=../var/tmp $(ROOT)/usr/lib/tmac:= LINKDEST=../share/lib/tmac $(ROOT)/usr/lib/32:= LINKDEST=. +$(ROOT)/usr/lib/elfedit/32:= LINKDEST=. $(ROOT)/usr/lib/libp/32:= LINKDEST=. $(ROOT)/usr/lib/lwp/32:= LINKDEST=. $(ROOT)/usr/lib/link_audit/32:= LINKDEST=. @@ -631,6 +636,7 @@ $(ROOT)/usr/ucblib/32:= LINKDEST=. $(BUILD64) $(ROOT)/lib/64:= LINKDEST=$(MACH64) $(BUILD64) $(ROOT)/lib/secure/64:= LINKDEST=$(MACH64) $(BUILD64) $(ROOT)/usr/lib/64:= LINKDEST=$(MACH64) +$(BUILD64) $(ROOT)/usr/lib/elfedit/64:= LINKDEST=$(MACH64) $(BUILD64) $(ROOT)/usr/lib/brand/lx/64:= LINKDEST=$(MACH64) $(BUILD64) $(ROOT)/usr/lib/libp/64:= LINKDEST=$(MACH64) $(BUILD64) $(ROOT)/usr/lib/lwp/64:= LINKDEST=$(MACH64) diff --git a/usr/src/cmd/sgs/Makefile b/usr/src/cmd/sgs/Makefile index c01267893d..5b6fd5d9fc 100644 --- a/usr/src/cmd/sgs/Makefile +++ b/usr/src/cmd/sgs/Makefile @@ -54,6 +54,7 @@ SUBDIRS-common= libconv \ ar \ dump \ elfdump \ + elfedit \ error \ gprof \ lari \ @@ -86,7 +87,8 @@ POFILES= $(POSUBDIRS:%=%/%.po) MSGSUBDIRS= ld ldd libld liblddbg \ libldstab librtld rtld libelf \ ldprof libcrle pvs elfdump \ - crle moe lari librtld_db + elfedit crle moe lari \ + librtld_db MSGDIR= messages diff --git a/usr/src/cmd/sgs/Makefile.com b/usr/src/cmd/sgs/Makefile.com index 07d05b93b4..4807a53dd1 100644 --- a/usr/src/cmd/sgs/Makefile.com +++ b/usr/src/cmd/sgs/Makefile.com @@ -101,8 +101,9 @@ DTEXTDOM = # Define any generic sgsmsg(1l) flags. The default message generation system # is to use gettext(3i), add the -C flag to switch to catgets(3c). -SGSMSG = $(SGSTOOLS)/$(MACH)/sgsmsg -CHKMSG = $(SGSTOOLS)/chkmsg.sh +SGSMSG = $(SGSTOOLS)/$(MACH)/sgsmsg +SGSMSG_PIGLATIN_NL = perl $(SGSTOOLS)/common/sgsmsg_piglatin_nl.pl +CHKMSG = $(SGSTOOLS)/chkmsg.sh SGSMSGVFLAG = SGSMSGFLAGS = $(SGSMSGVFLAG) -i $(SGSMSGID)/sgs.ident diff --git a/usr/src/cmd/sgs/Makefile.var b/usr/src/cmd/sgs/Makefile.var index f029382ea3..8d710d4eda 100644 --- a/usr/src/cmd/sgs/Makefile.var +++ b/usr/src/cmd/sgs/Makefile.var @@ -190,6 +190,12 @@ VAR_ELFDUMP_LLDFLAGS= '-R$$ORIGIN/../../lib' VAR_ELFDUMP_LLDFLAGS64 ='-R$$ORIGIN/../../../lib/$(MACH64)' # +# elfedit +# +VAR_ELFEDIT_LLDFLAGS= '-R$$ORIGIN/../../lib' +VAR_ELFEDIT_LLDFLAGS64 ='-R$$ORIGIN/../../../lib/$(MACH64)' + +# # lddstub # VAR_LDDSTUB_INTERP= -I'$$ORIGIN/ld.so.1' diff --git a/usr/src/cmd/sgs/crle/common/print.c b/usr/src/cmd/sgs/crle/common/print.c index 263d272ec4..7ebe3ff04c 100644 --- a/usr/src/cmd/sgs/crle/common/print.c +++ b/usr/src/cmd/sgs/crle/common/print.c @@ -286,12 +286,13 @@ scanconfig(Crle_desc * crle, Addr addr, int c_class) if ((id->id_data != M_DATA) || (id->id_machine != M_MACH)) { (void) fprintf(stderr, MSG_INTL(MSG_ARG_WRONGARCH), crle->c_name, crle->c_confil, - conv_ehdr_data(id->id_data, CONV_FMT_ALTFILE, + conv_ehdr_data(id->id_data, CONV_FMT_ALT_FILE, &inv_buf1), - conv_ehdr_mach(id->id_machine, CONV_FMT_ALTFILE, + conv_ehdr_mach(id->id_machine, CONV_FMT_ALT_FILE, &inv_buf2), - conv_ehdr_data(M_DATA, CONV_FMT_ALTFILE, &inv_buf3), - conv_ehdr_mach(M_MACH, CONV_FMT_ALTFILE, + conv_ehdr_data(M_DATA, CONV_FMT_ALT_FILE, + &inv_buf3), + conv_ehdr_mach(M_MACH, CONV_FMT_ALT_FILE, &inv_buf4)); return (INSCFG_RET_FAIL); } @@ -366,11 +367,11 @@ scanconfig(Crle_desc * crle, Addr addr, int c_class) */ if (id) (void) printf(MSG_INTL(MSG_DMP_PLATFORM), - conv_ehdr_class(id->id_class, CONV_FMT_ALTFILE, + conv_ehdr_class(id->id_class, CONV_FMT_ALT_FILE, &inv_buf1), - conv_ehdr_data(id->id_data, CONV_FMT_ALTFILE, + conv_ehdr_data(id->id_data, CONV_FMT_ALT_FILE, &inv_buf2), - conv_ehdr_mach(id->id_machine, CONV_FMT_ALTFILE, + conv_ehdr_mach(id->id_machine, CONV_FMT_ALT_FILE, &inv_buf3)); /* @@ -388,7 +389,7 @@ scanconfig(Crle_desc * crle, Addr addr, int c_class) if (head->ch_dlflags && (head->ch_dlflags != RTLD_REL_RELATIVE)) { (void) snprintf(_cmd, PATH_MAX, MSG_ORIG(MSG_CMD_FLAGS), - conv_dl_flag(head->ch_dlflags, CONV_FMT_ALTCRLE, + conv_dl_flag(head->ch_dlflags, CONV_FMT_ALT_CRLE, &dl_flag_buf)); cmd = strcpy(alloca(strlen(_cmd) + 1), _cmd); if (list_append(&cmdline, cmd) == 0) @@ -1052,11 +1053,11 @@ inspectconfig(Crle_desc * crle, int c_class) (void) printf(MSG_INTL(MSG_DEF_NOCONF), file); (void) printf(MSG_INTL(MSG_DMP_PLATFORM), conv_ehdr_class(M_CLASS, - CONV_FMT_ALTFILE, &inv_buf1), + CONV_FMT_ALT_FILE, &inv_buf1), conv_ehdr_data(M_DATA, - CONV_FMT_ALTFILE, &inv_buf2), + CONV_FMT_ALT_FILE, &inv_buf2), conv_ehdr_mach(M_MACH, - CONV_FMT_ALTFILE, &inv_buf3)); + CONV_FMT_ALT_FILE, &inv_buf3)); if (crle->c_flags & CRLE_AOUT) { diff --git a/usr/src/cmd/sgs/dump/common/dump.c b/usr/src/cmd/sgs/dump/common/dump.c index 43782456bb..9d995f6f4b 100644 --- a/usr/src/cmd/sgs/dump/common/dump.c +++ b/usr/src/cmd/sgs/dump/common/dump.c @@ -56,7 +56,7 @@ * - Unknown items to be printed as integers using decimal formatting * - The "Dump Style" versions of strings. */ -#define DUMP_CONVFMT (CONV_FMT_DECIMAL|CONV_FMT_ALTDUMP) +#define DUMP_CONVFMT (CONV_FMT_DECIMAL|CONV_FMT_ALT_DUMP) const char *UNKNOWN = "<unknown>"; @@ -1261,7 +1261,7 @@ dump_dynamic(Elf *elf_file, SCNTAB *p_scns, int num_scns, char *filename) break; case DT_FLAGS_1: str = conv_dyn_flag1( - p_dyn.d_un.d_val, + p_dyn.d_un.d_val, 0, &conv_buf.dyn_flag1); break; } diff --git a/usr/src/cmd/sgs/elfdump/common/elfdump.c b/usr/src/cmd/sgs/elfdump/common/elfdump.c index 1b41c6076f..a3354be467 100644 --- a/usr/src/cmd/sgs/elfdump/common/elfdump.c +++ b/usr/src/cmd/sgs/elfdump/common/elfdump.c @@ -2054,7 +2054,7 @@ dynamic(Cache *cache, Word shnum, Ehdr *ehdr, const char *file) 0, &c_buf.flag); break; case DT_FLAGS_1: - name = conv_dyn_flag1(dyn->d_un.d_val, + name = conv_dyn_flag1(dyn->d_un.d_val, 0, &c_buf.flag1); break; case DT_POSFLAG_1: @@ -3244,7 +3244,7 @@ regular(const char *file, int fd, Elf *elf, uint_t flags, int wfd) for (ndx = 0; ndx < phnum; phdr++, ndx++) { if (!match(0, conv_phdr_type(ehdr->e_machine, - phdr->p_type, CONV_FMT_ALTFILE, &inv_buf), ndx)) + phdr->p_type, CONV_FMT_ALT_FILE, &inv_buf), ndx)) continue; dbg_print(0, MSG_ORIG(MSG_STR_EMPTY)); diff --git a/usr/src/cmd/sgs/elfedit/Makefile b/usr/src/cmd/sgs/elfedit/Makefile new file mode 100644 index 0000000000..bf8288ad62 --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/Makefile @@ -0,0 +1,30 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# + +EXTRASUBDIRS= modules +include $(SRC)/cmd/sgs/Makefile.sub diff --git a/usr/src/cmd/sgs/elfedit/Makefile.com b/usr/src/cmd/sgs/elfedit/Makefile.com new file mode 100644 index 0000000000..2f38b6a1c5 --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/Makefile.com @@ -0,0 +1,74 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# + +PROG= elfedit + +include $(SRC)/cmd/Makefile.cmd +include $(SRC)/cmd/sgs/Makefile.com + +COMOBJ = elfedit.o sys.o util.o elfconst.o + +COMOBJ32 = elfedit_machelf32.o util_machelf32.o + +COMOBJ64 = elfedit_machelf64.o util_machelf64.o + +BLTOBJ = msg.o + +OBJS= $(BLTOBJ) $(COMOBJ) $(COMOBJ32) $(COMOBJ64) + +MAPFILE= ../common/mapfile-vers + +CPPFLAGS= -I. -I../common -I../../include -I../../include/$(MACH) \ + -I$(SRCBASE)/lib/libc/inc -I$(SRCBASE)/uts/$(ARCH)/sys \ + $(CPPFLAGS.master) +LLDFLAGS = $(VAR_ELFEDIT_LLDFLAGS) +LLDFLAGS64 = $(VAR_ELFEDIT_LLDFLAGS64) +LDFLAGS += $(VERSREF) $(USE_PROTO) -M$(MAPFILE) $(LLDFLAGS) $(ZLAZYLOAD) +LDLIBS += $(ELFLIBDIR) -lelf $(LDDBGLIBDIR) $(LDDBG_LIB) \ + $(CONVLIBDIR) $(CONV_LIB) -ltecla + +LINTFLAGS += -x +LINTFLAGS64 += -x + +BLTDEFS = msg.h +BLTDATA = msg.c +BLTMESG = $(SGSMSGDIR)/elfedit + +BLTFILES = $(BLTDEFS) $(BLTDATA) $(BLTMESG) + +SGSMSGCOM = ../common/elfedit.msg +SGSMSGTARG = $(SGSMSGCOM) +SGSMSGALL = $(SGSMSGCOM) +SGSMSGFLAGS += -h $(BLTDEFS) -d $(BLTDATA) -m $(BLTMESG) -n elfedit_msg + +SRCS = $(COMOBJ:%.o=../common/%.c) \ + $(COMOBJ32:%32.o=../common/%.c) \ + $(BLTDATA) +LINTSRCS = $(SRCS) ../common/lintsup.c + +CLEANFILES += $(LINTOUTS) $(BLTFILES) diff --git a/usr/src/cmd/sgs/elfedit/Makefile.targ b/usr/src/cmd/sgs/elfedit/Makefile.targ new file mode 100644 index 0000000000..0075260be2 --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/Makefile.targ @@ -0,0 +1,77 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# + +%.o: ../common/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +%32.o: ../common/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +%64.o: ../common/%.c + $(COMPILE.c) -D_ELF64 -o $@ $< + $(POST_PROCESS_O) + +%.o: $(SGSTOOLS)/common/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + +$(PROG): $(OBJS) $(MAPFILE) + $(LINK.c) -o $@ $(OBJS) $(LDLIBS) + $(POST_PROCESS) + +$(ROOTBIN64)/%: % + $(INS.file) + +all: $(PROG) + +clean: + $(RM) $(OBJS) $(CLEANFILES) + +delete: + $(RM) $(PROG) + +install \ +package: all $(ROOTPROG) + +include $(SRC)/cmd/Makefile.targ +include $(SRC)/cmd/sgs/Makefile.targ + +# Derived source and header files (messaging). + +catalog: $(BLTMESG) + @ cd ../modules; pwd; $(MAKE) catalog + +chkmsg: $(SRCS) + sh $(CHKMSG) $(CHKMSGFLAGS) $(SRCS) + +$(BLTDEFS) + \ +$(BLTDATA) + \ +$(BLTMESG): $(SGSMSGALL) + $(SGSMSG) $(SGSMSGFLAGS) $(SGSMSGALL) diff --git a/usr/src/cmd/sgs/elfedit/amd64/Makefile b/usr/src/cmd/sgs/elfedit/amd64/Makefile new file mode 100644 index 0000000000..75487b577b --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/amd64/Makefile @@ -0,0 +1,46 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +.KEEP_STATE: + +LLDFLAGS = $(LLDFLAGS64) +ELFLIBDIR = $(ELFLIBDIR64) +LDDBGLIBDIR = $(LDDBGLIBDIR64) +CONVLIBDIR = $(CONVLIBDIR64) + +ROOTPROG= $(ROOTPROG64) + +include ../Makefile.targ +include ../../Makefile.sub.64 + +lint: $(LINTOUT64) $(SGSLINTOUT) + +install \ +package: $(ROOTPROG64) diff --git a/usr/src/cmd/sgs/elfedit/common/_elfedit.h b/usr/src/cmd/sgs/elfedit/common/_elfedit.h new file mode 100644 index 0000000000..7de673f9d2 --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/common/_elfedit.h @@ -0,0 +1,263 @@ +/* + * 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. + */ + +#ifndef __ELFEDIT_H +#define __ELFEDIT_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <setjmp.h> +#include <libtecla.h> +#include <elfedit.h> + +/* + * Local include file for elfedit. + */ +#ifdef __cplusplus +extern "C" { +#endif + + +/* + * Maximum command line, and history + */ +#define ELFEDIT_MAXCMD 1024 +#define ELFEDIT_MAXHIST 1024 + +/* Maximum number of command completion arguments */ +#define ELFEDIT_MAXCPLARGS 128 + +/* Maximum length of a module name */ +#define ELFEDIT_MAXMODNAM 64 + + +/* + * In elfedit.h, you will find elfedit32_cmd_t and elfedit64_cmd_t + * typedefs. These types are identical, except for the definition + * of the cmd_func and cmd_cplfunc function pointers. These function + * pointers have different argument definitions that reflect the + * different object state definition blocks for the 32 and 64-bit cases. + * Yet, From a strictly machine based view, these two types are identical + * in size and layout: + * + * - At the machine level, all function pointers are simply + * machine sized words containing an address. + * + * - Other than the function pointers, the remaining fields + * are exactly the same in both cases. + * + * The vast majority of elfedit's internals that examine elfedit_cmd_t + * are looking at the non-function pointer fields. It simplfiies + * a great deal of code if we can treat elfedit32_cmd_t and elfedit64_cmd_t + * as equivalent types for this purpose. In C++, we would do this with + * a superclass. In C, we do it by defining another variant named + * elfeditGC_cmd_t (GC stands for "Generic Class"). The function pointers + * are replaced with (void *) pointers. This variant has the same size + * and layout as the others. We use it internally to represent either type. + * In the cases where we need to use the function pointers, we first cast + * them to the proper type for the ELFCLASS being processed. + * + * The existance of elfeditGC_cmd_t implies the need for elfeditGC_module_t, + * for the same reasons. + * + * It is extremely important that these definitions exactly mirror the + * definitions in elfedit.h. + */ +typedef struct { + void *cmd_func; + void *cmd_cplfunc; + const char **cmd_name; + elfedit_i18nhdl_t cmd_desc; + elfedit_i18nhdl_t cmd_help; + elfedit_cmd_optarg_t *cmd_opt; + elfedit_cmd_optarg_t *cmd_args; +} elfeditGC_cmd_t; + + +typedef struct { + elfedit_module_version_t mod_version; + const char *mod_name; + elfedit_i18nhdl_t mod_desc; + elfeditGC_cmd_t *mod_cmds; + elfedit_mod_i18nhdl_to_str_func_t mod_i18nhdl_to_str; +} elfeditGC_module_t; + + +/* + * The result of parsing a user command is one of these blocks entered + * at the end of state.user_cmd. They encapsulate the arguments and + * the command function to call. In combination with an elfedit_obj_state_t, + * they contain everything needed to execute a specified operation. A single + * call to free() suffices to release the ELFEDIT_USER_CMD and any memory + * it references. + */ +typedef struct user_cmd_t { + struct user_cmd_t *ucmd_next; /* Commands are kept in linked list */ + int ucmd_argc; /* # of arguments to command */ + const char **ucmd_argv; /* Argument strings */ + char *ucmd_orig_str; /* Command string as entered by user */ + elfeditGC_module_t *ucmd_mod; /* Module defining command */ + elfeditGC_cmd_t *ucmd_cmd; /* Command to call */ + int ucmd_ostyle_set; /* True if there is a per-cmd */ + /* output style active */ + elfedit_outstyle_t ucmd_ostyle; /* Per-cmd output style, if active */ +} USER_CMD_T; + +/* + * MODLIST_T is used to manage module definitions. Note that a simple linked + * list is used to maintain the set of active modules. This can be easily + * changed if the number of modules grows to a point where the lookup + * time is noticible. + */ +typedef struct moddef_t { + struct moddef_t *ml_next; /* Used for list of open mods */ + elfeditGC_module_t *ml_mod; /* The module definition */ + void *ml_dl_hdl; /* dlopen() handle for lib */ + const char *ml_path; /* Path used to open lib */ +} MODLIST_T; + + +/* + * Type of the global variable used to maintain elfedit state. + */ +typedef struct { + MODLIST_T *modlist; /* List of loaded commands */ + elfedit_flag_t flags; /* ELFEDIT_F_ command line options */ + elfedit_outstyle_t outstyle; /* Output style */ + struct { + int present; /* True if there is a source file. */ + /* False otherwise */ + /* + * The remaining file fields are not to be accessed + * unless present is True. + */ + const char *infile; /* Name of source file */ + const char *outfile; /* Name of file being edited */ + int unlink_on_exit; /* TRUE to unlink outfile on exit */ + int dirty; /* TRUE if outfile needs to be saved */ + } file; + struct { /* Jump buffer used for ELFEDIT_MSG_ERR */ + int active; /* True if MSG_ERR jumps to outer loop */ + sigjmp_buf env; /* jump environment buffer */ + } msg_jbuf; + struct { /* Search path used to find modules */ + size_t n; /* # of path segments */ + const char **seg; /* path segments */ + } modpath; + struct { /* Linked list of user commands to execute */ + size_t n; /* # of commands */ + USER_CMD_T *list; /* head of list */ + USER_CMD_T *tail; /* points at last element of list */ + } ucmd; + struct { /* Pager related state */ + FILE *fptr; /* Output file */ + } pager; + struct { + int is_tty; /* True in stdin is a tty */ + int full_tty; /* True if stdin and stdout are tty */ + int in_tecla; /* gl_get_line() is active */ + GetLine *gl; /* getline object */ + } input; + struct { /* ELF file state */ + int elfclass; /* ELFCLASS of file being edited */ + /* + * Information for the ELF object being edited. + * The value of elfclass determines which of these + * fields is valid in the current session. This is + * only usable if file.present is True. Otherwise, there + * is no object state, and these pointers will be NULL. + */ + union { + elfedit32_obj_state_t *s32; /* ELFCLASS32 */ + elfedit64_obj_state_t *s64; /* ELFCLASS64 */ + } obj_state; + } elf; + USER_CMD_T *cur_cmd; /* NULL, or currently executing command */ +} STATE_T; + + + +/* + * Type of item argument to elfedit_next_optarg(), used to pull together + * the information for a single command option or argument, handling + * the ELFEDIT_CMDOA_F_VALUE and ELFEDIT_CMDOA_F_INHERIT cases. + */ +typedef struct { + const char *oai_name; /* Name of option */ + const char *oai_vname; /* Name of value field if */ + /* ELFEDIT_CMDOA_F_VALUE */ + elfedit_i18nhdl_t oai_help; /* Help text for option */ + elfedit_cmd_oa_flag_t oai_flags; /* Additional attributes */ + elfedit_cmd_oa_mask_t oai_idmask; /* Returned by elfedit_getopt */ + elfedit_cmd_oa_mask_t oai_excmask; /* mutual exclusion mask */ +} elfedit_optarg_item_t; + + + +/* Global state is accessible between elfedit files */ +extern STATE_T state; + +/* Exported by sys.c, used in elfedit.c to initialize builtin sys module */ +extern MODLIST_T *elfedit_sys_init(elfedit_module_version_t version); + +/* Exported by util.c, used by elfedit.c and sys.c to process output style */ +extern int elfedit_atooutstyle(const char *str, elfedit_outstyle_t *outstyle); + +/* + * getopt related routines that are not public + */ +extern void elfedit_set_cmd_outstyle(const char *str); + +/* elfedit internal functions used by sys module */ +extern void elfedit_exit(int status); +extern elfeditGC_cmd_t *elfedit_find_command(const char *name, int must_exist, + elfeditGC_module_t **mod_ret); +extern const char *elfedit_format_command_usage(elfeditGC_module_t *mod, + elfeditGC_cmd_t *cmd, const char *wrap_str, size_t cur_col); +extern elfeditGC_module_t *elfedit_load_module(const char *name, int must_exist, + int allow_abs_path); +extern void elfedit_load_moddir(const char *dirpath, int must_exist, + int abs_path); +extern void elfedit_load_modpath(void); +extern void elfedit_unload_module(const char *name); +extern void elfedit_next_optarg(elfedit_cmd_optarg_t **optarg, + elfedit_optarg_item_t *item); +extern const char *elfedit_optarg_helpstr(elfeditGC_module_t *mod, + elfedit_optarg_item_t *item); + + +/* Used by elfedit_getopt_init() to access options array for command */ +elfeditGC_cmd_t *elfedit_curcmd(void); + +/* elfedit_machelf functions used by elfedit */ +extern void elfedit32_init_obj_state(const char *file, int fd, Elf *elf); +extern void elfedit64_init_obj_state(const char *file, int fd, Elf *elf); + +#ifdef __cplusplus +} +#endif + +#endif /* __ELFEDIT_H */ diff --git a/usr/src/cmd/sgs/elfedit/common/elfconst.c b/usr/src/cmd/sgs/elfedit/common/elfconst.c new file mode 100644 index 0000000000..88d8fade37 --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/common/elfconst.c @@ -0,0 +1,1542 @@ +/* + * 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 <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 <sys/auxv_386.h> +#include <sys/auxv_SPARC.h> +#include <msg.h> + + + +/* + * This file contains support for mapping well known ELF constants + * to their numeric values. It is a layer on top of the elfedit_atoui() + * routines defined in util.c. The idea is that centralizing all the + * support for such constants will improve consistency between modules, + * allow for sharing of commonly needed items, and make the modules + * simpler. + */ + + + + +/* + * elfedit output style, with and without leading -o + */ +static elfedit_atoui_sym_t sym_outstyle[] = { + { MSG_ORIG(MSG_STR_DEFAULT), ELFEDIT_OUTSTYLE_DEFAULT }, + { MSG_ORIG(MSG_STR_SIMPLE), ELFEDIT_OUTSTYLE_SIMPLE }, + { MSG_ORIG(MSG_STR_NUM), ELFEDIT_OUTSTYLE_NUM }, + { NULL } +}; +static elfedit_atoui_sym_t sym_minus_o_outstyle[] = { + { MSG_ORIG(MSG_STR_MINUS_O_DEFAULT), ELFEDIT_OUTSTYLE_DEFAULT }, + { MSG_ORIG(MSG_STR_MINUS_O_SIMPLE), ELFEDIT_OUTSTYLE_SIMPLE }, + { MSG_ORIG(MSG_STR_MINUS_O_NUM), ELFEDIT_OUTSTYLE_NUM }, + { NULL } +}; + + +/* + * Booleans + */ +static elfedit_atoui_sym_t sym_bool[] = { + { MSG_ORIG(MSG_STR_T), 1 }, + { MSG_ORIG(MSG_STR_F), 0 }, + { MSG_ORIG(MSG_STR_TRUE), 1 }, + { MSG_ORIG(MSG_STR_FALSE), 0 }, + { MSG_ORIG(MSG_STR_ON), 1 }, + { MSG_ORIG(MSG_STR_OFF), 0 }, + { MSG_ORIG(MSG_STR_YES), 1 }, + { MSG_ORIG(MSG_STR_NO), 0 }, + { MSG_ORIG(MSG_STR_Y), 1 }, + { MSG_ORIG(MSG_STR_N), 0 }, + { NULL } +}; + +/* + * ELF section indexes with support for the special index names. + */ +static elfedit_atoui_sym_t sym_shn[] = { + { MSG_ORIG(MSG_SHN_UNDEF), SHN_UNDEF }, + { MSG_ORIG(MSG_SHN_UNDEF_ALT1), SHN_UNDEF }, + + { MSG_ORIG(MSG_SHN_SUNW_IGNORE), SHN_SUNW_IGNORE }, + { MSG_ORIG(MSG_SHN_SUNW_IGNORE_ALT1), SHN_SUNW_IGNORE }, + + { MSG_ORIG(MSG_SHN_BEFORE), SHN_BEFORE }, + { MSG_ORIG(MSG_SHN_BEFORE_ALT1), SHN_BEFORE }, + + { MSG_ORIG(MSG_SHN_AFTER), SHN_AFTER }, + { MSG_ORIG(MSG_SHN_AFTER_ALT1), SHN_AFTER }, + + { MSG_ORIG(MSG_SHN_AMD64_LCOMMON), SHN_AMD64_LCOMMON }, + { MSG_ORIG(MSG_SHN_AMD64_LCOMMON_ALT1), SHN_AMD64_LCOMMON }, + + { MSG_ORIG(MSG_SHN_ABS), SHN_ABS }, + { MSG_ORIG(MSG_SHN_ABS_ALT1), SHN_ABS }, + + { MSG_ORIG(MSG_SHN_COMMON), SHN_COMMON }, + { MSG_ORIG(MSG_SHN_COMMON_ALT1), SHN_COMMON }, + + { MSG_ORIG(MSG_SHN_XINDEX), SHN_XINDEX }, + { MSG_ORIG(MSG_SHN_XINDEX_ALT1), SHN_XINDEX }, + + { NULL } +}; + +/* + * ELF section types. + */ +static elfedit_atoui_sym_t sym_sht[] = { + { MSG_ORIG(MSG_SHT_NULL), SHT_NULL }, + { MSG_ORIG(MSG_SHT_NULL_ALT1), SHT_NULL }, + + { MSG_ORIG(MSG_SHT_PROGBITS), SHT_PROGBITS }, + { MSG_ORIG(MSG_SHT_PROGBITS_ALT1), SHT_PROGBITS }, + + { MSG_ORIG(MSG_SHT_SYMTAB), SHT_SYMTAB }, + { MSG_ORIG(MSG_SHT_SYMTAB_ALT1), SHT_SYMTAB }, + + { MSG_ORIG(MSG_SHT_STRTAB), SHT_STRTAB }, + { MSG_ORIG(MSG_SHT_STRTAB_ALT1), SHT_STRTAB }, + + { MSG_ORIG(MSG_SHT_RELA), SHT_RELA }, + { MSG_ORIG(MSG_SHT_RELA_ALT1), SHT_RELA }, + + { MSG_ORIG(MSG_SHT_HASH), SHT_HASH }, + { MSG_ORIG(MSG_SHT_HASH_ALT1), SHT_HASH }, + + { MSG_ORIG(MSG_SHT_DYNAMIC), SHT_DYNAMIC }, + { MSG_ORIG(MSG_SHT_DYNAMIC_ALT1), SHT_DYNAMIC }, + + { MSG_ORIG(MSG_SHT_NOTE), SHT_NOTE }, + { MSG_ORIG(MSG_SHT_NOTE_ALT1), SHT_NOTE }, + + { MSG_ORIG(MSG_SHT_NOBITS), SHT_NOBITS }, + { MSG_ORIG(MSG_SHT_NOBITS_ALT1), SHT_NOBITS }, + + { MSG_ORIG(MSG_SHT_REL), SHT_REL }, + { MSG_ORIG(MSG_SHT_REL_ALT1), SHT_REL }, + + { MSG_ORIG(MSG_SHT_SHLIB), SHT_SHLIB }, + { MSG_ORIG(MSG_SHT_SHLIB_ALT1), SHT_SHLIB }, + + { MSG_ORIG(MSG_SHT_DYNSYM), SHT_DYNSYM }, + { MSG_ORIG(MSG_SHT_DYNSYM_ALT1), SHT_DYNSYM }, + + { MSG_ORIG(MSG_SHT_INIT_ARRAY), SHT_INIT_ARRAY }, + { MSG_ORIG(MSG_SHT_INIT_ARRAY_ALT1), SHT_INIT_ARRAY }, + + { MSG_ORIG(MSG_SHT_FINI_ARRAY), SHT_FINI_ARRAY }, + { MSG_ORIG(MSG_SHT_FINI_ARRAY_ALT1), SHT_FINI_ARRAY }, + + { MSG_ORIG(MSG_SHT_PREINIT_ARRAY), SHT_PREINIT_ARRAY }, + { MSG_ORIG(MSG_SHT_PREINIT_ARRAY_ALT1), SHT_PREINIT_ARRAY }, + + { MSG_ORIG(MSG_SHT_GROUP), SHT_GROUP }, + { MSG_ORIG(MSG_SHT_GROUP_ALT1), SHT_GROUP }, + + { MSG_ORIG(MSG_SHT_SYMTAB_SHNDX), SHT_SYMTAB_SHNDX }, + { MSG_ORIG(MSG_SHT_SYMTAB_SHNDX_ALT1), SHT_SYMTAB_SHNDX }, + + { MSG_ORIG(MSG_SHT_SUNW_SYMSORT), SHT_SUNW_symsort }, + { MSG_ORIG(MSG_SHT_SUNW_SYMSORT_ALT1), SHT_SUNW_symsort }, + + { MSG_ORIG(MSG_SHT_SUNW_TLSSORT), SHT_SUNW_tlssort }, + { MSG_ORIG(MSG_SHT_SUNW_TLSSORT_ALT1), SHT_SUNW_tlssort }, + + { MSG_ORIG(MSG_SHT_SUNW_LDYNSYM), SHT_SUNW_LDYNSYM }, + { MSG_ORIG(MSG_SHT_SUNW_LDYNSYM_ALT1), SHT_SUNW_LDYNSYM }, + + { MSG_ORIG(MSG_SHT_SUNW_DOF), SHT_SUNW_dof }, + { MSG_ORIG(MSG_SHT_SUNW_DOF_ALT1), SHT_SUNW_dof }, + + { MSG_ORIG(MSG_SHT_SUNW_CAP), SHT_SUNW_cap }, + { MSG_ORIG(MSG_SHT_SUNW_CAP_ALT1), SHT_SUNW_cap }, + + { MSG_ORIG(MSG_SHT_SUNW_SIGNATURE), SHT_SUNW_SIGNATURE }, + { MSG_ORIG(MSG_SHT_SUNW_SIGNATURE_ALT1), SHT_SUNW_SIGNATURE }, + + { MSG_ORIG(MSG_SHT_SUNW_ANNOTATE), SHT_SUNW_ANNOTATE }, + { MSG_ORIG(MSG_SHT_SUNW_ANNOTATE_ALT1), SHT_SUNW_ANNOTATE }, + + { MSG_ORIG(MSG_SHT_SUNW_DEBUGSTR), SHT_SUNW_DEBUGSTR }, + { MSG_ORIG(MSG_SHT_SUNW_DEBUGSTR_ALT1), SHT_SUNW_DEBUGSTR }, + + { MSG_ORIG(MSG_SHT_SUNW_DEBUG), SHT_SUNW_DEBUG }, + { MSG_ORIG(MSG_SHT_SUNW_DEBUG_ALT1), SHT_SUNW_DEBUG }, + + { MSG_ORIG(MSG_SHT_SUNW_MOVE), SHT_SUNW_move }, + { MSG_ORIG(MSG_SHT_SUNW_MOVE_ALT1), SHT_SUNW_move }, + + { MSG_ORIG(MSG_SHT_SUNW_COMDAT), SHT_SUNW_COMDAT }, + { MSG_ORIG(MSG_SHT_SUNW_COMDAT_ALT1), SHT_SUNW_COMDAT }, + + { MSG_ORIG(MSG_SHT_SUNW_SYMINFO), SHT_SUNW_syminfo }, + { MSG_ORIG(MSG_SHT_SUNW_SYMINFO_ALT1), SHT_SUNW_syminfo }, + + { MSG_ORIG(MSG_SHT_SUNW_VERDEF), SHT_SUNW_verdef }, + { MSG_ORIG(MSG_SHT_SUNW_VERDEF_ALT1), SHT_SUNW_verdef }, + + { MSG_ORIG(MSG_SHT_GNU_VERDEF), SHT_GNU_verdef }, + { MSG_ORIG(MSG_SHT_GNU_VERDEF_ALT1), SHT_GNU_verdef }, + + { MSG_ORIG(MSG_SHT_SUNW_VERNEED), SHT_SUNW_verneed }, + { MSG_ORIG(MSG_SHT_SUNW_VERNEED_ALT1), SHT_SUNW_verneed }, + + { MSG_ORIG(MSG_SHT_GNU_VERNEED), SHT_GNU_verneed }, + { MSG_ORIG(MSG_SHT_GNU_VERNEED_ALT1), SHT_GNU_verneed }, + + { MSG_ORIG(MSG_SHT_SUNW_VERSYM), SHT_SUNW_versym }, + { MSG_ORIG(MSG_SHT_SUNW_VERSYM_ALT1), SHT_SUNW_versym }, + + { MSG_ORIG(MSG_SHT_GNU_VERSYM), SHT_GNU_versym }, + { MSG_ORIG(MSG_SHT_GNU_VERSYM_ALT1), SHT_GNU_versym }, + + { MSG_ORIG(MSG_SHT_SPARC_GOTDATA), SHT_SPARC_GOTDATA }, + { MSG_ORIG(MSG_SHT_SPARC_GOTDATA_ALT1), SHT_SPARC_GOTDATA }, + + { MSG_ORIG(MSG_SHT_AMD64_UNWIND), SHT_AMD64_UNWIND }, + { MSG_ORIG(MSG_SHT_AMD64_UNWIND_ALT1), SHT_AMD64_UNWIND }, + + { NULL } +}; + +/* + * ELF section types. + */ +static elfedit_atoui_sym_t sym_sht_strtab[] = { + { MSG_ORIG(MSG_SHT_STRTAB), SHT_STRTAB }, + { MSG_ORIG(MSG_SHT_STRTAB_ALT1), SHT_STRTAB }, + + { NULL } +}; + + +/* + * ELF section types for symbol tables + */ +static elfedit_atoui_sym_t sym_sht_allsymtab[] = { + { MSG_ORIG(MSG_SHT_SYMTAB), SHT_SYMTAB }, + { MSG_ORIG(MSG_SHT_SYMTAB_ALT1), SHT_SYMTAB }, + + { MSG_ORIG(MSG_SHT_DYNSYM), SHT_DYNSYM }, + { MSG_ORIG(MSG_SHT_DYNSYM_ALT1), SHT_DYNSYM }, + + { MSG_ORIG(MSG_SHT_SUNW_LDYNSYM), SHT_SUNW_LDYNSYM }, + { MSG_ORIG(MSG_SHT_SUNW_LDYNSYM_ALT1), SHT_SUNW_LDYNSYM }, + + { NULL } +}; + +/* + * ELF section types for SHT_SYMTAB + */ +static elfedit_atoui_sym_t sym_sht_symtab[] = { + { MSG_ORIG(MSG_SHT_SYMTAB), SHT_SYMTAB }, + { MSG_ORIG(MSG_SHT_SYMTAB_ALT1), SHT_SYMTAB }, + + { NULL } +}; + +/* + * ELF section types for SHT_SYMTAB + */ +static elfedit_atoui_sym_t sym_sht_dynsym[] = { + { MSG_ORIG(MSG_SHT_DYNSYM), SHT_DYNSYM }, + { MSG_ORIG(MSG_SHT_DYNSYM_ALT1), SHT_DYNSYM }, + + { NULL } +}; + +/* + * ELF section types for SHT_SUNW_LDYNSYM + */ +static elfedit_atoui_sym_t sym_sht_ldynsym[] = { + { MSG_ORIG(MSG_SHT_SUNW_LDYNSYM), SHT_SUNW_LDYNSYM }, + { MSG_ORIG(MSG_SHT_SUNW_LDYNSYM_ALT1), SHT_SUNW_LDYNSYM }, + + { NULL } +}; + +/* + * ELF dynamic tag DT_ values + */ +static elfedit_atoui_sym_t sym_dt[] = { + { MSG_ORIG(MSG_DT_NULL), DT_NULL }, + { MSG_ORIG(MSG_DT_NULL_ALT1), DT_NULL }, + + { MSG_ORIG(MSG_DT_NEEDED), DT_NEEDED }, + { MSG_ORIG(MSG_DT_NEEDED_ALT1), DT_NEEDED }, + + { MSG_ORIG(MSG_DT_PLTRELSZ), DT_PLTRELSZ }, + { MSG_ORIG(MSG_DT_PLTRELSZ_ALT1), DT_PLTRELSZ }, + + { MSG_ORIG(MSG_DT_PLTGOT), DT_PLTGOT }, + { MSG_ORIG(MSG_DT_PLTGOT_ALT1), DT_PLTGOT }, + + { MSG_ORIG(MSG_DT_HASH), DT_HASH }, + { MSG_ORIG(MSG_DT_HASH_ALT1), DT_HASH }, + + { MSG_ORIG(MSG_DT_STRTAB), DT_STRTAB }, + { MSG_ORIG(MSG_DT_STRTAB_ALT1), DT_STRTAB }, + + { MSG_ORIG(MSG_DT_SYMTAB), DT_SYMTAB }, + { MSG_ORIG(MSG_DT_SYMTAB_ALT1), DT_SYMTAB }, + + { MSG_ORIG(MSG_DT_RELA), DT_RELA }, + { MSG_ORIG(MSG_DT_RELA_ALT1), DT_RELA }, + + { MSG_ORIG(MSG_DT_RELASZ), DT_RELASZ }, + { MSG_ORIG(MSG_DT_RELASZ_ALT1), DT_RELASZ }, + + { MSG_ORIG(MSG_DT_RELAENT), DT_RELAENT }, + { MSG_ORIG(MSG_DT_RELAENT_ALT1), DT_RELAENT }, + + { MSG_ORIG(MSG_DT_STRSZ), DT_STRSZ }, + { MSG_ORIG(MSG_DT_STRSZ_ALT1), DT_STRSZ }, + + { MSG_ORIG(MSG_DT_SYMENT), DT_SYMENT }, + { MSG_ORIG(MSG_DT_SYMENT_ALT1), DT_SYMENT }, + + { MSG_ORIG(MSG_DT_INIT), DT_INIT }, + { MSG_ORIG(MSG_DT_INIT_ALT1), DT_INIT }, + + { MSG_ORIG(MSG_DT_FINI), DT_FINI }, + { MSG_ORIG(MSG_DT_FINI_ALT1), DT_FINI }, + + { MSG_ORIG(MSG_DT_SONAME), DT_SONAME }, + { MSG_ORIG(MSG_DT_SONAME_ALT1), DT_SONAME }, + + { MSG_ORIG(MSG_DT_RPATH), DT_RPATH }, + { MSG_ORIG(MSG_DT_RPATH_ALT1), DT_RPATH }, + + { MSG_ORIG(MSG_DT_SYMBOLIC), DT_SYMBOLIC }, + { MSG_ORIG(MSG_DT_SYMBOLIC_ALT1), DT_SYMBOLIC }, + + { MSG_ORIG(MSG_DT_REL), DT_REL }, + { MSG_ORIG(MSG_DT_REL_ALT1), DT_REL }, + + { MSG_ORIG(MSG_DT_RELSZ), DT_RELSZ }, + { MSG_ORIG(MSG_DT_RELSZ_ALT1), DT_RELSZ }, + + { MSG_ORIG(MSG_DT_RELENT), DT_RELENT }, + { MSG_ORIG(MSG_DT_RELENT_ALT1), DT_RELENT }, + + { MSG_ORIG(MSG_DT_PLTREL), DT_PLTREL }, + { MSG_ORIG(MSG_DT_PLTREL_ALT1), DT_PLTREL }, + + { MSG_ORIG(MSG_DT_DEBUG), DT_DEBUG }, + { MSG_ORIG(MSG_DT_DEBUG_ALT1), DT_DEBUG }, + + { MSG_ORIG(MSG_DT_TEXTREL), DT_TEXTREL }, + { MSG_ORIG(MSG_DT_TEXTREL_ALT1), DT_TEXTREL }, + + { MSG_ORIG(MSG_DT_JMPREL), DT_JMPREL }, + { MSG_ORIG(MSG_DT_JMPREL_ALT1), DT_JMPREL }, + + { MSG_ORIG(MSG_DT_BIND_NOW), DT_BIND_NOW }, + { MSG_ORIG(MSG_DT_BIND_NOW_ALT1), DT_BIND_NOW }, + + { MSG_ORIG(MSG_DT_INIT_ARRAY), DT_INIT_ARRAY }, + { MSG_ORIG(MSG_DT_INIT_ARRAY_ALT1), DT_INIT_ARRAY }, + + { MSG_ORIG(MSG_DT_FINI_ARRAY), DT_FINI_ARRAY }, + { MSG_ORIG(MSG_DT_FINI_ARRAY_ALT1), DT_FINI_ARRAY }, + + { MSG_ORIG(MSG_DT_INIT_ARRAYSZ), DT_INIT_ARRAYSZ }, + { MSG_ORIG(MSG_DT_INIT_ARRAYSZ_ALT1), DT_INIT_ARRAYSZ }, + + { MSG_ORIG(MSG_DT_FINI_ARRAYSZ), DT_FINI_ARRAYSZ }, + { MSG_ORIG(MSG_DT_FINI_ARRAYSZ_ALT1), DT_FINI_ARRAYSZ }, + + { MSG_ORIG(MSG_DT_RUNPATH), DT_RUNPATH }, + { MSG_ORIG(MSG_DT_RUNPATH_ALT1), DT_RUNPATH }, + + { MSG_ORIG(MSG_DT_FLAGS), DT_FLAGS }, + { MSG_ORIG(MSG_DT_FLAGS_ALT1), DT_FLAGS }, + + { MSG_ORIG(MSG_DT_PREINIT_ARRAY), DT_PREINIT_ARRAY }, + { MSG_ORIG(MSG_DT_PREINIT_ARRAY_ALT1), DT_PREINIT_ARRAY }, + + { MSG_ORIG(MSG_DT_PREINIT_ARRAYSZ), DT_PREINIT_ARRAYSZ }, + { MSG_ORIG(MSG_DT_PREINIT_ARRAYSZ_ALT1), DT_PREINIT_ARRAYSZ }, + + { MSG_ORIG(MSG_DT_SUNW_AUXILIARY), DT_SUNW_AUXILIARY }, + { MSG_ORIG(MSG_DT_SUNW_AUXILIARY_ALT1), DT_SUNW_AUXILIARY }, + + { MSG_ORIG(MSG_DT_SUNW_RTLDINF), DT_SUNW_RTLDINF }, + { MSG_ORIG(MSG_DT_SUNW_RTLDINF_ALT1), DT_SUNW_RTLDINF }, + + { MSG_ORIG(MSG_DT_SUNW_FILTER), DT_SUNW_FILTER }, + { MSG_ORIG(MSG_DT_SUNW_FILTER_ALT1), DT_SUNW_FILTER }, + + { MSG_ORIG(MSG_DT_SUNW_CAP), DT_SUNW_CAP }, + { MSG_ORIG(MSG_DT_SUNW_CAP_ALT1), DT_SUNW_CAP }, + + { MSG_ORIG(MSG_DT_SUNW_SYMTAB), DT_SUNW_SYMTAB }, + { MSG_ORIG(MSG_DT_SUNW_SYMTAB_ALT1), DT_SUNW_SYMTAB }, + + { MSG_ORIG(MSG_DT_SUNW_SYMSZ), DT_SUNW_SYMSZ }, + { MSG_ORIG(MSG_DT_SUNW_SYMSZ_ALT1), DT_SUNW_SYMSZ }, + + { MSG_ORIG(MSG_DT_SUNW_SORTENT), DT_SUNW_SORTENT }, + { MSG_ORIG(MSG_DT_SUNW_SORTENT_ALT1), DT_SUNW_SORTENT }, + + { MSG_ORIG(MSG_DT_SUNW_SYMSORT), DT_SUNW_SYMSORT }, + { MSG_ORIG(MSG_DT_SUNW_SYMSORT_ALT1), DT_SUNW_SYMSORT }, + + { MSG_ORIG(MSG_DT_SUNW_SYMSORTSZ), DT_SUNW_SYMSORTSZ }, + { MSG_ORIG(MSG_DT_SUNW_SYMSORTSZ_ALT1), DT_SUNW_SYMSORTSZ }, + + { MSG_ORIG(MSG_DT_SUNW_TLSSORT), DT_SUNW_TLSSORT }, + { MSG_ORIG(MSG_DT_SUNW_TLSSORT_ALT1), DT_SUNW_TLSSORT }, + + { MSG_ORIG(MSG_DT_SUNW_TLSSORTSZ), DT_SUNW_TLSSORTSZ }, + { MSG_ORIG(MSG_DT_SUNW_TLSSORTSZ_ALT1), DT_SUNW_TLSSORTSZ }, + + { MSG_ORIG(MSG_DT_SUNW_STRPAD), DT_SUNW_STRPAD }, + { MSG_ORIG(MSG_DT_SUNW_STRPAD_ALT1), DT_SUNW_STRPAD }, + + { MSG_ORIG(MSG_DT_SPARC_REGISTER), DT_SPARC_REGISTER }, + { MSG_ORIG(MSG_DT_SPARC_REGISTER_ALT1), DT_SPARC_REGISTER }, + + { MSG_ORIG(MSG_DT_DEPRECATED_SPARC_REGISTER), + DT_DEPRECATED_SPARC_REGISTER }, + { MSG_ORIG(MSG_DT_DEPRECATED_SPARC_REGISTER_ALT1), + DT_DEPRECATED_SPARC_REGISTER }, + + { MSG_ORIG(MSG_DT_CHECKSUM), DT_CHECKSUM }, + { MSG_ORIG(MSG_DT_CHECKSUM_ALT1), DT_CHECKSUM }, + + { MSG_ORIG(MSG_DT_PLTPADSZ), DT_PLTPADSZ }, + { MSG_ORIG(MSG_DT_PLTPADSZ_ALT1), DT_PLTPADSZ }, + + { MSG_ORIG(MSG_DT_MOVEENT), DT_MOVEENT }, + { MSG_ORIG(MSG_DT_MOVEENT_ALT1), DT_MOVEENT }, + + { MSG_ORIG(MSG_DT_MOVESZ), DT_MOVESZ }, + { MSG_ORIG(MSG_DT_MOVESZ_ALT1), DT_MOVESZ }, + + { MSG_ORIG(MSG_DT_FEATURE_1), DT_FEATURE_1 }, + { MSG_ORIG(MSG_DT_FEATURE_1_ALT1), DT_FEATURE_1 }, + + { MSG_ORIG(MSG_DT_POSFLAG_1), DT_POSFLAG_1 }, + { MSG_ORIG(MSG_DT_POSFLAG_1_ALT1), DT_POSFLAG_1 }, + + { MSG_ORIG(MSG_DT_SYMINSZ), DT_SYMINSZ }, + { MSG_ORIG(MSG_DT_SYMINSZ_ALT1), DT_SYMINSZ }, + + { MSG_ORIG(MSG_DT_SYMINENT), DT_SYMINENT }, + { MSG_ORIG(MSG_DT_SYMINENT_ALT1), DT_SYMINENT }, + + { MSG_ORIG(MSG_DT_CONFIG), DT_CONFIG }, + { MSG_ORIG(MSG_DT_CONFIG_ALT1), DT_CONFIG }, + + { MSG_ORIG(MSG_DT_DEPAUDIT), DT_DEPAUDIT }, + { MSG_ORIG(MSG_DT_DEPAUDIT_ALT1), DT_DEPAUDIT }, + + { MSG_ORIG(MSG_DT_AUDIT), DT_AUDIT }, + { MSG_ORIG(MSG_DT_AUDIT_ALT1), DT_AUDIT }, + + { MSG_ORIG(MSG_DT_PLTPAD), DT_PLTPAD }, + { MSG_ORIG(MSG_DT_PLTPAD_ALT1), DT_PLTPAD }, + + { MSG_ORIG(MSG_DT_MOVETAB), DT_MOVETAB }, + { MSG_ORIG(MSG_DT_MOVETAB_ALT1), DT_MOVETAB }, + + { MSG_ORIG(MSG_DT_SYMINFO), DT_SYMINFO }, + { MSG_ORIG(MSG_DT_SYMINFO_ALT1), DT_SYMINFO }, + + { MSG_ORIG(MSG_DT_VERSYM), DT_VERSYM }, + { MSG_ORIG(MSG_DT_VERSYM_ALT1), DT_VERSYM }, + + { MSG_ORIG(MSG_DT_RELACOUNT), DT_RELACOUNT }, + { MSG_ORIG(MSG_DT_RELACOUNT_ALT1), DT_RELACOUNT }, + + { MSG_ORIG(MSG_DT_RELCOUNT), DT_RELCOUNT }, + { MSG_ORIG(MSG_DT_RELCOUNT_ALT1), DT_RELCOUNT }, + + { MSG_ORIG(MSG_DT_FLAGS_1), DT_FLAGS_1 }, + { MSG_ORIG(MSG_DT_FLAGS_1_ALT1), DT_FLAGS_1 }, + + { MSG_ORIG(MSG_DT_VERDEF), DT_VERDEF }, + { MSG_ORIG(MSG_DT_VERDEF_ALT1), DT_VERDEF }, + + { MSG_ORIG(MSG_DT_VERDEFNUM), DT_VERDEFNUM }, + { MSG_ORIG(MSG_DT_VERDEFNUM_ALT1), DT_VERDEFNUM }, + + { MSG_ORIG(MSG_DT_VERNEED), DT_VERNEED }, + { MSG_ORIG(MSG_DT_VERNEED_ALT1), DT_VERNEED }, + + { MSG_ORIG(MSG_DT_VERNEEDNUM), DT_VERNEEDNUM }, + { MSG_ORIG(MSG_DT_VERNEEDNUM_ALT1), DT_VERNEEDNUM }, + + { MSG_ORIG(MSG_DT_AUXILIARY), DT_AUXILIARY }, + { MSG_ORIG(MSG_DT_AUXILIARY_ALT1), DT_AUXILIARY }, + + { MSG_ORIG(MSG_DT_USED), DT_USED }, + { MSG_ORIG(MSG_DT_USED_ALT1), DT_USED }, + + { MSG_ORIG(MSG_DT_FILTER), DT_FILTER }, + { MSG_ORIG(MSG_DT_FILTER_ALT1), DT_FILTER }, + + { NULL } +}; + + +/* + * ELF DT_FLAGS DF_* values + */ +static elfedit_atoui_sym_t sym_df[] = { + { MSG_ORIG(MSG_DF_ORIGIN), DF_ORIGIN }, + { MSG_ORIG(MSG_DF_ORIGIN_ALT1), DF_ORIGIN }, + + { MSG_ORIG(MSG_DF_SYMBOLIC), DF_SYMBOLIC }, + { MSG_ORIG(MSG_DF_SYMBOLIC_ALT1), DF_SYMBOLIC }, + + { MSG_ORIG(MSG_DF_TEXTREL), DF_TEXTREL }, + { MSG_ORIG(MSG_DF_TEXTREL_ALT1), DF_TEXTREL }, + + { MSG_ORIG(MSG_DF_BIND_NOW), DF_BIND_NOW }, + { MSG_ORIG(MSG_DF_BIND_NOW_ALT1), DF_BIND_NOW }, + + { MSG_ORIG(MSG_DF_STATIC_TLS), DF_STATIC_TLS }, + { MSG_ORIG(MSG_DF_STATIC_TLS_ALT1), DF_STATIC_TLS }, + + { NULL } +}; + + +/* + * ELF DT_POSFLAG_1 DF_P1_* values + */ +static elfedit_atoui_sym_t sym_df_p1[] = { + { MSG_ORIG(MSG_DF_P1_LAZYLOAD), DF_P1_LAZYLOAD }, + { MSG_ORIG(MSG_DF_P1_LAZYLOAD_ALT1), DF_P1_LAZYLOAD }, + + { MSG_ORIG(MSG_DF_P1_GROUPPERM), DF_P1_GROUPPERM }, + { MSG_ORIG(MSG_DF_P1_GROUPPERM_ALT1), DF_P1_GROUPPERM }, + + { NULL } +}; + + +/* + * ELF DT_FLAGS_1 DF_1_* values + */ +static elfedit_atoui_sym_t sym_df_1[] = { + { MSG_ORIG(MSG_DF_1_NOW), DF_1_NOW }, + { MSG_ORIG(MSG_DF_1_NOW_ALT1), DF_1_NOW }, + + { MSG_ORIG(MSG_DF_1_GLOBAL), DF_1_GLOBAL }, + { MSG_ORIG(MSG_DF_1_GLOBAL_ALT1), DF_1_GLOBAL }, + + { MSG_ORIG(MSG_DF_1_GROUP), DF_1_GROUP }, + { MSG_ORIG(MSG_DF_1_GROUP_ALT1), DF_1_GROUP }, + + { MSG_ORIG(MSG_DF_1_NODELETE), DF_1_NODELETE }, + { MSG_ORIG(MSG_DF_1_NODELETE_ALT1), DF_1_NODELETE }, + + { MSG_ORIG(MSG_DF_1_LOADFLTR), DF_1_LOADFLTR }, + { MSG_ORIG(MSG_DF_1_LOADFLTR_ALT1), DF_1_LOADFLTR }, + + { MSG_ORIG(MSG_DF_1_INITFIRST), DF_1_INITFIRST }, + { MSG_ORIG(MSG_DF_1_INITFIRST_ALT1), DF_1_INITFIRST }, + + { MSG_ORIG(MSG_DF_1_NOOPEN), DF_1_NOOPEN }, + { MSG_ORIG(MSG_DF_1_NOOPEN_ALT1), DF_1_NOOPEN }, + + { MSG_ORIG(MSG_DF_1_ORIGIN), DF_1_ORIGIN }, + { MSG_ORIG(MSG_DF_1_ORIGIN_ALT1), DF_1_ORIGIN }, + + { MSG_ORIG(MSG_DF_1_DIRECT), DF_1_DIRECT }, + { MSG_ORIG(MSG_DF_1_DIRECT_ALT1), DF_1_DIRECT }, + + { MSG_ORIG(MSG_DF_1_TRANS), DF_1_TRANS }, + { MSG_ORIG(MSG_DF_1_TRANS_ALT1), DF_1_TRANS }, + + { MSG_ORIG(MSG_DF_1_INTERPOSE), DF_1_INTERPOSE }, + { MSG_ORIG(MSG_DF_1_INTERPOSE_ALT1), DF_1_INTERPOSE }, + + { MSG_ORIG(MSG_DF_1_NODEFLIB), DF_1_NODEFLIB }, + { MSG_ORIG(MSG_DF_1_NODEFLIB_ALT1), DF_1_NODEFLIB }, + + { MSG_ORIG(MSG_DF_1_NODUMP), DF_1_NODUMP }, + { MSG_ORIG(MSG_DF_1_NODUMP_ALT1), DF_1_NODUMP }, + + { MSG_ORIG(MSG_DF_1_CONFALT), DF_1_CONFALT }, + { MSG_ORIG(MSG_DF_1_CONFALT_ALT1), DF_1_CONFALT }, + + { MSG_ORIG(MSG_DF_1_ENDFILTEE), DF_1_ENDFILTEE }, + { MSG_ORIG(MSG_DF_1_ENDFILTEE_ALT1), DF_1_ENDFILTEE }, + + { MSG_ORIG(MSG_DF_1_DISPRELDNE), DF_1_DISPRELDNE }, + { MSG_ORIG(MSG_DF_1_DISPRELDNE_ALT1), DF_1_DISPRELDNE }, + + { MSG_ORIG(MSG_DF_1_DISPRELPND), DF_1_DISPRELPND }, + { MSG_ORIG(MSG_DF_1_DISPRELPND_ALT1), DF_1_DISPRELPND }, + + { MSG_ORIG(MSG_DF_1_NODIRECT), DF_1_NODIRECT }, + { MSG_ORIG(MSG_DF_1_NODIRECT_ALT1), DF_1_NODIRECT }, + + { MSG_ORIG(MSG_DF_1_IGNMULDEF), DF_1_IGNMULDEF }, + { MSG_ORIG(MSG_DF_1_IGNMULDEF_ALT1), DF_1_IGNMULDEF }, + + { MSG_ORIG(MSG_DF_1_NOKSYMS), DF_1_NOKSYMS }, + { MSG_ORIG(MSG_DF_1_NOKSYMS_ALT1), DF_1_NOKSYMS }, + + { MSG_ORIG(MSG_DF_1_NOHDR), DF_1_NOHDR }, + { MSG_ORIG(MSG_DF_1_NOHDR_ALT1), DF_1_NOHDR }, + + { MSG_ORIG(MSG_DF_1_EDITED), DF_1_EDITED }, + { MSG_ORIG(MSG_DF_1_EDITED_ALT1), DF_1_EDITED }, + + { MSG_ORIG(MSG_DF_1_NORELOC), DF_1_NORELOC }, + { MSG_ORIG(MSG_DF_1_NORELOC_ALT1), DF_1_NORELOC }, + + { MSG_ORIG(MSG_DF_1_SYMINTPOSE), DF_1_SYMINTPOSE }, + { MSG_ORIG(MSG_DF_1_SYMINTPOSE_ALT1), DF_1_SYMINTPOSE }, + + { MSG_ORIG(MSG_DF_1_GLOBAUDIT), DF_1_GLOBAUDIT }, + { MSG_ORIG(MSG_DF_1_GLOBAUDIT_ALT1), DF_1_GLOBAUDIT }, + + { NULL } +}; + + +/* + * ELF DT_FEATURE_1 DTF_1_* values + */ +static elfedit_atoui_sym_t sym_dtf_1[] = { + { MSG_ORIG(MSG_DTF_1_PARINIT), DTF_1_PARINIT }, + { MSG_ORIG(MSG_DTF_1_PARINIT_ALT1), DTF_1_PARINIT }, + + { MSG_ORIG(MSG_DTF_1_CONFEXP), DTF_1_CONFEXP }, + { MSG_ORIG(MSG_DTF_1_CONFEXP_ALT1), DTF_1_CONFEXP }, + + { NULL } +}; + +/* + * ELF header EI_* indexes + */ +static elfedit_atoui_sym_t sym_ei[] = { + { MSG_ORIG(MSG_EI_MAG0), EI_MAG0 }, + { MSG_ORIG(MSG_EI_MAG0_ALT1), EI_MAG0 }, + + { MSG_ORIG(MSG_EI_MAG1), EI_MAG1 }, + { MSG_ORIG(MSG_EI_MAG1_ALT1), EI_MAG1 }, + + { MSG_ORIG(MSG_EI_MAG2), EI_MAG2 }, + { MSG_ORIG(MSG_EI_MAG2_ALT1), EI_MAG2 }, + + { MSG_ORIG(MSG_EI_MAG3), EI_MAG3 }, + { MSG_ORIG(MSG_EI_MAG3_ALT1), EI_MAG3 }, + + { MSG_ORIG(MSG_EI_CLASS), EI_CLASS }, + { MSG_ORIG(MSG_EI_CLASS_ALT1), EI_CLASS }, + + { MSG_ORIG(MSG_EI_DATA), EI_DATA }, + { MSG_ORIG(MSG_EI_DATA_ALT1), EI_DATA }, + + { MSG_ORIG(MSG_EI_VERSION), EI_VERSION }, + { MSG_ORIG(MSG_EI_VERSION_ALT1), EI_VERSION }, + + { MSG_ORIG(MSG_EI_OSABI), EI_OSABI }, + { MSG_ORIG(MSG_EI_OSABI_ALT1), EI_OSABI }, + + { MSG_ORIG(MSG_EI_ABIVERSION), EI_ABIVERSION }, + { MSG_ORIG(MSG_EI_ABIVERSION_ALT1), EI_ABIVERSION }, + + { NULL } +}; + +/* + * ELF header ET_* file type values + */ +static elfedit_atoui_sym_t sym_et[] = { + { MSG_ORIG(MSG_ET_NONE), ET_NONE }, + { MSG_ORIG(MSG_ET_NONE_ALT1), ET_NONE }, + + { MSG_ORIG(MSG_ET_REL), ET_REL }, + { MSG_ORIG(MSG_ET_REL_ALT1), ET_REL }, + + { MSG_ORIG(MSG_ET_EXEC), ET_EXEC }, + { MSG_ORIG(MSG_ET_EXEC_ALT1), ET_EXEC }, + + { MSG_ORIG(MSG_ET_DYN), ET_DYN }, + { MSG_ORIG(MSG_ET_DYN_ALT1), ET_DYN }, + + { MSG_ORIG(MSG_ET_CORE), ET_CORE }, + { MSG_ORIG(MSG_ET_CORE_ALT1), ET_CORE }, + + { NULL } +}; + +/* + * ELFCLASS + */ +static elfedit_atoui_sym_t sym_elfclass[] = { + { MSG_ORIG(MSG_ELFCLASSNONE), ELFCLASSNONE }, + { MSG_ORIG(MSG_ELFCLASSNONE_ALT1), ELFCLASSNONE }, + + { MSG_ORIG(MSG_ELFCLASS32), ELFCLASS32 }, + { MSG_ORIG(MSG_ELFCLASS32_ALT1), ELFCLASS32 }, + + { MSG_ORIG(MSG_ELFCLASS64), ELFCLASS64 }, + { MSG_ORIG(MSG_ELFCLASS64_ALT1), ELFCLASS64 }, + + { NULL } +}; + +/* + * ELFDATA + */ +static elfedit_atoui_sym_t sym_elfdata[] = { + { MSG_ORIG(MSG_ELFDATANONE), ELFDATANONE }, + { MSG_ORIG(MSG_ELFDATANONE_ALT1), ELFDATANONE }, + + { MSG_ORIG(MSG_ELFDATA2LSB), ELFDATA2LSB }, + { MSG_ORIG(MSG_ELFDATA2LSB_ALT1), ELFDATA2LSB }, + + { MSG_ORIG(MSG_ELFDATA2MSB), ELFDATA2MSB }, + { MSG_ORIG(MSG_ELFDATA2MSB_ALT1), ELFDATA2MSB }, + + { NULL } +}; + +/* + * ELF header EF_* flags + */ +static elfedit_atoui_sym_t sym_ef[] = { + { MSG_ORIG(MSG_EF_SPARC_32PLUS), EF_SPARC_32PLUS }, + { MSG_ORIG(MSG_EF_SPARC_32PLUS_ALT1), EF_SPARC_32PLUS }, + + { MSG_ORIG(MSG_EF_SPARC_SUN_US1), EF_SPARC_SUN_US1 }, + { MSG_ORIG(MSG_EF_SPARC_SUN_US1_ALT1), EF_SPARC_SUN_US1 }, + + { MSG_ORIG(MSG_EF_SPARC_HAL_R1), EF_SPARC_HAL_R1 }, + { MSG_ORIG(MSG_EF_SPARC_HAL_R1_ALT1), EF_SPARC_HAL_R1 }, + + { MSG_ORIG(MSG_EF_SPARC_SUN_US3), EF_SPARC_SUN_US3 }, + { MSG_ORIG(MSG_EF_SPARC_SUN_US3_ALT1), EF_SPARC_SUN_US3 }, + + { MSG_ORIG(MSG_EF_SPARCV9_MM), EF_SPARCV9_MM }, + { MSG_ORIG(MSG_EF_SPARCV9_MM_ALT1), EF_SPARCV9_MM }, + + { MSG_ORIG(MSG_EF_SPARCV9_TSO), EF_SPARCV9_TSO }, + { MSG_ORIG(MSG_EF_SPARCV9_TSO_ALT1), EF_SPARCV9_TSO }, + + { MSG_ORIG(MSG_EF_SPARCV9_PSO), EF_SPARCV9_PSO }, + { MSG_ORIG(MSG_EF_SPARCV9_PSO_ALT1), EF_SPARCV9_PSO }, + + { MSG_ORIG(MSG_EF_SPARCV9_RMO), EF_SPARCV9_RMO }, + { MSG_ORIG(MSG_EF_SPARCV9_RMO_ALT1), EF_SPARCV9_RMO }, + + { NULL } +}; + +/* + * ELF header EV_* versions + */ +static elfedit_atoui_sym_t sym_ev[] = { + { MSG_ORIG(MSG_EV_NONE), EV_NONE }, + { MSG_ORIG(MSG_EV_NONE_ALT1), EV_NONE }, + + { MSG_ORIG(MSG_EV_CURRENT), EV_CURRENT }, + { MSG_ORIG(MSG_EV_CURRENT_ALT1), EV_CURRENT }, + + { NULL } +}; + +/* + * ELF EM_* machine types + */ +static elfedit_atoui_sym_t sym_em[] = { + { MSG_ORIG(MSG_EM_NONE), EM_NONE }, + { MSG_ORIG(MSG_EM_NONE_ALT1), EM_NONE }, + + { MSG_ORIG(MSG_EM_M32), EM_M32 }, + { MSG_ORIG(MSG_EM_M32_ALT1), EM_M32 }, + { MSG_ORIG(MSG_EM_M32_ALT2), EM_M32 }, + + { MSG_ORIG(MSG_EM_SPARC), EM_SPARC }, + { MSG_ORIG(MSG_EM_SPARC_ALT1), EM_SPARC }, + + { MSG_ORIG(MSG_EM_386), EM_386 }, + { MSG_ORIG(MSG_EM_386_ALT1), EM_386 }, + { MSG_ORIG(MSG_EM_386_ALT2), EM_386 }, + + { MSG_ORIG(MSG_EM_68K), EM_68K }, + { MSG_ORIG(MSG_EM_68K_ALT1), EM_68K }, + { MSG_ORIG(MSG_EM_68K_ALT2), EM_68K }, + + { MSG_ORIG(MSG_EM_88K), EM_88K }, + { MSG_ORIG(MSG_EM_88K_ALT1), EM_88K }, + { MSG_ORIG(MSG_EM_88K_ALT2), EM_88K }, + + { MSG_ORIG(MSG_EM_486), EM_486 }, + { MSG_ORIG(MSG_EM_486_ALT1), EM_486 }, + { MSG_ORIG(MSG_EM_486_ALT2), EM_486 }, + + { MSG_ORIG(MSG_EM_860), EM_860 }, + { MSG_ORIG(MSG_EM_860_ALT1), EM_860 }, + { MSG_ORIG(MSG_EM_860_ALT2), EM_860 }, + + { MSG_ORIG(MSG_EM_MIPS), EM_MIPS }, + { MSG_ORIG(MSG_EM_MIPS_ALT1), EM_MIPS }, + { MSG_ORIG(MSG_EM_MIPS_ALT2), EM_MIPS }, + + { MSG_ORIG(MSG_EM_S370), EM_S370 }, + { MSG_ORIG(MSG_EM_S370_ALT1), EM_S370 }, + + { MSG_ORIG(MSG_EM_MIPS_RS3_LE), EM_MIPS_RS3_LE }, + { MSG_ORIG(MSG_EM_MIPS_RS3_LE_ALT1), EM_MIPS_RS3_LE }, + { MSG_ORIG(MSG_EM_MIPS_RS3_LE_ALT2), EM_MIPS_RS3_LE }, + + { MSG_ORIG(MSG_EM_RS6000), EM_RS6000 }, + { MSG_ORIG(MSG_EM_RS6000_ALT1), EM_RS6000 }, + + { MSG_ORIG(MSG_EM_PA_RISC), EM_PA_RISC }, + { MSG_ORIG(MSG_EM_PA_RISC_ALT1), EM_PA_RISC }, + + { MSG_ORIG(MSG_EM_NCUBE), EM_nCUBE }, + { MSG_ORIG(MSG_EM_NCUBE_ALT1), EM_nCUBE }, + + { MSG_ORIG(MSG_EM_VPP500), EM_VPP500 }, + { MSG_ORIG(MSG_EM_VPP500_ALT1), EM_VPP500 }, + + { MSG_ORIG(MSG_EM_SPARC32PLUS), EM_SPARC32PLUS }, + { MSG_ORIG(MSG_EM_SPARC32PLUS_ALT1), EM_SPARC32PLUS }, + + { MSG_ORIG(MSG_EM_960), EM_960 }, + { MSG_ORIG(MSG_EM_960_ALT1), EM_960 }, + + { MSG_ORIG(MSG_EM_PPC), EM_PPC }, + { MSG_ORIG(MSG_EM_PPC_ALT1), EM_PPC }, + { MSG_ORIG(MSG_EM_PPC_ALT2), EM_PPC }, + + { MSG_ORIG(MSG_EM_PPC64), EM_PPC64 }, + { MSG_ORIG(MSG_EM_PPC64_ALT1), EM_PPC64 }, + { MSG_ORIG(MSG_EM_PPC64_ALT2), EM_PPC64 }, + + { MSG_ORIG(MSG_EM_S390), EM_S390 }, + { MSG_ORIG(MSG_EM_S390_ALT1), EM_S390 }, + + { MSG_ORIG(MSG_EM_V800), EM_V800 }, + { MSG_ORIG(MSG_EM_V800_ALT1), EM_V800 }, + + { MSG_ORIG(MSG_EM_FR20), EM_FR20 }, + { MSG_ORIG(MSG_EM_FR20_ALT1), EM_FR20 }, + + { MSG_ORIG(MSG_EM_RH32), EM_RH32 }, + { MSG_ORIG(MSG_EM_RH32_ALT1), EM_RH32 }, + + { MSG_ORIG(MSG_EM_RCE), EM_RCE }, + { MSG_ORIG(MSG_EM_RCE_ALT1), EM_RCE }, + + { MSG_ORIG(MSG_EM_ARM), EM_ARM }, + { MSG_ORIG(MSG_EM_ARM_ALT1), EM_ARM }, + + { MSG_ORIG(MSG_EM_ALPHA), EM_ALPHA }, + { MSG_ORIG(MSG_EM_ALPHA_ALT1), EM_ALPHA }, + + { MSG_ORIG(MSG_EM_SH), EM_SH }, + { MSG_ORIG(MSG_EM_SH_ALT1), EM_SH }, + + { MSG_ORIG(MSG_EM_SPARCV9), EM_SPARCV9 }, + { MSG_ORIG(MSG_EM_SPARCV9_ALT1), EM_SPARCV9 }, + + { MSG_ORIG(MSG_EM_TRICORE), EM_TRICORE }, + { MSG_ORIG(MSG_EM_TRICORE_ALT1), EM_TRICORE }, + + { MSG_ORIG(MSG_EM_ARC), EM_ARC }, + { MSG_ORIG(MSG_EM_ARC_ALT1), EM_ARC }, + + { MSG_ORIG(MSG_EM_H8_300), EM_H8_300 }, + { MSG_ORIG(MSG_EM_H8_300_ALT1), EM_H8_300 }, + + { MSG_ORIG(MSG_EM_H8_300H), EM_H8_300H }, + { MSG_ORIG(MSG_EM_H8_300H_ALT1), EM_H8_300H }, + + { MSG_ORIG(MSG_EM_H8S), EM_H8S }, + { MSG_ORIG(MSG_EM_H8S_ALT1), EM_H8S }, + + { MSG_ORIG(MSG_EM_H8_500), EM_H8_500 }, + { MSG_ORIG(MSG_EM_H8_500_ALT1), EM_H8_500 }, + + { MSG_ORIG(MSG_EM_IA_64), EM_IA_64 }, + { MSG_ORIG(MSG_EM_IA_64_ALT1), EM_IA_64 }, + + { MSG_ORIG(MSG_EM_MIPS_X), EM_MIPS_X }, + { MSG_ORIG(MSG_EM_MIPS_X_ALT1), EM_MIPS_X }, + + { MSG_ORIG(MSG_EM_COLDFIRE), EM_COLDFIRE }, + { MSG_ORIG(MSG_EM_COLDFIRE_ALT1), EM_COLDFIRE }, + + { MSG_ORIG(MSG_EM_68HC12), EM_68HC12 }, + { MSG_ORIG(MSG_EM_68HC12_ALT1), EM_68HC12 }, + + { MSG_ORIG(MSG_EM_MMA), EM_MMA }, + { MSG_ORIG(MSG_EM_MMA_ALT1), EM_MMA }, + + { MSG_ORIG(MSG_EM_PCP), EM_PCP }, + { MSG_ORIG(MSG_EM_PCP_ALT1), EM_PCP }, + + { MSG_ORIG(MSG_EM_NCPU), EM_NCPU }, + { MSG_ORIG(MSG_EM_NCPU_ALT1), EM_NCPU }, + + { MSG_ORIG(MSG_EM_NDR1), EM_NDR1 }, + { MSG_ORIG(MSG_EM_NDR1_ALT1), EM_NDR1 }, + + { MSG_ORIG(MSG_EM_STARCORE), EM_STARCORE }, + { MSG_ORIG(MSG_EM_STARCORE_ALT1), EM_STARCORE }, + + { MSG_ORIG(MSG_EM_ME16), EM_ME16 }, + { MSG_ORIG(MSG_EM_ME16_ALT1), EM_ME16 }, + + { MSG_ORIG(MSG_EM_ST100), EM_ST100 }, + { MSG_ORIG(MSG_EM_ST100_ALT1), EM_ST100 }, + + { MSG_ORIG(MSG_EM_TINYJ), EM_TINYJ }, + { MSG_ORIG(MSG_EM_TINYJ_ALT1), EM_TINYJ }, + + { MSG_ORIG(MSG_EM_AMD64), EM_AMD64 }, + { MSG_ORIG(MSG_EM_AMD64_ALT1), EM_AMD64 }, + + { MSG_ORIG(MSG_EM_PDSP), EM_PDSP }, + { MSG_ORIG(MSG_EM_PDSP_ALT1), EM_PDSP }, + + { MSG_ORIG(MSG_EM_FX66), EM_FX66 }, + { MSG_ORIG(MSG_EM_FX66_ALT1), EM_FX66 }, + + { MSG_ORIG(MSG_EM_ST9PLUS), EM_ST9PLUS }, + { MSG_ORIG(MSG_EM_ST9PLUS_ALT1), EM_ST9PLUS }, + + { MSG_ORIG(MSG_EM_ST7), EM_ST7 }, + { MSG_ORIG(MSG_EM_ST7_ALT1), EM_ST7 }, + + { MSG_ORIG(MSG_EM_68HC16), EM_68HC16 }, + { MSG_ORIG(MSG_EM_68HC16_ALT1), EM_68HC16 }, + + { MSG_ORIG(MSG_EM_68HC11), EM_68HC11 }, + { MSG_ORIG(MSG_EM_68HC11_ALT1), EM_68HC11 }, + + { MSG_ORIG(MSG_EM_68HC08), EM_68HC08 }, + { MSG_ORIG(MSG_EM_68HC08_ALT1), EM_68HC08 }, + + { MSG_ORIG(MSG_EM_68HC05), EM_68HC05 }, + { MSG_ORIG(MSG_EM_68HC05_ALT1), EM_68HC05 }, + + { MSG_ORIG(MSG_EM_SVX), EM_SVX }, + { MSG_ORIG(MSG_EM_SVX_ALT1), EM_SVX }, + + { MSG_ORIG(MSG_EM_ST19), EM_ST19 }, + { MSG_ORIG(MSG_EM_ST19_ALT1), EM_ST19 }, + + { MSG_ORIG(MSG_EM_VAX), EM_VAX }, + { MSG_ORIG(MSG_EM_VAX_ALT1), EM_VAX }, + + { MSG_ORIG(MSG_EM_CRIS), EM_CRIS }, + { MSG_ORIG(MSG_EM_CRIS_ALT1), EM_CRIS }, + + { MSG_ORIG(MSG_EM_JAVELIN), EM_JAVELIN }, + { MSG_ORIG(MSG_EM_JAVELIN_ALT1), EM_JAVELIN }, + + { MSG_ORIG(MSG_EM_FIREPATH), EM_FIREPATH }, + { MSG_ORIG(MSG_EM_FIREPATH_ALT1), EM_FIREPATH }, + + { MSG_ORIG(MSG_EM_ZSP), EM_ZSP }, + { MSG_ORIG(MSG_EM_ZSP_ALT1), EM_ZSP }, + + { MSG_ORIG(MSG_EM_MMIX), EM_MMIX }, + { MSG_ORIG(MSG_EM_MMIX_ALT1), EM_MMIX }, + + { MSG_ORIG(MSG_EM_HUANY), EM_HUANY }, + { MSG_ORIG(MSG_EM_HUANY_ALT1), EM_HUANY }, + + { MSG_ORIG(MSG_EM_PRISM), EM_PRISM }, + { MSG_ORIG(MSG_EM_PRISM_ALT1), EM_PRISM }, + + { MSG_ORIG(MSG_EM_AVR), EM_AVR }, + { MSG_ORIG(MSG_EM_AVR_ALT1), EM_AVR }, + + { MSG_ORIG(MSG_EM_FR30), EM_FR30 }, + { MSG_ORIG(MSG_EM_FR30_ALT1), EM_FR30 }, + + { MSG_ORIG(MSG_EM_D10V), EM_D10V }, + { MSG_ORIG(MSG_EM_D10V_ALT1), EM_D10V }, + + { MSG_ORIG(MSG_EM_D30V), EM_D30V }, + { MSG_ORIG(MSG_EM_D30V_ALT1), EM_D30V }, + + { MSG_ORIG(MSG_EM_V850), EM_V850 }, + { MSG_ORIG(MSG_EM_V850_ALT1), EM_V850 }, + + { MSG_ORIG(MSG_EM_M32R), EM_M32R }, + { MSG_ORIG(MSG_EM_M32R_ALT1), EM_M32R }, + + { MSG_ORIG(MSG_EM_MN10300), EM_MN10300 }, + { MSG_ORIG(MSG_EM_MN10300_ALT1), EM_MN10300 }, + + { MSG_ORIG(MSG_EM_MN10200), EM_MN10200 }, + { MSG_ORIG(MSG_EM_MN10200_ALT1), EM_MN10200 }, + + { MSG_ORIG(MSG_EM_PJ), EM_PJ }, + { MSG_ORIG(MSG_EM_PJ_ALT1), EM_PJ }, + + { MSG_ORIG(MSG_EM_OPENRISC), EM_OPENRISC }, + { MSG_ORIG(MSG_EM_OPENRISC_ALT1), EM_OPENRISC }, + + { MSG_ORIG(MSG_EM_ARC_A5), EM_ARC_A5 }, + { MSG_ORIG(MSG_EM_ARC_A5_ALT1), EM_ARC_A5 }, + + { MSG_ORIG(MSG_EM_XTENSA), EM_XTENSA }, + { MSG_ORIG(MSG_EM_XTENSA_ALT1), EM_XTENSA }, + + { NULL } +}; +#if (EM_NUM != (EM_XTENSA + 1)) +#error "EM_NUM has grown" +#endif + + +/* + * ELF header ELFOSABI_* values (and common aliases) + */ +static elfedit_atoui_sym_t sym_elfosabi[] = { + { MSG_ORIG(MSG_ELFOSABI_NONE), ELFOSABI_NONE }, + { MSG_ORIG(MSG_ELFOSABI_NONE_ALT1), ELFOSABI_NONE }, + + { MSG_ORIG(MSG_ELFOSABI_SYSV), ELFOSABI_SYSV }, + { MSG_ORIG(MSG_ELFOSABI_SYSV_ALT1), ELFOSABI_SYSV }, + + { MSG_ORIG(MSG_ELFOSABI_HPUX), ELFOSABI_HPUX }, + { MSG_ORIG(MSG_ELFOSABI_HPUX_ALT1), ELFOSABI_HPUX }, + + { MSG_ORIG(MSG_ELFOSABI_NETBSD), ELFOSABI_NETBSD }, + { MSG_ORIG(MSG_ELFOSABI_NETBSD_ALT1), ELFOSABI_NETBSD }, + + { MSG_ORIG(MSG_ELFOSABI_LINUX), ELFOSABI_LINUX }, + { MSG_ORIG(MSG_ELFOSABI_LINUX_ALT1), ELFOSABI_LINUX }, + + { MSG_ORIG(MSG_ELFOSABI_SOLARIS), ELFOSABI_SOLARIS }, + { MSG_ORIG(MSG_ELFOSABI_SOLARIS_ALT1), ELFOSABI_SOLARIS }, + + { MSG_ORIG(MSG_ELFOSABI_AIX), ELFOSABI_AIX }, + { MSG_ORIG(MSG_ELFOSABI_AIX_ALT1), ELFOSABI_AIX }, + + { MSG_ORIG(MSG_ELFOSABI_IRIX), ELFOSABI_IRIX }, + { MSG_ORIG(MSG_ELFOSABI_IRIX_ALT1), ELFOSABI_IRIX }, + + { MSG_ORIG(MSG_ELFOSABI_FREEBSD), ELFOSABI_FREEBSD }, + { MSG_ORIG(MSG_ELFOSABI_FREEBSD_ALT1), ELFOSABI_FREEBSD }, + + { MSG_ORIG(MSG_ELFOSABI_TRU64), ELFOSABI_TRU64 }, + { MSG_ORIG(MSG_ELFOSABI_TRU64_ALT1), ELFOSABI_TRU64 }, + + { MSG_ORIG(MSG_ELFOSABI_MODESTO), ELFOSABI_MODESTO }, + { MSG_ORIG(MSG_ELFOSABI_MODESTO_ALT1), ELFOSABI_MODESTO }, + + { MSG_ORIG(MSG_ELFOSABI_OPENBSD), ELFOSABI_OPENBSD }, + { MSG_ORIG(MSG_ELFOSABI_OPENBSD_ALT1), ELFOSABI_OPENBSD }, + + { MSG_ORIG(MSG_ELFOSABI_OPENVMS), ELFOSABI_OPENVMS }, + { MSG_ORIG(MSG_ELFOSABI_OPENVMS_ALT1), ELFOSABI_OPENVMS }, + + { MSG_ORIG(MSG_ELFOSABI_NSK), ELFOSABI_NSK }, + { MSG_ORIG(MSG_ELFOSABI_NSK_ALT1), ELFOSABI_NSK }, + + { MSG_ORIG(MSG_ELFOSABI_AROS), ELFOSABI_AROS }, + { MSG_ORIG(MSG_ELFOSABI_AROS_ALT1), ELFOSABI_AROS }, + + { MSG_ORIG(MSG_ELFOSABI_ARM), ELFOSABI_ARM }, + { MSG_ORIG(MSG_ELFOSABI_ARM_ALT1), ELFOSABI_ARM }, + + { MSG_ORIG(MSG_ELFOSABI_STANDALONE), ELFOSABI_STANDALONE }, + { MSG_ORIG(MSG_ELFOSABI_STANDALONE_ALT1), ELFOSABI_STANDALONE }, + + { NULL } +}; + + +/* + * Program header PT_* type values + */ +static elfedit_atoui_sym_t sym_pt[] = { + { MSG_ORIG(MSG_PT_NULL), PT_NULL }, + { MSG_ORIG(MSG_PT_NULL_ALT1), PT_NULL }, + + { MSG_ORIG(MSG_PT_LOAD), PT_LOAD }, + { MSG_ORIG(MSG_PT_LOAD_ALT1), PT_LOAD }, + + { MSG_ORIG(MSG_PT_DYNAMIC), PT_DYNAMIC }, + { MSG_ORIG(MSG_PT_DYNAMIC_ALT1), PT_DYNAMIC }, + + { MSG_ORIG(MSG_PT_INTERP), PT_INTERP }, + { MSG_ORIG(MSG_PT_INTERP_ALT1), PT_INTERP }, + + { MSG_ORIG(MSG_PT_NOTE), PT_NOTE }, + { MSG_ORIG(MSG_PT_NOTE_ALT1), PT_NOTE }, + + { MSG_ORIG(MSG_PT_SHLIB), PT_SHLIB }, + { MSG_ORIG(MSG_PT_SHLIB_ALT1), PT_SHLIB }, + + { MSG_ORIG(MSG_PT_PHDR), PT_PHDR }, + { MSG_ORIG(MSG_PT_PHDR_ALT1), PT_PHDR }, + + { MSG_ORIG(MSG_PT_TLS), PT_TLS }, + { MSG_ORIG(MSG_PT_TLS_ALT1), PT_TLS }, + + { MSG_ORIG(MSG_PT_SUNW_UNWIND), PT_SUNW_UNWIND }, + { MSG_ORIG(MSG_PT_SUNW_UNWIND_ALT1), PT_SUNW_UNWIND }, + + { MSG_ORIG(MSG_PT_SUNWBSS), PT_SUNWBSS }, + { MSG_ORIG(MSG_PT_SUNWBSS_ALT1), PT_SUNWBSS }, + + { MSG_ORIG(MSG_PT_SUNWSTACK), PT_SUNWSTACK }, + { MSG_ORIG(MSG_PT_SUNWSTACK_ALT1), PT_SUNWSTACK }, + + { MSG_ORIG(MSG_PT_SUNWDTRACE), PT_SUNWDTRACE }, + { MSG_ORIG(MSG_PT_SUNWDTRACE_ALT1), PT_SUNWDTRACE }, + + { MSG_ORIG(MSG_PT_SUNWCAP), PT_SUNWCAP }, + { MSG_ORIG(MSG_PT_SUNWCAP_ALT1), PT_SUNWCAP }, + + { NULL } +}; + + +/* + * Program header PF_* flag values + */ +static elfedit_atoui_sym_t sym_pf[] = { + { MSG_ORIG(MSG_PF_X), PF_X }, + { MSG_ORIG(MSG_PF_X_ALT1), PF_X }, + + { MSG_ORIG(MSG_PF_W), PF_W }, + { MSG_ORIG(MSG_PF_W_ALT1), PF_W }, + + { MSG_ORIG(MSG_PF_R), PF_R }, + { MSG_ORIG(MSG_PF_R_ALT1), PF_R }, + + { NULL } +}; + + +/* + * Section header SHF_* flag values + */ +static elfedit_atoui_sym_t sym_shf[] = { + { MSG_ORIG(MSG_SHF_WRITE), SHF_WRITE }, + { MSG_ORIG(MSG_SHF_WRITE_ALT1), SHF_WRITE }, + + { MSG_ORIG(MSG_SHF_ALLOC), SHF_ALLOC }, + { MSG_ORIG(MSG_SHF_ALLOC_ALT1), SHF_ALLOC }, + + { MSG_ORIG(MSG_SHF_EXECINSTR), SHF_EXECINSTR }, + { MSG_ORIG(MSG_SHF_EXECINSTR_ALT1), SHF_EXECINSTR }, + + { MSG_ORIG(MSG_SHF_MERGE), SHF_MERGE }, + { MSG_ORIG(MSG_SHF_MERGE_ALT1), SHF_MERGE }, + + { MSG_ORIG(MSG_SHF_STRINGS), SHF_STRINGS }, + { MSG_ORIG(MSG_SHF_STRINGS_ALT1), SHF_STRINGS }, + + { MSG_ORIG(MSG_SHF_INFO_LINK), SHF_INFO_LINK }, + { MSG_ORIG(MSG_SHF_INFO_LINK_ALT1), SHF_INFO_LINK }, + + { MSG_ORIG(MSG_SHF_LINK_ORDER), SHF_LINK_ORDER }, + { MSG_ORIG(MSG_SHF_LINK_ORDER_ALT1), SHF_LINK_ORDER }, + + { MSG_ORIG(MSG_SHF_OS_NONCONFORMING), SHF_OS_NONCONFORMING }, + { MSG_ORIG(MSG_SHF_OS_NONCONFORMING_ALT1), SHF_OS_NONCONFORMING }, + + { MSG_ORIG(MSG_SHF_GROUP), SHF_GROUP }, + { MSG_ORIG(MSG_SHF_GROUP_ALT1), SHF_GROUP }, + + { MSG_ORIG(MSG_SHF_TLS), SHF_TLS }, + { MSG_ORIG(MSG_SHF_TLS_ALT1), SHF_TLS }, + + { NULL } +}; + +/* + * ELF symbol bindings (st_info ELF_ST_BIND) + */ +static elfedit_atoui_sym_t sym_stb[] = { + { MSG_ORIG(MSG_STB_LOCAL), STB_LOCAL }, + { MSG_ORIG(MSG_STB_LOCAL_ALT1), STB_LOCAL }, + + { MSG_ORIG(MSG_STB_GLOBAL), STB_GLOBAL }, + { MSG_ORIG(MSG_STB_GLOBAL_ALT1), STB_GLOBAL }, + + { MSG_ORIG(MSG_STB_WEAK), STB_WEAK }, + { MSG_ORIG(MSG_STB_WEAK_ALT1), STB_WEAK }, + + { NULL } +}; + +/* + * ELF symbol types (st_info ELF_ST_TYPE) + */ +static elfedit_atoui_sym_t sym_stt[] = { + { MSG_ORIG(MSG_STT_NOTYPE), STT_NOTYPE }, + { MSG_ORIG(MSG_STT_NOTYPE_ALT1), STT_NOTYPE }, + + { MSG_ORIG(MSG_STT_OBJECT), STT_OBJECT }, + { MSG_ORIG(MSG_STT_OBJECT_ALT1), STT_OBJECT }, + + { MSG_ORIG(MSG_STT_FUNC), STT_FUNC }, + { MSG_ORIG(MSG_STT_FUNC_ALT1), STT_FUNC }, + + { MSG_ORIG(MSG_STT_SECTION), STT_SECTION }, + { MSG_ORIG(MSG_STT_SECTION_ALT1), STT_SECTION }, + + { MSG_ORIG(MSG_STT_FILE), STT_FILE }, + { MSG_ORIG(MSG_STT_FILE_ALT1), STT_FILE }, + + { MSG_ORIG(MSG_STT_COMMON), STT_COMMON }, + { MSG_ORIG(MSG_STT_COMMON_ALT1), STT_COMMON }, + + { MSG_ORIG(MSG_STT_TLS), STT_TLS }, + { MSG_ORIG(MSG_STT_TLS_ALT1), STT_TLS }, + + { NULL } +}; + +/* + * ELF symbol visibility (st_other ELF_ST_VISIBILITY) + */ +static elfedit_atoui_sym_t sym_stv[] = { + { MSG_ORIG(MSG_STV_DEFAULT), STV_DEFAULT }, + { MSG_ORIG(MSG_STV_DEFAULT_ALT1), STV_DEFAULT }, + + { MSG_ORIG(MSG_STV_INTERNAL), STV_INTERNAL }, + { MSG_ORIG(MSG_STV_INTERNAL_ALT1), STV_INTERNAL }, + + { MSG_ORIG(MSG_STV_HIDDEN), STV_HIDDEN }, + { MSG_ORIG(MSG_STV_HIDDEN_ALT1), STV_HIDDEN }, + + { MSG_ORIG(MSG_STV_PROTECTED), STV_PROTECTED }, + { MSG_ORIG(MSG_STV_PROTECTED_ALT1), STV_PROTECTED }, + + { NULL } +}; + +/* + * ELF syminfo SYMINFO_BT_ special boundto values + */ +static elfedit_atoui_sym_t sym_syminfo_bt[] = { + { MSG_ORIG(MSG_SYMINFO_BT_SELF), SYMINFO_BT_SELF }, + { MSG_ORIG(MSG_SYMINFO_BT_SELF_ALT1), SYMINFO_BT_SELF }, + + { MSG_ORIG(MSG_SYMINFO_BT_PARENT), SYMINFO_BT_PARENT }, + { MSG_ORIG(MSG_SYMINFO_BT_PARENT_ALT1), SYMINFO_BT_PARENT }, + + { MSG_ORIG(MSG_SYMINFO_BT_NONE), SYMINFO_BT_NONE }, + { MSG_ORIG(MSG_SYMINFO_BT_NONE_ALT1), SYMINFO_BT_NONE }, + + { NULL } +}; + + +/* + * ELF syminfo SYMINFO_FLG_ flags + */ +static elfedit_atoui_sym_t sym_syminfo_flg[] = { + { MSG_ORIG(MSG_SYMINFO_FLG_DIRECT), SYMINFO_FLG_DIRECT }, + { MSG_ORIG(MSG_SYMINFO_FLG_DIRECT_ALT1), SYMINFO_FLG_DIRECT }, + + { MSG_ORIG(MSG_SYMINFO_FLG_COPY), SYMINFO_FLG_COPY }, + { MSG_ORIG(MSG_SYMINFO_FLG_COPY_ALT1), SYMINFO_FLG_COPY }, + + { MSG_ORIG(MSG_SYMINFO_FLG_LAZYLOAD), SYMINFO_FLG_LAZYLOAD }, + { MSG_ORIG(MSG_SYMINFO_FLG_LAZYLOAD_ALT1), SYMINFO_FLG_LAZYLOAD }, + + { MSG_ORIG(MSG_SYMINFO_FLG_DIRECTBIND), SYMINFO_FLG_DIRECTBIND }, + { MSG_ORIG(MSG_SYMINFO_FLG_DIRECTBIND_ALT1), SYMINFO_FLG_DIRECTBIND }, + + { MSG_ORIG(MSG_SYMINFO_FLG_NOEXTDIRECT), SYMINFO_FLG_NOEXTDIRECT }, + { MSG_ORIG(MSG_SYMINFO_FLG_NOEXTDIRECT_ALT1), SYMINFO_FLG_NOEXTDIRECT }, + + { NULL } +}; + + +/* + * ELF capabilities tag CA_ values + */ +static elfedit_atoui_sym_t sym_ca[] = { + { MSG_ORIG(MSG_CA_SUNW_NULL), CA_SUNW_NULL }, + { MSG_ORIG(MSG_CA_SUNW_NULL_ALT1), CA_SUNW_NULL }, + + { MSG_ORIG(MSG_CA_SUNW_HW_1), CA_SUNW_HW_1 }, + { MSG_ORIG(MSG_CA_SUNW_HW_1_ALT1), CA_SUNW_HW_1 }, + + { MSG_ORIG(MSG_CA_SUNW_SF_1), CA_SUNW_SF_1 }, + { MSG_ORIG(MSG_CA_SUNW_SF_1_ALT1), CA_SUNW_SF_1 }, + + { NULL } +}; + +/* + * AV_386 flags used for CA_SUNW_HW_1 capabilities + */ +static elfedit_atoui_sym_t sym_av_386[] = { + { MSG_ORIG(MSG_AV_386_FPU), AV_386_FPU }, + { MSG_ORIG(MSG_AV_386_FPU_ALT1), AV_386_FPU }, + + { MSG_ORIG(MSG_AV_386_TSC), AV_386_TSC }, + { MSG_ORIG(MSG_AV_386_TSC_ALT1), AV_386_TSC }, + + { MSG_ORIG(MSG_AV_386_CX8), AV_386_CX8 }, + { MSG_ORIG(MSG_AV_386_CX8_ALT1), AV_386_CX8 }, + + { MSG_ORIG(MSG_AV_386_SEP), AV_386_SEP }, + { MSG_ORIG(MSG_AV_386_SEP_ALT1), AV_386_SEP }, + + { MSG_ORIG(MSG_AV_386_AMD_SYSC), AV_386_AMD_SYSC }, + { MSG_ORIG(MSG_AV_386_AMD_SYSC_ALT1), AV_386_AMD_SYSC }, + + { MSG_ORIG(MSG_AV_386_CMOV), AV_386_CMOV }, + { MSG_ORIG(MSG_AV_386_CMOV_ALT1), AV_386_CMOV }, + + { MSG_ORIG(MSG_AV_386_MMX), AV_386_MMX }, + { MSG_ORIG(MSG_AV_386_MMX_ALT1), AV_386_MMX }, + + { MSG_ORIG(MSG_AV_386_AMD_MMX), AV_386_AMD_MMX }, + { MSG_ORIG(MSG_AV_386_AMD_MMX_ALT1), AV_386_AMD_MMX }, + + { MSG_ORIG(MSG_AV_386_AMD_3DNOW), AV_386_AMD_3DNow }, + { MSG_ORIG(MSG_AV_386_AMD_3DNOW_ALT1), AV_386_AMD_3DNow }, + + { MSG_ORIG(MSG_AV_386_AMD_3DNOWX), AV_386_AMD_3DNowx }, + { MSG_ORIG(MSG_AV_386_AMD_3DNOWX_ALT1), AV_386_AMD_3DNowx }, + + { MSG_ORIG(MSG_AV_386_FXSR), AV_386_FXSR }, + { MSG_ORIG(MSG_AV_386_FXSR_ALT1), AV_386_FXSR }, + + { MSG_ORIG(MSG_AV_386_SSE), AV_386_SSE }, + { MSG_ORIG(MSG_AV_386_SSE_ALT1), AV_386_SSE }, + + { MSG_ORIG(MSG_AV_386_SSE2), AV_386_SSE2 }, + { MSG_ORIG(MSG_AV_386_SSE2_ALT1), AV_386_SSE2 }, + + { MSG_ORIG(MSG_AV_386_PAUSE), AV_386_PAUSE }, + { MSG_ORIG(MSG_AV_386_PAUSE_ALT1), AV_386_PAUSE }, + + { MSG_ORIG(MSG_AV_386_SSE3), AV_386_SSE3 }, + { MSG_ORIG(MSG_AV_386_SSE3_ALT1), AV_386_SSE3 }, + + { MSG_ORIG(MSG_AV_386_MON), AV_386_MON }, + { MSG_ORIG(MSG_AV_386_MON_ALT1), AV_386_MON }, + + { MSG_ORIG(MSG_AV_386_CX16), AV_386_CX16 }, + { MSG_ORIG(MSG_AV_386_CX16_ALT1), AV_386_CX16 }, + + { MSG_ORIG(MSG_AV_386_AHF), AV_386_AHF }, + { MSG_ORIG(MSG_AV_386_AHF_ALT1), AV_386_AHF }, + + { MSG_ORIG(MSG_AV_386_TSCP), AV_386_TSCP }, + { MSG_ORIG(MSG_AV_386_TSCP_ALT1), AV_386_TSCP }, + + { MSG_ORIG(MSG_AV_386_AMD_SSE4A), AV_386_AMD_SSE4A }, + { MSG_ORIG(MSG_AV_386_AMD_SSE4A_ALT1), AV_386_AMD_SSE4A }, + + { MSG_ORIG(MSG_AV_386_POPCNT), AV_386_POPCNT }, + { MSG_ORIG(MSG_AV_386_POPCNT_ALT1), AV_386_POPCNT }, + + { MSG_ORIG(MSG_AV_386_AMD_LZCNT), AV_386_AMD_LZCNT }, + { MSG_ORIG(MSG_AV_386_AMD_LZCNT_ALT1), AV_386_AMD_LZCNT }, + + { NULL } +}; + + +/* + * AV_SPARC flags used for CA_SUNW_HW_1 capabilities + */ +static elfedit_atoui_sym_t sym_av_sparc[] = { + { MSG_ORIG(MSG_AV_SPARC_MUL32), AV_SPARC_MUL32 }, + { MSG_ORIG(MSG_AV_SPARC_MUL32_ALT1), AV_SPARC_MUL32 }, + + { MSG_ORIG(MSG_AV_SPARC_DIV32), AV_SPARC_DIV32 }, + { MSG_ORIG(MSG_AV_SPARC_DIV32_ALT1), AV_SPARC_DIV32 }, + + { MSG_ORIG(MSG_AV_SPARC_FSMULD), AV_SPARC_FSMULD }, + { MSG_ORIG(MSG_AV_SPARC_FSMULD_ALT1), AV_SPARC_FSMULD }, + + { MSG_ORIG(MSG_AV_SPARC_V8PLUS), AV_SPARC_V8PLUS }, + { MSG_ORIG(MSG_AV_SPARC_V8PLUS_ALT1), AV_SPARC_V8PLUS }, + + { MSG_ORIG(MSG_AV_SPARC_POPC), AV_SPARC_POPC }, + { MSG_ORIG(MSG_AV_SPARC_POPC_ALT1), AV_SPARC_POPC }, + + { MSG_ORIG(MSG_AV_SPARC_VIS), AV_SPARC_VIS }, + { MSG_ORIG(MSG_AV_SPARC_VIS_ALT1), AV_SPARC_VIS }, + + { MSG_ORIG(MSG_AV_SPARC_VIS2), AV_SPARC_VIS2 }, + { MSG_ORIG(MSG_AV_SPARC_VIS2_ALT1), AV_SPARC_VIS2 }, + + { MSG_ORIG(MSG_AV_SPARC_ASI_BLK_INIT), AV_SPARC_ASI_BLK_INIT }, + { MSG_ORIG(MSG_AV_SPARC_ASI_BLK_INIT_ALT1), AV_SPARC_ASI_BLK_INIT }, + + { MSG_ORIG(MSG_AV_SPARC_FMAF), AV_SPARC_FMAF }, + { MSG_ORIG(MSG_AV_SPARC_FMAF_ALT1), AV_SPARC_FMAF }, + + { MSG_ORIG(MSG_AV_SPARC_FJFMAU), AV_SPARC_FJFMAU }, + { MSG_ORIG(MSG_AV_SPARC_FJFMAU_ALT1), AV_SPARC_FJFMAU }, + + { NULL } +}; + + +/* + * SF1_SUNW flags used for CA_SUNW_SF_1 capabilities + */ +static elfedit_atoui_sym_t sym_sf1_sunw[] = { + { MSG_ORIG(MSG_SF1_SUNW_FPKNWN), SF1_SUNW_FPKNWN }, + { MSG_ORIG(MSG_SF1_SUNW_FPKNWN_ALT1), SF1_SUNW_FPKNWN }, + + { MSG_ORIG(MSG_SF1_SUNW_FPUSED), SF1_SUNW_FPUSED }, + { MSG_ORIG(MSG_SF1_SUNW_FPUSED_ALT1), SF1_SUNW_FPUSED }, + + { NULL } +}; + + + + + + + +/* + * Array of pointers to atoui arrays for each constant type, indexed + * by elfedit_const_t value. The number and order of entries in this + * table must agree with the definition of elfedit_const_t in elfedit.h. + */ +static elfedit_atoui_sym_t *sym_table[] = { + sym_outstyle, /* 0: ELFEDIT_CONST_OUTSTYLE */ + sym_minus_o_outstyle, /* 1: ELFEDIT_CONST_OUTSTYLE_MO */ + sym_bool, /* 2: ELFEDIT_CONST_BOOL */ + sym_shn, /* 3: ELFEDIT_CONST_SHN */ + sym_sht, /* 4: ELFEDIT_CONST_SHT */ + sym_sht_strtab, /* 5: ELFEDIT_CONST_SHT_STRTAB */ + sym_sht_allsymtab, /* 6: ELFEDIT_CONST_SHT_ALLSYMTAB */ + sym_sht_symtab, /* 7: ELFEDIT_CONST_SHT_SYMTAB */ + sym_sht_dynsym, /* 8: ELFEDIT_CONST_SHT_DYNSYM */ + sym_sht_ldynsym, /* 9: ELFEDIT_CONST_SHT_LDYNSYM */ + sym_dt, /* 10: ELFEDIT_CONST_DT: Dynamic tags */ + sym_df, /* 11: ELFEDIT_CONST_DF: DT_FLAGS */ + sym_df_p1, /* 12: ELFEDIT_CONST_DF_P1: DF_POSFLAG_1 */ + sym_df_1, /* 13: ELFEDIT_CONST_DF_1: DT_FLAGS_1 */ + sym_dtf_1, /* 14: ELFEDIT_CONST_DTF_1: DT_FEATURE_1 */ + sym_ei, /* 15: ELFEDIT_CONST_EI: Ehdr e_ident indexes */ + sym_et, /* 16: ELFEDIT_CONST_ET: Ehdr obj type */ + sym_elfclass, /* 17: ELFEDIT_CONST_ELFCLASS: Ehdr class */ + sym_elfdata, /* 18: ELFEDIT_CONST_ELFDATA: Ehdr endian */ + sym_ef, /* 19: ELFEDIT_CONST_EF: Ehdr flags */ + sym_ev, /* 20: ELFEDIT_CONST_EV: Ehdr version */ + sym_em, /* 21: ELFEDIT_CONST_EM: Ehdr machine */ + sym_elfosabi, /* 22: ELFEDIT_CONST_ELFOSABI: Ehdr ABI */ + sym_pt, /* 23: ELFEDIT_CONST_PT: Phdr type */ + sym_pf, /* 24: ELFEDIT_CONST_PF: Phdr flags */ + sym_shf, /* 25: ELFEDIT_CONST_SHF: Shdr flags */ + sym_stb, /* 26: ELFEDIT_CONST_STB: Sym binding */ + sym_stt, /* 27: ELFEDIT_CONST_STT: Sym type */ + sym_stv, /* 28: ELFEDIT_CONST_STV: Sym visibility */ + sym_syminfo_bt, /* 29: ELFEDIT_CONST_SYMINFO_BT:Syminfo bndto */ + sym_syminfo_flg, /* 30: ELFEDIT_CONST_SYMINFO_FLG:Syminfo flag */ + sym_ca, /* 31: ELFEDIT_CONST_CA: Capabilities tags */ + sym_av_386, /* 32: ELFEDIT_CONST_AV_386: X86 HW caps */ + sym_av_sparc, /* 33: ELFEDIT_CONST_AV_SPARC: sparc HW caps */ + sym_sf1_sunw, /* 34: ELFEDIT_CONST_SF1_SUNW: software caps */ +}; + + + + + + + +/* + * Given an elfedit_const_t value, return the array of elfedit_atoui_sym_t + * entries that it represents. + */ +elfedit_atoui_sym_t * +elfedit_const_to_atoui(elfedit_const_t const_type) +{ + if ((const_type < 0) || + (const_type >= (sizeof (sym_table) / sizeof (sym_table[0])))) + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADCONST)); + + return (sym_table[const_type]); +} + + + +/* + * Return the elfedit_atoui_t array that corresponds to the + * CA_SUNW_HW_1 hardware capabiliies field for a given + * machine type. + * + * This routine will return NULL if there is no definition for the + * machine specified. + */ +elfedit_atoui_sym_t * +elfedit_mach_sunw_hw1_to_atoui(int mach) +{ + switch (mach) { + case EM_386: + case EM_486: + case EM_AMD64: + return (elfedit_const_to_atoui(ELFEDIT_CONST_AV_386)); + + case EM_SPARC: + case EM_SPARC32PLUS: + case EM_SPARCV9: + return (elfedit_const_to_atoui(ELFEDIT_CONST_AV_SPARC)); + } + + /* A machine we don't know about */ + return (NULL); +} diff --git a/usr/src/cmd/sgs/elfedit/common/elfedit.c b/usr/src/cmd/sgs/elfedit/common/elfedit.c new file mode 100644 index 0000000000..c3d4c5f379 --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/common/elfedit.c @@ -0,0 +1,3600 @@ +/* + * 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 <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <stdarg.h> +#include <fcntl.h> +#include <stdlib.h> +#include <stdio.h> +#include <signal.h> +#include <dirent.h> +#include <libelf.h> +#include <gelf.h> +#include <conv.h> +#include <dlfcn.h> +#include <link.h> +#include <stdarg.h> +#include <libgen.h> +#include <libintl.h> +#include <locale.h> +#include <unistd.h> +#include <errno.h> +#include <ctype.h> +#include <limits.h> +#include <strings.h> +#include <sgs.h> +#include "msg.h" +#include "_elfedit.h" +#include <debug.h> /* liblddb */ + + + +/* + * Column at which elfedit_format_command_usage() will wrap the + * generated usage string if the wrap argument is True (1). + */ +#define USAGE_WRAP_COL 55 + + + + +/* + * Type used to represent a string buffer that can grow as needed + * to hold strings of arbitrary length. The user should declare + * variables of this type sa static. The strbuf_ensure_size() function + * is used to ensure that it has a minimum desired size. + */ +typedef struct { + char *buf; /* String buffer */ + size_t n; /* Size of buffer */ +} STRBUF; + + + + +/* + * Types used by tokenize_user_cmd() to represent the result of + * spliting a user command into individual tokens. + */ +typedef struct { + char *tok_str; /* Token string */ + size_t tok_len; /* strlen(str) */ + size_t tok_line_off; /* Token offset in original string */ +} TOK_ELT; +typedef struct { + size_t tokst_cmd_len; /* Length of original user command, without */ + /* newline or NULL termination chars */ + size_t tokst_str_size; /* Space needed to hold all the resulting */ + /* tokens, including terminating NULL */ + TOK_ELT *tokst_buf; /* The array of tokens */ + size_t tokst_cnt; /* # of tokens in array */ + size_t tokst_bufsize; /* capacity of array */ +} TOK_STATE; + + + + +/* State block used by gettok_init() and gettok() */ +typedef struct { + const char *gtok_buf; /* Addr of buffer containing string */ + char *gtok_cur_buf; /* Addr withing buffer for next token */ + int gtok_inc_null_final; /* True if final NULL token used */ + int gtok_null_seen; /* True when NULL byte seen */ + TOK_ELT gtok_last_token; /* Last token parsed */ + +} GETTOK_STATE; + + + + +/* + * The elfedit_cpl_*() functions are used for command line completion. + * Currently this uses the tecla library, but to allow for changing the + * library used, we hide all tecla interfaces from our modules. Instead, + * cmd_match_fcn() builds an ELFEDIT_CPL_STATE struct, and we pass the + * address of that struct as an opaque handle to the modules. Since the + * pointer is opaque, the contents of ELFEDIT_CPL_STATE are free to change + * as necessary. + */ +typedef struct { + WordCompletion *ecpl_cpl; /* tecla handle */ + const char *ecpl_line; /* raw input line */ + int ecpl_word_start; /* start offset within line */ + int ecpl_word_end; /* offset just past token */ + /* + * ecpl_add_mod_colon is a secret handshake between + * elfedit_cpl_command() and elfedit_cpl_add_match(). It adds + * ':' to end of matched modules. + */ + int ecpl_add_mod_colon; + const char *ecpl_token_str; /* token being completed */ + size_t ecpl_token_len; /* strlen(ecpl_token_str) */ +} ELFEDIT_CPL_STATE; + + + + +/* This structure maintains elfedit global state */ +STATE_T state; + + + +/* + * Define a pair of static global variables that contain the + * ISA strings that correspond to %i and %I tokens in module search + * paths. + * + * isa_i_str - The ISA string for the currently running program + * isa_I_str - For 64-bit programs, the same as isa_i_str. For + * 32-bit programs, an empty string. + */ +#ifdef __sparc +#ifdef __sparcv9 +static const char *isa_i_str = MSG_ORIG(MSG_ISA_SPARC_64); +static const char *isa_I_str = MSG_ORIG(MSG_ISA_SPARC_64); +#else +static const char *isa_i_str = MSG_ORIG(MSG_ISA_SPARC_32); +static const char *isa_I_str = MSG_ORIG(MSG_STR_EMPTY); +#endif +#endif + +#ifdef __i386 +static const char *isa_i_str = MSG_ORIG(MSG_ISA_X86_32); +static const char *isa_I_str = MSG_ORIG(MSG_STR_EMPTY); +#endif +#ifdef __amd64 +static const char *isa_i_str = MSG_ORIG(MSG_ISA_X86_64); +static const char *isa_I_str = MSG_ORIG(MSG_ISA_X86_64); +#endif + + + +/* Forward declarations */ +static void free_user_cmds(void); +static void elfedit_pager_cleanup(void); + + + +/* + * We supply this function for the msg module + */ +const char * +_elfedit_msg(Msg mid) +{ + return (gettext(MSG_ORIG(mid))); +} + + +/* + * Copy at most min(cpsize, dstsize-1) bytes from src into dst, + * truncating src if necessary. The result is always null-terminated. + * + * entry: + * dst - Destination buffer + * src - Source string + * dstsize - sizeof(dst) + * + * note: + * This is similar to strncpy(), but with two modifications: + * 1) You specify the number of characters to copy, not just + * the size of the destination. Hence, you can copy non-NULL + * terminated strings. + * 2) The destination is guaranteed to be NULL terminated. strncpy() + * does not terminate a completely full buffer. + */ +static void +elfedit_strnbcpy(char *dst, const char *src, size_t cpsize, size_t dstsize) +{ + if (cpsize >= dstsize) + cpsize = dstsize - 1; + if (cpsize > 0) + (void) strncpy(dst, src, cpsize + 1); + dst[cpsize] = '\0'; +} + + +/* + * Calls exit() on behalf of elfedit. + */ +void +elfedit_exit(int status) +{ + if (state.file.present) { + /* Exiting with unflushed changes pending? Issue debug notice */ + if (state.file.dirty) + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_DIRTYEXIT)); + + /* + * If the edit file is marked for unlink on exit, then + * take care of it here. + */ + if (state.file.unlink_on_exit) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_UNLINKFILE), + state.file.outfile); + (void) unlink(state.file.outfile); + } + } + + exit(status); +} + + +/* + * Standard message function for elfedit. All user visible + * output, for error or informational reasons, should go through + * this function. + * + * entry: + * type - Type of message. One of the ELFEDIT_MSG_* values. + * format, ... - As per the printf() family + * + * exit: + * The desired message has been output. For informational + * messages, control returns to the caller. For errors, + * this routine will terminate execution or strip the execution + * stack and return control directly to the outer control loop. + * In either case, the caller will not receive control. + */ +/*PRINTFLIKE2*/ +void +elfedit_msg(elfedit_msg_t type, const char *format, ...) +{ + typedef enum { /* What to do after finished */ + DISP_RET = 0, /* Return to caller */ + DISP_JMP = 1, /* if (interactive) longjmp else exit */ + DISP_EXIT = 2 /* exit under all circumstances */ + } DISP; + + va_list args; + FILE *stream = stderr; + DISP disp = DISP_RET; + int do_output = 1; + int need_prefix = 1; + + va_start(args, format); + + switch (type) { + case ELFEDIT_MSG_ERR: + case ELFEDIT_MSG_CMDUSAGE: + disp = DISP_JMP; + break; + case ELFEDIT_MSG_FATAL: + disp = DISP_EXIT; + break; + case ELFEDIT_MSG_USAGE: + need_prefix = 0; + break; + case ELFEDIT_MSG_DEBUG: + if (!(state.flags & ELFEDIT_F_DEBUG)) + return; + stream = stdout; + break; + case ELFEDIT_MSG_QUIET: + do_output = 0; + disp = DISP_JMP; + break; + } + + + /* + * If there is a pager process running, we are returning to the + * caller, and the output is going to stdout, then let the + * pager handle it instead of writing it directly from this process. + * That way, the output gets paged along with everything else. + * + * If there is a pager process running, and we are not returning + * to the caller, then end the pager process now, before we generate + * any new output. This allows for any text buffered in the pager + * pipe to be output before the new stuff. + */ + if (state.pager.fptr != NULL) { + if (disp == DISP_RET) { + if (stream == stdout) + stream = state.pager.fptr; + } else { + elfedit_pager_cleanup(); + } + } + + /* + * If this message is coming from within the libtecla command + * completion code, call gl_normal_io() to give the library notice. + * That function sets the tty back to cooked mode and advances + * the cursor to the beginning of the next line so that our output + * will appear properly. When we return to the command completion code, + * tecla will re-enter raw mode and redraw the current command line. + */ + if (state.input.in_tecla) + (void) gl_normal_io(state.input.gl); + + if (do_output) { + if (need_prefix) + (void) fprintf(stream, MSG_ORIG(MSG_STR_ELFEDIT)); + (void) vfprintf(stream, format, args); + (void) fflush(stream); + } + va_end(args); + + /* + * If this is an error, then we do not return to the caller. + * The action taken depends on whether the outer loop has registered + * a jump buffer for us or not. + */ + if (disp != DISP_RET) { + if (state.msg_jbuf.active && (disp == DISP_JMP)) { + /* Free the user command list */ + free_user_cmds(); + + /* Clean up to reflect effect of non-local goto */ + state.input.in_tecla = FALSE; + + /* Jump to the outer loop to resume */ + siglongjmp(state.msg_jbuf.env, 1); + } else { + elfedit_exit(1); + } + } +} + + +/* + * Wrapper on elfedit_msg() that issues an error that results from + * a call to libelf. + * + * entry: + * file - Name of ELF object + * libelf_rtn_name - Name of routine that was called + * + * exit: + * An error has been issued that shows the routine called + * and the libelf error string for it from elf_errmsg(). + * This routine does not return to the caller. + */ +void +elfedit_elferr(const char *file, const char *libelf_rtn_name) +{ + const char *errstr = elf_errmsg(elf_errno()); + + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_LIBELF), file, + libelf_rtn_name, errstr ? errstr : MSG_INTL(MSG_FMT_UNKNOWN)); +} + + +/* + * Start an output pager process for elfedit_printf()/elfedit_write() to use. + * + * note: + * If this elfedit session is not interactive, then no pager is + * started. Paging is only intended for interactive use. The caller + * is not supposed to worry about this point, but simply to use + * this function to flag situations in which paging might be needed. + */ +void +elfedit_pager_init(void) +{ + const char *errstr; + const char *cmd; + int err; + + /* + * If there is no pager process running, start one. + * Only do this for interactive sessions --- elfedit_pager() + * won't use a pager in batch mode. + */ + if (state.msg_jbuf.active && state.input.full_tty && + (state.pager.fptr == NULL)) { + /* + * If the user has the PAGER environment variable set, + * then we will use that program. Otherwise we default + * to /bin/more. + */ + cmd = getenv(MSG_ORIG(MSG_STR_PAGER)); + if ((cmd == NULL) || (*cmd == '\0')) + cmd = MSG_ORIG(MSG_STR_BINMORE); + + /* + * The popen() manpage says that on failure, it "may set errno", + * which is somewhat ambiguous. We explicitly zero it here, and + * assume that any change is due to popen() failing. + */ + errno = 0; + state.pager.fptr = popen(cmd, MSG_ORIG(MSG_STR_W)); + if (state.pager.fptr == NULL) { + err = errno; + errstr = (err == 0) ? MSG_INTL(MSG_ERR_UNKNOWNSYSERR) : + strerror(err); + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_CNTEXEC), + MSG_ORIG(MSG_STR_ELFEDIT), cmd, errstr); + } + } +} + + +/* + * If there is a pager process present, close it out. + * + * note: + * This function is called from within elfedit_msg(), and as + * such, must not use elfedit_msg() to report errors. Furthermore, + * any such errors are not a sufficient reason to terminate the process + * or to longjmp(). This is a rare case where errors are written + * directly to stderr. + */ +static void +elfedit_pager_cleanup(void) +{ + if (state.pager.fptr != NULL) { + if (pclose(state.pager.fptr) == -1) + (void) fprintf(stderr, MSG_INTL(MSG_ERR_PAGERFINI)); + + state.pager.fptr = NULL; + } +} + + +/* + * Print general formtted text for the user, using printf()-style + * formatting. Uses the pager process if one has been started, or + * stdout otherwise. + */ +void +elfedit_printf(const char *format, ...) +{ + va_list args; + int err; + FILE *fptr; + int pager; + int broken_pipe = 0; + + /* + * If there is a pager process, then use it. Otherwise write + * directly to stdout. + */ + pager = (state.pager.fptr != NULL); + fptr = pager ? state.pager.fptr : stdout; + + va_start(args, format); + errno = 0; + err = vfprintf(fptr, format, args); + + /* Did we fail because a child pager process has exited? */ + broken_pipe = pager && (err < 0) && (errno == EPIPE); + + va_end(args); + + /* + * On error, we simply issue the error without cleaning up + * the pager process. The message code handles that as a standard + * part of error processing. + * + * We handle failure due to an exited pager process differently + * than a normal error, because it is usually due to the user + * intentionally telling it to. + */ + if (err < 0) { + if (broken_pipe) + elfedit_msg(ELFEDIT_MSG_QUIET, MSG_ORIG(MSG_STR_NULL)); + else + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_PRINTF)); + } +} + + +/* + * Some our modules use liblddb routines to format ELF output. + * In order to ensure that such output is sent to the pager pipe + * when there is one, and stdout otherwise, we redefine the dbg_print() + * function here. + * + * This item should be defined NODIRECT. + */ +/* PRINTFLIKE2 */ +void +dbg_print(Lm_list *lml, const char *format, ...) +{ + va_list ap; + int err; + FILE *fptr; + int pager; + int broken_pipe = 0; + +#if defined(lint) + /* + * The lml argument is only meaningful for diagnostics sent to ld.so.1. + * Supress the lint error by making a dummy assignment. + */ + lml = 0; +#endif + + /* + * If there is a pager process, then use it. Otherwise write + * directly to stdout. + */ + pager = (state.pager.fptr != NULL); + fptr = pager ? state.pager.fptr : stdout; + + va_start(ap, format); + errno = 0; + err = vfprintf(fptr, format, ap); + if (err >= 0) + err = fprintf(fptr, MSG_ORIG(MSG_STR_NL)); + + /* Did we fail because a child pager process has exited? */ + broken_pipe = (err < 0) && pager && (errno == EPIPE); + + va_end(ap); + + /* + * On error, we simply issue the error without cleaning up + * the pager process. The message code handles that as a standard + * part of error processing. + * + * We handle failure due to an exited pager process differently + * than a normal error, because it is usually due to the user + * intentionally telling it to. + */ + if (err < 0) { + if (broken_pipe) + elfedit_msg(ELFEDIT_MSG_QUIET, MSG_ORIG(MSG_STR_NULL)); + else + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_PRINTF)); + } +} + + +/* + * Write raw bytes of text in a manner similar to fwrite(). + * Uses the pager process if one has been started, or + * stdout otherwise. + */ +void +elfedit_write(const void *ptr, size_t size) +{ + FILE *fptr; + int err; + + /* + * If there is a pager process, then use it. Otherwise write + * directly to stdout. + */ + fptr = (state.pager.fptr == NULL) ? stdout : state.pager.fptr; + + if (fwrite(ptr, 1, size, fptr) != size) { + err = errno; + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_FWRITE), + strerror(err)); + } +} + + +/* + * Wrappers on malloc() and realloc() that check the result for success + * and issue an error if not. The caller can use the result of these + * functions without checking for a NULL pointer, as we do not return to + * the caller in the failure case. + */ +void * +elfedit_malloc(const char *item_name, size_t size) +{ + void *m; + + m = malloc(size); + if (m == NULL) { + int err = errno; + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_MALLOC), + item_name, strerror(err)); + } + + return (m); +} + +void * +elfedit_realloc(const char *item_name, void *ptr, size_t size) +{ + void *m; + + m = realloc(ptr, size); + if (m == NULL) { + int err = errno; + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_MALLOC), + item_name, strerror(err)); + } + + return (m); +} + + +/* + * Ensure that the given buffer has room for n bytes of data. + */ +static void +strbuf_ensure_size(STRBUF *str, size_t size) +{ +#define INITIAL_STR_ALLOC 128 + + size_t n; + + n = (str->n == 0) ? INITIAL_STR_ALLOC : str->n; + while (size > n) /* Double buffer until string fits */ + n *= 2; + if (n != str->n) { /* Alloc new string buffer if needed */ + str->buf = elfedit_realloc(MSG_INTL(MSG_ALLOC_UCMDSTR), + str->buf, n); + str->n = n; + } + +#undef INITIAL_STR_ALLOC +} + + +/* + * Extract the argument/option information for the next item referenced + * by optarg, and advance the pointer to the next item. + * + * entry: + * optarg - Address of pointer to argument or option array + * item - Struct to be filled in. + * + * exit: + * The item block has been filled in with the information for + * the next item in the optarg array. *optarg has been advanced + * to the next item. + */ +void +elfedit_next_optarg(elfedit_cmd_optarg_t **optarg, elfedit_optarg_item_t *item) +{ + /* + * Array of inheritable options/arguments. Indexed by one less + * than the corresponding ELFEDIT_STDOA_ value. + */ + static const elfedit_optarg_item_t stdoa[] = { + /* ELFEDIT_STDOA_O */ + { MSG_ORIG(MSG_STR_MINUS_O), MSG_ORIG(MSG_STR_OUTSTYLE), + /* MSG_INTL(MSG_STDOA_OPTDESC_O) */ + (elfedit_i18nhdl_t)MSG_STDOA_OPTDESC_O, + ELFEDIT_CMDOA_F_VALUE }, + + /* ELFEDIT_STDOA_AND */ + { MSG_ORIG(MSG_STR_MINUS_AND), NULL, + /* MSG_INTL(MSG_STDOA_OPTDESC_AND) */ + (elfedit_i18nhdl_t)MSG_STDOA_OPTDESC_AND, 0 }, + + /* ELFEDIT_STDOA_CMP */ + { MSG_ORIG(MSG_STR_MINUS_CMP), NULL, + /* MSG_INTL(MSG_STDOA_OPTDESC_CMP) */ + (elfedit_i18nhdl_t)MSG_STDOA_OPTDESC_CMP, 0 }, + + /* ELFEDIT_STDOA_OR */ + { MSG_ORIG(MSG_STR_MINUS_OR), NULL, + /* MSG_INTL(MSG_STDOA_OPTDESC_OR) */ + (elfedit_i18nhdl_t)MSG_STDOA_OPTDESC_OR, 0 }, + }; + + elfedit_cmd_optarg_t *oa; + + + /* Grab first item, advance the callers pointer over it */ + oa = (*optarg)++; + + if (oa->oa_flags & ELFEDIT_CMDOA_F_INHERIT) { + /* Values are pre-chewed in the stdoa array above */ + *item = stdoa[((uintptr_t)oa->oa_name) - 1]; + + /* + * Set the inherited flag so that elfedit_optarg_helpstr() + * can tell who is responsible for translating the help string. + */ + item->oai_flags |= ELFEDIT_CMDOA_F_INHERIT; + } else { /* Non-inherited item */ + item->oai_name = oa->oa_name; + if ((oa->oa_flags & ELFEDIT_CMDOA_F_VALUE) != 0) { + item->oai_vname = oa[1].oa_name; + + /* Advance users pointer past value element */ + (*optarg)++; + } else { + item->oai_vname = NULL; + } + item->oai_help = oa->oa_help; + item->oai_flags = oa->oa_flags; + } + + /* + * The module determines the idmask and excmask fields whether + * or not inheritance is in play. + */ + item->oai_idmask = oa->oa_idmask; + item->oai_excmask = oa->oa_excmask; +} + + + +/* + * Return the help string for an option/argument item, as returned + * by elfedit_next_optarg(). This routine handles the details of + * knowing whether the string is provided by elfedit itself (inherited), + * or needs to be translated by the module. + */ +const char * +elfedit_optarg_helpstr(elfeditGC_module_t *mod, elfedit_optarg_item_t *item) +{ + /* + * The help string from an inherited item comes right out + * of the main elfedit string table. + */ + if (item->oai_flags & ELFEDIT_CMDOA_F_INHERIT) + return (MSG_INTL((Msg) item->oai_help)); + + /* + * If the string is defined by the module, then we need to + * have the module translate it for us. + */ + return ((* mod->mod_i18nhdl_to_str)(item->oai_help)); +} + + + +/* + * Used by usage_optarg() to insert a character into the output buffer, + * advancing the buffer pointer and current column, and reducing the + * amount of remaining space. + */ +static void +usage_optarg_insert_ch(int ch, char **cur, size_t *n, size_t *cur_col) +{ + + *(*cur)++ = ch; + **cur = '\0'; + (*n)--; + (*cur_col)++; +} + +/* + * Used by usage_optarg() to insert a string into the output + * buffer, advancing the buffer pointer and current column, and reducing + * the amount of remaining space. + */ +static void +usage_optarg_insert_str(char **cur, size_t *n, size_t *cur_col, + const char *format, ...) +{ + size_t len; + va_list args; + + va_start(args, format); + len = vsnprintf(*cur, *n, format, args); + va_end(args); + + *cur += len; + *n -= len; + *cur_col += len; +} +/* + * Used by usage_optarg() to insert an optarg item string into the output + * buffer, advancing the buffer pointer and current column, and reducing + * the amount of remaining space. + */ +static void +usage_optarg_insert_item(elfedit_optarg_item_t *item, char **cur, + size_t *n, size_t *cur_col) +{ + size_t len; + + if (item->oai_flags & ELFEDIT_CMDOA_F_VALUE) { + len = snprintf(*cur, *n, MSG_ORIG(MSG_STR_HLPOPTARG2), + item->oai_name, item->oai_vname); + } else { + len = snprintf(*cur, *n, MSG_ORIG(MSG_STR_HLPOPTARG), + item->oai_name); + } + *cur += len; + *n -= len; + *cur_col += len; +} + + + +/* + * Write the options/arguments to the usage string. + * + * entry: + * main_buf_n - Size of main buffer from which buf and buf_n are + * allocated. + * buf - Address of pointer to where next item is to be placed. + * buf_n - Address of count of remaining bytes in buffer + * buf_cur_col - Address of current output column for current line + * of generated string. + * optarg - Options list + * isopt - True if these are options, false for arguments. + * wrap_str - String to indent wrapped lines. If NULL, lines + * are not wrapped + */ +static void +usage_optarg(size_t main_buf_n, char **buf, size_t *buf_n, size_t *buf_cur_col, + elfedit_cmd_optarg_t *optarg, int isopt, const char *wrap_str) +{ + /* + * An option can be combined into a simple format if it lacks + * these flags and is only one character in length. + */ + static const elfedit_cmd_oa_flag_t exflags = + (ELFEDIT_CMDOA_F_VALUE | ELFEDIT_CMDOA_F_MULT); + + /* + * A static buffer, which is grown as needed to accomodate + * the maximum usage string seen. + */ + static STRBUF simple_str; + + char *cur = *buf; + size_t n = *buf_n; + size_t cur_col = *buf_cur_col; + int len; + int use_simple = 0; + elfedit_optarg_item_t item; + elfedit_cmd_oa_mask_t optmask = 0; + int use_bkt; + + /* + * If processing options, pull the 1-character ones that don't have + * an associated value and don't have any mutual exclusion issues into + * a single combination string to go at the beginning of the usage. + */ + if (isopt) { + elfedit_cmd_optarg_t *tmp_optarg = optarg; + char *s; + + /* + * The simple string is guaranteed to fit in the same + * amount of space reserved for the main buffer. + */ + strbuf_ensure_size(&simple_str, main_buf_n); + s = simple_str.buf; + *s++ = ' '; + *s++ = '['; + *s++ = '-'; + while (tmp_optarg->oa_name != NULL) { + elfedit_next_optarg(&tmp_optarg, &item); + if (((item.oai_flags & exflags) == 0) && + (item.oai_name[2] == '\0') && + (item.oai_excmask == 0)) { + optmask |= item.oai_idmask; + *s++ = item.oai_name[1]; + } + } + + /* + * If we found more than one, then finish the string and + * add it. Don't do this for a single option, because + * it looks better in that case if the option shows up + * in alphabetical order rather than being hoisted. + */ + use_simple = (s > (simple_str.buf + 4)); + if (use_simple) { + *s++ = ']'; + *s++ = '\0'; + usage_optarg_insert_str(&cur, &n, &cur_col, + MSG_ORIG(MSG_STR_HLPOPTARG), simple_str.buf); + } else { + /* Not using it, so reset the cumulative options mask */ + optmask = 0; + } + } + + while (optarg->oa_name != NULL) { + elfedit_next_optarg(&optarg, &item); + + if (isopt) { + /* + * If this is an option that was pulled into the + * combination string above, then skip over it. + */ + if (use_simple && ((item.oai_flags & exflags) == 0) && + (item.oai_name[2] == '\0') && + (item.oai_excmask == 0)) + continue; + + /* + * If this is a mutual exclusion option that was + * picked up out of order by a previous iteration + * of this loop, then skip over it. + */ + if ((optmask & item.oai_idmask) != 0) + continue; + + /* Add this item to the accumulating options mask */ + optmask |= item.oai_idmask; + } + + /* Wrap line, or insert blank separator */ + if ((wrap_str != NULL) && (cur_col > USAGE_WRAP_COL)) { + len = snprintf(cur, n, MSG_ORIG(MSG_FMT_WRAPUSAGE), + wrap_str); + cur += len; + n -= len; + cur_col = len - 1; /* Don't count the newline */ + } else { + usage_optarg_insert_ch(' ', &cur, &n, &cur_col); + } + + use_bkt = (item.oai_flags & ELFEDIT_CMDOA_F_OPT) || isopt; + if (use_bkt) + usage_optarg_insert_ch('[', &cur, &n, &cur_col); + + /* Add the item to the buffer */ + usage_optarg_insert_item(&item, &cur, &n, &cur_col); + + /* + * If this item has a non-zero mutual exclusion mask, + * then look for the other items and display them all + * together with alternation (|). Note that plain arguments + * cannot have a non-0 exclusion mask, so this is + * effectively options-only (isopt != 0). + */ + if (item.oai_excmask != 0) { + elfedit_cmd_optarg_t *tmp_optarg = optarg; + elfedit_optarg_item_t tmp_item; + + /* + * When showing alternation, elipses for multiple + * copies need to appear inside the [] brackets. + */ + if (item.oai_flags & ELFEDIT_CMDOA_F_MULT) + usage_optarg_insert_str(&cur, &n, &cur_col, + MSG_ORIG(MSG_STR_ELIPSES)); + + + while (tmp_optarg->oa_name != NULL) { + elfedit_next_optarg(&tmp_optarg, &tmp_item); + if ((item.oai_excmask & tmp_item.oai_idmask) == + 0) + continue; + usage_optarg_insert_str(&cur, &n, &cur_col, + MSG_ORIG(MSG_STR_SP_BAR_SP)); + usage_optarg_insert_item(&tmp_item, + &cur, &n, &cur_col); + + /* + * Add it to the mask of seen options. + * This will keep us from showing it twice. + */ + optmask |= tmp_item.oai_idmask; + } + } + if (use_bkt) + usage_optarg_insert_ch(']', &cur, &n, &cur_col); + + /* + * If alternation was not shown above (non-zero exclusion mask) + * then the elipses for multiple copies are shown outside + * any [] brackets. + */ + if ((item.oai_excmask == 0) && + (item.oai_flags & ELFEDIT_CMDOA_F_MULT)) + usage_optarg_insert_str(&cur, &n, &cur_col, + MSG_ORIG(MSG_STR_ELIPSES)); + + } + + *buf = cur; + *buf_n = n; + *buf_cur_col = cur_col; +} + + + +/* + * Format the usage string for a command into a static buffer and + * return the pointer to the user. The resultant string is valid + * until the next call to this routine, and which point it + * will be overwritten or the memory is freed. + * + * entry: + * mod, cmd - Module and command definitions for command to be described + * wrap_str - NULL, or string to be used to indent when + * lines are wrapped. If NULL, no wrapping is done, and + * all output is on a single line. + * cur_col - Starting column at which the string will be displayed. + * Ignored if wrap_str is NULL. + */ +const char * +elfedit_format_command_usage(elfeditGC_module_t *mod, elfeditGC_cmd_t *cmd, + const char *wrap_str, size_t cur_col) +{ + + /* + * A static buffer, which is grown as needed to accomodate + * the maximum usage string seen. + */ + static STRBUF str; + + elfedit_cmd_optarg_t *optarg; + size_t len, n, elipses_len; + char *cur; + elfedit_optarg_item_t item; + + /* + * Estimate a worst case size for the usage string: + * - module name + * - lengths of the strings + * - every option or argument is enclosed in brackets + * - space in between each item, with an alternation (" | ") + * - elipses will be displayed with each option and argument + */ + n = strlen(mod->mod_name) + strlen(cmd->cmd_name[0]) + 6; + elipses_len = strlen(MSG_ORIG(MSG_STR_ELIPSES)); + if ((optarg = cmd->cmd_opt) != NULL) + while (optarg->oa_name != NULL) { + elfedit_next_optarg(&optarg, &item); + n += strlen(item.oai_name) + 5 + elipses_len; + } + if ((optarg = cmd->cmd_args) != NULL) + while (optarg->oa_name != NULL) { + elfedit_next_optarg(&optarg, &item); + n += strlen(item.oai_name) + 5 + elipses_len; + } + n++; /* Null termination */ + + /* + * If wrapping lines, we insert a newline and then wrap_str + * every USAGE_WRAP_COL characters. + */ + if (wrap_str != NULL) + n += ((n + USAGE_WRAP_COL) / USAGE_WRAP_COL) * + (strlen(wrap_str) + 1); + + strbuf_ensure_size(&str, n); + + /* Command name */ + cur = str.buf; + n = str.n; + if (strcmp(mod->mod_name, MSG_ORIG(MSG_MOD_SYS)) == 0) + len = snprintf(cur, n, MSG_ORIG(MSG_FMT_SYSCMD), + cmd->cmd_name[0]); + else + len = snprintf(cur, n, MSG_ORIG(MSG_FMT_MODCMD), + mod->mod_name, cmd->cmd_name[0]); + cur += len; + n -= len; + cur_col += len; + + if (cmd->cmd_opt != NULL) + usage_optarg(str.n, &cur, &n, &cur_col, cmd->cmd_opt, + 1, wrap_str); + if (cmd->cmd_args != NULL) + usage_optarg(str.n, &cur, &n, &cur_col, cmd->cmd_args, + 0, wrap_str); + + return (str.buf); +} + +/* + * Wrapper on elfedit_msg() that issues an ELFEDIT_MSG_USAGE + * error giving usage information for the command currently + * referenced by state.cur_cmd. + */ +void +elfedit_command_usage(void) +{ + elfedit_msg(ELFEDIT_MSG_CMDUSAGE, MSG_INTL(MSG_USAGE_CMD), + elfedit_format_command_usage(state.cur_cmd->ucmd_mod, + state.cur_cmd->ucmd_cmd, NULL, 0)); +} + + +/* + * This function allows the loadable modules to get the command line + * flags. + */ +elfedit_flag_t +elfedit_flags(void) +{ + return (state.flags); +} + +/* + * This function is used to register a per-command invocation output style + * that will momentarily override the global output style for the duration + * of the current command. This function must only be called by an + * active command. + * + * entry: + * str - One of the valid strings for the output style + */ +void +elfedit_set_cmd_outstyle(const char *str) +{ + if ((state.cur_cmd != NULL) && (str != NULL)) { + if (elfedit_atooutstyle(str, &state.cur_cmd->ucmd_ostyle) == 0) + elfedit_msg(ELFEDIT_MSG_ERR, + MSG_INTL(MSG_ERR_BADOSTYLE), str); + state.cur_cmd->ucmd_ostyle_set = 1; + } +} + +/* + * This function allows the loadable modules to get the output style. + */ +elfedit_outstyle_t +elfedit_outstyle(void) +{ + /* + * If there is an active per-command output style, + * return it. + */ + if ((state.cur_cmd != NULL) && (state.cur_cmd->ucmd_ostyle_set)) + return (state.cur_cmd->ucmd_ostyle); + + + return (state.outstyle); +} + +/* + * Return the command descriptor of the currently executing command. + * For use only by the modules or code called by the modules. + */ +elfeditGC_cmd_t * +elfedit_curcmd(void) +{ + return (state.cur_cmd->ucmd_cmd); +} + +/* + * Build a dynamically allocated elfedit_obj_state_t struct that + * contains a cache of the ELF file contents. This pre-chewed form + * is fed to each command, reducing the amount of ELF boilerplate + * code each command needs to contain. + * + * entry: + * file - Name of file to process + * + * exit: + * Fills state.elf with the necessary information for the open file. + * + * note: The resulting elfedit_obj_state_t is allocated from a single + * piece of memory, such that a single call to free() suffices + * to release it as well as any memory it references. + */ +static void +init_obj_state(const char *file) +{ + int fd; + Elf *elf; + int open_flag; + + /* + * In readonly mode, we open the file readonly so that it is + * impossible to modify the file by accident. This also allows + * us to access readonly files, perhaps in a case where we don't + * intend to change it. + * + * We always use ELF_C_RDWR with elf_begin(), even in a readonly + * session. This allows us to modify the in-memory image, which + * can be useful when examining a file, even though we don't intend + * to modify the on-disk data. The file is not writable in + * this case, and we don't call elf_update(), so it is safe to do so. + */ + open_flag = ((state.flags & ELFEDIT_F_READONLY) ? O_RDONLY : O_RDWR); + if ((fd = open(file, open_flag)) == -1) { + int err = errno; + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_CNTOPNFILE), + file, strerror(err)); + } + (void) elf_version(EV_CURRENT); + elf = elf_begin(fd, ELF_C_RDWR, NULL); + if (elf == NULL) { + (void) close(fd); + elfedit_elferr(file, MSG_ORIG(MSG_ELF_BEGIN)); + /*NOTREACHED*/ + } + + /* We only handle standalone ELF files */ + switch (elf_kind(elf)) { + case ELF_K_AR: + (void) close(fd); + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOAR), file); + break; + case ELF_K_ELF: + break; + default: + (void) close(fd); + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_UNRECELFFILE), + file); + break; + } + + /* + * Tell libelf that we take responsibility for object layout. + * Otherwise, it will compute "proper" values for layout and + * alignment fields, and these values can overwrite the values + * set in the elfedit session. We are modifying existing + * objects --- the layout concerns have already been dealt + * with when the object was built. + */ + (void) elf_flagelf(elf, ELF_C_SET, ELF_F_LAYOUT); + + /* Fill in state.elf.obj_state */ + state.elf.elfclass = gelf_getclass(elf); + switch (state.elf.elfclass) { + case ELFCLASS32: + elfedit32_init_obj_state(file, fd, elf); + break; + case ELFCLASS64: + elfedit64_init_obj_state(file, fd, elf); + break; + default: + (void) close(fd); + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADELFCLASS), + file); + break; + } +} + + +#if 0 +/* + * Debug routine. Dump the module list to stdout. + */ +static void +dbg_module_list(char *title) +{ + MODLIST_T *m; + + printf("<MODULE LIST: %s>\n", title); + for (m = state.modlist; m != NULL; m = m->next) { + printf("Module: >%s<\n", m->mod->mod_name); + printf(" hdl: %llx\n", m->dl_hdl); + printf(" path: >%s<\n", m->path ? m->path : "<builtin>"); + } + printf("<END OF MODULE LIST>\n"); +} +#endif + + +/* + * Search the module list for the named module. + * + * entry: + * name - Name of module to find + * insdef - Address of variable to receive address of predecessor + * node to the desired one. + * + * exit: + * If the module is it is found, this routine returns the pointer to + * its MODLIST_T structure. *insdef references the predecessor node, or + * is NULL if the found item is at the head of the list. + * + * If the module is not found, NULL is returned. *insdef references + * the predecessor node of the position where an entry for this module + * would be placed, or NULL if it would go at the beginning. + */ +static MODLIST_T * +module_loaded(const char *name, MODLIST_T **insdef) +{ + MODLIST_T *moddef; + int cmp; + + *insdef = NULL; + moddef = state.modlist; + if (moddef != NULL) { + cmp = strcasecmp(name, moddef->ml_mod->mod_name); + if (cmp == 0) { /* Desired module is first in list */ + return (moddef); + } else if (cmp > 0) { /* cmp > 0: Insert in middle/end */ + *insdef = moddef; + moddef = moddef->ml_next; + cmp = -1; + while (moddef && (cmp < 0)) { + cmp = strcasecmp(moddef->ml_mod->mod_name, + name); + if (cmp == 0) + return (moddef); + if (cmp < 0) { + *insdef = moddef; + moddef = (*insdef)->ml_next; + } + } + } + } + + return (NULL); +} + + +/* + * Determine if a file is a sharable object based on its file path. + * If path ends in a .so, followed optionally by a period and 1 or more + * digits, we say that it is and return a pointer to the first character + * of the suffix. Otherwise NULL is returned. + */ +static const char * +path_is_so(const char *path) +{ + int dotso_len; + const char *tail; + size_t len; + + len = strlen(path); + if (len == 0) + return (NULL); + tail = path + len; + if (isdigit(*(tail - 1))) { + while ((tail > path) && isdigit(*(tail - 1))) + tail--; + if ((tail <= path) || (*tail != '.')) + return (NULL); + } + dotso_len = strlen(MSG_ORIG(MSG_STR_DOTSO)); + if ((tail - path) < dotso_len) + return (NULL); + tail -= dotso_len; + if (strncmp(tail, MSG_ORIG(MSG_STR_DOTSO), dotso_len) == 0) + return (tail); + + return (NULL); +} + + +/* + * Locate the start of the unsuffixed file name within path. Returns pointer + * to first character of that name in path. + * + * entry: + * path - Path to be examined. + * tail - NULL, or pointer to position at tail of path from which + * the search for '/' characters should start. If NULL, + * strlen() is used to locate the end of the string. + * buf - NULL, or buffer to receive a copy of the characters that + * lie between the start of the filename and tail. + * bufsize - sizeof(buf) + * + * exit: + * The pointer to the first character of the unsuffixed file name + * within path is returned. If buf is non-NULL, the characters + * lying between that point and tail (or the end of path if tail + * is NULL) are copied into buf. + */ +static const char * +elfedit_basename(const char *path, const char *tail, char *buf, size_t bufsiz) +{ + const char *s; + + if (tail == NULL) + tail = path + strlen(path); + s = tail; + while ((s > path) && (*(s - 1) != '/')) + s--; + if (buf != NULL) + elfedit_strnbcpy(buf, s, tail - s, bufsiz); + return (s); +} + + +/* + * Issue an error on behalf of load_module(), taking care to release + * resources that routine may have aquired: + * + * entry: + * moddef - NULL, or a module definition to be released via free() + * dl_hdl - NULL, or a handle to a sharable object to release via + * dlclose(). + * dl_path - If dl_hdl is non-NULL, the path to the sharable object + * file that was loaded. + * format - A format string to pass to elfedit_msg(), containing + * no more than (3) %s format codes, and no other format codes. + * [s1-s4] - Strings to pass to elfedit_msg() to satisfy the four + * allowed %s codes in format. Should be set to NULL if the + * format string does not need them. + * + * note: + * This routine makes a copy of the s1-s4 strings before freeing any + * memory or unmapping the sharable library. It is therefore safe to + * use strings from moddef, or from the sharable library (which will + * be unmapped) to satisfy the other arguments s1-s4. + */ +static void +load_module_err(MODLIST_T *moddef, void *dl_hdl, const char *dl_path, + const char *format, const char *s1, const char *s2, const char *s3, + const char *s4) +{ +#define SCRBUFSIZE (PATH_MAX + 256) /* A path, plus some extra */ + + char s1_buf[SCRBUFSIZE]; + char s2_buf[SCRBUFSIZE]; + char s3_buf[SCRBUFSIZE]; + char s4_buf[SCRBUFSIZE]; + + /* + * The caller may provide strings for s1-s3 that are from + * moddef. If we free moddef, the printf() will die on access + * to free memory. We could push back on the user and force + * each call to carefully make copies of such data. However, this + * is an easy case to miss. Furthermore, this is an error case, + * and machine efficiency is not the main issue. We therefore make + * copies of the s1-s3 strings here into auto variables, and then + * use those copies. The user is freed from worrying about it. + * + * We use oversized stack based buffers instead of malloc() to + * reduce the number of ways that things can go wrong while + * reporting the error. + */ + if (s1 != NULL) + (void) strlcpy(s1_buf, s1, sizeof (s1_buf)); + if (s2 != NULL) + (void) strlcpy(s2_buf, s2, sizeof (s2_buf)); + if (s3 != NULL) + (void) strlcpy(s3_buf, s3, sizeof (s3_buf)); + if (s4 != NULL) + (void) strlcpy(s4_buf, s4, sizeof (s4_buf)); + + + if (moddef != NULL) + free(moddef); + + if ((dl_hdl != NULL) && (dlclose(dl_hdl) != 0)) + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_CNTDLCLOSE), + dl_path, dlerror()); + + elfedit_msg(ELFEDIT_MSG_ERR, format, s1_buf, s2_buf, s3_buf, s4_buf); +#undef SCRBUFSIZE +} + + +/* + * Load a module sharable object for load_module(). + * + * entry: + * path - Path of file to open + * moddef - If this function issues a non-returning error, it will + * first return the memory referenced by moddef. This argument + * is not used otherwise. + * must_exist - If True, we consider it to be an error if the file given + * by path does not exist. If False, no error is issued + * and a NULL value is quietly returned. + * + * exit: + * Returns a handle to the loaded object on success, or NULL if no + * file was loaded. + */ +static void * +load_module_dlopen(const char *path, MODLIST_T *moddef, int must_exist) +{ + int fd; + void *hdl; + + /* + * If the file is not required to exist, and it doesn't, then + * we want to quietly return without an error. + */ + if (!must_exist) { + fd = open(path, O_RDONLY); + if (fd >= 0) { + (void) close(fd); + } else if (errno == ENOENT) { + return (NULL); + } + } + + if ((hdl = dlopen(path, RTLD_LAZY|RTLD_FIRST)) == NULL) + load_module_err(moddef, NULL, NULL, + MSG_INTL(MSG_ERR_CNTDLOPEN), path, dlerror(), NULL, NULL); + + return (hdl); +} + + +/* + * Sanity check option arguments to prevent common errors. The rest of + * elfedit assumes these tests have been done, and does not check + * again. + */ +static void +validate_optarg(elfedit_cmd_optarg_t *optarg, int isopt, MODLIST_T *moddef, + const char *mod_name, const char *cmd_name, + void *dl_hdl, const char *dl_path) +{ +#define FAIL(_msg) errmsg = _msg; goto fail + + Msg errmsg; + elfedit_cmd_oa_mask_t optmask = 0; + + for (; optarg->oa_name != NULL; optarg++) { + /* + * If ELFEDIT_CMDOA_F_INHERIT is set: + * - oa_name must be a value in the range of + * known ELFEDIT_STDOA_ values. + * - oa_help must be NULL + * - ELFEDIT_CMDOA_F_INHERIT must be the only flag set + */ + if (optarg->oa_flags & ELFEDIT_CMDOA_F_INHERIT) { + if ((((uintptr_t)optarg->oa_name) > + ELFEDIT_NUM_STDOA) || + (optarg->oa_help != 0) || + (optarg->oa_flags != ELFEDIT_CMDOA_F_INHERIT)) + /* + * Can't use FAIL --- oa_name is not a valid + * string, and load_module_err() looks at args. + */ + load_module_err(moddef, dl_hdl, dl_path, + MSG_INTL(MSG_ERR_BADSTDOA), dl_path, + mod_name, cmd_name, NULL); + continue; + } + + if (isopt) { + /* + * Option name must start with a '-', and must + * have at one following character. + */ + if (optarg->oa_name[0] != '-') { + /* MSG_INTL(MSG_ERR_OPT_MODPRE) */ + FAIL(MSG_ERR_OPT_MODPRE); + } + if (optarg->oa_name[1] == '\0') { + /* MSG_INTL(MSG_ERR_OPT_MODLEN) */ + FAIL(MSG_ERR_OPT_MODLEN); + } + + /* + * oa_idmask must be 0, or it must have a single + * bit set (a power of 2).oa_excmask must be 0 + * if oa_idmask is 0 + */ + if (optarg->oa_idmask == 0) { + if (optarg->oa_excmask != 0) { + /* MSG_INTL(MSG_ERR_OPT_EXCMASKN0) */ + FAIL(MSG_ERR_OPT_EXCMASKN0); + } + } else { + if (elfedit_bits_set(optarg->oa_idmask, + sizeof (optarg->oa_idmask)) != 1) { + /* MSG_INTL(MSG_ERR_OPT_IDMASKPOW2) */ + FAIL(MSG_ERR_OPT_IDMASKPOW2); + } + + /* Non-zero idmask must be unique */ + if ((optarg->oa_idmask & optmask) != 0) { + /* MSG_INTL(MSG_ERR_OPT_IDMASKUNIQ) */ + FAIL(MSG_ERR_OPT_IDMASKUNIQ); + } + + /* Add this one to the overall mask */ + optmask |= optarg->oa_idmask; + } + } else { + /* + * Argument name cannot start with a'-', and must + * not be a null string. + */ + if (optarg->oa_name[0] == '-') { + /* MSG_INTL(MSG_ERR_ARG_MODPRE) */ + FAIL(MSG_ERR_ARG_MODPRE); + } + if (optarg->oa_name[1] == '\0') { + /* MSG_INTL(MSG_ERR_ARG_MODLEN) */ + FAIL(MSG_ERR_ARG_MODLEN); + } + + + /* oa_idmask and oa_excmask must both be 0 */ + if ((optarg->oa_idmask != 0) || + (optarg->oa_excmask != 0)) { + /* MSG_INTL(MSG_ERR_ARG_MASKNOT0) */ + FAIL(MSG_ERR_ARG_MASKNOT0); + } + + } + + /* + * If it takes a value, make sure that we are + * processing options, because CMDOA_F_VALUE is not + * allowed for plain arguments. Then check the following + * item in the list: + * - There must be a following item. + * - oa_name must be non-NULL. This is the only field + * that is used by elfedit. + * - oa_help, oa_flags, oa_idmask, and oa_excmask + * must be 0. + */ + if (optarg->oa_flags & ELFEDIT_CMDOA_F_VALUE) { + elfedit_cmd_optarg_t *oa1 = optarg + 1; + + if (!isopt) { + /* MSG_INTL(MSG_ERR_ARG_CMDOA_VAL) */ + FAIL(MSG_ERR_ARG_CMDOA_VAL); + } + + if ((optarg + 1)->oa_name == NULL) { + /* MSG_INTL(MSG_ERR_BADMODOPTVAL) */ + FAIL(MSG_ERR_BADMODOPTVAL); + } + + if (oa1->oa_name == NULL) { + /* MSG_INTL(MSG_ERR_CMDOA_VALNAM) */ + FAIL(MSG_ERR_CMDOA_VALNAM); + } + if ((oa1->oa_help != NULL) || (oa1->oa_flags != 0) || + (oa1->oa_idmask != 0) || (oa1->oa_excmask != 0)) { + /* MSG_INTL(MSG_ERR_CMDOA_VALNOT0) */ + FAIL(MSG_ERR_CMDOA_VALNOT0); + } + optarg++; + } + } + + + return; + +fail: + load_module_err(moddef, dl_hdl, dl_path, MSG_INTL(errmsg), + dl_path, mod_name, cmd_name, optarg->oa_name); +} + +/* + * Look up the specified module, loading the module if necessary, + * and return its definition, or NULL on failure. + * + * entry: + * name - Name of module to load. If name contains a '/' character or has + * a ".so" suffix, then it is taken to be an absolute file path, + * and is used directly as is. If name does not contain a '/' + * character, then we look for it against the locations in + * the module path, addint the '.so' suffix, and taking the first + * one we find. + * must_exist - If True, we consider it to be an error if we are unable + * to locate a file to load and the module does not already exist. + * If False, NULL is returned quietly in this case. + * allow_abs - True if absolute paths are allowed. False to disallow + * them. + * + * note: + * If the path is absolute, then we load the file and take the module + * name from the data returned by its elfedit_init() function. If a + * module of that name is already loaded, it is unloaded and replaced + * with the new one. + * + * If the path is non absolute, then we check to see if the module has + * already been loaded, and if so, we return that module definition. + * In this case, nothing new is loaded. If the module has not been loaded, + * we search the path for it and load it. If the module name provided + * by the elfedit_init() function does not match the name of the file, + * an error results. + */ +elfeditGC_module_t * +elfedit_load_module(const char *name, int must_exist, int allow_abs) +{ + elfedit_init_func_t *init_func; + elfeditGC_module_t *mod; + MODLIST_T *moddef, *insdef; + const char *path; + char path_buf[PATH_MAX + 1]; + void *hdl; + size_t i; + int is_abs_path; + elfeditGC_cmd_t *cmd; + + /* + * If the name includes a .so suffix, or has any '/' characters, + * then it is an absolute path that we use as is to load the named + * file. Otherwise, we iterate over the path, adding the .so suffix + * and load the first file that matches. + */ + is_abs_path = (path_is_so(name) != NULL) || + (name != elfedit_basename(name, NULL, NULL, 0)); + + if (is_abs_path && !allow_abs) + load_module_err(NULL, NULL, NULL, + MSG_INTL(MSG_ERR_UNRECMOD), name, NULL, NULL, NULL); + + /* + * If this is a non-absolute path, search for the module already + * having been loaded, and return it if so. + */ + if (!is_abs_path) { + moddef = module_loaded(name, &insdef); + if (moddef != NULL) + return (moddef->ml_mod); + /* + * As a result of module_loaded(), insdef now contains the + * immediate predecessor node for the new one, or NULL if + * it goes at the front. In the absolute-path case, we take + * care of this below, after the sharable object is loaded. + */ + } + + /* + * malloc() a module definition block before trying to dlopen(). + * Doing things in the other order can cause the dlopen()'d object + * to leak: If elfedit_malloc() fails, it can cause a jump to the + * outer command loop without returning to the caller. Hence, + * there will be no opportunity to clean up. Allocaing the module + * first allows us to free it if necessary. + */ + moddef = elfedit_malloc(MSG_INTL(MSG_ALLOC_MODDEF), + sizeof (*moddef) + PATH_MAX + 1); + moddef->ml_path = ((char *)moddef) + sizeof (*moddef); + + if (is_abs_path) { + path = name; + hdl = load_module_dlopen(name, moddef, must_exist); + } else { + hdl = NULL; + path = path_buf; + for (i = 0; i < state.modpath.n; i++) { + if (snprintf(path_buf, sizeof (path_buf), + MSG_ORIG(MSG_FMT_BLDSOPATH), state.modpath.seg[i], + name) > sizeof (path_buf)) + load_module_err(moddef, NULL, NULL, + MSG_INTL(MSG_ERR_PATHTOOLONG), + state.modpath.seg[i], name, NULL, NULL); + hdl = load_module_dlopen(path, moddef, 0); + } + if (must_exist && (hdl == NULL)) + load_module_err(moddef, NULL, NULL, + MSG_INTL(MSG_ERR_UNRECMOD), name, NULL, NULL, NULL); + } + + if (hdl == NULL) { + free(moddef); + return (NULL); + } + + if (state.elf.elfclass == ELFCLASS32) { + init_func = (elfedit_init_func_t *) + dlsym(hdl, MSG_ORIG(MSG_STR_ELFEDITINIT32)); + } else { + init_func = (elfedit_init_func_t *) + dlsym(hdl, MSG_ORIG(MSG_STR_ELFEDITINIT64)); + } + if (init_func == NULL) + load_module_err(moddef, hdl, path, + MSG_INTL(MSG_ERR_SONOTMOD), path, NULL, NULL, NULL); + + /* + * Note that the init function will be passing us an + * elfedit[32|64]_module_t pointer, which we cast to the + * generic module pointer type in order to be able to manage + * either type with one set of code. + */ + if (!(mod = (elfeditGC_module_t *)(* init_func)(ELFEDIT_VER_CURRENT))) + load_module_err(moddef, hdl, path, + MSG_INTL(MSG_ERR_BADMODLOAD), path, NULL, NULL, NULL); + + /* + * Enforce some rules, to help module developers: + * - The primary name of a command must not be + * the empty string (""). + * - Options must start with a '-' followed by at least + * one character. + * - Arguments and options must be well formed. + */ + for (cmd = mod->mod_cmds; cmd->cmd_func != NULL; cmd++) { + if (**cmd->cmd_name == '\0') + load_module_err(moddef, hdl, path, + MSG_INTL(MSG_ERR_NULLPRICMDNAM), mod->mod_name, + NULL, NULL, NULL); + + if (cmd->cmd_args != NULL) + validate_optarg(cmd->cmd_args, 0, moddef, mod->mod_name, + cmd->cmd_name[0], hdl, path); + if (cmd->cmd_opt != NULL) + validate_optarg(cmd->cmd_opt, 1, moddef, mod->mod_name, + cmd->cmd_name[0], hdl, path); + } + + /* + * Check the name the module provides. How we handle this depends + * on whether the path is absolute or the result of a path search. + */ + if (is_abs_path) { + MODLIST_T *old_moddef = module_loaded(mod->mod_name, &insdef); + + if (old_moddef != NULL) { /* Replace existing */ + free(moddef); /* Rare case: Don't need it */ + /* + * Be sure we don't unload builtin modules! + * These have a NULL dl_hdl field. + */ + if (old_moddef->ml_dl_hdl == NULL) + load_module_err(NULL, hdl, path, + MSG_INTL(MSG_ERR_CNTULSMOD), + old_moddef->ml_mod->mod_name, NULL, + NULL, NULL); + + /* Unload existing */ + if (dlclose(old_moddef->ml_dl_hdl) != 0) + elfedit_msg(ELFEDIT_MSG_ERR, + MSG_INTL(MSG_ERR_CNTDLCLOSE), + old_moddef->ml_path, dlerror()); + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_MODUNLOAD), + old_moddef->ml_mod->mod_name, old_moddef->ml_path); + old_moddef->ml_mod = mod; + old_moddef->ml_dl_hdl = hdl; + (void) strlcpy((char *)old_moddef->ml_path, path, + PATH_MAX + 1); + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_MODLOAD), + old_moddef->ml_mod->mod_name, path); + return (old_moddef->ml_mod); + } + /* + * insdef now contains the insertion point for the absolute + * path case. + */ + } else { + /* If the names don't match, then error */ + if (strcasecmp(name, mod->mod_name) != 0) + load_module_err(moddef, hdl, path, + MSG_INTL(MSG_ERR_BADMODNAME), + mod->mod_name, name, path, NULL); + } + + /* + * Link module into the module list. If insdef is NULL, + * it goes at the head. If insdef is non-NULL, it goes immediately + * after + */ + if (insdef == NULL) { + moddef->ml_next = state.modlist; + state.modlist = moddef; + } else { + moddef->ml_next = insdef->ml_next; + insdef->ml_next = moddef; + } + moddef->ml_mod = mod; + moddef->ml_dl_hdl = hdl; + (void) strlcpy((char *)moddef->ml_path, path, PATH_MAX + 1); + + elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_MODLOAD), + moddef->ml_mod->mod_name, path); + + return (moddef->ml_mod); +} + + +/* + * Unload the specified module + */ +void +elfedit_unload_module(const char *name) +{ + MODLIST_T *moddef, *insdef; + + moddef = module_loaded(name, &insdef); + if (moddef == NULL) + return; + + /* Built in modules cannot be unloaded. They have a NULL dl_hdl field */ + if (moddef->ml_dl_hdl == NULL) + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_CNTULSMOD), + moddef->ml_mod->mod_name); + + /* + * When we unload it, the name string goes with it. So + * announce it while we still can without having to make a copy. + */ + elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_MODUNLOAD), + moddef->ml_mod->mod_name, moddef->ml_path); + + /* + * Close it before going further. On failure, we'll jump, and the + * record will remain in the module list. On success, + * we'll retain control, and can safely remove it. + */ + if (dlclose(moddef->ml_dl_hdl) != 0) + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_CNTDLCLOSE), + moddef->ml_path, dlerror()); + + /* Unlink the record from the module list */ + if (insdef == NULL) + state.modlist = moddef->ml_next; + else + insdef->ml_next = moddef->ml_next; + + /* Release the memory */ + free(moddef); +} + + +/* + * Load all sharable objects found in the specified directory. + * + * entry: + * dirpath - Path of directory to process. + * must_exist - If True, it is an error if diropen() fails to open + * the given directory. Of False, we quietly ignore it and return. + * abs_path - If True, files are loaded using their literal paths. + * If False, their module name is extracted from the dirpath + * and a path based search is used to locate it. + */ +void +elfedit_load_moddir(const char *dirpath, int must_exist, int abs_path) +{ + char path[PATH_MAX + 1]; + DIR *dir; + struct dirent *dp; + const char *tail; + + dir = opendir(dirpath); + if (dir == NULL) { + int err = errno; + + if (!must_exist && (err == ENOENT)) + return; + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_CNTOPNDIR), + dirpath, strerror(err)); + /*NOTREACHED*/ + } + + while (dp = readdir(dir)) { + if ((tail = path_is_so(dp->d_name)) != NULL) { + if (abs_path) { + (void) snprintf(path, sizeof (path), + MSG_ORIG(MSG_FMT_BLDPATH), dirpath, + dp->d_name); + } else { + (void) elfedit_basename(dp->d_name, tail, + path, sizeof (path)); + } + (void) elfedit_load_module(path, must_exist, 1); + } + } + (void) closedir(dir); +} + + +/* + * Follow the module load path, and load the first module found for each + * given name. + */ +void +elfedit_load_modpath(void) +{ + size_t i; + + for (i = 0; i < state.modpath.n; i++) + elfedit_load_moddir(state.modpath.seg[i], 0, 0); +} + +/* + * Given a module definition, look for the specified command. + * Returns the command if found, and NULL otherwise. + */ +static elfeditGC_cmd_t * +find_cmd(elfeditGC_module_t *mod, const char *name) +{ + elfeditGC_cmd_t *cmd; + const char **cmd_name; + + for (cmd = mod->mod_cmds; cmd->cmd_func != NULL; cmd++) + for (cmd_name = cmd->cmd_name; *cmd_name; cmd_name++) + if (strcasecmp(name, *cmd_name) == 0) { + if (cmd_name != cmd->cmd_name) + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_CMDALIAS), + mod->mod_name, *cmd_name, + mod->mod_name, *cmd->cmd_name); + return (cmd); + } + + return (NULL); +} + + +/* + * Given a command name, return its command definition. + * + * entry: + * name - Command to be looked up + * must_exist - If True, we consider it to be an error if the command + * does not exist. If False, NULL is returned quietly in + * this case. + * mod_ret - NULL, or address of a variable to receive the + * module definition block of the module containing + * the command. + * + * exit: + * On success, returns a pointer to the command definition, and + * if mod_ret is non-NULL, *mod_ret receives a pointer to the + * module definition. On failure, must_exist determines the + * action taken: If must_exist is True, an error is issued and + * control does not return to the caller. If must_exist is False, + * NULL is quietly returned. + * + * note: + * A ':' in name is used to delimit the module and command names. + * If it is omitted, or if it is the first non-whitespace character + * in the name, then the built in sys: module is implied. + */ +elfeditGC_cmd_t * +elfedit_find_command(const char *name, int must_exist, + elfeditGC_module_t **mod_ret) +{ + elfeditGC_module_t *mod; + const char *mod_str; + const char *cmd_str; + char mod_buf[ELFEDIT_MAXMODNAM + 1]; + size_t n; + elfeditGC_cmd_t *cmd; + + + cmd_str = strstr(name, MSG_ORIG(MSG_STR_COLON)); + if (cmd_str == NULL) { /* No module name -> sys: */ + mod_str = MSG_ORIG(MSG_MOD_SYS); + cmd_str = name; + } else if (cmd_str == name) { /* Empty module name -> sys: */ + mod_str = MSG_ORIG(MSG_MOD_SYS); + cmd_str++; /* Skip the colon */ + } else { /* Have both module and command */ + n = cmd_str - name; + if (n >= sizeof (mod_buf)) { + if (must_exist) + elfedit_msg(ELFEDIT_MSG_ERR, + MSG_INTL(MSG_ERR_MODNAMTOOLONG), name); + return (NULL); + } + (void) strlcpy(mod_buf, name, n + 1); + mod_str = mod_buf; + cmd_str++; + } + + /* Lookup/load module. Won't return on error */ + mod = elfedit_load_module(mod_str, must_exist, 0); + if (mod == NULL) + return (NULL); + + /* Locate the command */ + cmd = find_cmd(mod, cmd_str); + if (cmd == NULL) { + if (must_exist) { + /* + * Catch empty command in order to provide + * a better error message. + */ + if (*cmd_str == '\0') { + elfedit_msg(ELFEDIT_MSG_ERR, + MSG_INTL(MSG_ERR_MODNOCMD), mod_str); + } else { + elfedit_msg(ELFEDIT_MSG_ERR, + MSG_INTL(MSG_ERR_UNRECCMD), + mod_str, cmd_str); + } + } + } else { + if (mod_ret != NULL) + *mod_ret = mod; + } + return (cmd); +} + + +/* + * Release all user command blocks found on state.ucmd + */ +static void +free_user_cmds(void) +{ + USER_CMD_T *next; + + while (state.ucmd.list) { + next = state.ucmd.list->ucmd_next; + free(state.ucmd.list); + state.ucmd.list = next; + } + state.ucmd.tail = NULL; + state.ucmd.n = 0; + state.cur_cmd = NULL; +} + + +/* + * Process all user command blocks found on state.ucmd, and then + * remove them from the list. + */ +static void +dispatch_user_cmds() +{ + USER_CMD_T *ucmd; + elfedit_cmdret_t cmd_ret; + + ucmd = state.ucmd.list; + if (ucmd) { + /* Do them, in order */ + for (; ucmd; ucmd = ucmd->ucmd_next) { + state.cur_cmd = ucmd; + if (!state.msg_jbuf.active) + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_EXECCMD), + ucmd->ucmd_orig_str); + /* + * The cmd_func field is the generic definition. + * We need to cast it to the type that matches + * the proper ELFCLASS before calling it. + */ + if (state.elf.elfclass == ELFCLASS32) { + elfedit32_cmd_func_t *cmd_func = + (elfedit32_cmd_func_t *) + ucmd->ucmd_cmd->cmd_func; + + cmd_ret = (* cmd_func)(state.elf.obj_state.s32, + ucmd->ucmd_argc, ucmd->ucmd_argv); + } else { + elfedit64_cmd_func_t *cmd_func = + (elfedit64_cmd_func_t *) + ucmd->ucmd_cmd->cmd_func; + + cmd_ret = (* cmd_func)(state.elf.obj_state.s64, + ucmd->ucmd_argc, ucmd->ucmd_argv); + } + state.cur_cmd = NULL; + /* If a pager was started, wrap it up */ + elfedit_pager_cleanup(); + + switch (cmd_ret) { + case ELFEDIT_CMDRET_MOD: + /* + * Command modified the output ELF image, + * mark the file as needing a flush to disk. + */ + state.file.dirty = 1; + break; + case ELFEDIT_CMDRET_FLUSH: + /* + * Command flushed the output file, + * clear the dirty bit. + */ + state.file.dirty = 0; + } + } + free_user_cmds(); + } +} + + +/* + * Prepare a GETTOK_STATE struct for gettok(). + * + * entry: + * gettok_state - gettok state block to use + * str - Writable buffer to tokenize. Note that gettok() + * is allowed to change the contents of this buffer. + * inc_null_final - If the line ends in whitespace instead of + * immediately hitting a NULL, and inc_null_final is TRUE, + * then a null final token is generated. Otherwise trailing + * whitespace is ignored. + */ +static void +gettok_init(GETTOK_STATE *gettok_state, char *buf, int inc_null_final) +{ + gettok_state->gtok_buf = gettok_state->gtok_cur_buf = buf; + gettok_state->gtok_inc_null_final = inc_null_final; + gettok_state->gtok_null_seen = 0; +} + + +/* + * Locate the next token from the buffer. + * + * entry: + * gettok_state - State of gettok() operation. Initialized + * by gettok_init(), and passed to gettok(). + * + * exit: + * If a token is found, gettok_state->gtok_last_token is filled in + * with the details and True (1) is returned. If no token is found, + * False (1) is returned, and the contents of + * gettok_state->gtok_last_token are undefined. + * + * note: + * - The token returned references the memory in gettok_state->gtok_buf. + * The caller should not modify the buffer until all such + * pointers have been discarded. + * - This routine will modify the contents of gettok_state->gtok_buf + * as necessary to remove quotes and eliminate escape + * (\)characters. + */ +static int +gettok(GETTOK_STATE *gettok_state) +{ + char *str = gettok_state->gtok_cur_buf; + char *look; + int quote_ch = '\0'; + + /* Skip leading whitespace */ + while (isspace(*str)) + str++; + + if (*str == '\0') { + /* + * If user requested it, and there was whitespace at the + * end, then generate one last null token. + */ + if (gettok_state->gtok_inc_null_final && + !gettok_state->gtok_null_seen) { + gettok_state->gtok_inc_null_final = 0; + gettok_state->gtok_null_seen = 1; + gettok_state->gtok_last_token.tok_str = str; + gettok_state->gtok_last_token.tok_len = 0; + gettok_state->gtok_last_token.tok_line_off = + str - gettok_state->gtok_buf; + return (1); + } + gettok_state->gtok_null_seen = 1; + return (0); + } + + /* + * Read token: The standard delimiter is whitespace, but + * we honor either single or double quotes. Also, we honor + * backslash escapes. + */ + gettok_state->gtok_last_token.tok_str = look = str; + gettok_state->gtok_last_token.tok_line_off = + look - gettok_state->gtok_buf; + for (; *look; look++) { + if (*look == quote_ch) { /* Terminates active quote */ + quote_ch = '\0'; + continue; + } + + if (quote_ch == '\0') { /* No quote currently active */ + if ((*look == '\'') || (*look == '"')) { + quote_ch = *look; /* New active quote */ + continue; + } + if (isspace(*look)) + break; + } + + if (*look == '\\') { + look++; + if (*look == '\0') /* Esc applied to NULL term? */ + break; + } + + if (look != str) + *str = *look; + str++; + } + gettok_state->gtok_last_token.tok_len = str - + gettok_state->gtok_last_token.tok_str; + gettok_state->gtok_null_seen = *look == '\0'; + if (!gettok_state->gtok_null_seen) + look++; + *str = '\0'; + gettok_state->gtok_cur_buf = look; + +#if 0 + printf("GETTOK >%s< len(%d) offset(%d)\n", + gettok_state->gtok_last_token.tok_str, + gettok_state->gtok_last_token.tok_len, + gettok_state->gtok_last_token.tok_line_off); +#endif + + return (1); +} + + +/* + * Tokenize the user command string, and return a pointer to the + * TOK_STATE buffer maintained by this function. That buffer contains + * the tokenized strings. + * + * entry: + * user_cmd_str - String to tokenize + * len - # of characters in user_cmd_str to examine. If + * (len < 0), then the complete string is processed + * stopping with the NULL termination. Otherwise, + * processing stops after len characters, and any + * remaining characters are ignored. + * inc_null_final - If True, and if user_cmd_str has whitespace + * at the end following the last non-null token, then + * a final null token will be included. If False, null + * tokens are ignored. + * + * note: + * This routine returns pointers to internally allocated memory. + * The caller must not alter anything contained in the TOK_STATE + * buffer returned. Furthermore, the the contents of TOK_STATE + * are only valid until the next call to tokenize_user_cmd(). + */ +static TOK_STATE * +tokenize_user_cmd(const char *user_cmd_str, size_t len, int inc_null_final) +{ +#define INITIAL_TOK_ALLOC 5 + + /* + * As we parse the user command, we need temporary space to + * hold the tokens. We do this by dynamically allocating a string + * buffer and a token array, and doubling them as necessary. This + * is a single threaded application, so static variables suffice. + */ + static STRBUF str; + static TOK_STATE tokst; + + GETTOK_STATE gettok_state; + size_t n; + + /* + * Make a copy we can modify. If (len == 0), take the entire + * string. Otherwise limit it to the specified length. + */ + tokst.tokst_cmd_len = strlen(user_cmd_str); + if ((len > 0) && (len < tokst.tokst_cmd_len)) + tokst.tokst_cmd_len = len; + tokst.tokst_cmd_len++; /* Room for NULL termination */ + strbuf_ensure_size(&str, tokst.tokst_cmd_len); + (void) strlcpy(str.buf, user_cmd_str, tokst.tokst_cmd_len); + + /* Trim off any newline character that might be present */ + if ((tokst.tokst_cmd_len > 1) && + (str.buf[tokst.tokst_cmd_len - 2] == '\n')) { + tokst.tokst_cmd_len--; + str.buf[tokst.tokst_cmd_len - 1] = '\0'; + } + + /* Tokenize the user command string into tok struct */ + gettok_init(&gettok_state, str.buf, inc_null_final); + tokst.tokst_str_size = 0; /* Space needed for token strings */ + for (tokst.tokst_cnt = 0; gettok(&gettok_state) != 0; + tokst.tokst_cnt++) { + /* If we need more room, expand the token buffer */ + if (tokst.tokst_cnt >= tokst.tokst_bufsize) { + n = (tokst.tokst_bufsize == 0) ? + INITIAL_TOK_ALLOC : (tokst.tokst_bufsize * 2); + tokst.tokst_buf = elfedit_realloc( + MSG_INTL(MSG_ALLOC_TOKBUF), tokst.tokst_buf, + n * sizeof (*tokst.tokst_buf)); + tokst.tokst_bufsize = n; + } + tokst.tokst_str_size += + gettok_state.gtok_last_token.tok_len + 1; + tokst.tokst_buf[tokst.tokst_cnt] = gettok_state.gtok_last_token; + } + /* fold the command token to lowercase */ + if (tokst.tokst_cnt > 0) { + char *s; + + for (s = tokst.tokst_buf[0].tok_str; *s; s++) + if (isupper(*s)) + *s = tolower(*s); + } + + return (&tokst); + +#undef INITIAL_TOK_ALLOC +} + + +/* + * Parse the user command string, and put an entry for it at the end + * of state.ucmd. + */ +static void +parse_user_cmd(const char *user_cmd_str) +{ + TOK_STATE *tokst; + char *s; + size_t n; + size_t len; + USER_CMD_T *ucmd; + elfeditGC_module_t *mod; + elfeditGC_cmd_t *cmd; + + /* + * Break it into tokens. If there are none, then it is + * an empty command and is ignored. + */ + tokst = tokenize_user_cmd(user_cmd_str, -1, 0); + if (tokst->tokst_cnt == 0) + return; + + /* Find the command. Won't return on error */ + cmd = elfedit_find_command(tokst->tokst_buf[0].tok_str, 1, &mod); + + /* + * If there is no ELF file being edited, then only commands + * from the sys: module are allowed. + */ + if ((state.file.present == 0) && + (strcmp(mod->mod_name, MSG_ORIG(MSG_MOD_SYS)) != 0)) + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOFILSYSONLY), + mod->mod_name, cmd->cmd_name[0]); + + + /* Allocate, fill in, and insert a USER_CMD_T block */ + n = S_DROUND(sizeof (USER_CMD_T)); + ucmd = elfedit_malloc(MSG_INTL(MSG_ALLOC_UCMD), + n + (sizeof (char *) * (tokst->tokst_cnt - 1)) + + tokst->tokst_cmd_len + tokst->tokst_str_size); + ucmd->ucmd_next = NULL; + ucmd->ucmd_argc = tokst->tokst_cnt - 1; + /*LINTED E_BAD_PTR_CAST_ALIGN*/ + ucmd->ucmd_argv = (const char **)(n + (char *)ucmd); + ucmd->ucmd_orig_str = (char *)(ucmd->ucmd_argv + ucmd->ucmd_argc); + (void) strncpy(ucmd->ucmd_orig_str, user_cmd_str, tokst->tokst_cmd_len); + ucmd->ucmd_mod = mod; + ucmd->ucmd_cmd = cmd; + ucmd->ucmd_ostyle_set = 0; + s = ucmd->ucmd_orig_str + tokst->tokst_cmd_len; + for (n = 1; n < tokst->tokst_cnt; n++) { + len = tokst->tokst_buf[n].tok_len + 1; + ucmd->ucmd_argv[n - 1] = s; + (void) strncpy(s, tokst->tokst_buf[n].tok_str, len); + s += len; + } + if (state.ucmd.list == NULL) { + state.ucmd.list = state.ucmd.tail = ucmd; + } else { + state.ucmd.tail->ucmd_next = ucmd; + state.ucmd.tail = ucmd; + } + state.ucmd.n++; +} + + +/* + * Copy infile to a new file with the name given by outfile. + */ +static void +create_outfile(const char *infile, const char *outfile) +{ + pid_t pid; + int statloc; + struct stat statbuf; + + + pid = fork(); + switch (pid) { + case -1: /* Unable to create process */ + { + int err = errno; + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_CNTFORK), + strerror(err)); + } + /*NOTREACHED*/ + return; + + case 0: + (void) execl(MSG_ORIG(MSG_STR_BINCP), + MSG_ORIG(MSG_STR_BINCP), infile, outfile, NULL); + /* + * exec() only returns on error. This is the child process, + * so we want to stay away from the usual error mechanism + * and handle things directly. + */ + { + int err = errno; + (void) fprintf(stderr, MSG_INTL(MSG_ERR_CNTEXEC), + MSG_ORIG(MSG_STR_ELFEDIT), + MSG_ORIG(MSG_STR_BINCP), strerror(err)); + } + exit(1); + /*NOTREACHED*/ + } + + /* This is the parent: Wait for the child to terminate */ + if (waitpid(pid, &statloc, 0) != pid) { + int err = errno; + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_CNTWAIT), + strerror(err)); + } + /* + * If the child failed, then terminate the process. There is no + * need for an error message, because the child will have taken + * care of that. + */ + if (!WIFEXITED(statloc) || (WEXITSTATUS(statloc) != 0)) + exit(1); + + /* Make sure the copy allows user write access */ + if (stat(outfile, &statbuf) == -1) { + int err = errno; + (void) unlink(outfile); + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_CNTSTAT), + outfile, strerror(err)); + } + if ((statbuf.st_mode & S_IWUSR) == 0) { + /* Only keep permission bits, and add user write */ + statbuf.st_mode |= S_IWUSR; + statbuf.st_mode &= 07777; /* Only keep the permission bits */ + if (chmod(outfile, statbuf.st_mode) == -1) { + int err = errno; + (void) unlink(outfile); + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_CNTCHMOD), + outfile, strerror(err)); + } + } +} + +/* + * Given a module path string, determine how long the resulting path will + * be when all % tokens have been expanded. + * + * entry: + * path - Path for which expanded length is desired + * origin_root - Root of $ORIGIN tree containing running elfedit program + * + * exit: + * Returns the value strlen() will give for the expanded path. + */ +static size_t +modpath_strlen(const char *path, const char *origin_root) +{ + size_t len = 0; + const char *s; + + s = path; + len = 0; + for (s = path; *s != '\0'; s++) { + if (*s == '%') { + s++; + switch (*s) { + case 'i': /* ISA of running elfedit */ + len += strlen(isa_i_str); + break; + case 'I': /* "" for 32-bit, same as %i for 64 */ + len += strlen(isa_I_str); + break; + case 'o': /* Insert default path */ + len += + modpath_strlen(MSG_ORIG(MSG_STR_MODPATH), + origin_root); + break; + case 'r': /* root of tree with running elfedit */ + len += strlen(origin_root); + break; + + case '%': /* %% is reduced to just '%' */ + len++; + break; + default: /* All other % codes are reserved */ + elfedit_msg(ELFEDIT_MSG_ERR, + MSG_INTL(MSG_ERR_BADPATHCODE), *s); + /*NOTREACHED*/ + break; + } + } else { /* Non-% character passes straight through */ + len++; + } + } + + return (len); +} + + +/* + * Given a module path string, and a buffer large enough to hold the results, + * fill the buffer with the expanded path. + * + * entry: + * path - Path for which expanded length is desired + * origin_root - Root of tree containing running elfedit program + * buf - Buffer to receive the result. buf must as large or larger + * than the value given by modpath_strlen(). + * + * exit: + * Returns pointer to location following the last character + * written to buf. A NULL byte is written to that address. + */ +static char * +modpath_expand(const char *path, const char *origin_root, char *buf) +{ + size_t len; + const char *cp_str; + + for (; *path != '\0'; path++) { + if (*path == '%') { + path++; + cp_str = NULL; + switch (*path) { + case 'i': /* ISA of running elfedit */ + cp_str = isa_i_str; + break; + case 'I': /* "" for 32-bit, same as %i for 64 */ + cp_str = isa_I_str; + break; + case 'o': /* Insert default path */ + buf = modpath_expand(MSG_ORIG(MSG_STR_MODPATH), + origin_root, buf); + break; + case 'r': + cp_str = origin_root; + break; + case '%': /* %% is reduced to just '%' */ + *buf++ = *path; + break; + default: /* All other % codes are reserved */ + elfedit_msg(ELFEDIT_MSG_ERR, + MSG_INTL(MSG_ERR_BADPATHCODE), *path); + /*NOTREACHED*/ + break; + } + if ((cp_str != NULL) && ((len = strlen(cp_str)) > 0)) { + bcopy(cp_str, buf, len); + buf += len; + } + } else { /* Non-% character passes straight through */ + *buf++ = *path; + } + } + + *buf = '\0'; + return (buf); +} + + +/* + * Establish the module search path: state.modpath + * + * The path used comes from the following sources, taking the first + * one that has a value, and ignoring any others: + * + * - ELFEDIT_PATH environment variable + * - -L command line argument + * - Default value + * + * entry: + * path - NULL, or the value of the -L command line argument + * + * exit: + * state.modpath has been filled in + */ +static void +establish_modpath(const char *cmdline_path) +{ + char origin_root[PATH_MAX + 1]; /* Where elfedit binary is */ + const char *path; /* Initial path */ + char *expath; /* Expanded path */ + size_t len; + char *src, *dst; + + path = getenv(MSG_ORIG(MSG_STR_ENVVAR)); + if (path == NULL) + path = cmdline_path; + if (path == NULL) + path = MSG_ORIG(MSG_STR_MODPATH); + + + /* + * Root of tree containing running for running program. 32-bit elfedit + * is installed in /usr/bin, and 64-bit elfedit is one level lower + * in an ISA-specific subdirectory. So, we find the root by + * getting the $ORGIN of the current running program, and trimming + * off the last 2 (32-bit) or 3 (64-bit) directories. + * + * On a standard system, this will simply yield '/'. However, + * doing it this way allows us to run elfedit from a proto area, + * and pick up modules from the same proto area instead of those + * installed on the system. + */ + if (dlinfo(RTLD_SELF, RTLD_DI_ORIGIN, &origin_root) == -1) + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_CNTGETORIGIN)); + len = (sizeof (char *) == 8) ? 3 : 2; + src = origin_root + strlen(origin_root); + while ((src > origin_root) && (len > 0)) { + if (*(src - 1) == '/') + len--; + src--; + } + *src = '\0'; + + + /* + * Calculate space needed to hold expanded path. Note that + * this assumes that MSG_STR_MODPATH will never contain a '%o' + * code, and so, the expansion is not recursive. The codes allowed + * are: + * %i - ISA of running elfedit (sparc, sparcv9, etc) + * %I - 64-bit ISA: Same as %i for 64-bit versions of elfedit, + * but yields empty string for 32-bit ISAs. + * %o - The original (default) path. + * %r - Root of tree holding elfedit program. + * %% - A single % + * + * A % followed by anything else is an error. This allows us to + * add new codes in the future without backward compatability issues. + */ + len = modpath_strlen(path, origin_root); + + expath = elfedit_malloc(MSG_INTL(MSG_ALLOC_EXPATH), len + 1); + (void) modpath_expand(path, origin_root, expath); + + /* + * Count path segments, eliminate extra '/', and replace ':' + * with NULL. + */ + state.modpath.n = 1; + for (src = dst = expath; *src; src++) { + if (*src == '/') { + switch (*(src + 1)) { + case '/': + case ':': + case '\0': + continue; + } + } + if (*src == ':') { + state.modpath.n++; + *dst = '\0'; + } else if (src != dst) { + *dst = *src; + } + dst++; + } + if (src != dst) + *dst = '\0'; + + state.modpath.seg = elfedit_malloc(MSG_INTL(MSG_ALLOC_PATHARR), + sizeof (state.modpath.seg[0]) * state.modpath.n); + + src = expath; + for (len = 0; len < state.modpath.n; len++) { + if (*src == '\0') { + state.modpath.seg[len] = MSG_ORIG(MSG_STR_DOT); + src++; + } else { + state.modpath.seg[len] = src; + src += strlen(src) + 1; + } + } +} + +/* + * When interactive (reading commands from a tty), we catch + * SIGINT in order to restart the outer command loop. + */ +/*ARGSUSED*/ +static void +sigint_handler(int sig, siginfo_t *sip, void *ucp) +{ + /* Jump to the outer loop to resume */ + if (state.msg_jbuf.active) { + state.msg_jbuf.active = 0; + siglongjmp(state.msg_jbuf.env, 1); + } +} + + +static void +usage(int full) +{ + elfedit_msg(ELFEDIT_MSG_USAGE, MSG_INTL(MSG_USAGE_BRIEF)); + if (full) { + elfedit_msg(ELFEDIT_MSG_USAGE, MSG_INTL(MSG_USAGE_DETAIL1)); + elfedit_msg(ELFEDIT_MSG_USAGE, MSG_INTL(MSG_USAGE_DETAIL2)); + elfedit_msg(ELFEDIT_MSG_USAGE, MSG_INTL(MSG_USAGE_DETAIL3)); + elfedit_msg(ELFEDIT_MSG_USAGE, MSG_INTL(MSG_USAGE_DETAIL4)); + elfedit_msg(ELFEDIT_MSG_USAGE, MSG_INTL(MSG_USAGE_DETAIL5)); + elfedit_msg(ELFEDIT_MSG_USAGE, MSG_INTL(MSG_USAGE_DETAIL6)); + elfedit_msg(ELFEDIT_MSG_USAGE, MSG_INTL(MSG_USAGE_DETAIL_LAST)); + } + elfedit_exit(2); +} + + +/* + * In order to complete commands, we need to know about them, + * which means that we need to force all the modules to be + * loaded. This is a relatively expensive operation, so we use + * this function, which avoids doing it more than once in a session. + */ +static void +elfedit_cpl_load_modules(void) +{ + static int loaded; + + if (!loaded) { + elfedit_load_modpath(); + loaded = 1; /* Don't do it again */ + } +} + +/* + * Compare the token to the given string, and if they share a common + * initial sequence, add the tail of string to the tecla command completion + * buffer: + * + * entry: + * cpldata - Current completion state + * str - String to match against token + * casefold - True to allow case insensitive completion, False + * if case must match exactly. + */ +void +elfedit_cpl_match(void *cpldata, const char *str, int casefold) +{ + ELFEDIT_CPL_STATE *cstate = (ELFEDIT_CPL_STATE *) cpldata; + const char *cont_suffix; + const char *type_suffix; + + /* + * Reasons to return immediately: + * - NULL strings have no completion value + * - The string is shorter than the existing item being completed + */ + if ((str == NULL) || (*str == '\0') || + ((cstate->ecpl_token_len != 0) && + ((strlen(str) < cstate->ecpl_token_len)))) + return; + + /* If the string does not share the existing prefix, don't use it */ + if (casefold) { + if (strncasecmp(cstate->ecpl_token_str, str, + cstate->ecpl_token_len) != 0) + return; + } else { + if (strncmp(cstate->ecpl_token_str, str, + cstate->ecpl_token_len) != 0) + return; + } + + if (cstate->ecpl_add_mod_colon) { + cont_suffix = type_suffix = MSG_ORIG(MSG_STR_COLON); + } else { + cont_suffix = MSG_ORIG(MSG_STR_SPACE); + type_suffix = NULL; + } + (void) cpl_add_completion(cstate->ecpl_cpl, cstate->ecpl_line, + cstate->ecpl_word_start, cstate->ecpl_word_end, + str + cstate->ecpl_token_len, type_suffix, cont_suffix); + +} + + +/* + * Compare the token to the names of the commands from the given module, + * and if they share a common initial sequence, add the tail of string + * to the tecla command completion buffer: + * + * entry: + * tok_buf - Token user has entered + * tok_len - strlen(tok_buf) + * mod - Module definition from which commands should be matched + * cpl, line, word_start, word_end, cont_suffix - As documented + * for gl_get_line() and cpl_add_completion. + */ +static void +match_module_cmds(ELFEDIT_CPL_STATE *cstate, elfeditGC_module_t *mod) +{ + elfeditGC_cmd_t *cmd; + const char **cmd_name; + + for (cmd = mod->mod_cmds; cmd->cmd_func != NULL; cmd++) + for (cmd_name = cmd->cmd_name; *cmd_name; cmd_name++) + elfedit_cpl_match(cstate, *cmd_name, 1); +} + + +/* + * Compare the token to the known module names, and add those that + * match to the list of alternatives via elfedit_cpl_match(). + * + * entry: + * load_all_modules - If True, causes all modules to be loaded + * before processing is done. If False, only the modules + * currently seen will be used. + */ +void +elfedit_cpl_module(void *cpldata, int load_all_modules) +{ + ELFEDIT_CPL_STATE *cstate = (ELFEDIT_CPL_STATE *) cpldata; + MODLIST_T *modlist; + + if (load_all_modules) + elfedit_cpl_load_modules(); + + for (modlist = state.modlist; modlist != NULL; + modlist = modlist->ml_next) { + elfedit_cpl_match(cstate, modlist->ml_mod->mod_name, 1); + } +} + + +/* + * Compare the token to all the known commands, and add those that + * match to the list of alternatives. + * + * note: + * This routine will force modules to be loaded as necessary to + * obtain the names it needs to match. + */ +void +elfedit_cpl_command(void *cpldata) +{ + ELFEDIT_CPL_STATE *cstate = (ELFEDIT_CPL_STATE *) cpldata; + ELFEDIT_CPL_STATE colon_state; + const char *colon_pos; + MODLIST_T *modlist; + MODLIST_T *insdef; + char buf[128]; + + /* + * Is there a colon in the command? If so, locate its offset within + * the raw input line. + */ + for (colon_pos = cstate->ecpl_token_str; + *colon_pos && (*colon_pos != ':'); colon_pos++) + ; + + /* + * If no colon was seen, then we are completing a module name, + * or one of the commands from 'sys:' + */ + if (*colon_pos == '\0') { + /* + * Setting cstate->add_mod_colon tells elfedit_cpl_match() + * to add an implicit ':' to the names it matches. We use it + * here so the user doesn't have to enter the ':' manually. + * Hiding this in the opaque state instead of making it + * an argument to that function gives us the ability to + * change it later without breaking the published interface. + */ + cstate->ecpl_add_mod_colon = 1; + elfedit_cpl_module(cpldata, 1); + cstate->ecpl_add_mod_colon = 0; + + /* Add bare (no sys: prefix) commands from the sys: module */ + match_module_cmds(cstate, + elfedit_load_module(MSG_ORIG(MSG_MOD_SYS), 1, 0)); + + return; + } + + /* + * A colon was seen, so we have a module name. Extract the name, + * substituting 'sys' for the case where the given name is empty. + */ + if (colon_pos == 0) + (void) strlcpy(buf, MSG_ORIG(MSG_MOD_SYS), sizeof (buf)); + else + elfedit_strnbcpy(buf, cstate->ecpl_token_str, + colon_pos - cstate->ecpl_token_str, sizeof (buf)); + + /* + * Locate the module. If it isn't already loaded, make an explicit + * attempt to load it and try again. If a module definition is + * obtained, process the commands it supplies. + */ + modlist = module_loaded(buf, &insdef); + if (modlist == NULL) { + (void) elfedit_load_module(buf, 0, 0); + modlist = module_loaded(buf, &insdef); + } + if (modlist != NULL) { + /* + * Make a copy of the cstate, and adjust the line and + * token so that the new one starts just past the colon + * character. We know that the colon exists because + * of the preceeding test that found it. Therefore, we do + * not need to test against running off the end of the + * string here. + */ + colon_state = *cstate; + while (colon_state.ecpl_line[colon_state.ecpl_word_start] != + ':') + colon_state.ecpl_word_start++; + while (*colon_state.ecpl_token_str != ':') { + colon_state.ecpl_token_str++; + colon_state.ecpl_token_len--; + } + /* Skip past the ':' character */ + colon_state.ecpl_word_start++; + colon_state.ecpl_token_str++; + colon_state.ecpl_token_len--; + + match_module_cmds(&colon_state, modlist->ml_mod); + } +} + + +/* + * Command completion function for use with libtacla. + */ +/*ARGSUSED1*/ +static int +cmd_match_fcn(WordCompletion *cpl, void *data, const char *line, int word_end) +{ + const char *argv[ELFEDIT_MAXCPLARGS]; + ELFEDIT_CPL_STATE cstate; + TOK_STATE *tokst; + int ndx; + int i; + elfeditGC_module_t *mod; + elfeditGC_cmd_t *cmd; + int num_opt; + int opt_term_seen; + int skip_one; + elfedit_cmd_optarg_t *optarg; + elfedit_optarg_item_t item; + int ostyle_ndx = -1; + + /* + * For debugging, enable the following block. It tells the tecla + * library that the program using is going to write to stdout. + * It will put the tty back into normal mode, and it will cause + * tecla to redraw the current input line when it gets control back. + */ +#if 0 + gl_normal_io(state.input.gl); +#endif + + /* + * Tokenize the line up through word_end. The last token in + * the list is the one requiring completion. + */ + tokst = tokenize_user_cmd(line, word_end, 1); + if (tokst->tokst_cnt == 0) + return (0); + + /* Set up the cstate block, containing the completion state */ + ndx = tokst->tokst_cnt - 1; /* Index of token to complete */ + cstate.ecpl_cpl = cpl; + cstate.ecpl_line = line; + cstate.ecpl_word_start = tokst->tokst_buf[ndx].tok_line_off; + cstate.ecpl_word_end = word_end; + cstate.ecpl_add_mod_colon = 0; + cstate.ecpl_token_str = tokst->tokst_buf[ndx].tok_str; + cstate.ecpl_token_len = tokst->tokst_buf[ndx].tok_len; + + /* + * If there is only one token, then we are completing the + * command itself. + */ + if (ndx == 0) { + elfedit_cpl_command(&cstate); + return (0); + } + + /* + * There is more than one token. Use the first one to + * locate the definition for the command. If we don't have + * a definition for the command, then there's nothing more + * we can do. + */ + cmd = elfedit_find_command(tokst->tokst_buf[0].tok_str, 0, &mod); + if (cmd == NULL) + return (0); + + /* + * Since we know the command, give them a quick usage message. + * It may be that they just need a quick reminder about the form + * of the command and the options. + */ + (void) gl_normal_io(state.input.gl); + elfedit_printf(MSG_INTL(MSG_USAGE_CMD), + elfedit_format_command_usage(mod, cmd, NULL, 0)); + + + /* + * We have a generous setting for ELFEDIT_MAXCPLARGS, so there + * should always be plenty of room. If there's not room, we + * can't proceed. + */ + if (ndx >= ELFEDIT_MAXCPLARGS) + return (0); + + /* + * Put pointers to the tokens into argv, and determine how + * many of the tokens are optional arguments. + * + * We consider the final optional argument to be the rightmost + * argument that starts with a '-'. If a '--' is seen, then + * we stop there, and any argument that follows is a plain argument + * (even if it starts with '-'). + * + * We look for an inherited '-o' option, because we are willing + * to supply command completion for these values. + */ + num_opt = 0; + opt_term_seen = 0; + skip_one = 0; + for (i = 0; i < ndx; i++) { + argv[i] = tokst->tokst_buf[i + 1].tok_str; + if (opt_term_seen || skip_one) { + skip_one = 0; + continue; + } + skip_one = 0; + ostyle_ndx = -1; + if ((strcmp(argv[i], MSG_ORIG(MSG_STR_MINUS_MINUS)) == NULL) || + (*argv[i] != '-')) { + opt_term_seen = 1; + continue; + } + num_opt = i + 1; + /* + * If it is a recognised ELFEDIT_CMDOA_F_VALUE option, + * then the item following it is the associated value. + * Check for this and skip the value. + * + * At the same time, look for STDOA_OPT_O inherited + * options. We want to identify the index of any such + * item. Although the option is simply "-o", we are willing + * to treat any option that starts with "-o" as a potential + * STDOA_OPT_O. This lets us to command completion for things + * like "-onum", and is otherwise harmless, the only cost + * being a few additional strcmps by the cpl code. + */ + if ((optarg = cmd->cmd_opt) == NULL) + continue; + while (optarg->oa_name != NULL) { + int is_ostyle_optarg = + (optarg->oa_flags & ELFEDIT_CMDOA_F_INHERIT) && + (optarg->oa_name == ELFEDIT_STDOA_OPT_O); + + elfedit_next_optarg(&optarg, &item); + if (item.oai_flags & ELFEDIT_CMDOA_F_VALUE) { + if (is_ostyle_optarg && (strncmp(argv[i], + MSG_ORIG(MSG_STR_MINUS_O), 2) == 0)) + ostyle_ndx = i + 1; + + if (strcmp(item.oai_name, argv[i]) == 0) { + num_opt = i + 2; + skip_one = 1; + break; + } + /* + * If it didn't match "-o" exactly, but it is + * ostyle_ndx, then it is a potential combined + * STDOA_OPT_O, as discussed above. It counts + * as a single argument. + */ + if (ostyle_ndx == ndx) + break; + } + } + } + +#if 0 + printf("NDX(%d) NUM_OPT(%d) ostyle_ndx(%d)\n", ndx, num_opt, + ostyle_ndx); +#endif + + if (ostyle_ndx != -1) { + /* + * If ostyle_ndx is one less than ndx, and ndx is + * the same as num_opt, then we have a definitive + * STDOA_OPT_O inherited outstyle option. We supply + * the value strings, and are done. + */ + if ((ostyle_ndx == (ndx - 1)) && (ndx == num_opt)) { + elfedit_cpl_atoconst(&cstate, ELFEDIT_CONST_OUTSTYLE); + return (0); + } + + /* + * If ostyle is the same as ndx, then we have an option + * staring with "-o" that may end up being a STDOA_OPT_O, + * and we are still inside that token. In this case, we + * supply completion strings that include the leading + * "-o" followed by the values, without a space + * (i.e. "-onum"). We then fall through, allowing any + * other options starting with "-o" to be added + * below. elfedit_cpl_match() will throw out the incorrect + * options, so it is harmless to add these extra items in + * the worst case, and useful otherwise. + */ + if (ostyle_ndx == ndx) + elfedit_cpl_atoconst(&cstate, + ELFEDIT_CONST_OUTSTYLE_MO); + } + + /* + * If (ndx <= num_opt), then the token needing completion + * is an option. If the leading '-' is there, then we should fill + * in all of the option alternatives. If anything follows the '-' + * though, we assume that the user has already figured out what + * option to use, and we leave well enough alone. + * + * Note that we are intentionally ignoring a related case + * where supplying option strings would be legal: In the case + * where we are one past the last option (ndx == (num_opt + 1)), + * and the current option is an empty string, the argument can + * be either a plain argument or an option --- the user needs to + * enter the next character before we can tell. It would be + * OK to enter the option strings in this case. However, consider + * what happens when the first plain argument to the command does + * not provide any command completion (e.g. it is a plain integer). + * In this case, tecla will see that all the alternatives start + * with '-', and will insert a '-' into the input. If the user + * intends the next argument to be plain, they will have to delete + * this '-', which is annoying. Worse than that, they may be confused + * by it, and think that the plain argument is not allowed there. + * The best solution is to not supply option strings unless the + * user first enters the '-'. + */ + if ((ndx <= num_opt) && (argv[ndx - 1][0] == '-')) { + if ((optarg = cmd->cmd_opt) != NULL) { + while (optarg->oa_name != NULL) { + elfedit_next_optarg(&optarg, &item); + elfedit_cpl_match(&cstate, item.oai_name, 1); + } + } + return (0); + } + + /* + * At this point we know that ndx and num_opt are not equal. + * If num_opt is larger than ndx, then we have an ELFEDIT_CMDOA_F_VALUE + * argument at the end, and the following value has not been entered. + * + * If ndx is greater than num_opt, it means that we are looking + * at a plain argument (or in the case where (ndx == (num_opt + 1)), + * a *potential* plain argument. + * + * If the command has a completion function registered, then we + * hand off the remaining work to it. The cmd_cplfunc field is + * the generic definition. We need to cast it to the type that matches + * the proper ELFCLASS before calling it. + */ + if (state.elf.elfclass == ELFCLASS32) { + elfedit32_cmdcpl_func_t *cmdcpl_func = + (elfedit32_cmdcpl_func_t *)cmd->cmd_cplfunc; + + if (cmdcpl_func != NULL) + (* cmdcpl_func)(state.elf.obj_state.s32, + &cstate, ndx, argv, num_opt); + } else { + elfedit64_cmdcpl_func_t *cmdcpl_func = + (elfedit64_cmdcpl_func_t *)cmd->cmd_cplfunc; + + if (cmdcpl_func != NULL) + (* cmdcpl_func)(state.elf.obj_state.s64, + &cstate, ndx, argv, num_opt); + } + + return (0); +} + + +/* + * Read a line of input from stdin, and return pointer to it. + * + * This routine uses a private buffer, so the contents of the returned + * string are only good until the next call. + */ +static const char * +read_cmd(void) +{ + char *s; + + if (state.input.full_tty) { + state.input.in_tecla = TRUE; + s = gl_get_line(state.input.gl, + MSG_ORIG(MSG_STR_PROMPT), NULL, -1); + state.input.in_tecla = FALSE; + /* + * gl_get_line() returns NULL for EOF or for error. EOF is fine, + * but we need to catch and report anything else. Since + * reading from stdin is critical to our operation, an + * error implies that we cannot recover and must exit. + */ + if ((s == NULL) && + (gl_return_status(state.input.gl) == GLR_ERROR)) { + elfedit_msg(ELFEDIT_MSG_FATAL, MSG_INTL(MSG_ERR_GLREAD), + gl_error_message(state.input.gl, NULL, 0)); + } + } else { + /* + * This should be a dynamically sized buffer, but for now, + * I'm going to take a simpler path. + */ + static char cmd_buf[ELFEDIT_MAXCMD + 1]; + + s = fgets(cmd_buf, sizeof (cmd_buf), stdin); + } + + /* Return user string, or 'quit' on EOF */ + return (s ? s : MSG_ORIG(MSG_SYS_CMD_QUIT)); +} + +int +main(int argc, char **argv, char **envp) +{ + /* + * Note: This function can use setjmp()/longjmp() which does + * not preserve the values of auto/register variables. Hence, + * variables that need their values preserved across a jump must + * be marked volatile, or must not be auto/register. + * + * Volatile can be messy, because it requires explictly casting + * away the attribute when passing it to functions, or declaring + * those functions with the attribute as well. In a single threaded + * program like this one, an easier approach is to make things + * static. That can be done here, or by putting things in the + * 'state' structure. + */ + + int c, i; + int num_batch = 0; + char **batch_list = NULL; + const char *modpath = NULL; + + /* + * Always have liblddb display unclipped section names. + * This global is exported by liblddb, and declared in debug.h. + */ + dbg_desc->d_extra |= DBG_E_LONG; + + opterr = 0; + while ((c = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) { + switch (c) { + case 'a': + state.flags |= ELFEDIT_F_AUTOPRINT; + break; + + case 'd': + state.flags |= ELFEDIT_F_DEBUG; + break; + + case 'e': + /* + * Delay parsing the -e options until after the call to + * conv_check_native() so that we won't bother loading + * modules of the wrong class. + */ + if (batch_list == NULL) + batch_list = elfedit_malloc( + MSG_INTL(MSG_ALLOC_BATCHLST), + sizeof (*batch_list) * (argc - 1)); + batch_list[num_batch++] = optarg; + break; + + case 'L': + modpath = optarg; + break; + + case 'o': + if (elfedit_atooutstyle(optarg, &state.outstyle) == 0) + usage(1); + break; + + case 'r': + state.flags |= ELFEDIT_F_READONLY; + break; + + case '?': + usage(1); + } + } + + /* + * We allow 0, 1, or 2 files: + * + * The no-file case is an extremely limited mode, in which the + * only commands allowed to execute come from the sys: module. + * This mode exists primarily to allow easy access to the help + * facility. + * + * To get full access to elfedit's capablities, there must + * be an input file. If this is not a readonly + * session, then an optional second output file is allowed. + * + * In the case where two files are given and the session is + * readonly, use a full usage message, because the simple + * one isn't enough for the user to understand their error. + * Otherwise, the simple usage message suffices. + */ + argc = argc - optind; + if ((argc == 2) && (state.flags & ELFEDIT_F_READONLY)) + usage(1); + if (argc > 2) + usage(0); + + state.file.present = (argc != 0); + + /* + * If we have a file to edit, and unless told otherwise by the + * caller, we try to run the 64-bit version of this program + * when the system is capable of it. If that fails, then we + * continue on with the currently running version. + * + * To force 32-bit execution on a 64-bit host, set the + * LD_NOEXEC_64 environment variable to a non-empty value. + * + * There is no reason to bother with this if in "no file" mode. + */ + if (state.file.present != 0) + (void) conv_check_native(argv, envp); + + elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_VERSION), + (sizeof (char *) == 8) ? 64 : 32); + + /* + * Put a module definition for the builtin system module on the + * module list. We know it starts out empty, so we do not have + * to go through a more general insertion process than this. + */ + state.modlist = elfedit_sys_init(ELFEDIT_VER_CURRENT); + + /* Establish the search path for loadable modules */ + establish_modpath(modpath); + + /* + * Now that we are running the final version of this program, + * deal with the input/output file(s). + */ + if (state.file.present == 0) { + /* + * This is arbitrary --- we simply need to be able to + * load modules so that we can access their help strings + * and command completion functions. Without a file, we + * will refuse to call commands from any module other + * than sys. Those commands have been written to be aware + * of the case where there is no input file, and are + * therefore safe to run. + */ + state.elf.elfclass = ELFCLASS32; + elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_NOFILE)); + + } else { + state.file.infile = argv[optind]; + if (argc == 1) { + state.file.outfile = state.file.infile; + if (state.flags & ELFEDIT_F_READONLY) + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_READONLY)); + else + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_INPLACEWARN), + state.file.infile); + } else { + state.file.outfile = argv[optind + 1]; + create_outfile(state.file.infile, state.file.outfile); + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_CPFILE), + state.file.infile, state.file.outfile); + /* + * We are editing a copy of the original file that we + * just created. If we should exit before the edits are + * updated, then we want to unlink this copy so that we + * don't leave junk lying around. Once an update + * succeeds however, we'll leave it in place even + * if an error occurs afterwards. + */ + state.file.unlink_on_exit = 1; + optind++; /* Edit copy instead of the original */ + } + + init_obj_state(state.file.outfile); + } + + + /* + * Process commands. + * + * If any -e options were used, then do them and + * immediately exit. On error, exit immediately without + * updating the target ELF file. On success, the 'write' + * and 'quit' commands are implicit in this mode. + * + * If no -e options are used, read commands from stdin. + * quit must be explicitly used. Exit is implicit on EOF. + * If stdin is a tty, then errors do not cause the editor + * to terminate. Rather, the error message is printed, and the + * user prompted to continue. + */ + if (batch_list != NULL) { /* -e was used */ + /* Compile the commands */ + for (i = 0; i < num_batch; i++) + parse_user_cmd(batch_list[i]); + free(batch_list); + + /* + * 'write' and 'quit' are implicit in this mode. + * Add them as well. + */ + if ((state.flags & ELFEDIT_F_READONLY) == 0) + parse_user_cmd(MSG_ORIG(MSG_SYS_CMD_WRITE)); + parse_user_cmd(MSG_ORIG(MSG_SYS_CMD_QUIT)); + + /* And run them. This won't return, thanks to the 'quit' */ + dispatch_user_cmds(); + } else { + state.input.is_tty = isatty(fileno(stdin)); + state.input.full_tty = state.input.is_tty && + isatty(fileno(stdout)); + + if (state.input.full_tty) { + struct sigaction act; + + act.sa_sigaction = sigint_handler; + (void) sigemptyset(&act.sa_mask); + act.sa_flags = 0; + if (sigaction(SIGINT, &act, NULL) == -1) { + int err = errno; + elfedit_msg(ELFEDIT_MSG_ERR, + MSG_INTL(MSG_ERR_SIGACTION), strerror(err)); + } + /* + * If pager process exits before we are done + * writing, we can see SIGPIPE. Prevent it + * from killing the process. + */ + (void) sigignore(SIGPIPE); + + /* Open tecla handle for command line editing */ + state.input.gl = new_GetLine(ELFEDIT_MAXCMD, + ELFEDIT_MAXHIST); + /* Register our command completion function */ + (void) gl_customize_completion(state.input.gl, + NULL, cmd_match_fcn); + + /* + * Make autoprint the default for interactive + * sessions. + */ + state.flags |= ELFEDIT_F_AUTOPRINT; + } + for (;;) { + /* + * If this is an interactive session, then use + * sigsetjmp()/siglongjmp() to recover from bad + * commands and keep going. A non-0 return from + * sigsetjmp() means that an error just occurred. + * In that case, we simply restart this loop. + */ + if (state.input.is_tty) { + if (sigsetjmp(state.msg_jbuf.env, 1) != 0) { + if (state.input.full_tty) + gl_abandon_line(state.input.gl); + continue; + } + state.msg_jbuf.active = TRUE; + } + + /* + * Force all output out before each command. + * This is a no-OP when a tty is in use, but + * in a pipeline, it ensures that the block + * mode buffering doesn't delay output past + * the completion of each command. + * + * If we didn't do this, the output would eventually + * arrive at its destination, but the lag can be + * annoying when you pipe the output into a tool + * that displays the results in real time. + */ + (void) fflush(stdout); + (void) fflush(stderr); + + parse_user_cmd(read_cmd()); + dispatch_user_cmds(); + state.msg_jbuf.active = FALSE; + } + } + + + /*NOTREACHED*/ + return (0); +} diff --git a/usr/src/cmd/sgs/elfedit/common/elfedit.msg b/usr/src/cmd/sgs/elfedit/common/elfedit.msg new file mode 100644 index 0000000000..beca028867 --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/common/elfedit.msg @@ -0,0 +1,1548 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# + +@ _START_ + +# Message file for cmd/sgs/elfedit. + +@ MSG_ID_ELFEDIT + + +# Usage Messages + +@ MSG_USAGE_BRIEF "usage: elfedit [-adrw] [-e cmd] [-L modpath] \ + [-o style] [file] [outfile]\n" +@ MSG_USAGE_DETAIL1 "\t[-a] Autoprint (show edit results)\n" +@ MSG_USAGE_DETAIL2 "\t[-d] Issue messages describing internal \ + operations\n" +@ MSG_USAGE_DETAIL3 "\t[-e cmd] edit command\n" +@ MSG_USAGE_DETAIL4 "\t[-L modpath] Set module path\n" +@ MSG_USAGE_DETAIL5 "\t[-o ostyle] Output style (default|simple|num)\n" +@ MSG_USAGE_DETAIL6 "\t[-r] Readonly session (outfile not \ + allowed)\n" +@ MSG_USAGE_DETAIL_LAST "\n\tExtensive help for edit commands is available.\n\ + \tEnter 'help' at the elfedit prompt.\n" +@ MSG_USAGE_CMD "usage: %s\n" + + +# sys:set option names + +@ MSG_SYSSET_A "autoprint flag" +@ MSG_SYSSET_D "debug flag" + + +# Names of things we allocate dynamically + +@ MSG_ALLOC_OBJSTATE "object state" +@ MSG_ALLOC_SYMTABOS "symbol table information buffer" +@ MSG_ALLOC_MODDEF "module definition" +@ MSG_ALLOC_UCMD "user command state" +@ MSG_ALLOC_UCMDSTR "user command string buffer" +@ MSG_ALLOC_TOKBUF "user command token buffer" +@ MSG_ALLOC_BATCHLST "list of -e commands" +@ MSG_ALLOC_EXPATH "expanded module search path" +@ MSG_ALLOC_PATHARR "search path array" +@ MSG_ALLOC_HELPITEM "help state" +@ MSG_ALLOC_SECMSGPRE "section message prefix string" + +# Format strings + +@ MSG_FMT_BUILTIN "<built in>" +@ MSG_FMT_UNKNOWN "<unknown>" + +# Debug messages + +@ MSG_DEBUG_ADDDYNFLG "[%d: %s][%d]: Set DF_1_EDITED flag\n" +@ MSG_DEBUG_SEEDYNFLG "[%d: %s][%d]: Previously edited file \ + (DF_1_EDITED flag is set) \n" +@ MSG_DEBUG_CMDALIAS "Command %s:%s is an alias for %s:%s\n" +@ MSG_DEBUG_MODLOAD "load module: %s: %s\n" +@ MSG_DEBUG_MODUNLOAD "unload module: %s: %s\n" +@ MSG_DEBUG_CPFILE "copied %s to output file: %s\n"; +@ MSG_DEBUG_UNLINKFILE "unlink unsaved output file: %s\n"; +@ MSG_DEBUG_VERSION "%d-bit version\n" +@ MSG_DEBUG_READONLY "session is readonly\n"; +@ MSG_DEBUG_NOFILE "no ELF object specified. Limited functionalty is available\n"; +@ MSG_DEBUG_DIRTYEXIT "discarding unsaved edits\n"; +@ MSG_DEBUG_FNDCAP "[%d: %s]: capabilities section\n" +@ MSG_DEBUG_FNDDYN "[%d: %s]: dynamic section\n" +@ MSG_DEBUG_FNDSTR "[%d: %s][%d]: string: %s\n" +@ MSG_DEBUG_FNDSTRTAB "[%d: %s]: string table section\n" +@ MSG_DEBUG_FNDSYMTAB "[%d: %s]: %s symbol table section\n" +@ MSG_DEBUG_FNDSYMINFO "[%d: %s]: syminfo section\n" +@ MSG_DEBUG_FNDVERSYM "[%d: %s]: versym section: [%d: %s]\n" +@ MSG_DEBUG_FNDXSHNDX "[%d: %s]: extended section index section: [%d: %s]\n" +@ MSG_DEBUG_EXISTSTR "[%d: %s][%d]: Found existing string in section: %s\n" +@ MSG_DEBUG_ADDSTR "[%d: %s][%d]: Using %d/%d byes from reserved area \ + to add string: %s\n" +@ MSG_DEBUG_NULL2DYNFL1 "[%d: %s]: No existing flags1 field to modify. \ + Will use extra DT_NULL in slot [%d] \n" +@ MSG_DEBUG_AUX_LINK "[%d: %s]: Ignoring section: sh_link field references \ + non-symbol table section: [%d]\n" +@ MSG_DEBUG_AUX_SIZE "[%d: %s][%d]: Ignoring section: Not enough elements \ + for corresponding symbol table: [%d: %s][%d]\n" +@ MSG_DEBUG_EXECCMD "command: %s\n" +@ MSG_DEBUG_SHNAM2NDX "[%d: %s]: section name: %s\n" +@ MSG_DEBUG_SYMNAM2NDX "[%d: %s][%d]: symbol \"%s\"\n" +@ MSG_DEBUG_INPLACEWARN "warning: editing input file in place is not \ + recommended: %s\n" +@ MSG_DEBUG_SHNDX_RANGE "Specified section index [%d] is outside of valid \ + of range for this object: 0-%d\n" +@ MSG_DEBUG_ARRCPY_1 "%s: copy array element [%d] to [%d]\n" +@ MSG_DEBUG_ARRCPY_N "%s: copy array elements [%d-%d] to [%d-%d]\n" +@ MSG_DEBUG_ARRZERO_1 "%s[%d]: zero array element\n" +@ MSG_DEBUG_ARRZERO_N "%s[%d-%d]: zero %d array elements\n" +@ MSG_DEBUG_ARRMOVE_1 "%s: moved element [%d] to [%d]\n" +@ MSG_DEBUG_ARRMOVE_N "%s: moved %d elements from [%d-%d] to [%d-%d]\n" + +# Errors + +@ MSG_ERR_NOFILSYSONLY "No ELF object specified. Only commands from \ + module sys: are allowed: %s:%s\n" +@ MSG_ERR_BADOSTYLE "Unrecognized output style \ + (default|simple|num): %s\n" +@ MSG_ERR_BADCONST "internal error: bad constant value in \ + elfedit_const_to_atoui()\n" +@ MSG_ERR_BADGETVAL "internal error: bad required value passed to \ + elfedit_XXX_get_value()\n" +@ MSG_ERR_PATHTOOLONG "path too long: %s/%s.so\n" +@ MSG_ERR_CNTDLOPEN "unable to load module sharable object %s: %s\n" +@ MSG_ERR_CNTDLCLOSE "unable to unload module sharable object %s: %s\n" +@ MSG_ERR_UNRECMOD "no such module: %s\n" +@ MSG_ERR_UNRECCMD "no such command: %s:%s\n" +@ MSG_ERR_SONOTMOD "sharable object is not a valid elfedit module: %s\n" +@ MSG_ERR_CNTULSMOD "cannot unload built in module: %s\n" +@ MSG_ERR_NULLPRICMDNAM "module has empty string for primary command: %s\n" +@ MSG_ERR_BADMODLOAD "elfedit module failed to initialize: %s\n" +@ MSG_ERR_BADMODNAME "sharable library provides module '%s' rather \ + than expected '%s': %s\n" +@ MSG_ERR_OPT_MODPRE "command option name must start with \ + a '-': %s : %s:%s %s\n" +@ MSG_ERR_OPT_MODLEN "command option name must have at least one character: \ + %s : %s:%s %s\n" +@ MSG_ERR_OPT_EXCMASKN0 "command option oa_excmask is non-zero when \ + oa_idmask is zero: %s : %s:%s %s\n" +@ MSG_ERR_OPT_IDMASKPOW2 "command option oa_idmask must be 0 or power \ + of 2: %s : %s:%s %s\n" +@ MSG_ERR_OPT_IDMASKUNIQ "command option oa_idmask must be 0 or must be unique \ + value: %s : %s:%s %s\n" +@ MSG_ERR_ARG_MODPRE "command argument name may not start with \ + a '-': %s : %s:%s %s\n" +@ MSG_ERR_ARG_MODLEN "command argument name must have at least one \ + character: %s : %s:%s %s\n" +@ MSG_ERR_ARG_CMDOA_VAL "command argument has ELFEDIT_CMDOA_F_VALUE set, \ + which is only allowed for command \ + options: %s : %s:%s %s\n" +@ MSG_ERR_ARG_MASKNOT0 "command argument oa_idmask and oa_excmask fields \ + must both be set to 0: %s : %s:%s %s\n" +@ MSG_ERR_BADSTDOA "internal error: argument or option uses \ + ELFEDIT_CMDOA_F_VALUE incorrectly: %s : %s:%s\n" +@ MSG_ERR_CMDOA_VALNAM "ELFEDIT_CMDOA_F_VALUE optarg has NULL \ + oa_name: %s : %s:%s %s\n" +@ MSG_ERR_CMDOA_VALNOT0 "ELFEDIT_CMDOA_F_VALUE optarg has non-0 oa_help, \ + oa_flags, oa_idmask or oa_excmask \ + field: %s : %s:%s %s\n" +@ MSG_ERR_BADMODOPTVAL "command option has ELFEDIT_CMDOA_F_VALUE bit set, \ + but following value item is missing: %s : %s:%s %s\n" +@ MSG_ERR_CNTOPNFILE "open failed: %s: %s\n" +@ MSG_ERR_CNTOPNDIR "unable to read directory: %s: %s\n" +@ MSG_ERR_SIGACTION "unable to set signal handler: %s\n" +@ MSG_ERR_NOAR "unable to edit ELF archive: %s\n" +@ MSG_ERR_UNRECELFFILE "unable to edit non-ELF file: %s\n" +@ MSG_ERR_BADELFCLASS "unable to edit file with unknown ELFCLASS: %s\n" +@ MSG_ERR_MALLOC "%s: malloc: %s\n" +@ MSG_ERR_LIBELF "%s: %s failed: %s\n" +@ MSG_ERR_MODNOCMD "module '%s' specified without a command\n" +@ MSG_ERR_CNTFORK "unable to execute child process: %s\n" +@ MSG_ERR_CNTWAIT "unable to wait for child process: %s\n" +@ MSG_ERR_CNTEXEC "%sunable to exec %s: %s\n" +@ MSG_ERR_CNTSTAT "unable to stat %s: %s\n" +@ MSG_ERR_CNTCHMOD "unable to chmod %s: %s\n" +@ MSG_ERR_BADSECNDX "Specified section index [%d] is outside valid \ + range: 1-%d\n" +@ MSG_ERR_NOCAP "ELF object does not have a capabilities section\n" +@ MSG_ERR_NODYN "ELF object does not have a dynamic section\n" +@ MSG_ERR_NOSYM "[%d: %s]: Symbol table does not contain symbol: %s\n" +@ MSG_ERR_NOSYMTAB "symbol table section not found\n" +@ MSG_ERR_NOSYMINFO "ELF object does not have a syminfo section\n" +@ MSG_ERR_NOTSYMTAB "[%d: %s]: section is not a symbol table\n" +@ MSG_ERR_STRSHNDX "string section index %d is outside expected \ + range %d - %d\n" +@ MSG_ERR_NOTSTRSH "[%d: %s]: Section is not a string table as expected\n" +@ MSG_ERR_NOSTRPAD "[%d: %s]: String table does not have room to add \ + string\n" +@ MSG_ERR_BADSTROFF "[%d: %s]: String offset [%d] is outside valid \ + range: 0-%d\n" +@ MSG_ERR_NOVERSYMSEC "[%d: %s]: symbol table does not have an associated \ + versym section\n" +@ MSG_ERR_NOXSHSEC "[%d: %s]: symbol table does not have an associated \ + extended index section\n" +@ MSG_ERR_BADATOISTR "not a valid numeric value: '%s'\n" +@ MSG_ERR_ATOIRANGE "%s value is out of range [%lld - %lld]: %lld\n" +@ MSG_ERR_ATOUIRANGE "%s value is out of range [%llu - %llu]: %llu\n" +@ MSG_ERR_BADPATHCODE "Unrecognized code encountered in module \ + search path: %%%c\n" +@ MSG_ERR_UNKNOWNSYSERR "<unknown>" +@ MSG_ERR_PAGERFINI "Error encountered closing pager process\n" +@ MSG_ERR_PRINTF "Error encountered writing output\n" +@ MSG_ERR_FWRITE "Error encountered writing output: %s\n" +@ MSG_ERR_MODNAMTOOLONG "module name too long: %s\n" +@ MSG_ERR_CNTGETORIGIN "Unable to determine elfedit $ORIGIN\n" +@ MSG_ERR_GLREAD "error reading from stdin: %s\n" +@ MSG_ERR_READONLY "Operation not allowed in readonly session\n" +@ MSG_ERR_NODIRTYQUIT "Output ELF file has changes pending. Use 'write' \ + to save them, or 'quit -f' to exit without saving\n" +@ MSG_ERR_NOSECNAM "File does not contain section of name: %s\n" +@ MSG_ERR_NOSECTYP "File does not contain section of type: %s\n" +@ MSG_ERR_ARRBNDS "%s[%d]: attempt to access elements outside \ + of valid of range for this section: 0-%d\n" +@ MSG_ERR_ARRMVOVERLAP "%s: Array source [%d-%d] and destination \ + [%d-%d] regions overlap\n" + +# Format strings for sys:help +@ MSG_HLPFMT_MOD "\nMODULE\n %s - %s\n" +@ MSG_HLPFMT_NAME "\nNAME\n %s - %s\n" +@ MSG_HLPFMT_SYNOPSIS "\nSYNOPSIS\n %s\n" +@ MSG_HLPFMT_ALIASES "\nALIASES\n" +@ MSG_HLPFMT_MODDEFCMD "module default"; +@ MSG_HLPFMT_DEFCMD "\t\t(Default Command For Module)"; +@ MSG_HLPFMT_DESC "\nDESCRIPTION\n" +@ MSG_HLPFMT_ARGS "\nARGUMENTS\n" +@ MSG_HLPFMT_OPT "\nOPTIONS\n" +@ MSG_HLPFMT_MULTIEND "[End: %s, Next: %s]\n" +@ MSG_HLPFMT_INFILE "Input File: %s\n" +@ MSG_HLPFMT_INFILERO "Input File: %s (readonly)\n" +@ MSG_HLPFMT_INFILENONE "Input File: <not present>\n" +@ MSG_HLPFMT_OUTFILE "Output File: %s\n" +@ MSG_HLPFMT_CNGPENDING " (changes pending)\n" +@ MSG_HLPFMT_VARHDR "\nOptions:\n" +@ MSG_HLPFMT_AFLG " a (Autoprint): %s\n" +@ MSG_HLPFMT_DFLG " d (Debug): %s\n" +@ MSG_HLPFMT_OFLG " o (Output Style): %s\n" +@ MSG_HLPFMT_PATHHDR "\nModule Load Path:\n" +@ MSG_HLPFMT_MODHDR "\nCurrently Loaded Modules:\n" +@ MSG_HLPFMT_SUMSYNOPSIS "\n %s\n" + + +# Names we use when an ELF item lacks a name + +@ MSG_UNKNOWNSECNAM "<unknown section name>" +@ MSG_BADSYMOFFSETNAM "<bad symbol name>" + + +# builtin sys: module description + +@ MSG_MOD_SYS_DESC "Built in elfedit commands" + + +# 1-line description strings for builtin commands. + +@ MSG_SYS_DESC_HELP "Display module information and/or command \ + documentation" +@ MSG_SYS_DESC_LOAD "Load module(s)" +@ MSG_SYS_DESC_SET "Set elfedit options" +@ MSG_SYS_DESC_STATUS "Session status (files, modules, options)" +@ MSG_SYS_DESC_QUIT "Exit elfedit session" +@ MSG_SYS_DESC_UNLOAD "Unload module(s)" +@ MSG_SYS_DESC_WRITE "Flush any changes back to current ELF file" + + +# Command option description strings for builtin commands + +@ MSG_SYS_OPTDESC_HELP_S "\ + Generate a command synopsis rather than full command help.\n" + +@ MSG_SYS_OPTDESC_LOAD_A "\ + Load every module that can be found by following the module\n\ + load path.\n" +@ MSG_SYS_OPTDESC_QUIT_F "\ + Exit the elfedit session without first requiring changes to\n\ + be saved. Any modifications made to the output file will be\n\ + quietly discarded, and will be lost." +@ MSG_SYS_OPTDESC_UNLOAD_A "\ + Unload every currently loaded module. Loaded modules can be\n\ + displayed using the \"status\" command.\n" + + +# Command option description strings for builtin commands + +@ MSG_ARGDESC_HELP_ARG "\ + Items for which help is desired. Module names and/or command\n\ + names are allowed, as described above.\n" +@ MSG_ARGDESC_LOAD_MODNAME "Name(s) of modules to be loaded.\n" +@ MSG_ARGDESC_SET_OPTION "Name of option to be set.\n" +@ MSG_ARGDESC_SET_VALUE "Value to be set for option.\n" +@ MSG_ARGDESC_UNLOAD_MODNAME "Name(s) of modules to be loaded.\n" + + +# Help text for builtin commands. + +@ MSG_SYS_HELP_HELP_NOARG " \ + Welcome to elfedit, a utility for examining and editing\n\ + ELF objects. This brief discussion will tell you the basics\n\ + you need to know in order to use the elfedit help facility.\n\ + With that, you will be able to find desired information about\n\ + elfedit and its available commands.\n\ + \n\ + To reach the point where you are reading this text, you entered\n\ + the elfedit command \"help\", without any arguments. Actually, you\n\ + may have entered any of the following:\n\ + \n\ + \t?, help, man, sys:?, sys:help, sys:man\n\ + \n\ + As we will see below, these are simply different names for the\n\ + help command.\n\ + \n\ + You use elfedit by issuing commands for it to execute.\n\ + The syntax is similar to that used by Unix command line\n\ + utilities, and follows the general form:\n\ + \n\ + \t> module:command [-opt]... arg...\n\ + \n\ + The '>' character is the elfedit prompt, and not part of the\n\ + command. We show elfedit commands with the prompt, but you\n\ + should not type the prompt in. elfedit supplies it to let\n\ + you know when it is expecting a command to process.\n\ + \n\ + As with a Unix utility, there are options (which start with a '-'\n\ + character) and plain arguments (which do not start with a '-').\n\ + The plain arguments follow the options. The options and plain\n\ + arguments differ from command to command. Each command sets its own\n\ + rules for whether it accepts options and arguments, as well as\n\ + which ones and how many. These details are found in the online\n\ + help that is available for each command. To learn more about\n\ + any command, use the help command:\n\ + \n\ + \t> help cmdname\n\ + \n\ + where 'cmdname' is the name of the command you are interested in.\n\ + help is simply an elfedit command, like any other. As such, you\n\ + can read the full documentation for help by entering the command:\n\ + \n\ + \t> help sys:help\n\ + \n\ + elfedit functionality is organized as \"modules\", which are\n\ + dynamically loadable ELF objects that contain related editing\n\ + commands. To refer to a command, you enter its module name,\n\ + a colon (:), and the command name, all as a single unit without\n\ + any intervening white-space. The 'sys' module is special: It is\n\ + a built in module that contains the core commands required for\n\ + elfedit to work. As a convenience, if you omit the module name\n\ + from a command, elfedit assumes that you are referring to the sys\n\ + module. This is why sys:help and help are really the same command,\n\ + and why we did not have to write the above help command as:\n\ + \n\ + \t> sys:help sys:help\n\ + \n\ + In fact, we could have written it even more simply, as:\n\ + \n\ + \t> help help\n\ + \n\ + To access a command from any module other than sys, you must\n\ + enter both the module and command names. This means that if\n\ + you write your own module, the module name needs to be unique,\n\ + but the command names it supplies can be the same names used by\n\ + other modules. For instance, most elfedit modules supply a command\n\ + named dump to display information about their part of the ELF \n\ + file in a style similar to that used by the Unix elfdump command.\n\ + Despite having the same name (dump), these are all distinct and\n\ + separate commands. elfedit uses the module/command pair to know\n\ + which one you mean.\n\ + \n\ + elfedit commands can sometimes have more than one name, or alias.\n\ + Usually, each command only has one name, but there are some\n\ + exceptions. For example, as we have already seen, sys:?, and \n\ + sys:man are aliases of sys:help. These are all common names\n\ + that different programs use to supply help. elfedit accepts all\n\ + of these names in the hope that a new user who doesn't know\n\ + elfedit yet will try one of them, and find this information.\n\ + \n\ + Most modules provide a \"default command\". This command will be\n\ + run if you provide only the module name. Most modules use this\n\ + feature to provide a shortcut for their \"dump\" command. For\n\ + instance, both of the following commands run dyn:dump:\n\ + \n\ + \t> dyn:\n\ + \t> dyn:dump\n\ + \n\ + Although the command name dump was not required, the colon\n\ + (:) character is. Without it, elfedit will think you mean the\n\ + command sys:dyn.\n\ + \n\ + Using the help command (sys:help), you can easily learn about\n\ + the other commands that are available. To see which modules\n\ + are available and a synopsis of the commands they provide:\n\ + \n\ + \t> help -s\n\ + \n\ + To see the full documentation for a command, you give the\n\ + name of the command to the help command as a plain argument.\n\ + As we saw above, this command will show you the detailed\n\ + documentation for the help command itself:\n\ + \n\ + \t> help help\n\ + \n\ + The arguments to help can also be module names, without the\n\ + command. In that case, output similar to that from the -s\n\ + option will be displayed for that module.\n\ + \n\ + If you are new to elfedit, we recommend that you start by learning\n\ + about the commands in the sys module. This will provide you with\n\ + such basic knowledge as how to find out the status of your session\n\ + (sys:status) or how to exit the elfedit program (sys:quit). Once\n\ + you understand the basic commands, you can branch out and learn\n\ + about the available modules and commands and how they can be used\n\ + to edit ELF files.\n" + + + + +@ MSG_SYS_HELP_HELP " \ + The sys:help command provides information on elfedit modules\n\ + and commands:\n\ + \n\ + o\tIf called with command names as arguments, documentation\n\ + \tfor each given command is displayed. If the -s option is\n\ + \tspecified, a basic synopsis for the command is given.\n\ + \tOtherwise, the full documentation is shown.\n\ + \n\ + o\tIf called with module names as arguments, the name and\n\ + \tpurpose of each module is shown, along with a brief synopsis\n\ + \tof the commands the module provides.\n\ + \n\ + o\tIf called with the -s option, and no arguments, a brief\n\ + \tsynopsis of every command is shown, organized by module,\n\ + \tfor every module visible from the module load path.\n\ + \n\ + o\tIf called with no arguments, and the -s option is not\n\ + \tused, a brief welcome message is displayed, giving basic\n\ + \tinformation on elfedit operation and the use of the\n\ + \thelp command.\n" + +@ MSG_SYS_HELP_LOAD "\ + The sys:load command is used to explicitly load elfedit modules.\n\ + \n\ + Most of the functionality available in elfedit is not built\n\ + into the elfedit program directly. Instead, functionality\n\ + is contained in \"modules\", which are implemented as dynamically\n\ + loadable ELF sharable objects. This design allows for easy\n\ + extensibility of elfedit's abilities, and it is also efficient,\n\ + since it allows elfedit to be a relatively small program.\n\ + \n\ + elfedit will automatically load a module under the following\n\ + circumstances:\n\ + \n \ + o\tA command from the module needs to be run.\n\ + \n \ + o\tTo display help information about the module or a command\n\ + \tfound in the module.\n\ + \n \ + o\tTo perform command completion in an interactive session.\n\ + \tCommand completion can cause many, or all modules visible\n\ + \tin the module path to be loaded.\n\ + \n\ + There is usually little need for explicit module loading.\n\ + It is usually best to allow elfedit to load modules as they\n\ + are needed.\n" + +@ MSG_SYS_HELP_SET "\ + Set options that control how elfedit works.\n\ + \n\ + Most variables accept boolen (true/false) values. The sys:set\n\ + command accepts any of the following as a boolean value:\n\ + 0/1, true/false, t/f, yes/no, y/n, on/off.\n\ + \n\ + The variables, and their allowed values, are as follows:\n\ + \n\ + a\tAutoprint [boolean]\n\ + \tWhen autoprint is active, elfedit automatically displays\n\ + \tthe results of any edits after carrying them out. By default,\n\ + \tautoprint is on for interactive sessions, and false for\n\ + \tsessions where the input is not a tty. The elfedit -a option\n\ + \tcan be used to enable autoprint at session start.\n\ + \n\ + d\tDebug [boolean]\n\ + \tWhen enabled, elfedit issues detailed messages showing\n\ + \twhere ELF data is being accessed, and how specific edits\n\ + \tare being carried out. Debug mode is off by default. The\n\ + \telfedit -d option can be used to enable debug mode at\n\ + \tsession start.\n\ + \n\ + o\tOutput Style [default, simple, num]\n\ + \tControls the format in which elfedit prints ELF data:\n\ + \n\ + \tdefault\n\ + \tInformation is displayed in a style similar to that used by\n\ + \tthe elfdump utility. This style is best for interactive use.\n\ + \n\ + \tsimple\n\ + \tData is displayed in a simple format, without extraneous\n\ + \tinformation or formatting. Strings are displayed as is.\n\ + \tNumbers are displayed as symbolic constants when possible,\n\ + \tand in integer form otherwise.\n\ + \n\ + \tnum\n\ + \tInteger values are always shown in integer form. Strings\n\ + \tare shown as the integer offset into the containing string\n\ + \ttable.\n" + +@ MSG_SYS_HELP_STATUS "\ + The status of the current elfedit session is shown:\n\ + \n\ + o\tInput and output files\n\ + \n\ + o\tCurrent settings of the elfedit options (See 'help set'\n\ + \tfor more information on elfedit options)\n\ + \n\ + o\tModule load path\n\ + \n\ + o\tLoaded modules and the paths of the sharable objects\n\ + \tthat provide them\n" + +@ MSG_SYS_HELP_QUIT "\ + Exits the elfedit session.\n\ + \n\ + elfedit will normally refuse to exit a non-readonly session\n\ + while there are unsaved edits pending. The sys:write command\n\ + can be used to save such edits, or the -f option can be used to\n\ + discard pending edits and exit immediately.\n" + +@ MSG_SYS_HELP_UNLOAD "\ + The sys:unload command is used to explicitly unload elfedit modules.\n\ + \n\ + There is usually little need to explicitly unload modules.\n\ + \n\ + The description of the sys:load command discusses module loading\n\ + in more detail.\n" + +@ MSG_SYS_HELP_WRITE "\ + Writes all pending edits to the output file. Until this is done,\n\ + the edits are not permanent, and can be abandoned by exiting the\n\ + session using the -f option to sys:quit. Once sys:write is used,\n\ + these changes become permanent.\n" + + + +# Command option description strings for inheritable option strings + +@ MSG_STDOA_OPTDESC_AND "\ + The new value should be bitwised AND'd against the\n\ + existing value.\n" + +@ MSG_STDOA_OPTDESC_CMP "\ + The new value should be bitwise complemented\n\ + (1 values set to 0, and 0 values set to 1) before being\n\ + applied to the existing value.\n" + +@ MSG_STDOA_OPTDESC_O "\ + Overrides the global output style (as set via the sys:set\n\ + command) for the duration of the call to this command.\n\ + The valid values for the outstyle argument are: default,\n\ + simple, or num.\n\ + \n\ + Output styles are described in more detail in the documentation\n\ + for the sys:set command.\n" + +@ MSG_STDOA_OPTDESC_OR "\ + The new value should be bitwised OR'd against the\n\ + existing value.\n" + + + + +@ _END_ + + +# The following strings represent reserved words, files, pathnames and symbols. +# Reference to this strings is via the MSG_ORIG() macro, and thus no message +# translation is required. + +# Names of libelf functions + +@ MSG_ELF_BEGIN "elf_begin" +@ MSG_ELF_GETEHDR "elf_getehdr" +@ MSG_ELF_GETDATA "elf_getdata" +@ MSG_ELF_GETPHNUM "elf_getphnum" +@ MSG_ELF_GETPHDR "elf_getphdr" +@ MSG_ELF_GETSCN "elf_getscn" +@ MSG_ELF_GETSHDR "elf_getshdr" +@ MSG_ELF_GETSHNUM "elf_getshnum" +@ MSG_ELF_GETSHSTRNDX "elf_getshstrndx" +@ MSG_ELF_UPDATE "elf_update" + + +# Names of special section indexes + +@ MSG_SHN_UNDEF "SHN_UNDEF" # 0 +@ MSG_SHN_UNDEF_ALT1 "undef" +@ MSG_SHN_SUNW_IGNORE "SHN_SUNW_IGNORE" # 0xff3f +@ MSG_SHN_SUNW_IGNORE_ALT1 "sunw_ignore" +@ MSG_SHN_BEFORE "SHN_BEFORE" # 0xff00 +@ MSG_SHN_BEFORE_ALT1 "before" +@ MSG_SHN_AFTER "SHN_AFTER" # 0xff01 +@ MSG_SHN_AFTER_ALT1 "after" +@ MSG_SHN_AMD64_LCOMMON "SHN_AMD64_LCOMMON" # 0xff02 +@ MSG_SHN_AMD64_LCOMMON_ALT1 "amd64_lcommon" +@ MSG_SHN_ABS "SHN_ABS" # 0xfff1 +@ MSG_SHN_ABS_ALT1 "abs" +@ MSG_SHN_COMMON "SHN_COMMON" # 0xfff2 +@ MSG_SHN_COMMON_ALT1 "common" +@ MSG_SHN_XINDEX "SHN_XINDEX" # 0xffff +@ MSG_SHN_XINDEX_ALT1 "xindex" + + +# Names of sh_type SHT_* type constants + +@ MSG_SHT_NULL "SHT_NULL" # 0 +@ MSG_SHT_NULL_ALT1 "null" +@ MSG_SHT_PROGBITS "SHT_PROGBITS" # 1 +@ MSG_SHT_PROGBITS_ALT1 "progbits" +@ MSG_SHT_SYMTAB "SHT_SYMTAB" # 2 +@ MSG_SHT_SYMTAB_ALT1 "symtab" +@ MSG_SHT_STRTAB "SHT_STRTAB" # 3 +@ MSG_SHT_STRTAB_ALT1 "strtab" +@ MSG_SHT_RELA "SHT_RELA" # 4 +@ MSG_SHT_RELA_ALT1 "rela" +@ MSG_SHT_HASH "SHT_HASH" # 5 +@ MSG_SHT_HASH_ALT1 "hash" +@ MSG_SHT_DYNAMIC "SHT_DYNAMIC" # 6 +@ MSG_SHT_DYNAMIC_ALT1 "dynamic" +@ MSG_SHT_NOTE "SHT_NOTE" # 7 +@ MSG_SHT_NOTE_ALT1 "note" +@ MSG_SHT_NOBITS "SHT_NOBITS" # 8 +@ MSG_SHT_NOBITS_ALT1 "nobits" +@ MSG_SHT_REL "SHT_REL" # 9 +@ MSG_SHT_REL_ALT1 "rel" +@ MSG_SHT_SHLIB "SHT_SHLIB" # 10 +@ MSG_SHT_SHLIB_ALT1 "shlib" +@ MSG_SHT_DYNSYM "SHT_DYNSYM" # 11 +@ MSG_SHT_DYNSYM_ALT1 "dynsym" +@ MSG_SHT_INIT_ARRAY "SHT_INIT_ARRAY" # 14 +@ MSG_SHT_INIT_ARRAY_ALT1 "init_array" +@ MSG_SHT_FINI_ARRAY "SHT_FINI_ARRAY" # 15 +@ MSG_SHT_FINI_ARRAY_ALT1 "fini_array" +@ MSG_SHT_PREINIT_ARRAY "SHT_PREINIT_ARRAY" # 16 +@ MSG_SHT_PREINIT_ARRAY_ALT1 "preinit_ARRAY" +@ MSG_SHT_GROUP "SHT_GROUP" # 17 +@ MSG_SHT_GROUP_ALT1 "group" +@ MSG_SHT_SYMTAB_SHNDX "SHT_SYMTAB_SHNDX" # 18 +@ MSG_SHT_SYMTAB_SHNDX_ALT1 "symtab_shndx" +@ MSG_SHT_SUNW_SYMSORT "SHT_SUNW_symsort" # 0x6ffffff1 +@ MSG_SHT_SUNW_SYMSORT_ALT1 "sunw_symsort" +@ MSG_SHT_SUNW_TLSSORT "SHT_SUNW_tlssort" # 0x6ffffff2 +@ MSG_SHT_SUNW_TLSSORT_ALT1 "sunw_tlssort" +@ MSG_SHT_SUNW_LDYNSYM "SHT_SUNW_LDYNSYM" # 0x6ffffff3 +@ MSG_SHT_SUNW_LDYNSYM_ALT1 "sunw_ldynsym" +@ MSG_SHT_SUNW_DOF "SHT_SUNW_dof" # 0x6ffffff4 +@ MSG_SHT_SUNW_DOF_ALT1 "sunw_dof" +@ MSG_SHT_SUNW_CAP "SHT_SUNW_cap" # 0x6ffffff5 +@ MSG_SHT_SUNW_CAP_ALT1 "sunw_cap" +@ MSG_SHT_SUNW_SIGNATURE "SHT_SUNW_SIGNATURE" # 0x6ffffff6 +@ MSG_SHT_SUNW_SIGNATURE_ALT1 "sunw_signature" +@ MSG_SHT_SUNW_ANNOTATE "SHT_SUNW_ANNOTATE" # 0x6ffffff7 +@ MSG_SHT_SUNW_ANNOTATE_ALT1 "sunw_annotate" +@ MSG_SHT_SUNW_DEBUGSTR "SHT_SUNW_DEBUGSTR" # 0x6ffffff8 +@ MSG_SHT_SUNW_DEBUGSTR_ALT1 "sunw_debugstr" +@ MSG_SHT_SUNW_DEBUG "SHT_SUNW_DEBUG" # 0x6ffffff9 +@ MSG_SHT_SUNW_DEBUG_ALT1 "sunw_debug" +@ MSG_SHT_SUNW_MOVE "SHT_SUNW_move" # 0x6ffffffa +@ MSG_SHT_SUNW_MOVE_ALT1 "sunw_move" +@ MSG_SHT_SUNW_COMDAT "SHT_SUNW_COMDAT" # 0x6ffffffb +@ MSG_SHT_SUNW_COMDAT_ALT1 "sunw_comdat" +@ MSG_SHT_SUNW_SYMINFO "SHT_SUNW_syminfo" # 0x6ffffffc +@ MSG_SHT_SUNW_SYMINFO_ALT1 "sunw_syminfo" +@ MSG_SHT_SUNW_VERDEF "SHT_SUNW_verdef" # 0x6ffffffd +@ MSG_SHT_SUNW_VERDEF_ALT1 "sunw_verdef" +@ MSG_SHT_GNU_VERDEF "SHT_GNU_verdef" # 0x6ffffffd +@ MSG_SHT_GNU_VERDEF_ALT1 "gnu_verdef" +@ MSG_SHT_SUNW_VERNEED "SHT_SUNW_verneed" # 0x6ffffffe +@ MSG_SHT_SUNW_VERNEED_ALT1 "sunw_verneed" +@ MSG_SHT_GNU_VERNEED "SHT_GNU_verneed" # 0x6ffffffe +@ MSG_SHT_GNU_VERNEED_ALT1 "gnu_verneed" +@ MSG_SHT_SUNW_VERSYM "SHT_SUNW_versym" # 0x6fffffff +@ MSG_SHT_SUNW_VERSYM_ALT1 "sunw_versym" +@ MSG_SHT_GNU_VERSYM "SHT_GNU_versym" # 0x6fffffff +@ MSG_SHT_GNU_VERSYM_ALT1 "gnu_versym" +@ MSG_SHT_SPARC_GOTDATA "SHT_SPARC_GOTDATA" # 0x7000000 +@ MSG_SHT_SPARC_GOTDATA_ALT1 "sparc_gotdata" +@ MSG_SHT_AMD64_UNWIND "SHT_AMD64_UNWIND" # 0x7000000 +@ MSG_SHT_AMD64_UNWIND_ALT1 "amd64_unwind" + + +# Names of dynamic section entry tags + +@ MSG_DT_NULL "DT_NULL" # 0 +@ MSG_DT_NULL_ALT1 "null" +@ MSG_DT_NEEDED "DT_NEEDED" # 1 +@ MSG_DT_NEEDED_ALT1 "needed" +@ MSG_DT_PLTRELSZ "DT_PLTRELSZ" # 2 +@ MSG_DT_PLTRELSZ_ALT1 "pltrelsz" +@ MSG_DT_PLTGOT "DT_PLTGOT" # 3 +@ MSG_DT_PLTGOT_ALT1 "pltgot" +@ MSG_DT_HASH "DT_HASH" # 4 +@ MSG_DT_HASH_ALT1 "hash" +@ MSG_DT_STRTAB "DT_STRTAB" # 5 +@ MSG_DT_STRTAB_ALT1 "strtab" +@ MSG_DT_SYMTAB "DT_SYMTAB" # 6 +@ MSG_DT_SYMTAB_ALT1 "symtab" +@ MSG_DT_RELA "DT_RELA" # 7 +@ MSG_DT_RELA_ALT1 "rela" +@ MSG_DT_RELASZ "DT_RELASZ" # 8 +@ MSG_DT_RELASZ_ALT1 "relasz" +@ MSG_DT_RELAENT "DT_RELAENT" # 9 +@ MSG_DT_RELAENT_ALT1 "relaent" +@ MSG_DT_STRSZ "DT_STRSZ" # 10 +@ MSG_DT_STRSZ_ALT1 "strsz" +@ MSG_DT_SYMENT "DT_SYMENT" # 11 +@ MSG_DT_SYMENT_ALT1 "syment" +@ MSG_DT_INIT "DT_INIT" # 12 +@ MSG_DT_INIT_ALT1 "init" +@ MSG_DT_FINI "DT_FINI" # 13 +@ MSG_DT_FINI_ALT1 "fini" +@ MSG_DT_SONAME "DT_SONAME" # 14 +@ MSG_DT_SONAME_ALT1 "soname" +@ MSG_DT_RPATH "DT_RPATH" # 15 +@ MSG_DT_RPATH_ALT1 "rpath" +@ MSG_DT_SYMBOLIC "DT_SYMBOLIC" # 16 +@ MSG_DT_SYMBOLIC_ALT1 "symbolic" +@ MSG_DT_REL "DT_REL" # 17 +@ MSG_DT_REL_ALT1 "rel" +@ MSG_DT_RELSZ "DT_RELSZ" # 18 +@ MSG_DT_RELSZ_ALT1 "relsz" +@ MSG_DT_RELENT "DT_RELENT" # 19 +@ MSG_DT_RELENT_ALT1 "relent" +@ MSG_DT_PLTREL "DT_PLTREL" # 20 +@ MSG_DT_PLTREL_ALT1 "pltrel" +@ MSG_DT_DEBUG "DT_DEBUG" # 21 +@ MSG_DT_DEBUG_ALT1 "debug" +@ MSG_DT_TEXTREL "DT_TEXTREL" # 22 +@ MSG_DT_TEXTREL_ALT1 "textrel" +@ MSG_DT_JMPREL "DT_JMPREL" # 23 +@ MSG_DT_JMPREL_ALT1 "jmprel" +@ MSG_DT_BIND_NOW "DT_BIND_NOW" # 24 +@ MSG_DT_BIND_NOW_ALT1 "bind_now" +@ MSG_DT_INIT_ARRAY "DT_INIT_ARRAY" # 25 +@ MSG_DT_INIT_ARRAY_ALT1 "init_array" +@ MSG_DT_FINI_ARRAY "DT_FINI_ARRAY" # 26 +@ MSG_DT_FINI_ARRAY_ALT1 "fini_array" +@ MSG_DT_INIT_ARRAYSZ "DT_INIT_ARRAYSZ" # 27 +@ MSG_DT_INIT_ARRAYSZ_ALT1 "init_arraysz" +@ MSG_DT_FINI_ARRAYSZ "DT_FINI_ARRAYSZ" # 28 +@ MSG_DT_FINI_ARRAYSZ_ALT1 "fini_arraysz" +@ MSG_DT_RUNPATH "DT_RUNPATH" # 29 +@ MSG_DT_RUNPATH_ALT1 "runpath" +@ MSG_DT_FLAGS "DT_FLAGS" # 30 +@ MSG_DT_FLAGS_ALT1 "flags" +@ MSG_DT_PREINIT_ARRAY "DT_PREINIT_ARRAY" # 32 +@ MSG_DT_PREINIT_ARRAY_ALT1 "preinit_array" +@ MSG_DT_PREINIT_ARRAYSZ "DT_PREINIT_ARRAYSZ" # 33 +@ MSG_DT_PREINIT_ARRAYSZ_ALT1 "preinit_arraysz" +@ MSG_DT_SUNW_AUXILIARY "DT_SUNW_AUXILIARY" # 0x6000000d +@ MSG_DT_SUNW_AUXILIARY_ALT1 "sunw_auxiliary" +@ MSG_DT_SUNW_RTLDINF "DT_SUNW_RTLDINF" # 0x6000000e +@ MSG_DT_SUNW_RTLDINF_ALT1 "sunw_rtldinf" +@ MSG_DT_SUNW_FILTER "DT_SUNW_FILTER" # 0x6000000f +@ MSG_DT_SUNW_FILTER_ALT1 "sunw_filter" +@ MSG_DT_SUNW_CAP "DT_SUNW_CAP" # 0x60000010 +@ MSG_DT_SUNW_CAP_ALT1 "sunw_cap" +@ MSG_DT_SUNW_SYMTAB "DT_SUNW_SYMTAB" # 0x60000011 +@ MSG_DT_SUNW_SYMTAB_ALT1 "sunw_symtab" +@ MSG_DT_SUNW_SYMSZ "DT_SUNW_SYMSZ" # 0x60000012 +@ MSG_DT_SUNW_SYMSZ_ALT1 "sunw_symsz" +@ MSG_DT_SUNW_SORTENT "DT_SUNW_SORTENT" # 0x60000013 +@ MSG_DT_SUNW_SORTENT_ALT1 "sunw_sortent" +@ MSG_DT_SUNW_SYMSORT "DT_SUNW_SYMSORT" # 0x60000014 +@ MSG_DT_SUNW_SYMSORT_ALT1 "sunw_symsort" +@ MSG_DT_SUNW_SYMSORTSZ "DT_SUNW_SYMSORTSZ" # 0x60000015 +@ MSG_DT_SUNW_SYMSORTSZ_ALT1 "sunw_symsortsz" +@ MSG_DT_SUNW_TLSSORT "DT_SUNW_TLSSORT" # 0x60000016 +@ MSG_DT_SUNW_TLSSORT_ALT1 "sunw_tlssort" +@ MSG_DT_SUNW_TLSSORTSZ "DT_SUNW_TLSSORTSZ" # 0x60000017 +@ MSG_DT_SUNW_TLSSORTSZ_ALT1 "sunw_tlssortsz" +@ MSG_DT_SUNW_STRPAD "DT_SUNW_STRPAD" # 0x60000019 +@ MSG_DT_SUNW_STRPAD_ALT1 "sunw_strpad" +@ MSG_DT_SPARC_REGISTER "DT_SPARC_REGISTER" # 0x70000001 +@ MSG_DT_SPARC_REGISTER_ALT1 "sparc_register" +@ MSG_DT_DEPRECATED_SPARC_REGISTER "DT_DEPRECATED_SPARC_REGISTER" # 0x7000001 +@ MSG_DT_DEPRECATED_SPARC_REGISTER_ALT1 "deprecated_sparc_register" +@ MSG_DT_CHECKSUM "DT_CHECKSUM" # 0x6ffffdf8 +@ MSG_DT_CHECKSUM_ALT1 "checksum" +@ MSG_DT_PLTPADSZ "DT_PLTPADSZ" # 0x6ffffdf9 +@ MSG_DT_PLTPADSZ_ALT1 "pltpadsz" +@ MSG_DT_MOVEENT "DT_MOVEENT" # 0x6ffffdfa +@ MSG_DT_MOVEENT_ALT1 "moveent" +@ MSG_DT_MOVESZ "DT_MOVESZ" # 0x6ffffdfb +@ MSG_DT_MOVESZ_ALT1 "movesz" +@ MSG_DT_FEATURE_1 "DT_FEATURE_1" # 0x6ffffdfc +@ MSG_DT_FEATURE_1_ALT1 "feature_1" +@ MSG_DT_POSFLAG_1 "DT_POSFLAG_1" # 0x6ffffdfd +@ MSG_DT_POSFLAG_1_ALT1 "posflag_1" +@ MSG_DT_SYMINSZ "DT_SYMINSZ" # 0x6ffffdfe +@ MSG_DT_SYMINSZ_ALT1 "syminsz" +@ MSG_DT_SYMINENT "DT_SYMINENT" # 0x6ffffdff +@ MSG_DT_SYMINENT_ALT1 "syminent" +@ MSG_DT_CONFIG "DT_CONFIG" # 0x6ffffefa +@ MSG_DT_CONFIG_ALT1 "config" +@ MSG_DT_DEPAUDIT "DT_DEPAUDIT" # 0x6ffffefb +@ MSG_DT_DEPAUDIT_ALT1 "depaudit" +@ MSG_DT_AUDIT "DT_AUDIT" # 0x6ffffefc +@ MSG_DT_AUDIT_ALT1 "audit" +@ MSG_DT_PLTPAD "DT_PLTPAD" # 0x6ffffefd +@ MSG_DT_PLTPAD_ALT1 "pltpad" +@ MSG_DT_MOVETAB "DT_MOVETAB" # 0x6ffffefe +@ MSG_DT_MOVETAB_ALT1 "movetab" +@ MSG_DT_SYMINFO "DT_SYMINFO" # 0x6ffffeff +@ MSG_DT_SYMINFO_ALT1 "syminfo" +@ MSG_DT_VERSYM "DT_VERSYM" # 0x6ffffff0 +@ MSG_DT_VERSYM_ALT1 "versym" +@ MSG_DT_RELACOUNT "DT_RELACOUNT" # 0x6ffffff9 +@ MSG_DT_RELACOUNT_ALT1 "relacount" +@ MSG_DT_RELCOUNT "DT_RELCOUNT" # 0x6ffffffa +@ MSG_DT_RELCOUNT_ALT1 "relcount" +@ MSG_DT_FLAGS_1 "DT_FLAGS_1" # 0x6ffffffb +@ MSG_DT_FLAGS_1_ALT1 "flags_1" +@ MSG_DT_VERDEF "DT_VERDEF" # 0x6ffffffc +@ MSG_DT_VERDEF_ALT1 "verdef" +@ MSG_DT_VERDEFNUM "DT_VERDEFNUM" # 0x6ffffffd +@ MSG_DT_VERDEFNUM_ALT1 "verdefnum" +@ MSG_DT_VERNEED "DT_VERNEED" # 0x6ffffffe +@ MSG_DT_VERNEED_ALT1 "verneed" +@ MSG_DT_VERNEEDNUM "DT_VERNEEDNUM" # 0x6fffffff +@ MSG_DT_VERNEEDNUM_ALT1 "verneednum" +@ MSG_DT_AUXILIARY "DT_AUXILIARY" # 0x7ffffffd +@ MSG_DT_AUXILIARY_ALT1 "auxiliary" +@ MSG_DT_USED "DT_USED" # 0x7ffffffe +@ MSG_DT_USED_ALT1 "used" +@ MSG_DT_FILTER "DT_FILTER" # 0x7fffffff +@ MSG_DT_FILTER_ALT1 "filter" + + +# DT_FLAGS .dynamic entry +@ MSG_DF_ORIGIN "DF_ORIGIN" # 0x00000001 +@ MSG_DF_ORIGIN_ALT1 "origin" +@ MSG_DF_SYMBOLIC "DF_SYMBOLIC" # 0x00000002 +@ MSG_DF_SYMBOLIC_ALT1 "symbolic" +@ MSG_DF_TEXTREL "DF_TEXTREL" # 0x00000004 +@ MSG_DF_TEXTREL_ALT1 "textrel" +@ MSG_DF_BIND_NOW "DF_BIND_NOW" # 0x00000008 +@ MSG_DF_BIND_NOW_ALT1 "bind_now" +@ MSG_DF_STATIC_TLS "DF_STATIC_TLS" # 0x00000010 +@ MSG_DF_STATIC_TLS_ALT1 "static_tls" + + +# DT_POSFLAG_1 .dynamic entry + +@ MSG_DF_P1_LAZYLOAD "DF_P1_LAZYLOAD" # 0x00000001 +@ MSG_DF_P1_LAZYLOAD_ALT1 "lazyload" +@ MSG_DF_P1_GROUPPERM "DF_P1_GROUPPERM" # 0x00000002 +@ MSG_DF_P1_GROUPPERM_ALT1 "groupperm" + + +# DT_FLAGS_1 .dynamic entry + +@ MSG_DF_1_NOW "DF_1_NOW" # 0x00000001 +@ MSG_DF_1_NOW_ALT1 "now" +@ MSG_DF_1_GLOBAL "DF_1_GLOBAL" # 0x00000002 +@ MSG_DF_1_GLOBAL_ALT1 "global" +@ MSG_DF_1_GROUP "DF_1_GROUP" # 0x00000004 +@ MSG_DF_1_GROUP_ALT1 "group" +@ MSG_DF_1_NODELETE "DF_1_NODELETE" # 0x00000008 +@ MSG_DF_1_NODELETE_ALT1 "nodelete" +@ MSG_DF_1_LOADFLTR "DF_1_LOADFLTR" # 0x00000010 +@ MSG_DF_1_LOADFLTR_ALT1 "loadfltr" +@ MSG_DF_1_INITFIRST "DF_1_INITFIRST" # 0x00000020 +@ MSG_DF_1_INITFIRST_ALT1 "initfirst" +@ MSG_DF_1_NOOPEN "DF_1_NOOPEN" # 0x00000040 +@ MSG_DF_1_NOOPEN_ALT1 "noopen" +@ MSG_DF_1_ORIGIN "DF_1_ORIGIN" # 0x00000080 +@ MSG_DF_1_ORIGIN_ALT1 "origin" +@ MSG_DF_1_DIRECT "DF_1_DIRECT" # 0x00000100 +@ MSG_DF_1_DIRECT_ALT1 "direct" +@ MSG_DF_1_TRANS "DF_1_TRANS" # 0x00000200 +@ MSG_DF_1_TRANS_ALT1 "trans" +@ MSG_DF_1_INTERPOSE "DF_1_INTERPOSE" # 0x00000400 +@ MSG_DF_1_INTERPOSE_ALT1 "interpose" +@ MSG_DF_1_NODEFLIB "DF_1_NODEFLIB" # 0x00000800 +@ MSG_DF_1_NODEFLIB_ALT1 "nodeflib" +@ MSG_DF_1_NODUMP "DF_1_NODUMP" # 0x00001000 +@ MSG_DF_1_NODUMP_ALT1 "nodump" +@ MSG_DF_1_CONFALT "DF_1_CONFALT" # 0x00002000 +@ MSG_DF_1_CONFALT_ALT1 "confalt" +@ MSG_DF_1_ENDFILTEE "DF_1_ENDFILTEE" # 0x00004000 +@ MSG_DF_1_ENDFILTEE_ALT1 "endfiltee" +@ MSG_DF_1_DISPRELDNE "DF_1_DISPRELDNE" # 0x00008000 +@ MSG_DF_1_DISPRELDNE_ALT1 "dispreldne" +@ MSG_DF_1_DISPRELPND "DF_1_DISPRELPND" # 0x00010000 +@ MSG_DF_1_DISPRELPND_ALT1 "disprelpnd" +@ MSG_DF_1_NODIRECT "DF_1_NODIRECT" # 0x00020000 +@ MSG_DF_1_NODIRECT_ALT1 "nodirect" +@ MSG_DF_1_IGNMULDEF "DF_1_IGNMULDEF" # 0x00040000 +@ MSG_DF_1_IGNMULDEF_ALT1 "ignmuldef" +@ MSG_DF_1_NOKSYMS "DF_1_NOKSYMS" # 0x00080000 +@ MSG_DF_1_NOKSYMS_ALT1 "noksyms" +@ MSG_DF_1_NOHDR "DF_1_NOHDR" # 0x00100000 +@ MSG_DF_1_NOHDR_ALT1 "nohdr" +@ MSG_DF_1_EDITED "DF_1_EDITED" # 0x00200000 +@ MSG_DF_1_EDITED_ALT1 "edited" +@ MSG_DF_1_NORELOC "DF_1_NORELOC" # 0x00400000 +@ MSG_DF_1_NORELOC_ALT1 "noreloc" +@ MSG_DF_1_SYMINTPOSE "DF_1_SYMINTPOSE" # 0x00800000 +@ MSG_DF_1_SYMINTPOSE_ALT1 "symintpose" +@ MSG_DF_1_GLOBAUDIT "DF_1_GLOBAUDIT" # 0x01000000 +@ MSG_DF_1_GLOBAUDIT_ALT1 "globaudit" + + +# DT_FEATURE_1 .dynamic entry + +@ MSG_DTF_1_PARINIT "DTF_1_PARINIT" # 0x00000001 +@ MSG_DTF_1_PARINIT_ALT1 "parinit" +@ MSG_DTF_1_CONFEXP "DTF_1_CONFEXP" # 0x00000002 +@ MSG_DTF_1_CONFEXP_ALT1 "confexp" + + +# EI_* indexes into ELF header e_ident[] array + +@ MSG_EI_MAG0 "EI_MAG0" # 0 +@ MSG_EI_MAG0_ALT1 "mag0" +@ MSG_EI_MAG1 "EI_MAG1" # 1 +@ MSG_EI_MAG1_ALT1 "mag1" +@ MSG_EI_MAG2 "EI_MAG2" # 2 +@ MSG_EI_MAG2_ALT1 "mag2" +@ MSG_EI_MAG3 "EI_MAG3" # 3 +@ MSG_EI_MAG3_ALT1 "mag3" +@ MSG_EI_CLASS "EI_CLASS" # 4 +@ MSG_EI_CLASS_ALT1 "class" +@ MSG_EI_DATA "EI_DATA" # 5 +@ MSG_EI_DATA_ALT1 "data" +@ MSG_EI_VERSION "EI_VERSION" # 6 +@ MSG_EI_VERSION_ALT1 "version" +@ MSG_EI_OSABI "EI_OSABI" # 7 +@ MSG_EI_OSABI_ALT1 "osabi" +@ MSG_EI_ABIVERSION "EI_ABIVERSION" # 8 +@ MSG_EI_ABIVERSION_ALT1 "abiversion" + + +# ET_* type constants + +@ MSG_ET_NONE "ET_NONE" # 0 +@ MSG_ET_NONE_ALT1 "none" +@ MSG_ET_REL "ET_REL" # 1 +@ MSG_ET_REL_ALT1 "rel" +@ MSG_ET_EXEC "ET_EXEC" # 2 +@ MSG_ET_EXEC_ALT1 "exec" +@ MSG_ET_DYN "ET_DYN" # 3 +@ MSG_ET_DYN_ALT1 "dyn" +@ MSG_ET_CORE "ET_CORE" # 4 +@ MSG_ET_CORE_ALT1 "core" + + +# ELFCLASS* constants + +@ MSG_ELFCLASSNONE "ELFCLASSNONE" # 0 +@ MSG_ELFCLASSNONE_ALT1 "none" +@ MSG_ELFCLASS32 "ELFCLASS32" # 1 +@ MSG_ELFCLASS32_ALT1 "32" +@ MSG_ELFCLASS64 "ELFCLASS64" # 2 +@ MSG_ELFCLASS64_ALT1 "64" + + +# ELFDATA* constants + +@ MSG_ELFDATANONE "ELFDATANONE" # 0 +@ MSG_ELFDATANONE_ALT1 "none" +@ MSG_ELFDATA2LSB "ELFDATA2LSB" # 1 +@ MSG_ELFDATA2LSB_ALT1 "lsb" +@ MSG_ELFDATA2MSB "ELFDATA2MSB" # 2 +@ MSG_ELFDATA2MSB_ALT1 "msb" + + +# Elf header EF_* flags + +@ MSG_EF_SPARC_32PLUS "EF_SPARC_32PLUS" # 0x000100 +@ MSG_EF_SPARC_32PLUS_ALT1 "sparc_32plus" +@ MSG_EF_SPARC_SUN_US1 "EF_SPARC_SUN_US1" # 0x000200 +@ MSG_EF_SPARC_SUN_US1_ALT1 "sparc_sun_us1" +@ MSG_EF_SPARC_HAL_R1 "EF_SPARC_HAL_R1" # 0x000400 +@ MSG_EF_SPARC_HAL_R1_ALT1 "sparc_hal_r1" +@ MSG_EF_SPARC_SUN_US3 "EF_SPARC_SUN_US3" # x000800 +@ MSG_EF_SPARC_SUN_US3_ALT1 "sparc_sun_us3" +@ MSG_EF_SPARCV9_MM "EF_SPARCV9_MM" # 0x3 +@ MSG_EF_SPARCV9_MM_ALT1 "sparcv9_mm" +@ MSG_EF_SPARCV9_TSO "EF_SPARCV9_TSO" # 0x0 +@ MSG_EF_SPARCV9_TSO_ALT1 "sparcv9_tso" +@ MSG_EF_SPARCV9_PSO "EF_SPARCV9_PSO" # 0x1 +@ MSG_EF_SPARCV9_PSO_ALT1 "sparcv9_pso" +@ MSG_EF_SPARCV9_RMO "EF_SPARCV9_RMO" # 0x2 +@ MSG_EF_SPARCV9_RMO_ALT1 "sparcv9_rmo" + + +# Elf header EV_* versions + +@ MSG_EV_NONE "EV_NONE" # 0 +@ MSG_EV_NONE_ALT1 "none" +@ MSG_EV_CURRENT "EV_CURRENT" # 1 +@ MSG_EV_CURRENT_ALT1 "current" + + +# EM_* machine names. Note that there is more than one string for some +# of these. The main name for each one is the same as it's constant +# name in sys/elf.h, and start with the EM_ prefix. The alternative names +# are the alternative names provided by libconv. + +@ MSG_EM_NONE "EM_NONE" # 0 +@ MSG_EM_NONE_ALT1 "none" +@ MSG_EM_M32 "EM_M32" # 1 +@ MSG_EM_M32_ALT1 "m32" +@ MSG_EM_M32_ALT2 "WE32100" +@ MSG_EM_SPARC "EM_SPARC" # 2 +@ MSG_EM_SPARC_ALT1 "sparc" +@ MSG_EM_386 "EM_386" # 3 +@ MSG_EM_386_ALT1 "386" +@ MSG_EM_386_ALT2 "80386" +@ MSG_EM_68K "EM_68K" # 4 +@ MSG_EM_68K_ALT1 "68k" +@ MSG_EM_68K_ALT2 "68000" +@ MSG_EM_88K "EM_88K" # 5 +@ MSG_EM_88K_ALT1 "88k" +@ MSG_EM_88K_ALT2 "88000" +@ MSG_EM_486 "EM_486" # 6 +@ MSG_EM_486_ALT1 "486" +@ MSG_EM_486_ALT2 "80486" +@ MSG_EM_860 "EM_860" # 7 +@ MSG_EM_860_ALT1 "860" +@ MSG_EM_860_ALT2 "i860" +@ MSG_EM_MIPS "EM_MIPS" # 8 +@ MSG_EM_MIPS_ALT1 "mips" +@ MSG_EM_MIPS_ALT2 "rs3000_be" +@ MSG_EM_S370 "EM_S370" # 9 +@ MSG_EM_S370_ALT1 "s370" +@ MSG_EM_MIPS_RS3_LE "EM_MIPS_RS3_LE" # 10 +@ MSG_EM_MIPS_RS3_LE_ALT1 "mips_rs3_le" +@ MSG_EM_MIPS_RS3_LE_ALT2 "RS3000_LE" +@ MSG_EM_RS6000 "EM_RS6000" # 11 +@ MSG_EM_RS6000_ALT1 "rs6000" +@ MSG_EM_PA_RISC "EM_PA_RISC" # 15 +@ MSG_EM_PA_RISC_ALT1 "pa_risc" +@ MSG_EM_NCUBE "EM_nCUBE" # 16 +@ MSG_EM_NCUBE_ALT1 "ncube" +@ MSG_EM_VPP500 "EM_VPP500" # 17 +@ MSG_EM_VPP500_ALT1 "vpp500" +@ MSG_EM_SPARC32PLUS "EM_SPARC32PLUS" # 18 +@ MSG_EM_SPARC32PLUS_ALT1 "sparc32plus" +@ MSG_EM_960 "EM_960" # 19 +@ MSG_EM_960_ALT1 "960" +@ MSG_EM_PPC "EM_PPC" # 20 +@ MSG_EM_PPC_ALT1 "ppc" +@ MSG_EM_PPC_ALT2 "PowerPC" +@ MSG_EM_PPC64 "EM_PPC64" #21 +@ MSG_EM_PPC64_ALT1 "ppc64" +@ MSG_EM_PPC64_ALT2 "PowerPC64" +@ MSG_EM_S390 "EM_S390" #22 +@ MSG_EM_S390_ALT1 "s390" +@ MSG_EM_V800 "EM_V800" #36 +@ MSG_EM_V800_ALT1 "v800" +@ MSG_EM_FR20 "EM_FR20" #37 +@ MSG_EM_FR20_ALT1 "fr20" +@ MSG_EM_RH32 "EM_RH32" #38 +@ MSG_EM_RH32_ALT1 "rh32" +@ MSG_EM_RCE "EM_RCE" #39 +@ MSG_EM_RCE_ALT1 "rce" +@ MSG_EM_ARM "EM_ARM" #40 +@ MSG_EM_ARM_ALT1 "arm" +@ MSG_EM_ALPHA "EM_ALPHA" #41 +@ MSG_EM_ALPHA_ALT1 "alpha" +@ MSG_EM_SH "EM_SH" #42 +@ MSG_EM_SH_ALT1 "sh" +@ MSG_EM_SPARCV9 "EM_SPARCV9" #43 +@ MSG_EM_SPARCV9_ALT1 "sparcv9" +@ MSG_EM_TRICORE "EM_TRICORE" #44 +@ MSG_EM_TRICORE_ALT1 "tricore" +@ MSG_EM_ARC "EM_ARC" #45 +@ MSG_EM_ARC_ALT1 "arc" +@ MSG_EM_H8_300 "EM_H8_300" #46 +@ MSG_EM_H8_300_ALT1 "h8_300" +@ MSG_EM_H8_300H "EM_H8_300H" #47 +@ MSG_EM_H8_300H_ALT1 "h8_300h" +@ MSG_EM_H8S "EM_H8S" #48 +@ MSG_EM_H8S_ALT1 "h8s" +@ MSG_EM_H8_500 "EM_H8_500" #49 +@ MSG_EM_H8_500_ALT1 "h8_500" +@ MSG_EM_IA_64 "EM_IA_64" #50 +@ MSG_EM_IA_64_ALT1 "ia_64" +@ MSG_EM_MIPS_X "EM_MIPS_X" #51 +@ MSG_EM_MIPS_X_ALT1 "mips_x" +@ MSG_EM_COLDFIRE "EM_COLDFIRE" #52 +@ MSG_EM_COLDFIRE_ALT1 "coldfire" +@ MSG_EM_68HC12 "EM_68HC12" #53 +@ MSG_EM_68HC12_ALT1 "68hc12" +@ MSG_EM_MMA "EM_MMA" #54 +@ MSG_EM_MMA_ALT1 "mma" +@ MSG_EM_PCP "EM_PCP" #55 +@ MSG_EM_PCP_ALT1 "pcp" +@ MSG_EM_NCPU "EM_NCPU" #56 +@ MSG_EM_NCPU_ALT1 "ncpu" +@ MSG_EM_NDR1 "EM_NDR1" #57 +@ MSG_EM_NDR1_ALT1 "ndr1" +@ MSG_EM_STARCORE "EM_STARCORE" #58 +@ MSG_EM_STARCORE_ALT1 "starcore" +@ MSG_EM_ME16 "EM_ME16" #59 +@ MSG_EM_ME16_ALT1 "me16" +@ MSG_EM_ST100 "EM_ST100" #60 +@ MSG_EM_ST100_ALT1 "st100" +@ MSG_EM_TINYJ "EM_TINYJ" #61 +@ MSG_EM_TINYJ_ALT1 "tinyj" +@ MSG_EM_AMD64 "EM_AMD64" #62 +@ MSG_EM_AMD64_ALT1 "amd64" +@ MSG_EM_PDSP "EM_PDSP" #63 +@ MSG_EM_PDSP_ALT1 "pdsp" +@ MSG_EM_FX66 "EM_FX66" #66 +@ MSG_EM_FX66_ALT1 "fx66" +@ MSG_EM_ST9PLUS "EM_ST9PLUS" #67 +@ MSG_EM_ST9PLUS_ALT1 "st9plus" +@ MSG_EM_ST7 "EM_ST7" #68 +@ MSG_EM_ST7_ALT1 "st7" +@ MSG_EM_68HC16 "EM_68HC16" #69 +@ MSG_EM_68HC16_ALT1 "68hc16" +@ MSG_EM_68HC11 "EM_68HC11" #70 +@ MSG_EM_68HC11_ALT1 "68hc11" +@ MSG_EM_68HC08 "EM_68HC08" #71 +@ MSG_EM_68HC08_ALT1 "68hc08" +@ MSG_EM_68HC05 "EM_68HC05" #72 +@ MSG_EM_68HC05_ALT1 "68hc05" +@ MSG_EM_SVX "EM_SVX" #73 +@ MSG_EM_SVX_ALT1 "svx" +@ MSG_EM_ST19 "EM_ST19" #74 +@ MSG_EM_ST19_ALT1 "st19" +@ MSG_EM_VAX "EM_VAX" #75 +@ MSG_EM_VAX_ALT1 "vax" +@ MSG_EM_CRIS "EM_CRIS" #76 +@ MSG_EM_CRIS_ALT1 "cris" +@ MSG_EM_JAVELIN "EM_JAVELIN" #77 +@ MSG_EM_JAVELIN_ALT1 "javelin" +@ MSG_EM_FIREPATH "EM_FIREPATH" #78 +@ MSG_EM_FIREPATH_ALT1 "firepath" +@ MSG_EM_ZSP "EM_ZSP" #79 +@ MSG_EM_ZSP_ALT1 "zsp" +@ MSG_EM_MMIX "EM_MMIX" #80 +@ MSG_EM_MMIX_ALT1 "mmix" +@ MSG_EM_HUANY "EM_HUANY" #81 +@ MSG_EM_HUANY_ALT1 "huany" +@ MSG_EM_PRISM "EM_PRISM" #82 +@ MSG_EM_PRISM_ALT1 "prism" +@ MSG_EM_AVR "EM_AVR" #83 +@ MSG_EM_AVR_ALT1 "avr" +@ MSG_EM_FR30 "EM_FR30" #84 +@ MSG_EM_FR30_ALT1 "fr30" +@ MSG_EM_D10V "EM_D10V" #85 +@ MSG_EM_D10V_ALT1 "d10v" +@ MSG_EM_D30V "EM_D30V" #86 +@ MSG_EM_D30V_ALT1 "d30v" +@ MSG_EM_V850 "EM_V850" #87 +@ MSG_EM_V850_ALT1 "v850" +@ MSG_EM_M32R "EM_M32R" #88 +@ MSG_EM_M32R_ALT1 "m32r" +@ MSG_EM_MN10300 "EM_MN10300" #89 +@ MSG_EM_MN10300_ALT1 "mn10300" +@ MSG_EM_MN10200 "EM_MN10200" #90 +@ MSG_EM_MN10200_ALT1 "mn10200" +@ MSG_EM_PJ "EM_PJ" #91 +@ MSG_EM_PJ_ALT1 "pj" +@ MSG_EM_OPENRISC "EM_OPENRISC" #92 +@ MSG_EM_OPENRISC_ALT1 "openrisc" +@ MSG_EM_ARC_A5 "EM_ARC_A5" #93 +@ MSG_EM_ARC_A5_ALT1 "arc_a5" +@ MSG_EM_XTENSA "EM_XTENSA" #94 +@ MSG_EM_XTENSA_ALT1 "xtensa" + + + +# ELFOSABI names + +@ MSG_ELFOSABI_NONE "ELFOSABI_NONE" +@ MSG_ELFOSABI_NONE_ALT1 "none" +@ MSG_ELFOSABI_SYSV "ELFOSABI_SYSV" +@ MSG_ELFOSABI_SYSV_ALT1 "sysv" +@ MSG_ELFOSABI_HPUX "ELFOSABI_HPUX" +@ MSG_ELFOSABI_HPUX_ALT1 "hpux" +@ MSG_ELFOSABI_NETBSD "ELFOSABI_NETBSD" +@ MSG_ELFOSABI_NETBSD_ALT1 "netbsd" +@ MSG_ELFOSABI_LINUX "ELFOSABI_LINUX" +@ MSG_ELFOSABI_LINUX_ALT1 "linux" +@ MSG_ELFOSABI_SOLARIS "ELFOSABI_SOLARIS" +@ MSG_ELFOSABI_SOLARIS_ALT1 "solaris" +@ MSG_ELFOSABI_AIX "ELFOSABI_AIX" +@ MSG_ELFOSABI_AIX_ALT1 "aix" +@ MSG_ELFOSABI_IRIX "ELFOSABI_IRIX" +@ MSG_ELFOSABI_IRIX_ALT1 "irix" +@ MSG_ELFOSABI_FREEBSD "ELFOSABI_FREEBSD" +@ MSG_ELFOSABI_FREEBSD_ALT1 "freebsd" +@ MSG_ELFOSABI_TRU64 "ELFOSABI_TRU64" +@ MSG_ELFOSABI_TRU64_ALT1 "tru64" +@ MSG_ELFOSABI_MODESTO "ELFOSABI_MODESTO" +@ MSG_ELFOSABI_MODESTO_ALT1 "modesto" +@ MSG_ELFOSABI_OPENBSD "ELFOSABI_OPENBSD" +@ MSG_ELFOSABI_OPENBSD_ALT1 "openbsd" +@ MSG_ELFOSABI_OPENVMS "ELFOSABI_OPENVMS" +@ MSG_ELFOSABI_OPENVMS_ALT1 "openvms" +@ MSG_ELFOSABI_NSK "ELFOSABI_NSK" +@ MSG_ELFOSABI_NSK_ALT1 "nsk" +@ MSG_ELFOSABI_AROS "ELFOSABI_AROS" +@ MSG_ELFOSABI_AROS_ALT1 "aros" +@ MSG_ELFOSABI_ARM "ELFOSABI_ARM" +@ MSG_ELFOSABI_ARM_ALT1 "arm" +@ MSG_ELFOSABI_STANDALONE "ELFOSABI_STANDALONE" +@ MSG_ELFOSABI_STANDALONE_ALT1 "standalone" + + +# Program header PT_ segment types + +@ MSG_PT_NULL "PT_NULL" # 0 +@ MSG_PT_NULL_ALT1 "null" +@ MSG_PT_LOAD "PT_LOAD" # 1 +@ MSG_PT_LOAD_ALT1 "load" +@ MSG_PT_DYNAMIC "PT_DYNAMIC" # 2 +@ MSG_PT_DYNAMIC_ALT1 "dynamic" +@ MSG_PT_INTERP "PT_INTERP" # 3 +@ MSG_PT_INTERP_ALT1 "interp" +@ MSG_PT_NOTE "PT_NOTE" # 4 +@ MSG_PT_NOTE_ALT1 "note" +@ MSG_PT_SHLIB "PT_SHLIB" # 5 +@ MSG_PT_SHLIB_ALT1 "shlib" +@ MSG_PT_PHDR "PT_PHDR" # 6 +@ MSG_PT_PHDR_ALT1 "phdr" +@ MSG_PT_TLS "PT_TLS" # 7 +@ MSG_PT_TLS_ALT1 "tls" +@ MSG_PT_SUNW_UNWIND "PT_SUNW_UNWIND" # 0x6464e550 +@ MSG_PT_SUNW_UNWIND_ALT1 "sunw_unwind" +@ MSG_PT_SUNWBSS "PT_SUNWBSS" # 0x6ffffffa +@ MSG_PT_SUNWBSS_ALT1 "sunwbss" +@ MSG_PT_SUNWSTACK "PT_SUNWSTACK" # 0x6ffffffb +@ MSG_PT_SUNWSTACK_ALT1 "sunwstack" +@ MSG_PT_SUNWDTRACE "PT_SUNWDTRACE" # 0x6ffffffc +@ MSG_PT_SUNWDTRACE_ALT1 "sunwdtrace" +@ MSG_PT_SUNWCAP "PT_SUNWCAP" # 0x6ffffffd +@ MSG_PT_SUNWCAP_ALT1 "sunwcap" + + +# Program header PF_ segment flags + +@ MSG_PF_X "PF_X" # 0x1 +@ MSG_PF_X_ALT1 "x" +@ MSG_PF_W "PF_W" # 0x2 +@ MSG_PF_W_ALT1 "w" +@ MSG_PF_R "PF_R" # 0x4 +@ MSG_PF_R_ALT1 "r" + + +# Section header SHF_* flags + +@ MSG_SHF_WRITE "SHF_WRITE" # 0x01 +@ MSG_SHF_WRITE_ALT1 "write" +@ MSG_SHF_ALLOC "SHF_ALLOC" # 0x02 +@ MSG_SHF_ALLOC_ALT1 "alloc" +@ MSG_SHF_EXECINSTR "SHF_EXECINSTR" # 0x04 +@ MSG_SHF_EXECINSTR_ALT1 "execinstr" +@ MSG_SHF_MERGE "SHF_MERGE" # 0x10 +@ MSG_SHF_MERGE_ALT1 "merge" +@ MSG_SHF_STRINGS "SHF_STRINGS" # 0x20 +@ MSG_SHF_STRINGS_ALT1 "strings" +@ MSG_SHF_INFO_LINK "SHF_INFO_LINK" # 0x40 +@ MSG_SHF_INFO_LINK_ALT1 "info_link" +@ MSG_SHF_LINK_ORDER "SHF_LINK_ORDER" # 0x80 +@ MSG_SHF_LINK_ORDER_ALT1 "link_order" +@ MSG_SHF_OS_NONCONFORMING "SHF_OS_NONCONFORMING" # 0x100 +@ MSG_SHF_OS_NONCONFORMING_ALT1 "os_nonconforming" +@ MSG_SHF_GROUP "SHF_GROUP" # 0x200 +@ MSG_SHF_GROUP_ALT1 "group" +@ MSG_SHF_TLS "SHF_TLS" # 0x400 +@ MSG_SHF_TLS_ALT1 "tls" + + +# Names of st_info ELF_ST_BIND symbol binding constants + +@ MSG_STB_LOCAL "STB_LOCAL" # 0 +@ MSG_STB_LOCAL_ALT1 "local" +@ MSG_STB_GLOBAL "STB_GLOBAL" # 1 +@ MSG_STB_GLOBAL_ALT1 "global" +@ MSG_STB_WEAK "STB_WEAK" # 2 +@ MSG_STB_WEAK_ALT1 "weak" + + +# Names of st_info ELF_ST_TYPE symbol type constants + +@ MSG_STT_NOTYPE "STT_NOTYPE" # 0 +@ MSG_STT_NOTYPE_ALT1 "notype" +@ MSG_STT_OBJECT "STT_OBJECT" # 1 +@ MSG_STT_OBJECT_ALT1 "object" +@ MSG_STT_FUNC "STT_FUNC" # 2 +@ MSG_STT_FUNC_ALT1 "func" +@ MSG_STT_SECTION "STT_SECTION" # 3 +@ MSG_STT_SECTION_ALT1 "section" +@ MSG_STT_FILE "STT_FILE" # 4 +@ MSG_STT_FILE_ALT1 "file" +@ MSG_STT_COMMON "STT_COMMON" # 5 +@ MSG_STT_COMMON_ALT1 "common" +@ MSG_STT_TLS "STT_TLS" # 6 +@ MSG_STT_TLS_ALT1 "tls" + + +# Names of st_other ELF_ST_VISIBILITY symbol visibility constants + +@ MSG_STV_DEFAULT "STV_DEFAULT" # 0 +@ MSG_STV_DEFAULT_ALT1 "default" +@ MSG_STV_INTERNAL "STV_INTERNAL" # 1 +@ MSG_STV_INTERNAL_ALT1 "internal" +@ MSG_STV_HIDDEN "STV_HIDDEN" # 2 +@ MSG_STV_HIDDEN_ALT1 "hidden" +@ MSG_STV_PROTECTED "STV_PROTECTED" # 3 +@ MSG_STV_PROTECTED_ALT1 "protected" + + +# Names of si_boundto SYMINFO_BT_ symbol type constants + +@ MSG_SYMINFO_BT_SELF "SYMINFO_BT_SELF" # 0xffff +@ MSG_SYMINFO_BT_SELF_ALT1 "self" +@ MSG_SYMINFO_BT_PARENT "SYMINFO_BT_PARENT" # 0xfffe +@ MSG_SYMINFO_BT_PARENT_ALT1 "parent" +@ MSG_SYMINFO_BT_NONE "SYMINFO_BT_NONE" # 0xfffd +@ MSG_SYMINFO_BT_NONE_ALT1 "none" + + +# Names of si_flags SYMINFO_FLG_ symbol type constants + +@ MSG_SYMINFO_FLG_DIRECT "SYMINFO_FLG_DIRECT" # 0x01 +@ MSG_SYMINFO_FLG_DIRECT_ALT1 "direct" +@ MSG_SYMINFO_FLG_COPY "SYMINFO_FLG_COPY" # 0x04 +@ MSG_SYMINFO_FLG_COPY_ALT1 "copy" +@ MSG_SYMINFO_FLG_LAZYLOAD "SYMINFO_FLG_LAZYLOAD" # 0x08 +@ MSG_SYMINFO_FLG_LAZYLOAD_ALT1 "lazyload" +@ MSG_SYMINFO_FLG_DIRECTBIND "SYMINFO_FLG_DIRECTBIND" # 0x10 +@ MSG_SYMINFO_FLG_DIRECTBIND_ALT1 "directbind" +@ MSG_SYMINFO_FLG_NOEXTDIRECT "SYMINFO_FLG_NOEXTDIRECT" # 0x20 +@ MSG_SYMINFO_FLG_NOEXTDIRECT_ALT1 "noextdirect" + + +# Names of capabilities section CA_ tag + +@ MSG_CA_SUNW_NULL "CA_SUNW_NULL" # 0 +@ MSG_CA_SUNW_NULL_ALT1 "null" +@ MSG_CA_SUNW_HW_1 "CA_SUNW_HW_1" # 1 +@ MSG_CA_SUNW_HW_1_ALT1 "hw_1" +@ MSG_CA_SUNW_SF_1 "CA_SUNW_SF_1" # 2 +@ MSG_CA_SUNW_SF_1_ALT1 "sf_1" + +# AV_386 flags used for CA_SUNW_HW_1 capabilities + +@ MSG_AV_386_FPU "AV_386_FPU" # 0x00001 +@ MSG_AV_386_FPU_ALT1 "fpu" +@ MSG_AV_386_TSC "AV_386_TSC" # 0x00002 +@ MSG_AV_386_TSC_ALT1 "tsc" +@ MSG_AV_386_CX8 "AV_386_CX8" # 0x00004 +@ MSG_AV_386_CX8_ALT1 "cx8" +@ MSG_AV_386_SEP "AV_386_SEP" # 0x00008 +@ MSG_AV_386_SEP_ALT1 "sep" +@ MSG_AV_386_AMD_SYSC "AV_386_AMD_SYSC" # 0x00010 +@ MSG_AV_386_AMD_SYSC_ALT1 "amd_sysc" +@ MSG_AV_386_CMOV "AV_386_CMOV" # 0x00020 +@ MSG_AV_386_CMOV_ALT1 "cmov" +@ MSG_AV_386_MMX "AV_386_MMX" # 0x00040 +@ MSG_AV_386_MMX_ALT1 "mmx" +@ MSG_AV_386_AMD_MMX "AV_386_AMD_MMX" # 0x00080 +@ MSG_AV_386_AMD_MMX_ALT1 "amd_mmx" +@ MSG_AV_386_AMD_3DNOW "AV_386_AMD_3DNow" # 0x00100 +@ MSG_AV_386_AMD_3DNOW_ALT1 "amd_3dnow" +@ MSG_AV_386_AMD_3DNOWX "AV_386_AMD_3DNowx" # 0x00200 +@ MSG_AV_386_AMD_3DNOWX_ALT1 "amd_3dnowx" +@ MSG_AV_386_FXSR "AV_386_FXSR" # 0x00400 +@ MSG_AV_386_FXSR_ALT1 "fxsr" +@ MSG_AV_386_SSE "AV_386_SSE" # 0x00800 +@ MSG_AV_386_SSE_ALT1 "sse" +@ MSG_AV_386_SSE2 "AV_386_SSE2" # 0x01000 +@ MSG_AV_386_SSE2_ALT1 "sse2" +@ MSG_AV_386_PAUSE "AV_386_PAUSE" # 0x02000 +@ MSG_AV_386_PAUSE_ALT1 "pause" +@ MSG_AV_386_SSE3 "AV_386_SSE3" # 0x04000 +@ MSG_AV_386_SSE3_ALT1 "sse3" +@ MSG_AV_386_MON "AV_386_MON" # 0x08000 +@ MSG_AV_386_MON_ALT1 "mon" +@ MSG_AV_386_CX16 "AV_386_CX16" # 0x10000 +@ MSG_AV_386_CX16_ALT1 "cx16" +@ MSG_AV_386_AHF "AV_386_AHF" # 0x20000 +@ MSG_AV_386_AHF_ALT1 "ahf" +@ MSG_AV_386_TSCP "AV_386_TSCP" # 0x40000 +@ MSG_AV_386_TSCP_ALT1 "tscp" +@ MSG_AV_386_AMD_SSE4A "AV_386_AMD_SSE4A" # 0x80000 +@ MSG_AV_386_AMD_SSE4A_ALT1 "amd_sse4a" +@ MSG_AV_386_POPCNT "AV_386_POPCNT" # 0x100000 +@ MSG_AV_386_POPCNT_ALT1 "popcnt" +@ MSG_AV_386_AMD_LZCNT "AV_386_AMD_LZCNT" # 0x200000 +@ MSG_AV_386_AMD_LZCNT_ALT1 "amd_lzcnt" + + +# AV_SPARC flags used for CA_SUNW_HW_1 capabilities + +@ MSG_AV_SPARC_MUL32 "AV_SPARC_MUL32" # 0x0001 +@ MSG_AV_SPARC_MUL32_ALT1 "mul32" +@ MSG_AV_SPARC_DIV32 "AV_SPARC_DIV32" # 0x0002 +@ MSG_AV_SPARC_DIV32_ALT1 "div32" +@ MSG_AV_SPARC_FSMULD "AV_SPARC_FSMULD" # 0x0004 +@ MSG_AV_SPARC_FSMULD_ALT1 "fsmuld" +@ MSG_AV_SPARC_V8PLUS "AV_SPARC_V8PLUS" # 0x0008 +@ MSG_AV_SPARC_V8PLUS_ALT1 "v8plus" +@ MSG_AV_SPARC_POPC "AV_SPARC_POPC" # 0x0010 +@ MSG_AV_SPARC_POPC_ALT1 "popc" +@ MSG_AV_SPARC_VIS "AV_SPARC_VIS" # 0x0020 +@ MSG_AV_SPARC_VIS_ALT1 "vis" +@ MSG_AV_SPARC_VIS2 "AV_SPARC_VIS2" # 0x0040 +@ MSG_AV_SPARC_VIS2_ALT1 "vis2" +@ MSG_AV_SPARC_ASI_BLK_INIT "AV_SPARC_ASI_BLK_INIT" # 0x0080 +@ MSG_AV_SPARC_ASI_BLK_INIT_ALT1 "asi_blk_init" +@ MSG_AV_SPARC_FMAF "AV_SPARC_FMAF" # 0x0100 +@ MSG_AV_SPARC_FMAF_ALT1 "fmaf" +@ MSG_AV_SPARC_FJFMAU "AV_SPARC_FJFMAU" # 0x4000 +@ MSG_AV_SPARC_FJFMAU_ALT1 "fjfmau" + + +# SF1_SUNW flags used for CA_SUNW_SF_1 capabilities + +@ MSG_SF1_SUNW_FPKNWN "SF1_SUNW_FPKNWN" # 0x001 +@ MSG_SF1_SUNW_FPKNWN_ALT1 "fpknwn" +@ MSG_SF1_SUNW_FPUSED "SF1_SUNW_FPUSED" # 0x002 +@ MSG_SF1_SUNW_FPUSED_ALT1 "fpused" + + +# ISA strings. These could be separated into separate message modules +# on a per-platform basis if their size became large, but this is probably +# cheaper for this small set of strings. +@ MSG_ISA_SPARC_32 "sparc" +@ MSG_ISA_SPARC_64 "sparcv9" +@ MSG_ISA_X86_32 "i386" +@ MSG_ISA_X86_64 "amd64" + +# Format strings + +@ MSG_FMT_BLDPATH "%s/%s" +@ MSG_FMT_BLDSOPATH "%s/%s.so" +@ MSG_FMT_MODCMD "%s:%s" +@ MSG_FMT_SYSCMD "[sys]:%s" +@ MSG_FMT_WORDVAL "%u" +@ MSG_FMT_WRAPUSAGE "\n%s" +@ MSG_FMT_SECMSGPRE "[%d: %s]" + +# Miscellaneous clutter + +@ MSG_STR_NULL "" +@ MSG_STR_ARG "arg" +@ MSG_STR_SP_BAR_SP " | " +@ MSG_STR_ELIPSES "..." +@ MSG_STR_OPTIONS "ade:L:o:rw" +@ MSG_STR_ELFEDIT "elfedit: " +@ MSG_STR_PROMPT "> " +@ MSG_STR_NL "\n" +@ MSG_STR_TAB "\t" +@ MSG_STR_BINCP "/bin/cp" +@ MSG_STR_BINMORE "/bin/more" +@ MSG_STR_PAGER "PAGER" +@ MSG_STR_ELFEDITINIT32 "elfedit32_init" +@ MSG_STR_ELFEDITINIT64 "elfedit64_init" +@ MSG_STR_HLPINDENT " "; +@ MSG_STR_HLPUSEINDENT " "; +@ MSG_STR_HLPSUMINDENT " "; +@ MSG_STR_HLPOPTARG "%s"; +@ MSG_STR_HLPOPTARG2 "%s %s"; +@ MSG_STR_ENVVAR "ELFEDIT_PATH" +@ MSG_STR_MODPATH "%r/usr/lib/elfedit/%I" +@ MSG_STR_EMPTY "" +@ MSG_STR_DOT "." +@ MSG_STR_COLON ":" +@ MSG_STR_SPACE " " +@ MSG_STR_COMMA_SP ", " +@ MSG_STR_CPAREN ")" +@ MSG_STR_DOTSO ".so" +@ MSG_STR_MINUS_MINUS "--" +@ MSG_STR_MINUS_A "-a" +@ MSG_STR_MINUS_AND "-and" +@ MSG_STR_MINUS_CMP "-cmp" +@ MSG_STR_MINUS_F "-f" +@ MSG_STR_MINUS_S "-s" +@ MSG_STR_MINUS_O "-o" +@ MSG_STR_MINUS_OR "-or" +@ MSG_STR_MODNAME "modname" +@ MSG_STR_TRUE "true" +@ MSG_STR_FALSE "false" +@ MSG_STR_ON "on" +@ MSG_STR_OFF "off" +@ MSG_STR_YES "yes" +@ MSG_STR_NO "no" +@ MSG_STR_0 "0" +@ MSG_STR_1 "1" +@ MSG_STR_A "a" +@ MSG_STR_D "d" +@ MSG_STR_F "f" +@ MSG_STR_N "n" +@ MSG_STR_O "o" +@ MSG_STR_OPTION "option" +@ MSG_STR_T "t" +@ MSG_STR_VALUE "value" +@ MSG_STR_W "w" +@ MSG_STR_Y "y" +@ MSG_STR_DEFAULT "default" +@ MSG_STR_MINUS_O_DEFAULT "-odefault" +@ MSG_STR_SIMPLE "simple" +@ MSG_STR_MINUS_O_SIMPLE "-osimple" +@ MSG_STR_NUM "num" +@ MSG_STR_MINUS_O_NUM "-onum" +@ MSG_STR_OUTSTYLE "outstyle" + + +# Format strings for sys:help +@ MSG_HLPFMT_MULTIHDR "::::::::::::::\n%s\n::::::::::::::\n" +@ MSG_HLPFMT_NAMDSCCOL " %-15s%s\n" +@ MSG_HLPFMT_NAMDSCHDR "%s - %s\n" +@ MSG_HLPFMT_NAMSUMHDR " %s - %s\n" +@ MSG_HLPFMT_PATHELT " %s\n" +@ MSG_HLPFMT_MULTNAM "%s (" + +# name of builtin sys: module + +@ MSG_MOD_SYS "sys" + +# Names of sys: builtin commands +@ MSG_SYS_CMD_HELP "help" +@ MSG_SYS_CMD_HELP_A1 "?" +@ MSG_SYS_CMD_HELP_A2 "man" +@ MSG_SYS_CMD_LOAD "load" +@ MSG_SYS_CMD_QUIT "quit" +@ MSG_SYS_CMD_QUIT_A1 "exit" +@ MSG_SYS_CMD_QUIT_A2 "bye" +@ MSG_SYS_CMD_SET "set" +@ MSG_SYS_CMD_STATUS "status" +@ MSG_SYS_CMD_UNLOAD "unload" +@ MSG_SYS_CMD_WRITE "write" +@ MSG_SYS_CMD_WRITE_A1 "flush" +@ MSG_SYS_CMD_WRITE_A2 "save" diff --git a/usr/src/cmd/sgs/elfedit/common/elfedit_machelf.c b/usr/src/cmd/sgs/elfedit/common/elfedit_machelf.c new file mode 100644 index 0000000000..e651ba334b --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/common/elfedit_machelf.c @@ -0,0 +1,453 @@ +/* + * 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" + +/* + * ELFCLASS specific code for elfedit, built once for each class + */ +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <machdep.h> +#include <libelf.h> +#include <strings.h> +#include <sgs.h> +#include "msg.h" +#include "_elfedit.h" + + + +/* + * Look up the elfedit_symtab_t that corresponds to the symbol table + * referenced by the sh_link field of the given auxiliary section. + * + * entry: + * obj_state - Partially constructed object state from + * elfedit_init_obj_state(). + * auxsec - Section that is associated with the symbol table section + * + * exit: + * Returns the pointer to the elfedit_symtab_t entry that is + * referenced by the auxiliary section. If not found, + * outputs a debug message, and returns NULL. + */ +static elfedit_symtab_t * +get_symtab(elfedit_obj_state_t *obj_state, elfedit_section_t *auxsec) +{ + elfedit_symtab_t *symtab = obj_state->os_symtab; + Word sh_link = auxsec->sec_shdr->sh_link; + Word i; + + for (i = 0; i < obj_state->os_symtabnum; i++, symtab++) + if (symtab->symt_shndx == sh_link) + return (symtab); + + /* + * If we don't return above, it doesn't reference a valid + * symbol table. Issue warning. + */ + elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_AUX_LINK), + EC_WORD(auxsec->sec_shndx), auxsec->sec_name, + EC_WORD(sh_link)); + + return (NULL); +} + + +/* + * Fill in state.elf.obj_state with a a dynamically allocated + * elfedit_obj_state_t struct of the appropriate ELFCLASS. + * This pre-chewed form is fed to each command, reducing the amount + * of ELF boilerplate code each command needs to contain. + * + * entry: + * file - Name of file to process + * fd - Descriptor of open file which has been successfully + * processed by elf_begin(). + * elf - Elf handle returned by elf_begin + * + * exit: + * An elfedit_obj_state_t struct of the appropriate ELFCLASS has + * been dynamically allocated, and state.elf.obj_state references it. + * On failure, this routine does not return to the caller. + * + * note: The resulting elfedit_obj_state_t is allocated from a single + * piece of memory, such that a single call to free() suffices + * to release it as well as any memory it references. + */ +#ifdef _ELF64 +void +elfedit64_init_obj_state(const char *file, int fd, Elf *elf) +#else +void +elfedit32_init_obj_state(const char *file, int fd, Elf *elf) +#endif +{ +#define INITIAL_SYMTABNDX_ALLOC 5 + + /* + * This macro is used to call functions from libelf, all of which + * return NULL for failure and something else for success. On error, + * libelf_fail_name is set and execution jumps to the libelf_failure + * label for handling. Otherwise, the results of the call are ready + * for use by the caller. + */ +#define LIBELF(_libelf_expr, _name) \ + if ((_libelf_expr) == NULL) { \ + libelf_fail_name = _name; \ + goto libelf_failure; \ + } + + const char *libelf_fail_name; /* Used for LIBELF errors */ + + Elf_Scn *scn; + Elf_Data *data; + uint_t ndx; + size_t len, os_size, secarr_size; + char *names = 0; + size_t names_len; + elfedit_section_t *_cache; + elfedit_obj_state_t tstate; + elfedit_obj_state_t *obj_state = NULL; + Word *symtabndx = NULL; + Word symtabndx_size = 0; + elfedit_symtab_t *symtab; + + tstate.os_file = file; + tstate.os_fd = fd; + tstate.os_elf = elf; + tstate.os_dynndx = SHN_UNDEF; + tstate.os_symtabnum = 0; + + LIBELF(tstate.os_ehdr = elf_getehdr(tstate.os_elf), + MSG_ORIG(MSG_ELF_GETEHDR)) + + /* Program header array count and address */ + LIBELF(elf_getphnum(tstate.os_elf, &tstate.os_phnum), + MSG_ORIG(MSG_ELF_GETPHNUM)) + if (tstate.os_phnum > 0) { + LIBELF((tstate.os_phdr = elf_getphdr(tstate.os_elf)), + MSG_ORIG(MSG_ELF_GETPHDR)) + } else { + tstate.os_phdr = NULL; + } + + + LIBELF(elf_getshnum(tstate.os_elf, &tstate.os_shnum), + MSG_ORIG(MSG_ELF_GETSHNUM)) + + + /* + * Obtain the .shstrtab data buffer to provide the required section + * name strings. + */ + LIBELF(elf_getshstrndx(tstate.os_elf, &tstate.os_shstrndx), + MSG_ORIG(MSG_ELF_GETSHSTRNDX)) + LIBELF((scn = elf_getscn(tstate.os_elf, tstate.os_shstrndx)), + MSG_ORIG(MSG_ELF_GETSCN)) + LIBELF((data = elf_getdata(scn, NULL)), MSG_ORIG(MSG_ELF_GETDATA)) + names = data->d_buf; + names_len = (names == NULL) ? 0 : data->d_size; + + /* + * Count the number of symbol tables and capture their indexes. + * Find the dynamic section. + */ + for (ndx = 1, scn = NULL; scn = elf_nextscn(tstate.os_elf, scn); + ndx++) { + Shdr *shdr; + + LIBELF(shdr = elf_getshdr(scn), MSG_ORIG(MSG_ELF_GETSHDR)); + + switch (shdr->sh_type) { + case SHT_DYNAMIC: + /* Save index of dynamic section for use below */ + tstate.os_dynndx = ndx; + break; + + case SHT_SYMTAB: + case SHT_DYNSYM: + case SHT_SUNW_LDYNSYM: + if (symtabndx_size <= tstate.os_symtabnum) { + symtabndx_size = (symtabndx_size == 0) ? + INITIAL_SYMTABNDX_ALLOC : + (symtabndx_size * 2); + symtabndx = elfedit_realloc( + MSG_INTL(MSG_ALLOC_SYMTABOS), symtabndx, + symtabndx_size * sizeof (symtabndx[0])); + } + symtabndx[tstate.os_symtabnum++] = ndx; + break; + } + } + + /* + * Allocate space to hold the state. We allocate space for everything + * in one chunk to make releasing it easy: + * (1) elfedit_obj_state_t struct + * (2) The array of elfedit_section_t items referenced from + * the elfedit_obj_state_t struct. + * (3) The array of elfedit_symtab_t items referenced from + * the elfedit_obj_state_t struct. + * (4) The file name. + * + * Note that we round up the size of (1) and (2) to a double boundary + * to ensure proper alignment of (2) and (3). (4) can align on any + * boundary. + */ + os_size = S_DROUND(sizeof (tstate)); + secarr_size = (tstate.os_shnum * sizeof (elfedit_section_t)); + secarr_size = S_DROUND(secarr_size); + len = strlen(tstate.os_file) + 1; + obj_state = elfedit_malloc(MSG_INTL(MSG_ALLOC_OBJSTATE), + os_size + secarr_size + + (tstate.os_symtabnum * sizeof (elfedit_symtab_t)) + len); + *obj_state = tstate; + + /*LINTED E_BAD_PTR_CAST_ALIGN*/ + obj_state->os_secarr = (elfedit_section_t *) + ((char *)obj_state + os_size); + if (obj_state->os_symtabnum == 0) + obj_state->os_symtab = NULL; + else + /*LINTED E_BAD_PTR_CAST_ALIGN*/ + obj_state->os_symtab = (elfedit_symtab_t *) + ((char *)obj_state->os_secarr + secarr_size); + obj_state->os_file = + (char *)(obj_state->os_symtab + tstate.os_symtabnum); + (void) strncpy((char *)obj_state->os_file, tstate.os_file, len); + + /* + * Fill in obj_state->os_secarr with information for each section. + * At the same time, fill in obj_state->os_symtab with the symbol + * table related data. + */ + bzero(obj_state->os_secarr, sizeof (obj_state->os_secarr[0])); + _cache = obj_state->os_secarr; + LIBELF(scn = elf_getscn(tstate.os_elf, 0), + MSG_ORIG(MSG_ELF_GETSCN)); + _cache->sec_scn = scn; + LIBELF(_cache->sec_shdr = elf_getshdr(scn), MSG_ORIG(MSG_ELF_GETSHDR)); + _cache->sec_name = (_cache->sec_shdr->sh_name < names_len) ? + (names + _cache->sec_shdr->sh_name) : MSG_INTL(MSG_UNKNOWNSECNAM); + _cache++; + + if (obj_state->os_symtab != NULL) { + bzero(obj_state->os_symtab, + sizeof (obj_state->os_symtab[0]) * obj_state->os_symtabnum); + for (ndx = 0; ndx < obj_state->os_symtabnum; ndx++) + obj_state->os_symtab[ndx].symt_shndx = symtabndx[ndx]; + free(symtabndx); + } + + for (ndx = 1, scn = NULL; scn = elf_nextscn(tstate.os_elf, scn); + ndx++, _cache++) { + _cache->sec_shndx = ndx; + _cache->sec_scn = scn; + LIBELF(_cache->sec_shdr = elf_getshdr(scn), + MSG_ORIG(MSG_ELF_GETSHDR)) + _cache->sec_data = elf_getdata(scn, NULL); + _cache->sec_name = (_cache->sec_shdr->sh_name < names_len) ? + (names + _cache->sec_shdr->sh_name) : + MSG_INTL(MSG_UNKNOWNSECNAM); + + switch (_cache->sec_shdr->sh_type) { + case SHT_SYMTAB_SHNDX: + symtab = get_symtab(obj_state, _cache); + symtab->symt_xshndx = ndx; + break; + + case SHT_SUNW_syminfo: + symtab = get_symtab(obj_state, _cache); + symtab->symt_syminfo = ndx; + break; + + case SHT_SUNW_versym: + symtab = get_symtab(obj_state, _cache); + symtab->symt_versym = ndx; + break; + } + } + + /* + * Sanity check the symbol tables, and discard any auxiliary + * sections without enough elements. + */ + symtab = obj_state->os_symtab; + for (ndx = 0; ndx < obj_state->os_symtabnum; ndx++, symtab++) { + elfedit_section_t *symsec; + Word symsec_cnt, aux_cnt; + + symsec = &obj_state->os_secarr[symtab->symt_shndx]; + symsec_cnt = symsec->sec_shdr->sh_size / sizeof (Sym); + + /* Extended section indexes */ + if (symtab->symt_xshndx != SHN_UNDEF) { + _cache = &obj_state->os_secarr[symtab->symt_xshndx]; + aux_cnt = _cache->sec_shdr->sh_size / sizeof (Word); + if (symsec_cnt > aux_cnt) + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_AUX_SIZE), + EC_WORD(ndx), _cache->sec_name, + EC_WORD(aux_cnt), + EC_WORD(symsec->sec_shndx), + symsec->sec_name, EC_WORD(aux_cnt)); + } + + /* Syminfo */ + if (symtab->symt_syminfo != SHN_UNDEF) { + _cache = &obj_state->os_secarr[symtab->symt_syminfo]; + aux_cnt = _cache->sec_shdr->sh_size / sizeof (Syminfo); + if (symsec_cnt > aux_cnt) + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_AUX_SIZE), + EC_WORD(ndx), _cache->sec_name, + EC_WORD(aux_cnt), + EC_WORD(symsec->sec_shndx), + symsec->sec_name, EC_WORD(aux_cnt)); + } + + /* Versym */ + if (symtab->symt_versym != SHN_UNDEF) { + _cache = &obj_state->os_secarr[symtab->symt_versym]; + aux_cnt = _cache->sec_shdr->sh_size / sizeof (Versym); + if (symsec_cnt > aux_cnt) + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_AUX_SIZE), + EC_WORD(ndx), _cache->sec_name, + EC_WORD(aux_cnt), + EC_WORD(symsec->sec_shndx), + symsec->sec_name, EC_WORD(aux_cnt)); + } + } + + /* + * If this object has a dynsym section with a FLAGS_1 field, + * then set the DF_1_EDITED bit. elfedit allows changes that + * can break the resulting program, so knowing that a file was + * edited can be helpful when encountering a core file or other + * unexpected failure in the field. A single bit can't tell you + * what was changed, but it will alert you to the possibility that + * some additional questions might be in order. + */ + if (obj_state->os_dynndx != SHN_UNDEF) { + Word i; + Word numdyn; + elfedit_section_t *dynsec; + elfedit_dyn_elt_t flags_1_elt; + elfedit_dyn_elt_t null_elt; + Dyn *dyn; + + dynsec = &obj_state->os_secarr[obj_state->os_dynndx]; + dyn = (Dyn *) dynsec->sec_data->d_buf; + numdyn = dynsec->sec_shdr->sh_size / + dynsec->sec_shdr->sh_entsize; + elfedit_dyn_elt_init(&flags_1_elt); + elfedit_dyn_elt_init(&null_elt); + for (i = 0; i < numdyn; i++) { + + switch (dyn[i].d_tag) { + case DT_NULL: + /* + * Remember state of the first DT_NULL. If there + * are more than one (i.e. the first one is not + * in the final spot), and there is no flags1, + * then we will turn the first one into a + * DT_FLAGS_1. + */ + if (!null_elt.dn_seen) + elfedit_dyn_elt_save(&null_elt, i, + &dyn[i]); + break; + + case DT_FLAGS_1: + elfedit_dyn_elt_save(&flags_1_elt, i, &dyn[i]); + break; + } + } + /* If don't have a flags1 field, can we make one from a NULL? */ + if (!flags_1_elt.dn_seen && null_elt.dn_seen && + (null_elt.dn_ndx < (numdyn - 1))) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_NULL2DYNFL1), + EC_WORD(obj_state->os_dynndx), + dynsec->sec_name, EC_WORD(null_elt.dn_ndx)); + flags_1_elt.dn_seen = 1; + flags_1_elt.dn_ndx = null_elt.dn_ndx; + flags_1_elt.dn_dyn.d_tag = DT_FLAGS_1; + flags_1_elt.dn_dyn.d_un.d_val = 0; + } + /* + * If there is a flags 1 field, add the edit flag if + * it is not present, and report it's presence otherwise. + */ + if (flags_1_elt.dn_seen) { + if (flags_1_elt.dn_dyn.d_un.d_val & DF_1_EDITED) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_SEEDYNFLG), + EC_WORD(obj_state->os_dynndx), + dynsec->sec_name, + EC_WORD(flags_1_elt.dn_ndx)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_ADDDYNFLG), + EC_WORD(obj_state->os_dynndx), + dynsec->sec_name, + EC_WORD(flags_1_elt.dn_ndx)); + flags_1_elt.dn_dyn.d_un.d_val |= DF_1_EDITED; + dyn[flags_1_elt.dn_ndx] = flags_1_elt.dn_dyn; + elfedit_modified_data(dynsec); + } + } + } + +#ifdef _ELF64 + state.elf.obj_state.s64 = obj_state; +#else + state.elf.obj_state.s32 = obj_state; +#endif + return; + +libelf_failure: + /* + * Control comes here if there is an error with LIBELF. + * + * entry: + * libelf_fail_name - Name of failing libelf function + * tstate.os_file - Name of ELF file being processed + * tstate.os_fd - Descriptor of open ELF file + * + * exit: + * - dynamic memory is released if necessary + * - The error issued + */ + if (obj_state != NULL) + free(obj_state); + (void) close(tstate.os_fd); + elfedit_elferr(tstate.os_file, libelf_fail_name); +#undef LIBELF_FAILURE +#undef INITIAL_SYMTABNDX_ALLOC +} diff --git a/usr/src/cmd/sgs/elfedit/common/lintsup.c b/usr/src/cmd/sgs/elfedit/common/lintsup.c new file mode 100644 index 0000000000..410f5525a1 --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/common/lintsup.c @@ -0,0 +1,122 @@ +/* + * 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. + */ +/* LINTLIBRARY */ +/* PROTOLIB1 */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Supplemental Pseudo-code to get lint to consider these symbols used. + */ +#include <msg.h> +#include <debug.h> +#include <elfedit.h> + +/* + * Lint doesn't understand that both elfedit{32|64}_init_obj_state() + * gets built, because it doesn't know that elfedit_machelf.c gets + * compiled twice. The difference between this case and the others + * is that we don't use macros to give them both the same name, + * because elfedit.c needs to know about both explictly. So, + * supply the "missing" one here, for lint's benefit. + * + * This dummy routine eliminates the "name used but not defined" + * errors that otherwise result. + */ +#ifdef _ELF64 +/*ARGSUSED*/ +void +elfedit32_init_obj_state(const char *file, int fd, Elf *elf) +{ +} +#else +/*ARGSUSED*/ +void +elfedit64_init_obj_state(const char *file, int fd, Elf *elf) +{ +} +#endif + + +void +foo() +{ + dbg_print(NULL, NULL, 0); + + elfedit_array_elts_delete(NULL, NULL, 0, 0, 0, 0); + elfedit_array_elts_move(NULL, NULL, 0, 0, 0, 0, 0, NULL); + + (void) _elfedit_msg((Msg)&__elfedit_msg[0]); + + (void) elfedit_atoi(NULL, NULL); + (void) elfedit_atoui(NULL, NULL); + (void) elfedit_atoconst(NULL, 0); + + (void) elfedit_atoi2(NULL, NULL, NULL); + (void) elfedit_atoui2(NULL, NULL, NULL); + (void) elfedit_atoconst2(NULL, 0, NULL); + + (void) elfedit_atoi_range(NULL, NULL, 0, 0, NULL); + (void) elfedit_atoui_range(NULL, NULL, 0, 0, NULL); + (void) elfedit_atoconst_range(NULL, NULL, 0, 0, 0); + + (void) elfedit_atoi_range2(NULL, 0, 0, NULL, NULL); + (void) elfedit_atoui_range2(NULL, 0, 0, NULL, NULL); + (void) elfedit_atoconst_range2(NULL, 0, 0, 0, NULL); + + (void) elfedit_atoi_value_to_str(NULL, 0, 0); + (void) elfedit_atoui_value_to_str(NULL, 0, 0); + (void) elfedit_atoconst_value_to_str(0, 0, 0); + + (void) elfedit_atoshndx(NULL, 0); + + (void) elfedit_cpl_atoi(NULL, NULL); + (void) elfedit_cpl_atoui(NULL, NULL); + (void) elfedit_cpl_atoconst(NULL, 0); + + (void) elfedit_dyn_offset_to_str(NULL, NULL); + (void) elfedit_dynstr_insert(NULL, NULL, NULL, NULL); + (void) elfedit_flags(); + (void) elfedit_modified_ehdr(NULL); + (void) elfedit_modified_phdr(NULL); + (void) elfedit_modified_shdr(NULL); + (void) elfedit_mach_sunw_hw1_to_atoui(0); + (void) elfedit_name_to_shndx(NULL, NULL); + (void) elfedit_name_to_symndx(NULL, NULL, NULL, ELFEDIT_MSG_ERR, NULL); + (void) elfedit_outstyle(); + (void) elfedit_sec_getcap(NULL, NULL, NULL); + (void) elfedit_sec_getdyn(NULL, NULL, NULL); + (void) elfedit_sec_getstr(NULL, 0); + (void) elfedit_sec_getsyminfo(NULL, NULL, NULL); + (void) elfedit_sec_getsymtab(NULL, 0, 0, NULL, NULL, NULL, NULL); + (void) elfedit_sec_getversym(NULL, NULL, NULL, NULL); + (void) elfedit_sec_getxshndx(NULL, NULL, NULL, NULL); + (void) elfedit_sec_msgprefix(NULL); + (void) elfedit_shndx_to_name(NULL, NULL); + (void) elfedit_strtab_insert(NULL, NULL, NULL, NULL); + (void) elfedit_strtab_insert_test(NULL, NULL, NULL, NULL); + (void) elfedit_type_to_shndx(NULL, 0); +} diff --git a/usr/src/cmd/sgs/elfedit/common/mapfile-vers b/usr/src/cmd/sgs/elfedit/common/mapfile-vers new file mode 100644 index 0000000000..5f0efd4e9e --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/common/mapfile-vers @@ -0,0 +1,185 @@ +# +# 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. +# +#ident "%Z%%M% %I% %E% SMI" +# + +{ + global: + main; # debuggers seem to like this. + + + + # liblddbg dbg_print() function + dbg_print = NODIRECT; + + + + # Core API + elfedit_command_usage; + elfedit_cpl_match; + elfedit_cpl_module; + elfedit_cpl_command; + elfedit_elferr; + elfedit_flags; + elfedit_malloc; + elfedit_msg; + elfedit_outstyle; + elfedit_pager_init; + elfedit_printf; + elfedit_realloc; + + + + # ato[u]i routines + elfedit_const_to_atoui; + elfedit_mach_sunw_hw1_to_atoui; + + elfedit_atoi; + elfedit_atoui; + elfedit_atoconst; + + elfedit_atoi2; + elfedit_atoui2; + elfedit_atoconst2; + + elfedit_atoi_range; + elfedit_atoui_range; + elfedit_atoconst_range; + + elfedit_atoi_range2; + elfedit_atoui_range2; + elfedit_atoconst_range2; + + elfedit_atoi_value_to_str; + elfedit_atoui_value_to_str; + elfedit_atoconst_value_to_str; + + elfedit_cpl_atoi; + elfedit_cpl_atoui; + elfedit_cpl_atoconst; + + + + # Convenience functions built on top of the ato[u]i routines + elfedit_atobool; + elfedit_atoshndx; + + + + # Getopt + elfedit_getopt_init; + elfedit_getopt; + + + + # Utilities + elfedit_array_elts_delete; + + elfedit_array_elts_move; + + elfedit_bits_set; + + elfedit32_dyn_elt_init; + elfedit64_dyn_elt_init; + + elfedit32_dyn_elt_save; + elfedit64_dyn_elt_save; + + elfedit32_dyn_offset_to_str; + elfedit64_dyn_offset_to_str; + + elfedit32_dynstr_getpad; + elfedit64_dynstr_getpad; + + elfedit32_dynstr_insert; + elfedit64_dynstr_insert; + + elfedit32_modified_ehdr; + elfedit64_modified_ehdr; + + elfedit32_modified_phdr; + elfedit64_modified_phdr; + + elfedit32_modified_shdr; + elfedit64_modified_shdr; + + elfedit32_modified_data; + elfedit64_modified_data; + + elfedit32_name_to_shndx; + elfedit64_name_to_shndx; + + elfedit32_name_to_symndx; + elfedit64_name_to_symndx; + + elfedit32_offset_to_str; + elfedit64_offset_to_str; + + elfedit32_sec_findstr; + elfedit64_sec_findstr; + + elfedit32_sec_getcap; + elfedit64_sec_getcap; + + elfedit32_sec_getdyn; + elfedit64_sec_getdyn; + + elfedit32_sec_getstr; + elfedit64_sec_getstr; + + elfedit32_sec_getsyminfo; + elfedit64_sec_getsyminfo; + + elfedit32_sec_getsymtab; + elfedit64_sec_getsymtab; + + elfedit32_sec_getversym; + elfedit64_sec_getversym; + + elfedit32_sec_getxshndx; + elfedit64_sec_getxshndx; + + elfedit32_sec_issymtab; + elfedit64_sec_issymtab; + + elfedit32_shndx_to_name; + elfedit64_shndx_to_name; + + elfedit32_sec_msgprefix; + elfedit64_sec_msgprefix; + + elfedit32_strtab_insert; + elfedit64_strtab_insert; + + elfedit32_strtab_insert_test; + elfedit64_strtab_insert_test; + + elfedit32_type_to_shndx; + elfedit64_type_to_shndx; + + local: + *; +}; diff --git a/usr/src/cmd/sgs/elfedit/common/sys.c b/usr/src/cmd/sgs/elfedit/common/sys.c new file mode 100644 index 0000000000..92b3564fc1 --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/common/sys.c @@ -0,0 +1,1042 @@ +/* + * 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 <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <strings.h> +#include <elfedit.h> +#include "_elfedit.h" +#include "msg.h" + + + + +/* + * This file provides the builtin sys module. It is similar to the + * other modules, but differs in several important ways: + * + * - It is built as a static part of elfedit, and not + * as a sharable object. + * - It must be avaialble before the ELFCLASS of the object + * is known, so it is not ELFCLASS specific. We don't build + * it twice with machdep.h, as we do for the loadable modules. + * This means that commands need to test for the type + * of their obj_state argument at runtime. + * - The init function signature is different. We build an entire + * module definition statically. + */ + + + +/* + * 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 sys_opt_t enum specifies a bit value for every optional argument + * allowed by a command in this module. + */ +typedef enum { + SYS_OPT_F_ALL = 1, /* -a */ + SYS_OPT_F_FORCE = 2, /* -f */ + SYS_OPT_F_SYNOPSIS = 4, /* -s */ +} dyn_opt_t; + + +/* + * Given a generic (void *) pointer to an obj_state argument, determine + * which type it is, and return the st_file, st_fd and st_elf fields. + */ +static void +get_obj_state_info(void *obj_state, const char **file, int *fd, Elf **elf) +{ + if (state.elf.elfclass == ELFCLASS32) { + elfedit32_obj_state_t *s = (elfedit32_obj_state_t *)obj_state; + + *file = s->os_file; + *fd = s->os_fd; + *elf = s->os_elf; + } else { + elfedit64_obj_state_t *s = (elfedit64_obj_state_t *)obj_state; + + *file = s->os_file; + *fd = s->os_fd; + *elf = s->os_elf; + } +} + + + +/* + * Helper for cmd_help(). Displays synopsis information for one command. + */ +static void +cmd_help_synopsis(elfeditGC_module_t *mod, elfeditGC_cmd_t *cmd) +{ + char name_buf[128]; + const char *name; + const char **cmd_name; + + if (cmd->cmd_name[1] == NULL) { /* One name */ + name = *cmd->cmd_name; + } else { + const char *cname; + int need_comma = 0; + + name = name_buf; + (void) snprintf(name_buf, sizeof (name_buf), + MSG_ORIG(MSG_HLPFMT_MULTNAM), cmd->cmd_name[0]); + for (cmd_name = cmd->cmd_name + 1; + *cmd_name; cmd_name++) { + if (need_comma) + (void) strlcat(name_buf, + MSG_ORIG(MSG_STR_COMMA_SP), + sizeof (name_buf)); + need_comma = 1; + cname = (cmd_name[0][0] == '\0') ? + MSG_INTL(MSG_HLPFMT_MODDEFCMD) : *cmd_name; + (void) strlcat(name_buf, cname, + sizeof (name_buf)); + } + (void) strlcat(name_buf, MSG_ORIG(MSG_STR_CPAREN), + sizeof (name_buf)); + } + elfedit_printf(MSG_ORIG(MSG_HLPFMT_NAMSUMHDR), name, + (* mod->mod_i18nhdl_to_str)(cmd->cmd_desc)); + elfedit_printf(MSG_INTL(MSG_HLPFMT_SUMSYNOPSIS), + elfedit_format_command_usage(mod, cmd, + MSG_ORIG(MSG_STR_HLPSUMINDENT), + strlen(MSG_ORIG(MSG_STR_HLPSUMINDENT)))); +} + + +/* + * Helper for cmd_help(). Displays synopsis information for one module. + */ +static void +cmd_help_showmod(elfeditGC_module_t *mod) +{ + elfeditGC_cmd_t *cmd; + + elfedit_printf(MSG_ORIG(MSG_HLPFMT_NAMDSCHDR), + mod->mod_name, (* mod->mod_i18nhdl_to_str)(mod->mod_desc)); + for (cmd = mod->mod_cmds; cmd->cmd_func != NULL; cmd++) { + if (cmd != mod->mod_cmds) + elfedit_printf(MSG_ORIG(MSG_STR_NL)); + elfedit_printf(MSG_ORIG(MSG_STR_NL)); + cmd_help_synopsis(mod, cmd); + } +} + + +/* + * Given a string containing newline characters, break it into + * individual lines, and output each line with the given + * prefix string in front. + */ +static void +write_help_str(const char *str, const char *prefix) +{ + size_t i; + + if (str == NULL) + return; + while (*str) { + i = strcspn(str, MSG_ORIG(MSG_STR_NL)); + if (*(str + i) != '\0') + i++; + elfedit_printf(prefix); + elfedit_write(str, i); + str += i; + } +} + + +/* + * Given a title, and a NULL terminated list of option/argument + * descriptors, output the list contents. + */ +static void +write_optarg(elfeditGC_module_t *mod, const char *title, + elfedit_cmd_optarg_t *optarg) +{ + int cnt; + int len; + const char *help; + elfedit_optarg_item_t item; + + elfedit_printf(title); + for (cnt = 0; optarg->oa_name != NULL; cnt++) { + elfedit_next_optarg(&optarg, &item); + + /* Insert a blank line between items */ + if (cnt > 0) + elfedit_printf(MSG_ORIG(MSG_STR_NL)); + + /* Indentation */ + elfedit_printf(MSG_ORIG(MSG_STR_HLPINDENT)); + len = strlen(item.oai_name); + help = elfedit_optarg_helpstr(mod, &item); + if (item.oai_flags & ELFEDIT_CMDOA_F_VALUE) { + len += 1 + strlen(item.oai_vname); + elfedit_printf(MSG_ORIG(MSG_STR_HLPOPTARG2), + item.oai_name, item.oai_vname); + } else { + elfedit_printf(MSG_ORIG(MSG_STR_HLPOPTARG), + item.oai_name); + } + + /* + * If name is too long, inject a newline to avoid + * crowding the help text. + */ + if (len > 3) + elfedit_printf(MSG_ORIG(MSG_STR_NL)); + + /* Output the help text with a tab prefix */ + write_help_str(help, MSG_ORIG(MSG_STR_TAB)); + } +} + + +/* + * Implementation of sys:help + */ +/*ARGSUSED*/ +static elfedit_cmdret_t +cmd_help(void *obj_state, int argc, const char *argv[]) +{ +#define INITIAL_ITEM_ALLOC 4 + + + /* + * An array of this type is used to collect the data needed to + * generate help output. + */ + typedef struct { + elfeditGC_cmd_t *cmd; + elfeditGC_module_t *cmd_mod; /* Used with cmd */ + elfeditGC_module_t *mod; + } ITEM; + + static ITEM *item; + static int item_cnt; + + MODLIST_T *modlist; + int dispcnt; + size_t i; + elfeditGC_module_t *mod; + elfeditGC_cmd_t *cmd; + int minus_s = 0; + elfedit_getopt_state_t getopt_state; + ITEM *cur_item; + + /* + * Process options. The only option accepted is -s, so we + * don't even have to check the idmask to know. + */ + elfedit_getopt_init(&getopt_state, &argc, &argv); + while (elfedit_getopt(&getopt_state) != NULL) + minus_s = 1; + + /* + * This command can produce an arbitrary amount of output, so + * run a pager. + */ + elfedit_pager_init(); + + if (argc == 0) { + if (minus_s) { + /* Force all modules to load so we have data */ + elfedit_load_modpath(); + for (modlist = state.modlist; modlist; + modlist = modlist->ml_next) { + cmd_help_showmod(modlist->ml_mod); + if (modlist->ml_next != NULL) { + elfedit_printf(MSG_ORIG(MSG_STR_NL)); + elfedit_printf(MSG_ORIG(MSG_STR_NL)); + } + } + return (ELFEDIT_CMDRET_NONE); + } + + /* + * If no arguments are present, we display a simple + * "how to use help" tutorial, which will hopefully + * bootstrap the user into a position where they + * know how to run the help command, and then find + * what they're really after. + */ + elfedit_printf(MSG_INTL(MSG_SYS_HELP_HELP_NOARG)); + return (ELFEDIT_CMDRET_NONE); + } + + + /* + * As we process the arguments, we are willing to treat each + * one as either a module or a command: + * 1) An item without a colon can be a module, + * or a command from the sys: module. + * 2) An item with a colon, and no command part is + * a module, and it can also be the default + * command for the module, if it has one. We choose + * to only display the module info in this case, since + * the use of "" to represent the default command is + * an implementation detail, not a user-facing concept. + * 3) An item with a colon and a command part can only be + * a command. + * + * Note that there are cases where one argument can have two + * valid interpretations. In this case, we display them both. + * + * Pass over the arguments and determine how many distinct + * "things" we need to display. At the same time, force any + * needed modules to load so that the debug load messages won't + * show up in between the displayed items, and save the command + * and module definitions we will need to generate the output. + */ + if (argc > item_cnt) { + int n = (item_cnt == 0) ? INITIAL_ITEM_ALLOC : item_cnt; + + while (n < argc) + n *= 2; + + item = elfedit_realloc(MSG_INTL(MSG_ALLOC_HELPITEM), item, + n * sizeof (*item)); + item_cnt = n; + } + + dispcnt = 0; + for (i = 0; i < argc; i++) { + const char *colon = strchr(argv[i], ':'); + + if (colon == NULL) { /* No colon: sys: cmd or module */ + item[i].cmd = + elfedit_find_command(argv[i], 0, &item[i].cmd_mod); + if (item[i].cmd != NULL) + dispcnt++; + + /* + * Also try to load it as a module. If a command + * was found, then this need not succeed. Otherwise, + * it has to be a module, and we cause an error + * to be issued if not. + */ + item[i].mod = elfedit_load_module(argv[i], + item[i].cmd == NULL, 0); + if (item[i].mod != NULL) + dispcnt++; + } else if (*(colon + 1) == '\0') { + /* Just colon: Module (and maybe default command) */ + char buf[ELFEDIT_MAXMODNAM + 1]; + const char *str = argv[i]; + int len = colon - str; + + item[i].cmd = NULL; + /* Strip off the colon */ + if (len < sizeof (buf)) { + (void) strncpy(buf, str, len); + buf[len] = '\0'; + str = buf; + } + item[i].mod = elfedit_load_module(str, 1, 0); + dispcnt++; + } else { /* A command */ + item[i].cmd = + elfedit_find_command(argv[i], 1, &item[i].cmd_mod); + dispcnt++; + item[i].mod = NULL; + } + } + + /* + * Having validated the items, loop over them again and produce + * the required help output. + */ + for (cur_item = item; argc--; argv++, cur_item++) { + + + /* Help for a module? */ + if (cur_item->mod != NULL) { + if (dispcnt > 1) + elfedit_printf(MSG_ORIG(MSG_HLPFMT_MULTIHDR), + *argv); + cmd_help_showmod(cur_item->mod); + if ((dispcnt > 1) && (argc > 0)) + elfedit_printf(MSG_INTL(MSG_HLPFMT_MULTIEND), + argv[0], argv[1]); + /* An empty line after the last line of output */ + elfedit_printf(MSG_ORIG(MSG_STR_NL)); + } + + /* Help for a command? */ + if (cur_item->cmd == NULL) + continue; + cmd = cur_item->cmd; + mod = cur_item->cmd_mod; + if (dispcnt > 1) + elfedit_printf(MSG_ORIG(MSG_HLPFMT_MULTIHDR), *argv); + + /* If -s, display quick synopsis rather than the whole thing */ + if (minus_s) { + cmd_help_synopsis(mod, cmd); + continue; + } + + elfedit_printf(MSG_INTL(MSG_HLPFMT_MOD), mod->mod_name, + (* mod->mod_i18nhdl_to_str)(mod->mod_desc)); + elfedit_printf(MSG_INTL(MSG_HLPFMT_NAME), + *cmd->cmd_name, + (* mod->mod_i18nhdl_to_str)(cmd->cmd_desc)); + elfedit_printf(MSG_INTL(MSG_HLPFMT_SYNOPSIS), + elfedit_format_command_usage(mod, cmd, + MSG_ORIG(MSG_STR_HLPUSEINDENT), + strlen(MSG_ORIG(MSG_STR_HLPINDENT)))); + /* If there are alias names, show them */ + if (cmd->cmd_name[1] != NULL) { + const char **alias = cmd->cmd_name + 1; + + elfedit_printf(MSG_INTL(MSG_HLPFMT_ALIASES)); + do { + elfedit_printf( + MSG_ORIG(MSG_STR_HLPINDENT)); + elfedit_printf( + MSG_ORIG(MSG_FMT_MODCMD), + mod->mod_name, *alias); + if (**alias == '\0') + elfedit_printf( + MSG_INTL(MSG_HLPFMT_DEFCMD)); + elfedit_printf(MSG_ORIG(MSG_STR_NL)); + alias++; + } while (*alias); + } + elfedit_printf(MSG_INTL(MSG_HLPFMT_DESC)); + write_help_str( + (* mod->mod_i18nhdl_to_str)(cmd->cmd_help), + MSG_ORIG(MSG_STR_HLPINDENT)); + if (cmd->cmd_args != NULL) + write_optarg(mod, MSG_INTL(MSG_HLPFMT_ARGS), + cmd->cmd_args); + if (cmd->cmd_opt != NULL) + write_optarg(mod, MSG_INTL(MSG_HLPFMT_OPT), + cmd->cmd_opt); + if ((dispcnt > 1) && (argc > 0)) + elfedit_printf(MSG_INTL(MSG_HLPFMT_MULTIEND), + argv[0], argv[1]); + /* An empty line after the last line of output */ + elfedit_printf(MSG_ORIG(MSG_STR_NL)); + } + + return (ELFEDIT_CMDRET_NONE); + +#undef INITIAL_ITEM_ALLOC +} + + +/* + * Command completion function for sys:help + */ +/*ARGSUSED*/ +static void +cpl_help(void *obj_state, void *cpldata, int argc, const char *argv[], + int num_opt) +{ + /* + * The arguments can be any module or command. Supplying the + * commands implicitly supplies the modules too. + */ + elfedit_cpl_command(cpldata); +} + + +/* + * Implementation of sys:load + */ +/*ARGSUSED*/ +static elfedit_cmdret_t +cmd_load(void *obj_state, int argc, const char *argv[]) +{ + elfedit_getopt_state_t getopt_state; + elfedit_getopt_ret_t *getopt_ret; + struct stat statbuf; + + elfedit_getopt_init(&getopt_state, &argc, &argv); + while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL) { + switch (getopt_ret->gor_idmask) { + case SYS_OPT_F_ALL: + elfedit_load_modpath(); + break; + } + } + + /* For each remaining argument, load them individually */ + for (; argc-- > 0; argv++) { + /* Is it a directory? Load everything in it */ + if ((stat(*argv, &statbuf) == 0) && + (statbuf.st_mode & S_IFDIR)) { + elfedit_load_moddir(*argv, 1, 1); + } else { /* Not a directory. Normal load */ + (void) elfedit_load_module(*argv, 1, 1); + } + } + + return (0); +} + + +/* + * Command completion function for sys:load + */ +/*ARGSUSED*/ +static void +cpl_load(void *obj_state, void *cpldata, int argc, const char *argv[], + int num_opt) +{ + /* + * Module names. Note that this causes elfedit to load all + * of the modules, which probably makes the current load + * operation unnecessary. This could be improved, but I don't + * see it as worth the complexity. Explicit load calls are + * rare, and the user will usually not use command completion. + */ + elfedit_cpl_module(cpldata, 1); +} + + +/* + * Implementation of sys:quit + */ +/*ARGSUSED*/ +static elfedit_cmdret_t +cmd_quit(void *obj_state, int argc, const char *argv[]) +{ + elfedit_getopt_state_t getopt_state; + elfedit_getopt_ret_t *getopt_ret; + int force = 0; + const char *file; + int fd; + Elf *elf; + + elfedit_getopt_init(&getopt_state, &argc, &argv); + while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL) { + switch (getopt_ret->gor_idmask) { + case SYS_OPT_F_FORCE: + force = 1; + break; + } + } + if (argc != 0) + elfedit_command_usage(); + + if (state.file.present) { + /* + * If session is not READONLY, then refuse to quit if file + * needs flushing and -f option was not used. + */ + if (!(state.flags & ELFEDIT_F_READONLY) && state.file.dirty && + !force) + elfedit_msg(ELFEDIT_MSG_ERR, + MSG_INTL(MSG_ERR_NODIRTYQUIT)); + + get_obj_state_info(obj_state, &file, &fd, &elf); + (void) close(fd); + (void) elf_end(elf); + free(obj_state); + } + + elfedit_exit(0); + /*NOTREACHED*/ + return (0); +} + + +/* + * Implementation of sys:status + */ +/*ARGSUSED*/ +static elfedit_cmdret_t +cmd_status(void *obj_state, int argc, const char *argv[]) +{ + MODLIST_T *modlist; + const char *s; + size_t i; + + if (argc > 0) + elfedit_command_usage(); + + /* + * This command can produce an arbitrary amount of output, so + * run a pager. + */ + elfedit_pager_init(); + + /* Files */ + if (state.file.present == 0) { + elfedit_printf(MSG_INTL(MSG_HLPFMT_INFILENONE)); + } else if (state.flags & ELFEDIT_F_READONLY) { + elfedit_printf(MSG_INTL(MSG_HLPFMT_INFILERO), + state.file.infile); + } else { + elfedit_printf(MSG_INTL(MSG_HLPFMT_INFILE), state.file.infile); + elfedit_printf(MSG_INTL(MSG_HLPFMT_OUTFILE), + state.file.outfile); + } + if (state.file.dirty) + elfedit_printf(MSG_INTL(MSG_HLPFMT_CNGPENDING)); + + /* Option Variables */ + elfedit_printf(MSG_INTL(MSG_HLPFMT_VARHDR)); + elfedit_printf(MSG_INTL(MSG_HLPFMT_AFLG), + (state.flags & ELFEDIT_F_AUTOPRINT) ? MSG_ORIG(MSG_STR_ON) : + MSG_ORIG(MSG_STR_OFF)); + elfedit_printf(MSG_INTL(MSG_HLPFMT_DFLG), + (state.flags & ELFEDIT_F_DEBUG) ? MSG_ORIG(MSG_STR_ON) : + MSG_ORIG(MSG_STR_OFF)); + elfedit_printf(MSG_INTL(MSG_HLPFMT_OFLG), + elfedit_atoconst_value_to_str(ELFEDIT_CONST_OUTSTYLE, + state.outstyle, 1)); + + /* Module Load Path */ + elfedit_printf(MSG_INTL(MSG_HLPFMT_PATHHDR)); + for (i = 0; i < state.modpath.n; i++) + elfedit_printf(MSG_ORIG(MSG_HLPFMT_PATHELT), + state.modpath.seg[i]); + + /* Currently Loaded Modules */ + elfedit_printf(MSG_INTL(MSG_HLPFMT_MODHDR)); + for (modlist = state.modlist; modlist; + modlist = modlist->ml_next) { + s = modlist->ml_path ? modlist->ml_path : + MSG_INTL(MSG_FMT_BUILTIN); + elfedit_printf(MSG_ORIG(MSG_HLPFMT_NAMDSCCOL), + modlist->ml_mod->mod_name, s); + } + + return (ELFEDIT_CMDRET_NONE); +} + +/* + * Implementation of sys:set + */ +/*ARGSUSED*/ +static elfedit_cmdret_t +cmd_set(void *obj_state, int argc, const char *argv[]) +{ + if ((argc != 2) || (strlen(argv[0]) > 1)) + elfedit_command_usage(); + + switch (**argv) { + case 'a': + case 'A': + if (elfedit_atobool(argv[1], MSG_INTL(MSG_SYSSET_A))) + state.flags |= ELFEDIT_F_AUTOPRINT; + else + state.flags &= ~ELFEDIT_F_AUTOPRINT; + break; + + case 'd': + case 'D': + if (elfedit_atobool(argv[1], MSG_INTL(MSG_SYSSET_D))) + state.flags |= ELFEDIT_F_DEBUG; + else + state.flags &= ~ELFEDIT_F_DEBUG; + break; + + case 'o': + case 'O': + if (elfedit_atooutstyle(argv[1], &state.outstyle) == 0) + elfedit_msg(ELFEDIT_MSG_ERR, + MSG_INTL(MSG_ERR_BADOSTYLE), argv[1]); + break; + + default: + elfedit_command_usage(); + } + + return (0); +} + + +/* + * Command completion function for sys:set + */ +/*ARGSUSED*/ +static void +cpl_set(void *obj_state, void *cpldata, int argc, const char *argv[], + int num_opt) +{ + const char *s; + + /* + * This command doesn't accept options, so num_opt should be + * 0. This is a defensive measure, in case that should change. + */ + argc -= num_opt; + argv += num_opt; + + if ((argc < 1) || (argc > 2)) + return; + + if (argc == 1) { /* The first argument is a variable letter */ + elfedit_cpl_match(cpldata, MSG_ORIG(MSG_STR_A), 1); + elfedit_cpl_match(cpldata, MSG_ORIG(MSG_STR_D), 1); + elfedit_cpl_match(cpldata, MSG_ORIG(MSG_STR_O), 1); + elfedit_cpl_match(cpldata, MSG_ORIG(MSG_STR_W), 1); + return; + } + + /* We're dealing with the second argument, the value */ + s = argv[0]; + if (strlen(s) > 1) /* One letter variables */ + return; + switch (*s) { + case 'a': /* Booleans */ + case 'A': + case 'd': + case 'D': + case 'w': + case 'W': + /* The second argument is a boolean */ + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_BOOL); + + /* The numbers are not symbolic, but we want them in the list */ + elfedit_cpl_match(cpldata, MSG_ORIG(MSG_STR_0), 1); + elfedit_cpl_match(cpldata, MSG_ORIG(MSG_STR_1), 1); + break; + + case 'o': /* Output style */ + case 'O': + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_OUTSTYLE); + break; + } +} + + +/* + * Implementation of sys:unload + */ +/*ARGSUSED*/ +static elfedit_cmdret_t +cmd_unload(void *obj_state, int argc, const char *argv[]) +{ + elfedit_getopt_state_t getopt_state; + elfedit_getopt_ret_t *getopt_ret; + MODLIST_T *moddef; + int do_all = 0; + + elfedit_getopt_init(&getopt_state, &argc, &argv); + while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL) { + switch (getopt_ret->gor_idmask) { + case SYS_OPT_F_ALL: + do_all = 1; + break; + } + } + + /* + * If -a is specified, unload everything except builtins. Don't + * allow plain arguments in this case because there is nothing + * left to unload after -a. + */ + if (do_all) { + if (argc > 0) + elfedit_command_usage(); + /* + * Until we run out of non-builtin modules, take the first + * one from the list and unload it. Each removal alters + * the list, so we always start at the beginning, but this + * is efficient since we always remove the first available item + */ + while (state.modlist != NULL) { + for (moddef = state.modlist; moddef != NULL; + moddef = moddef->ml_next) + if (moddef->ml_dl_hdl != NULL) break; + + /* If we made it to the end, then the list is empty */ + if (moddef == NULL) + break; + + elfedit_unload_module(moddef->ml_mod->mod_name); + } + return (0); + } + + /* Unload each module individually */ + for (; argc-- > 0; argv++) + elfedit_unload_module(*argv); + + return (0); +} + + +/* + * Command completion function for sys:unload + */ +/*ARGSUSED*/ +static void +cpl_unload(void *obj_state, void *cpldata, int argc, const char *argv[], + int num_opt) +{ + /* + * Module names. Don't allow elfedit to load all the modules, + * as the only modules we want to unload are those already + * in memory. + */ + elfedit_cpl_module(cpldata, 0); +} + + +/* + * Implementation of sys:write + */ +/*ARGSUSED2*/ +static elfedit_cmdret_t +cmd_write(void *obj_state, int argc, const char *argv[]) +{ + const char *file; + int fd; + Elf *elf; + + if (argc != 0) + elfedit_command_usage(); + + if (state.file.present != 0) { + if (state.flags & ELFEDIT_F_READONLY) + elfedit_msg(ELFEDIT_MSG_ERR, + MSG_INTL(MSG_ERR_READONLY)); + + get_obj_state_info(obj_state, &file, &fd, &elf); + if (elf_update(elf, ELF_C_WRITE) == -1) + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_LIBELF), + file, MSG_ORIG(MSG_ELF_UPDATE), + elf_errmsg(elf_errno())); + + /* + * An update has succeeded for this file, so revoke the need + * to unlink it on exit. + */ + state.file.unlink_on_exit = 0; + } + + return (ELFEDIT_CMDRET_FLUSH); +} + + + + + +/*ARGSUSED*/ +MODLIST_T * +elfedit_sys_init(elfedit_module_version_t version) +{ + /* sys:help */ + static const char *name_help[] = { MSG_ORIG(MSG_SYS_CMD_HELP), + MSG_ORIG(MSG_SYS_CMD_HELP_A1), MSG_ORIG(MSG_SYS_CMD_HELP_A2), + NULL }; + static elfedit_cmd_optarg_t opt_help[] = { + { MSG_ORIG(MSG_STR_MINUS_S), + /* MSG_INTL(MSG_SYS_OPTDESC_HELP_S) */ + ELFEDIT_I18NHDL(MSG_SYS_OPTDESC_HELP_S), 0, + SYS_OPT_F_SYNOPSIS, 0 }, + { NULL } + }; + static elfedit_cmd_optarg_t arg_help[] = { + { MSG_ORIG(MSG_STR_ARG), + /* MSG_INTL(MSG_ARGDESC_HELP_ARG) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_HELP_ARG), + ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT }, + { NULL } + }; + + /* sys:load */ + static const char *name_load[] = { + MSG_ORIG(MSG_SYS_CMD_LOAD), NULL }; + static elfedit_cmd_optarg_t opt_load[] = { + { MSG_ORIG(MSG_STR_MINUS_A), + /* MSG_INTL(MSG_SYS_OPTDESC_LOAD_A) */ + ELFEDIT_I18NHDL(MSG_SYS_OPTDESC_LOAD_A), 0, + SYS_OPT_F_ALL, 0 }, + { NULL } + }; + static elfedit_cmd_optarg_t arg_load[] = { + { MSG_ORIG(MSG_STR_MODNAME), + /* MSG_INTL(MSG_ARGDESC_LOAD_MODNAME) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_LOAD_MODNAME), + ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT }, + { NULL } + }; + + /* sys:quit */ + static const char *name_quit[] = { MSG_ORIG(MSG_SYS_CMD_QUIT), + MSG_ORIG(MSG_SYS_CMD_QUIT_A1), MSG_ORIG(MSG_SYS_CMD_QUIT_A2), + NULL }; + static elfedit_cmd_optarg_t opt_quit[] = { + { MSG_ORIG(MSG_STR_MINUS_F), + /* MSG_INTL(MSG_SYS_OPTDESC_QUIT_F) */ + ELFEDIT_I18NHDL(MSG_SYS_OPTDESC_QUIT_F), 0, + SYS_OPT_F_FORCE, 0 }, + { NULL } + }; + + /* sys:status */ + static const char *name_status[] = { + MSG_ORIG(MSG_SYS_CMD_STATUS), NULL }; + + /* sys:set */ + static const char *name_set[] = { + MSG_ORIG(MSG_SYS_CMD_SET), NULL }; + static elfedit_cmd_optarg_t arg_set[] = { + { MSG_ORIG(MSG_STR_OPTION), + /* MSG_INTL(MSG_ARGDESC_SET_OPTION) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_SET_OPTION), 0 }, + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_ARGDESC_SET_VALUE) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_SET_VALUE), 0 }, + { NULL } + }; + + /* sys:unload */ + static const char *name_unload[] = { + MSG_ORIG(MSG_SYS_CMD_UNLOAD), NULL }; + static elfedit_cmd_optarg_t opt_unload[] = { + { MSG_ORIG(MSG_STR_MINUS_A), + /* MSG_INTL(MSG_SYS_OPTDESC_UNLOAD_A) */ + ELFEDIT_I18NHDL(MSG_SYS_OPTDESC_UNLOAD_A), 0, + SYS_OPT_F_ALL, 0}, + { NULL } + }; + static elfedit_cmd_optarg_t arg_unload[] = { + { MSG_ORIG(MSG_STR_MODNAME), + /* MSG_INTL(MSG_ARGDESC_UNLOAD_MODNAME) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_UNLOAD_MODNAME), + ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT }, + { NULL } + }; + + /* sys:write */ + static const char *name_write[] = { MSG_ORIG(MSG_SYS_CMD_WRITE), + MSG_ORIG(MSG_SYS_CMD_WRITE_A1), MSG_ORIG(MSG_SYS_CMD_WRITE_A2), + NULL }; + + static elfedit_cmd_t cmds[] = { + /* sym:help */ + { (elfedit_cmd_func_t *)cmd_help, + (elfedit_cmdcpl_func_t *)cpl_help, name_help, + /* MSG_INTL(MSG_SYS_DESC_HELP) */ + ELFEDIT_I18NHDL(MSG_SYS_DESC_HELP), + /* MSG_INTL(MSG_SYS_HELP_HELP) */ + ELFEDIT_I18NHDL(MSG_SYS_HELP_HELP), + opt_help, arg_help }, + + /* sym:load */ + { (elfedit_cmd_func_t *)cmd_load, + (elfedit_cmdcpl_func_t *)cpl_load, name_load, + /* MSG_INTL(MSG_SYS_DESC_LOAD) */ + ELFEDIT_I18NHDL(MSG_SYS_DESC_LOAD), + /* MSG_INTL(MSG_SYS_HELP_LOAD) */ + ELFEDIT_I18NHDL(MSG_SYS_HELP_LOAD), + opt_load, arg_load }, + + /* sym:quit */ + { (elfedit_cmd_func_t *)cmd_quit, NULL, name_quit, + /* MSG_INTL(MSG_SYS_DESC_QUIT) */ + ELFEDIT_I18NHDL(MSG_SYS_DESC_QUIT), + /* MSG_INTL(MSG_SYS_HELP_QUIT) */ + ELFEDIT_I18NHDL(MSG_SYS_HELP_QUIT), + opt_quit, NULL }, + + /* sym:status */ + { (elfedit_cmd_func_t *)cmd_status, NULL, name_status, + /* MSG_INTL(MSG_SYS_DESC_STATUS) */ + ELFEDIT_I18NHDL(MSG_SYS_DESC_STATUS), + /* MSG_INTL(MSG_SYS_HELP_STATUS) */ + ELFEDIT_I18NHDL(MSG_SYS_HELP_STATUS), + NULL, NULL }, + + /* sym:set */ + { (elfedit_cmd_func_t *)cmd_set, + (elfedit_cmdcpl_func_t *)cpl_set, name_set, + /* MSG_INTL(MSG_SYS_DESC_SET) */ + ELFEDIT_I18NHDL(MSG_SYS_DESC_SET), + /* MSG_INTL(MSG_SYS_HELP_SET) */ + ELFEDIT_I18NHDL(MSG_SYS_HELP_SET), + NULL, arg_set }, + + /* sym:unload */ + { (elfedit_cmd_func_t *)cmd_unload, + (elfedit_cmdcpl_func_t *)cpl_unload, name_unload, + /* MSG_INTL(MSG_SYS_DESC_UNLOAD) */ + ELFEDIT_I18NHDL(MSG_SYS_DESC_UNLOAD), + /* MSG_INTL(MSG_SYS_HELP_UNLOAD) */ + ELFEDIT_I18NHDL(MSG_SYS_HELP_UNLOAD), + opt_unload, arg_unload }, + + /* sym:write */ + { (elfedit_cmd_func_t *)cmd_write, NULL, name_write, + /* MSG_INTL(MSG_SYS_DESC_WRITE) */ + ELFEDIT_I18NHDL(MSG_SYS_DESC_WRITE), + /* MSG_INTL(MSG_SYS_HELP_WRITE) */ + ELFEDIT_I18NHDL(MSG_SYS_HELP_WRITE), + NULL, NULL}, + + { NULL } + }; + + static elfedit_module_t module = { + ELFEDIT_VER_CURRENT, MSG_ORIG(MSG_MOD_SYS), + /* MSG_INTL(MSG_MOD_SYS_DESC) */ + ELFEDIT_I18NHDL(MSG_MOD_SYS_DESC), + cmds, mod_i18nhdl_to_str }; + + static MODLIST_T moddef = { + NULL, /* next */ + (elfeditGC_module_t *)&module, /* Module definition */ + NULL, /* Didn't dlopen() it, so NULL handle */ + NULL /* Didn't dlopen() it, so no file path */ + }; + + return (&moddef); +} diff --git a/usr/src/cmd/sgs/elfedit/common/util.c b/usr/src/cmd/sgs/elfedit/common/util.c new file mode 100644 index 0000000000..b80ce2c2e4 --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/common/util.c @@ -0,0 +1,914 @@ +/* + * 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 <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> + + + +/* + * This file contains utility functions that are of general use + * to different elfedit modules for solving common problems. + * The functions in this file are not ELFCLASS specific. Those + * functions are found in util_machelf.c + * + * NOTE: This module contains functions with names + * elfedit_atoi, and elfedit_atoui, that are otherwise identical. + * These functions are for signed, and unsigned integers, respectively. + * In general, I supply one comment header for each such pair, + * and put their implementations together. + * + * There are also functions with names elfedit_atoconst. These are + * convenience wrappers that use the corresponding elfedit_atoui() + * function to process an array of symbolic names provided by a call + * elfedit_const_to_atoui(). + */ + + + + +/* + * Given a value and an array of elfedit_ato[u]i items, return a pointer + * to the symbolic name for the value. + * + * entry: + * sym - NULL terminated array of name->value mappings. + * value - Value to be found + * required - If True, and value is not found, an error is issued. + * Callers should only set required to True when they know + * a priori that the value will be found --- the error + * is reported as an internal programming error. + * + * exit: + * If the array contains an entry with the given value, the + * name for the first such entry will be returned. + * + * If no entry is found: If required is True (1), an error is + * issued and this routine does not return to the caller. If required + * is False (0), then NULL is returned. + */ +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); + + /* Value did not match any of the entries */ + 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); + + /* Value did not match any of the entries */ + 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)); +} + + +/* + * Process the symbolic name to value mappings passed to the + * atoi and atoui functions. + * + * entry: + * sym - NULL terminated array of name->value mappings. + * value - Address of variable to recieve corresponding value. + * + * exit: + * If a mapping is found, *value is set to it, and True is returned. + * Otherwise False is returned. + */ +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); + } + } + + /* No symbolic mapping was found */ + 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); + } + } + + /* No symbolic mapping was found */ + return (0); +} + + + +/* + * A command completion function for atoi and atoui mappings. + */ +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)); +} + + + + + +/* + * Convert a string to a numeric value. Strings starting with '0' + * are taken to be octal, those staring with '0x' are hex, and all + * others are decimal. + * + * entry: + * str - String to be converted + * sym - NULL, or NULL terminated array of name/value pairs. + * + * [elfedit_atoi2() and elfedit_atoui2() only] + * v - Address of variable to receive resulting value. + * + * exit: + * elfedit_atoi2() and elfedit_atoui2(): + * On success, returns True (1) and *v is set to the value. + * On failure, returns False (0) and *v is undefined. + * + * elfedit_atoi() and elfedit_atoui(): + * If the string is convertable, the value is returned. + * Otherwise an error is issued and this routine does + * not return to the caller. + */ +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); + + /* If the left over part contains anything but whitespace, fail */ + 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); + + /* If the left over part contains anything but whitespace, fail */ + 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))); +} + +/* + * Convert a string to a numeric value using elfedit_ato[u]i and + * ensure that the resulting value lies within a given range. + * elfedit_ato[u]i_range() requires values to be in the range + * (min <= value <= max). + * + * entry: + * str - String to be converted + * min, max - If check_range is true, the allowed range that the + * resulting value must lie in. + * sym - NULL, or NULL terminated array of name/value pairs. + * + * entry [elfedit_atoi_range() and elfedit_atoui_range() only]: + * item_name - String describing item for which value is being read. + * + * entry [elfedit_atoi_range2() and elfedit_atoui_range2() only]: + * v - Address of variable to receive resulting value. + * + * exit: + * elfedit_atoi_range2() and elfedit_atoui_range2(): + * On success, returns True (1) and *v is set to the value. + * On failure, returns False (0) and *v is undefined. + * + * elfedit_atoi_range() and elfedit_atoui_range(): + * If the string is convertable, the value is returned. + * Otherwise an error is issued and this routine does + * not return to the caller. + */ +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))); +} + + +/* + * Convenience wrapper on elfedit_atoui_range() that expects to see + * boolean values. Returns 1 for true, and 0 for false. + */ +int +elfedit_atobool(const char *str, const char *item_name) +{ + + return (elfedit_atoconst_range(str, item_name, 0, 1, + ELFEDIT_CONST_BOOL) != 0); +} + + + +/* + * Convenience wrapper on elfedit_atoui() to read a section index + * that understands the special SHN_ names. + * + * entry: + * str - String to process + * shnum - Number of sections in the ELF file + * + * exit: + * If it is possible to convert str to a number, that value + * is returned. If the value is out of range for the file, + * a warning message to that effect is issued. On failure, + * an error is issued and this routine does not return to + * the caller. + */ +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); +} + + + +/* + * Convert an output style string into it's integer constant. This + * routine reports success/failure via the return value rather than + * by throwing errors so that it can be used to process command + * line options at program startup, before + * the elfedit framework is initialized. + */ +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); +} + + + + +/* + * Initialize a state block for processing by elfedit_getopt(). + * + * entry: + * state - State block to initialize + * cmd_name - NULL, or name of command for which we are processing + * options. + * argc, argv - Address of variables giving number of options and + * access to the option strings. + * + * note: + * cmd_name can only be set to NULL when this routine is called + * by, or below, a currently active command. Otherwise, results + * are undefined (crashing or corruption) if there isn't one. + */ +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-centric version of getopt() + * + * entry: + * state - Getopt state, which must have been previously initialized + * via a call to elfedit_getopt_init. + * + * exit: + * If an option is matched, this routine returns a pointer to an + * elfedit_getopt_ret_t buffer (which comes from the storage used + * for state). If there are no more options to process, NULL is returned. + * + * Syntax errors are reported via elfedit_command_usage(), and this + * routine does not return to the caller. + * + * note: + * - The caller should not access the contents of state directly. + * Those contents are private, and subject to change. + * - Once a call to this routine returns NULL, the argc/argv have + * have been ajusted so that they reference the plain arguments. + */ +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) { + /* + * Reasons to bail out immediately: + * - The command does not accept options + * - We've already reported the final option. + * - There are no more arguments. + * - The next argument does not start with '-' + */ + if ((state->go_optarg == NULL) || state->go_done || + (argc <= 0) || (*(argv[0]) != '-')) { + state->go_done = 1; + return (NULL); + } + + argstr = argv[0]; + + /* A '-' by itself is a syntax error */ + if (argstr[1] == '\0') + elfedit_command_usage(); + + /* A '--' option means we should stop at this point */ + if ((argstr[1] == '-') && (argstr[2] == '\0')) { + (*state->go_argc)--; + (*state->go_argv)++; + return (NULL); + } + + /* + * We have a string that starts with a '-'. + * Does it match an option? + */ + 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 the option is a single letter that accepts + * a value, then we allow the combined syntax + * -ovalue, where no space is reqired between the + * option flag and the value string. + */ + if ((item.oai_name[2] == '\0') && need_value && + (argstr[1] == item.oai_name[1]) && + (argstr[2] != '\0')) { + /* + * We have a match. However, there may also + * be a straightforward match that we have + * not yet found. If so, we want to prefer that + * case over this one. So rather than return + * it immediately, we capture the information + * and keep looking. If nothing else surfaces, + * we'll use this later. + */ + 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; + } + + /* Try for a straightforward match */ + if (strcmp(argstr, item.oai_name) == 0) { + (*state->go_argc) = --argc; + (*state->go_argv) = ++argv; + + /* Mutually exclusive option already seen? */ + if (item.oai_excmask & state->go_idmask) + elfedit_command_usage(); + + /* Return the match */ + state->go_idmask |= item.oai_idmask; + state->go_ret.gor_idmask = item.oai_idmask; + if (need_value) { + /* If out of args, syntax error */ + 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); + } + } + + /* + * No straightforward matches: Did we get a match with + * the special single letter and combined value? If so + * return that now. + */ + if (sgl_with_value.valid) { + (*state->go_argc)--; + (*state->go_argv)++; + + /* Mutually exclusive option already seen? */ + 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); + } + + /* + * If nothing above matched, make this option the single + * group string and see if the characters in it all match + * as single letter options without values. + */ + state->go_sglgrp = argstr + 1; /* Skip '-' */ + } + + /* + * If there is a single group string, take the first character + * and try to match it to an 1-letter option that does not + * require a value. + */ + if (state->go_sglgrp != NULL) { + int ch = *state->go_sglgrp++; + + /* If that is the last character, clear single group mode */ + 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])) { + /* + * It matches. If the option requires a value + * then it cannot be in a group. + */ + if (item.oai_flags & ELFEDIT_CMDOA_F_VALUE) + elfedit_command_usage(); + + /* Mutually exclusive option already seen? */ + if (item.oai_excmask & state->go_idmask) + elfedit_command_usage(); + + /* Return the match */ + state->go_idmask |= item.oai_idmask; + state->go_ret.gor_idmask = item.oai_idmask; + state->go_ret.gor_value = NULL; + return (&state->go_ret); + } + } + } + + /* Nothing matched. We have a syntax error */ + elfedit_command_usage(); + /*NOTREACHED*/ + return (NULL); +} + + +/* + * Return the count of non-zero bits in the value v. + * + * entry: + * v - Value to test + * sizeof_orig_v - The result of using the sizeof operator + * on the original value of v. The value received + * by this routine has been cast to an unsigned 64-bit + * integer, so having the caller use sizeof allows us to + * avoid testing bits that were not in the original. + */ +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); +} + + +/* + * "delete" items in an array by copying the following items up + * over the "deleted" items and then zero filling the vacated + * slots at the bottom. + * + * entry: + * name_str - Array identification prefix to use for debug message + * data_start - Address of 1st byte in array + * entsize - sizeof a single element of the array + * num_ent - # of elements in array + * start_ndx - Index of first item to be deleted + * cnt - # of items to delete + * + * exit: + * Any errors are issued and control does not return to the + * caller. On success, the items have been removed, zero filling + * has been done, and debug messages issued. + */ +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; + + /* The specified index and range must be in bounds */ + 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)); + + /* + * Everything below the deleted items moves up. + * Note that bcopy() is documented to handle overlapping + * src/dst correctly, so we make no effort to handle this + * element by element, but issue a single operation. + * + * If we're doing the last element, there is nothing to + * move up, and we skip this step, moving on to the zeroing below. + */ + 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)); + } + } + + /* Zero out the vacated elements at the end */ + 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)); + } +} + + +/* + * move the location of items in an array by shifting the surround + * items into the vacated hole and them putting the values into + * the new location. + * + * entry: + * name_str - Array identification prefix to use for debug message + * data_start - Address of 1st byte in array + * entsize - sizeof a single element of the array + * num_ent - # of elements in array + * start_ndx - Index of first item to be moved + * dst_ndx - Index to receive the moved block + * cnt - # of items to move + * scr_item - Space allocated by the caller sufficient to hold + * one item from the array. Used to swap elements. + * + * exit: + * Any errors are issued and control does not return to the + * caller. On success, the items have been moved, and debug + * messages issued. + */ +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; + + /* The specified source and destination ranges must be in bounds */ + 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 source and destination are same, there's nothing to do */ + if (srcndx == dstndx) + return; + + /* + * It is meaningless to do a move where the source and destination + * are overlapping, because this "move" amounts to shifting + * the existing items around into a new position. If there is + * more than one element, then overlap is possible and we need + * to test for it. + */ + if (cnt > 1) { + size_t low, hi; + + if (srcndx > dstndx) { + low = dstndx; + hi = srcndx; + } else { + low = srcndx; + hi = dstndx; + } + /* Ensure that the src and dst don't overlap */ + 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--) { + /* + * Copy item at srcndx to scratch location + * + * save = dyn[srcndx]; + */ + bcopy(data + (srcndx * entsize), scr_item, entsize); + + /* + * Shift items after source up through destination + * to source. bcopy() handles overlapped copies. + * + * for (i = srcndx; i < dstndx; i++) + * dyn[i] = dyn[i + 1]; + */ + bcopy(data + ((srcndx + 1) * entsize), + data + (srcndx * entsize), + (dstndx - srcndx) * entsize); + + /* + * Copy saved item into destination slot + * + * dyn[dstndx] = save; + */ + bcopy(scr_item, data + (dstndx * entsize), entsize); + } + } else { + for (; cnt-- > 0; srcndx++, dstndx++) { + /* + * Copy item at srcndx to scratch location + * + * save = dyn[srcndx]; + */ + bcopy(data + (srcndx * entsize), scr_item, entsize); + + /* + * Shift items from destination through item below + * source up one. bcopy() handles overlapped copies. + * + * for (i = srcndx; i > dstndx; i--) + * dyn[i] = dyn[i - 1]; + */ + bcopy(data + (dstndx * entsize), + data + ((dstndx + 1) * entsize), + (srcndx - dstndx) * entsize); + + /* + * Copy saved item into destination slot + * + * dyn[dstndx] = save; + */ + bcopy(scr_item, data + (dstndx * entsize), entsize); + } + } +} diff --git a/usr/src/cmd/sgs/elfedit/common/util_machelf.c b/usr/src/cmd/sgs/elfedit/common/util_machelf.c new file mode 100644 index 0000000000..f3538ba2fa --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/common/util_machelf.c @@ -0,0 +1,1149 @@ +/* + * 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 <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <libintl.h> +#include <machdep.h> +#include <libelf.h> +#include <link.h> +#include <strings.h> +#include <ctype.h> +#include "msg.h" +#include <elfedit.h> +#include <conv.h> +#include <sys/elf_SPARC.h> +#include <sys/elf_amd64.h> + + + +/* + * ELFCLASS specific code that would otherwise be found in util.c + */ + + + + +/* + * When you modify ELF constructs, you need to tell libelf that you've + * done so. Otherwise, the changes may not be flushed back to the + * output file. + * + * The elfedit_modified_*() functions exist to simplify the calls to + * the underlying elf_flag*() functions. + */ +void +elfedit_modified_ehdr(elfedit_obj_state_t *obj_state) +{ + (void) elf_flagehdr(obj_state->os_elf, ELF_C_SET, ELF_F_DIRTY); +} + +void +elfedit_modified_phdr(elfedit_obj_state_t *obj_state) +{ + (void) elf_flagphdr(obj_state->os_elf, ELF_C_SET, ELF_F_DIRTY); +} + +void +elfedit_modified_shdr(elfedit_section_t *s) +{ + (void) elf_flagshdr(s->sec_scn, ELF_C_SET, ELF_F_DIRTY); +} + +void +elfedit_modified_data(elfedit_section_t *s) +{ + (void) elf_flagdata(s->sec_data, ELF_C_SET, ELF_F_DIRTY); +} + + + +/* + * Prepare an elfedit_dyn_elt_t structure for use. + */ +void +elfedit_dyn_elt_init(elfedit_dyn_elt_t *elt) +{ + elt->dn_seen = 0; +} + +/* + * Given a dynamic section item, save it in the given elfedit_dyn_elt_t + * structure and mark that structure to show that it is present. + */ +void +elfedit_dyn_elt_save(elfedit_dyn_elt_t *elt, Word ndx, Dyn *dyn) +{ + elt->dn_seen = 1; + elt->dn_ndx = ndx; + elt->dn_dyn = *dyn; +} + + +/* + * Return the index of the first section that has the given name. + * + * entry: + * obj_state - Object state. + * shnam - Name of desired section + * + * exit: + * On success, returns the section index. On failure, an error + * is issued, and this routine does not return to the caller. + */ +Word +elfedit_name_to_shndx(elfedit_obj_state_t *obj_state, const char *shnam) +{ + elfedit_section_t *sec = obj_state->os_secarr; + Word ndx; + Word shnum = obj_state->os_shnum; + + for (ndx = 0; ndx < shnum; ndx++, sec++) { + if (strcmp(shnam, sec->sec_name) == 0) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_SHNAM2NDX), + EC_WORD(sec->sec_shndx), sec->sec_name, shnam); + return (ndx); + } + } + + /* If didn't return in loop above, the name doesn't match */ + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSECNAM), shnam); + /*NOTREACHED*/ + return (SHN_UNDEF); +} + + + +/* + * Return the index of the first section that has the given type. + * + * entry: + * obj_state - Object state. + * shtype - Type of desired section + * + * exit: + * On success, returns the section index. On failure, an error + * is issued, and this routine does not return to the caller. + */ +Word +elfedit_type_to_shndx(elfedit_obj_state_t *obj_state, Word shtype) +{ + Conv_inv_buf_t inv_buf; + elfedit_section_t *sec = obj_state->os_secarr; + Word ndx; + Word shnum = obj_state->os_shnum; + + for (ndx = 0; ndx < shnum; ndx++, sec++) { + if (shtype == sec->sec_shdr->sh_type) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_SHNAM2NDX), + EC_WORD(sec->sec_shndx), sec->sec_name, + conv_sec_type(obj_state->os_ehdr->e_machine, + shtype, 0, &inv_buf)); + return (ndx); + } + } + + /* If didn't return in loop above, the name doesn't match */ + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSECTYP), + conv_sec_type(obj_state->os_ehdr->e_machine, shtype, 0, &inv_buf)); + /*NOTREACHED*/ + return (SHN_UNDEF); +} + + + +/* + * Locate the index of the first symbol that has the given name + * + * entry: + * obj_state - Object state. + * symsec - Symbol section + * strsec = String section + * name - String giving name of symbol to lookup + * msg_type - ELFEDIT_MSG_ type code to use with message + * issued if name does not exist in symbol table. + * ret_symndx - Address of variable to receive index. + * + * exit: + * On success, issues debug message, sets *ret_symndx, and returns + * True (1). + * + * On failure, issues a message using msg_type to determine + * the type of message sent. If the message does not take control away + * from the caller, False (0) is returned. + * + * note: + * Although the string table is referenced by the sh_link field of + * the symbol table, we require the user to supply it rather than + * look it up. The reason for this is that the caller will usually + * have looked it up, and we wish to avoid multiple debug messages + * from being issued to that effect. + */ +int +elfedit_name_to_symndx(elfedit_section_t *symsec, elfedit_section_t *strsec, + const char *name, elfedit_msg_t msg_type, Word *ret_symndx) + +{ + Sym *sym = (Sym *) symsec->sec_data->d_buf; + Word cnt = symsec->sec_shdr->sh_size / symsec->sec_shdr->sh_entsize; + Word ndx, offset; + const char *curname; + + for (ndx = 0; ndx < cnt; ndx++) { + offset = sym[ndx].st_name; + + curname = elfedit_offset_to_str(strsec, offset, + ELFEDIT_MSG_ERR, 0); + if (strcmp(curname, name) == 0) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_SYMNAM2NDX), + EC_WORD(symsec->sec_shndx), + symsec->sec_name, EC_WORD(ndx), name); + *ret_symndx = ndx; + return (1); + } + } + + /* If didn't return in loop above, the name doesn't match */ + elfedit_msg(msg_type, MSG_INTL(MSG_ERR_NOSYM), + EC_WORD(symsec->sec_shndx), symsec->sec_name, name); + /*NOTREACHED*/ + return (0); /* lint */ +} + + +/* + * Given a section index, turn it into a descriptive string. + * - If it is one of the special reserved indexes, the + * symbolic name is returned. + * - If it is a regular section, in range for the file, + * the name associated with the section is returned. + * - Otherwise, the number is formatted as numeric ASCII. + * + * exit: + * A pointer to the static buffer containing the name is + * returned. This pointer is valid until the next call + * to elfedit_shndx_to_name(), and which point it may + * be overwritten. + */ +const char * +elfedit_shndx_to_name(elfedit_obj_state_t *obj_state, Word shndx) +{ + /* + * This routine can be called twice within a single C statement, + * so we use alternating buffers on each call to allow this + * without requiring the caller to supply a buffer (the size of + * which they don't know). + */ + static char buf1[64], buf2[64]; + static char *buf; + + if ((obj_state->os_ehdr->e_machine == EM_AMD64) && + (shndx == SHN_AMD64_LCOMMON)) + return (MSG_ORIG(MSG_SHN_AMD64_LCOMMON)); + + switch (shndx) { + case SHN_UNDEF: + return (MSG_ORIG(MSG_SHN_UNDEF)); + case SHN_SUNW_IGNORE: + return (MSG_ORIG(MSG_SHN_SUNW_IGNORE)); + case SHN_BEFORE: + return (MSG_ORIG(MSG_SHN_BEFORE)); + case SHN_AFTER: + return (MSG_ORIG(MSG_SHN_AFTER)); + case SHN_AMD64_LCOMMON: + if (obj_state->os_ehdr->e_machine == EM_AMD64) + return (MSG_ORIG(MSG_SHN_AMD64_LCOMMON)); + break; + case SHN_ABS: + return (MSG_ORIG(MSG_SHN_ABS)); + case SHN_COMMON: + return (MSG_ORIG(MSG_SHN_COMMON)); + case SHN_XINDEX: + return (MSG_ORIG(MSG_SHN_XINDEX)); + } + + + /* + * If it is outside of the reserved area, and inside the + * range of section indexes in the ELF file, then show + * the section name. + */ + if ((shndx < obj_state->os_shnum) && + ((shndx < SHN_LORESERVE) || (shndx > SHN_HIRESERVE))) + return (obj_state->os_secarr[shndx].sec_name); + + /* Switch buffers */ + buf = (buf == buf1) ? buf2 : buf1; + + /* + * If we haven't identified it by now, format the + * number in a static buffer and return that. + */ + (void) snprintf(buf, sizeof (buf1), + MSG_ORIG(MSG_FMT_WORDVAL), shndx); + return (buf); +} + + +/* + * Locate the capabilities section for this object + * + * entry: + * obj_state - Object state for open object to query. + * cap - Address of variable to recieve pointer to capabilities + * section data buffer. + * num - Address of variable to receive number of items + * referenced by cap. + * + * exit: + * On success, returns section descriptor, and sets the + * variables referenced by cap and num. On failure, + * does not return. + */ +elfedit_section_t * +elfedit_sec_getcap(elfedit_obj_state_t *obj_state, Cap **cap, Word *num) +{ + Word cnt; + elfedit_section_t *cache; + + for (cnt = 1; cnt < obj_state->os_shnum; cnt++) { + cache = &obj_state->os_secarr[cnt]; + if (cache->sec_shdr->sh_type == SHT_SUNW_cap) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_FNDCAP), + EC_WORD(cnt), cache->sec_name); + *cap = (Cap *) cache->sec_data->d_buf; + *num = cache->sec_shdr->sh_size / + cache->sec_shdr->sh_entsize; + return (cache); + } + } + + /* If here, this object has no capabilities section */ + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOCAP)); + + /*NOTREACHED*/ + return (NULL); +} + + +/* + * Locate the dynamic section for this object + * + * entry: + * obj_state - Object state for open object to query. + * dyn - Address of variable to recieve pointer to dynamic + * section data buffer. + * numdyn - Address of variable to receive number of items + * referenced by dyn. + * + * exit: + * On success, returns section descriptor, and sets the + * variables referenced by dyn and numdyn. On failure, + * does not return. + */ +elfedit_section_t * +elfedit_sec_getdyn(elfedit_obj_state_t *obj_state, Dyn **dyn, Word *num) +{ + elfedit_section_t *cache; + + if (obj_state->os_dynndx != SHN_UNDEF) { + cache = &obj_state->os_secarr[obj_state->os_dynndx]; + elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDDYN), + EC_WORD(cache->sec_shndx), cache->sec_name); + *dyn = (Dyn *) cache->sec_data->d_buf; + *num = cache->sec_shdr->sh_size / cache->sec_shdr->sh_entsize; + return (cache); + } + + /* If here, this object has no dynamic section */ + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NODYN)); + + /*NOTREACHED*/ + return (NULL); +} + + +/* + * Locate the syminfo section for this object + * + * entry: + * obj_state - Object state for open object to query. + * syminfo - Address of variable to recieve pointer to syminfo + * section data buffer. + * num - Address of variable to receive number of items + * referenced by syminfo. + * + * exit: + * On success, returns section descriptor, and sets the + * variables referenced by syminfo and num. On failure, + * does not return. + */ +elfedit_section_t * +elfedit_sec_getsyminfo(elfedit_obj_state_t *obj_state, Syminfo **syminfo, + Word *num) +{ + Word cnt; + elfedit_section_t *cache; + + for (cnt = 1; cnt < obj_state->os_shnum; cnt++) { + cache = &obj_state->os_secarr[cnt]; + if (cache->sec_shdr->sh_type == SHT_SUNW_syminfo) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_FNDSYMINFO), + EC_WORD(cnt), cache->sec_name); + *syminfo = (Syminfo *) cache->sec_data->d_buf; + *num = cache->sec_shdr->sh_size / + cache->sec_shdr->sh_entsize; + return (cache); + } + } + + /* If here, this object has no syminfo section */ + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSYMINFO)); + + /*NOTREACHED*/ + return (NULL); +} + + +/* + * Check the given section to see if it is a known symbol table type. + * + * entry: + * sec - Section to check + * issue_err - True if this routine should issue an error and + * not return to the caller if sec is not a symbol table. + * atoui_list - NULL, or address of variable to receive a pointer to + * an array of elfedit_atoui_sym_t items describing the + * type of symbol table found. This array is useful for + * doing command completion. + * + * exit: + * If sec is a symbol table: + * - If atoui_list is non-NULL, *atoui_list is set to the + * appropriate ELFEDIT_CONST_xx list of items. + * - True (1) is returned + * If sec is not a symbol table and issue_err is True: + * - An error is issued, and this routine does not + * return to the caller. + * Otherwise: + * - If atoui_list is non-NULL, *atoui_list is set to NULL. + * - False (0) is returned + */ +int +elfedit_sec_issymtab(elfedit_section_t *sec, int issue_err, + elfedit_atoui_sym_t **atoui_list) +{ + elfedit_const_t const_type; + int ret = 1; + + /* Is the section a symbol table? */ + switch (sec->sec_shdr->sh_type) { + case SHT_SYMTAB: + const_type = ELFEDIT_CONST_SHT_SYMTAB; + break; + case SHT_DYNSYM: + const_type = ELFEDIT_CONST_SHT_DYNSYM; + break; + case SHT_SUNW_LDYNSYM: + const_type = ELFEDIT_CONST_SHT_LDYNSYM; + break; + default: + if (issue_err) + elfedit_msg(ELFEDIT_MSG_ERR, + MSG_INTL(MSG_ERR_NOTSYMTAB), + EC_WORD(sec->sec_shndx), sec->sec_name); + ret = 0; + break; + } + + if (atoui_list != NULL) + *atoui_list = (ret == 0) ? NULL : + elfedit_const_to_atoui(const_type); + + return (ret); +} + + + +/* + * Locate a symbol table section for this object + * + * entry: + * obj_state - Object state for open object to query. + * by_index - If True, we want to locate the section with the + * section index given by index. If False, we return + * the section with the name given by name. + * index, name - Key to search for. See by_index. + * sym - Address of variable to recieve pointer to symbol + * section data buffer. + * numsym - Address of variable to receive number of symbols + * referenced by sym. + * aux_info - Address of variable to receive pointer to the + * elfedit_symtab_t struct that ties the symbol table and + * its related auxiliary sections together. NULL if this + * information is not required. + * + * exit: + * On success, returns section descriptor, and sets the + * variables referenced by sym, and numsym. On failure, + * does not return. + */ +elfedit_section_t * +elfedit_sec_getsymtab(elfedit_obj_state_t *obj_state, int by_index, + Word index, const char *name, Sym **sym, Word *num, + elfedit_symtab_t **aux_info) +{ + Word ndx; + elfedit_section_t *symsec = NULL; + elfedit_symtab_t *symtab; + const char *type_name; + + /* If looking it up by index, make sure the index is in range */ + if (by_index && (index >= obj_state->os_shnum)) + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADSECNDX), + EC_WORD(index), EC_WORD(obj_state->os_shnum - 1)); + + /* + * Look at each known symbol table in turn until the desired + * one is hit, or there are no more. + */ + symtab = obj_state->os_symtab; + for (ndx = 0; ndx < obj_state->os_symtabnum; ndx++, symtab++) { + elfedit_section_t *s = + &obj_state->os_secarr[symtab->symt_shndx]; + + if ((by_index && (symtab->symt_shndx == index)) || + (!by_index && (strcmp(s->sec_name, name) == 0))) { + symsec = s; + break; + } + } + + /* Did we get a section? */ + if (symsec == NULL) + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSYMTAB)); + + /* Got it. Report to the user and return the necessary data */ + (void) elfedit_sec_issymtab(symsec, 1, NULL); + type_name = elfedit_atoconst_value_to_str(ELFEDIT_CONST_SHT_ALLSYMTAB, + symsec->sec_shdr->sh_type, 1); + elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDSYMTAB), + EC_WORD(symsec->sec_shndx), symsec->sec_name, type_name); + *sym = (Sym *) symsec->sec_data->d_buf; + *num = symsec->sec_shdr->sh_size / symsec->sec_shdr->sh_entsize; + if (aux_info != NULL) + *aux_info = symtab; + return (symsec); +} + + + +/* + * Locate the extended symbol index section associated with a symbol + * table section. + * + * entry: + * obj_state - Object state for open object to query. + * symsec - Symbol table section for which extended index + * index section is required. + * xshndx - Address of variable to recieve pointer to section index + * array data buffer. + * numxshndx - Address of variable to receive number of indices + * referenced by ndx. + * + * exit: + * On success, returns extended index section descriptor, and sets the + * variables referenced by xshndx, and numxshndx. On failure, + * does not return. + * + * note: + * Since the extended section index is found in the sec_xshndx field + * of the elfedit_section_t, the caller may be tempted to bypass this + * routine and access it directly. That temptation should be resisted, + * as this routine performs useful error checking, and also handles + * the issuing of the standard MSG_DEBUG messages. + */ +elfedit_section_t * +elfedit_sec_getxshndx(elfedit_obj_state_t *obj_state, + elfedit_section_t *symsec, Word **xshndx, Word *num) +{ + elfedit_section_t *xshndxsec; + elfedit_symtab_t *symtab; + Word ndx; + + /* Sanity check: symsec must be a symbol table */ + (void) elfedit_sec_issymtab(symsec, 1, NULL); + + symtab = obj_state->os_symtab; + for (ndx = 0; ndx < obj_state->os_symtabnum; ndx++, symtab++) + if (symsec->sec_shndx == symtab->symt_shndx) + break; + + /* + * Issue error if the symbol table lacks an extended index section. + * The caller won't ask unless they encounter an SHN_XINDEX value, + * in which case the lack of the index section denotes a corrupt + * ELF file. + */ + if ((ndx == obj_state->os_symtabnum) || + (symtab->symt_xshndx == SHN_UNDEF)) + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOXSHSEC), + EC_WORD(symsec->sec_shndx), symsec->sec_name); + + /* Got it. Report to the user and return the necessary data */ + xshndxsec = &obj_state->os_secarr[symtab->symt_xshndx]; + elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDXSHNDX), + EC_WORD(symsec->sec_shndx), symsec->sec_name, + EC_WORD(xshndxsec->sec_shndx), xshndxsec->sec_name); + *xshndx = (Word *) xshndxsec->sec_data->d_buf; + *num = xshndxsec->sec_shdr->sh_size / xshndxsec->sec_shdr->sh_entsize; + return (xshndxsec); +} + + + +/* + * Locate the versym section associated with a symbol table section. + * + * entry: + * obj_state - Object state for open object to query. + * symsec - Symbol table section for which extended index + * index section is required. + * versym - Address of variable to recieve pointer to section index + * array data buffer. + * numversym - Address of variable to receive number of indices + * referenced by ndx. + * + * exit: + * On success, returns versym section descriptor, and sets the + * variables referenced by versym, and numversym. On failure, + * does not return. + * + * note: + * Since the versym section index is found in the sec_versym field + * of the elfedit_section_t, the caller may be tempted to bypass this + * routine and access it directly. That temptation should be resisted, + * as this routine performs useful error checking, and also handles + * the issuing of the standard MSG_DEBUG messages. + */ +elfedit_section_t * +elfedit_sec_getversym(elfedit_obj_state_t *obj_state, + elfedit_section_t *symsec, Versym **versym, Word *num) +{ + elfedit_section_t *versymsec; + elfedit_symtab_t *symtab; + Word ndx; + + /* Sanity check: symsec must be a symbol table */ + (void) elfedit_sec_issymtab(symsec, 1, NULL); + + symtab = obj_state->os_symtab; + for (ndx = 0; ndx < obj_state->os_symtabnum; ndx++, symtab++) + if (symsec->sec_shndx == symtab->symt_shndx) + break; + /* + * Issue error if the symbol table lacks a versym section. + * The caller won't ask unless they see a non-null + * aux.symtab.sec_versym, so this should not be a problem. + */ + if ((ndx == obj_state->os_symtabnum) || + (symtab->symt_versym == SHN_UNDEF)) + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOVERSYMSEC), + EC_WORD(symsec->sec_shndx), symsec->sec_name); + + /* Got it. Report to the user and return the necessary data */ + versymsec = &obj_state->os_secarr[symtab->symt_versym]; + elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDVERSYM), + EC_WORD(symsec->sec_shndx), symsec->sec_name, + EC_WORD(versymsec->sec_shndx), versymsec->sec_name); + *versym = (Versym *) versymsec->sec_data->d_buf; + *num = versymsec->sec_shdr->sh_size / versymsec->sec_shdr->sh_entsize; + return (versymsec); +} + + + +/* + * Locate the string table specified by shndx for this object. + * + * exit: + * Returns section descriptor on success. On failure, does not return. + */ +elfedit_section_t * +elfedit_sec_getstr(elfedit_obj_state_t *obj_state, Word shndx) +{ + elfedit_section_t *strsec; + + if ((shndx == 0) || (shndx >= obj_state->os_shnum)) + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_STRSHNDX), + EC_WORD(shndx), EC_WORD(1), + EC_WORD(obj_state->os_shnum - 1)); + + strsec = &obj_state->os_secarr[shndx]; + if (strsec->sec_shdr->sh_type != SHT_STRTAB) + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOTSTRSH), + EC_WORD(shndx), strsec->sec_name); + + elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDSTRTAB), + EC_WORD(shndx), strsec->sec_name); + return (strsec); +} + + +/* + * Returns the offset of the specified string from within + * the given section. + * + * entry: + * sec - Descriptor for section + * tail_ign - If non-zero, the # of characters at the end of the + * section that should be ignored and not searched. + * str - String we are looking for. + * ret_offset - Address of variable to receive result + * + * exit: + * Returns 1 for success, and 0 for failure. If successful, *ret_offset + * is set to the offset of the found string within the section. + */ +int +elfedit_sec_findstr(elfedit_section_t *sec, Word tail_ign, + const char *str, Word *ret_offset) +{ + int str_fch = *str; /* First character in str */ + Word len; /* # characters in table */ + char *s; /* ptr to strings within table */ + const char *tail; /* 1 past final character of table */ + + + /* Size of the section, minus the reserved part (if any) at the end */ + len = sec->sec_shdr->sh_size - tail_ign; + + /* + * Move through the section character by character looking for + * a match. Moving character by character instead of skipping + * from NULL terminated string to string allows us to use + * the tails longer strings (i.e. we want "bar", and "foobar" exists). + * We look at the first character manually before calling strcmp() + * to lower the cost of this approach. + */ + s = (char *)sec->sec_data->d_buf; + tail = s + len; + for (; s <= tail; s++) { + if ((*s == str_fch) && (strcmp(s, str) == 0)) { + *ret_offset = s - (char *)sec->sec_data->d_buf; + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_EXISTSTR), + EC_WORD(sec->sec_shndx), sec->sec_name, + EC_WORD(*ret_offset), s); + return (1); + } + } + + /* Didn't find it. Report failure */ + return (0); +} + + +/* + * Locate the DT_SUNW_STRPAD element of the given dynamic section if + * it exists. + * + * entry: + * dynsec - Dynamic section descriptor + * dyn_strpad - Address of variable to receive the results. + * The caller is responsible for calling elfedit_dyn_elt_init() + * on this variable beforehand. + * + * exit: + * The dynamic section is searched, and if a DT_SUNW_STRPAD element + * is found, dyn_strpad is updated via elfedit_dyn_elt_save() to + * reference it. + * + * Returns the final value of dyn_strpad->dn_seen. + */ +int +elfedit_dynstr_getpad(elfedit_section_t *dynsec, elfedit_dyn_elt_t *dyn_strpad) +{ + Dyn *dyn = (Dyn *) dynsec->sec_data->d_buf; + Word numdyn = dynsec->sec_shdr->sh_size / dynsec->sec_shdr->sh_entsize; + Word i; + + /* Go through dynamic section tags and find the STRPAD entry */ + for (i = 0; i < numdyn; i++) { + if (dyn[i].d_tag == DT_SUNW_STRPAD) { + elfedit_dyn_elt_save(dyn_strpad, i, &dyn[i]); + break; + } + } + + return (dyn_strpad->dn_seen); +} + + + +/* + * Given references to the dynamic section, its string table, + * and the DT_SUNW_STRPAD entry of the dynamic section, returns + * the offset of the specified string from within the given string table, + * adding it if possible. + * + * entry: + * dynsec - Dynamic section descriptor + * strsec - Descriptor for string table assocated with dynamic section + * dyn_strpad - DT_SUNW_STRPAD element from dynamic section + * str - String we are looking for. + * + * exit: + * On success, the offset of the given string within the string + * table is returned. If the string does not exist within the table, + * but there is a valid DT_SUNW_STRPAD reserved section, then we + * add the string, and update the dynamic section STRPAD element + * to reflect the space we use. + * + * This routine does not return on failure. + */ +Word +elfedit_dynstr_insert(elfedit_section_t *dynsec, elfedit_section_t *strsec, + elfedit_dyn_elt_t *dyn_strpad, const char *str) +{ + Word ins_off; /* Table offset to 1st reserved byte */ + char *s; /* ptr to strings within table */ + Word len; /* Length of str inc. NULL byte */ + Word tail_ign; /* # reserved bytes at end of strtab */ + + + tail_ign = dyn_strpad->dn_seen ? dyn_strpad->dn_dyn.d_un.d_val : 0; + + /* Does the string already existin the string table? */ + if (elfedit_sec_findstr(strsec, tail_ign, str, &len)) + return (len); + + /* + * The desired string does not already exist. Do we have + * room to add it? + */ + len = strlen(str) + 1; + if (!dyn_strpad->dn_seen || (len > dyn_strpad->dn_dyn.d_un.d_val)) + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSTRPAD), + EC_WORD(strsec->sec_shdr->sh_link), + strsec->sec_name); + + + /* + * We will add the string at the first byte of the reserved NULL + * area at the end. The DT_SUNW_STRPAD dynamic element gives us + * the size of that reserved space. + */ + ins_off = strsec->sec_shdr->sh_size - tail_ign; + s = ((char *)strsec->sec_data->d_buf) + ins_off; + + /* Announce the operation */ + elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_ADDSTR), + EC_WORD(strsec->sec_shndx), strsec->sec_name, + EC_WORD(ins_off), EC_WORD(len), + EC_WORD(dyn_strpad->dn_dyn.d_un.d_val), str); + + /* + * Copy the string into the pad area at the end, and + * mark the data area as dirty so libelf will flush our + * changes to the string data. + */ + (void) strncpy(s, str, dyn_strpad->dn_dyn.d_un.d_val); + elfedit_modified_data(strsec); + + /* Update the DT_STRPAD dynamic entry */ + dyn_strpad->dn_dyn.d_un.d_val -= len; + ((Dyn *) dynsec->sec_data->d_buf)[dyn_strpad->dn_ndx] = + dyn_strpad->dn_dyn; + elfedit_modified_data(dynsec); + + return (ins_off); +} + + +/* + * Test to see if a call to elfedit_strtab_insert() will succeed. + * + * entry: + * obj_state - Object state for open object to query. + * strsec - Descriptor for string table + * dynsec - NULL, or descriptor for dynamic section. Providing + * a non-NULL value here will prevent elfedit_strtab_insert() + * from looking it up, and the duplicate debug message that + * would result. + * str - String we are looking for. + * + * exit: + * If the string exists within the string table, or if an attempt + * to insert it will be successful, quietly return. Otherwise, throw + * the error elfedit_strtab_insert() would throw under the + * same circumstances. + * + */ +void +elfedit_strtab_insert_test(elfedit_obj_state_t *obj_state, + elfedit_section_t *strsec, elfedit_section_t *dynsec, const char *str) +{ + Word len; /* Length of str inc. NULL byte */ + int is_dynstr = 0; + Word tail_ign = 0; + + + /* + * The dynstr is a special case, because we can add strings + * to it under certain circumstances. So, we look for the + * dynamic section, and if it exists, compare its sh_link to + * the string section index. If they match, it is the dynstr, + * and we use elfedit_dynstr_insert() to do the work. + */ + if (dynsec == NULL) { + if (obj_state->os_dynndx != SHN_UNDEF) { + dynsec = &obj_state->os_secarr[obj_state->os_dynndx]; + if ((dynsec->sec_shdr->sh_type == SHT_DYNAMIC) && + (strsec->sec_shndx == dynsec->sec_shdr->sh_link)) { + is_dynstr = 1; + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_FNDDYN), + EC_WORD(dynsec->sec_shndx), + dynsec->sec_name); + } + } + } else { + if (strsec->sec_shndx == dynsec->sec_shdr->sh_link) + is_dynstr = 1; + } + + + if (is_dynstr) { + elfedit_dyn_elt_t dyn_strpad; + + /* Determine the size of the STRPAD area, if any */ + elfedit_dyn_elt_init(&dyn_strpad); + if (elfedit_dynstr_getpad(dynsec, &dyn_strpad) != 0) + tail_ign = dyn_strpad.dn_dyn.d_un.d_val; + } + + /* + * If the string is already in the string table, we + * can't fail. + */ + if (elfedit_sec_findstr(strsec, tail_ign, str, &len) != 0) + return; + + /* + * It's not in the table, but if this is the dynstr, and + * there is enough room, we will be able to add it. + */ + if (is_dynstr && (tail_ign > strlen(str))) + return; + + /* Can't do it. Issue error */ + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSTRPAD), + EC_WORD(strsec->sec_shdr->sh_link), strsec->sec_name); +} + + +/* + * Returns the offset of the specified string from within + * the given string table, adding it if possible. + * + * entry: + * obj_state - Object state for open object to query. + * strsec - Descriptor for string table + * dynsec - NULL, or descriptor for dynamic section. Providing + * a non-NULL value here will prevent elfedit_strtab_insert() + * from looking it up, and the duplicate debug message that + * would result. + * str - String we are looking for. + * + * exit: + * On success, the offset of the given string within the string + * table is returned. If the string does not exist within the table, + * and it is possible to add it, elfedit_strtab_insert() will + * add the string, and then return the offset. + * + * If the string does not exist in the string table, and cannot + * be added, this routine issues an error message and does not + * return to the caller. + */ +Word +elfedit_strtab_insert(elfedit_obj_state_t *obj_state, elfedit_section_t *strsec, + elfedit_section_t *dynsec, const char *str) +{ + Word len; /* Length of str inc. NULL byte */ + int is_dynstr = 0; + elfedit_dyn_elt_t dyn_strpad; + + + /* + * The dynstr is a special case, because we can add strings + * to it under certain circumstances. So, we look for the + * dynamic section, and if it exists, compare its sh_link to + * the string section index. If they match, it is the dynstr, + * and we use elfedit_dynstr_insert() to do the work. + */ + if (dynsec == NULL) { + if (obj_state->os_dynndx != SHN_UNDEF) { + dynsec = &obj_state->os_secarr[obj_state->os_dynndx]; + if ((dynsec->sec_shdr->sh_type == SHT_DYNAMIC) && + (strsec->sec_shndx == dynsec->sec_shdr->sh_link)) { + is_dynstr = 1; + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_FNDDYN), + EC_WORD(dynsec->sec_shndx), + dynsec->sec_name); + } + } + } else { + if (strsec->sec_shndx == dynsec->sec_shdr->sh_link) + is_dynstr = 1; + } + + if (is_dynstr) { + elfedit_dyn_elt_init(&dyn_strpad); + (void) elfedit_dynstr_getpad(dynsec, &dyn_strpad); + return (elfedit_dynstr_insert(dynsec, strsec, + &dyn_strpad, str)); + } + + /* + * This is not the dynstr, so we are limited to strings that + * already exist within it. Try to find one. + */ + if (elfedit_sec_findstr(strsec, 0, str, &len)) + return (len); + + /* Can't do it. Issue error */ + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSTRPAD), + EC_WORD(strsec->sec_shdr->sh_link), strsec->sec_name); + /*NOTREACHED*/ + + return (0); +} + + +/* + * Return the string found at the given offset within the specified + * string table. + * + * entry: + * strsec - Section descriptor for string table section + * offset - Offset of desired string in string table + * msg_type - ELFEDIT_MSG_ type code to use with message + * issued if offset is out of range for the symbol table. + * debug_msg - True if should issue debug message for string found. + * + * exit: + * If the offset is within the section, the string pointer + * is returned. Otherwise an error is issued using msg_type + * to determine the type of message. If this routine retains + * control after the message is issued, a safe string is returned. + */ +const char * +elfedit_offset_to_str(elfedit_section_t *strsec, Word offset, + elfedit_msg_t msg_type, int debug_msg) +{ + const char *str; + + /* Make sure it is a string table section */ + if (strsec->sec_shdr->sh_type != SHT_STRTAB) + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOTSTRSH), + EC_WORD(strsec->sec_shndx), strsec->sec_name); + + /* Ensure the offset is in range */ + if (offset >= strsec->sec_data->d_size) { + elfedit_msg(msg_type, MSG_INTL(MSG_ERR_BADSTROFF), + EC_WORD(strsec->sec_shndx), strsec->sec_name, + EC_WORD(offset), EC_WORD(strsec->sec_data->d_size - 1)); + /* + * If the msg_type is a type that returns, give the + * user a safe string to use. + */ + str = MSG_INTL(MSG_BADSYMOFFSETNAM); + } else { + /* Return the string */ + str = ((const char *)strsec->sec_data->d_buf) + offset; + } + + if (debug_msg) + elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDSTR), + EC_WORD(strsec->sec_shndx), strsec->sec_name, + EC_WORD(offset), str); + return (str); +} + + +/* + * Given a string table section, and a dynamic section entry + * that supplies a string offset, return the string found at + * the given offset. This routine is a convenience wrapper on + * elfedit_offset_to_str(). + * + * exit: + * As per elfedit_offset_to_str(). + */ +const char * +elfedit_dyn_offset_to_str(elfedit_section_t *strsec, elfedit_dyn_elt_t *dynelt) +{ + return (elfedit_offset_to_str(strsec, dynelt->dn_dyn.d_un.d_val, + ELFEDIT_MSG_ERR, 0)); +} + + +/* + * Given a section, fabricate a string for the form: + * + * "[#: name]" + * + * as used at the beginning of debug messages. A pointer to static + * memory is returned, and is good until the next such call. + */ +const char * +elfedit_sec_msgprefix(elfedit_section_t *sec) +{ + static char *buf; + static size_t bufsize; + + size_t need; + + need = 64 + strlen(sec->sec_name); + if (need > bufsize) { + buf = elfedit_realloc(MSG_INTL(MSG_ALLOC_SECMSGPRE), buf, need); + bufsize = need; + } + + (void) snprintf(buf, bufsize, MSG_ORIG(MSG_FMT_SECMSGPRE), + EC_WORD(sec->sec_shndx), sec->sec_name); + + return (buf); +} diff --git a/usr/src/cmd/sgs/elfedit/i386/Makefile b/usr/src/cmd/sgs/elfedit/i386/Makefile new file mode 100644 index 0000000000..11b6540fbb --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/i386/Makefile @@ -0,0 +1,35 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +.KEEP_STATE: + +lint: $(LINTOUT32) $(SGSLINTOUT) + +include ../Makefile.targ diff --git a/usr/src/cmd/sgs/elfedit/modules/Makefile b/usr/src/cmd/sgs/elfedit/modules/Makefile new file mode 100644 index 0000000000..864315211c --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/modules/Makefile @@ -0,0 +1,54 @@ +# +# 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 +# +# +# ident "%Z%%M% %I% %E% SMI" +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +include $(SRC)/Makefile.master + + +SUBDIRS= $(MACH) + +all:= TARGET= all +chkmsg:= TARGET= chkmsg +catalog:= TARGET= catalog +install:= TARGET= install +package:= TARGET= package +clean:= TARGET= clean +clobber:= TARGET= clobber +lint:= TARGET= lint + +.KEEP_STATE: + +package all chkmsg catalog clean clobber lint install: \ + $(SUBDIRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + @if [ -d $(MACH64) ]; then \ + cd $(MACH64); pwd; $(MAKE) $(TARGET); \ + else /bin/true; fi + + +FRC: diff --git a/usr/src/cmd/sgs/elfedit/modules/Makefile.com b/usr/src/cmd/sgs/elfedit/modules/Makefile.com new file mode 100644 index 0000000000..1628b8f2ff --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/modules/Makefile.com @@ -0,0 +1,117 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../../../../../lib/Makefile.lib +include ../../../Makefile.com + +CAP_LIB= cap.so +CAP_OBJ= cap_msg.o cap32.o cap64.o + +DYN_LIB= dyn.so +DYN_OBJ= dyn_msg.o dyn32.o dyn64.o + +EHDR_LIB= ehdr.so +EHDR_OBJ= ehdr_msg.o ehdr32.o ehdr64.o + +PHDR_LIB= phdr.so +PHDR_OBJ= phdr_msg.o phdr32.o phdr64.o + +SHDR_LIB= shdr.so +SHDR_OBJ= shdr_msg.o shdr32.o shdr64.o + +SYM_LIB= sym.so +SYM_OBJ= sym_msg.o sym32.o sym64.o + +SYMINFO_LIB= syminfo.so +SYMINFO_OBJ= syminfo_msg.o syminfo32.o syminfo64.o + +ELFEDITLIBS= $(CAP_LIB) $(DYN_LIB) $(EHDR_LIB) $(PHDR_LIB) \ + $(SHDR_LIB) $(SYM_LIB) $(SYMINFO_LIB) + +PICDIR= pics + +CAP_PICS= $(CAP_OBJ:%.o=$(PICDIR)/%.o) +DYN_PICS= $(DYN_OBJ:%.o=$(PICDIR)/%.o) +EHDR_PICS= $(EHDR_OBJ:%.o=$(PICDIR)/%.o) +PHDR_PICS= $(PHDR_OBJ:%.o=$(PICDIR)/%.o) +SHDR_PICS= $(SHDR_OBJ:%.o=$(PICDIR)/%.o) +SYM_PICS= $(SYM_OBJ:%.o=$(PICDIR)/%.o) +SYMINFO_PICS= $(SYMINFO_OBJ:%.o=$(PICDIR)/%.o) + +LDLIBS += $(ELFLIBDIR) -lelf $(LDDBGLIBDIR) $(LDDBG_LIB) \ + $(CONVLIBDIR) $(CONV_LIB) -lc + +$(CAP_LIB):= PICS = $(CAP_PICS) +$(DYN_LIB):= PICS = $(DYN_PICS) +$(EHDR_LIB):= PICS = $(EHDR_PICS) +$(PHDR_LIB):= PICS = $(PHDR_PICS) +$(SHDR_LIB):= PICS = $(SHDR_PICS) +$(SYM_LIB):= PICS = $(SYM_PICS) +$(SYMINFO_LIB):= PICS = $(SYMINFO_PICS) + +$(CAP_LIB):= SONAME = $(CAP_LIB) +$(DYN_LIB):= SONAME = $(DYN_LIB) +$(EHDR_LIB):= SONAME = $(EHDR_LIB) +$(PHDR_LIB):= SONAME = $(PHDR_LIB) +$(SHDR_LIB):= SONAME = $(SHDR_LIB) +$(SYM_LIB):= SONAME = $(SYM_LIB) +$(SYMINFO_LIB):= SONAME = $(SYMINFO_LIB) + +# All the modules use a shared mapfile +MAPFILES = ../common/mapfile-vers + +CPPFLAGS += -I../../../include -I../../../include/$(MACH) \ + -I../$(SRCBASE)/lib/libc/inc -D_REENTRANT +LLDFLAGS = '-R$$ORIGIN/../../../lib' +LLDFLAGS64 = '-R$$ORIGIN/../../../../lib/$(MACH64)' +LDFLAGS += $(USE_PROTO) $(LLDFLAGS) +DYNFLAGS += $(VERSREF) + +LINTFLAGS += -uaxs $(LDLIBS) +LINTFLAGS64 += -uaxs $(LDLIBS64) + +BLTDEFS = $(ELFEDITLIBS:%.so=%_msg.h) +BLTDATA = $(ELFEDITLIBS:%.so=%_msg.c) +BLTFILES = $(BLTDEFS) $(BLTDATA) + +CLEANFILES += $(BLTFILES) $(LINTOUT) $(PICDIR)/* +CLOBBERFILES += $(ELFEDITLIBS) + +ROOTELFEDITDIR= $(ROOT)/usr/lib/elfedit +ROOTELFEDITDIR64= $(ROOT)/usr/lib/elfedit/$(MACH64) +ROOTELFEDITLIBS= $(ROOTELFEDITDIR)/$(MTARG)$(CAP_LIB) \ + $(ROOTELFEDITDIR)/$(MTARG)$(DYN_LIB) \ + $(ROOTELFEDITDIR)/$(MTARG)$(EHDR_LIB) \ + $(ROOTELFEDITDIR)/$(MTARG)$(PHDR_LIB) \ + $(ROOTELFEDITDIR)/$(MTARG)$(SHDR_LIB) \ + $(ROOTELFEDITDIR)/$(MTARG)$(SYM_LIB) \ + $(ROOTELFEDITDIR)/$(MTARG)$(SYMINFO_LIB) + + +FILEMODE= 0755 + +.PARALLEL: $(ELFEDITLIBS) diff --git a/usr/src/cmd/sgs/elfedit/modules/Makefile.targ b/usr/src/cmd/sgs/elfedit/modules/Makefile.targ new file mode 100644 index 0000000000..52851b195f --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/modules/Makefile.targ @@ -0,0 +1,145 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# + + +$(PICDIR)/%.o: %.c + $(COMPILE.c) $< -o $@ + $(POST_PROCESS_O) + +$(PICDIR)/%.o: ../common/%.c + $(COMPILE.c) $< -o $@ + $(POST_PROCESS_O) + +$(PICDIR)/%32.o: ../common/%.c + $(COMPILE.c) $< -o $@ + $(POST_PROCESS_O) + +$(PICDIR)/%64.o: ../common/%.c + $(COMPILE.c) -D_ELF64 $< -o $@ + $(POST_PROCESS_O) + + +$(CAP_LIB): $(CAP_PICS) + $(BUILD.SO) $(LLDFLAGS) + $(POST_PROCESS_SO) + +$(DYN_LIB): $(DYN_PICS) + $(BUILD.SO) $(LLDFLAGS) + $(POST_PROCESS_SO) + +$(EHDR_LIB): $(EHDR_PICS) + $(BUILD.SO) $(LLDFLAGS) + $(POST_PROCESS_SO) + +$(PHDR_LIB): $(PHDR_PICS) + $(BUILD.SO) $(LLDFLAGS) + $(POST_PROCESS_SO) + +$(SHDR_LIB): $(SHDR_PICS) + $(BUILD.SO) $(LLDFLAGS) + $(POST_PROCESS_SO) + +$(SYM_LIB): $(SYM_PICS) + $(BUILD.SO) $(LLDFLAGS) + $(POST_PROCESS_SO) + +$(SYMINFO_LIB): $(SYMINFO_PICS) + $(BUILD.SO) $(LLDFLAGS) + $(POST_PROCESS_SO) + + +$(ROOTELFEDITDIR): + $(INS.dir) + +$(ROOTELFEDITDIR64): + $(INS.dir) + + +$(ROOTELFEDITDIR)/%: % + $(INS.file) + +$(ROOTELFEDITDIR64)/%: % + $(INS.file) + + +../common/%.c: %_msg.h + +%_msg.h %_msg.c: $(SGSMSG) ../common/%.msg + $(SGSMSG) $(SGSMSGFLAGS) -l -h $@ -d $@ \ + -m $(SGSMSGDIR)/elfedit_$* -n $*_msg $< + +# This rule causes the message catalog file to be created under +# sgs/messages, but does not regenerate the C or header file for the module. +$(SGSMSGDIR)/elfedit_%: $(SGSMSG) ../common/%.msg + $(SGSMSG) $(SGSMSGFLAGS) -l -m $(SGSMSGDIR)/elfedit_$* $< + +$(SGSMSG): + @ cd $(SGSTOOLS)/$(MACH); pwd; $(MAKE) catalog + @ pwd + +catalog: $(SGSMSGDIR)/elfedit_cap \ + $(SGSMSGDIR)/elfedit_dyn \ + $(SGSMSGDIR)/elfedit_ehdr \ + $(SGSMSGDIR)/elfedit_phdr \ + $(SGSMSGDIR)/elfedit_shdr \ + $(SGSMSGDIR)/elfedit_sym \ + $(SGSMSGDIR)/elfedit_syminfo + + +chkmsg: $(SRCS) + sh $(CHKMSG) -m ../common/cap.msg ../common/cap.c + sh $(CHKMSG) -m ../common/dyn.msg ../common/dyn.c + sh $(CHKMSG) -m ../common/ehdr.msg ../common/ehdr.c + sh $(CHKMSG) -m ../common/phdr.msg ../common/phdr.c + sh $(CHKMSG) -m ../common/shdr.msg ../common/shdr.c + sh $(CHKMSG) -m ../common/sym.msg ../common/sym.c + sh $(CHKMSG) -m ../common/syminfo.msg ../common/syminfo.c + +lint: + @echo "\nLint of: cap.so" > $(LINTOUT) + @echo "========================" >> $(LINTOUT) + $(LINT.c) ../common/cap.c >> $(LINTOUT) 2>&1 + @echo "\nLint of: dyn.so" >> $(LINTOUT) + @echo "========================" >> $(LINTOUT) + $(LINT.c) ../common/dyn.c >> $(LINTOUT) 2>&1 + @echo "\nLint of: ehdr.so" >> $(LINTOUT) + @echo "========================" >> $(LINTOUT) + $(LINT.c) ../common/ehdr.c >> $(LINTOUT) 2>&1 + @echo "\nLint of: phdr.so" >> $(LINTOUT) + @echo "========================" >> $(LINTOUT) + $(LINT.c) ../common/phdr.c >> $(LINTOUT) 2>&1 + @echo "\nLint of: shdr.so" >> $(LINTOUT) + @echo "========================" >> $(LINTOUT) + $(LINT.c) ../common/shdr.c >> $(LINTOUT) 2>&1 + @echo "\nLint of: sym.so" >> $(LINTOUT) + @echo "========================" >> $(LINTOUT) + $(LINT.c) ../common/sym.c >> $(LINTOUT) 2>&1 + @echo "\nLint of: syminfo.so" >> $(LINTOUT) + @echo "========================" >> $(LINTOUT) + $(LINT.c) ../common/syminfo.c >> $(LINTOUT) 2>&1 + +include $(SRC)/lib/Makefile.targ diff --git a/usr/src/cmd/sgs/elfedit/modules/amd64/Makefile b/usr/src/cmd/sgs/elfedit/modules/amd64/Makefile new file mode 100644 index 0000000000..c69276347c --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/modules/amd64/Makefile @@ -0,0 +1,56 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +LDDBGLIBDIR = $(LDDBGLIBDIR64) +CONVLIBDIR = $(CONVLIBDIR64) +ELFLIBDIR = $(ELFLIBDIR64) +MTARG = amd64/ + +lint := CONV_LIB = $(CONV_LIB64) +lint := LDDBG_LIB = $(LDDBG_LIB64) + +CFLAGS64 += $(C_PICFLAGS64) + +LLDFLAGS = $(LLDFLAGS64) + +LINTFLAGS64 += $(VAR_LINTFLAGS64) + + +.KEEP_STATE: + +all: $(PICDIR) .WAIT $(ELFEDITLIBS) + +install \ +package: all .WAIT $(ROOTELFEDITDIR64) .WAIT $(ROOTELFEDITLIBS) + + +include ../Makefile.targ +include ../../../Makefile.sub.64 + diff --git a/usr/src/cmd/sgs/elfedit/modules/common/cap.c b/usr/src/cmd/sgs/elfedit/modules/common/cap.c new file mode 100644 index 0000000000..3457945b9f --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/modules/common/cap.c @@ -0,0 +1,1021 @@ +/* + * 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 <ctype.h> +#include <machdep.h> +#include <elfedit.h> +#include <sys/elf_SPARC.h> +#include <strings.h> +#include <debug.h> +#include <conv.h> +#include <cap_msg.h> + + +/* + * Capabilities section + */ + + + + +/* + * This module uses shared code for several of the commands. + * It is sometimes necessary to know which specific command + * is active. + */ +typedef enum { + /* Dump command, used as module default to display dynamic section */ + CAP_CMD_T_DUMP = 0, /* cap:dump */ + + /* Commands that do not correspond directly to a specific DT tag */ + CAP_CMD_T_TAG = 1, /* cap:tag */ + CAP_CMD_T_VALUE = 2, /* cap:value */ + CAP_CMD_T_DELETE = 3, /* cap:delete */ + CAP_CMD_T_MOVE = 4, /* cap:shift */ + + /* Commands that embody tag specific knowledge */ + CAP_CMD_T_HW1 = 5, /* cap:hw1 */ + CAP_CMD_T_SF1 = 6, /* cap:sf1 */ +} CAP_CMD_T; + + + +#ifndef _ELF64 +/* + * We supply this function for the msg module + */ +const char * +_cap_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 cap_opt_t enum specifies a bit value for every optional + * argument allowed by a command in this module. + */ +typedef enum { + CAP_OPT_F_AND = 1, /* -and: AND (&) values to dest */ + CAP_OPT_F_CMP = 2, /* -cmp: Complement (~) values */ + CAP_OPT_F_CAPNDX = 4, /* -capndx: elt is tag index, */ + /* not name */ + CAP_OPT_F_OR = 8, /* -or: OR (|) values to dest */ +} cap_opt_t; + + +/* + * A variable of type ARGSTATE is used by each command to maintain + * information about the arguments and related things. It is + * initialized by process_args(), and used by the other routines. + */ +typedef struct { + elfedit_obj_state_t *obj_state; + struct { + elfedit_section_t *sec; /* Capabilities section reference */ + Cap *data; /* Start of capabilities section data */ + Word num; /* # Capabilities elts */ + } cap; + cap_opt_t optmask; /* Mask of options used */ + int argc; /* # of plain arguments */ + const char **argv; /* Plain arguments */ +} ARGSTATE; + + + +/* + * Standard argument processing for cap module + * + * entry + * obj_state, argc, argv - Standard command 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[], + ARGSTATE *argstate) +{ + elfedit_getopt_state_t getopt_state; + elfedit_getopt_ret_t *getopt_ret; + + bzero(argstate, sizeof (*argstate)); + argstate->obj_state = obj_state; + + 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; + + /* 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 the capabilities section */ + argstate->cap.sec = elfedit_sec_getcap(obj_state, &argstate->cap.data, + &argstate->cap.num); +} + + + +/* + * Print ELF capabilities values, taking the calling command, and output style + * into account. + * + * entry: + * cmd - CAP_CMD_T_* value giving identify of caller + * autoprint - If True, output is only produced if the elfedit + * autoprint flag is set. If False, output is always produced. + * argstate - Argument state block + * print_type - Specifies which capabilities elements to display. + * ndx = If print_type is PRINT_CAP_T_NDX, displays the index specified. + * Otherwise ignored. + */ +typedef enum { + PRINT_CAP_T_ALL = 0, /* Show all indexes */ + PRINT_CAP_T_NDX = 1, /* Show capabilities[arg] only */ + PRINT_CAP_T_TAG = 2 /* Show all elts with tag type */ + /* given by arg */ +} PRINT_CAP_T; + +static void +print_cap(CAP_CMD_T cmd, int autoprint, ARGSTATE *argstate, + PRINT_CAP_T print_type, Word arg) +{ + elfedit_outstyle_t outstyle; + Word cnt, ndx, printed = 0; + Cap *cap; + int header_done = 0; + Xword last_c_val = 0; + + if (autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0)) + return; + + /* + * Pick an output style. cap:dump is required to use the default + * style. The other commands use the current output style. + */ + outstyle = (cmd == CAP_CMD_T_DUMP) ? + ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle(); + + /* How many elements do we examine? */ + if (print_type == PRINT_CAP_T_NDX) { + if (arg >= argstate->cap.num) + return; /* Out of range */ + ndx = arg; + cnt = 1; + } else { + ndx = 0; + cnt = argstate->cap.num; + } + + cap = &argstate->cap.data[ndx]; + for (; cnt--; cap++, ndx++) { + /* + * If we are only displaying certain tag types and + * this isn't one of those, move on to next element. + */ + if ((print_type == PRINT_CAP_T_TAG) && (cap->c_tag != arg)) + continue; + + if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) { + if (header_done == 0) { + header_done = 1; + Elf_cap_title(0); + } + Elf_cap_entry(NULL, cap, ndx, + argstate->obj_state->os_ehdr->e_machine); + } else { + /* + * In simple or numeric mode under a print type + * that is based on tag type rather than on index, + * quietly: If we've already printed this value, + * don't print it again. A common example of this + * is PRINT_CAP_T_RUNPATH when both CA_RPATH and + * CA_RUNPATH are present with the same value. + */ + if ((print_type == PRINT_CAP_T_TAG) && printed && + (last_c_val == cap->c_un.c_val)) + continue; + + if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { + union { + Conv_cap_val_hw1_buf_t hw1; + Conv_cap_val_sf1_buf_t sf1; + } c_buf; + + switch (cap->c_tag) { + case CA_SUNW_HW_1: + elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), + conv_cap_val_hw1(cap->c_un.c_val, + argstate->obj_state->os_ehdr-> + e_machine, + CONV_FMT_NOBKT, &c_buf.hw1)); + printed = 1; + continue; + case CA_SUNW_SF_1: + elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), + conv_cap_val_sf1(cap->c_un.c_val, + argstate->obj_state->os_ehdr-> + e_machine, + CONV_FMT_NOBKT, &c_buf.sf1)); + printed = 1; + continue; + } + } + elfedit_printf(MSG_ORIG(MSG_FMT_HEXXWORDNL), + cap->c_un.c_val); + } + printed = 1; + last_c_val = cap->c_un.c_val; + } + + /* + * If nothing was output under the print types that are + * based on tag type, issue an error saying it doesn't exist. + */ + if (!printed && (print_type == PRINT_CAP_T_TAG)) { + Conv_inv_buf_t inv_buf; + + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOCAELT), + EC_WORD(argstate->cap.sec->sec_shndx), + argstate->cap.sec->sec_name, conv_cap_tag(arg, &inv_buf)); + } +} + + +/* + * Process the elt argument: This will be a tag type if -capndx is + * not present and this is a print request. It will be an index otherwise. + * + * entry: + * argstate - Argument state block + * arg - Argument string to be converted into an index + * argname - String giving the name by which the argument is + * referred in the online help for the command. + * print_request - True if the command is to print the current + * value(s) and return without changing anything. + * print_type - Address of variable containing PRINT_CAP_T_ + * code specifying how the elements will be displayed. + * + * exit: + * If print_request is False: arg is converted into an integer value. + * If -capndx was used, we convert it into an integer. If it was not + * used, then arg is a tag name --- we find the first capabilities entry + * that matches. If no entry matches, and there is an extra CA_NULL, + * it is added. Otherwise an error is issued. *print_type is set + * to PRINT_CAP_T_NDX. + * + * If print_request is True: If -capndx was used, arg is converted into + * an integer value, *print_type is set to PRINT_CAP_T_NDX, and + * the value is returned. If -capndx was not used, *print_type is set to + * PRINT_CAP_T_TAG, and the tag value is returned. + */ +static Word +arg_to_index(ARGSTATE *argstate, const char *arg, const char *argname, + int print_request, PRINT_CAP_T *print_type) +{ + Word ndx, ca_value; + + + /* Assume we are returning an index, alter as needed below */ + *print_type = PRINT_CAP_T_NDX; + + /* If -capndx was used, this is a simple numeric index */ + if ((argstate->optmask & CAP_OPT_F_CAPNDX) != 0) + return ((Word) elfedit_atoui_range(arg, argname, 0, + argstate->cap.num - 1, NULL)); + + /* The argument is a CA_ tag type, not a numeric index */ + ca_value = (Word) elfedit_atoconst(arg, ELFEDIT_CONST_CA); + + /* + * If this is a printing request, then we let print_cap() show + * all the items with this tag type. + */ + if (print_request) { + *print_type = PRINT_CAP_T_TAG; + return (ca_value); + } + + /* Locate the first entry with the given tag type */ + for (ndx = 0; ndx < argstate->cap.num; ndx++) { + if (argstate->cap.data[ndx].c_tag == ca_value) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_CA2NDX), + EC_WORD(argstate->cap.sec->sec_shndx), + argstate->cap.sec->sec_name, EC_WORD(ndx), arg); + return (ndx); + } + } + + /* No room to create one, so we're out of options and must fail */ + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOCAELT), + EC_WORD(argstate->cap.sec->sec_shndx), + argstate->cap.sec->sec_name, arg); + + /*NOTREACHED*/ + return (0); /* For lint */ +} + + +/* + * Argument processing for the bitmask commands. Convert the arguments + * to integer form, apply -and/-cmp/-or, and return the resulting value. + * + * entry: + * argstate - Argument state block + * orig - Value of original bitmask + * const_sym - NULL, or array of name->integer mappings for + * applicable symbolic constant names. + */ +static Word +flag_bitop(ARGSTATE *argstate, Word orig, const elfedit_atoui_sym_t *const_sym) +{ + Word flags = 0; + int i; + + /* Collect the arguments */ + for (i = 0; i < argstate->argc; i++) + flags |= (Word) elfedit_atoui(argstate->argv[i], const_sym); + + /* Complement the value? */ + if (argstate->optmask & CAP_OPT_F_CMP) + flags = ~flags; + + /* Perform any requested bit operations */ + if (argstate->optmask & CAP_OPT_F_AND) + flags &= orig; + else if (argstate->optmask & CAP_OPT_F_OR) + flags |= orig; + + return (flags); +} + + + +/* + * Common body for the cap: 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 CAP_CMD_T_* constants listed above, specifying + * which command to implement. + * obj_state, argc, argv - Standard command arguments + */ +static elfedit_cmdret_t +cmd_body(CAP_CMD_T cmd, elfedit_obj_state_t *obj_state, + int argc, const char *argv[]) +{ + ARGSTATE argstate; + Cap *cap; + const char *cap_name; + Word cap_ndx, cap_num; + elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE; + PRINT_CAP_T print_type = PRINT_CAP_T_ALL; + Word ndx; + int print_only = 0; + int do_autoprint = 1; + + /* Process the optional arguments */ + process_args(obj_state, argc, argv, &argstate); + + cap = argstate.cap.data; + cap_num = argstate.cap.num; + cap_name = argstate.cap.sec->sec_name; + cap_ndx = argstate.cap.sec->sec_shndx; + + /* Check number of arguments, gather information */ + switch (cmd) { + case CAP_CMD_T_DUMP: + /* cap:dump can accept an optional index argument */ + if (argstate.argc > 1) + elfedit_command_usage(); + print_only = 1; + if (argstate.argc == 1) + ndx = arg_to_index(&argstate, argstate.argv[0], + MSG_ORIG(MSG_STR_ELT), print_only, &print_type); + break; + + case CAP_CMD_T_TAG: + case CAP_CMD_T_VALUE: + print_only = (argstate.argc != 2); + if (argstate.argc > 0) { + if (argstate.argc > 2) + elfedit_command_usage(); + ndx = arg_to_index(&argstate, argstate.argv[0], + MSG_ORIG(MSG_STR_ELT), print_only, &print_type); + } + break; + + case CAP_CMD_T_DELETE: + if ((argstate.argc < 1) || (argstate.argc > 2)) + elfedit_command_usage(); + ndx = arg_to_index(&argstate, argstate.argv[0], + MSG_ORIG(MSG_STR_ELT), + 0, &print_type); + do_autoprint = 0; + break; + + case CAP_CMD_T_MOVE: + if ((argstate.argc < 2) || (argstate.argc > 3)) + elfedit_command_usage(); + ndx = arg_to_index(&argstate, argstate.argv[0], + MSG_ORIG(MSG_STR_ELT), 0, &print_type); + do_autoprint = 0; + break; + + case CAP_CMD_T_HW1: + print_only = (argstate.argc == 0); + ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str( + ELFEDIT_CONST_CA, CA_SUNW_HW_1, 1), + MSG_ORIG(MSG_STR_VALUE), print_only, &print_type); + break; + + case CAP_CMD_T_SF1: + print_only = (argstate.argc == 0); + ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str( + ELFEDIT_CONST_CA, CA_SUNW_SF_1, 1), + MSG_ORIG(MSG_STR_VALUE), print_only, &print_type); + break; + + default: + /* Note expected: All commands should have been caught above */ + elfedit_command_usage(); + break; + } + + + /* If this is a request to print current values, do it and return */ + if (print_only) { + print_cap(cmd, 0, &argstate, print_type, ndx); + return (ELFEDIT_CMDRET_NONE); + } + + + switch (cmd) { + /* + * CAP_CMD_T_DUMP can't get here: It is a print-only + * command. + */ + + case CAP_CMD_T_TAG: + { + Conv_inv_buf_t inv_buf1, inv_buf2; + Word c_tag = (Word) elfedit_atoconst(argstate.argv[1], + ELFEDIT_CONST_CA); + + if (cap[ndx].c_tag == c_tag) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_S_OK), + cap_ndx, cap_name, EC_WORD(ndx), + conv_cap_tag(c_tag, &inv_buf1)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_S_CHG), + cap_ndx, cap_name, EC_WORD(ndx), + conv_cap_tag(cap[ndx].c_tag, &inv_buf1), + conv_cap_tag(c_tag, &inv_buf2)); + cap[ndx].c_tag = c_tag; + ret = ELFEDIT_CMDRET_MOD; + } + } + break; + + case CAP_CMD_T_VALUE: + { + Xword c_val = (Xword) + elfedit_atoui(argstate.argv[1], NULL); + + if (cap[ndx].c_un.c_val == c_val) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_X_OK), + argstate.cap.sec->sec_shndx, + argstate.cap.sec->sec_name, + EC_WORD(ndx), EC_XWORD(c_val)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_X_CHG), + argstate.cap.sec->sec_shndx, + argstate.cap.sec->sec_name, + EC_WORD(ndx), EC_XWORD(cap[ndx].c_un.c_val), + EC_XWORD(c_val)); + cap[ndx].c_un.c_val = c_val; + ret = ELFEDIT_CMDRET_MOD; + } + } + break; + + case CAP_CMD_T_DELETE: + { + Word cnt = (argstate.argc == 1) ? 1 : + (Word) elfedit_atoui_range(argstate.argv[1], + MSG_ORIG(MSG_STR_COUNT), 1, cap_num - ndx, NULL); + const char *msg_prefix = + elfedit_sec_msgprefix(argstate.cap.sec); + + elfedit_array_elts_delete(msg_prefix, argstate.cap.data, + sizeof (Cap), cap_num, ndx, cnt); + ret = ELFEDIT_CMDRET_MOD; + } + break; + + case CAP_CMD_T_MOVE: + { + Cap save; + Word cnt; + Word dstndx; + const char *msg_prefix = + elfedit_sec_msgprefix(argstate.cap.sec); + + dstndx = (Word) + elfedit_atoui_range(argstate.argv[1], + MSG_ORIG(MSG_STR_DST_INDEX), 0, cap_num - 1, + NULL); + if (argstate.argc == 2) { + cnt = 1; + } else { + cnt = (Word) elfedit_atoui_range( + argstate.argv[2], MSG_ORIG(MSG_STR_COUNT), + 1, cap_num, NULL); + } + elfedit_array_elts_move(msg_prefix, argstate.cap.data, + sizeof (save), cap_num, ndx, dstndx, cnt, &save); + ret = ELFEDIT_CMDRET_MOD; + } + break; + + + case CAP_CMD_T_HW1: + { + Conv_cap_val_hw1_buf_t buf1, buf2; + Half mach = argstate.obj_state->os_ehdr->e_machine; + Xword hw1; + + hw1 = flag_bitop(&argstate, cap[ndx].c_un.c_val, + elfedit_mach_sunw_hw1_to_atoui(mach)); + + /* Set the value */ + if (cap[ndx].c_un.c_val == hw1) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_BSB_OK), cap_ndx, + cap_name, EC_WORD(ndx), + conv_cap_val_hw1(cap[ndx].c_un.c_val, mach, + CONV_FMT_NOBKT, &buf1)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_BSB_CHG), + cap_ndx, cap_name, EC_WORD(ndx), + conv_cap_val_hw1(cap[ndx].c_un.c_val, mach, + CONV_FMT_NOBKT, &buf1), + conv_cap_val_hw1(hw1, mach, + CONV_FMT_NOBKT, &buf2)); + ret = ELFEDIT_CMDRET_MOD; + cap[ndx].c_un.c_val = hw1; + } + } + break; + + case CAP_CMD_T_SF1: + { + Conv_cap_val_sf1_buf_t buf1, buf2; + Half mach = argstate.obj_state->os_ehdr->e_machine; + Xword sf1; + + sf1 = flag_bitop(&argstate, cap[ndx].c_un.c_val, + elfedit_const_to_atoui(ELFEDIT_CONST_SF1_SUNW)); + + /* Set the value */ + if (cap[ndx].c_un.c_val == sf1) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_BSB_OK), cap_ndx, + cap_name, EC_WORD(ndx), + conv_cap_val_sf1(cap[ndx].c_un.c_val, mach, + CONV_FMT_NOBKT, &buf1)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_BSB_CHG), + cap_ndx, cap_name, EC_WORD(ndx), + conv_cap_val_sf1(cap[ndx].c_un.c_val, mach, + CONV_FMT_NOBKT, &buf1), + conv_cap_val_sf1(sf1, mach, + CONV_FMT_NOBKT, &buf2)); + ret = ELFEDIT_CMDRET_MOD; + cap[ndx].c_un.c_val = sf1; + } + } + break; + } + + /* + * If we modified the capabilities section header, tell libelf. + */ + if (ret == ELFEDIT_CMDRET_MOD) + elfedit_modified_data(argstate.cap.sec); + + /* Do autoprint */ + if (do_autoprint) + print_cap(cmd, 1, &argstate, print_type, ndx); + + return (ret); +} + + + +/* + * Command completion functions for the commands + */ + +/* + * Command completion for the first argument, which specifies + * the capabilities element to use. Examines the options to see if + * -capndx is present, and if not, supplies the completion + * strings for argument 1. + */ +/*ARGSUSED*/ +static void +cpl_eltarg(elfedit_obj_state_t *obj_state, void *cpldata, int argc, + const char *argv[], int num_opt) +{ + Word i; + + /* Make sure it's the first argument */ + if ((argc - num_opt) != 1) + return; + + /* Is -capndx present? If so, we don't complete tag types */ + for (i = 0; i < num_opt; i++) + if (strcmp(argv[i], MSG_ORIG(MSG_STR_MINUS_CAPNDX)) == 0) + return; + + /* + * Supply capability tag names. There are very few of these, so + * rather than worry about whether a given tag exists in the + * file or not, we simply serve up all the possibilities. + */ + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_CA); +} + + +/*ARGSUSED*/ +static void +cpl_tag(elfedit_obj_state_t *obj_state, void *cpldata, int argc, + const char *argv[], int num_opt) +{ + /* First argument */ + if ((argc - num_opt) == 1) { + cpl_eltarg(obj_state, cpldata, argc, argv, num_opt); + return; + } + + /* The second argument is always a tag value */ + if ((argc - num_opt) == 2) + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_CA); +} + +/*ARGSUSED*/ +static void +cpl_hw1(elfedit_obj_state_t *obj_state, void *cpldata, int argc, + const char *argv[], int num_opt) +{ + elfedit_atoui_sym_t *sym_const; + + /* This routine allows multiple flags to be specified */ + + /* + * If there is no object, then supply all the hardware + * capabilities we know of. + */ + if (obj_state == NULL) { + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_AV_386); + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_AV_SPARC); + return; + } + + /* + * Supply the hardware capabilities for the type of + * machine the object is for, if we know any. + */ + sym_const = elfedit_mach_sunw_hw1_to_atoui( + obj_state->os_ehdr->e_machine); + if (sym_const != NULL) + elfedit_cpl_atoui(cpldata, sym_const); +} + +/*ARGSUSED*/ +static void +cpl_sf1(elfedit_obj_state_t *obj_state, void *cpldata, int argc, + const char *argv[], int num_opt) +{ + /* This routine allows multiple flags to be specified */ + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SF1_SUNW); +} + + +/* + * 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(CAP_CMD_T_DUMP, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_tag(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(CAP_CMD_T_TAG, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_value(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(CAP_CMD_T_VALUE, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_delete(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(CAP_CMD_T_DELETE, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_move(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(CAP_CMD_T_MOVE, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_hw1(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(CAP_CMD_T_HW1, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_sf1(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(CAP_CMD_T_SF1, obj_state, argc, argv)); +} + + + +/*ARGSUSED*/ +elfedit_module_t * +elfedit_init(elfedit_module_version_t version) +{ + /* For commands that only accept -and, -cmp, -o, and -or */ + static elfedit_cmd_optarg_t opt_ostyle_bitop[] = { + { ELFEDIT_STDOA_OPT_AND, NULL, + ELFEDIT_CMDOA_F_INHERIT, CAP_OPT_F_AND, CAP_OPT_F_OR }, + { ELFEDIT_STDOA_OPT_CMP, NULL, + ELFEDIT_CMDOA_F_INHERIT, CAP_OPT_F_CMP, 0 }, + { ELFEDIT_STDOA_OPT_O, NULL, + ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, + { ELFEDIT_STDOA_OPT_OR, NULL, + ELFEDIT_CMDOA_F_INHERIT, CAP_OPT_F_OR, CAP_OPT_F_AND }, + { NULL } + }; + + /* For commands that only accept -capndx */ + static elfedit_cmd_optarg_t opt_capndx[] = { + { MSG_ORIG(MSG_STR_MINUS_CAPNDX), + /* MSG_INTL(MSG_OPTDESC_CAPNDX) */ + ELFEDIT_I18NHDL(MSG_OPTDESC_CAPNDX), 0, + CAP_OPT_F_CAPNDX, 0 }, + { NULL } + }; + + /* For commands thataccept -capndx and output styles */ + static elfedit_cmd_optarg_t opt_ostyle_capndx[] = { + { MSG_ORIG(MSG_STR_MINUS_CAPNDX), + /* MSG_INTL(MSG_OPTDESC_CAPNDX) */ + ELFEDIT_I18NHDL(MSG_OPTDESC_CAPNDX), 0, + CAP_OPT_F_CAPNDX, 0 }, + { ELFEDIT_STDOA_OPT_O, NULL, + ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, + { NULL } + }; + + + /* cap: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 arg_dump[] = { + { MSG_ORIG(MSG_STR_ELT), + /* MSG_INTL(MSG_ARGDESC_ELT) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_ELT), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + + /* cap:tag */ + static const char *name_tag[] = { MSG_ORIG(MSG_CMD_TAG), NULL }; + static elfedit_cmd_optarg_t arg_tag[] = { + { MSG_ORIG(MSG_STR_ELT), + /* MSG_INTL(MSG_A1_TAG_ELT) */ + ELFEDIT_I18NHDL(MSG_A1_TAG_ELT), + ELFEDIT_CMDOA_F_OPT }, + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_A2_TAG_VALUE) */ + ELFEDIT_I18NHDL(MSG_A2_TAG_VALUE), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + + /* cap:value */ + static const char *name_value[] = { MSG_ORIG(MSG_CMD_VALUE), NULL }; + static elfedit_cmd_optarg_t arg_value[] = { + { MSG_ORIG(MSG_STR_ELT), + /* MSG_INTL(MSG_ARGDESC_ELT) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_ELT), + ELFEDIT_CMDOA_F_OPT }, + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_A2_VALUE_VALUE) */ + ELFEDIT_I18NHDL(MSG_A2_VALUE_VALUE), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + /* cap:delete */ + static const char *name_delete[] = { MSG_ORIG(MSG_CMD_DELETE), NULL }; + static elfedit_cmd_optarg_t arg_delete[] = { + { MSG_ORIG(MSG_STR_ELT), + /* MSG_INTL(MSG_ARGDESC_ELT) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_ELT), + 0 }, + { MSG_ORIG(MSG_STR_COUNT), + /* MSG_INTL(MSG_A2_DELETE_COUNT) */ + ELFEDIT_I18NHDL(MSG_A2_DELETE_COUNT), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + /* cap:move */ + static const char *name_move[] = { MSG_ORIG(MSG_CMD_MOVE), NULL }; + static elfedit_cmd_optarg_t arg_move[] = { + { MSG_ORIG(MSG_STR_ELT), + /* MSG_INTL(MSG_ARGDESC_ELT) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_ELT), + 0 }, + { MSG_ORIG(MSG_STR_DST_INDEX), + /* MSG_INTL(MSG_A2_MOVE_DST_INDEX) */ + ELFEDIT_I18NHDL(MSG_A2_MOVE_DST_INDEX), + 0 }, + { MSG_ORIG(MSG_STR_COUNT), + /* MSG_INTL(MSG_A3_MOVE_COUNT) */ + ELFEDIT_I18NHDL(MSG_A3_MOVE_COUNT), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + /* cap:hw1 */ + static const char *name_hw1[] = { MSG_ORIG(MSG_CMD_HW1), NULL }; + static elfedit_cmd_optarg_t arg_hw1[] = { + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_A1_HW1_VALUE) */ + ELFEDIT_I18NHDL(MSG_A1_HW1_VALUE), + ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT }, + { NULL } + }; + + /* cap:sf1 */ + static const char *name_sf1[] = { MSG_ORIG(MSG_CMD_SF1), NULL }; + static elfedit_cmd_optarg_t arg_sf1[] = { + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_A1_SF1_VALUE) */ + ELFEDIT_I18NHDL(MSG_A1_SF1_VALUE), + ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT }, + { NULL } + }; + + + + + static elfedit_cmd_t cmds[] = { + /* cap:dump */ + { cmd_dump, cpl_eltarg, name_dump, + /* MSG_INTL(MSG_DESC_DUMP) */ + ELFEDIT_I18NHDL(MSG_DESC_DUMP), + /* MSG_INTL(MSG_HELP_DUMP) */ + ELFEDIT_I18NHDL(MSG_HELP_DUMP), + opt_capndx, arg_dump }, + + /* cap:tag */ + { cmd_tag, cpl_tag, name_tag, + /* MSG_INTL(MSG_DESC_TAG) */ + ELFEDIT_I18NHDL(MSG_DESC_TAG), + /* MSG_INTL(MSG_HELP_TAG) */ + ELFEDIT_I18NHDL(MSG_HELP_TAG), + opt_ostyle_capndx, arg_tag }, + + /* cap:value */ + { cmd_value, cpl_eltarg, name_value, + /* MSG_INTL(MSG_DESC_VALUE) */ + ELFEDIT_I18NHDL(MSG_DESC_VALUE), + /* MSG_INTL(MSG_HELP_VALUE) */ + ELFEDIT_I18NHDL(MSG_HELP_VALUE), + opt_ostyle_capndx, arg_value }, + + /* cap:delete */ + { cmd_delete, cpl_eltarg, name_delete, + /* MSG_INTL(MSG_DESC_DELETE) */ + ELFEDIT_I18NHDL(MSG_DESC_DELETE), + /* MSG_INTL(MSG_HELP_DELETE) */ + ELFEDIT_I18NHDL(MSG_HELP_DELETE), + opt_capndx, arg_delete }, + + /* cap:move */ + { cmd_move, cpl_eltarg, name_move, + /* MSG_INTL(MSG_DESC_MOVE) */ + ELFEDIT_I18NHDL(MSG_DESC_MOVE), + /* MSG_INTL(MSG_HELP_MOVE) */ + ELFEDIT_I18NHDL(MSG_HELP_MOVE), + opt_capndx, arg_move }, + + /* cap:hw1 */ + { cmd_hw1, cpl_hw1, name_hw1, + /* MSG_INTL(MSG_DESC_HW1) */ + ELFEDIT_I18NHDL(MSG_DESC_HW1), + /* MSG_INTL(MSG_HELP_HW1) */ + ELFEDIT_I18NHDL(MSG_HELP_HW1), + opt_ostyle_bitop, arg_hw1 }, + + /* cap:sf1 */ + { cmd_sf1, cpl_sf1, name_sf1, + /* MSG_INTL(MSG_DESC_SF1) */ + ELFEDIT_I18NHDL(MSG_DESC_SF1), + /* MSG_INTL(MSG_HELP_SF1) */ + ELFEDIT_I18NHDL(MSG_HELP_SF1), + opt_ostyle_bitop, arg_sf1 }, + + { 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); +} diff --git a/usr/src/cmd/sgs/elfedit/modules/common/cap.msg b/usr/src/cmd/sgs/elfedit/modules/common/cap.msg new file mode 100644 index 0000000000..54743a2a26 --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/modules/common/cap.msg @@ -0,0 +1,251 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" + +@ _START_ + +# Message file for elfedit 'cap' module + +@ MSG_ID_ELFEDIT_CAP + + +# Debug messages + +@ MSG_DEBUG_S_OK "[%d: %s][%d]: value unchanged: %s\n" +@ MSG_DEBUG_S_CHG "[%d: %s][%d]: change from %s to %s\n" +@ MSG_DEBUG_BSB_OK "[%d: %s][%d]: value unchanged: [%s]\n" +@ MSG_DEBUG_BSB_CHG "[%d: %s][%d]: change from [%s] to [%s]\n" +@ MSG_DEBUG_X_OK "[%d: %s][%d]: value unchanged: %#llx\n" +@ MSG_DEBUG_X_CHG "[%d: %s][%d]: change from %#llx to %#llx\n" +@ MSG_DEBUG_CA2NDX "[%d: %s][%d]: Capability entry for tag: %s\n" + + +# Errors + +@ MSG_ERR_NOCAELT "[%d: %s]: Capabilities section does not contain \ + tag: %s\n" + + +# Module description + +@ MSG_MOD_DESC "Capabilities Section" + + + +# 1-line description strings + +@ MSG_DESC_DUMP "Dump Capabilities Section" +@ MSG_DESC_TAG "Change element tag" +@ MSG_DESC_VALUE "Change element value" +@ MSG_DESC_DELETE "Delete elements" +@ MSG_DESC_MOVE "Move elements" +@ MSG_DESC_HW1 "Hardware capabilities bit values" +@ MSG_DESC_SF1 "Software capabilities bit values" + + +# Commmand option description strings + +@ MSG_OPTDESC_CAPNDX "\ + Interpret the elt argument as a direct index into the\n\ + capabilities section, rather than as a CA_ tag value.\n" + + +# Command argument description strings + +@ MSG_A1_TAG_ELT "\ + Capabilities element to be examined or changed. By default,\n\ + this is a CA_ tag value. The index of the first element\n\ + in the capabilities section that has the specified tag value\n\ + will be used. The value specified can be one of the well known\n\ + CA_ constants, or any integer.\n\ + \n\ + If the -capndx option is specified, elt is instead interpreted\n\ + as a simple integer index into the capabilities section.\n" + +@ MSG_A2_TAG_VALUE "\ + Value to be set for c_tag field of specified capabilities\n\ + element. Tag values can be specified using the well known\n\ + CA_ symbolic constants from /usr/include/sys/elf.h, or\n\ + as integers.\n" + +@ MSG_ARGDESC_ELT "\ + Element within capabilities section. By default, this is a\n\ + tag value. In this case, the index of the first capabilities\n\ + element with the specified tag value will be used. Tag values\n\ + can be specified using the well known CA_ symbolic constants\n\ + from /usr/include/sys/elf.h, or as integers. If the -capndx\n\ + option is specified, then elt is instead interpreted as a\n\ + direct numeric index into the capabilities section.\n" + +@ MSG_A2_VALUE_VALUE "\ + Value to set for specified capabilities section element.\n\ + This is a numeric value which is used directly.\n" + +@ MSG_A2_DELETE_COUNT "\ + Number of capabilities elements to delete, starting at the\n\ + specified position. This value cannot exceed the number\n\ + of slots remaining in the table below the specified position.\n\ + If count is not supplied, a single element is deleted.\n" + +@ MSG_A2_MOVE_DST_INDEX "\ + Numeric index within capabilities section to which the element(s)\n\ + should be moved.\n" + +@ MSG_A3_MOVE_COUNT "\ + Number of capabilities elements to move. This value cannot\n\ + exceed the number of slots remaining in the table below\n\ + the specified position. If count is not supplied, a\n\ + single element is moved.\n" + +@ MSG_A1_HW1_VALUE "\ + Hardware capability values. This can be an integer value,\n\ + any of the AV_386_ symbolic constants defined in\n\ + /usr/include/sys/auxv_386.h, or the AV_SPARC symbolic\n\ + constants defined in /usr/include/sys/auxv_SPARC.h\n" + +@ MSG_A1_SF1_VALUE "\ + Software capability values. This can be an integer value,\n\ + any of the SF1_SUNW_ symbolic constants defined in\n\ + /usr/include/sys/elf.h\n" + + + +# Help strings + +@ MSG_HELP_DUMP " \ + The cap:dump command is used to display the contents of the\n\ + capabilities section using the same style used by the elfdump\n\ + program.\n" + +@ MSG_HELP_TAG " \ + The cap:tag command is used to display or alter the\n\ + type of an element in the capabilities section. This information\n\ + is found in the c_tag field of a capabilities element.\n\ + \n\ + If cap:tag is called without arguments, the value of c_tag\n\ + for every element in the capabilities section is shown. If called\n\ + with the elt argument, the specified elements are displayed.\n\ + If both arguments are present, the c_tag field of the specified\n\ + capabilities element is set to the given value.\n" + +@ MSG_HELP_VALUE " \ + The cap:value command is used to display or alter the\n\ + value of an element in the capabilities section. The value\n\ + of a capabilities element is found in the c_un union of the\n\ + element.\n\ + \n\ + If cap:value is called without arguments, the value of every\n\ + element in the capabilities section is shown. If called with the\n\ + elt argument, the value of the specified elements are displayed.\n\ + If both arguments are present, the value of the specified\n\ + capabilities element is set to the given value.\n" + +@ MSG_HELP_DELETE " \ + The cap:delete command is used to delete one or more elements\n\ + in the capabilities section. The elements following the deleted\n\ + items move up, and new CA_NULL elements are inserted at the\n\ + end of the capabilities section to fill the vacated space.\n" + +@ MSG_HELP_MOVE " \ + The cap:move command is used to move the position of one\n\ + or more elements in the capabilities section. The specified\n\ + number of elements are moved from elt to dst_index.\n" + +@ MSG_HELP_HW1 " \ + The cap:hw1 command is used to display or alter the\n\ + value of the hardware capabilities element (CA_SUNW_HW_1).\n\ + \n\ + If cap:hw1 is called without arguments, the current\n\ + value is shown. If one or more value arguments are present,\n\ + the following steps are taken:\n\ + \n \ + o\tAll the value arguments are OR'd together.\n\ + \n \ + o\tIf the -cmp option has been specified, the new value\n\ + \tis complemented.\n\ + \n \ + o\tThe CA_SUNW_HW_1 element of the capabilities section is\n\ + \tupdated with the new value. If -and is specified, the new\n\ + \tvalue is AND'd against the existing value. If -or is\n\ + \tspecified, the new value is OR'd against the existing\n\ + \tvalue. If neither -and or -or are specified, the new value\n\ + \treplaces the existing value.\n" + +@ MSG_HELP_SF1 " \ + The cap:sf1 command is used to display or alter the\n\ + value of the software capabilities element (CA_SUNW_SF_1).\n\ + \n\ + If cap:sf1 is called without arguments, the current\n\ + value is shown. If one or more value arguments are present,\n\ + the following steps are taken:\n\ + \n \ + o\tAll the value arguments are OR'd together.\n\ + \n \ + o\tIf the -cmp option has been specified, the new value\n\ + \tis complemented.\n\ + \n \ + o\tThe CA_SUNW_SF_1 element of the capabilities section is\n\ + \tupdated with the new value. If -and is specified, the new\n\ + \tvalue is AND'd against the existing value. If -or is\n\ + \tspecified, the new value is OR'd against the existing\n\ + \tvalue. If neither -and or -or are specified, the new value\n\ + replaces the existing value.\n" + +@ _END_ + + +# The following strings represent reserved words, files, pathnames and symbols. +# Reference to this strings is via the MSG_ORIG() macro, and thus no message +# translation is required. + + +# Strings +@ MSG_STR_EMPTY "" +@ MSG_STR_COUNT "count" +@ MSG_STR_ELT "elt" +@ MSG_STR_DST_INDEX "dst_index" +@ MSG_STR_MINUS_CAPNDX "-capndx" +@ MSG_STR_VALUE "value" + +# Format strings +@ MSG_FMT_STRNL "%s\n" +@ MSG_FMT_HEXXWORDNL "%#llx\n" + + +# Module name + +@ MSG_MOD_NAME "cap" + + +# Command names + +@ MSG_CMD_DUMP "dump" +@ MSG_CMD_TAG "tag" +@ MSG_CMD_VALUE "value" +@ MSG_CMD_DELETE "delete" +@ MSG_CMD_MOVE "move" +@ MSG_CMD_HW1 "hw1" +@ MSG_CMD_SF1 "sf1" diff --git a/usr/src/cmd/sgs/elfedit/modules/common/dyn.c b/usr/src/cmd/sgs/elfedit/modules/common/dyn.c new file mode 100644 index 0000000000..9f47042ffb --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/modules/common/dyn.c @@ -0,0 +1,1821 @@ +/* + * 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 <ctype.h> +#include <machdep.h> +#include <elfedit.h> +#include <sys/elf_SPARC.h> +#include <strings.h> +#include <debug.h> +#include <conv.h> +#include <dyn_msg.h> + + +/* + * Dynamic section + */ + + + + +/* + * This module uses shared code for several of the commands. + * It is sometimes necessary to know which specific command + * is active. + */ +typedef enum { + /* Dump command, used as module default to display dynamic section */ + DYN_CMD_T_DUMP = 0, /* dyn:dump */ + + /* Commands that do not correspond directly to a specific DT tag */ + DYN_CMD_T_TAG = 1, /* dyn:tag */ + DYN_CMD_T_VALUE = 2, /* dyn:value */ + DYN_CMD_T_DELETE = 3, /* dyn:delete */ + DYN_CMD_T_MOVE = 4, /* dyn:shift */ + + /* Commands that embody tag specific knowledge */ + DYN_CMD_T_RUNPATH = 5, /* dyn:runpath/rpath */ + DYN_CMD_T_POSFLAG1 = 6, /* dyn:posflag1 */ + DYN_CMD_T_FLAGS = 7, /* dyn:flags */ + DYN_CMD_T_FLAGS1 = 8, /* dyn:flags1 */ + DYN_CMD_T_FEATURE1 = 9, /* dyn:feature1 */ + DYN_CMD_T_CHECKSUM = 10 /* dyn:checksum */ +} DYN_CMD_T; + + + +#ifndef _ELF64 +/* + * We supply this function for the msg module + */ +const char * +_dyn_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 dyn_opt_t enum specifies a bit value for every optional + * argument allowed by a command in this module. + */ +typedef enum { + DYN_OPT_F_ADD = 1, /* -add: Add new elt rather than */ + /* modifying an existing one */ + DYN_OPT_F_AND = 2, /* -and: AND (&) values to dest */ + DYN_OPT_F_CMP = 4, /* -cmp: Complement (~) values */ + DYN_OPT_F_DYNNDX = 8, /* -dynndx: elt is tag index, */ + /* not name */ + DYN_OPT_F_OR = 16, /* -or: OR (|) values to dest */ + DYN_OPT_F_STRVAL = 32 /* -s: value is string, not integer */ +} dyn_opt_t; + + +/* + * A variable of type ARGSTATE is used by each command to maintain + * information about the arguments and related things. It is + * initialized by process_args(), and used by the other routines. + */ +typedef struct { + elfedit_obj_state_t *obj_state; + elfedit_section_t *strsec; /* Dynamic string table ref */ + struct { + elfedit_section_t *sec; /* Dynamic section reference */ + Dyn *data; /* Start dynamic section data */ + Word num; /* # dynamic elts */ + Word null_ndx; /* Index of first DT_NULL */ + Word num_null_ndx; /* # of DT_NULL elements */ + } dyn; + dyn_opt_t optmask; /* Mask of options used */ + int argc; /* # of plain arguments */ + const char **argv; /* Plain arguments */ +} ARGSTATE; + + + +/* + * Set argstate null_ndx field for current dynamic area + */ +static void +set_null_ndx(ARGSTATE *argstate) +{ + Word num, null_ndx; + + num = argstate->dyn.num; + argstate->dyn.num_null_ndx = 0; + for (null_ndx = 0; null_ndx < num; null_ndx++) + if (argstate->dyn.data[null_ndx].d_tag == DT_NULL) { + argstate->dyn.num_null_ndx++; + break; + } + argstate->dyn.null_ndx = null_ndx; + + /* Count the number of remaining DT_NULL items */ + for (; null_ndx < num; null_ndx++) + if (argstate->dyn.data[null_ndx].d_tag == DT_NULL) + argstate->dyn.num_null_ndx++; +} + + +/* + * Convert the first available DT_NULL slot in the dynamic section + * into something else. + * + * entry: + * argstate - Argument state block + * d_tag, d_val - Values to be set in new element + * + * exit: + * If an extra DT_NULL slot is available, a debug message is + * issued, the slot is converted to its new use, and the argstate + * block state related to DT_NULL slots is updated. + * + * if no extra DT_NULL slot is present, an error is issued and + * this routine does not return to the caller. + */ +static Word +convert_dt_null(ARGSTATE *argstate, Word d_tag, Xword d_val) +{ + Conv_inv_buf_t inv_buf; + Word ndx; + Dyn *dyn; + + /* If we lack an extra element, we can't continue */ + if (argstate->dyn.num_null_ndx <= 1) + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOEXTRANULL), + EC_WORD(argstate->dyn.sec->sec_shndx), + argstate->dyn.sec->sec_name); + + elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CONVNULL), + EC_WORD(argstate->dyn.sec->sec_shndx), argstate->dyn.sec->sec_name, + EC_WORD(argstate->dyn.null_ndx), conv_dyn_tag(d_tag, + argstate->obj_state->os_ehdr->e_machine, 0, &inv_buf)); + + ndx = argstate->dyn.null_ndx; + dyn = &argstate->dyn.data[ndx]; + dyn->d_tag = d_tag; + dyn->d_un.d_val = d_val; + + /* Recompute the DT_NULL situation */ + set_null_ndx(argstate); + + return (ndx); +} + + +/* + * Standard argument processing for dyn module + * + * entry + * obj_state, argc, argv - Standard command 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[], + ARGSTATE *argstate) +{ + elfedit_getopt_state_t getopt_state; + elfedit_getopt_ret_t *getopt_ret; + + bzero(argstate, sizeof (*argstate)); + argstate->obj_state = obj_state; + + 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; + + /* 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 the dynamic section, and the assocated string table */ + argstate->dyn.sec = elfedit_sec_getdyn(obj_state, &argstate->dyn.data, + &argstate->dyn.num); + argstate->strsec = elfedit_sec_getstr(obj_state, + argstate->dyn.sec->sec_shdr->sh_link); + + /* Index of first DT_NULL */ + set_null_ndx(argstate); +} + + + +/* + * Print ELF header values, taking the calling command, and output style + * into account. + * + * entry: + * cmd - DYN_CMD_T_* value giving identify of caller + * autoprint - If True, output is only produced if the elfedit + * autoprint flag is set. If False, output is always produced. + * argstate - Argument state block + * print_type - Specifies which dynamic elements to display. + * ndx = If print_type is PRINT_DYN_T_NDX, displays the index specified. + * Otherwise ignored. + */ +typedef enum { + PRINT_DYN_T_ALL = 0, /* Show all indexes */ + PRINT_DYN_T_NDX = 1, /* Show dynamic[arg] only */ + PRINT_DYN_T_TAG = 2, /* Show all elts with tag type */ + /* given by arg */ + PRINT_DYN_T_RUNPATH = 3 /* Show all runpath/rpath elts */ + +} PRINT_DYN_T; + +static void +print_dyn(DYN_CMD_T cmd, int autoprint, ARGSTATE *argstate, + PRINT_DYN_T print_type, Word arg) +{ + elfedit_outstyle_t outstyle; + Conv_fmt_flags_t flags_fmt_flags; + Word end_ndx, cnt, ndx, printed = 0; + Dyn *dyn; + int header_done = 0; + Xword last_d_val; + + if (autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0)) + return; + + /* + * Pick an output style. dyn:dump is required to use the default + * style. The other commands use the current output style. + */ + outstyle = (cmd == DYN_CMD_T_DUMP) ? + ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle(); + + /* + * When using the simple output style, omit the + * brackets from around the values. + */ + flags_fmt_flags = (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) ? + CONV_FMT_NOBKT : 0; + + /* How many elements do we examine? */ + if (print_type == PRINT_DYN_T_NDX) { + if (arg >= argstate->dyn.num) + return; /* Out of range */ + ndx = arg; + cnt = 1; + } else { + ndx = 0; + cnt = argstate->dyn.num; + } + + dyn = &argstate->dyn.data[ndx]; + for (; cnt--; dyn++, ndx++) { + union { + Conv_dyn_flag_buf_t flag; + Conv_dyn_flag1_buf_t flag1; + Conv_dyn_posflag1_buf_t posflag1; + Conv_dyn_feature1_buf_t feature1; + } c_buf; + const char *name; + + /* + * If we are only displaying certain tag types and + * this isn't one of those, move on to next element. + */ + switch (print_type) { + case PRINT_DYN_T_TAG: + if (dyn->d_tag != arg) + continue; + break; + case PRINT_DYN_T_RUNPATH: + if ((dyn->d_tag != DT_RPATH) && + (dyn->d_tag != DT_RUNPATH)) + continue; + break; + } + + /* + * Print the information numerically, and if possible + * as a string. + */ + name = NULL; + switch (dyn->d_tag) { + case DT_NULL: + if (!((outstyle == ELFEDIT_OUTSTYLE_DEFAULT) && + (print_type == PRINT_DYN_T_ALL) && + (dyn->d_un.d_val == 0))) + break; + end_ndx = ndx; + /* + * Special case: DT_NULLs can come in groups + * that we prefer to reduce to a single line. + */ + while ((end_ndx < (argstate->dyn.num - 1)) && + ((dyn + 1)->d_tag == DT_NULL) && + ((dyn + 1)->d_un.d_val == 0)) { + dyn++; + end_ndx++; + cnt--; + } + if (header_done == 0) { + header_done = 1; + Elf_dyn_title(0); + } + Elf_dyn_null_entry(0, dyn, ndx, end_ndx); + ndx = end_ndx; + printed = 1; + last_d_val = dyn->d_un.d_val; + continue; + + /* + * Print the information numerically, and if possible + * as a string. + */ + case DT_NEEDED: + case DT_SONAME: + case DT_FILTER: + case DT_AUXILIARY: + case DT_CONFIG: + case DT_RPATH: + case DT_RUNPATH: + case DT_USED: + case DT_DEPAUDIT: + case DT_AUDIT: + case DT_SUNW_AUXILIARY: + case DT_SUNW_FILTER: + name = elfedit_offset_to_str(argstate->strsec, + dyn->d_un.d_val, ELFEDIT_MSG_DEBUG, 0); + break; + + case DT_FLAGS: + name = conv_dyn_flag(dyn->d_un.d_val, + flags_fmt_flags, &c_buf.flag); + break; + case DT_FLAGS_1: + name = conv_dyn_flag1(dyn->d_un.d_val, + flags_fmt_flags, &c_buf.flag1); + break; + case DT_POSFLAG_1: + name = conv_dyn_posflag1(dyn->d_un.d_val, + flags_fmt_flags, &c_buf.posflag1); + break; + case DT_FEATURE_1: + name = conv_dyn_feature1(dyn->d_un.d_val, + flags_fmt_flags, &c_buf.feature1); + break; + case DT_DEPRECATED_SPARC_REGISTER: + name = MSG_INTL(MSG_STR_DEPRECATED); + break; + } + + if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) { + if (header_done == 0) { + header_done = 1; + Elf_dyn_title(0); + } + if (name == NULL) + name = MSG_ORIG(MSG_STR_EMPTY); + Elf_dyn_entry(0, dyn, ndx, name, + argstate->obj_state->os_ehdr->e_machine); + } else { + /* + * In simple or numeric mode under a print type + * that is based on tag type rather than on index, + * quietly: If we've already printed this value, + * don't print it again. A common example of this + * is PRINT_DYN_T_RUNPATH when both DT_RPATH and + * DT_RUNPATH are present with the same value. + */ + switch (print_type) { + case PRINT_DYN_T_TAG: + case PRINT_DYN_T_RUNPATH: + if (printed && (last_d_val == dyn->d_un.d_val)) + continue; + } + + if ((name != NULL) && + (outstyle == ELFEDIT_OUTSTYLE_SIMPLE)) { + elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), name); + } else { + elfedit_printf(MSG_ORIG(MSG_FMT_HEXXWORDNL), + dyn->d_un.d_val); + } + } + printed = 1; + last_d_val = dyn->d_un.d_val; + } + + /* + * If nothing was output under the print types that are + * based on tag type, issue an error saying it doesn't exist. + */ + if (!printed) { + if (print_type == PRINT_DYN_T_TAG) { + Conv_inv_buf_t inv_buf; + + elfedit_msg(ELFEDIT_MSG_ERR, + MSG_INTL(MSG_ERR_NODYNELT), + EC_WORD(argstate->dyn.sec->sec_shndx), + argstate->dyn.sec->sec_name, conv_dyn_tag(arg, + argstate->obj_state->os_ehdr->e_machine, + 0, &inv_buf)); + } + + if (print_type == PRINT_DYN_T_RUNPATH) + elfedit_msg(ELFEDIT_MSG_ERR, + MSG_INTL(MSG_ERR_NORUNPATH), + EC_WORD(argstate->dyn.sec->sec_shndx), + argstate->dyn.sec->sec_name); + } +} + + +/* + * Process the elt argument: This will be a tag type if -dynndx is + * not present and this is a print request. It will be an index otherwise. + * + * entry: + * argstate - Argument state block + * arg - Argument string to be converted into an index + * argname - String giving the name by which the argument is + * referred in the online help for the command. + * print_request - True if the command is to print the current + * value(s) and return without changing anything. + * print_type - Address of variable containing PRINT_DYN_T_ + * code specifying how the elements will be displayed. + * + * exit: + * If print_request is False: arg is converted into an integer value. + * If -dynndx was used, we convert it into an integer. If it was not + * used, then arg is a tag name --- we find the first dynamic entry + * that matches. If no entry matches, and there is an extra DT_NULL, + * it is added. Otherwise an error is issued. *print_type is set + * to PRINT_DYN_T_NDX. + * + * If print_request is True: If -dynndx was used, arg is converted into + * an integer value, *print_type is set to PRINT_DYN_T_NDX, and + * the value is returned. If -dynndx was not used, *print_type is set to + * PRINT_DYN_T_TAG, and the tag value is returned. + */ +static Word +arg_to_index(ARGSTATE *argstate, const char *arg, const char *argname, + int print_request, PRINT_DYN_T *print_type) +{ + Word ndx, dt_value; + + + /* Assume we are returning an index, alter as needed below */ + *print_type = PRINT_DYN_T_NDX; + + /* If -dynndx was used, this is a simple numeric index */ + if ((argstate->optmask & DYN_OPT_F_DYNNDX) != 0) + return ((Word) elfedit_atoui_range(arg, argname, 0, + argstate->dyn.num - 1, NULL)); + + /* The argument is a DT_ tag type, not a numeric index */ + dt_value = (Word) elfedit_atoconst(arg, ELFEDIT_CONST_DT); + + /* + * If this is a printing request, then we let print_dyn() show + * all the items with this tag type. + */ + if (print_request) { + *print_type = PRINT_DYN_T_TAG; + return (dt_value); + } + + /* Locate the first entry with the given tag type */ + for (ndx = 0; ndx < argstate->dyn.num; ndx++) { + if (argstate->dyn.data[ndx].d_tag == dt_value) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_DT2NDX), + EC_WORD(argstate->dyn.sec->sec_shndx), + argstate->dyn.sec->sec_name, EC_WORD(ndx), arg); + return (ndx); + } + } + + /* Not found. Can we create one? */ + if (argstate->dyn.num_null_ndx > 1) + return (convert_dt_null(argstate, dt_value, 0)); + + /* No room to create one, so we're out of options and must fail */ + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NODTELT), + EC_WORD(argstate->dyn.sec->sec_shndx), + argstate->dyn.sec->sec_name, arg); + + /*NOTREACHED*/ + return (0); /* For lint */ +} + + +/* + * Called by cmd_body() for dyn:value. Implements the core functionality + * for that command. + * + * This routine expects that both the index and value arguments are + * present. + */ +static elfedit_cmdret_t +cmd_body_value(ARGSTATE *argstate, Word *ret_ndx) +{ + elfedit_section_t *dynsec = argstate->dyn.sec; + elfedit_section_t *strsec = argstate->strsec; + elfedit_dyn_elt_t strpad_elt; + Word i; + Dyn *dyn = argstate->dyn.data; + Word numdyn = argstate->dyn.num; + int minus_add = ((argstate->optmask & DYN_OPT_F_ADD) != 0); + int minus_s = ((argstate->optmask & DYN_OPT_F_STRVAL) != 0); + int minus_dynndx = ((argstate->optmask & DYN_OPT_F_DYNNDX) != 0); + Word arg1, tmp_val; + Xword arg2; + int arg2_known = 1; + + + elfedit_dyn_elt_init(&strpad_elt); + + /* + * The first argument is an index if -dynndx is used, and is a + * tag value otherwise. + */ + arg1 = minus_dynndx ? + elfedit_atoui_range(argstate->argv[0], MSG_ORIG(MSG_STR_ELT), + 0, numdyn - 1, NULL) : + elfedit_atoconst(argstate->argv[0], ELFEDIT_CONST_DT); + + if (minus_s) { + /* + * Don't allow the user to specify -s when manipulating a + * DT_SUNW_STRPAD element. Since DT_SUNW_STRPAD is used to + * manage the extra space used for strings, this would break + * our ability to add the string. + */ + if ((!minus_dynndx && (arg1 == DT_SUNW_STRPAD)) || + (minus_dynndx && (dyn[arg1].d_tag == DT_SUNW_STRPAD))) + elfedit_msg(ELFEDIT_MSG_ERR, + MSG_INTL(MSG_ERR_STRPADSTRVAL), + EC_WORD(dynsec->sec_shndx), dynsec->sec_name); + + /* Locate DT_SUNW_STRPAD element if present */ + strpad_elt.dn_dyn.d_un.d_val = 0; + (void) elfedit_dynstr_getpad(argstate->dyn.sec, &strpad_elt); + + /* + * Look up the string: If the user specified the -dynndx + * -option, then we will insert it if possible, and + * fail with an error if not. However, if they did not + * specify -dynndx, we want to look up the string if it is + * already there, but defer the insertion. The reason for + * this is that we may have to grab an unused DT_NULL element + * below, and if there are none available, we won't want + * to have modified the string table. + * + * This isn't a problem, because if the string isn't + * in the string table, it can't be used by a dynamic element. + * Hence, we don't need to insert it to know that there is + * no match. + */ + if (minus_dynndx == 0) { + if (elfedit_sec_findstr(strsec, + strpad_elt.dn_dyn.d_un.d_val, argstate->argv[1], + &tmp_val) == 0) { + arg2_known = 0; + } else { + arg2 = tmp_val; + } + } else { + arg2 = elfedit_dynstr_insert(dynsec, strsec, + &strpad_elt, argstate->argv[1]); + } + } else { /* Argument 2 is an integer */ + arg2 = elfedit_atoui(argstate->argv[1], NULL); + } + + + if (!minus_dynndx && !(minus_add && !arg2_known)) { + /* + * Search the dynamic section and see if an item with the + * specified tag value already exists. We can reduce this + * to a simple update of an existing value if -add is not + * specified or the existing d_un value matches the new one. + * + * In either of these cases, we will change arg1 to be the + * index, and set minus_dynndx, causing the simple update to + * happen immediately below. + */ + for (i = 0; i < numdyn; i++) { + if ((dyn[i].d_tag == arg1) && + (!minus_add || (dyn[i].d_un.d_val == arg2))) { + arg1 = i; + minus_dynndx = 1; + break; + } + } + } + + /* + * If -dynndx is used, then this is a relatively simple + * operation, as we simply write over the specified index. + */ + if (minus_dynndx) { + /* + * If we held back from inserting a new string into + * the dynstr above, we insert it now, because we + * have a slot in the dynamic section, and we need + * the string offset ot finish. + */ + if (!arg2_known) + arg2 = elfedit_dynstr_insert(dynsec, strsec, + &strpad_elt, argstate->argv[1]); + + *ret_ndx = arg1; + if (dyn[arg1].d_un.d_val == arg2) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_X_OK), + dynsec->sec_shndx, dynsec->sec_name, + EC_WORD(arg1), EC_XWORD(arg2)); + return (ELFEDIT_CMDRET_NONE); + } else { + /* Warn if setting DT_NULL value to non-zero */ + if ((dyn[arg1].d_tag == DT_NULL) && (arg2 != 0)) + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_DTNULLVALUE), + dynsec->sec_shndx, dynsec->sec_name, + EC_WORD(arg1), EC_XWORD(arg2)); + + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_X_CHG), + dynsec->sec_shndx, dynsec->sec_name, + EC_WORD(arg1), EC_XWORD(dyn[arg1].d_un.d_val), + EC_XWORD(arg2)); + dyn[arg1].d_un.d_val = arg2; + return (ELFEDIT_CMDRET_MOD); + } + } + + /* + * We need a new slot in the dynamic section. If we can't have + * one, then we fail. + */ + if (argstate->dyn.num_null_ndx <= 1) + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOEXTRANULL), + EC_WORD(dynsec->sec_shndx), dynsec->sec_name); + + /* + * If we still need to insert a new string into the dynstr, + * then it is safe now, because if we succeed, we know that + * there is an available slot to receive it. If we fail, we + * haven't claimed the extra slot yet, and it will be unharmed. + */ + if (!arg2_known) + arg2 = elfedit_dynstr_insert(dynsec, strsec, + &strpad_elt, argstate->argv[1]); + + /* Use an extra DT_NULL slot and enter the new element */ + *ret_ndx = convert_dt_null(argstate, arg1, arg2); + return (ELFEDIT_CMDRET_MOD); +} + + + +/* + * Called by cmd_body() for dyn:runpath. Implements the core functionality + * for that command. + * + * History Lesson And Strategy: + * + * This routine handles both DT_RPATH and DT_RUNPATH entries, altering + * either or both if they are present. + * + * The original SYSV ABI only had DT_RPATH, and the runtime loader used + * it to search for things in the following order: + * + * DT_RPATH, LD_LIBRARY_PATH, defaults + * + * Solaris did not follow this rule, an extremely rare deviation from + * the ABI. Environment variables should supercede everything else, + * otherwise they are not very useful. This decision was made at the + * very beginning of the SunOS 5.x development, so we have always + * deviated from the ABI and and instead search in the order + * + * LD_LIBRARY_PATH, DT_RPATH, defaults + * + * Other Unix variants initially followed the ABI, but in recent years + * have come to agree with the early Solaris folks that it was a mistake. + * Hence, DT_RUNPATH was invented, with the search order: + * + * LD_LIBRARY_PATH, DT_RUNPATH, defaults + * + * So for Solaris, DT_RPATH and DT_RUNPATH mean the same thing. If both + * are present (which does happen), we set them both to the new + * value. If either one is present, we set that one. If neither is + * present, and we have a spare DT_NULL slot, we create a DT_RUNPATH, but + * not a DT_RPATH, to conserve available slots for other uses. + */ +static elfedit_cmdret_t +cmd_body_runpath(ARGSTATE *argstate) +{ + elfedit_section_t *dynsec = argstate->dyn.sec; + elfedit_section_t *strsec = argstate->strsec; + elfedit_dyn_elt_t rpath_elt; + elfedit_dyn_elt_t runpath_elt; + elfedit_dyn_elt_t strpad_elt; + Word i; + Dyn *dyn = argstate->dyn.data; + Word numdyn = argstate->dyn.num; + + /* Go through the tags and gather what we need */ + elfedit_dyn_elt_init(&rpath_elt); + elfedit_dyn_elt_init(&runpath_elt); + elfedit_dyn_elt_init(&strpad_elt); + for (i = 0; i < numdyn; i++) { + switch (dyn[i].d_tag) { + case DT_RPATH: + elfedit_dyn_elt_save(&rpath_elt, i, &dyn[i]); + break; + + case DT_RUNPATH: + elfedit_dyn_elt_save(&runpath_elt, i, &dyn[i]); + break; + + case DT_SUNW_STRPAD: + elfedit_dyn_elt_save(&strpad_elt, i, &dyn[i]); + break; + } + } + + /* Do we have an available dynamic section entry to use? */ + if (rpath_elt.dn_seen || runpath_elt.dn_seen) { + /* + * We have seen a DT_RPATH, or a DT_RUNPATH, or both. + * If all of these have the same string as the desired + * new value, then we don't need to alter anything and can + * simply return. Otherwise, we'll modify them all to have + * the new string (below). + */ + if ((!rpath_elt.dn_seen || + (strcmp(elfedit_dyn_offset_to_str(strsec, &rpath_elt), + argstate->argv[0]) == 0)) && + (!runpath_elt.dn_seen || + (strcmp(elfedit_dyn_offset_to_str(strsec, &runpath_elt), + argstate->argv[0]) == 0))) { + if (rpath_elt.dn_seen) + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_OLDRPATHOK), + EC_WORD(dynsec->sec_shndx), + dynsec->sec_name, EC_WORD(rpath_elt.dn_ndx), + elfedit_atoconst_value_to_str( + ELFEDIT_CONST_DT, DT_RPATH, 1)); + if (runpath_elt.dn_seen) + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_OLDRPATHOK), + EC_WORD(dynsec->sec_shndx), + dynsec->sec_name, + EC_WORD(runpath_elt.dn_ndx), + elfedit_atoconst_value_to_str( + ELFEDIT_CONST_DT, DT_RUNPATH, 1)); + return (ELFEDIT_CMDRET_NONE); + } + } else if (argstate->dyn.num_null_ndx <= 1) { + /* + * There is no DT_RPATH or DT_RUNPATH in the dynamic array, + * and there are no extra DT_NULL entries that we can + * convert into one. We cannot proceed. + */ + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOEXTRANULL), + EC_WORD(dynsec->sec_shndx), dynsec->sec_name); + } + + /* Does the string exist in the table already, or can we add it? */ + rpath_elt.dn_dyn.d_un.d_val = runpath_elt.dn_dyn.d_un.d_val = + elfedit_dynstr_insert(dynsec, strsec, &strpad_elt, + argstate->argv[0]); + + /* Update DT_RPATH entry if present */ + if (rpath_elt.dn_seen) { + elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_PREVRPATH), + EC_WORD(dynsec->sec_shndx), dynsec->sec_name, + EC_WORD(rpath_elt.dn_ndx), + elfedit_atoconst_value_to_str( + ELFEDIT_CONST_DT, DT_RPATH, 1), + elfedit_dyn_offset_to_str(strsec, &rpath_elt)); + dyn[rpath_elt.dn_ndx] = rpath_elt.dn_dyn; + } + + /* + * Update the DT_RUNPATH entry in the dynamic section, if present. + * If one is not present, and there is also no DT_RPATH, then + * we use a spare DT_NULL entry to create a new DT_RUNPATH. + */ + if (runpath_elt.dn_seen || !rpath_elt.dn_seen) { + if (runpath_elt.dn_seen) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_PREVRPATH), + EC_WORD(dynsec->sec_shndx), dynsec->sec_name, + EC_WORD(runpath_elt.dn_ndx), + elfedit_atoconst_value_to_str( + ELFEDIT_CONST_DT, DT_RUNPATH, 1), + elfedit_dyn_offset_to_str(strsec, &runpath_elt)); + dyn[runpath_elt.dn_ndx] = runpath_elt.dn_dyn; + } else { /* Using a spare DT_NULL entry */ + (void) convert_dt_null(argstate, DT_RUNPATH, + runpath_elt.dn_dyn.d_un.d_val); + } + } + + return (ELFEDIT_CMDRET_MOD); +} + + + +/* + * Argument processing for the bitmask commands. Convert the arguments + * to integer form, apply -and/-cmp/-or, and return the resulting value. + * + * entry: + * argstate - Argument state block + * orig - Value of original bitmask + * const_type - ELFEDIT_CONST_* value for type of constants + */ +static Word +flag_bitop(ARGSTATE *argstate, Word orig, elfedit_const_t const_type) +{ + Word flags = 0; + int i; + + /* Collect the arguments */ + for (i = 0; i < argstate->argc; i++) + flags |= (Word) elfedit_atoconst(argstate->argv[i], const_type); + + /* Complement the value? */ + if (argstate->optmask & DYN_OPT_F_CMP) + flags = ~flags; + + /* Perform any requested bit operations */ + if (argstate->optmask & DYN_OPT_F_AND) + flags &= orig; + else if (argstate->optmask & DYN_OPT_F_OR) + flags |= orig; + + return (flags); +} + + + +/* + * Common body for the dyn: 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 DYN_CMD_T_* constants listed above, specifying + * which command to implement. + * obj_state, argc, argv - Standard command arguments + */ +static elfedit_cmdret_t +cmd_body(DYN_CMD_T cmd, elfedit_obj_state_t *obj_state, + int argc, const char *argv[]) +{ + ARGSTATE argstate; + Dyn *dyn; + const char *dyn_name; + Word dyn_ndx, dyn_num, null_ndx; + elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE; + PRINT_DYN_T print_type = PRINT_DYN_T_ALL; + Word ndx; + int print_only = 0; + int do_autoprint = 1; + + /* Process the optional arguments */ + process_args(obj_state, argc, argv, &argstate); + + dyn = argstate.dyn.data; + dyn_num = argstate.dyn.num; + dyn_name = argstate.dyn.sec->sec_name; + dyn_ndx = argstate.dyn.sec->sec_shndx; + + /* Check number of arguments, gather information */ + switch (cmd) { + case DYN_CMD_T_DUMP: + /* dyn:dump can accept an optional index argument */ + if (argstate.argc > 1) + elfedit_command_usage(); + print_only = 1; + if (argstate.argc == 1) + ndx = arg_to_index(&argstate, argstate.argv[0], + MSG_ORIG(MSG_STR_ELT), print_only, &print_type); + break; + + case DYN_CMD_T_TAG: + print_only = (argstate.argc != 2); + if (argstate.argc > 0) { + if (argstate.argc > 2) + elfedit_command_usage(); + ndx = arg_to_index(&argstate, argstate.argv[0], + MSG_ORIG(MSG_STR_ELT), print_only, &print_type); + } + break; + + case DYN_CMD_T_VALUE: + print_only = (argstate.argc != 2); + if (argstate.argc > 2) + elfedit_command_usage(); + if (argstate.argc > 0) { + if (print_only) { + ndx = arg_to_index(&argstate, argstate.argv[0], + MSG_ORIG(MSG_STR_ELT), + print_only, &print_type); + } else { + print_type = PRINT_DYN_T_NDX; + } + } + break; + + case DYN_CMD_T_DELETE: + if ((argstate.argc < 1) || (argstate.argc > 2)) + elfedit_command_usage(); + ndx = arg_to_index(&argstate, argstate.argv[0], + MSG_ORIG(MSG_STR_ELT), + 0, &print_type); + do_autoprint = 0; + break; + + case DYN_CMD_T_MOVE: + if ((argstate.argc < 2) || (argstate.argc > 3)) + elfedit_command_usage(); + ndx = arg_to_index(&argstate, argstate.argv[0], + MSG_ORIG(MSG_STR_ELT), 0, &print_type); + do_autoprint = 0; + break; + + case DYN_CMD_T_RUNPATH: + if (argstate.argc > 1) + elfedit_command_usage(); + /* + * dyn:runpath does not accept an explicit index + * argument, so we implicitly only show the DT_RPATH and + * DT_RUNPATH elements. + */ + print_type = PRINT_DYN_T_RUNPATH; + print_only = (argstate.argc == 0); + break; + + case DYN_CMD_T_POSFLAG1: + print_only = (argstate.argc == 0); + ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str( + ELFEDIT_CONST_DT, DT_POSFLAG_1, 1), + MSG_ORIG(MSG_STR_VALUE), print_only, &print_type); + break; + + case DYN_CMD_T_FLAGS: + print_only = (argstate.argc == 0); + ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str( + ELFEDIT_CONST_DT, DT_FLAGS, 1), + MSG_ORIG(MSG_STR_VALUE), print_only, &print_type); + break; + + case DYN_CMD_T_FLAGS1: + print_only = (argstate.argc == 0); + ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str( + ELFEDIT_CONST_DT, DT_FLAGS_1, 1), + MSG_ORIG(MSG_STR_VALUE), print_only, &print_type); + break; + + case DYN_CMD_T_FEATURE1: + print_only = (argstate.argc == 0); + ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str( + ELFEDIT_CONST_DT, DT_FEATURE_1, 1), + MSG_ORIG(MSG_STR_VALUE), print_only, &print_type); + break; + + case DYN_CMD_T_CHECKSUM: + ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str( + ELFEDIT_CONST_DT, DT_CHECKSUM, 1), + MSG_ORIG(MSG_STR_VALUE), print_only, &print_type); + break; + + default: + /* Note expected: All commands should have been caught above */ + elfedit_command_usage(); + break; + } + + + /* If this is a request to print current values, do it and return */ + if (print_only) { + print_dyn(cmd, 0, &argstate, print_type, ndx); + return (ELFEDIT_CMDRET_NONE); + } + + + switch (cmd) { + /* + * DYN_CMD_T_DUMP can't get here: It is a print-only + * command. + */ + + case DYN_CMD_T_TAG: + { + Conv_inv_buf_t inv_buf1, inv_buf2; + Half mach = argstate.obj_state->os_ehdr->e_machine; + Word d_tag = (Word) elfedit_atoconst(argstate.argv[1], + ELFEDIT_CONST_DT); + + if (dyn[ndx].d_tag == d_tag) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_S_OK), + dyn_ndx, + dyn_name, EC_WORD(ndx), + conv_dyn_tag(d_tag, mach, 0, &inv_buf1)); + } else { + Word orig_d_tag = dyn[ndx].d_tag; + + ret = ELFEDIT_CMDRET_MOD; + dyn[ndx].d_tag = d_tag; + + /* + * Update null termination index. Warn if we + * just clobbered the only DT_NULL termination + * for the array. + */ + null_ndx = argstate.dyn.null_ndx; + set_null_ndx(&argstate); + if ((argstate.dyn.null_ndx >= + argstate.dyn.num) && + (null_ndx != argstate.dyn.null_ndx)) + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_NULLTERM), + dyn_ndx, dyn_name, + EC_WORD(ndx), + conv_dyn_tag(d_tag, mach, + 0, &inv_buf1)); + + /* + * Warning if + * - Inserting a DT_NULL cuts off following + * non-null elements. + * - Inserting a non-DT_NULL after the + * first null element, will be + * ignored by rtld. + */ + if (d_tag == DT_NULL) { + if ((ndx + 1) < null_ndx) + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_NULCLIP), + dyn_ndx, dyn_name, + EC_WORD(ndx), + conv_dyn_tag(d_tag, mach, + 0, &inv_buf1)); + } else { + if ((ndx + 1) > argstate.dyn.null_ndx) + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_NULHIDE), + dyn_ndx, dyn_name, + EC_WORD(ndx), + conv_dyn_tag(d_tag, mach, + 0, &inv_buf1)); + } + + /* Debug message that we changed it */ + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_S_CHG), + dyn_ndx, dyn_name, EC_WORD(ndx), + conv_dyn_tag(orig_d_tag, mach, 0, + &inv_buf1), + conv_dyn_tag(d_tag, mach, 0, &inv_buf2)); + } + } + break; + + case DYN_CMD_T_VALUE: + ret = cmd_body_value(&argstate, &ndx); + break; + + case DYN_CMD_T_DELETE: + { + Word cnt = (argstate.argc == 1) ? 1 : + (Word) elfedit_atoui_range(argstate.argv[1], + MSG_ORIG(MSG_STR_COUNT), 1, dyn_num - ndx, NULL); + const char *msg_prefix = + elfedit_sec_msgprefix(argstate.dyn.sec); + + elfedit_array_elts_delete(msg_prefix, argstate.dyn.data, + sizeof (Dyn), dyn_num, ndx, cnt); + ret = ELFEDIT_CMDRET_MOD; + } + break; + + case DYN_CMD_T_MOVE: + { + Dyn save; + Word cnt; + Word dstndx; + const char *msg_prefix = + elfedit_sec_msgprefix(argstate.dyn.sec); + + dstndx = (Word) + elfedit_atoui_range(argstate.argv[1], + MSG_ORIG(MSG_STR_DST_INDEX), 0, dyn_num - 1, + NULL); + if (argstate.argc == 2) { + cnt = 1; + } else { + cnt = (Word) elfedit_atoui_range( + argstate.argv[2], MSG_ORIG(MSG_STR_COUNT), + 1, dyn_num, NULL); + } + elfedit_array_elts_move(msg_prefix, argstate.dyn.data, + sizeof (save), dyn_num, ndx, dstndx, cnt, &save); + ret = ELFEDIT_CMDRET_MOD; + } + break; + + + case DYN_CMD_T_RUNPATH: + ret = cmd_body_runpath(&argstate); + break; + + case DYN_CMD_T_POSFLAG1: + { + Conv_dyn_posflag1_buf_t buf1, buf2; + Word flags; + + flags = flag_bitop(&argstate, dyn[ndx].d_un.d_val, + ELFEDIT_CONST_DF_P1); + + /* Set the value */ + if (dyn[ndx].d_un.d_val == flags) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_S_OK), dyn_ndx, + dyn_name, EC_WORD(ndx), + conv_dyn_posflag1(dyn[ndx].d_un.d_val, 0, + &buf1)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_S_CHG), + dyn_ndx, dyn_name, EC_WORD(ndx), + conv_dyn_posflag1(dyn[ndx].d_un.d_val, 0, + &buf1), + conv_dyn_posflag1(flags, 0, &buf2)); + ret = ELFEDIT_CMDRET_MOD; + dyn[ndx].d_un.d_val = flags; + } + } + break; + + case DYN_CMD_T_FLAGS: + { + Conv_dyn_flag_buf_t buf1, buf2; + Word flags; + + flags = flag_bitop(&argstate, dyn[ndx].d_un.d_val, + ELFEDIT_CONST_DF); + + /* Set the value */ + if (dyn[ndx].d_un.d_val == flags) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_S_OK), dyn_ndx, + dyn_name, EC_WORD(ndx), + conv_dyn_flag(dyn[ndx].d_un.d_val, 0, + &buf1)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_S_CHG), + dyn_ndx, dyn_name, EC_WORD(ndx), + conv_dyn_flag(dyn[ndx].d_un.d_val, 0, + &buf1), + conv_dyn_flag(flags, 0, &buf2)); + ret = ELFEDIT_CMDRET_MOD; + dyn[ndx].d_un.d_val = flags; + } + } + break; + + case DYN_CMD_T_FLAGS1: + { + Conv_dyn_flag1_buf_t buf1, buf2; + Word flags1; + + flags1 = flag_bitop(&argstate, dyn[ndx].d_un.d_val, + ELFEDIT_CONST_DF_1); + + /* Set the value */ + if (dyn[ndx].d_un.d_val == flags1) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_S_OK), dyn_ndx, + dyn_name, EC_WORD(ndx), + conv_dyn_flag1(dyn[ndx].d_un.d_val, + 0, &buf1)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_S_CHG), + dyn_ndx, dyn_name, EC_WORD(ndx), + conv_dyn_flag1(dyn[ndx].d_un.d_val, + 0, &buf1), + conv_dyn_flag1(flags1, 0, &buf2)); + ret = ELFEDIT_CMDRET_MOD; + dyn[ndx].d_un.d_val = flags1; + } + } + break; + + case DYN_CMD_T_FEATURE1: + { + Conv_dyn_feature1_buf_t buf1, buf2; + Word flags; + + flags = flag_bitop(&argstate, dyn[ndx].d_un.d_val, + ELFEDIT_CONST_DTF_1); + + /* Set the value */ + if (dyn[ndx].d_un.d_val == flags) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_S_OK), dyn_ndx, + dyn_name, EC_WORD(ndx), + conv_dyn_feature1(dyn[ndx].d_un.d_val, 0, + &buf1)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_S_CHG), + dyn_ndx, dyn_name, EC_WORD(ndx), + conv_dyn_feature1(dyn[ndx].d_un.d_val, 0, + &buf1), + conv_dyn_feature1(flags, 0, &buf2)); + ret = ELFEDIT_CMDRET_MOD; + dyn[ndx].d_un.d_val = flags; + } + } + break; + + case DYN_CMD_T_CHECKSUM: + { + long checksum = elf_checksum(obj_state->os_elf); + + /* Set the value */ + if (dyn[ndx].d_un.d_val == checksum) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_X_OK), dyn_ndx, + dyn_name, EC_WORD(ndx), EC_XWORD(checksum)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_X_CHG), + dyn_ndx, dyn_name, EC_WORD(ndx), + EC_XWORD(dyn[ndx].d_un.d_val), + EC_XWORD(checksum)); + ret = ELFEDIT_CMDRET_MOD; + dyn[ndx].d_un.d_val = checksum; + } + + } + } + + /* + * If we modified the dynamic section header, tell libelf. + */ + if (ret == ELFEDIT_CMDRET_MOD) + elfedit_modified_data(argstate.dyn.sec); + + /* Do autoprint */ + if (do_autoprint) + print_dyn(cmd, 1, &argstate, print_type, ndx); + + return (ret); +} + + + +/* + * Command completion functions for the commands + */ + +/* + * Command completion for the first argument, which specifies + * the dynamic element to use. Examines the options to see if + * -dynndx is present, and if not, supplies the completion + * strings for argument 1. + */ +/*ARGSUSED*/ +static void +cpl_eltarg(elfedit_obj_state_t *obj_state, void *cpldata, int argc, + const char *argv[], int num_opt) +{ + elfedit_section_t *cache; + Dyn *dyn; + Word i; + const char *s; + char *s2; + char buf[128]; + + /* Make sure it's the first argument */ + if ((argc - num_opt) != 1) + return; + + /* Is -dynndx present? If so, we don't complete tag types */ + for (i = 0; i < num_opt; i++) + if (strcmp(argv[i], MSG_ORIG(MSG_STR_MINUS_DYNNDX)) == 0) + return; + + /* + * If there is no object, or if there is no dynamic section, + * then supply all possible names. + */ + if ((obj_state == NULL) || (obj_state->os_dynndx == SHN_UNDEF)) { + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DT); + return; + } + + /* Supply completions for the tags present in the dynamic section */ + cache = &obj_state->os_secarr[obj_state->os_dynndx]; + dyn = (Dyn *) cache->sec_data->d_buf; + i = cache->sec_shdr->sh_size / cache->sec_shdr->sh_entsize; + for (; i-- > 0; dyn++) { + s = elfedit_atoconst_value_to_str(ELFEDIT_CONST_DT, + dyn->d_tag, 0); + if (s == NULL) + continue; + elfedit_cpl_match(cpldata, s, 1); + + /* + * To get the informal tag names that are lowercase + * and lack the leading DT_, we copy the string we + * have into a buffer and process it. + */ + if (strlen(s) < 3) + continue; + (void) strlcpy(buf, s + 3, sizeof (buf)); + for (s2 = buf; *s2 != '\0'; s2++) + if (isupper(*s2)) + *s2 = tolower(*s2); + elfedit_cpl_match(cpldata, buf, 1); + } +} + + +/*ARGSUSED*/ +static void +cpl_tag(elfedit_obj_state_t *obj_state, void *cpldata, int argc, + const char *argv[], int num_opt) +{ + /* First argument */ + if ((argc - num_opt) == 1) { + cpl_eltarg(obj_state, cpldata, argc, argv, num_opt); + return; + } + + /* The second argument is always a tag value */ + if ((argc - num_opt) == 2) + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DT); +} + +/*ARGSUSED*/ +static void +cpl_posflag1(elfedit_obj_state_t *obj_state, void *cpldata, int argc, + const char *argv[], int num_opt) +{ + /* This routine allows multiple flags to be specified */ + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DF_P1); +} + +/*ARGSUSED*/ +static void +cpl_flags(elfedit_obj_state_t *obj_state, void *cpldata, int argc, + const char *argv[], int num_opt) +{ + /* This routine allows multiple flags to be specified */ + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DF); +} + +/*ARGSUSED*/ +static void +cpl_flags1(elfedit_obj_state_t *obj_state, void *cpldata, int argc, + const char *argv[], int num_opt) +{ + /* This routine allows multiple flags to be specified */ + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DF_1); +} + +/*ARGSUSED*/ +static void +cpl_feature1(elfedit_obj_state_t *obj_state, void *cpldata, int argc, + const char *argv[], int num_opt) +{ + /* This routine allows multiple flags to be specified */ + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DTF_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(DYN_CMD_T_DUMP, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_tag(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(DYN_CMD_T_TAG, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_value(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(DYN_CMD_T_VALUE, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_delete(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(DYN_CMD_T_DELETE, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_move(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(DYN_CMD_T_MOVE, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_runpath(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(DYN_CMD_T_RUNPATH, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_posflag1(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(DYN_CMD_T_POSFLAG1, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_flags(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(DYN_CMD_T_FLAGS, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_flags1(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(DYN_CMD_T_FLAGS1, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_feature1(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(DYN_CMD_T_FEATURE1, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_checksum(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(DYN_CMD_T_CHECKSUM, obj_state, argc, argv)); +} + + + +/*ARGSUSED*/ +elfedit_module_t * +elfedit_init(elfedit_module_version_t version) +{ + /* For commands that only accept -o */ + static elfedit_cmd_optarg_t opt_ostyle[] = { + { ELFEDIT_STDOA_OPT_O, NULL, + ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, + { NULL } + }; + + /* For commands that only accept -and, -cmp, -o, -or */ + static elfedit_cmd_optarg_t opt_ostyle_bitop[] = { + { ELFEDIT_STDOA_OPT_AND, NULL, + ELFEDIT_CMDOA_F_INHERIT, DYN_OPT_F_AND, DYN_OPT_F_OR }, + { ELFEDIT_STDOA_OPT_CMP, NULL, + ELFEDIT_CMDOA_F_INHERIT, DYN_OPT_F_CMP, 0 }, + { ELFEDIT_STDOA_OPT_O, NULL, + ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, + { ELFEDIT_STDOA_OPT_OR, NULL, + ELFEDIT_CMDOA_F_INHERIT, DYN_OPT_F_OR, DYN_OPT_F_AND }, + { NULL } + }; + + /* For commands that only accept -dynndx */ + static elfedit_cmd_optarg_t opt_minus_dynndx[] = { + { MSG_ORIG(MSG_STR_MINUS_DYNNDX), + /* MSG_INTL(MSG_OPTDESC_DYNNDX) */ + ELFEDIT_I18NHDL(MSG_OPTDESC_DYNNDX), 0, + DYN_OPT_F_DYNNDX, 0 }, + { NULL } + }; + + /* dyn: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 arg_dump[] = { + { MSG_ORIG(MSG_STR_ELT), + /* MSG_INTL(MSG_ARGDESC_ELT) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_ELT), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + + /* dyn:tag */ + static const char *name_tag[] = { MSG_ORIG(MSG_CMD_TAG), NULL }; + static elfedit_cmd_optarg_t opt_tag[] = { + { MSG_ORIG(MSG_STR_MINUS_DYNNDX), + /* MSG_INTL(MSG_OPTDESC_DYNNDX) */ + ELFEDIT_I18NHDL(MSG_OPTDESC_DYNNDX), 0, + DYN_OPT_F_DYNNDX, 0 }, + { ELFEDIT_STDOA_OPT_O, NULL, + ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, + { NULL } + }; + static elfedit_cmd_optarg_t arg_tag[] = { + { MSG_ORIG(MSG_STR_ELT), + /* MSG_INTL(MSG_A1_TAG_ELT) */ + ELFEDIT_I18NHDL(MSG_A1_TAG_ELT), + ELFEDIT_CMDOA_F_OPT }, + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_A2_TAG_VALUE) */ + ELFEDIT_I18NHDL(MSG_A2_TAG_VALUE), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + + /* dyn:value */ + static const char *name_value[] = { MSG_ORIG(MSG_CMD_VALUE), NULL }; + static elfedit_cmd_optarg_t opt_value[] = { + { MSG_ORIG(MSG_STR_MINUS_ADD), + /* MSG_INTL(MSG_OPTDESC_ADD) */ + ELFEDIT_I18NHDL(MSG_OPTDESC_ADD), 0, + DYN_OPT_F_ADD, DYN_OPT_F_DYNNDX }, + { MSG_ORIG(MSG_STR_MINUS_DYNNDX), + /* MSG_INTL(MSG_OPTDESC_DYNNDX) */ + ELFEDIT_I18NHDL(MSG_OPTDESC_DYNNDX), 0, + DYN_OPT_F_DYNNDX, DYN_OPT_F_ADD }, + { ELFEDIT_STDOA_OPT_O, NULL, + ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, + { MSG_ORIG(MSG_STR_MINUS_S), + /* MSG_INTL(MSG_OPTDESC_S) */ + ELFEDIT_I18NHDL(MSG_OPTDESC_S), 0, + DYN_OPT_F_STRVAL, 0 }, + { NULL } + }; + static elfedit_cmd_optarg_t arg_value[] = { + { MSG_ORIG(MSG_STR_ELT), + /* MSG_INTL(MSG_ARGDESC_ELT) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_ELT), + ELFEDIT_CMDOA_F_OPT }, + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_A2_VALUE_VALUE) */ + ELFEDIT_I18NHDL(MSG_A2_VALUE_VALUE), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + /* dyn:delete */ + static const char *name_delete[] = { MSG_ORIG(MSG_CMD_DELETE), NULL }; + static elfedit_cmd_optarg_t arg_delete[] = { + { MSG_ORIG(MSG_STR_ELT), + /* MSG_INTL(MSG_ARGDESC_ELT) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_ELT), + 0 }, + { MSG_ORIG(MSG_STR_COUNT), + /* MSG_INTL(MSG_A2_DELETE_COUNT) */ + ELFEDIT_I18NHDL(MSG_A2_DELETE_COUNT), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + /* dyn:move */ + static const char *name_move[] = { MSG_ORIG(MSG_CMD_MOVE), NULL }; + static elfedit_cmd_optarg_t arg_move[] = { + { MSG_ORIG(MSG_STR_ELT), + /* MSG_INTL(MSG_ARGDESC_ELT) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_ELT), + 0 }, + { MSG_ORIG(MSG_STR_DST_INDEX), + /* MSG_INTL(MSG_A2_MOVE_DST_INDEX) */ + ELFEDIT_I18NHDL(MSG_A2_MOVE_DST_INDEX), + 0 }, + { MSG_ORIG(MSG_STR_COUNT), + /* MSG_INTL(MSG_A3_MOVE_COUNT) */ + ELFEDIT_I18NHDL(MSG_A3_MOVE_COUNT), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + /* dyn:runpath / dyn:rpath */ + static const char *name_runpath[] = { MSG_ORIG(MSG_CMD_RUNPATH), + MSG_ORIG(MSG_CMD_RUNPATH_A1), NULL }; + static elfedit_cmd_optarg_t arg_runpath[] = { + { MSG_ORIG(MSG_STR_NEWPATH), + /* MSG_INTL(MSG_A1_RUNPATH_NEWPATH) */ + ELFEDIT_I18NHDL(MSG_A1_RUNPATH_NEWPATH), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + /* dyn:posflag1 */ + static const char *name_posflag1[] = { MSG_ORIG(MSG_CMD_POSFLAG1), + NULL }; + static elfedit_cmd_optarg_t arg_posflag1[] = { + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_A1_POSFLAG1_VALUE) */ + ELFEDIT_I18NHDL(MSG_A1_POSFLAG1_VALUE), + ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT }, + { NULL } + }; + + /* dyn:flags */ + static const char *name_flags[] = { MSG_ORIG(MSG_CMD_FLAGS), NULL }; + static elfedit_cmd_optarg_t arg_flags[] = { + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_A1_FLAGS_VALUE) */ + ELFEDIT_I18NHDL(MSG_A1_FLAGS_VALUE), + ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT }, + { NULL } + }; + + /* dyn:flags1 */ + static const char *name_flags1[] = { MSG_ORIG(MSG_CMD_FLAGS1), NULL }; + static elfedit_cmd_optarg_t arg_flags1[] = { + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_A1_FLAGS1_VALUE) */ + ELFEDIT_I18NHDL(MSG_A1_FLAGS1_VALUE), + ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT }, + { NULL } + }; + + /* dyn:feature1 */ + static const char *name_feature1[] = { MSG_ORIG(MSG_CMD_FEATURE1), + NULL }; + static elfedit_cmd_optarg_t arg_feature1[] = { + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_A1_FEATURE1_VALUE) */ + ELFEDIT_I18NHDL(MSG_A1_FEATURE1_VALUE), + ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT }, + { NULL } + }; + + /* dyn:checksum */ + static const char *name_checksum[] = { MSG_ORIG(MSG_CMD_CHECKSUM), + NULL }; + + + + static elfedit_cmd_t cmds[] = { + /* dyn:dump */ + { cmd_dump, cpl_eltarg, name_dump, + /* MSG_INTL(MSG_DESC_DUMP) */ + ELFEDIT_I18NHDL(MSG_DESC_DUMP), + /* MSG_INTL(MSG_HELP_DUMP) */ + ELFEDIT_I18NHDL(MSG_HELP_DUMP), + opt_minus_dynndx, arg_dump }, + + /* dyn:tag */ + { cmd_tag, cpl_tag, name_tag, + /* MSG_INTL(MSG_DESC_TAG) */ + ELFEDIT_I18NHDL(MSG_DESC_TAG), + /* MSG_INTL(MSG_HELP_TAG) */ + ELFEDIT_I18NHDL(MSG_HELP_TAG), + opt_tag, arg_tag }, + + /* dyn:value */ + { cmd_value, cpl_eltarg, name_value, + /* MSG_INTL(MSG_DESC_VALUE) */ + ELFEDIT_I18NHDL(MSG_DESC_VALUE), + /* MSG_INTL(MSG_HELP_VALUE) */ + ELFEDIT_I18NHDL(MSG_HELP_VALUE), + opt_value, arg_value }, + + /* dyn:delete */ + { cmd_delete, cpl_eltarg, name_delete, + /* MSG_INTL(MSG_DESC_DELETE) */ + ELFEDIT_I18NHDL(MSG_DESC_DELETE), + /* MSG_INTL(MSG_HELP_DELETE) */ + ELFEDIT_I18NHDL(MSG_HELP_DELETE), + opt_minus_dynndx, arg_delete }, + + /* dyn:move */ + { cmd_move, cpl_eltarg, name_move, + /* MSG_INTL(MSG_DESC_MOVE) */ + ELFEDIT_I18NHDL(MSG_DESC_MOVE), + /* MSG_INTL(MSG_HELP_MOVE) */ + ELFEDIT_I18NHDL(MSG_HELP_MOVE), + opt_minus_dynndx, arg_move }, + + /* dyn:runpath */ + { cmd_runpath, NULL, name_runpath, + /* MSG_INTL(MSG_DESC_RUNPATH) */ + ELFEDIT_I18NHDL(MSG_DESC_RUNPATH), + /* MSG_INTL(MSG_HELP_RUNPATH) */ + ELFEDIT_I18NHDL(MSG_HELP_RUNPATH), + opt_ostyle, arg_runpath }, + + /* dyn:posflag1 */ + { cmd_posflag1, cpl_posflag1, name_posflag1, + /* MSG_INTL(MSG_DESC_POSFLAG1) */ + ELFEDIT_I18NHDL(MSG_DESC_POSFLAG1), + /* MSG_INTL(MSG_HELP_POSFLAG1) */ + ELFEDIT_I18NHDL(MSG_HELP_POSFLAG1), + opt_ostyle_bitop, arg_posflag1 }, + + /* dyn:flags */ + { cmd_flags, cpl_flags, name_flags, + /* MSG_INTL(MSG_DESC_FLAGS) */ + ELFEDIT_I18NHDL(MSG_DESC_FLAGS), + /* MSG_INTL(MSG_HELP_FLAGS) */ + ELFEDIT_I18NHDL(MSG_HELP_FLAGS), + opt_ostyle_bitop, arg_flags }, + + /* dyn:flags1 */ + { cmd_flags1, cpl_flags1, name_flags1, + /* MSG_INTL(MSG_DESC_FLAGS1) */ + ELFEDIT_I18NHDL(MSG_DESC_FLAGS1), + /* MSG_INTL(MSG_HELP_FLAGS1) */ + ELFEDIT_I18NHDL(MSG_HELP_FLAGS1), + opt_ostyle_bitop, arg_flags1 }, + + /* dyn:feature1 */ + { cmd_feature1, cpl_feature1, name_feature1, + /* MSG_INTL(MSG_DESC_FEATURE1) */ + ELFEDIT_I18NHDL(MSG_DESC_FEATURE1), + /* MSG_INTL(MSG_HELP_FEATURE1) */ + ELFEDIT_I18NHDL(MSG_HELP_FEATURE1), + opt_ostyle_bitop, arg_feature1 }, + + /* dyn:checksum */ + { cmd_checksum, NULL, name_checksum, + /* MSG_INTL(MSG_DESC_CHECKSUM) */ + ELFEDIT_I18NHDL(MSG_DESC_CHECKSUM), + /* MSG_INTL(MSG_HELP_CHECKSUM) */ + ELFEDIT_I18NHDL(MSG_HELP_CHECKSUM), + NULL, NULL }, + + { 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); +} diff --git a/usr/src/cmd/sgs/elfedit/modules/common/dyn.msg b/usr/src/cmd/sgs/elfedit/modules/common/dyn.msg new file mode 100644 index 0000000000..63b91a24cc --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/modules/common/dyn.msg @@ -0,0 +1,431 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" + + +@ _START_ + +# Message file for elfedit 'dyn' module + +@ MSG_ID_ELFEDIT_DYN + + +# Strings +@ MSG_STR_DEPRECATED "(deprecated value)" + +# Debug messages + +@ MSG_DEBUG_S_OK "[%d: %s][%d]: value unchanged: %s\n" +@ MSG_DEBUG_S_CHG "[%d: %s][%d]: change from %s to %s\n" +@ MSG_DEBUG_X_OK "[%d: %s][%d]: value unchanged: %#llx\n" +@ MSG_DEBUG_X_CHG "[%d: %s][%d]: change from %#llx to %#llx\n" +@ MSG_DEBUG_PREVRPATH "[%d: %s][%d]: Reusing existing %s entry: %s\n" +@ MSG_DEBUG_OLDRPATHOK "[%d: %s][%d]: Existing %s already has desired \ + value\n" +@ MSG_DEBUG_CONVNULL "[%d: %s][%d]: No existing %s to modify. Converting \ + extra DT_NULL\n" +@ MSG_DEBUG_DT2NDX "[%d: %s][%d]: Dynamic entry for tag: %s\n" +@ MSG_DEBUG_NULCLIP "[%d: %s][%d]: ELF warning: null element will cause \ + the runtime linker to ignore the non-null \ + elements that follow: %s\n" +@ MSG_DEBUG_NULHIDE "[%d: %s][%d]: ELF warning: this non-null element \ + follows the first DT_NULL element, and will be \ + ignored by the runtime linker: %s\n" +@ MSG_DEBUG_NULLTERM "[%d: %s][%d]: ELF warning: dynamic section is \ + must be terminated by a DT_NULL. The runtime linker \ + will be unable to use this object: %s\n" +@ MSG_DEBUG_DTNULLVALUE "[%d: %s][%d]: ELF warning: DT_NULL element value \ + is expected to be 0: %#llx\n" + + +# Errors + +@ MSG_ERR_NODTELT "[%d: %s]: Dynamic section does not contain tag: %s\n" +@ MSG_ERR_NOEXTRANULL "[%d: %s]: Dynamic section does not have room to add \ + a new element\n" +@ MSG_ERR_NORUNPATH "[%d: %s]: no runpath (DT_RPATH or DT_RUNPATH) found\n" +@ MSG_ERR_NODYNELT "[%d: %s]: no elements of type %s found\n" +@ MSG_ERR_STRPADSTRVAL "[%d: %s]: -s option cannot be used with \ + DT_SUNW_STRPAD dynamic element\n" + + +# Module description + +@ MSG_MOD_DESC "Dynamic Section" + + + +# 1-line description strings + +@ MSG_DESC_DUMP "Dump Dynamic Section" +@ MSG_DESC_TAG "Change element tag" +@ MSG_DESC_VALUE "Change element value" +@ MSG_DESC_DELETE "Delete elements" +@ MSG_DESC_MOVE "Move elements" +@ MSG_DESC_RUNPATH "Set runpath" +@ MSG_DESC_POSFLAG1 "DT_POSFLAG_1 bit values" +@ MSG_DESC_FLAGS "DT_FLAGS bit values" +@ MSG_DESC_FLAGS1 "DT_FLAGS_1 bit values" +@ MSG_DESC_FEATURE1 "DT_FEATURE_1 bit values" +@ MSG_DESC_CHECKSUM "Recompute DT_CHECKSUM" + + +# Commmand option description strings + +@ MSG_OPTDESC_ADD "\ + By default, dyn:value modifies the first element of the\n\ + dynamic section that has the specified tag type, creating\n\ + a new element only if no element of the specified type\n\ + exists, and if room exists in the file. If -add is specified,\n\ + dyn:value will always create a new element for the new value,\n\ + leaving any existing elements with the same tag untouched.\n" + +@ MSG_OPTDESC_S "\ + Interpret the value argument as a string rather than an\n\ + integer. If the specified string already exists in the dynamic\n\ + string table, the offset of that string is stored in the\n\ + dynamic entry. If the string does not exist in the string table,\n\ + but there is room to add it, the new string is added and then\n\ + the offset is placed in the dynamic entry.\n" + +@ MSG_OPTDESC_DYNNDX "\ + Interpret the elt argument as a direct index into the dynamic\n\ + section, rather than as a DT_ tag value.\n" + + +# Command argument description strings + +@ MSG_A1_TAG_ELT "\ + Dynamic element to be examined or changed. By default, this\n\ + is a DT_ tag value. The index of the first element in the\n\ + dynamic section that has the specified tag value will be used.\n\ + The value specified can be one of the well known DT_ constants,\n\ + or any integer.\n\ + \n\ + If the -dynndx option is specified, elt is instead interpreted\n\ + as a simple integer index into the dynamic section.\n" + +@ MSG_A2_TAG_VALUE "\ + Value to be set for d_tag field of specified dynamic\n\ + element. Tag values can be specified using the well known\n\ + DT_ symbolic constants from /usr/include/sys/link.h, or\n\ + as integers.\n" + +@ MSG_ARGDESC_ELT "\ + Element within dynamic section. By default, this is a tag\n\ + value. In this case, the index of the first dynamic element\n\ + with the specified tag value will be used. Tag values can\n\ + be specified using the well known DT_ symbolic constants from\n\ + /usr/include/sys/link.h, or as integers. If the -dynndx\n\ + option is specified, then elt is instead interpreted as a\n\ + direct numeric index into the dynamic section.\n" + +@ MSG_A2_VALUE_VALUE "\ + Value to set for specified dynamic section element. By\n\ + default, this is a numeric value which is used directly.\n\ + If the -s option is used, this is a string value, and the\n\ + dynamic element will receive the numeric offset of the\n\ + specified string from within the associated dynamic string\n\ + table.\n" + +@ MSG_A2_DELETE_COUNT "\ + Number of dynamic elements to delete, starting at the\n\ + specified position. This value cannot exceed the number\n\ + of slots remaining in the table below the specified position.\n\ + If count is not supplied, a single element is deleted.\n" + +@ MSG_A2_MOVE_DST_INDEX "\ + Numeric index within dynamic section to which the element(s)\n\ + should be moved.\n" + +@ MSG_A3_MOVE_COUNT "\ + Number of dynamic elements to move. This value cannot\n\ + exceed the number of slots remaining in the table below\n\ + the specified position. If count is not supplied, a\n\ + single element is moved.\n" + +@ MSG_A1_RUNPATH_NEWPATH "\ + New runpath string for the ELF object.\n" + +@ MSG_A1_POSFLAG1_VALUE "\ + Position dependent state flags which are applied to the\n\ + element immediately following. This can be an integer\n\ + value, or any of the DF_P1_ symbolic constants defined\n\ + in /usr/include/sys/link.h\n" + +@ MSG_A1_FLAGS_VALUE "\ + Flag values. This can be an integer value, or any of the\n\ + DF_ symbolic constants defined in /usr/include/sys/link.h\n" + +@ MSG_A1_FLAGS1_VALUE "\ + Flag values. This can be an integer value, or any of the\n\ + DF_1_ symbolic constants defined in /usr/include/sys/link.h\n" + +@ MSG_A1_FEATURE1_VALUE "\ + Feature values. This can be an integer value, or any of\n\ + the DTF_1_ symbolic constants defined in\n\ + /usr/include/sys/link.h\n" + + +# Help strings + +@ MSG_HELP_DUMP " \ + The dyn:dump command is used to display the contents of the\n\ + dynamic section using the same style used by the elfdump program.\n" + +@ MSG_HELP_TAG " \ + The dyn:tag command is used to display or alter the\n\ + type of an element in the dynamic section. This information\n\ + is found in the d_tag field of a dynamic element.\n\ + \n\ + If dyn:tag is called without arguments, the value of d_tag\n\ + for every element in the dynamic section is shown. If called\n\ + with the elt argument, the specified elements are displayed.\n\ + If both arguments are present, the d_tag field of the specified\n\ + dynamic element is set to the given value.\n" + +@ MSG_HELP_VALUE " \ + The dyn:value command is used to display or alter the\n\ + value of an element in the dynamic section, or to add\n\ + a new element of a desired type. The value of a dynamic\n\ + element is found in the d_un union of the element.\n\ + \n\ + If dyn:value is called without arguments, the value of every\n\ + element in the dynamic section is shown. If called with the\n\ + elt argument, the value of the specified elements are displayed.\n\ + If both arguments are present, the value of the specified\n\ + dynamic element is set to the given value.\n" + +@ MSG_HELP_DELETE " \ + The dyn:delete command is used to delete one or more elements\n\ + in the dynamic section. The elements following the deleted\n\ + items move up, and new DT_NULL elements are inserted at the\n\ + end of the dynamic section to fill the vacated space.\n\ + \n\ + Other parts of the ELF object may have dependencies on the\n\ + position and values of existing dynamic elements. Moving or\n\ + deleting dynamic elements can therefore break the object,\n\ + and should be done with caution. Among the potential issues:\n\ + \n\ + o\tDT_POSFLAG_1 has a positional dependency on the item that\n\ + \tfollows it. If that item is removed, the DT_POSFLAG_1 will\n\ + \tapply to the new item that moves below it.\n\ + \n\ + o\tSyminfo sections reference DT_NEEDED elements in the dynamic\n\ + \tsection by index. Moving or deleting such elements will break\n\ + \tthis dependency.\n" + +@ MSG_HELP_MOVE " \ + The dyn:move command is used to move the position of one\n\ + or more elements in the dynamic section. The specified\n\ + number of elements are moved from elt to dst_index.\n\ + \n\ + Other parts of the ELF object may have dependencies on the\n\ + position and values of existing dynamic elements. Moving or\n\ + deleting dynamic elements can therefore break the object,\n\ + and should be done with caution. Among the potential issues:\n\ + \n\ + o\tDT_POSFLAG_1 has a positional dependency on the item that\n\ + \tfollows it. If that item is removed, the DT_POSFLAG_1 will\n\ + \tapply to the new item that moves below it.\n\ + \n\ + o\tSyminfo sections reference DT_NEEDED elements in the dynamic\n\ + \tsection by index. Moving or deleting such elements will break\n\ + \tthis dependency.\n" + +@ MSG_HELP_RUNPATH " \ + The dyn:runpath command is used to display or alter the\n\ + runpath of the ELF object.\n\ + \n\ + If dyn:runpath is called without arguments, the existing runpath\n\ + is shown. If called with the newpath argument, the runpath is set\n\ + to the given string, if possible.\n\ + \n\ + Not all files can be modified to have a new runpath:\n\ + \n\ + o\tThe desired string must already exist in the dynamic string\n\ + \ttable, or there must be enough room in the reserved section\n\ + \tsection at the end (DT_SUNW_STRPAD) for the new string to be\n\ + \tadded.\n\ + \n\ + o\tThe dynamic section must already have a DT_RPATH or DT_RUNPATH\n\ + \telement, or there must be an extra DT_NULL slot at the end\n\ + \twhere a DT_RUNPATH can be inserted.\n\ + \n\ + If the file has both DT_RPATH and DT_RUNPATH elements in\n\ + the dynamic section, both are set to the new value. If no\n\ + runpath entry exists, a new DT_RUNPATH is inserted if the room\n\ + for it exists.\n" + +@ MSG_HELP_POSFLAG1 " \ + The dyn:posflag1 command is used to display or alter the\n\ + DT_POSFLAG_1 flags values.\n\ + \n\ + If dyn:posflag1 is called without arguments, the current\n\ + value is shown. If one or more value arguments are present,\n\ + the following steps are taken:\n\ + \n \ + o\tAll the value arguments are OR'd together.\n\ + \n \ + o\tIf the -cmp option has been specified, the new value\n\ + \tis complemented.\n\ + \n \ + o\tThe DT_POSFLAG_1 element of the dynamic section is updated\n\ + \twith the new value. If -and is specified, the new value is\n\ + \tAND'd against the existing value. If -or is specified,\n\ + \tthe new value is OR'd against the existing value. If\n\ + \tneither -and or -or are specified, the new value replaces\n\ + \tthe existing value.\n\ + \n\ + If the current dynamic section does not have a current\n\ + DT_POSFLAG_1 element, and room for it exists at the end\n\ + of the section, a new one is inserted.\n" + +@ MSG_HELP_FLAGS " \ + The dyn:flags command is used to display or alter the\n\ + value of the DT_FLAGS dynamic element.\n\ + \n\ + If dyn:flags is called without arguments, the current\n\ + value is shown. If one or more value arguments are present,\n\ + the following steps are taken:\n\ + \n \ + o\tAll the value arguments are OR'd together.\n\ + \n \ + o\tIf the -cmp option has been specified, the new value\n\ + \tis complemented.\n\ + \n \ + o\tThe DT_FLAGS element of the dynamic section is updated\n\ + \twith the new value. If -and is specified, the new value is\n\ + \tAND'd against the existing value. If -or is specified,\n\ + \tthe new value is OR'd against the existing value. If\n\ + \tneither -and or -or are specified, the new value replaces\n\ + \tthe existing value.\n\ + \n\ + If the current dynamic section does not have a current\n\ + DT_FLAGS element, and room for it exists at the end\n\ + of the section, a new one is inserted.\n" + +@ MSG_HELP_FLAGS1 " \ + The dyn:flags1 command is used to display or alter the\n\ + value of the DT_FLAGS_1 dynamic element.\n\ + \n\ + If dyn:flags1 is called without arguments, the current\n\ + value is shown. If one or more value arguments are present,\n\ + the following steps are taken:\n\ + \n \ + o\tAll the value arguments are OR'd together.\n\ + \n \ + o\tIf the -cmp option has been specified, the new value\n\ + \tis complemented.\n\ + \n \ + o\tThe DT_FLAGS_1 element of the dynamic section is updated\n\ + \twith the new value. If -and is specified, the new value is\n\ + \tAND'd against the existing value. If -or is specified,\n\ + \tthe new value is OR'd against the existing value. If\n\ + \tneither -and or -or are specified, the new value replaces\n\ + \tthe existing value.\n\ + \n\ + If the current dynamic section does not have a current\n\ + DT_FLAGS_1 element, and room for it exists at the end\n\ + of the section, a new one is inserted.\n" + +@ MSG_HELP_FEATURE1 " \ + The dyn:feature1 command is used to display or alter the\n\ + value of the DT_FEATURE_1 dynamic element.\n\ + \n\ + If dyn:feature1 is called without arguments, the current\n\ + value is shown. If one or more value arguments are present,\n\ + the following steps are taken:\n\ + \n \ + o\tAll the value arguments are OR'd together.\n\ + \n \ + o\tIf the -cmp option has been specified, the new value\n\ + \tis complemented.\n\ + \n \ + o\tThe DT_FEATURE_1 element of the dynamic section is updated\n\ + \twith the new value. If -and is specified, the new value is\n\ + \tAND'd against the existing value. If -or is specified,\n\ + \tthe new value is OR'd against the existing value. If\n\ + \tneither -and or -or are specified, the new value replaces\n\ + \tthe existing value.\n\ + \n\ + If the current dynamic section does not have a current\n\ + DT_FEATURE_1 element, and room for it exists at the end\n\ + of the section, a new one is inserted.\n" + +@ MSG_HELP_CHECKSUM " \ + The dyn:checksum command recomputes the value of the DT_CHECKSUM\n\ + dynamic element. It calls the elf32_checksum() for 32-bit objects,\n\ + or elf64_checksum() for 64-bit objects, and then sets the value of\n\ + the DT_CHECKSUM element to the resulting value.\n\ + \n\ + If the current dynamic section does not have a current\n\ + DT_CHECKSUM element, and room for it exists at the end\n\ + of the section, a new one is inserted.\n" + +@ _END_ + + +# The following strings represent reserved words, files, pathnames and symbols. +# Reference to this strings is via the MSG_ORIG() macro, and thus no message +# translation is required. + + +# Strings +@ MSG_STR_EMPTY "" +@ MSG_STR_COUNT "count" +@ MSG_STR_ELT "elt" +@ MSG_STR_DST_INDEX "dst_index" +@ MSG_STR_MINUS_ADD "-add" +@ MSG_STR_MINUS_DYNNDX "-dynndx" +@ MSG_STR_MINUS_S "-s" +@ MSG_STR_NEWPATH "newpath" +@ MSG_STR_VALUE "value" + +# Format strings +@ MSG_FMT_STRNL "%s\n" +@ MSG_FMT_HEXXWORDNL "%#llx\n" + + +# Module name + +@ MSG_MOD_NAME "dyn" + + +# Command names + +@ MSG_CMD_DUMP "dump" +@ MSG_CMD_TAG "tag" +@ MSG_CMD_VALUE "value" +@ MSG_CMD_DELETE "delete" +@ MSG_CMD_MOVE "move" +@ MSG_CMD_RUNPATH "runpath" +@ MSG_CMD_RUNPATH_A1 "rpath" +@ MSG_CMD_POSFLAG1 "posflag1" +@ MSG_CMD_FLAGS "flags" +@ MSG_CMD_FLAGS1 "flags1" +@ MSG_CMD_FEATURE1 "feature1" +@ MSG_CMD_CHECKSUM "checksum" diff --git a/usr/src/cmd/sgs/elfedit/modules/common/ehdr.c b/usr/src/cmd/sgs/elfedit/modules/common/ehdr.c new file mode 100644 index 0000000000..4dcca291f7 --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/modules/common/ehdr.c @@ -0,0 +1,2233 @@ +/* + * 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 <stdio.h> +#include <ctype.h> +#include <machdep.h> +#include <elfedit.h> +#include <sys/elf_SPARC.h> +#include <sys/elf_amd64.h> +#include <strings.h> +#include <conv.h> +#include <debug.h> +#include <ehdr_msg.h> + + + + +#define MAXNDXSIZE 10 + + + + +/* + * This module handles changes to the ELF header + */ + + + +/* + * This module uses shared code for several of the commands. + * It is sometimes necessary to know which specific command + * is active. + */ +typedef enum { + /* Dump command, used as module default to display ELF header */ + EHDR_CMD_T_DUMP = 0, /* ehdr:dump */ + + /* Commands that correspond directly to ELF header fields */ + EHDR_CMD_T_E_IDENT = 1, /* ehdr:e_ident */ + EHDR_CMD_T_E_TYPE = 2, /* ehdr:e_type */ + EHDR_CMD_T_E_MACHINE = 3, /* ehdr:e_machine */ + EHDR_CMD_T_E_VERSION = 4, /* ehdr:e_version */ + EHDR_CMD_T_E_ENTRY = 5, /* ehdr:e_entry */ + EHDR_CMD_T_E_PHOFF = 6, /* ehdr:e_phoff */ + EHDR_CMD_T_E_SHOFF = 7, /* ehdr:e_shoff */ + EHDR_CMD_T_E_FLAGS = 8, /* ehdr:e_flags */ + EHDR_CMD_T_E_EHSIZE = 9, /* ehdr:e_ehsize */ + EHDR_CMD_T_E_PHENTSIZE = 10, /* ehdr:e_phentsize */ + EHDR_CMD_T_E_PHNUM = 11, /* ehdr:e_phnum */ + EHDR_CMD_T_E_SHENTSIZE = 12, /* ehdr:e_shentsize */ + EHDR_CMD_T_E_SHNUM = 13, /* ehdr:e_shnum */ + EHDR_CMD_T_E_SHSTRNDX = 14, /* ehdr:e_shstrndx */ + + /* Commands that correspond to the e_ident[] array in ELF hdr */ + EHDR_CMD_T_EI_MAG0 = 15, /* ehdr:ei_mag0 */ + EHDR_CMD_T_EI_MAG1 = 16, /* ehdr:ei_mag1 */ + EHDR_CMD_T_EI_MAG2 = 17, /* ehdr:ei_mag2 */ + EHDR_CMD_T_EI_MAG3 = 18, /* ehdr:ei_mag3 */ + EHDR_CMD_T_EI_CLASS = 19, /* ehdr:ei_class */ + EHDR_CMD_T_EI_DATA = 20, /* ehdr:ei_data */ + EHDR_CMD_T_EI_VERSION = 21, /* ehdr:ei_version */ + EHDR_CMD_T_EI_OSABI = 22, /* ehdr:ei_osabi */ + EHDR_CMD_T_EI_ABIVERSION = 23 /* ehdr:ei_abiversion */ +} EHDR_CMD_T; + + + + + + +#ifndef _ELF64 +/* + * We supply this function for the msg module + */ +const char * +_ehdr_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 ehdr_opt_t enum specifies a bit value for every optional + * argument allowed by a command in this module. + */ +typedef enum { + EHDR_OPT_F_AND = 1, /* -and: AND (&) values to dest */ + EHDR_OPT_F_CMP = 2, /* -cmp: Complement (~) values */ + EHDR_OPT_F_OR = 4, /* -or: OR (|) values to dest */ + EHDR_OPT_F_SHNDX = 8, /* -shndx: sec argument is index of */ + /* section, not name */ + EHDR_OPT_F_SHTYP = 16 /* -shtyp: sec argument is type of */ + /* section, not name */ +} ehdr_opt_t; + + +/* + * A variable of type ARGSTATE is used by each command to maintain + * information about the arguments and related things. It is + * initialized by process_args(), and used by the other routines. + */ +typedef struct { + elfedit_obj_state_t *obj_state; + ehdr_opt_t optmask; /* Mask of options used */ + int argc; /* # of plain arguments */ + const char **argv; /* Plain arguments */ +} ARGSTATE; + + + +/* + * Standard argument processing for ehdr module + * + * entry + * obj_state, argc, argv - Standard command 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[], + ARGSTATE *argstate) +{ + elfedit_getopt_state_t getopt_state; + elfedit_getopt_ret_t *getopt_ret; + + bzero(argstate, sizeof (*argstate)); + argstate->obj_state = obj_state; + + 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; + + /* 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; +} + + + + + + +/* + * Format the given magic number byte into a buffer + * + * entry: + * value - Value of the magic value byte given by + * ehdr->ei_ident[EI_MAG?] + */ +static const char * +conv_magic_value(int value) +{ + /* + * This routine can be called twice within a single C statement, + * so we use alternating buffers on each call to allow this + * without requiring the caller to supply a buffer (the size of + * which they don't know). + */ + static char buf1[20]; + static char buf2[20]; + static char *buf; + + /* Switch buffers */ + buf = (buf == buf1) ? buf2 : buf1; + + if (isprint(value)) + (void) snprintf(buf, sizeof (buf1), + MSG_ORIG(MSG_FMT_HEXNUM_QCHR), value, value); + else + (void) snprintf(buf, sizeof (buf1), + MSG_ORIG(MSG_FMT_HEXNUM), value); + return (buf); +} + + + +/* + * Print ELF header values, taking the calling command, and output style + * into account. + * + * entry: + * cmd - EHDR_CMD_T_* value giving identify of caller + * e_ident_ndx - Ignored unless cmd is EHDR_CMD_T_E_IDENT. In IDENT + * case, index of item in e_ident[] array to display, or + * -1 to display the entire array. + * autoprint - If True, output is only produced if the elfedit + * autoprint flag is set. If False, output is always produced. + * argstate - Argument state block + */ +static void +print_ehdr(EHDR_CMD_T cmd, int e_ident_ndx, int autoprint, + ARGSTATE *argstate) +{ + elfedit_outstyle_t outstyle; + Conv_fmt_flags_t flags_fmt_flags = 0; + Ehdr *ehdr; + int c; + Conv_inv_buf_t inv_buf; + + if (autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0)) + return; + + /* + * Pick an output style. ehdr:dump is required to use the default + * style. The other commands use the current output style. + */ + if (cmd == EHDR_CMD_T_DUMP) { + outstyle = ELFEDIT_OUTSTYLE_DEFAULT; + } else { + outstyle = elfedit_outstyle(); + + /* + * When the caller specifies the simple output style, + * omit the brackets from around the values. + */ + if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) + flags_fmt_flags = CONV_FMT_NOBKT; + + /* + * For things that show a single header item, switch + * from default to simple mode. + */ + if ((outstyle == ELFEDIT_OUTSTYLE_DEFAULT) && + ((cmd != EHDR_CMD_T_E_IDENT) || (e_ident_ndx != -1))) + outstyle = ELFEDIT_OUTSTYLE_SIMPLE; + } + + ehdr = argstate->obj_state->os_ehdr; + + /* + * If doing default output, use elfdump style where we + * show the full ELF header. In this case, the command + * that called us doesn't matter. This can only happen + * from ehdr:dump or ehdr:e_ident/ + */ + if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) { + const char *ndx, *value; + char ndx_buf[64], value_buf[20]; + int i; + + if (cmd == EHDR_CMD_T_DUMP) { + Elf_ehdr(NULL, ehdr, + argstate->obj_state->os_secarr[0].sec_shdr); + elfedit_printf(MSG_ORIG(MSG_STR_NL)); + } + + /* + * Elf_ehdr() does not display all of e_ident[], so we + * augment by displaying the entire array separately. + */ + elfedit_printf(MSG_ORIG(MSG_STR_EIDENT_HDR)); + + for (i = 0; i < EI_NIDENT; i++) { + ndx = value = NULL; + + switch (i) { + case EI_MAG0: + case EI_MAG1: + case EI_MAG2: + case EI_MAG3: + ndx = elfedit_atoconst_value_to_str( + ELFEDIT_CONST_EI, i, 1); + value = conv_magic_value(ehdr->e_ident[i]); + break; + case EI_CLASS: + ndx = elfedit_atoconst_value_to_str( + ELFEDIT_CONST_EI, EI_CLASS, 1); + value = conv_ehdr_class(ehdr->e_ident[EI_CLASS], + 0, &inv_buf); + break; + case EI_DATA: + ndx = elfedit_atoconst_value_to_str( + ELFEDIT_CONST_EI, EI_DATA, 1); + value = conv_ehdr_data(ehdr->e_ident[EI_DATA], + 0, &inv_buf); + break; + case EI_VERSION: + ndx = elfedit_atoconst_value_to_str( + ELFEDIT_CONST_EI, EI_VERSION, 1); + value = conv_ehdr_vers( + ehdr->e_ident[EI_VERSION], 0, &inv_buf); + break; + case EI_OSABI: + ndx = elfedit_atoconst_value_to_str( + ELFEDIT_CONST_EI, EI_OSABI, 1); + value = conv_ehdr_osabi(ehdr->e_ident[EI_OSABI], + 0, &inv_buf); + break; + case EI_ABIVERSION: + ndx = elfedit_atoconst_value_to_str( + ELFEDIT_CONST_EI, EI_ABIVERSION, 1); + value = value_buf; + (void) snprintf(value_buf, sizeof (value_buf), + MSG_ORIG(MSG_FMT_HEXNUM), ehdr->e_ident[i]); + break; + default: + value = value_buf; + (void) snprintf(value_buf, sizeof (value_buf), + MSG_ORIG(MSG_FMT_HEXNUM), ehdr->e_ident[i]); + break; + } + + if (ndx == NULL) + (void) snprintf(ndx_buf, sizeof (ndx_buf), + MSG_ORIG(MSG_FMT_BKTINT), i); + else + (void) snprintf(ndx_buf, sizeof (ndx_buf), + MSG_ORIG(MSG_FMT_BKTSTR), ndx); + elfedit_printf(MSG_ORIG(MSG_FMT_EI_ELT), + ndx_buf, value); + } + return; + } + + + switch (cmd) { + case EHDR_CMD_T_E_IDENT: + { + int i, cnt; + + /* Show one element, or the entire thing? */ + if (e_ident_ndx == -1) { + i = 0; + cnt = EI_NIDENT; + } else { + i = e_ident_ndx; + cnt = 1; + } + + for (; cnt-- > 0; i++) { + /* + * If using numeric style, or there is + * no conversion routine for this item, + * print a simple hex value. + */ + if ((outstyle == ELFEDIT_OUTSTYLE_NUM) || + (i >= EI_ABIVERSION)) { + elfedit_printf( + MSG_ORIG(MSG_FMT_HEXNUMNL), + ehdr->e_ident[i]); + continue; + } + + /* Handle special cases in simple mode */ + switch (i) { + case EI_MAG0: + case EI_MAG1: + case EI_MAG2: + case EI_MAG3: + elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), + conv_magic_value(ehdr->e_ident[i])); + continue; + case EI_CLASS: + elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), + conv_ehdr_class( + ehdr->e_ident[EI_CLASS], 0, + &inv_buf)); + continue; + case EI_DATA: + elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), + conv_ehdr_data( + ehdr->e_ident[EI_DATA], 0, + &inv_buf)); + continue; + case EI_VERSION: + elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), + conv_ehdr_vers( + ehdr->e_ident[EI_VERSION], 0, + &inv_buf)); + continue; + case EI_OSABI: + elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), + conv_ehdr_osabi( + ehdr->e_ident[EI_OSABI], 0, + &inv_buf)); + continue; + } + } + } + return; + + case EHDR_CMD_T_E_TYPE: + if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) + elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), + conv_ehdr_type(ehdr->e_type, 0, &inv_buf)); + else + elfedit_printf(MSG_ORIG(MSG_FMT_DECNUMNL), + ehdr->e_type); + return; + + case EHDR_CMD_T_E_MACHINE: + if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { + elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), + conv_ehdr_mach(ehdr->e_machine, 0, &inv_buf)); + } else { + elfedit_printf(MSG_ORIG(MSG_FMT_DECNUMNL), + EC_WORD(ehdr->e_machine)); + } + return; + + case EHDR_CMD_T_E_VERSION: + if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) + elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), + conv_ehdr_vers(ehdr->e_version, 0, &inv_buf)); + else + elfedit_printf(MSG_ORIG(MSG_FMT_DECNUMNL), + ehdr->e_version); + return; + + case EHDR_CMD_T_E_ENTRY: + elfedit_printf(MSG_ORIG(MSG_FMT_HEXNUMNL), + EC_WORD(ehdr->e_entry)); + return; + + case EHDR_CMD_T_E_PHOFF: + elfedit_printf(MSG_ORIG(MSG_FMT_HEXNUMNL), + EC_WORD(ehdr->e_phoff)); + return; + + case EHDR_CMD_T_E_SHOFF: + elfedit_printf(MSG_ORIG(MSG_FMT_HEXNUMNL), + EC_WORD(ehdr->e_shoff)); + return; + + case EHDR_CMD_T_E_FLAGS: + if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { + Conv_ehdr_flags_buf_t flags_buf; + + elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), + conv_ehdr_flags(ehdr->e_machine, ehdr->e_flags, + flags_fmt_flags, &flags_buf)); + } else { + elfedit_printf(MSG_ORIG(MSG_FMT_HEXNUMNL), + ehdr->e_flags); + } + return; + + case EHDR_CMD_T_E_EHSIZE: + elfedit_printf(MSG_ORIG(MSG_FMT_DECNUMNL), + EC_WORD(ehdr->e_ehsize)); + return; + + case EHDR_CMD_T_E_PHENTSIZE: + elfedit_printf(MSG_ORIG(MSG_FMT_DECNUMNL), + EC_WORD(ehdr->e_phentsize)); + return; + + case EHDR_CMD_T_E_PHNUM: + { + Word num = ehdr->e_phnum; + + /* + * If using extended indexes, fetch the real + * value from shdr[0].sh_info + */ + if (num == PN_XNUM) + num = argstate->obj_state-> + os_secarr[0].sec_shdr->sh_info; + + elfedit_printf(MSG_ORIG(MSG_FMT_DECNUMNL), + EC_WORD(num)); + } + return; + + case EHDR_CMD_T_E_SHENTSIZE: + elfedit_printf(MSG_ORIG(MSG_FMT_DECNUMNL), + EC_WORD(ehdr->e_shentsize)); + return; + + case EHDR_CMD_T_E_SHNUM: + { + Word num = ehdr->e_shnum; + + /* + * If using extended indexes, fetch the real + * value from shdr[0].sh_size + */ + if (num == 0) + num = argstate->obj_state-> + os_secarr[0].sec_shdr->sh_size; + + elfedit_printf(MSG_ORIG(MSG_FMT_DECNUMNL), + EC_WORD(num)); + } + return; + + case EHDR_CMD_T_E_SHSTRNDX: + { + Word num = ehdr->e_shstrndx; + + /* + * If using extended indexes, fetch the real + * value from shdr[0].sh_link + */ + if (num == SHN_XINDEX) + num = argstate->obj_state-> + os_secarr[0].sec_shdr->sh_link; + + elfedit_printf(MSG_ORIG(MSG_FMT_DECNUMNL), + EC_WORD(num)); + } + return; + + case EHDR_CMD_T_EI_MAG0: + case EHDR_CMD_T_EI_MAG1: + case EHDR_CMD_T_EI_MAG2: + case EHDR_CMD_T_EI_MAG3: + /* This depends on EHDR_CMD_T_EI_MAG[0-3] being contiguous */ + c = ehdr->e_ident[cmd - EHDR_CMD_T_EI_MAG0]; + if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) + elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), + conv_magic_value(c)); + else + elfedit_printf(MSG_ORIG(MSG_FMT_HEXNUMNL), c); + return; + + case EHDR_CMD_T_EI_CLASS: + c = ehdr->e_ident[EI_CLASS]; + if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) + elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), + conv_ehdr_class(c, 0, &inv_buf)); + else + elfedit_printf(MSG_ORIG(MSG_FMT_HEXNUMNL), c); + return; + + case EHDR_CMD_T_EI_DATA: + c = ehdr->e_ident[EI_DATA]; + if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) + elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), + conv_ehdr_data(c, 0, &inv_buf)); + else + elfedit_printf(MSG_ORIG(MSG_FMT_HEXNUMNL), c); + return; + + case EHDR_CMD_T_EI_VERSION: + c = ehdr->e_ident[EI_VERSION]; + if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) + elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), + conv_ehdr_vers(c, 0, &inv_buf)); + else + elfedit_printf(MSG_ORIG(MSG_FMT_HEXNUMNL), c); + return; + + case EHDR_CMD_T_EI_OSABI: + c = ehdr->e_ident[EI_OSABI]; + if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { + elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), + conv_ehdr_osabi(c, 0, &inv_buf)); + } else { + elfedit_printf(MSG_ORIG(MSG_FMT_HEXNUMNL), + EC_WORD(c)); + } + return; + + case EHDR_CMD_T_EI_ABIVERSION: + elfedit_printf(MSG_ORIG(MSG_FMT_HEXNUMNL), + EC_WORD(ehdr->e_ident[EI_ABIVERSION])); + return; + } +} + + +/* + * Common body for the ehdr: 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 EHDR_CMD_T_* constants listed above, specifying + * which command to implement. + * obj_state, argc, argv - Standard command arguments + */ +static elfedit_cmdret_t +cmd_body(EHDR_CMD_T cmd, elfedit_obj_state_t *obj_state, + int argc, const char *argv[]) +{ + /* + * When a call comes in for ehdr:e_ident[ndx], and the + * specified element is one that we have a special command + * for, then we revector to that special command instead + * of using the generic ehdr:e_ident processing. This array, + * which is indexed by the e_ident[] index value is used + * to decide if that is the case. If the resulting value + * is EHDR_CMD_T_E_IDENT, then the generic processing is + * used. Otherwise, we revector to the specified command. + */ + static const int e_ident_revector[16] = { + EHDR_CMD_T_EI_MAG0, /* 0: EI_MAG0 */ + EHDR_CMD_T_EI_MAG1, /* 1: EI_MAG1 */ + EHDR_CMD_T_EI_MAG2, /* 2: EI_MAG2 */ + EHDR_CMD_T_EI_MAG3, /* 3: EI_MAG3 */ + EHDR_CMD_T_EI_CLASS, /* 4: EI_CLASS */ + EHDR_CMD_T_EI_DATA, /* 5: EI_DATA */ + EHDR_CMD_T_EI_VERSION, /* 6: EI_VERSION */ + EHDR_CMD_T_EI_OSABI, /* 7: EI_OSABI */ + EHDR_CMD_T_EI_ABIVERSION, /* 8: EI_ABIVERSION */ + EHDR_CMD_T_E_IDENT, /* 9: generic */ + EHDR_CMD_T_E_IDENT, /* 10: generic */ + EHDR_CMD_T_E_IDENT, /* 11: generic */ + EHDR_CMD_T_E_IDENT, /* 12: generic */ + EHDR_CMD_T_E_IDENT, /* 13: generic */ + EHDR_CMD_T_E_IDENT, /* 14: generic */ + EHDR_CMD_T_E_IDENT, /* 15: generic */ + }; + + + ARGSTATE argstate; + Ehdr *ehdr; + elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE; + int e_ident_ndx = -1; + Conv_inv_buf_t inv_buf1, inv_buf2; + + /* Process the optional arguments */ + process_args(obj_state, argc, argv, &argstate); + + /* Check number of arguments */ + switch (cmd) { + case EHDR_CMD_T_DUMP: + /* ehdr:dump does not accept arguments */ + if (argstate.argc > 0) + elfedit_command_usage(); + break; + case EHDR_CMD_T_E_IDENT: + /* + * ehdr:e_ident accepts 1 or 2 arguments, the first + * being the index into the array, and the second being + * the value. If there are arguments, then process the + * index, and remove it from the argument list. + */ + if (argstate.argc > 0) { + if (argstate.argc > 2) + elfedit_command_usage(); + e_ident_ndx = (int) + elfedit_atoconst_range(argstate.argv[0], + MSG_ORIG(MSG_STR_INDEX), 0, EI_NIDENT - 1, + ELFEDIT_CONST_EI); + argstate.argc--; + argstate.argv++; + + /* + * If the index is for one of the e_ident elements + * that we have a special command for, then switch + * to that command. e_ident_revector[] returns + * EHDR_CMD_T_E_IDENT in the cases where such a command + * does not exist, in which case we'll continue with the + * generic code. + */ + cmd = e_ident_revector[e_ident_ndx]; + } + break; + case EHDR_CMD_T_E_FLAGS: + /* ehdr:e_flags accepts an arbitrary number of arguments */ + break; + default: + /* The remaining commands accept a single optional argument */ + if (argstate.argc > 1) + elfedit_command_usage(); + break; + } + + /* If there are no arguments, dump the ELF header and return */ + if (argstate.argc == 0) { + print_ehdr(cmd, e_ident_ndx, 0, &argstate); + return (ELFEDIT_CMDRET_NONE); + } + + ehdr = obj_state->os_ehdr; + switch (cmd) { + /* + * EHDR_CMD_T_DUMP can't get here: It never has an + * argument, and is handled above. + */ + + case EHDR_CMD_T_E_IDENT: + { + /* + * Only those e_ident[] elements for which we + * don't have a specialized command come here. + * The argument is a value to be set in + * e_ident[e_ident_ndx]. + */ + uchar_t value = (uchar_t) + elfedit_atoui_range(argstate.argv[0], + MSG_ORIG(MSG_STR_VALUE), 0, 255, NULL); + + if (ehdr->e_ident[e_ident_ndx] == value) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_EI_D_X_OK), + e_ident_ndx, EC_WORD(value)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_EI_D_X_CHG), + e_ident_ndx, ehdr->e_ident[e_ident_ndx], + value); + ret = ELFEDIT_CMDRET_MOD; + ehdr->e_ident[e_ident_ndx] = value; + } + } + break; + + case EHDR_CMD_T_E_TYPE: + { + /* The argument gives the object type */ + Half type = (Half) elfedit_atoconst(argstate.argv[0], + ELFEDIT_CONST_ET); + const char *name = MSG_ORIG(MSG_CMD_E_TYPE); + + if (ehdr->e_type == type) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_E_S_OK), name, + conv_ehdr_type(ehdr->e_type, 0, &inv_buf1)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_E_S_CHG), name, + conv_ehdr_type(ehdr->e_type, 0, &inv_buf1), + conv_ehdr_type(type, 0, &inv_buf2)); + ret = ELFEDIT_CMDRET_MOD; + ehdr->e_type = type; + } + } + break; + + case EHDR_CMD_T_E_MACHINE: + { + /* The argument gives the machine code */ + Half mach = (Half) elfedit_atoconst(argstate.argv[0], + ELFEDIT_CONST_EM); + const char *name = MSG_ORIG(MSG_CMD_E_MACHINE); + + if (ehdr->e_machine == mach) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_E_S_OK), name, + conv_ehdr_mach(ehdr->e_machine, 0, + &inv_buf1)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_E_S_CHG), name, + conv_ehdr_mach(ehdr->e_machine, 0, + &inv_buf1), + conv_ehdr_mach(mach, 0, &inv_buf2)); + ret = ELFEDIT_CMDRET_MOD; + ehdr->e_machine = mach; + } + } + break; + + case EHDR_CMD_T_E_VERSION: + { + /* The argument gives the version */ + Word ver = (Word) elfedit_atoconst(argstate.argv[0], + ELFEDIT_CONST_EV); + const char *name = MSG_ORIG(MSG_CMD_E_VERSION); + + if (ehdr->e_version == ver) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_E_S_OK), name, + conv_ehdr_vers(ehdr->e_version, 0, + &inv_buf1)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_E_S_CHG), name, + conv_ehdr_vers(ehdr->e_version, 0, + &inv_buf1), + conv_ehdr_vers(ver, 0, &inv_buf2)); + ret = ELFEDIT_CMDRET_MOD; + ehdr->e_version = ver; + } + } + break; + + case EHDR_CMD_T_E_ENTRY: + { + /* The argument gives the entry address */ + Addr entry = (Addr) + elfedit_atoui(argstate.argv[0], NULL); + const char *name = MSG_ORIG(MSG_CMD_E_ENTRY); + + if (ehdr->e_entry == entry) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_E_LLX_OK), name, + EC_ADDR(ehdr->e_entry)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_E_LLX_CHG), name, + EC_ADDR(ehdr->e_entry), EC_ADDR(entry)); + ret = ELFEDIT_CMDRET_MOD; + ehdr->e_entry = entry; + } + } + break; + + case EHDR_CMD_T_E_PHOFF: + { + /* The argument gives the program header offset */ + Off off = (Off) elfedit_atoui(argstate.argv[0], + NULL); + const char *name = MSG_ORIG(MSG_CMD_E_PHOFF); + + if (ehdr->e_phoff == off) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_E_LLX_OK), name, + EC_OFF(ehdr->e_phoff)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_E_LLX_CHG), name, + EC_OFF(ehdr->e_phoff), EC_OFF(off)); + ret = ELFEDIT_CMDRET_MOD; + ehdr->e_phoff = off; + } + } + break; + + case EHDR_CMD_T_E_SHOFF: + { + /* The argument gives the section header offset */ + Off off = (Off) elfedit_atoui(argstate.argv[0], + NULL); + const char *name = MSG_ORIG(MSG_CMD_E_SHOFF); + + if (ehdr->e_shoff == off) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_E_LLX_OK), name, + EC_OFF(ehdr->e_shoff)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_E_LLX_CHG), name, + EC_OFF(ehdr->e_shoff), EC_OFF(off)); + ret = ELFEDIT_CMDRET_MOD; + ehdr->e_shoff = off; + } + } + break; + + case EHDR_CMD_T_E_FLAGS: + { + Conv_ehdr_flags_buf_t flags_buf1, flags_buf2; + const char *name = MSG_ORIG(MSG_CMD_E_FLAGS); + Word flags = 0; + int i; + + /* Collect the arguments */ + for (i = 0; i < argstate.argc; i++) + flags |= (Word) + elfedit_atoconst(argstate.argv[i], + ELFEDIT_CONST_EF); + + /* Complement the value? */ + if (argstate.optmask & EHDR_OPT_F_CMP) + flags = ~flags; + + /* Perform any requested bit operations */ + if (argstate.optmask & EHDR_OPT_F_AND) + flags &= ehdr->e_flags; + else if (argstate.optmask & EHDR_OPT_F_OR) + flags |= ehdr->e_flags; + + /* Set the value */ + if (ehdr->e_flags == flags) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_E_S_OK), name, + conv_ehdr_flags(ehdr->e_machine, + ehdr->e_flags, 0, &flags_buf1)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_E_S_CHG), name, + conv_ehdr_flags(ehdr->e_machine, + ehdr->e_flags, 0, &flags_buf1), + conv_ehdr_flags(ehdr->e_machine, + flags, 0, &flags_buf2)); + ret = ELFEDIT_CMDRET_MOD; + ehdr->e_flags = flags; + } + } + break; + + case EHDR_CMD_T_E_EHSIZE: + { + /* The argument gives the ELF header size */ + Half ehsize = (Half) elfedit_atoui(argstate.argv[0], + NULL); + const char *name = MSG_ORIG(MSG_CMD_E_EHSIZE); + + if (ehdr->e_ehsize == ehsize) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_E_D_OK), name, + EC_WORD(ehdr->e_ehsize)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_E_D_CHG), name, + EC_WORD(ehdr->e_ehsize), EC_WORD(ehsize)); + ret = ELFEDIT_CMDRET_MOD; + ehdr->e_ehsize = ehsize; + } + } + break; + + case EHDR_CMD_T_E_PHENTSIZE: + { + /* + * The argument gives the size of a program + * header element. + */ + Half phentsize = (Half) elfedit_atoui(argstate.argv[0], + NULL); + const char *name = MSG_ORIG(MSG_CMD_E_PHENTSIZE); + + if (ehdr->e_phentsize == phentsize) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_E_D_OK), name, + EC_WORD(ehdr->e_phentsize)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_E_D_CHG), name, + EC_WORD(ehdr->e_phentsize), + EC_WORD(phentsize)); + ret = ELFEDIT_CMDRET_MOD; + ehdr->e_phentsize = phentsize; + } + } + break; + + case EHDR_CMD_T_E_PHNUM: + { + /* The argument gives the number of program headers */ + Word phnum = (Word) elfedit_atoui(argstate.argv[0], + NULL); + const char *name = MSG_ORIG(MSG_CMD_E_PHNUM); + elfedit_section_t *sec0 = &obj_state->os_secarr[0]; + Shdr *shdr0 = sec0->sec_shdr; + Half e_phnum; + Word sh_info; + + if (phnum >= PN_XNUM) { + e_phnum = PN_XNUM; + sh_info = phnum; + } else { + e_phnum = phnum; + sh_info = 0; + } + + if (ehdr->e_phnum == e_phnum) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_E_D_OK), name, + EC_WORD(ehdr->e_phnum)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_E_D_CHG), name, + EC_WORD(ehdr->e_phnum), e_phnum); + ret = ELFEDIT_CMDRET_MOD; + ehdr->e_phnum = e_phnum; + } + if (shdr0->sh_info == sh_info) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_SHDR0_D_OK), + MSG_ORIG(MSG_STR_SH_INFO), + EC_WORD(shdr0->sh_info)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_SHDR0_D_CHG), + MSG_ORIG(MSG_STR_SH_INFO), + EC_WORD(shdr0->sh_info), sh_info); + ret = ELFEDIT_CMDRET_MOD; + shdr0->sh_info = sh_info; + elfedit_modified_shdr(sec0); + } + } + break; + + case EHDR_CMD_T_E_SHENTSIZE: + { + /* + * The argument gives the size of a program + * header element. + */ + Half shentsize = (Half) elfedit_atoui(argstate.argv[0], + NULL); + const char *name = MSG_ORIG(MSG_CMD_E_SHENTSIZE); + + if (ehdr->e_shentsize == shentsize) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_E_D_OK), name, + EC_WORD(ehdr->e_shentsize)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_E_D_CHG), name, + EC_WORD(ehdr->e_shentsize), + EC_WORD(shentsize)); + ret = ELFEDIT_CMDRET_MOD; + ehdr->e_shentsize = shentsize; + } + } + break; + + case EHDR_CMD_T_E_SHNUM: + { + /* The argument gives the number of section headers */ + Word shnum = (Word) elfedit_atoui(argstate.argv[0], + NULL); + const char *name = MSG_ORIG(MSG_CMD_E_SHNUM); + elfedit_section_t *sec0 = &obj_state->os_secarr[0]; + Shdr *shdr0 = sec0->sec_shdr; + Half e_shnum; + Word sh_size; + + if (shnum >= SHN_LORESERVE) { + e_shnum = 0; + sh_size = shnum; + } else { + e_shnum = shnum; + sh_size = 0; + } + + if (ehdr->e_shnum == e_shnum) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_E_D_OK), name, + EC_WORD(ehdr->e_shnum)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_E_D_CHG), name, + EC_WORD(ehdr->e_shnum), e_shnum); + ret = ELFEDIT_CMDRET_MOD; + ehdr->e_shnum = e_shnum; + } + if (shdr0->sh_size == sh_size) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_SHDR0_D_OK), + MSG_ORIG(MSG_STR_SH_SIZE), + EC_WORD(shdr0->sh_size)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_SHDR0_D_CHG), + MSG_ORIG(MSG_STR_SH_SIZE), + EC_WORD(shdr0->sh_size), sh_size); + ret = ELFEDIT_CMDRET_MOD; + shdr0->sh_size = sh_size; + elfedit_modified_shdr(sec0); + } + } + break; + + case EHDR_CMD_T_E_SHSTRNDX: + { + const char *name = MSG_ORIG(MSG_CMD_E_SHSTRNDX); + Word shstrndx; + elfedit_section_t *sec0 = &obj_state->os_secarr[0]; + Shdr *shdr0 = sec0->sec_shdr; + Half e_shstrndx; + Word sh_link; + + /* + * By default, sec argument is name of section. + * If -shndx is used, it is a numeric index, and + * if -shtyp is used, it is a section type. + */ + if (argstate.optmask & EHDR_OPT_F_SHNDX) + shstrndx = elfedit_atoshndx(argstate.argv[0], + obj_state->os_shnum); + else if (argstate.optmask & EHDR_OPT_F_SHTYP) + shstrndx = elfedit_type_to_shndx(obj_state, + elfedit_atoconst(argstate.argv[0], + ELFEDIT_CONST_SHT)); + else + shstrndx = elfedit_name_to_shndx(obj_state, + argstate.argv[0]); + + /* Warn if the section isn't a string table */ + if ((shstrndx >= obj_state->os_shnum) || + ((shstrndx >= SHN_LORESERVE) && + (shstrndx <= SHN_HIRESERVE)) || + (obj_state->os_secarr[shstrndx].sec_shdr->sh_type != + SHT_STRTAB)) + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_NOTSTRTAB), name, + EC_WORD(shstrndx)); + + if (shstrndx >= SHN_LORESERVE) { + e_shstrndx = SHN_XINDEX; + sh_link = shstrndx; + } else { + e_shstrndx = shstrndx; + sh_link = 0; + } + + if (ehdr->e_shstrndx == e_shstrndx) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_E_D_OK), name, + EC_WORD(ehdr->e_shstrndx)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_E_D_CHG), name, + EC_WORD(ehdr->e_shstrndx), e_shstrndx); + ret = ELFEDIT_CMDRET_MOD; + ehdr->e_shstrndx = e_shstrndx; + } + if (shdr0->sh_link == sh_link) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_SHDR0_D_OK), + MSG_ORIG(MSG_STR_SH_LINK), + EC_WORD(shdr0->sh_link)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_SHDR0_D_CHG), + MSG_ORIG(MSG_STR_SH_LINK), + EC_WORD(shdr0->sh_link), sh_link); + ret = ELFEDIT_CMDRET_MOD; + shdr0->sh_link = sh_link; + elfedit_modified_shdr(sec0); + } + } + break; + + case EHDR_CMD_T_EI_MAG0: + case EHDR_CMD_T_EI_MAG1: + case EHDR_CMD_T_EI_MAG2: + case EHDR_CMD_T_EI_MAG3: + { + /* + * This depends on EHDR_CMD_T_EI_MAG[0-3] + * being contiguous + */ + int ei_ndx = (cmd - EHDR_CMD_T_EI_MAG0) + EI_MAG0; + + /* The argument gives the magic number byte */ + int mag = (int)elfedit_atoui_range(argstate.argv[0], + MSG_ORIG(MSG_STR_VALUE), 0, 255, NULL); + + if (ehdr->e_ident[ei_ndx] == mag) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_EI_S_S_OK), + elfedit_atoconst_value_to_str( + ELFEDIT_CONST_EI, ei_ndx, 1), + conv_magic_value(ehdr->e_ident[ei_ndx])); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_EI_S_S_CHG), + elfedit_atoconst_value_to_str( + ELFEDIT_CONST_EI, ei_ndx, 1), + conv_magic_value(ehdr->e_ident[ei_ndx]), + conv_magic_value(mag)); + ret = ELFEDIT_CMDRET_MOD; + ehdr->e_ident[ei_ndx] = mag; + } + } + break; + + case EHDR_CMD_T_EI_CLASS: + { + /* The argument gives the ELFCLASS value */ + int class = (int)elfedit_atoconst_range( + argstate.argv[0], MSG_ORIG(MSG_STR_VALUE), 0, 255, + ELFEDIT_CONST_ELFCLASS); + const char *name = elfedit_atoconst_value_to_str( + ELFEDIT_CONST_EI, EI_CLASS, 1); + + if (ehdr->e_ident[EI_CLASS] == class) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_EI_S_S_OK), name, + conv_ehdr_class(class, 0, &inv_buf1)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_EI_S_S_CHG), name, + conv_ehdr_class(ehdr->e_ident[EI_CLASS], + 0, &inv_buf1), + conv_ehdr_class(class, 0, &inv_buf2)); + ret = ELFEDIT_CMDRET_MOD; + ehdr->e_ident[EI_CLASS] = class; + } + } + break; + + case EHDR_CMD_T_EI_DATA: + { + /* The argument gives the ELFDATA value */ + int data = (int)elfedit_atoconst_range(argstate.argv[0], + MSG_ORIG(MSG_STR_VALUE), 0, 255, + ELFEDIT_CONST_ELFDATA); + const char *name = elfedit_atoconst_value_to_str( + ELFEDIT_CONST_EI, EI_DATA, 1); + + if (ehdr->e_ident[EI_DATA] == data) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_EI_S_S_OK), name, + conv_ehdr_data(data, 0, &inv_buf1)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_EI_S_S_CHG), name, + conv_ehdr_data(ehdr->e_ident[EI_DATA], + 0, &inv_buf1), + conv_ehdr_data(data, 0, &inv_buf2)); + ret = ELFEDIT_CMDRET_MOD; + ehdr->e_ident[EI_DATA] = data; + } + } + break; + + case EHDR_CMD_T_EI_VERSION: + { + /* The argument gives the version */ + int ver = (int)elfedit_atoconst_range(argstate.argv[0], + MSG_ORIG(MSG_STR_VALUE), 0, 255, ELFEDIT_CONST_EV); + const char *name = elfedit_atoconst_value_to_str( + ELFEDIT_CONST_EI, EI_VERSION, 1); + + if (ehdr->e_ident[EI_VERSION] == ver) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_EI_S_S_OK), name, + conv_ehdr_vers(ver, 0, &inv_buf1)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_EI_S_S_CHG), name, + conv_ehdr_vers(ehdr->e_ident[EI_VERSION], + 0, &inv_buf1), + conv_ehdr_vers(ver, 0, &inv_buf2)); + ret = ELFEDIT_CMDRET_MOD; + ehdr->e_ident[EI_VERSION] = ver; + } + } + break; + + case EHDR_CMD_T_EI_OSABI: + { + /* The argument gives the ABI code */ + int osabi = (int)elfedit_atoconst_range( + argstate.argv[0], MSG_ORIG(MSG_STR_VALUE), 0, 255, + ELFEDIT_CONST_ELFOSABI); + const char *name = elfedit_atoconst_value_to_str( + ELFEDIT_CONST_EI, EI_OSABI, 1); + + if (ehdr->e_ident[EI_OSABI] == osabi) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_EI_S_S_OK), name, + conv_ehdr_osabi(osabi, 0, &inv_buf1)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_EI_S_S_CHG), name, + conv_ehdr_osabi(ehdr->e_ident[EI_OSABI], + 0, &inv_buf1), + conv_ehdr_osabi(osabi, 0, &inv_buf2)); + ret = ELFEDIT_CMDRET_MOD; + ehdr->e_ident[EI_OSABI] = osabi; + } + } + break; + + case EHDR_CMD_T_EI_ABIVERSION: + { + /* The argument gives the ABI version */ + int abiver = (int)elfedit_atoui_range(argstate.argv[0], + MSG_ORIG(MSG_STR_VALUE), 0, 255, NULL); + const char *name = elfedit_atoconst_value_to_str( + ELFEDIT_CONST_EI, EI_ABIVERSION, 1); + + if (ehdr->e_ident[EI_ABIVERSION] == abiver) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_EI_S_X_OK), name, + EC_WORD(abiver)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_EI_S_X_CHG), name, + EC_WORD(ehdr->e_ident[EI_ABIVERSION]), + EC_WORD(abiver)); + ret = ELFEDIT_CMDRET_MOD; + ehdr->e_ident[EI_ABIVERSION] = abiver; + } + } + break; + } + + /* + * If we modified the ELF header, tell libelf. + */ + if (ret == ELFEDIT_CMDRET_MOD) + elfedit_modified_ehdr(obj_state); + + /* Do autoprint */ + print_ehdr(cmd, e_ident_ndx, 1, &argstate); + + return (ret); +} + + + + +/* + * Command completion functions for the various commands + */ + +/*ARGSUSED*/ +static void +cpl_e_ident(elfedit_obj_state_t *obj_state, void *cpldata, int argc, + const char *argv[], int num_opt) +{ + elfedit_atoui_t ndx; + + /* + * This command doesn't accept options, so num_opt should be + * 0. This is a defensive measure, in case that should change. + */ + argc -= num_opt; + argv += num_opt; + + if (argc == 1) { + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_EI); + return; + } + + if (argc != 2) + return; + + /* + * In order to offer up the right completion strings for + * the value, we need to know what index was given for + * the first argument. If we don't recognize the index, + * we want to return quietly without issuing an error, + * so we use elfedit_atoui_range2(), which returns + * a success/failure result and does not throw any errors. + */ + if (elfedit_atoconst_range2(argv[0], 0, EI_NIDENT - 1, + ELFEDIT_CONST_EI, &ndx) == 0) + return; + switch (ndx) { + case EI_CLASS: + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_ELFCLASS); + break; + case EI_DATA: + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_ELFDATA); + break; + case EI_VERSION: + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_EV); + break; + case EI_OSABI: + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_ELFOSABI); + break; + } +} + +/*ARGSUSED*/ +static void +cpl_e_type(elfedit_obj_state_t *obj_state, void *cpldata, int argc, + const char *argv[], int num_opt) +{ + /* + * This command doesn't accept options, so num_opt should be + * 0. This is a defensive measure, in case that should change. + */ + argc -= num_opt; + argv += num_opt; + + if (argc == 1) + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_ET); +} + +/*ARGSUSED*/ +static void +cpl_e_machine(elfedit_obj_state_t *obj_state, void *cpldata, int argc, + const char *argv[], int num_opt) +{ + /* + * This command doesn't accept options, so num_opt should be + * 0. This is a defensive measure, in case that should change. + */ + argc -= num_opt; + argv += num_opt; + + if (argc == 1) + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_EM); +} + +/*ARGSUSED*/ +static void +cpl_e_version(elfedit_obj_state_t *obj_state, void *cpldata, int argc, + const char *argv[], int num_opt) +{ + /* + * This command doesn't accept options, so num_opt should be + * 0. This is a defensive measure, in case that should change. + */ + argc -= num_opt; + argv += num_opt; + + if (argc == 1) + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_EV); +} + +/*ARGSUSED*/ +static void +cpl_e_flags(elfedit_obj_state_t *obj_state, void *cpldata, int argc, + const char *argv[], int num_opt) +{ + /* This routine allows multiple flags to be specified */ + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_EF); +} + +/*ARGSUSED*/ +static void +cpl_e_shstrndx(elfedit_obj_state_t *obj_state, void *cpldata, int argc, + const char *argv[], int num_opt) +{ + enum { NAME, INDEX, TYPE } op; + Word ndx; + + /* + * The plainargument can be a section name, index, or + * type, based on the options used. All have completions. + */ + if (argc != (num_opt + 1)) + return; + + op = NAME; + for (ndx = 0; ndx < num_opt; ndx++) { + if (strcmp(argv[ndx], MSG_ORIG(MSG_STR_MINUS_SHNDX)) == 0) + op = INDEX; + else if (strcmp(argv[ndx], MSG_ORIG(MSG_STR_MINUS_SHTYP)) == 0) + op = TYPE; + } + + if (obj_state == NULL) { /* No object available */ + if (op == TYPE) + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SHT); + return; + } + + /* + * Loop over the sections and supply command completion + * for the string tables in the file. + */ + for (ndx = 0; ndx < obj_state->os_shnum; ndx++) { + elfedit_section_t *sec = &obj_state->os_secarr[ndx]; + + if (sec->sec_shdr->sh_type != SHT_STRTAB) + 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), + ndx); + elfedit_cpl_match(cpldata, index, 1); + } + break; + case TYPE: + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SHT_STRTAB); + break; + } + } +} + +/*ARGSUSED*/ +static void +cpl_ei_class(elfedit_obj_state_t *obj_state, void *cpldata, int argc, + const char *argv[], int num_opt) +{ + /* + * This command doesn't accept options, so num_opt should be + * 0. This is a defensive measure, in case that should change. + */ + argc -= num_opt; + argv += num_opt; + + if (argc == 1) + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_ELFCLASS); +} + +/*ARGSUSED*/ +static void +cpl_ei_data(elfedit_obj_state_t *obj_state, void *cpldata, int argc, + const char *argv[], int num_opt) +{ + /* + * This command doesn't accept options, so num_opt should be + * 0. This is a defensive measure, in case that should change. + */ + argc -= num_opt; + argv += num_opt; + + if (argc == 1) + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_ELFDATA); +} + +/*ARGSUSED*/ +static void +cpl_ei_osabi(elfedit_obj_state_t *obj_state, void *cpldata, int argc, + const char *argv[], int num_opt) +{ + /* + * This command doesn't accept options, so num_opt should be + * 0. This is a defensive measure, in case that should change. + */ + argc -= num_opt; + argv += num_opt; + + if (argc == 1) + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_ELFOSABI); +} + + + + +/* + * 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(EHDR_CMD_T_DUMP, obj_state, argc, argv)); +} + + +static elfedit_cmdret_t +cmd_e_ident(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(EHDR_CMD_T_E_IDENT, obj_state, argc, argv)); +} + + +static elfedit_cmdret_t +cmd_e_type(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(EHDR_CMD_T_E_TYPE, obj_state, argc, argv)); +} + + +static elfedit_cmdret_t +cmd_e_machine(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(EHDR_CMD_T_E_MACHINE, obj_state, argc, argv)); +} + + +static elfedit_cmdret_t +cmd_e_version(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(EHDR_CMD_T_E_VERSION, obj_state, argc, argv)); +} + + +static elfedit_cmdret_t +cmd_e_entry(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(EHDR_CMD_T_E_ENTRY, obj_state, argc, argv)); +} + + +static elfedit_cmdret_t +cmd_e_phoff(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(EHDR_CMD_T_E_PHOFF, obj_state, argc, argv)); +} + + +static elfedit_cmdret_t +cmd_e_shoff(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(EHDR_CMD_T_E_SHOFF, obj_state, argc, argv)); +} + + +static elfedit_cmdret_t +cmd_e_flags(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(EHDR_CMD_T_E_FLAGS, obj_state, argc, argv)); +} + + +static elfedit_cmdret_t +cmd_e_ehsize(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(EHDR_CMD_T_E_EHSIZE, obj_state, argc, argv)); +} + + +static elfedit_cmdret_t +cmd_e_phentsize(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(EHDR_CMD_T_E_PHENTSIZE, obj_state, argc, argv)); +} + + +static elfedit_cmdret_t +cmd_e_phnum(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(EHDR_CMD_T_E_PHNUM, obj_state, argc, argv)); +} + + +static elfedit_cmdret_t +cmd_e_shentsize(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(EHDR_CMD_T_E_SHENTSIZE, obj_state, argc, argv)); +} + + +static elfedit_cmdret_t +cmd_e_shnum(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(EHDR_CMD_T_E_SHNUM, obj_state, argc, argv)); +} + + +static elfedit_cmdret_t +cmd_e_shstrndx(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(EHDR_CMD_T_E_SHSTRNDX, obj_state, argc, argv)); +} + + +static elfedit_cmdret_t +cmd_ei_mag0(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(EHDR_CMD_T_EI_MAG0, obj_state, argc, argv)); +} + + +static elfedit_cmdret_t +cmd_ei_mag1(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(EHDR_CMD_T_EI_MAG1, obj_state, argc, argv)); +} + + +static elfedit_cmdret_t +cmd_ei_mag2(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(EHDR_CMD_T_EI_MAG2, obj_state, argc, argv)); +} + + +static elfedit_cmdret_t +cmd_ei_mag3(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(EHDR_CMD_T_EI_MAG3, obj_state, argc, argv)); +} + + +static elfedit_cmdret_t +cmd_ei_class(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(EHDR_CMD_T_EI_CLASS, obj_state, argc, argv)); +} + + +static elfedit_cmdret_t +cmd_ei_data(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(EHDR_CMD_T_EI_DATA, obj_state, argc, argv)); +} + + +static elfedit_cmdret_t +cmd_ei_version(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(EHDR_CMD_T_EI_VERSION, obj_state, argc, argv)); +} + + +static elfedit_cmdret_t +cmd_ei_osabi(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(EHDR_CMD_T_EI_OSABI, obj_state, argc, argv)); +} + + +static elfedit_cmdret_t +cmd_ei_abiversion(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(EHDR_CMD_T_EI_ABIVERSION, obj_state, argc, argv)); +} + + + + +/*ARGSUSED*/ +elfedit_module_t * +elfedit_init(elfedit_module_version_t version) +{ + /* Many of the commands only accept -o */ + static elfedit_cmd_optarg_t opt_std[] = { + { ELFEDIT_STDOA_OPT_O, NULL, + ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, + { NULL } + }; + + + /* ehdr:dump */ + static const char *name_dump[] = { + MSG_ORIG(MSG_CMD_DUMP), + MSG_ORIG(MSG_STR_EMPTY), /* "" makes this the default command */ + NULL + }; + + /* ehdr:e_ident */ + static const char *name_e_ident[] = { + MSG_ORIG(MSG_CMD_E_IDENT), NULL }; + static elfedit_cmd_optarg_t arg_e_ident[] = { + { MSG_ORIG(MSG_STR_INDEX), + /* MSG_INTL(MSG_ARGDESC_E_IDENT_NDX) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_E_IDENT_NDX), + ELFEDIT_CMDOA_F_OPT, 0 }, + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_ARGDESC_E_IDENT_VALUE) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_E_IDENT_VALUE), + ELFEDIT_CMDOA_F_OPT, 0 }, + { NULL } + }; + + /* ehdr:e_type */ + static const char *name_e_type[] = { + MSG_ORIG(MSG_CMD_E_TYPE), NULL }; + static elfedit_cmd_optarg_t arg_e_type[] = { + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_ARGDESC_E_TYPE_VALUE) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_E_TYPE_VALUE), + ELFEDIT_CMDOA_F_OPT, 0 }, + { NULL } + }; + + /* ehdr:e_machine */ + static const char *name_e_machine[] = { + MSG_ORIG(MSG_CMD_E_MACHINE), NULL }; + static elfedit_cmd_optarg_t arg_e_machine[] = { + { MSG_ORIG(MSG_STR_TYPE), + /* MSG_INTL(MSG_ARGDESC_E_MACHINE_VALUE) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_E_MACHINE_VALUE), + ELFEDIT_CMDOA_F_OPT, 0 }, + { NULL } + }; + + /* ehdr:e_version */ + static const char *name_e_version[] = { + MSG_ORIG(MSG_CMD_E_VERSION), NULL }; + static elfedit_cmd_optarg_t arg_e_version[] = { + { MSG_ORIG(MSG_STR_VERSION), + /* MSG_INTL(MSG_ARGDESC_E_VERSION_VALUE) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_E_VERSION_VALUE), + ELFEDIT_CMDOA_F_OPT, 0 }, + { NULL } + }; + + /* ehdr:e_entry */ + static const char *name_e_entry[] = { + MSG_ORIG(MSG_CMD_E_ENTRY), NULL }; + static elfedit_cmd_optarg_t arg_e_entry[] = { + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_ARGDESC_E_ENTRY_VALUE) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_E_ENTRY_VALUE), + ELFEDIT_CMDOA_F_OPT, 0 }, + { NULL } + }; + + /* ehdr:e_phoff */ + static const char *name_e_phoff[] = { + MSG_ORIG(MSG_CMD_E_PHOFF), NULL }; + static elfedit_cmd_optarg_t arg_e_phoff[] = { + { MSG_ORIG(MSG_STR_OFFSET), + /* MSG_INTL(MSG_ARGDESC_E_PHOFF_VALUE) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_E_PHOFF_VALUE), + ELFEDIT_CMDOA_F_OPT, 0 }, + { NULL } + }; + + /* ehdr:e_shoff */ + static const char *name_e_shoff[] = { + MSG_ORIG(MSG_CMD_E_SHOFF), NULL }; + static elfedit_cmd_optarg_t arg_e_shoff[] = { + { MSG_ORIG(MSG_STR_OFFSET), + /* MSG_INTL(MSG_ARGDESC_E_SHOFF_VALUE) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_E_SHOFF_VALUE), + ELFEDIT_CMDOA_F_OPT, 0 }, + { NULL } + }; + + /* ehdr:e_flags */ + static const char *name_e_flags[] = { + MSG_ORIG(MSG_CMD_E_FLAGS), NULL }; + static elfedit_cmd_optarg_t opt_e_flags[] = { + { ELFEDIT_STDOA_OPT_AND, NULL, + ELFEDIT_CMDOA_F_INHERIT, EHDR_OPT_F_AND, EHDR_OPT_F_OR }, + { ELFEDIT_STDOA_OPT_CMP, NULL, + ELFEDIT_CMDOA_F_INHERIT, EHDR_OPT_F_CMP, 0 }, + { ELFEDIT_STDOA_OPT_O, NULL, + ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, + { ELFEDIT_STDOA_OPT_OR, NULL, + ELFEDIT_CMDOA_F_INHERIT, EHDR_OPT_F_OR, EHDR_OPT_F_AND }, + { NULL } + }; + static elfedit_cmd_optarg_t arg_e_flags[] = { + { MSG_ORIG(MSG_STR_FLAGVALUE), + /* MSG_INTL(MSG_ARGDESC_E_FLAGS_VALUE) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_E_FLAGS_VALUE), + ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT, 0 }, + { NULL } + }; + + /* ehdr:e_ehsize */ + static const char *name_e_ehsize[] = { + MSG_ORIG(MSG_CMD_E_EHSIZE), NULL }; + static elfedit_cmd_optarg_t arg_e_ehsize[] = { + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_ARGDESC_E_EHSIZE_VALUE) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_E_EHSIZE_VALUE), + ELFEDIT_CMDOA_F_OPT, 0 }, + { NULL } + }; + + /* ehdr:e_phentsize */ + static const char *name_e_phentsize[] = { + MSG_ORIG(MSG_CMD_E_PHENTSIZE), NULL }; + static elfedit_cmd_optarg_t arg_e_phentsize[] = { + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_ARGDESC_E_PHENTSIZE_VALUE) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_E_PHENTSIZE_VALUE), + ELFEDIT_CMDOA_F_OPT, 0 }, + { NULL } + }; + + /* ehdr:e_phnum */ + static const char *name_e_phnum[] = { + MSG_ORIG(MSG_CMD_E_PHNUM), NULL }; + static elfedit_cmd_optarg_t arg_e_phnum[] = { + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_ARGDESC_E_PHNUM_VALUE) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_E_PHNUM_VALUE), + ELFEDIT_CMDOA_F_OPT, 0 }, + { NULL } + }; + + /* ehdr:e_shentsize */ + static const char *name_e_shentsize[] = { + MSG_ORIG(MSG_CMD_E_SHENTSIZE), NULL }; + static elfedit_cmd_optarg_t arg_e_shentsize[] = { + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_ARGDESC_E_SHENTSIZE_VALUE) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_E_SHENTSIZE_VALUE), + ELFEDIT_CMDOA_F_OPT, 0 }, + { NULL } + }; + + /* ehdr:e_shnum */ + static const char *name_e_shnum[] = { + MSG_ORIG(MSG_CMD_E_SHNUM), NULL }; + static elfedit_cmd_optarg_t arg_e_shnum[] = { + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_ARGDESC_E_SHNUM_VALUE) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_E_SHNUM_VALUE), + ELFEDIT_CMDOA_F_OPT, 0 }, + { NULL } + }; + + /* ehdr:e_shstrndx */ + static const char *name_e_shstrndx[] = { + MSG_ORIG(MSG_CMD_E_SHSTRNDX), NULL }; + static elfedit_cmd_optarg_t opt_e_shstrndx[] = { + { ELFEDIT_STDOA_OPT_O, NULL, + ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, + { MSG_ORIG(MSG_STR_MINUS_SHNDX), + /* MSG_INTL(MSG_OPTDESC_SHNDX) */ + ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), 0, + EHDR_OPT_F_SHNDX, EHDR_OPT_F_SHTYP }, + { MSG_ORIG(MSG_STR_MINUS_SHTYP), + /* MSG_INTL(MSG_OPTDESC_SHTYP) */ + ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), 0, + EHDR_OPT_F_SHTYP, EHDR_OPT_F_SHNDX, }, + { NULL } + }; + static elfedit_cmd_optarg_t arg_e_shstrndx[] = { + { MSG_ORIG(MSG_STR_SEC), + /* MSG_INTL(MSG_ARGDESC_E_SHSTRNDX_SEC) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_E_SHSTRNDX_SEC), + ELFEDIT_CMDOA_F_OPT, 0 }, + { NULL } + }; + + /* ehdr:ei_mag0 */ + static const char *name_ei_mag0[] = { + MSG_ORIG(MSG_CMD_EI_MAG0), NULL }; + static elfedit_cmd_optarg_t arg_ei_mag0[] = { + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_ARGDESC_EI_MAG0_VALUE) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_EI_MAG0_VALUE), + ELFEDIT_CMDOA_F_OPT, 0 }, + { NULL } + }; + + /* ehdr:ei_mag1 */ + static const char *name_ei_mag1[] = { + MSG_ORIG(MSG_CMD_EI_MAG1), NULL }; + static elfedit_cmd_optarg_t arg_ei_mag1[] = { + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_ARGDESC_EI_MAG1_VALUE) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_EI_MAG1_VALUE), + ELFEDIT_CMDOA_F_OPT, 0 }, + { NULL } + }; + + /* ehdr:ei_mag2 */ + static const char *name_ei_mag2[] = { + MSG_ORIG(MSG_CMD_EI_MAG2), NULL }; + static elfedit_cmd_optarg_t arg_ei_mag2[] = { + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_ARGDESC_EI_MAG2_VALUE) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_EI_MAG2_VALUE), + ELFEDIT_CMDOA_F_OPT, 0 }, + { NULL } + }; + + /* ehdr:ei_mag3 */ + static const char *name_ei_mag3[] = { + MSG_ORIG(MSG_CMD_EI_MAG3), NULL }; + static elfedit_cmd_optarg_t arg_ei_mag3[] = { + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_ARGDESC_EI_MAG3_VALUE) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_EI_MAG3_VALUE), + ELFEDIT_CMDOA_F_OPT, 0 }, + { NULL } + }; + + /* ehdr:ei_class */ + static const char *name_ei_class[] = { + MSG_ORIG(MSG_CMD_EI_CLASS), NULL }; + static elfedit_cmd_optarg_t arg_ei_class[] = { + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_ARGDESC_EI_CLASS_VALUE) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_EI_CLASS_VALUE), + ELFEDIT_CMDOA_F_OPT, 0 }, + { NULL } + }; + + /* ehdr:ei_data */ + static const char *name_ei_data[] = { + MSG_ORIG(MSG_CMD_EI_DATA), NULL }; + static elfedit_cmd_optarg_t arg_ei_data[] = { + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_ARGDESC_EI_DATA_VALUE) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_EI_DATA_VALUE), + ELFEDIT_CMDOA_F_OPT, 0 }, + { NULL } + }; + + /* ehdr:ei_version */ + static const char *name_ei_version[] = { + MSG_ORIG(MSG_CMD_EI_VERSION), NULL }; + /* Note: arg_e_version is also used for this command */ + + /* ehdr:ei_osabi */ + static const char *name_ei_osabi[] = { + MSG_ORIG(MSG_CMD_EI_OSABI), NULL }; + static elfedit_cmd_optarg_t arg_ei_osabi[] = { + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_ARGDESC_EI_OSABI_VALUE) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_EI_OSABI_VALUE), + ELFEDIT_CMDOA_F_OPT, 0 }, + { NULL } + }; + + /* ehdr:ei_abiversion */ + static const char *name_ei_abiversion[] = { + MSG_ORIG(MSG_CMD_EI_ABIVERSION), NULL }; + static elfedit_cmd_optarg_t arg_ei_abiversion[] = { + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_ARGDESC_EI_ABIVERSION_VALUE) */ + ELFEDIT_I18NHDL(MSG_ARGDESC_EI_ABIVERSION_VALUE), + ELFEDIT_CMDOA_F_OPT, 0 }, + { NULL } + }; + + + + + static elfedit_cmd_t cmds[] = { + /* ehdr:dump */ + { cmd_dump, NULL, name_dump, + /* MSG_INTL(MSG_DESC_DUMP) */ + ELFEDIT_I18NHDL(MSG_DESC_DUMP), + /* MSG_INTL(MSG_HELP_DUMP) */ + ELFEDIT_I18NHDL(MSG_HELP_DUMP), + NULL, NULL }, + + /* ehdr:e_ident */ + { cmd_e_ident, cpl_e_ident, name_e_ident, + /* MSG_INTL(MSG_DESC_E_IDENT) */ + ELFEDIT_I18NHDL(MSG_DESC_E_IDENT), + /* MSG_INTL(MSG_HELP_E_IDENT) */ + ELFEDIT_I18NHDL(MSG_HELP_E_IDENT), + opt_std, arg_e_ident }, + + /* ehdr:e_type */ + { cmd_e_type, cpl_e_type, name_e_type, + /* MSG_INTL(MSG_DESC_E_TYPE) */ + ELFEDIT_I18NHDL(MSG_DESC_E_TYPE), + /* MSG_INTL(MSG_HELP_E_TYPE) */ + ELFEDIT_I18NHDL(MSG_HELP_E_TYPE), + opt_std, arg_e_type }, + + /* ehdr:e_machine */ + { cmd_e_machine, cpl_e_machine, name_e_machine, + /* MSG_INTL(MSG_DESC_E_MACHINE) */ + ELFEDIT_I18NHDL(MSG_DESC_E_MACHINE), + /* MSG_INTL(MSG_HELP_E_MACHINE) */ + ELFEDIT_I18NHDL(MSG_HELP_E_MACHINE), + opt_std, arg_e_machine }, + + /* ehdr:e_version */ + { cmd_e_version, cpl_e_version, name_e_version, + /* MSG_INTL(MSG_DESC_E_VERSION) */ + ELFEDIT_I18NHDL(MSG_DESC_E_VERSION), + /* MSG_INTL(MSG_HELP_E_VERSION) */ + ELFEDIT_I18NHDL(MSG_HELP_E_VERSION), + opt_std, arg_e_version }, + + /* ehdr:e_entry */ + { cmd_e_entry, NULL, name_e_entry, + /* MSG_INTL(MSG_DESC_E_ENTRY) */ + ELFEDIT_I18NHDL(MSG_DESC_E_ENTRY), + /* MSG_INTL(MSG_HELP_E_ENTRY) */ + ELFEDIT_I18NHDL(MSG_HELP_E_ENTRY), + opt_std, arg_e_entry }, + + /* ehdr:e_phoff */ + { cmd_e_phoff, NULL, name_e_phoff, + /* MSG_INTL(MSG_DESC_E_PHOFF) */ + ELFEDIT_I18NHDL(MSG_DESC_E_PHOFF), + /* MSG_INTL(MSG_HELP_E_PHOFF) */ + ELFEDIT_I18NHDL(MSG_HELP_E_PHOFF), + opt_std, arg_e_phoff }, + + /* ehdr:e_shoff */ + { cmd_e_shoff, NULL, name_e_shoff, + /* MSG_INTL(MSG_DESC_E_SHOFF) */ + ELFEDIT_I18NHDL(MSG_DESC_E_SHOFF), + /* MSG_INTL(MSG_HELP_E_SHOFF) */ + ELFEDIT_I18NHDL(MSG_HELP_E_SHOFF), + opt_std, arg_e_shoff }, + + /* ehdr:e_flags */ + { cmd_e_flags, cpl_e_flags, name_e_flags, + /* MSG_INTL(MSG_DESC_E_FLAGS) */ + ELFEDIT_I18NHDL(MSG_DESC_E_FLAGS), + /* MSG_INTL(MSG_HELP_E_FLAGS) */ + ELFEDIT_I18NHDL(MSG_HELP_E_FLAGS), + opt_e_flags, arg_e_flags }, + + /* ehdr:e_ehsize */ + { cmd_e_ehsize, NULL, name_e_ehsize, + /* MSG_INTL(MSG_DESC_E_EHSIZE) */ + ELFEDIT_I18NHDL(MSG_DESC_E_EHSIZE), + /* MSG_INTL(MSG_HELP_E_EHSIZE) */ + ELFEDIT_I18NHDL(MSG_HELP_E_EHSIZE), + opt_std, arg_e_ehsize }, + + /* ehdr:e_phentsize */ + { cmd_e_phentsize, NULL, name_e_phentsize, + /* MSG_INTL(MSG_DESC_E_PHENTSIZE) */ + ELFEDIT_I18NHDL(MSG_DESC_E_PHENTSIZE), + /* MSG_INTL(MSG_HELP_E_PHENTSIZE) */ + ELFEDIT_I18NHDL(MSG_HELP_E_PHENTSIZE), + opt_std, arg_e_phentsize }, + + /* ehdr:e_phnum */ + { cmd_e_phnum, NULL, name_e_phnum, + /* MSG_INTL(MSG_DESC_E_PHNUM) */ + ELFEDIT_I18NHDL(MSG_DESC_E_PHNUM), + /* MSG_INTL(MSG_HELP_E_PHNUM) */ + ELFEDIT_I18NHDL(MSG_HELP_E_PHNUM), + opt_std, arg_e_phnum }, + + /* ehdr:e_shentsize */ + { cmd_e_shentsize, NULL, name_e_shentsize, + /* MSG_INTL(MSG_DESC_E_SHENTSIZE) */ + ELFEDIT_I18NHDL(MSG_DESC_E_SHENTSIZE), + /* MSG_INTL(MSG_HELP_E_SHENTSIZE) */ + ELFEDIT_I18NHDL(MSG_HELP_E_SHENTSIZE), + opt_std, arg_e_shentsize }, + + /* ehdr:e_shnum */ + { cmd_e_shnum, NULL, name_e_shnum, + /* MSG_INTL(MSG_DESC_E_SHNUM) */ + ELFEDIT_I18NHDL(MSG_DESC_E_SHNUM), + /* MSG_INTL(MSG_HELP_E_SHNUM) */ + ELFEDIT_I18NHDL(MSG_HELP_E_SHNUM), + opt_std, arg_e_shnum }, + + /* ehdr:e_shstrndx */ + { cmd_e_shstrndx, cpl_e_shstrndx, name_e_shstrndx, + /* MSG_INTL(MSG_DESC_E_SHSTRNDX) */ + ELFEDIT_I18NHDL(MSG_DESC_E_SHSTRNDX), + /* MSG_INTL(MSG_HELP_E_SHSTRNDX) */ + ELFEDIT_I18NHDL(MSG_HELP_E_SHSTRNDX), + opt_e_shstrndx, arg_e_shstrndx }, + + /* ehdr:ei_mag0 */ + { cmd_ei_mag0, NULL, name_ei_mag0, + /* MSG_INTL(MSG_DESC_EI_MAG0) */ + ELFEDIT_I18NHDL(MSG_DESC_EI_MAG0), + /* MSG_INTL(MSG_HELP_EI_MAG0) */ + ELFEDIT_I18NHDL(MSG_HELP_EI_MAG0), + opt_std, arg_ei_mag0 }, + + /* ehdr:ei_mag1 */ + { cmd_ei_mag1, NULL, name_ei_mag1, + /* MSG_INTL(MSG_DESC_EI_MAG1) */ + ELFEDIT_I18NHDL(MSG_DESC_EI_MAG1), + /* MSG_INTL(MSG_HELP_EI_MAG1) */ + ELFEDIT_I18NHDL(MSG_HELP_EI_MAG1), + opt_std, arg_ei_mag1 }, + + /* ehdr:ei_mag2 */ + { cmd_ei_mag2, NULL, name_ei_mag2, + /* MSG_INTL(MSG_DESC_EI_MAG2) */ + ELFEDIT_I18NHDL(MSG_DESC_EI_MAG2), + /* MSG_INTL(MSG_HELP_EI_MAG2) */ + ELFEDIT_I18NHDL(MSG_HELP_EI_MAG2), + opt_std, arg_ei_mag2 }, + + /* ehdr:ei_mag3 */ + { cmd_ei_mag3, NULL, name_ei_mag3, + /* MSG_INTL(MSG_DESC_EI_MAG3) */ + ELFEDIT_I18NHDL(MSG_DESC_EI_MAG3), + /* MSG_INTL(MSG_HELP_EI_MAG3) */ + ELFEDIT_I18NHDL(MSG_HELP_EI_MAG3), + opt_std, arg_ei_mag3 }, + + /* ehdr:ei_class */ + { cmd_ei_class, cpl_ei_class, name_ei_class, + /* MSG_INTL(MSG_DESC_EI_CLASS) */ + ELFEDIT_I18NHDL(MSG_DESC_EI_CLASS), + /* MSG_INTL(MSG_HELP_EI_CLASS) */ + ELFEDIT_I18NHDL(MSG_HELP_EI_CLASS), + opt_std, arg_ei_class }, + + /* ehdr:ei_data */ + { cmd_ei_data, cpl_ei_data, name_ei_data, + /* MSG_INTL(MSG_DESC_EI_DATA) */ + ELFEDIT_I18NHDL(MSG_DESC_EI_DATA), + /* MSG_INTL(MSG_HELP_EI_DATA) */ + ELFEDIT_I18NHDL(MSG_HELP_EI_DATA), + opt_std, arg_ei_data }, + + /* ehdr:ei_version */ + { cmd_ei_version, cpl_e_version, name_ei_version, + /* MSG_INTL(MSG_DESC_EI_VERSION) */ + ELFEDIT_I18NHDL(MSG_DESC_EI_VERSION), + /* MSG_INTL(MSG_HELP_EI_VERSION) */ + ELFEDIT_I18NHDL(MSG_HELP_EI_VERSION), + opt_std, arg_e_version }, + + /* ehdr:ei_osabi */ + { cmd_ei_osabi, cpl_ei_osabi, name_ei_osabi, + /* MSG_INTL(MSG_DESC_EI_OSABI) */ + ELFEDIT_I18NHDL(MSG_DESC_EI_OSABI), + /* MSG_INTL(MSG_HELP_EI_OSABI) */ + ELFEDIT_I18NHDL(MSG_HELP_EI_OSABI), + opt_std, arg_ei_osabi }, + + /* ehdr:ei_abiversion */ + { cmd_ei_abiversion, NULL, name_ei_abiversion, + /* MSG_INTL(MSG_DESC_EI_ABIVERSION) */ + ELFEDIT_I18NHDL(MSG_DESC_EI_ABIVERSION), + /* MSG_INTL(MSG_HELP_EI_ABIVERSION) */ + ELFEDIT_I18NHDL(MSG_HELP_EI_ABIVERSION), + opt_std, arg_ei_abiversion }, + + { 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); +} diff --git a/usr/src/cmd/sgs/elfedit/modules/common/ehdr.msg b/usr/src/cmd/sgs/elfedit/modules/common/ehdr.msg new file mode 100644 index 0000000000..2db5cde3b1 --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/modules/common/ehdr.msg @@ -0,0 +1,650 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" + +@ _START_ + +# Message file for elfedit 'ehdr' module + +@ MSG_ID_ELFEDIT_EHDR + + +# Debug messages +@ MSG_DEBUG_E_S_OK "ehdr.%s: value unchanged: %s\n" +@ MSG_DEBUG_E_S_CHG "ehdr.%s: change from %s to %s\n" +@ MSG_DEBUG_E_D_OK "ehdr.%s: value unchanged: %d\n" +@ MSG_DEBUG_E_D_CHG "ehdr.%s: change from %d to %d\n" +@ MSG_DEBUG_E_LLX_OK "ehdr.%s: value unchanged: %#llx\n" +@ MSG_DEBUG_E_LLX_CHG "ehdr.%s: change from %#llx to %#llx\n" +@ MSG_DEBUG_EI_S_S_OK "ehdr.e_ident[%s]: value unchanged: %s\n"; +@ MSG_DEBUG_EI_S_S_CHG "ehdr.e_ident[%s]: change from %s to %s\n" +@ MSG_DEBUG_EI_S_X_OK "ehdr.e_ident[%s]: value unchanged: %#x\n"; +@ MSG_DEBUG_EI_S_X_CHG "ehdr.e_ident[%s]: change from %#x to %#x\n" +@ MSG_DEBUG_EI_D_X_OK "ehdr.e_ident[%d]: value unchanged: %#x\n" +@ MSG_DEBUG_EI_D_X_CHG "ehdr.e_ident[%d]: change from %#x to %#x\n" +@ MSG_DEBUG_SHDR0_D_OK "shdr[0].%s: value unchanged: %d\n" +@ MSG_DEBUG_SHDR0_D_CHG "shdr[0].%s: change from %d to %d\n" +@ MSG_DEBUG_NOTSTRTAB "ehdr.%s: ELF warning: section is not a \ + string table: %d\n" + + +# Module description + +@ MSG_MOD_DESC "ELF Header" + + +# 1-line description strings + +@ MSG_DESC_DUMP "Dump ELF Header" +@ MSG_DESC_E_IDENT "ELF Identification" +@ MSG_DESC_E_TYPE "Object File Type" +@ MSG_DESC_E_MACHINE "Machine Architecture" +@ MSG_DESC_E_VERSION "Object File Version" +@ MSG_DESC_E_ENTRY "Starting Virtual Address" +@ MSG_DESC_E_PHOFF "Program Header Table File Offset" +@ MSG_DESC_E_SHOFF "Section Header Table File Offset" +@ MSG_DESC_E_FLAGS "Processor-Specific Flags" +@ MSG_DESC_E_EHSIZE "ELF Header's Size" +@ MSG_DESC_E_PHENTSIZE "Program Header Table Entry Size" +@ MSG_DESC_E_PHNUM "Number Program Header Entries" +@ MSG_DESC_E_SHENTSIZE "Section Header Table Entry Size" +@ MSG_DESC_E_SHNUM "Number Section Header Entries" +@ MSG_DESC_E_SHSTRNDX "Section Name String Table Index" + +@ MSG_DESC_EI_MAG0 "File Identification Byte #1" +@ MSG_DESC_EI_MAG1 "File Identification Byte #2" +@ MSG_DESC_EI_MAG2 "File Identification Byte #3" +@ MSG_DESC_EI_MAG3 "File Identification Byte #4" +@ MSG_DESC_EI_CLASS "File Class (System Word Size)" +@ MSG_DESC_EI_DATA "Data Encoding (Byte Order)" +@ MSG_DESC_EI_VERSION "File Version" +@ MSG_DESC_EI_OSABI "Operating System / ABI Identification" +@ MSG_DESC_EI_ABIVERSION "ABI version" + +# Command option description strings + +@ MSG_OPTDESC_SHNDX "\ + Interpret the sec argument as a section index rather than\n\ + as a section name. section can be one of the well known SHN_\n\ + symbolic constants, or any integer.\n" + +@ MSG_OPTDESC_SHTYP "\ + Interpret the sec argument as a section type rather than\n\ + as a section name. section can be one of the well known SHT_\n\ + symbolic constants, or any integer.\n" + +# Command argument description strings + +@ MSG_ARGDESC_E_IDENT_NDX "\ + Index of element of e_ident[] array. This can be\n\ + an integer value, or any of the EI_ symbolic constants\n\ + defined in /usr/include/sys/elf.h.\n" + +@ MSG_ARGDESC_E_IDENT_VALUE "\ + New value for element of e_ident[] array. This can be\n\ + an integer value, or any symbolic constants defined in\n\ + /usr/include/sys/elf.h that apply to the selected item.\n" + +@ MSG_ARGDESC_E_TYPE_VALUE "\ + New value for type of the ELF object. This can be\n\ + an integer value, or any of the ET_ symbolic constants\n\ + defined in /usr/include/sys/elf.h.\n" + +@ MSG_ARGDESC_E_MACHINE_VALUE "\ + New value for architecture of the ELF object. This can be\n\ + an integer value, or any of the EM_ symbolic constants\n\ + defined in /usr/include/sys/elf.h.\n" + +@ MSG_ARGDESC_E_VERSION_VALUE "\ + New value for version of the ELF object. This can be\n\ + an integer value, or any of the EV_ symbolic constants\n\ + defined in /usr/include/sys/elf.h.\n" + +@ MSG_ARGDESC_E_ENTRY_VALUE "\ + New value for virtual address to which the system first transfers control.\n" + +@ MSG_ARGDESC_E_PHOFF_VALUE "\ + New value for program header table's file offset.\n" + +@ MSG_ARGDESC_E_SHOFF_VALUE "\ + New value for section header table's file offset.\n" + +@ MSG_ARGDESC_E_FLAGS_VALUE "\ + New value for processor-specific flags. This can be an integer\n\ + value, or any of the EF_ symbolic constants defined in the\n\ + system header files\n" + +@ MSG_ARGDESC_E_EHSIZE_VALUE "\ + New value for size of ELF header, in bytes.\n" + +@ MSG_ARGDESC_E_PHENTSIZE_VALUE "\ + New value for size of one entry in the file's program header table,\n\ + in bytes.\n" + +@ MSG_ARGDESC_E_PHNUM_VALUE "\ + New value for number of entries in the program header table.\n" + +@ MSG_ARGDESC_E_SHENTSIZE_VALUE "\ + New value for size of one entry in the file's section header table,\n\ + in bytes.\n" + +@ MSG_ARGDESC_E_SHNUM_VALUE "\ + New value for number of entries in the section header table.\n" + +@ MSG_ARGDESC_E_SHSTRNDX_SEC "\ + String table section containing section name strings.\n\ + By default, this argument is interpreted as the name\n\ + of the desired section. The section index of the first\n\ + section with the specified name is used.\n\ + \n\ + If -shndx is set, then sec is a section index, and is\n\ + interpreted as an integer, or one of the well known SHN_\n\ + symbolic constant names.\n\ + \n\ + If -shtyp is set, then sec is a section type, and is\n\ + interpreted as an integer, or one of the well known SHT_\n\ + symbolic constant names. The section index of the first\n\ + section with the specified type is used.\n" + +@ MSG_ARGDESC_EI_MAG0_VALUE "\ + New value for first byte of file magic number.\n" + +@ MSG_ARGDESC_EI_MAG1_VALUE "\ + New value for second byte of file magic number.\n" + +@ MSG_ARGDESC_EI_MAG2_VALUE "\ + New value for third byte of file magic number.\n" + +@ MSG_ARGDESC_EI_MAG3_VALUE "\ + New value for fourth byte of file magic number.\n" + +@ MSG_ARGDESC_EI_CLASS_VALUE "\ + New value for file's class. This can be an integer value, or any of\n\ + the ELFCLASS symbolic constants defined in /usr/include/sys/elf.h.\n" + +@ MSG_ARGDESC_EI_DATA_VALUE "\ + New value for file's data encoding. This can be an integer\n\ + value, or any ELFDATA symbolic constants defined in\n\ + /usr/include/sys/elf.h.\n" + +# Note: EI_VERSION uses the same string as E_VERSION, above + +@ MSG_ARGDESC_EI_OSABI_VALUE "\ + New value for ABI identification of the ELF object. This can be\n\ + an integer value, or any of the ELFOSABI_ symbolic constants\n\ + defined in /usr/include/sys/elf.h.\n" + +@ MSG_ARGDESC_EI_ABIVERSION_VALUE "\ + New value for version of the ABI to which the object is targeted.\n" + + +# Help strings + +@ MSG_HELP_DUMP " \ + The ehdr:dump command is used to display the contents of\n\ + the ELF header using the same style used by the elfdump program.\n" + +@ MSG_HELP_E_IDENT " \ + Examine or modify ELF Identification information for the\n\ + object. This information is found in the e_ident array in\n\ + the ELF header.\n\ + \n\ + If ehdr:e_ident is called without any argument, all values\n\ + the value in e_ident are shown. If called with the index\n\ + argument, the selected element of e_ident is shown. If also\n\ + called with the value argument, the selected e_ident element\n\ + is updated with the new value.\n" + + +@ MSG_HELP_E_TYPE " \ + Examine or modify the object file type. This information is\n\ + found in the e_type field of the ELF header.\n\ + \n\ + If ehdr:e_type is called without an argument, the value of\n\ + e_type is shown. If called with the value argument, the\n\ + e_type field is updated with the new value.\n\ + \n\ + Note: Changing the type code of an object does not change the\n\ + other contents of the file, and is unlikely to produce a usable\n\ + ELF object.\n" + + +@ MSG_HELP_E_MACHINE " \ + Examine or modify the required architecture of the object.\n\ + This information is found in the e_machine field of the\n\ + ELF header.\n\ + \n\ + If ehdr:e_machine is called without an argument, the value of\n\ + e_machine is shown. If called with the value argument, the\n\ + e_machine field is updated with the new value.\n\ + \n\ + Note: Changing the architecture code of an object does not change the\n\ + other contents of the file, and is unlikely to produce a usable\n\ + ELF object.\n" + + +@ MSG_HELP_E_VERSION " \ + Examine or modify the object file version. This information\n\ + is found in the e_version field of the ELF header.\n\ + \n\ + If ehdr:e_version is called without an argument, the value of\n\ + e_version is shown. If called with the value argument, the\n\ + e_version field is updated with the new value.\n\ + \n\ + Note: The e_ident[EI_VERSION] element of the ELF header\n\ + identification array also contains a version value. These\n\ + two fields should be set to the same value. Use the\n\ + ehdr:ei_version command to change that element.\n" + + +@ MSG_HELP_E_ENTRY " \ + Examine or modify the virtual address to which the system\n\ + first transfers control, thus starting the process. This\n\ + information is found in the e_entry field of the ELF header.\n\ + If the file has no associated entry point, this member\n\ + holds zero.\n\ + \n\ + If ehdr:e_entry is called without an argument, the value of\n\ + e_entry is shown. If called with the value argument, the\n\ + e_entry field is updated with the new value.\n\ + \n\ + Note: The entry point of an object is highly system\n\ + dependent. Changing it is likely to produce an object that\n\ + does not run properly.\n" + + +@ MSG_HELP_E_PHOFF " \ + Examine or modify the program header table's file offset.\n\ + This information is found in the e_phoff field of the\n\ + ELF header. If the file has no program header table, this\n\ + member holds zero.\n\ + \n\ + If ehdr:e_phoff is called without an argument, the value of\n\ + e_phoff is shown. If called with the value argument, the\n\ + e_phoff field is updated with the new value.\n\ + \n\ + Note: Changing the e_phoff field of an object does not change\n\ + the actual layout of the file or move the program header table.\n\ + As such, changing this value is likely to produce an unusable\n\ + ELF object.\n" + + +@ MSG_HELP_E_SHOFF " \ + Examine or modify the section header table's file offset.\n\ + This information is found in the e_shoff field of the\n\ + ELF header. If the file has no section header table, this\n\ + member holds zero.\n\ + \n\ + If ehdr:e_shoff is called without an argument, the value of\n\ + e_shoff is shown. If called with the value argument, the\n\ + e_shoff field is updated with the new value.\n\ + \n\ + Note: Changing the e_shoff field of an object does not change\n\ + the actual layout of the file or move the section header table.\n\ + As such, changing this value is likely to produce an unusable\n\ + ELF object.\n" + + +@ MSG_HELP_E_FLAGS " \ + Examine or modify the processor specific flags associated\n\ + with the file. This information is found in the e_flags\n\ + field of the ELF header.\n\ + \n\ + If ehdr:e_flags is called without an argument, the value of\n\ + e_flags is shown. If called with one or more flag_value\n\ + arguments, the the following steps are taken:\n\ + \n \ + o\tAll the flag_value arguments are OR'd together.\n\ + \n \ + o\tIf the -cmp option has been specified, the new value\n\ + \tis complemented.\n\ + \n \ + o\tThe e_flags field of the ELF header is updated with\n\ + \tthe new value. If -and is specified, the new value is\n\ + \tAND'd against the existing value. If -or is specified,\n\ + \tthe new value is OR'd against the existing value. If\n\ + \tneither -and or -or are specified, the new value replaces\n\ + \tthe existing value.\n\ + \n\ + Note: Changing the e_flags field of an object does not change\n\ + the code contained in the file. Setting a flag that implies\n\ + an ability the existing code cannot support will produce an\n\ + unusable ELF object.\n" + + +@ MSG_HELP_E_EHSIZE " \ + Examine or modify the size of the ELF header. This information\n\ + is found in the e_ehsize field of the ELF header.\n\ + \n\ + If ehdr:e_ehsize is called without an argument, the value of\n\ + e_ehsize is shown. If called with the value argument, the\n\ + e_ehsize field is updated with the new value.\n\ + \n\ + Note: Changing the e_ehsize field of the ELF header does not\n\ + change the size of the actual ELF header data structure. Setting\n\ + it to a different value is likely to produce an unusable ELF object.\n" + + +@ MSG_HELP_E_PHENTSIZE " \ + Examine or modify the size of one entry in the file's program\n\ + header table. This information is found in the e_phentsize\n\ + field of the ELF header.\n\ + \n\ + If ehdr:e_phentsize is called without an argument, the value of\n\ + e_phentsize is shown. If called with the value argument, the\n\ + e_phentsize field is updated with the new value.\n\ + \n\ + Note: Changing the e_phentsize field of the ELF header does\n\ + not change the size of the actual program header array elements.\n\ + Setting it to a different value is likely to produce an unusable\n\ + ELF object.\n" + + +@ MSG_HELP_E_PHNUM " \ + Examine or modify the number of entries in the program header\n\ + table. This information is found in the e_phnum field of the\n\ + ELF header, or in the sh_link field of the first section header\n\ + in the case of extended program indexes.\n\ + \n\ + If the number of program headers is greater than or equal\n\ + to PN_XNUM (0xffff), e_phnum has the value PN_XNUM, and the\n\ + actual number of program header table entries is contained\n\ + in the sh_info field of the section header at index 0.\n\ + \n\ + If ehdr:e_phnum is called without an argument, the number\n\ + of program headers is shown. If called with the value argument,\n\ + the number is updated with the new value.\n\ + \n\ + Note: Changing e_phnum and/or the sh_link field of the first\n\ + section header does not change the size of the actual program\n\ + header array in the file.\n" + + +@ MSG_HELP_E_SHENTSIZE " \ + Examine or modify the size of one entry in the file's section\n\ + header table. This information is found in the e_shentsize\n\ + field of the ELF header.\n\ + \n\ + If ehdr:e_shentsize is called without an argument, the value of\n\ + e_shentsize is shown. If called with the value argument, the\n\ + e_shentsize field is updated with the new value.\n\ + \n\ + Note: Changing the e_shentsize field of the ELF header does\n\ + not change the size of the actual section header array elements.\n\ + Setting it to a different value is likely to produce an unusable\n\ + ELF object.\n" + + +@ MSG_HELP_E_SHNUM " \ + Examine or modify the number of entries in the section header\n\ + table. This information is found in the e_shnum field of the\n\ + ELF header, or in the sh_size field of the first section header\n\ + in the case of extended section indexes.\n\ + \n\ + If the number of sections is greater than or equal to\n\ + SHN_LORESERVE (0xff00), e_shnum has the value zero, and\n\ + the actual number of section header table entries is\n\ + contained in the sh_size field of the section header\n\ + at index 0.\n\ + \n\ + If ehdr:e_shnum is called without an argument, the number of\n\ + sections is shown. If called with the value argument, the\n\ + number of sections is updated with the new value.\n\ + \n\ + Note: Changing e_shnum and/or the sh_size field of the first\n\ + section header does not change the size of the actual section\n\ + header array in the file.\n" + + +@ MSG_HELP_E_SHSTRNDX " \ + Examine or modify the section table index of the entry that is\n\ + associated with the section name string table. This information\n\ + is found in the e_shstrndx field of the ELF header, or in the\n\ + sh_link field of the first section header in the case of\n\ + extended section indexes. If the file has no section name\n\ + string table, this member holds the value SHN_UNDEF.\n\ + \n\ + If the section name string table section index is greater\n\ + than or equal to SHN_LORESERVE (0xff00), e_shstrndx has the\n\ + value SHN_XINDEX (0xffff) and the actual index of the section\n\ + name string table section is contained in the sh_link field of\n\ + the section header at index 0.\n\ + \n\ + If ehdr:e_shstrndx is called without an argument, the index of\n\ + the section name string table is shown. If called with the value\n\ + argument, the ELF header is updated with the new value.\n\ + \n\ + Note: The e_shstrndx field of the ELF header must reference\n\ + a string table section. Otherwise, diagnostic tools will be\n\ + confused by the resulting object.\n" + + +@ MSG_HELP_EI_MAG0 " \ + Examine or modify the first byte of the object's \"magic number\".\n\ + The magic number is the first 4 bytes of the object file, and is\n\ + used to identify it as being an ELF object. This information\n\ + is found in the e_ident[EI_MAG0] field of the ELF header.\n\ + \n\ + If ehdr:ei_mag0 is called without an argument, the value of\n\ + e_ident[EI_MAG0] is shown. If called with the value argument,\n\ + the e_ident[EI_MAG0] field is updated with the new value.\n\ + \n\ + Note: Changing the e_ident[EI_MAG0] field of the ELF header\n\ + to a value other than 0x7f will cause the system to fail to\n\ + identify it as an ELF object.\n" + + +@ MSG_HELP_EI_MAG1 " \ + Examine or modify the second byte of the object's \"magic number\".\n\ + The magic number is the first 4 bytes of the object file, and is\n\ + used to identify it as being an ELF object. This information\n\ + is found in the e_ident[EI_MAG1] field of the ELF header.\n\ + \n\ + If ehdr:ei_mag1 is called without an argument, the value of\n\ + e_ident[EI_MAG1] is shown. If called with the value argument,\n\ + the e_ident[EI_MAG1] field is updated with the new value.\n\ + \n\ + Note: Changing the e_ident[EI_MAG1] field of the ELF header\n\ + to a value other than 0x45 ('E') will cause the system to\n\ + fail to identify it as an ELF object.\n" + + +@ MSG_HELP_EI_MAG2 " \ + Examine or modify the third byte of the object's \"magic number\".\n\ + The magic number is the first 4 bytes of the object file, and is\n\ + used to identify it as being an ELF object. This information\n\ + is found in the e_ident[EI_MAG2] field of the ELF header.\n\ + \n\ + If ehdr:ei_mag2 is called without an argument, the value of\n\ + e_ident[EI_MAG2] is shown. If called with the value argument,\n\ + the e_ident[EI_MAG2] field is updated with the new value.\n\ + \n\ + Note: Changing the e_ident[EI_MAG2] field of the ELF header\n\ + to a value other than 0x4c ('L') will cause the system to\n\ + fail to identify it as an ELF object.\n" + + +@ MSG_HELP_EI_MAG3 " \ + Examine or modify the fourth byte of the object's \"magic number\".\n\ + The magic number is the first 4 bytes of the object file, and is\n\ + used to identify it as being an ELF object. This information\n\ + is found in the e_ident[EI_MAG3] field of the ELF header.\n\ + \n\ + If ehdr:ei_mag3 is called without an argument, the value of\n\ + e_ident[EI_MAG3] is shown. If called with the value argument,\n\ + e_ident[EI_MAG3] field is updated with the new value.\n\ + \n\ + Note: Changing the e_ident[EI_MAG3] field of the ELF header\n\ + to a value other than 0x46 ('F') will cause the system to\n\ + fail to identify it as an ELF object.\n" + + +@ MSG_HELP_EI_CLASS " \ + Examine or modify the file's class (system word size). This\n\ + information is found in the e_ident[EI_CLASS] field of the\n\ + ELF header.\n\ + \n\ + If ehdr:ei_class is called without an argument, the value of\n\ + e_ident[EI_CLASS] is shown. If called with the value argument,\n\ + the e_ident[EI_CLASS] field is updated with the new value.\n\ + \n\ + Note: Changing the e_ident[EI_CLASS] field of the ELF header\n\ + does not alter the contents of the file, and is therefore\n\ + likely to render the file unusable.\n" + +@ MSG_HELP_EI_DATA " \ + Examine or modify the file's data encoding (byte order). This\n\ + information is found in the e_ident[EI_DATA] field of the\n\ + ELF header.\n\ + \n\ + If ehdr:ei_data is called without an argument, the value of\n\ + e_ident[EI_DATA] is shown. If called with the value argument,\n\ + the e_ident[EI_DATA] field is updated with the new value.\n\ + \n\ + Note: Changing the e_ident[EI_DATA] field of the ELF header\n\ + does not alter the contents of the file or the byte order\n\ + of the data, and is therefore likely to render the file unusable.\n" + + +@ MSG_HELP_EI_VERSION " \ + Examine or modify the object file version. This information\n\ + is found in the e_ident[EI_VERSION] field of the ELF header.\n\ + \n\ + If ehdr:ei_version is called without an argument, the value\n\ + of e_ident[EI_VERSION] is shown. If called with the value\n\ + argument, the e_ident[EI_VERSION] field is updated with the\n\ + new value.\n\ + \n\ + Note: The e_version element of the ELF header also contains\n\ + a version value. These two fields should be set to the same\n\ + value. Use the ehdr:e_version command to change that element.\n" + + +@ MSG_HELP_EI_OSABI " \ + Examine or modify the operating system / ABI identification for\n\ + the object. This information is kept in the e_ident[EI_OSABI]\n\ + field of the ELF header.\n\ + \n\ + If ehdr:ei_osabi is called without arguments, current value of\n\ + e_ident[EI_OSABI] is shown. If called with the value argument,\n\ + the e_ident[EI_OSABI] field is updated with the new value.\n\ + \n\ + Note: Changing the e_ident[EI_OSABI] field of the ELF header\n\ + does not alter the contents of the file, or cause the actual\n\ + ABI to be altered. Setting an incompatible ABI value is likely\n\ + to cause the object to become unusable.\n" + + +@ MSG_HELP_EI_ABIVERSION " \ + Examine or modify the ABI version for the object. This\n\ + information is kept in the e_ident[EI_ABIVERSION] field of\n\ + the ELF header.\n\ + \n\ + If ehdr:ei_abiversion is called without arguments, the current\n\ + value of e_ident[EI_ABIVERSION] is shown. If called with the\n\ + value argument, the e_ident[EI_ABIVERSION] field is updated with\n\ + the new value.\n\ + \n\ + Note: The meaning of the e_ident[EI_ABIVERSION] field of\n\ + the ELF header depends on the value of e_ident[EI_OSABI]\n\ + (See ehdr:ei_osabi).\n" + + +@ _END_ + + + +# Strings + +@ MSG_STR_EMPTY "" +@ MSG_STR_NL "\n" +@ MSG_STR_VALUE "value" +@ MSG_STR_EIDENT_HDR "e_ident:\n" +@ MSG_STR_INDEX "index" +@ MSG_STR_SEC "sec" +@ MSG_STR_TYPE "type" +@ MSG_STR_VERSION "version" +@ MSG_STR_OFFSET "offset" +@ MSG_STR_FLAGVALUE "flag_value" +@ MSG_STR_MINUS_SHNDX "-shndx" +@ MSG_STR_MINUS_SHTYP "-shtyp" +@ MSG_STR_SH_INFO "sh_info" +@ MSG_STR_SH_LINK "sh_link" +@ MSG_STR_SH_SIZE "sh_size" + + +# Format strings +@ MSG_FMT_BKTSTR "[%s]" +@ MSG_FMT_BKTINT "[%d]" +@ MSG_FMT_STRNL "%s\n" +@ MSG_FMT_WORDVAL "%u" +@ MSG_FMT_DECNUMNL "%d\n" +@ MSG_FMT_HEXNUM "%#x" +@ MSG_FMT_HEXNUMNL "%#x\n" +@ MSG_FMT_HEXNUM_QCHR "%#x ('%c')" +@ MSG_FMT_EI_ELT " %-18s%s\n" + + + + +# The following strings represent reserved words, files, pathnames and symbols. +# Reference to this strings is via the MSG_ORIG() macro, and thus no message +# translation is required. + + +# Module name + +@ MSG_MOD_NAME "ehdr" + + +# Command names + +@ MSG_CMD_DUMP "dump" + +@ MSG_CMD_E_IDENT "e_ident" +@ MSG_CMD_E_TYPE "e_type" +@ MSG_CMD_E_MACHINE "e_machine" +@ MSG_CMD_E_VERSION "e_version" +@ MSG_CMD_E_ENTRY "e_entry" +@ MSG_CMD_E_PHOFF "e_phoff" +@ MSG_CMD_E_SHOFF "e_shoff" +@ MSG_CMD_E_FLAGS "e_flags" +@ MSG_CMD_E_EHSIZE "e_ehsize" +@ MSG_CMD_E_PHENTSIZE "e_phentsize" +@ MSG_CMD_E_PHNUM "e_phnum" +@ MSG_CMD_E_SHENTSIZE "e_shentsize" +@ MSG_CMD_E_SHNUM "e_shnum" +@ MSG_CMD_E_SHSTRNDX "e_shstrndx" + +@ MSG_CMD_EI_MAG0 "ei_mag0" +@ MSG_CMD_EI_MAG1 "ei_mag1" +@ MSG_CMD_EI_MAG2 "ei_mag2" +@ MSG_CMD_EI_MAG3 "ei_mag3" +@ MSG_CMD_EI_CLASS "ei_class" +@ MSG_CMD_EI_DATA "ei_data" +@ MSG_CMD_EI_VERSION "ei_version" +@ MSG_CMD_EI_OSABI "ei_osabi" +@ MSG_CMD_EI_ABIVERSION "ei_abiversion" diff --git a/usr/src/cmd/sgs/elfedit/modules/common/mapfile-vers b/usr/src/cmd/sgs/elfedit/modules/common/mapfile-vers new file mode 100644 index 0000000000..373b5af383 --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/modules/common/mapfile-vers @@ -0,0 +1,191 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# + +# This mapfile is shared by all of the elfedit modules. +# These sharable objects only export two functions, +# elfedit[32|64]_init. Everything else is reduced to +# local scope. +# +# The routines exported by elfedit for use by the modules +# are also defined here, using the PARENT mapfile keyword. + +SUNWprivate_1.1 { + global: + # Standard init routines exported by every module + elfedit32_init; + elfedit64_init; + + + # liblddbg dbg_print() function + dbg_print = PARENT NODIRECT; + + + # Core API + elfedit_command_usage = PARENT; + elfedit_cpl_match = PARENT; + elfedit_elferr = PARENT; + elfedit_flags = PARENT; + elfedit_malloc = PARENT; + elfedit_msg = PARENT; + elfedit_outstyle = PARENT; + elfedit_pager_init = PARENT; + elfedit_printf = PARENT; + elfedit_realloc = PARENT; + + + + # ato[u]i routines + elfedit_const_to_atoui = PARENT; + elfedit_mach_sunw_hw1_to_atoui = PARENT; + + elfedit_atoi = PARENT; + elfedit_atoui = PARENT; + elfedit_atoconst = PARENT; + + elfedit_atoi2 = PARENT; + elfedit_atoui2 = PARENT; + elfedit_atoconst2 = PARENT; + + elfedit_atoi_range = PARENT; + elfedit_atoui_range = PARENT; + elfedit_atoconst_range = PARENT; + + elfedit_atoi_range2 = PARENT; + elfedit_atoui_range2 = PARENT; + elfedit_atoconst_range2 = PARENT; + + elfedit_atoi_value_to_str = PARENT; + elfedit_atoui_value_to_str = PARENT; + elfedit_atoconst_value_to_str = PARENT; + + elfedit_cpl_atoi = PARENT; + elfedit_cpl_atoui = PARENT; + elfedit_cpl_atoconst = PARENT; + + + + # Convenience functions built on top of the ato[u]i routines + elfedit_atobool = PARENT; + elfedit_atoshndx = PARENT; + + + + # Getopt + elfedit_getopt_init = PARENT; + elfedit_getopt = PARENT; + + + + # Utilities + elfedit_array_elts_delete = PARENT; + + elfedit_array_elts_move = PARENT; + + elfedit_bits_set = PARENT; + + elfedit32_dyn_elt_init = PARENT; + elfedit64_dyn_elt_init = PARENT; + + elfedit32_dyn_elt_save = PARENT; + elfedit64_dyn_elt_save = PARENT; + + elfedit32_dyn_offset_to_str = PARENT; + elfedit64_dyn_offset_to_str = PARENT; + + elfedit32_dynstr_getpad = PARENT; + elfedit64_dynstr_getpad = PARENT; + + elfedit32_dynstr_insert = PARENT; + elfedit64_dynstr_insert = PARENT; + + elfedit32_modified_data = PARENT; + elfedit64_modified_data = PARENT; + + elfedit32_modified_ehdr = PARENT; + elfedit64_modified_ehdr = PARENT; + + elfedit32_modified_phdr = PARENT; + elfedit64_modified_phdr = PARENT; + + elfedit32_modified_shdr = PARENT; + elfedit64_modified_shdr = PARENT; + + elfedit32_name_to_shndx = PARENT; + elfedit64_name_to_shndx = PARENT; + + elfedit32_name_to_symndx = PARENT; + elfedit64_name_to_symndx = PARENT; + + elfedit32_offset_to_str = PARENT; + elfedit64_offset_to_str = PARENT; + + elfedit32_sec_findstr = PARENT; + elfedit64_sec_findstr = PARENT; + + elfedit32_sec_getcap = PARENT; + elfedit64_sec_getcap = PARENT; + + elfedit32_sec_getdyn = PARENT; + elfedit64_sec_getdyn = PARENT; + + elfedit32_sec_getstr = PARENT; + elfedit64_sec_getstr = PARENT; + + elfedit32_sec_getsyminfo = PARENT; + elfedit64_sec_getsyminfo = PARENT; + + elfedit32_sec_getsymtab = PARENT; + elfedit64_sec_getsymtab = PARENT; + + elfedit32_sec_getversym = PARENT; + elfedit64_sec_getversym = PARENT; + + elfedit32_sec_getxshndx = PARENT; + elfedit64_sec_getxshndx = PARENT; + + elfedit32_sec_issymtab = PARENT; + elfedit64_sec_issymtab = PARENT; + + elfedit32_shndx_to_name = PARENT; + elfedit64_shndx_to_name = PARENT; + + elfedit32_sec_msgprefix = PARENT; + elfedit64_sec_msgprefix = PARENT; + + elfedit32_strtab_insert = PARENT; + elfedit64_strtab_insert = PARENT; + + elfedit32_strtab_insert_test = PARENT; + elfedit64_strtab_insert_test = PARENT; + + elfedit32_type_to_shndx = PARENT; + elfedit64_type_to_shndx = PARENT; + +local: + *; +}; diff --git a/usr/src/cmd/sgs/elfedit/modules/common/phdr.c b/usr/src/cmd/sgs/elfedit/modules/common/phdr.c new file mode 100644 index 0000000000..1d40c14ecd --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/modules/common/phdr.c @@ -0,0 +1,1386 @@ +/* + * 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 <machdep.h> +#include <elfedit.h> +#include <strings.h> +#include <conv.h> +#include <debug.h> +#include <phdr_msg.h> + + +/* + * Program headers + */ + + + +/* + * This module uses shared code for several of the commands. + * It is sometimes necessary to know which specific command + * is active. + */ +typedef enum { + /* Dump command, used as module default to display dynamic section */ + PHDR_CMD_T_DUMP = 0, /* phdr:dump */ + + /* Commands that correspond directly to program header fields */ + PHDR_CMD_T_P_TYPE = 1, /* phdr:p_type */ + PHDR_CMD_T_P_OFFSET = 2, /* phdr:p_offset */ + PHDR_CMD_T_P_VADDR = 3, /* phdr:p_vaddr */ + PHDR_CMD_T_P_PADDR = 4, /* phdr:p_paddr */ + PHDR_CMD_T_P_FILESZ = 5, /* phdr:p_filesz */ + PHDR_CMD_T_P_MEMSZ = 6, /* phdr:p_memsz */ + PHDR_CMD_T_P_FLAGS = 7, /* phdr:p_flags */ + PHDR_CMD_T_P_ALIGN = 8, /* phdr:p_align */ + + /* Commands that do not correspond directly to a specific phdr tag */ + PHDR_CMD_T_INTERP = 9, /* phdr:interp */ + PHDR_CMD_T_DELETE = 10, /* phdr:delete */ + PHDR_CMD_T_MOVE = 11 /* phdr:move */ +} PHDR_CMD_T; + + + +/* + * The following type is ued by locate_interp() to return + * information about the interpreter program header. + */ +typedef struct { + Word phndx; /* Index of PT_INTERP header */ + Phdr *phdr; /* PT_INTERP header */ + elfedit_section_t *sec; /* Section containing string */ + Word stroff; /* Offset into string section */ + const char *str; /* Interpreter string */ +} INTERP_STATE; + + +#ifndef _ELF64 +/* + * We supply this function for the msg module + */ +const char * +_phdr_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 phdr_opt_t enum specifies a bit value for every optional + * argument allowed by a command in this module. + */ +typedef enum { + PHDR_OPT_F_AND = 1, /* -and: AND (&) values to dest */ + PHDR_OPT_F_CMP = 2, /* -cmp: Complement (~) values */ + PHDR_OPT_F_PHNDX = 4, /* -phndx: Program header by index, */ + /* not by name */ + PHDR_OPT_F_OR = 8 /* -or: OR (|) values to dest */ +} phdr_opt_t; + + +/* + * A variable of type ARGSTATE is used by each command to maintain + * information about the section headers and related things. It is + * initialized by process_args(), and used by the other routines. + */ +typedef struct { + elfedit_obj_state_t *obj_state; + phdr_opt_t optmask; /* Mask of options used */ + int argc; /* # of plain arguments */ + const char **argv; /* Plain arguments */ + int ndx_set; /* True if ndx is valid */ + Word ndx; /* Index of header if cmd */ + /* accepts it */ + int print_req; /* Call is a print request */ +} ARGSTATE; + + +/* + * Standard argument processing for phdr module + * + * entry + * obj_state, argc, argv - Standard command arguments + * optmask - Mask of allowed optional arguments. + * cmd - PHDR_CMD_T_* value giving identify of caller + * 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[], + PHDR_CMD_T cmd, ARGSTATE *argstate) +{ + elfedit_getopt_state_t getopt_state; + elfedit_getopt_ret_t *getopt_ret; + + bzero(argstate, sizeof (*argstate)); + argstate->obj_state = obj_state; + + 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; + + /* Are the right number of plain arguments present? */ + switch (cmd) { + case PHDR_CMD_T_DUMP: + if (argc > 1) + elfedit_command_usage(); + argstate->print_req = 1; + break; + case PHDR_CMD_T_P_FLAGS: + /* phdr:sh_flags allows an arbitrary number of arguments */ + argstate->print_req = (argc < 2); + break; + case PHDR_CMD_T_INTERP: + if (argc > 1) + elfedit_command_usage(); + argstate->print_req = (argc == 0); + break; + case PHDR_CMD_T_DELETE: + if ((argc < 1) || (argc > 2)) + elfedit_command_usage(); + argstate->print_req = 0; + break; + case PHDR_CMD_T_MOVE: + if ((argc < 2) || (argc > 3)) + elfedit_command_usage(); + argstate->print_req = 0; + break; + + default: + /* The remaining commands accept 2 plain arguments */ + if (argc > 2) + elfedit_command_usage(); + argstate->print_req = (argc < 2); + break; + } + + /* Return the updated values of argc/argv */ + argstate->argc = argc; + argstate->argv = argv; + + argstate->ndx_set = 0; + if ((argc > 0) && (cmd != PHDR_CMD_T_INTERP)) { + /* + * If the -phndx option is present, the first argument is + * the index of the header to use. Otherwise, it is a + * name corresponding to its type, similar to the way + * elfdump works with its -N option. + */ + if (argstate->optmask & PHDR_OPT_F_PHNDX) { + argstate->ndx = (Word) elfedit_atoui_range( + argstate->argv[0], MSG_ORIG(MSG_STR_ELEMENT), 0, + argstate->obj_state->os_phnum - 1, NULL); + argstate->ndx_set = 1; + } else { + Conv_inv_buf_t inv_buf; + Word i; + Phdr *phdr; + + argstate->ndx = (Word) elfedit_atoconst( + argstate->argv[0], ELFEDIT_CONST_PT); + phdr = obj_state->os_phdr; + for (i = 0; i < obj_state->os_phnum; i++, phdr++) { + if (phdr->p_type == argstate->ndx) { + argstate->ndx = i; + argstate->ndx_set = 1; + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_PHDR), + EC_WORD(i), conv_phdr_type( + obj_state->os_ehdr->e_machine, + phdr->p_type, 0, &inv_buf)); + break; + } + } + if (i == argstate->obj_state->os_phnum) + elfedit_msg(ELFEDIT_MSG_ERR, + MSG_INTL(MSG_ERR_NOPHDR), conv_phdr_type( + obj_state->os_ehdr->e_machine, + argstate->ndx, 0, &inv_buf)); + } + } + + /* If there may be an arbitrary amount of output, use a pager */ + if (argc == 0) + elfedit_pager_init(); + +} + + + +/* + * Locate the interpreter string for the object and related information + * + * entry: + * obj_state - Object state + * interp - NULL, or variable to be filled in with information + * about the interpteter string. + */ +static const char * +locate_interp(elfedit_obj_state_t *obj_state, INTERP_STATE *interp) +{ + INTERP_STATE local_interp; + elfedit_section_t *strsec; /* String table */ + size_t phnum; /* # of program headers */ + int phndx; /* Index of PT_INTERP program header */ + Phdr *phdr; /* Program header array */ + Word i; + + if (interp == NULL) + interp = &local_interp; + + /* Locate the PT_INTERP program header */ + phnum = obj_state->os_phnum; + phdr = obj_state->os_phdr; + + for (phndx = 0; phndx < phnum; phndx++) { + if (phdr[phndx].p_type == PT_INTERP) { + interp->phndx = phndx; + interp->phdr = phdr + phndx; + break; + } + } + /* If no PT_INTERP program header found, we cannot proceed */ + if (phndx == phnum) + elfedit_elferr(obj_state->os_file, + MSG_INTL(MSG_ERR_NOINTERPPHDR)); + + /* + * Locate the section containing the interpteter string as well + * as the string itself. + * + * The program header contains a direct offset to the string, so + * we find the section by walking through the them looking for + * the one with a base and size that would contain the string. + * Note that this target section cannot be in a NOBITS section. + */ + for (i = 1; i < obj_state->os_shnum; i++) { + strsec = &obj_state->os_secarr[i]; + + if ((strsec->sec_shdr->sh_type != SHT_NOBITS) && + (interp->phdr->p_offset >= strsec->sec_shdr->sh_offset) && + ((interp->phdr->p_offset + interp->phdr->p_filesz) <= + (strsec->sec_shdr->sh_offset + + strsec->sec_shdr->sh_size))) { + interp->sec = strsec; + + interp->stroff = interp->phdr->p_offset - + strsec->sec_shdr->sh_offset; + interp->str = ((char *)strsec->sec_data->d_buf) + + interp->stroff; + return (interp->str); + } + } + + /* + * We don't expect to get here: If there is a PT_INTERP header, + * we fully expect the string to exist. + */ + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOINTERPSEC)); + /*NOTREACHED*/ + + return (NULL); /* For lint */ +} + +/* + * Print program header 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 - PHDR_CMD_T_* value giving identify of caller + * argstate - State block for section header array + * ndx - Index of first program header to display + * cnt - Number of program headers to display + */ +static void +print_phdr(PHDR_CMD_T cmd, int autoprint, ARGSTATE *argstate) +{ + elfedit_outstyle_t outstyle; + Word ndx, cnt; + + if (autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0)) + return; + + if (argstate->ndx_set) { + ndx = argstate->ndx; + cnt = 1; + } else { + ndx = 0; + cnt = argstate->obj_state->os_phnum; + } + + /* + * Pick an output style. phdr:dump is required to use the default + * style. The other commands use the current output style. + */ + outstyle = (cmd == PHDR_CMD_T_DUMP) ? + ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle(); + + /* + * If doing default output, use elfdump style where we + * show all program header attributes. In this case, the + * command that called us doesn't matter. + * + * Let PHDR_CMD_T_INTERP fall through: It isn't per-phdr like + * the other commands. + */ + if ((outstyle == ELFEDIT_OUTSTYLE_DEFAULT) && + (cmd != PHDR_CMD_T_INTERP)) { + Half mach = argstate->obj_state->os_ehdr->e_machine; + Phdr *phdr = argstate->obj_state->os_phdr + ndx; + + for (; cnt--; ndx++, phdr++) { + elfedit_printf(MSG_ORIG(MSG_STR_NL)); + elfedit_printf(MSG_INTL(MSG_ELF_PHDR), EC_WORD(ndx)); + Elf_phdr(0, mach, phdr); + } + return; + } + + switch (cmd) { + case PHDR_CMD_T_P_TYPE: + for (; cnt--; ndx++) { + Word p_type = argstate->obj_state->os_phdr[ndx].p_type; + Conv_inv_buf_t inv_buf; + + if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { + Half mach = + argstate->obj_state->os_ehdr->e_machine; + + elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), + conv_phdr_type(mach, p_type, 0, &inv_buf)); + } else { + elfedit_printf(MSG_ORIG(MSG_FMT_X_NL), + EC_WORD(p_type)); + } + } + return; + + case PHDR_CMD_T_P_OFFSET: + for (; cnt--; ndx++) + elfedit_printf(MSG_ORIG(MSG_FMT_LLX_NL), + EC_OFF(argstate->obj_state->os_phdr[ndx].p_offset)); + return; + + case PHDR_CMD_T_P_VADDR: + for (; cnt--; ndx++) + elfedit_printf(MSG_ORIG(MSG_FMT_LLX_NL), + EC_ADDR(argstate->obj_state->os_phdr[ndx].p_vaddr)); + return; + + case PHDR_CMD_T_P_PADDR: + for (; cnt--; ndx++) + elfedit_printf(MSG_ORIG(MSG_FMT_LLX_NL), + EC_ADDR(argstate->obj_state->os_phdr[ndx].p_paddr)); + return; + + case PHDR_CMD_T_P_FILESZ: + for (; cnt--; ndx++) + elfedit_printf(MSG_ORIG(MSG_FMT_LLX_NL), + EC_XWORD(argstate->obj_state-> + os_phdr[ndx].p_filesz)); + return; + + case PHDR_CMD_T_P_MEMSZ: + for (; cnt--; ndx++) + elfedit_printf(MSG_ORIG(MSG_FMT_LLX_NL), + EC_XWORD(argstate->obj_state-> + os_phdr[ndx].p_memsz)); + return; + + case PHDR_CMD_T_P_FLAGS: + for (; cnt--; ndx++) { + Word p_flags = + argstate->obj_state->os_phdr[ndx].p_flags; + + if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { + Conv_phdr_flags_buf_t phdr_flags_buf; + + elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), + conv_phdr_flags(p_flags, CONV_FMT_NOBKT, + &phdr_flags_buf)); + } else { + elfedit_printf(MSG_ORIG(MSG_FMT_X_NL), + EC_WORD(p_flags)); + } + } + return; + + case PHDR_CMD_T_P_ALIGN: + for (; cnt--; ndx++) + elfedit_printf(MSG_ORIG(MSG_FMT_LLX_NL), + EC_XWORD(argstate->obj_state-> + os_phdr[ndx].p_align)); + return; + + case PHDR_CMD_T_INTERP: + { + INTERP_STATE interp; + + (void) locate_interp(argstate->obj_state, &interp); + switch (outstyle) { + + case ELFEDIT_OUTSTYLE_DEFAULT: + elfedit_printf(MSG_INTL(MSG_FMT_ELF_INTERP), + interp.sec->sec_name, interp.str); + break; + case ELFEDIT_OUTSTYLE_SIMPLE: + elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), + interp.str); + break; + case ELFEDIT_OUTSTYLE_NUM: + elfedit_printf(MSG_ORIG(MSG_FMT_U_NL), + EC_WORD(interp.stroff)); + break; + } + } + return; + } +} + + +/* + * Called from cmd_body() in the case where a plain argument + * is given to phdr:interp to change the interpreter. + */ +static elfedit_cmdret_t +cmd_body_set_interp(ARGSTATE *argstate) +{ + elfedit_obj_state_t *obj_state = argstate->obj_state; + elfedit_section_t *strsec; /* String table */ + INTERP_STATE interp; + Word numdyn; /* # of elements in dyn arr */ + size_t phnum; /* # of program headers */ + Phdr *phdr; /* Program header array */ + Word i, j; + Word str_offset; /* Offset in strsec to new interp str */ + int str_found = 0; /* True when we have new interp str */ + Word str_size; /* Size of new interp string + NULL */ + + phnum = obj_state->os_phnum; + phdr = obj_state->os_phdr; + + /* Locate the PT_INTERP program header */ + (void) locate_interp(obj_state, &interp); + strsec = interp.sec; + str_offset = interp.stroff; + + /* + * If the given string is the same as the existing interpreter + * string, say so and return. + */ + if (strcmp(interp.str, argstate->argv[0]) == 0) { + elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_OLDINTERPOK), + EC_WORD(strsec->sec_shndx), strsec->sec_name, + EC_WORD(str_offset), interp.str); + return (ELFEDIT_CMDRET_NONE); + } + + /* + * An ELF PT_INTERP usually references its own special section + * instead of some other string table. The ELF ABI says that this + * section must be named ".interp". Hence, this is a rare case + * in which the name of a section can be taken as an indication + * of its contents. .interp is typically sized to just fit + * the original string, including its NULL termination. You can + * treat it as a string table with one string. + * + * Thanks to 'elfedit', it may be that we encounter a file where + * PT_INTERP does not reference the .interp section. This will happen + * if elfedit is used to change the interpreter to a string that is + * too big to fit in .interp, in which case we will use the + * .dynstr string table (That code is below, in this function). + * + * Given the above facts, our next step is to locate the .interp + * section and see if our new string will fit in it. Since we can't + * depend on PT_INTERP, we search the section headers to find a + * section whith the following characteristics: + * - The name is ".interp". + * - Section is allocable (SHF_ALLOC) and SHT_PROGBITS. + * - It is not part of a writable segment. + * If we find such a section, and the new string fits, we will + * write it there. + */ + str_size = strlen(argstate->argv[0]) + 1; + for (i = 1; i < obj_state->os_shnum; i++) { + strsec = &obj_state->os_secarr[i]; + if ((strcmp(strsec->sec_name, MSG_ORIG(MSG_SEC_INTERP)) == 0) && + (strsec->sec_shdr->sh_flags & SHF_ALLOC) && + (strsec->sec_shdr->sh_type & SHT_PROGBITS)) { + for (j = 0; j < phnum; j++) { + Phdr *tphdr = &phdr[j]; + if ((strsec->sec_shdr->sh_offset >= + tphdr->p_offset) && + ((strsec->sec_shdr->sh_offset + + strsec->sec_shdr->sh_size) <= + (tphdr->p_offset + tphdr->p_filesz)) && + (tphdr->p_flags & PF_W)) { + break; + } + } + if ((j == phnum) && + (str_size <= strsec->sec_shdr->sh_size)) { + /* .interp section found, and has room */ + str_found = 1; + str_offset = 0; + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_NEWISTR), EC_WORD(j), + strsec->sec_name, EC_WORD(str_offset), + argstate->argv[0]); + /* Put new value in section */ + (void) strncpy((char *)strsec->sec_data->d_buf, + argstate->argv[0], + strsec->sec_shdr->sh_size); + /* Set libelf dirty bit so change is flushed */ + elfedit_modified_data(strsec); + break; + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_LNGISTR), EC_WORD(j), + strsec->sec_name, EC_WORD(str_offset), + EC_WORD(str_size), + EC_WORD(strsec->sec_shdr->sh_size), + argstate->argv[0]); + } + } + } + + /* + * If the above did not find a string within the .interp section, + * then we have a second option. If this ELF object has a dynamic + * section, then we are willing to use strings from within the + * associated .dynstr string table. And if there is reserved space + * in .dynstr (as reported by the DT_SUNW_STRPAD dynamic entry), + * then we are even willing to add a new string to .dynstr. + */ + if (!str_found) { + elfedit_section_t *dynsec; + Dyn *dyn; + + dynsec = elfedit_sec_getdyn(obj_state, &dyn, &numdyn); + strsec = elfedit_sec_getstr(obj_state, + dynsec->sec_shdr->sh_link); + + /* Does string exist in the table already, or can we add it? */ + str_offset = elfedit_strtab_insert(obj_state, strsec, + dynsec, argstate->argv[0]); + } + + + /* + * If we are here, we know we have a replacement string, because + * the errors from checking .dynamic/.dynstr will not allow + * things to get here otherwise. + * + * The PT_INTERP program header references the string directly, + * so we add the section offset to the string offset. + */ + interp.phdr->p_offset = strsec->sec_shdr->sh_offset + str_offset; + interp.phdr->p_filesz = str_size; + elfedit_modified_phdr(obj_state); + elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_SETPHINTERP), + EC_WORD(interp.phndx), EC_XWORD(interp.phdr->p_offset), + EC_XWORD(interp.phdr->p_filesz)); + + return (ELFEDIT_CMDRET_MOD); +} + + +/* + * Common body for the phdr: 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 PHDR_CMD_T_* constants listed above, specifying + * which command to implement. + * obj_state, argc, argv - Standard command arguments + */ +static elfedit_cmdret_t +cmd_body(PHDR_CMD_T cmd, elfedit_obj_state_t *obj_state, + int argc, const char *argv[]) +{ + ARGSTATE argstate; + Phdr *phdr; + elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE; + int do_autoprint = 1; + + process_args(obj_state, argc, argv, cmd, &argstate); + + /* If this is a printing request, print and return */ + if (argstate.print_req) { + print_phdr(cmd, 0, &argstate); + return (ELFEDIT_CMDRET_NONE); + } + + + if (argstate.ndx_set) + phdr = &argstate.obj_state->os_phdr[argstate.ndx]; + + switch (cmd) { + /* + * PHDR_CMD_T_DUMP can't get here: It never has more than + * one argument, and is handled above. + */ + + case PHDR_CMD_T_P_TYPE: + { + Half mach = obj_state->os_ehdr->e_machine; + Word p_type = elfedit_atoconst(argstate.argv[1], + ELFEDIT_CONST_PT); + Conv_inv_buf_t inv_buf1, inv_buf2; + + if (phdr->p_type == p_type) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_S_OK), + argstate.ndx, MSG_ORIG(MSG_CMD_P_TYPE), + conv_phdr_type(mach, phdr->p_type, + 0, &inv_buf1)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_S_CHG), + argstate.ndx, MSG_ORIG(MSG_CMD_P_TYPE), + conv_phdr_type(mach, phdr->p_type, 0, + &inv_buf1), + conv_phdr_type(mach, p_type, 0, &inv_buf2)); + ret = ELFEDIT_CMDRET_MOD; + phdr->p_type = p_type; + } + } + break; + + case PHDR_CMD_T_P_OFFSET: + { + Off p_offset; + + p_offset = elfedit_atoui(argstate.argv[1], NULL); + if (phdr->p_offset == p_offset) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_LLX_OK), + argstate.ndx, MSG_ORIG(MSG_CMD_P_OFFSET), + EC_XWORD(phdr->p_offset)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_LLX_CHG), + argstate.ndx, MSG_ORIG(MSG_CMD_P_OFFSET), + EC_XWORD(phdr->p_offset), + EC_XWORD(p_offset)); + ret = ELFEDIT_CMDRET_MOD; + phdr->p_offset = p_offset; + } + } + break; + + case PHDR_CMD_T_P_VADDR: + { + Addr p_vaddr = elfedit_atoui(argstate.argv[1], NULL); + + if (phdr->p_vaddr == p_vaddr) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_LLX_OK), + argstate.ndx, MSG_ORIG(MSG_CMD_P_VADDR), + EC_ADDR(phdr->p_vaddr)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_LLX_CHG), + argstate.ndx, MSG_ORIG(MSG_CMD_P_VADDR), + EC_ADDR(phdr->p_vaddr), EC_ADDR(p_vaddr)); + ret = ELFEDIT_CMDRET_MOD; + phdr->p_vaddr = p_vaddr; + } + } + break; + + case PHDR_CMD_T_P_PADDR: + { + Addr p_paddr = elfedit_atoui(argstate.argv[1], NULL); + + if (phdr->p_paddr == p_paddr) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_LLX_OK), + argstate.ndx, MSG_ORIG(MSG_CMD_P_PADDR), + EC_ADDR(phdr->p_paddr)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_LLX_CHG), + argstate.ndx, MSG_ORIG(MSG_CMD_P_PADDR), + EC_ADDR(phdr->p_paddr), EC_ADDR(p_paddr)); + ret = ELFEDIT_CMDRET_MOD; + phdr->p_paddr = p_paddr; + } + } + break; + + case PHDR_CMD_T_P_FILESZ: + { + Xword p_filesz = elfedit_atoui(argstate.argv[1], NULL); + + if (phdr->p_filesz == p_filesz) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_LLX_OK), + argstate.ndx, MSG_ORIG(MSG_CMD_P_FILESZ), + EC_XWORD(phdr->p_filesz)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_LLX_CHG), + argstate.ndx, MSG_ORIG(MSG_CMD_P_FILESZ), + EC_XWORD(phdr->p_filesz), + EC_XWORD(p_filesz)); + ret = ELFEDIT_CMDRET_MOD; + phdr->p_filesz = p_filesz; + } + } + break; + + case PHDR_CMD_T_P_MEMSZ: + { + Xword p_memsz = elfedit_atoui(argstate.argv[1], NULL); + + if (phdr->p_memsz == p_memsz) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_LLX_OK), + argstate.ndx, MSG_ORIG(MSG_CMD_P_MEMSZ), + EC_XWORD(phdr->p_memsz)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_LLX_CHG), + argstate.ndx, MSG_ORIG(MSG_CMD_P_MEMSZ), + EC_XWORD(phdr->p_memsz), + EC_XWORD(p_memsz)); + ret = ELFEDIT_CMDRET_MOD; + phdr->p_memsz = p_memsz; + } + } + break; + + case PHDR_CMD_T_P_FLAGS: + { + Conv_phdr_flags_buf_t buf1, buf2; + Word p_flags = 0; + int i; + + /* Collect the flag arguments */ + for (i = 1; i < argstate.argc; i++) + p_flags |= + (Word) elfedit_atoconst(argstate.argv[i], + ELFEDIT_CONST_PF); + + /* Complement the value? */ + if (argstate.optmask & PHDR_OPT_F_CMP) + p_flags = ~p_flags; + + /* Perform any requested bit operations */ + if (argstate.optmask & PHDR_OPT_F_AND) + p_flags &= phdr->p_flags; + else if (argstate.optmask & PHDR_OPT_F_OR) + p_flags |= phdr->p_flags; + + /* Set the value */ + if (phdr->p_flags == p_flags) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_S_OK), + argstate.ndx, MSG_ORIG(MSG_CMD_P_FLAGS), + conv_phdr_flags(phdr->p_flags, 0, &buf1)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_S_CHG), + argstate.ndx, MSG_ORIG(MSG_CMD_P_FLAGS), + conv_phdr_flags(phdr->p_flags, 0, &buf1), + conv_phdr_flags(p_flags, 0, &buf2)); + ret = ELFEDIT_CMDRET_MOD; + phdr->p_flags = p_flags; + } + } + break; + + case PHDR_CMD_T_P_ALIGN: + { + Xword p_align = elfedit_atoui(argstate.argv[1], NULL); + + if (phdr->p_align == p_align) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_LLX_OK), + argstate.ndx, MSG_ORIG(MSG_CMD_P_ALIGN), + EC_XWORD(phdr->p_align)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_LLX_CHG), + argstate.ndx, MSG_ORIG(MSG_CMD_P_ALIGN), + EC_XWORD(phdr->p_align), + EC_XWORD(p_align)); + ret = ELFEDIT_CMDRET_MOD; + phdr->p_align = p_align; + } + } + break; + + case PHDR_CMD_T_INTERP: + ret = cmd_body_set_interp(&argstate); + break; + + case PHDR_CMD_T_DELETE: + { + Word cnt = (argstate.argc == 1) ? 1 : + (Word) elfedit_atoui_range(argstate.argv[1], + MSG_ORIG(MSG_STR_COUNT), 1, + obj_state->os_phnum - argstate.ndx, NULL); + + elfedit_array_elts_delete(MSG_ORIG(MSG_MOD_NAME), + obj_state->os_phdr, sizeof (Phdr), + obj_state->os_phnum, argstate.ndx, cnt); + do_autoprint = 0; + ret = ELFEDIT_CMDRET_MOD; + } + break; + + case PHDR_CMD_T_MOVE: + { + Phdr save; + Word cnt; + Word dstndx; + + do_autoprint = 0; + dstndx = (Word) + elfedit_atoui_range(argstate.argv[1], + MSG_ORIG(MSG_STR_DST_INDEX), 0, + obj_state->os_phnum - 1, NULL); + if (argstate.argc == 2) { + cnt = 1; + } else { + cnt = (Word) elfedit_atoui_range( + argstate.argv[2], MSG_ORIG(MSG_STR_COUNT), + 1, obj_state->os_phnum, NULL); + } + elfedit_array_elts_move(MSG_ORIG(MSG_MOD_NAME), + obj_state->os_phdr, sizeof (save), + obj_state->os_phnum, argstate.ndx, dstndx, + cnt, &save); + ret = ELFEDIT_CMDRET_MOD; + } + break; + } + + /* + * If we modified the section header array, tell libelf. + */ + if (ret == ELFEDIT_CMDRET_MOD) + elfedit_modified_phdr(obj_state); + + /* Do autoprint */ + if (do_autoprint) + print_phdr(cmd, 1, &argstate); + + return (ret); +} + + + +/* + * Command completion functions for the various commands + */ + +/* + * A number of the commands accept a PT_ constant as their first + * argument as long as the -phndx option is not used. + */ +/*ARGSUSED*/ +static void +cpl_1starg_pt(elfedit_obj_state_t *obj_state, void *cpldata, int argc, + const char *argv[], int num_opt) +{ + int i; + + for (i = 0; i < num_opt; i++) + if (strcmp(MSG_ORIG(MSG_STR_MINUS_PHNDX), argv[i]) == 0) + return; + + if (argc == (num_opt + 1)) + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_PT); +} + +/*ARGSUSED*/ +static void +cpl_p_type(elfedit_obj_state_t *obj_state, void *cpldata, int argc, + const char *argv[], int num_opt) +{ + /* The first argument follows the standard rules */ + cpl_1starg_pt(obj_state, cpldata, argc, argv, num_opt); + + /* The second argument can be a PT_ value */ + if (argc == (num_opt + 2)) + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_PT); +} + + +/*ARGSUSED*/ +static void +cpl_p_flags(elfedit_obj_state_t *obj_state, void *cpldata, int argc, + const char *argv[], int num_opt) +{ + /* The first argument follows the standard rules */ + cpl_1starg_pt(obj_state, cpldata, argc, argv, num_opt); + + /* The second and following arguments can be an PF_ value */ + if (argc >= (num_opt + 2)) + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_PF); +} + + + +/* + * 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(PHDR_CMD_T_DUMP, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_p_type(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(PHDR_CMD_T_P_TYPE, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_p_offset(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(PHDR_CMD_T_P_OFFSET, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_p_vaddr(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(PHDR_CMD_T_P_VADDR, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_p_paddr(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(PHDR_CMD_T_P_PADDR, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_p_filesz(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(PHDR_CMD_T_P_FILESZ, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_p_memsz(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(PHDR_CMD_T_P_MEMSZ, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_p_flags(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(PHDR_CMD_T_P_FLAGS, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_p_align(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(PHDR_CMD_T_P_ALIGN, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_interp(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(PHDR_CMD_T_INTERP, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_delete(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(PHDR_CMD_T_DELETE, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_move(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(PHDR_CMD_T_MOVE, obj_state, argc, argv)); +} + + +/*ARGSUSED*/ +elfedit_module_t * +elfedit_init(elfedit_module_version_t version) +{ + /* Multiple commands accept a standard set of options */ + static elfedit_cmd_optarg_t opt_std[] = { + { ELFEDIT_STDOA_OPT_O, NULL, + ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, + { MSG_ORIG(MSG_STR_MINUS_PHNDX), + /* MSG_INTL(MSG_OPTDESC_PHNDX) */ + ELFEDIT_I18NHDL(MSG_OPTDESC_PHNDX), 0, + PHDR_OPT_F_PHNDX, 0 }, + { NULL } + }; + + /* For commands that only accept -phndx */ + static elfedit_cmd_optarg_t opt_minus_phndx[] = { + { MSG_ORIG(MSG_STR_MINUS_PHNDX), + /* MSG_INTL(MSG_OPTDESC_PHNDX) */ + ELFEDIT_I18NHDL(MSG_OPTDESC_PHNDX), 0, + PHDR_OPT_F_PHNDX, 0 }, + { NULL } + }; + + + /* phdr: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 arg_dump[] = { + { MSG_ORIG(MSG_STR_ELEMENT), + /* MSG_INTL(MSG_A1_ELEMENT) */ + ELFEDIT_I18NHDL(MSG_A1_ELEMENT), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + /* phdr:p_type */ + static const char *name_p_type[] = { MSG_ORIG(MSG_CMD_P_TYPE), NULL }; + static elfedit_cmd_optarg_t arg_p_type[] = { + { MSG_ORIG(MSG_STR_ELEMENT), + /* MSG_INTL(MSG_A1_ELEMENT) */ + ELFEDIT_I18NHDL(MSG_A1_ELEMENT), + ELFEDIT_CMDOA_F_OPT }, + { MSG_ORIG(MSG_STR_TYPE), + /* MSG_INTL(MSG_A2_P_TYPE_TYPE) */ + ELFEDIT_I18NHDL(MSG_A2_P_TYPE_TYPE), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + /* phdr:p_offset */ + static const char *name_p_offset[] = { MSG_ORIG(MSG_CMD_P_OFFSET), + NULL }; + static elfedit_cmd_optarg_t arg_p_offset[] = { + { MSG_ORIG(MSG_STR_ELEMENT), + /* MSG_INTL(MSG_A1_ELEMENT) */ + ELFEDIT_I18NHDL(MSG_A1_ELEMENT), + ELFEDIT_CMDOA_F_OPT }, + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_A2_P_OFFSET_VALUE) */ + ELFEDIT_I18NHDL(MSG_A2_P_OFFSET_VALUE), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + /* phdr:p_vaddr */ + static const char *name_p_vaddr[] = { MSG_ORIG(MSG_CMD_P_VADDR), + NULL }; + static elfedit_cmd_optarg_t arg_p_vaddr[] = { + { MSG_ORIG(MSG_STR_ELEMENT), + /* MSG_INTL(MSG_A1_ELEMENT) */ + ELFEDIT_I18NHDL(MSG_A1_ELEMENT), + ELFEDIT_CMDOA_F_OPT }, + { MSG_ORIG(MSG_STR_ADDR), + /* MSG_INTL(MSG_A2_P_VADDR_ADDR) */ + ELFEDIT_I18NHDL(MSG_A2_P_VADDR_ADDR), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + /* phdr:p_paddr */ + static const char *name_p_paddr[] = { MSG_ORIG(MSG_CMD_P_PADDR), + NULL }; + static elfedit_cmd_optarg_t arg_p_paddr[] = { + { MSG_ORIG(MSG_STR_ELEMENT), + /* MSG_INTL(MSG_A1_ELEMENT) */ + ELFEDIT_I18NHDL(MSG_A1_ELEMENT), + ELFEDIT_CMDOA_F_OPT }, + { MSG_ORIG(MSG_STR_ADDR), + /* MSG_INTL(MSG_A2_P_PADDR_ADDR) */ + ELFEDIT_I18NHDL(MSG_A2_P_PADDR_ADDR), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + /* phdr:p_filesz */ + static const char *name_p_filesz[] = { MSG_ORIG(MSG_CMD_P_FILESZ), + NULL }; + static elfedit_cmd_optarg_t arg_p_filesz[] = { + /* MSG_INTL(MSG_A1_ELEMENT) */ + { MSG_ORIG(MSG_STR_ELEMENT), ELFEDIT_I18NHDL(MSG_A1_ELEMENT), + ELFEDIT_CMDOA_F_OPT }, + { MSG_ORIG(MSG_STR_SIZE), + /* MSG_INTL(MSG_A2_P_FILESZ_SIZE) */ + ELFEDIT_I18NHDL(MSG_A2_P_FILESZ_SIZE), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + /* phdr:p_memsz */ + static const char *name_p_memsz[] = { MSG_ORIG(MSG_CMD_P_MEMSZ), + NULL }; + static elfedit_cmd_optarg_t arg_p_memsz[] = { + { MSG_ORIG(MSG_STR_ELEMENT), + /* MSG_INTL(MSG_A1_ELEMENT) */ + ELFEDIT_I18NHDL(MSG_A1_ELEMENT), + ELFEDIT_CMDOA_F_OPT }, + { MSG_ORIG(MSG_STR_SIZE), + /* MSG_INTL(MSG_A2_P_MEMSZ_SIZE) */ + ELFEDIT_I18NHDL(MSG_A2_P_MEMSZ_SIZE), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + /* shdr:p_flags */ + static const char *name_p_flags[] = { + MSG_ORIG(MSG_CMD_P_FLAGS), NULL }; + static elfedit_cmd_optarg_t opt_p_flags[] = { + { ELFEDIT_STDOA_OPT_AND, NULL, + ELFEDIT_CMDOA_F_INHERIT, PHDR_OPT_F_AND, PHDR_OPT_F_OR }, + { ELFEDIT_STDOA_OPT_CMP, NULL, + ELFEDIT_CMDOA_F_INHERIT, PHDR_OPT_F_CMP, 0 }, + { MSG_ORIG(MSG_STR_MINUS_PHNDX), + /* MSG_INTL(MSG_OPTDESC_PHNDX) */ + ELFEDIT_I18NHDL(MSG_OPTDESC_PHNDX), 0, + PHDR_OPT_F_PHNDX, 0 }, + { ELFEDIT_STDOA_OPT_O, NULL, + ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, + { ELFEDIT_STDOA_OPT_OR, NULL, + ELFEDIT_CMDOA_F_INHERIT, PHDR_OPT_F_OR, PHDR_OPT_F_AND }, + { NULL } + }; + static elfedit_cmd_optarg_t arg_p_flags[] = { + { MSG_ORIG(MSG_STR_ELEMENT), + /* MSG_INTL(MSG_A1_ELEMENT) */ + ELFEDIT_I18NHDL(MSG_A1_ELEMENT), + ELFEDIT_CMDOA_F_OPT }, + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_A2_P_FLAGS_VALUE) */ + ELFEDIT_I18NHDL(MSG_A2_P_FLAGS_VALUE), + ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT }, + { NULL } + }; + + /* phdr:p_align */ + static const char *name_p_align[] = { MSG_ORIG(MSG_CMD_P_ALIGN), + NULL }; + static elfedit_cmd_optarg_t arg_p_align[] = { + { MSG_ORIG(MSG_STR_ELEMENT), + /* MSG_INTL(MSG_A1_ELEMENT) */ + ELFEDIT_I18NHDL(MSG_A1_ELEMENT), + ELFEDIT_CMDOA_F_OPT }, + { MSG_ORIG(MSG_STR_ALIGN), + /* MSG_INTL(MSG_A2_P_ALIGN_ALIGN) */ + ELFEDIT_I18NHDL(MSG_A2_P_ALIGN_ALIGN), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + /* phdr:interp */ + static const char *name_interp[] = { MSG_ORIG(MSG_CMD_INTERP), NULL }; + static elfedit_cmd_optarg_t opt_interp[] = { + { ELFEDIT_STDOA_OPT_O, NULL, + ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, + { NULL } + }; + static elfedit_cmd_optarg_t arg_interp[] = { + { MSG_ORIG(MSG_STR_NEWPATH), + /* MSG_INTL(MSG_A1_INTERP_NEWPATH) */ + ELFEDIT_I18NHDL(MSG_A1_INTERP_NEWPATH), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + /* phdr:delete */ + static const char *name_delete[] = { MSG_ORIG(MSG_CMD_DELETE), NULL }; + static elfedit_cmd_optarg_t arg_delete[] = { + { MSG_ORIG(MSG_STR_ELEMENT), + /* MSG_INTL(MSG_A1_ELEMENT) */ + ELFEDIT_I18NHDL(MSG_A1_ELEMENT), + ELFEDIT_CMDOA_F_OPT }, + { MSG_ORIG(MSG_STR_COUNT), + /* MSG_INTL(MSG_A2_DELETE_COUNT) */ + ELFEDIT_I18NHDL(MSG_A2_DELETE_COUNT), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + /* phdr:move */ + static const char *name_move[] = { MSG_ORIG(MSG_CMD_MOVE), NULL }; + static elfedit_cmd_optarg_t arg_move[] = { + { MSG_ORIG(MSG_STR_ELEMENT), + /* MSG_INTL(MSG_A1_ELEMENT) */ + ELFEDIT_I18NHDL(MSG_A1_ELEMENT), + ELFEDIT_CMDOA_F_OPT }, + { MSG_ORIG(MSG_STR_DST_INDEX), + /* MSG_INTL(MSG_A2_MOVE_DST_INDEX) */ + ELFEDIT_I18NHDL(MSG_A2_MOVE_DST_INDEX), + 0 }, + { MSG_ORIG(MSG_STR_COUNT), + /* MSG_INTL(MSG_A3_MOVE_COUNT) */ + ELFEDIT_I18NHDL(MSG_A3_MOVE_COUNT), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + static elfedit_cmd_t cmds[] = { + /* phdr:dump */ + { cmd_dump, cpl_1starg_pt, name_dump, + /* MSG_INTL(MSG_DESC_DUMP) */ + ELFEDIT_I18NHDL(MSG_DESC_DUMP), + /* MSG_INTL(MSG_HELP_DUMP) */ + ELFEDIT_I18NHDL(MSG_HELP_DUMP), + opt_minus_phndx, arg_dump }, + + /* phdr:p_type */ + { cmd_p_type, cpl_p_type, name_p_type, + /* MSG_INTL(MSG_DESC_P_TYPE) */ + ELFEDIT_I18NHDL(MSG_DESC_P_TYPE), + /* MSG_INTL(MSG_HELP_P_TYPE) */ + ELFEDIT_I18NHDL(MSG_HELP_P_TYPE), + opt_std, arg_p_type }, + + /* phdr:p_offset */ + { cmd_p_offset, cpl_1starg_pt, name_p_offset, + /* MSG_INTL(MSG_DESC_P_OFFSET) */ + ELFEDIT_I18NHDL(MSG_DESC_P_OFFSET), + /* MSG_INTL(MSG_HELP_P_OFFSET) */ + ELFEDIT_I18NHDL(MSG_HELP_P_OFFSET), + opt_std, arg_p_offset }, + + /* phdr:p_vaddr */ + { cmd_p_vaddr, cpl_1starg_pt, name_p_vaddr, + /* MSG_INTL(MSG_DESC_P_VADDR) */ + ELFEDIT_I18NHDL(MSG_DESC_P_VADDR), + /* MSG_INTL(MSG_HELP_P_VADDR) */ + ELFEDIT_I18NHDL(MSG_HELP_P_VADDR), + opt_std, arg_p_vaddr }, + + /* phdr:p_paddr */ + { cmd_p_paddr, cpl_1starg_pt, name_p_paddr, + /* MSG_INTL(MSG_DESC_P_PADDR) */ + ELFEDIT_I18NHDL(MSG_DESC_P_PADDR), + /* MSG_INTL(MSG_HELP_P_PADDR) */ + ELFEDIT_I18NHDL(MSG_HELP_P_PADDR), + opt_std, arg_p_paddr }, + + /* phdr:p_filesz */ + { cmd_p_filesz, cpl_1starg_pt, name_p_filesz, + /* MSG_INTL(MSG_DESC_P_FILESZ) */ + ELFEDIT_I18NHDL(MSG_DESC_P_FILESZ), + /* MSG_INTL(MSG_HELP_P_FILESZ) */ + ELFEDIT_I18NHDL(MSG_HELP_P_FILESZ), + opt_std, arg_p_filesz }, + + /* phdr:p_memsz */ + { cmd_p_memsz, cpl_1starg_pt, name_p_memsz, + /* MSG_INTL(MSG_DESC_P_MEMSZ) */ + ELFEDIT_I18NHDL(MSG_DESC_P_MEMSZ), + /* MSG_INTL(MSG_HELP_P_MEMSZ) */ + ELFEDIT_I18NHDL(MSG_HELP_P_MEMSZ), + opt_std, arg_p_memsz }, + + /* phdr:p_flags */ + { cmd_p_flags, cpl_p_flags, name_p_flags, + /* MSG_INTL(MSG_DESC_P_FLAGS) */ + ELFEDIT_I18NHDL(MSG_DESC_P_FLAGS), + /* MSG_INTL(MSG_HELP_P_FLAGS) */ + ELFEDIT_I18NHDL(MSG_HELP_P_FLAGS), + opt_p_flags, arg_p_flags }, + + /* phdr:p_align */ + { cmd_p_align, cpl_1starg_pt, name_p_align, + /* MSG_INTL(MSG_DESC_P_ALIGN) */ + ELFEDIT_I18NHDL(MSG_DESC_P_ALIGN), + /* MSG_INTL(MSG_HELP_P_ALIGN) */ + ELFEDIT_I18NHDL(MSG_HELP_P_ALIGN), + opt_std, arg_p_align }, + + /* phdr:interp */ + { cmd_interp, NULL, name_interp, + /* MSG_INTL(MSG_DESC_INTERP) */ + ELFEDIT_I18NHDL(MSG_DESC_INTERP), + /* MSG_INTL(MSG_HELP_INTERP) */ + ELFEDIT_I18NHDL(MSG_HELP_INTERP), + opt_interp, arg_interp }, + + /* phdr:delete */ + { cmd_delete, cpl_1starg_pt, name_delete, + /* MSG_INTL(MSG_DESC_DELETE) */ + ELFEDIT_I18NHDL(MSG_DESC_DELETE), + /* MSG_INTL(MSG_HELP_DELETE) */ + ELFEDIT_I18NHDL(MSG_HELP_DELETE), + opt_minus_phndx, arg_delete }, + + /* phdr:move */ + { cmd_move, cpl_1starg_pt, name_move, + /* MSG_INTL(MSG_DESC_MOVE) */ + ELFEDIT_I18NHDL(MSG_DESC_MOVE), + /* MSG_INTL(MSG_HELP_MOVE) */ + ELFEDIT_I18NHDL(MSG_HELP_MOVE), + opt_minus_phndx, arg_move }, + + { 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); +} diff --git a/usr/src/cmd/sgs/elfedit/modules/common/phdr.msg b/usr/src/cmd/sgs/elfedit/modules/common/phdr.msg new file mode 100644 index 0000000000..2671e61284 --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/modules/common/phdr.msg @@ -0,0 +1,381 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" + +@ _START_ + +# Message file for elfedit 'phdr' module + +@ MSG_ID_ELFEDIT_PHDR + + +# Program header format +@ MSG_ELF_PHDR "Program header [%d]:\n" + +# Debug messages +@ MSG_DEBUG_PHDR "phdr[%d]: Program header: %s\n" +@ MSG_DEBUG_OLDINTERPOK "[%d: %s][%d]: value unchanged: %s\n" +@ MSG_DEBUG_SETPHINTERP "phdr[%d]: update PT_INTERP program header: \ + p_offset=%#llx, p_size=%#llx\n" +@ MSG_DEBUG_NEWISTR "[%d: %s][%d]: Write new value in .interp \ + section: %s\n" +@ MSG_DEBUG_LNGISTR "[%d: %s][%d]: New value too long (%d bytes) for \ + .interp section (%d bytes): %s\n" +@ MSG_DEBUG_S_OK "phdr[%d].%s: value unchanged: %s\n" +@ MSG_DEBUG_S_CHG "phdr[%d].%s: change from %s to %s\n" +@ MSG_DEBUG_LLX_OK "phdr[%d].%s: value unchanged: %#llx\n" +@ MSG_DEBUG_LLX_CHG "phdr[%d].%s: change from %#llx to %#llx\n" + +# Format strings + +@ MSG_FMT_ELF_INTERP "Interpreter Section: %s\n\t%s\n" + + + +# Errors + +@ MSG_ERR_NOINTERPPHDR "ELF object does not have an interpreter \ + program header\n" +@ MSG_ERR_NOINTERPSEC "Unable to locate section corresponding to PT_INTERP \ + program header\n" +@ MSG_ERR_NOPHDR "No program header with specified type available: %s\n" + + +# Module description + +@ MSG_MOD_DESC "Program Header" + + +# 1-line description strings + +@ MSG_DESC_DUMP "Dump Program Header Contents" +@ MSG_DESC_P_TYPE "Segment type" +@ MSG_DESC_P_OFFSET "Offset from start of file" +@ MSG_DESC_P_VADDR "Virtual address of 1st byte in memory" +@ MSG_DESC_P_PADDR "Segment's physical address" +@ MSG_DESC_P_FILESZ "# of bytes in file image of segment" +@ MSG_DESC_P_MEMSZ "# bytes in memory image of segment" +@ MSG_DESC_P_FLAGS "Segment flags" +@ MSG_DESC_P_ALIGN "Segment alignmnent" +@ MSG_DESC_INTERP "Dynamic object interpreter (PT_INTERP)" +@ MSG_DESC_DELETE "Delete program headers" +@ MSG_DESC_MOVE "Move program headers" + + +# Command option description strings + +@ MSG_OPTDESC_PHNDX "\ + Interpret the element argument as a program header index\n\ + rather than as a program header type.\n" + +# Command argument description strings + +@ MSG_A1_ELEMENT "\ + Type of program header. The first program header with the\n\ + specified type will be used. If the -phndx option is used,\n\ + then element is instead an integer giving the index of the\n\ + specified program header element.\n" + +@ MSG_A1_INTERP_NEWPATH "\ + Path of new interpreter for ELF PT_INTERP program header.\n" + +@ MSG_A2_P_TYPE_TYPE "\ + Value to set for segment type. The value can be an integer,\n\ + or one of hte well known PT_ symbolic constant names.\n" + +@ MSG_A2_P_OFFSET_VALUE "\ + Integer value to set for program header p_offset field.\n\ + The value of p_offset gives the offset from the beginning\n\ + of the file at which the first byte of the segment resides.\n" + +@ MSG_A2_P_VADDR_ADDR "\ + Integer value to set for virtual address at which the first\n\ + byte of the segment resides in memory.\n" + +@ MSG_A2_P_PADDR_ADDR "\ + Integer value to set for physical address at which the first\n\ + byte of the segment resides in memory.\n" + +@ MSG_A2_P_FILESZ_SIZE "\ + Integer value to set for number of bytes in the file image\n\ + of the segment, which can be zero.\n" + +@ MSG_A2_P_MEMSZ_SIZE "\ + Integer value to set for number of bytes in the memory image\n\ + of the segment, which can be zero.\n" + +@ MSG_A2_P_FLAGS_VALUE "\ + Segment flags. PF_ flag constants are accepted, as is\n\ + any integer.\n" + +@ MSG_A2_P_ALIGN_ALIGN "\ + Value to which the segment is aligned in memory, and in\n\ + the file.\n" + +@ MSG_A2_DELETE_COUNT "\ + Number of program header elements to delete, starting\n\ + at the specified position. This value cannot exceed the number\n\ + of slots remaining in the header table below the specified.\n\ + position If count is not supplied, a single element is deleted.\n" + +@ MSG_A2_MOVE_DST_INDEX "\ + Numeric index within program header to which the element(s)\n\ + should be moved.\n" + +@ MSG_A3_MOVE_COUNT "\ + Number of program header elements to move. This value\n\ + cannot exceed the number of slots remaining in the program\n\ + header table below the specified position. If count is not\n\ + supplied, a single header element is moved.\n" + + +# Help strings + +@ MSG_HELP_DUMP " \ + The phdr:dump command is used to display program headers\n\ + using the same style used by the elfdump program.\n\ + \n\ + If phdr:dump is called without an argument, information for\n\ + every program header is shown. If called with the element\n\ + argument, the information for the program header symbol at\n\ + that index is displayed.\n" + +@ MSG_HELP_P_TYPE " \ + The phdr:p_type command is used to display or alter the\n\ + segment type program header. This information is maintained\n\ + in the p_type field of an ELF program header element.\n\ + \n\ + If phdr:p_type is called without arguments, the value of\n\ + p_type for every element of the program header array is\n\ + shown. If called with the element argument, the value of the\n\ + program header specified is displayed. If both arguments are\n\ + present, the p_type field of the program header at the\n\ + specified position is set to the given value.\n" + +@ MSG_HELP_P_OFFSET " \ + The phdr:p_offset command is used to display or alter the\n\ + p_offset field of the specified program header.\n\ + \n\ + p_offset provides the offset from the beginning of the\n\ + at which the first byte of the segment resides.\n\ + \n\ + If phdr:p_offset is called without arguments, the value\n\ + of p_offset for every element in the program header array\n\ + is shown. If called with the element argument, the value\n\ + of the element specified is displayed. If both arguments are\n\ + present, the p_offset field of the element at the\n\ + specifiedindex is set to the given value.\n" + +@ MSG_HELP_P_VADDR " \ + The phdr:p_vaddr command is used to display or alter the\n\ + p_vaddr field of the specified program header.\n\ + \n\ + p_vaddr provides the virtual address at which the first byte\n\ + of the segment resides in memory\n\ + \n\ + If phdr:p_vaddr is called without arguments, the value\n\ + of p_vaddr for every element in the program header array\n\ + is shown. If called with the element argument, the value\n\ + of the element specified is displayed. If both arguments are\n\ + present, the p_vaddr field of the element at the specified\n\ + index is set to the given value.\n" + +@ MSG_HELP_P_PADDR " \ + The phdr:p_paddr command is used to display or alter the\n\ + p_paddr field of the specified program header.\n\ + \n\ + p_paddr provides the physical address at which the first\n\ + byte of the segment resides in memory, for systems in which\n\ + physical addressing is relevant. Because the system ignores\n\ + physical addressing for application programs, this member\n\ + has unspecified contents for executable files and shared\n\ + objects.\n\ + \n\ + If phdr:p_paddr is called without arguments, the value\n\ + of p_paddr for every element in the program header array\n\ + is shown. If called with the element argument, the value\n\ + of the element specified is displayed. If both arguments are\n\ + present, the p_paddr field of the element at the specified\n\ + index is set to the given value.\n" + +@ MSG_HELP_P_FILESZ " \ + The phdr:p_filesz command is used to display or alter the\n\ + p_filesz field of the specified program header.\n\ + \n\ + p_filesz contains the number of bytes in the file image\n\ + of the segment. This value can be zero.\n\ + \n\ + If phdr:p_filesz is called without arguments, the value\n\ + of p_filesz for every element in the program header array\n\ + is shown. If called with the element argument, the value\n\ + of the element specified is displayed. If both arguments are\n\ + present, the p_filesz field of the element at the specified\n\ + index is set to the given value.\n" + +@ MSG_HELP_P_MEMSZ " \ + The phdr:p_memsz command is used to display or alter the\n\ + p_memsz field of the specified program header.\n\ + \n\ + p_memsz contains the number of bytes in the memory image\n\ + of the segment. This value can be zero.\n\ + \n\ + If phdr:p_memsz is called without arguments, the value\n\ + of p_memsz for every element in the program header array\n\ + is shown. If called with the element argument, the value\n\ + of the element specified is displayed. If both arguments are\n\ + present, the p_memsz field of the element at the specified\n\ + index is set to the given value.\n" + +@ MSG_HELP_P_FLAGS " \ + The phdr:p_flags command is used to display or alter the\n\ + flags that are associated with the segment described by\n\ + the program header.\n\ + \n\ + If phdr:p_flags is called without arguments, the value\n\ + of p_flags for every element in the program header array\n\ + is shown. If called with the element argument, the value of\n\ + the program header at that index is displayed. If one or\n\ + more value arguments are present, the following steps are\n\ + taken:\n\ + \n\ + o\tAll the value arguments are OR'd together.\n\ + \n\ + o\tIf the -cmp option has been specified, the new value\n\ + \tis complemented.\n\ + \n\ + o\tThe p_flags field of the section header is updated with\n\ + \tthe new value. If -and is specified, the new value is\n\ + \tAND'd against the existing value. If -or is specified,\n\ + \tthe new value is OR'd against the existing value. If\n\ + \tneither -and or -or are specified, the new value replaces\n\ + \tthe existing value.\n" + +@ MSG_HELP_P_ALIGN " \ + The phdr:p_align command is used to display or alter the\n\ + p_align field of the specified program header.\n\ + \n\ + p_align is the value to which the segment is aligned in\n\ + memory, and in the file. Values 0 and 1 mean no alignment\n\ + is required. Otherwise, p_align should be a positive\n\ + integral power of 2, and p_vaddr should equal p_offset,\n\ + modulo p_align.\n\ + \n\ + If phdr:p_align is called without arguments, the value\n\ + of p_align for every element in the program header array\n\ + is shown. If called with the element argument, the value\n\ + of the element specified is displayed. If both arguments are\n\ + present, the p_align field of the element at the specified\n\ + index is set to the given value.\n" + +@ MSG_HELP_INTERP " \ + The phdr:interp command is used to display or alter the\n\ + interpreter of the ELF object.\n\ + \n\ + If phdr:interp is called without arguments, the existing\n\ + interpreter is shown. If called with the newpath argument,\n\ + the interpreter is set to the given string, if possible.\n\ + \n\ + An ELF PT_INTERP program header usually references its own\n\ + special section instead of some other string table. The ELF\n\ + ABI says that this section must be named \".interp\". .interp\n\ + is typically sized to just fit the original string, including\n\ + its NULL termination. You can treat it as a string table with\n\ + one string. If the new interpreter path is short enough to fit\n\ + in this .interp section, phdr:interp simply replaces the old\n\ + path with the new one.\n\ + \n\ + In the case where the new path is too long to fit in the .interp\n\ + section, phdr:interp will attempt to use the dynamic string table\n\ + instead. This is not always possible: The desired string must\n\ + already exist in the dynamic string table, or there must be\n\ + enough room in the reserved section at the end (DT_SUNW_STRPAD)\n\ + for the new string to be added.\n" + +@ MSG_HELP_DELETE " \ + The phdr:delete command is used to delete one or more elements\n\ + in the program header. The elements following the deleted items\n\ + move up, and the vacated elements at the end are zero filled.\n" + +@ MSG_HELP_MOVE " \ + The phdr:move command is used to move the position of one\n\ + or more elements in the program header array. The specified\n\ + number of elements are moved from elt to dst_index.\n" + + +@ _END_ + + +# Strings + +@ MSG_STR_EMPTY "" +@ MSG_STR_NL "\n" +@ MSG_STR_ALIGN "align" +@ MSG_STR_ADDR "addr" +@ MSG_STR_COUNT "count" +@ MSG_STR_DST_INDEX "dst_index" +@ MSG_STR_ELEMENT "element" +@ MSG_STR_NEWPATH "newpath" +@ MSG_STR_SIZE "size" +@ MSG_STR_TYPE "type" +@ MSG_STR_VALUE "value" +@ MSG_STR_MINUS_PHNDX "-phndx" + +# Format strings + +@ MSG_FMT_U_NL "%u\n" +@ MSG_FMT_X_NL "%#x\n" +@ MSG_FMT_LLX_NL "%#llx\n" +@ MSG_FMT_STRNL "%s\n" + + + +# The following strings represent reserved words, files, pathnames and symbols. +# Reference to this strings is via the MSG_ORIG() macro, and thus no message +# translation is required. + +# ELF section names +@ MSG_SEC_INTERP ".interp" + + +# Module name + +@ MSG_MOD_NAME "phdr" + + +# Command names + +@ MSG_CMD_DUMP "dump" +@ MSG_CMD_P_TYPE "p_type" +@ MSG_CMD_P_OFFSET "p_offset" +@ MSG_CMD_P_VADDR "p_vaddr" +@ MSG_CMD_P_PADDR "p_paddr" +@ MSG_CMD_P_FILESZ "p_filesz" +@ MSG_CMD_P_MEMSZ "p_memsz" +@ MSG_CMD_P_FLAGS "p_flags" +@ MSG_CMD_P_ALIGN "p_align" +@ MSG_CMD_INTERP "interp" +@ MSG_CMD_DELETE "delete" +@ MSG_CMD_MOVE "move" diff --git a/usr/src/cmd/sgs/elfedit/modules/common/shdr.c b/usr/src/cmd/sgs/elfedit/modules/common/shdr.c new file mode 100644 index 0000000000..50a0cd9ac1 --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/modules/common/shdr.c @@ -0,0 +1,1207 @@ +/* + * 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 <stdio.h> +#include <unistd.h> +#include <machdep.h> +#include <elfedit.h> +#include <sys/elf_SPARC.h> +#include <sys/elf_amd64.h> +#include <strings.h> +#include <debug.h> +#include <conv.h> +#include <shdr_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 { + SHDR_CMD_T_DUMP = 0, /* shdr:dump */ + + SHDR_CMD_T_SH_ADDR = 1, /* shdr:sh_addr */ + SHDR_CMD_T_SH_ADDRALIGN = 2, /* shdr:sh_addralign */ + SHDR_CMD_T_SH_ENTSIZE = 3, /* shdr:sh_entsize */ + SHDR_CMD_T_SH_FLAGS = 4, /* shdr:sh_flags */ + SHDR_CMD_T_SH_INFO = 5, /* shdr:sh_info */ + SHDR_CMD_T_SH_LINK = 6, /* shdr:sh_link */ + SHDR_CMD_T_SH_NAME = 7, /* shdr:sh_name */ + SHDR_CMD_T_SH_OFFSET = 8, /* shdr:sh_offset */ + SHDR_CMD_T_SH_SIZE = 9, /* shdr:sh_size */ + SHDR_CMD_T_SH_TYPE = 10 /* shdr:sh_type */ +} SHDR_CMD_T; + + + +#ifndef _ELF64 +/* + * We supply this function for the msg module. Only one copy is needed. + */ +const char * +_shdr_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 shdr_opt_t enum specifies a bit value for every optional + * argument allowed by a command in this module. + */ +typedef enum { + SHDR_OPT_F_AND = 1, /* -and: AND (&) values to dest */ + SHDR_OPT_F_CMP = 2, /* -cmp: Complement (~) values */ + SHDR_OPT_F_NAMOFFSET = 4, /* -name_offset: Name arg is numeric */ + /* ofset rather than string */ + SHDR_OPT_F_OR = 8, /* -or: OR (|) values to dest */ + SHDR_OPT_F_SHNDX = 16, /* -shndx: Section by index, not name */ + SHDR_OPT_F_SHTYP = 32 /* -shtyp: Section by type, not name */ +} shdr_opt_t; + + +/* + * A variable of type ARGSTATE is used by each command to maintain + * information about the section headers and related things. It is + * initialized by process_args(), and used by the other routines. + */ +typedef struct { + elfedit_obj_state_t *obj_state; + shdr_opt_t optmask; /* Mask of options used */ + int argc; /* # of plain arguments */ + const char **argv; /* Plain arguments */ +} ARGSTATE; + + + + +/* + * Standard argument processing for shdr module + * + * entry + * obj_state, argc, argv - Standard command arguments + * optmask - Mask of allowed optional arguments. + * cmd - SHDR_CMD_T_* value giving identify of caller + * 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[], + SHDR_CMD_T cmd, ARGSTATE *argstate) +{ + elfedit_getopt_state_t getopt_state; + elfedit_getopt_ret_t *getopt_ret; + + bzero(argstate, sizeof (*argstate)); + argstate->obj_state = obj_state; + + 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; + + /* Are the right number of plain arguments present? */ + switch (cmd) { + case SHDR_CMD_T_DUMP: + if (argc > 1) + elfedit_command_usage(); + break; + case SHDR_CMD_T_SH_FLAGS: + /* shdr:sh_flags allows an arbitrary number of arguments */ + break; + default: + /* The remaining commands accept 2 plain arguments */ + if (argc > 2) + elfedit_command_usage(); + break; + } + + /* 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; +} + + + +/* + * Print section header 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 - SHDR_CMD_T_* value giving identify of caller + * argstate - State block for section header array + * ndx - Index of first section to display + * cnt - Number of sections to display + */ +static void +print_shdr(SHDR_CMD_T cmd, int autoprint, ARGSTATE *argstate, + Word ndx, Word cnt) +{ + elfedit_outstyle_t outstyle; + + if ((autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0)) || + (cnt == 0)) + return; + + /* + * Pick an output style. shdr:dump is required to use the default + * style. The other commands use the current output style. + */ + outstyle = (cmd == SHDR_CMD_T_DUMP) ? + ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle(); + + /* + * If doing default output, use elfdump style where we + * show all section header attributes. In this case, the + * command that called us doesn't matter + */ + if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) { + Half mach = argstate->obj_state->os_ehdr->e_machine; + + for (; cnt--; ndx++) { + elfedit_section_t *sec = + &argstate->obj_state->os_secarr[ndx]; + + elfedit_printf(MSG_ORIG(MSG_STR_NL)); + elfedit_printf(MSG_INTL(MSG_ELF_SHDR), ndx, + sec->sec_name); + Elf_shdr(NULL, mach, sec->sec_shdr); + } + return; + } + + + switch (cmd) { + case SHDR_CMD_T_SH_ADDR: + for (; cnt--; ndx++) { + Shdr *shdr = + argstate->obj_state->os_secarr[ndx].sec_shdr; + + elfedit_printf(MSG_ORIG(MSG_FMT_XWORDHEXNL), + EC_XWORD(shdr->sh_addr)); + } + return; + + case SHDR_CMD_T_SH_ADDRALIGN: + for (; cnt--; ndx++) { + Shdr *shdr = + argstate->obj_state->os_secarr[ndx].sec_shdr; + + elfedit_printf(MSG_ORIG(MSG_FMT_XWORDHEXNL), + EC_XWORD(shdr->sh_addralign)); + } + return; + + case SHDR_CMD_T_SH_ENTSIZE: + for (; cnt--; ndx++) { + Shdr *shdr = + argstate->obj_state->os_secarr[ndx].sec_shdr; + + elfedit_printf(MSG_ORIG(MSG_FMT_XWORDHEXNL), + EC_XWORD(shdr->sh_entsize)); + } + return; + + case SHDR_CMD_T_SH_FLAGS: + for (; cnt--; ndx++) { + Shdr *shdr = + argstate->obj_state->os_secarr[ndx].sec_shdr; + if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { + Conv_sec_flags_buf_t sec_flags_buf; + + elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), + conv_sec_flags(shdr->sh_flags, + CONV_FMT_NOBKT, &sec_flags_buf)); + } else { + elfedit_printf(MSG_ORIG(MSG_FMT_XWORDHEXNL), + EC_XWORD(shdr->sh_flags)); + } + } + return; + + case SHDR_CMD_T_SH_INFO: + for (; cnt--; ndx++) { + Shdr *shdr = + argstate->obj_state->os_secarr[ndx].sec_shdr; + + elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL), + EC_WORD(shdr->sh_info)); + } + return; + + case SHDR_CMD_T_SH_LINK: + for (; cnt--; ndx++) { + Shdr *shdr = + argstate->obj_state->os_secarr[ndx].sec_shdr; + + elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL), + EC_WORD(shdr->sh_link)); + } + return; + + case SHDR_CMD_T_SH_NAME: + /* + * In simple output mode, we show the string. In numeric + * mode, we show the string table offset. + */ + for (; cnt--; ndx++) { + elfedit_section_t *shdr_sec = + &argstate->obj_state->os_secarr[ndx]; + + if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { + elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), + shdr_sec->sec_name); + } else { + elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL), + EC_WORD(shdr_sec->sec_shdr->sh_name)); + } + } + return; + + case SHDR_CMD_T_SH_OFFSET: + for (; cnt--; ndx++) { + Shdr *shdr = + argstate->obj_state->os_secarr[ndx].sec_shdr; + + elfedit_printf(MSG_ORIG(MSG_FMT_XWORDHEXNL), + EC_XWORD(shdr->sh_offset)); + } + return; + + case SHDR_CMD_T_SH_SIZE: + for (; cnt--; ndx++) { + Shdr *shdr = + argstate->obj_state->os_secarr[ndx].sec_shdr; + + elfedit_printf(MSG_ORIG(MSG_FMT_XWORDHEXNL), + EC_XWORD(shdr->sh_size)); + } + return; + + case SHDR_CMD_T_SH_TYPE: + for (; cnt--; ndx++) { + Shdr *shdr = + argstate->obj_state->os_secarr[ndx].sec_shdr; + Conv_inv_buf_t inv_buf; + if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { + Half mach = + argstate->obj_state->os_ehdr->e_machine; + + elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), + conv_sec_type(mach, shdr->sh_type, 0, + &inv_buf)); + } else { + elfedit_printf(MSG_ORIG(MSG_FMT_WORDHEXNL), + EC_WORD(shdr->sh_type)); + } + } + return; + } +} + + +/* + * Common body for the shdr: 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 SHDR_CMD_T_* constants listed above, specifying + * which command to implement. + * obj_state, argc, argv - Standard command arguments + */ +static elfedit_cmdret_t +cmd_body(SHDR_CMD_T cmd, elfedit_obj_state_t *obj_state, + int argc, const char *argv[]) +{ + ARGSTATE argstate; + Word ndx; + elfedit_section_t *shdr_sec; + Shdr *shdr; + elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE; + + process_args(obj_state, argc, argv, cmd, &argstate); + + /* If there are no arguments, dump the whole table and return */ + if (argstate.argc == 0) { + print_shdr(cmd, 0, &argstate, 0, obj_state->os_shnum); + return (ELFEDIT_CMDRET_NONE); + } + + /* + * The first argument gives the section to use. This can be a + * name (default), section index, or section type, depending on + * the options used. + */ + if (argstate.optmask & SHDR_OPT_F_SHNDX) + ndx = elfedit_atoshndx(argstate.argv[0], obj_state->os_shnum); + else if (argstate.optmask & SHDR_OPT_F_SHTYP) + ndx = elfedit_type_to_shndx(obj_state, + elfedit_atoconst(argstate.argv[0], ELFEDIT_CONST_SHT)); + else + ndx = elfedit_name_to_shndx(obj_state, argstate.argv[0]); + + /* If there is a single argument, display that item and return */ + if (argstate.argc == 1) { + print_shdr(cmd, 0, &argstate, ndx, 1); + return (ELFEDIT_CMDRET_NONE); + } + + /* + * Section [0] is supposed to be all zero unless extended sections + * are in force. Rather than setting extended values directly, + * it is expected to be handled by the ELF header module. So, a + * direct change here is probably not what was intended. + */ + if (ndx == 0) + elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CHGSHDR0)); + + /* The second value is an integer giving a new value */ + shdr_sec = &obj_state->os_secarr[ndx]; + shdr = shdr_sec->sec_shdr; + switch (cmd) { + /* + * SHDR_CMD_T_DUMP can't get here: It never has more than + * one argument, and is handled above. + */ + + case SHDR_CMD_T_SH_ADDR: + { + Addr sh_addr = elfedit_atoui(argstate.argv[1], NULL); + + if (shdr->sh_addr == sh_addr) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_LLX_OK), + ndx, shdr_sec->sec_name, + MSG_ORIG(MSG_CMD_SH_ADDR), + EC_ADDR(shdr->sh_addr)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_LLX_CHG), + ndx, shdr_sec->sec_name, + MSG_ORIG(MSG_CMD_SH_ADDR), + EC_ADDR(shdr->sh_addr), EC_ADDR(sh_addr)); + ret = ELFEDIT_CMDRET_MOD; + shdr->sh_addr = sh_addr; + } + } + break; + + case SHDR_CMD_T_SH_ADDRALIGN: + { + Xword sh_addralign; + + sh_addralign = elfedit_atoui(argstate.argv[1], NULL); + if (elfedit_bits_set(sh_addralign, + sizeof (sh_addralign)) > 1) + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_ADDRALIGN), + argstate.argv[1]); + if (shdr->sh_addralign == sh_addralign) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_LLX_OK), + ndx, shdr_sec->sec_name, + MSG_ORIG(MSG_CMD_SH_ADDRALIGN), + EC_XWORD(shdr->sh_addralign)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_LLX_CHG), + ndx, shdr_sec->sec_name, + MSG_ORIG(MSG_CMD_SH_ADDRALIGN), + EC_XWORD(shdr->sh_addralign), + EC_XWORD(sh_addralign)); + ret = ELFEDIT_CMDRET_MOD; + shdr->sh_addralign = sh_addralign; + } + } + break; + + case SHDR_CMD_T_SH_ENTSIZE: + { + Xword sh_entsize; + + sh_entsize = elfedit_atoui(argstate.argv[1], NULL); + if (shdr->sh_entsize == sh_entsize) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_LLX_OK), + ndx, shdr_sec->sec_name, + MSG_ORIG(MSG_CMD_SH_ENTSIZE), + EC_XWORD(shdr->sh_entsize)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_LLX_CHG), + ndx, shdr_sec->sec_name, + MSG_ORIG(MSG_CMD_SH_ENTSIZE), + EC_XWORD(shdr->sh_entsize), + EC_XWORD(sh_entsize)); + ret = ELFEDIT_CMDRET_MOD; + shdr->sh_entsize = sh_entsize; + } + } + break; + + case SHDR_CMD_T_SH_FLAGS: + { + Conv_sec_flags_buf_t buf1, buf2; + Word sh_flags = 0; + int i; + + /* Collect the flag arguments */ + for (i = 1; i < argstate.argc; i++) + sh_flags |= + (Word) elfedit_atoconst(argstate.argv[i], + ELFEDIT_CONST_SHF); + + /* Complement the value? */ + if (argstate.optmask & SHDR_OPT_F_CMP) + sh_flags = ~sh_flags; + + /* Perform any requested bit operations */ + if (argstate.optmask & SHDR_OPT_F_AND) + sh_flags &= shdr->sh_flags; + else if (argstate.optmask & SHDR_OPT_F_OR) + sh_flags |= shdr->sh_flags; + + /* Set the value */ + if (shdr->sh_flags == sh_flags) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_S_OK), + ndx, shdr_sec->sec_name, + MSG_ORIG(MSG_CMD_SH_FLAGS), + conv_sec_flags(shdr->sh_flags, 0, &buf1)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_S_CHG), + ndx, shdr_sec->sec_name, + MSG_ORIG(MSG_CMD_SH_FLAGS), + conv_sec_flags(shdr->sh_flags, 0, &buf1), + conv_sec_flags(sh_flags, 0, &buf2)); + ret = ELFEDIT_CMDRET_MOD; + shdr->sh_flags = sh_flags; + } + } + break; + + case SHDR_CMD_T_SH_INFO: + { + Word sh_info = elfedit_atoui(argstate.argv[1], NULL); + + if (shdr->sh_info == sh_info) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_D_OK), + ndx, shdr_sec->sec_name, + MSG_ORIG(MSG_CMD_SH_INFO), + EC_WORD(shdr->sh_info)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_D_CHG), + ndx, shdr_sec->sec_name, + MSG_ORIG(MSG_CMD_SH_INFO), + EC_WORD(shdr->sh_info), EC_WORD(sh_info)); + ret = ELFEDIT_CMDRET_MOD; + shdr->sh_info = sh_info; + } + } + break; + + case SHDR_CMD_T_SH_LINK: + { + Word sh_link = elfedit_atoui(argstate.argv[1], NULL); + + if (shdr->sh_link == sh_link) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_D_OK), + ndx, shdr_sec->sec_name, + MSG_ORIG(MSG_CMD_SH_LINK), + EC_WORD(shdr->sh_link)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_D_CHG), + ndx, shdr_sec->sec_name, + MSG_ORIG(MSG_CMD_SH_LINK), + EC_WORD(shdr->sh_link), EC_WORD(sh_link)); + ret = ELFEDIT_CMDRET_MOD; + shdr->sh_link = sh_link; + } + } + break; + + case SHDR_CMD_T_SH_NAME: + { + elfedit_section_t *shstr_sec = + &obj_state->os_secarr[obj_state->os_shstrndx]; + Word sh_name; + + /* + * If -name_offset was specified, this is an offset + * into the string table. Otherwise it is a string + * we need to turn into an offset. + */ + sh_name = (argstate.optmask & SHDR_OPT_F_NAMOFFSET) ? + elfedit_atoui(argstate.argv[1], NULL) : + elfedit_strtab_insert(obj_state, + shstr_sec, NULL, argstate.argv[1]); + if (shdr->sh_name == sh_name) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_D_OK), + ndx, shdr_sec->sec_name, + MSG_ORIG(MSG_CMD_SH_NAME), + EC_WORD(shdr->sh_name)); + } else { + /* + * The section name is cached, so we must + * also update that value. This call will + * warn if the offset is out of range, and + * will supply a safe string in that case. + */ + shdr_sec->sec_name = + elfedit_offset_to_str(shstr_sec, + sh_name, ELFEDIT_MSG_DEBUG, 1); + + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_D_CHG), + ndx, shdr_sec->sec_name, + MSG_ORIG(MSG_CMD_SH_NAME), + EC_WORD(shdr->sh_name), EC_WORD(sh_name)); + ret = ELFEDIT_CMDRET_MOD; + shdr->sh_name = sh_name; + } + } + break; + + case SHDR_CMD_T_SH_OFFSET: + { + Off sh_offset; + + sh_offset = elfedit_atoui(argstate.argv[1], NULL); + if (shdr->sh_offset == sh_offset) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_LLX_OK), + ndx, shdr_sec->sec_name, + MSG_ORIG(MSG_CMD_SH_OFFSET), + EC_XWORD(shdr->sh_offset)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_LLX_CHG), + ndx, shdr_sec->sec_name, + MSG_ORIG(MSG_CMD_SH_OFFSET), + EC_XWORD(shdr->sh_offset), + EC_XWORD(sh_offset)); + ret = ELFEDIT_CMDRET_MOD; + shdr->sh_offset = sh_offset; + } + } + break; + + case SHDR_CMD_T_SH_SIZE: + { + Xword sh_size; + + sh_size = elfedit_atoui(argstate.argv[1], NULL); + if (shdr->sh_size == sh_size) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_LLX_OK), + ndx, shdr_sec->sec_name, + MSG_ORIG(MSG_CMD_SH_SIZE), + EC_XWORD(shdr->sh_size)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_LLX_CHG), + ndx, shdr_sec->sec_name, + MSG_ORIG(MSG_CMD_SH_SIZE), + EC_XWORD(shdr->sh_size), + EC_XWORD(sh_size)); + ret = ELFEDIT_CMDRET_MOD; + shdr->sh_size = sh_size; + } + } + break; + + case SHDR_CMD_T_SH_TYPE: + { + Half mach = obj_state->os_ehdr->e_machine; + Word sh_type = elfedit_atoconst(argstate.argv[1], + ELFEDIT_CONST_SHT); + Conv_inv_buf_t inv_buf1, inv_buf2; + + if (shdr->sh_type == sh_type) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_S_OK), + ndx, shdr_sec->sec_name, + MSG_ORIG(MSG_CMD_SH_TYPE), + conv_sec_type(mach, shdr->sh_type, + 0, &inv_buf1)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_S_CHG), + ndx, shdr_sec->sec_name, + MSG_ORIG(MSG_CMD_SH_TYPE), + conv_sec_type(mach, shdr->sh_type, 0, + &inv_buf1), + conv_sec_type(mach, sh_type, 0, &inv_buf2)); + ret = ELFEDIT_CMDRET_MOD; + shdr->sh_type = sh_type; + } + } + break; + } + + /* + * If we modified the section header array, tell libelf. + */ + if (ret == ELFEDIT_CMDRET_MOD) + elfedit_modified_shdr(shdr_sec); + + /* Do autoprint */ + print_shdr(cmd, 1, &argstate, ndx, 1); + + return (ret); +} + + + + +/* + * Command completion functions for the various commands + */ + +/* + * All of the commands accept the same first argument (sec) that + * specifies the section. This argument can be a section name + * (default), section index, or section type, depending on the + * options used. This routine determines which case is current, + * and then supplies completion for the first argument. + */ +static void +cpl_1starg_sec(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; + + if (argc != (num_opt + 1)) + return; + + op = NAME; + for (ndx = 0; ndx < num_opt; ndx++) { + if (strcmp(argv[ndx], MSG_ORIG(MSG_STR_MINUS_SHNDX)) == 0) + op = INDEX; + else if (strcmp(argv[ndx], MSG_ORIG(MSG_STR_MINUS_SHTYP)) == 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_sh_flags(elfedit_obj_state_t *obj_state, void *cpldata, int argc, + const char *argv[], int num_opt) +{ + /* Handle -shXXX options */ + cpl_1starg_sec(obj_state, cpldata, argc, argv, num_opt); + + /* The second and following arguments can be an SHF_ value */ + if (argc >= (num_opt + 2)) + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SHF); +} + +/*ARGSUSED*/ +static void +cpl_sh_type(elfedit_obj_state_t *obj_state, void *cpldata, int argc, + const char *argv[], int num_opt) +{ + /* Handle -shXXX options */ + cpl_1starg_sec(obj_state, cpldata, argc, argv, num_opt); + + /* The second argument can be an SHT_ value */ + if (argc == (num_opt + 2)) + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SHT); +} + + + +/* + * 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(SHDR_CMD_T_DUMP, obj_state, argc, argv)); +} + + +static elfedit_cmdret_t +cmd_sh_addr(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(SHDR_CMD_T_SH_ADDR, obj_state, argc, argv)); +} + + +static elfedit_cmdret_t +cmd_sh_addralign(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(SHDR_CMD_T_SH_ADDRALIGN, obj_state, argc, argv)); +} + + +static elfedit_cmdret_t +cmd_sh_entsize(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(SHDR_CMD_T_SH_ENTSIZE, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_sh_flags(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(SHDR_CMD_T_SH_FLAGS, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_sh_info(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(SHDR_CMD_T_SH_INFO, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_sh_link(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(SHDR_CMD_T_SH_LINK, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_sh_name(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(SHDR_CMD_T_SH_NAME, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_sh_offset(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(SHDR_CMD_T_SH_OFFSET, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_sh_size(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(SHDR_CMD_T_SH_SIZE, obj_state, argc, argv)); +} + +static elfedit_cmdret_t +cmd_sh_type(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(SHDR_CMD_T_SH_TYPE, 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[] = { + { ELFEDIT_STDOA_OPT_O, NULL, + ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, + { MSG_ORIG(MSG_STR_MINUS_SHNDX), + /* MSG_INTL(MSG_OPTDESC_SHNDX) */ + ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), 0, + SHDR_OPT_F_SHNDX, SHDR_OPT_F_SHTYP }, + { MSG_ORIG(MSG_STR_MINUS_SHTYP), + /* MSG_INTL(MSG_OPTDESC_SHTYP) */ + ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), 0, + SHDR_OPT_F_SHTYP, SHDR_OPT_F_SHNDX }, + { NULL } + }; + + /* shdr:sh_addr */ + static const char *name_sh_addr[] = { + MSG_ORIG(MSG_CMD_SH_ADDR), NULL }; + static elfedit_cmd_optarg_t arg_sh_addr[] = { + { MSG_ORIG(MSG_STR_SEC), + /* MSG_INTL(MSG_A1_SEC) */ + ELFEDIT_I18NHDL(MSG_A1_SEC), + ELFEDIT_CMDOA_F_OPT }, + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_A2_DESC_SH_ADDR) */ + ELFEDIT_I18NHDL(MSG_A2_DESC_SH_ADDR), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + /* shdr: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_SHNDX), + /* MSG_INTL(MSG_OPTDESC_SHNDX) */ + ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), 0, + SHDR_OPT_F_SHNDX, SHDR_OPT_F_SHTYP }, + { MSG_ORIG(MSG_STR_MINUS_SHTYP), + /* MSG_INTL(MSG_OPTDESC_SHTYP) */ + ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), 0, + SHDR_OPT_F_SHTYP, SHDR_OPT_F_SHNDX }, + { NULL } + }; + static elfedit_cmd_optarg_t arg_dump[] = { + { MSG_ORIG(MSG_STR_SEC), + /* MSG_INTL(MSG_A1_SEC) */ + ELFEDIT_I18NHDL(MSG_A1_SEC), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + /* shdr:sh_addralign */ + static const char *name_sh_addralign[] = { + MSG_ORIG(MSG_CMD_SH_ADDRALIGN), NULL }; + static elfedit_cmd_optarg_t arg_sh_addralign[] = { + { MSG_ORIG(MSG_STR_SEC), + /* MSG_INTL(MSG_A1_SEC) */ + ELFEDIT_I18NHDL(MSG_A1_SEC), + ELFEDIT_CMDOA_F_OPT }, + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_A2_DESC_SH_ADDRALIGN) */ + ELFEDIT_I18NHDL(MSG_A2_DESC_SH_ADDRALIGN), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + /* shdr:sh_entsize */ + static const char *name_sh_entsize[] = { + MSG_ORIG(MSG_CMD_SH_ENTSIZE), NULL }; + static elfedit_cmd_optarg_t arg_sh_entsize[] = { + { MSG_ORIG(MSG_STR_SEC), + /* MSG_INTL(MSG_A1_SEC) */ + ELFEDIT_I18NHDL(MSG_A1_SEC), + ELFEDIT_CMDOA_F_OPT }, + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_A2_DESC_SH_ENTSIZE) */ + ELFEDIT_I18NHDL(MSG_A2_DESC_SH_ENTSIZE), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + /* shdr:sh_flags */ + static const char *name_sh_flags[] = { + MSG_ORIG(MSG_CMD_SH_FLAGS), NULL }; + static elfedit_cmd_optarg_t opt_sh_flags[] = { + { ELFEDIT_STDOA_OPT_AND, NULL, + ELFEDIT_CMDOA_F_INHERIT, SHDR_OPT_F_AND, SHDR_OPT_F_OR }, + { ELFEDIT_STDOA_OPT_CMP, NULL, + ELFEDIT_CMDOA_F_INHERIT, SHDR_OPT_F_CMP, 0 }, + { ELFEDIT_STDOA_OPT_O, NULL, + ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, + { ELFEDIT_STDOA_OPT_OR, NULL, + ELFEDIT_CMDOA_F_INHERIT, SHDR_OPT_F_OR, SHDR_OPT_F_AND }, + { MSG_ORIG(MSG_STR_MINUS_SHNDX), + /* MSG_INTL(MSG_OPTDESC_SHNDX) */ + ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), 0, + SHDR_OPT_F_SHNDX, SHDR_OPT_F_SHTYP }, + { MSG_ORIG(MSG_STR_MINUS_SHTYP), + /* MSG_INTL(MSG_OPTDESC_SHTYP) */ + ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), 0, + SHDR_OPT_F_SHTYP, SHDR_OPT_F_SHNDX }, + { NULL } + }; + static elfedit_cmd_optarg_t arg_sh_flags[] = { + { MSG_ORIG(MSG_STR_SEC), + /* MSG_INTL(MSG_A1_SEC) */ + ELFEDIT_I18NHDL(MSG_A1_SEC), + ELFEDIT_CMDOA_F_OPT }, + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_A2_DESC_SH_FLAGS) */ + ELFEDIT_I18NHDL(MSG_A2_DESC_SH_FLAGS), + ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT }, + { NULL } + }; + + /* shdr:sh_info */ + static const char *name_sh_info[] = { + MSG_ORIG(MSG_CMD_SH_INFO), NULL }; + static elfedit_cmd_optarg_t arg_sh_info[] = { + { MSG_ORIG(MSG_STR_SEC), + /* MSG_INTL(MSG_A1_SEC) */ + ELFEDIT_I18NHDL(MSG_A1_SEC), + ELFEDIT_CMDOA_F_OPT }, + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_A2_DESC_SH_INFO) */ + ELFEDIT_I18NHDL(MSG_A2_DESC_SH_INFO), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + /* shdr:sh_link */ + static const char *name_sh_link[] = { + MSG_ORIG(MSG_CMD_SH_LINK), NULL }; + static elfedit_cmd_optarg_t arg_sh_link[] = { + { MSG_ORIG(MSG_STR_SEC), + /* MSG_INTL(MSG_A1_SEC) */ + ELFEDIT_I18NHDL(MSG_A1_SEC), + ELFEDIT_CMDOA_F_OPT }, + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_A2_DESC_SH_LINK) */ + ELFEDIT_I18NHDL(MSG_A2_DESC_SH_LINK), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + /* shdr:sh_name */ + static const char *name_sh_name[] = { + MSG_ORIG(MSG_CMD_SH_NAME), NULL }; + static elfedit_cmd_optarg_t opt_sh_name[] = { + { MSG_ORIG(MSG_STR_MINUS_NAME_OFFSET), + /* MSG_INTL(MSG_OPTDESC_NAME_OFFSET) */ + ELFEDIT_I18NHDL(MSG_OPTDESC_NAME_OFFSET), 0, + SHDR_OPT_F_NAMOFFSET, 0 }, + { ELFEDIT_STDOA_OPT_O, NULL, + ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, + { MSG_ORIG(MSG_STR_MINUS_SHNDX), + /* MSG_INTL(MSG_OPTDESC_SHNDX) */ + ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), 0, + SHDR_OPT_F_SHNDX, SHDR_OPT_F_SHTYP }, + { MSG_ORIG(MSG_STR_MINUS_SHTYP), + /* MSG_INTL(MSG_OPTDESC_SHTYP) */ + ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), 0, + SHDR_OPT_F_SHTYP, SHDR_OPT_F_SHNDX }, + { NULL } + }; + static elfedit_cmd_optarg_t arg_sh_name[] = { + { MSG_ORIG(MSG_STR_SEC), + /* MSG_INTL(MSG_A1_SEC) */ + ELFEDIT_I18NHDL(MSG_A1_SEC), + ELFEDIT_CMDOA_F_OPT }, + { MSG_ORIG(MSG_STR_NAME), + /* MSG_INTL(MSG_A2_DESC_SH_NAME) */ + ELFEDIT_I18NHDL(MSG_A2_DESC_SH_NAME), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + /* shdr:sh_offset */ + static const char *name_sh_offset[] = { + MSG_ORIG(MSG_CMD_SH_OFFSET), NULL }; + static elfedit_cmd_optarg_t arg_sh_offset[] = { + { MSG_ORIG(MSG_STR_SEC), + /* MSG_INTL(MSG_A1_SEC) */ + ELFEDIT_I18NHDL(MSG_A1_SEC), + ELFEDIT_CMDOA_F_OPT }, + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_A2_DESC_SH_OFFSET) */ + ELFEDIT_I18NHDL(MSG_A2_DESC_SH_OFFSET), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + /* shdr:sh_size */ + static const char *name_sh_size[] = { + MSG_ORIG(MSG_CMD_SH_SIZE), NULL }; + static elfedit_cmd_optarg_t arg_sh_size[] = { + { MSG_ORIG(MSG_STR_SEC), + /* MSG_INTL(MSG_A1_SEC) */ + ELFEDIT_I18NHDL(MSG_A1_SEC), + ELFEDIT_CMDOA_F_OPT }, + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_A2_DESC_SH_SIZE) */ + ELFEDIT_I18NHDL(MSG_A2_DESC_SH_SIZE), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + /* shdr:sh_type */ + static const char *name_sh_type[] = { + MSG_ORIG(MSG_CMD_SH_TYPE), NULL }; + static elfedit_cmd_optarg_t arg_sh_type[] = { + { MSG_ORIG(MSG_STR_SEC), + /* MSG_INTL(MSG_A1_SEC) */ + ELFEDIT_I18NHDL(MSG_A1_SEC), + ELFEDIT_CMDOA_F_OPT }, + { MSG_ORIG(MSG_STR_VALUE), + /* MSG_INTL(MSG_A2_DESC_SH_TYPE) */ + ELFEDIT_I18NHDL(MSG_A2_DESC_SH_TYPE), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + static elfedit_cmd_t cmds[] = { + /* shdr:dump */ + { cmd_dump, cpl_1starg_sec, 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 }, + + /* shdr:sh_addr */ + { cmd_sh_addr, cpl_1starg_sec, name_sh_addr, + /* MSG_INTL(MSG_DESC_SH_ADDR) */ + ELFEDIT_I18NHDL(MSG_DESC_SH_ADDR), + /* MSG_INTL(MSG_HELP_SH_ADDR) */ + ELFEDIT_I18NHDL(MSG_HELP_SH_ADDR), + opt_std, arg_sh_addr }, + + /* shdr:sh_addralign */ + { cmd_sh_addralign, cpl_1starg_sec, name_sh_addralign, + /* MSG_INTL(MSG_DESC_SH_ADDRALIGN) */ + ELFEDIT_I18NHDL(MSG_DESC_SH_ADDRALIGN), + /* MSG_INTL(MSG_HELP_SH_ADDRALIGN) */ + ELFEDIT_I18NHDL(MSG_HELP_SH_ADDRALIGN), + opt_std, arg_sh_addralign }, + + /* shdr:sh_entsize */ + { cmd_sh_entsize, cpl_1starg_sec, name_sh_entsize, + /* MSG_INTL(MSG_DESC_SH_ENTSIZE) */ + ELFEDIT_I18NHDL(MSG_DESC_SH_ENTSIZE), + /* MSG_INTL(MSG_HELP_SH_ENTSIZE) */ + ELFEDIT_I18NHDL(MSG_HELP_SH_ENTSIZE), + opt_std, arg_sh_entsize }, + + /* shdr:sh_flags */ + { cmd_sh_flags, cpl_sh_flags, name_sh_flags, + /* MSG_INTL(MSG_DESC_SH_FLAGS) */ + ELFEDIT_I18NHDL(MSG_DESC_SH_FLAGS), + /* MSG_INTL(MSG_HELP_SH_FLAGS) */ + ELFEDIT_I18NHDL(MSG_HELP_SH_FLAGS), + opt_sh_flags, arg_sh_flags }, + + /* shdr:sh_info */ + { cmd_sh_info, cpl_1starg_sec, name_sh_info, + /* MSG_INTL(MSG_DESC_SH_INFO) */ + ELFEDIT_I18NHDL(MSG_DESC_SH_INFO), + /* MSG_INTL(MSG_HELP_SH_INFO) */ + ELFEDIT_I18NHDL(MSG_HELP_SH_INFO), + opt_std, arg_sh_info }, + + /* shdr:sh_link */ + { cmd_sh_link, cpl_1starg_sec, name_sh_link, + /* MSG_INTL(MSG_DESC_SH_LINK) */ + ELFEDIT_I18NHDL(MSG_DESC_SH_LINK), + /* MSG_INTL(MSG_HELP_SH_LINK) */ + ELFEDIT_I18NHDL(MSG_HELP_SH_LINK), + opt_std, arg_sh_link }, + + /* shdr:sh_name */ + { cmd_sh_name, cpl_1starg_sec, name_sh_name, + /* MSG_INTL(MSG_DESC_SH_NAME) */ + ELFEDIT_I18NHDL(MSG_DESC_SH_NAME), + /* MSG_INTL(MSG_HELP_SH_NAME) */ + ELFEDIT_I18NHDL(MSG_HELP_SH_NAME), + opt_sh_name, arg_sh_name }, + + /* shdr:sh_offset */ + { cmd_sh_offset, cpl_1starg_sec, name_sh_offset, + /* MSG_INTL(MSG_DESC_SH_OFFSET) */ + ELFEDIT_I18NHDL(MSG_DESC_SH_OFFSET), + /* MSG_INTL(MSG_HELP_SH_OFFSET) */ + ELFEDIT_I18NHDL(MSG_HELP_SH_OFFSET), + opt_std, arg_sh_offset }, + + /* shdr:sh_size */ + { cmd_sh_size, cpl_1starg_sec, name_sh_size, + /* MSG_INTL(MSG_DESC_SH_SIZE) */ + ELFEDIT_I18NHDL(MSG_DESC_SH_SIZE), + /* MSG_INTL(MSG_HELP_SH_SIZE) */ + ELFEDIT_I18NHDL(MSG_HELP_SH_SIZE), + opt_std, arg_sh_size }, + + /* shdr:sh_type */ + { cmd_sh_type, cpl_sh_type, name_sh_type, + /* MSG_INTL(MSG_DESC_SH_TYPE) */ + ELFEDIT_I18NHDL(MSG_DESC_SH_TYPE), + /* MSG_INTL(MSG_HELP_SH_TYPE) */ + ELFEDIT_I18NHDL(MSG_HELP_SH_TYPE), + opt_std, arg_sh_type }, + + { 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); +} diff --git a/usr/src/cmd/sgs/elfedit/modules/common/shdr.msg b/usr/src/cmd/sgs/elfedit/modules/common/shdr.msg new file mode 100644 index 0000000000..31703e14cb --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/modules/common/shdr.msg @@ -0,0 +1,381 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" + +@ _START_ + +# Message file for elfedit 'shdr' module + +@ MSG_ID_ELFEDIT_SHDR + + +# Section header format +@ MSG_ELF_SHDR "Section Header[%d]: sh_name: %s\n" + +# Debug messages + +@ MSG_DEBUG_S_OK "shdr[%d: %s].%s: value unchanged: %s\n" +@ MSG_DEBUG_S_CHG "shdr[%d: %s].%s: change from %s to %s\n" +@ MSG_DEBUG_LLX_OK "shdr[%d: %s].%s: value unchanged: %#llx\n" +@ MSG_DEBUG_LLX_CHG "shdr[%d: %s].%s: change from %#llx to %#llx\n" +@ MSG_DEBUG_D_OK "shdr[%d: %s].%s: value unchanged: %d\n" +@ MSG_DEBUG_D_CHG "shdr[%d: %s].%s: change from %d to %d\n" +@ MSG_DEBUG_CHGSHDR0 "ELF warning: Unexpected direct change to \ + section header [0]: Header [0] is used for \ + extended section and program headers by the ehdr \ + module, and should otherwise be completely zero\n" +@ MSG_DEBUG_ADDRALIGN "ELF warning: sh_addralign value is expected to \ + be 0, 1, or a power of 2: %s\n" + + +# Module description + +@ MSG_MOD_DESC "Section Header Array" + + +# 1-line description strings + +@ MSG_DESC_DUMP "Dump Section Headers" + +@ MSG_DESC_SH_ADDR "Section memory address" +@ MSG_DESC_SH_ADDRALIGN "Section address alignment" +@ MSG_DESC_SH_ENTSIZE "Section per-item size" +@ MSG_DESC_SH_FLAGS "Section flags" +@ MSG_DESC_SH_INFO "Section info" +@ MSG_DESC_SH_LINK "Section link" +@ MSG_DESC_SH_NAME "Section name" +@ MSG_DESC_SH_OFFSET "Section file offset" +@ MSG_DESC_SH_SIZE "Section size (bytes)" +@ MSG_DESC_SH_TYPE "Section type" + + +# Command option description strings + +@ MSG_OPTDESC_SHNDX "\ + Interpret the sec argument as a section index rather than\n\ + as a section name. section can be one of the well known SHN_\n\ + symbolic constants, or any integer.\n" + +@ MSG_OPTDESC_SHTYP "\ + Interpret the sec argument as a section type rather than\n\ + as a section name. section can be one of the well known SHT_\n\ + symbolic constants, or any integer.\n" + +@ MSG_OPTDESC_NAME_OFFSET "\ + Interpret the name argument as a string table offset rather\n\ + than as a string.\n" + + +# Command argument descriptions + +@ MSG_A1_SEC "\ + Section to examine or modify. By default, this argument is\n\ + interpreted as the name of the desired section. The section\n\ + index of the first section with the specified name is used.\n\ + \n\ + If -shndx is set, then sec is a section index, and is\n\ + interpreted as an integer, or one of the well known SHN_\n\ + symbolic constant names.\n\ + \n\ + If -shtyp is set, then sec is a section type, and is\n\ + interpreted as an integer, or one of the well known SHT_\n\ + symbolic constant names. The section index of the first\n\ + section with the specified type is used.\n" + +@ MSG_A2_DESC_SH_ADDR "Integer value to set for section address.\n" + +@ MSG_A2_DESC_SH_ADDRALIGN "\ + Integer value to set for section alignment.\n" + +@ MSG_A2_DESC_SH_ENTSIZE "\ + Integer value to set for size of an individual element in\n\ + a section of fixed-size entries.\n" + +@ MSG_A2_DESC_SH_FLAGS "\ + Section flags. SHF_ flag constants are accepted, as is\n\ + any integer.\n" + +@ MSG_A2_DESC_SH_INFO "\ + Integer value to set for symbol sh_info field. The meaning\n\ + of this value depends on the type of the section.\n" + +@ MSG_A2_DESC_SH_LINK "\ + Integer value to set for symbol sh_link field. The meaning\n\ + of this value depends on the type of the section.\n" + +@ MSG_A2_DESC_SH_NAME "\ + Name to set for section. If the -name_offset option is\n\ + used, this is an integer offset into the section header\n\ + string table. Otherwise, it is a string, which will be\n\ + looked up in the symbol table in order to obtain the needed\n\ + offset value.\n" + +@ MSG_A2_DESC_SH_OFFSET "\ + Integer value to set for symbol sh_offset field. The value\n\ + of sh_offset gives the byte offset from the beginning of\n\ + the file to the first byte in the section. For SHT_NOBITS\n\ + sections, this member indicates the conceptual offset in the\n\ + file, as the section occupies no space in the file.\n" + +@ MSG_A2_DESC_SH_SIZE "\ + Integer value to set for size of section, in bytes. Unless the\n\ + section type is SHT_NOBITS, the section occupies sh_size bytes\n\ + in the file. A section of type SHT_NOBITS can have a nonzero\n\ + size, but the section occupies no space in the file.\n" + +@ MSG_A2_DESC_SH_TYPE "\ + Value to set for section type. The value can be an integer,\n\ + or one of the well known SHT_ symbolic constant names.\n" + + + +# Help strings + +@ MSG_HELP_DUMP " \ + The shdr:dump command is used to display section header\n\ + information using the same style used by the elfdump program.\n\ + \n\ + If shdr:dump is called without arguments, information for every\n\ + section header in the object is shown. If called with the shndx\n\ + argument, the section header at that index is displayed.\n" + +@ MSG_HELP_SH_ADDR " \ + The shdr:sh_addr command is used to display or alter the\n\ + starting virtual memory address of the section.\n\ + \n\ + If the section appears in the memory image of a process,\n\ + this member gives the address at which the sections's\n\ + first byte should reside. Otherwise, the member is expected\n\ + to contain the value zero.\n\ + \n\ + If shdr:sh_addr is called without arguments, the value of\n\ + sh_addr for every section in the section header array is\n\ + shown. If called with the shndx argument, the value of the\n\ + section at that index is displayed. If both arguments are\n\ + present, the sh_addr field of the section at the specified\n\ + index is set to the given value.\n" + +@ MSG_HELP_SH_ADDRALIGN " \ + The shdr:sh_addralign command is used to display or alter the\n\ + alignment constraint for the section.\n\ + \n\ + Some sections have address alignment constraints. For example,\n\ + if a section holds a double-word, the system must ensure\n\ + double-word alignment for the entire section. In this case,\n\ + the value of sh_addr must be congruent to 0, modulo the value\n\ + of sh_addralign. Currently, only 0 and positive integral\n\ + powers of 2 are used in Solaris ELF files. Values 0 and 1\n\ + mean the section has no alignment constraints.\n\ + \n\ + If shdr:sh_addralign is called without arguments, the value\n\ + of sh_addralign for every section in the section header array\n\ + is shown. If called with the shndx argument, the value of the\n\ + section at that index is displayed. If both arguments are\n\ + present, the sh_addralign field of the section at the specified\n\ + index is set to the given value.\n" + +@ MSG_HELP_SH_ENTSIZE " \ + The shdr:sh_entsize command is used to display or alter the\n\ + per-item entry size for the section.\n\ + \n\ + Some sections hold a table of fixed-size entries, such as a\n\ + symbol table. For such a section, this member gives the size\n\ + in bytes of each entry. By convention, the member is set to\n\ + the value zero if the section does not hold a table of\n\ + fixed-size entries.\n\ + \n\ + If shdr:sh_entsize is called without arguments, the value\n\ + of sh_entsize for every section in the section header array\n\ + is shown. If called with the shndx argument, the value of the\n\ + section at that index is displayed. If both arguments are\n\ + present, the sh_entsize field of the section at the specified\n\ + index is set to the given value.\n" + +@ MSG_HELP_SH_FLAGS " \ + The shdr:sh_flags command is used to display or alter the\n\ + flags that are associated with the section.\n\ + \n\ + \n\ + If shdr:sh_flags is called without arguments, the value\n\ + of sh_flags for every section in the section header array\n\ + is shown. If called with the shndx argument, the value of\n\ + the section at that index is displayed. If one or more\n\ + value arguments are present, the following steps are taken:\n\ + \n \ + o\tAll the value arguments are OR'd together.\n\ + \n \ + o\tIf the -cmp option has been specified, the new value\n\ + \tis complemented.\n\ + \n \ + o\tThe sh_flags field of the section header is updated with\n\ + \tthe new value. If -and is specified, the new value is\n\ + \tAND'd against the existing value. If -or is specified,\n\ + \tthe new value is OR'd against the existing value. If\n\ + \tneither -and or -or are specified, the new value replaces\n\ + \tthe existing value.\n" + +@ MSG_HELP_SH_INFO " \ + The shdr:sh_info command is used to display or alter the\n\ + sh_info field of the specified section.\n\ + \n\ + sh_info contains extra information, the interpretation\n\ + of which depends on the section type.\n\ + \n\ + If shdr:sh_info is called without arguments, the value\n\ + of sh_info for every section in the section header array\n\ + is shown. If called with the shndx argument, the value of the\n\ + section at that index is displayed. If both arguments are\n\ + present, the sh_info field of the section at the specified\n\ + index is set to the given value.\n" + +@ MSG_HELP_SH_LINK " \ + The shdr:sh_link command is used to display or alter the\n\ + sh_link field of the specified section.\n\ + \n\ + sh_link contains extra information, the interpretation\n\ + of which depends on the section type.\n\ + \n\ + If shdr:sh_link is called without arguments, the value\n\ + of sh_link for every section in the section header array\n\ + is shown. If called with the shndx argument, the value of the\n\ + section at that index is displayed. If both arguments are\n\ + present, the sh_link field of the section at the specified\n\ + index is set to the given value.\n" + +@ MSG_HELP_SH_NAME " \ + The shdr:sh_name command is used to display or alter the\n\ + name associated with a specified section.\n\ + \n\ + The sh_name field of a section header is an index into\n\ + the section header string table section giving the location\n\ + of a null terminated string.\n\ + \n\ + If shdr:sh_name is called without arguments, the name of\n\ + every section in the section header array is shown. If called\n\ + with the shndx argument, the name of the section at that\n\ + index is displayed. If both arguments are present, the\n\ + sh_name field of the section at the specified index is set\n\ + to the given value.\n\ + \n\ + When changing the name of a section, you should be aware\n\ + that the name selected must exist within the section header\n\ + string table, as it is not possible to add new strings to\n\ + this string table.\n" + +@ MSG_HELP_SH_OFFSET " \ + The shdr:sh_offset command is used to display or alter the\n\ + sh_offset field of the specified section.\n\ + \n\ + sh_offset provides the byte offset from the beginning of\n\ + the file to the first byte in the section. For a SHT_NOBITS\n\ + section, this member indicates the conceptual offset in\n\ + the file, as the section occupies no space in the file.\n\ + \n\ + If shdr:sh_offset is called without arguments, the value\n\ + of sh_offset for every section in the section header array\n\ + is shown. If called with the shndx argument, the value of the\n\ + section at that index is displayed. If both arguments are\n\ + present, the sh_offset field of the section at the specified\n\ + index is set to the given value.\n" + +@ MSG_HELP_SH_SIZE " \ + The shdr:sh_size command is used to display or alter the\n\ + sh_size field of the specified section.\n\ + \n\ + sh_size provides the section's size in bytes. Unless the\n\ + section type is SHT_NOBITS, the section occupies sh_size\n\ + bytes in the file. A section of type SHT_NOBITS can have\n\ + a non-zero size, but the section occupies no space in the file.\n\ + \n\ + If shdr:sh_size is called without arguments, the value\n\ + of sh_size for every section in the section header array\n\ + is shown. If called with the shndx argument, the value of the\n\ + section at that index is displayed. If both arguments are\n\ + present, the sh_size field of the section at the specified\n\ + index is set to the given value.\n" + +@ MSG_HELP_SH_TYPE " \ + The shdr:sh_type command is used to display or alter the\n\ + sh_type field of the specified section.\n\ + \n\ + The type of a section categorizes the section's contents\n\ + and semantics.\n\ + \n\ + If shdr:sh_type is called without arguments, the value\n\ + of sh_type for every section in the section header array\n\ + is shown. If called with the shndx argument, the value of the\n\ + section at that index is displayed. If both arguments are\n\ + present, the sh_type field of the section at the specified\n\ + index is set to the given value.\n" + + + +@ _END_ + + +# The following strings represent reserved words, files, pathnames and symbols. +# Reference to this strings is via the MSG_ORIG() macro, and thus no message +# translation is required. + + +# Miscellaneous clutter +@ MSG_STR_EMPTY "" +@ MSG_STR_NL "\n" +@ MSG_STR_MINUS_SHNDX "-shndx" +@ MSG_STR_MINUS_SHTYP "-shtyp" +@ MSG_STR_MINUS_NAME_OFFSET "-name_offset" +@ MSG_STR_NAME "name" +@ MSG_STR_SEC "sec" +@ MSG_STR_VALUE "value" + + +# Format strings + +@ MSG_FMT_WORDVALNL "%u\n" +@ MSG_FMT_WORDHEXNL "%#x\n" +@ MSG_FMT_XWORDHEXNL "%#llx\n" +@ MSG_FMT_STRNL "%s\n" + + +# Module name + +@ MSG_MOD_NAME "shdr" + + +# Command names + +@ MSG_CMD_DUMP "dump" + +@ MSG_CMD_SH_ADDR "sh_addr" +@ MSG_CMD_SH_ADDRALIGN "sh_addralign" +@ MSG_CMD_SH_ENTSIZE "sh_entsize" +@ MSG_CMD_SH_FLAGS "sh_flags" +@ MSG_CMD_SH_INFO "sh_info" +@ MSG_CMD_SH_LINK "sh_link" +@ MSG_CMD_SH_NAME "sh_name" +@ MSG_CMD_SH_OFFSET "sh_offset" +@ MSG_CMD_SH_SIZE "sh_size" +@ MSG_CMD_SH_TYPE "sh_type" diff --git a/usr/src/cmd/sgs/elfedit/modules/common/sym.c b/usr/src/cmd/sgs/elfedit/modules/common/sym.c new file mode 100644 index 0000000000..c963586e20 --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/modules/common/sym.c @@ -0,0 +1,2031 @@ +/* + * 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" + +#define ELF_TARGET_AMD64 /* SHN_AMD64_LCOMMON */ + +#include <stdio.h> +#include <unistd.h> +#include <machdep.h> +#include <elfedit.h> +#include <strings.h> +#include <debug.h> +#include <conv.h> +#include <sym_msg.h> + + + + +#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); +} +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; + 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, 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_FULLNAME, &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_FULLNAME, &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_FULLNAME, &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_FULLNAME, &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_FULLNAME, + &inv_buf1), + conv_sym_info_bind(bind, CONV_FMT_ALT_FULLNAME, &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_FULLNAME, + &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_FULLNAME, + &inv_buf1), + conv_sym_info_type(mach, type, CONV_FMT_ALT_FULLNAME, + &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_PROTECTED, 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_FULLNAME, + &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_FULLNAME, + &inv_buf1), + conv_sym_other_vis(vis, CONV_FMT_ALT_FULLNAME, &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 needs + * be a symbol table. + */ + if (explicit) + (void) elfedit_sec_issymtab(&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 explicit table specified, only that table is considered */ + if (explicit && (symtab->symt_shndx != index)) + 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: + { + char index[MAXNDXSIZE]; + + (void) snprintf(index, sizeof (index), + MSG_ORIG(MSG_FMT_WORDVAL), + symtab->symt_shndx); + elfedit_cpl_match(cpldata, index, 1); + } + break; + case TYPE: + { + elfedit_atoui_sym_t *cpl_list; + + (void) elfedit_sec_issymtab(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), NULL, 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), NULL, 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), NULL, 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, NULL, + 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), NULL, 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), NULL, 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), NULL, 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), NULL, 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), NULL, 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), NULL, 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, NULL, + 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), NULL, 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), NULL, 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), NULL, 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, NULL, + 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); +} diff --git a/usr/src/cmd/sgs/elfedit/modules/common/sym.msg b/usr/src/cmd/sgs/elfedit/modules/common/sym.msg new file mode 100644 index 0000000000..0fe21d7eeb --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/modules/common/sym.msg @@ -0,0 +1,413 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" + +@ _START_ + +# Message file for elfedit 'sym' module + +@ MSG_ID_ELFEDIT_SYM + + +# Command argument strings +@ MSG_ARG_SECNDX "symbol section index" +@ MSG_ARG_SYM "Name of desired symbol within symbol table(s)" +@ MSG_ARG_SYMVIS "symbol visibility" +@ MSG_ARG_SYMBIND "symbol binding" + +# Names of things we allocate dynamically + +@ MSG_ALLOC_ARGSTATE "symbol table state" + +# Format strings +@ MSG_FMT_SYMTAB "Symbol Table Section: %s\n" + +# Debug messages + +@ MSG_DEBUG_S_OK "[%d: %s][%d].%s: value unchanged: %s\n" +@ MSG_DEBUG_S_CHG "[%d: %s][%d].%s: change from %s to %s\n" +@ MSG_DEBUG_EXT_S_OK "[%d: %s][%d]: value unchanged: %s\n" +@ MSG_DEBUG_EXT_S_CHG "[%d: %s][%d]: change from %s to %s\n" +@ MSG_DEBUG_D_OK "[%d: %s][%d].%s: value unchanged: %d\n" +@ MSG_DEBUG_D_CHG "[%d: %s][%d].%s: change from %d to %d\n" +@ MSG_DEBUG_LLX_OK "[%d: %s][%d].%s: value unchanged: %#llx\n" +@ MSG_DEBUG_LLX_CHG "[%d: %s][%d].%s: change from %#llx to %#llx\n" +@ MSG_DEBUG_SHNDX_UNDEF0 "ELF warning: symbol [0] is expected to reference \ + SHN_UNDEF\n" +@ MSG_DEBUG_SHNDX_XINDEX "ELF warning: SHN_XINDEX is not supposed to \ + be set directly\n" +@ MSG_DEBUG_SHNDX_EFORCE "[%d: %s][%d]: ELF warning: Section index does not \ + normally go in extended index section: %d\n" +@ MSG_DEBUG_LBINDGSYM "[%d: %s][%d]: ELF warning: local binding set for \ + symbol in global part of symbol table \ + (shdr[%d].sh_info == %d)\n" +@ MSG_DEBUG_GBINDLSYM "[%d: %s][%d]: ELF warning: global binding set for \ + symbol in local part of symbol table \ + (shdr[%d].sh_info == %d)\n" +@ MSG_DEBUG_DYNSYMNAMCHG "[%d: %s][%d]: ELF warning: changing the name \ + of a symbol in the dynamic symbol table will confuse \ + the hash section and likely render the object \ + unusable\n" +@ MSG_DEBUG_CHGSYMELT0 "[%d: %s][%d]: ELF warning: Symbol [0] is expected \ + to be NULL\n" + +# Errors + +@ MSG_ERR_NOSYMTAB "Object does not have any symbol tables\n"; +@ MSG_ERR_NEEDEXPSYMTAB "The -symndx option requires a symbol table to be \ + explicitly specified (-shnam, -shndx, or \ + -shtyp options)\n" + + + +# Module description + +@ MSG_MOD_DESC "Symbol Section" + + +# 1-line description strings + +@ MSG_DESC_DUMP "Dump Symbol Table" +@ MSG_DESC_ST_BIND "Symbol binding" +@ MSG_DESC_ST_INFO "st_info (binding and type)" +@ MSG_DESC_ST_NAME "Symbol name" +@ MSG_DESC_ST_OTHER "st_other (visibility)" +@ MSG_DESC_ST_SHNDX "Symbol section index" +@ MSG_DESC_ST_SIZE "Symbol size" +@ MSG_DESC_ST_TYPE "Symbol type" +@ MSG_DESC_ST_VALUE "Symbol value" +@ MSG_DESC_ST_VISIBILITY "Symbol visibility" + + +# Command option description strings + +@ MSG_OPTDESC_E "\ + Force the use of the extended index section to hold the\n\ + specified section index, even if it is small enough to fit\n\ + into the symbol st_shndx field. Note that this will produce\n\ + a non-standard ELF file.\n" +@ MSG_OPTDESC_SHNDX "\ + Use the symbol table found in the ELF section with the\n\ + specified index.\n" +@ MSG_OPTDESC_SHNAM "\ + Use the symbol table found in the ELF section with the\n\ + specified name.\n" +@ MSG_OPTDESC_SHTYP "\ + Use the first symbol table found in the ELF section with\n\ + the specified section type.\n" +@ MSG_OPTDESC_SECSHNDX "\ + Interpret the sec argument as a section index rather than\n\ + as a section name. section can be one of the well known SHN_\n\ + symbolic constants, or any integer.\n" +@ MSG_OPTDESC_SECSHTYP "\ + Interpret the sec argument as a section type rather than\n\ + as a section name. section can be one of the well known SHT_\n\ + symbolic constants, or any integer.\n" +@ MSG_OPTDESC_NAME_OFFSET "\ + Interpret the name argument as a string table offset rather\n\ + than as a string.\n" + +@ MSG_OPTDESC_SYMNDX "\ + The sym argument supplies a numeric index into the symbol\n\ + section instead of the name of the symbol. The symbol table\n\ + to use must be explicitly specified (-shnam, -shndx, or\n\ + -shtyp option) when -symndx is used.\n". + +# Command argument descriptions + +@ MSG_A1_SYM "Name of desired symbol within symbol table.\n" + +@ MSG_A2_DESC_ST_BIND "Symbol binding. STB_ symbol constants are\n\ + accepted, as is any integer in the range 0 - 15.\n" + +@ MSG_A2_DESC_ST_INFO "Integer value to set for symbol st_info field.\n\ + Note that the fact that the value of st_info affects both\n\ + the symbol binding and type values.\n" + +@ MSG_A2_DESC_ST_NAME "\ + Name to set for symbol. If the -name_offset option is used,\n\ + this is an integer offset into the string table section\n\ + associated with the symbol table. Otherwise, it is a string,\n\ + which will be looked up in the symbol table (and inserted if\n\ + necessary, and if possible) in order to obtain the needed\n\ + offset value.\n" + +@ MSG_A2_DESC_ST_OTHER "\ + Integer value to set for symbol st_other field. Note\n\ + that the fact that the value of st_other affects the\n\ + symbol visibility value.\n" + +@ MSG_A2_DESC_ST_SEC "\ + Section to set for symbol section index. By default, this\n\ + argument is interpreted as the name of the desired section.\n\ + The section index of the first section with the specified\n\ + name is used.\n\ + \n\ + If -secshndx is set, then sec is a section index,\n\ + and is interpreted as an integer, or one of the well known\n\ + SHN_ symbolic constant names.\n\ + \n\ + If -secshtyp is set, then sec is a section type,\n\ + and is interpreted as an integer, or one of the well known\n\ + SHT_ symbolic constant names. The section index of the first\n\ + section with the specified type is used.\n" + + +@ MSG_A2_DESC_ST_SIZE "Integer value to set for symbol size.\n" + +@ MSG_A2_DESC_ST_TYPE "\ + Symbol type. STT_ symbol constants are accepted, as is any\n\ + integer in the range 0 - 15.\n" + +@ MSG_A2_DESC_ST_VALUE "Integer value to set for symbol value.\n" + +@ MSG_A2_DESC_ST_VISIBILITY "\ + Symbol visibility. STV_ symbol constants are accepted, as\n\ + are integer values.\n" + + + +# Help strings + +@ MSG_HELP_DUMP " \ + The sym:dump command is used to display symbol information\n\ + using the same style used by the elfdump program.\n\ + \n\ + By default, symbols are taken from all available symbol tables.\n\ + The symbol table to use can be changed using the -shnam, -shndx,\n\ + or -shtyp options. Only one of these options can be used at a time.\n\ + \n\ + If sym:dump is called without arguments, information for every\n\ + symbol in the symbol table is shown. If called with the symndx\n\ + argument, the information forthe symbol at that index is\n\ + displayed.\n" + +@ MSG_HELP_ST_BIND " \ + The sym:st_bind command is used to display or alter symbol\n\ + binding. Symbol binding is found in the st_bind portion of the\n\ + st_info field of an ELF symbol.\n\ + \n\ + By default, symbols are taken from all available symbol tables.\n\ + The symbol table to use can be changed using the -shnam, -shndx,\n\ + or -shtyp options. Only one of these options can be used at a time.\n\ + \n\ + If sym:st_bind is called without arguments, the value of\n\ + st_bind for every symbol in the symbol table is shown. If\n\ + called with the symndx argument, the value of the symbol at that\n\ + index is displayed. If both arguments are present, the st_bind\n\ + field of the symbol at the specified index is set to the given\n\ + value.\n" + +@ MSG_HELP_ST_INFO " \ + The sym:st_info command is used to display or alter the\n\ + st_info field of the specified symbol. It provides raw access\n\ + to the entire st_info value. Normally, the sym:st_bind or sym:st_type\n\ + commands are used in preference to sym:st_info.\n\ + \n\ + By default, symbols are taken from all available symbol tables.\n\ + The symbol table to use can be changed using the -shnam, -shndx,\n\ + or -shtyp options. Only one of these options can be used at a time.\n\ + If sym:st_info is called without arguments, the value of st_info\n\ + for every symbol in the symbol table is shown. If called with the\n\ + symndx argument, the value of the symbol at that index is displayed.\n\ + If both arguments are present, the st_info field of the symbol at\n\ + the specified index is set to the given value.\n" + +@ MSG_HELP_ST_NAME " \ + The sym:st_name command is used to display or alter the\n\ + name associated with a specified symbol.\n\ + \n\ + By default, symbols are taken from all available symbol tables.\n\ + The symbol table to use can be changed using the -shnam, -shndx,\n\ + or -shtyp options. Only one of these options can be used at a time.\n\ + \n\ + If sym:st_name is called without arguments, the value of st_name\n\ + for every symbol in the symbol table is shown. If called with the\n\ + symndx argument, the name of the symbol at that index is displayed.\n\ + If both arguments are present, the name field of the symbol at\n\ + the specified index is set to the given value.\n\ + \n\ + When changing the name of a symbol, you should be aware of the\n\ + following limitations:\n\ + \n \ + o\tIt is only possible to change the name of a symbol in a\n\ + \tnon-dynamic symbol table to one of the names already found\n\ + \tin the associated string table.\n\ + \n \ + o\tChanging the name of a symbol in the dynamic symbol table\n\ + \twill lead to the hash table having inaccurate information\n\ + \tabout the symbol table, and is likely render the object\n\ + \tunusable.\n" + +@ MSG_HELP_ST_OTHER " \ + The sym:st_other command is used to display or alter the\n\ + st_other field of the specified symbol. It provides raw access\n\ + to the entire st_other value. Normally, the sym:st_visibility\n\ + command is used in preference to sym:st_other.\n\ + \n\ + By default, symbols are taken from all available symbol tables.\n\ + The symbol table to use can be changed using the -shnam, -shndx,\n\ + or -shtyp options. Only one of these options can be used at a time.\n\ + \n\ + If sym:st_other is called without arguments, the value of st_other\n\ + for every symbol in the symbol table is shown. If called with the\n\ + symndx argument, the value of the symbol at that index is displayed.\n\ + If both arguments are present, the st_other field of the symbol at\n\ + the specified index is set to the given value.\n" + +@ MSG_HELP_ST_SHNDX " \ + Every symbol table entry is defined in relation to some section.\n\ + This information is maintained in the st_shndx field of an ELF\n\ + symbol. The sym:st_shndx command is used to display or alter the\n\ + st_shndx field of the specified symbol.\n\ + \n\ + By default, symbols are taken from all available symbol tables.\n\ + The symbol table to use can be changed using the -shnam, -shndx,\n\ + or -shtyp options. Only one of these options can be used at a time.\n\ + \n\ + If sym:st_shndx is called without arguments, the value of st_shndx\n\ + for every symbol in the symbol table is shown. If called with the\n\ + symndx argument, the value of the symbol at that index is displayed.\n\ + If both arguments are present, the st_shndx field of the symbol at\n\ + the specified index is set to the given value.\n\ + \n\ + sym:st_shndx is aware of extended section indexes, and will\n\ + access/modify the extended index sections associated with a given\n\ + symbol table as necessary.\n" + +@ MSG_HELP_ST_SIZE " \ + The sym:st_size command is used to display or alter the\n\ + size of the specified symbol (st_size field).\n\ + \n\ + By default, symbols are taken from all available symbol tables.\n\ + The symbol table to use can be changed using the -shnam, -shndx,\n\ + or -shtyp options. Only one of these options can be used at a time.\n\ + \n\ + If sym:st_size is called without arguments, the value of st_size\n\ + for every symbol in the symbol table is shown. If called with\n\ + the symndx argument, the size of the symbol at that index is\n\ + displayed. If both arguments are present, the st_size field of\n\ + the symbol at the specified index is set to the given value.\n" + +@ MSG_HELP_ST_TYPE " \ + The sym:st_type command is used to display or alter the\n\ + st_type portion of the st_info field of the specified\n\ + symbol.\n\ + \n\ + By default, symbols are taken from all available symbol tables.\n\ + The symbol table to use can be changed using the -shnam, -shndx,\n\ + or -shtyp options. Only one of these options can be used at a time.\n\ + \n\ + If sym:st_type is called without arguments, the value of\n\ + st_type for every symbol in the symbol table is shown. If\n\ + called with the symndx argument, the value of the symbol at that\n\ + index is displayed. If both arguments are present, the st_type\n\ + field of the symbol at the specified index is set to the given value.\n" + +@ MSG_HELP_ST_VALUE " \ + The sym:st_value command is used to display or alter the\n\ + value of the specified symbol (st_value field).\n\ + \n\ + By default, symbols are taken from all available symbol tables.\n\ + The symbol table to use can be changed using the -shnam, -shndx,\n\ + or -shtyp options. Only one of these options can be used at a time.\n\ + \n\ + If sym:st_value is called without arguments, the value of\n\ + st_value for every symbol in the symbol table is shown. If\n\ + called with the symndx argument, the value of the symbol at that\n\ + index is displayed. If both arguments are present, the st_value\n\ + field of the symbol at the specified index is set to the given value.\n" + +@ MSG_HELP_ST_VISIBILITY " \ + The sym:st_visibility command is used to display or alter the\n\ + st_visibility portion of the st_other field of the specified\n\ + symbol.\n\ + \n\ + By default, symbols are taken from all available symbol tables.\n\ + The symbol table to use can be changed using the -shnam, -shndx,\n\ + or -shtyp options. Only one of these options can be used at a time.\n\ + \n\ + If sym:st_visibility is called without arguments, the value of\n\ + st_visibility for every symbol in the symbol table is shown. If\n\ + called with the symndx argument, the value of the symbol at that\n\ + index is displayed. If both arguments are present, the st_visibility\n\ + field of the symbol at the specified index is set to the given value.\n" + + +@ _END_ + + +# The following strings represent reserved words, files, pathnames and symbols. +# Reference to this strings is via the MSG_ORIG() macro, and thus no message +# translation is required. + + +# Miscellaneous clutter +@ MSG_STR_EMPTY "" +@ MSG_STR_NL "\n" +@ MSG_STR_MINUS_E "-e" +@ MSG_STR_MINUS_SHNAM "-shnam" +@ MSG_STR_MINUS_SHNDX "-shndx" +@ MSG_STR_MINUS_SHTYP "-shtyp" +@ MSG_STR_MINUS_SYMNDX "-symndx" +@ MSG_STR_MINUS_NAME_OFFSET "-name_offset" +@ MSG_STR_MINUS_SECSHNDX "-secshndx" +@ MSG_STR_MINUS_SECSHTYP "-secshtyp" +@ MSG_STR_INDEX "index" +@ MSG_STR_NAME "name" +@ MSG_STR_SEC "sec" +@ MSG_STR_SYM "sym" +@ MSG_STR_TYPE "type" +@ MSG_STR_VALUE "value" + + +# Format strings + +@ MSG_FMT_WORDVAL "%u" +@ MSG_FMT_WORDVALNL "%u\n" +@ MSG_FMT_XWORDVALNL_32 "0x%8.8x\n" +@ MSG_FMT_XWORDVALNL_64 "0x%16.16llx\n" +@ MSG_FMT_STRNL "%s\n" +@ MSG_FMT_INDEX " [%lld]" + + +# Module name + +@ MSG_MOD_NAME "sym" + + +# Command names + +@ MSG_CMD_DUMP "dump" +@ MSG_CMD_ST_BIND "st_bind" +@ MSG_CMD_ST_INFO "st_info" +@ MSG_CMD_ST_NAME "st_name" +@ MSG_CMD_ST_OTHER "st_other" +@ MSG_CMD_ST_SHNDX "st_shndx" +@ MSG_CMD_ST_SIZE "st_size" +@ MSG_CMD_ST_TYPE "st_type" +@ MSG_CMD_ST_VALUE "st_value" +@ MSG_CMD_ST_VISIBILITY "st_visibility" diff --git a/usr/src/cmd/sgs/elfedit/modules/common/syminfo.c b/usr/src/cmd/sgs/elfedit/modules/common/syminfo.c new file mode 100644 index 0000000000..c419694b94 --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/modules/common/syminfo.c @@ -0,0 +1,882 @@ +/* + * 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 <stdio.h> +#include <unistd.h> +#include <machdep.h> +#include <elfedit.h> +#include <strings.h> +#include <debug.h> +#include <conv.h> +#include <syminfo_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 { + SYMINFO_CMD_T_DUMP = 0, /* syminfo:dump */ + + SYMINFO_CMD_T_SI_BOUNDTO = 1, /* syminfo:si_boundto */ + SYMINFO_CMD_T_SI_FLAGS = 2 /* syminfo:si_boundto */ +} SYMINFO_CMD_T; + + + +#ifndef _ELF64 +/* + * We supply this function for the msg module. Only one copy is needed. + */ +const char * +_syminfo_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 { + SYMINFO_OPT_F_AND = 1, /* -and: AND (&) values to dest */ + SYMINFO_OPT_F_CMP = 2, /* -cmp: Complement (~) values */ + SYMINFO_OPT_F_NEEDED = 4, /* -needed: arg is name of object to */ + /* be referenced via DT_NEEDED */ + /* dynamic entry */ + SYMINFO_OPT_F_OR = 8, /* -or: OR (|) values to dest */ + SYMINFO_OPT_F_SYMNDX = 16 /* -symndx: Sym specified by index */ +} syminfo_opt_t; + + +/* + * A variable of type ARGSTATE is used by each command to maintain + * information about the syminfo section being used, as and for any + * auxiliary sections that are related to it. This 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. + */ +typedef struct { + elfedit_obj_state_t *obj_state; + syminfo_opt_t optmask; /* Mask of options used */ + int argc; /* # of plain arguments */ + const char **argv; /* Plain arguments */ + struct { /* Syminfo */ + elfedit_section_t *sec; + Syminfo *data; + Word n; + } syminfo; + struct { /* Symbol table */ + elfedit_section_t *sec; + Sym *data; + Word n; + } sym; + struct { /* String table */ + elfedit_section_t *sec; + } str; + struct { /* Dynamic section */ + elfedit_section_t *sec; + Dyn *data; + Word n; + } dynamic; +} ARGSTATE; + + + +/* + * Standard argument processing for syminfo 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. + * + * note: + * Only the syminfo section is initially referenced by + * argstate. Use the argstate_add_XXX() routines below to + * access any other sections needed. + */ +static void +process_args(elfedit_obj_state_t *obj_state, int argc, const char *argv[], + SYMINFO_CMD_T cmd, ARGSTATE *argstate) +{ + elfedit_getopt_state_t getopt_state; + elfedit_getopt_ret_t *getopt_ret; + + bzero(argstate, sizeof (*argstate)); + argstate->obj_state = obj_state; + + 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; + + /* + * Usage error if there are too many plain arguments. + * - syminfo:dump accepts a single argument + * - syminfo:si_boundto accepts 2 arguments + * - syminfo:si_flags accepts an unbounded number + */ + if (((cmd == SYMINFO_CMD_T_DUMP) && (argc > 1)) || + ((cmd == SYMINFO_CMD_T_SI_BOUNDTO) && (argc > 2))) + 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 the syminfo section */ + argstate->syminfo.sec = elfedit_sec_getsyminfo(obj_state, + &argstate->syminfo.data, &argstate->syminfo.n); +} + + + +/* + * We maintain the state of the current syminfo table in a ARGSTATE + * structure. A syminfo is related to the dynamic symbol table, and + * can reference the dynamic section of the object. We don't look those + * 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 initialze the + * state block with just the syminfo section, and then one of the + * argstate_add_XXX() functions is used as needed to fetch the + * additional sections. + * + * entry: + * argstate - 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 +argstate_add_sym(ARGSTATE *argstate) +{ + if (argstate->sym.sec != NULL) + return; + + argstate->sym.sec = elfedit_sec_getsymtab(argstate->obj_state, + 1, argstate->syminfo.sec->sec_shdr->sh_link, NULL, + &argstate->sym.data, &argstate->sym.n, NULL); +} +static void +argstate_add_str(ARGSTATE *argstate) +{ + if (argstate->str.sec != NULL) + return; + + argstate_add_sym(argstate); + argstate->str.sec = elfedit_sec_getstr(argstate->obj_state, + argstate->sym.sec->sec_shdr->sh_link); +} +static void +argstate_add_dynamic(ARGSTATE *argstate) +{ + if (argstate->dynamic.sec != NULL) + return; + + argstate->dynamic.sec = elfedit_sec_getdyn(argstate->obj_state, + &argstate->dynamic.data, &argstate->dynamic.n); +} + + + +/* + * Display syminfo section entries in the style used by elfdump. + * + * entry: + * argstate - State block for current symbol table. + * ndx - Index of first symbol to display + * cnt - Number of symbols to display + */ +static void +dump_syminfo(ARGSTATE *argstate, Word ndx, Word cnt) +{ + Syminfo *syminfo; + Sym *sym; + Dyn *dyn; + + syminfo = argstate->syminfo.data + ndx; + + argstate_add_sym(argstate); + sym = argstate->sym.data + ndx; + + argstate_add_str(argstate); + + argstate_add_dynamic(argstate); + dyn = argstate->dynamic.data; + + /* + * Loop through the syminfo entries. + */ + Elf_syminfo_title(0); + + for (; cnt-- > 0; ndx++, syminfo++, sym++) { + const char *needed = NULL, *name; + + name = elfedit_offset_to_str(argstate->str.sec, + sym->st_name, ELFEDIT_MSG_ERR, 0); + + if ((syminfo->si_boundto < SYMINFO_BT_LOWRESERVE) && + (syminfo->si_boundto < argstate->dynamic.n) && + ((dyn[syminfo->si_boundto].d_tag == DT_NEEDED) || + (dyn[syminfo->si_boundto].d_tag == DT_USED))) + needed = elfedit_offset_to_str(argstate->str.sec, + dyn[syminfo->si_boundto].d_un.d_val, + ELFEDIT_MSG_ERR, 0); + else + needed = MSG_ORIG(MSG_STR_EMPTY); + + Elf_syminfo_entry(0, ndx, syminfo, name, needed); + } +} + + + +/* + * Print syminfo values, taking the calling command, and output style + * into account. + * + * entry: + * cmd - SYMINFO_CMD_T_* value giving identify of caller + * 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. + * ndx - Index of first symbol to display + * cnt - Number of symbols to display + */ +static void +print_syminfo(SYMINFO_CMD_T cmd, int autoprint, ARGSTATE *argstate, + Word ndx, Word cnt) +{ + elfedit_outstyle_t outstyle; + Syminfo *syminfo; + + if ((autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0)) || + (cnt == 0)) + return; + + /* + * Pick an output style. syminfo:dump is required to use the default + * style. The other commands use the current output style. + */ + outstyle = (cmd == SYMINFO_CMD_T_DUMP) ? + ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle(); + + /* + * 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_syminfo(argstate, ndx, cnt); + return; + } + + syminfo = argstate->syminfo.data; + + switch (cmd) { + case SYMINFO_CMD_T_SI_BOUNDTO: + if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { + /* Find the dynamic section and string table */ + argstate_add_dynamic(argstate); + argstate_add_str(argstate); + } + + for (syminfo += ndx; cnt--; syminfo++) { + Half bndto = syminfo->si_boundto; + + if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { + const char *str = NULL; + + switch (bndto) { + case SYMINFO_BT_SELF: + str = elfedit_atoconst_value_to_str( + ELFEDIT_CONST_SYMINFO_BT, + SYMINFO_BT_SELF, 1); + break; + case SYMINFO_BT_PARENT: + str = elfedit_atoconst_value_to_str( + ELFEDIT_CONST_SYMINFO_BT, + SYMINFO_BT_PARENT, 1); + break; + case SYMINFO_BT_NONE: + str = elfedit_atoconst_value_to_str( + ELFEDIT_CONST_SYMINFO_BT, + SYMINFO_BT_NONE, 1); + break; + } + if ((str == NULL) && + (bndto < SYMINFO_BT_LOWRESERVE) && + (argstate->dynamic.sec != NULL) && + (bndto < argstate->dynamic.n) && + (argstate->dynamic.data[bndto].d_tag == + DT_NEEDED)) + str = elfedit_offset_to_str( + argstate->str.sec, + argstate->dynamic.data[bndto]. + d_un.d_val, ELFEDIT_MSG_ERR, 0); + + if (str != NULL) { + elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), + str); + continue; + } + } + + /* + * If we reach this point, we are either in numeric + * mode, or we were unable to find a string above. + * In either case, output as integer. + */ + elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL), + EC_WORD(bndto)); + } + break; + + case SYMINFO_CMD_T_SI_FLAGS: + for (syminfo += ndx; cnt--; syminfo++) { + if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { + Conv_syminfo_flags_buf_t buf; + + elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), + conv_syminfo_flags(syminfo->si_flags, + CONV_FMT_NOBKT, &buf)); + } else { + elfedit_printf(MSG_ORIG(MSG_FMT_HEXNUMNL), + EC_WORD(syminfo->si_flags)); + } + } + break; + } +} + + +/* + * Convert the given argument string into a symbol table index. + * + * entry: + * argstate - State block for current symbol table. + * arg - String containing symbol index argument. + * + * exit: + * On success, returns the symbol index. On failure, an error + * is issued and this routine does not return. + */ +static Word +arg_to_symndx(ARGSTATE *argstate, const char *arg) +{ + Word symndx; + + /* + * If the -symndx option was specified, arg is an index + * into the symbol table. + */ + if (argstate->optmask & SYMINFO_OPT_F_SYMNDX) + return (elfedit_atoui_range(arg, MSG_ORIG(MSG_STR_SYM), + 0, argstate->syminfo.n - 1, NULL)); + + /* + * arg is a symbol name. Return the index of the first symbol + * that matches + */ + argstate_add_sym(argstate); + argstate_add_str(argstate); + + (void) elfedit_name_to_symndx(argstate->sym.sec, + argstate->str.sec, arg, ELFEDIT_MSG_ERR, &symndx); + + return (symndx); +} + + +/* + * Given a string argument representing an object, return the index of + * the dynamic section that should be used for the si_boundto value. + */ +static Half +needed_to_boundto(ARGSTATE *argstate, const char *arg) +{ + Conv_inv_buf_t inv_buf; + elfedit_dyn_elt_t strpad_elt; + elfedit_dyn_elt_t null_elt; + elfedit_section_t *dynsec; + Word null_cnt; + Dyn *dyn; + Word str_offset, ndx, numdyn; + int have_string; + + argstate_add_str(argstate); + argstate_add_dynamic(argstate); + dynsec = argstate->dynamic.sec; + numdyn = argstate->dynamic.n; + + /* Locate DT_SUNW_STRPAD element if present and locate the DT_NULLs */ + elfedit_dyn_elt_init(&strpad_elt); + elfedit_dyn_elt_init(&null_elt); + null_cnt = 0; + strpad_elt.dn_dyn.d_un.d_val = 0; + dyn = argstate->dynamic.data; + for (ndx = 0; ndx < numdyn; dyn++, ndx++) { + switch (dyn->d_tag) { + case DT_NULL: + /* Count all the nulls, remember the first one */ + null_cnt++; + if (!null_elt.dn_seen) + elfedit_dyn_elt_save(&null_elt, ndx, dyn); + break; + + case DT_SUNW_STRPAD: + elfedit_dyn_elt_save(&strpad_elt, ndx, dyn); + break; + } + } + + /* + * Look up the string in the string table and get its offset. If + * this succeeds, then it is possible that there is a DT_NEEDED + * dynamic entry that references it. + */ + have_string = elfedit_sec_findstr(argstate->str.sec, + strpad_elt.dn_dyn.d_un.d_val, arg, &str_offset) != 0; + if (have_string) { + dyn = argstate->dynamic.data; + for (ndx = 0; ndx < numdyn; dyn++, ndx++) { + if (((dyn->d_tag == DT_NEEDED) || + (dyn->d_tag == DT_USED)) && + (dyn->d_un.d_val == str_offset)) + goto done; + } + } + + /* + * It doesn't already exist. We might be able to add a DT_NEEDED + * to the dynamic section if an extra DT_NULL is available. + * Otherwise, we have to fail here. + */ + if (null_cnt < 2) + elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOEXTRANULL), + EC_WORD(dynsec->sec_shndx), dynsec->sec_name); + + /* + * If the string is not already in the string table, try to + * insert it. If it succeeds, we will convert the DT_NULL. + * Otherwise, an error will be issued and control will not + * return here. + */ + if (!have_string) + str_offset = elfedit_dynstr_insert(dynsec, + argstate->str.sec, &strpad_elt, arg); + + /* Convert the extra DT_NULL */ + ndx = null_elt.dn_ndx; + elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CONVNULL), + EC_WORD(dynsec->sec_shndx), dynsec->sec_name, EC_WORD(ndx), + conv_dyn_tag(DT_NEEDED, argstate->obj_state->os_ehdr->e_machine, + 0, &inv_buf)); + dyn = argstate->dynamic.data + ndx; + dyn->d_tag = DT_NEEDED; + dyn->d_un.d_val = str_offset; + elfedit_modified_data(dynsec); + +done: + elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDNEEDED), + dynsec->sec_shndx, dynsec->sec_name, ndx, arg); + return (ndx); +} + +/* + * Common body for the syminfo: 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 SYMINFO_CMD_T_* constants listed above, specifying + * which command to implement. + * obj_state, argc, argv - Standard command arguments + */ +static elfedit_cmdret_t +cmd_body(SYMINFO_CMD_T cmd, elfedit_obj_state_t *obj_state, + int argc, const char *argv[]) +{ + ARGSTATE argstate; + Word ndx; + Syminfo *syminfo; + elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE; + + process_args(obj_state, argc, argv, cmd, &argstate); + + /* If there are no arguments, dump the whole table and return */ + if (argstate.argc == 0) { + print_syminfo(cmd, 0, &argstate, 0, argstate.syminfo.n); + return (ELFEDIT_CMDRET_NONE); + } + + /* The first argument is the symbol name/index */ + ndx = arg_to_symndx(&argstate, argstate.argv[0]); + + /* If there is a single argument, display that item and return */ + if (argstate.argc == 1) { + print_syminfo(cmd, 0, &argstate, ndx, 1); + return (ELFEDIT_CMDRET_NONE); + } + + syminfo = &argstate.syminfo.data[ndx]; + + /* + * Syminfo [0] holds the value SYMINFO_CURRENT, as a versioning + * technique. You're not supposed to mess with it. + */ + if (ndx == 0) + elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CHGSYMINFO0), + EC_WORD(argstate.syminfo.sec->sec_shndx), + argstate.syminfo.sec->sec_name, EC_WORD(ndx)); + + /* The second value supplies a new value for the item */ + switch (cmd) { + /* + * SYMINFO_CMD_T_DUMP can't get here: It never has more than + * one argument, and is handled above. + */ + + case SYMINFO_CMD_T_SI_BOUNDTO: + { + const char *name = MSG_ORIG(MSG_CMD_SI_BOUNDTO); + Half boundto; + + if (argstate.optmask & SYMINFO_OPT_F_NEEDED) + boundto = needed_to_boundto(&argstate, + argstate.argv[1]); + else + boundto = elfedit_atoconst_range( + argstate.argv[1], MSG_ORIG(MSG_STR_VALUE), + 0, 0xffff, ELFEDIT_CONST_SYMINFO_BT); + + if (syminfo->si_boundto == boundto) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_X_OK), + argstate.syminfo.sec->sec_shndx, + argstate.syminfo.sec->sec_name, ndx, name, + syminfo->si_boundto); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_X_CHG), + argstate.syminfo.sec->sec_shndx, + argstate.syminfo.sec->sec_name, ndx, name, + syminfo->si_boundto, boundto); + ret = ELFEDIT_CMDRET_MOD; + syminfo->si_boundto = boundto; + } + } + break; + + case SYMINFO_CMD_T_SI_FLAGS: + { + Conv_syminfo_flags_buf_t flags_buf1, flags_buf2; + const char *name = MSG_ORIG(MSG_CMD_SI_FLAGS); + Half flags = 0; + int i; + + /* Collect the arguments */ + for (i = 1; i < argstate.argc; i++) + flags |= (Word) + elfedit_atoconst(argstate.argv[i], + ELFEDIT_CONST_SYMINFO_FLG); + + /* Complement the value? */ + if (argstate.optmask & SYMINFO_OPT_F_CMP) + flags = ~flags; + + /* Perform any requested bit operations */ + if (argstate.optmask & SYMINFO_OPT_F_AND) + flags &= syminfo->si_flags; + else if (argstate.optmask & SYMINFO_OPT_F_OR) + flags |= syminfo->si_flags; + + /* Set the value */ + if (syminfo->si_flags == flags) { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_S_OK), + argstate.syminfo.sec->sec_shndx, + argstate.syminfo.sec->sec_name, ndx, name, + conv_syminfo_flags(syminfo->si_flags, + 0, &flags_buf1)); + } else { + elfedit_msg(ELFEDIT_MSG_DEBUG, + MSG_INTL(MSG_DEBUG_S_CHG), + argstate.syminfo.sec->sec_shndx, + argstate.syminfo.sec->sec_name, ndx, name, + conv_syminfo_flags(syminfo->si_flags, + 0, &flags_buf1), + conv_syminfo_flags(flags, 0, &flags_buf2)); + ret = ELFEDIT_CMDRET_MOD; + syminfo->si_flags = flags; + } + } + break; + } + + /* + * If we modified the syminfo section, tell libelf. + */ + if (ret == ELFEDIT_CMDRET_MOD) + elfedit_modified_data(argstate.syminfo.sec); + + /* Do autoprint */ + print_syminfo(cmd, 1, &argstate, ndx, 1); + + return (ret); +} + + + + +/* + * Command completion functions for the various commands + */ +/*ARGSUSED*/ +static void +cpl_si_boundto(elfedit_obj_state_t *obj_state, void *cpldata, int argc, + const char *argv[], int num_opt) +{ + int i; + + /* + * If -needed option is not present, the second argument can be + * an SYMINFO_BT_ value. + */ + if (argc != (num_opt + 2)) + return; + + /* Is -needed there? If so, no completion is possible so return */ + for (i = 0; i < num_opt; i++) + if (strcmp(argv[i], MSG_ORIG(MSG_STR_MINUS_NEEDED)) == 0) + return; + + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SYMINFO_BT); +} + +/*ARGSUSED*/ +static void +cpl_si_flags(elfedit_obj_state_t *obj_state, void *cpldata, int argc, + const char *argv[], int num_opt) +{ + /* The second argument can be an SYMINFO_FLG_ value */ + if (argc == (num_opt + 2)) + elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SYMINFO_FLG); +} + + + +/* + * 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(SYMINFO_CMD_T_DUMP, obj_state, argc, argv)); +} + + +static elfedit_cmdret_t +cmd_si_boundto(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(SYMINFO_CMD_T_SI_BOUNDTO, obj_state, argc, argv)); +} + + +static elfedit_cmdret_t +cmd_si_flags(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) +{ + return (cmd_body(SYMINFO_CMD_T_SI_FLAGS, obj_state, argc, argv)); +} + + + + +/*ARGSUSED*/ +elfedit_module_t * +elfedit_init(elfedit_module_version_t version) +{ + /* 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_SYMNDX), + /* MSG_INTL(MSG_OPTDESC_SYMNDX) */ + ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0, + SYMINFO_OPT_F_SYMNDX, 0 }, + { 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:si_boundto */ + static const char *name_si_boundto[] = { + MSG_ORIG(MSG_CMD_SI_BOUNDTO), NULL }; + static elfedit_cmd_optarg_t opt_si_boundto[] = { + { MSG_ORIG(MSG_STR_MINUS_NEEDED), + /* MSG_INTL(MSG_OPTDESC_NEEDED) */ + ELFEDIT_I18NHDL(MSG_OPTDESC_NEEDED), 0, + SYMINFO_OPT_F_NEEDED, 0 }, + { ELFEDIT_STDOA_OPT_O, NULL, + ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, + { MSG_ORIG(MSG_STR_MINUS_SYMNDX), + /* MSG_INTL(MSG_OPTDESC_SYMNDX) */ + ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0, + SYMINFO_OPT_F_SYMNDX, 0 }, + { NULL } + }; + static elfedit_cmd_optarg_t arg_si_boundto[] = { + { 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_SI_BOUNDTO) */ + ELFEDIT_I18NHDL(MSG_A2_DESC_SI_BOUNDTO), + ELFEDIT_CMDOA_F_OPT }, + { NULL } + }; + + /* sym:si_flags */ + static const char *name_si_flags[] = { + MSG_ORIG(MSG_CMD_SI_FLAGS), NULL }; + static elfedit_cmd_optarg_t opt_si_flags[] = { + { ELFEDIT_STDOA_OPT_AND, NULL, ELFEDIT_CMDOA_F_INHERIT, + SYMINFO_OPT_F_AND, SYMINFO_OPT_F_OR }, + { ELFEDIT_STDOA_OPT_CMP, NULL, + ELFEDIT_CMDOA_F_INHERIT, SYMINFO_OPT_F_CMP, 0 }, + { ELFEDIT_STDOA_OPT_O, NULL, + ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, + { ELFEDIT_STDOA_OPT_OR, NULL, ELFEDIT_CMDOA_F_INHERIT, + SYMINFO_OPT_F_OR, SYMINFO_OPT_F_AND }, + { MSG_ORIG(MSG_STR_MINUS_SYMNDX), + /* MSG_INTL(MSG_OPTDESC_SYMNDX) */ + ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0, + SYMINFO_OPT_F_SYMNDX, 0 }, + { NULL } + }; + static elfedit_cmd_optarg_t arg_si_flags[] = { + { 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_SI_FLAGS) */ + ELFEDIT_I18NHDL(MSG_A2_DESC_SI_FLAGS), + ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT }, + { NULL } + }; + + static elfedit_cmd_t cmds[] = { + /* sym:dump */ + { cmd_dump, NULL, 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:si_boundto */ + { cmd_si_boundto, cpl_si_boundto, name_si_boundto, + /* MSG_INTL(MSG_DESC_SI_BOUNDTO) */ + ELFEDIT_I18NHDL(MSG_DESC_SI_BOUNDTO), + /* MSG_INTL(MSG_HELP_SI_BOUNDTO) */ + ELFEDIT_I18NHDL(MSG_HELP_SI_BOUNDTO), + opt_si_boundto, arg_si_boundto }, + + /* sym:si_flags */ + { cmd_si_flags, cpl_si_flags, name_si_flags, + /* MSG_INTL(MSG_DESC_SI_FLAGS) */ + ELFEDIT_I18NHDL(MSG_DESC_SI_FLAGS), + /* MSG_INTL(MSG_HELP_SI_FLAGS) */ + ELFEDIT_I18NHDL(MSG_HELP_SI_FLAGS), + opt_si_flags, arg_si_flags }, + + { 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); +} diff --git a/usr/src/cmd/sgs/elfedit/modules/common/syminfo.msg b/usr/src/cmd/sgs/elfedit/modules/common/syminfo.msg new file mode 100644 index 0000000000..70af2e4f57 --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/modules/common/syminfo.msg @@ -0,0 +1,192 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" + +@ _START_ + +# Message file for elfedit 'syminfo' module + +@ MSG_ID_ELFEDIT_SYMINFO + + +# Debug messages + +@ MSG_DEBUG_S_OK "[%d: %s][%d].%s: value unchanged: %s\n" +@ MSG_DEBUG_S_CHG "[%d: %s][%d].%s: change from %s to %s\n" +@ MSG_DEBUG_X_OK "[%d: %s][%d].%s: value unchanged: %#x\n" +@ MSG_DEBUG_X_CHG "[%d: %s][%d].%s: change from %#x to %#x\n" +@ MSG_DEBUG_FNDNEEDED "[%d: %s][%d]: DT_NEEDED element for si_boundto: %s\n" +@ MSG_DEBUG_CONVNULL "[%d: %s][%d]: No existing %s to modify. Converting \ + extra DT_NULL\n" +@ MSG_DEBUG_CHGSYMINFO0 "[%d: %s][%d]: ELF warning: element [0] is expected to \ + contain SYMINFO_VERSION, and should not be altered\n" + +# Errors + +@ MSG_ERR_NOEXTRANULL "[%d: %s]: Dynamic section does not have room to add \ + a new element\n" + + + +# Module description + +@ MSG_MOD_DESC "Syminfo Section" + + +# 1-line description strings + +@ MSG_DESC_DUMP "Dump Syminfo Section" +@ MSG_DESC_SI_BOUNDTO "Symbol to Object Binding" +@ MSG_DESC_SI_FLAGS "Binding Flags" + + +# Command option description strings + +@ MSG_OPTDESC_NEEDED "\ + The value argument is a string giving the name of an ELF\n\ + object. The si_boundto field will be set to the index of the\n\ + corresponding DT_NEEDED entry of the dynamic section. If no\n\ + such DT_NEEDED entry exists in the dynamic section and there\n\ + is sufficient room, it will be added in order to satisfy this\n\ + request\n" + +@ MSG_OPTDESC_SYMNDX "\ + The sym argument supplies a numeric index into the syminfo\n\ + section instead of the name of the symbol.\n". + + +# Command argument descriptions + +@ MSG_A1_SYM "Name of desired symbol within symbol table.\n" + +@ MSG_A2_DESC_SI_BOUNDTO "\ + An integer value that describes the object this symbol is\n\ + bound to. SYMINFO_BT_ symbolic constants are accepted to\n\ + represent special values (self, parent, none), or the value\n\ + can be the index of a dynamic section element.\n" + +@ MSG_A2_DESC_SI_FLAGS "\ + New value for symbol binding flags. SYMINFO_FLG_ symbolic\n\ + constants are accepted, as is any integer.\n" + + + +# Help strings + +@ MSG_HELP_DUMP " \ + The syminfo:dump command is used to display information\n\ + from the syminfo section using the same style used by the\n\ + elfdump program.\n\ + \n\ + The syminfo section augments the information found in the\n\ + dynamic symbol table.\n\ + \n\ + If sym:dump is called without arguments, syminfo information\n\ + for every symbol in the symbol table is shown. If called with\n\ + the sym argument, the information for that symbol is\n\ + displayed.\n" + +@ MSG_HELP_SI_BOUNDTO " \ + The syminfo:si_boundto command is used to display or alter\n\ + the external object the symbol is bound to. This information\n\ + is found in the si_boundto field of a syminfo structure. It is\n\ + an integer that contains one of the special SYMINFO_BT_ values,\n\ + or alternaltively, an index into the dynamic section of the\n\ + ELF object.\n\ + \n\ + If syminfo:si_boundto is called without arguments, the value of\n\ + si_boundto for every symbol in the symbol table is shown. If\n\ + called with the sym argument, the si_boundto information for\n\ + that is displayed. If both arguments are present, the second\n\ + argument supplies a new value for si_boundto.\n\ + \n\ + By default, value is an integer, which will have one of the\n\ + special SYMINFO_BT_ values, or which will be the index of an\n\ + element in the dynamic section. Alternatively, the -needed\n\ + option can be used to specify a string with the name of an\n\ + object. If -needed is is used, si_boundto will be set to the\n\ + index of the DT_NEEDED entry in the dynamic section that\n\ + corresponds to the given name. If no such DT_NEEDED element\n\ + exists, and room is available to add it, it will be added in\n\ + order to faciliate this operation.\n" + +@ MSG_HELP_SI_FLAGS " \ + Examine or modify the syminfo binding flags associated\n\ + with a given symbol. This information is found in the\n\ + si_flags field of the syminfo structure.\n\ + \n\ + If syminfo:si_flags is called without arguments, the value\n\ + of si_flags for every symbol in the symbol table is shown.\n\ + If called with the sym argument, the si_flags information\n\ + for that symbol is displayed. If one or more value arguments\n\ + are present, the the following steps are taken:\n\ + \n \ + o\tAll the value arguments are OR'd together.\n\ + \n \ + o\tIf the -cmp option has been specified, the new value\n\ + \tis complemented.\n\ + \n \ + o\tThe si_flags field of the syminfo structure is updated\n\ + \twith the new value. If -and is specified, the new value is\n\ + \tAND'd against the existing value. If -or is specified,\n\ + \tthe new value is OR'd against the existing value. If\n\ + \tneither -and or -or are specified, the new value replaces\n\ + \tthe existing value.\n" + + +@ _END_ + + +# The following strings represent reserved words, files, pathnames and symbols. +# Reference to this strings is via the MSG_ORIG() macro, and thus no message +# translation is required. + + +# Miscellaneous clutter +@ MSG_STR_EMPTY "" +@ MSG_STR_MINUS_NEEDED "-needed" +@ MSG_STR_MINUS_SYMNDX "-symndx" +@ MSG_STR_SYM "sym" +@ MSG_STR_VALUE "value" + + +# Format strings + +@ MSG_FMT_WORDVALNL "%u\n" +@ MSG_FMT_HEXNUMNL "%#x\n" +@ MSG_FMT_STRNL "%s\n" + + +# Module name + +@ MSG_MOD_NAME "syminfo" + + +# Command names + +@ MSG_CMD_DUMP "dump" +@ MSG_CMD_SI_BOUNDTO "si_boundto" +@ MSG_CMD_SI_FLAGS "si_flags" diff --git a/usr/src/cmd/sgs/elfedit/modules/i386/Makefile b/usr/src/cmd/sgs/elfedit/modules/i386/Makefile new file mode 100644 index 0000000000..d8203060c0 --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/modules/i386/Makefile @@ -0,0 +1,43 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +lint := CONV_LIB = $(CONV_LIB32) +lint := LDDBG_LIB = $(LDDBG_LIB32) + +CFLAGS += $(C_PICFLAGS) + +.KEEP_STATE: + +all: $(OBJDIR) $(PICDIR) .WAIT $(ELFEDITLIBS) + +install \ +package: all .WAIT $(ROOTELFEDITDIR) .WAIT $(ROOTELFEDITLIBS) + +include ../Makefile.targ diff --git a/usr/src/cmd/sgs/elfedit/modules/sparc/Makefile b/usr/src/cmd/sgs/elfedit/modules/sparc/Makefile new file mode 100644 index 0000000000..d8203060c0 --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/modules/sparc/Makefile @@ -0,0 +1,43 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +lint := CONV_LIB = $(CONV_LIB32) +lint := LDDBG_LIB = $(LDDBG_LIB32) + +CFLAGS += $(C_PICFLAGS) + +.KEEP_STATE: + +all: $(OBJDIR) $(PICDIR) .WAIT $(ELFEDITLIBS) + +install \ +package: all .WAIT $(ROOTELFEDITDIR) .WAIT $(ROOTELFEDITLIBS) + +include ../Makefile.targ diff --git a/usr/src/cmd/sgs/elfedit/modules/sparcv9/Makefile b/usr/src/cmd/sgs/elfedit/modules/sparcv9/Makefile new file mode 100644 index 0000000000..13c70cd279 --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/modules/sparcv9/Makefile @@ -0,0 +1,53 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +LDDBGLIBDIR = $(LDDBGLIBDIR64) +CONVLIBDIR = $(CONVLIBDIR64) +ELFLIBDIR = $(ELFLIBDIR64) +MTARG = sparcv9/ + +lint := CONV_LIB = $(CONV_LIB64) +lint := LDDBG_LIB = $(LDDBG_LIB64) + +CFLAGS64 += $(C_PICFLAGS64) + +LLDFLAGS = $(LLDFLAGS64) + +LINTFLAGS64 += $(VAR_LINTFLAGS64) + +.KEEP_STATE: + +all: $(PICDIR) .WAIT $(ELFEDITLIBS) + +install \ +package: all .WAIT $(ROOTELFEDITDIR64) .WAIT $(ROOTELFEDITLIBS) + +include ../Makefile.targ +include ../../../Makefile.sub.64 diff --git a/usr/src/cmd/sgs/elfedit/sparc/Makefile b/usr/src/cmd/sgs/elfedit/sparc/Makefile new file mode 100644 index 0000000000..11b6540fbb --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/sparc/Makefile @@ -0,0 +1,35 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +.KEEP_STATE: + +lint: $(LINTOUT32) $(SGSLINTOUT) + +include ../Makefile.targ diff --git a/usr/src/cmd/sgs/elfedit/sparcv9/Makefile b/usr/src/cmd/sgs/elfedit/sparcv9/Makefile new file mode 100644 index 0000000000..75487b577b --- /dev/null +++ b/usr/src/cmd/sgs/elfedit/sparcv9/Makefile @@ -0,0 +1,46 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +.KEEP_STATE: + +LLDFLAGS = $(LLDFLAGS64) +ELFLIBDIR = $(ELFLIBDIR64) +LDDBGLIBDIR = $(LDDBGLIBDIR64) +CONVLIBDIR = $(CONVLIBDIR64) + +ROOTPROG= $(ROOTPROG64) + +include ../Makefile.targ +include ../../Makefile.sub.64 + +lint: $(LINTOUT64) $(SGSLINTOUT) + +install \ +package: $(ROOTPROG64) diff --git a/usr/src/cmd/sgs/include/conv.h b/usr/src/cmd/sgs/include/conv.h index 6c337754b5..a5dd597266 100644 --- a/usr/src/cmd/sgs/include/conv.h +++ b/usr/src/cmd/sgs/include/conv.h @@ -108,16 +108,16 @@ typedef union { /* conv_ehdr_flags() */ -#define CONF_EHDR_FLAGS_BASE_BUFSIZE 69 +#define CONV_EHDR_FLAGS_BASE_BUFSIZE 69 #define CONV32_EHDR_FLAGS_BUFSIZE \ - (CONF_EHDR_FLAGS_BASE_BUFSIZE + CONV32_INV_BUFSIZE) + (CONV_EHDR_FLAGS_BASE_BUFSIZE + CONV32_INV_BUFSIZE) typedef union { Conv32_inv_buf_t inv_buf; char buf[CONV32_EHDR_FLAGS_BUFSIZE]; } Conv32_ehdr_flags_buf_t; #define CONV64_EHDR_FLAGS_BUFSIZE \ - (CONF_EHDR_FLAGS_BASE_BUFSIZE + CONV64_INV_BUFSIZE) + (CONV_EHDR_FLAGS_BASE_BUFSIZE + CONV64_INV_BUFSIZE) typedef union { Conv64_inv_buf_t inv_buf; char buf[CONV64_EHDR_FLAGS_BUFSIZE]; @@ -288,16 +288,16 @@ typedef union { /* conv_dyn_posflag1() */ -#define CONF_DYN_POSFLAG1_BASE_BUFSIZE 23 +#define CONV_DYN_POSFLAG1_BASE_BUFSIZE 23 #define CONV32_DYN_POSFLAG1_BUFSIZE \ - (CONF_DYN_POSFLAG1_BASE_BUFSIZE + CONV32_INV_BUFSIZE) + (CONV_DYN_POSFLAG1_BASE_BUFSIZE + CONV32_INV_BUFSIZE) typedef union { Conv32_inv_buf_t inv_buf; char buf[CONV32_DYN_POSFLAG1_BUFSIZE]; } Conv32_dyn_posflag1_buf_t; #define CONV64_DYN_POSFLAG1_BUFSIZE \ - (CONF_DYN_POSFLAG1_BASE_BUFSIZE + CONV64_INV_BUFSIZE) + (CONV_DYN_POSFLAG1_BASE_BUFSIZE + CONV64_INV_BUFSIZE) typedef union { Conv64_inv_buf_t inv_buf; char buf[CONV64_DYN_POSFLAG1_BUFSIZE]; @@ -305,16 +305,16 @@ typedef union { /* conv_dyn_flag() */ -#define CONF_DYN_FLAG_BASE_BUFSIZE 48 +#define CONV_DYN_FLAG_BASE_BUFSIZE 48 #define CONV32_DYN_FLAG_BUFSIZE \ - (CONF_DYN_FLAG_BASE_BUFSIZE + CONV32_INV_BUFSIZE) + (CONV_DYN_FLAG_BASE_BUFSIZE + CONV32_INV_BUFSIZE) typedef union { Conv32_inv_buf_t inv_buf; char buf[CONV32_DYN_FLAG_BUFSIZE]; } Conv32_dyn_flag_buf_t; #define CONV64_DYN_FLAG_BUFSIZE \ - (CONF_DYN_FLAG_BASE_BUFSIZE + CONV64_INV_BUFSIZE) + (CONV_DYN_FLAG_BASE_BUFSIZE + CONV64_INV_BUFSIZE) typedef union { Conv64_inv_buf_t inv_buf; char buf[CONV64_DYN_FLAG_BUFSIZE]; @@ -322,16 +322,16 @@ typedef union { /* conv_dyn_flag1() */ -#define CONF_DYN_FLAG1_BASE_BUFSIZE 223 +#define CONV_DYN_FLAG1_BASE_BUFSIZE 223 #define CONV32_DYN_FLAG1_BUFSIZE \ - (CONF_DYN_FLAG1_BASE_BUFSIZE + CONV32_INV_BUFSIZE) + (CONV_DYN_FLAG1_BASE_BUFSIZE + CONV32_INV_BUFSIZE) typedef union { Conv32_inv_buf_t inv_buf; char buf[CONV32_DYN_FLAG1_BUFSIZE]; } Conv32_dyn_flag1_buf_t; #define CONV64_DYN_FLAG1_BUFSIZE \ - (CONF_DYN_FLAG1_BASE_BUFSIZE + CONV64_INV_BUFSIZE) + (CONV_DYN_FLAG1_BASE_BUFSIZE + CONV64_INV_BUFSIZE) typedef union { Conv64_inv_buf_t inv_buf; char buf[CONV64_DYN_FLAG1_BUFSIZE]; @@ -339,16 +339,16 @@ typedef union { /* conv_dyn_feature1() */ -#define CONF_DYN_FEATURE1_BASE_BUFSIZE 20 +#define CONV_DYN_FEATURE1_BASE_BUFSIZE 20 #define CONV32_DYN_FEATURE1_BUFSIZE \ - (CONF_DYN_FEATURE1_BASE_BUFSIZE + CONV32_INV_BUFSIZE) + (CONV_DYN_FEATURE1_BASE_BUFSIZE + CONV32_INV_BUFSIZE) typedef union { Conv32_inv_buf_t inv_buf; char buf[CONV32_DYN_FEATURE1_BUFSIZE]; } Conv32_dyn_feature1_buf_t; #define CONV64_DYN_FEATURE1_BUFSIZE \ - (CONF_DYN_FEATURE1_BASE_BUFSIZE + CONV64_INV_BUFSIZE) + (CONV_DYN_FEATURE1_BASE_BUFSIZE + CONV64_INV_BUFSIZE) typedef union { Conv64_inv_buf_t inv_buf; char buf[CONV64_DYN_FEATURE1_BUFSIZE]; @@ -356,16 +356,16 @@ typedef union { /* conv_bnd_type() */ -#define CONF_BND_TYPE_BASE_BUFSIZE 29 +#define CONV_BND_TYPE_BASE_BUFSIZE 29 #define CONV32_BND_TYPE_BUFSIZE \ - (CONF_BND_TYPE_BASE_BUFSIZE + CONV32_INV_BUFSIZE) + (CONV_BND_TYPE_BASE_BUFSIZE + CONV32_INV_BUFSIZE) typedef union { Conv32_inv_buf_t inv_buf; char buf[CONV32_BND_TYPE_BUFSIZE]; } Conv32_bnd_type_buf_t; #define CONV64_BND_TYPE_BUFSIZE \ - (CONF_BND_TYPE_BASE_BUFSIZE + CONV64_INV_BUFSIZE) + (CONV_BND_TYPE_BASE_BUFSIZE + CONV64_INV_BUFSIZE) typedef union { Conv64_inv_buf_t inv_buf; char buf[CONV64_BND_TYPE_BUFSIZE]; @@ -373,16 +373,16 @@ typedef union { /* conv_bnd_obj() */ -#define CONF_BND_OBJ_BASE_BUFSIZE 38 +#define CONV_BND_OBJ_BASE_BUFSIZE 38 #define CONV32_BND_OBJ_BUFSIZE \ - (CONF_BND_OBJ_BASE_BUFSIZE + CONV32_INV_BUFSIZE) + (CONV_BND_OBJ_BASE_BUFSIZE + CONV32_INV_BUFSIZE) typedef union { Conv32_inv_buf_t inv_buf; char buf[CONV32_BND_OBJ_BUFSIZE]; } Conv32_bnd_obj_buf_t; #define CONV64_BND_OBJ_BUFSIZE \ - (CONF_BND_OBJ_BASE_BUFSIZE + CONV64_INV_BUFSIZE) + (CONV_BND_OBJ_BASE_BUFSIZE + CONV64_INV_BUFSIZE) typedef union { Conv64_inv_buf_t inv_buf; char buf[CONV64_BND_OBJ_BUFSIZE]; @@ -390,16 +390,16 @@ typedef union { /* conv_phdr_flags() */ -#define CONF_PHDR_FLAGS_BASE_BUFSIZE 35 +#define CONV_PHDR_FLAGS_BASE_BUFSIZE 35 #define CONV32_PHDR_FLAGS_BUFSIZE \ - (CONF_PHDR_FLAGS_BASE_BUFSIZE + CONV32_INV_BUFSIZE) + (CONV_PHDR_FLAGS_BASE_BUFSIZE + CONV32_INV_BUFSIZE) typedef union { Conv32_inv_buf_t inv_buf; char buf[CONV32_PHDR_FLAGS_BUFSIZE]; } Conv32_phdr_flags_buf_t; #define CONV64_PHDR_FLAGS_BUFSIZE \ - (CONF_PHDR_FLAGS_BASE_BUFSIZE + CONV64_INV_BUFSIZE) + (CONV_PHDR_FLAGS_BASE_BUFSIZE + CONV64_INV_BUFSIZE) typedef union { Conv64_inv_buf_t inv_buf; char buf[CONV64_PHDR_FLAGS_BUFSIZE]; @@ -407,16 +407,16 @@ typedef union { /* conv_sec_flags() */ -#define CONF_SEC_FLAGS_BASE_BUFSIZE 168 +#define CONV_SEC_FLAGS_BASE_BUFSIZE 168 #define CONV32_SEC_FLAGS_BUFSIZE \ - (CONF_SEC_FLAGS_BASE_BUFSIZE + CONV32_INV_BUFSIZE) + (CONV_SEC_FLAGS_BASE_BUFSIZE + CONV32_INV_BUFSIZE) typedef union { Conv32_inv_buf_t inv_buf; char buf[CONV32_SEC_FLAGS_BUFSIZE]; } Conv32_sec_flags_buf_t; #define CONV64_SEC_FLAGS_BUFSIZE \ - (CONF_SEC_FLAGS_BASE_BUFSIZE + CONV64_INV_BUFSIZE) + (CONV_SEC_FLAGS_BASE_BUFSIZE + CONV64_INV_BUFSIZE) typedef union { Conv64_inv_buf_t inv_buf; char buf[CONV64_SEC_FLAGS_BUFSIZE]; @@ -435,6 +435,23 @@ typedef union { } Conv64_dwarf_ehe_buf_t; +/* conv_syminfo_flags() */ +#define CONV_SYMINFO_FLAGS_BASE_BUFSIZE 36 +#define CONV32_SYMINFO_FLAGS_BUFSIZE \ + (CONV_SYMINFO_FLAGS_BASE_BUFSIZE + CONV32_INV_BUFSIZE) +typedef union { + Conv32_inv_buf_t inv_buf; + char buf[CONV32_SYMINFO_FLAGS_BUFSIZE]; +} Conv32_syminfo_flags_buf_t; + +#define CONV64_SYMINFO_FLAGS_BUFSIZE \ + (CONV_SYMINFO_FLAGS_BASE_BUFSIZE + CONV64_INV_BUFSIZE) +typedef union { + Conv64_inv_buf_t inv_buf; + char buf[CONV64_SYMINFO_FLAGS_BUFSIZE]; +} Conv64_syminfo_flags_buf_t; + + /* * Generic names for class specific buffer types above @@ -450,6 +467,7 @@ typedef union { #define CONV_BND_OBJ_BUFSIZE CONV64_BND_OBJ_BUFSIZE #define CONV_PHDR_FLAGS_BUFSIZE CONV64_PHDR_FLAGS_BUFSIZE #define CONV_SEC_FLAGS_BUFSIZE CONV64_SEC_FLAGS_BUFSIZE +#define CONV_SYMINFO_FLAGS_BUFSIZE CONV64_SYMINFO_FLAGS_BUFSIZE #define Conv_inv_buf_t Conv64_inv_buf_t #define Conv_ehdr_flags_buf_t Conv64_ehdr_flags_buf_t @@ -473,6 +491,7 @@ typedef union { #define Conv_phdr_flags_buf_t Conv64_phdr_flags_buf_t #define Conv_sec_flags_buf_t Conv64_sec_flags_buf_t #define Conv_dwarf_ehe_buf_t Conv64_dwarf_ehe_buf_t +#define Conv_syminfo_flags_buf_t Conv64_syminfo_flags_buf_t #else #define CONV_INV_BUFSIZE CONV32_INV_BUFSIZE #define CONV_EHDR_FLAGS_BUFSIZE CONV32_EHDR_FLAGS_BUFSIZE @@ -484,6 +503,7 @@ typedef union { #define CONV_BND_OBJ_BUFSIZE CONV32_BND_OBJ_BUFSIZE #define CONV_PHDR_FLAGS_BUFSIZE CONV32_PHDR_FLAGS_BUFSIZE #define CONV_SEC_FLAGS_BUFSIZE CONV32_SEC_FLAGS_BUFSIZE +#define CONV_SYMINFO_FLAGS_BUFSIZE CONV32_SYMINFO_FLAGS_BUFSIZE #define Conv_inv_buf_t Conv32_inv_buf_t #define Conv_ehdr_flags_buf_t Conv32_ehdr_flags_buf_t @@ -507,30 +527,65 @@ typedef union { #define Conv_phdr_flags_buf_t Conv32_phdr_flags_buf_t #define Conv_sec_flags_buf_t Conv32_sec_flags_buf_t #define Conv_dwarf_ehe_buf_t Conv32_dwarf_ehe_buf_t +#define Conv_syminfo_flags_buf_t Conv32_syminfo_flags_buf_t #endif /* + * Many conversion routines accept a fmt_flags argument of this type + * to allow the caller to modify the output. There are two parts to + * this value: + * + * (1) Format requests (decimal vs hex, etc...) + * (2) The low order bits specified by CONV_MASK_FMT_ALT + * and retrieved by CONV_TYPE_FMT_ALT are integer + * values that specify that an alternate set of + * strings should be used. This is necessary because + * different utilities evolved to use different strings, + * and there are backward compatability guarantees in + * place that prevent changing them. + * + * These values are designed such that a caller can always supply a + * simple 0 in order to receive "default" behavior. + */ +typedef int Conv_fmt_flags_t; + +/* + * The bottom 8 bits of Conv_fmt_flags_t are used to encode + * alternative strings. + * + * If a given conversion routine does not support alternative strings + * for a given CONV_FMT_ALT type, it silently ignores the request and + * supplies the default set. This means that a utility like dump(1) is + * free to specify its special type in every conversion routine call, + * without regard to whether it has any special meaning for that particular + * routine. It will receive its special strings if there are any, and + * the defaults otherwise. + */ +#define CONV_MASK_FMT_ALT 0xff +#define CONV_TYPE_FMT_ALT(fmt_flags) (fmt_flags & CONV_MASK_FMT_ALT) + +#define CONV_FMT_ALT_DEFAULT 0 /* "Standard" strings */ +#define CONV_FMT_ALT_DUMP 1 /* Style of strings used by dump(1) */ +#define CONV_FMT_ALT_FILE 2 /* Style of strings used by file(1) */ +#define CONV_FMT_ALT_CRLE 3 /* Style of strings used by crle(1) */ +#define CONV_FMT_ALT_FULLNAME 4 /* Strings should be full #define */ + /* (e.g. STB_LOCAL, not LOCL) */ + +/* * Flags that alter standard formatting for conversion routines. + * These bits start after the range occupied by CONV_MASK_FMT_ALT. */ -#define CONV_FMT_DECIMAL 0x01 /* conv_invalid_val() should print */ +#define CONV_FMT_DECIMAL 0x0100 /* conv_invalid_val() should print */ /* integer print as decimal */ /* (default is hex) */ -#define CONV_FMT_SPACE 0x02 /* conv_invalid_val() should append */ +#define CONV_FMT_SPACE 0x0200 /* conv_invalid_val() should append */ /* a space after the number. */ -#define CONV_FMT_ALTDUMP 0x04 /* Output strings using the versions */ - /* used by the dump program. */ -#define CONV_FMT_ALTFILE 0x08 /* Output strings in the form used */ - /* by the file(1) command */ -#define CONV_FMT_ALTCRLE 0x10 /* Output strings in the form used */ - /* by the crle(1) command */ +#define CONV_FMT_NOBKT 0x0400 /* conv_expn_field() should omit */ + /* prefix and suffix strings */ -/* - * Mask of CONV_FMT bits that reflect a desire to use alternate strings. - */ -#define CONV_FMTALTMASK (CONV_FMT_ALTDUMP | CONV_FMT_ALTFILE) /* * The expansion of bit-field data items is driven from a value descriptor and @@ -589,7 +644,8 @@ extern const char *conv_config_upm(const char *, const char *, const char *, size_t); extern const char *conv_def_tag(Symref, Conv_inv_buf_t *); extern const char *conv_demangle_name(const char *); -extern const char *conv_dl_flag(int, int, Conv_dl_flag_buf_t *); +extern const char *conv_dl_flag(int, Conv_fmt_flags_t, + Conv_dl_flag_buf_t *); extern const char *conv_dl_mode(int, int, Conv_dl_mode_buf_t *); extern const char *conv_dwarf_ehe(uint_t, Conv_dwarf_ehe_buf_t *); extern const char *conv_elfdata_type(Elf_Type, Conv_inv_buf_t *); @@ -643,8 +699,10 @@ extern const char *conv_ver_index(Versym, int, Conv_inv_buf_t *); #define conv_sym_info_type conv64_sym_info_type #define conv_sym_shndx conv64_sym_shndx #define conv_sym_other conv64_sym_other +#define conv_sym_other_vis conv64_sym_other_vis #define conv_sym_value conv64_sym_value #define conv_sym_SPARC_value conv64_sym_SPARC_value +#define conv_syminfo_flags conv64_syminfo_flags #else #define conv_bnd_obj conv32_bnd_obj #define conv_bnd_type conv32_bnd_type @@ -681,52 +739,80 @@ extern const char *conv_ver_index(Versym, int, Conv_inv_buf_t *); #define conv_sym_info_type conv32_sym_info_type #define conv_sym_shndx conv32_sym_shndx #define conv_sym_other conv32_sym_other +#define conv_sym_other_vis conv32_sym_other_vis #define conv_sym_value conv32_sym_value #define conv_sym_SPARC_value conv32_sym_SPARC_value +#define conv_syminfo_flags conv32_syminfo_flags #endif extern const char *conv_bnd_obj(uint_t, Conv_bnd_obj_buf_t *); extern const char *conv_bnd_type(uint_t, Conv_bnd_type_buf_t *); extern const char *conv_cap_tag(Xword, Conv_inv_buf_t *); extern const char *conv_cap_val(Xword, Xword, Half, Conv_cap_val_buf_t *); -extern const char *conv_cap_val_hw1(Xword, Half, +extern const char *conv_cap_val_hw1(Xword, Half, Conv_fmt_flags_t, Conv_cap_val_hw1_buf_t *); -extern const char *conv_cap_val_sf1(Xword, Half, +extern const char *conv_cap_val_sf1(Xword, Half, Conv_fmt_flags_t, Conv_cap_val_sf1_buf_t *); -extern const char *conv_dyn_flag1(Xword, Conv_dyn_flag1_buf_t *); -extern const char *conv_dyn_flag(Xword, int, Conv_dyn_flag_buf_t *); -extern const char *conv_dyn_posflag1(Xword, int, +extern const char *conv_dyn_flag1(Xword, Conv_fmt_flags_t, + Conv_dyn_flag1_buf_t *); +extern const char *conv_dyn_flag(Xword, Conv_fmt_flags_t, + Conv_dyn_flag_buf_t *); +extern const char *conv_dyn_posflag1(Xword, Conv_fmt_flags_t, Conv_dyn_posflag1_buf_t *); -extern const char *conv_dyn_tag(Xword, Half, int, Conv_inv_buf_t *); -extern const char *conv_dyn_feature1(Xword, int, +extern const char *conv_dyn_tag(Xword, Half, Conv_fmt_flags_t, + Conv_inv_buf_t *); +extern const char *conv_dyn_feature1(Xword, Conv_fmt_flags_t, Conv_dyn_feature1_buf_t *); -extern const char *conv_ehdr_class(uchar_t, int, Conv_inv_buf_t *); -extern const char *conv_ehdr_data(uchar_t, int, Conv_inv_buf_t *); -extern const char *conv_ehdr_flags(Half, Word, Conv_ehdr_flags_buf_t *); -extern const char *conv_ehdr_mach(Half, int, Conv_inv_buf_t *); -extern const char *conv_ehdr_osabi(uchar_t, int, Conv_inv_buf_t *); -extern const char *conv_ehdr_type(Half, int, Conv_inv_buf_t *); -extern const char *conv_ehdr_vers(Word, int, Conv_inv_buf_t *); -extern int conv_expn_field(CONV_EXPN_FIELD_ARG *); -extern const char *conv_invalid_val(Conv_inv_buf_t *, Xword, int); -extern const char *conv_phdr_flags(Word, Conv_phdr_flags_buf_t *); -extern const char *conv_phdr_type(Half, Word, int, Conv_inv_buf_t *); +extern const char *conv_ehdr_class(uchar_t, Conv_fmt_flags_t, + Conv_inv_buf_t *); +extern const char *conv_ehdr_data(uchar_t, Conv_fmt_flags_t, + Conv_inv_buf_t *); +extern const char *conv_ehdr_flags(Half, Word, Conv_fmt_flags_t, + Conv_ehdr_flags_buf_t *); +extern const char *conv_ehdr_mach(Half, Conv_fmt_flags_t, + Conv_inv_buf_t *); +extern const char *conv_ehdr_osabi(uchar_t, Conv_fmt_flags_t, + Conv_inv_buf_t *); +extern const char *conv_ehdr_type(Half, Conv_fmt_flags_t, + Conv_inv_buf_t *); +extern const char *conv_ehdr_vers(Word, Conv_fmt_flags_t, + Conv_inv_buf_t *); +extern int conv_expn_field(CONV_EXPN_FIELD_ARG *, + Conv_fmt_flags_t); +extern const char *conv_invalid_val(Conv_inv_buf_t *, Xword, + Conv_fmt_flags_t); +extern const char *conv_phdr_flags(Word, Conv_fmt_flags_t fmt_flags, + Conv_phdr_flags_buf_t *); +extern const char *conv_phdr_type(Half, Word, Conv_fmt_flags_t, + Conv_inv_buf_t *); extern const char *conv_reject_desc(Rej_desc *, Conv_reject_desc_buf_t *); -extern const char *conv_reloc_type(Half, Word, int, Conv_inv_buf_t *); -extern const char *conv_reloc_type_static(Half, Word, int); -extern const char *conv_reloc_386_type(Word, int, Conv_inv_buf_t *); -extern const char *conv_reloc_amd64_type(Word, int, Conv_inv_buf_t *); -extern const char *conv_reloc_SPARC_type(Word, int, Conv_inv_buf_t *); -extern const char *conv_sec_flags(Xword, Conv_sec_flags_buf_t *); +extern const char *conv_reloc_type(Half, Word, Conv_fmt_flags_t, + Conv_inv_buf_t *); +extern const char *conv_reloc_type_static(Half, Word, Conv_fmt_flags_t); +extern const char *conv_reloc_386_type(Word, Conv_fmt_flags_t, + Conv_inv_buf_t *); +extern const char *conv_reloc_amd64_type(Word, Conv_fmt_flags_t, + Conv_inv_buf_t *); +extern const char *conv_reloc_SPARC_type(Word, Conv_fmt_flags_t, + Conv_inv_buf_t *); +extern const char *conv_sec_flags(Xword, Conv_fmt_flags_t, + Conv_sec_flags_buf_t *); extern const char *conv_sec_linkinfo(Word, Xword, Conv_inv_buf_t *); -extern const char *conv_sec_type(Half, Word, int, Conv_inv_buf_t *); -extern const char *conv_sym_info_bind(uchar_t, int, Conv_inv_buf_t *); -extern const char *conv_sym_info_type(Half, uchar_t, int, +extern const char *conv_sec_type(Half, Word, Conv_fmt_flags_t, + Conv_inv_buf_t *); +extern const char *conv_sym_info_bind(uchar_t, Conv_fmt_flags_t, + Conv_inv_buf_t *); +extern const char *conv_sym_info_type(Half, uchar_t, Conv_fmt_flags_t, Conv_inv_buf_t *); extern const char *conv_sym_shndx(Half, Conv_inv_buf_t *); extern const char *conv_sym_other(uchar_t, Conv_inv_buf_t *); +extern const char *conv_sym_other_vis(uchar_t, Conv_fmt_flags_t, + Conv_inv_buf_t *); extern const char *conv_sym_value(Half, uchar_t, Addr, Conv_inv_buf_t *); -extern const char *conv_sym_SPARC_value(Addr, int, Conv_inv_buf_t *); +extern const char *conv_sym_SPARC_value(Addr, Conv_fmt_flags_t, + Conv_inv_buf_t *); +extern const char *conv_syminfo_flags(Xword flags, Conv_fmt_flags_t, + Conv_syminfo_flags_buf_t *syminfo_flags_buf); #ifdef __cplusplus } diff --git a/usr/src/cmd/sgs/include/elfedit.h b/usr/src/cmd/sgs/include/elfedit.h new file mode 100644 index 0000000000..0c51b6872c --- /dev/null +++ b/usr/src/cmd/sgs/include/elfedit.h @@ -0,0 +1,1065 @@ +/* + * 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. + */ + +#ifndef _ELFEDIT_H +#define _ELFEDIT_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <libelf.h> +#include <stdarg.h> + +/* The following are here to support use of elfedit_msg() */ +#include <sys/machelf.h> /* EC_ macros */ +#include <libintl.h> + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + * elfedit uses elfedit_printf() to produce generic output to stdout. + * elfedit_msg() is used to produce error message, or specific types + * of terse informational messages: + * + * ELFEDIT_MSG_ERR: + * Issues an error to stderr. elfedit_msg() does not return + * to the caller. Control returns to the outer loop in + * interactive use. elfedit exits in non-interactive use. + * + * ELFEDIT_MSG_FATAL: + * Issues an error to stderr. elfedit_msg() exits the process, + * and does not return to the caller. + * + * ELFEDIT_MSG_USAGE: + * Issues an elfedit usage message to stderr, and + * returns to the caller. + * + * ELFEDIT_MSG_CMDUSAGE + * Issues an elfedit usage message to stderr, and + * does not return to the caller. + * + * ELFEDIT_MSG_DEBUG + * If the ELFEDIT_F_DEBUG flag is set, the message + * is printed to stdout, otherwise no output is produced. + * elfedit_msg() returns to the caller. + * + * ELFEDIT_MSG_QUIET + * This is a very special case, intended to handle the + * case where the pager subprocess exits before we are + * done producing output (the user presses 'q'). It acts + * just like ELFEDIT_MSG_ERR, except that no message is + * actually printed. + * + * In the cases where elfedit_msg() does not return to the caller, the + * behavior depends on the mode of execution. If running in interactive + * mode (reading from a tty), control is returned directly to the outer + * elfedit control loop to read another command. If not running in interactive + * mode, elfedit exits with a non-zero status. + */ +typedef enum { + ELFEDIT_MSG_ERR = 0, + ELFEDIT_MSG_FATAL = 1, + ELFEDIT_MSG_USAGE = 2, + ELFEDIT_MSG_CMDUSAGE = 3, + ELFEDIT_MSG_DEBUG = 4, + ELFEDIT_MSG_QUIET = 5 +} elfedit_msg_t; + + +/* + * Information for a single ELF section. + * + * NOTE: sec_xshndx + * A symbol table can have an associated SHT_SYMTAB_SHNDX section. This + * happens when the number of sections is too large to fit in the + * ELF symbol st_shndx field, which is a 16-bit value. The sec_xshndx + * field will be SHN_UNDEF if there is no such section, and will be + * the section index of the extended section index section assocated + * with the symbol table otherwise. + * + * NOTE: sec_versym + * Symbol table sections can have an SHT_SUNW_VERSYM section that + * contains its version indices. Other types of section will have + * this field set to SHN_UNDEF. + */ +typedef struct { + Elf32_Word sec_shndx; /* Section index */ + Elf_Scn *sec_scn; /* Section descriptor */ + Elf32_Shdr *sec_shdr; /* Section header */ + Elf_Data *sec_data; /* Data region of section */ + const char *sec_name; /* Name of section */ +} elfedit32_section_t; + +typedef struct { + Elf64_Word sec_shndx; + Elf_Scn *sec_scn; + Elf64_Shdr *sec_shdr; + Elf_Data *sec_data; + const char *sec_name; +} elfedit64_section_t; + +#ifdef _ELF64 +#define elfedit_section_t elfedit64_section_t +#else +#define elfedit_section_t elfedit32_section_t +#endif + + +/* + * We maintain extra information for symbol tables. We look them + * up frequently, so we want to eliminate expensive linear searches + * of the entire section header array. Also, symbol tables usually + * have associated parallal sections (syminfo, versym, extended indexes, etc) + * and we want to eliminate repeated linear lookups for them, as well as + * the basic error checking that is necessary to ensure they match the + * symbol table they're given. + * + * This extra information is kept in elfedit_symtab_t structs. Each field + * is a section index, with SHN_UNDEF used for those that do not apply. + */ +typedef struct { + Elf32_Word symt_shndx; /* Symbol table section index */ + Elf32_Word symt_xshndx; /* Index of extended index section */ + Elf32_Word symt_syminfo; /* Index of versym section */ + Elf32_Word symt_versym; /* Index of versym section */ +} elfedit32_symtab_t; + +typedef struct { + Elf64_Word symt_shndx; + Elf64_Word symt_xshndx; + Elf64_Word symt_versym; + Elf64_Word symt_syminfo; +} elfedit64_symtab_t; + +#ifdef _ELF64 +#define elfedit_symtab_t elfedit64_symtab_t +#else +#define elfedit_symtab_t elfedit32_symtab_t +#endif + + +/* + * Information for a single ELF object. + * + * note: + * elfedit is intended to be an expert's tool, capable of modifying + * nearly everything in the file, whether or not such modifications + * are a good idea. At the same time, elfedit, via libelf, relies + * on the contents of the object to properly locate information in + * the file. As this is the same information that elfedit allows the + * user to modify, it should be obvious that the potential exists + * for users to corrupt the file to the degree that elfedit itself + * may fail, or produce spurious results. We allow such changes for + * several reasons: + * + * 1) Such corruption does not happen in the most obvious and + * useful operations elfedit supports, but comes as a result + * of modifying fields that contain size and offset information + * used to navigate the file. Non-ELF developers have + * little practical reason to change such things. + * + * 2) Producing a corrupt ELF file can be very useful + * for R&D and/or testing purposes. + * + * 3) ELF is sufficiently complex that no absolute guarantees can + * be made about "safe" operations, beyond the basic + * and obvious things that are of practical use. + * + * One way we protect ourselves is via the information cached in + * the elfedit_obj_state_t structure at startup. By using this + * information, rather than constantly fetching it via libelf, + * we protect ourselves against many user changes, such as changing the + * program or section header offsets, or similar size/position fields. + * + * Of course, we make no assurances that that we will be able to + * read the resulting file in a subsequent session. + */ +typedef struct { + const char *os_file; /* Path to ELF file */ + int os_fd; /* Open file descriptor */ + Elf *os_elf; /* ELF descriptor */ + Elf32_Ehdr *os_ehdr; /* ELF header */ + Elf32_Word os_dynndx; /* Index of dynamic section */ + size_t os_shstrndx; /* Index of section header */ + /* string table section */ + size_t os_shnum; /* # of sections in file */ + elfedit32_section_t *os_secarr; /* Section data */ + size_t os_phnum; /* # of program headers */ + Elf32_Phdr *os_phdr; /* Program header array */ + size_t os_symtabnum; /* # items in os_symtab[] */ + elfedit32_symtab_t *os_symtab; /* Array of symbol tbl info */ +} elfedit32_obj_state_t; + +typedef struct { + const char *os_file; + int os_fd; + Elf *os_elf; + Elf64_Ehdr *os_ehdr; + Elf64_Word os_dynndx; + size_t os_shstrndx; + size_t os_shnum; + elfedit64_section_t *os_secarr; + size_t os_phnum; + Elf64_Phdr *os_phdr; + size_t os_symtabnum; + elfedit64_symtab_t *os_symtab; +} elfedit64_obj_state_t; + +#ifdef _ELF64 +#define elfedit_obj_state_t elfedit64_obj_state_t +#else +#define elfedit_obj_state_t elfedit32_obj_state_t +#endif + + +/* + * Bit values for editor state. + */ +typedef enum { + ELFEDIT_F_AUTOPRINT = 1, /* Print informational text about edits */ + ELFEDIT_F_DEBUG = 2, /* Print informational text about operations */ + ELFEDIT_F_READONLY = 4, /* File is processed readonly */ +} elfedit_flag_t; + +/* + * Type used to represent the output style for printing ELF values. + * + * DEFAULT - Output is in 'elfdump' style, designed for human eyes. + * Headers, and additional information are shown. + * SIMPLE - Output is simple, consisting only of the target item. + * Integer values are shown as symbolic constants when possible, + * and integers otherwise. + * NUM - Like SIMPLE, except integer values are always shown as + * integer constants, and strings are shown as the integer + * offset into the string table. + */ +typedef enum { + ELFEDIT_OUTSTYLE_DEFAULT = 0, + ELFEDIT_OUTSTYLE_SIMPLE = 1, + ELFEDIT_OUTSTYLE_NUM = 2 +} elfedit_outstyle_t; + + +/* + * The elfedit_module_t, and the types it references, are defined + * by loadable elfedit modules, and used by elfedit. These structures + * need to communicate internationalized strings for elfedit to print. + * + * We want to leave the choice of internationalization APIs, as well as + * the decision about whether or not to even to it to the individual + * modules. Hence, we do not use a simple (const char *) pointer to + * communicate potentially internationalized strings. Instead, we define + * elfedit_i18nhdl_t, an opaque type guaranteed to be large enough + * to hold a pointer. Each module casts the handle needed to access the + * string to this type. Each module also supplies a function + * (mod_i18nhdl_to_str field of elfedit_module_t) that given one + * of these opaque keys, will return a (const char *) pointer to the + * actual string, for elfedit to print. + * + * If the underlying module doesn't want to implement i18n support, + * all it has to do is cast the strings to elfedit_i18nhdl_t and + * back. + */ +typedef uintptr_t elfedit_i18nhdl_t; + + + +/* + * Macro to handle casting international string "handles" to the + * elfedit_i18nhdl_t opaque type. + */ +#define ELFEDIT_I18NHDL(_i18n_str_ref) ((elfedit_i18nhdl_t)_i18n_str_ref) + + +/* + * Return values from command functions + */ +typedef enum { + ELFEDIT_CMDRET_NONE = 0, /* Nothing to report */ + ELFEDIT_CMDRET_MOD = 1, /* Command modified output ELF file */ + ELFEDIT_CMDRET_FLUSH = 2 /* Output file flushed: elf_update() */ +} elfedit_cmdret_t; + +/* + * Prototype of an implementation function for an edit command. Note that + * commands do not return a status: + * - Success is indicated by a normal return. + * - The command indicates a fatal error by calling elfedit_msg() with the + * ELFEDIT_MSG_ERR type, in which case execution does not return + * to the command, and the elfedit command loop knows that an + * error occurred. + * - The command is responsible for using the standard libelf + * mechanisms to indicate when changes have been made to + * the ELF file. + */ +typedef elfedit_cmdret_t elfedit32_cmd_func_t(elfedit32_obj_state_t *state, + int argc, const char *argv[]); +typedef elfedit_cmdret_t elfedit64_cmd_func_t(elfedit64_obj_state_t *state, + int argc, const char *argv[]); +#ifdef _ELF64 +#define elfedit_cmd_func_t elfedit64_cmd_func_t +#else +#define elfedit_cmd_func_t elfedit32_cmd_func_t +#endif + + +/* + * An elfedit command (elfedit_cmd_t) has a cmd_cpl field that + * can be set to a command completion function. If such a function + * is present (non-NULL), and the user presses the tab key at the + * command line while the cursor is at a plain (non option) argument, + * elfedit calls the function, passing it all the tokens up through + * the one needing completion. The function can use elfedit_cpl_match() + * to enter possible alternatives. Additionally, there are helper + * functions built on top of elfedit_cpl_match() that simplify common cases. + * + * elfedit_cpl_ato[iu]() - enter matches from elfedit_ato[iu]_sym_t + * mappings. + * elfedit_cpl_atoconst() - Enter matches for well known constants + * elfedit_cpl_command() - enter matches for all known commands + * elfedit_cpl_mod() - enter matches for all known modules. + * + * The completion function is passed the following arguments: + * + * obj_state - Object state. Will be NULL if elfedit session does not + * have an active object. The completion function must test + * the pointer before using it. + * cpldata - Completion data, to be passed to elfedit_cpl_match() + * or the helper functions built on it to register alternative + * strings. + * argc, argv - The tokens from the start of the line throught + * the one needing completion, which will always + * be cmdcpl_argv[cmdcpl_argc - 1]. + * num_opt - A count of the optional arguments (those starting with + * '-' at the beginning of argv. This means that argv[num_opt] + * is the first plain argument, and the 1-based positional + * number of the plain argument for which command completion + * is needed is (argc - num_opt). + */ +typedef void elfedit32_cmdcpl_func_t(elfedit32_obj_state_t *state, + void *cpldata, int argc, const char *argv[], int num_opt); +typedef void elfedit64_cmdcpl_func_t(elfedit64_obj_state_t *state, + void *cpldata, int argc, const char *argv[], int num_opt); +#ifdef _ELF64 +#define elfedit_cmdcpl_func_t elfedit64_cmdcpl_func_t +#else +#define elfedit_cmdcpl_func_t elfedit32_cmdcpl_func_t +#endif + + + + +/* + * Command option/argument descriptor. These structures + * are used to represent each option and plain argument accepted + * by a command, via the cmd_opt and cmd_args fields in the + * command definition (elfedit_cmd_t). Each descriptor consists + * of a name, a help string (formatted for display via sys:help), + * and a flags field that conveys extra information about the + * item: + * + * ELFEDIT_CMDOA_F_OPT + * The item is optional. This flag is implicit for options + * and need only be set for plain arguments. + * + * ELFEDIT_CMDOA_F_VALUE + * The item has a value, which is found in the following + * item. This flag only has meaning for options, and should + * not be set for plain arguments. The descriptor for the + * value is found in the next array element, and only the + * oa_name field is used (the other should be set t 0). + * + * ELFEDIT_CMDOA_F_MULT + * More than one of the specified items may be specified + * + * ELFEDIT_CMDOA_F_INHERIT + * This is an item for which a common definition exists. + * Elfedit will substitute the standard values for the + * name, help text, and flags. This enforces consistency + * in documentation, plus it is easier for the module author. + * When ELFEDIT_CMDOA_F_INHERIT is set: + * - oa_name should be set to one of the ELFEDIT_STDOA_ + * values to specifiy which standard item is being + * inherited. + * - oa_help must be set to NULL. + * - It is an error to set any other flags with + * ELFEDIT_CMDOA_F_INHERIT. + * - oa_idmask and oa_excmask are used in the normal way. + * + * The oa_idmask and oa_excmask fields are used to identify options, + * and to support mutual exclusion (when two or more options cannot be + * used together). They are ignored for arguments, and should be set to 0. + * oa_idmask is used to uniquely identify each item. When elfedit_getopt() + * matches an option, it returns the value of oa_idmask to the caller to + * indicate which option was matched. elfedit enforces the following rules + * for oa_idmask, and will refuse to load a module that does not follow them: + * - The value of oa_idmask must be 0, or have a value that + * is a power of 2 (i.e. only has one bit set). + * - Each item that sets a non-0 value for oa_idmask must have + * a unique value. + * - If oa_idmask is 0, oa_excmask must be 0 also. + * - oa_excmask is set to 0 if an item is not mutually exclusive + * to any other item. Otherwise, it should set the bit + * values representing the items it is mutually exclusive to. + * - An oa_idmask value of 0 can be used for any item that + * the module does not need to identify, and which + * is not mutually exclusive to any other item. + * As elfedit_getopt() processes items, it maintains a bitmask combining the + * oa_idmask fields of all the options already seen. For each option, it uses + * oa_excmask to check for conflicts. + * + * note: elfedit enforces the rule that options consist of a '-' + * character followed by at least one character when a module + * is loaded. + */ +typedef enum { + ELFEDIT_CMDOA_F_OPT = 1, /* Item is optional */ + ELFEDIT_CMDOA_F_VALUE = 2, /* Item has a value arg following */ + ELFEDIT_CMDOA_F_MULT = 4, /* More than one are allowed */ + ELFEDIT_CMDOA_F_INHERIT = 8, /* Inherit definition: See above */ +} elfedit_cmd_oa_flag_t; + +typedef u_longlong_t elfedit_cmd_oa_mask_t; + +typedef struct { + const char *oa_name; /* Name of option */ + elfedit_i18nhdl_t oa_help; /* Help text for option */ + elfedit_cmd_oa_flag_t oa_flags; /* Additional attributes */ + elfedit_cmd_oa_mask_t oa_idmask; /* Unique id, returned by */ + /* elfedit_getopt */ + /* for use by caller */ + elfedit_cmd_oa_mask_t oa_excmask; /* Mutual exclusion mask */ +} elfedit_cmd_optarg_t; + + + +/* + * These values define the standard options and arguments that a module + * can inherit using the ELFEDIT_CMDOA_F_INHERIT flag (described above). + * New items must be added at the end --- reordering the list will + * require all modules to be rebuilt. + * + * Note: 0 cannot be used as a ELFEDIT_STDOA_ value, because a NULL + * value of oa_name is used to terminate argument and options lists. + * Therefore, these values start at 1. + */ +#define ELFEDIT_STDOA_OPT_O ((const char *) 1) /* -o ostyle */ +#define ELFEDIT_STDOA_OPT_AND ((const char *) 2) /* -and */ +#define ELFEDIT_STDOA_OPT_CMP ((const char *) 3) /* -cmp */ +#define ELFEDIT_STDOA_OPT_OR ((const char *) 4) /* -or */ + +#define ELFEDIT_NUM_STDOA 4 /* # of ELFEDIT_STDOA_ definitions */ + + + +/* + * Definition of a command + * + * This structure includes an elfedit_cmd_func_t pointer, which has + * different definitions for different ELFCLASS. Rather than needlessly + * complicate the code with three versions of this type, and any + * type that uses it, we simply use the GenericClass type. elfedit + * will always cast this to the correct type before calling a module. + * + * cmd_name is an array of pointers to the names for the command. + * The "primary" name should always be first, followed by any alias + * names. The final element of the array must be a NULL pointer, + * which terminates the list. Every command is required to have at + * least one name, so code is allowed to assume that the first element + * of cmd_name is non-NULL, and contains the primary name. + * + * Many modules provide a "default" command, which is a command + * that is run if only the module name is specified, followed + * by a colon (i.e. "sym:"). The way this is implemented is to + * give the desired default command an empty string as an alias. + * Note that the primary name cannot be an empty string, only the + * alias name. + * + * cmd_opts and cmd_args are each an array of elfedit_cmd_argdesc_t + * structures, that describe the options and plain arguments accepted + * by the command. These arrays are used to general help text for + * the commands. The cmd_opts array is also used to provide command + * completion for options. Both of these arrays are terminated by + * a final NULL element (all fields zero). + */ +typedef struct { + elfedit32_cmd_func_t *cmd_func; /* Implementation */ + elfedit32_cmdcpl_func_t *cmd_cplfunc; /* Completion function */ + const char **cmd_name; /* Cmd names (null term.) */ + elfedit_i18nhdl_t cmd_desc; /* Short desc. of cmd purpose */ + elfedit_i18nhdl_t cmd_help; /* Help text for the command */ + elfedit_cmd_optarg_t *cmd_opt; /* Options */ + elfedit_cmd_optarg_t *cmd_args; /* Plain arguments */ +} elfedit32_cmd_t; + +typedef struct { + elfedit64_cmd_func_t *cmd_func; + elfedit64_cmdcpl_func_t *cmd_cplfunc; + const char **cmd_name; + elfedit_i18nhdl_t cmd_desc; + elfedit_i18nhdl_t cmd_help; + elfedit_cmd_optarg_t *cmd_opt; + elfedit_cmd_optarg_t *cmd_args; +} elfedit64_cmd_t; + +#ifdef _ELF64 +#define elfedit_cmd_t elfedit64_cmd_t +#else +#define elfedit_cmd_t elfedit32_cmd_t +#endif + + + +/* + * elfedit modules version themselves so that we can alter the definition + * of elfedit_module_t in a backward compatible way. + */ +typedef enum { + ELFEDIT_VER_NONE = 0, + ELFEDIT_VER_CURRENT = 1, + ELFEDIT_VER_NUM = 2 +} elfedit_module_version_t; + + +/* + * Each module returns a pointer to an elfedit_module_t, describing + * what commands the module provides. + * + * Note: mod_cmds is a NULL terminated array of command defs. This + * means that the final element in the array should have all of its + * fields set to NULL. + * + * The mod_i18nhdl_to_str function pointer is explained above + * with the definition of elfedit_i18nhdl_t. + */ +typedef const char *(* elfedit_mod_i18nhdl_to_str_func_t)(elfedit_i18nhdl_t); + +typedef struct { + elfedit_module_version_t mod_version; /* version */ + const char *mod_name; /* Name of module */ + elfedit_i18nhdl_t mod_desc; /* Short desc. of mod purpose */ + elfedit32_cmd_t *mod_cmds; /* Array of command defs */ + /* i18n -> (char *) fcn */ + elfedit_mod_i18nhdl_to_str_func_t mod_i18nhdl_to_str; +} elfedit32_module_t; + +typedef struct { + elfedit_module_version_t mod_version; + const char *mod_name; + elfedit_i18nhdl_t mod_desc; + elfedit64_cmd_t *mod_cmds; + elfedit_mod_i18nhdl_to_str_func_t mod_i18nhdl_to_str; +} elfedit64_module_t; + +#ifdef _ELF64 +#define elfedit_module_t elfedit64_module_t +#else +#define elfedit_module_t elfedit32_module_t +#endif + + +/* + * Each module is a sharable library, expected to provide a single global + * function, named elfedit_init(), with the following prototype. + */ +typedef elfedit_module_t *elfedit_init_func_t(elfedit_module_version_t version); + + + + +/* + * Core elfedit functions exported for use by modules + */ +extern void elfedit_command_usage(void); +extern void elfedit_cpl_command(void *cpldata); +extern void elfedit_cpl_match(void *cpldata, const char *str, int casefold); +extern void elfedit_elferr(const char *file, const char *libelf_rtn_name); +extern elfedit_flag_t elfedit_flags(void); +extern void *elfedit_malloc(const char *item_name, size_t size); +extern void elfedit_msg(elfedit_msg_t type, const char *format, ...); +extern elfedit_outstyle_t elfedit_outstyle(void); +extern void elfedit_pager_init(void); +extern void elfedit_printf(const char *format, ...); +extern void *elfedit_realloc(const char *item_name, void *ptr, size_t size); +extern void elfedit_write(const void *ptr, size_t size); + +/* + * Core elfedit functions exported for use by sys: module only + */ +extern void elfedit_cpl_module(void *cpldata, int load_all_modules); + + +/* + * elfedit modules are expected to define two functions, one for + * each ELFCLASS. Define a generic name for this function, based on + * the class being supported by the including module. + */ +#ifdef _ELF64 +#define elfedit_init elfedit64_init +#else +#define elfedit_init elfedit32_init +#endif + + + +/* + * It is common to search the dynamic section for specific elements. + * Structures of this type are used to represent the contents of such + * elements in a systematic way. The elfedit_dyn_elt_init() function + * is used to prepare these strucutres for use. + */ +typedef struct { + int dn_seen; /* True if this item has been seen */ + Elf32_Word dn_ndx; /* Index of item in dynamic array */ + Elf32_Dyn dn_dyn; /* Contents of dynamic item */ +} elfedit32_dyn_elt_t; + +typedef struct { + int dn_seen; + Elf64_Word dn_ndx; + Elf64_Dyn dn_dyn; +} elfedit64_dyn_elt_t; + +#ifdef _ELF64 +#define elfedit_dyn_elt_t elfedit64_dyn_elt_t +#else +#define elfedit_dyn_elt_t elfedit32_dyn_elt_t +#endif + +/* + * The elfedit_atoi() and elfedit_atoui() functions can optionally + * accept an array of these structures, giving symbolic names that + * will be accepted instead of numeric codes. If such an array is + * present, the supplied string has it's leading and trailing whitespace + * removed and is then compared to the list, and if there is a match, + * the corresponding integer value is returned. + * + * The final array element must have its name field set to NULL. + */ +typedef u_longlong_t elfedit_atoui_t; +typedef struct { + const char *sym_name; + elfedit_atoui_t sym_value; +} elfedit_atoui_sym_t; +typedef longlong_t elfedit_atoi_t; +typedef struct { + const char *sym_name; + elfedit_atoi_t sym_value; +} elfedit_atoi_sym_t; + + +/* + * The elfedit_atoconst*() functions are built on top of the atoui routines. + * These routines accept an elfedit_const_t code instead of a + * pointer to an elfedit_atoui_sym_t array, and use internally + * predefined tables of elfedit_atoui_sym_t in order to do the desired + * mappings. elfedit modules are encouraged to use these standard + * tables instead of defining their own elfedit_atoui_sym_t arrays. + * + * note: + * - The values assigned here must be in agreement with the + * sym_table[] array defined in elfconst.c. + * - Once defined, these values must not change. Reordering the + * list will require all modules to be rebuilt, and will + * break backward compatability. New items should be + * added to the end. + */ +typedef enum { + ELFEDIT_CONST_OUTSTYLE = 0, /* elfedit output styles */ + ELFEDIT_CONST_OUTSTYLE_MO = 1, /* ostyles with -o prefix */ + ELFEDIT_CONST_BOOL = 2, /* boolean names */ + ELFEDIT_CONST_SHN = 3, /* ELF SHN_ section indexes */ + ELFEDIT_CONST_SHT = 4, /* ELF SHT_ section types */ + ELFEDIT_CONST_SHT_STRTAB = 5, /* ELF SHT_STRTAB */ + ELFEDIT_CONST_SHT_ALLSYMTAB = 6, /* ELF SHT_ symbol table */ + /* section types */ + ELFEDIT_CONST_SHT_SYMTAB = 7, /* ELF SHT_SYMTAB */ + ELFEDIT_CONST_SHT_DYNSYM = 8, /* ELF SHT_DYNSYM */ + ELFEDIT_CONST_SHT_LDYNSYM = 9, /* ELF SHT_SUNW_LDYNSYM */ + ELFEDIT_CONST_DT = 10, /* Dynamic tags: DT_ */ + ELFEDIT_CONST_DF = 11, /* DT_FLAGS bits */ + ELFEDIT_CONST_DF_P1 = 12, /* DF_POSFLAG_1 bits */ + ELFEDIT_CONST_DF_1 = 13, /* DT_FLAGS_1 bits */ + ELFEDIT_CONST_DTF_1 = 14, /* DT_FEATURE_1 bits */ + ELFEDIT_CONST_EI = 15, /* ELF header e_ident indexes */ + ELFEDIT_CONST_ET = 16, /* Ehdr obj type */ + ELFEDIT_CONST_ELFCLASS = 17, /* Ehdr wordsize (32,64) */ + ELFEDIT_CONST_ELFDATA = 18, /* Ehdr endian */ + ELFEDIT_CONST_EF = 19, /* Ehdr flags */ + ELFEDIT_CONST_EV = 20, /* Ehdr version */ + ELFEDIT_CONST_EM = 21, /* Ehdr machine */ + ELFEDIT_CONST_ELFOSABI = 22, /* Ehdr ABI */ + ELFEDIT_CONST_PT = 23, /* Phdr type */ + ELFEDIT_CONST_PF = 24, /* Phdr flags */ + ELFEDIT_CONST_SHF = 25, /* Shdr flags */ + ELFEDIT_CONST_STB = 26, /* Sym binding */ + ELFEDIT_CONST_STT = 27, /* Sym type */ + ELFEDIT_CONST_STV = 28, /* Sym visibility */ + ELFEDIT_CONST_SYMINFO_BT = 29, /* Syminfo boundto */ + ELFEDIT_CONST_SYMINFO_FLG = 30, /* Syminfo flags */ + ELFEDIT_CONST_CA = 31, /* Capabilities tags: CA_ */ + ELFEDIT_CONST_AV_386 = 32, /* X86 hardware caps */ + ELFEDIT_CONST_AV_SPARC = 33, /* sparc hardware caps */ + ELFEDIT_CONST_SF1_SUNW = 34, /* software capabilities */ +} elfedit_const_t; + +/* + * Given an elfedit_const_t, return the array of elfedit_atoui_sym_t + * entries that it represents. + */ +extern elfedit_atoui_sym_t *elfedit_const_to_atoui(elfedit_const_t const_type); + +/* + * Return the elfedit_atoui_t array that corresponds to the + * CA_SUNW_HW_1 hardware capabiliies field for a given + * machine type. + */ +extern elfedit_atoui_sym_t *elfedit_mach_sunw_hw1_to_atoui(int mach); + +/* + * ato[u]i and const routines, used to turn strings into numeric values, + * with support for mapping symbol names to numbers, and range checking. + */ +extern elfedit_atoi_t elfedit_atoi(const char *str, + const elfedit_atoi_sym_t *sym); +extern elfedit_atoui_t elfedit_atoui(const char *str, + const elfedit_atoui_sym_t *sym); +extern elfedit_atoui_t elfedit_atoconst(const char *str, + elfedit_const_t const_type); + +extern int elfedit_atoi2(const char *str, const elfedit_atoi_sym_t *sym, + elfedit_atoi_t *v); +extern int elfedit_atoui2(const char *str, const elfedit_atoui_sym_t *sym, + elfedit_atoui_t *); +extern int elfedit_atoconst2(const char *str, elfedit_const_t const_type, + elfedit_atoui_t *); + +extern 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); +extern 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); +extern 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); + +extern 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); +extern 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); +extern int elfedit_atoconst_range2(const char *str, elfedit_atoui_t min, + elfedit_atoui_t max, elfedit_const_t const_type, elfedit_atoui_t *v); + +extern const char *elfedit_atoi_value_to_str(const elfedit_atoi_sym_t *sym, + elfedit_atoi_t value, int required); +extern const char *elfedit_atoui_value_to_str(const elfedit_atoui_sym_t *sym, + elfedit_atoui_t value, int required); +extern const char *elfedit_atoconst_value_to_str(elfedit_const_t const_type, + elfedit_atoui_t value, int required); + +extern void elfedit_cpl_atoi(void *cpldata, const elfedit_atoi_sym_t *sym); +extern void elfedit_cpl_atoui(void *cpldata, const elfedit_atoui_sym_t *sym); +extern void elfedit_cpl_atoconst(void *cpldata, elfedit_const_t const_type); + + +/* + * Convenience functions built on top of the ato[u]i routines. + */ +extern int elfedit_atobool(const char *str, const char *item_name); +extern elfedit_atoui_t elfedit_atoshndx(const char *str, size_t shnum); + + +/* + * elfedit provides a getopt utility for use by the module commands. + * elfedit_getopt_state_t is the state block used by elfedit_getopt(). + * elfedit_getopt_ret_t is the definition of the values returned to + * the user by elfedit_getopt() when an option is matched. Elfedit + * getopt processing is done as follows: + * + * 1) The caller initializes an elfedit_getopt_state_t struct via + * a call to elfedit_getopt_init(). The contents of this structure + * must not be accessed by the caller, as they are all private and + * subject to change. + * 2) Repeated calls are made to elfedit_getopt(), as long as it returns + * a non-NULL pointer to an elfedit_getopt_ret_t structure. If the + * matched option has a value (ELFEDIT_CMDOA_F_VALUE), then the gor_value + * field contains the pointer to the string. Otherwise, gor_value is NULL. + * 3) As elfedit_getopt() consumes optional arguments from the argc/argv + * passed to elfedit_getopt_init(), it adjusts argc/argc to skip over + * them. Once elfedit_getopt() returns NULL to indicate that there are no + * more options to match, argc/argv have been adjusted so that they + * reference the plain arguments. + */ +typedef struct { + elfedit_cmd_oa_mask_t gor_idmask; /* oa_idmask from matching */ + /* elfedit_cmd_optarg_t. Can be */ + /* used to quickly identify opt */ + const char *gor_value; /* Opt value if ELFEDIT_CMDOA_F_VALUE */ + /* Otherwise, NULL */ +} elfedit_getopt_ret_t; +typedef struct { + int *go_argc; /* Pointer to # of options */ + const char ***go_argv; /* Ptr to array of opt strs */ + elfedit_cmd_optarg_t *go_optarg; /* Array of allowed options */ + elfedit_cmd_oa_mask_t go_idmask; /* Combined id masks of all */ + /* seen options */ + int go_done; /* True if last option seen */ + const char *go_sglgrp; /* Group of 1-letter opts */ + elfedit_getopt_ret_t go_ret; /* Data returned to user */ +} elfedit_getopt_state_t; + + + +/* + * getopt related routines + */ +extern void elfedit_getopt_init(elfedit_getopt_state_t *, + int *, const char ***); +extern elfedit_getopt_ret_t *elfedit_getopt(elfedit_getopt_state_t *); + + + +/* + * Additional utility functions exported for use by modules + */ +extern 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); + +extern 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); + +extern int elfedit_bits_set(u_longlong_t v, int sizeof_orig_v); + +extern void elfedit32_dyn_elt_init(elfedit32_dyn_elt_t *dyn_elt); +extern void elfedit64_dyn_elt_init(elfedit64_dyn_elt_t *dyn_elt); + +extern void elfedit32_dyn_elt_save(elfedit32_dyn_elt_t *elt, Elf32_Word ndx, + Elf32_Dyn *dyn); +extern void elfedit64_dyn_elt_save(elfedit64_dyn_elt_t *elt, Elf64_Word ndx, + Elf64_Dyn *dyn); + +const char *elfedit32_dyn_offset_to_str(elfedit32_section_t *strsec, + elfedit32_dyn_elt_t *dynelt); +const char *elfedit64_dyn_offset_to_str(elfedit64_section_t *strsec, + elfedit64_dyn_elt_t *dynelt); + +extern int elfedit32_dynstr_getpad(elfedit32_section_t *dynsec, + elfedit32_dyn_elt_t *dyn_strpad); +extern int elfedit64_dynstr_getpad(elfedit64_section_t *dynsec, + elfedit64_dyn_elt_t *dyn_strpad); + +extern Elf32_Word elfedit32_dynstr_insert(elfedit32_section_t *dynsec, + elfedit32_section_t *strsec, elfedit32_dyn_elt_t *dyn_strpad, + const char *str); +extern Elf64_Word elfedit64_dynstr_insert(elfedit64_section_t *dynsec, + elfedit64_section_t *strsec, elfedit64_dyn_elt_t *dyn_strpad, + const char *str); + +extern void elfedit32_modified_data(elfedit32_section_t *s); +extern void elfedit64_modified_data(elfedit64_section_t *s); + +extern void elfedit32_modified_ehdr(elfedit32_obj_state_t *obj_state); +extern void elfedit64_modified_ehdr(elfedit64_obj_state_t *obj_state); + +extern void elfedit32_modified_phdr(elfedit32_obj_state_t *obj_state); +extern void elfedit64_modified_phdr(elfedit64_obj_state_t *obj_state); + +extern void elfedit32_modified_shdr(elfedit32_section_t *s); +extern void elfedit64_modified_shdr(elfedit64_section_t *s); + +extern Elf32_Word elfedit32_name_to_shndx(elfedit32_obj_state_t *obj_state, + const char *shnam); +extern Elf64_Word elfedit64_name_to_shndx(elfedit64_obj_state_t *obj_state, + const char *shnam); + +extern Elf32_Word elfedit32_type_to_shndx(elfedit32_obj_state_t *obj_state, + Elf32_Word shtype); +extern Elf64_Word elfedit64_type_to_shndx(elfedit64_obj_state_t *obj_state, + Elf64_Word shtype); + +extern int elfedit32_name_to_symndx(elfedit32_section_t *symsec, + elfedit32_section_t *strsec, const char *name, elfedit_msg_t msg_type, + Elf32_Word *ret_symndx); +extern int elfedit64_name_to_symndx(elfedit64_section_t *symsec, + elfedit64_section_t *strsec, const char *name, elfedit_msg_t msg_type, + Elf64_Word *ret_symndx); + +extern const char *elfedit32_offset_to_str(elfedit32_section_t *strsec, + Elf32_Word offset, elfedit_msg_t msg_type, int debug_msg); +extern const char *elfedit64_offset_to_str(elfedit64_section_t *strsec, + Elf64_Word offset, elfedit_msg_t msg_type, int debug_msg); + +extern int elfedit32_sec_findstr(elfedit32_section_t *sec, Elf32_Word tail_ign, + const char *str, Elf32_Word *ret_offset); +extern int elfedit64_sec_findstr(elfedit64_section_t *sec, Elf64_Word tail_ign, + const char *str, Elf64_Word *ret_offset); + +extern elfedit32_section_t *elfedit32_sec_getcap( + elfedit32_obj_state_t *obj_state, Elf32_Cap **cap, Elf32_Word *num); +extern elfedit64_section_t *elfedit64_sec_getcap( + elfedit64_obj_state_t *obj_state, Elf64_Cap **cap, Elf64_Word *num); + +extern elfedit32_section_t *elfedit32_sec_getdyn( + elfedit32_obj_state_t *obj_state, Elf32_Dyn **dyn, Elf32_Word *num); +extern elfedit64_section_t *elfedit64_sec_getdyn( + elfedit64_obj_state_t *obj_state, Elf64_Dyn **dyn, Elf64_Word *num); + +extern elfedit32_section_t *elfedit32_sec_getstr( + elfedit32_obj_state_t *obj_state, Elf32_Word shndx); +extern elfedit64_section_t *elfedit64_sec_getstr( + elfedit64_obj_state_t *obj_state, Elf64_Word shndx); + +extern elfedit32_section_t *elfedit32_sec_getsyminfo( + elfedit32_obj_state_t *obj_state, Elf32_Syminfo **syminfo, Elf32_Word *num); +extern elfedit64_section_t *elfedit64_sec_getsyminfo( + elfedit64_obj_state_t *obj_state, Elf64_Syminfo **syminfo, Elf64_Word *num); + +extern elfedit32_section_t *elfedit32_sec_getsymtab( + elfedit32_obj_state_t *obj_state, int by_index, Elf32_Word index, + const char *name, Elf32_Sym **sym, Elf32_Word *num, + elfedit32_symtab_t **aux_info); +extern elfedit64_section_t *elfedit64_sec_getsymtab( + elfedit64_obj_state_t *obj_state, int by_index, Elf64_Word index, + const char *name, Elf64_Sym **sym, Elf64_Word *num, + elfedit64_symtab_t **aux_info); + +extern elfedit32_section_t *elfedit32_sec_getversym( + elfedit32_obj_state_t *obj_state, elfedit32_section_t *symsec, + Elf32_Versym **versym, Elf32_Word *num); +extern elfedit64_section_t *elfedit64_sec_getversym( + elfedit64_obj_state_t *obj_state, elfedit64_section_t *symsec, + Elf64_Versym **versym, Elf64_Word *num); + +extern elfedit32_section_t *elfedit32_sec_getxshndx( + elfedit32_obj_state_t *obj_state, elfedit32_section_t *symsec, + Elf32_Word **xshndx, Elf32_Word *num); +extern elfedit64_section_t *elfedit64_sec_getxshndx( + elfedit64_obj_state_t *obj_state, elfedit64_section_t *symsec, + Elf64_Word **xshndx, Elf64_Word *num); + +extern int elfedit32_sec_issymtab(elfedit32_section_t *sec, int issue_err, + elfedit_atoui_sym_t **atoui_list); +extern int elfedit64_sec_issymtab(elfedit64_section_t *sec, int issue_err, + elfedit_atoui_sym_t **atoui_list); + +extern const char *elfedit32_sec_msgprefix(elfedit32_section_t *sec); +extern const char *elfedit64_sec_msgprefix(elfedit64_section_t *sec); + +extern const char *elfedit32_shndx_to_name(elfedit32_obj_state_t *obj_state, + Elf32_Word shndx); +extern const char *elfedit64_shndx_to_name(elfedit64_obj_state_t *obj_state, + Elf64_Word shndx); + +extern Elf32_Word elfedit32_strtab_insert(elfedit32_obj_state_t *obj_state, + elfedit32_section_t *strsec, elfedit32_section_t *dynsec, const char *str); +extern Elf64_Word elfedit64_strtab_insert(elfedit64_obj_state_t *obj_state, + elfedit64_section_t *strsec, elfedit64_section_t *dynsec, const char *str); + +extern void elfedit32_strtab_insert_test(elfedit32_obj_state_t *obj_state, + elfedit32_section_t *strsec, elfedit32_section_t *dynsec, const char *str); +extern void elfedit64_strtab_insert_test(elfedit64_obj_state_t *obj_state, + elfedit64_section_t *strsec, elfedit64_section_t *dynsec, const char *str); + +extern Elf32_Word elfedit32_type_to_shndx(elfedit32_obj_state_t *obj_state, + Elf32_Word shtype); +extern Elf64_Word elfedit64_type_to_shndx(elfedit64_obj_state_t *obj_state, + Elf64_Word shtype); + + + +/* + * Map the generic names for each of the ELFCLASS specific routines + * above to reference the proper routine for the current compilation. + */ +#ifdef _ELF64 +#define elfedit_dyn_elt_init elfedit64_dyn_elt_init +#define elfedit_dyn_elt_save elfedit64_dyn_elt_save +#define elfedit_dyn_offset_to_str elfedit64_dyn_offset_to_str +#define elfedit_dynstr_getpad elfedit64_dynstr_getpad +#define elfedit_dynstr_insert elfedit64_dynstr_insert +#define elfedit_modified_data elfedit64_modified_data +#define elfedit_modified_ehdr elfedit64_modified_ehdr +#define elfedit_modified_phdr elfedit64_modified_phdr +#define elfedit_modified_shdr elfedit64_modified_shdr +#define elfedit_name_to_shndx elfedit64_name_to_shndx +#define elfedit_name_to_symndx elfedit64_name_to_symndx +#define elfedit_offset_to_str elfedit64_offset_to_str +#define elfedit_sec_findstr elfedit64_sec_findstr +#define elfedit_sec_getcap elfedit64_sec_getcap +#define elfedit_sec_getdyn elfedit64_sec_getdyn +#define elfedit_sec_getstr elfedit64_sec_getstr +#define elfedit_sec_getsyminfo elfedit64_sec_getsyminfo +#define elfedit_sec_getsymtab elfedit64_sec_getsymtab +#define elfedit_sec_getversym elfedit64_sec_getversym +#define elfedit_sec_getxshndx elfedit64_sec_getxshndx +#define elfedit_sec_issymtab elfedit64_sec_issymtab +#define elfedit_shndx_to_name elfedit64_shndx_to_name +#define elfedit_sec_msgprefix elfedit64_sec_msgprefix +#define elfedit_strtab_insert elfedit64_strtab_insert +#define elfedit_strtab_insert_test elfedit64_strtab_insert_test +#define elfedit_type_to_shndx elfedit64_type_to_shndx +#else +#define elfedit_dyn_elt_init elfedit32_dyn_elt_init +#define elfedit_dyn_elt_save elfedit32_dyn_elt_save +#define elfedit_dyn_offset_to_str elfedit32_dyn_offset_to_str +#define elfedit_dynstr_getpad elfedit32_dynstr_getpad +#define elfedit_dynstr_insert elfedit32_dynstr_insert +#define elfedit_modified_data elfedit32_modified_data +#define elfedit_modified_ehdr elfedit32_modified_ehdr +#define elfedit_modified_phdr elfedit32_modified_phdr +#define elfedit_modified_shdr elfedit32_modified_shdr +#define elfedit_name_to_shndx elfedit32_name_to_shndx +#define elfedit_name_to_symndx elfedit32_name_to_symndx +#define elfedit_offset_to_str elfedit32_offset_to_str +#define elfedit_sec_findstr elfedit32_sec_findstr +#define elfedit_sec_getcap elfedit32_sec_getcap +#define elfedit_sec_getdyn elfedit32_sec_getdyn +#define elfedit_sec_getstr elfedit32_sec_getstr +#define elfedit_sec_getsyminfo elfedit32_sec_getsyminfo +#define elfedit_sec_getsymtab elfedit32_sec_getsymtab +#define elfedit_sec_getversym elfedit32_sec_getversym +#define elfedit_sec_getxshndx elfedit32_sec_getxshndx +#define elfedit_sec_issymtab elfedit32_sec_issymtab +#define elfedit_shndx_to_name elfedit32_shndx_to_name +#define elfedit_sec_msgprefix elfedit32_sec_msgprefix +#define elfedit_strtab_insert elfedit32_strtab_insert +#define elfedit_strtab_insert_test elfedit32_strtab_insert_test +#define elfedit_type_to_shndx elfedit32_type_to_shndx +#endif + + +#ifdef __cplusplus +} +#endif + +#endif /* _ELFEDIT_H */ diff --git a/usr/src/cmd/sgs/libconv/Makefile.com b/usr/src/cmd/sgs/libconv/Makefile.com index 17cd34cc8f..2b8e665843 100644 --- a/usr/src/cmd/sgs/libconv/Makefile.com +++ b/usr/src/cmd/sgs/libconv/Makefile.com @@ -20,7 +20,7 @@ # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -33,14 +33,16 @@ COMOBJS32 = cap32.o dynamic32.o \ phdr32.o \ relocate_i38632.o relocate_amd6432.o \ relocate_sparc32.o sections32.o \ - symbols32.o symbols_sparc32.o + symbols32.o symbols_sparc32.o \ + syminfo32.o COMOBJS64 = cap64.o dynamic64.o \ elf64.o globals64.o \ phdr64.o \ relocate_i38664.o relocate_amd6464.o \ relocate_sparc64.o sections64.o \ - symbols64.o symbols_sparc64.o + symbols64.o symbols_sparc64.o \ + syminfo64.o COMOBJS= arch.o config.o \ data.o deftag.o \ diff --git a/usr/src/cmd/sgs/libconv/common/_conv.h b/usr/src/cmd/sgs/libconv/common/_conv.h index d5d46ea72f..b73aadf28a 100644 --- a/usr/src/cmd/sgs/libconv/common/_conv.h +++ b/usr/src/cmd/sgs/libconv/common/_conv.h @@ -68,27 +68,19 @@ extern "C" { * a result string, if necessary. * bufsize - sizeof(buf) * val - The value for which a string is desired. - * flags - CONV_FMT_* values, used to influence formatting of - * the resulting string. - * num_msg - # of Msg entries in msg, msg_altdump, and msg_altfile. + * flags - CONV_FMT_* values to be passed to conv_invalid_val() if + * necessary. The caller is reponsible for having examined + * the CONV_FMT_ALT_* part of flags and passing the proper + * msg array. + * num_msg - # of Msg entries in msg. * msg - Array of num_msg Msg items corresponding to the possible * strings corresponding to val. - * msg_altdump - NULL, or array of num_msg Msg items, to be used - * instead of msg when the CONV_FMT_ALTDUMP flag is set. - * msg_altfile - NULL, or array of num_msg Msg items, to be used - * instead of msg when the CONV_FMT_ALTFILE flag is set. * * exit: * If val lies in the range [0-(num_msg-1)], then the string - * corresponding to it is returned: - * 1) If CONV_FMT_ALTDUMP is set and msg_altdump is non-NULL, - * the string comes from msg_altdump. - * 2) If CONV_FMT_ALTFILE is set and msg_altfile is non-NULL, - * the string comes from msg_altfile. - * 3) If neither of the previous rules holds, the string - * comes from msg. - * if val is outside the range, an ASCII representation of it is - * formatted into string, and that is returned. + * corresponding to it is returned. If val is outside the range, + * conv_invalid_val() is called to format an ASCII representation + * of it into string, and that is returned. * * note: * Ideally, this would be a function defined in globals.c. @@ -100,18 +92,11 @@ extern "C" { #define DEFINE_conv_map2str \ static \ const char * \ -conv_map2str(Conv_inv_buf_t *inv_buf, int val, int flags, int num_msg, \ - const Msg *msg, const Msg *msg_altdump, const Msg *msg_altfile) \ +conv_map2str(Conv_inv_buf_t *inv_buf, int val, Conv_fmt_flags_t flags, \ + int num_msg, const Msg *msg) \ { \ - if ((val >= 0) && (val < num_msg)) { \ - if ((flags & CONV_FMT_ALTDUMP) && msg_altdump) { \ - return (MSG_ORIG(msg_altdump[val])); \ - } else if ((flags & CONV_FMT_ALTFILE) && msg_altfile) { \ - return (MSG_ORIG(msg_altfile[val])); \ - } else { \ - return (MSG_ORIG(msg[val])); \ - } \ - } \ + if ((val >= 0) && (val < num_msg)) \ + return (MSG_ORIG(msg[val])); \ \ /* If we get here, it's an unknown value */ \ return (conv_invalid_val(inv_buf, val, flags)); \ diff --git a/usr/src/cmd/sgs/libconv/common/cap.c b/usr/src/cmd/sgs/libconv/common/cap.c index eae6bd9f4e..0b4a91e0be 100644 --- a/usr/src/cmd/sgs/libconv/common/cap.c +++ b/usr/src/cmd/sgs/libconv/common/cap.c @@ -37,46 +37,60 @@ static int conv_cap_1(Xword val, char *str, size_t len, Half mach, + Conv_fmt_flags_t fmt_flags, int (*fptr)(uint64_t, char *, size_t, int, ushort_t)) { size_t _len; + int do_bkt = (fmt_flags & CONV_FMT_NOBKT) == 0; - _len = sprintf(str, MSG_ORIG(MSG_GBL_OSQBRKT), EC_XWORD(val)); + /* + * Note that for the purposes of this routine, I consider + * CONV_FMT_NOBKT to mean no brackets, or anything that + * is placed outside of them. We also drop the hex version + * of the flags that are put in front of the opening bracket. + */ + if (do_bkt) { + _len = sprintf(str, MSG_ORIG(MSG_GBL_OSQBRKT), EC_XWORD(val)); - len -= _len; - str += _len; + len -= _len; + str += _len; + } if ((*fptr)(val, str, len, CAP_FMT_SNGSPACE, mach) != 0) return (0); - _len = strlen(str); - if ((len - _len) >= MSG_GBL_CSQBRKT_SIZE) { - str += _len; - (void) strcpy(str, MSG_ORIG(MSG_GBL_CSQBRKT)); + if (do_bkt) { + _len = strlen(str); + if ((len - _len) >= MSG_GBL_CSQBRKT_SIZE) { + str += _len; + (void) strcpy(str, MSG_ORIG(MSG_GBL_CSQBRKT)); + } } return (1); } const char * -conv_cap_val_hw1(Xword val, Half mach, Conv_cap_val_hw1_buf_t *cap_val_hw1_buf) +conv_cap_val_hw1(Xword val, Half mach, Conv_fmt_flags_t fmt_flags, + Conv_cap_val_hw1_buf_t *cap_val_hw1_buf) { if (val == 0) return (MSG_ORIG(MSG_GBL_ZERO)); if (conv_cap_1(val, cap_val_hw1_buf->buf, sizeof (cap_val_hw1_buf->buf), - mach, hwcap_1_val2str) == 0) + mach, fmt_flags, hwcap_1_val2str) == 0) return (conv_invalid_val(&cap_val_hw1_buf->inv_buf, val, 0)); return ((const char *)cap_val_hw1_buf->buf); } const char * -conv_cap_val_sf1(Xword val, Half mach, Conv_cap_val_sf1_buf_t *cap_val_sf1_buf) +conv_cap_val_sf1(Xword val, Half mach, Conv_fmt_flags_t fmt_flags, + Conv_cap_val_sf1_buf_t *cap_val_sf1_buf) { if (val == 0) return (MSG_ORIG(MSG_GBL_ZERO)); if (conv_cap_1(val, cap_val_sf1_buf->buf, sizeof (cap_val_sf1_buf->buf), - mach, sfcap_1_val2str) == 0) + mach, fmt_flags, sfcap_1_val2str) == 0) return (conv_invalid_val(&cap_val_sf1_buf->inv_buf, val, 0)); return ((const char *)cap_val_sf1_buf->buf); } @@ -99,10 +113,10 @@ const char * conv_cap_val(Xword tag, Xword val, Half mach, Conv_cap_val_buf_t *cap_val_buf) { if (tag == CA_SUNW_HW_1) - return (conv_cap_val_hw1(val, mach, + return (conv_cap_val_hw1(val, mach, 0, &cap_val_buf->cap_val_hw1_buf)); else if (tag == CA_SUNW_SF_1) - return (conv_cap_val_sf1(val, mach, + return (conv_cap_val_sf1(val, mach, 0, &cap_val_buf->cap_val_sf1_buf)); else return (conv_invalid_val(&cap_val_buf->inv_buf, val, 0)); diff --git a/usr/src/cmd/sgs/libconv/common/config.c b/usr/src/cmd/sgs/libconv/common/config.c index 43cc8e6a95..1ea5436173 100644 --- a/usr/src/cmd/sgs/libconv/common/config.c +++ b/usr/src/cmd/sgs/libconv/common/config.c @@ -80,7 +80,7 @@ conv_config_feat(int features, Conv_config_feat_buf_t *config_feat_buf) conv_arg.buf = config_feat_buf->buf; conv_arg.oflags = conv_arg.rflags = features; - (void) conv_expn_field(&conv_arg); + (void) conv_expn_field(&conv_arg, 0); return ((const char *)config_feat_buf->buf); } @@ -160,7 +160,7 @@ conv_config_obj(ushort_t flags, Conv_config_obj_buf_t *config_obj_buf) *lstr = NULL; conv_arg.oflags = conv_arg.rflags &= ~RTC_OBJ_OPTINAL; - (void) conv_expn_field(&conv_arg); + (void) conv_expn_field(&conv_arg, 0); return ((const char *)config_obj_buf->buf); } diff --git a/usr/src/cmd/sgs/libconv/common/dl.c b/usr/src/cmd/sgs/libconv/common/dl.c index fbdece6427..072de7ec24 100644 --- a/usr/src/cmd/sgs/libconv/common/dl.c +++ b/usr/src/cmd/sgs/libconv/common/dl.c @@ -95,7 +95,7 @@ conv_dl_mode(int mode, int fabricate, Conv_dl_mode_buf_t *dl_mode_buf) conv_arg.oflags = mode; conv_arg.rflags = mode & ~(RTLD_LAZY | RTLD_NOW | RTLD_GLOBAL); - (void) conv_expn_field(&conv_arg); + (void) conv_expn_field(&conv_arg, 0); return ((const char *)dl_mode_buf->buf); } @@ -139,7 +139,8 @@ conv_dl_mode(int mode, int fabricate, Conv_dl_mode_buf_t *dl_mode_buf) * we build a "|" separated string. */ const char * -conv_dl_flag(int flags, int fmt_flags, Conv_dl_flag_buf_t *dl_flag_buf) +conv_dl_flag(int flags, Conv_fmt_flags_t fmt_flags, + Conv_dl_flag_buf_t *dl_flag_buf) { static Val_desc vda[] = { { RTLD_REL_RELATIVE, MSG_ORIG(MSG_RTLD_REL_RELATIVE) }, @@ -164,7 +165,7 @@ conv_dl_flag(int flags, int fmt_flags, Conv_dl_flag_buf_t *dl_flag_buf) return (MSG_ORIG(MSG_GBL_ZERO)); conv_arg.buf = dl_flag_buf->buf; - if (fmt_flags & CONV_FMT_ALTCRLE) { + if (CONV_TYPE_FMT_ALT(fmt_flags) == CONV_FMT_ALT_CRLE) { conv_arg.prefix = conv_arg.suffix = MSG_ORIG(MSG_GBL_QUOTE); conv_arg.sep = MSG_ORIG(MSG_GBL_SEP); } else { /* Use default delimiters */ @@ -178,7 +179,7 @@ conv_dl_flag(int flags, int fmt_flags, Conv_dl_flag_buf_t *dl_flag_buf) *lstr = NULL; conv_arg.oflags = conv_arg.rflags = flags; - (void) conv_expn_field(&conv_arg); + (void) conv_expn_field(&conv_arg, fmt_flags); return ((const char *)dl_flag_buf->buf); } diff --git a/usr/src/cmd/sgs/libconv/common/dynamic.c b/usr/src/cmd/sgs/libconv/common/dynamic.c index 184bfa0c63..532c0d82ce 100644 --- a/usr/src/cmd/sgs/libconv/common/dynamic.c +++ b/usr/src/cmd/sgs/libconv/common/dynamic.c @@ -61,7 +61,7 @@ DEFINE_conv_map2str #endif const char * -conv_dyn_posflag1(Xword flags, int fmt_flags, +conv_dyn_posflag1(Xword flags, Conv_fmt_flags_t fmt_flags, Conv_dyn_posflag1_buf_t *dyn_posflag1_buf) { static Val_desc vda[] = { @@ -85,10 +85,11 @@ conv_dyn_posflag1(Xword flags, int fmt_flags, if (flags == 0) return (MSG_ORIG(MSG_GBL_ZERO)); - arg = (fmt_flags & CONV_FMT_ALTDUMP) ? &conv_arg_alt : &conv_arg; + arg = (CONV_TYPE_FMT_ALT(fmt_flags) == CONV_FMT_ALT_DUMP) ? + &conv_arg_alt : &conv_arg; arg->buf = dyn_posflag1_buf->buf; arg->oflags = arg->rflags = flags; - (void) conv_expn_field(arg); + (void) conv_expn_field(arg, fmt_flags); return ((const char *)dyn_posflag1_buf); } @@ -115,7 +116,8 @@ conv_dyn_posflag1(Xword flags, int fmt_flags, #endif const char * -conv_dyn_flag(Xword flags, int fmt_flags, Conv_dyn_flag_buf_t *dyn_flag_buf) +conv_dyn_flag(Xword flags, Conv_fmt_flags_t fmt_flags, + Conv_dyn_flag_buf_t *dyn_flag_buf) { static Val_desc vda[] = { { DF_ORIGIN, MSG_ORIG(MSG_DF_ORIGIN) }, @@ -133,12 +135,12 @@ conv_dyn_flag(Xword flags, int fmt_flags, Conv_dyn_flag_buf_t *dyn_flag_buf) conv_arg.buf = dyn_flag_buf->buf; conv_arg.oflags = conv_arg.rflags = flags; - if (fmt_flags & CONV_FMT_ALTDUMP) { + if (CONV_TYPE_FMT_ALT(fmt_flags) == CONV_FMT_ALT_DUMP) { conv_arg.prefix = conv_arg.suffix = MSG_ORIG(MSG_STR_EMPTY); } else { conv_arg.prefix = conv_arg.suffix = NULL; } - (void) conv_expn_field(&conv_arg); + (void) conv_expn_field(&conv_arg, fmt_flags); return ((const char *)dyn_flag_buf->buf); } @@ -184,7 +186,8 @@ conv_dyn_flag(Xword flags, int fmt_flags, Conv_dyn_flag_buf_t *dyn_flag_buf) #endif const char * -conv_dyn_flag1(Xword flags, Conv_dyn_flag1_buf_t *dyn_flag1_buf) +conv_dyn_flag1(Xword flags, Conv_fmt_flags_t fmt_flags, + Conv_dyn_flag1_buf_t *dyn_flag1_buf) { static Val_desc vda[] = { { DF_1_NOW, MSG_ORIG(MSG_DF1_NOW) }, @@ -222,7 +225,7 @@ conv_dyn_flag1(Xword flags, Conv_dyn_flag1_buf_t *dyn_flag1_buf) conv_arg.oflags = conv_arg.rflags = flags; conv_arg.buf = dyn_flag1_buf->buf; - (void) conv_expn_field(&conv_arg); + (void) conv_expn_field(&conv_arg, fmt_flags); return ((const char *)dyn_flag1_buf->buf); } @@ -246,7 +249,7 @@ conv_dyn_flag1(Xword flags, Conv_dyn_flag1_buf_t *dyn_flag1_buf) #endif const char * -conv_dyn_feature1(Xword flags, int fmt_flags, +conv_dyn_feature1(Xword flags, Conv_fmt_flags_t fmt_flags, Conv_dyn_feature1_buf_t *dyn_feature1_buf) { static Val_desc vda[] = { @@ -262,18 +265,19 @@ conv_dyn_feature1(Xword flags, int fmt_flags, conv_arg.buf = dyn_feature1_buf->buf; conv_arg.oflags = conv_arg.rflags = flags; - if (fmt_flags & CONV_FMT_ALTDUMP) { + if (CONV_TYPE_FMT_ALT(fmt_flags) == CONV_FMT_ALT_DUMP) { conv_arg.prefix = conv_arg.suffix = MSG_ORIG(MSG_STR_EMPTY); } else { conv_arg.prefix = conv_arg.suffix = NULL; } - (void) conv_expn_field(&conv_arg); + (void) conv_expn_field(&conv_arg, fmt_flags); return ((const char *)dyn_feature1_buf->buf); } const char * -conv_dyn_tag(Xword tag, Half mach, int fmt_flags, Conv_inv_buf_t *inv_buf) +conv_dyn_tag(Xword tag, Half mach, Conv_fmt_flags_t fmt_flags, + Conv_inv_buf_t *inv_buf) { /* * Dynamic tag values are sparse, cover a wide range, and have @@ -399,9 +403,15 @@ conv_dyn_tag(Xword tag, Half mach, int fmt_flags, Conv_inv_buf_t *inv_buf) - if (tag <= DT_FLAGS) + if (tag <= DT_FLAGS) { + /* use 'dump' style? */ + if (CONV_TYPE_FMT_ALT(fmt_flags) == CONV_FMT_ALT_DUMP) + return (conv_map2str(inv_buf, tag, fmt_flags, + ARRAY_NELTS(tags_null_alt), tags_null_alt)); + /* Standard style */ return (conv_map2str(inv_buf, tag, fmt_flags, - ARRAY_NELTS(tags_null), tags_null, tags_null_alt, NULL)); + ARRAY_NELTS(tags_null), tags_null)); + } DYN_RANGE(DT_PREINIT_ARRAY, tags_preinit_array); DYN_RANGE(DT_SUNW_AUXILIARY, tags_sunw_auxiliary); if (tag == DT_SUNW_STRPAD) @@ -466,7 +476,7 @@ conv_bnd_type(uint_t flags, Conv_bnd_type_buf_t *bnd_type_buf) conv_arg.buf = bnd_type_buf->buf; conv_arg.oflags = conv_arg.rflags = flags; - (void) conv_expn_field(&conv_arg); + (void) conv_expn_field(&conv_arg, 0); return ((const char *)bnd_type_buf->buf); } @@ -519,7 +529,7 @@ conv_bnd_obj(uint_t flags, Conv_bnd_obj_buf_t *bnd_obj_buf) */ conv_arg.buf = bnd_obj_buf->buf; conv_arg.oflags = flags; - (void) conv_expn_field(&conv_arg); + (void) conv_expn_field(&conv_arg, 0); return ((const char *)bnd_obj_buf->buf); } diff --git a/usr/src/cmd/sgs/libconv/common/elf.c b/usr/src/cmd/sgs/libconv/common/elf.c index c27385e50b..e67882ab08 100644 --- a/usr/src/cmd/sgs/libconv/common/elf.c +++ b/usr/src/cmd/sgs/libconv/common/elf.c @@ -42,7 +42,8 @@ DEFINE_conv_map2str const char * -conv_ehdr_class(uchar_t class, int fmt_flags, Conv_inv_buf_t *inv_buf) +conv_ehdr_class(uchar_t class, Conv_fmt_flags_t fmt_flags, + Conv_inv_buf_t *inv_buf) { static const Msg classes[] = { MSG_ELFCLASSNONE, MSG_ELFCLASS32, MSG_ELFCLASS64 @@ -51,12 +52,22 @@ conv_ehdr_class(uchar_t class, int fmt_flags, Conv_inv_buf_t *inv_buf) MSG_ELFCLASSNONE_ALT, MSG_ELFCLASS32_ALT, MSG_ELFCLASS64_ALT }; + /* Use alternative strings? */ + switch (CONV_TYPE_FMT_ALT(fmt_flags)) { + case CONV_FMT_ALT_DUMP: + case CONV_FMT_ALT_FILE: + return (conv_map2str(inv_buf, class, fmt_flags, + ARRAY_NELTS(classes_alt), classes_alt)); + } + + /* Use default strings */ return (conv_map2str(inv_buf, class, fmt_flags, - ARRAY_NELTS(classes), classes, classes_alt, classes_alt)); + ARRAY_NELTS(classes), classes)); } const char * -conv_ehdr_data(uchar_t data, int fmt_flags, Conv_inv_buf_t *inv_buf) +conv_ehdr_data(uchar_t data, Conv_fmt_flags_t fmt_flags, + Conv_inv_buf_t *inv_buf) { static const Msg datas[] = { MSG_ELFDATANONE, MSG_ELFDATA2LSB, MSG_ELFDATA2MSB @@ -68,8 +79,19 @@ conv_ehdr_data(uchar_t data, int fmt_flags, Conv_inv_buf_t *inv_buf) MSG_ELFDATANONE_ALT, MSG_ELFDATA2LSB_ALT2, MSG_ELFDATA2MSB_ALT2 }; + /* Use alternative strings? */ + switch (CONV_TYPE_FMT_ALT(fmt_flags)) { + case CONV_FMT_ALT_DUMP: + return (conv_map2str(inv_buf, data, fmt_flags, + ARRAY_NELTS(datas_dump), datas_dump)); + case CONV_FMT_ALT_FILE: + return (conv_map2str(inv_buf, data, fmt_flags, + ARRAY_NELTS(datas_file), datas_file)); + } + + /* Use default strings */ return (conv_map2str(inv_buf, data, fmt_flags, - ARRAY_NELTS(datas), datas, datas_dump, datas_file)); + ARRAY_NELTS(datas), datas)); } static const Msg machines[EM_NUM] = { @@ -145,15 +167,25 @@ static const Msg machines_alt[EM_NUM] = { #endif const char * -conv_ehdr_mach(Half machine, int fmt_flags, Conv_inv_buf_t *inv_buf) +conv_ehdr_mach(Half machine, Conv_fmt_flags_t fmt_flags, + Conv_inv_buf_t *inv_buf) { + /* Use alternative strings? */ + switch (CONV_TYPE_FMT_ALT(fmt_flags)) { + case CONV_FMT_ALT_DUMP: + case CONV_FMT_ALT_FILE: + return (conv_map2str(inv_buf, machine, fmt_flags, + ARRAY_NELTS(machines_alt), machines_alt)); + } + + /* Use default strings */ return (conv_map2str(inv_buf, machine, fmt_flags, - ARRAY_NELTS(machines), machines, machines_alt, machines_alt)); + ARRAY_NELTS(machines), machines)); } const char * -conv_ehdr_type(Half etype, int fmt_flags, Conv_inv_buf_t *inv_buf) +conv_ehdr_type(Half etype, Conv_fmt_flags_t fmt_flags, Conv_inv_buf_t *inv_buf) { static const Msg etypes[] = { MSG_ET_NONE, MSG_ET_REL, MSG_ET_EXEC, @@ -165,18 +197,32 @@ conv_ehdr_type(Half etype, int fmt_flags, Conv_inv_buf_t *inv_buf) }; if (etype == ET_SUNWPSEUDO) { - return ((fmt_flags & CONV_FMTALTMASK) - ? MSG_ORIG(MSG_ET_SUNWPSEUDO_ALT) - : MSG_ORIG(MSG_ET_SUNWPSEUDO)); + switch (CONV_TYPE_FMT_ALT(fmt_flags)) { + case CONV_FMT_ALT_DUMP: + case CONV_FMT_ALT_FILE: + return (MSG_ORIG(MSG_ET_SUNWPSEUDO_ALT)); + default: + return (MSG_ORIG(MSG_ET_SUNWPSEUDO)); + } } + /* Use alternative strings? */ + switch (CONV_TYPE_FMT_ALT(fmt_flags)) { + case CONV_FMT_ALT_DUMP: + case CONV_FMT_ALT_FILE: + return (conv_map2str(inv_buf, etype, fmt_flags, + ARRAY_NELTS(etypes_alt), etypes_alt)); + } + + /* Use default strings */ return (conv_map2str(inv_buf, etype, fmt_flags, - ARRAY_NELTS(etypes), etypes, etypes_alt, etypes_alt)); + ARRAY_NELTS(etypes), etypes)); } const char * -conv_ehdr_vers(Word version, int fmt_flags, Conv_inv_buf_t *inv_buf) +conv_ehdr_vers(Word version, Conv_fmt_flags_t fmt_flags, + Conv_inv_buf_t *inv_buf) { static const Msg versions[] = { MSG_EV_NONE, MSG_EV_CURRENT @@ -185,8 +231,17 @@ conv_ehdr_vers(Word version, int fmt_flags, Conv_inv_buf_t *inv_buf) MSG_EV_NONE_ALT, MSG_EV_CURRENT_ALT }; + /* Use alternative strings? */ + switch (CONV_TYPE_FMT_ALT(fmt_flags)) { + case CONV_FMT_ALT_DUMP: + case CONV_FMT_ALT_FILE: + return (conv_map2str(inv_buf, version, fmt_flags, + ARRAY_NELTS(versions_alt), versions_alt)); + } + + /* Use default strings */ return (conv_map2str(inv_buf, version, fmt_flags, - ARRAY_NELTS(versions), versions, versions_alt, versions_alt)); + ARRAY_NELTS(versions), versions)); } #define EFLAGSZ CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \ @@ -213,7 +268,8 @@ conv_ehdr_vers(Word version, int fmt_flags, Conv_inv_buf_t *inv_buf) * Make a string representation of the e_flags field. */ const char * -conv_ehdr_flags(Half mach, Word flags, Conv_ehdr_flags_buf_t *flags_buf) +conv_ehdr_flags(Half mach, Word flags, Conv_fmt_flags_t fmt_flags, + Conv_ehdr_flags_buf_t *flags_buf) { static Val_desc vda[] = { { EF_SPARC_32PLUS, MSG_ORIG(MSG_EF_SPARC_32PLUS) }, @@ -251,7 +307,7 @@ conv_ehdr_flags(Half mach, Word flags, Conv_ehdr_flags_buf_t *flags_buf) } *lstr = NULL; - (void) conv_expn_field(&conv_arg); + (void) conv_expn_field(&conv_arg, fmt_flags); return (conv_arg.buf); } @@ -263,7 +319,8 @@ conv_ehdr_flags(Half mach, Word flags, Conv_ehdr_flags_buf_t *flags_buf) * Make a string representation of the e_ident[EI_OSABI] field. */ const char * -conv_ehdr_osabi(uchar_t osabi, int fmt_flags, Conv_inv_buf_t *inv_buf) +conv_ehdr_osabi(uchar_t osabi, Conv_fmt_flags_t fmt_flags, + Conv_inv_buf_t *inv_buf) { static const Msg osabi_arr[] = { MSG_OSABI_NONE, MSG_OSABI_HPUX, @@ -290,20 +347,38 @@ conv_ehdr_osabi(uchar_t osabi, int fmt_flags, Conv_inv_buf_t *inv_buf) switch (osabi) { case ELFOSABI_ARM: - str = (fmt_flags & CONV_FMTALTMASK) ? - MSG_ORIG(MSG_OSABI_ARM_ALT) : MSG_ORIG(MSG_OSABI_ARM); + switch (CONV_TYPE_FMT_ALT(fmt_flags)) { + case CONV_FMT_ALT_DUMP: + case CONV_FMT_ALT_FILE: + str = MSG_ORIG(MSG_OSABI_ARM_ALT); + break; + default: + str = MSG_ORIG(MSG_OSABI_ARM); + } break; case ELFOSABI_STANDALONE: - str = (fmt_flags & CONV_FMTALTMASK) ? - MSG_ORIG(MSG_OSABI_STANDALONE_ALT) : - MSG_ORIG(MSG_OSABI_STANDALONE); + switch (CONV_TYPE_FMT_ALT(fmt_flags)) { + case CONV_FMT_ALT_DUMP: + case CONV_FMT_ALT_FILE: + str = MSG_ORIG(MSG_OSABI_STANDALONE_ALT); + break; + default: + str = MSG_ORIG(MSG_OSABI_STANDALONE); + } break; default: - str = conv_map2str(inv_buf, osabi, fmt_flags, - ARRAY_NELTS(osabi_arr), osabi_arr, osabi_arr_alt, - osabi_arr_alt); + switch (CONV_TYPE_FMT_ALT(fmt_flags)) { + case CONV_FMT_ALT_DUMP: + case CONV_FMT_ALT_FILE: + str = conv_map2str(inv_buf, osabi, fmt_flags, + ARRAY_NELTS(osabi_arr_alt), osabi_arr_alt); + break; + default: + str = conv_map2str(inv_buf, osabi, fmt_flags, + ARRAY_NELTS(osabi_arr), osabi_arr); + } break; } @@ -341,7 +416,7 @@ conv_reject_desc(Rej_desc * rej, Conv_reject_desc_buf_t *reject_desc_buf) /* * Only called from ld.so.1, thus M_MACH is hardcoded. */ - return (conv_ehdr_flags(M_MACH, (Word)info, + return (conv_ehdr_flags(M_MACH, (Word)info, 0, &reject_desc_buf->flags_buf)); else if (type == SGS_REJ_UNKFILE) return ((const char *)0); diff --git a/usr/src/cmd/sgs/libconv/common/globals.c b/usr/src/cmd/sgs/libconv/common/globals.c index b74863e427..19a89bdd83 100644 --- a/usr/src/cmd/sgs/libconv/common/globals.c +++ b/usr/src/cmd/sgs/libconv/common/globals.c @@ -45,7 +45,8 @@ * to the string is returned. */ const char * -conv_invalid_val(Conv_inv_buf_t *inv_buf, Xword value, int fmt_flags) +conv_invalid_val(Conv_inv_buf_t *inv_buf, Xword value, + Conv_fmt_flags_t fmt_flags) { const char *fmt; @@ -151,7 +152,7 @@ cef_cp(CONV_EXPN_FIELD_ARG *arg, CONV_EXPN_FIELD_STATE *state, * case, arg->buf contains a numeric representation of the value. */ int -conv_expn_field(CONV_EXPN_FIELD_ARG *arg) +conv_expn_field(CONV_EXPN_FIELD_ARG *arg, Conv_fmt_flags_t fmt_flags) { const Val_desc *vde; CONV_EXPN_FIELD_STATE state; @@ -167,9 +168,10 @@ conv_expn_field(CONV_EXPN_FIELD_ARG *arg) state.sep_str_len = strlen(state.sep_str); /* Prefix string */ - if (!cef_cp(arg, &state, FALSE, - (arg->prefix ? arg->prefix : MSG_ORIG(MSG_GBL_OSQBRKT)))) - return (FALSE); + if ((fmt_flags & CONV_FMT_NOBKT) == 0) + if (!cef_cp(arg, &state, FALSE, + (arg->prefix ? arg->prefix : MSG_ORIG(MSG_GBL_OSQBRKT)))) + return (FALSE); /* Any strings in the lead_str array go at the head of the list */ lead_str = arg->lead_str; @@ -201,15 +203,16 @@ conv_expn_field(CONV_EXPN_FIELD_ARG *arg) if (rflags) { Conv_inv_buf_t inv_buf; - (void) conv_invalid_val(&inv_buf, rflags, 0); + (void) conv_invalid_val(&inv_buf, rflags, fmt_flags); if (!cef_cp(arg, &state, TRUE, inv_buf.buf)) return (FALSE); } /* Suffix string */ - if (!cef_cp(arg, &state, FALSE, - (arg->suffix ? arg->suffix : MSG_ORIG(MSG_GBL_CSQBRKT)))) - return (FALSE); + if ((fmt_flags & CONV_FMT_NOBKT) == 0) + if (!cef_cp(arg, &state, FALSE, + (arg->suffix ? arg->suffix : MSG_ORIG(MSG_GBL_CSQBRKT)))) + return (FALSE); /* Terminate the buffer */ *state.cur = '\0'; diff --git a/usr/src/cmd/sgs/libconv/common/group.c b/usr/src/cmd/sgs/libconv/common/group.c index 65bbd65a67..88f93fc186 100644 --- a/usr/src/cmd/sgs/libconv/common/group.c +++ b/usr/src/cmd/sgs/libconv/common/group.c @@ -75,7 +75,7 @@ conv_grphdl_flags(uint_t flags, Conv_grphdl_flags_buf_t *grphdl_flags_buf) conv_arg.buf = grphdl_flags_buf->buf; conv_arg.oflags = conv_arg.rflags = flags; - (void) conv_expn_field(&conv_arg); + (void) conv_expn_field(&conv_arg, 0); return ((const char *)grphdl_flags_buf->buf); } @@ -127,7 +127,7 @@ conv_grpdesc_flags(uint_t flags, Conv_grpdesc_flags_buf_t *grpdesc_flags_buf) conv_arg.buf = grpdesc_flags_buf->buf; conv_arg.oflags = conv_arg.rflags = flags; - (void) conv_expn_field(&conv_arg); + (void) conv_expn_field(&conv_arg, 0); return ((const char *)grpdesc_flags_buf->buf); } diff --git a/usr/src/cmd/sgs/libconv/common/llib-lconv b/usr/src/cmd/sgs/libconv/common/llib-lconv index 4473fd2a8e..404ac872dd 100644 --- a/usr/src/cmd/sgs/libconv/common/llib-lconv +++ b/usr/src/cmd/sgs/libconv/common/llib-lconv @@ -49,7 +49,7 @@ const char *conv_dl_flag(int, int, Conv_dl_flag_buf_t *); const char *conv_dl_mode(int, int, Conv_dl_mode_buf_t *); const char *conv_dwarf_ehe(uint_t, Conv_dwarf_ehe_buf_t *); const char *conv_elfdata_type(Elf_Type, Conv_inv_buf_t *); -int conv_expn_field(CONV_EXPN_FIELD_ARG *); +int conv_expn_field(CONV_EXPN_FIELD_ARG *, Conv_fmt_flags_t); const char *conv_grphdl_flags(uint_t, Conv_grphdl_flags_buf_t *); const char *conv_grpdesc_flags(uint_t, Conv_grpdesc_flags_buf_t *); Isa_desc *conv_isalist(void); @@ -74,16 +74,18 @@ const char *conv32_cap_val(Elf32_Word, Elf32_Word, Half, Conv32_cap_val_buf_t *); const char *conv64_cap_val(Elf64_Xword, Elf64_Xword, Half, Conv64_cap_val_buf_t *); -const char *conv32_cap_val_hw1(Elf32_Word, Half, +const char *conv32_cap_val_hw1(Elf32_Word, Half, Conv_fmt_flags_t, Conv32_cap_val_hw1_buf_t *); -const char *conv64_cap_val_hw1(Elf64_Xword, Half, +const char *conv64_cap_val_hw1(Elf64_Xword, Half, Conv_fmt_flags_t, Conv64_cap_val_hw1_buf_t *); -const char *conv32_cap_val_sf1(Elf32_Word, Half, +const char *conv32_cap_val_sf1(Elf32_Word, Half, Conv_fmt_flags_t, Conv32_cap_val_sf1_buf_t *); -const char *conv64_cap_val_sf1(Elf64_Xword, Half, +const char *conv64_cap_val_sf1(Elf64_Xword, Half, Conv_fmt_flags_t, Conv64_cap_val_sf1_buf_t *); -const char *conv32_dyn_flag1(Elf32_Word, Conv32_dyn_flag1_buf_t *); -const char *conv64_dyn_flag1(Elf64_Xword, Conv64_dyn_flag1_buf_t *); +const char *conv32_dyn_flag1(Elf32_Word, Conv_fmt_flags_t, + Conv32_dyn_flag1_buf_t *); +const char *conv64_dyn_flag1(Elf64_Xword, Conv_fmt_flags_t, + Conv64_dyn_flag1_buf_t *); const char *conv32_dyn_flag(Elf32_Word, int, Conv32_dyn_flag_buf_t *); const char *conv64_dyn_flag(Elf64_Xword, int, Conv64_dyn_flag_buf_t *); const char *conv32_dyn_posflag1(Elf32_Word, int, @@ -102,9 +104,9 @@ const char *conv32_ehdr_class(uchar_t, int, Conv32_inv_buf_t *); const char *conv64_ehdr_class(uchar_t, int, Conv64_inv_buf_t *); const char *conv32_ehdr_data(uchar_t, int, Conv32_inv_buf_t *); const char *conv64_ehdr_data(uchar_t, int, Conv64_inv_buf_t *); -const char *conv32_ehdr_flags(Elf32_Half, Elf32_Word, +const char *conv32_ehdr_flags(Elf32_Half, Elf32_Word, Conv_fmt_flags_t, Conv32_ehdr_flags_buf_t *); -const char *conv64_ehdr_flags(Elf64_Half, Elf64_Word, +const char *conv64_ehdr_flags(Elf64_Half, Elf64_Word, Conv_fmt_flags_t, Conv64_ehdr_flags_buf_t *); const char *conv32_ehdr_mach(Elf32_Half, int, Conv32_inv_buf_t *); const char *conv64_ehdr_mach(Elf64_Half, int, Conv64_inv_buf_t *); @@ -114,8 +116,10 @@ const char *conv32_ehdr_vers(Elf32_Word, int, Conv32_inv_buf_t *); const char *conv64_ehdr_vers(Elf64_Word, int, Conv64_inv_buf_t *); const char *conv32_invalid_val(Conv32_inv_buf_t *, Elf32_Word, int); const char *conv64_invalid_val(Conv64_inv_buf_t *, Elf64_Xword, int); -const char *conv32_phdr_flags(Word, Conv32_phdr_flags_buf_t *); -const char *conv64_phdr_flags(Word, Conv64_phdr_flags_buf_t *); +const char *conv32_phdr_flags(Word, Conv_fmt_flags_t, + Conv32_phdr_flags_buf_t *); +const char *conv64_phdr_flags(Word, Conv_fmt_flags_t, + Conv64_phdr_flags_buf_t *); const char *conv32_phdr_type(Elf32_Half, Word, int, Conv32_inv_buf_t *); const char *conv64_phdr_type(Elf64_Half, Word, int, Conv64_inv_buf_t *); const char *conv32_reject_desc(Rej_desc *, Conv32_reject_desc_buf_t *); @@ -130,8 +134,10 @@ const char *conv32_reloc_amd64_type(Word, int, Conv32_inv_buf_t *); const char *conv64_reloc_amd64_type(Word, int, Conv64_inv_buf_t *); const char *conv32_reloc_SPARC_type(Word, int, Conv32_inv_buf_t *); const char *conv64_reloc_SPARC_type(Word, int, Conv64_inv_buf_t *); -const char *conv32_sec_flags(Elf32_Word, Conv32_sec_flags_buf_t *); -const char *conv64_sec_flags(Elf64_Xword, Conv64_sec_flags_buf_t *); +const char *conv32_sec_flags(Elf32_Word, Conv_fmt_flags_t, + Conv32_sec_flags_buf_t *); +const char *conv64_sec_flags(Elf64_Xword, Conv_fmt_flags_t, + Conv64_sec_flags_buf_t *); const char *conv32_sec_linkinfo(Elf32_Word, Elf32_Word, Conv32_inv_buf_t *); const char *conv64_sec_linkinfo(Elf64_Word, Elf64_Xword, diff --git a/usr/src/cmd/sgs/libconv/common/phdr.c b/usr/src/cmd/sgs/libconv/common/phdr.c index 77bcd50395..7c9a06caf1 100644 --- a/usr/src/cmd/sgs/libconv/common/phdr.c +++ b/usr/src/cmd/sgs/libconv/common/phdr.c @@ -37,7 +37,8 @@ DEFINE_conv_map2str const char * -conv_phdr_type(Half mach, Word type, int fmt_flags, Conv_inv_buf_t *inv_buf) +conv_phdr_type(Half mach, Word type, Conv_fmt_flags_t fmt_flags, + Conv_inv_buf_t *inv_buf) { static const Msg phdrs[] = { MSG_PT_NULL, MSG_PT_LOAD, @@ -67,15 +68,33 @@ error "PT_NUM has grown. Update phdrs[]" #endif if (type < PT_NUM) { - return (conv_map2str(inv_buf, type, fmt_flags, - ARRAY_NELTS(phdrs), phdrs, phdrs_alt, phdrs_alt)); + switch (CONV_TYPE_FMT_ALT(fmt_flags)) { + case CONV_FMT_ALT_DUMP: + case CONV_FMT_ALT_FILE: + return (conv_map2str(inv_buf, type, fmt_flags, + ARRAY_NELTS(phdrs_alt), phdrs_alt)); + default: + return (conv_map2str(inv_buf, type, fmt_flags, + ARRAY_NELTS(phdrs), phdrs)); + } } else if ((type >= PT_SUNWBSS) && (type <= PT_HISUNW)) { - return (conv_map2str(inv_buf, (type - PT_SUNWBSS), fmt_flags, - ARRAY_NELTS(uphdrs), uphdrs, uphdrs_alt, uphdrs_alt)); + switch (CONV_TYPE_FMT_ALT(fmt_flags)) { + case CONV_FMT_ALT_DUMP: + case CONV_FMT_ALT_FILE: + return (conv_map2str(inv_buf, (type - PT_SUNWBSS), + fmt_flags, ARRAY_NELTS(uphdrs_alt), uphdrs_alt)); + default: + return (conv_map2str(inv_buf, (type - PT_SUNWBSS), + fmt_flags, ARRAY_NELTS(uphdrs), uphdrs)); + } } else if ((type == PT_SUNW_UNWIND) && (mach == EM_AMD64)) { - return ((fmt_flags & CONV_FMTALTMASK) ? - MSG_ORIG(MSG_PT_SUNW_UNWIND_ALT) : - MSG_ORIG(MSG_PT_SUNW_UNWIND)); + switch (CONV_TYPE_FMT_ALT(fmt_flags)) { + case CONV_FMT_ALT_DUMP: + case CONV_FMT_ALT_FILE: + return (MSG_ORIG(MSG_PT_SUNW_UNWIND_ALT)); + default: + return (MSG_ORIG(MSG_PT_SUNW_UNWIND)); + } } else return (conv_invalid_val(inv_buf, type, 0)); } @@ -101,7 +120,8 @@ error "PT_NUM has grown. Update phdrs[]" #endif const char * -conv_phdr_flags(Word flags, Conv_phdr_flags_buf_t *phdr_flags_buf) +conv_phdr_flags(Word flags, Conv_fmt_flags_t fmt_flags, + Conv_phdr_flags_buf_t *phdr_flags_buf) { static Val_desc vda[] = { { PF_X, MSG_ORIG(MSG_PF_X) }, @@ -118,7 +138,7 @@ conv_phdr_flags(Word flags, Conv_phdr_flags_buf_t *phdr_flags_buf) conv_arg.buf = phdr_flags_buf->buf; conv_arg.oflags = conv_arg.rflags = flags; - (void) conv_expn_field(&conv_arg); + (void) conv_expn_field(&conv_arg, fmt_flags); return ((const char *)phdr_flags_buf->buf); } diff --git a/usr/src/cmd/sgs/libconv/common/relocate.c b/usr/src/cmd/sgs/libconv/common/relocate.c index 7cad0bc735..048a51e494 100644 --- a/usr/src/cmd/sgs/libconv/common/relocate.c +++ b/usr/src/cmd/sgs/libconv/common/relocate.c @@ -35,7 +35,8 @@ * Generic front-end that determines machine specific relocations. */ const char * -conv_reloc_type(Half mach, Word type, int fmt_flags, Conv_inv_buf_t *inv_buf) +conv_reloc_type(Half mach, Word type, Conv_fmt_flags_t fmt_flags, + Conv_inv_buf_t *inv_buf) { switch (mach) { case EM_386: @@ -59,7 +60,7 @@ conv_reloc_type(Half mach, Word type, int fmt_flags, Conv_inv_buf_t *inv_buf) * do_reloc(). */ const char * -conv_reloc_type_static(Half mach, Word type, int fmt_flags) +conv_reloc_type_static(Half mach, Word type, Conv_fmt_flags_t fmt_flags) { static Conv_inv_buf_t inv_buf; diff --git a/usr/src/cmd/sgs/libconv/common/relocate_amd64.c b/usr/src/cmd/sgs/libconv/common/relocate_amd64.c index 598b4d58d7..f219c482a2 100644 --- a/usr/src/cmd/sgs/libconv/common/relocate_amd64.c +++ b/usr/src/cmd/sgs/libconv/common/relocate_amd64.c @@ -61,7 +61,8 @@ static const Msg rels[R_AMD64_NUM] = { #endif const char * -conv_reloc_amd64_type(Word type, int fmt_flags, Conv_inv_buf_t *inv_buf) +conv_reloc_amd64_type(Word type, Conv_fmt_flags_t fmt_flags, + Conv_inv_buf_t *inv_buf) { if (type >= R_AMD64_NUM) return (conv_invalid_val(inv_buf, type, fmt_flags)); diff --git a/usr/src/cmd/sgs/libconv/common/relocate_i386.c b/usr/src/cmd/sgs/libconv/common/relocate_i386.c index 41c1f6789c..0d81ca4712 100644 --- a/usr/src/cmd/sgs/libconv/common/relocate_i386.c +++ b/usr/src/cmd/sgs/libconv/common/relocate_i386.c @@ -64,7 +64,8 @@ static const Msg rels[R_386_NUM] = { #endif const char * -conv_reloc_386_type(Word type, int fmt_flags, Conv_inv_buf_t *inv_buf) +conv_reloc_386_type(Word type, Conv_fmt_flags_t fmt_flags, + Conv_inv_buf_t *inv_buf) { if (type >= R_386_NUM) return (conv_invalid_val(inv_buf, type, fmt_flags)); return (MSG_ORIG(rels[type])); diff --git a/usr/src/cmd/sgs/libconv/common/relocate_sparc.c b/usr/src/cmd/sgs/libconv/common/relocate_sparc.c index 2735cf2078..e158b3ae18 100644 --- a/usr/src/cmd/sgs/libconv/common/relocate_sparc.c +++ b/usr/src/cmd/sgs/libconv/common/relocate_sparc.c @@ -88,7 +88,8 @@ static const Msg rels[R_SPARC_NUM] = { #endif const char * -conv_reloc_SPARC_type(Word type, int fmt_flags, Conv_inv_buf_t *inv_buf) +conv_reloc_SPARC_type(Word type, Conv_fmt_flags_t fmt_flags, + Conv_inv_buf_t *inv_buf) { if (type >= R_SPARC_NUM) return (conv_invalid_val(inv_buf, type, fmt_flags)); diff --git a/usr/src/cmd/sgs/libconv/common/sections.c b/usr/src/cmd/sgs/libconv/common/sections.c index 6446c4efde..fa55682e1d 100644 --- a/usr/src/cmd/sgs/libconv/common/sections.c +++ b/usr/src/cmd/sgs/libconv/common/sections.c @@ -90,31 +90,49 @@ static const Msg usecs_alt[SHT_HISUNW - SHT_LOSUNW + 1] = { const char * -conv_sec_type(Half mach, Word sec, int fmt_flags, Conv_inv_buf_t *inv_buf) +conv_sec_type(Half mach, Word sec, Conv_fmt_flags_t fmt_flags, + Conv_inv_buf_t *inv_buf) { if (sec < SHT_NUM) { - return (conv_map2str(inv_buf, sec, fmt_flags, - ARRAY_NELTS(secs), secs, secs_alt, NULL)); + switch (CONV_TYPE_FMT_ALT(fmt_flags)) { + case CONV_FMT_ALT_DUMP: + return (conv_map2str(inv_buf, sec, fmt_flags, + ARRAY_NELTS(secs_alt), secs_alt)); + default: + return (conv_map2str(inv_buf, sec, fmt_flags, + ARRAY_NELTS(secs), secs)); + } } else if ((sec >= SHT_LOSUNW) && (sec <= SHT_HISUNW)) { - return (conv_map2str(inv_buf, sec - SHT_LOSUNW, - fmt_flags, ARRAY_NELTS(usecs), usecs, usecs_alt, NULL)); + switch (CONV_TYPE_FMT_ALT(fmt_flags)) { + case CONV_FMT_ALT_DUMP: + return (conv_map2str(inv_buf, sec - SHT_LOSUNW, + fmt_flags, ARRAY_NELTS(usecs_alt), usecs_alt)); + default: + return (conv_map2str(inv_buf, sec - SHT_LOSUNW, + fmt_flags, ARRAY_NELTS(usecs), usecs)); + } } else if ((sec >= SHT_LOPROC) && (sec <= SHT_HIPROC)) { switch (mach) { case EM_SPARC: case EM_SPARC32PLUS: case EM_SPARCV9: - if (sec == SHT_SPARC_GOTDATA) { - return (fmt_flags & CONV_FMT_ALTDUMP) - ? MSG_ORIG(MSG_SHT_SPARC_GOTDATA_ALT) - : MSG_ORIG(MSG_SHT_SPARC_GOTDATA); + if (sec != SHT_SPARC_GOTDATA) + break; + switch (CONV_TYPE_FMT_ALT(fmt_flags)) { + case CONV_FMT_ALT_DUMP: + case CONV_FMT_ALT_FILE: + return (MSG_ORIG(MSG_SHT_SPARC_GOTDATA_ALT)); } - break; + return (MSG_ORIG(MSG_SHT_SPARC_GOTDATA)); case EM_AMD64: - if (sec == SHT_AMD64_UNWIND) { - return (fmt_flags & CONV_FMT_ALTDUMP) - ? MSG_ORIG(MSG_SHT_AMD64_UNWIND_ALT) - : MSG_ORIG(MSG_SHT_AMD64_UNWIND); + if (sec != SHT_AMD64_UNWIND) + break; + switch (CONV_TYPE_FMT_ALT(fmt_flags)) { + case CONV_FMT_ALT_DUMP: + case CONV_FMT_ALT_FILE: + return (MSG_ORIG(MSG_SHT_AMD64_UNWIND_ALT)); } + return (MSG_ORIG(MSG_SHT_AMD64_UNWIND)); } } @@ -152,7 +170,8 @@ conv_sec_type(Half mach, Word sec, int fmt_flags, Conv_inv_buf_t *inv_buf) #endif const char * -conv_sec_flags(Xword flags, Conv_sec_flags_buf_t *sec_flags_buf) +conv_sec_flags(Xword flags, Conv_fmt_flags_t fmt_flags, + Conv_sec_flags_buf_t *sec_flags_buf) { static Val_desc vda[] = { { SHF_WRITE, MSG_ORIG(MSG_SHF_WRITE) }, @@ -178,7 +197,7 @@ conv_sec_flags(Xword flags, Conv_sec_flags_buf_t *sec_flags_buf) conv_arg.buf = sec_flags_buf->buf; conv_arg.oflags = conv_arg.rflags = flags; - (void) conv_expn_field(&conv_arg); + (void) conv_expn_field(&conv_arg, fmt_flags); return ((const char *)sec_flags_buf->buf); } @@ -193,6 +212,6 @@ conv_sec_linkinfo(Word info, Xword flags, Conv_inv_buf_t *inv_buf) return (MSG_ORIG(MSG_SHN_AFTER)); } - (void) conv_invalid_val(inv_buf, info, 1); + (void) conv_invalid_val(inv_buf, info, CONV_FMT_DECIMAL); return ((const char *)inv_buf->buf); } diff --git a/usr/src/cmd/sgs/libconv/common/segments.c b/usr/src/cmd/sgs/libconv/common/segments.c index 458aab7b00..7bff64fb90 100644 --- a/usr/src/cmd/sgs/libconv/common/segments.c +++ b/usr/src/cmd/sgs/libconv/common/segments.c @@ -89,7 +89,7 @@ conv_seg_flags(Half flags, Conv_seg_flags_buf_t *seg_flags_buf) conv_arg.buf = seg_flags_buf->buf; conv_arg.oflags = conv_arg.rflags = flags; - (void) conv_expn_field(&conv_arg); + (void) conv_expn_field(&conv_arg, 0); return ((const char *)seg_flags_buf->buf); } diff --git a/usr/src/cmd/sgs/libconv/common/symbols.c b/usr/src/cmd/sgs/libconv/common/symbols.c index 243d410c97..de72b27e35 100644 --- a/usr/src/cmd/sgs/libconv/common/symbols.c +++ b/usr/src/cmd/sgs/libconv/common/symbols.c @@ -50,7 +50,7 @@ conv_sym_other(uchar_t other, Conv_inv_buf_t *inv_buf) inv_buf->buf[ndx++] = visibility[vis]; /* - * If unkown bits are present in stother - throw out a '?' + * If unknown bits are present in st_other - throw out a '?' */ if (other & ~MSK_SYM_VISIBILITY) inv_buf->buf[ndx++] = '?'; @@ -60,36 +60,87 @@ conv_sym_other(uchar_t other, Conv_inv_buf_t *inv_buf) } const char * -conv_sym_info_type(Half mach, uchar_t type, int fmt_flags, +conv_sym_other_vis(uchar_t value, Conv_fmt_flags_t fmt_flags, + Conv_inv_buf_t *inv_buf) +{ + static const Msg vis[] = { + MSG_STV_DEFAULT, MSG_STV_INTERNAL, + MSG_STV_HIDDEN, MSG_STV_PROTECTED + }; + + static const Msg vis_alt[] = { + MSG_STV_DEFAULT_ALT, MSG_STV_INTERNAL_ALT, + MSG_STV_HIDDEN_ALT, MSG_STV_PROTECTED_ALT + }; + + if (value >= (sizeof (vis) / sizeof (vis[0]))) + return (conv_invalid_val(inv_buf, value, fmt_flags)); + + /* If full ELF names are desired, use those strings */ + if (CONV_TYPE_FMT_ALT(fmt_flags) == CONV_FMT_ALT_FULLNAME) + return (MSG_ORIG(vis_alt[value])); + + /* Default strings */ + return (MSG_ORIG(vis[value])); +} + +const char * +conv_sym_info_type(Half mach, uchar_t type, Conv_fmt_flags_t fmt_flags, Conv_inv_buf_t *inv_buf) { static const Msg types[] = { - MSG_STT_NOTYPE, MSG_STT_OBJECT, MSG_STT_FUNC, - MSG_STT_SECTION, MSG_STT_FILE, MSG_STT_COMMON, + MSG_STT_NOTYPE, MSG_STT_OBJECT, + MSG_STT_FUNC, MSG_STT_SECTION, + MSG_STT_FILE, MSG_STT_COMMON, MSG_STT_TLS }; + static const Msg types_alt[] = { + MSG_STT_NOTYPE_ALT, MSG_STT_OBJECT_ALT, + MSG_STT_FUNC_ALT, MSG_STT_SECTION_ALT, + MSG_STT_FILE_ALT, MSG_STT_COMMON_ALT, + MSG_STT_TLS_ALT + }; + if (type < STT_NUM) { + /* If full ELF names are desired, use those strings */ + if (CONV_TYPE_FMT_ALT(fmt_flags) == CONV_FMT_ALT_FULLNAME) + return (MSG_ORIG(types_alt[type])); + + /* Default strings */ return (MSG_ORIG(types[type])); } else if (((mach == EM_SPARC) || (mach == EM_SPARC32PLUS) || (mach == EM_SPARCV9)) && (type == STT_SPARC_REGISTER)) { - return (MSG_ORIG(MSG_STT_REGISTER)); + if (CONV_TYPE_FMT_ALT(fmt_flags) == CONV_FMT_ALT_FULLNAME) + return (MSG_ORIG(MSG_STT_SPARC_REGISTER_ALT)); + + return (MSG_ORIG(MSG_STT_SPARC_REGISTER)); } else { return (conv_invalid_val(inv_buf, type, fmt_flags)); } } const char * -conv_sym_info_bind(uchar_t bind, int fmt_flags, Conv_inv_buf_t *inv_buf) +conv_sym_info_bind(uchar_t bind, Conv_fmt_flags_t fmt_flags, + Conv_inv_buf_t *inv_buf) { static const Msg binds[] = { MSG_STB_LOCAL, MSG_STB_GLOBAL, MSG_STB_WEAK }; + static const Msg binds_alt[] = { + MSG_STB_LOCAL_ALT, MSG_STB_GLOBAL_ALT, MSG_STB_WEAK_ALT + }; + if (bind >= STB_NUM) return (conv_invalid_val(inv_buf, bind, fmt_flags)); - else - return (MSG_ORIG(binds[bind])); + + /* If full ELF names are desired, use those strings */ + if (CONV_TYPE_FMT_ALT(fmt_flags) == CONV_FMT_ALT_FULLNAME) + return (MSG_ORIG(binds_alt[bind])); + + /* Default strings */ + return (MSG_ORIG(binds[bind])); } const char * diff --git a/usr/src/cmd/sgs/libconv/common/symbols.msg b/usr/src/cmd/sgs/libconv/common/symbols.msg index 43f6f1c204..9abd1fb1a8 100644 --- a/usr/src/cmd/sgs/libconv/common/symbols.msg +++ b/usr/src/cmd/sgs/libconv/common/symbols.msg @@ -19,24 +19,44 @@ # CDDL HEADER END # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # -@ MSG_STT_NOTYPE "NOTY" -@ MSG_STT_OBJECT "OBJT" -@ MSG_STT_FUNC "FUNC" -@ MSG_STT_SECTION "SECT" -@ MSG_STT_FILE "FILE" -@ MSG_STT_COMMON "COMM" -@ MSG_STT_TLS "TLS " -@ MSG_STT_REGISTER "REGI" +@ MSG_STT_NOTYPE "NOTY" +@ MSG_STT_NOTYPE_ALT "STT_NOTYPE" +@ MSG_STT_OBJECT "OBJT" +@ MSG_STT_OBJECT_ALT "STT_OBJECT" +@ MSG_STT_FUNC "FUNC" +@ MSG_STT_FUNC_ALT "STT_FUNC" +@ MSG_STT_SECTION "SECT" +@ MSG_STT_SECTION_ALT "STT_SECTION" +@ MSG_STT_FILE "FILE" +@ MSG_STT_FILE_ALT "STT_FILE" +@ MSG_STT_COMMON "COMM" +@ MSG_STT_COMMON_ALT "STT_COMMON" +@ MSG_STT_TLS "TLS " +@ MSG_STT_TLS_ALT "STT_TLS" +@ MSG_STT_SPARC_REGISTER "REGI" +@ MSG_STT_SPARC_REGISTER_ALT "STT_SPARC_REGISTER" @ MSG_STB_LOCAL "LOCL" +@ MSG_STB_LOCAL_ALT "STB_LOCAL" @ MSG_STB_GLOBAL "GLOB" +@ MSG_STB_GLOBAL_ALT "STB_GLOBAL" @ MSG_STB_WEAK "WEAK" +@ MSG_STB_WEAK_ALT "STB_WEAK" + +@ MSG_STV_DEFAULT "D" +@ MSG_STV_DEFAULT_ALT "STV_DEFAULT" +@ MSG_STV_INTERNAL "I" +@ MSG_STV_INTERNAL_ALT "STV_INTERNAL" +@ MSG_STV_HIDDEN "H" +@ MSG_STV_HIDDEN_ALT "STV_HIDDEN" +@ MSG_STV_PROTECTED "P" +@ MSG_STV_PROTECTED_ALT "STV_PROTECTED" @ MSG_SHN_UNDEF "UNDEF" @ MSG_SHN_SUNW_IGNORE "IGNORE" diff --git a/usr/src/cmd/sgs/libconv/common/symbols_sparc.c b/usr/src/cmd/sgs/libconv/common/symbols_sparc.c index 5dcc8eedd1..41180d1c37 100644 --- a/usr/src/cmd/sgs/libconv/common/symbols_sparc.c +++ b/usr/src/cmd/sgs/libconv/common/symbols_sparc.c @@ -42,7 +42,8 @@ static const Msg registers[] = { 0, }; const char * -conv_sym_SPARC_value(Addr val, int fmt_flags, Conv_inv_buf_t *inv_buf) +conv_sym_SPARC_value(Addr val, Conv_fmt_flags_t fmt_flags, + Conv_inv_buf_t *inv_buf) { if ((val < STO_SPARC_REGISTER_G1) || (val > STO_SPARC_REGISTER_G7)) { return (conv_invalid_val(inv_buf, val, fmt_flags)); diff --git a/usr/src/cmd/sgs/libconv/common/syminfo.c b/usr/src/cmd/sgs/libconv/common/syminfo.c new file mode 100644 index 0000000000..4ea76c9606 --- /dev/null +++ b/usr/src/cmd/sgs/libconv/common/syminfo.c @@ -0,0 +1,85 @@ +/* + * 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" + +/* + * String conversion routines for syminfo attributes. + */ +#include <stdio.h> +#include <sys/machelf.h> +#include "_conv.h" +#include "syminfo_msg.h" + + + +#define FLAGSZ CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \ + MSG_SYMINFO_FLG_DIRECT_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \ + MSG_SYMINFO_FLG_COPY_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \ + MSG_SYMINFO_FLG_LAZYLOAD_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \ + MSG_SYMINFO_FLG_DIRECTBIND_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \ + CONV_INV_BUFSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE + +/* + * Ensure that Conv_syminfo_flags_buf_t is large enough: + * + * FLAGSZ is the real minimum size of the buffer required by + * conv_syminfo_flags(). However, Conv_syminfo_flags_buf_t uses + * CONV_SYMINFO_FLAGS_BUFSIZE to set the buffer size. We do things + * this way because the definition of FLAGSZ uses information that + * is not available in the environment of other programs that include + * the conv.h header file. + */ +#if CONV_SYMINFO_FLAGS_BUFSIZE < FLAGSZ +#error "CONV_SYMINFO_FLAGS_BUFSIZE is not large enough" +#endif + +const char * +conv_syminfo_flags(Xword flags, Conv_fmt_flags_t fmt_flags, + Conv_syminfo_flags_buf_t *syminfo_flags_buf) +{ + static Val_desc vda[] = { + { SYMINFO_FLG_DIRECT, MSG_ORIG(MSG_SYMINFO_FLG_DIRECT) }, + { SYMINFO_FLG_COPY, MSG_ORIG(MSG_SYMINFO_FLG_COPY) }, + { SYMINFO_FLG_LAZYLOAD, MSG_ORIG(MSG_SYMINFO_FLG_LAZYLOAD) }, + { SYMINFO_FLG_DIRECTBIND, + MSG_ORIG(MSG_SYMINFO_FLG_DIRECTBIND) }, + { SYMINFO_FLG_NOEXTDIRECT, + MSG_ORIG(MSG_SYMINFO_FLG_NOEXTDIRECT) }, + { 0, 0 } + }; + static CONV_EXPN_FIELD_ARG conv_arg = { + NULL, sizeof (syminfo_flags_buf->buf), vda }; + + if (flags == 0) + return (MSG_ORIG(MSG_GBL_ZERO)); + + conv_arg.buf = syminfo_flags_buf->buf; + conv_arg.oflags = conv_arg.rflags = flags; + conv_arg.prefix = conv_arg.suffix = NULL; + (void) conv_expn_field(&conv_arg, fmt_flags); + + return ((const char *)syminfo_flags_buf->buf); +} diff --git a/usr/src/cmd/sgs/libconv/common/syminfo.msg b/usr/src/cmd/sgs/libconv/common/syminfo.msg new file mode 100644 index 0000000000..b5ccd09db4 --- /dev/null +++ b/usr/src/cmd/sgs/libconv/common/syminfo.msg @@ -0,0 +1,34 @@ +# +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# + +@ MSG_SYMINFO_FLG_DIRECT "DIRECT" +@ MSG_SYMINFO_FLG_COPY "COPY" +@ MSG_SYMINFO_FLG_LAZYLOAD "LAZYLOAD" +@ MSG_SYMINFO_FLG_DIRECTBIND "DIRECTBIND" +@ MSG_SYMINFO_FLG_NOEXTDIRECT "NOEXTDIRECT" + +@ MSG_GBL_ZERO "0" diff --git a/usr/src/cmd/sgs/libelf/common/checksum.c b/usr/src/cmd/sgs/libelf/common/checksum.c index 7ea7684f51..2bb2d8041f 100644 --- a/usr/src/cmd/sgs/libelf/common/checksum.c +++ b/usr/src/cmd/sgs/libelf/common/checksum.c @@ -94,8 +94,12 @@ elf32_checksum(Elf * elf) * stream to be processed from different architectures - presently this * is irrelevant, as the checksum simply sums the data bytes, their * order doesn't matter. But being uncooked is slightly less overhead. + * + * If the file is writable, the raw data will not reflect any + * changes made in the process, so the uncooked version is only + * for readonly files. */ - if (elf->ed_myflags & EDF_MEMORY) + if ((elf->ed_myflags & (EDF_MEMORY | EDF_WRITE)) != 0) getdata = elf_getdata; else getdata = elf_rawdata; diff --git a/usr/src/cmd/sgs/liblddbg/common/bindings.c b/usr/src/cmd/sgs/liblddbg/common/bindings.c index b7210f6a98..71ae008f9e 100644 --- a/usr/src/cmd/sgs/liblddbg/common/bindings.c +++ b/usr/src/cmd/sgs/liblddbg/common/bindings.c @@ -119,7 +119,7 @@ Dbg_bind_global(Rt_map *flmp, Addr fabs, Off foff, Xword pltndx, binfo &= DBG_BINFO_MSK; if (binfo) { conv_arg.oflags = conv_arg.rflags = binfo; - (void) conv_expn_field(&conv_arg); + (void) conv_expn_field(&conv_arg, 0); } else { binfostr[0] = '\0'; } diff --git a/usr/src/cmd/sgs/liblddbg/common/cap.c b/usr/src/cmd/sgs/liblddbg/common/cap.c index 3930b74d5e..6659c302cc 100644 --- a/usr/src/cmd/sgs/liblddbg/common/cap.c +++ b/usr/src/cmd/sgs/liblddbg/common/cap.c @@ -60,7 +60,7 @@ Dbg_cap_val_hw1(Lm_list *lml, Xword val, Half mach) Dbg_util_nl(lml, DBG_NL_FRC); dbg_print(lml, MSG_INTL(MSG_CAP_VAL_HW1), - conv_cap_val_hw1(val, mach, &cap_val_hw1_buf)); + conv_cap_val_hw1(val, mach, 0, &cap_val_hw1_buf)); Dbg_util_nl(lml, DBG_NL_FRC); } diff --git a/usr/src/cmd/sgs/liblddbg/common/elf.c b/usr/src/cmd/sgs/liblddbg/common/elf.c index 7ff7af9f19..083a7ea80f 100644 --- a/usr/src/cmd/sgs/liblddbg/common/elf.c +++ b/usr/src/cmd/sgs/liblddbg/common/elf.c @@ -61,7 +61,7 @@ Elf_ehdr(Lm_list *lml, Ehdr *ehdr, Shdr *shdr0) * numeric (e.g. "0x200") or text representation (e.g. * "[ EF_SPARC_SUN_US1 ]"). */ - flgs = conv_ehdr_flags(ehdr->e_machine, ehdr->e_flags, &flags_buf); + flgs = conv_ehdr_flags(ehdr->e_machine, ehdr->e_flags, 0, &flags_buf); if (flgs[0] == '[') dbg_print(lml, MSG_ORIG(MSG_ELF_FLAGS_FMT), flgs); else @@ -104,7 +104,7 @@ Elf_ehdr(Lm_list *lml, Ehdr *ehdr, Shdr *shdr0) dbg_print(lml, MSG_ORIG(MSG_STR_EMPTY)); dbg_print(lml, MSG_ORIG(MSG_SHD0_TITLE)); dbg_print(lml, MSG_ORIG(MSG_SHD0_ADDR), EC_ADDR(shdr0->sh_addr), - conv_sec_flags(shdr0->sh_flags, &sec_flags_buf)); + conv_sec_flags(shdr0->sh_flags, 0, &sec_flags_buf)); dbg_print(lml, MSG_ORIG(MSG_SHD0_SIZE), EC_XWORD(shdr0->sh_size), conv_sec_type(ehdr->e_machine, shdr0->sh_type, 0, &inv_buf1)); dbg_print(lml, MSG_ORIG(MSG_SHD0_OFFSET), EC_OFF(shdr0->sh_offset), diff --git a/usr/src/cmd/sgs/liblddbg/common/entry.c b/usr/src/cmd/sgs/liblddbg/common/entry.c index 6fdecca74f..8e21a10c3d 100644 --- a/usr/src/cmd/sgs/liblddbg/common/entry.c +++ b/usr/src/cmd/sgs/liblddbg/common/entry.c @@ -42,12 +42,12 @@ Dbg_ent_entry(Lm_list *lml, Half mach, Ent_desc *enp) dbg_print(lml, MSG_ORIG(MSG_ECR_NAME), (enp->ec_name ? enp->ec_name : MSG_INTL(MSG_STR_NULL)), - conv_sec_flags(enp->ec_attrmask, &sec_flags_buf)); + conv_sec_flags(enp->ec_attrmask, 0, &sec_flags_buf)); dbg_print(lml, MSG_ORIG(MSG_ECR_SEGMENT), (enp->ec_segment->sg_name ? enp->ec_segment->sg_name : MSG_INTL(MSG_STR_NULL)), - conv_sec_flags(enp->ec_attrbits, &sec_flags_buf)); + conv_sec_flags(enp->ec_attrbits, 0, &sec_flags_buf)); dbg_print(lml, MSG_ORIG(MSG_ECR_NDX), EC_WORD(enp->ec_ndx), conv_sec_type(mach, enp->ec_type, 0, &inv_buf)); diff --git a/usr/src/cmd/sgs/liblddbg/common/phdr.c b/usr/src/cmd/sgs/liblddbg/common/phdr.c index dd04b4b7f0..f1587cc86c 100644 --- a/usr/src/cmd/sgs/liblddbg/common/phdr.c +++ b/usr/src/cmd/sgs/liblddbg/common/phdr.c @@ -37,7 +37,7 @@ Elf_phdr(Lm_list *lml, Half mach, Phdr *phdr) Conv_phdr_flags_buf_t phdr_flags_buf; dbg_print(lml, MSG_ORIG(MSG_PHD_VADDR), EC_ADDR(phdr->p_vaddr), - conv_phdr_flags(phdr->p_flags, &phdr_flags_buf)); + conv_phdr_flags(phdr->p_flags, 0, &phdr_flags_buf)); dbg_print(lml, MSG_ORIG(MSG_PHD_PADDR), EC_ADDR(phdr->p_paddr), conv_phdr_type(mach, phdr->p_type, 0, &inv_buf)); dbg_print(lml, MSG_ORIG(MSG_PHD_FILESZ), EC_XWORD(phdr->p_filesz), diff --git a/usr/src/cmd/sgs/liblddbg/common/shdr.c b/usr/src/cmd/sgs/liblddbg/common/shdr.c index c366c91ca5..9b73d08c70 100644 --- a/usr/src/cmd/sgs/liblddbg/common/shdr.c +++ b/usr/src/cmd/sgs/liblddbg/common/shdr.c @@ -37,7 +37,7 @@ Elf_shdr(Lm_list *lml, Half mach, Shdr *shdr) Conv_sec_flags_buf_t sec_flags_buf; dbg_print(lml, MSG_ORIG(MSG_SHD_ADDR), EC_ADDR(shdr->sh_addr), - conv_sec_flags(shdr->sh_flags, &sec_flags_buf)); + conv_sec_flags(shdr->sh_flags, 0, &sec_flags_buf)); dbg_print(lml, MSG_ORIG(MSG_SHD_SIZE), EC_XWORD(shdr->sh_size), conv_sec_type(mach, shdr->sh_type, 0, &inv_buf1)); if (shdr->sh_entsize == 0) { diff --git a/usr/src/cmd/sgs/liblddbg/common/tls.c b/usr/src/cmd/sgs/liblddbg/common/tls.c index d9074c543e..3df8c6e5fc 100644 --- a/usr/src/cmd/sgs/liblddbg/common/tls.c +++ b/usr/src/cmd/sgs/liblddbg/common/tls.c @@ -53,7 +53,7 @@ Dbg_tls_modent(Lm_list *lml, TLS_modinfo * tmodent) if ((flags = tmodent->tm_flags) != 0) { conv_arg.oflags = conv_arg.rflags = flags; - (void) conv_expn_field(&conv_arg); + (void) conv_expn_field(&conv_arg, 0); } else { flagstr[0] = '\0'; } diff --git a/usr/src/cmd/sgs/messages/Makefile.com b/usr/src/cmd/sgs/messages/Makefile.com index 3a3f837525..c709739a1d 100644 --- a/usr/src/cmd/sgs/messages/Makefile.com +++ b/usr/src/cmd/sgs/messages/Makefile.com @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# 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. @@ -22,7 +21,7 @@ # # ident "%Z%%M% %I% %E% SMI" # -# Copyright 2000,2003 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # cmd/sgs/messages/Makefile.com @@ -46,8 +45,14 @@ MSGFMT= msgfmt POFILES= ld ldd libld liblddbg \ libldstab librtld rtld libelf \ - ldprof libcrle crle pvs \ - elfdump lari + ldprof libcrle crle moe \ + pvs elfdump elfedit lari + +# These message files are generated as a side effect of generating the +# elfedit messages. Otherwise they are the same thing as POFILES +POFILES_ELFEDIT_MODULES = \ + elfedit_cap elfedit_dyn elfedit_ehdr elfedit_phdr \ + elfedit_shdr elfedit_sym elfedit_syminfo lari # Define a local version of the message catalog. Test using: LANG=piglatin @@ -61,4 +66,4 @@ TEST_MOFILE= $(TEXT_DOMAIN).mo CLEANFILES= $(POFILE) $(TEST_MSGID) $(TEST_MSGSTR) $(TEST_POFILE) \ $(TEST_MOFILE) -CLOBBERFILES= $(POFILES) +CLOBBERFILES= $(POFILES) $(POFILES_ELFEDIT_MODULES) diff --git a/usr/src/cmd/sgs/messages/Makefile.targ b/usr/src/cmd/sgs/messages/Makefile.targ index 980b43ca41..72cfa7d045 100644 --- a/usr/src/cmd/sgs/messages/Makefile.targ +++ b/usr/src/cmd/sgs/messages/Makefile.targ @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# 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. @@ -22,8 +21,8 @@ # #ident "%Z%%M% %I% %E% SMI" # -# Copyright (c) 2000 by Sun Microsystems, Inc. -# All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. # # cmd/sgs/messages/Makefile.targ @@ -44,9 +43,15 @@ delete lint: clean: $(RM) $(CLEANFILES) -$(POFILE): $(POFILES) +# The elfedit modules message files need a special rule that runs +# the elfedit catalog target. It generates module messages files +# as part of that process. +$(POFILES_ELFEDIT_MODULES) : + @ cd ../../elfedit; pwd; $(MAKE) catalog + +$(POFILE): $(POFILES) $(POFILES_ELFEDIT_MODULES) $(RM) $(POFILE) - cat $(POFILES) > $(POFILE) + cat $(POFILES) $(POFILES_ELFEDIT_MODULES) > $(POFILE) # Install a local version of the message catalog. Test using: LANG=piglatin @@ -61,12 +66,13 @@ $(MSGDIR)/$(TEST_MOFILE): \ $(MSGFMT) -o $(MSGDIR)/$(TEST_MOFILE) $(TEST_POFILE) $(TEST_MSGID): $(POFILE) - grep "^msgid" $(POFILE) | nl -v1 -i2 > $(TEST_MSGID) + grep "^msgid" $(POFILE) | \ + $(SGSMSG_PIGLATIN_NL) 1 > $(TEST_MSGID) $(TEST_MSGSTR): $(POFILE) cat $(POFILE) | $(SGSTOOLS)/$(MACH)/piglatin | \ grep "^sgidmay" | sed -e "s/^sgidmay/msgstr/" | \ - nl -v2 -i2 > $(TEST_MSGSTR) + $(SGSMSG_PIGLATIN_NL) 2 > $(TEST_MSGSTR) $(MSGDIR): -@mkdir -p $(MSGDIR) diff --git a/usr/src/cmd/sgs/messages/sgs.ident b/usr/src/cmd/sgs/messages/sgs.ident index 2b7a23580a..f7cbf4bd9c 100644 --- a/usr/src/cmd/sgs/messages/sgs.ident +++ b/usr/src/cmd/sgs/messages/sgs.ident @@ -50,4 +50,12 @@ MSG_ID_PVS 22 SUNW_OST_SGS /* sgs/pvs */ MSG_ID_CRLE 23 SUNW_OST_SGS /* sgs/crle */ MSG_ID_ELFDUMP 24 SUNW_OST_SGS /* sgs/elfdump */ MSG_ID_MOE 25 SUNW_OST_SGS /* sgs/moe */ -MSG_ID_MISC 26 SUNW_OST_SGS + +MSG_ID_ELFEDIT 26 SUNW_OST_SGS /* sgs/elfedit */ +MSG_ID_ELFEDIT_CAP 27 SUNW_OST_SGS /* cap: */ +MSG_ID_ELFEDIT_DYN 27 SUNW_OST_SGS /* dyn: */ +MSG_ID_ELFEDIT_EHDR 27 SUNW_OST_SGS /* ehdr: */ +MSG_ID_ELFEDIT_PHDR 27 SUNW_OST_SGS /* phdr: */ +MSG_ID_ELFEDIT_SHDR 27 SUNW_OST_SGS /* shdr: */ +MSG_ID_ELFEDIT_SYM 27 SUNW_OST_SGS /* sym: */ +MSG_ID_ELFEDIT_SYMINFO 27 SUNW_OST_SGS /* syminfo: */ diff --git a/usr/src/cmd/sgs/packages/Makefile b/usr/src/cmd/sgs/packages/Makefile index 2535ca42ae..9a1ade7112 100644 --- a/usr/src/cmd/sgs/packages/Makefile +++ b/usr/src/cmd/sgs/packages/Makefile @@ -29,10 +29,6 @@ include $(SRC)/Makefile.master include $(SRC)/cmd/sgs/Makefile.var -EXTBUILD:sh= if [ ! -h ../ext -a ! -d ../ext ]; \ - then /bin/sh setup_pkg_ext .. ; \ - fi - BUILDLOG= package_build.$(MACH).log MACHS:sh= if [ "$MACH" = "sparc" ]; \ @@ -70,10 +66,6 @@ SUBDIRS2 = ../rtld \ $(RDBDIRS) -PKGDIRS_EXT:sh= if [ -f ../ext/packages/pkgdirs ]; \ - then cat ../ext/packages/pkgdirs; \ - fi - # # Package dirs are directories which specifically # have a 'package' target. This target is used to key @@ -83,6 +75,8 @@ PKGDIRS_EXT:sh= if [ -f ../ext/packages/pkgdirs ]; \ PKGDIRS= ../libcrle \ ../libld \ ../elfdump \ + ../elfedit \ + ../elfedit/modules \ ../crle \ ../dump \ ../lari \ @@ -92,7 +86,7 @@ PKGDIRS= ../libcrle \ ../nm \ ../mcs \ ../moe \ - ../pvs $(PKGDIRS_EXT) + ../pvs $(SUBDIRS1) $(SUBDIRS2) := TARGET = install $(PKGDIRS) := TARGET = package diff --git a/usr/src/cmd/sgs/packages/Makefile.com b/usr/src/cmd/sgs/packages/Makefile.com index ea5dcc85d0..748d1618c5 100644 --- a/usr/src/cmd/sgs/packages/Makefile.com +++ b/usr/src/cmd/sgs/packages/Makefile.com @@ -32,10 +32,8 @@ LINTLOG= ../lint.$(MACH).log PKGARCHIVE= . DATAFILES= copyright prototype_com prototype_$(MACH) postinstall \ preremove depend checkinstall -DATAFILES_EXT= prototype_com_ext_usr_bin prototype_com_ext_usr_lib \ - prototype_$(MACH)_ext_usr_bin prototype_$(MACH)_ext_usr_lib README= SUNWonld-README -FILES= $(DATAFILES) $(DATAFILES_EXT) pkginfo +FILES= $(DATAFILES) pkginfo PACKAGE= SUNWonld ROOTONLD= $(ROOT)/opt/SUNWonld ROOTREADME= $(README:%=$(ROOTONLD)/%) diff --git a/usr/src/cmd/sgs/packages/Makefile.lint b/usr/src/cmd/sgs/packages/Makefile.lint index 3929a0869b..de72fe8103 100644 --- a/usr/src/cmd/sgs/packages/Makefile.lint +++ b/usr/src/cmd/sgs/packages/Makefile.lint @@ -55,13 +55,11 @@ LSUBDIRS2 = ../rtld \ ../libldmake \ ../rtld/mdbmod -LINTLDIRS_EXT:sh= if [ -f ../ext/packages/lintldirs ]; \ - then cat ../ext/packages/lintldirs; \ - fi - LINTLDIRS= ../libld \ ../sgsdemangler \ ../elfdump \ + ../elfedit \ + ../elfedit/modules \ ../crle \ ../dump \ ../ld \ @@ -69,7 +67,7 @@ LINTLDIRS= ../libld \ ../nm \ ../mcs \ ../moe \ - ../pvs $(LINTLDIRS_EXT) + ../pvs $(LSUBDIRS1) $(LSUBDIRS2) := TARGET = lint $(LINTLDIRS) := TARGET = lint diff --git a/usr/src/cmd/sgs/packages/Makefile.targ b/usr/src/cmd/sgs/packages/Makefile.targ index 2248669f66..3a81b4edc7 100644 --- a/usr/src/cmd/sgs/packages/Makefile.targ +++ b/usr/src/cmd/sgs/packages/Makefile.targ @@ -38,9 +38,6 @@ pkg: FRC $(DATAFILES): ../common/$$@ $(RM) $@; cp ../common/$@ $@ -$(DATAFILES_EXT): ../../ext/packages/common/$$@ - $(RM) $@; cp ../../ext/packages/common/$@ $@ - awk_pkginfo: ../bld_awk_pkginfo ../common/$(README) ../bld_awk_pkginfo -R ../common/$(README) $(VERDEBUG) \ -m $(MACH) -r "$(RELEASE)" -o $@ diff --git a/usr/src/cmd/sgs/packages/common/SUNWonld-README b/usr/src/cmd/sgs/packages/common/SUNWonld-README index cc8b3ab545..25ca0584f2 100644 --- a/usr/src/cmd/sgs/packages/common/SUNWonld-README +++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README @@ -1259,3 +1259,5 @@ Bugid Risk Synopsis 6602294 ps_pbrandname breaks apps linked directly against librtld_db (link-editor components only) 6603313 dlclose() can fail to unload objects after fix for 6573641 +6234471 need a way to edit ELF objects + PSARC/2007/509 elfedit diff --git a/usr/src/cmd/sgs/packages/common/prototype_com b/usr/src/cmd/sgs/packages/common/prototype_com index 50cef0c8c6..8554628d55 100644 --- a/usr/src/cmd/sgs/packages/common/prototype_com +++ b/usr/src/cmd/sgs/packages/common/prototype_com @@ -63,7 +63,6 @@ s none $SGSDIR/lib/librtld_db.so=librtld_db.so.1 f none $SGSDIR/lib/librtld_db.so.1=lib/librtld_db.so.1 755 root bin d none $SGSDIR/usr/bin 755 root bin f none $SGSDIR/usr/bin/crle=usr/bin/crle 555 root bin -!include prototype_com_ext_usr_bin f none $SGSDIR/usr/bin/ldd=usr/bin/ldd 555 root bin f none $SGSDIR/usr/bin/moe=usr/bin/moe 555 root bin f none $SGSDIR/usr/bin/pvs=usr/bin/pvs 555 root bin @@ -75,6 +74,7 @@ f none $SGSDIR/usr/bin/dump=usr/bin/dump 0555 root bin s none $SGSDIR/usr/ccs/bin/dump=../../bin/dump f none $SGSDIR/usr/bin/elfdump=usr/bin/elfdump 0555 root bin s none $SGSDIR/usr/ccs/bin/elfdump=../../bin/elfdump +f none $SGSDIR/usr/bin/elfedit=usr/bin/elfedit 0555 root bin f none $SGSDIR/usr/bin/lari=usr/bin/lari 0555 root bin s none $SGSDIR/usr/ccs/bin/lari=../../bin/lari f none $SGSDIR/usr/bin/ld=usr/bin/ld 755 root bin @@ -106,7 +106,15 @@ f none $SGSDIR/usr/lib/0@0.so.1=usr/lib/0@0.so.1 755 root bin f none $SGSDIR/usr/lib/lddstub=usr/lib/lddstub 555 root bin f none $SGSDIR/usr/lib/libcrle.so.1=usr/lib/libcrle.so.1 755 root bin f none $SGSDIR/usr/lib/libldstab.so.1=usr/lib/libldstab.so.1 755 root bin -!include prototype_com_ext_usr_lib +d none $SGSDIR/usr/lib/elfedit 755 root bin +s none $SGSDIR/usr/lib/elfedit/32=. +f none $SGSDIR/usr/lib/elfedit/cap.so=usr/lib/elfedit/cap.so 755 root bin +f none $SGSDIR/usr/lib/elfedit/dyn.so=usr/lib/elfedit/dyn.so 755 root bin +f none $SGSDIR/usr/lib/elfedit/ehdr.so=usr/lib/elfedit/ehdr.so 755 root bin +f none $SGSDIR/usr/lib/elfedit/phdr.so=usr/lib/elfedit/phdr.so 755 root bin +f none $SGSDIR/usr/lib/elfedit/shdr.so=usr/lib/elfedit/shdr.so 755 root bin +f none $SGSDIR/usr/lib/elfedit/sym.so=usr/lib/elfedit/sym.so 755 root bin +f none $SGSDIR/usr/lib/elfedit/syminfo.so=usr/lib/elfedit/syminfo.so 755 root bin d none $SGSDIR/usr/lib/link_audit 755 root bin s none $SGSDIR/usr/lib/link_audit/32=. f none $SGSDIR/usr/lib/link_audit/ldprof.so.1=usr/lib/link_audit/ldprof.so.1 755 root bin diff --git a/usr/src/cmd/sgs/packages/common/prototype_i386 b/usr/src/cmd/sgs/packages/common/prototype_i386 index 99ad8d802d..95d0aabf58 100644 --- a/usr/src/cmd/sgs/packages/common/prototype_i386 +++ b/usr/src/cmd/sgs/packages/common/prototype_i386 @@ -51,7 +51,6 @@ f none $SGSDIR/lib/amd64/librtld_db.so.1=lib/amd64/librtld_db.so.1 755 root bin s none $SGSDIR/lib/amd64/librtld_db.so=librtld_db.so.1 d none $SGSDIR/usr/bin/amd64 755 root bin f none $SGSDIR/usr/bin/amd64/crle=usr/bin/amd64/crle 555 root bin -!include prototype_i386_ext_usr_bin f none $SGSDIR/usr/bin/amd64/moe=usr/bin/amd64/moe 555 root bin f none $SGSDIR/usr/bin/amd64/pvs=usr/bin/amd64/pvs 555 root bin d none $SGSDIR/usr/ccs/bin/amd64 755 root bin @@ -59,6 +58,7 @@ f none $SGSDIR/usr/bin/amd64/dump=usr/bin/amd64/dump 0555 root bin s none $SGSDIR/usr/ccs/bin/amd64/dump=../../../bin/amd64/dump f none $SGSDIR/usr/bin/amd64/elfdump=usr/bin/amd64/elfdump 0555 root bin s none $SGSDIR/usr/ccs/bin/amd64/elfdump=../../../bin/amd64/elfdump +f none $SGSDIR/usr/bin/amd64/elfedit=usr/bin/amd64/elfedit 0555 root bin f none $SGSDIR/usr/bin/amd64/ld=usr/bin/amd64/ld 755 root bin s none $SGSDIR/usr/ccs/bin/amd64/ld=../../../bin/amd64/ld f none $SGSDIR/usr/bin/amd64/nm=usr/bin/amd64/nm 0555 root bin @@ -67,7 +67,15 @@ f none $SGSDIR/usr/bin/amd64/mcs=usr/bin/amd64/mcs 0555 root bin s none $SGSDIR/usr/ccs/bin/amd64/mcs=../../../bin/amd64/mcs l none $SGSDIR/usr/bin/amd64/strip=./mcs s none $SGSDIR/usr/ccs/bin/amd64/strip=../../../bin/amd64/strip -!include prototype_i386_ext_usr_lib +d none $SGSDIR/usr/lib/elfedit/amd64 755 root bin +s none $SGSDIR/usr/lib/elfedit/64=amd64 +f none $SGSDIR/usr/lib/elfedit/amd64/cap.so=usr/lib/elfedit/amd64/cap.so 755 root bin +f none $SGSDIR/usr/lib/elfedit/amd64/dyn.so=usr/lib/elfedit/amd64/dyn.so 755 root bin +f none $SGSDIR/usr/lib/elfedit/amd64/ehdr.so=usr/lib/elfedit/amd64/ehdr.so 755 root bin +f none $SGSDIR/usr/lib/elfedit/amd64/phdr.so=usr/lib/elfedit/amd64/phdr.so 755 root bin +f none $SGSDIR/usr/lib/elfedit/amd64/shdr.so=usr/lib/elfedit/amd64/shdr.so 755 root bin +f none $SGSDIR/usr/lib/elfedit/amd64/sym.so=usr/lib/elfedit/amd64/sym.so 755 root bin +f none $SGSDIR/usr/lib/elfedit/amd64/syminfo.so=usr/lib/elfedit/amd64/syminfo.so 755 root bin d none $SGSDIR/usr/lib/link_audit/amd64 755 root bin s none $SGSDIR/usr/lib/link_audit/64=amd64 f none $SGSDIR/usr/lib/link_audit/amd64/ldprof.so.1=usr/lib/link_audit/amd64/ldprof.so.1 755 root bin diff --git a/usr/src/cmd/sgs/packages/common/prototype_sparc b/usr/src/cmd/sgs/packages/common/prototype_sparc index d93bc1381f..9dbba99f42 100644 --- a/usr/src/cmd/sgs/packages/common/prototype_sparc +++ b/usr/src/cmd/sgs/packages/common/prototype_sparc @@ -51,7 +51,6 @@ f none $SGSDIR/lib/sparcv9/librtld_db.so.1=lib/sparcv9/librtld_db.so.1 755 root s none $SGSDIR/lib/sparcv9/librtld_db.so=librtld_db.so.1 d none $SGSDIR/usr/bin/sparcv9 755 root bin f none $SGSDIR/usr/bin/sparcv9/crle=usr/bin/sparcv9/crle 555 root bin -!include prototype_sparc_ext_usr_bin f none $SGSDIR/usr/bin/sparcv9/moe=usr/bin/sparcv9/moe 555 root bin f none $SGSDIR/usr/bin/sparcv9/pvs=usr/bin/sparcv9/pvs 555 root bin d none $SGSDIR/usr/ccs/bin/sparcv9 755 root bin @@ -59,6 +58,7 @@ f none $SGSDIR/usr/bin/sparcv9/dump=usr/bin/sparcv9/dump 0555 root bin s none $SGSDIR/usr/ccs/bin/sparcv9/dump=../../../bin/sparcv9/dump f none $SGSDIR/usr/bin/sparcv9/elfdump=usr/bin/sparcv9/elfdump 0555 root bin s none $SGSDIR/usr/ccs/bin/sparcv9/elfdump=../../../bin/sparcv9/elfdump +f none $SGSDIR/usr/bin/sparcv9/elfedit=usr/bin/sparcv9/elfedit 0555 root bin f none $SGSDIR/usr/bin/sparcv9/ld=usr/bin/sparcv9/ld 755 root bin s none $SGSDIR/usr/ccs/bin/sparcv9/ld=../../../bin/sparcv9/ld f none $SGSDIR/usr/bin/sparcv9/nm=usr/bin/sparcv9/nm 0555 root bin @@ -68,7 +68,15 @@ s none $SGSDIR/usr/ccs/bin/sparcv9/mcs=../../../bin/sparcv9/mcs 0555 root bin l none $SGSDIR/usr/bin/sparcv9/strip=./mcs s none $SGSDIR/usr/ccs/bin/sparcv9/strip=../../../bin/sparcv9/strip f none $SGSDIR/usr/lib/ld.so=usr/lib/ld.so 755 root bin -!include prototype_sparc_ext_usr_lib +d none $SGSDIR/usr/lib/elfedit/sparcv9 755 root bin +s none $SGSDIR/usr/lib/elfedit/64=sparcv9 +f none $SGSDIR/usr/lib/elfedit/sparcv9/cap.so=usr/lib/elfedit/sparcv9/cap.so 755 root bin +f none $SGSDIR/usr/lib/elfedit/sparcv9/dyn.so=usr/lib/elfedit/sparcv9/dyn.so 755 root bin +f none $SGSDIR/usr/lib/elfedit/sparcv9/ehdr.so=usr/lib/elfedit/sparcv9/ehdr.so 755 root bin +f none $SGSDIR/usr/lib/elfedit/sparcv9/phdr.so=usr/lib/elfedit/sparcv9/phdr.so 755 root bin +f none $SGSDIR/usr/lib/elfedit/sparcv9/shdr.so=usr/lib/elfedit/sparcv9/shdr.so 755 root bin +f none $SGSDIR/usr/lib/elfedit/sparcv9/sym.so=usr/lib/elfedit/sparcv9/sym.so 755 root bin +f none $SGSDIR/usr/lib/elfedit/sparcv9/syminfo.so=usr/lib/elfedit/sparcv9/syminfo.so 755 root bin d none $SGSDIR/usr/lib/link_audit/sparcv9 755 root bin s none $SGSDIR/usr/lib/link_audit/64=sparcv9 f none $SGSDIR/usr/lib/link_audit/sparcv9/ldprof.so.1=usr/lib/link_audit/sparcv9/ldprof.so.1 755 root bin diff --git a/usr/src/cmd/sgs/rtld/common/cap.c b/usr/src/cmd/sgs/rtld/common/cap.c index fa549c4f25..5329fec2b0 100644 --- a/usr/src/cmd/sgs/rtld/common/cap.c +++ b/usr/src/cmd/sgs/rtld/common/cap.c @@ -96,7 +96,8 @@ hwcap_check(Rej_desc *rej, Ehdr *ehdr) static Conv_cap_val_hw1_buf_t cap_buf; rej->rej_type = SGS_REJ_HWCAP_1; - rej->rej_str = conv_cap_val_hw1(val, M_MACH, &cap_buf); + rej->rej_str = + conv_cap_val_hw1(val, M_MACH, 0, &cap_buf); return (0); } diff --git a/usr/src/cmd/sgs/rtld/common/setup.c b/usr/src/cmd/sgs/rtld/common/setup.c index fb99646f57..b373e3aa99 100644 --- a/usr/src/cmd/sgs/rtld/common/setup.c +++ b/usr/src/cmd/sgs/rtld/common/setup.c @@ -708,7 +708,8 @@ setup(char **envp, auxv_t *auxv, Word _flags, char *_platform, int _syspagsz, Conv_cap_val_hw1_buf_t cap_val_hw1_buf; const char *str = - conv_cap_val_hw1(mhwcap, M_MACH, &cap_val_hw1_buf); + conv_cap_val_hw1(mhwcap, M_MACH, 0, + &cap_val_hw1_buf); if (lml_main.lm_flags & LML_FLG_TRC_ENABLE) { (void) printf(MSG_INTL(MSG_LDD_GEN_HWCAP_1), diff --git a/usr/src/cmd/sgs/rtld/mdbmod/common/rtld.c b/usr/src/cmd/sgs/rtld/mdbmod/common/rtld.c index 8fcebd1e8c..056929df2b 100644 --- a/usr/src/cmd/sgs/rtld/mdbmod/common/rtld.c +++ b/usr/src/cmd/sgs/rtld/mdbmod/common/rtld.c @@ -1462,7 +1462,8 @@ dcmd_ElfEhdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) * received a numeric (e.g. "0x200") or text representation * (e.g. "[ EF_SPARC_SUN_US1 ]"). */ - flgs = conv_ehdr_flags(ehdr.e_machine, ehdr.e_flags, &ehdr_flags_buf); + flgs = conv_ehdr_flags(ehdr.e_machine, ehdr.e_flags, + 0, &ehdr_flags_buf); if (flgs[0] == '[') mdb_printf(MSG_ORIG(MSG_EHDR_LINE5), flgs); else @@ -1505,7 +1506,7 @@ dcmd_ElfPhdr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) mdb_printf(MSG_ORIG(MSG_EPHDR_TITLE), addr); mdb_printf(MSG_ORIG(MSG_EPHDR_LINE1), phdr.p_vaddr, - conv_phdr_flags(phdr.p_flags, &phdr_flags_buf)); + conv_phdr_flags(phdr.p_flags, 0, &phdr_flags_buf)); mdb_printf(MSG_ORIG(MSG_EPHDR_LINE2), phdr.p_paddr, conv_phdr_type(M_MACH, phdr.p_type, 0, &inv_buf)); mdb_printf(MSG_ORIG(MSG_EPHDR_LINE3), phdr.p_filesz, phdr.p_memsz); diff --git a/usr/src/cmd/sgs/tools/common/piglatin.c b/usr/src/cmd/sgs/tools/common/piglatin.c index f29d38daef..db656eb587 100644 --- a/usr/src/cmd/sgs/tools/common/piglatin.c +++ b/usr/src/cmd/sgs/tools/common/piglatin.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * 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. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2000, 2002 Sun Microsystems, Inc. + * Copyright 2007 Sun Microsystems, Inc. * All rights reserved. * Use is subject to license terms. * @@ -43,7 +42,7 @@ int main() { - char buffer[200], * cb, * sb; + char buffer[32767], * cb, * sb; int ic, ignore = 0, word = 0; sb = cb = &buffer[0]; diff --git a/usr/src/cmd/sgs/tools/common/sgsmsg_piglatin_nl.pl b/usr/src/cmd/sgs/tools/common/sgsmsg_piglatin_nl.pl new file mode 100644 index 0000000000..7aabedb25f --- /dev/null +++ b/usr/src/cmd/sgs/tools/common/sgsmsg_piglatin_nl.pl @@ -0,0 +1,77 @@ +#!/usr/bin/perl + +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# 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 +# +#ident "%Z%%M% %I% %E% SMI" + + +# +# Replacement for /usr/bin/nl in the sgs/messages piglatin tests. +# +# usage: sgsmsg_piglatin_nl start_index +# +# where start_index is the staring number +# +# +# The sgs/messages test target used to use /usr/bin/nl as part +# of the process of adding a piglatin translation to the file. +# The invocations looked like: +# +# nl -v1 -i2 +# or +# nl -v2 -i2 +# +# This adds line numbers to the beginning of each non-empty line +# from stdin, counting by 2, and starting at either 1 or 2, depending +# on whether the master file, or the piglatin file is being processed. +# +# The output format is "%6d\t%s". Empty lines are replaced with +# 7 space characters in the output, and the line number is not +# incremented. +# +# The problem with nl is that it has a 2K buffer for input lines, +# and our catalog files can have some very long lines, thanks to +# the elfedit module help strings. This perl script emulates nl +# to the extent required to replace it in the sgs piglatin tests, +# while not breaking lines longer than 2K characters. + +use warnings; +use strict; + +use vars qw($script $lineno); + +$script = 'sgsmsg_piglatin_nl'; + +die "usage: $script start_index\n" if ($ARGV[0] eq ''); +$lineno = int($ARGV[0]); + + +while (<STDIN>) { + if (($_ ne "") && ($_ ne "\n")) { + printf ("%6d\t%s", $lineno, $_); + $lineno += 2; + } else { + print " \n"; + } +} diff --git a/usr/src/pkgdefs/SUNWbtool/Makefile b/usr/src/pkgdefs/SUNWbtool/Makefile index f248e7bccb..0977075a6d 100644 --- a/usr/src/pkgdefs/SUNWbtool/Makefile +++ b/usr/src/pkgdefs/SUNWbtool/Makefile @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# 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. @@ -22,13 +21,12 @@ # #ident "%Z%%M% %I% %E% SMI" # -# Copyright (c) 1993 by Sun Microsystems, Inc. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. # include ../Makefile.com -DATAFILES += depend - .KEEP_STATE: all: $(FILES) diff --git a/usr/src/pkgdefs/SUNWbtool/depend b/usr/src/pkgdefs/SUNWbtool/depend new file mode 100644 index 0000000000..b757622d62 --- /dev/null +++ b/usr/src/pkgdefs/SUNWbtool/depend @@ -0,0 +1,52 @@ +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# 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 +# +# ident ident "%Z%%M% %I% %E% SMI" +# +# This package information file defines software dependencies associated +# with the pkg. You can define three types of pkg dependencies with this file: +# P indicates a prerequisite for installation +# I indicates an incompatible package +# R indicates a reverse dependency +# <pkg.abbr> see pkginfo(4), PKG parameter +# <name> see pkginfo(4), NAME parameter +# <version> see pkginfo(4), VERSION parameter +# <arch> see pkginfo(4), ARCH parameter +# <type> <pkg.abbr> <name> +# (<arch>)<version> +# (<arch>)<version> +# ... +# <type> <pkg.abbr> <name> +# ... +# + +P SUNWcar Core Architecture, (Root) +P SUNWcakr Core Solaris Kernel Architecture (Root) +P SUNWkvm Core Architecture, (Kvm) +P SUNWcsr Core Solaris, (Root) +P SUNWckr Core Solaris Kernel (Root) +P SUNWcnetr Core Solaris Network Infrastructure (Root) +P SUNWcsu Core Solaris, (Usr) +P SUNWcsd Core Solaris Devices +P SUNWcsl Core Solaris Libraries +P SUNWtecla Tecla command-line editing library diff --git a/usr/src/pkgdefs/SUNWbtool/pkginfo.tmpl b/usr/src/pkgdefs/SUNWbtool/pkginfo.tmpl index 8691af1292..3deaa39c6b 100644 --- a/usr/src/pkgdefs/SUNWbtool/pkginfo.tmpl +++ b/usr/src/pkgdefs/SUNWbtool/pkginfo.tmpl @@ -20,7 +20,7 @@ # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -36,7 +36,7 @@ BASEDIR=/ SUNW_PKGVERS="1.0" CATEGORY="system" CLASSES="none" -DESC="software development utilities, including ar, dis, dump, elfdump, lex, lorder, mcs, nm, prof, ranlib, rpcgen, size, strip, tsort, and yacc" +DESC="software development utilities, including ar, dis, dump, elfdump, elfedit, lex, lorder, mcs, nm, prof, ranlib, rpcgen, size, strip, tsort, and yacc" EMAIL="" HOTLINE="Please contact your local service provider" MAXINST="1000" diff --git a/usr/src/pkgdefs/SUNWbtool/prototype_com b/usr/src/pkgdefs/SUNWbtool/prototype_com index 7150ba1fde..4d1d742c77 100644 --- a/usr/src/pkgdefs/SUNWbtool/prototype_com +++ b/usr/src/pkgdefs/SUNWbtool/prototype_com @@ -55,6 +55,7 @@ f none usr/bin/dump 0555 root bin s none usr/ccs/bin/dump=../../bin/dump f none usr/bin/elfdump 0555 root bin s none usr/ccs/bin/elfdump=../../bin/elfdump +f none usr/bin/elfedit 0555 root bin f none usr/bin/error 0555 root bin s none usr/ccs/bin/error=../../bin/error f none usr/bin/gprof 0555 root bin @@ -102,3 +103,12 @@ s none usr/ccs/lib/llib-ll.ln=../../lib/llib-ll.ln f none usr/lib/llib-ly 0644 root bin f none usr/lib/llib-ly.ln 0644 root bin s none usr/ccs/lib/llib-ly.ln=../../lib/llib-ly.ln +d none usr/lib/elfedit 755 root bin +s none usr/lib/elfedit/32=. +f none usr/lib/elfedit/cap.so 755 root bin +f none usr/lib/elfedit/dyn.so 755 root bin +f none usr/lib/elfedit/ehdr.so 755 root bin +f none usr/lib/elfedit/phdr.so 755 root bin +f none usr/lib/elfedit/shdr.so 755 root bin +f none usr/lib/elfedit/sym.so 755 root bin +f none usr/lib/elfedit/syminfo.so 755 root bin diff --git a/usr/src/pkgdefs/SUNWbtool/prototype_i386 b/usr/src/pkgdefs/SUNWbtool/prototype_i386 index 0302a317a7..f8493c5bb4 100644 --- a/usr/src/pkgdefs/SUNWbtool/prototype_i386 +++ b/usr/src/pkgdefs/SUNWbtool/prototype_i386 @@ -54,6 +54,7 @@ f none usr/bin/amd64/dump 0555 root bin s none usr/ccs/bin/amd64/dump=../../../bin/amd64/dump f none usr/bin/amd64/elfdump 0555 root bin s none usr/ccs/bin/amd64/elfdump=../../../bin/amd64/elfdump +f none usr/bin/amd64/elfedit 0555 root bin f none usr/bin/amd64/mcs 0555 root bin s none usr/ccs/bin/amd64/mcs=../../../bin/amd64/mcs f none usr/bin/amd64/nm 0555 root bin @@ -65,3 +66,12 @@ s none usr/ccs/bin/amd64/strip=../../../bin/amd64/strip d none usr/lib/amd64 0755 root bin f none usr/lib/amd64/llib-ll.ln 0644 root bin f none usr/lib/amd64/llib-ly.ln 0644 root bin +d none usr/lib/elfedit/amd64 755 root bin +s none usr/lib/elfedit/64=amd64 +f none usr/lib/elfedit/amd64/cap.so 755 root bin +f none usr/lib/elfedit/amd64/dyn.so 755 root bin +f none usr/lib/elfedit/amd64/ehdr.so 755 root bin +f none usr/lib/elfedit/amd64/phdr.so 755 root bin +f none usr/lib/elfedit/amd64/shdr.so 755 root bin +f none usr/lib/elfedit/amd64/sym.so 755 root bin +f none usr/lib/elfedit/amd64/syminfo.so 755 root bin diff --git a/usr/src/pkgdefs/SUNWbtool/prototype_sparc b/usr/src/pkgdefs/SUNWbtool/prototype_sparc index 0075746059..85f90a2669 100644 --- a/usr/src/pkgdefs/SUNWbtool/prototype_sparc +++ b/usr/src/pkgdefs/SUNWbtool/prototype_sparc @@ -54,6 +54,7 @@ f none usr/bin/sparcv9/dump 0555 root bin s none usr/ccs/bin/sparcv9/dump=../../../bin/sparcv9/dump f none usr/bin/sparcv9/elfdump 0555 root bin s none usr/ccs/bin/sparcv9/elfdump=../../../bin/sparcv9/elfdump +f none usr/bin/sparcv9/elfedit 0555 root bin f none usr/bin/sparcv9/mcs 0555 root bin s none usr/ccs/bin/sparcv9/mcs=../../../bin/sparcv9/mcs f none usr/bin/sparcv9/nm 0555 root bin @@ -65,3 +66,12 @@ s none usr/ccs/bin/sparcv9/strip=../../../bin/sparcv9/strip d none usr/lib/sparcv9 0755 root bin f none usr/lib/sparcv9/llib-ll.ln 0644 root bin f none usr/lib/sparcv9/llib-ly.ln 0644 root bin +d none usr/lib/elfedit/sparcv9 755 root bin +s none usr/lib/elfedit/64=sparcv9 +f none usr/lib/elfedit/sparcv9/cap.so 755 root bin +f none usr/lib/elfedit/sparcv9/dyn.so 755 root bin +f none usr/lib/elfedit/sparcv9/ehdr.so 755 root bin +f none usr/lib/elfedit/sparcv9/phdr.so 755 root bin +f none usr/lib/elfedit/sparcv9/shdr.so 755 root bin +f none usr/lib/elfedit/sparcv9/sym.so 755 root bin +f none usr/lib/elfedit/sparcv9/syminfo.so 755 root bin |