summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorab196087 <none@none>2007-09-19 08:15:57 -0700
committerab196087 <none@none>2007-09-19 08:15:57 -0700
commitd29b2c4438482eb00488be49a1f5d6835f455546 (patch)
tree541f5471fe500cce2429019f17f9f87ddcf80b76
parent90685d2c52744c6540828f16cdd2db815d467e37 (diff)
downloadillumos-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
-rw-r--r--deleted_files/usr/src/cmd/sgs/packages/setup_pkg_ext (renamed from usr/src/cmd/sgs/packages/setup_pkg_ext)0
-rw-r--r--usr/src/Targetdirs6
-rw-r--r--usr/src/cmd/sgs/Makefile4
-rw-r--r--usr/src/cmd/sgs/Makefile.com5
-rw-r--r--usr/src/cmd/sgs/Makefile.var6
-rw-r--r--usr/src/cmd/sgs/crle/common/print.c23
-rw-r--r--usr/src/cmd/sgs/dump/common/dump.c4
-rw-r--r--usr/src/cmd/sgs/elfdump/common/elfdump.c4
-rw-r--r--usr/src/cmd/sgs/elfedit/Makefile30
-rw-r--r--usr/src/cmd/sgs/elfedit/Makefile.com74
-rw-r--r--usr/src/cmd/sgs/elfedit/Makefile.targ77
-rw-r--r--usr/src/cmd/sgs/elfedit/amd64/Makefile46
-rw-r--r--usr/src/cmd/sgs/elfedit/common/_elfedit.h263
-rw-r--r--usr/src/cmd/sgs/elfedit/common/elfconst.c1542
-rw-r--r--usr/src/cmd/sgs/elfedit/common/elfedit.c3600
-rw-r--r--usr/src/cmd/sgs/elfedit/common/elfedit.msg1548
-rw-r--r--usr/src/cmd/sgs/elfedit/common/elfedit_machelf.c453
-rw-r--r--usr/src/cmd/sgs/elfedit/common/lintsup.c122
-rw-r--r--usr/src/cmd/sgs/elfedit/common/mapfile-vers185
-rw-r--r--usr/src/cmd/sgs/elfedit/common/sys.c1042
-rw-r--r--usr/src/cmd/sgs/elfedit/common/util.c914
-rw-r--r--usr/src/cmd/sgs/elfedit/common/util_machelf.c1149
-rw-r--r--usr/src/cmd/sgs/elfedit/i386/Makefile35
-rw-r--r--usr/src/cmd/sgs/elfedit/modules/Makefile54
-rw-r--r--usr/src/cmd/sgs/elfedit/modules/Makefile.com117
-rw-r--r--usr/src/cmd/sgs/elfedit/modules/Makefile.targ145
-rw-r--r--usr/src/cmd/sgs/elfedit/modules/amd64/Makefile56
-rw-r--r--usr/src/cmd/sgs/elfedit/modules/common/cap.c1021
-rw-r--r--usr/src/cmd/sgs/elfedit/modules/common/cap.msg251
-rw-r--r--usr/src/cmd/sgs/elfedit/modules/common/dyn.c1821
-rw-r--r--usr/src/cmd/sgs/elfedit/modules/common/dyn.msg431
-rw-r--r--usr/src/cmd/sgs/elfedit/modules/common/ehdr.c2233
-rw-r--r--usr/src/cmd/sgs/elfedit/modules/common/ehdr.msg650
-rw-r--r--usr/src/cmd/sgs/elfedit/modules/common/mapfile-vers191
-rw-r--r--usr/src/cmd/sgs/elfedit/modules/common/phdr.c1386
-rw-r--r--usr/src/cmd/sgs/elfedit/modules/common/phdr.msg381
-rw-r--r--usr/src/cmd/sgs/elfedit/modules/common/shdr.c1207
-rw-r--r--usr/src/cmd/sgs/elfedit/modules/common/shdr.msg381
-rw-r--r--usr/src/cmd/sgs/elfedit/modules/common/sym.c2031
-rw-r--r--usr/src/cmd/sgs/elfedit/modules/common/sym.msg413
-rw-r--r--usr/src/cmd/sgs/elfedit/modules/common/syminfo.c882
-rw-r--r--usr/src/cmd/sgs/elfedit/modules/common/syminfo.msg192
-rw-r--r--usr/src/cmd/sgs/elfedit/modules/i386/Makefile43
-rw-r--r--usr/src/cmd/sgs/elfedit/modules/sparc/Makefile43
-rw-r--r--usr/src/cmd/sgs/elfedit/modules/sparcv9/Makefile53
-rw-r--r--usr/src/cmd/sgs/elfedit/sparc/Makefile35
-rw-r--r--usr/src/cmd/sgs/elfedit/sparcv9/Makefile46
-rw-r--r--usr/src/cmd/sgs/include/conv.h222
-rw-r--r--usr/src/cmd/sgs/include/elfedit.h1065
-rw-r--r--usr/src/cmd/sgs/libconv/Makefile.com8
-rw-r--r--usr/src/cmd/sgs/libconv/common/_conv.h39
-rw-r--r--usr/src/cmd/sgs/libconv/common/cap.c40
-rw-r--r--usr/src/cmd/sgs/libconv/common/config.c4
-rw-r--r--usr/src/cmd/sgs/libconv/common/dl.c9
-rw-r--r--usr/src/cmd/sgs/libconv/common/dynamic.c42
-rw-r--r--usr/src/cmd/sgs/libconv/common/elf.c125
-rw-r--r--usr/src/cmd/sgs/libconv/common/globals.c21
-rw-r--r--usr/src/cmd/sgs/libconv/common/group.c4
-rw-r--r--usr/src/cmd/sgs/libconv/common/llib-lconv32
-rw-r--r--usr/src/cmd/sgs/libconv/common/phdr.c40
-rw-r--r--usr/src/cmd/sgs/libconv/common/relocate.c5
-rw-r--r--usr/src/cmd/sgs/libconv/common/relocate_amd64.c3
-rw-r--r--usr/src/cmd/sgs/libconv/common/relocate_i386.c3
-rw-r--r--usr/src/cmd/sgs/libconv/common/relocate_sparc.c3
-rw-r--r--usr/src/cmd/sgs/libconv/common/sections.c53
-rw-r--r--usr/src/cmd/sgs/libconv/common/segments.c2
-rw-r--r--usr/src/cmd/sgs/libconv/common/symbols.c67
-rw-r--r--usr/src/cmd/sgs/libconv/common/symbols.msg38
-rw-r--r--usr/src/cmd/sgs/libconv/common/symbols_sparc.c3
-rw-r--r--usr/src/cmd/sgs/libconv/common/syminfo.c85
-rw-r--r--usr/src/cmd/sgs/libconv/common/syminfo.msg34
-rw-r--r--usr/src/cmd/sgs/libelf/common/checksum.c6
-rw-r--r--usr/src/cmd/sgs/liblddbg/common/bindings.c2
-rw-r--r--usr/src/cmd/sgs/liblddbg/common/cap.c2
-rw-r--r--usr/src/cmd/sgs/liblddbg/common/elf.c4
-rw-r--r--usr/src/cmd/sgs/liblddbg/common/entry.c4
-rw-r--r--usr/src/cmd/sgs/liblddbg/common/phdr.c2
-rw-r--r--usr/src/cmd/sgs/liblddbg/common/shdr.c2
-rw-r--r--usr/src/cmd/sgs/liblddbg/common/tls.c2
-rw-r--r--usr/src/cmd/sgs/messages/Makefile.com19
-rw-r--r--usr/src/cmd/sgs/messages/Makefile.targ24
-rw-r--r--usr/src/cmd/sgs/messages/sgs.ident10
-rw-r--r--usr/src/cmd/sgs/packages/Makefile12
-rw-r--r--usr/src/cmd/sgs/packages/Makefile.com4
-rw-r--r--usr/src/cmd/sgs/packages/Makefile.lint8
-rw-r--r--usr/src/cmd/sgs/packages/Makefile.targ3
-rw-r--r--usr/src/cmd/sgs/packages/common/SUNWonld-README2
-rw-r--r--usr/src/cmd/sgs/packages/common/prototype_com12
-rw-r--r--usr/src/cmd/sgs/packages/common/prototype_i38612
-rw-r--r--usr/src/cmd/sgs/packages/common/prototype_sparc12
-rw-r--r--usr/src/cmd/sgs/rtld/common/cap.c3
-rw-r--r--usr/src/cmd/sgs/rtld/common/setup.c3
-rw-r--r--usr/src/cmd/sgs/rtld/mdbmod/common/rtld.c5
-rw-r--r--usr/src/cmd/sgs/tools/common/piglatin.c9
-rw-r--r--usr/src/cmd/sgs/tools/common/sgsmsg_piglatin_nl.pl77
-rw-r--r--usr/src/pkgdefs/SUNWbtool/Makefile10
-rw-r--r--usr/src/pkgdefs/SUNWbtool/depend52
-rw-r--r--usr/src/pkgdefs/SUNWbtool/pkginfo.tmpl4
-rw-r--r--usr/src/pkgdefs/SUNWbtool/prototype_com10
-rw-r--r--usr/src/pkgdefs/SUNWbtool/prototype_i38610
-rw-r--r--usr/src/pkgdefs/SUNWbtool/prototype_sparc10
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