summaryrefslogtreecommitdiff
path: root/usr/src/cmd/sgs
diff options
context:
space:
mode:
authorAli Bahrami <Ali.Bahrami@Sun.COM>2010-02-22 09:19:31 -0700
committerAli Bahrami <Ali.Bahrami@Sun.COM>2010-02-22 09:19:31 -0700
commit69112edd987c28fa551d4f8d9362a84a45365f17 (patch)
tree26319d6d073c90c67126a3b5f0d86a55c8952ced /usr/src/cmd/sgs
parentbb664d7ba7a656b21763d44dfc2da581c11444af (diff)
downloadillumos-joyent-69112edd987c28fa551d4f8d9362a84a45365f17.tar.gz
6916788 ld version 2 mapfile syntax
PSARC/2009/688 Human readable and extensible ld mapfile syntax
Diffstat (limited to 'usr/src/cmd/sgs')
-rw-r--r--usr/src/cmd/sgs/Makefile.com10
-rw-r--r--usr/src/cmd/sgs/elfdump/Makefile.com4
-rw-r--r--usr/src/cmd/sgs/elfedit/Makefile.com4
-rw-r--r--usr/src/cmd/sgs/elfedit/common/elfedit.c93
-rw-r--r--usr/src/cmd/sgs/elfwrap/Makefile.com6
-rw-r--r--usr/src/cmd/sgs/gprof/Makefile.com6
-rw-r--r--usr/src/cmd/sgs/include/conv.h26
-rw-r--r--usr/src/cmd/sgs/include/debug.h118
-rw-r--r--usr/src/cmd/sgs/include/elfedit.h4
-rw-r--r--usr/src/cmd/sgs/include/i386/machdep_x86.h6
-rw-r--r--usr/src/cmd/sgs/include/libld.h259
-rw-r--r--usr/src/cmd/sgs/include/sgs.h10
-rw-r--r--usr/src/cmd/sgs/include/sparc/machdep_sparc.h10
-rw-r--r--usr/src/cmd/sgs/lari/lari.pl12
-rw-r--r--usr/src/cmd/sgs/ldd/common/ldd.c7
-rw-r--r--usr/src/cmd/sgs/ldprof/Makefile.com4
-rw-r--r--usr/src/cmd/sgs/libconv/Makefile.com22
-rw-r--r--usr/src/cmd/sgs/libconv/common/c_literal.c84
-rw-r--r--usr/src/cmd/sgs/libconv/common/cap.c9
-rw-r--r--usr/src/cmd/sgs/libconv/common/cap.msg4
-rw-r--r--usr/src/cmd/sgs/libconv/common/entry.c140
-rw-r--r--usr/src/cmd/sgs/libconv/common/entry.msg36
-rw-r--r--usr/src/cmd/sgs/libconv/common/lintsup.c6
-rw-r--r--usr/src/cmd/sgs/libconv/common/llib-lconv6
-rw-r--r--usr/src/cmd/sgs/libconv/common/map.c52
-rw-r--r--usr/src/cmd/sgs/libconv/common/map.msg29
-rw-r--r--usr/src/cmd/sgs/libconv/common/segments.c32
-rw-r--r--usr/src/cmd/sgs/libconv/common/segments.msg17
-rw-r--r--usr/src/cmd/sgs/libld/Makefile.com24
-rw-r--r--usr/src/cmd/sgs/libld/common/_libld.h62
-rw-r--r--usr/src/cmd/sgs/libld/common/_map.h367
-rw-r--r--usr/src/cmd/sgs/libld/common/args.c46
-rw-r--r--usr/src/cmd/sgs/libld/common/debug.c8
-rw-r--r--usr/src/cmd/sgs/libld/common/entry.c425
-rw-r--r--usr/src/cmd/sgs/libld/common/files.c94
-rw-r--r--usr/src/cmd/sgs/libld/common/ldentry.c22
-rw-r--r--usr/src/cmd/sgs/libld/common/ldmain.c6
-rw-r--r--usr/src/cmd/sgs/libld/common/libld.intel.msg6
-rw-r--r--usr/src/cmd/sgs/libld/common/libld.msg454
-rw-r--r--usr/src/cmd/sgs/libld/common/libld.sparc.msg17
-rw-r--r--usr/src/cmd/sgs/libld/common/machrel.amd.c3
-rw-r--r--usr/src/cmd/sgs/libld/common/machrel.intel.c3
-rw-r--r--usr/src/cmd/sgs/libld/common/machrel.sparc.c3
-rw-r--r--usr/src/cmd/sgs/libld/common/map.c2724
-rw-r--r--usr/src/cmd/sgs/libld/common/map_core.c2838
-rw-r--r--usr/src/cmd/sgs/libld/common/map_support.c1488
-rw-r--r--usr/src/cmd/sgs/libld/common/map_v2.c3183
-rw-r--r--usr/src/cmd/sgs/libld/common/order.c18
-rw-r--r--usr/src/cmd/sgs/libld/common/outfile.c18
-rw-r--r--usr/src/cmd/sgs/libld/common/place.c299
-rw-r--r--usr/src/cmd/sgs/libld/common/sections.c113
-rw-r--r--usr/src/cmd/sgs/libld/common/syms.c6
-rw-r--r--usr/src/cmd/sgs/libld/common/unwind.c4
-rw-r--r--usr/src/cmd/sgs/libld/common/update.c38
-rw-r--r--usr/src/cmd/sgs/liblddbg/common/cap.c67
-rw-r--r--usr/src/cmd/sgs/liblddbg/common/debug.c41
-rw-r--r--usr/src/cmd/sgs/liblddbg/common/entry.c41
-rw-r--r--usr/src/cmd/sgs/liblddbg/common/liblddbg.msg128
-rw-r--r--usr/src/cmd/sgs/liblddbg/common/llib-llddbg88
-rw-r--r--usr/src/cmd/sgs/liblddbg/common/map.c216
-rw-r--r--usr/src/cmd/sgs/liblddbg/common/mapfile-vers46
-rw-r--r--usr/src/cmd/sgs/liblddbg/common/sections.c22
-rw-r--r--usr/src/cmd/sgs/liblddbg/common/segments.c70
-rw-r--r--usr/src/cmd/sgs/libldstab/Makefile.com4
-rw-r--r--usr/src/cmd/sgs/nm/amd64/Makefile4
-rw-r--r--usr/src/cmd/sgs/nm/i386/Makefile6
-rw-r--r--usr/src/cmd/sgs/nm/sparc/Makefile6
-rw-r--r--usr/src/cmd/sgs/nm/sparcv9/Makefile4
-rw-r--r--usr/src/cmd/sgs/packages/common/SUNWonld-README2
-rw-r--r--usr/src/cmd/sgs/prof/Makefile.com6
-rw-r--r--usr/src/cmd/sgs/rtld/common/debug.c8
-rw-r--r--usr/src/cmd/sgs/rtld/common/object.c9
-rw-r--r--usr/src/cmd/sgs/rtld/common/rtld.msg4
73 files changed, 11043 insertions, 3014 deletions
diff --git a/usr/src/cmd/sgs/Makefile.com b/usr/src/cmd/sgs/Makefile.com
index e628e6eee7..568a1a70ca 100644
--- a/usr/src/cmd/sgs/Makefile.com
+++ b/usr/src/cmd/sgs/Makefile.com
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
@@ -50,10 +50,15 @@ C99_DISABLE = $(C99_ENABLE)
CFLAGS += $(CCVERBOSE) $(DEBUG) $(XFFLAG)
CFLAGS64 += $(CCVERBOSE) $(DEBUG) $(XFFLAG)
+#
+# Location of the shared elfcap code
+#
+ELFCAP= $(SRC)/common/elfcap
+
# Reassign CPPFLAGS so that local search paths are used before any parent
# $ROOT paths.
CPPFLAGS = -I. -I../common -I../../include -I../../include/$(MACH) \
- $(VAR_CPPFLAGS) $(CPPFLAGS.master)
+ $(VAR_CPPFLAGS) $(CPPFLAGS.master) -I$(ELFCAP)
# PICS64 is unique to our environment
$(PICS64) := sparc_CFLAGS += -xregs=no%appl -K pic
@@ -91,6 +96,7 @@ ELFLIBDIR64 = -L$(SGSHOME)/libelf/$(MACH64)
LDDBGLIBDIR = -L$(SGSHOME)/liblddbg/$(MACH)
LDDBGLIBDIR64 = -L$(SGSHOME)/liblddbg/$(MACH64)
+
# The cmd/Makefile.com and lib/Makefile.com define TEXT_DOMAIN. We don't need
# this definition as the sgs utilities obtain their domain via sgsmsg(1l).
diff --git a/usr/src/cmd/sgs/elfdump/Makefile.com b/usr/src/cmd/sgs/elfdump/Makefile.com
index 19c8c82ba5..c76aae3c61 100644
--- a/usr/src/cmd/sgs/elfdump/Makefile.com
+++ b/usr/src/cmd/sgs/elfdump/Makefile.com
@@ -20,7 +20,7 @@
#
#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
@@ -49,7 +49,7 @@ MAPOPT= $(MAPFILE:%=-M%)
CPPFLAGS= -I. -I../common -I../../include -I../../include/$(MACH) \
-I$(SRCBASE)/lib/libc/inc -I$(SRCBASE)/uts/$(ARCH)/sys \
- $(CPPFLAGS.master)
+ $(CPPFLAGS.master) -I$(ELFCAP)
LLDFLAGS = $(VAR_ELFDUMP_LLDFLAGS)
LLDFLAGS64 = $(VAR_LD_LLDFLAGS64)
LDFLAGS += $(VERSREF) $(USE_PROTO) $(MAPOPT) $(LLDFLAGS)
diff --git a/usr/src/cmd/sgs/elfedit/Makefile.com b/usr/src/cmd/sgs/elfedit/Makefile.com
index 5321b97146..ce17e88b2d 100644
--- a/usr/src/cmd/sgs/elfedit/Makefile.com
+++ b/usr/src/cmd/sgs/elfedit/Makefile.com
@@ -20,7 +20,7 @@
#
#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
@@ -43,7 +43,7 @@ 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)
+ $(CPPFLAGS.master) -I$(ELFCAP)
LLDFLAGS = $(VAR_ELFEDIT_LLDFLAGS)
LLDFLAGS64 = $(VAR_ELFEDIT_LLDFLAGS64)
LDFLAGS += $(VERSREF) $(USE_PROTO) -M$(MAPFILE) $(LLDFLAGS)
diff --git a/usr/src/cmd/sgs/elfedit/common/elfedit.c b/usr/src/cmd/sgs/elfedit/common/elfedit.c
index 3879d65446..2018d93bdd 100644
--- a/usr/src/cmd/sgs/elfedit/common/elfedit.c
+++ b/usr/src/cmd/sgs/elfedit/common/elfedit.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -2224,90 +2224,6 @@ dispatch_user_cmds()
/*
- * Given the pointer to the character following a '\' character in
- * a C style literal, return the ASCII character code it represents,
- * and advance the string pointer to the character following the last
- * character in the escape sequence.
- *
- * entry:
- * str - Address of string pointer to first character following
- * the backslash.
- *
- * exit:
- * If the character is not valid, an error is thrown and this routine
- * does not return to its caller. Otherwise, it returns the ASCII
- * code for the translated character, and *str has been advanced.
- */
-static int
-translate_c_esc(char **str)
-{
- char *s = *str;
- int ch;
- int i;
-
- ch = *s++;
- switch (ch) {
- case 'a':
- ch = '\a';
- break;
- case 'b':
- ch = '\b';
- break;
- case 'f':
- ch = '\f';
- break;
- case 'n':
- ch = '\n';
- break;
- case 'r':
- ch = '\r';
- break;
- case 't':
- ch = '\t';
- break;
- case 'v':
- ch = '\v';
- break;
-
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- /* Octal constant: There can be up to 3 digits */
- ch -= '0';
- for (i = 0; i < 2; i++) {
- if ((*s < '0') || (*s > '7'))
- break;
- ch = (ch << 3) + (*s++ - '0');
- }
- break;
-
- /*
- * There are some cases where ch already has the desired value.
- * These cases exist simply to remove the special meaning that
- * character would otherwise have. We need to match them to
- * prevent them from falling into the default error case.
- */
- case '\\':
- case '\'':
- case '"':
- break;
-
- default:
- elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADCESC), ch);
- break;
- }
-
- *str = s;
- return (ch);
-}
-
-
-/*
* Prepare a GETTOK_STATE struct for gettok().
*
* entry:
@@ -2430,7 +2346,12 @@ gettok(GETTOK_STATE *gettok_state)
}
if (quote_ch == '"') {
- *str++ = translate_c_esc(&look);
+ int ch = conv_translate_c_esc(&look);
+
+ if (ch == -1)
+ elfedit_msg(ELFEDIT_MSG_ERR,
+ MSG_INTL(MSG_ERR_BADCESC), *look);
+ *str++ = ch;
look--; /* for() will advance by 1 */
continue;
}
diff --git a/usr/src/cmd/sgs/elfwrap/Makefile.com b/usr/src/cmd/sgs/elfwrap/Makefile.com
index 40b2e1e933..17322c7523 100644
--- a/usr/src/cmd/sgs/elfwrap/Makefile.com
+++ b/usr/src/cmd/sgs/elfwrap/Makefile.com
@@ -20,11 +20,9 @@
#
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
PROG= elfwrap
@@ -50,7 +48,7 @@ OBJS= $(BLTOBJ) $(COMOBJ) $(MACHOBJ) $(COMOBJ32) $(COMOBJ64) \
MAPFILES = $(MAPFILE.NGB)
MAPOPTS = $(MAPFILES:%=-M%)
-CPPFLAGS = -I. -I../common -I../../include $(CPPFLAGS.master)
+CPPFLAGS = -I. -I../common -I../../include $(CPPFLAGS.master) -I$(ELFCAP)
LLDFLAGS =
LLDFLAGS64 =
LDFLAGS += $(VERSREF) $(USE_PROTO) $(MAPOPTS) $(LLDFLAGS)
diff --git a/usr/src/cmd/sgs/gprof/Makefile.com b/usr/src/cmd/sgs/gprof/Makefile.com
index 812f2c8dc7..bb7f707877 100644
--- a/usr/src/cmd/sgs/gprof/Makefile.com
+++ b/usr/src/cmd/sgs/gprof/Makefile.com
@@ -19,9 +19,7 @@
# CDDL HEADER END
#
#
-# ident "%Z%%M% %I% %E% SMI"
-#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# cmd/sgs/gprof/Makefile.com
@@ -41,7 +39,7 @@ SRCS= $(COMOBJS:%.o=../common/%.c)
INCLIST= -I../common -I../../include -I../../include/$(MACH)
DEFLIST= -DELF_OBJ -DELF
-CPPFLAGS= $(INCLIST) $(DEFLIST) $(CPPFLAGS.master)
+CPPFLAGS= $(INCLIST) $(DEFLIST) $(CPPFLAGS.master) -I$(ELFCAP)
CFLAGS += $(CCVERBOSE)
C99MODE= $(C99_ENABLE)
LDLIBS += $(CONVLIBDIR) $(CONV_LIB) $(ELFLIBDIR) -lelf
diff --git a/usr/src/cmd/sgs/include/conv.h b/usr/src/cmd/sgs/include/conv.h
index 177f89f631..e7fa3d36bc 100644
--- a/usr/src/cmd/sgs/include/conv.h
+++ b/usr/src/cmd/sgs/include/conv.h
@@ -23,7 +23,7 @@
* Copyright (c) 1988 AT&T
* All Rights Reserved
*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -200,7 +200,7 @@ typedef union {
} Conv_grpdesc_flags_buf_t;
/* conv_seg_flags() */
-#define CONV_SEG_FLAGS_BUFSIZE 196
+#define CONV_SEG_FLAGS_BUFSIZE 241
typedef union {
Conv_inv_buf_t inv_buf;
char buf[CONV_SEG_FLAGS_BUFSIZE];
@@ -354,6 +354,20 @@ typedef union {
char buf[CONV_VER_FLAGS_BUFSIZE];
} Conv_ver_flags_buf_t;
+/* conv_ent_flags() */
+#define CONV_ENT_FLAGS_BUFSIZE 69
+typedef union {
+ Conv_inv_buf_t inv_buf;
+ char buf[CONV_ENT_FLAGS_BUFSIZE];
+} Conv_ent_flags_buf_t;
+
+/* conv_ent_files_flags() */
+#define CONV_ENT_FILES_FLAGS_BUFSIZE 89
+typedef union {
+ Conv_inv_buf_t inv_buf;
+ char buf[CONV_ENT_FILES_FLAGS_BUFSIZE];
+} Conv_ent_files_flags_buf_t;
+
/*
* conv_time()
*
@@ -718,6 +732,7 @@ extern char *conv_strproc_trim(char *);
extern Boolean conv_strproc_extract_value(char *, size_t, int,
const char **);
extern int conv_sys_eclass(void);
+extern int conv_translate_c_esc(char **);
/*
* Generic core formatting and iteration functionality
@@ -824,9 +839,14 @@ extern const char *conv_ehdr_type(uchar_t, Half, Conv_fmt_flags_t,
extern const char *conv_ehdr_vers(Word, Conv_fmt_flags_t,
Conv_inv_buf_t *);
extern const char *conv_elfdata_type(Elf_Type, Conv_inv_buf_t *);
+extern const char *conv_ent_flags(ec_flags_t, Conv_ent_flags_buf_t *);
+extern const char *conv_ent_files_flags(Word, Conv_fmt_flags_t fmt_flags,
+ Conv_ent_files_flags_buf_t *);
extern const char *conv_grphdl_flags(uint_t, Conv_grphdl_flags_buf_t *);
extern const char *conv_grpdesc_flags(uint_t, Conv_grpdesc_flags_buf_t *);
extern Isa_desc *conv_isalist(void);
+extern const char *conv_mapfile_version(Word, Conv_fmt_flags_t,
+ Conv_inv_buf_t *);
extern const char *conv_phdr_flags(uchar_t, Word, Conv_fmt_flags_t,
Conv_phdr_flags_buf_t *);
extern const char *conv_phdr_type(uchar_t, Half, Word, Conv_fmt_flags_t,
@@ -844,7 +864,7 @@ extern const char *conv_reloc_SPARC_type(Word, Conv_fmt_flags_t,
Conv_inv_buf_t *);
extern const char *conv_sec_type(uchar_t, Half, Word, Conv_fmt_flags_t,
Conv_inv_buf_t *);
-extern const char *conv_seg_flags(Half, Conv_seg_flags_buf_t *);
+extern const char *conv_seg_flags(sg_flags_t, Conv_seg_flags_buf_t *);
extern void conv_str_to_c_literal(const char *buf, size_t n,
Conv_str_to_c_literal_func_t *cb_func,
void *uvalue);
diff --git a/usr/src/cmd/sgs/include/debug.h b/usr/src/cmd/sgs/include/debug.h
index ad97f73257..936f84ada4 100644
--- a/usr/src/cmd/sgs/include/debug.h
+++ b/usr/src/cmd/sgs/include/debug.h
@@ -134,12 +134,6 @@ extern "C" {
#define DBG_BINFO_REF_MSK 0xf000
-#define DBG_CAP_INITIAL 0
-#define DBG_CAP_IGNORE 1
-#define DBG_CAP_OLD 2
-#define DBG_CAP_NEW 3
-#define DBG_CAP_RESOLVED 4
-
#define DBG_REL_START 1
#define DBG_REL_FINISH 2
#define DBG_REL_NONE 3
@@ -154,6 +148,26 @@ extern "C" {
#define DBG_BNDREJ_NUM DBG_BNDREJ_SINGLE
/*
+ * Dbg_state_str() is used to obtain commonly used "state transition"
+ * strings used in various debugging output.
+ */
+#define DBG_STATE_ADD 0 /* add */
+#define DBG_STATE_CURRENT 1 /* current */
+#define DBG_STATE_EXCLUDE 2 /* exclude */
+#define DBG_STATE_IGNORED 3 /* ignored */
+#define DBG_STATE_MOD_BEFORE 4 /* modify (before) */
+#define DBG_STATE_MOD_AFTER 5 /* modify (after) */
+#define DBG_STATE_NEW 6 /* new */
+#define DBG_STATE_NEW_IMPLICIT 7 /* new (implicit) */
+#define DBG_STATE_OUT 8 /* out */
+#define DBG_STATE_RESET 9 /* reset */
+#define DBG_STATE_RESOLVED 10 /* resolved */
+
+#define DBG_STATE_NUM 11
+typedef uint_t dbg_state_t;
+extern const char *Dbg_state_str(dbg_state_t);
+
+/*
* Define a debug descriptor, and a user macro that inspects the descriptor as
* a means of triggering a class of diagnostic output.
*/
@@ -169,6 +183,11 @@ typedef struct {
extern Dbg_desc *dbg_desc;
+/*
+ * Macros used to avoid calls to liblddbg unless debugging is enabled.
+ * liblddbg is lazy loaded --- this prevents it from happening unless
+ * it will actually be used.
+ */
#define DBG_ENABLED (dbg_desc->d_class)
#define DBG_CALL(func) if (DBG_ENABLED) func
@@ -241,6 +260,9 @@ typedef enum { DBG_CALLER_LD, DBG_CALLER_RTLD } dbg_setup_caller_t;
extern int Dbg_setup(dbg_setup_caller_t, const char *,
Dbg_desc *, const char **);
+/* Call dbg_print() to produce linker version output */
+extern void Dbg_version(void);
+
/* Call dbg_print() to produce help output */
extern void Dbg_help(void);
@@ -258,11 +280,13 @@ extern void Dbg_help(void);
#define Dbg_bind_reject Dbg64_bind_reject
#define Dbg_bind_weak Dbg64_bind_weak
+#define Dbg_cap_entry Dbg64_cap_entry
+#define Dbg_cap_entry2 Dbg64_cap_entry2
#define Dbg_cap_val_hw1 Dbg64_cap_val_hw1
#define Dbg_cap_hw_candidate Dbg64_cap_hw_candidate
#define Dbg_cap_hw_filter Dbg64_cap_hw_filter
-#define Dbg_cap_mapfile Dbg64_cap_mapfile
-#define Dbg_cap_sec_entry Dbg64_cap_sec_entry
+#define Dbg_cap_mapfile_title Dbg64_cap_mapfile_title
+#define Dbg_cap_out_title Dbg64_cap_out_title
#define Dbg_cap_sec_title Dbg64_cap_sec_title
#define Dbg_cb_iphdr_enter Dbg64_cb_iphdr_enter
@@ -324,17 +348,22 @@ extern void Dbg_help(void);
#define Dbg_libs_yp Dbg64_libs_yp
#define Dbg_libs_ylu Dbg64_libs_ylu
-#define Dbg_map_dash Dbg64_map_dash
+#define Dbg_map_cexp_id Dbg64_map_cexp_id
+#define Dbg_map_dv Dbg64_map_dv
+#define Dbg_map_dv_entry Dbg64_map_dv_entry
#define Dbg_map_ent Dbg64_map_ent
+#define Dbg_map_ent_ord_title Dbg64_map_ent_ord_title
+#define Dbg_map_hdr_noalloc Dbg64_map_hdr_noalloc
#define Dbg_map_parse Dbg64_map_parse
-#define Dbg_map_pipe Dbg64_map_pipe
+#define Dbg_map_pass Dbg64_map_pass
+#define Dbg_map_post_title Dbg64_map_post_title
#define Dbg_map_seg Dbg64_map_seg
-#define Dbg_map_set_atsign Dbg64_map_set_atsign
-#define Dbg_map_set_equal Dbg64_map_set_equal
+#define Dbg_map_seg_order Dbg64_map_seg_order
+#define Dbg_map_seg_os_order Dbg64_map_seg_os_order
#define Dbg_map_size_new Dbg64_map_size_new
#define Dbg_map_size_old Dbg64_map_size_old
-#define Dbg_map_sort Dbg64_map_sort
#define Dbg_map_sort_seg Dbg64_map_sort_seg
+#define Dbg_map_sort_title Dbg64_map_sort_title
#define Dbg_map_symbol Dbg64_map_symbol
#define Dbg_map_version Dbg64_map_version
@@ -473,11 +502,13 @@ extern void Dbg_help(void);
#define Dbg_bind_reject Dbg32_bind_reject
#define Dbg_bind_weak Dbg32_bind_weak
+#define Dbg_cap_entry Dbg32_cap_entry
+#define Dbg_cap_entry2 Dbg32_cap_entry2
#define Dbg_cap_val_hw1 Dbg32_cap_val_hw1
#define Dbg_cap_hw_candidate Dbg32_cap_hw_candidate
#define Dbg_cap_hw_filter Dbg32_cap_hw_filter
-#define Dbg_cap_mapfile Dbg32_cap_mapfile
-#define Dbg_cap_sec_entry Dbg32_cap_sec_entry
+#define Dbg_cap_mapfile_title Dbg32_cap_mapfile_title
+#define Dbg_cap_out_title Dbg32_cap_out_title
#define Dbg_cap_sec_title Dbg32_cap_sec_title
#define Dbg_cb_iphdr_enter Dbg32_cb_iphdr_enter
@@ -539,17 +570,22 @@ extern void Dbg_help(void);
#define Dbg_libs_yp Dbg32_libs_yp
#define Dbg_libs_ylu Dbg32_libs_ylu
-#define Dbg_map_dash Dbg32_map_dash
+#define Dbg_map_cexp_id Dbg32_map_cexp_id
+#define Dbg_map_dv Dbg32_map_dv
+#define Dbg_map_dv_entry Dbg32_map_dv_entry
#define Dbg_map_ent Dbg32_map_ent
+#define Dbg_map_ent_ord_title Dbg32_map_ent_ord_title
+#define Dbg_map_hdr_noalloc Dbg32_map_hdr_noalloc
#define Dbg_map_parse Dbg32_map_parse
-#define Dbg_map_pipe Dbg32_map_pipe
+#define Dbg_map_pass Dbg32_map_pass
+#define Dbg_map_post_title Dbg32_map_post_title
#define Dbg_map_seg Dbg32_map_seg
-#define Dbg_map_set_atsign Dbg32_map_set_atsign
-#define Dbg_map_set_equal Dbg32_map_set_equal
+#define Dbg_map_seg_order Dbg32_map_seg_order
+#define Dbg_map_seg_os_order Dbg32_map_seg_os_order
#define Dbg_map_size_new Dbg32_map_size_new
#define Dbg_map_size_old Dbg32_map_size_old
-#define Dbg_map_sort Dbg32_map_sort
#define Dbg_map_sort_seg Dbg32_map_sort_seg
+#define Dbg_map_sort_title Dbg32_map_sort_title
#define Dbg_map_symbol Dbg32_map_symbol
#define Dbg_map_version Dbg32_map_version
@@ -718,10 +754,12 @@ extern void Dbg_bind_pltpad_to(Rt_map *, Addr, const char *, const char *);
extern void Dbg_bind_reject(Rt_map *, Rt_map *, const char *, int);
extern void Dbg_bind_weak(Rt_map *, Addr, Addr, const char *);
+extern void Dbg_cap_entry(Lm_list *, dbg_state_t, Xword, Xword, Half);
+extern void Dbg_cap_entry2(Lm_list *, dbg_state_t, Xword, CapMask *, Half);
extern void Dbg_cap_hw_candidate(Lm_list *, const char *);
extern void Dbg_cap_hw_filter(Lm_list *, const char *, Rt_map *);
-extern void Dbg_cap_mapfile(Lm_list *, Xword, Xword, Half);
-extern void Dbg_cap_sec_entry(Lm_list *, uint_t, Xword, Xword, Half);
+extern void Dbg_cap_mapfile_title(Lm_list *, Lineno);
+extern void Dbg_cap_out_title(Lm_list *);
extern void Dbg_cap_sec_title(Lm_list *, const char *);
extern void Dbg_cap_val_hw1(Lm_list *, Xword, Half);
@@ -734,7 +772,7 @@ extern const char *
Dbg_demangle_name(const char *);
extern void Dbg_ent_entry(Lm_list *, uchar_t, Half, Ent_desc *);
-extern void Dbg_ent_print(Lm_list *, uchar_t, Half, Alist *, Boolean);
+extern void Dbg_ent_print(Lm_list *, uchar_t, Half, APlist *);
extern void Dbg_file_analyze(Rt_map *);
extern void Dbg_file_aout(Lm_list *, const char *, Addr, size_t,
@@ -794,17 +832,26 @@ extern void Dbg_libs_update(Lm_list *, APlist *, APlist *);
extern void Dbg_libs_yp(Lm_list *, const char *);
extern void Dbg_libs_ylu(Lm_list *, const char *, const char *, int);
-extern void Dbg_map_dash(Lm_list *, const char *);
-extern void Dbg_map_ent(Lm_list *, Boolean, Ent_desc *, Ofl_desc *);
-extern void Dbg_map_parse(Lm_list *, const char *);
-extern void Dbg_map_pipe(Lm_list *, Sg_desc *, const char *, const Word);
-extern void Dbg_map_seg(Ofl_desc *, int, Sg_desc *);
-extern void Dbg_map_set_atsign(Boolean);
-extern void Dbg_map_set_equal(Boolean);
-extern void Dbg_map_size_new(Lm_list *, const char *);
-extern void Dbg_map_size_old(Ofl_desc *, Sym_desc *);
-extern void Dbg_map_sort(Lm_list *);
-extern void Dbg_map_sort_seg(Lm_list *, Sg_desc *, int);
+extern void Dbg_map_cexp_id(Lm_list *, Boolean, const char *, Lineno,
+ const char *);
+extern void Dbg_map_dv(Lm_list *, const char *, Lineno);
+extern void Dbg_map_dv_entry(Lm_list *, Lineno, int, const char *);
+extern void Dbg_map_ent(Lm_list *, Ent_desc *, Ofl_desc *, Lineno);
+extern void Dbg_map_ent_ord_title(Lm_list *, const char *);
+extern void Dbg_map_hdr_noalloc(Lm_list *, Lineno);
+extern void Dbg_map_parse(Lm_list *, const char *, int);
+extern void Dbg_map_pass(Lm_list *, Boolean, const char *, Lineno,
+ const char *);
+extern void Dbg_map_post_title(Lm_list *);
+extern void Dbg_map_seg(Ofl_desc *, dbg_state_t, int, Sg_desc *, Lineno);
+extern void Dbg_map_seg_order(Ofl_desc *, uchar_t, Half, dbg_state_t,
+ Lineno);
+extern void Dbg_map_seg_os_order(Lm_list *, Sg_desc *, const char *,
+ Word, Lineno);
+extern void Dbg_map_size_new(Lm_list *, const char *, const char *, Lineno);
+extern void Dbg_map_size_old(Ofl_desc *, Sym_desc *, const char *, Lineno);
+extern void Dbg_map_sort_title(Lm_list *, Boolean);
+extern void Dbg_map_sort_seg(Lm_list *, uchar_t, Half, Sg_desc *);
extern void Dbg_map_symbol(Ofl_desc *, Sym_desc *);
extern void Dbg_map_version(Lm_list *, const char *, const char *, int);
@@ -859,7 +906,8 @@ extern void Dbg_sec_redirected(Lm_list *, Is_desc *, const char *);
extern void Dbg_sec_strtab(Lm_list *, Os_desc *, Str_tbl *);
extern void Dbg_sec_unsup_strmerge(Lm_list *, Is_desc *);
-extern void Dbg_seg_desc_entry(Lm_list *, uchar_t, Half, int, Sg_desc *);
+extern void Dbg_seg_desc_entry(Lm_list *, uchar_t, Half, int, Sg_desc *,
+ Boolean);
extern void Dbg_seg_entry(Ofl_desc *, int, Sg_desc *);
extern void Dbg_seg_list(Lm_list *, uchar_t, Half, APlist *);
extern void Dbg_seg_os(Ofl_desc *, Os_desc *, int);
diff --git a/usr/src/cmd/sgs/include/elfedit.h b/usr/src/cmd/sgs/include/elfedit.h
index 5332e3aa63..65e696b738 100644
--- a/usr/src/cmd/sgs/include/elfedit.h
+++ b/usr/src/cmd/sgs/include/elfedit.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -356,7 +356,7 @@ typedef elfedit_cmdret_t elfedit64_cmd_func_t(elfedit64_obj_state_t *state,
* 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
+ * argc, argv - The tokens from the start of the line through
* the one needing completion, which will always
* be cmdcpl_argv[cmdcpl_argc - 1].
* num_opt - A count of the optional arguments (those starting with
diff --git a/usr/src/cmd/sgs/include/i386/machdep_x86.h b/usr/src/cmd/sgs/include/i386/machdep_x86.h
index b53f02554a..1b328fa919 100644
--- a/usr/src/cmd/sgs/include/i386/machdep_x86.h
+++ b/usr/src/cmd/sgs/include/i386/machdep_x86.h
@@ -23,7 +23,7 @@
* Copyright (c) 1988 AT&T
* All Rights Reserved
*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Global include file for all sgs ia32 based machine dependent macros,
@@ -202,12 +202,14 @@ extern "C" {
#define M_PLT_SHF_FLAGS (SHF_ALLOC | SHF_EXECINSTR)
/*
- * Make data segment information transparent to the common code.
+ * Make default data segment and stack flags transparent to the common code.
*/
#ifdef _ELF64
#define M_DATASEG_PERM (PF_R | PF_W)
+#define M_STACK_PERM (PF_R | PF_W)
#else
#define M_DATASEG_PERM (PF_R | PF_W | PF_X)
+#define M_STACK_PERM (PF_R | PF_W | PF_X)
#endif
/*
diff --git a/usr/src/cmd/sgs/include/libld.h b/usr/src/cmd/sgs/include/libld.h
index e32d893ad6..fcb81f7460 100644
--- a/usr/src/cmd/sgs/include/libld.h
+++ b/usr/src/cmd/sgs/include/libld.h
@@ -23,7 +23,7 @@
* Copyright (c) 1988 AT&T
* All Rights Reserved
*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -37,6 +37,7 @@
#include <string_table.h>
#include <sys/avl.h>
#include <alist.h>
+#include <elfcap.h>
#ifdef __cplusplus
extern "C" {
@@ -164,6 +165,29 @@ typedef struct wrap_sym_node {
/*
+ * Bitmasks for a single capability. Capabilities come from input objects,
+ * augmented or replaced by mapfile directives. In addition, mapfile directives
+ * can be used to exclude bits that would otherwise be set in the output object.
+ */
+typedef struct {
+ elfcap_mask_t cm_value; /* Bitmask value */
+ elfcap_mask_t cm_exclude; /* Bits to remove from final object */
+} CapMask;
+
+/*
+ * Combine the bitmask in a CapMask with the exclusion mask and
+ * return the resulting final value.
+ */
+#define CAPMASK_VALUE(_cbmp) ((_cbmp)->cm_value & ~(_cbmp)->cm_exclude)
+
+typedef struct {
+ CapMask c_hw_1; /* CA_SUNW_HW_1 capabilities */
+ CapMask c_sf_1; /* CA_SUNW_SF_1 capabilities */
+ CapMask c_hw_2; /* CA_SUNW_HW_2 capabilities */
+} Outcapset;
+
+
+/*
* Output file processing structure
*/
typedef Lword ofl_flag_t;
@@ -180,7 +204,10 @@ struct ofl_desc {
size_t ofl_size; /* image size */
APlist *ofl_maps; /* list of input mapfiles */
APlist *ofl_segs; /* list of segments */
- Alist *ofl_ents; /* list of entrance descriptors */
+ APlist *ofl_segs_order; /* SEGMENT_ORDER segments */
+ avl_tree_t ofl_segs_avl; /* O(log N) access to named segments */
+ APlist *ofl_ents; /* list of entrance descriptors */
+ avl_tree_t ofl_ents_avl; /* O(log N) access to named ent. desc */
APlist *ofl_objs; /* relocatable object file list */
Word ofl_objscnt; /* and count */
APlist *ofl_ars; /* archive library list */
@@ -310,8 +337,7 @@ struct ofl_desc {
char *ofl_audit; /* object auditing required (-p) */
Alist *ofl_symfltrs; /* per-symbol filtees and their */
Alist *ofl_dtsfltrs; /* associated .dynamic/.dynstrs */
- Xword ofl_hwcap_1; /* hardware capabilities */
- Xword ofl_sfcap_1; /* software capabilities */
+ Outcapset ofl_ocapset; /* object capabilities */
Lm_list *ofl_lml; /* runtime link-map list */
Gottable *ofl_gottable; /* debugging got information */
Rlxrel_cache ofl_sr_cache; /* Cache last result from */
@@ -337,8 +363,9 @@ struct ofl_desc {
#define FLG_OF_SYMBOLIC 0x00002000 /* bind global symbols: -Bsymbolic */
#define FLG_OF_ADDVERS 0x00004000 /* add version stamp: -Qy */
#define FLG_OF_NOLDYNSYM 0x00008000 /* -znoldynsym set */
-#define FLG_OF_SEGORDER 0x00010000 /* segment ordering is required */
-#define FLG_OF_SEGSORT 0x00020000 /* segment sorting is required */
+#define FLG_OF_IS_ORDER 0x00010000 /* input section ordering within a */
+ /* segment is required */
+#define FLG_OF_EC_FILES 0x00020000 /* Ent_desc exist w/non-NULL ec_files */
#define FLG_OF_TEXTREL 0x00040000 /* text relocations have been found */
#define FLG_OF_MULDEFS 0x00080000 /* multiple symbols are allowed */
#define FLG_OF_TLSPHDR 0x00100000 /* a TLS program header is required */
@@ -366,7 +393,7 @@ struct ofl_desc {
#define FLG_OF_AUTOELM 0x002000000000 /* automatically eliminate */
/* unspecified global symbols */
#define FLG_OF_REDLSYM 0x004000000000 /* reduce local symbols */
-#define FLG_OF_SECORDER 0x008000000000 /* section ordering is required */
+#define FLG_OF_OS_ORDER 0x008000000000 /* output section ordering required */
#define FLG_OF_OSABI 0x010000000000 /* tag object as ELFOSABI_SOLARIS */
#define FLG_OF_ADJOSCNT 0x020000000000 /* ajust ofl_shdrcnt to accommodate */
/* discarded sections */
@@ -377,49 +404,51 @@ struct ofl_desc {
* archive descriptor so that they may be reset should the archive require a
* rescan to try and resolve undefined symbols.
*/
-#define FLG_OF1_ALLEXRT 0x00000001 /* extract all members from an */
+#define FLG_OF1_ALLEXRT 0x0000000001 /* extract all members from an */
/* archive file */
-#define FLG_OF1_WEAKEXT 0x00000002 /* allow archive extraction to */
+#define FLG_OF1_WEAKEXT 0x0000000002 /* allow archive extraction to */
/* resolve weak references */
-#define MSK_OF1_ARCHIVE 0x00000003 /* archive flags mask */
-
-#define FLG_OF1_NOINTRP 0x00000008 /* -z nointerp flag set */
-#define FLG_OF1_ZDIRECT 0x00000010 /* -z direct flag set */
-#define FLG_OF1_NDIRECT 0x00000020 /* no-direct bindings specified */
-#define FLG_OF1_OVHWCAP 0x00000040 /* override any input hardware or */
-#define FLG_OF1_OVSFCAP 0x00000080 /* software capabilities */
-#define FLG_OF1_RELDYN 0x00000100 /* process .dynamic in rel obj */
-#define FLG_OF1_NRLXREL 0x00000200 /* -z norelaxreloc flag set */
-#define FLG_OF1_RLXREL 0x00000400 /* -z relaxreloc flag set */
-#define FLG_OF1_IGNORE 0x00000800 /* ignore unused dependencies */
-
-#define FLG_OF1_NOSGHND 0x00001000 /* -z nosighandler flag set */
-#define FLG_OF1_TEXTOFF 0x00002000 /* text relocations are ok */
-#define FLG_OF1_ABSEXEC 0x00004000 /* -zabsexec set */
-#define FLG_OF1_LAZYLD 0x00008000 /* lazy loading of objects enabled */
-#define FLG_OF1_GRPPRM 0x00010000 /* dependencies are to have */
+#define MSK_OF1_ARCHIVE 0x0000000003 /* archive flags mask */
+
+#define FLG_OF1_NOINTRP 0x0000000008 /* -z nointerp flag set */
+#define FLG_OF1_ZDIRECT 0x0000000010 /* -z direct flag set */
+#define FLG_OF1_NDIRECT 0x0000000020 /* no-direct bindings specified */
+
+#define FLG_OF1_RELDYN 0x0000000100 /* process .dynamic in rel obj */
+#define FLG_OF1_NRLXREL 0x0000000200 /* -z norelaxreloc flag set */
+#define FLG_OF1_RLXREL 0x0000000400 /* -z relaxreloc flag set */
+#define FLG_OF1_IGNORE 0x0000000800 /* ignore unused dependencies */
+
+#define FLG_OF1_NOSGHND 0x0000001000 /* -z nosighandler flag set */
+#define FLG_OF1_TEXTOFF 0x0000002000 /* text relocations are ok */
+#define FLG_OF1_ABSEXEC 0x0000004000 /* -zabsexec set */
+#define FLG_OF1_LAZYLD 0x0000008000 /* lazy loading of objects enabled */
+#define FLG_OF1_GRPPRM 0x0000010000 /* dependencies are to have */
/* GROUPPERM enabled */
-#define FLG_OF1_OVRFLW 0x00020000 /* size exceeds 32-bit limitation */
+#define FLG_OF1_OVRFLW 0x0000020000 /* size exceeds 32-bit limitation */
/* of 32-bit libld */
-#define FLG_OF1_NOPARTI 0x00040000 /* -znopartial set */
-#define FLG_OF1_BSSOREL 0x00080000 /* output relocation against bss */
+#define FLG_OF1_NOPARTI 0x0000040000 /* -znopartial set */
+#define FLG_OF1_BSSOREL 0x0000080000 /* output relocation against bss */
/* section */
-#define FLG_OF1_TLSOREL 0x00100000 /* output relocation against .tlsbss */
+#define FLG_OF1_TLSOREL 0x0000100000 /* output relocation against .tlsbss */
/* section */
-#define FLG_OF1_MEMORY 0x00200000 /* produce a memory model */
-#define FLG_OF1_NGLBDIR 0x00400000 /* no DT_1_DIRECT flag allowed */
-#define FLG_OF1_ENCDIFF 0x00800000 /* Host running linker has different */
+#define FLG_OF1_MEMORY 0x0000200000 /* produce a memory model */
+#define FLG_OF1_NGLBDIR 0x0000400000 /* no DT_1_DIRECT flag allowed */
+#define FLG_OF1_ENCDIFF 0x0000800000 /* Host running linker has different */
/* byte order than output object */
-#define FLG_OF1_VADDR 0x01000000 /* user segment defines a vaddr */
-#define FLG_OF1_EXTRACT 0x02000000 /* archive member has been extracted */
-#define FLG_OF1_RESCAN 0x04000000 /* any archives should be rescanned */
-#define FLG_OF1_IGNPRC 0x08000000 /* ignore processing required */
-#define FLG_OF1_NCSTTAB 0x10000000 /* -znocompstrtab set */
-#define FLG_OF1_DONE 0x20000000 /* link-editor processing complete */
-#define FLG_OF1_NONREG 0x40000000 /* non-regular file specified as */
+#define FLG_OF1_VADDR 0x0001000000 /* a segment defines explicit vaddr */
+#define FLG_OF1_EXTRACT 0x0002000000 /* archive member has been extracted */
+#define FLG_OF1_RESCAN 0x0004000000 /* any archives should be rescanned */
+#define FLG_OF1_IGNPRC 0x0008000000 /* ignore processing required */
+#define FLG_OF1_NCSTTAB 0x0010000000 /* -znocompstrtab set */
+#define FLG_OF1_DONE 0x0020000000 /* link-editor processing complete */
+#define FLG_OF1_NONREG 0x0040000000 /* non-regular file specified as */
/* the output file */
-#define FLG_OF1_ALNODIR 0x80000000 /* establish NODIRECT for all */
+#define FLG_OF1_ALNODIR 0x0080000000 /* establish NODIRECT for all */
/* exported interfaces. */
+#define FLG_OF1_OVHWCAP1 0x0100000000 /* override CA_SUNW_HW_1 capabilities */
+#define FLG_OF1_OVSFCAP1 0x0200000000 /* override CA_SUNW_SF_1 capabilities */
+#define FLG_OF1_OVHWCAP2 0x0400000000 /* override CA_SUNW_HW_2 capabilities */
/*
* Test to see if the output file would allow the presence of
@@ -665,7 +694,7 @@ struct is_desc { /* input section descriptor */
#define FLG_IS_RELUPD 0x0008 /* symbol defined here may have moved */
#define FLG_IS_SECTREF 0x0010 /* section has been referenced */
#define FLG_IS_GDATADEF 0x0020 /* section contains global data sym */
-#define FLG_IS_EXTERNAL 0x0040 /* isp from an user file */
+#define FLG_IS_EXTERNAL 0x0040 /* isp from a user file */
#define FLG_IS_INSTRMRG 0x0080 /* Usable SHF_MERGE|SHF_STRINGS sec */
#define FLG_IS_GNSTRMRG 0x0100 /* Generated mergeable string section */
#define FLG_IS_GROUPS 0x0200 /* section has groups to process */
@@ -733,76 +762,99 @@ struct os_desc { /* Output section descriptor */
#define FLG_OS_SECTREF 0x04 /* isps are not affected by -zignore */
/*
- * Types of segment index.
+ * The sg_id field of the segment descriptor is used to establish the default
+ * order for program headers and segments in the output object. Segments are
+ * ordered according to the following SGID values that classify them based on
+ * their attributes. The initial set of built in segments are in this order,
+ * and new mapfile defined segments are inserted into these groups. Within a
+ * given SGID group, the position of new segments depends on the syntax
+ * version of the mapfile that creates them. Version 1 (original sysv)
+ * mapfiles place the new segment at the head of their group (reverse creation
+ * order). The newer syntax places them at the end, following the others
+ * (creation order).
+ *
+ * Note that any new segments must always be added after PT_PHDR and
+ * PT_INTERP (refer Generic ABI, Page 5-4).
*/
-typedef enum {
- LD_PHDR,
- LD_INTERP,
- LD_SUNWCAP,
- LD_TEXT,
- LD_DATA,
- LD_BSS,
+#define SGID_PHDR 0 /* PT_PHDR */
+#define SGID_INTERP 1 /* PT_INTERP */
+#define SGID_SUNWCAP 2 /* PT_SUNWCAP */
+#define SGID_TEXT 3 /* PT_LOAD */
+#define SGID_DATA 4 /* PT_LOAD */
+#define SGID_BSS 5 /* PT_LOAD */
#if defined(_ELF64)
- LD_LRODATA, /* (amd64-only) */
- LD_LDATA, /* (amd64-only) */
+#define SGID_LRODATA 6 /* PT_LOAD (amd64-only) */
+#define SGID_LDATA 7 /* PT_LOAD (amd64-only) */
#endif
- LD_DYN,
- LD_DTRACE,
- LD_TLS,
- LD_UNWIND,
- LD_NOTE,
- LD_EXTRA,
- LD_NUM
-} Segment_id;
-
+#define SGID_TEXT_EMPTY 8 /* PT_LOAD, reserved (?E in version 1 syntax) */
+#define SGID_NULL_EMPTY 9 /* PT_NULL, reserved (?E in version 1 syntax) */
+#define SGID_DYN 10 /* PT_DYNAMIC */
+#define SGID_DTRACE 11 /* PT_SUNWDTRACE */
+#define SGID_TLS 12 /* PT_TLS */
+#define SGID_UNWIND 13 /* PT_SUNW_UNWIND */
+#define SGID_SUNWSTACK 14 /* PT_SUNWSTACK */
+#define SGID_NOTE 15 /* PT_NOTE */
+#define SGID_NULL 16 /* PT_NULL, mapfile defined empty phdr slots */
+ /* for use by post processors */
+#define SGID_EXTRA 17 /* PT_NULL (final catchall) */
+
+typedef Half sg_flags_t;
struct sg_desc { /* output segment descriptor */
- Segment_id sg_id; /* segment identifier (for sorting) */
+ Word sg_id; /* segment identifier (for sorting) */
Phdr sg_phdr; /* segment header for output file */
- const char *sg_name; /* segment name */
+ const char *sg_name; /* segment name for PT_LOAD, PT_NOTE, */
+ /* and PT_NULL, otherwise NULL */
Xword sg_round; /* data rounding required (mapfile) */
Xword sg_length; /* maximum segment length; if 0 */
/* segment is not specified */
APlist *sg_osdescs; /* list of output section descriptors */
- APlist *sg_secorder; /* list specifying section ordering */
- /* for the segment */
- Half sg_flags;
- Sym_desc *sg_sizesym; /* size symbol for this segment */
- Xword sg_addralign; /* LCM of sh_addralign */
+ APlist *sg_is_order; /* list of entry criteria */
+ /* giving input section order */
+ Alist *sg_os_order; /* list specifying output section */
+ /* ordering for the segment */
+ sg_flags_t sg_flags;
+ APlist *sg_sizesym; /* size symbols for this segment */
+ Xword sg_align; /* LCM of sh_addralign */
Elf_Scn *sg_fscn; /* the SCN of the first section. */
+ avl_node_t sg_avlnode; /* AVL book-keeping */
};
-#define FLG_SG_VADDR 0x0001 /* vaddr segment attribute set */
-#define FLG_SG_PADDR 0x0002 /* paddr segment attribute set */
-#define FLG_SG_LENGTH 0x0004 /* length segment attribute set */
-#define FLG_SG_ALIGN 0x0008 /* align segment attribute set */
-#define FLG_SG_ROUND 0x0010 /* round segment attribute set */
-#define FLG_SG_FLAGS 0x0020 /* flags segment attribute set */
-#define FLG_SG_TYPE 0x0040 /* type segment attribute set */
-#define FLG_SG_ORDER 0x0080 /* has ordering been turned on for */
- /* this segment. */
- /* i.e. ?[O] option in mapfile */
-#define FLG_SG_NOHDR 0x0100 /* don't map ELF or phdrs into */
- /* this segment */
-#define FLG_SG_EMPTY 0x0200 /* an empty segment specification */
+#define FLG_SG_P_VADDR 0x0001 /* p_vaddr segment attribute set */
+#define FLG_SG_P_PADDR 0x0002 /* p_paddr segment attribute set */
+#define FLG_SG_LENGTH 0x0004 /* length segment attribute set */
+#define FLG_SG_P_ALIGN 0x0008 /* p_align segment attribute set */
+#define FLG_SG_ROUND 0x0010 /* round segment attribute set */
+#define FLG_SG_P_FLAGS 0x0020 /* p_flags segment attribute set */
+#define FLG_SG_P_TYPE 0x0040 /* p_type segment attribute set */
+#define FLG_SG_IS_ORDER 0x0080 /* input section ordering is required */
+ /* for this segment. */
+#define FLG_SG_NOHDR 0x0100 /* don't map ELF or phdrs into */
+ /* this segment */
+#define FLG_SG_EMPTY 0x0200 /* an empty segment specification */
/* no input sections will be */
/* associated to this section */
-#define FLG_SG_KEY 0x0400 /* segment requires sort keys */
-#define FLG_SG_DISABLED 0x0800 /* this segment is disabled */
-#define FLG_SG_PHREQ 0x1000 /* this segment requires a program */
+#define FLG_SG_KEY 0x0400 /* segment requires sort keys */
+#define FLG_SG_NODISABLE 0x0800 /* FLG_SG_DISABLED is not allowed on */
+ /* this segment */
+#define FLG_SG_DISABLED 0x1000 /* this segment is disabled */
+#define FLG_SG_PHREQ 0x2000 /* this segment requires a program */
/* header */
+#define FLG_SG_ORDERED 0x4000 /* SEGMENT_ORDER segment */
struct sec_order {
const char *sco_secname; /* section name to be ordered */
- Word sco_index; /* ordering index for section */
Half sco_flags;
};
#define FLG_SGO_USED 0x0001 /* was ordering used? */
+typedef Half ec_flags_t;
struct ent_desc { /* input section entrance criteria */
- APlist *ec_files; /* files from which to accept */
+ const char *ec_name; /* entrace criteria name, or NULL */
+ Alist *ec_files; /* files from which to accept */
/* sections */
- const char *ec_name; /* name to match (NULL if none) */
+ const char *ec_is_name; /* input section name to match */
+ /* (NULL if none) */
Word ec_type; /* section type */
Word ec_attrmask; /* section attribute mask (AWX) */
Word ec_attrbits; /* sections attribute bits */
@@ -811,11 +863,35 @@ struct ent_desc { /* input section entrance criteria */
/* meeting this criteria should */
/* inserted. Used for reordering */
/* of sections. */
- Half ec_flags;
+ ec_flags_t ec_flags;
+ avl_node_t ec_avlnode; /* AVL book-keeping */
};
#define FLG_EC_BUILTIN 0x0001 /* built in descriptor */
#define FLG_EC_USED 0x0002 /* entrance criteria met? */
+#define FLG_EC_CATCHALL 0x0004 /* Catches any section */
+
+/*
+ * Ent_desc_file is the type of element maintained in the ec_files Alist
+ * of an entrance criteria descriptor. Each item maintains one file
+ * path, and a set of flags that specify the type of comparison it implies,
+ * and other information about it. The comparison type is maintained in
+ * the bottom byte of the flags.
+ */
+#define TYP_ECF_MASK 0x00ff /* Comparison type mask */
+#define TYP_ECF_PATH 0 /* Compare to file path */
+#define TYP_ECF_BASENAME 1 /* Compare to file basename */
+#define TYP_ECF_OBJNAME 2 /* Compare to regular file basename, */
+ /* or to archive member name */
+#define TYP_ECF_NUM 3
+
+#define FLG_ECF_ARMEMBER 0x0100 /* name includes archive member */
+
+typedef struct {
+ Word edf_flags; /* Type of comparison */
+ const char *edf_name; /* String to compare to */
+ size_t edf_name_len; /* strlen(edf_name) */
+} Ent_desc_file;
/*
* One structure is allocated for a move entry, and associated to the symbol
@@ -1178,6 +1254,13 @@ typedef struct ar_desc {
*/
#define FLG_ARD_EXTRACT 0x00010000 /* archive member has been extracted */
+/* Mapfile versions supported by libld */
+#define MFV_NONE 0 /* Not a valid version */
+#define MFV_SYSV 1 /* Original System V syntax */
+#define MFV_SOLARIS 2 /* Solaris mapfile syntax */
+#define MFV_NUM 3 /* # of mapfile versions */
+
+
/*
* Function Declarations.
*/
diff --git a/usr/src/cmd/sgs/include/sgs.h b/usr/src/cmd/sgs/include/sgs.h
index bee03e6819..a4d7d02c8e 100644
--- a/usr/src/cmd/sgs/include/sgs.h
+++ b/usr/src/cmd/sgs/include/sgs.h
@@ -24,7 +24,7 @@
* All Rights Reserved
*
*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Global include file for all sgs.
@@ -130,6 +130,14 @@ typedef enum {
ERR_NUM /* Must be last */
} Error;
+/*
+ * Type used to represent line numbers within files, and a corresponding
+ * printing macro for it.
+ */
+typedef ulong_t Lineno;
+#define EC_LINENO(_x) EC_XWORD(_x) /* "llu" */
+
+
#if defined(_LP64) && !defined(_ELF64)
#define S_ERROR (~(uint_t)0)
#else
diff --git a/usr/src/cmd/sgs/include/sparc/machdep_sparc.h b/usr/src/cmd/sgs/include/sparc/machdep_sparc.h
index fa361b6425..9ac5553a34 100644
--- a/usr/src/cmd/sgs/include/sparc/machdep_sparc.h
+++ b/usr/src/cmd/sgs/include/sparc/machdep_sparc.h
@@ -23,7 +23,7 @@
* Copyright (c) 1988 AT&T
* All Rights Reserved
*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Global include file for all sgs SPARC machine dependent macros, constants
@@ -186,9 +186,15 @@ extern "C" {
#define M_PLT_SHF_FLAGS (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR)
/*
- * Make data segment information transparent to the common code.
+ * Make default data segment and stack flags transparent to the common code.
*/
#define M_DATASEG_PERM (PF_R | PF_W | PF_X)
+#ifdef _ELF64
+#define M_STACK_PERM (PF_R | PF_W)
+#else
+#define M_STACK_PERM (PF_R | PF_W | PF_X)
+#endif
+
/*
* Define a set of identifies for special sections. These allow the sections
diff --git a/usr/src/cmd/sgs/lari/lari.pl b/usr/src/cmd/sgs/lari/lari.pl
index c398bd3590..7a1683bac9 100644
--- a/usr/src/cmd/sgs/lari/lari.pl
+++ b/usr/src/cmd/sgs/lari/lari.pl
@@ -21,7 +21,7 @@
#
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# Link Analysis of Runtime Interfaces.
@@ -584,10 +584,14 @@ sub ProcBindings {
}
$Offset++;
}
- # The symbol being bound, "... symbol `.*' ...".
+ # The symbol being bound. Over the years, we have used
+ # a ` quoting style, and more recently a ' style.
+ # Match either of:
+ # "... symbol `.*' ...".
+ # "... symbol '.*' ...".
while ($Fields[$Offset]) {
- if ($Fields[$Offset] =~ /^\`(.*)\'$/) {
- $SymName = $1;
+ if ($Fields[$Offset] =~ /^(\`|\')(.*)\'$/) {
+ $SymName = $2;
$Offset++;
last;
}
diff --git a/usr/src/cmd/sgs/ldd/common/ldd.c b/usr/src/cmd/sgs/ldd/common/ldd.c
index eff6fd23cf..22eb7faeb5 100644
--- a/usr/src/cmd/sgs/ldd/common/ldd.c
+++ b/usr/src/cmd/sgs/ldd/common/ldd.c
@@ -22,7 +22,7 @@
* All Rights Reserved
*
*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -532,8 +532,9 @@ elf_check(int nfile, char *fname, char *cname, Elf *elf, int fflag)
/*
* If there is a dynamic section, then check for the DF_1_NOHDR
- * flag, and bail if it is present. Those objects are created using
- * the ?N mapfile option: The ELF header and program headers are
+ * flag, and bail if it is present. Such objects are created using
+ * a mapfile option (?N in the version 1 syntax, or HDR_NOALLOC
+ * otherwise). The ELF header and program headers are
* not mapped as part of the first segment, and virtual addresses
* are computed without them. If ldd tries to interpret such
* a file, it will become confused and generate bad output or
diff --git a/usr/src/cmd/sgs/ldprof/Makefile.com b/usr/src/cmd/sgs/ldprof/Makefile.com
index 8e8c9f0727..915a3ded52 100644
--- a/usr/src/cmd/sgs/ldprof/Makefile.com
+++ b/usr/src/cmd/sgs/ldprof/Makefile.com
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
@@ -46,7 +46,7 @@ CPPFLAGS= -I. -I../common -I../../include \
-I$(SRCBASE)/uts/common/krtld \
-I$(SRC)/common/sgsrtcid \
-I$(SRCBASE)/uts/$(ARCH)/sys \
- $(CPPFLAGS.master)
+ $(CPPFLAGS.master) -I$(ELFCAP)
CFLAGS += $(C_PICFLAGS)
lint := ZRECORD =
diff --git a/usr/src/cmd/sgs/libconv/Makefile.com b/usr/src/cmd/sgs/libconv/Makefile.com
index 68a360da5f..902e914f57 100644
--- a/usr/src/cmd/sgs/libconv/Makefile.com
+++ b/usr/src/cmd/sgs/libconv/Makefile.com
@@ -20,7 +20,7 @@
#
#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
@@ -40,12 +40,13 @@ COMOBJS= arch.o c_literal.o \
deftag.o demangle.o \
dl.o dwarf.o \
dwarf_ehe.o dynamic.o \
- elf.o globals.o \
- group.o lddstub.o \
+ elf.o entry.o \
+ globals.o group.o \
+ lddstub.o map.o \
phdr.o relocate.o \
- relocate_i386.o relocate_amd64.o \
- relocate_sparc.o sections.o \
- segments.o strproc.o \
+ relocate_i386.o relocate_amd64.o \
+ relocate_sparc.o sections.o \
+ segments.o strproc.o \
symbols.o syminfo.o \
tokens.o time.o \
version.o
@@ -60,10 +61,11 @@ BLTOBJS= arch_msg.o c_literal_msg.o \
deftag_msg.o demangle_msg.o \
dl_msg.o dwarf_msg.o \
dwarf_ehe_msg.o dynamic_msg.o \
- elf_msg.o globals_msg.o \
- group_msg.o lddstub_msg.o \
+ elf_msg.o entry_msg.o \
+ globals_msg.o group_msg.o \
+ map_msg.o lddstub_msg.o \
phdr_msg.o relocate_amd64_msg.o \
- relocate_i386_msg.o relocate_sparc_msg.o \
+ relocate_i386_msg.o relocate_sparc_msg.o \
sections_msg.o segments_msg.o \
symbols_msg.o symbols_sparc_msg.o \
syminfo_msg.o time_msg.o \
@@ -73,8 +75,6 @@ BLTOBJS= arch_msg.o c_literal_msg.o \
OBJECTS = $(COMOBJS) $(COMOBJS32) $(COMOBJS64) $(ELFCAP_OBJS) \
$(ASOBJS) $(BLTOBJS)
-ELFCAP= $(SRC)/common/elfcap
-
#
# This library is unusual since it's a static archive of PIC objects.
# Since static archives should never contain CTF data (regardless of
diff --git a/usr/src/cmd/sgs/libconv/common/c_literal.c b/usr/src/cmd/sgs/libconv/common/c_literal.c
index 8d7d124663..2dc83d2ef8 100644
--- a/usr/src/cmd/sgs/libconv/common/c_literal.c
+++ b/usr/src/cmd/sgs/libconv/common/c_literal.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -137,3 +137,85 @@ conv_str_to_c_literal(const char *buf, size_t n,
}
}
}
+
+/*
+ * Given the pointer to the character following a '\' character in
+ * a C style literal, return the ASCII character code it represents,
+ * and advance the string pointer to the character following the last
+ * character in the escape sequence.
+ *
+ * entry:
+ * str - Address of string pointer to first character following
+ * the backslash.
+ *
+ * exit:
+ * If the character is not valid, -1 is returned. Otherwise
+ * it returns the ASCII code for the translated character, and
+ * *str has been advanced.
+ */
+int
+conv_translate_c_esc(char **str)
+{
+ char *s = *str;
+ int ch, i;
+
+ ch = *s++;
+ switch (ch) {
+ case 'a':
+ ch = '\a';
+ break;
+ case 'b':
+ ch = '\b';
+ break;
+ case 'f':
+ ch = '\f';
+ break;
+ case 'n':
+ ch = '\n';
+ break;
+ case 'r':
+ ch = '\r';
+ break;
+ case 't':
+ ch = '\t';
+ break;
+ case 'v':
+ ch = '\v';
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ /* Octal constant: There can be up to 3 digits */
+ ch -= '0';
+ for (i = 0; i < 2; i++) {
+ if ((*s < '0') || (*s > '7'))
+ break;
+ ch = (ch << 3) + (*s++ - '0');
+ }
+ break;
+
+ /*
+ * There are some cases where ch already has the desired value.
+ * These cases exist simply to remove the special meaning that
+ * character would otherwise have. We need to match them to
+ * prevent them from falling into the default error case.
+ */
+ case '\\':
+ case '\'':
+ case '"':
+ break;
+
+ default:
+ ch = -1;
+ break;
+ }
+
+ *str = s;
+ return (ch);
+}
diff --git a/usr/src/cmd/sgs/libconv/common/cap.c b/usr/src/cmd/sgs/libconv/common/cap.c
index 242b34f54b..f732c381f5 100644
--- a/usr/src/cmd/sgs/libconv/common/cap.c
+++ b/usr/src/cmd/sgs/libconv/common/cap.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -36,13 +36,16 @@
const conv_ds_t **
conv_cap_tag_strings(Conv_fmt_flags_t fmt_flags)
{
+#if (CA_SUNW_NUM != (CA_SUNW_HW_2 + 1))
+#error "CA_SUNW_NUM has grown"
+#endif
static const Msg tags_cf[] = {
MSG_CA_SUNW_NULL_CF, MSG_CA_SUNW_HW_1_CF,
- MSG_CA_SUNW_SF_1_CF
+ MSG_CA_SUNW_SF_1_CF, MSG_CA_SUNW_HW_2_CF
};
static const Msg tags_nf[] = {
MSG_CA_SUNW_NULL_NF, MSG_CA_SUNW_HW_1_NF,
- MSG_CA_SUNW_SF_1_NF
+ MSG_CA_SUNW_SF_1_NF, MSG_CA_SUNW_HW_2_NF,
};
static const conv_ds_msg_t ds_tags_cf = {
CONV_DS_MSG_INIT(ELFCLASSNONE, tags_cf) };
diff --git a/usr/src/cmd/sgs/libconv/common/cap.msg b/usr/src/cmd/sgs/libconv/common/cap.msg
index 286b59e003..4f12ccd160 100644
--- a/usr/src/cmd/sgs/libconv/common/cap.msg
+++ b/usr/src/cmd/sgs/libconv/common/cap.msg
@@ -1,5 +1,5 @@
#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# CDDL HEADER START
@@ -30,6 +30,8 @@
@ MSG_CA_SUNW_HW_1_NF "hw_1"
@ MSG_CA_SUNW_SF_1_CF "CA_SUNW_SF_1" # 2
@ MSG_CA_SUNW_SF_1_NF "sf_1"
+@ MSG_CA_SUNW_HW_2_CF "CA_SUNW_HW_2" # 3
+@ MSG_CA_SUNW_HW_2_NF "hw_2"
@ MSG_GBL_ZERO "0"
@ MSG_GBL_OSQBRKT "0x%llx [ "
diff --git a/usr/src/cmd/sgs/libconv/common/entry.c b/usr/src/cmd/sgs/libconv/common/entry.c
new file mode 100644
index 0000000000..6c8c4e0850
--- /dev/null
+++ b/usr/src/cmd/sgs/libconv/common/entry.c
@@ -0,0 +1,140 @@
+/*
+ * 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 2010 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * String conversion routine for segment flags.
+ */
+#include <string.h>
+#include <libld.h>
+#include "_conv.h"
+#include "entry_msg.h"
+
+#define ENTSZ CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
+ MSG_FLG_EC_BUILTIN_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+ MSG_FLG_EC_USED_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+ MSG_FLG_EC_CATCHALL_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+ CONV_INV_BUFSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
+
+/*
+ * Ensure that Conv_ent_flags_buf_t is large enough:
+ *
+ * ENTSZ is the real minimum size of the buffer required by conv_ent_flags().
+ * However, Conv_ent_flags_buf_t uses CONV_ENT_FLAGS_BUFSIZE to set the
+ * buffer size. We do things this way because the definition of ENTSZ uses
+ * information that is not available in the environment of other programs
+ * that include the conv.h header file.
+ */
+#if (CONV_ENT_FLAGS_BUFSIZE != ENTSZ) && !defined(__lint)
+#define REPORT_BUFSIZE ENTSZ
+#include "report_bufsize.h"
+#error "CONV_ENT_FLAGS_BUFSIZE does not match ENTSZ"
+#endif
+
+const char *
+conv_ent_flags(ec_flags_t flags, Conv_ent_flags_buf_t *ent_flags_buf)
+{
+ static Val_desc vda[] = {
+ { FLG_EC_BUILTIN, MSG_FLG_EC_BUILTIN },
+ { FLG_EC_USED, MSG_FLG_EC_USED },
+ { FLG_EC_CATCHALL, MSG_FLG_EC_CATCHALL },
+ { 0, 0 }
+ };
+ static CONV_EXPN_FIELD_ARG conv_arg = {
+ NULL, sizeof (ent_flags_buf->buf) };
+
+ if (flags == 0)
+ return (MSG_ORIG(MSG_GBL_ZERO));
+
+ conv_arg.buf = ent_flags_buf->buf;
+ conv_arg.oflags = conv_arg.rflags = flags;
+ (void) conv_expn_field(&conv_arg, vda, 0);
+
+ return ((const char *)ent_flags_buf->buf);
+}
+
+
+#define ECFSZ CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
+ MSG_TYP_ECF_PATH_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+ MSG_TYP_ECF_BASENAME_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+ MSG_TYP_ECF_OBJNAME_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+ MSG_FLG_ECF_ARMEMBER_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+ CONV_INV_BUFSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
+
+/*
+ * Ensure that Conv_ent_flags_buf_t is large enough:
+ *
+ * ENTSZ is the real minimum size of the buffer required by conv_ent_flags().
+ * However, Conv_ent_flags_buf_t uses CONV_ENT_FLAGS_BUFSIZE to set the
+ * buffer size. We do things this way because the definition of ENTSZ uses
+ * information that is not available in the environment of other programs
+ * that include the conv.h header file.
+ */
+#if (CONV_ENT_FILES_FLAGS_BUFSIZE != ECFSZ) && !defined(__lint)
+#define REPORT_BUFSIZE ECFSZ
+#include "report_bufsize.h"
+#error "CONV_ENT_FILES_FLAGS_BUFSIZE does not match ECFSZ"
+#endif
+
+/*
+ * Make a string representation of the End_desc_file edf_flags field.
+ */
+const char *
+conv_ent_files_flags(Word flags, Conv_fmt_flags_t fmt_flags,
+ Conv_ent_files_flags_buf_t *flags_buf)
+{
+ static const Msg types[] = {
+ MSG_TYP_ECF_PATH, MSG_TYP_ECF_BASENAME, MSG_TYP_ECF_OBJNAME
+ };
+#if TYP_ECF_NUM != (TYP_ECF_OBJNAME + 1)
+#error "types has grown"
+#endif
+
+ static Val_desc vda[] = {
+ { FLG_ECF_ARMEMBER, MSG_FLG_ECF_ARMEMBER },
+ { 0, 0 }
+ };
+
+ static const char *leading_str_arr[2];
+ static CONV_EXPN_FIELD_ARG conv_arg = {
+ NULL, sizeof (flags_buf->buf), leading_str_arr };
+
+ Word type_idx;
+
+ type_idx = flags & TYP_ECF_MASK;
+ if (type_idx < TYP_ECF_NUM) {
+ leading_str_arr[0] = MSG_ORIG(types[type_idx]);
+ flags &= ~TYP_ECF_MASK;
+ } else {
+ leading_str_arr[0] = NULL;
+ }
+
+ conv_arg.buf = flags_buf->buf;
+ conv_arg.oflags = conv_arg.rflags = flags;
+
+ (void) conv_expn_field(&conv_arg, vda, fmt_flags);
+
+ return (conv_arg.buf);
+}
diff --git a/usr/src/cmd/sgs/libconv/common/entry.msg b/usr/src/cmd/sgs/libconv/common/entry.msg
new file mode 100644
index 0000000000..e93b58ea75
--- /dev/null
+++ b/usr/src/cmd/sgs/libconv/common/entry.msg
@@ -0,0 +1,36 @@
+#
+# 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 2010 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+@ MSG_FLG_EC_BUILTIN "FLG_EC_BUILTIN"
+@ MSG_FLG_EC_USED "FLG_EC_USED"
+@ MSG_FLG_EC_CATCHALL "FLG_EC_CATCHALL"
+
+@ MSG_TYP_ECF_PATH "TYP_ECF_PATH"
+@ MSG_TYP_ECF_BASENAME "TYP_ECF_BASENAME"
+@ MSG_TYP_ECF_OBJNAME "TYP_ECF_OBJNAME"
+@ MSG_FLG_ECF_ARMEMBER "FLG_ECF_ARMEMBER"
+
+@ MSG_GBL_ZERO "0"
diff --git a/usr/src/cmd/sgs/libconv/common/lintsup.c b/usr/src/cmd/sgs/libconv/common/lintsup.c
index 306f562f63..58d58f8405 100644
--- a/usr/src/cmd/sgs/libconv/common/lintsup.c
+++ b/usr/src/cmd/sgs/libconv/common/lintsup.c
@@ -22,7 +22,7 @@
/* PROTOLIB1 */
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -66,9 +66,11 @@
#include "dwarf_msg.h"
#include "dynamic_msg.h"
#include "elf_msg.h"
+#include "entry_msg.h"
#include "globals_msg.h"
#include "group_msg.h"
#include "lddstub_msg.h"
+#include "map_msg.h"
#include "phdr_msg.h"
#include "relocate_amd64_msg.h"
#include "relocate_i386_msg.h"
@@ -99,9 +101,11 @@ foo()
USE(_sgs_msg_libconv_dwarf);
USE(_sgs_msg_libconv_dynamic);
USE(_sgs_msg_libconv_elf);
+ USE(_sgs_msg_libconv_entry);
USE(_sgs_msg_libconv_globals);
USE(_sgs_msg_libconv_group);
USE(_sgs_msg_libconv_lddstub);
+ USE(_sgs_msg_libconv_map);
USE(_sgs_msg_libconv_phdr);
USE(_sgs_msg_libconv_relocate_amd64);
USE(_sgs_msg_libconv_relocate_i386);
diff --git a/usr/src/cmd/sgs/libconv/common/llib-lconv b/usr/src/cmd/sgs/libconv/common/llib-lconv
index 58b2f65b39..623bc8060b 100644
--- a/usr/src/cmd/sgs/libconv/common/llib-lconv
+++ b/usr/src/cmd/sgs/libconv/common/llib-lconv
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* LINTLIBRARY */
@@ -136,9 +136,13 @@ const char *conv_ehdr_type(uchar_t, Half, Conv_fmt_flags_t,
Conv_inv_buf_t *);
const char *conv_ehdr_vers(Word, Conv_fmt_flags_t, Conv_inv_buf_t *);
const char *conv_elfdata_type(Elf_Type, Conv_inv_buf_t *);
+const char *conv_ent_flags(ec_flags_t, Conv_ent_flags_buf_t *);
+const char *conv_ent_filcmp(Word, Conv_fmt_flags_t, Conv_inv_buf_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);
+const char *conv_mapfile_version(Word, Conv_fmt_flags_t,
+ Conv_inv_buf_t *);
const char *conv_phdr_flags(uchar_t, Word, Conv_fmt_flags_t,
Conv_phdr_flags_buf_t *);
const char *conv_phdr_type(uchar_t, Half, Word, Conv_fmt_flags_t,
diff --git a/usr/src/cmd/sgs/libconv/common/map.c b/usr/src/cmd/sgs/libconv/common/map.c
new file mode 100644
index 0000000000..6cb9dc7272
--- /dev/null
+++ b/usr/src/cmd/sgs/libconv/common/map.c
@@ -0,0 +1,52 @@
+/*
+ * 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 2010 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * String conversion routines for mapfile related items.
+ * These items are not ELF constructs. However, we have a need
+ * to display them.
+ */
+#include <stdio.h>
+#include <_conv.h>
+#include <map_msg.h>
+
+const char *
+conv_mapfile_version(Word version, Conv_fmt_flags_t fmt_flags,
+ Conv_inv_buf_t *inv_buf)
+{
+ static const Msg versions[] = {
+ MSG_VER_NONE, MSG_VER_SYSV, MSG_VER_SOLARIS
+ };
+#if MFV_NUM != (MFV_SOLARIS + 1)
+#error "NT_NUM has grown. Update mapfile versions[]"
+#endif
+ static const conv_ds_msg_t ds_versions = {
+ CONV_DS_MSG_INIT(MFV_NONE, versions) };
+ static const conv_ds_t *ds[] = { CONV_DS_ADDR(ds_versions), NULL };
+
+ return (conv_map_ds(ELFOSABI_NONE, EM_NONE, version, ds, fmt_flags,
+ inv_buf));
+}
diff --git a/usr/src/cmd/sgs/libconv/common/map.msg b/usr/src/cmd/sgs/libconv/common/map.msg
new file mode 100644
index 0000000000..e8ff8bd6d6
--- /dev/null
+++ b/usr/src/cmd/sgs/libconv/common/map.msg
@@ -0,0 +1,29 @@
+#
+# 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 2010 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+@ MSG_VER_NONE "none"
+@ MSG_VER_SYSV "SysV"
+@ MSG_VER_SOLARIS "Solaris"
diff --git a/usr/src/cmd/sgs/libconv/common/segments.c b/usr/src/cmd/sgs/libconv/common/segments.c
index d121a4a167..4c89301288 100644
--- a/usr/src/cmd/sgs/libconv/common/segments.c
+++ b/usr/src/cmd/sgs/libconv/common/segments.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -33,19 +33,21 @@
#include "segments_msg.h"
#define SEGSZ CONV_EXPN_FIELD_DEF_PREFIX_SIZE + \
- MSG_FLG_SG_VADDR_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
- MSG_FLG_SG_PADDR_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+ MSG_FLG_SG_P_VADDR_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+ MSG_FLG_SG_P_PADDR_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
MSG_FLG_SG_LENGTH_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
- MSG_FLG_SG_ALIGN_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+ MSG_FLG_SG_P_ALIGN_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
MSG_FLG_SG_ROUND_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
- MSG_FLG_SG_FLAGS_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
- MSG_FLG_SG_TYPE_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
- MSG_FLG_SG_ORDER_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+ MSG_FLG_SG_P_FLAGS_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+ MSG_FLG_SG_P_TYPE_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+ MSG_FLG_SG_IS_ORDER_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
MSG_FLG_SG_NOHDR_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
MSG_FLG_SG_EMPTY_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
MSG_FLG_SG_KEY_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+ MSG_FLG_SG_NODISABLE_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
MSG_FLG_SG_DISABLED_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
MSG_FLG_SG_PHREQ_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
+ MSG_FLG_SG_ORDERED_SIZE + CONV_EXPN_FIELD_DEF_SEP_SIZE + \
CONV_INV_BUFSIZE + CONV_EXPN_FIELD_DEF_SUFFIX_SIZE
/*
@@ -64,22 +66,24 @@
#endif
const char *
-conv_seg_flags(Half flags, Conv_seg_flags_buf_t *seg_flags_buf)
+conv_seg_flags(sg_flags_t flags, Conv_seg_flags_buf_t *seg_flags_buf)
{
static Val_desc vda[] = {
- { FLG_SG_VADDR, MSG_FLG_SG_VADDR },
- { FLG_SG_PADDR, MSG_FLG_SG_PADDR },
+ { FLG_SG_P_VADDR, MSG_FLG_SG_P_VADDR },
+ { FLG_SG_P_PADDR, MSG_FLG_SG_P_PADDR },
{ FLG_SG_LENGTH, MSG_FLG_SG_LENGTH },
- { FLG_SG_ALIGN, MSG_FLG_SG_ALIGN },
+ { FLG_SG_P_ALIGN, MSG_FLG_SG_P_ALIGN },
{ FLG_SG_ROUND, MSG_FLG_SG_ROUND },
- { FLG_SG_FLAGS, MSG_FLG_SG_FLAGS },
- { FLG_SG_TYPE, MSG_FLG_SG_TYPE },
- { FLG_SG_ORDER, MSG_FLG_SG_ORDER },
+ { FLG_SG_P_FLAGS, MSG_FLG_SG_P_FLAGS },
+ { FLG_SG_P_TYPE, MSG_FLG_SG_P_TYPE },
+ { FLG_SG_IS_ORDER, MSG_FLG_SG_IS_ORDER },
{ FLG_SG_NOHDR, MSG_FLG_SG_NOHDR },
{ FLG_SG_EMPTY, MSG_FLG_SG_EMPTY },
{ FLG_SG_KEY, MSG_FLG_SG_KEY },
+ { FLG_SG_NODISABLE, MSG_FLG_SG_NODISABLE },
{ FLG_SG_DISABLED, MSG_FLG_SG_DISABLED },
{ FLG_SG_PHREQ, MSG_FLG_SG_PHREQ },
+ { FLG_SG_ORDERED, MSG_FLG_SG_ORDERED },
{ 0, 0 }
};
static CONV_EXPN_FIELD_ARG conv_arg = {
diff --git a/usr/src/cmd/sgs/libconv/common/segments.msg b/usr/src/cmd/sgs/libconv/common/segments.msg
index 7c9f708c07..619960f172 100644
--- a/usr/src/cmd/sgs/libconv/common/segments.msg
+++ b/usr/src/cmd/sgs/libconv/common/segments.msg
@@ -20,23 +20,24 @@
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-@ MSG_FLG_SG_VADDR "FLG_SG_VADDR"
-@ MSG_FLG_SG_PADDR "FLG_SG_PADDR"
+@ MSG_FLG_SG_P_VADDR "FLG_SG_P_VADDR"
+@ MSG_FLG_SG_P_PADDR "FLG_SG_P_PADDR"
@ MSG_FLG_SG_LENGTH "FLG_SG_LENGTH"
-@ MSG_FLG_SG_ALIGN "FLG_SG_ALIGN"
+@ MSG_FLG_SG_P_ALIGN "FLG_SG_P_ALIGN"
@ MSG_FLG_SG_ROUND "FLG_SG_ROUND"
-@ MSG_FLG_SG_FLAGS "FLG_SG_FLAGS"
-@ MSG_FLG_SG_TYPE "FLG_SG_TYPE"
-@ MSG_FLG_SG_ORDER "FLG_SG_ORDER"
+@ MSG_FLG_SG_P_FLAGS "FLG_SG_P_FLAGS"
+@ MSG_FLG_SG_P_TYPE "FLG_SG_P_TYPE"
+@ MSG_FLG_SG_IS_ORDER "FLG_SG_IS_ORDER"
@ MSG_FLG_SG_NOHDR "FLG_SG_NOHDR"
@ MSG_FLG_SG_EMPTY "FLG_SG_EMPTY"
@ MSG_FLG_SG_KEY "FLG_SG_KEY"
+@ MSG_FLG_SG_NODISABLE "FLG_SG_NODISABLE"
@ MSG_FLG_SG_DISABLED "FLG_SG_DISABLED"
@ MSG_FLG_SG_PHREQ "FLG_SG_PHREQ"
+@ MSG_FLG_SG_ORDERED "FLG_SG_ORDERED"
@ MSG_GBL_ZERO "0"
diff --git a/usr/src/cmd/sgs/libld/Makefile.com b/usr/src/cmd/sgs/libld/Makefile.com
index 8453714c6a..186b4dcfa7 100644
--- a/usr/src/cmd/sgs/libld/Makefile.com
+++ b/usr/src/cmd/sgs/libld/Makefile.com
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
@@ -30,17 +30,19 @@ COMOBJS = debug.o globals.o util.o
COMOBJS32 = args32.o entry32.o exit32.o groups32.o \
ldentry32.o ldlibs32.o ldmachdep32.o ldmain32.o \
- libs32.o files32.o map32.o order32.o \
- outfile32.o place32.o relocate32.o resolve32.o \
- sections32.o sunwmove32.o support32.o syms32.o \
- update32.o unwind32.o version32.o wrap32.o
+ libs32.o files32.o map32.o map_core32.o \
+ map_support32.o map_v232.o order32.o outfile32.o \
+ place32.o relocate32.o resolve32.o sections32.o \
+ sunwmove32.o support32.o syms32.o update32.o \
+ unwind32.o version32.o wrap32.o
COMOBJS64 = args64.o entry64.o exit64.o groups64.o \
ldentry64.o ldlibs64.o ldmachdep64.o ldmain64.o \
- libs64.o files64.o map64.o order64.o \
- outfile64.o place64.o relocate64.o resolve64.o \
- sections64.o sunwmove64.o support64.o syms64.o \
- update64.o unwind64.o version64.o wrap64.o
+ libs64.o files64.o map64.o map_core64.o \
+ map_support64.o map_v264.o order64.o outfile64.o \
+ place64.o relocate64.o resolve64.o sections64.o \
+ sunwmove64.o support64.o syms64.o update64.o \
+ unwind64.o version64.o wrap64.o
TOOLOBJS = alist.o assfail.o findprime.o string_table.o \
strhash.o
@@ -83,7 +85,6 @@ include $(SRC)/lib/Makefile.lib
include $(SRC)/cmd/sgs/Makefile.com
SRCDIR = ../common
-ELFCAP= $(SRC)/common/elfcap
# Location of the shared relocation engines maintained under usr/src/uts.
@@ -94,8 +95,7 @@ KRTLD_SPARC = $(SRCBASE)/uts/$(VAR_PLAT_sparc)/krtld
CPPFLAGS += -DUSE_LIBLD_MALLOC -I$(SRCBASE)/lib/libc/inc \
- -I$(SRCBASE)/uts/common/krtld -I$(ELFCAP) \
- -I$(SRCBASE)/uts/sparc \
+ -I$(SRCBASE)/uts/common/krtld -I$(SRCBASE)/uts/sparc \
$(VAR_LIBLD_CPPFLAGS)
LDLIBS += $(CONVLIBDIR) $(CONV_LIB) $(LDDBGLIBDIR) $(LDDBG_LIB) \
$(ELFLIBDIR) -lelf $(DLLIB) -lc
diff --git a/usr/src/cmd/sgs/libld/common/_libld.h b/usr/src/cmd/sgs/libld/common/_libld.h
index 835eb28b61..e24cb10b21 100644
--- a/usr/src/cmd/sgs/libld/common/_libld.h
+++ b/usr/src/cmd/sgs/libld/common/_libld.h
@@ -23,7 +23,7 @@
* Copyright (c) 1988 AT&T
* All Rights Reserved
*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -68,6 +68,7 @@ typedef struct {
Xword m_segm_origin; /* Default 1st segment origin */
Xword m_segm_aorigin; /* Alternative 1st segment origin */
Word m_dataseg_perm; /* data segment permission mask */
+ Word m_stack_perm; /* ABI default stack permission mask */
Word m_word_align; /* alignment to use for Word sections */
const char *m_def_interp; /* Def. interpreter for dyn objects */
@@ -314,7 +315,7 @@ struct _ld_heap {
* strings that will be created in the .dynstr, with .dynamic entries.
*/
typedef struct {
- char *dft_str; /* dynstr string */
+ const char *dft_str; /* dynstr string */
Word dft_flag; /* auxiliary/filtee type */
Half dft_ndx; /* eventual ndx into .dynamic */
} Dfltr_desc;
@@ -359,8 +360,10 @@ typedef struct {
#define AL_CNT_OS_ISDESCS_BA 4 /* os_isdesc: BEFORE|AFTER */
#define AL_CNT_OS_ISDESCS 60 /* os_isdesc: ORDERED|DEFAULT */
+#define AL_CNT_SG_IS_ORDER 40 /* sg_is_order */
#define AL_CNT_SG_OSDESC 40 /* sg_osdescs */
#define AL_CNT_SG_SECORDER 40 /* sg_secorder */
+#define AL_CNT_SG_SIZESYM 1 /* sg_sizesym */
#define AL_CNT_SDP_GOT 1 /* sd_GOTndxs */
#define AL_CNT_SDP_MOVE 1 /* sd_move */
@@ -533,6 +536,34 @@ typedef struct {
} Isd_node;
/*
+ * Type used to break down an input file path into its component parts,
+ * as used by ld_place_section() to compare an input file path to
+ * entrance criteria ec_files file strings.
+ *
+ * We define a path in the usual Unix '/' separated manner, augmented
+ * with an optional archive member suffix enclosed in parenthesis:
+ *
+ * /dir/.../dir/basename(armember)
+ *
+ * The basename is the final path component, and includes the archive
+ * member, if present. The meaning of "object name" depends on whether or
+ * not the file comes from an archive or not. If not an archive, it is the
+ * same as the basename. If an archive, it is the name of the archive member
+ * from within the file.
+ *
+ * Variables of this type are initialized with ld_place_path_info_init().
+ */
+typedef struct {
+ const char *ppi_path; /* Full path */
+ const char *ppi_bname; /* basename(ppi_path) */
+ const char *ppi_oname; /* object name: Not NULL terminated */
+ Boolean ppi_isar; /* TRUE if path has archive member */
+ size_t ppi_path_len; /* strlen(ppi_path) */
+ size_t ppi_bname_len; /* strlen(ppi_bname) */
+ size_t ppi_oname_len; /* strlen(ppi_oname) */
+} Place_path_info;
+
+/*
* Local data items.
*/
extern char *Plibpath;
@@ -577,6 +608,7 @@ extern Sdf_desc *sdf_find(const char *, APlist *);
#define ld_bswap_Xword ld64_bswap_Xword
#define ld_disp_errmsg ld64_disp_errmsg
#define ld_ent_check ld64_ent_check
+#define ld_ent_lookup ld64_ent_lookup
#define ld_exit ld64_exit
#define ld_find_library ld64_find_library
#define ld_finish_libs ld64_finish_libs
@@ -593,8 +625,10 @@ extern Sdf_desc *sdf_find(const char *, APlist *);
#define ld_make_text ld64_make_text
#define ld_map_out ld64_map_out
#define ld_map_parse ld64_map_parse
+#define ld_map_post_process ld64_map_post_process
#define ld_open_outfile ld64_open_outfile
#define ld_os_first_isdesc ld64_os_first_isdesc
+#define ld_place_path_info_init ld64_place_path_info_init
#define ld_place_section ld64_place_section
#define ld_process_archive ld64_process_archive
#define ld_process_files ld64_process_files
@@ -610,8 +644,8 @@ extern Sdf_desc *sdf_find(const char *, APlist *);
#define ld_reloc_targval_get ld64_reloc_targval_get
#define ld_reloc_targval_set ld64_reloc_targval_set
#define ld_sec_validate ld64_sec_validate
+#define ld_seg_lookup ld64_seg_lookup
#define ld_sort_ordered ld64_sort_ordered
-#define ld_sort_seg_list ld64_sort_seg_list
#define ld_stt_section_sym_name ld64_stt_section_sym_name
#define ld_sunw_ldmach ld64_sunw_ldmach
#define ld_sup_atexit ld64_sup_atexit
@@ -665,6 +699,7 @@ extern Sdf_desc *sdf_find(const char *, APlist *);
#define ld_bswap_Xword ld32_bswap_Xword
#define ld_disp_errmsg ld32_disp_errmsg
#define ld_ent_check ld32_ent_check
+#define ld_ent_lookup ld32_ent_lookup
#define ld_exit ld32_exit
#define ld_find_library ld32_find_library
#define ld_finish_libs ld32_finish_libs
@@ -681,8 +716,10 @@ extern Sdf_desc *sdf_find(const char *, APlist *);
#define ld_make_text ld32_make_text
#define ld_map_out ld32_map_out
#define ld_map_parse ld32_map_parse
+#define ld_map_post_process ld32_map_post_process
#define ld_open_outfile ld32_open_outfile
#define ld_os_first_isdesc ld32_os_first_isdesc
+#define ld_place_path_info_init ld32_place_path_info_init
#define ld_place_section ld32_place_section
#define ld_process_archive ld32_process_archive
#define ld_process_files ld32_process_files
@@ -698,8 +735,8 @@ extern Sdf_desc *sdf_find(const char *, APlist *);
#define ld_reloc_targval_get ld32_reloc_targval_get
#define ld_reloc_targval_set ld32_reloc_targval_set
#define ld_sec_validate ld32_sec_validate
+#define ld_seg_lookup ld32_seg_lookup
#define ld_sort_ordered ld32_sort_ordered
-#define ld_sort_seg_list ld32_sort_seg_list
#define ld_stt_section_sym_name ld32_stt_section_sym_name
#define ld_sunw_ldmach ld32_sunw_ldmach
#define ld_sup_atexit ld32_sup_atexit
@@ -763,6 +800,8 @@ extern Xword ld_bswap_Xword(Xword);
extern void ld_disp_errmsg(const char *, Rel_desc *, Ofl_desc *);
extern void ld_ent_check(Ofl_desc *);
+extern Ent_desc *ld_ent_lookup(Ofl_desc *, const char *name,
+ avl_index_t *where);
extern int ld_exit(Ofl_desc *);
extern uintptr_t ld_find_library(const char *, Ofl_desc *);
@@ -786,13 +825,16 @@ extern uintptr_t ld_make_parexpn_data(Ofl_desc *, size_t, Xword);
extern uintptr_t ld_make_sunwmove(Ofl_desc *, int);
extern Is_desc *ld_make_text(Ofl_desc *, size_t);
extern void ld_map_out(Ofl_desc *);
-extern uintptr_t ld_map_parse(const char *, Ofl_desc *);
+extern Boolean ld_map_parse(const char *, Ofl_desc *);
+extern Boolean ld_map_post_process(Ofl_desc *);
extern uintptr_t ld_open_outfile(Ofl_desc *);
extern Is_desc *ld_os_first_isdesc(Os_desc *);
-extern Os_desc *ld_place_section(Ofl_desc *, Is_desc *, int,
- const char *);
+extern Place_path_info *ld_place_path_info_init(Ofl_desc *, Ifl_desc *,
+ Place_path_info *);
+extern Os_desc *ld_place_section(Ofl_desc *, Is_desc *,
+ Place_path_info *path_info, int, const char *);
extern uintptr_t ld_process_archive(const char *, int, Ar_desc *,
Ofl_desc *);
extern uintptr_t ld_process_files(Ofl_desc *, int, char **);
@@ -802,7 +844,8 @@ extern Ifl_desc *ld_process_ifl(const char *, const char *, int, Elf *,
extern uintptr_t ld_process_move(Ofl_desc *);
extern Ifl_desc *ld_process_open(const char *, const char *, int *,
Ofl_desc *, Word, Rej_desc *);
-extern uintptr_t ld_process_ordered(Ifl_desc *, Ofl_desc *, Word);
+extern uintptr_t ld_process_ordered(Ofl_desc *, Ifl_desc *,
+ Place_path_info *path_info, Word);
extern uintptr_t ld_process_sym_reloc(Ofl_desc *, Rel_desc *, Rel *,
Is_desc *, const char *, Word);
@@ -815,9 +858,10 @@ extern int ld_reloc_targval_get(Ofl_desc *, Rel_desc *,
extern int ld_reloc_targval_set(Ofl_desc *, Rel_desc *,
uchar_t *, Xword);
+extern Sg_desc *ld_seg_lookup(Ofl_desc *, const char *,
+ avl_index_t *where);
extern void ld_sec_validate(Ofl_desc *);
extern uintptr_t ld_sort_ordered(Ofl_desc *);
-extern uintptr_t ld_sort_seg_list(Ofl_desc *);
extern Half ld_sunw_ldmach();
extern void ld_sup_atexit(Ofl_desc *, int);
extern void ld_sup_open(Ofl_desc *, const char **, const char **,
diff --git a/usr/src/cmd/sgs/libld/common/_map.h b/usr/src/cmd/sgs/libld/common/_map.h
new file mode 100644
index 0000000000..68d7baa07e
--- /dev/null
+++ b/usr/src/cmd/sgs/libld/common/_map.h
@@ -0,0 +1,367 @@
+/*
+ * 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 2010 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Local include file for libld mapfile subsystem.
+ */
+
+#ifndef _MAP_DOT_H
+#define _MAP_DOT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Macro used to size name buffer corresponding to a NULL terminated array
+ * of structures each of which contains a name string. Macro is used per-name.
+ * 2 extra characters are allowed per item to allow for a ', ' delimiter
+ * or NULL termination.
+ */
+#define KW_NAME_SIZE(_size) (_size##_SIZE + 2)
+
+/*
+ * Variant of isspace() that excludes newline characters. Requires <ctype.h>.
+ */
+#define isspace_nonl(_s) (isspace(_s) && ((_s) != '\n'))
+
+/*
+ * Type used to insert NULL characters in the mapfile text and later
+ * back them out and restore the original character. The mapfile text
+ * is held in a single string, so when we want to access sub-strings,
+ * it is necessary to temporarily insert NULLs to prevent the entire
+ * mapfile from that point forward being output.
+ */
+typedef struct {
+ char *np_ptr; /* Address patched with NULL character */
+ char np_ch; /* Character originally found at *np_ptr */
+} ld_map_npatch_t;
+
+/*
+ * ld_map_gettoken() uses a table of 128 bytes to determine how to
+ * process a token starting with any 7-bit ASCII value. The table is
+ * indexed by the character code, and returns one of the TK_* token values.
+ */
+typedef const char mf_tokdisp_t[128];
+
+/*
+ * The definition of an unquoted identifier differs based on the mapfile
+ * version. Rather than write a separate function to locate identifiers
+ * for each version, we use a single function that relies on a per-character
+ * table that encodes which characters can start an identifier, and which
+ * can continue one, for each supported mapfile version.
+ *
+ * Two bits are used for each version, one for the start attribute, and the
+ * other for continuation. The first two bits are not used (version 0), the
+ * next 2 are used for version 1, the following 2 for version 2, and so on.
+ */
+#define TKID_ATTR_B_START 1
+#define TKID_ATTR_B_CONT 2
+
+#define TKID_ATTR_START(_ver) (TKID_ATTR_B_START << (_ver * 2))
+#define TKID_ATTR_CONT(_ver) (TKID_ATTR_B_CONT << (_ver * 2))
+
+/* Convenience macros for chars that both start and continue an identifier */
+#define TKID_ATTR(_ver) ((TKID_ATTR_B_START | TKID_ATTR_B_CONT) << (_ver * 2))
+
+/*
+ * State for a mapfile held in memory.
+ */
+typedef struct {
+ Ofl_desc *mf_ofl; /* Output descriptor being processed */
+ char *mf_name; /* Mapfile name */
+ Ifl_desc *mf_ifl; /* NULL, or pseudo input file */
+ /* descriptor from ld_map_ifl() */
+ char *mf_text; /* Text of mapfile */
+ char *mf_next; /* Next char in mapfile to examine */
+ const char *mf_tokdisp; /* mf_tokdisp_t dispatch table to use */
+ Lineno mf_lineno; /* Line # within mf_text */
+ int mf_version; /* Mapfile syntax version */
+ int mf_tkid_start; /* TKID bitvalue for characters that */
+ /* start an unquoted identifier */
+ int mf_tkid_cont; /* TKID bitvalue for characters that */
+ /* continue an unquoted ident. */
+ int mf_next_ch; /* 0, or character read from *mf_next */
+ /* prior to inserting NULL */
+ Aliste mf_ec_insndx; /* Insert index for entrance criteria */
+ /* Each mapfile starts at the */
+ /* top, inserting each ec in the */
+ /* file in the order seen. */
+} Mapfile;
+
+/*
+ * A very large percentage of mapfile errors start with the
+ * calling sequence:
+ * eprintf(ofl->ofl_lml, ERR_XXX, format, mf->mf_name,
+ * mf->mf_lineno...)
+ * The mf_fatal() and mf_warn() varadic macros are used to supply all
+ * of boilerplate, resulting in visually simpler code.
+ *
+ * mf_fatal0()/mf_warn0() are used when the format does not require any
+ * additional arguments and the varargs list is empty. The GNU cpp has a
+ * syntax for eliminating the extra comma (, ##__VA_ARGS__), but this isn't
+ * supported by the Sun compilers yet.
+ */
+#define mf_fatal0(_mf, _fmt) \
+ eprintf((_mf)->mf_ofl->ofl_lml, ERR_FATAL, _fmt, (_mf)->mf_name, \
+ EC_LINENO((_mf)->mf_lineno))
+#define mf_fatal(_mf, _fmt, ...) \
+ eprintf((_mf)->mf_ofl->ofl_lml, ERR_FATAL, _fmt, (_mf)->mf_name, \
+ EC_LINENO((_mf)->mf_lineno), __VA_ARGS__)
+
+#define mf_warn0(_mf, _fmt) \
+ eprintf((_mf)->mf_ofl->ofl_lml, ERR_WARNING, _fmt, (_mf)->mf_name, \
+ EC_LINENO((_mf)->mf_lineno))
+#define mf_warn(_mf, _fmt, ...) \
+ eprintf((_mf)->mf_ofl->ofl_lml, ERR_WARNING, _fmt, (_mf)->mf_name, \
+ EC_LINENO((_mf)->mf_lineno), __VA_ARGS__)
+
+/* Possible return values from ld_map_gettoken */
+typedef enum {
+ TK_ERROR = -1, /* Error in lexical analysis */
+ TK_EOF = 0, /* End of file: Requires TK_F_EOFOK to be set */
+ /* or EOF results in TK_ERROR */
+ TK_STRING = 1, /* String literal */
+ TK_COLON = 2, /* : */
+ TK_SEMICOLON = 3, /* ; */
+ TK_EQUAL = 4, /* = */
+ TK_PLUSEQ = 5, /* += */
+ TK_MINUSEQ = 6, /* -= */
+ TK_ATSIGN = 7, /* @ */
+ TK_DASH = 8, /* - */
+ TK_LEFTBKT = 9, /* { */
+ TK_RIGHTBKT = 10, /* } */
+ TK_PIPE = 11, /* | */
+ TK_INT = 12, /* Integer value: Unsigned machine word */
+ TK_STAR = 13, /* * */
+ TK_BANG = 14, /* ! */
+
+ /*
+ * Items below this point are for the use of ld_map_gettoken().
+ * They indicate a character that requires the lexical analyzer
+ * to carry out some additional computation (OPeration), resulting
+ * in one of the simple token types above, which is returned to
+ * the caller. The TK_OP_ tokens are implementation details that are
+ * never returned to a caller of ld_map_gettoken().
+ */
+ TK_OP_EOF, /* end of file */
+ TK_OP_ILLCHR, /* unprintable illegal character */
+ TK_OP_BADCHR, /* printable but unexpected character */
+ TK_OP_WS, /* whitespace */
+ TK_OP_NL, /* newline */
+ TK_OP_SIMQUOTE, /* simple quoting */
+ TK_OP_CQUOTE, /* quoting with C string literal escapes */
+ TK_OP_CMT, /* Comment */
+ TK_OP_CDIR, /* Control directive */
+ TK_OP_NUM, /* Decimial, hex, or octal value */
+ TK_OP_ID, /* unquoted identifier using syntax rules */
+ /* appropriate for mapfile version */
+ TK_OP_CEQUAL, /* One of += or -= */
+} Token;
+
+/*
+ * Type used by ld_map_gettoken() to return values for token types that
+ * have them.
+ */
+typedef union {
+ char *tkv_str; /* TK_STRING */
+ struct { /* TK_INT */
+ char *tkvi_str; /* String making up integer */
+ size_t tkvi_cnt; /* # characters in tkvi_str */
+ Xword tkvi_value; /* Resulting value */
+ } tkv_int;
+} ld_map_tkval_t;
+
+/*
+ * Values for gettoken() flags argument. These flags are used to
+ * alter gettoken() default behavior under certain conditions.
+ */
+#define TK_F_EOFOK 1 /* Quietly return TK_EOF instead of normal */
+ /* TK_ERROR "premature EOF" error */
+#define TK_F_STRLC 2 /* TK_STRING: Convert string to lowercase */
+#define TK_F_KEYWORD 4 /* For directives and attributes: Disallow */
+ /* quoted TK_STRING tokens */
+
+/*
+ * Possible return values from ld_map_strtoxword()
+ */
+typedef enum {
+ STRTOXWORD_OK, /* Operation successful */
+ STRTOXWORD_TOOBIG, /* Otherwise valid value is too large */
+ STRTOXWORD_BAD /* String not recognized as an integer */
+} ld_map_strtoxword_t;
+
+/*
+ * Possible return values from ld_map_seg_insert()
+ */
+typedef enum {
+ SEG_INS_OK = 0, /* Segment was inserted */
+ SEG_INS_FAIL = 1, /* Segment not inserted --- fatal */
+ SEG_INS_SKIP = 2 /* Segment not inserted --- ignore */
+} ld_map_seg_ins_t;
+
+/*
+ * Enumeration of different symbol scope possible in a mapfile
+ */
+typedef enum {
+ FLG_SCOPE_HIDD, /* symbol defined hidden/local */
+ FLG_SCOPE_DFLT, /* symbol defined default/global */
+ FLG_SCOPE_PROT, /* symbol defined protected/symbolic */
+ FLG_SCOPE_EXPT, /* symbol defined exported */
+ FLG_SCOPE_SNGL, /* symbol defined singleton */
+ FLG_SCOPE_ELIM /* symbol defined eliminate */
+} ld_map_scope_t;
+
+/* State of a mapfile symbol version */
+typedef struct {
+ const char *mv_name; /* NULL, or version name */
+ Ver_desc *mv_vdp; /* Descriptor for version */
+ ld_map_scope_t mv_scope; /* Current scope type */
+ size_t mv_errcnt; /* Count of errors against version */
+} ld_map_ver_t;
+
+/* State of a mapfile symbol definition */
+typedef struct {
+ const char *ms_name; /* symbol name */
+ sd_flag_t ms_sdflags; /* 0 / mapfile set flags */
+ Word ms_shndx; /* SHN_UNDEF / mapfile set sec index */
+ uchar_t ms_type; /* STT_NOTYPE / mapfile set type */
+ Addr ms_value; /* user set value, if ms_value_set */
+ Addr ms_size; /* 0 / mapfile set size */
+ const char *ms_filtee; /* NULL or filtee name */
+ Boolean ms_value_set; /* TRUE if ms_value set, even if to 0 */
+ Word ms_dft_flag; /* 0, or type of filter in ms_filtee */
+} ld_map_sym_t;
+
+#if defined(_ELF64)
+
+#define ld_map_cap_sanitize ld64_map_cap_sanitize
+#define ld_map_cap_set_ovflag ld64_map_cap_set_ovflag
+#define ld_map_dv ld64_map_dv
+#define ld_map_dv_entry ld64_map_dv_entry
+#define ld_map_gettoken ld64_map_gettoken
+#define ld_map_ifl ld64_map_ifl
+#define ld_map_parse_v1 ld64_map_parse_v1
+#define ld_map_parse_v2 ld64_map_parse_v2
+#define ld_map_seg_alloc ld64_map_seg_alloc
+#define ld_map_seg_ent_add ld64_map_seg_ent_add
+#define ld_map_seg_ent_files ld64_map_seg_ent_files
+#define ld_map_seg_index ld64_map_seg_index
+#define ld_map_seg_insert ld64_map_seg_insert
+#define ld_map_seg_lookup ld64_map_seg_lookup
+#define ld_map_seg_os_order_add ld64_map_seg_os_order_add
+#define ld_map_seg_size_symbol ld64_map_seg_size_symbol
+#define ld_map_seg_stack ld64_map_seg_stack
+#define ld_map_strtoxword ld64_map_strtoxword
+#define ld_map_sym_enter ld64_map_sym_enter
+#define ld_map_sym_filtee ld64_map_sym_filtee
+#define ld_map_sym_scope ld64_map_sym_scope
+#define ld_map_sym_autoreduce ld64_map_sym_autoreduce
+#define ld_map_sym_ver_fini ld64_map_sym_ver_fini
+#define ld_map_sym_ver_init ld64_map_sym_ver_init
+#define ld_map_tokenstr ld64_map_tokenstr
+
+#else
+
+#define ld_map_cap_sanitize ld32_map_cap_sanitize
+#define ld_map_cap_set_ovflag ld32_map_cap_set_ovflag
+#define ld_map_dv ld32_map_dv
+#define ld_map_dv_entry ld32_map_dv_entry
+#define ld_map_gettoken ld32_map_gettoken
+#define ld_map_ifl ld32_map_ifl
+#define ld_map_parse_v1 ld32_map_parse_v1
+#define ld_map_parse_v2 ld32_map_parse_v2
+#define ld_map_seg_alloc ld32_map_seg_alloc
+#define ld_map_seg_ent_add ld32_map_seg_ent_add
+#define ld_map_seg_ent_files ld32_map_seg_ent_files
+#define ld_map_seg_index ld32_map_seg_index
+#define ld_map_seg_insert ld32_map_seg_insert
+#define ld_map_seg_lookup ld32_map_seg_lookup
+#define ld_map_seg_os_order_add ld32_map_seg_os_order_add
+#define ld_map_seg_size_symbol ld32_map_seg_size_symbol
+#define ld_map_seg_stack ld32_map_seg_stack
+#define ld_map_strtoxword ld32_map_strtoxword
+#define ld_map_sym_enter ld32_map_sym_enter
+#define ld_map_sym_filtee ld32_map_sym_filtee
+#define ld_map_sym_scope ld32_map_sym_scope
+#define ld_map_sym_autoreduce ld32_map_sym_autoreduce
+#define ld_map_sym_ver_fini ld32_map_sym_ver_fini
+#define ld_map_sym_ver_init ld32_map_sym_ver_init
+#define ld_map_tokenstr ld32_map_tokenstr
+
+#endif
+
+/*
+ * Core functions used to parse mapfiles
+ */
+extern void ld_map_lowercase(char *);
+extern Token ld_map_gettoken(Mapfile *, int, ld_map_tkval_t *);
+extern Boolean ld_map_parse_v1(Mapfile *);
+extern Boolean ld_map_parse_v2(Mapfile *);
+extern ld_map_strtoxword_t ld_map_strtoxword(const char *restrict,
+ char **restrict, Xword *);
+extern const char *ld_map_tokenstr(Token, ld_map_tkval_t *,
+ Conv_inv_buf_t *);
+
+/*
+ * Support code shared between the different mapfile parsing code, used to
+ * provide a common implementation manipulating link-editor state.
+ */
+extern Boolean ld_map_cap_sanitize(Mapfile *, Word, CapMask *);
+extern void ld_map_cap_set_ovflag(Mapfile *, Word);
+extern void *ld_map_kwfind(const char *, void *, size_t, size_t);
+extern char *ld_map_kwnames(void *, size_t, size_t, char *, size_t);
+extern Sdf_desc *ld_map_dv(Mapfile *, const char *);
+extern Boolean ld_map_dv_entry(Mapfile *, Sdf_desc *, Boolean,
+ const char *);
+extern Ifl_desc *ld_map_ifl(Mapfile *);
+extern Sg_desc *ld_map_seg_alloc(const char *, Word, sg_flags_t);
+extern Ent_desc *ld_map_seg_ent_add(Mapfile *, Sg_desc *, const char *);
+extern Boolean ld_map_seg_ent_files(Mapfile *mf, Ent_desc *,
+ Word, const char *);
+extern Xword ld_map_seg_index(Mapfile *, Sg_desc *);
+extern ld_map_seg_ins_t ld_map_seg_insert(Mapfile *, dbg_state_t, Sg_desc *,
+ avl_index_t where);
+extern Boolean ld_map_seg_os_order_add(Mapfile *, Sg_desc *,
+ const char *);
+extern Boolean ld_map_seg_size_symbol(Mapfile *, Sg_desc *, Token,
+ const char *symname);
+extern Sg_desc *ld_map_seg_stack(Mapfile *);
+extern Boolean ld_map_sym_enter(Mapfile *, ld_map_ver_t *,
+ ld_map_sym_t *);
+extern void ld_map_sym_filtee(Mapfile *, ld_map_ver_t *,
+ ld_map_sym_t *, Word, const char *);
+extern void ld_map_sym_scope(Mapfile *, const char *,
+ ld_map_ver_t *);
+extern void ld_map_sym_autoreduce(Mapfile *, ld_map_ver_t *);
+extern Boolean ld_map_sym_ver_fini(Mapfile *, ld_map_ver_t *);
+extern Boolean ld_map_sym_ver_init(Mapfile *, char *, ld_map_ver_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MAP_DOT_H */
diff --git a/usr/src/cmd/sgs/libld/common/args.c b/usr/src/cmd/sgs/libld/common/args.c
index a79cc69b45..f768f109b8 100644
--- a/usr/src/cmd/sgs/libld/common/args.c
+++ b/usr/src/cmd/sgs/libld/common/args.c
@@ -23,7 +23,7 @@
* Copyright (c) 1988 AT&T
* All Rights Reserved
*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -636,46 +636,20 @@ check_flags(Ofl_desc * ofl, int argc)
return (S_ERROR);
/*
- * Process any mapfiles after establishing the entrance criteria as
- * the user may be redefining or adding sections/segments.
+ * Process mapfiles. Mapfile can redefine or add sections/segments,
+ * so this must come after the default entrance criteria are established
+ * (above).
*/
if (ofl->ofl_maps) {
const char *name;
Aliste idx;
- Is_desc *isp;
for (APLIST_TRAVERSE(ofl->ofl_maps, idx, name))
- if (ld_map_parse(name, ofl) == S_ERROR)
+ if (!ld_map_parse(name, ofl))
return (S_ERROR);
- if (ofl->ofl_flags & FLG_OF_SEGSORT)
- if (ld_sort_seg_list(ofl) == S_ERROR)
- return (S_ERROR);
-
- /*
- * Mapfiles may have been used to create symbol definitions
- * with backing storage. Although the backing storage is
- * associated with an input section, the association of the
- * section to an output section (and segment) is initially
- * deferred. Now that all mapfile processing is complete, any
- * entrance criteria requirements have been processed, and
- * these backing storage sections can be associated with the
- * appropriate output section (and segment).
- */
- if (ofl->ofl_maptext || ofl->ofl_mapdata)
- DBG_CALL(Dbg_sec_backing(ofl->ofl_lml));
-
- for (APLIST_TRAVERSE(ofl->ofl_maptext, idx, isp)) {
- if (ld_place_section(ofl, isp,
- ld_targ.t_id.id_text, NULL) == (Os_desc *)S_ERROR)
- return (S_ERROR);
- }
-
- for (APLIST_TRAVERSE(ofl->ofl_mapdata, idx, isp)) {
- if (ld_place_section(ofl, isp,
- ld_targ.t_id.id_data, NULL) == (Os_desc *)S_ERROR)
- return (S_ERROR);
- }
+ if (!ld_map_post_process(ofl))
+ return (S_ERROR);
}
/*
@@ -1934,10 +1908,10 @@ ld_process_files(Ofl_desc *ofl, int argc, char **argv)
return (S_ERROR);
/*
- * If segment ordering was specified (using mapfile) verify things
- * are ok.
+ * If input section ordering was specified within some segment
+ * using a mapfile, verify that the expected sections were seen.
*/
- if (ofl->ofl_flags & FLG_OF_SEGORDER)
+ if (ofl->ofl_flags & FLG_OF_IS_ORDER)
ld_ent_check(ofl);
return (1);
diff --git a/usr/src/cmd/sgs/libld/common/debug.c b/usr/src/cmd/sgs/libld/common/debug.c
index 127a921987..28d2464307 100644
--- a/usr/src/cmd/sgs/libld/common/debug.c
+++ b/usr/src/cmd/sgs/libld/common/debug.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -122,9 +122,11 @@ dbg_setup(Ofl_desc *ofl, const char *options, int phase)
}
/*
- * Now that the output file is established, generate help
- * output if the user specified the debug help token.
+ * Now that the output file is established, identify the linker
+ * package, and generate help output if the user specified the
+ * debug help token.
*/
+ Dbg_version();
if (dbg_desc->d_extra & DBG_E_HELP)
Dbg_help();
diff --git a/usr/src/cmd/sgs/libld/common/entry.c b/usr/src/cmd/sgs/libld/common/entry.c
index c6bfb1acd2..0309ad7b0d 100644
--- a/usr/src/cmd/sgs/libld/common/entry.c
+++ b/usr/src/cmd/sgs/libld/common/entry.c
@@ -23,7 +23,7 @@
* Copyright (c) 1988 AT&T
* All Rights Reserved
*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -36,16 +36,15 @@
#include "_libld.h"
/*
- * The loader uses a `segment descriptor' list to describe the output
- * segments it can potentially create. This list is initially seeded
- * using the templates contained in the sg_desc[] array below. Additional
- * segments may be added using a mapfile.
+ * The link-editor uses a segment descriptor list to describe the program
+ * headers, and related output segments, it can potentially create. This
+ * list is initially seeded using the templates contained in the sg_desc
+ * array below. Additional segments may be added using a mapfile.
*
- * The entries in sg_desc[] must be put in the order defined by the
- * Segment_id enum, such that a given LD_XXX value can serve as
- * an index into sg_desc[] for the corresponding descriptor.
+ * The entries in sg_desc must be put in the order defined by the
+ * Segment_id enum.
*
- * The entries in sg_desc[] are initialized using the SG_DESC_INIT macro
+ * The entries in sg_desc are initialized using the SG_DESC_INIT macro
* for two reasons:
*
* 1) The first field of the Sg_desc struct is a program header
@@ -54,110 +53,275 @@
* to handle this transparently.
* 2) Most of the fields in the Sg_desc entries are set to 0.
* Use of a macro allows us to hide the clutter.
+ *
+ * If a given program header can be referenced via an entrance criteria
+ * (i.e. can serve as a segment), then it must be given a unique sg_name.
+ * Program headers that cannot be a segment (PHDR, INTERP, DYNAMIC, etc)
+ * must have a NULL sg_name --- their program header type identifies them.
*/
#ifdef _ELF64
#define SG_DESC_INIT(id, p_type, p_flags, sg_name, sg_flags) \
{ id, { p_type, p_flags, 0, 0, 0, 0, 0, 0}, \
- sg_name, 0, 0, NULL, NULL, sg_flags, NULL, 0, NULL}
+ sg_name, 0, 0, NULL, NULL, NULL, sg_flags, NULL, 0, NULL}
#else
#define SG_DESC_INIT(id, p_type, p_flags, sg_name, sg_flags) \
{ id, { p_type, 0, 0, 0, 0, 0, p_flags, 0}, \
- sg_name, 0, 0, NULL, NULL, sg_flags, NULL, 0, NULL}
+ sg_name, 0, 0, NULL, NULL, NULL, sg_flags, NULL, 0, NULL}
#endif
-static const Sg_desc sg_desc[LD_NUM] = {
- SG_DESC_INIT(LD_PHDR, PT_PHDR, PF_R + PF_X, MSG_ORIG(MSG_ENT_PHDR),
- (FLG_SG_TYPE | FLG_SG_FLAGS)),
-
- SG_DESC_INIT(LD_INTERP, PT_INTERP, PF_R, MSG_ORIG(MSG_ENT_INTERP),
- (FLG_SG_TYPE | FLG_SG_FLAGS)),
-
- SG_DESC_INIT(LD_SUNWCAP, PT_SUNWCAP, PF_R, MSG_ORIG(MSG_ENT_SUNWCAP),
- (FLG_SG_TYPE | FLG_SG_FLAGS)),
-
- SG_DESC_INIT(LD_TEXT, PT_LOAD, PF_R + PF_X, MSG_ORIG(MSG_ENT_TEXT),
- (FLG_SG_TYPE | FLG_SG_FLAGS)),
-
- SG_DESC_INIT(LD_DATA, PT_LOAD, 0, MSG_ORIG(MSG_ENT_DATA),
- (FLG_SG_TYPE | FLG_SG_FLAGS)),
-
- SG_DESC_INIT(LD_BSS, PT_LOAD, 0, MSG_ORIG(MSG_ENT_BSS),
- (FLG_SG_TYPE | FLG_SG_FLAGS | FLG_SG_DISABLED)),
+/*
+ * Predefined segment descriptors:
+ *
+ * The C language guarantees that a structure containing only fields of
+ * identical type is indistinguishable from a simple array containing
+ * the same number of items of the same type. They will have the same
+ * size, alignment, and internal layout:
+ *
+ * - A pointer to one is equivalent to a pointer to the other, and you
+ * can cast safely between them.
+ *
+ * - You can put both into a union, and access the elements within
+ * either way (by index, or by name).
+ *
+ * We use this fact here to create an "array" of predefined segment
+ * descriptors, assigning each one a mnemonic name that can be used to point
+ * at it from a predefined entrance criteria descriptor (below). These
+ * segments are positioned in the default order that will result in the
+ * output object, unless a mapfile alters things.
+ */
+typedef struct {
+ Sg_desc psg_phdr;
+ Sg_desc psg_interp;
+ Sg_desc psg_sunwcap;
+ Sg_desc psg_text;
+ Sg_desc psg_data;
+ Sg_desc psg_bss;
+#if defined(_ELF64)
+ Sg_desc psg_lrodata; /* (amd64-only) */
+ Sg_desc psg_ldata; /* (amd64-only) */
+#endif
+ Sg_desc psg_dynamic;
+ Sg_desc psg_sunwdtrace;
+ Sg_desc psg_tls;
+ Sg_desc psg_unwind;
+ Sg_desc psg_sunwstack;
+ Sg_desc psg_note;
+ Sg_desc psg_extra;
+} predef_seg_t;
+
+static const size_t predef_seg_nelts =
+ (sizeof (predef_seg_t) / sizeof (Sg_desc));
+
+static predef_seg_t sg_desc = {
+ /* psg_phdr */
+ SG_DESC_INIT(SGID_PHDR, PT_PHDR, PF_R + PF_X, NULL,
+ (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
+
+ /* psg_interp */
+ SG_DESC_INIT(SGID_INTERP, PT_INTERP, PF_R, NULL,
+ (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
+
+ /* psg_sunwcap */
+ SG_DESC_INIT(SGID_SUNWCAP, PT_SUNWCAP, PF_R, NULL,
+ (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
+
+ /* psg_text */
+ SG_DESC_INIT(SGID_TEXT, PT_LOAD, PF_R + PF_X, MSG_ORIG(MSG_ENT_TEXT),
+ (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
+
+ /* psg_data */
+ SG_DESC_INIT(SGID_DATA, PT_LOAD, 0, MSG_ORIG(MSG_ENT_DATA),
+ (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
+
+ /* psg_bss */
+ SG_DESC_INIT(SGID_BSS, PT_LOAD, 0, MSG_ORIG(MSG_ENT_BSS),
+ (FLG_SG_P_TYPE | FLG_SG_P_FLAGS | FLG_SG_DISABLED)),
#if defined(_ELF64)
- /* (amd64-only) */
- SG_DESC_INIT(LD_LRODATA, PT_LOAD, PF_R, MSG_ORIG(MSG_ENT_LRODATA),
- (FLG_SG_TYPE | FLG_SG_FLAGS)),
+ /* psg_lrodata (amd64-only ) */
+ SG_DESC_INIT(SGID_LRODATA, PT_LOAD, PF_R, MSG_ORIG(MSG_ENT_LRODATA),
+ (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
- /* (amd64-only) */
- SG_DESC_INIT(LD_LDATA, PT_LOAD, 0, MSG_ORIG(MSG_ENT_LDATA),
- (FLG_SG_TYPE | FLG_SG_FLAGS)),
+ /* psg_ldata (amd64-only ) */
+ SG_DESC_INIT(SGID_LDATA, PT_LOAD, 0, MSG_ORIG(MSG_ENT_LDATA),
+ (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
#endif
- SG_DESC_INIT(LD_DYN, PT_DYNAMIC, 0, MSG_ORIG(MSG_ENT_DYNAMIC),
- (FLG_SG_TYPE | FLG_SG_FLAGS)),
+ /* psg_dynamic */
+ SG_DESC_INIT(SGID_DYN, PT_DYNAMIC, 0, NULL,
+ (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
+
+ /* psg_sunwdtrace */
+ SG_DESC_INIT(SGID_DTRACE, PT_SUNWDTRACE, 0, NULL,
+ (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
- SG_DESC_INIT(LD_DTRACE, PT_SUNWDTRACE, 0, MSG_ORIG(MSG_ENT_DTRACE),
- (FLG_SG_TYPE | FLG_SG_FLAGS)),
+ /* psg_tls */
+ SG_DESC_INIT(SGID_TLS, PT_TLS, PF_R, NULL,
+ (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
- SG_DESC_INIT(LD_TLS, PT_TLS, PF_R, MSG_ORIG(MSG_ENT_TLS),
- (FLG_SG_TYPE | FLG_SG_FLAGS)),
+ /* psg_unwind */
+ SG_DESC_INIT(SGID_UNWIND, PT_SUNW_UNWIND, PF_R, NULL,
+ (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
- SG_DESC_INIT(LD_UNWIND, PT_SUNW_UNWIND, PF_R, MSG_ORIG(MSG_ENT_UNWIND),
- (FLG_SG_TYPE | FLG_SG_FLAGS)),
+ /* psg_sunwstack */
+ SG_DESC_INIT(SGID_SUNWSTACK, PT_SUNWSTACK, 0, NULL,
+ (FLG_SG_P_TYPE | FLG_SG_P_FLAGS | FLG_SG_DISABLED)),
- SG_DESC_INIT(LD_NOTE, PT_NOTE, 0, MSG_ORIG(MSG_ENT_NOTE), FLG_SG_TYPE),
+ /* psg_note */
+ SG_DESC_INIT(SGID_NOTE, PT_NOTE, 0, MSG_ORIG(MSG_ENT_NOTE),
+ FLG_SG_P_TYPE),
- SG_DESC_INIT(LD_EXTRA, PT_NULL, 0, MSG_ORIG(MSG_ENT_EXTRA), FLG_SG_TYPE)
+ /*
+ * psg_extra
+ *
+ * This segment is referenced by the final entrance criteria descriptor
+ * to catch any segment not otherwise placed. It cannot be disabled
+ * via a mapfile.
+ */
+ SG_DESC_INIT(SGID_EXTRA, PT_NULL, 0, MSG_ORIG(MSG_ENT_EXTRA),
+ (FLG_SG_P_TYPE | FLG_SG_NODISABLE))
};
+#undef SG_DESC_INIT
/*
* The processing of input files by the link-editor involves matching the
- * files sections to an `entrance descriptor definition'. The entrance
- * criteria can be modified further using a mapfile. Each entrance criteria
- * is associated with a segment descriptor, thus a mapping of input sections
- * to output segments is maintained.
+ * input file sections against an ordered list of entrance criteria
+ * descriptors. The following template defines the built in entrance criteria
+ * list. This list can be augmented using a mapfile. Each entrance criteria
+ * is associated with a segment descriptor, providing the means for mapping
+ * input sections to output segments.
*
- * Note the trick used for the ec_segment field, which is supposed to be a
- * pointer to a segment descriptor. We initialize this with the index of the
- * descriptor, and then turn it into an actual pointer at runtime, once memory
- * has been allocated and the templates copied.
+ * As with the segment descriptors, the EC_DESC_INIT macro is used
+ * to reduce boilerplate clutter.
*/
+#define EC_DESC_INIT(ec_type, ec_attrmask, ec_attrbits, _seg_field, ec_flags) \
+ { NULL, NULL, NULL, ec_type, ec_attrmask, ec_attrbits, \
+ &sg_desc.psg_ ## _seg_field, 0, FLG_EC_BUILTIN | ec_flags }
+
static const Ent_desc ent_desc[] = {
- {NULL, MSG_ORIG(MSG_ENT_NOTE), SHT_NOTE, 0, 0,
- (Sg_desc *)LD_NOTE, 0, FLG_EC_BUILTIN},
+ EC_DESC_INIT(SHT_NOTE, 0, 0, note, 0),
+
#if defined(_ELF64) /* (amd64-only) */
- {NULL, MSG_ORIG(MSG_ENT_LRODATA), NULL,
- SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE,
- SHF_ALLOC + SHF_AMD64_LARGE,
- (Sg_desc *)LD_LRODATA, 0, FLG_EC_BUILTIN},
+ EC_DESC_INIT(0, SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE,
+ SHF_ALLOC + SHF_AMD64_LARGE, lrodata, 0),
#endif
- {NULL, MSG_ORIG(MSG_ENT_TEXT), NULL,
- SHF_ALLOC + SHF_WRITE, SHF_ALLOC,
- (Sg_desc *)LD_TEXT, 0, FLG_EC_BUILTIN},
+ EC_DESC_INIT(0, SHF_ALLOC + SHF_WRITE, SHF_ALLOC, text, 0),
- {NULL, MSG_ORIG(MSG_ENT_BSS), SHT_NOBITS,
- SHF_ALLOC + SHF_WRITE, SHF_ALLOC + SHF_WRITE,
- (Sg_desc *)LD_BSS, 0, FLG_EC_BUILTIN},
+ EC_DESC_INIT(SHT_NOBITS, SHF_ALLOC + SHF_WRITE, SHF_ALLOC + SHF_WRITE,
+ bss, 0),
#if defined(_ELF64) /* (amd64-only) */
- {NULL, MSG_ORIG(MSG_ENT_LBSS), SHT_NOBITS,
- SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE,
- SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE,
- (Sg_desc *)LD_DATA, 0, FLG_EC_BUILTIN},
-
- {NULL, MSG_ORIG(MSG_ENT_LDATA), NULL,
- SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE,
- SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE,
- (Sg_desc *)LD_LDATA, 0, FLG_EC_BUILTIN},
+ EC_DESC_INIT(SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE,
+ SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE, data, 0),
+
+ EC_DESC_INIT(0, SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE,
+ SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE, ldata, 0),
#endif
- {NULL, MSG_ORIG(MSG_ENT_DATA), NULL,
- SHF_ALLOC + SHF_WRITE, SHF_ALLOC + SHF_WRITE,
- (Sg_desc *)LD_DATA, 0, FLG_EC_BUILTIN},
+ EC_DESC_INIT(0, SHF_ALLOC + SHF_WRITE, SHF_ALLOC + SHF_WRITE, data, 0),
- {NULL, MSG_ORIG(MSG_ENT_EXTRA), 0, 0, 0,
- (Sg_desc *)LD_EXTRA, 0, FLG_EC_BUILTIN}
+ /*
+ * Final catchall rule sends remaining sections to "extra"
+ * NULL segment, which has been tagged as FLG_SG_NODISABLE,
+ * and which will therefore always accept them.
+ */
+ EC_DESC_INIT(0, 0, 0, extra, FLG_EC_CATCHALL)
};
+#undef EC_DESC_INIT
+
+/*
+ * AVL comparison function for Sg_desc items in ofl_segs_avl.
+ *
+ * entry:
+ * n1, n2 - pointers to nodes to be compared
+ *
+ * exit:
+ * Returns -1 if (n1 < n2), 0 if they are equal, and 1 if (n1 > n2)
+ */
+static int
+ofl_segs_avl_cmp(const void *n1, const void *n2)
+{
+ int rc;
+
+ rc = strcmp(((Sg_desc *)n1)->sg_name, ((Sg_desc *)n2)->sg_name);
+
+ if (rc > 0)
+ return (1);
+ if (rc < 0)
+ return (-1);
+ return (0);
+}
+
+/*
+ * AVL comparison function for Ent_desc items in ofl_ents_avl.
+ *
+ * entry:
+ * n1, n2 - pointers to nodes to be compared
+ *
+ * exit:
+ * Returns -1 if (n1 < n2), 0 if they are equal, and 1 if (n1 > n2)
+ */
+static int
+ofl_ents_avl_cmp(const void *n1, const void *n2)
+{
+ int rc;
+
+ /*
+ * There are entrance criteria nodes with NULL pointer names,
+ * but they are never entered into the AVL tree. Hence, we can
+ * assume that both nodes have names.
+ */
+ rc = strcmp(((Ent_desc *)n1)->ec_name, ((Ent_desc *)n2)->ec_name);
+
+ if (rc > 0)
+ return (1);
+ if (rc < 0)
+ return (-1);
+ return (0);
+}
+
+/*
+ * Lookup a segment descriptor by name.
+ *
+ * entry:
+ * ofl - Output descriptor
+ * name - Name of desired segment
+ *
+ * exit:
+ * On success, returns pointer to descriptor. On failure, returns NULL.
+ */
+Sg_desc *
+ld_seg_lookup(Ofl_desc *ofl, const char *name, avl_index_t *where)
+{
+ Sg_desc sg;
+
+ sg.sg_name = name;
+ return (avl_find(&ofl->ofl_segs_avl, &sg, where));
+}
+
+
+/*
+ * Look up an entrance criteria record by name
+ *
+ * entry:
+ * mf - Mapfile descriptor
+ * name - Name of entrance criteria to locate
+ *
+ * exit:
+ * On success, a pointer to the entrace criteria record is
+ * returned. On failure, NULL is returned.
+ *
+ * note:
+ * Entrance criteria are not required to have names. Only
+ * named entrance criteria can be looked up via this method.
+ */
+Ent_desc *
+ld_ent_lookup(Ofl_desc *ofl, const char *name, avl_index_t *where)
+{
+ Ent_desc en;
+
+ en.ec_name = name;
+ return (avl_find(&ofl->ofl_ents_avl, &en, where));
+}
/*
* Initialize new entrance and segment descriptors and add them as lists to
@@ -166,7 +330,8 @@ static const Ent_desc ent_desc[] = {
uintptr_t
ld_ent_setup(Ofl_desc *ofl, Xword segalign)
{
- const Ent_desc *oenp;
+ Ent_desc *enp;
+ predef_seg_t *psegs;
Sg_desc *sgp;
size_t idx;
@@ -185,6 +350,15 @@ ld_ent_setup(Ofl_desc *ofl, Xword segalign)
avl_create(&ofl->ofl_symavl, &ld_sym_avl_comp, sizeof (Sym_avlnode),
SGSOFFSETOF(Sym_avlnode, sav_node));
+ /* Initialize segment AVL tree */
+ avl_create(&ofl->ofl_segs_avl, ofl_segs_avl_cmp,
+ sizeof (Sg_desc), SGSOFFSETOF(Sg_desc, sg_avlnode));
+
+ /* Initialize entrance criteria AVL tree */
+ avl_create(&ofl->ofl_ents_avl, ofl_ents_avl_cmp, sizeof (Ent_desc),
+ SGSOFFSETOF(Ent_desc, ec_avlnode));
+
+
/*
* Allocate and initialize writable copies of both the entrance and
* segment descriptors.
@@ -193,12 +367,13 @@ ld_ent_setup(Ofl_desc *ofl, Xword segalign)
* elements than are needed. For now, we are willing to overallocate
* a small amount to simplify the code.
*/
- if ((sgp = libld_malloc(sizeof (sg_desc))) == NULL)
+ if ((psegs = libld_malloc(sizeof (sg_desc))) == NULL)
return (S_ERROR);
- (void) memcpy(sgp, sg_desc, sizeof (sg_desc));
+ (void) memcpy(psegs, &sg_desc, sizeof (sg_desc));
+ sgp = (Sg_desc *) psegs;
/*
- * The data segment permissions can differ:
+ * The data segment and stack permissions can differ:
*
* - Architecural/ABI per-platform differences
* - Whether the object is built statically or dynamically
@@ -206,16 +381,17 @@ ld_ent_setup(Ofl_desc *ofl, Xword segalign)
* Those segments so affected have their program header flags
* set here at runtime, rather than in the sg_desc templates above.
*/
- sgp[LD_DATA].sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm;
- sgp[LD_BSS].sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm;
- sgp[LD_DYN].sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm;
- sgp[LD_DTRACE].sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm;
+ psegs->psg_data.sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm;
+ psegs->psg_bss.sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm;
+ psegs->psg_dynamic.sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm;
+ psegs->psg_sunwdtrace.sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm;
#if defined(_ELF64)
- sgp[LD_LDATA].sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm;
- sgp[LD_DTRACE].sg_phdr.p_flags |= PF_X;
+ psegs->psg_ldata.sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm;
+ psegs->psg_sunwdtrace.sg_phdr.p_flags |= PF_X;
#endif
+ psegs->psg_sunwstack.sg_phdr.p_flags = ld_targ.t_m.m_stack_perm;
if ((ofl->ofl_flags & FLG_OF_DYNAMIC) == 0)
- sgp[LD_DATA].sg_phdr.p_flags |= PF_X;
+ psegs->psg_data.sg_phdr.p_flags |= PF_X;
/*
* Traverse the new entrance descriptor list converting the segment
@@ -223,45 +399,82 @@ ld_ent_setup(Ofl_desc *ofl, Xword segalign)
* descriptor list. Add each entrance descriptor to the output file
* list.
*/
- for (idx = 0, oenp = ent_desc;
- idx < (sizeof (ent_desc) / sizeof (ent_desc[0])); idx++, oenp++) {
- Ent_desc *nenp;
+ if ((enp = libld_malloc(sizeof (ent_desc))) == NULL)
+ return (S_ERROR);
+ (void) memcpy(enp, ent_desc, sizeof (ent_desc));
+ for (idx = 0; idx < (sizeof (ent_desc) / sizeof (ent_desc[0])); idx++,
+ enp++) {
#if defined(_ELF64)
/* Don't use the amd64 entry conditions for non-amd64 targets */
- if ((oenp->ec_attrmask & SHF_AMD64_LARGE) &&
+ if ((enp->ec_attrmask & SHF_AMD64_LARGE) &&
(ld_targ.t_m.m_mach != EM_AMD64))
continue;
#endif
- if ((nenp = alist_append(&(ofl->ofl_ents), oenp,
- sizeof (Ent_desc), AL_CNT_OFL_ENTRANCE)) == NULL)
+ if (aplist_append(&ofl->ofl_ents, enp,
+ AL_CNT_OFL_ENTRANCE) == NULL)
return (S_ERROR);
- nenp->ec_segment = &sgp[(long)oenp->ec_segment];
+ /*
+ * The segment pointer is currently pointing at a template
+ * segment descriptor in sg_desc. Compute its array index,
+ * and then use that index to compute the address of the
+ * corresponding descriptor in the writable copy.
+ */
+ enp->ec_segment =
+ &sgp[(enp->ec_segment - (Sg_desc *) &sg_desc)];
}
/*
- * Traverse the new segment descriptor list adding each entry to the
- * segment descriptor list. For each loadable segment initialize
- * a default alignment (ld(1) and ld.so.1 initialize this differently).
+ * Add each segment descriptor to the segment descriptor list. The
+ * ones with non-NULL sg_name are also entered into the AVL tree.
+ * For each loadable segment initialize a default alignment. Note
+ * that ld(1) and ld.so.1 initialize this differently.
*/
- for (idx = 0; idx < LD_NUM; idx++, sgp++) {
+ for (idx = 0; idx < predef_seg_nelts; idx++, sgp++) {
Phdr *phdr = &(sgp->sg_phdr);
#if defined(_ELF64)
/* Ignore amd64 segment templates for non-amd64 targets */
- switch (idx) {
- case LD_LRODATA:
- case LD_LDATA:
+ switch (sgp->sg_id) {
+ case SGID_LRODATA:
+ case SGID_LDATA:
if ((ld_targ.t_m.m_mach != EM_AMD64))
continue;
}
#endif
+ if (phdr->p_type == PT_LOAD)
+ phdr->p_align = segalign;
+
if ((aplist_append(&ofl->ofl_segs, sgp,
AL_CNT_SEGMENTS)) == NULL)
return (S_ERROR);
- if (phdr->p_type == PT_LOAD)
- phdr->p_align = segalign;
+
+#ifdef NDEBUG /* assert() is enabled */
+ /*
+ * Enforce the segment name rule: Any segment that can
+ * be referenced by an entrance descriptor must have
+ * a name. Any segment that cannot, must have a NULL
+ * name pointer.
+ */
+ switch (phdr->p_type) {
+ case PT_LOAD:
+ case PT_NOTE:
+ case PT_NULL:
+ assert(sgp->sg_name != NULL);
+ break;
+ default:
+ assert(sgp->sg_name == NULL);
+ break;
+ }
+#endif
+
+ /*
+ * Add named segment descriptors to the AVL tree to
+ * provide O(logN) lookups.
+ */
+ if (sgp->sg_name != NULL)
+ avl_add(&ofl->ofl_segs_avl, sgp);
}
return (1);
diff --git a/usr/src/cmd/sgs/libld/common/files.c b/usr/src/cmd/sgs/libld/common/files.c
index e251f3a47b..dfdb5a4658 100644
--- a/usr/src/cmd/sgs/libld/common/files.c
+++ b/usr/src/cmd/sgs/libld/common/files.c
@@ -23,7 +23,7 @@
* Copyright (c) 1988 AT&T
* All Rights Reserved
*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -240,15 +240,17 @@ process_section(const char *name, Ifl_desc *ifl, Shdr *shdr, Elf_Scn *scn,
static void
sf1_cap(Ofl_desc *ofl, Xword val, Ifl_desc *ifl, Is_desc *cisp)
{
+#define FP_FLAGS (SF1_SUNW_FPKNWN | SF1_SUNW_FPUSED)
+
Xword badval;
/*
* If a mapfile has established definitions to override any input
* capabilities, ignore any new input capabilities.
*/
- if (ofl->ofl_flags1 & FLG_OF1_OVSFCAP) {
- Dbg_cap_sec_entry(ofl->ofl_lml, DBG_CAP_IGNORE, CA_SUNW_SF_1,
- val, ld_targ.t_m.m_mach);
+ if (ofl->ofl_flags1 & FLG_OF1_OVSFCAP1) {
+ DBG_CALL(Dbg_cap_entry(ofl->ofl_lml, DBG_STATE_IGNORED,
+ CA_SUNW_SF_1, val, ld_targ.t_m.m_mach));
return;
}
@@ -284,7 +286,7 @@ sf1_cap(Ofl_desc *ofl, Xword val, Ifl_desc *ifl, Is_desc *cisp)
EC_XWORD(badval));
val &= SF1_SUNW_MASK;
}
- if ((val & (SF1_SUNW_FPKNWN | SF1_SUNW_FPUSED)) == SF1_SUNW_FPUSED) {
+ if ((val & FP_FLAGS) == SF1_SUNW_FPUSED) {
eprintf(ofl->ofl_lml, ERR_WARNING, MSG_INTL(MSG_FIL_BADSF1),
ifl->ifl_name, EC_WORD(cisp->is_scnndx), cisp->is_name,
EC_XWORD(val));
@@ -307,7 +309,8 @@ sf1_cap(Ofl_desc *ofl, Xword val, Ifl_desc *ifl, Is_desc *cisp)
* The runtime linker will refuse to use this dependency.
*/
if ((val & SF1_SUNW_ADDR32) && (ofl->ofl_flags & FLG_OF_EXEC) &&
- ((ofl->ofl_sfcap_1 & SF1_SUNW_ADDR32) == 0)) {
+ ((ofl->ofl_ocapset.c_sf_1.cm_value &
+ SF1_SUNW_ADDR32) == 0)) {
eprintf(ofl->ofl_lml, ERR_WARNING,
MSG_INTL(MSG_FIL_EXADDR32SF1), ifl->ifl_name,
EC_WORD(cisp->is_scnndx), cisp->is_name);
@@ -316,35 +319,49 @@ sf1_cap(Ofl_desc *ofl, Xword val, Ifl_desc *ifl, Is_desc *cisp)
return;
}
- Dbg_cap_sec_entry(ofl->ofl_lml, DBG_CAP_OLD, CA_SUNW_SF_1,
- ofl->ofl_sfcap_1, ld_targ.t_m.m_mach);
- Dbg_cap_sec_entry(ofl->ofl_lml, DBG_CAP_NEW, CA_SUNW_SF_1,
- val, ld_targ.t_m.m_mach);
+ if (DBG_ENABLED) {
+ Dbg_cap_entry2(ofl->ofl_lml, DBG_STATE_CURRENT, CA_SUNW_SF_1,
+ &ofl->ofl_ocapset.c_sf_1, ld_targ.t_m.m_mach);
+ Dbg_cap_entry(ofl->ofl_lml, DBG_STATE_NEW, CA_SUNW_SF_1,
+ val, ld_targ.t_m.m_mach);
+ }
/*
* Determine the resolution of the present frame pointer and the
* new input relocatable objects frame pointer.
*/
- if ((ofl->ofl_sfcap_1 & (SF1_SUNW_FPKNWN | SF1_SUNW_FPUSED)) ==
- (SF1_SUNW_FPKNWN | SF1_SUNW_FPUSED)) {
+ if ((ofl->ofl_ocapset.c_sf_1.cm_value & FP_FLAGS) == FP_FLAGS) {
/*
* If the new relocatable object isn't using a frame pointer,
* reduce the present state to unused.
*/
- if ((val & (SF1_SUNW_FPKNWN | SF1_SUNW_FPUSED)) !=
- (SF1_SUNW_FPKNWN | SF1_SUNW_FPUSED))
- ofl->ofl_sfcap_1 &= ~SF1_SUNW_FPUSED;
+ if ((val & FP_FLAGS) != FP_FLAGS)
+ ofl->ofl_ocapset.c_sf_1.cm_value &= ~SF1_SUNW_FPUSED;
- } else if ((ofl->ofl_sfcap_1 & SF1_SUNW_FPKNWN) == 0) {
/*
- * If the present state is unknown, take the new relocatable
- * object frame pointer usage.
+ * Having processed the frame pointer bits, remove them from
+ * the value so they don't get OR'd in below.
*/
- ofl->ofl_sfcap_1 = val;
+ val &= ~FP_FLAGS;
+
+ } else if ((ofl->ofl_ocapset.c_sf_1.cm_value & SF1_SUNW_FPKNWN) == 0) {
+ /*
+ * If the present frame pointer state is unknown, mask it out
+ * and allow the values from the new relocatable object
+ * to overwrite them.
+ */
+ ofl->ofl_ocapset.c_sf_1.cm_value &= ~FP_FLAGS;
+ } else {
+ /* Do not take the frame pointer flags from the object */
+ val &= ~FP_FLAGS;
}
- Dbg_cap_sec_entry(ofl->ofl_lml, DBG_CAP_RESOLVED, CA_SUNW_SF_1,
- ofl->ofl_sfcap_1, ld_targ.t_m.m_mach);
+ ofl->ofl_ocapset.c_sf_1.cm_value |= val;
+
+ DBG_CALL(Dbg_cap_entry2(ofl->ofl_lml, DBG_STATE_RESOLVED, CA_SUNW_SF_1,
+ &ofl->ofl_ocapset.c_sf_1, ld_targ.t_m.m_mach));
+
+#undef FP_FLAGS
}
/*
@@ -360,9 +377,9 @@ hw1_cap(Ofl_desc *ofl, Xword val)
* If a mapfile has established definitions to override any input
* capabilities, ignore any new input capabilities.
*/
- if (ofl->ofl_flags1 & FLG_OF1_OVHWCAP) {
- Dbg_cap_sec_entry(ofl->ofl_lml, DBG_CAP_IGNORE, CA_SUNW_HW_1,
- val, ld_targ.t_m.m_mach);
+ if (ofl->ofl_flags1 & FLG_OF1_OVHWCAP1) {
+ DBG_CALL(Dbg_cap_entry(ofl->ofl_lml, DBG_STATE_IGNORED,
+ CA_SUNW_HW_1, val, ld_targ.t_m.m_mach));
return;
}
@@ -373,15 +390,17 @@ hw1_cap(Ofl_desc *ofl, Xword val)
if (val == 0)
return;
- Dbg_cap_sec_entry(ofl->ofl_lml, DBG_CAP_OLD, CA_SUNW_HW_1,
- ofl->ofl_hwcap_1, ld_targ.t_m.m_mach);
- Dbg_cap_sec_entry(ofl->ofl_lml, DBG_CAP_NEW, CA_SUNW_HW_1, val,
- ld_targ.t_m.m_mach);
+ if (DBG_ENABLED) {
+ Dbg_cap_entry2(ofl->ofl_lml, DBG_STATE_CURRENT, CA_SUNW_HW_1,
+ &ofl->ofl_ocapset.c_hw_1, ld_targ.t_m.m_mach);
+ Dbg_cap_entry(ofl->ofl_lml, DBG_STATE_NEW, CA_SUNW_HW_1, val,
+ ld_targ.t_m.m_mach);
+ }
- ofl->ofl_hwcap_1 |= val;
+ ofl->ofl_ocapset.c_hw_1.cm_value |= val;
- Dbg_cap_sec_entry(ofl->ofl_lml, DBG_CAP_RESOLVED, CA_SUNW_HW_1,
- ofl->ofl_hwcap_1, ld_targ.t_m.m_mach);
+ DBG_CALL(Dbg_cap_entry2(ofl->ofl_lml, DBG_STATE_RESOLVED, CA_SUNW_HW_1,
+ &ofl->ofl_ocapset.c_hw_1, ld_targ.t_m.m_mach));
}
/*
@@ -1608,6 +1627,14 @@ process_elf(Ifl_desc *ifl, Elf *elf, Ofl_desc *ofl)
uintptr_t error;
Is_desc *vdfisp, *vndisp, *vsyisp, *sifisp, *capisp;
Sdf_desc *sdf;
+ Place_path_info path_info_buf, *path_info;
+
+ /*
+ * Path information buffer used by ld_place_section() and related
+ * routines. This information is used to evaluate entrance criteria
+ * with non-empty file matching lists (ec_files).
+ */
+ path_info = ld_place_path_info_init(ofl, ifl, &path_info_buf);
/*
* First process the .shstrtab section so that later sections can
@@ -1895,7 +1922,7 @@ process_elf(Ifl_desc *ifl, Elf *elf, Ofl_desc *ofl)
* output section.
*/
if ((isp->is_flags & FLG_IS_ORDERED) == 0) {
- if (ld_place_section(ofl, isp,
+ if (ld_place_section(ofl, isp, path_info,
isp->is_keyident, NULL) == (Os_desc *)S_ERROR)
return (S_ERROR);
continue;
@@ -1926,7 +1953,8 @@ process_elf(Ifl_desc *ifl, Elf *elf, Ofl_desc *ofl)
continue;
/* ld_process_ordered() calls ld_place_section() */
- if (ld_process_ordered(ifl, ofl, ndx) == S_ERROR)
+ if (ld_process_ordered(ofl, ifl, path_info, ndx) ==
+ S_ERROR)
return (S_ERROR);
/* If we've done them all, stop searching */
diff --git a/usr/src/cmd/sgs/libld/common/ldentry.c b/usr/src/cmd/sgs/libld/common/ldentry.c
index 02381df3dd..27cfd9437f 100644
--- a/usr/src/cmd/sgs/libld/common/ldentry.c
+++ b/usr/src/cmd/sgs/libld/common/ldentry.c
@@ -23,7 +23,7 @@
* Copyright (c) 1988 AT&T
* All Rights Reserved
*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -197,23 +197,27 @@ ld_ent_check(Ofl_desc * ofl)
* one for criterias where a filename is used and the other
* for those without a filename.
*/
- for (ALIST_TRAVERSE(ofl->ofl_ents, ndx, enp)) {
- const char *file;
-
- if (((enp->ec_segment->sg_flags & FLG_SG_ORDER) == 0) ||
+ for (APLIST_TRAVERSE(ofl->ofl_ents, ndx, enp)) {
+ /*
+ * No warning if any of the following hold:
+ * - The segment has no entrance criteria requiring
+ * input section sorting (FLG_SG_IS_ORDER not set).
+ * - The entrance criteria was used to place a section.
+ * - The specific entrance criteria does not require sorting
+ */
+ if (((enp->ec_segment->sg_flags & FLG_SG_IS_ORDER) == 0) ||
(enp->ec_flags & FLG_EC_USED) || (enp->ec_ordndx == 0))
continue;
- if (enp->ec_files &&
- ((file = enp->ec_files->apl_data[0]) != NULL)) {
+ if (alist_nitems(enp->ec_files) > 0) {
eprintf(ofl->ofl_lml, ERR_WARNING,
MSG_INTL(MSG_ENT_NOSEC_1), enp->ec_segment->sg_name,
- enp->ec_name, file);
+ enp->ec_is_name);
} else {
eprintf(ofl->ofl_lml, ERR_WARNING,
MSG_INTL(MSG_ENT_NOSEC_2), enp->ec_segment->sg_name,
- enp->ec_name);
+ enp->ec_is_name);
}
}
}
diff --git a/usr/src/cmd/sgs/libld/common/ldmain.c b/usr/src/cmd/sgs/libld/common/ldmain.c
index 3549b5c63b..826fd798f3 100644
--- a/usr/src/cmd/sgs/libld/common/ldmain.c
+++ b/usr/src/cmd/sgs/libld/common/ldmain.c
@@ -23,7 +23,7 @@
* Copyright (c) 1988 AT&T
* All Rights Reserved
*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -212,7 +212,7 @@ ld_main(int argc, char **argv, Half mach)
DBG_CALL(Dbg_ent_print(ofl->ofl_lml,
ofl->ofl_dehdr->e_ident[EI_OSABI], ofl->ofl_dehdr->e_machine,
- ofl->ofl_ents, (ofl->ofl_flags & FLG_OF_DYNAMIC) != 0));
+ ofl->ofl_ents));
DBG_CALL(Dbg_seg_list(ofl->ofl_lml,
ofl->ofl_dehdr->e_ident[EI_OSABI], ofl->ofl_dehdr->e_machine,
ofl->ofl_segs));
@@ -332,7 +332,7 @@ ld_main(int argc, char **argv, Half mach)
* for any directives that have not been matched.
* Also, if SHF_ORDERED sections exist, set up sort key values.
*/
- if (ofl->ofl_flags & (FLG_OF_SECORDER | FLG_OF_KEY))
+ if (ofl->ofl_flags & (FLG_OF_OS_ORDER | FLG_OF_KEY))
ld_sec_validate(ofl);
/*
diff --git a/usr/src/cmd/sgs/libld/common/libld.intel.msg b/usr/src/cmd/sgs/libld/common/libld.intel.msg
index 98e3e0ad6b..f24b505737 100644
--- a/usr/src/cmd/sgs/libld/common/libld.intel.msg
+++ b/usr/src/cmd/sgs/libld/common/libld.intel.msg
@@ -20,11 +20,9 @@
#
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
@ _START_
@@ -35,7 +33,7 @@
instruction sequence"
@ MSG_PLT_PLT0FAIL "creation of PLT entry plt0 failed"
-@ MSG_PLT_PLTNFAIL "creation of PLT[%d] for symbol `%s' failed"
+@ MSG_PLT_PLTNFAIL "creation of PLT[%d] for symbol '%s' failed"
@ MSG_UNW_BADCIEVERS "unwind table: file %s: section %s: \
bad cie version %d: offset 0x%llx\n"
diff --git a/usr/src/cmd/sgs/libld/common/libld.msg b/usr/src/cmd/sgs/libld/common/libld.msg
index e7c50bae5a..c0f3445cf1 100644
--- a/usr/src/cmd/sgs/libld/common/libld.msg
+++ b/usr/src/cmd/sgs/libld/common/libld.msg
@@ -20,7 +20,7 @@
#
#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
@@ -52,7 +52,7 @@
# usage: ld [-6:abc:.....] file(s)
# [-a] create an absolute file
# [-b] do not do special PIC relocations in a.out
-# [-c file] record configuration `file'
+# [-c file] record configuration 'file'
#
@ MSG_ARG_USAGE "usage: ld [-%s] file(s)\n"
@ MSG_ARG_DETAIL_3 "\t[-32]\t\tenforce a 32-bit link-edit\n"
@@ -74,12 +74,12 @@
@ MSG_ARG_DETAIL_CBS "\t[-B symbolic]\tbind external references to \
definitions when creating\n\
\t\t\tshared objects\n"
-@ MSG_ARG_DETAIL_C "\t[-c name]\trecord configuration file `name'\n"
+@ MSG_ARG_DETAIL_C "\t[-c name]\trecord configuration file 'name'\n"
@ MSG_ARG_DETAIL_CC "\t[-C]\t\tdemangle C++ symbol name diagnostics\n"
@ MSG_ARG_DETAIL_D "\t[-d y | n]\toperate in dynamic|static mode\n"
@ MSG_ARG_DETAIL_CD "\t[-D token,...]\tprint diagnostic messages\n"
@ MSG_ARG_DETAIL_E "\t[-e epsym], [--entry epsym]\n\
- \t\t\tuse `epsym' as entry point address\n"
+ \t\t\tuse 'epsym' as entry point address\n"
@ MSG_ARG_DETAIL_F "\t[-f name], [--auxiliary name]\n\
\t\t\tspecify library for which this file is an \
auxiliary\n\t\t\tfilter\n"
@@ -88,20 +88,20 @@
@ MSG_ARG_DETAIL_CG "\t[-G], [-shared]\n\
\t\t\tcreate a shared object\n"
@ MSG_ARG_DETAIL_H "\t[-h name], [--soname name]\n\
- \t\t\tuse `name' as internal shared object identifier\n"
+ \t\t\tuse 'name' as internal shared object identifier\n"
@ MSG_ARG_DETAIL_I "\t[-i]\t\tignore LD_LIBRARY_PATH setting\n"
-@ MSG_ARG_DETAIL_CI "\t[-I name]\tuse `name' as path of interpreter\n"
+@ MSG_ARG_DETAIL_CI "\t[-I name]\tuse 'name' as path of interpreter\n"
@ MSG_ARG_DETAIL_L "\t[-l x], [--library x]\n\
\t\t\tsearch for libx.so or libx.a\n"
@ MSG_ARG_DETAIL_CL "\t[-L path], [--library-path path]\n\
- \t\t\tsearch for libraries in directory `path'\n"
+ \t\t\tsearch for libraries in directory 'path'\n"
@ MSG_ARG_DETAIL_M "\t[-m]\t\tprint memory map\n"
@ MSG_ARG_DETAIL_CM "\t[-M mapfile]\tuse processing directives contained \
- in `mapfile'\n"
+ in 'mapfile'\n"
@ MSG_ARG_DETAIL_CN "\t[-N string]\tcreate a dynamic dependency for \
- `string'\n"
+ 'string'\n"
@ MSG_ARG_DETAIL_O "\t[-o outfile], [--output outfile]\n\
- \t\t\tname the output file `outfile'\n"
+ \t\t\tname the output file 'outfile'\n"
@ MSG_ARG_DETAIL_P "\t[-p auditlib]\tidentify audit library to accompany \
this object\n"
@ MSG_ARG_DETAIL_CP "\t[-P auditlib]\tidentify audit library for \
@@ -121,10 +121,10 @@
@ MSG_ARG_DETAIL_T "\t[-t]\t\tdo not warn of multiply-defined symbols \
that have\n\t\t\tdifferent sizes or alignments\n"
@ MSG_ARG_DETAIL_U "\t[-u symname], [--undefined symname]\n\
- \t\t\tcreate an undefined symbol `symname'\n"
+ \t\t\tcreate an undefined symbol 'symname'\n"
@ MSG_ARG_DETAIL_CV "\t[-V], [--version]\n\
\t\t\tprint version information\n"
-@ MSG_ARG_DETAIL_CY "\t[-Y P,dirlist]\tuse `dirlist' as a default path \
+@ MSG_ARG_DETAIL_CY "\t[-Y P,dirlist]\tuse 'dirlist' as a default path \
when searching for\n\
\t\t\tlibraries\n"
@ MSG_ARG_DETAIL_ZA "\t[-z absexec]\twhen building an executable absolute \
@@ -170,7 +170,7 @@
\t\t\tbe executed before the .init section of any \
other\n\t\t\tobjects\n"
@ MSG_ARG_DETAIL_ZINT "\t[-z interpose]\
- \tdynamic object is to be an `interposer' on direct\n\
+ \tdynamic object is to be an 'interposer' on direct\n\
\t\t\tbindings\n"
@ MSG_ARG_DETAIL_ZLAZY "\t[-z lazyload | nolazyload]\n\
\t\t\tenable|disable delayed loading of shared \
@@ -273,7 +273,7 @@
@ MSG_REL_UNSUPSZ "relocation error: %s: file %s: symbol %s: \
offset size (%d bytes) is not supported"
@ MSG_REL_INVALOFFSET "relocation error: %s: file %s section [%u]%s: \
- invalid offset symbol `%s': offset 0x%llx"
+ invalid offset symbol '%s': offset 0x%llx"
@ MSG_REL_INVALRELT "relocation error: file %s: section [%u]%s: \
invalid relocation type: 0x%x"
@ MSG_REL_EMPTYSEC "relocation error: %s: file %s: symbol %s: \
@@ -376,12 +376,12 @@
@ MSG_FIL_MULINC_1 "file %s: attempted multiple inclusion of file"
@ MSG_FIL_MULINC_2 "file %s: linked to %s: attempted multiple inclusion \
of file"
-@ MSG_FIL_SOINSTAT "input of shared object `%s' in static mode"
+@ MSG_FIL_SOINSTAT "input of shared object '%s' in static mode"
@ MSG_FIL_INVALSEC "file %s: section [%u]%s has invalid type %s"
@ MSG_FIL_NOTFOUND "file %s: required by %s, not found"
@ MSG_FIL_MALSTR "file %s: section [%u]%s: malformed string table, \
initial or final byte"
-@ MSG_FIL_PTHTOLONG "`%s/%s' pathname too long"
+@ MSG_FIL_PTHTOLONG "'%s/%s' pathname too long"
@ MSG_FIL_EXCLUDE "file %s: section [%u]%s contains both SHF_EXCLUDE and \
SHF_ALLOC flags: SHF_EXCLUDE ignored"
@ MSG_FIL_INTERRUPT "file %s: creation interrupted: %s"
@@ -400,8 +400,6 @@
@ MSG_FIL_UNKCAP "file %s: section [%u]%s: unknown capability tag: %d"
@ MSG_FIL_BADSF1 "file %s: section [%u]%s: unknown software \
capabilities: 0x%llx; ignored"
-@ MSG_MAPFIL_BADSF1 "file %s: line %llu: unknown software \
- capabilities: 0x%llx; ignored"
@ MSG_FIL_INADDR32SF1 "file %s: section [%u]%s: software capability ADDR32: is \
ineffective when building 32-bit object; ignored"
@ MSG_FIL_EXADDR32SF1 "file %s: section [%u]%s: software capability ADDR32: \
@@ -413,9 +411,9 @@
# Recording name conflicts
-@ MSG_REC_OPTCNFLT "recording name conflict: file `%s' and %s provide \
+@ MSG_REC_OPTCNFLT "recording name conflict: file '%s' and %s provide \
identical dependency names: %s"
-@ MSG_REC_OBJCNFLT "recording name conflict: file `%s' and file `%s' \
+@ MSG_REC_OBJCNFLT "recording name conflict: file '%s' and file '%s' \
provide identical dependency names: %s %s"
@ MSG_REC_CNFLTHINT "(possible multiple inclusion of the same file)"
@@ -447,26 +445,26 @@
# Section processing errors
-@ MSG_SCN_NONALLOC "%s: non-allocatable section `%s' directed to a \
- loadable segment"
+@ MSG_SCN_NONALLOC "%s: non-allocatable section '%s' directed to a \
+ loadable segment: %s"
# Symbol processing errors
-@ MSG_SYM_NOSECDEF "symbol `%s' in file %s has no section definition"
-@ MSG_SYM_INVSEC "symbol `%s' in file %s associated with invalid \
+@ MSG_SYM_NOSECDEF "symbol '%s' in file %s has no section definition"
+@ MSG_SYM_INVSEC "symbol '%s' in file %s associated with invalid \
section[%lld]"
-@ MSG_SYM_TLS "symbol `%s' in file %s (STT_TLS), is defined \
+@ MSG_SYM_TLS "symbol '%s' in file %s (STT_TLS), is defined \
in a non-SHF_TLS section"
-@ MSG_SYM_BADADDR "symbol `%s' in file %s: section [%u]%s: size %#llx: \
+@ MSG_SYM_BADADDR "symbol '%s' in file %s: section [%u]%s: size %#llx: \
symbol (address %#llx, size %#llx) lies outside \
of containing section"
-@ MSG_SYM_BADADDR_ROTXT "symbol `%s' in file %s: readonly text section \
+@ MSG_SYM_BADADDR_ROTXT "symbol '%s' in file %s: readonly text section \
[%u]%s: size %#llx: symbol (address %#llx, \
size %#llx) lies outside of containing section"
-@ MSG_SYM_MULDEF "symbol `%s' is multiply-defined:"
-@ MSG_SYM_CONFVIS "symbol `%s' has conflicting visibilities:"
-@ MSG_SYM_DIFFTYPE "symbol `%s' has differing types:"
-@ MSG_SYM_DIFFATTR "symbol `%s' has differing %s:\n\
+@ MSG_SYM_MULDEF "symbol '%s' is multiply-defined:"
+@ MSG_SYM_CONFVIS "symbol '%s' has conflicting visibilities:"
+@ MSG_SYM_DIFFTYPE "symbol '%s' has differing types:"
+@ MSG_SYM_DIFFATTR "symbol '%s' has differing %s:\n\
\t(file %s value=0x%llx; file %s value=0x%llx);"
@ MSG_SYM_FILETYPES "\t(file %s type=%s; file %s type=%s);"
@ MSG_SYM_VISTYPES "\t(file %s visibility=%s; file %s visibility=%s);"
@@ -480,10 +478,10 @@
ignored:\n\t(file %s value=%s);"
@ MSG_SYM_NONGLOB "global symbol %s has non-global binding:\n\
\t(file %s value=%s);"
-@ MSG_SYM_RESERVE "reserved symbol `%s' already defined in file %s"
-@ MSG_SYM_NOTNULL "undefined symbol `%s' with non-zero value encountered \
+@ MSG_SYM_RESERVE "reserved symbol '%s' already defined in file %s"
+@ MSG_SYM_NOTNULL "undefined symbol '%s' with non-zero value encountered \
from file %s"
-@ MSG_SYM_DUPSORTADDR "section %s: symbol `%s' and symbol `%s' have the \
+@ MSG_SYM_DUPSORTADDR "section %s: symbol '%s' and symbol '%s' have the \
same address: %#llx: remove duplicate with \
NOSORTSYM mapfile directive"
@@ -497,7 +495,7 @@
associated symbol size is unknown %s"
@ MSG_PSYM_NOSTATIC "and partial initialization cannot be deferred to \
a static object"
-@ MSG_MOVE_OVERLAP "file %s: section [%u]%s: symbol `%s' overlapping move \
+@ MSG_MOVE_OVERLAP "file %s: section [%u]%s: symbol '%s' overlapping move \
initialization: start=0x%llx, length=0x%llx: \
start=0x%llx, length=0x%llx"
@ MSG_PSYM_EXPREASON1 "output file is static object"
@@ -551,42 +549,43 @@
@ MSG_SYM_UND_BNDLOCAL "%-35s %s (symbol scope specifies local binding)"
@ MSG_SYM_ENTRY "entry point"
-@ MSG_SYM_UNDEF "%s symbol `%s' is undefined"
-@ MSG_SYM_EXTERN "%s symbol `%s' is undefined (symbol belongs to \
+@ MSG_SYM_UNDEF "%s symbol '%s' is undefined"
+@ MSG_SYM_EXTERN "%s symbol '%s' is undefined (symbol belongs to \
dependency %s)"
-@ MSG_SYM_NOCRT "symbol `%s' not found, but %s section exists - \
+@ MSG_SYM_NOCRT "symbol '%s' not found, but %s section exists - \
possible link-edit without using the compiler driver"
# Output file update messages
-@ MSG_UPD_NOREADSEG "No read-only segments found. Setting `_etext' to 0"
-@ MSG_UPD_NORDWRSEG "No read-write segments found. Setting `_edata' to 0"
-@ MSG_UPD_NOSEG "Setting `end' and `_end' to 0"
+@ MSG_UPD_NOREADSEG "No read-only segments found. Setting '_etext' to 0"
+@ MSG_UPD_NORDWRSEG "No read-write segments found. Setting '_edata' to 0"
+@ MSG_UPD_NOSEG "Setting 'end' and '_end' to 0"
@ MSG_UPD_SEGOVERLAP "%s: segment address overlap;\n\
\tprevious segment ending at address 0x%llx overlaps\n\
- \tuser defined segment `%s' starting at address 0x%llx"
+ \tuser defined segment '%s' starting at address 0x%llx"
@ MSG_UPD_LARGSIZE "%s: segment %s calculated size 0x%llx\n\
\tis larger than user-defined size 0x%llx"
@ MSG_UPD_NOBITS "NOBITS section found before end of initialized data"
+@ MSG_SEG_FIRNOTLOAD "First segment has type %s, PT_LOAD required: %s"
# Version processing messages
@ MSG_VER_HIGHER "file %s: version revision %d is higher than \
expected %d"
-@ MSG_VER_NOEXIST "file %s: version `%s' does not exist:\n\
+@ MSG_VER_NOEXIST "file %s: version '%s' does not exist:\n\
\trequired by file %s"
-@ MSG_VER_UNDEF "version `%s' undefined, referenced by version `%s':\n\
+@ MSG_VER_UNDEF "version '%s' undefined, referenced by version '%s':\n\
\trequired by file %s"
-@ MSG_VER_UNAVAIL "file %s: version `%s' is unavailable:\n\
+@ MSG_VER_UNAVAIL "file %s: version '%s' is unavailable:\n\
\trequired by file %s"
-@ MSG_VER_DEFINED "version symbol `%s' already defined in file %s"
-@ MSG_VER_INVALNDX "version symbol `%s' from file %s has an invalid \
+@ MSG_VER_DEFINED "version symbol '%s' already defined in file %s"
+@ MSG_VER_INVALNDX "version symbol '%s' from file %s has an invalid \
version index (%d)"
-@ MSG_VER_ADDVERS "unused $ADDVERS specification from file `%s' \
- for object `%s'\nversion(s):"
+@ MSG_VER_ADDVERS "unused $ADDVERS specification from file '%s' \
+ for object '%s'\nversion(s):"
@ MSG_VER_ADDVER "\t%s"
@ MSG_VER_CYCLIC "following versions generate cyclic dependency:"
@@ -638,14 +637,29 @@
@ MSG_REJ_UNKFILE "file %s: unknown file type"
@ MSG_REJ_HWCAP_1 "file %s: hardware capability unsupported: %s"
+
@ _END_
# The following strings represent reserved names. Reference to these strings
# is via the MSG_ORIG() macro, and thus translations are not required.
+@ MSG_STR_EOF "<eof>"
+@ MSG_STR_ERROR "<error>"
@ MSG_STR_EMPTY ""
+@ MSG_QSTR_BANG "'!'"
@ MSG_STR_COLON ":"
+@ MSG_QSTR_COLON "':'"
+@ MSG_QSTR_SEMICOLON "';'"
+@ MSG_QSTR_EQUAL "'='"
+@ MSG_QSTR_PLUSEQ "'+='"
+@ MSG_QSTR_MINUSEQ "'-='"
+@ MSG_QSTR_ATSIGN "'@'"
+@ MSG_QSTR_DASH "'-'"
+@ MSG_QSTR_LEFTBKT "'{'"
+@ MSG_QSTR_RIGHTBKT "'}'"
+@ MSG_QSTR_PIPE "'|'"
+@ MSG_QSTR_STAR "'*'"
@ MSG_STR_DOT "."
@ MSG_STR_SLASH "/"
@ MSG_STR_DYNAMIC "(.dynamic)"
@@ -656,10 +670,25 @@
@ MSG_STR_OSREL "$OSREL"
@ MSG_STR_UU_REAL_U "__real_"
@ MSG_STR_UU_WRAP_U "__wrap_"
+@ MSG_STR_UELF32 "_ELF32"
+@ MSG_STR_UELF64 "_ELF64"
+@ MSG_STR_USPARC "_sparc"
+@ MSG_STR_UX86 "_x86"
+@ MSG_STR_TRUE "true"
+
+@ MSG_STR_CDIR_ADD "$add"
+@ MSG_STR_CDIR_CLEAR "$clear"
+@ MSG_STR_CDIR_ERROR "$error"
+@ MSG_STR_CDIR_MFVER "$mapfile_version"
+@ MSG_STR_CDIR_IF "$if"
+@ MSG_STR_CDIR_ELIF "$elif"
+@ MSG_STR_CDIR_ELSE "$else"
+@ MSG_STR_CDIR_ENDIF "$endif"
+
@ MSG_FMT_ARMEM "%s(%s)"
@ MSG_FMT_COLPATH "%s:%s"
-@ MSG_FMT_SYMNAM "`%s'"
+@ MSG_FMT_SYMNAM "'%s'"
@ MSG_FMT_NULLSYMNAM "%s[%d]"
@ MSG_FMT_STRCAT "%s%s"
@@ -738,24 +767,15 @@
@ MSG_SCN_GCC_X_TBL ".gcc_except_table"
@ MSG_SCN_JCR ".jcr"
-# Entry criteria strings (segment names)
+# Segment names for segments referenced by entrance criteria
@ MSG_ENT_BSS "bss"
@ MSG_ENT_DATA "data"
-@ MSG_ENT_DTRACE "dtrace"
-@ MSG_ENT_DYNAMIC "dynamic"
@ MSG_ENT_EXTRA "extra"
-@ MSG_ENT_INTERP "interp"
-@ MSG_ENT_LBSS "lbss"
@ MSG_ENT_LDATA "ldata"
@ MSG_ENT_LRODATA "lrodata"
@ MSG_ENT_NOTE "note"
-@ MSG_ENT_PHDR "phdr"
@ MSG_ENT_TEXT "text"
-@ MSG_ENT_TLS "tls"
-@ MSG_ENT_UNWIND "unwind"
-
-@ MSG_ENT_SUNWCAP "SUNW_cap"
# Symbol names
@@ -830,7 +850,7 @@
@ MSG_MARG_INCOMP "%s and %s are incompatible"
@ MSG_ARG_MTONCE "option %s appears more than once, first setting taken"
@ MSG_MARG_MTONCE "%s appears more than once, first setting taken"
-@ MSG_ARG_ILLEGAL "option %s has illegal argument `%s'"
+@ MSG_ARG_ILLEGAL "option %s has illegal argument '%s'"
@ MSG_ARG_YP "option -YP and -Y%c may not be specified concurrently"
@ MSG_ARG_STRIP "%s specified with %s; only debugging \
information stripped"
@@ -838,7 +858,7 @@
@ MSG_ARG_NOFLTR "option %s is only meaningful when building a filter"
@ MSG_ARG_NODEFLIB "the default library search path has been suppressed, \
but no runpaths have been specified via %s"
-@ MSG_ARG_NOENTRY "entry point symbol `%s' is undefined"
+@ MSG_ARG_NOENTRY "entry point symbol '%s' is undefined"
@ MSG_ARG_UNSUPPORTED "option %s is no longer supported; ignored"
@ MSG_ARG_FLAGS "flags processing errors"
@@ -934,9 +954,9 @@
#
@ MSG_ENT_MUL_ENTRY_2 "\t\t\t\t\t\t\t%s\n"
-@ MSG_ENT_NOSEC_1 "mapfile: %s segment: section `%s' does not appear \
- in file `%s'"
-@ MSG_ENT_NOSEC_2 "mapfile: %s segment: section `%s' does not appear \
+@ MSG_ENT_NOSEC_1 "mapfile: %s segment: section '%s' does not appear \
+ in mapfile specified input file(s)"
+@ MSG_ENT_NOSEC_2 "mapfile: %s segment: section '%s' does not appear \
in any input file"
# Library messages
@@ -948,80 +968,95 @@
# Mapfile processing messages
-@ MSG_MAP_BADFLAG "%s: %lld: badly formed section flags `%s'"
-@ MSG_MAP_REDEFATT "%s: %lld: redefining %s attribute for `%s'"
-@ MSG_MAP_PREMEOF "%s: %lld: premature EOF"
-@ MSG_MAP_ILLCHAR "%s: %lld: illegal character `\\%03o'"
-@ MSG_MAP_MALFORM "%s: %lld: malformed entry"
-@ MSG_MAP_NONLOAD "%s: %lld: %s not allowed on non-LOAD segments"
-@ MSG_MAP_NOSTACK1 "%s: %lld: %s not allowed on STACK segment"
-@ MSG_MAP_NOSTACK2 "%s: %lld: multiple STACK segments are not allowed"
-@ MSG_MAP_MOREONCE "%s: %lld: %s set more than once on same line"
-@ MSG_MAP_NOTERM "%s: %lld: string does not terminate with a `\"'"
-@ MSG_MAP_SECINSEG "%s: %lld: section within segment ordering done on \
- a non-existent segment `%s'"
-@ MSG_MAP_UNEXDEP "%s: %lld: dependency `%s' unexpected; ignored"
-@ MSG_MAP_UNEXTOK "%s: %lld: unexpected occurrence of `%c' token"
-
-@ MSG_MAP_SEGEMPLOAD "%s: %lld: empty segment must be of type LOAD or NULL"
-@ MSG_MAP_SEGEMPEXE "%s: %lld: a LOAD empty segment definition is only \
+@ MSG_MAP_BADAUTORED "%s: %llu: auto-reduction ('*') can only be used in \
+ hidden/local, or eliminate scope"
+@ MSG_MAP_BADFLAG "%s: %llu: badly formed section flags '%s'"
+@ MSG_MAP_BADBNAME "%s: %llu: basename cannot contain path \
+ separator ('/'): %s"
+@ MSG_MAP_BADONAME "%s: %llu: object name cannot contain path \
+ separator ('/'): %s"
+@ MSG_MAP_REDEFATT "%s: %llu: redefining %s attribute for '%s'"
+@ MSG_MAP_PREMEOF "%s: %llu: premature EOF"
+@ MSG_MAP_ILLCHAR "%s: %llu: illegal character '\\%03o'"
+@ MSG_MAP_MALFORM "%s: %llu: malformed entry"
+@ MSG_MAP_NONLOAD "%s: %llu: %s not allowed on non-LOAD segments"
+@ MSG_MAP_NOSTACK1 "%s: %llu: %s not allowed on STACK segment"
+@ MSG_MAP_MOREONCE "%s: %llu: %s set more than once on same line"
+@ MSG_MAP_NOTERM "%s: %llu: unterminated quoted string: %s"
+@ MSG_MAP_SECINSEG "%s: %llu: section within segment ordering done on \
+ a non-existent segment '%s'"
+@ MSG_MAP_UNEXINHERIT "%s: %llu: unnamed version cannot inherit from other \
+ versions: %s"
+@ MSG_MAP_UNEXTOK "%s: %llu: unexpected occurrence of '%c' token"
+
+@ MSG_MAP_SEGEMPLOAD "%s: %llu: empty segment must be of type LOAD or NULL"
+@ MSG_MAP_SEGEMPEXE "%s: %llu: a LOAD empty segment definition is only \
allowed when creating a dynamic executable"
-@ MSG_MAP_SEGEMPATT "%s: %lld: a LOAD empty segment must have an address \
+@ MSG_MAP_SEGEMPATT "%s: %llu: a LOAD empty segment must have an address \
and size"
-@ MSG_MAP_SEGEMPNOATT "%s: %lld: a NULL empty segment must not have an address \
- or size"
-@ MSG_MAP_SEGEMPSEC "%s: %lld: empty segment can not have sections \
+@ MSG_MAP_SEGEMPNOATT "%s: %llu: a NULL empty segment must not have an \
+ address or size"
+@ MSG_MAP_SEGEMPSEC "%s: %llu: empty segment can not have sections \
assigned to it"
-@ MSG_MAP_SEGEMNOPERM "%s: %lld: empty segment must not have \
+@ MSG_MAP_SEGEMNOPERM "%s: %llu: empty segment must not have \
p_flags set: 0x%x"
-@ MSG_MAP_UNKSYMSCO "%s: %lld: unknown symbol scope definition `%s'"
-@ MSG_MAP_UNKSYMDEF "%s: %lld: unknown symbol definition `%s'"
-@ MSG_MAP_UNKSEGTYP "%s: %lld: unknown internal segment type %d"
-@ MSG_MAP_UNKSOTYP "%s: %lld: unknown shared object type `%s'"
-@ MSG_MAP_UNKSEGATT "%s: %lld: unknown segment attribute `%s'"
-@ MSG_MAP_UNKSEGFLG "%s: %lld: unknown segment flag `?%c'"
-@ MSG_MAP_UNKSECTYP "%s: %lld: unknown section type `%s'"
-
-@ MSG_MAP_SEGSIZE "%s: %lld: segment `%s' already has a size symbol"
-@ MSG_MAP_SEGADDR "%s: %lld: segment address or length `%s' %s"
-@ MSG_MAP_BADCAPVAL "%s: %lld: bad capability value `%s': %s"
-@ MSG_MAP_UNKCAPATTR "%s: %lld: unknown capability attribute `%s'"
-@ MSG_MAP_EMPTYCAP "%s: %lld: empty capability definition; ignored"
-@ MSG_MAP_SEGRESV "%s: %lld: segments `interp' or `dynamic' may not be \
- changed"
-
-@ MSG_MAP_SYMDEF1 "%s: %lld: symbol `%s' is already defined in file: \
+@ MSG_MAP_CNTADDRORDER "%s: %llu: segment cannot have an explicit address \
+ and also be in the SEGMENT_ORDER list: %s"
+@ MSG_MAP_CNTDISSEG "%s: %llu: segment cannot be disabled: %s"
+@ MSG_MAP_DUPNAMENT "%s: %llu: cannot redefine entrance criteria: %s"
+@ MSG_MAP_DUPORDSEG "%s: %llu: segment is already in %s list: %s"
+@ MSG_MAP_DUP_OS_ORD "%s: %llu: section is already in OS_ORDER list: %s"
+@ MSG_MAP_DUP_IS_ORD "%s: %llu: entrance criteria is already in \
+ IS_ORDER list: %s"
+@ MSG_MAP_UNKENT "%s: %llu: unknown entrance criteria \
+ (ASSIGN_SECTION): %s"
+@ MSG_MAP_UNKSEG "%s: %llu: unknown segment: %s"
+@ MSG_MAP_UNKSYMDEF "%s: %llu: unknown symbol definition: %s"
+@ MSG_MAP_UNKSEGTYP "%s: %llu: unknown internal segment type %d"
+@ MSG_MAP_UNKSOTYP "%s: %llu: unknown shared object type: %s"
+@ MSG_MAP_UNKSEGATT "%s: %llu: unknown segment attribute: %s"
+@ MSG_MAP_UNKSEGFLG "%s: %llu: unknown segment flag: ?%c"
+@ MSG_MAP_UNKSECTYP "%s: %llu: unknown section type: %s"
+
+@ MSG_MAP_SEGSIZE "%s: %lld: existing segment size symbols cannot \
+ be reset: %s"
+@ MSG_MAP_SEGADDR "%s: %llu: segment address or length '%s' %s"
+@ MSG_MAP_BADCAPVAL "%s: %llu: bad capability value: %s"
+@ MSG_MAP_UNKCAPATTR "%s: %llu: unknown capability attribute '%s'"
+@ MSG_MAP_EMPTYCAP "%s: %llu: empty capability definition; ignored"
+
+@ MSG_MAP_SYMDEF1 "%s: %llu: symbol '%s' is already defined in file: \
%s: %s"
-@ MSG_MAP_SYMDEF2 "%s: %lld: symbol `%s': %s"
+@ MSG_MAP_SYMDEF2 "%s: %llu: symbol '%s': %s"
-@ MSG_MAP_EXPSCOL "%s: %lld: expected a `;'"
-@ MSG_MAP_EXPEQU "%s: %lld: expected a `=', `:', `|', or `@'"
-@ MSG_MAP_EXPSEGATT "%s: %lld: expected one or more segment attributes \
- after an `='"
-@ MSG_MAP_EXPSEGNAM "%s: %lld: expected a segment name at the beginning \
+@ MSG_MAP_EXPSCOL "%s: %llu: expected a ';'"
+@ MSG_MAP_EXPEQU "%s: %llu: expected a '=', ':', '|', or '@'"
+@ MSG_MAP_EXPSEGATT "%s: %llu: expected one or more segment attributes \
+ after an '='"
+@ MSG_MAP_EXPSEGNAM "%s: %llu: expected a segment name at the beginning \
of a line"
-@ MSG_MAP_EXPSYM_1 "%s: %lld: expected a symbol name after `@'"
-@ MSG_MAP_EXPSYM_2 "%s: %lld: expected a symbol name after `{'"
-@ MSG_MAP_EXPSEC "%s: %lld: expected a section name after `|'"
-@ MSG_MAP_EXPSO "%s: %lld: expected a shared object definition \
- after `-'"
-@ MSG_MAP_EXPVERS "%s: %lld: expected a `;' or version reference \
- after `}'"
-@ MSG_MAP_MULTFILTEE "%s: %lld: multiple filtee definitions are unsupported"
-@ MSG_MAP_NOFILTER "%s: %lld: filtee definition required"
-@ MSG_MAP_BADSF1 "%s: %lld: unknown software capabilities: 0x%llx; \
+@ MSG_MAP_EXPSEGTYPE "%s: %llu: %s segment cannot be used with %s \
+ directive: %s"
+@ MSG_MAP_EXPSYM_1 "%s: %llu: expected a symbol name after '@'"
+@ MSG_MAP_EXPSYM_2 "%s: %llu: expected a symbol name after '{'"
+@ MSG_MAP_EXPSEC "%s: %llu: expected a section name after '|'"
+@ MSG_MAP_EXPSO "%s: %llu: expected a shared object definition \
+ after '-'"
+@ MSG_MAP_MULTFILTEE "%s: %llu: multiple filtee definitions are unsupported"
+@ MSG_MAP_NOFILTER "%s: %llu: filtee definition required"
+@ MSG_MAP_BADSF1 "%s: %llu: unknown software capabilities: 0x%llx; \
ignored"
-@ MSG_MAP_INADDR32SF1 "%s: %lld: software capability ADDR32: is ineffective \
+@ MSG_MAP_INADDR32SF1 "%s: %llu: software capability ADDR32: is ineffective \
when building 32-bit object: ignored"
-@ MSG_MAP_NOINTPOSE "%s: %lld: interposition symbols can only be defined \
+@ MSG_MAP_NOINTPOSE "%s: %llu: interposition symbols can only be defined \
when building a dynamic executable"
-@ MSG_MAP_NOEXVLSZ "%s: %lld: value and size attributes are incompatible \
+@ MSG_MAP_NOEXVLSZ "%s: %llu: value and size attributes are incompatible \
with extern or parent symbols"
-@ MSG_MAP_FLTR_ONLYAVL "%s: %lld: symbol filtering is only available when \
+@ MSG_MAP_FLTR_ONLYAVL "%s: %llu: symbol filtering is only available when \
building a shared object"
-@ MSG_MAP_SEGSAME "segments `%s' and `%s' have the same assigned \
+@ MSG_MAP_SEGSAME "segments '%s' and '%s' have the same assigned \
virtual address"
@ MSG_MAP_EXCLIMIT "exceeds internal limit"
@ MSG_MAP_NOBADFRM "number is badly formed"
@@ -1059,6 +1094,98 @@
@ MSG_MAP_SECORDER "section ordering requested, but no matching section \
found: segment: %s section: %s"
+
+# Mapfile Directives
+
+@ MSG_MAP_EXP_ATTR "%s: %llu: expected attribute name (%s), or \
+ terminator (';', '}'): %s"
+@ MSG_MAP_EXP_CAPMASK "%s: %llu: expected capability name, integer value, or \
+ terminator (';', '}'): %s"
+@ MSG_MAP_EXP_CAPNAME "%s: %llu: expected name, or terminator (';', '}'): %s"
+@ MSG_MAP_EXP_CAPID "%s: %llu: expected name, or '{' following %s: %s"
+@ MSG_MAP_EXP_CAPHW "%s: %llu: expected hardware capability, or \
+ terminator (';', '}'): %s"
+@ MSG_MAP_EXP_CAPSF "%s: %llu: expected software capability, or \
+ terminator (';', '}'): %s"
+@ MSG_MAP_EXP_EQ "%s: %llu: expected '=' following %s: %s"
+@ MSG_MAP_EXP_EQ_ALL "%s: %llu: expected '=', '+=', or '-=' following %s: %s"
+@ MSG_MAP_EXP_EQ_PEQ "%s: %llu: expected '=' following %s: %s"
+@ MSG_MAP_EXP_DIR "%s: %llu: expected mapfile directive (%s): %s"
+@ MSG_MAP_SFLG_EXBANG "%s: %llu: '!' appears without corresponding flag"
+@ MSG_MAP_EXP_FILNAM "%s: %llu: expected file name following %s: %s"
+@ MSG_MAP_EXP_FILPATH "%s: %llu: expected file path following %s: %s"
+@ MSG_MAP_EXP_INT "%s: %llu: expected integer value following %s: %s"
+@ MSG_MAP_EXP_LBKT "%s: %llu: expected '{' following %s: %s"
+@ MSG_MAP_EXP_OBJNAM "%s: %llu: expected object name following %s: %s"
+@ MSG_MAP_SFLG_ONEBANG "%s: %llu: '!' can only be specified once per flag"
+@ MSG_MAP_EXP_SECFLAG "%s: %llu: expected section flag (%s), '!', or \
+ terminator (';', '}'): %s"
+@ MSG_MAP_EXP_SECNAM "%s: %llu: expected section name following %s: %s"
+@ MSG_MAP_EXP_SEGFLAG "%s: %llu: expected segment flag (%s), or \
+ terminator (';', '}'): %s"
+@ MSG_MAP_EXP_ECNAM "%s: %llu: expected entrance criteria (ASSIGN_SECTION) \
+ name, or terminator (';', '}'): %s"
+@ MSG_MAP_EXP_SEGNAM "%s: %llu: expected segment name following %s: %s"
+@ MSG_MAP_EXP_SEM "%s: %llu: expected ';' to terminate %s: %s"
+@ MSG_MAP_EXP_SEMLBKT "%s: %llu: expected ';' or '{' following %s: %s"
+@ MSG_MAP_EXP_SEMRBKT "%s: %llu: expected ';' or '}' to terminate %s: %s"
+@ MSG_MAP_EXP_SHTYPE "%s: %llu: expected section type: %s"
+@ MSG_MAP_EXP_SYM "%s: %llu: expected symbol name, symbol scope, \
+ or '*': %s"
+@ MSG_MAP_EXP_SYMEND "%s: %llu: expected inherited version name, or \
+ terminator (';'): %s"
+@ MSG_MAP_EXP_SYMDELIM "%s: %llu: expected one of ':', ';', or '{': %s"
+@ MSG_MAP_EXP_SYMFLAG "%s: %llu: expected symbol flag (%s), or \
+ terminator (';', '}'): %s"
+@ MSG_MAP_EXP_SYMNAM "%s: %llu: expected symbol name following %s: %s"
+@ MSG_MAP_EXP_SYMSCOPE "%s: %llu: expected symbol scope (%s): %s"
+@ MSG_MAP_EXP_SYMTYPE "%s: %llu: expected symbol type (%s): %s"
+@ MSG_MAP_EXP_VERSION "%s: %llu: expected version name following %s: %s"
+@ MSG_MAP_BADEXTRA "%s: %llu: unexpected text found following %s directive"
+@ MSG_MAP_VALUELIMIT "%s: %llu: numeric value exceeds word size: %s"
+@ MSG_MAP_MALVALUE "%s: %llu: malformed numeric value: %s"
+@ MSG_MAP_BADVALUETAIL "%s: %llu: unexpected characters following numeric \
+ constant: %s"
+@ MSG_MAP_WSNEEDED "%s: %llu: whitespace needed before token: %s"
+@ MSG_MAP_BADCHAR "%s: %llu: unexpected text: %s"
+@ MSG_MAP_BADKWQUOTE "%s: %llu: mapfile keywords should not be quoted: %s"
+@ MSG_MAP_CDIR_NOTBOL "%s: %llu: mapfile control directive not at start of \
+ line: %s"
+@ MSG_MAP_NOATTR "%s: %llu: %s specified no attributes (empty {})"
+@ MSG_MAP_NOVALUES "%s: %llu: %s specified without values"
+@ MSG_MAP_INTERR "<internal error>"
+@ MSG_MAP_ISORDVER "%s: %llu: version 0 mapfile ?O flag and version 1 \
+ segment IS_ORDER attribute are mutually exclusive: %s"
+@ MSG_MAP_SYMATTR "symbol attributes";
+
+# Mapfile Control Directives
+
+@ MSG_MAP_CDIR_BADVDIR "%s: %llu: $mapfile_version directive must specify \
+ version 2 or higher: %d"
+@ MSG_MAP_CDIR_BADVER "%s: %llu: unknown mapfile version: %d"
+@ MSG_MAP_CDIR_REPVER "%s: %llu: $mapfile_version must be first directive \
+ in file"
+@ MSG_MAP_CDIR_REQARG "%s: %llu: %s directive requires an argument"
+@ MSG_MAP_CDIR_REQNOARG "%s: %llu: %s directive does not accept arguments"
+@ MSG_MAP_CDIR_BAD "%s: %llu: unrecognized mapfile control directive"
+@ MSG_MAP_CDIR_NOIF "%s: %llu: %s directive used without opening $if"
+@ MSG_MAP_CDIR_ELSE "%s: %llu: %s directive preceded by $else on line %d"
+@ MSG_MAP_CDIR_NOEND "%s: %llu: EOF encountered without closing $endif \
+ for $if on line %d"
+@ MSG_MAP_CDIR_ERROR "%s: %llu: error: %s"
+
+
+# Mapfile Conditional Expressions
+
+@ MSG_MAP_CEXP_TOKERR "%s: %llu: syntax error in conditional expression at: %s"
+@ MSG_MAP_CEXP_SEMERR "%s: %llu: malformed conditional expression"
+@ MSG_MAP_CEXP_BADOPUSE "%s: %llu: invalid operator use in conditional \
+ expression"
+@ MSG_MAP_CEXP_UNBALPAR "%s: %llu: unbalanced parenthesis in conditional \
+ expression"
+@ MSG_MAP_BADCESC "%s: %llu: unrecognized escape in double quoted \
+ token: \\%c\n"
+
# Generic error diagnostic labels
@ MSG_STR_NULL "(null)"
@@ -1096,13 +1223,10 @@
@ MSG_STR_STRNL "%s\n"
@ MSG_STR_NL "\n"
-@ MSG_STR_INTERP "interp"
@ MSG_STR_LD_DYNAMIC "dynamic"
@ MSG_STR_SYMBOLIC "symbolic"
@ MSG_STR_ELIMINATE "eliminate"
@ MSG_STR_LOCAL "local"
-@ MSG_STR_EXPORTED "exported"
-@ MSG_STR_SINGLETON "singleton"
@ MSG_STR_PROGBITS "progbits"
@ MSG_STR_SYMTAB "symtab"
@ MSG_STR_DYNSYM "dynsym"
@@ -1276,14 +1400,11 @@
# Mapfile tokens
-@ MSG_MAP_TOK_1 "\"\n"
-@ MSG_MAP_TOK_2 " \"\t\n:;=#"
@ MSG_MAP_LOAD "load"
@ MSG_MAP_NOTE "note"
@ MSG_MAP_NULL "null"
@ MSG_MAP_STACK "stack"
@ MSG_MAP_ADDVERS "addvers"
-@ MSG_MAP_GLOBAL "global"
@ MSG_MAP_FUNCTION "function"
@ MSG_MAP_DATA "data"
@ MSG_MAP_COMMON "common"
@@ -1291,9 +1412,6 @@
@ MSG_MAP_EXTERN "extern"
@ MSG_MAP_DIRECT "direct"
@ MSG_MAP_NODIRECT "nodirect"
-@ MSG_MAP_DEFAULT "default"
-@ MSG_MAP_PROTECTED "protected"
-@ MSG_MAP_HIDDEN "hidden"
@ MSG_MAP_FILTER "filter"
@ MSG_MAP_AUXILIARY "auxiliary"
@ MSG_MAP_OVERRIDE "override"
@@ -1301,5 +1419,71 @@
@ MSG_MAP_DYNSORT "dynsort"
@ MSG_MAP_NODYNSORT "nodynsort"
-@ MSG_STR_DTRACE "PT_SUNWDTRACE"
+@ MSG_MAPKW_ALIGN "ALIGN"
+@ MSG_MAPKW_ALLOC "ALLOC"
+@ MSG_MAPKW_ALLOW "ALLOW"
+@ MSG_MAPKW_AMD64_LARGE "AMD64_LARGE"
+@ MSG_MAPKW_ASSIGN_SECTION "ASSIGN_SECTION"
+@ MSG_MAPKW_AUX "AUXILIARY"
+@ MSG_MAPKW_CAPABILITY "CAPABILITY"
+@ MSG_MAPKW_COMMON "COMMON"
+@ MSG_MAPKW_DATA "DATA"
+@ MSG_MAPKW_DEFAULT "DEFAULT"
+@ MSG_MAPKW_DEPEND_VERSIONS "DEPEND_VERSIONS"
+@ MSG_MAPKW_DIRECT "DIRECT"
+@ MSG_MAPKW_DISABLE "DISABLE"
+@ MSG_MAPKW_DYNSORT "DYNSORT"
+@ MSG_MAPKW_ELIMINATE "ELIMINATE"
+@ MSG_MAPKW_EXECUTE "EXECUTE"
+@ MSG_MAPKW_EXPORTED "EXPORTED"
+@ MSG_MAPKW_EXTERN "EXTERN"
+@ MSG_MAPKW_FILTER "FILTER"
+@ MSG_MAPKW_FILE_BASENAME "FILE_BASENAME"
+@ MSG_MAPKW_FILE_PATH "FILE_PATH"
+@ MSG_MAPKW_FILE_OBJNAME "FILE_OBJNAME"
+@ MSG_MAPKW_FUNCTION "FUNCTION"
+@ MSG_MAPKW_FLAGS "FLAGS"
+@ MSG_MAPKW_GLOBAL "GLOBAL"
+@ MSG_MAPKW_INTERPOSE "INTERPOSE"
+@ MSG_MAPKW_HIDDEN "HIDDEN"
+@ MSG_MAPKW_HDR_NOALLOC "HDR_NOALLOC"
+@ MSG_MAPKW_HW "HW"
+@ MSG_MAPKW_HW_1 "HW_1"
+@ MSG_MAPKW_HW_2 "HW_2"
+@ MSG_MAPKW_IS_NAME "IS_NAME"
+@ MSG_MAPKW_IS_ORDER "IS_ORDER"
+@ MSG_MAPKW_LOAD_SEGMENT "LOAD_SEGMENT"
+@ MSG_MAPKW_LOCAL "LOCAL"
+@ MSG_MAPKW_MACHINE "MACHINE"
+@ MSG_MAPKW_MAX_SIZE "MAX_SIZE"
+@ MSG_MAPKW_NOHDR "NOHDR"
+@ MSG_MAPKW_NODIRECT "NODIRECT"
+@ MSG_MAPKW_NODYNSORT "NODYNSORT"
+@ MSG_MAPKW_NOTE_SEGMENT "NOTE_SEGMENT"
+@ MSG_MAPKW_NULL_SEGMENT "NULL_SEGMENT"
+@ MSG_MAPKW_OS_ORDER "OS_ORDER"
+@ MSG_MAPKW_PADDR "PADDR"
+@ MSG_MAPKW_PARENT "PARENT"
+@ MSG_MAPKW_PHDR_ADD_NULL "PHDR_ADD_NULL"
+@ MSG_MAPKW_PLATFORM "PLATFORM"
+@ MSG_MAPKW_PROTECTED "PROTECTED"
+@ MSG_MAPKW_READ "READ"
+@ MSG_MAPKW_ROUND "ROUND"
+@ MSG_MAPKW_REQUIRE "REQUIRE"
+@ MSG_MAPKW_SEGMENT_ORDER "SEGMENT_ORDER"
+@ MSG_MAPKW_SF "SF"
+@ MSG_MAPKW_SF_1 "SF_1"
+@ MSG_MAPKW_SINGLETON "SINGLETON"
+@ MSG_MAPKW_SIZE "SIZE"
+@ MSG_MAPKW_SIZE_SYMBOL "SIZE_SYMBOL"
+@ MSG_MAPKW_STACK "STACK"
+@ MSG_MAPKW_SYMBOL_SCOPE "SYMBOL_SCOPE"
+@ MSG_MAPKW_SYMBOL_VERSION "SYMBOL_VERSION"
+@ MSG_MAPKW_SYMBOLIC "SYMBOLIC"
+@ MSG_MAPKW_TYPE "TYPE"
+@ MSG_MAPKW_VADDR "VADDR"
+@ MSG_MAPKW_VALUE "VALUE"
+@ MSG_MAPKW_WRITE "WRITE"
+
+@ MSG_STR_DTRACE "PT_SUNWDTRACE"
diff --git a/usr/src/cmd/sgs/libld/common/libld.sparc.msg b/usr/src/cmd/sgs/libld/common/libld.sparc.msg
index 77b228bdd7..0705946e0d 100644
--- a/usr/src/cmd/sgs/libld/common/libld.sparc.msg
+++ b/usr/src/cmd/sgs/libld/common/libld.sparc.msg
@@ -20,10 +20,9 @@
#
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
@ _START_
@@ -45,22 +44,22 @@
@ MSG_REL_BADGOTFIX "relocation error: %s: file %s: symbol %s: \
internal gotop_fixups error"
@ MSG_REL_ASSIGNGOT "internal error: assign_got() invalid got index \
- 0x%llx for symbol `%s'"
-@ MSG_REL_SMALLGOT "too many symbols require `small' PIC references:\n\
+ 0x%llx for symbol '%s'"
+@ MSG_REL_SMALLGOT "too many symbols require 'small' PIC references:\n\
\thave %d, maximum %d -- recompile some \
modules -K PIC."
@ MSG_REL_MIXEDGOT "too many symbols require mixed mode \
- (both `small' and `large') PIC references:\n\
+ (both 'small' and 'large') PIC references:\n\
\thave %d, maximum %d -- recompile some \
modules -K PIC."
@ MSG_SYM_INCOMPREG1 "register %s symbol used incompatibly:\n\
- \t(file %s symbol `%s', file %s symbol `%s');"
-@ MSG_SYM_INCOMPREG2 "register symbol `%s' used incompatibly:\n\
+ \t(file %s symbol '%s', file %s symbol '%s');"
+@ MSG_SYM_INCOMPREG2 "register symbol '%s' used incompatibly:\n\
\t(file %s value=%s, file %s value=%s);"
@ MSG_SYM_INCOMPREG3 "register %s local symbol visibility incompatible:\n\
- \t(file %s symbol `%s', file %s symbol `%s');"
-@ MSG_SYM_MULTINIREG "register %s symbol `%s' multiply-initialized:\n\
+ \t(file %s symbol '%s', file %s symbol '%s');"
+@ MSG_SYM_MULTINIREG "register %s symbol '%s' multiply-initialized:\n\
\t(file %s shndx=ABS, file %s shndx=ABS);"
@ MSG_SYM_BADSCRATCH "file %s: section %s: symbol[%d]: %s: malformed \
diff --git a/usr/src/cmd/sgs/libld/common/machrel.amd.c b/usr/src/cmd/sgs/libld/common/machrel.amd.c
index 10f5f54b80..d667217a76 100644
--- a/usr/src/cmd/sgs/libld/common/machrel.amd.c
+++ b/usr/src/cmd/sgs/libld/common/machrel.amd.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -1540,6 +1540,7 @@ ld_targ_init_x86(void)
M_SEGM_ORIGIN, /* m_segm_origin */
M_SEGM_AORIGIN, /* m_segm_aorigin */
M_DATASEG_PERM, /* m_dataseg_perm */
+ M_STACK_PERM, /* m_stack_perm */
M_WORD_ALIGN, /* m_word_align */
MSG_ORIG(MSG_PTH_RTLD_AMD64), /* m_def_interp */
diff --git a/usr/src/cmd/sgs/libld/common/machrel.intel.c b/usr/src/cmd/sgs/libld/common/machrel.intel.c
index 617ab4257e..697cee6bb0 100644
--- a/usr/src/cmd/sgs/libld/common/machrel.intel.c
+++ b/usr/src/cmd/sgs/libld/common/machrel.intel.c
@@ -24,7 +24,7 @@
* Copyright (c) 1988 AT&T
* All Rights Reserved
*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -1637,6 +1637,7 @@ ld_targ_init_x86(void)
M_SEGM_ORIGIN, /* m_segm_origin */
M_SEGM_AORIGIN, /* m_segm_aorigin */
M_DATASEG_PERM, /* m_dataseg_perm */
+ M_STACK_PERM, /* m_stack_perm */
M_WORD_ALIGN, /* m_word_align */
MSG_ORIG(MSG_PTH_RTLD), /* m_def_interp */
diff --git a/usr/src/cmd/sgs/libld/common/machrel.sparc.c b/usr/src/cmd/sgs/libld/common/machrel.sparc.c
index 15869650e5..b3a7633576 100644
--- a/usr/src/cmd/sgs/libld/common/machrel.sparc.c
+++ b/usr/src/cmd/sgs/libld/common/machrel.sparc.c
@@ -23,7 +23,7 @@
* Copyright (c) 1988 AT&T
* All Rights Reserved
*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -2168,6 +2168,7 @@ ld_targ_init_sparc(void)
M_SEGM_ORIGIN, /* m_segm_origin */
M_SEGM_AORIGIN, /* m_segm_aorigin */
M_DATASEG_PERM, /* m_dataseg_perm */
+ M_STACK_PERM, /* m_stack_perm */
M_WORD_ALIGN, /* m_word_align */
/* m_def_interp */
#if defined(_ELF64)
diff --git a/usr/src/cmd/sgs/libld/common/map.c b/usr/src/cmd/sgs/libld/common/map.c
index 91fd7e2376..fb84b8e0e3 100644
--- a/usr/src/cmd/sgs/libld/common/map.c
+++ b/usr/src/cmd/sgs/libld/common/map.c
@@ -23,166 +23,26 @@
* Copyright (c) 1988 AT&T
* All Rights Reserved
*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
- * Map file parsing.
+ * Map file parsing (Original SysV syntax).
*/
-#include <fcntl.h>
#include <string.h>
+#include <strings.h>
#include <stdio.h>
#include <unistd.h>
-#include <sys/stat.h>
#include <errno.h>
#include <limits.h>
-#include <dirent.h>
#include <ctype.h>
#include <elfcap.h>
#include <debug.h>
#include "msg.h"
#include "_libld.h"
+#include "_map.h"
-#if defined(_ELF64)
-#define STRTOADDR strtoull
-#define XWORD_MAX ULLONG_MAX
-#else /* Elf32 */
-#define STRTOADDR strtoul
-#define XWORD_MAX UINT_MAX
-#endif /* _ELF64 */
-
-/* Possible return values from gettoken */
-typedef enum {
- TK_ERROR = -1, /* Error in lexical analysis */
- TK_STRING = 0,
- TK_COLON = 1,
- TK_SEMICOLON = 2,
- TK_EQUAL = 3,
- TK_ATSIGN = 4,
- TK_DASH = 5,
- TK_LEFTBKT = 6,
- TK_RIGHTBKT = 7,
- TK_PIPE = 8,
- TK_EOF = 9
-} Token;
-
-
-static char *Mapspace; /* Malloc space holding mapfile. */
-static ulong_t Line_num; /* Current mapfile line number. */
-static char *Start_tok; /* First character of current token. */
-static char *nextchr; /* Next char in mapfile to examine. */
-
-/*
- * Convert a string to lowercase.
- */
-static void
-lowercase(char *str)
-{
- while (*str = tolower(*str))
- str++;
-}
-
-/*
- * Get a token from the mapfile.
- *
- * entry:
- * ofl - Output file descriptor
- * mapfile - Name of mapfile
- * eof_ok - If False, end of file causes a premature EOF error to be
- * issued. If True, TK_EOF is returned quietly.
- */
-static Token
-gettoken(Ofl_desc *ofl, const char *mapfile, int eof_ok)
-{
- static char oldchr = '\0'; /* Char at end of current token. */
- char *end; /* End of the current token. */
-
- /* Cycle through the characters looking for tokens. */
- for (;;) {
- if (oldchr != '\0') {
- *nextchr = oldchr;
- oldchr = '\0';
- }
- if (!isascii(*nextchr) ||
- (!isprint(*nextchr) && !isspace(*nextchr) &&
- (*nextchr != '\0'))) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_ILLCHAR), mapfile,
- EC_XWORD(Line_num), *((uchar_t *)nextchr));
- return (TK_ERROR);
- }
- switch (*nextchr) {
- case '\0': /* End of file. */
- if (!eof_ok)
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_PREMEOF), mapfile,
- EC_XWORD(Line_num));
- return (TK_EOF);
-
- case ' ': /* White space. */
- case '\t':
- nextchr++;
- break;
- case '\n': /* White space too, but bump line number. */
- nextchr++;
- Line_num++;
- break;
- case '#': /* Comment. */
- while (*nextchr != '\n' && *nextchr != '\0')
- nextchr++;
- break;
- case ':':
- nextchr++;
- return (TK_COLON);
- case ';':
- nextchr++;
- return (TK_SEMICOLON);
- case '=':
- nextchr++;
- return (TK_EQUAL);
- case '@':
- nextchr++;
- return (TK_ATSIGN);
- case '-':
- nextchr++;
- return (TK_DASH);
- case '|':
- nextchr++;
- return (TK_PIPE);
- case '{':
- nextchr++;
- return (TK_LEFTBKT);
- case '}':
- nextchr++;
- return (TK_RIGHTBKT);
- case '"':
- Start_tok = ++nextchr;
- if (((end = strpbrk(nextchr,
- MSG_ORIG(MSG_MAP_TOK_1))) == NULL) ||
- (*end != '"')) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_NOTERM), mapfile,
- EC_XWORD(Line_num));
- return (TK_ERROR);
- }
- *end = '\0';
- nextchr = end + 1;
- return (TK_STRING);
- default: /* string. */
- Start_tok = nextchr; /* CSTYLED */
- end = strpbrk(nextchr, MSG_ORIG(MSG_MAP_TOK_2));
- if (end == NULL)
- nextchr = Start_tok + strlen(Start_tok);
- else {
- nextchr = end;
- oldchr = *nextchr;
- *nextchr = '\0';
- }
- return (TK_STRING);
- }
- }
-}
/*
* Process a hardware/software capabilities segment declaration definition.
@@ -205,88 +65,60 @@ gettoken(Ofl_desc *ofl, const char *mapfile, int eof_ok)
*
* effectively removes any capabilities information from the final image.
*/
-static uintptr_t
-map_cap(const char *mapfile, Word type, Ofl_desc *ofl)
+static Boolean
+map_cap(Mapfile *mf, Word type, CapMask *capmask)
{
- Token tok; /* Current token. */
- Xword number;
- int used = 0;
+ Token tok; /* Current token. */
+ Xword number;
+ int used = 0;
+ Ofl_desc *ofl = mf->mf_ofl;
+ ld_map_tkval_t tkv; /* Value of token */
+ elfcap_mask_t value = 0;
+
+ if (DBG_ENABLED) {
+ Dbg_cap_mapfile_title(ofl->ofl_lml, mf->mf_lineno);
+ Dbg_cap_entry2(ofl->ofl_lml, DBG_STATE_CURRENT, CA_SUNW_HW_1,
+ capmask, ld_targ.t_m.m_mach);
+ }
- while ((tok = gettoken(ofl, mapfile, 0)) != TK_SEMICOLON) {
+ while ((tok = ld_map_gettoken(mf, TK_F_STRLC, &tkv)) !=
+ TK_SEMICOLON) {
if (tok != TK_STRING) {
if (tok != TK_ERROR)
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_EXPSEGATT), mapfile,
- EC_XWORD(Line_num));
- return (S_ERROR);
+ mf_fatal0(mf, MSG_INTL(MSG_MAP_EXPSEGATT));
+ return (FALSE);
}
- lowercase(Start_tok);
-
/*
* First, determine if the token represents the reserved
* OVERRIDE keyword.
*/
- if (strncmp(Start_tok, MSG_ORIG(MSG_MAP_OVERRIDE),
+ if (strncmp(tkv.tkv_str, MSG_ORIG(MSG_MAP_OVERRIDE),
MSG_MAP_OVERRIDE_SIZE) == 0) {
- if (type == CA_SUNW_HW_1)
- ofl->ofl_flags1 |= FLG_OF1_OVHWCAP;
- else
- ofl->ofl_flags1 |= FLG_OF1_OVSFCAP;
+ ld_map_cap_set_ovflag(mf, type);
used++;
continue;
}
- /*
- * Next, determine if the token represents a machine specific
- * hardware capability, or a generic software capability.
- */
- if (type == CA_SUNW_HW_1) {
- if ((number = (Xword)elfcap_hw1_from_str(
- ELFCAP_STYLE_LC, Start_tok,
- ld_targ.t_m.m_mach)) != 0) {
- ofl->ofl_hwcap_1 |= number;
- used++;
- continue;
- }
- } else {
- if ((number = (Xword)elfcap_sf1_from_str(
- ELFCAP_STYLE_LC, Start_tok,
- ld_targ.t_m.m_mach)) != 0) {
- ofl->ofl_sfcap_1 |= number;
- used++;
- continue;
- }
+ /* Is the token a symbolic capability name? */
+ if ((number = (Xword)elfcap_tag_from_str(ELFCAP_STYLE_LC,
+ type, tkv.tkv_str, ld_targ.t_m.m_mach)) != 0) {
+ value |= number;
+ used++;
+ continue;
}
/*
- * Next, determine if the token represents a numeric value.
+ * Is the token a numeric value?
*/
- if (Start_tok[0] == 'v') {
- char *end_tok;
-
- errno = 0;
- number = (Xword)strtoul(&Start_tok[1], &end_tok, 0);
- if (errno) {
- int err = errno;
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_BADCAPVAL),
- mapfile, EC_XWORD(Line_num), Start_tok,
- strerror(err));
- return (S_ERROR);
- }
- if (end_tok != strchr(Start_tok, '\0')) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_BADCAPVAL), mapfile,
- EC_XWORD(Line_num), Start_tok,
- MSG_INTL(MSG_MAP_NOBADFRM));
- return (S_ERROR);
+ if (tkv.tkv_str[0] == 'v') {
+ if (ld_map_strtoxword(&tkv.tkv_str[1], NULL,
+ &number) != STRTOXWORD_OK) {
+ mf_fatal(mf, MSG_INTL(MSG_MAP_BADCAPVAL),
+ tkv.tkv_str);
+ return (FALSE);
}
-
- if (type == CA_SUNW_HW_1)
- ofl->ofl_hwcap_1 |= number;
- else
- ofl->ofl_sfcap_1 |= number;
+ value |= number;
used++;
continue;
}
@@ -295,90 +127,198 @@ map_cap(const char *mapfile, Word type, Ofl_desc *ofl)
* We have an unknown token.
*/
used++;
- eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_MAP_UNKCAPATTR),
- mapfile, EC_XWORD(Line_num), Start_tok);
- return (S_ERROR);
+ mf_fatal(mf, MSG_INTL(MSG_MAP_UNKCAPATTR), tkv.tkv_str);
+ return (FALSE);
}
- /*
- * Catch any empty declarations, and indicate any software capabilities
- * have been initialized if necessary.
- */
+ /* Catch empty declarations */
if (used == 0) {
- eprintf(ofl->ofl_lml, ERR_WARNING, MSG_INTL(MSG_MAP_EMPTYCAP),
- mapfile, EC_XWORD(Line_num));
- } else if (type == CA_SUNW_SF_1) {
- Lword badsf1;
-
- /*
- * Note, hardware capabilities, beyond the tokens that are
- * presently known, can be accepted using the V0xXXX notation,
- * and as these simply get or'd into the output image, we allow
- * any values to be supplied. Software capability tokens
- * however, have an algorithm of acceptance and update (see
- * sf1_cap() in files.c). Therefore only allow software
- * capabilities that are known.
- */
- if ((badsf1 = (ofl->ofl_sfcap_1 & ~SF1_SUNW_MASK)) != 0) {
- eprintf(ofl->ofl_lml, ERR_WARNING,
- MSG_INTL(MSG_MAP_BADSF1), mapfile,
- EC_XWORD(Line_num), EC_LWORD(badsf1));
- ofl->ofl_sfcap_1 &= SF1_SUNW_MASK;
- }
- if ((ofl->ofl_sfcap_1 &
- (SF1_SUNW_FPKNWN | SF1_SUNW_FPUSED)) == SF1_SUNW_FPUSED) {
- eprintf(ofl->ofl_lml, ERR_WARNING,
- MSG_INTL(MSG_MAPFIL_BADSF1), mapfile,
- EC_XWORD(Line_num), EC_LWORD(SF1_SUNW_FPUSED));
- ofl->ofl_sfcap_1 &= ~SF1_SUNW_FPUSED;
- }
-#if !defined(_ELF64)
- /*
- * The SF1_SUNW_ADDR32 software capability is only meaningful
- * when building a 64-bit object. Warn the user, and remove the
- * setting, if we're building a 32-bit object.
- */
- if (ofl->ofl_sfcap_1 & SF1_SUNW_ADDR32) {
- eprintf(ofl->ofl_lml, ERR_WARNING,
- MSG_INTL(MSG_MAP_INADDR32SF1), mapfile,
- EC_XWORD(Line_num));
- ofl->ofl_sfcap_1 &= ~SF1_SUNW_ADDR32;
- }
-#endif
+ mf_warn0(mf, MSG_INTL(MSG_MAP_EMPTYCAP));
+ return (TRUE);
}
- return (1);
+
+ Dbg_cap_entry(ofl->ofl_lml, DBG_STATE_NEW, type, value,
+ ld_targ.t_m.m_mach);
+ capmask->cm_value |= value;
+
+ /* Sanity check the resulting bits */
+ if (!ld_map_cap_sanitize(mf, type, capmask))
+ return (FALSE);
+
+ DBG_CALL(Dbg_cap_entry2(ofl->ofl_lml, DBG_STATE_RESOLVED, type,
+ capmask, ld_targ.t_m.m_mach));
+
+ return (TRUE);
}
/*
- * Common segment error checking.
+ * Parse the flags for a segment definition. Called by map_equal().
+ *
+ * entry:
+ * mf - Mapfile descriptor
+ * sgp - Segment being defined
+ * b_flags - Address of b_flags variable from map_equal().
+ * *bflags is TRUE if flags have already been seen in, the
+ * current segment definition directive, and FALSE otherwise.
+ * flag_tok - Flags string, starting with the '?' character.
+ *
+ * exit:
+ * On success, the flags have been parsed and the segment updated,
+ * *b_flags is set to TRUE, and TRUE is returned. On error, FALSE
+ * is returned.
*/
static Boolean
-seg_check(const char *mapfile, Sg_desc *sgp, Ofl_desc *ofl, Boolean b_type,
- Word p_type)
+map_equal_flags(Mapfile *mf, Sg_desc *sgp, Boolean *b_flags,
+ const char *flag_tok)
{
- if (b_type) {
- eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_MAP_MOREONCE),
- mapfile, EC_XWORD(Line_num), MSG_INTL(MSG_MAP_SEGTYP));
+ Word tmp_flags = 0;
+
+ if (*b_flags) {
+ mf_fatal(mf, MSG_INTL(MSG_MAP_MOREONCE),
+ MSG_INTL(MSG_MAP_SEGFLAG));
return (FALSE);
}
- if ((sgp->sg_flags & FLG_SG_TYPE) && (sgp->sg_phdr.p_type != p_type)) {
- eprintf(ofl->ofl_lml, ERR_WARNING, MSG_INTL(MSG_MAP_REDEFATT),
- mapfile, EC_XWORD(Line_num), MSG_INTL(MSG_MAP_SEGTYP),
- sgp->sg_name);
+
+ /* Skip over the leading '?' character */
+ flag_tok++;
+
+ /*
+ * If ? has nothing following leave the flags cleared,
+ * otherwise OR in any flags specified.
+ */
+ while (*flag_tok) {
+ switch (*flag_tok) {
+ case 'r':
+ tmp_flags |= PF_R;
+ break;
+ case 'w':
+ tmp_flags |= PF_W;
+ break;
+ case 'x':
+ tmp_flags |= PF_X;
+ break;
+ case 'e':
+ sgp->sg_flags |= FLG_SG_EMPTY;
+ break;
+ case 'o':
+ /*
+ * The version 1 ?O option is incompatible with
+ * the version 2 SEGMENT IS_ORDER attribute.
+ */
+ if (aplist_nitems(sgp->sg_is_order) > 0) {
+ mf_fatal(mf, MSG_INTL(MSG_MAP_ISORDVER),
+ sgp->sg_name);
+ return (FALSE);
+ }
+
+ /*
+ * Set FLG_SG_IS_ORDER to indicate that segment has
+ * had the ?O flag set by a version 1 mapfile.
+ */
+ sgp->sg_flags |= FLG_SG_IS_ORDER;
+ break;
+ case 'n':
+ /*
+ * If segment ends up as the first loadable segment,
+ * it will not include the the ELF and program headers.
+ */
+ sgp->sg_flags |= FLG_SG_NOHDR;
+ break;
+ default:
+ mf_fatal(mf, MSG_INTL(MSG_MAP_UNKSEGFLG), *flag_tok);
+ return (FALSE);
+ }
+ flag_tok++;
}
+
+ /*
+ * Warn when changing flags except when we're adding or removing "X"
+ * from a RW PT_LOAD segment.
+ */
+ if ((sgp->sg_flags & FLG_SG_P_FLAGS) &&
+ (sgp->sg_phdr.p_flags != tmp_flags) &&
+ !(sgp->sg_phdr.p_type == PT_LOAD &&
+ (tmp_flags & (PF_R|PF_W)) == (PF_R|PF_W) &&
+ (tmp_flags ^ sgp->sg_phdr.p_flags) == PF_X))
+ mf_warn(mf, MSG_INTL(MSG_MAP_REDEFATT),
+ MSG_INTL(MSG_MAP_SEGFLAG), sgp->sg_name);
+
+ sgp->sg_flags |= FLG_SG_P_FLAGS;
+ sgp->sg_phdr.p_flags = tmp_flags;
+ *b_flags = TRUE;
+
return (TRUE);
}
/*
+ * Read an address (value) or size Xword from a TK_STRING token value
+ * where the first letter of the string is a letter ('v', 'l', 's', ...)
+ * followed by the numeric value.
+ *
+ * entry:
+ * mf - Mapfile descriptor
+ * tkv - TK_STRING token to parse
+ * value - Address of variable to receive the resulting value.
+ *
+ * exit:
+ * Returns TRUE for success. On failure, issues an error message
+ * and returns FALSE.
+ */
+static Boolean
+valuetoxword(Mapfile *mf, ld_map_tkval_t *tkv, Xword *value)
+{
+ switch (ld_map_strtoxword(&tkv->tkv_str[1], NULL, value)) {
+ case STRTOXWORD_OK:
+ return (TRUE);
+
+ case STRTOXWORD_TOOBIG:
+ mf_fatal(mf, MSG_INTL(MSG_MAP_SEGADDR), tkv->tkv_str,
+ MSG_INTL(MSG_MAP_EXCLIMIT));
+ break;
+ default:
+ mf_fatal(mf, MSG_INTL(MSG_MAP_SEGADDR), tkv->tkv_str,
+ MSG_INTL(MSG_MAP_NOBADFRM));
+ break;
+ }
+
+ return (FALSE);
+}
+
+/*
* Process a mapfile segment declaration definition.
* segment_name = segment_attribute;
* segment_attribute : segment_type segment_flags virtual_addr
* physical_addr length alignment
*/
-static uintptr_t
-map_equal(const char *mapfile, Sg_desc *sgp, Ofl_desc *ofl)
+static Boolean
+map_equal(Mapfile *mf, Sg_desc *sgp)
{
+ /*
+ * Segment type. Users are permitted to define PT_LOAD,
+ * PT_NOTE, PT_SUNWSTACK and PT_NULL segments. Other segment
+ * types are only defined in seg_desc[].
+ */
+ typedef struct {
+ const char *name; /* Name for segment type */
+ Word p_type; /* PT_ constant corresponding to name */
+ sg_flags_t sg_flags; /* Seg descriptor flags to apply */
+ } seg_types_t;
+
+ static seg_types_t seg_type_arr[] = {
+ { MSG_ORIG(MSG_MAP_LOAD), PT_LOAD, FLG_SG_P_TYPE },
+ { MSG_ORIG(MSG_MAP_STACK), PT_SUNWSTACK,
+ FLG_SG_P_TYPE | FLG_SG_EMPTY },
+ { MSG_ORIG(MSG_MAP_NULL), PT_NULL, FLG_SG_P_TYPE },
+ { MSG_ORIG(MSG_MAP_NOTE), PT_NOTE, FLG_SG_P_TYPE },
+
+ /* Array must be NULL terminated */
+ { NULL }
+ };
+
+
+ seg_types_t *seg_type;
Token tok; /* Current token. */
+ ld_map_tkval_t tkv; /* Value of token */
Boolean b_type = FALSE; /* True if seg types found. */
Boolean b_flags = FALSE; /* True if seg flags found. */
Boolean b_len = FALSE; /* True if seg length found. */
@@ -387,166 +327,69 @@ map_equal(const char *mapfile, Sg_desc *sgp, Ofl_desc *ofl)
Boolean b_paddr = FALSE; /* True if seg physical addr found. */
Boolean b_align = FALSE; /* True if seg alignment found. */
- while ((tok = gettoken(ofl, mapfile, 0)) != TK_SEMICOLON) {
+ while ((tok = ld_map_gettoken(mf, TK_F_STRLC, &tkv)) !=
+ TK_SEMICOLON) {
if (tok != TK_STRING) {
if (tok != TK_ERROR)
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_EXPSEGATT), mapfile,
- EC_XWORD(Line_num));
- return (S_ERROR);
+ mf_fatal0(mf, MSG_INTL(MSG_MAP_EXPSEGATT));
+ return (FALSE);
}
- lowercase(Start_tok);
-
/*
- * Segment type. Users are permitted to define PT_LOAD,
- * PT_NOTE, PT_STACK and PT_NULL segments. Other segment types
- * are only defined in seg_desc[].
+ * If it is the name of a segment type, set the type
+ * and flags fields in the descriptor.
*/
- if (strcmp(Start_tok, MSG_ORIG(MSG_MAP_LOAD)) == 0) {
- if ((b_type = seg_check(mapfile, sgp, ofl, b_type,
- PT_LOAD)) == FALSE)
- return (S_ERROR);
-
- sgp->sg_phdr.p_type = PT_LOAD;
- sgp->sg_flags |= FLG_SG_TYPE;
-
- } else if (strcmp(Start_tok, MSG_ORIG(MSG_MAP_STACK)) == 0) {
- if ((b_type = seg_check(mapfile, sgp, ofl, b_type,
- PT_SUNWSTACK)) == FALSE)
- return (S_ERROR);
-
- sgp->sg_phdr.p_type = PT_SUNWSTACK;
- sgp->sg_flags |= (FLG_SG_TYPE | FLG_SG_EMPTY);
-
- } else if (strcmp(Start_tok, MSG_ORIG(MSG_MAP_NULL)) == 0) {
- if ((b_type = seg_check(mapfile, sgp, ofl, b_type,
- PT_NULL)) == FALSE)
- return (S_ERROR);
-
- sgp->sg_phdr.p_type = PT_NULL;
- sgp->sg_flags |= FLG_SG_TYPE;
-
- } else if (strcmp(Start_tok, MSG_ORIG(MSG_MAP_NOTE)) == 0) {
- if ((b_type = seg_check(mapfile, sgp, ofl, b_type,
- PT_NOTE)) == FALSE)
- return (S_ERROR);
-
- sgp->sg_phdr.p_type = PT_NOTE;
- sgp->sg_flags |= FLG_SG_TYPE;
- }
-
- /* Segment Flags. */
-
- else if (*Start_tok == '?') {
- Word tmp_flags = 0;
- char *flag_tok = Start_tok + 1;
-
- if (b_flags) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_MOREONCE), mapfile,
- EC_XWORD(Line_num),
- MSG_INTL(MSG_MAP_SEGFLAG));
- return (S_ERROR);
- }
-
- /*
- * If ? has nothing following leave the flags cleared,
- * otherwise or in any flags specified.
- */
- if (*flag_tok) {
- while (*flag_tok) {
- switch (*flag_tok) {
- case 'r':
- tmp_flags |= PF_R;
- break;
- case 'w':
- tmp_flags |= PF_W;
- break;
- case 'x':
- tmp_flags |= PF_X;
- break;
- case 'e':
- sgp->sg_flags |= FLG_SG_EMPTY;
- break;
- case 'o':
- sgp->sg_flags |= FLG_SG_ORDER;
- ofl->ofl_flags |=
- FLG_OF_SEGORDER;
- break;
- case 'n':
- sgp->sg_flags |= FLG_SG_NOHDR;
- break;
- default:
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_UNKSEGFLG),
- mapfile, EC_XWORD(Line_num),
- *flag_tok);
- return (S_ERROR);
- }
- flag_tok++;
+ for (seg_type = seg_type_arr; seg_type->name; seg_type++) {
+ if (strcmp(tkv.tkv_str, seg_type->name) == 0) {
+ if (b_type) {
+ mf_fatal(mf, MSG_INTL(MSG_MAP_MOREONCE),
+ MSG_INTL(MSG_MAP_SEGTYP));
+ return (FALSE);
}
+ if ((sgp->sg_flags & FLG_SG_P_TYPE) &&
+ (sgp->sg_phdr.p_type != seg_type->p_type)) {
+ mf_warn(mf, MSG_INTL(MSG_MAP_REDEFATT),
+ MSG_INTL(MSG_MAP_SEGTYP),
+ sgp->sg_name);
+ }
+
+ sgp->sg_phdr.p_type = seg_type->p_type;
+ sgp->sg_flags |= seg_type->sg_flags;
+ break;
}
- /*
- * Warn when changing flags except when we're
- * adding or removing "X" from a RW PT_LOAD
- * segment.
- */
- if ((sgp->sg_flags & FLG_SG_FLAGS) &&
- (sgp->sg_phdr.p_flags != tmp_flags) &&
- !(sgp->sg_phdr.p_type == PT_LOAD &&
- (tmp_flags & (PF_R|PF_W)) == (PF_R|PF_W) &&
- (tmp_flags ^ sgp->sg_phdr.p_flags) == PF_X)) {
- eprintf(ofl->ofl_lml, ERR_WARNING,
- MSG_INTL(MSG_MAP_REDEFATT), mapfile,
- EC_XWORD(Line_num),
- MSG_INTL(MSG_MAP_SEGFLAG), sgp->sg_name);
- }
- sgp->sg_flags |= FLG_SG_FLAGS;
- sgp->sg_phdr.p_flags = tmp_flags;
- b_flags = TRUE;
+ }
+ if (seg_type->name != NULL) /* Matched segment type */
+ continue; /* next token */
+
+ /* Segment Flags */
+ if (*tkv.tkv_str == '?') {
+ if (!map_equal_flags(mf, sgp, &b_flags, tkv.tkv_str))
+ return (FALSE);
+ continue; /* next token */
}
- /* Segment address, length, alignment or rounding number. */
-
- else if ((Start_tok[0] == 'l') || (Start_tok[0] == 'v') ||
- (Start_tok[0] == 'a') || (Start_tok[0] == 'p') ||
- (Start_tok[0] == 'r')) {
- char *end_tok;
- Xword number;
-
- if ((number = (Xword)STRTOADDR(&Start_tok[1], &end_tok,
- 0)) >= XWORD_MAX) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_SEGADDR), mapfile,
- EC_XWORD(Line_num), Start_tok,
- MSG_INTL(MSG_MAP_EXCLIMIT));
- return (S_ERROR);
- }
+ /* Segment address, length, alignment or rounding number */
+ if ((tkv.tkv_str[0] == 'l') || (tkv.tkv_str[0] == 'v') ||
+ (tkv.tkv_str[0] == 'a') || (tkv.tkv_str[0] == 'p') ||
+ (tkv.tkv_str[0] == 'r')) {
+ Xword number;
- if (end_tok != strchr(Start_tok, '\0')) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_SEGADDR), mapfile,
- EC_XWORD(Line_num), Start_tok,
- MSG_INTL(MSG_MAP_NOBADFRM));
- return (S_ERROR);
- }
+ if (!valuetoxword(mf, &tkv, &number))
+ return (FALSE);
- switch (*Start_tok) {
+ switch (*tkv.tkv_str) {
case 'l':
if (b_len) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
+ mf_fatal(mf,
MSG_INTL(MSG_MAP_MOREONCE),
- mapfile, EC_XWORD(Line_num),
MSG_INTL(MSG_MAP_SEGLEN));
- return (S_ERROR);
+ return (FALSE);
}
if ((sgp->sg_flags & FLG_SG_LENGTH) &&
(sgp->sg_length != number))
- eprintf(ofl->ofl_lml, ERR_WARNING,
+ mf_warn(mf,
MSG_INTL(MSG_MAP_REDEFATT),
- mapfile, EC_XWORD(Line_num),
MSG_INTL(MSG_MAP_SEGLEN),
sgp->sg_name);
sgp->sg_length = number;
@@ -555,17 +398,15 @@ map_equal(const char *mapfile, Sg_desc *sgp, Ofl_desc *ofl)
break;
case 'r':
if (b_round) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
+ mf_fatal(mf,
MSG_INTL(MSG_MAP_MOREONCE),
- mapfile, EC_XWORD(Line_num),
MSG_INTL(MSG_MAP_SEGROUND));
- return (S_ERROR);
+ return (FALSE);
}
if ((sgp->sg_flags & FLG_SG_ROUND) &&
(sgp->sg_round != number))
- eprintf(ofl->ofl_lml, ERR_WARNING,
+ mf_warn(mf,
MSG_INTL(MSG_MAP_REDEFATT),
- mapfile, EC_XWORD(Line_num),
MSG_INTL(MSG_MAP_SEGROUND),
sgp->sg_name);
sgp->sg_round = number;
@@ -574,73 +415,69 @@ map_equal(const char *mapfile, Sg_desc *sgp, Ofl_desc *ofl)
break;
case 'v':
if (b_vaddr) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
+ mf_fatal(mf,
MSG_INTL(MSG_MAP_MOREONCE),
- mapfile, EC_XWORD(Line_num),
MSG_INTL(MSG_MAP_SEGVADDR));
- return (S_ERROR);
+ return (FALSE);
}
- if ((sgp->sg_flags & FLG_SG_VADDR) &&
+ if ((sgp->sg_flags & FLG_SG_P_VADDR) &&
(sgp->sg_phdr.p_vaddr != number))
- eprintf(ofl->ofl_lml, ERR_WARNING,
+ mf_warn(mf,
MSG_INTL(MSG_MAP_REDEFATT),
- mapfile, EC_XWORD(Line_num),
MSG_INTL(MSG_MAP_SEGVADDR),
sgp->sg_name);
/* LINTED */
sgp->sg_phdr.p_vaddr = (Addr)number;
- sgp->sg_flags |= FLG_SG_VADDR;
- ofl->ofl_flags1 |= FLG_OF1_VADDR;
- ofl->ofl_flags |= FLG_OF_SEGSORT;
+ sgp->sg_flags |= FLG_SG_P_VADDR;
b_vaddr = TRUE;
break;
case 'p':
if (b_paddr) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
+ mf_fatal(mf,
MSG_INTL(MSG_MAP_MOREONCE),
- mapfile, EC_XWORD(Line_num),
MSG_INTL(MSG_MAP_SEGPHYS));
- return (S_ERROR);
+ return (FALSE);
}
- if ((sgp->sg_flags & FLG_SG_PADDR) &&
+ if ((sgp->sg_flags & FLG_SG_P_PADDR) &&
(sgp->sg_phdr.p_paddr != number))
- eprintf(ofl->ofl_lml, ERR_WARNING,
+ mf_warn(mf,
MSG_INTL(MSG_MAP_REDEFATT),
- mapfile, EC_XWORD(Line_num),
MSG_INTL(MSG_MAP_SEGPHYS),
sgp->sg_name);
/* LINTED */
sgp->sg_phdr.p_paddr = (Addr)number;
- sgp->sg_flags |= FLG_SG_PADDR;
+ sgp->sg_flags |= FLG_SG_P_PADDR;
b_paddr = TRUE;
break;
case 'a':
if (b_align) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
+ mf_fatal(mf,
MSG_INTL(MSG_MAP_MOREONCE),
- mapfile, EC_XWORD(Line_num),
MSG_INTL(MSG_MAP_SEGALIGN));
- return (S_ERROR);
+ return (FALSE);
}
- if ((sgp->sg_flags & FLG_SG_ALIGN) &&
+ if ((sgp->sg_flags & FLG_SG_P_ALIGN) &&
(sgp->sg_phdr.p_align != number))
- eprintf(ofl->ofl_lml, ERR_WARNING,
+ mf_warn(mf,
MSG_INTL(MSG_MAP_REDEFATT),
- mapfile, EC_XWORD(Line_num),
MSG_INTL(MSG_MAP_SEGALIGN),
sgp->sg_name);
/* LINTED */
sgp->sg_phdr.p_align = (Xword)number;
- sgp->sg_flags |= FLG_SG_ALIGN;
+ sgp->sg_flags |= FLG_SG_P_ALIGN;
b_align = TRUE;
break;
}
- } else {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_UNKSEGATT), mapfile,
- EC_XWORD(Line_num), Start_tok);
- return (S_ERROR);
+
+ continue; /* next token */
}
+
+ /*
+ * If we reach the bottom of this loop, we have an
+ * unrecognized token.
+ */
+ mf_fatal(mf, MSG_INTL(MSG_MAP_UNKSEGATT), tkv.tkv_str);
+ return (FALSE);
}
/*
@@ -650,7 +487,8 @@ map_equal(const char *mapfile, Sg_desc *sgp, Ofl_desc *ofl)
* PT_LOAD reservations are only allowed within executables, as the
* reservation must be established through exec() as part of initial
* process loading. In addition, PT_LOAD reservations must have an
- * associated address and size.
+ * associated address and size. Note: This is an obsolete feature,
+ * not supported by the newer mapfile syntax.
*
* PT_NULL program headers are established for later use by applications
* such as the post-optimizer. PT_NULL headers should have no other
@@ -663,40 +501,32 @@ map_equal(const char *mapfile, Sg_desc *sgp, Ofl_desc *ofl)
* Any style of empty segment should have no permissions.
*/
if (sgp->sg_phdr.p_flags != 0) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_SEGEMNOPERM), mapfile,
- EC_XWORD(Line_num),
+ mf_fatal(mf, MSG_INTL(MSG_MAP_SEGEMNOPERM),
EC_WORD(sgp->sg_phdr.p_flags));
- return (S_ERROR);
+ return (FALSE);
}
if (sgp->sg_phdr.p_type == PT_LOAD) {
- if ((ofl->ofl_flags & FLG_OF_EXEC) == 0) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_SEGEMPEXE), mapfile,
- EC_XWORD(Line_num));
- return (S_ERROR);
+ if ((mf->mf_ofl->ofl_flags & FLG_OF_EXEC) == 0) {
+ mf_fatal0(mf, MSG_INTL(MSG_MAP_SEGEMPEXE));
+ return (FALSE);
}
- if ((sgp->sg_flags & (FLG_SG_LENGTH | FLG_SG_VADDR)) !=
- (FLG_SG_LENGTH | FLG_SG_VADDR)) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_SEGEMPATT), mapfile,
- EC_XWORD(Line_num));
- return (S_ERROR);
+ if ((sgp->sg_flags &
+ (FLG_SG_LENGTH | FLG_SG_P_VADDR)) !=
+ (FLG_SG_LENGTH | FLG_SG_P_VADDR)) {
+ mf_fatal0(mf, MSG_INTL(MSG_MAP_SEGEMPATT));
+ return (FALSE);
}
} else if (sgp->sg_phdr.p_type == PT_NULL) {
- if ((sgp->sg_flags & (FLG_SG_LENGTH | FLG_SG_VADDR)) &&
+ if ((sgp->sg_flags &
+ (FLG_SG_LENGTH | FLG_SG_P_VADDR)) &&
((sgp->sg_length != 0) ||
(sgp->sg_phdr.p_vaddr != 0))) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_SEGEMPNOATT), mapfile,
- EC_XWORD(Line_num));
- return (S_ERROR);
+ mf_fatal0(mf, MSG_INTL(MSG_MAP_SEGEMPNOATT));
+ return (FALSE);
}
} else {
- eprintf(ofl->ofl_lml, ERR_WARNING,
- MSG_INTL(MSG_MAP_SEGEMPLOAD), mapfile,
- EC_XWORD(Line_num));
+ mf_warn0(mf, MSG_INTL(MSG_MAP_SEGEMPLOAD));
sgp->sg_phdr.p_type = PT_LOAD;
}
}
@@ -705,9 +535,9 @@ map_equal(const char *mapfile, Sg_desc *sgp, Ofl_desc *ofl)
* All segment attributes have now been scanned. Certain flags do not
* make sense if this is not a loadable segment, fix if necessary.
* Note, if the segment is of type PT_NULL it must be new, and any
- * defaults will be applied back in ld_map_parse().
- * When clearing an attribute leave the flag set as an indicator for
- * later entries re-specifying the same segment.
+ * defaults will be applied by ld_map_seg_insert(). When clearing an
+ * attribute leave the flag set as an indicator for later entries
+ * re-specifying the same segment.
*/
if ((sgp->sg_phdr.p_type != PT_NULL) &&
(sgp->sg_phdr.p_type != PT_LOAD)) {
@@ -718,126 +548,129 @@ map_equal(const char *mapfile, Sg_desc *sgp, Ofl_desc *ofl)
else
fmt = MSG_INTL(MSG_MAP_NONLOAD);
- if ((sgp->sg_flags & FLG_SG_FLAGS) &&
+ if ((sgp->sg_flags & FLG_SG_P_FLAGS) &&
(sgp->sg_phdr.p_type != PT_SUNWSTACK)) {
if (sgp->sg_phdr.p_flags != 0) {
- eprintf(ofl->ofl_lml, ERR_WARNING,
- MSG_INTL(MSG_MAP_NONLOAD), mapfile,
- EC_XWORD(Line_num),
+ mf_warn(mf, MSG_INTL(MSG_MAP_NONLOAD),
MSG_INTL(MSG_MAP_SEGFLAG));
sgp->sg_phdr.p_flags = 0;
}
}
if (sgp->sg_flags & FLG_SG_LENGTH)
if (sgp->sg_length != 0) {
- eprintf(ofl->ofl_lml, ERR_WARNING,
- fmt, mapfile, EC_XWORD(Line_num),
- MSG_INTL(MSG_MAP_SEGLEN));
+ mf_warn(mf, fmt, MSG_INTL(MSG_MAP_SEGLEN));
sgp->sg_length = 0;
}
if (sgp->sg_flags & FLG_SG_ROUND)
if (sgp->sg_round != 0) {
- eprintf(ofl->ofl_lml, ERR_WARNING,
- fmt, mapfile, EC_XWORD(Line_num),
- MSG_INTL(MSG_MAP_SEGROUND));
+ mf_warn(mf, fmt, MSG_INTL(MSG_MAP_SEGROUND));
sgp->sg_round = 0;
}
- if (sgp->sg_flags & FLG_SG_VADDR) {
+ if (sgp->sg_flags & FLG_SG_P_VADDR) {
if (sgp->sg_phdr.p_vaddr != 0) {
- eprintf(ofl->ofl_lml, ERR_WARNING,
- fmt, mapfile, EC_XWORD(Line_num),
- MSG_INTL(MSG_MAP_SEGVADDR));
+ mf_warn(mf, fmt, MSG_INTL(MSG_MAP_SEGVADDR));
sgp->sg_phdr.p_vaddr = 0;
}
}
- if (sgp->sg_flags & FLG_SG_PADDR)
+ if (sgp->sg_flags & FLG_SG_P_PADDR)
if (sgp->sg_phdr.p_paddr != 0) {
- eprintf(ofl->ofl_lml, ERR_WARNING,
- fmt, mapfile, EC_XWORD(Line_num),
- MSG_INTL(MSG_MAP_SEGPHYS));
+ mf_warn(mf, fmt, MSG_INTL(MSG_MAP_SEGPHYS));
sgp->sg_phdr.p_paddr = 0;
}
- if (sgp->sg_flags & FLG_SG_ALIGN)
+ if (sgp->sg_flags & FLG_SG_P_ALIGN)
if (sgp->sg_phdr.p_align != 0) {
- eprintf(ofl->ofl_lml, ERR_WARNING,
- fmt, mapfile, EC_XWORD(Line_num),
- MSG_INTL(MSG_MAP_SEGALIGN));
+ mf_warn(mf, fmt, MSG_INTL(MSG_MAP_SEGALIGN));
sgp->sg_phdr.p_align = 0;
}
}
- return (1);
+ return (TRUE);
}
/*
* Process a mapfile mapping directives definition.
+ *
* segment_name : section_attribute [ : file_name ]
- * segment_attribute : section_name section_type section_flags;
+ *
+ * Where segment_attribute is one of: section_name section_type section_flags;
*/
-static uintptr_t
-map_colon(Ofl_desc *ofl, const char *mapfile, Ent_desc *enp)
+static Boolean
+map_colon(Mapfile *mf, Ent_desc *enp)
{
- Token tok; /* Current token. */
-
+ Token tok;
+ ld_map_tkval_t tkv;
Boolean b_name = FALSE;
Boolean b_type = FALSE;
Boolean b_attr = FALSE;
Boolean b_bang = FALSE;
- static Xword index = 0;
- while (((tok = gettoken(ofl, mapfile, 0)) != TK_COLON) &&
+ /*
+ * Start out assuming that this entrance criteria will be empty,
+ * and therefore match anything. We clear the CATCHALL flag below
+ * if this turns out not to be the case.
+ */
+ enp->ec_flags |= FLG_EC_CATCHALL;
+
+ while (((tok = ld_map_gettoken(mf, 0, &tkv)) != TK_COLON) &&
(tok != TK_SEMICOLON)) {
- if ((tok == TK_ERROR) || (tok == TK_EOF))
- return (S_ERROR);
+ if (tok == TK_ERROR)
+ return (FALSE);
+ if (tok != TK_STRING) {
+ mf_fatal0(mf, MSG_INTL(MSG_MAP_MALFORM));
+ return (FALSE);
+ }
/* Segment type. */
- if (*Start_tok == '$') {
+ if (*tkv.tkv_str == '$') {
if (b_type) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_MOREONCE), mapfile,
- EC_XWORD(Line_num),
+ mf_fatal(mf, MSG_INTL(MSG_MAP_MOREONCE),
MSG_INTL(MSG_MAP_SECTYP));
- return (S_ERROR);
+ return (FALSE);
}
b_type = TRUE;
- Start_tok++;
- lowercase(Start_tok);
- if (strcmp(Start_tok, MSG_ORIG(MSG_STR_PROGBITS)) == 0)
+ tkv.tkv_str++;
+ ld_map_lowercase(tkv.tkv_str);
+ if (strcmp(tkv.tkv_str, MSG_ORIG(MSG_STR_PROGBITS)) ==
+ 0)
enp->ec_type = SHT_PROGBITS;
- else if (strcmp(Start_tok,
+ else if (strcmp(tkv.tkv_str,
MSG_ORIG(MSG_STR_SYMTAB)) == 0)
enp->ec_type = SHT_SYMTAB;
- else if (strcmp(Start_tok,
+ else if (strcmp(tkv.tkv_str,
MSG_ORIG(MSG_STR_DYNSYM)) == 0)
enp->ec_type = SHT_DYNSYM;
- else if (strcmp(Start_tok,
+ else if (strcmp(tkv.tkv_str,
MSG_ORIG(MSG_STR_STRTAB)) == 0)
enp->ec_type = SHT_STRTAB;
- else if ((strcmp(Start_tok,
+ else if ((strcmp(tkv.tkv_str,
MSG_ORIG(MSG_STR_REL)) == 0) ||
- (strcmp(Start_tok, MSG_ORIG(MSG_STR_RELA)) == 0))
+ (strcmp(tkv.tkv_str, MSG_ORIG(MSG_STR_RELA)) == 0))
enp->ec_type = ld_targ.t_m.m_rel_sht_type;
- else if (strcmp(Start_tok, MSG_ORIG(MSG_STR_HASH)) == 0)
+ else if (strcmp(tkv.tkv_str, MSG_ORIG(MSG_STR_HASH)) ==
+ 0)
enp->ec_type = SHT_HASH;
- else if (strcmp(Start_tok, MSG_ORIG(MSG_STR_LIB)) == 0)
+ else if (strcmp(tkv.tkv_str, MSG_ORIG(MSG_STR_LIB)) ==
+ 0)
enp->ec_type = SHT_SHLIB;
- else if (strcmp(Start_tok,
+ else if (strcmp(tkv.tkv_str,
MSG_ORIG(MSG_STR_LD_DYNAMIC)) == 0)
enp->ec_type = SHT_DYNAMIC;
- else if (strcmp(Start_tok, MSG_ORIG(MSG_STR_NOTE)) == 0)
+ else if (strcmp(tkv.tkv_str, MSG_ORIG(MSG_STR_NOTE)) ==
+ 0)
enp->ec_type = SHT_NOTE;
- else if (strcmp(Start_tok,
+ else if (strcmp(tkv.tkv_str,
MSG_ORIG(MSG_STR_NOBITS)) == 0)
enp->ec_type = SHT_NOBITS;
else {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_UNKSECTYP), mapfile,
- EC_XWORD(Line_num), Start_tok);
- return (S_ERROR);
+ mf_fatal(mf, MSG_INTL(MSG_MAP_UNKSECTYP),
+ tkv.tkv_str);
+ return (FALSE);
}
+ enp->ec_flags &= ~FLG_EC_CATCHALL;
+
/*
* Segment flags.
* If a segment flag is specified then the appropriate bit is
@@ -846,37 +679,33 @@ map_colon(Ofl_desc *ofl, const char *mapfile, Ent_desc *enp)
* ie. for ?A the attrmask is set and the attrbit is set,
* for ?!A the attrmask is set and the attrbit is clear.
*/
- } else if (*Start_tok == '?') {
+ } else if (*tkv.tkv_str == '?') {
if (b_attr) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_MOREONCE), mapfile,
- EC_XWORD(Line_num),
+ mf_fatal(mf, MSG_INTL(MSG_MAP_MOREONCE),
MSG_INTL(MSG_MAP_SECFLAG));
- return (S_ERROR);
+ return (FALSE);
}
b_attr = TRUE;
b_bang = FALSE;
- Start_tok++;
- lowercase(Start_tok);
- for (; *Start_tok != '\0'; Start_tok++)
- switch (*Start_tok) {
+ tkv.tkv_str++;
+ ld_map_lowercase(tkv.tkv_str);
+ for (; *tkv.tkv_str != '\0'; tkv.tkv_str++)
+ switch (*tkv.tkv_str) {
case '!':
if (b_bang) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
+ mf_fatal(mf,
MSG_INTL(MSG_MAP_BADFLAG),
- mapfile, EC_XWORD(Line_num),
- Start_tok);
- return (S_ERROR);
+ tkv.tkv_str);
+ return (FALSE);
}
b_bang = TRUE;
break;
case 'a':
if (enp->ec_attrmask & SHF_ALLOC) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
+ mf_fatal(mf,
MSG_INTL(MSG_MAP_BADFLAG),
- mapfile, EC_XWORD(Line_num),
- Start_tok);
- return (S_ERROR);
+ tkv.tkv_str);
+ return (FALSE);
}
enp->ec_attrmask |= SHF_ALLOC;
if (!b_bang)
@@ -885,11 +714,10 @@ map_colon(Ofl_desc *ofl, const char *mapfile, Ent_desc *enp)
break;
case 'w':
if (enp->ec_attrmask & SHF_WRITE) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
+ mf_fatal(mf,
MSG_INTL(MSG_MAP_BADFLAG),
- mapfile, EC_XWORD(Line_num),
- Start_tok);
- return (S_ERROR);
+ tkv.tkv_str);
+ return (FALSE);
}
enp->ec_attrmask |= SHF_WRITE;
if (!b_bang)
@@ -898,11 +726,10 @@ map_colon(Ofl_desc *ofl, const char *mapfile, Ent_desc *enp)
break;
case 'x':
if (enp->ec_attrmask & SHF_EXECINSTR) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
+ mf_fatal(mf,
MSG_INTL(MSG_MAP_BADFLAG),
- mapfile, EC_XWORD(Line_num),
- Start_tok);
- return (S_ERROR);
+ tkv.tkv_str);
+ return (FALSE);
}
enp->ec_attrmask |= SHF_EXECINSTR;
if (!b_bang)
@@ -911,236 +738,115 @@ map_colon(Ofl_desc *ofl, const char *mapfile, Ent_desc *enp)
b_bang = FALSE;
break;
default:
- eprintf(ofl->ofl_lml, ERR_FATAL,
+ mf_fatal(mf,
MSG_INTL(MSG_MAP_BADFLAG),
- mapfile, EC_XWORD(Line_num),
- Start_tok);
- return (S_ERROR);
+ tkv.tkv_str);
+ return (FALSE);
}
+ if (enp->ec_attrmask != 0)
+ enp->ec_flags &= ~FLG_EC_CATCHALL;
+
/*
* Section name.
*/
} else {
if (b_name) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_MOREONCE), mapfile,
- EC_XWORD(Line_num),
+ mf_fatal(mf, MSG_INTL(MSG_MAP_MOREONCE),
MSG_INTL(MSG_MAP_SECNAME));
- return (S_ERROR);
+ return (FALSE);
}
b_name = TRUE;
- if ((enp->ec_name =
- libld_malloc(strlen(Start_tok) + 1)) == NULL)
- return (S_ERROR);
- (void) strcpy((char *)enp->ec_name, Start_tok);
- /*
- * Set the index for text reordering.
- */
- enp->ec_ordndx = ++index;
+ enp->ec_is_name = tkv.tkv_str;
+ enp->ec_flags &= ~FLG_EC_CATCHALL;
}
}
if (tok == TK_COLON) {
/*
* File names.
*/
- while ((tok = gettoken(ofl, mapfile, 0)) != TK_SEMICOLON) {
- char *file;
+ while ((tok = ld_map_gettoken(mf, 0, &tkv)) != TK_SEMICOLON) {
+ Word ecf_type;
if (tok != TK_STRING) {
if (tok != TK_ERROR)
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_MALFORM), mapfile,
- EC_XWORD(Line_num));
- return (S_ERROR);
+ mf_fatal0(mf,
+ MSG_INTL(MSG_MAP_MALFORM));
+ return (FALSE);
}
- if ((file =
- libld_malloc(strlen(Start_tok) + 1)) == NULL)
- return (S_ERROR);
- (void) strcpy(file, Start_tok);
-
- if (aplist_append(&(enp->ec_files), file,
- AL_CNT_EC_FILES) == NULL)
- return (S_ERROR);
+
+ /*
+ * A leading '*' means that this should be a basename
+ * comparison rather than a full path. It's not a glob
+ * wildcard, although it looks like one.
+ */
+ if (tkv.tkv_str[0] == '*') {
+ ecf_type = TYP_ECF_BASENAME;
+ tkv.tkv_str++;
+ } else {
+ ecf_type = TYP_ECF_PATH;
+ }
+ if (!ld_map_seg_ent_files(mf, enp, ecf_type,
+ tkv.tkv_str))
+ return (FALSE);
+ enp->ec_flags &= ~FLG_EC_CATCHALL;
}
}
- return (1);
-}
-
-/*
- * Obtain a pseudo input file descriptor to assign to a mapfile. This is
- * required any time a symbol is generated. Traverse the input file
- * descriptors looking for a match. As all mapfile processing occurs before
- * any real input file processing this list is going to be small and we don't
- * need to do any filename clash checking.
- */
-static Ifl_desc *
-map_ifl(const char *mapfile, Ofl_desc *ofl)
-{
- Ifl_desc *ifl;
- Aliste idx;
-
- for (APLIST_TRAVERSE(ofl->ofl_objs, idx, ifl))
- if (strcmp(ifl->ifl_name, mapfile) == 0)
- return (ifl);
-
- if ((ifl = libld_calloc(sizeof (Ifl_desc), 1)) == NULL)
- return ((Ifl_desc *)S_ERROR);
- ifl->ifl_name = mapfile;
- ifl->ifl_flags = (FLG_IF_MAPFILE | FLG_IF_NEEDED | FLG_IF_FILEREF);
- if ((ifl->ifl_ehdr = libld_calloc(sizeof (Ehdr), 1)) == NULL)
- return ((Ifl_desc *)S_ERROR);
- ifl->ifl_ehdr->e_type = ET_REL;
-
- if (aplist_append(&ofl->ofl_objs, ifl, AL_CNT_OFL_OBJS) == NULL)
- return ((Ifl_desc *)S_ERROR);
- else
- return (ifl);
+ return (TRUE);
}
/*
* Process a mapfile size symbol definition.
* segment_name @ symbol_name;
*/
-static uintptr_t
-map_atsign(const char *mapfile, Sg_desc *sgp, Ofl_desc *ofl)
+static Boolean
+map_atsign(Mapfile *mf, Sg_desc *sgp)
{
- Sym *sym; /* New symbol pointer */
- Sym_desc *sdp; /* New symbol node pointer */
- Ifl_desc *ifl; /* Dummy input file structure */
Token tok; /* Current token. */
- avl_index_t where;
+ ld_map_tkval_t tkv; /* Value of token */
- if ((tok = gettoken(ofl, mapfile, 0)) != TK_STRING) {
+ if ((tok = ld_map_gettoken(mf, 0, &tkv)) != TK_STRING) {
if (tok != TK_ERROR)
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_EXPSYM_1), mapfile,
- EC_XWORD(Line_num));
- return (S_ERROR);
- }
-
- if (sgp->sg_sizesym != NULL) {
- eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_MAP_SEGSIZE),
- mapfile, EC_XWORD(Line_num), sgp->sg_name);
- return (S_ERROR);
+ mf_fatal0(mf, MSG_INTL(MSG_MAP_EXPSYM_1));
+ return (FALSE);
}
- /*
- * Make sure we have a pseudo file descriptor to associate to the
- * symbol.
- */
- if ((ifl = map_ifl(mapfile, ofl)) == (Ifl_desc *)S_ERROR)
- return (S_ERROR);
-
- /*
- * Make sure the symbol doesn't already exist. It is possible that the
- * symbol has been scoped or versioned, in which case it does exist
- * but we can freely update it here.
- */
- if ((sdp = ld_sym_find(Start_tok, SYM_NOHASH, &where, ofl)) == NULL) {
- char *name;
- Word hval;
-
- if ((name = libld_malloc(strlen(Start_tok) + 1)) == NULL)
- return (S_ERROR);
- (void) strcpy(name, Start_tok);
-
- if ((sym = libld_calloc(sizeof (Sym), 1)) == NULL)
- return (S_ERROR);
- sym->st_shndx = SHN_ABS;
- sym->st_size = 0;
- sym->st_info = ELF_ST_INFO(STB_GLOBAL, STT_OBJECT);
-
- DBG_CALL(Dbg_map_size_new(ofl->ofl_lml, name));
- /* LINTED */
- hval = (Word)elf_hash(name);
- if ((sdp = ld_sym_enter(name, sym, hval, ifl, ofl, 0, SHN_ABS,
- (FLG_SY_SPECSEC | FLG_SY_GLOBREF), &where)) ==
- (Sym_desc *)S_ERROR)
- return (S_ERROR);
- sdp->sd_flags &= ~FLG_SY_CLEAN;
- DBG_CALL(Dbg_map_symbol(ofl, sdp));
- } else {
- sym = sdp->sd_sym;
-
- if (sym->st_shndx == SHN_UNDEF) {
- sdp->sd_shndx = sym->st_shndx = SHN_ABS;
- sdp->sd_flags |= FLG_SY_SPECSEC;
- sym->st_size = 0;
- sym->st_info = ELF_ST_INFO(STB_GLOBAL, STT_OBJECT);
-
- sdp->sd_flags &= ~FLG_SY_MAPREF;
-
- DBG_CALL(Dbg_map_size_old(ofl, sdp));
- } else {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_SYMDEF1), mapfile,
- EC_XWORD(Line_num), demangle(sdp->sd_name),
- sdp->sd_file->ifl_name,
- MSG_INTL(MSG_MAP_DIFF_SYMMUL));
- return (S_ERROR);
- }
- }
+ /* Add the symbol to the segment */
+ if (!ld_map_seg_size_symbol(mf, sgp, TK_PLUSEQ, tkv.tkv_str))
+ return (FALSE);
- /*
- * Assign the symbol to the segment.
- */
- sgp->sg_sizesym = sdp;
- if (gettoken(ofl, mapfile, 0) != TK_SEMICOLON) {
+ if (ld_map_gettoken(mf, 0, &tkv) != TK_SEMICOLON) {
if (tok != TK_ERROR)
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_EXPSCOL), mapfile,
- EC_XWORD(Line_num));
- return (S_ERROR);
+ mf_fatal0(mf, MSG_INTL(MSG_MAP_EXPSCOL));
+ return (FALSE);
}
- return (1);
+ return (TRUE);
}
-static uintptr_t
-map_pipe(Ofl_desc *ofl, const char *mapfile, Sg_desc *sgp)
+static Boolean
+map_pipe(Mapfile *mf, Sg_desc *sgp)
{
- char *sec_name; /* section name */
Token tok; /* current token. */
- Sec_order *sc_order;
- static Word index = 0; /* used to maintain a increasing */
- /* index for section ordering. */
+ ld_map_tkval_t tkv; /* Value of token */
- if ((tok = gettoken(ofl, mapfile, 0)) != TK_STRING) {
+ if ((tok = ld_map_gettoken(mf, 0, &tkv)) != TK_STRING) {
if (tok != TK_ERROR)
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_EXPSEC), mapfile,
- EC_XWORD(Line_num));
- return (S_ERROR);
+ mf_fatal0(mf, MSG_INTL(MSG_MAP_EXPSEC));
+ return (FALSE);
}
- if ((sec_name = libld_malloc(strlen(Start_tok) + 1)) == NULL)
- return (S_ERROR);
- (void) strcpy(sec_name, Start_tok);
-
- if ((sc_order = libld_malloc(sizeof (Sec_order))) == NULL)
- return (S_ERROR);
-
- sc_order->sco_secname = sec_name;
- sc_order->sco_index = ++index;
-
- if (aplist_append(&sgp->sg_secorder, sc_order,
- AL_CNT_SG_SECORDER) == NULL)
- return (S_ERROR);
-
- ofl->ofl_flags |= FLG_OF_SECORDER;
- DBG_CALL(Dbg_map_pipe(ofl->ofl_lml, sgp, sec_name, index));
+ if (!ld_map_seg_os_order_add(mf, sgp, tkv.tkv_str))
+ return (FALSE);
- if ((tok = gettoken(ofl, mapfile, 0)) != TK_SEMICOLON) {
+ if ((tok = ld_map_gettoken(mf, 0, &tkv)) != TK_SEMICOLON) {
if (tok != TK_ERROR)
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_EXPSCOL), mapfile,
- EC_XWORD(Line_num));
- return (S_ERROR);
+ mf_fatal0(mf, MSG_INTL(MSG_MAP_EXPSCOL));
+ return (FALSE);
}
- return (1);
+ return (TRUE);
}
/*
@@ -1149,40 +855,29 @@ map_pipe(Ofl_desc *ofl, const char *mapfile, Sg_desc *sgp)
* shared object definition : [ shared object type [ = SONAME ]]
* [ versions ];
*/
-static uintptr_t
-map_dash(const char *mapfile, char *name, Ofl_desc *ofl)
+static Boolean
+map_dash(Mapfile *mf, char *name)
{
- char *version;
Token tok;
Sdf_desc *sdf;
- Sdv_desc sdv;
+ ld_map_tkval_t tkv; /* Value of token */
enum {
MD_NONE = 0,
MD_ADDVERS,
} dolkey = MD_NONE;
-
- /*
- * If a shared object definition for this file already exists use it,
- * otherwise allocate a new descriptor.
- */
- if ((sdf = sdf_find(name, ofl->ofl_socntl)) == NULL) {
- if ((sdf = sdf_add(name, &ofl->ofl_socntl)) ==
- (Sdf_desc *)S_ERROR)
- return (S_ERROR);
- sdf->sdf_rfile = mapfile;
- }
+ /* Get descriptor for dependency */
+ if ((sdf = ld_map_dv(mf, name)) == NULL)
+ return (FALSE);
/*
* Get the shared object descriptor string.
*/
- while ((tok = gettoken(ofl, mapfile, 0)) != TK_SEMICOLON) {
+ while ((tok = ld_map_gettoken(mf, 0, &tkv)) != TK_SEMICOLON) {
if ((tok != TK_STRING) && (tok != TK_EQUAL)) {
if (tok != TK_ERROR)
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_EXPSO), mapfile,
- EC_XWORD(Line_num));
- return (S_ERROR);
+ mf_fatal0(mf, MSG_INTL(MSG_MAP_EXPSO));
+ return (FALSE);
}
/*
@@ -1190,36 +885,22 @@ map_dash(const char *mapfile, char *name, Ofl_desc *ofl)
* definition.
*/
if (tok == TK_EQUAL) {
- if ((tok = gettoken(ofl, mapfile, 0)) != TK_STRING) {
+ if ((tok = ld_map_gettoken(mf, 0, &tkv)) !=
+ TK_STRING) {
if (tok != TK_ERROR)
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_EXPSO), mapfile,
- EC_XWORD(Line_num));
- return (S_ERROR);
+ mf_fatal0(mf,
+ MSG_INTL(MSG_MAP_EXPSO));
+ return (FALSE);
}
switch (dolkey) {
case MD_ADDVERS:
- sdf->sdf_flags |= FLG_SDF_ADDVER;
-
- if ((version = libld_malloc(
- strlen(Start_tok) + 1)) == NULL)
- return (S_ERROR);
- (void) strcpy(version, Start_tok);
-
- sdv.sdv_name = version;
- sdv.sdv_ref = mapfile;
- sdv.sdv_flags = 0;
-
- if (alist_append(&sdf->sdf_verneed, &sdv,
- sizeof (Sdv_desc),
- AL_CNT_SDF_VERSIONS) == NULL)
- return (S_ERROR);
+ if (!ld_map_dv_entry(mf, sdf, TRUE,
+ tkv.tkv_str))
+ return (FALSE);
break;
case MD_NONE:
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_UNEXTOK), mapfile,
- EC_XWORD(Line_num), '=');
- return (S_ERROR);
+ mf_fatal(mf, MSG_INTL(MSG_MAP_UNEXTOK), '=');
+ return (FALSE);
}
dolkey = MD_NONE;
continue;
@@ -1229,23 +910,20 @@ map_dash(const char *mapfile, char *name, Ofl_desc *ofl)
* A shared object type has been specified. This may also be
* accompanied by an SONAME redefinition (see above).
*/
- if (*Start_tok == '$') {
+ if (*tkv.tkv_str == '$') {
if (dolkey != MD_NONE) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_UNEXTOK), mapfile,
- EC_XWORD(Line_num), '$');
- return (S_ERROR);
+ mf_fatal(mf, MSG_INTL(MSG_MAP_UNEXTOK), '$');
+ return (FALSE);
}
- Start_tok++;
- lowercase(Start_tok);
- if (strcmp(Start_tok,
- MSG_ORIG(MSG_MAP_ADDVERS)) == 0)
+ tkv.tkv_str++;
+ ld_map_lowercase(tkv.tkv_str);
+ if (strcmp(tkv.tkv_str, MSG_ORIG(MSG_MAP_ADDVERS)) ==
+ 0) {
dolkey = MD_ADDVERS;
- else {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_UNKSOTYP), mapfile,
- EC_XWORD(Line_num), Start_tok);
- return (S_ERROR);
+ } else {
+ mf_fatal(mf, MSG_INTL(MSG_MAP_UNKSOTYP),
+ tkv.tkv_str);
+ return (FALSE);
}
continue;
}
@@ -1253,23 +931,11 @@ map_dash(const char *mapfile, char *name, Ofl_desc *ofl)
/*
* shared object version requirement.
*/
- if ((version = libld_malloc(strlen(Start_tok) + 1)) == NULL)
- return (S_ERROR);
- (void) strcpy(version, Start_tok);
-
- sdf->sdf_flags |= FLG_SDF_SELECT;
-
- sdv.sdv_name = version;
- sdv.sdv_ref = mapfile;
- sdv.sdv_flags = 0;
-
- if (alist_append(&sdf->sdf_vers, &sdv, sizeof (Sdv_desc),
- AL_CNT_SDF_VERSIONS) == NULL)
- return (S_ERROR);
+ if (!ld_map_dv_entry(mf, sdf, FALSE, tkv.tkv_str))
+ return (FALSE);
}
- DBG_CALL(Dbg_map_dash(ofl->ofl_lml, name));
- return (1);
+ return (TRUE);
}
@@ -1285,126 +951,42 @@ map_dash(const char *mapfile, char *name, Ofl_desc *ofl)
* } [ dependency ];
*
*/
-#define FLG_SCOPE_HIDD 0 /* symbol defined hidden/local */
-#define FLG_SCOPE_DFLT 1 /* symbol defined default/global */
-#define FLG_SCOPE_PROT 2 /* symbol defined protected/symbolic */
-#define FLG_SCOPE_EXPT 3 /* symbol defined exported */
-#define FLG_SCOPE_SNGL 4 /* symbol defined singleton */
-#define FLG_SCOPE_ELIM 5 /* symbol defined eliminate */
-
-static uintptr_t
-map_version(const char *mapfile, char *name, Ofl_desc *ofl)
+static Boolean
+map_version(Mapfile *mf, char *name)
{
Token tok;
- Sym *sym;
- int scope = FLG_SCOPE_DFLT, errcnt = 0;
- Ver_desc *vdp;
- Word hash;
- Ifl_desc *ifl;
- avl_index_t where;
-
- /*
- * If we're generating segments within the image then any symbol
- * reductions will be processed (ie. applied to relocations and symbol
- * table entries). Otherwise (when creating a relocatable object) any
- * versioning information is simply recorded for use in a later
- * (segment generating) link-edit.
- */
- if (ofl->ofl_flags & FLG_OF_RELOBJ)
- ofl->ofl_flags |= FLG_OF_VERDEF;
+ ld_map_tkval_t tkv; /* Value of token */
+ ld_map_ver_t mv;
+ ld_map_sym_t ms;
+ Ofl_desc *ofl = mf->mf_ofl;
- /*
- * If this is a new mapfile reference generate an input file descriptor
- * to represent it. Otherwise this must simply be a new version within
- * the mapfile we've previously been processing, in this case continue
- * to use the original input file descriptor.
- */
- if ((ifl = map_ifl(mapfile, ofl)) == (Ifl_desc *)S_ERROR)
- return (S_ERROR);
-
- /*
- * If no version descriptors have yet been set up, initialize a base
- * version to represent the output file itself. This `base' version
- * catches any internally generated symbols (_end, _etext, etc.) and
- * serves to initialize the output version descriptor count.
- */
- if (ofl->ofl_vercnt == 0) {
- if (ld_vers_base(ofl) == (Ver_desc *)S_ERROR)
- return (S_ERROR);
- }
-
- /*
- * If this definition has an associated version name then generate a
- * new version descriptor and an associated version symbol index table.
- */
- if (name) {
- ofl->ofl_flags |= FLG_OF_VERDEF;
-
- /*
- * Traverse the present version descriptor list to see if there
- * is already one of the same name, otherwise create a new one.
- */
- /* LINTED */
- hash = (Word)elf_hash(name);
- if (((vdp = ld_vers_find(name, hash,
- ofl->ofl_verdesc)) == NULL) &&
- ((vdp = ld_vers_desc(name, hash,
- &ofl->ofl_verdesc)) == (Ver_desc *)S_ERROR))
- return (S_ERROR);
-
- /*
- * Initialize any new version with an index, the file from which
- * it was first referenced, and a WEAK flag (indicates that
- * there are no symbols assigned to it yet).
- */
- if (vdp->vd_ndx == 0) {
- /* LINTED */
- vdp->vd_ndx = (Half)++ofl->ofl_vercnt;
- vdp->vd_file = ifl;
- vdp->vd_flags = VER_FLG_WEAK;
- }
- } else {
- /*
- * If a version definition hasn't been specified assign any
- * symbols to the base version.
- */
- vdp = (Ver_desc *)ofl->ofl_verdesc->apl_data[0];
- }
+ /* Establish the version descriptor and related data */
+ if (!ld_map_sym_ver_init(mf, name, &mv))
+ return (FALSE);
/*
* Scan the mapfile entry picking out scoping and symbol definitions.
*/
- while ((tok = gettoken(ofl, mapfile, 0)) != TK_RIGHTBKT) {
- Sym_desc *sdp;
- Word shndx = SHN_UNDEF;
- uchar_t type = STT_NOTYPE;
- Addr value = 0, size = 0;
- char *_name, *filtee = NULL;
- sd_flag_t sdflags = 0;
- uint_t filter = 0, novalue = 1, dftflag;
- const char *conflict;
-
- if ((tok != TK_STRING) && (tok != TK_COLON)) {
- if (tok == TK_ERROR)
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_EXPSYM_2), mapfile,
- EC_XWORD(Line_num));
- if ((tok == TK_ERROR) || (tok == TK_EOF))
- return (S_ERROR);
- errcnt++;
+ while ((tok = ld_map_gettoken(mf, 0, &tkv)) != TK_RIGHTBKT) {
+ uint_t filter = 0;
+
+ if (tok != TK_STRING) {
+ if (tok == TK_ERROR) {
+ mf_fatal0(mf, MSG_INTL(MSG_MAP_EXPSYM_2));
+ return (FALSE);
+ }
+ mv.mv_errcnt++;
continue;
}
- if ((_name = libld_malloc(strlen(Start_tok) + 1)) == NULL)
- return (S_ERROR);
- (void) strcpy(_name, Start_tok);
+ /* The default value for all the symbol attributes is 0 */
+ (void) memset(&ms, 0, sizeof (ms));
+ ms.ms_name = tkv.tkv_str;
- if (tok != TK_COLON) {
- tok = gettoken(ofl, mapfile, 0);
- if ((tok == TK_ERROR) || (tok == TK_EOF)) {
- errcnt++;
- continue;
- }
+ tok = ld_map_gettoken(mf, 0, &tkv);
+ if (tok == TK_ERROR) {
+ mv.mv_errcnt++;
+ continue;
}
/*
@@ -1417,56 +999,11 @@ map_version(const char *mapfile, char *name, Ofl_desc *ofl)
* will a user get a weak version (which is how we document the
* creation of weak versions).
*/
- vdp->vd_flags &= ~VER_FLG_WEAK;
+ mv.mv_vdp->vd_flags &= ~VER_FLG_WEAK;
switch (tok) {
case TK_COLON:
- /*
- * Establish a new scope. All symbols added by this
- * mapfile are actually global entries, and are assigned
- * the scope that is presently in effect.
- *
- * If a protected/symbolic scope is detected, remember
- * this. If a protected/symbolic scope is the only
- * scope defined in this (or any other mapfiles), then
- * the mode -Bsymbolic is established.
- */
- if ((strcmp(MSG_ORIG(MSG_MAP_DEFAULT), _name) == 0) ||
- (strcmp(MSG_ORIG(MSG_MAP_GLOBAL), _name) == 0)) {
- scope = FLG_SCOPE_DFLT;
- ofl->ofl_flags |= FLG_OF_MAPGLOB;
-
- } else if ((strcmp(MSG_ORIG(MSG_MAP_HIDDEN),
- _name) == 0) ||
- (strcmp(MSG_ORIG(MSG_STR_LOCAL), _name) == 0)) {
- scope = FLG_SCOPE_HIDD;
-
- } else if ((strcmp(MSG_ORIG(MSG_MAP_PROTECTED),
- _name) == 0) ||
- (strcmp(MSG_ORIG(MSG_STR_SYMBOLIC), _name) == 0)) {
- scope = FLG_SCOPE_PROT;
- ofl->ofl_flags |= FLG_OF_MAPSYMB;
-
- } else if (strcmp(MSG_ORIG(MSG_STR_EXPORTED),
- _name) == 0) {
- scope = FLG_SCOPE_EXPT;
-
- } else if (strcmp(MSG_ORIG(MSG_STR_SINGLETON),
- _name) == 0) {
- scope = FLG_SCOPE_SNGL;
- ofl->ofl_flags |= FLG_OF_MAPGLOB;
-
- } else if (strcmp(MSG_ORIG(MSG_STR_ELIMINATE),
- _name) == 0) {
- scope = FLG_SCOPE_ELIM;
-
- } else {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_UNKSYMSCO), mapfile,
- EC_XWORD(Line_num), _name);
- errcnt++;
- break;
- }
+ ld_map_sym_scope(mf, ms.ms_name, &mv);
continue;
case TK_EQUAL:
@@ -1476,29 +1013,24 @@ map_version(const char *mapfile, char *name, Ofl_desc *ofl)
* alignment specified and then fall through to process
* the entire symbols information.
*/
- while ((tok = gettoken(ofl, mapfile, 0)) !=
+ while ((tok = ld_map_gettoken(mf, 0, &tkv)) !=
TK_SEMICOLON) {
- if ((tok == TK_ERROR) || (tok == TK_EOF))
- return (S_ERROR);
+ if (tok == TK_ERROR)
+ return (FALSE);
+ if (tok != TK_STRING) {
+ mf_fatal0(mf,
+ MSG_INTL(MSG_MAP_MALFORM));
+ return (FALSE);
+ }
+
/*
- * If we had previously seen a filter or
- * auxiliary filter requirement, the next string
- * is the filtee itself.
+ * If we had previously seen AUX or FILTER,
+ * the next string is the filtee itself.
+ * Add it, and clear the filter flag.
*/
if (filter) {
- if (filtee) {
- /* BEGIN CSTYLED */
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_MULTFILTEE),
- mapfile, EC_XWORD(Line_num));
- errcnt++;
- continue;
- /* END CSTYLED */
- }
- if ((filtee = libld_malloc(
- strlen(Start_tok) + 1)) == NULL)
- return (S_ERROR);
- (void) strcpy(filtee, Start_tok);
+ ld_map_sym_filtee(mf, &mv, &ms,
+ filter, tkv.tkv_str);
filter = 0;
continue;
}
@@ -1506,190 +1038,139 @@ map_version(const char *mapfile, char *name, Ofl_desc *ofl)
/*
* Determine any Value or Size attributes.
*/
- lowercase(Start_tok);
-
- if (Start_tok[0] == 'v' ||
- Start_tok[0] == 's') {
- char *end_tok;
- Lword number;
-
- if ((number = (Lword)STRTOADDR(
- &Start_tok[1], &end_tok, 0)) ==
- XWORD_MAX) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_SEGADDR),
- mapfile, EC_XWORD(Line_num),
- Start_tok,
- MSG_INTL(MSG_MAP_EXCLIMIT));
- errcnt++;
- continue;
- }
+ ld_map_lowercase(tkv.tkv_str);
- if (end_tok !=
- strchr(Start_tok, '\0')) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_SEGADDR),
- mapfile, EC_XWORD(Line_num),
- Start_tok,
- MSG_INTL(MSG_MAP_NOBADFRM));
- errcnt++;
- continue;
+ if (tkv.tkv_str[0] == 'v' ||
+ tkv.tkv_str[0] == 's') {
+ Xword number;
+
+ if (!valuetoxword(mf, &tkv, &number)) {
+ mv.mv_errcnt++;
+ return (FALSE);
}
- switch (*Start_tok) {
+ switch (*tkv.tkv_str) {
case 'v':
/* BEGIN CSTYLED */
- if (value) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
+ if (ms.ms_value) {
+ mf_fatal(mf,
MSG_INTL(MSG_MAP_MOREONCE),
- mapfile, EC_XWORD(Line_num),
MSG_INTL(MSG_MAP_SYMVAL));
- errcnt++;
+ mv.mv_errcnt++;
continue;
}
/* LINTED */
- value = (Addr)number;
- novalue = 0;
+ ms.ms_value = (Addr)number;
+ ms.ms_value_set = TRUE;
break;
/* END CSTYLED */
case 's':
/* BEGIN CSTYLED */
- if (size) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
+ if (ms.ms_size) {
+ mf_fatal(mf,
MSG_INTL(MSG_MAP_MOREONCE),
- mapfile, EC_XWORD(Line_num),
MSG_INTL(MSG_MAP_SYMSIZE));
- errcnt++;
+ mv.mv_errcnt++;
continue;
}
/* LINTED */
- size = (Addr)number;
+ ms.ms_size = (Addr)number;
break;
/* END CSTYLED */
}
- } else if (strcmp(Start_tok,
+ } else if (strcmp(tkv.tkv_str,
MSG_ORIG(MSG_MAP_FUNCTION)) == 0) {
- shndx = SHN_ABS;
- sdflags |= FLG_SY_SPECSEC;
- type = STT_FUNC;
- } else if (strcmp(Start_tok,
+ ms.ms_shndx = SHN_ABS;
+ ms.ms_sdflags |= FLG_SY_SPECSEC;
+ ms.ms_type = STT_FUNC;
+ } else if (strcmp(tkv.tkv_str,
MSG_ORIG(MSG_MAP_DATA)) == 0) {
- shndx = SHN_ABS;
- sdflags |= FLG_SY_SPECSEC;
- type = STT_OBJECT;
- } else if (strcmp(Start_tok,
+ ms.ms_shndx = SHN_ABS;
+ ms.ms_sdflags |= FLG_SY_SPECSEC;
+ ms.ms_type = STT_OBJECT;
+ } else if (strcmp(tkv.tkv_str,
MSG_ORIG(MSG_MAP_COMMON)) == 0) {
- shndx = SHN_COMMON;
- sdflags |= FLG_SY_SPECSEC;
- type = STT_OBJECT;
- } else if (strcmp(Start_tok,
+ ms.ms_shndx = SHN_COMMON;
+ ms.ms_sdflags |= FLG_SY_SPECSEC;
+ ms.ms_type = STT_OBJECT;
+ } else if (strcmp(tkv.tkv_str,
MSG_ORIG(MSG_MAP_PARENT)) == 0) {
- sdflags |= FLG_SY_PARENT;
+ ms.ms_sdflags |= FLG_SY_PARENT;
ofl->ofl_flags |= FLG_OF_SYMINFO;
- } else if (strcmp(Start_tok,
+ } else if (strcmp(tkv.tkv_str,
MSG_ORIG(MSG_MAP_EXTERN)) == 0) {
- sdflags |= FLG_SY_EXTERN;
+ ms.ms_sdflags |= FLG_SY_EXTERN;
ofl->ofl_flags |= FLG_OF_SYMINFO;
- } else if (strcmp(Start_tok,
+ } else if (strcmp(tkv.tkv_str,
MSG_ORIG(MSG_MAP_DIRECT)) == 0) {
- sdflags |= FLG_SY_DIR;
+ ms.ms_sdflags |= FLG_SY_DIR;
ofl->ofl_flags |= FLG_OF_SYMINFO;
- } else if (strcmp(Start_tok,
+ } else if (strcmp(tkv.tkv_str,
MSG_ORIG(MSG_MAP_NODIRECT)) == 0) {
- sdflags |= FLG_SY_NDIR;
+ ms.ms_sdflags |= FLG_SY_NDIR;
ofl->ofl_flags |= FLG_OF_SYMINFO;
ofl->ofl_flags1 |=
(FLG_OF1_NDIRECT | FLG_OF1_NGLBDIR);
- } else if (strcmp(Start_tok,
+ } else if (strcmp(tkv.tkv_str,
MSG_ORIG(MSG_MAP_FILTER)) == 0) {
- /* BEGIN CSTYLED */
- if (!(ofl->ofl_flags &
- FLG_OF_SHAROBJ)) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_FLTR_ONLYAVL),
- mapfile, EC_XWORD(Line_num));
- errcnt++;
- break;
- }
- /* END CSTYLED */
- dftflag = filter = FLG_SY_STDFLTR;
- sdflags |= FLG_SY_STDFLTR;
- ofl->ofl_flags |= FLG_OF_SYMINFO;
+ /* Next token is the filtee */
+ filter = FLG_SY_STDFLTR;
continue;
- } else if (strcmp(Start_tok,
+ } else if (strcmp(tkv.tkv_str,
MSG_ORIG(MSG_MAP_AUXILIARY)) == 0) {
- /* BEGIN CSTYLED */
- if (!(ofl->ofl_flags &
- FLG_OF_SHAROBJ)) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_FLTR_ONLYAVL),
- mapfile, EC_XWORD(Line_num));
- errcnt++;
- break;
- }
- /* END CSTYLED */
- dftflag = filter = FLG_SY_AUXFLTR;
- sdflags |= FLG_SY_AUXFLTR;
- ofl->ofl_flags |= FLG_OF_SYMINFO;
+ /* Next token is the filtee */
+ filter = FLG_SY_AUXFLTR;
continue;
- } else if (strcmp(Start_tok,
+ } else if (strcmp(tkv.tkv_str,
MSG_ORIG(MSG_MAP_INTERPOSE)) == 0) {
/* BEGIN CSTYLED */
if (!(ofl->ofl_flags & FLG_OF_EXEC)) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_NOINTPOSE),
- mapfile, EC_XWORD(Line_num));
- errcnt++;
+ mf_fatal0(mf,
+ MSG_INTL(MSG_MAP_NOINTPOSE));
+ mv.mv_errcnt++;
break;
}
/* END CSTYLED */
- sdflags |= FLG_SY_INTPOSE;
+ ms.ms_sdflags |= FLG_SY_INTPOSE;
ofl->ofl_flags |= FLG_OF_SYMINFO;
ofl->ofl_dtflags_1 |= DF_1_SYMINTPOSE;
continue;
- } else if (strcmp(Start_tok,
+ } else if (strcmp(tkv.tkv_str,
MSG_ORIG(MSG_MAP_DYNSORT)) == 0) {
- sdflags |= FLG_SY_DYNSORT;
- sdflags &= ~FLG_SY_NODYNSORT;
+ ms.ms_sdflags |= FLG_SY_DYNSORT;
+ ms.ms_sdflags &= ~FLG_SY_NODYNSORT;
continue;
- } else if (strcmp(Start_tok,
+ } else if (strcmp(tkv.tkv_str,
MSG_ORIG(MSG_MAP_NODYNSORT)) == 0) {
- sdflags &= ~FLG_SY_DYNSORT;
- sdflags |= FLG_SY_NODYNSORT;
+ ms.ms_sdflags &= ~FLG_SY_DYNSORT;
+ ms.ms_sdflags |= FLG_SY_NODYNSORT;
continue;
} else {
- eprintf(ofl->ofl_lml, ERR_FATAL,
+ mf_fatal(mf,
MSG_INTL(MSG_MAP_UNKSYMDEF),
- mapfile, EC_XWORD(Line_num),
- Start_tok);
- errcnt++;
+ tkv.tkv_str);
+ mv.mv_errcnt++;
continue;
}
}
/* FALLTHROUGH */
case TK_SEMICOLON:
+ /* Auto-reduction directive ('*')? */
+ if (*ms.ms_name == '*') {
+ ld_map_sym_autoreduce(mf, &mv);
+ continue;
+ }
+
/*
- * The special auto-reduction directive `*' can be
- * specified in hidden/local, and eliminate scope. This
- * directive indicates that all symbols processed that
- * are not explicitly defined to be global are to be
- * reduced to hidden/local scope in, or eliminated from,
- * the output image.
- *
- * An auto-reduction directive also implies that a
- * version definition be created, as the user has
- * effectively defined an interface.
+ * Catch the error where the AUX or FILTER keyword
+ * was used, but the filtee wasn't supplied.
*/
- if (*_name == '*') {
- if (scope == FLG_SCOPE_HIDD)
- ofl->ofl_flags |=
- (FLG_OF_VERDEF | FLG_OF_AUTOLCL);
- else if (scope == FLG_SCOPE_ELIM) {
- ofl->ofl_flags |=
- (FLG_OF_VERDEF | FLG_OF_AUTOELM);
- }
+ if (filter && (ms.ms_filtee == NULL)) {
+ mf_fatal(mf, MSG_INTL(MSG_MAP_NOFILTER),
+ ms.ms_name);
+ mv.mv_errcnt++;
continue;
}
@@ -1700,767 +1181,100 @@ map_version(const char *mapfile, char *name, Ofl_desc *ofl)
* resolution process. Symbols defined as locals will
* be reduced in scope after all input file processing.
*/
- /* LINTED */
- hash = (Word)elf_hash(_name);
- DBG_CALL(Dbg_map_version(ofl->ofl_lml, name, _name,
- scope));
- if ((sdp = ld_sym_find(_name, hash, &where,
- ofl)) == NULL) {
- if ((sym =
- libld_calloc(sizeof (Sym), 1)) == NULL)
- return (S_ERROR);
-
- /*
- * Make sure any parent or external declarations
- * fall back to references.
- */
- if (sdflags & (FLG_SY_PARENT | FLG_SY_EXTERN)) {
- /*
- * Turn it into a reference by setting
- * the section index to UNDEF.
- */
- sym->st_shndx = shndx = SHN_UNDEF;
-
- /*
- * It is wrong to to specify size
- * or value for an external symbol.
- */
- if ((novalue == 0) || (size != 0)) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_NOEXVLSZ),
- mapfile,
- EC_XWORD(Line_num));
- errcnt++;
- continue;
- }
- } else {
- sym->st_shndx = (Half)shndx;
- }
-
- sym->st_value = value;
- sym->st_size = size;
- sym->st_info = ELF_ST_INFO(STB_GLOBAL, type);
-
- if ((sdp = ld_sym_enter(_name, sym, hash,
- ifl, ofl, 0, shndx, sdflags,
- &where)) == (Sym_desc *)S_ERROR)
- return (S_ERROR);
-
- sdp->sd_flags &= ~FLG_SY_CLEAN;
-
- /*
- * Identify any references. FLG_SY_MAPREF is
- * turned off once a relocatable object with
- * the same symbol is found, thus the existence
- * of FLG_SY_MAPREF at symbol validation is
- * used to flag undefined/misspelled entries.
- */
- if (sym->st_shndx == SHN_UNDEF)
- sdp->sd_flags |=
- (FLG_SY_MAPREF | FLG_SY_GLOBREF);
-
- } else {
- conflict = NULL;
- sym = sdp->sd_sym;
-
- /*
- * If this symbol already exists, make sure this
- * definition doesn't conflict with the former.
- * Provided it doesn't, multiple definitions
- * from different mapfiles can augment each
- * other.
- */
- /* BEGIN CSTYLED */
- if (sym->st_value) {
- if (value && (sym->st_value != value))
- conflict =
- MSG_INTL(MSG_MAP_DIFF_SYMVAL);
- } else {
- sym->st_value = value;
- }
- if (sym->st_size) {
- if (size && (sym->st_size != size))
- conflict = MSG_INTL(MSG_MAP_DIFF_SYMSZ);
- } else {
- sym->st_size = size;
- }
- if (ELF_ST_TYPE(sym->st_info) != STT_NOTYPE) {
- if ((type != STT_NOTYPE) &&
- (ELF_ST_TYPE(sym->st_info) != type))
- conflict =
- MSG_INTL(MSG_MAP_DIFF_SYMTYP);
- } else {
- sym->st_info =
- ELF_ST_INFO(STB_GLOBAL, type);
- }
- if (sym->st_shndx != SHN_UNDEF) {
- if ((shndx != SHN_UNDEF) &&
- (sym->st_shndx != shndx))
- conflict =
- MSG_INTL(MSG_MAP_DIFF_SYMNDX);
- } else {
- sym->st_shndx = sdp->sd_shndx = shndx;
- }
- /* END CSTYLED */
-
- if ((sdp->sd_flags & MSK_SY_GLOBAL) &&
- (sdp->sd_aux->sa_overndx !=
- VER_NDX_GLOBAL) &&
- (vdp->vd_ndx != VER_NDX_GLOBAL) &&
- (sdp->sd_aux->sa_overndx != vdp->vd_ndx)) {
- conflict =
- MSG_INTL(MSG_MAP_DIFF_SYMVER);
- }
-
- if (conflict) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_SYMDEF1), mapfile,
- EC_XWORD(Line_num), demangle(_name),
- sdp->sd_file->ifl_name, conflict);
- errcnt++;
- continue;
- }
-
- /*
- * If this mapfile entry supplies a definition,
- * indicate that the symbol is now used.
- */
- if (shndx != SHN_UNDEF)
- sdp->sd_flags |= FLG_SY_MAPUSED;
- }
-
- /*
- * A symbol declaration that defines a size but no
- * value is processed as a request to create an
- * associated backing section. The intent behind this
- * functionality is to provide OBJT definitions within
- * filters that are not ABS. ABS symbols don't allow
- * copy-relocations to be established to filter OBJT
- * definitions.
- */
- if ((shndx == SHN_ABS) && size && novalue) {
- /* Create backing section if not there */
- if (sdp->sd_isc == NULL) {
- Is_desc *isp;
-
- if (type == STT_OBJECT) {
- if ((isp = ld_make_data(ofl,
- size)) ==
- (Is_desc *)S_ERROR)
- return (S_ERROR);
- } else {
- if ((isp = ld_make_text(ofl,
- size)) ==
- (Is_desc *)S_ERROR)
- return (S_ERROR);
- }
-
- sdp->sd_isc = isp;
- isp->is_file = ifl;
- }
-
- /*
- * Now that backing storage has been created,
- * associate the symbol descriptor. Remove the
- * symbols special section tag so that it will
- * be assigned the correct section index as part
- * of update symbol processing.
- */
- sdp->sd_flags &= ~FLG_SY_SPECSEC;
- sdflags &= ~FLG_SY_SPECSEC;
- }
-
- /*
- * Indicate the new symbols scope. Although the
- * symbols st_other field will eventually be updated as
- * part of writing out the final symbol, update the
- * st_other field here to trigger better diagnostics
- * during symbol validation (for example, undefined
- * references that are defined symbolic in a mapfile).
- */
- if (scope == FLG_SCOPE_HIDD) {
- /*
- * This symbol needs to be reduced to local.
- */
- if (ofl->ofl_flags & FLG_OF_REDLSYM) {
- sdp->sd_flags |=
- (FLG_SY_HIDDEN | FLG_SY_ELIM);
- sdp->sd_sym->st_other = STV_ELIMINATE;
- } else {
- sdp->sd_flags |= FLG_SY_HIDDEN;
- sdp->sd_sym->st_other = STV_HIDDEN;
- }
- } else if (scope == FLG_SCOPE_ELIM) {
- /*
- * This symbol needs to be eliminated. Note,
- * the symbol is also tagged as local to trigger
- * any necessary relocation processing prior
- * to the symbol being eliminated.
- */
- sdp->sd_flags |= (FLG_SY_HIDDEN | FLG_SY_ELIM);
- sdp->sd_sym->st_other = STV_ELIMINATE;
-
- } else {
- /*
- * This symbol is explicitly defined to remain
- * global.
- */
- sdp->sd_flags |= sdflags;
-
- /*
- * Qualify any global scope.
- */
- if (scope == FLG_SCOPE_SNGL) {
- sdp->sd_flags |=
- (FLG_SY_SINGLE | FLG_SY_NDIR);
- sdp->sd_sym->st_other = STV_SINGLETON;
- } else if (scope == FLG_SCOPE_PROT) {
- sdp->sd_flags |= FLG_SY_PROTECT;
- sdp->sd_sym->st_other = STV_PROTECTED;
- } else if (scope == FLG_SCOPE_EXPT) {
- sdp->sd_flags |= FLG_SY_EXPORT;
- sdp->sd_sym->st_other = STV_EXPORTED;
- } else
- sdp->sd_flags |= FLG_SY_DEFAULT;
-
- /*
- * Record the present version index for later
- * potential versioning.
- */
- if ((sdp->sd_aux->sa_overndx == 0) ||
- (sdp->sd_aux->sa_overndx == VER_NDX_GLOBAL))
- sdp->sd_aux->sa_overndx = vdp->vd_ndx;
- vdp->vd_flags |= FLG_VER_REFER;
- }
-
- conflict = NULL;
-
- /*
- * Carry out some validity checks to ensure incompatible
- * symbol characteristics have not been defined.
- * These checks are carried out after symbols are added
- * or resolved, to catch single instance, and
- * multi-instance definition inconsistencies.
- */
- if ((sdp->sd_flags & (FLG_SY_HIDDEN | FLG_SY_ELIM)) &&
- ((scope != FLG_SCOPE_HIDD) &&
- (scope != FLG_SCOPE_ELIM))) {
- conflict = MSG_INTL(MSG_MAP_DIFF_SYMLCL);
-
- } else if ((sdp->sd_flags &
- (FLG_SY_SINGLE | FLG_SY_EXPORT)) &&
- ((scope != FLG_SCOPE_DFLT) &&
- (scope != FLG_SCOPE_EXPT) &&
- (scope != FLG_SCOPE_SNGL))) {
- conflict = MSG_INTL(MSG_MAP_DIFF_SYMGLOB);
-
- } else if ((sdp->sd_flags & FLG_SY_PROTECT) &&
- ((scope != FLG_SCOPE_DFLT) &&
- (scope != FLG_SCOPE_PROT))) {
- conflict = MSG_INTL(MSG_MAP_DIFF_SYMPROT);
-
- } else if ((sdp->sd_flags & FLG_SY_NDIR) &&
- (scope == FLG_SCOPE_PROT)) {
- conflict = MSG_INTL(MSG_MAP_DIFF_PROTNDIR);
-
- } else if ((sdp->sd_flags & FLG_SY_DIR) &&
- (scope == FLG_SCOPE_SNGL)) {
- conflict = MSG_INTL(MSG_MAP_DIFF_SNGLDIR);
- }
-
- if (conflict) {
- /*
- * Select the conflict message from either a
- * single instance or multi-instance definition.
- */
- if (sdp->sd_file->ifl_name == mapfile) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_SYMDEF2), mapfile,
- EC_XWORD(Line_num), demangle(_name),
- conflict);
- } else {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_SYMDEF1), mapfile,
- EC_XWORD(Line_num), demangle(_name),
- sdp->sd_file->ifl_name, conflict);
- }
- errcnt++;
- continue;
- }
-
- /*
- * Indicate that this symbol has been explicitly
- * contributed from a mapfile.
- */
- sdp->sd_flags |= (FLG_SY_MAPFILE | FLG_SY_EXPDEF);
-
- /*
- * If we've encountered a symbol definition simulate
- * that an input file has been processed - this allows
- * things like filters to be created purely from a
- * mapfile.
- */
- if (type != STT_NOTYPE)
- ofl->ofl_objscnt++;
- DBG_CALL(Dbg_map_symbol(ofl, sdp));
-
- /*
- * If this symbol has an associated filtee, record the
- * filtee string and associate the string index with the
- * symbol. This is used later to associate the syminfo
- * information with the necessary .dynamic entry.
- */
- if (filter && (filtee == NULL)) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_NOFILTER), mapfile,
- EC_XWORD(Line_num), _name);
- errcnt++;
- continue;
- }
-
- if (filtee) {
- Dfltr_desc * dftp;
- Sfltr_desc sft;
- Aliste idx, _idx, nitems;
-
- /*
- * Make sure we don't duplicate any filtee
- * strings, and create a new descriptor if
- * necessary.
- */
- idx = nitems = alist_nitems(ofl->ofl_dtsfltrs);
- for (ALIST_TRAVERSE(ofl->ofl_dtsfltrs, _idx,
- dftp)) {
- if ((dftflag != dftp->dft_flag) ||
- (strcmp(dftp->dft_str, filtee)))
- continue;
- idx = _idx;
- break;
- }
- if (idx == nitems) {
- Dfltr_desc dft;
-
- dft.dft_str = filtee;
- dft.dft_flag = dftflag;
- dft.dft_ndx = 0;
-
- /*
- * The following append puts the new
- * item at the offset contained in
- * idx, because we know idx contains
- * the index of the next available slot.
- */
- if (alist_append(&ofl->ofl_dtsfltrs,
- &dft, sizeof (Dfltr_desc),
- AL_CNT_OFL_DTSFLTRS) == NULL)
- return (S_ERROR);
- }
-
- /*
- * Create a new filter descriptor for this
- * symbol.
- */
- sft.sft_sdp = sdp;
- sft.sft_idx = idx;
-
- if (alist_append(&ofl->ofl_symfltrs,
- &sft, sizeof (Sfltr_desc),
- AL_CNT_OFL_SYMFLTRS) == NULL)
- return (S_ERROR);
- }
+ if (!ld_map_sym_enter(mf, &mv, &ms))
+ return (FALSE);
break;
default:
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_EXPSCOL), mapfile,
- EC_XWORD(Line_num));
- errcnt++;
+ mf_fatal0(mf, MSG_INTL(MSG_MAP_EXPSCOL));
+ mv.mv_errcnt++;
continue;
}
}
- if (errcnt)
- return (S_ERROR);
+ if (mv.mv_errcnt)
+ return (FALSE);
/*
* Determine if any version references are provided after the close
- * bracket.
- */
- while ((tok = gettoken(ofl, mapfile, 0)) != TK_SEMICOLON) {
- Ver_desc *_vdp;
- char *_name;
-
- if (tok != TK_STRING) {
- if (tok != TK_ERROR)
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_EXPVERS), mapfile,
- EC_XWORD(Line_num));
- return (S_ERROR);
- }
-
- name = Start_tok;
- if (vdp->vd_ndx == VER_NDX_GLOBAL) {
- eprintf(ofl->ofl_lml, ERR_WARNING,
- MSG_INTL(MSG_MAP_UNEXDEP), mapfile,
- EC_XWORD(Line_num), name);
- continue;
- }
-
- /*
- * Generate a new version descriptor if it doesn't already
- * exist.
- */
- /* LINTED */
- hash = (Word)elf_hash(name);
- if ((_vdp = ld_vers_find(name, hash,
- ofl->ofl_verdesc)) == NULL) {
- if ((_name = libld_malloc(strlen(name) + 1)) == NULL)
- return (S_ERROR);
- (void) strcpy(_name, name);
-
- if ((_vdp = ld_vers_desc(_name, hash,
- &ofl->ofl_verdesc)) == (Ver_desc *)S_ERROR)
- return (S_ERROR);
- }
-
- /*
- * Add the new version descriptor to the parent version
- * descriptors reference list. Indicate the version descriptors
- * first reference (used for error disgnostics if undefined
- * version dependencies remain).
- */
- if (ld_vers_find(name, hash, vdp->vd_deps) == NULL)
- if (aplist_append(&vdp->vd_deps, _vdp,
- AL_CNT_VERDESCS) == NULL)
- return (S_ERROR);
-
- if (_vdp->vd_ref == NULL)
- _vdp->vd_ref = vdp;
- }
- return (1);
-}
-
-/*
- * If a user has provided segment definitions via a mapfile, and these segments
- * have been assigned virtual addresses, sort the associated segments by
- * increasing virtual address.
- *
- * Only PT_LOAD segments can be assigned a virtual address. These segments can
- * be one of two types:
- *
- * - Standard segments for text, data or bss. These segments will have been
- * inserted before the default text (first PT_LOAD) segment.
- *
- * - Empty (reservation) segments. These segment will have been inserted at
- * the end of any default PT_LOAD segments.
- *
- * Any standard segments that are assigned a virtual address will be sorted,
- * and as their definitions precede any default PT_LOAD segments, these segments
- * will be assigned sections before any defaults.
- *
- * Any reservation segments are also sorted amoung themselves, as these segments
- * must still follow the standard default segments.
- */
-uintptr_t
-ld_sort_seg_list(Ofl_desc *ofl)
-{
- APlist *seg1 = NULL, *seg2 = NULL;
- Sg_desc *sgp1;
- Aliste idx1;
-
-#define FIRST_SEGMENT(type) \
- ((type == PT_PHDR) || (type == PT_INTERP) || (type == PT_SUNWCAP))
-
- /*
- * Add the .phdr and .interp segments to our list. These segments must
- * occur before any PT_LOAD segments (refer exec/elf/elf.c). Also add
- * the capabilities segment. This isn't essential, but the capabilities
- * section is one of the first in an object.
- */
- for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp1)) {
- Word type = sgp1->sg_phdr.p_type;
-
- if (FIRST_SEGMENT(type)) {
- if (aplist_append(&seg1, sgp1, AL_CNT_SEGMENTS) == NULL)
- return (S_ERROR);
- }
- }
-
- /*
- * Add the loadable segments to another list in sorted order.
+ * bracket, parsing up to the terminating ';'.
*/
- DBG_CALL(Dbg_map_sort(ofl->ofl_lml));
- for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp1)) {
- DBG_CALL(Dbg_map_sort_seg(ofl->ofl_lml, sgp1, 1));
-
- if (sgp1->sg_phdr.p_type != PT_LOAD)
- continue;
-
- /*
- * If the loadable segment does not contain a vaddr, simply
- * append it to the new list.
- */
- if ((sgp1->sg_flags & FLG_SG_VADDR) == 0) {
- if (aplist_append(&seg2, sgp1, AL_CNT_SEGMENTS) == NULL)
- return (S_ERROR);
-
- } else {
- Aliste idx2;
- Sg_desc *sgp2;
- int inserted = 0;
-
- /*
- * Traverse the segment list we are creating, looking
- * for a segment that defines a vaddr.
- */
- for (APLIST_TRAVERSE(seg2, idx2, sgp2)) {
- /*
- * Any real segments that contain vaddr's need
- * to be sorted. Any reservation segments also
- * need to be sorted. However, any reservation
- * segments should be placed after any real
- * segments.
- */
- if (((sgp2->sg_flags &
- (FLG_SG_VADDR | FLG_SG_EMPTY)) == 0) &&
- (sgp1->sg_flags & FLG_SG_EMPTY))
- continue;
-
- if ((sgp2->sg_flags & FLG_SG_VADDR) &&
- ((sgp2->sg_flags & FLG_SG_EMPTY) ==
- (sgp1->sg_flags & FLG_SG_EMPTY))) {
- if (sgp1->sg_phdr.p_vaddr ==
- sgp2->sg_phdr.p_vaddr) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_SEGSAME),
- sgp1->sg_name,
- sgp2->sg_name);
- return (S_ERROR);
- }
-
- if (sgp1->sg_phdr.p_vaddr >
- sgp2->sg_phdr.p_vaddr)
- continue;
- }
-
- /*
- * Insert this segment before the segment on
- * the seg2 list.
- */
- if (aplist_insert(&seg2, sgp1, AL_CNT_SEGMENTS,
- idx2) == NULL)
- return (S_ERROR);
- inserted = 1;
- break;
- }
-
- /*
- * If the segment being inspected has not been inserted
- * in the segment list, simply append it to the list.
- */
- if ((inserted == 0) && (aplist_append(&seg2,
- sgp1, AL_CNT_SEGMENTS) == NULL))
- return (S_ERROR);
- }
- }
-
- /*
- * Add the sorted loadable segments to our initial segment list.
- */
- for (APLIST_TRAVERSE(seg2, idx1, sgp1)) {
- if (aplist_append(&seg1, sgp1, AL_CNT_SEGMENTS) == NULL)
- return (S_ERROR);
- }
-
- /*
- * Add all other segments to our list.
- */
- for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp1)) {
- Word type = sgp1->sg_phdr.p_type;
-
- if (!FIRST_SEGMENT(type) && (type != PT_LOAD)) {
- if (aplist_append(&seg1, sgp1, AL_CNT_SEGMENTS) == NULL)
- return (S_ERROR);
- }
- }
- free((void *)ofl->ofl_segs);
- ofl->ofl_segs = NULL;
-
- /*
- * Now rebuild the original list and process all of the
- * segment/section ordering information if present.
- */
- for (APLIST_TRAVERSE(seg1, idx1, sgp1)) {
- DBG_CALL(Dbg_map_sort_seg(ofl->ofl_lml, sgp1, 0));
- if (aplist_append(&ofl->ofl_segs, sgp1,
- AL_CNT_SEGMENTS) == NULL)
- return (S_ERROR);
- }
-
-#undef FIRST_SEGMENT
+ if (!ld_map_sym_ver_fini(mf, &mv))
+ return (FALSE);
- return (1);
+ return (TRUE);
}
/*
- * Parse the mapfile.
+ * Parse the mapfile --- Sysv syntax
*/
-uintptr_t
-ld_map_parse(const char *mapfile, Ofl_desc *ofl)
+Boolean
+ld_map_parse_v1(Mapfile *mf)
{
- struct stat stat_buf; /* stat of mapfile */
- int mapfile_fd; /* descriptor for mapfile */
Sg_desc *sgp1; /* seg descriptor being manipulated */
- Sg_desc *sgp2; /* temp segment descriptor pointer */
- Ent_desc *enp; /* Segment entrance criteria. */
+ Ent_desc *enp; /* segment entrance criteria. */
Token tok; /* current token. */
- Aliste endx = 0; /* next place for entrance criterion */
- Boolean new_segment; /* If true, defines new segment. */
+ Boolean new_segment; /* If true, defines new segment */
char *name;
- static int num_stack = 0; /* number of stack segment */
- int err;
-
- DBG_CALL(Dbg_map_parse(ofl->ofl_lml, mapfile));
-
- /*
- * Determine if we're dealing with a file or a directory.
- */
- if (stat(mapfile, &stat_buf) == -1) {
- err = errno;
- eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_SYS_STAT),
- mapfile, strerror(err));
- return (S_ERROR);
- }
- if (S_ISDIR(stat_buf.st_mode)) {
- DIR *dirp;
- struct dirent *denp;
-
- /*
- * Open the directory and interpret each visible file as a
- * mapfile.
- */
- if ((dirp = opendir(mapfile)) == NULL)
- return (1);
-
- while ((denp = readdir(dirp)) != NULL) {
- char path[PATH_MAX];
-
- /*
- * Ignore any hidden filenames. Construct the full
- * pathname to the new mapfile.
- */
- if (*denp->d_name == '.')
- continue;
- (void) snprintf(path, PATH_MAX, MSG_ORIG(MSG_STR_PATH),
- mapfile, denp->d_name);
- if (ld_map_parse(path, ofl) == S_ERROR)
- return (S_ERROR);
- }
- (void) closedir(dirp);
- return (1);
- } else if (!S_ISREG(stat_buf.st_mode)) {
- eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_SYS_NOTREG),
- mapfile);
- return (S_ERROR);
- }
-
- /*
- * We read the entire mapfile into memory.
- */
- if ((Mapspace = libld_malloc(stat_buf.st_size + 1)) == NULL)
- return (S_ERROR);
- if ((mapfile_fd = open(mapfile, O_RDONLY)) == -1) {
- err = errno;
- eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN),
- mapfile, strerror(err));
- return (S_ERROR);
- }
-
- if (read(mapfile_fd, Mapspace, stat_buf.st_size) != stat_buf.st_size) {
- err = errno;
- eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_SYS_READ),
- mapfile, strerror(err));
- return (S_ERROR);
- }
- Mapspace[stat_buf.st_size] = '\0';
- nextchr = Mapspace;
-
- /*
- * Set up any global variables, the line number counter and file name.
- */
- Line_num = 1;
+ Ofl_desc *ofl = mf->mf_ofl;
+ ld_map_tkval_t tkv; /* Value of token */
+ avl_index_t where;
/*
* We now parse the mapfile until the gettoken routine returns EOF.
*/
- while ((tok = gettoken(ofl, mapfile, 1)) != TK_EOF) {
- Aliste idx;
- int ndx;
-
- /*
- * Don't know which segment yet.
- */
- sgp1 = NULL;
+ while ((tok = ld_map_gettoken(mf, TK_F_EOFOK, &tkv)) != TK_EOF) {
+ Xword ndx;
/*
* At this point we are at the beginning of a line, and the
- * variable `Start_tok' points to the first string on the line.
+ * variable tkv.tkv_str points to the first string on the line.
* All mapfile entries start with some string token except it
* is possible for a scoping definition to start with `{'.
*/
if (tok == TK_LEFTBKT) {
- if (map_version(mapfile, (char *)0, ofl) == S_ERROR)
- return (S_ERROR);
+ if (!map_version(mf, NULL))
+ return (FALSE);
continue;
}
if (tok != TK_STRING) {
if (tok != TK_ERROR)
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_EXPSEGNAM), mapfile,
- EC_XWORD(Line_num));
- return (S_ERROR);
+ mf_fatal0(mf, MSG_INTL(MSG_MAP_EXPSEGNAM));
+ return (FALSE);
}
/*
* Save the initial token.
*/
- if ((name = libld_malloc(strlen(Start_tok) + 1)) == NULL)
- return (S_ERROR);
- (void) strcpy(name, Start_tok);
+ name = tkv.tkv_str;
/*
* Now check the second character on the line. The special `-'
* and `{' characters do not involve any segment manipulation so
* we handle them first.
*/
- tok = gettoken(ofl, mapfile, 0);
- if ((tok == TK_ERROR) || (tok == TK_EOF))
- return (S_ERROR);
+ tok = ld_map_gettoken(mf, 0, &tkv);
+ if (tok == TK_ERROR)
+ return (FALSE);
if (tok == TK_DASH) {
- if (map_dash(mapfile, name, ofl) == S_ERROR)
- return (S_ERROR);
+ if (!map_dash(mf, name))
+ return (FALSE);
continue;
}
if (tok == TK_LEFTBKT) {
- if (map_version(mapfile, name, ofl) == S_ERROR)
- return (S_ERROR);
+ if (!map_version(mf, name))
+ return (FALSE);
continue;
}
/*
* If we're here we need to interpret the first string as a
- * segment name. Find the segment named in the token.
+ * segment name. Is this an already known segment?
*/
- ndx = 0;
- for (APLIST_TRAVERSE(ofl->ofl_segs, idx, sgp2)) {
- if (strcmp(sgp2->sg_name, name) == 0) {
- sgp1 = sgp2;
- sgp2->sg_flags &= ~FLG_SG_DISABLED;
- new_segment = FALSE;
- break;
- }
- ndx++;
- }
+ sgp1 = ld_seg_lookup(mf->mf_ofl, name, &where);
+ new_segment = sgp1 == NULL;
+ if (!new_segment)
+ sgp1->sg_flags &= ~FLG_SG_DISABLED;
/*
* If the second token is a '|' then we had better have found a
@@ -2469,229 +1283,181 @@ ld_map_parse(const char *mapfile, Ofl_desc *ofl)
*/
if (tok == TK_PIPE) {
if (sgp1 == NULL) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_SECINSEG), mapfile,
- EC_XWORD(Line_num), name);
- return (S_ERROR);
- } else {
- if (map_pipe(ofl, mapfile, sgp1) == S_ERROR)
- return (S_ERROR);
- continue;
+ mf_fatal(mf, MSG_INTL(MSG_MAP_SECINSEG),
+ name);
+ return (FALSE);
}
+ if (!map_pipe(mf, sgp1))
+ return (FALSE);
+ continue;
}
/*
- * If segment is still NULL then it does not exist. Create a
- * new segment, and leave its values as 0 so that map_equal()
- * can detect changing attributes.
+ * If segment does not exist, allocate a descriptor with
+ * its values set to 0 so that map_equal() can detect
+ * changing attributes.
*/
- if (sgp1 == NULL) {
- if ((sgp1 =
- libld_calloc(sizeof (Sg_desc), 1)) == NULL)
- return (S_ERROR);
- sgp1->sg_phdr.p_type = PT_NULL;
- sgp1->sg_name = name;
- new_segment = TRUE;
- }
-
- if ((strcmp(sgp1->sg_name, MSG_ORIG(MSG_STR_INTERP)) == 0) ||
- (strcmp(sgp1->sg_name, MSG_ORIG(MSG_STR_LD_DYNAMIC)) ==
- 0)) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_SEGRESV), mapfile,
- EC_XWORD(Line_num));
- return (S_ERROR);
- }
+ if (new_segment &&
+ ((sgp1 = ld_map_seg_alloc(name, PT_NULL, 0)) == NULL))
+ return (FALSE);
/*
* Now check the second token from the input line.
*/
- if (tok == TK_EQUAL) {
+ switch (tok) {
+ case TK_EQUAL: /* Create/modify segment */
+ /*
+ * We use the same syntax for hardware/software
+ * capabilities as we do for segments. If the
+ * "segment name" matches one of these, then
+ * process the capabilities instead of treating it
+ * as a segment. Note that no dynamic memory has
+ * been allocated for the segment descriptor yet,
+ * so we can bail without leaking memory.
+ */
if (strcmp(sgp1->sg_name,
MSG_ORIG(MSG_STR_HWCAP_1)) == 0) {
- if (map_cap(mapfile, CA_SUNW_HW_1,
- ofl) == S_ERROR)
- return (S_ERROR);
- DBG_CALL(Dbg_cap_mapfile(ofl->ofl_lml,
- CA_SUNW_HW_1, ofl->ofl_hwcap_1,
- ld_targ.t_m.m_mach));
+ if (!map_cap(mf, CA_SUNW_HW_1,
+ &ofl->ofl_ocapset.c_hw_1))
+ return (FALSE);
continue;
- } else if (strcmp(sgp1->sg_name,
+ }
+ if (strcmp(sgp1->sg_name,
MSG_ORIG(MSG_STR_SFCAP_1)) == 0) {
- if (map_cap(mapfile, CA_SUNW_SF_1,
- ofl) == S_ERROR)
- return (S_ERROR);
- DBG_CALL(Dbg_cap_mapfile(ofl->ofl_lml,
- CA_SUNW_SF_1, ofl->ofl_sfcap_1,
- ld_targ.t_m.m_mach));
+ if (!map_cap(mf, CA_SUNW_SF_1,
+ &ofl->ofl_ocapset.c_sf_1))
+ return (FALSE);
continue;
- } else {
- if (map_equal(mapfile, sgp1, ofl) == S_ERROR)
- return (S_ERROR);
- DBG_CALL(Dbg_map_set_equal(new_segment));
}
- } else if (tok == TK_COLON) {
+
/*
- * If this is an existing segment reservation, sections
- * can't be assigned to it.
+ * If not a new segment, show the initial value
+ * before modifying it.
*/
- if ((new_segment == FALSE) &&
- (sgp1->sg_flags & FLG_SG_EMPTY)) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_SEGEMPSEC), mapfile,
- EC_XWORD(Line_num));
- return (S_ERROR);
+ if (!new_segment && DBG_ENABLED) {
+ ndx = ld_map_seg_index(mf, sgp1);
+ Dbg_map_seg(ofl, DBG_STATE_MOD_BEFORE,
+ ndx, sgp1, mf->mf_lineno);
}
+ /* Process the segment */
+ if (!map_equal(mf, sgp1))
+ return (FALSE);
+
/*
- * We are looking at a new entrance criteria line.
- * Note that entrance criteria are added in the order
- * they are found in the mapfile, but are placed before
- * any default criteria.
+ * Special case for STACK "segments":
+ *
+ * The ability to modify the stack flags was added
+ * long after this sysv syntax was designed. It was
+ * fit into the existing syntax by treating it as a
+ * segment. However, there can only be one stack program
+ * header, while segment syntax requires user to supply
+ * a name. This is confusing, and it allows the user to
+ * attempt to create more than one stack segment. The
+ * original implementation had a test to catch this.
+ *
+ * If this is a stack segment, locate the real stack
+ * descriptor and transfer the flags to it. We then
+ * free the allocated descriptor without inserting it.
+ * The end result is that all stack segments simply
+ * alter the one stack descriptor, and the segment
+ * name is ignored.
*/
- if ((enp = alist_insert(&(ofl->ofl_ents), NULL,
- sizeof (Ent_desc), AL_CNT_OFL_ENTRANCE,
- endx)) == NULL)
- return (S_ERROR);
-
- enp->ec_segment = sgp1;
- endx++;
-
- if (map_colon(ofl, mapfile, enp) == S_ERROR)
- return (S_ERROR);
- DBG_CALL(Dbg_map_ent(ofl->ofl_lml, new_segment,
- enp, ofl));
- } else if (tok == TK_ATSIGN) {
- if (map_atsign(mapfile, sgp1, ofl) == S_ERROR)
- return (S_ERROR);
- DBG_CALL(Dbg_map_set_atsign(new_segment));
- } else if (tok != TK_ERROR) {
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_EXPEQU), mapfile,
- EC_XWORD(Line_num));
- return (S_ERROR);
- }
+ if (sgp1->sg_phdr.p_type == PT_SUNWSTACK) {
+ Sg_desc *stack = ld_map_seg_stack(mf);
+
+ if (sgp1->sg_flags & FLG_SG_P_FLAGS)
+ stack->sg_phdr.p_flags =
+ sgp1->sg_phdr.p_flags;
+ free(sgp1);
+
+ DBG_CALL(Dbg_map_seg(ofl,
+ DBG_STATE_MOD_AFTER, ndx, sgp1,
+ mf->mf_lineno));
+ break;
+ }
- /*
- * Having completed parsing an entry in the mapfile determine
- * if the segment to which it applies is new.
- */
- if (new_segment) {
/*
- * If specific fields have not been supplied via
- * map_equal(), make sure defaults are supplied.
+ * If this is a new segment, finish its initialization
+ * and insert it into the segment list.
*/
- if (((sgp1->sg_flags & FLG_SG_TYPE) == 0) &&
- (sgp1->sg_phdr.p_type == PT_NULL)) {
- /*
- * Default to a loadable segment.
- */
- sgp1->sg_phdr.p_type = PT_LOAD;
- sgp1->sg_flags |= FLG_SG_TYPE;
- }
- if (sgp1->sg_phdr.p_type == PT_LOAD) {
- if ((sgp1->sg_flags & FLG_SG_FLAGS) == 0) {
- /*
- * Default to read/write and execute.
- */
- sgp1->sg_phdr.p_flags =
- PF_R + PF_W + PF_X;
- sgp1->sg_flags |= FLG_SG_FLAGS;
- }
- if ((sgp1->sg_flags & FLG_SG_ALIGN) == 0) {
- /*
- * Default to segment alignment
- */
- sgp1->sg_phdr.p_align =
- ld_targ.t_m.m_segm_align;
- sgp1->sg_flags |= FLG_SG_ALIGN;
+ if (new_segment) {
+ switch (ld_map_seg_insert(mf, DBG_STATE_NEW,
+ sgp1, where)) {
+ case SEG_INS_SKIP:
+ continue;
+ case SEG_INS_FAIL:
+ return (FALSE);
}
+ } else {
+ /* Not new. Show what's changed */
+ DBG_CALL(Dbg_map_seg(ofl,
+ DBG_STATE_MOD_AFTER, ndx, sgp1,
+ mf->mf_lineno));
}
+ break;
+ case TK_COLON: /* Section to segment mapping */
/*
- * Determine where the new item should be inserted in
- * the segment descriptor list. Presently the user can
- * only add the following:
- *
- * PT_LOAD added before the text segment.
- * PT_NULL/empty PT_LOAD
- * added after the data/bss segments, thus
- * we add before the dynamic segment.
- * PT_SUNWSTACK
- * added before the final note segment.
- * PT_NOTE added before the final note segment.
+ * If this is a new segment, finish its initialization
+ * and insert it into the segment list.
*
- * Note that any new segments must always be added
- * after any PT_PHDR and PT_INTERP (refer Generic ABI,
- * Page 5-4).
+ * If it is not a new segment, ensure that it is
+ * not an empty segment reservation, as sections
+ * cannot be assigned to those.
*/
- switch (sgp1->sg_phdr.p_type) {
- case PT_LOAD:
- case PT_NULL:
- if (sgp1->sg_flags & FLG_SG_EMPTY)
- sgp1->sg_id = LD_DYN;
- else
- sgp1->sg_id = LD_TEXT;
- break;
- case PT_SUNWSTACK:
- sgp1->sg_id = LD_NOTE;
- if (++num_stack >= 2) {
- /*
- * Currently the number of sunw_stack
- * segment is limited to 1.
- */
- eprintf(ofl->ofl_lml, ERR_WARNING,
- MSG_INTL(MSG_MAP_NOSTACK2),
- mapfile, EC_XWORD(Line_num));
+ if (new_segment) {
+ switch (ld_map_seg_insert(mf,
+ DBG_STATE_NEW_IMPLICIT, sgp1, where)) {
+ case SEG_INS_SKIP:
continue;
+ case SEG_INS_FAIL:
+ return (FALSE);
}
- break;
- case PT_NOTE:
- sgp1->sg_id = LD_NOTE;
- break;
- default:
- eprintf(ofl->ofl_lml, ERR_FATAL,
- MSG_INTL(MSG_MAP_UNKSEGTYP), mapfile,
- EC_XWORD(Line_num),
- EC_WORD(sgp1->sg_phdr.p_type));
- return (S_ERROR);
+ } else if (sgp1->sg_flags & FLG_SG_EMPTY) {
+ mf_fatal0(mf, MSG_INTL(MSG_MAP_SEGEMPSEC));
+ return (FALSE);
}
- ndx = 0;
- for (APLIST_TRAVERSE(ofl->ofl_segs, idx, sgp2)) {
- if (sgp1->sg_id > sgp2->sg_id) {
- ndx++;
+ /*
+ * Create new entrance criteria descriptor, and
+ * process the mapping directive.
+ */
+ enp = ld_map_seg_ent_add(mf, sgp1, NULL);
+ if ((enp == NULL) || !map_colon(mf, enp))
+ return (FALSE);
+ DBG_CALL(Dbg_map_ent(ofl->ofl_lml, enp, ofl,
+ mf->mf_lineno));
+ break;
+
+ case TK_ATSIGN: /* Section size symbol */
+ /*
+ * If this is a new segment, finish its initialization
+ * and insert it into the segment list.
+ */
+ if (new_segment) {
+ switch (ld_map_seg_insert(mf,
+ DBG_STATE_NEW_IMPLICIT, sgp1, where)) {
+ case SEG_INS_SKIP:
continue;
+ case SEG_INS_FAIL:
+ return (FALSE);
}
-
- if (aplist_insert(&ofl->ofl_segs, sgp1,
- AL_CNT_SEGMENTS, idx) == NULL)
- return (S_ERROR);
- break;
}
- }
- DBG_CALL(Dbg_map_seg(ofl, ndx, sgp1));
- }
+ if (!map_atsign(mf, sgp1))
+ return (FALSE);
+ break;
- /*
- * If the output file is a static file without an interpreter, and
- * if any virtual address is specified, then set the ?N flag for
- * backward compatibility.
- */
- if (!(ofl->ofl_flags & FLG_OF_DYNAMIC) &&
- !(ofl->ofl_flags & FLG_OF_RELOBJ) &&
- !(ofl->ofl_osinterp) &&
- (ofl->ofl_flags1 & FLG_OF1_VADDR))
- ofl->ofl_dtflags_1 |= DF_1_NOHDR;
+ case TK_ERROR:
+ return (FALSE); /* Error was already issued */
- /*
- * If the output file is a relocatable file, then ?N has no effect.
- * Make sure this flag isn't set.
- */
- if (ofl->ofl_flags & FLG_OF_RELOBJ)
- ofl->ofl_dtflags_1 &= ~DF_1_NOHDR;
+ default:
+ mf_fatal0(mf, MSG_INTL(MSG_MAP_EXPEQU));
+ return (FALSE);
+ }
+ }
- return (1);
+ return (TRUE);
}
diff --git a/usr/src/cmd/sgs/libld/common/map_core.c b/usr/src/cmd/sgs/libld/common/map_core.c
new file mode 100644
index 0000000000..86c0117c5d
--- /dev/null
+++ b/usr/src/cmd/sgs/libld/common/map_core.c
@@ -0,0 +1,2838 @@
+/*
+ * 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 (c) 1988 AT&T
+ * All Rights Reserved
+ *
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Map file parsing (Shared Core Code).
+ */
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <limits.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <debug.h>
+#include "msg.h"
+#include "_libld.h"
+#include "_map.h"
+
+/*
+ * There are two styles of mapfile supported by the link-editor:
+ *
+ * 1) The original System V defined syntax, as augmented at Sun
+ * from Solaris 2.0 through Solaris 10. This style is also known
+ * as version 1.
+ *
+ * 2) A newer syntax, currently at version 2.
+ *
+ * The original syntax uses special characters (=, :, -, |, etc) as
+ * operators to indicate the operation being specified. Over the years,
+ * this syntax has been problematic:
+ *
+ * 1) Too cryptic: It's hard for people to remember which character
+ * means what.
+ *
+ * 2) Limited expansion potential: There only a few special characters
+ * available on the keyboard for new features, and it is difficult to
+ * add options to existing ones.
+ *
+ * Adding new features into this framework (2) have the effect of
+ * making the syntax even more cryptic (1). The newer syntax addresses
+ * these issues by moving to an extendible identifier based syntax that
+ * allows new features to be added without complicating old ones.
+ *
+ * The new syntax uses the following terminology:
+ *
+ * - Control directives are the directives that start with a '$'.
+ * They control how the mapfile is interpreted. We use the 'cdir_'
+ * prefix on functions and variables related to these directives.
+ *
+ * - Conditional Expressions are the expressions found in $if and $elif
+ * control directives. They evaluate to boolean true/false values.
+ * We use the 'cexp_' prefix for functions and variables related to
+ * these expressions.
+ *
+ * - Regular Directives are names (SYMBOL, VERSION, etc) that convey
+ * directions to the link-editor for building the output object.
+ *
+ * This file contains core code used by both mapfile styles: File management,
+ * lexical analysis, and other shared core functionality. It also contains
+ * the code for control directives, as they are intrinsically part of
+ * lexical analysis --- this is disabled when processing Sysv mapfiles.
+ */
+
+/*
+ * We use a stack of cdir_level_t structs to manage $if/$elif/$else/$endif
+ * processing. At each level, we keep track of the information needed to
+ * determine whether or not to process nested input lines or skip them,
+ * along with information needed to report errors.
+ */
+typedef struct {
+ Lineno cdl_if_lineno; /* Line number of opening $if */
+ Lineno cdl_else_lineno; /* 0, or line on which $else seen */
+ int cdl_done; /* True if no longer accepts input */
+ int cdl_pass; /* True if currently accepting input */
+} cdir_level_t;
+
+/* Operators in the expressions accepted by $if/$elif */
+typedef enum {
+ CEXP_OP_NONE, /* Not an operator */
+ CEXP_OP_AND, /* && */
+ CEXP_OP_OR, /* || */
+ CEXP_OP_NEG, /* ! */
+ CEXP_OP_OPAR, /* ( */
+ CEXP_OP_CPAR /* ) */
+} cexp_op_t;
+
+/*
+ * Type of conditional expression identifier AVL tree nodes
+ */
+typedef struct cexp_name_node {
+ avl_node_t ceid_avlnode; /* AVL book-keeping */
+ const char *ceid_name; /* boolean identifier name */
+} cexp_id_node_t;
+
+
+/*
+ * Declare a "stack" type, containing a pointer to data, a count of
+ * allocated, and currently used items in the stack. The data type
+ * is specified as the _type argument.
+ */
+#define STACK(_type) \
+ struct { \
+ _type *stk_s; /* Stack array */ \
+ size_t stk_n; /* Current stack depth */ \
+ size_t stk_n_alloc; /* # of elements pointed at by s */ \
+ }
+
+/*
+ * The following type represents a "generic" stack, where the data
+ * type is (void). This type is never instantiated. However, it has
+ * the same struct layout as any other STACK(), and is therefore a good
+ * generic type that can be used for stack_resize().
+ */
+typedef STACK(void) generic_stack_t;
+
+/*
+ * Ensure that the stack has enough room to push one more item
+ */
+#define STACK_RESERVE(_stack, _n_default) \
+ (((_stack).stk_n < (_stack).stk_n_alloc) || \
+ stack_resize((generic_stack_t *)&(_stack).stk_s, _n_default, \
+ sizeof (*(_stack).stk_s)))
+
+/*
+ * Reset a stack to empty.
+ */
+#define STACK_RESET(_stack) (_stack).stk_n = 0;
+
+/*
+ * True if stack is empty, False otherwise.
+ */
+#define STACK_IS_EMPTY(_stack) ((_stack).stk_n == 0)
+
+/*
+ * Push a value onto a stack. Caller must ensure that stack has room.
+ * This macro is intended to be used as the LHS of an assignment, the
+ * RHS of which is the value:
+ *
+ * STACK_PUSH(stack) = value;
+ */
+#define STACK_PUSH(_stack) (_stack).stk_s[(_stack).stk_n++]
+
+/*
+ * Pop a value off a stack. Caller must ensure
+ * that stack is not empty.
+ */
+#define STACK_POP(_stack) ((_stack).stk_s[--(_stack).stk_n])
+
+/*
+ * Access top element on stack without popping. Caller must ensure
+ * that stack is not empty.
+ */
+#define STACK_TOP(_stack) (((_stack).stk_s)[(_stack).stk_n - 1])
+
+/*
+ * Initial sizes used for the stacks: The stacks are allocated on demand
+ * to these sizes, and then doubled as necessary until they are large enough.
+ *
+ * The ideal size would be large enough that only a single allocation
+ * occurs, and our defaults should generally have that effect. However,
+ * in doing so, we run the risk of a latent error in the resize code going
+ * undetected until triggered by a large task in the field. For this reason,
+ * we set the sizes to the smallest size possible when compiled for debug.
+ */
+#ifdef DEBUG
+#define CDIR_STACK_INIT 1
+#define CEXP_OP_STACK_INIT 1
+#define CEXP_VAL_STACK_INIT 1
+#else
+#define CDIR_STACK_INIT 16
+#define CEXP_OP_STACK_INIT 8
+#define CEXP_VAL_STACK_INIT (CEXP_OP_STACK_INIT * 2) /* 2 vals per binop */
+#endif
+
+
+/*
+ * Persistent state maintained by map module in between calls.
+ *
+ * This is kept as static file scope data, because it is only used
+ * when libld is called by ld, and not by rtld. If that should change,
+ * the code is designed so that it can become reentrant easily:
+ *
+ * - Add a pointer to the output descriptor to a structure of this type,
+ * allocated dynamically on the first call to ld_map_parse().
+ * - Change all references to lms to instead reference the pointer in
+ * the output descriptor.
+ *
+ * Until then, it is simpler not to expose these details.
+ */
+typedef struct {
+ int lms_cdir_valid; /* Allow control dir. on entry to gettoken() */
+ STACK(cdir_level_t) lms_cdir_stack; /* Conditional input level */
+ STACK(cexp_op_t) lms_cexp_op_stack; /* Cond. expr operators */
+ STACK(uchar_t) lms_cexp_val_stack; /* Cond. expr values */
+ avl_tree_t *lms_cexp_id;
+} ld_map_state_t;
+static ld_map_state_t lms;
+
+
+/*
+ * Version 1 (SysV) syntax dispatch table for ld_map_gettoken(). For each
+ * of the 7-bit ASCII characters, determine how the lexical analyzer
+ * should behave.
+ *
+ * This table must be kept in sync with tkid_attr[] below.
+ *
+ * Identifier Note:
+ * The Linker and Libraries Guide states that the original syntax uses
+ * C identifier rules, allowing '.' to be treated as a letter. However,
+ * the implementation is considerably looser than that: Any character
+ * with an ASCII code (0-127) which is printable and not used to start
+ * another token is allowed to start an identifier, and they are terminated
+ * by any of: space, double quote, tab, newline, ':', ';', '=', or '#'.
+ * The original code has been replaced, but this table encodes the same
+ * rules, to ensure backward compatibility.
+ */
+static const mf_tokdisp_t gettok_dispatch_v1 = {
+ TK_OP_EOF, /* 0 - NUL */
+ TK_OP_ILLCHR, /* 1 - SOH */
+ TK_OP_ILLCHR, /* 2 - STX */
+ TK_OP_ILLCHR, /* 3 - ETX */
+ TK_OP_ILLCHR, /* 4 - EOT */
+ TK_OP_ILLCHR, /* 5 - ENQ */
+ TK_OP_ILLCHR, /* 6 - ACK */
+ TK_OP_ILLCHR, /* 7 - BEL */
+ TK_OP_ILLCHR, /* 8 - BS */
+ TK_OP_WS, /* 9 - HT */
+ TK_OP_NL, /* 10 - NL */
+ TK_OP_WS, /* 11 - VT */
+ TK_OP_WS, /* 12 - FF */
+ TK_OP_WS, /* 13 - CR */
+ TK_OP_ILLCHR, /* 14 - SO */
+ TK_OP_ILLCHR, /* 15 - SI */
+ TK_OP_ILLCHR, /* 16 - DLE */
+ TK_OP_ILLCHR, /* 17 - DC1 */
+ TK_OP_ILLCHR, /* 18 - DC2 */
+ TK_OP_ILLCHR, /* 19 - DC3 */
+ TK_OP_ILLCHR, /* 20 - DC4 */
+ TK_OP_ILLCHR, /* 21 - NAK */
+ TK_OP_ILLCHR, /* 22 - SYN */
+ TK_OP_ILLCHR, /* 23 - ETB */
+ TK_OP_ILLCHR, /* 24 - CAN */
+ TK_OP_ILLCHR, /* 25 - EM */
+ TK_OP_ILLCHR, /* 26 - SUB */
+ TK_OP_ILLCHR, /* 27 - ESC */
+ TK_OP_ILLCHR, /* 28 - FS */
+ TK_OP_ILLCHR, /* 29 - GS */
+ TK_OP_ILLCHR, /* 30 - RS */
+ TK_OP_ILLCHR, /* 31 - US */
+ TK_OP_WS, /* 32 - SP */
+ TK_OP_ID, /* 33 - ! */
+ TK_OP_SIMQUOTE, /* 34 - " */
+ TK_OP_CMT, /* 35 - # */
+ TK_OP_ID, /* 36 - $ */
+ TK_OP_ID, /* 37 - % */
+ TK_OP_ID, /* 38 - & */
+ TK_OP_ID, /* 39 - ' */
+ TK_OP_ID, /* 40 - ( */
+ TK_OP_ID, /* 41 - ) */
+ TK_OP_ID, /* 42 - * */
+ TK_OP_ID, /* 43 - + */
+ TK_OP_ID, /* 44 - , */
+ TK_DASH, /* 45 - - */
+ TK_OP_ID, /* 46 - . */
+ TK_OP_ID, /* 47 - / */
+ TK_OP_ID, /* 48 - 0 */
+ TK_OP_ID, /* 49 - 1 */
+ TK_OP_ID, /* 50 - 2 */
+ TK_OP_ID, /* 51 - 3 */
+ TK_OP_ID, /* 52 - 4 */
+ TK_OP_ID, /* 53 - 5 */
+ TK_OP_ID, /* 54 - 6 */
+ TK_OP_ID, /* 55 - 7 */
+ TK_OP_ID, /* 56 - 8 */
+ TK_OP_ID, /* 57 - 9 */
+ TK_COLON, /* 58 - : */
+ TK_SEMICOLON, /* 59 - ; */
+ TK_OP_ID, /* 60 - < */
+ TK_EQUAL, /* 61 - = */
+ TK_OP_ID, /* 62 - > */
+ TK_OP_ID, /* 63 - ? */
+ TK_ATSIGN, /* 64 - @ */
+ TK_OP_ID, /* 65 - A */
+ TK_OP_ID, /* 66 - B */
+ TK_OP_ID, /* 67 - C */
+ TK_OP_ID, /* 68 - D */
+ TK_OP_ID, /* 69 - E */
+ TK_OP_ID, /* 70 - F */
+ TK_OP_ID, /* 71 - G */
+ TK_OP_ID, /* 72 - H */
+ TK_OP_ID, /* 73 - I */
+ TK_OP_ID, /* 74 - J */
+ TK_OP_ID, /* 75 - K */
+ TK_OP_ID, /* 76 - L */
+ TK_OP_ID, /* 77 - M */
+ TK_OP_ID, /* 78 - N */
+ TK_OP_ID, /* 79 - O */
+ TK_OP_ID, /* 80 - P */
+ TK_OP_ID, /* 81 - Q */
+ TK_OP_ID, /* 82 - R */
+ TK_OP_ID, /* 83 - S */
+ TK_OP_ID, /* 84 - T */
+ TK_OP_ID, /* 85 - U */
+ TK_OP_ID, /* 86 - V */
+ TK_OP_ID, /* 87 - W */
+ TK_OP_ID, /* 88 - X */
+ TK_OP_ID, /* 89 - Y */
+ TK_OP_ID, /* 90 - Z */
+ TK_OP_ID, /* 91 - [ */
+ TK_OP_ID, /* 92 - \ */
+ TK_OP_ID, /* 93 - ] */
+ TK_OP_ID, /* 94 - ^ */
+ TK_OP_ID, /* 95 - _ */
+ TK_OP_ID, /* 96 - ` */
+ TK_OP_ID, /* 97 - a */
+ TK_OP_ID, /* 98 - b */
+ TK_OP_ID, /* 99 - c */
+ TK_OP_ID, /* 100 - d */
+ TK_OP_ID, /* 101 - e */
+ TK_OP_ID, /* 102 - f */
+ TK_OP_ID, /* 103 - g */
+ TK_OP_ID, /* 104 - h */
+ TK_OP_ID, /* 105 - i */
+ TK_OP_ID, /* 106 - j */
+ TK_OP_ID, /* 107 - k */
+ TK_OP_ID, /* 108 - l */
+ TK_OP_ID, /* 109 - m */
+ TK_OP_ID, /* 110 - n */
+ TK_OP_ID, /* 111 - o */
+ TK_OP_ID, /* 112 - p */
+ TK_OP_ID, /* 113 - q */
+ TK_OP_ID, /* 114 - r */
+ TK_OP_ID, /* 115 - s */
+ TK_OP_ID, /* 116 - t */
+ TK_OP_ID, /* 117 - u */
+ TK_OP_ID, /* 118 - v */
+ TK_OP_ID, /* 119 - w */
+ TK_OP_ID, /* 120 - x */
+ TK_OP_ID, /* 121 - y */
+ TK_OP_ID, /* 122 - z */
+ TK_LEFTBKT, /* 123 - { */
+ TK_PIPE, /* 124 - | */
+ TK_RIGHTBKT, /* 125 - } */
+ TK_OP_ID, /* 126 - ~ */
+ TK_OP_ILLCHR, /* 127 - DEL */
+};
+
+/*
+ * Version 2 syntax dispatch table for ld_map_gettoken(). For each of the
+ * 7-bit ASCII characters, determine how the lexical analyzer should behave.
+ *
+ * This table must be kept in sync with tkid_attr[] below.
+ *
+ * Identifier Note:
+ * We define a letter as being one of the character [A-Z], [a-z], or [_%/.]
+ * A digit is the numbers [0-9], or [$-]. An unquoted identifier is defined
+ * as a letter, followed by any number of letters or digits. This is a loosened
+ * version of the C definition of an identifier. The extra characters not
+ * allowed by C are common in section names and/or file paths.
+ */
+static const mf_tokdisp_t gettok_dispatch_v2 = {
+ TK_OP_EOF, /* 0 - NUL */
+ TK_OP_ILLCHR, /* 1 - SOH */
+ TK_OP_ILLCHR, /* 2 - STX */
+ TK_OP_ILLCHR, /* 3 - ETX */
+ TK_OP_ILLCHR, /* 4 - EOT */
+ TK_OP_ILLCHR, /* 5 - ENQ */
+ TK_OP_ILLCHR, /* 6 - ACK */
+ TK_OP_ILLCHR, /* 7 - BEL */
+ TK_OP_ILLCHR, /* 8 - BS */
+ TK_OP_WS, /* 9 - HT */
+ TK_OP_NL, /* 10 - NL */
+ TK_OP_WS, /* 11 - VT */
+ TK_OP_WS, /* 12 - FF */
+ TK_OP_WS, /* 13 - CR */
+ TK_OP_ILLCHR, /* 14 - SO */
+ TK_OP_ILLCHR, /* 15 - SI */
+ TK_OP_ILLCHR, /* 16 - DLE */
+ TK_OP_ILLCHR, /* 17 - DC1 */
+ TK_OP_ILLCHR, /* 18 - DC2 */
+ TK_OP_ILLCHR, /* 19 - DC3 */
+ TK_OP_ILLCHR, /* 20 - DC4 */
+ TK_OP_ILLCHR, /* 21 - NAK */
+ TK_OP_ILLCHR, /* 22 - SYN */
+ TK_OP_ILLCHR, /* 23 - ETB */
+ TK_OP_ILLCHR, /* 24 - CAN */
+ TK_OP_ILLCHR, /* 25 - EM */
+ TK_OP_ILLCHR, /* 26 - SUB */
+ TK_OP_ILLCHR, /* 27 - ESC */
+ TK_OP_ILLCHR, /* 28 - FS */
+ TK_OP_ILLCHR, /* 29 - GS */
+ TK_OP_ILLCHR, /* 30 - RS */
+ TK_OP_ILLCHR, /* 31 - US */
+ TK_OP_WS, /* 32 - SP */
+ TK_BANG, /* 33 - ! */
+ TK_OP_CQUOTE, /* 34 - " */
+ TK_OP_CMT, /* 35 - # */
+ TK_OP_CDIR, /* 36 - $ */
+ TK_OP_ID, /* 37 - % */
+ TK_OP_BADCHR, /* 38 - & */
+ TK_OP_SIMQUOTE, /* 39 - ' */
+ TK_OP_BADCHR, /* 40 - ( */
+ TK_OP_BADCHR, /* 41 - ) */
+ TK_STAR, /* 42 - * */
+ TK_OP_CEQUAL, /* 43 - + */
+ TK_OP_BADCHR, /* 44 - , */
+ TK_OP_CEQUAL, /* 45 - - */
+ TK_OP_ID, /* 46 - . */
+ TK_OP_ID, /* 47 - / */
+ TK_OP_NUM, /* 48 - 0 */
+ TK_OP_NUM, /* 49 - 1 */
+ TK_OP_NUM, /* 50 - 2 */
+ TK_OP_NUM, /* 51 - 3 */
+ TK_OP_NUM, /* 52 - 4 */
+ TK_OP_NUM, /* 53 - 5 */
+ TK_OP_NUM, /* 54 - 6 */
+ TK_OP_NUM, /* 55 - 7 */
+ TK_OP_NUM, /* 56 - 8 */
+ TK_OP_NUM, /* 57 - 9 */
+ TK_COLON, /* 58 - : */
+ TK_SEMICOLON, /* 59 - ; */
+ TK_OP_BADCHR, /* 60 - < */
+ TK_EQUAL, /* 61 - = */
+ TK_OP_BADCHR, /* 62 - > */
+ TK_OP_BADCHR, /* 63 - ? */
+ TK_OP_BADCHR, /* 64 - @ */
+ TK_OP_ID, /* 65 - A */
+ TK_OP_ID, /* 66 - B */
+ TK_OP_ID, /* 67 - C */
+ TK_OP_ID, /* 68 - D */
+ TK_OP_ID, /* 69 - E */
+ TK_OP_ID, /* 70 - F */
+ TK_OP_ID, /* 71 - G */
+ TK_OP_ID, /* 72 - H */
+ TK_OP_ID, /* 73 - I */
+ TK_OP_ID, /* 74 - J */
+ TK_OP_ID, /* 75 - K */
+ TK_OP_ID, /* 76 - L */
+ TK_OP_ID, /* 77 - M */
+ TK_OP_ID, /* 78 - N */
+ TK_OP_ID, /* 79 - O */
+ TK_OP_ID, /* 80 - P */
+ TK_OP_ID, /* 81 - Q */
+ TK_OP_ID, /* 82 - R */
+ TK_OP_ID, /* 83 - S */
+ TK_OP_ID, /* 84 - T */
+ TK_OP_ID, /* 85 - U */
+ TK_OP_ID, /* 86 - V */
+ TK_OP_ID, /* 87 - W */
+ TK_OP_ID, /* 88 - X */
+ TK_OP_ID, /* 89 - Y */
+ TK_OP_ID, /* 90 - Z */
+ TK_OP_BADCHR, /* 91 - [ */
+ TK_OP_BADCHR, /* 92 - \ */
+ TK_OP_BADCHR, /* 93 - ] */
+ TK_OP_BADCHR, /* 94 - ^ */
+ TK_OP_ID, /* 95 - _ */
+ TK_OP_BADCHR, /* 96 - ` */
+ TK_OP_ID, /* 97 - a */
+ TK_OP_ID, /* 98 - b */
+ TK_OP_ID, /* 99 - c */
+ TK_OP_ID, /* 100 - d */
+ TK_OP_ID, /* 101 - e */
+ TK_OP_ID, /* 102 - f */
+ TK_OP_ID, /* 103 - g */
+ TK_OP_ID, /* 104 - h */
+ TK_OP_ID, /* 105 - i */
+ TK_OP_ID, /* 106 - j */
+ TK_OP_ID, /* 107 - k */
+ TK_OP_ID, /* 108 - l */
+ TK_OP_ID, /* 109 - m */
+ TK_OP_ID, /* 110 - n */
+ TK_OP_ID, /* 111 - o */
+ TK_OP_ID, /* 112 - p */
+ TK_OP_ID, /* 113 - q */
+ TK_OP_ID, /* 114 - r */
+ TK_OP_ID, /* 115 - s */
+ TK_OP_ID, /* 116 - t */
+ TK_OP_ID, /* 117 - u */
+ TK_OP_ID, /* 118 - v */
+ TK_OP_ID, /* 119 - w */
+ TK_OP_ID, /* 120 - x */
+ TK_OP_ID, /* 121 - y */
+ TK_OP_ID, /* 122 - z */
+ TK_LEFTBKT, /* 123 - { */
+ TK_OP_BADCHR, /* 124 - | */
+ TK_RIGHTBKT, /* 125 - } */
+ TK_OP_BADCHR, /* 126 - ~ */
+ TK_OP_ILLCHR, /* 127 - DEL */
+};
+
+
+/*
+ * Table used to identify unquoted identifiers. Each element of this array
+ * contains a bitmask indicating whether the character it represents starts,
+ * or continues an identifier, for each supported mapfile syntax version.
+ */
+static const char tkid_attr[128] = {
+ 0, /* 0 - NUL */
+ TKID_ATTR_CONT(1), /* 1 - SOH */
+ TKID_ATTR_CONT(1), /* 2 - STX */
+ TKID_ATTR_CONT(1), /* 3 - ETX */
+ TKID_ATTR_CONT(1), /* 4 - EOT */
+ TKID_ATTR_CONT(1), /* 5 - ENQ */
+ TKID_ATTR_CONT(1), /* 6 - ACK */
+ TKID_ATTR_CONT(1), /* 7 - BEL */
+ TKID_ATTR_CONT(1), /* 8 - BS */
+ 0, /* 9 - HT */
+ 0, /* 10 - NL */
+ TKID_ATTR_CONT(1), /* 11 - VT */
+ TKID_ATTR_CONT(1), /* 12 - FF */
+ TKID_ATTR_CONT(1), /* 13 - CR */
+ TKID_ATTR_CONT(1), /* 14 - SO */
+ TKID_ATTR_CONT(1), /* 15 - SI */
+ TKID_ATTR_CONT(1), /* 16 - DLE */
+ TKID_ATTR_CONT(1), /* 17 - DC1 */
+ TKID_ATTR_CONT(1), /* 18 - DC2 */
+ TKID_ATTR_CONT(1), /* 19 - DC3 */
+ TKID_ATTR_CONT(1), /* 20 - DC4 */
+ TKID_ATTR_CONT(1), /* 21 - NAK */
+ TKID_ATTR_CONT(1), /* 22 - SYN */
+ TKID_ATTR_CONT(1), /* 23 - ETB */
+ TKID_ATTR_CONT(1), /* 24 - CAN */
+ TKID_ATTR_CONT(1), /* 25 - EM */
+ TKID_ATTR_CONT(1), /* 26 - SUB */
+ TKID_ATTR_CONT(1), /* 27 - ESC */
+ TKID_ATTR_CONT(1), /* 28 - FS */
+ TKID_ATTR_CONT(1), /* 29 - GS */
+ TKID_ATTR_CONT(1), /* 30 - RS */
+ TKID_ATTR_CONT(1), /* 31 - US */
+ 0, /* 32 - SP */
+ TKID_ATTR(1), /* 33 - ! */
+ 0, /* 34 - " */
+ 0, /* 35 - # */
+ TKID_ATTR(1) | TKID_ATTR_CONT(2), /* 36 - $ */
+ TKID_ATTR(1) | TKID_ATTR_CONT(2), /* 37 - % */
+ TKID_ATTR(1), /* 38 - & */
+ TKID_ATTR(1), /* 39 - ' */
+ TKID_ATTR(1), /* 40 - ( */
+ TKID_ATTR(1), /* 41 - ) */
+ TKID_ATTR(1), /* 42 - * */
+ TKID_ATTR(1), /* 43 - + */
+ TKID_ATTR(1), /* 44 - , */
+ TKID_ATTR_CONT(1) | TKID_ATTR_CONT(2), /* 45 - - */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 46 - . */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 47 - / */
+ TKID_ATTR(1) | TKID_ATTR_CONT(2), /* 48 - 0 */
+ TKID_ATTR(1) | TKID_ATTR_CONT(2), /* 49 - 1 */
+ TKID_ATTR(1) | TKID_ATTR_CONT(2), /* 50 - 2 */
+ TKID_ATTR(1) | TKID_ATTR_CONT(2), /* 51 - 3 */
+ TKID_ATTR(1) | TKID_ATTR_CONT(2), /* 52 - 4 */
+ TKID_ATTR(1) | TKID_ATTR_CONT(2), /* 53 - 5 */
+ TKID_ATTR(1) | TKID_ATTR_CONT(2), /* 54 - 6 */
+ TKID_ATTR(1) | TKID_ATTR_CONT(2), /* 55 - 7 */
+ TKID_ATTR(1) | TKID_ATTR_CONT(2), /* 56 - 8 */
+ TKID_ATTR(1) | TKID_ATTR_CONT(2), /* 57 - 9 */
+ 0, /* 58 - : */
+ 0, /* 59 - ; */
+ TKID_ATTR(1), /* 60 - < */
+ 0, /* 61 - = */
+ TKID_ATTR(1), /* 62 - > */
+ TKID_ATTR(1), /* 63 - ? */
+ TKID_ATTR_CONT(1), /* 64 - @ */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 65 - A */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 66 - B */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 67 - C */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 68 - D */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 69 - E */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 70 - F */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 71 - G */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 72 - H */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 73 - I */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 74 - J */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 75 - K */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 76 - L */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 77 - M */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 78 - N */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 79 - O */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 80 - P */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 81 - Q */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 82 - R */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 83 - S */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 84 - T */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 85 - U */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 86 - V */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 87 - W */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 88 - X */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 89 - Y */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 90 - Z */
+ TKID_ATTR(1), /* 91 - [ */
+ TKID_ATTR(1), /* 92 - \ */
+ TKID_ATTR(1), /* 93 - ] */
+ TKID_ATTR(1), /* 94 - ^ */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 95 - _ */
+ TKID_ATTR(1), /* 96 - ` */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 97 - a */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 98 - b */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 99 - c */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 100 - d */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 101 - e */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 102 - f */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 103 - g */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 104 - h */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 105 - i */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 106 - j */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 107 - k */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 108 - l */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 109 - m */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 110 - n */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 111 - o */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 112 - p */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 113 - q */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 114 - r */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 115 - s */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 116 - t */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 117 - u */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 118 - v */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 119 - w */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 120 - x */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 121 - y */
+ TKID_ATTR(1) | TKID_ATTR(2), /* 122 - z */
+ TKID_ATTR_CONT(1), /* 123 - { */
+ TKID_ATTR_CONT(1), /* 124 - | */
+ TKID_ATTR_CONT(1), /* 125 - } */
+ TKID_ATTR(1), /* 126 - ~ */
+ TKID_ATTR_CONT(1), /* 127 - DEL */
+};
+
+
+/*
+ * Advance the given string pointer to the next newline character,
+ * or the terminating NULL if there is none.
+ */
+inline static void
+advance_to_eol(char **str)
+{
+ char *s = *str;
+
+ while ((*s != '\n') && (*s != '\0'))
+ s++;
+ *str = s;
+}
+
+/*
+ * Insert a NULL patch at the given address
+ */
+inline static void
+null_patch_set(char *str, ld_map_npatch_t *np)
+{
+ np->np_ptr = str;
+ np->np_ch = *str;
+ *str = '\0';
+}
+
+/*
+ * Undo a NULL patch
+ */
+inline static void
+null_patch_undo(ld_map_npatch_t *np)
+{
+ *np->np_ptr = np->np_ch;
+}
+
+/*
+ * Insert a NULL patch at the end of the line containing str.
+ */
+static void
+null_patch_eol(char *str, ld_map_npatch_t *np)
+{
+ advance_to_eol(&str);
+ null_patch_set(str, np);
+}
+
+/*
+ * Locate the end of an unquoted identifier.
+ *
+ * entry:
+ * mf - Mapfile descriptor, positioned to first character
+ * of identifier.
+ *
+ * exit:
+ * If the item pointed at by mf is not an identifier, returns NULL.
+ * Otherwise, returns pointer to character after the last character
+ * of the identifier.
+ */
+inline static char *
+ident_delimit(Mapfile *mf)
+{
+ char *str = mf->mf_next;
+ ld_map_npatch_t np;
+ int c = *str++;
+
+ /* If not a valid start character, report the error */
+ if ((c & 0x80) || !(tkid_attr[c] & mf->mf_tkid_start)) {
+ null_patch_set(str, &np);
+ mf_fatal(mf, MSG_INTL(MSG_MAP_BADCHAR), str);
+ null_patch_undo(&np);
+ return (NULL);
+ }
+
+ /* Keep going until we hit a non-continuing character */
+ for (c = *str; !(c & 0x80) && (tkid_attr[c] & mf->mf_tkid_cont);
+ c = *++str)
+ ;
+
+ return (str);
+}
+
+/*
+ * Allocate memory for a stack.
+ *
+ * entry:
+ * stack - Pointer to stack for which memory is required, cast
+ * to the generic stack type.
+ * n_default - Size to use for initial allocation.
+ * elt_size - sizeof(elt), where elt is the actual stack data type.
+ *
+ * exit:
+ * Returns (1) on success. On error (memory allocation), a message
+ * is printed and False (0) is returned.
+ *
+ * note:
+ * The caller casts the pointer to their actual datatype-specific stack
+ * to be a (generic_stack_t *). The C language will give all stack
+ * structs the same size and layout as long as the underlying platform
+ * uses a single integral type for pointers. Hence, this cast is safe,
+ * and lets a generic routine modify data-specific types without being
+ * aware of those types.
+ */
+static Boolean
+stack_resize(generic_stack_t *stack, size_t n_default, size_t elt_size)
+{
+ size_t new_n_alloc;
+ void *newaddr;
+
+ /* Use initial size first, and double the allocation on each call */
+ new_n_alloc = (stack->stk_n_alloc == 0) ?
+ n_default : (stack->stk_n_alloc * 2);
+
+ newaddr = libld_realloc(stack->stk_s, new_n_alloc * elt_size);
+ if (newaddr == NULL)
+ return (FALSE);
+
+ stack->stk_s = newaddr;
+ stack->stk_n_alloc = new_n_alloc;
+ return (TRUE);
+}
+
+/*
+ * AVL comparison function for cexp_id_node_t items.
+ *
+ * entry:
+ * n1, n2 - pointers to nodes to be compared
+ *
+ * exit:
+ * Returns -1 if (n1 < n2), 0 if they are equal, and 1 if (n1 > n2)
+ */
+static int
+cexp_ident_cmp(const void *n1, const void *n2)
+{
+ int rc;
+
+ rc = strcmp(((cexp_id_node_t *)n1)->ceid_name,
+ ((cexp_id_node_t *)n2)->ceid_name);
+
+ if (rc > 0)
+ return (1);
+ if (rc < 0)
+ return (-1);
+ return (0);
+}
+
+
+/*
+ * Returns True (1) if name is in the conditional expression identifier
+ * AVL tree, and False (0) otherwise.
+ */
+static int
+cexp_ident_test(const char *name)
+{
+ cexp_id_node_t node;
+
+ node.ceid_name = name;
+ return (avl_find(lms.lms_cexp_id, &node, 0) != NULL);
+}
+
+/*
+ * Add a new boolean identifier to the conditional expression identifier
+ * AVL tree.
+ *
+ * entry:
+ * mf - If non-NULL, the mapfile descriptor for the mapfile
+ * containing the $add directive. NULL if this is an
+ * initialization call.
+ * name - Name of identifier. Must point at stable storage that will
+ * not be moved or modified by the caller following this call.
+ *
+ * exit:
+ * On success, True (1) is returned and name has been entered.
+ * On failure, False (0) is returned and an error has been printed.
+ */
+static int
+cexp_ident_add(Mapfile *mf, const char *name)
+{
+ cexp_id_node_t *node;
+
+ if (mf != NULL) {
+ DBG_CALL(Dbg_map_cexp_id(mf->mf_ofl->ofl_lml, 1,
+ mf->mf_name, mf->mf_lineno, name));
+
+ /* If is already known, don't do it again */
+ if (cexp_ident_test(name))
+ return (1);
+ }
+
+ if ((node = libld_calloc(sizeof (*node), 1)) == NULL)
+ return (0);
+ node->ceid_name = name;
+ avl_add(lms.lms_cexp_id, node);
+ return (1);
+}
+
+/*
+ * Remove a boolean identifier from the conditional expression identifier
+ * AVL tree.
+ *
+ * entry:
+ * mf - Mapfile descriptor
+ * name - Name of identifier.
+ *
+ * exit:
+ * If the name was in the tree, it has been removed. If not,
+ * then this routine quietly returns.
+ */
+static void
+cexp_ident_clear(Mapfile *mf, const char *name)
+{
+ cexp_id_node_t node;
+ cexp_id_node_t *real_node;
+
+ DBG_CALL(Dbg_map_cexp_id(mf->mf_ofl->ofl_lml, 0,
+ mf->mf_name, mf->mf_lineno, name));
+
+ node.ceid_name = name;
+ real_node = avl_find(lms.lms_cexp_id, &node, 0);
+ if (real_node != NULL)
+ avl_remove(lms.lms_cexp_id, real_node);
+}
+
+/*
+ * Initialize the AVL tree that holds the names of the currently defined
+ * boolean identifiers for conditional expressions ($if/$elif).
+ *
+ * entry:
+ * ofl - Output file descriptor
+ *
+ * exit:
+ * On success, TRUE (1) is returned and lms.lms_cexp_id is ready for use.
+ * On failure, FALSE (0) is returned.
+ */
+static Boolean
+cexp_ident_init(void)
+{
+ /* If already done, use it */
+ if (lms.lms_cexp_id != NULL)
+ return (TRUE);
+
+ lms.lms_cexp_id = libld_calloc(sizeof (*lms.lms_cexp_id), 1);
+ if (lms.lms_cexp_id == NULL)
+ return (FALSE);
+ avl_create(lms.lms_cexp_id, cexp_ident_cmp, sizeof (cexp_id_node_t),
+ SGSOFFSETOF(cexp_id_node_t, ceid_avlnode));
+
+
+ /* ELFCLASS */
+ if (cexp_ident_add(NULL, (ld_targ.t_m.m_class == ELFCLASS32) ?
+ MSG_ORIG(MSG_STR_UELF32) : MSG_ORIG(MSG_STR_UELF64)) == 0)
+ return (FALSE);
+
+ /* Machine */
+ switch (ld_targ.t_m.m_mach) {
+ case EM_386:
+ case EM_AMD64:
+ if (cexp_ident_add(NULL, MSG_ORIG(MSG_STR_UX86)) == 0)
+ return (FALSE);
+ break;
+
+ case EM_SPARC:
+ case EM_SPARCV9:
+ if (cexp_ident_add(NULL, MSG_ORIG(MSG_STR_USPARC)) == 0)
+ return (FALSE);
+ break;
+ }
+
+ /* true is always defined */
+ if (cexp_ident_add(NULL, MSG_ORIG(MSG_STR_TRUE)) == 0)
+ return (FALSE);
+
+ return (TRUE);
+}
+
+/*
+ * Validate the string starting at mf->mf_next as being a
+ * boolean conditional expression identifier.
+ *
+ * entry:
+ * mf - Mapfile descriptor
+ * len - NULL, or address of variable to receive strlen() of identifier
+ * directive - If (len == NULL), string giving name of directive being
+ * processed. Ignored if (len != NULL).
+ *
+ * exit:
+ * On success:
+ * - If len is NULL, a NULL is inserted following the final
+ * character of the identifier, and the remainder of the string
+ * is tested to ensure it is empty, or only contains whitespace.
+ * - If len is non-NULL, *len is set to the number of characters
+ * in the identifier, and the rest of the string is not modified.
+ * - TRUE (1) is returned
+ *
+ * On failure, returns FALSE (0).
+ */
+static Boolean
+cexp_ident_validate(Mapfile *mf, size_t *len, const char *directive)
+{
+ char *tail;
+
+ if ((tail = ident_delimit(mf)) == NULL)
+ return (FALSE);
+
+ /*
+ * If len is non-NULL, we simple count the number of characters
+ * consumed by the identifier and are done. If len is NULL, then
+ * ensure there's nothing left but whitespace, and NULL terminate
+ * the identifier to remove it.
+ */
+ if (len != NULL) {
+ *len = tail - mf->mf_next;
+ } else if (*tail != '\0') {
+ *tail++ = '\0';
+ while (isspace(*tail))
+ tail++;
+ if (*tail != '\0') {
+ mf_fatal(mf, MSG_INTL(MSG_MAP_BADEXTRA), directive);
+ return (FALSE);
+ }
+ }
+
+ return (TRUE);
+}
+
+/*
+ * Push a new operator onto the conditional expression operator stack.
+ *
+ * entry:
+ * mf - Mapfile descriptor
+ * op - Operator to push
+ *
+ * exit:
+ * On success, TRUE (1) is returned, otherwise FALSE (0).
+ */
+static Boolean
+cexp_push_op(cexp_op_t op)
+{
+ if (STACK_RESERVE(lms.lms_cexp_op_stack, CEXP_OP_STACK_INIT) == 0)
+ return (FALSE);
+
+ STACK_PUSH(lms.lms_cexp_op_stack) = op;
+ return (TRUE);
+}
+
+/*
+ * Evaluate the basic operator (non-paren) at the top of lms.lms_cexp_op_stack,
+ * and push the results on lms.lms_cexp_val_stack.
+ *
+ * exit:
+ * On success, returns TRUE (1). On error, FALSE (0) is returned,
+ * and the caller is responsible for issuing the error.
+ */
+static Boolean
+cexp_eval_op(void)
+{
+ cexp_op_t op;
+ uchar_t val;
+
+ op = STACK_POP(lms.lms_cexp_op_stack);
+ switch (op) {
+ case CEXP_OP_AND:
+ if (lms.lms_cexp_val_stack.stk_n < 2)
+ return (FALSE);
+ val = STACK_POP(lms.lms_cexp_val_stack);
+ STACK_TOP(lms.lms_cexp_val_stack) = val &&
+ STACK_TOP(lms.lms_cexp_val_stack);
+ break;
+
+ case CEXP_OP_OR:
+ if (lms.lms_cexp_val_stack.stk_n < 2)
+ return (FALSE);
+ val = STACK_POP(lms.lms_cexp_val_stack);
+ STACK_TOP(lms.lms_cexp_val_stack) = val ||
+ STACK_TOP(lms.lms_cexp_val_stack);
+ break;
+
+ case CEXP_OP_NEG:
+ if (lms.lms_cexp_val_stack.stk_n < 1)
+ return (FALSE);
+ STACK_TOP(lms.lms_cexp_val_stack) =
+ !STACK_TOP(lms.lms_cexp_val_stack);
+ break;
+ default:
+ return (FALSE);
+ }
+
+ return (TRUE);
+}
+
+/*
+ * Evaluate an expression for a $if/$elif control directive.
+ *
+ * entry:
+ * mf - Mapfile descriptor for NULL terminated string
+ * containing the expression.
+ *
+ * exit:
+ * The contents of str are modified by this routine.
+ * One of the following values are returned:
+ * -1 Syntax error encountered (an error is printed)
+ * 0 The expression evaluates to False
+ * 1 The expression evaluates to True.
+ *
+ * note:
+ * A simplified version of Dijkstra's Shunting Yard algorithm is used
+ * to convert this syntax into postfix form and then evaluate it.
+ * Our version has no functions and a tiny set of operators.
+ *
+ * The expressions consist of boolean identifiers, which can be
+ * combined using the following operators, listed from highest
+ * precedence to least:
+ *
+ * Operator Meaning
+ * -------------------------------------------------
+ * (expr) sub-expression, non-associative
+ * ! logical negation, prefix, left associative
+ * && || logical and/or, binary, left associative
+ *
+ * The operands manipulated by these operators are names, consisting of
+ * a sequence of letters and digits. The first character must be a letter.
+ * Underscore (_) and period (.) are also considered to be characters.
+ * An operand is considered True if it is found in our set of known
+ * names (lms.lms_cexp_id), and False otherwise.
+ *
+ * The Shunting Yard algorithm works using two stacks, one for operators,
+ * and a second for operands. The infix input expression is tokenized from
+ * left to right and processed in order. Issues of associativity and
+ * precedence are managed by reducing (poping and evaluating) items with
+ * higer precedence before pushing additional tokens with lower precedence.
+ */
+static int
+cexp_eval_expr(Mapfile *mf)
+{
+ char *ident;
+ size_t len;
+ cexp_op_t new_op = CEXP_OP_AND; /* to catch binop at start */
+ ld_map_npatch_t np;
+ char *str = mf->mf_next;
+
+ STACK_RESET(lms.lms_cexp_op_stack);
+ STACK_RESET(lms.lms_cexp_val_stack);
+
+ for (; *str; str++) {
+
+ /* Skip whitespace */
+ while (isspace(*str))
+ str++;
+ if (!*str)
+ break;
+
+ switch (*str) {
+ case '&':
+ case '|':
+ if (*(str + 1) != *str)
+ goto token_error;
+ if ((new_op != CEXP_OP_NONE) &&
+ (new_op != CEXP_OP_CPAR)) {
+ mf_fatal0(mf, MSG_INTL(MSG_MAP_CEXP_BADOPUSE));
+ return (-1);
+ }
+ str++;
+
+ /*
+ * As this is a left associative binary operator, we
+ * need to process all operators of equal or higher
+ * precedence before pushing the new operator.
+ */
+ while (!STACK_IS_EMPTY(lms.lms_cexp_op_stack)) {
+ cexp_op_t op = STACK_TOP(lms.lms_cexp_op_stack);
+
+
+ if ((op != CEXP_OP_AND) && (op != CEXP_OP_OR) &&
+ (op != CEXP_OP_NEG))
+ break;
+
+ if (!cexp_eval_op())
+ goto semantic_error;
+ }
+
+ new_op = (*str == '&') ? CEXP_OP_AND : CEXP_OP_OR;
+ if (!cexp_push_op(new_op))
+ return (-1);
+ break;
+
+ case '!':
+ new_op = CEXP_OP_NEG;
+ if (!cexp_push_op(new_op))
+ return (-1);
+ break;
+
+ case '(':
+ new_op = CEXP_OP_OPAR;
+ if (!cexp_push_op(new_op))
+ return (-1);
+ break;
+
+ case ')':
+ new_op = CEXP_OP_CPAR;
+
+ /* Evaluate the operator stack until reach '(' */
+ while (!STACK_IS_EMPTY(lms.lms_cexp_op_stack) &&
+ (STACK_TOP(lms.lms_cexp_op_stack) != CEXP_OP_OPAR))
+ if (!cexp_eval_op())
+ goto semantic_error;
+
+ /*
+ * If the top of operator stack is not an open paren,
+ * when we have an error. In this case, the operator
+ * stack will be empty due to the loop above.
+ */
+ if (STACK_IS_EMPTY(lms.lms_cexp_op_stack))
+ goto unbalpar_error;
+ lms.lms_cexp_op_stack.stk_n--; /* Pop OPAR */
+ break;
+
+ default:
+ /* Ensure there's room to push another operand */
+ if (STACK_RESERVE(lms.lms_cexp_val_stack,
+ CEXP_VAL_STACK_INIT) == 0)
+ return (0);
+ new_op = CEXP_OP_NONE;
+
+ /*
+ * Operands cannot be numbers. However, we accept two
+ * special cases: '0' means false, and '1' is true.
+ * This is done to support the common C idiom of
+ * '#if 1' and '#if 0' to conditionalize code under
+ * development.
+ */
+ if ((*str == '0') || (*str == '1')) {
+ STACK_PUSH(lms.lms_cexp_val_stack) =
+ (*str == '1');
+ break;
+ }
+
+ /* Look up the identifier */
+ ident = mf->mf_next = str;
+ if (!cexp_ident_validate(mf, &len, NULL))
+ return (-1);
+ str += len - 1; /* loop will advance past final ch */
+ null_patch_set(&ident[len], &np);
+ STACK_PUSH(lms.lms_cexp_val_stack) =
+ cexp_ident_test(ident);
+ null_patch_undo(&np);
+
+ break;
+ }
+ }
+
+ /* Evaluate the operator stack until empty */
+ while (!STACK_IS_EMPTY(lms.lms_cexp_op_stack)) {
+ if (STACK_TOP(lms.lms_cexp_op_stack) == CEXP_OP_OPAR)
+ goto unbalpar_error;
+
+ if (!cexp_eval_op())
+ goto semantic_error;
+ }
+
+ /* There should be exactly one value left */
+ if (lms.lms_cexp_val_stack.stk_n != 1)
+ goto semantic_error;
+
+ /* Final value is the result */
+ return (lms.lms_cexp_val_stack.stk_s[0]);
+
+ /* Errors issued more than once are handled below, accessed via goto */
+
+token_error: /* unexpected characters in input stream */
+ mf_fatal(mf, MSG_INTL(MSG_MAP_CEXP_TOKERR), str);
+ return (-1);
+
+semantic_error: /* valid tokens, but in invalid arrangement */
+ mf_fatal0(mf, MSG_INTL(MSG_MAP_CEXP_SEMERR));
+ return (-1);
+
+unbalpar_error: /* Extra or missing parenthesis */
+ mf_fatal0(mf, MSG_INTL(MSG_MAP_CEXP_UNBALPAR));
+ return (-1);
+}
+
+/*
+ * Process a mapfile control directive. These directives start with
+ * the dollar character, and are used to manage details of the mapfile
+ * itself, such as version and conditional input.
+ *
+ * entry:
+ * mf - Mapfile descriptor
+ *
+ * exit:
+ * Returns TRUE (1) for success, and FALSE (0) on error. In the
+ * error case, a descriptive error is issued.
+ */
+static Boolean
+cdir_process(Mapfile *mf)
+{
+ typedef enum { /* Directive types */
+ CDIR_T_UNKNOWN = 0, /* Unrecognized control directive */
+ CDIR_T_ADD, /* $add */
+ CDIR_T_CLEAR, /* $clear */
+ CDIR_T_ERROR, /* $error */
+ CDIR_T_VERSION, /* $mapfile_version */
+ CDIR_T_IF, /* $if */
+ CDIR_T_ELIF, /* $elif */
+ CDIR_T_ELSE, /* $else */
+ CDIR_T_ENDIF, /* $endif */
+ } cdir_t;
+
+ typedef enum { /* Types of arguments accepted by directives */
+ ARG_T_NONE, /* Directive takes no arguments */
+ ARG_T_EXPR, /* Directive takes a conditional expression */
+ ARG_T_ID, /* Conditional expression identifier */
+ ARG_T_STR, /* Non-empty string */
+ ARG_T_IGN /* Ignore the argument */
+ } cdir_arg_t;
+
+ typedef struct {
+ const char *md_name; /* Directive name */
+ size_t md_size; /* strlen(md_name) */
+ cdir_arg_t md_arg; /* Type of arguments */
+ cdir_t md_op; /* CDIR_T_ code */
+ } cdir_match_t;
+
+ /* Control Directives: The most likely items are listed first */
+ static cdir_match_t match_data[] = {
+ { MSG_ORIG(MSG_STR_CDIR_IF), MSG_STR_CDIR_IF_SIZE,
+ ARG_T_EXPR, CDIR_T_IF },
+ { MSG_ORIG(MSG_STR_CDIR_ENDIF), MSG_STR_CDIR_ENDIF_SIZE,
+ ARG_T_NONE, CDIR_T_ENDIF },
+ { MSG_ORIG(MSG_STR_CDIR_ELSE), MSG_STR_CDIR_ELSE_SIZE,
+ ARG_T_NONE, CDIR_T_ELSE },
+ { MSG_ORIG(MSG_STR_CDIR_ELIF), MSG_STR_CDIR_ELIF_SIZE,
+ ARG_T_EXPR, CDIR_T_ELIF },
+ { MSG_ORIG(MSG_STR_CDIR_ERROR), MSG_STR_CDIR_ERROR_SIZE,
+ ARG_T_STR, CDIR_T_ERROR },
+ { MSG_ORIG(MSG_STR_CDIR_ADD), MSG_STR_CDIR_ADD_SIZE,
+ ARG_T_ID, CDIR_T_ADD },
+ { MSG_ORIG(MSG_STR_CDIR_CLEAR), MSG_STR_CDIR_CLEAR_SIZE,
+ ARG_T_ID, CDIR_T_CLEAR },
+ { MSG_ORIG(MSG_STR_CDIR_MFVER), MSG_STR_CDIR_MFVER_SIZE,
+ ARG_T_IGN, CDIR_T_VERSION },
+
+ { NULL, 0,
+ ARG_T_IGN, CDIR_T_UNKNOWN }
+ };
+
+ cdir_match_t *mdptr;
+ char *tail;
+ int expr_eval; /* Result of evaluating ARG_T_EXPR */
+ Mapfile arg_mf;
+ cdir_level_t *level;
+ int pass, parent_pass; /* Currently accepting input */
+
+restart:
+ /* Is the immediate context passing input? */
+ pass = STACK_IS_EMPTY(lms.lms_cdir_stack) ||
+ STACK_TOP(lms.lms_cdir_stack).cdl_pass;
+
+ /* Is the surrounding (parent) context passing input? */
+ parent_pass = (lms.lms_cdir_stack.stk_n <= 1) ||
+ lms.lms_cdir_stack.stk_s[lms.lms_cdir_stack.stk_n - 2].cdl_pass;
+
+
+ for (mdptr = match_data; mdptr->md_name; mdptr++) {
+ /* Prefix must match, or we move on */
+ if (strncmp(mf->mf_next, mdptr->md_name,
+ mdptr->md_size) != 0)
+ continue;
+ tail = mf->mf_next + mdptr->md_size;
+
+ /*
+ * If there isn't whitespace, or a NULL terminator following
+ * the prefix, then even though our prefix matched, the actual
+ * token is longer, and we don't have a match.
+ */
+ if (!isspace(*tail) && (*tail != '\0'))
+ continue;
+
+ /* We have matched a valid control directive */
+ break;
+ }
+
+ /* Advance input to end of the current line */
+ advance_to_eol(&mf->mf_next);
+
+ /*
+ * Set up a temporary mapfile descriptor to reference the
+ * argument string. The benefit of this second block, is that
+ * we can advance the real one to the next line now, which allows
+ * us to return at any time knowing that the input has been moved
+ * to the proper spot. This simplifies the error cases.
+ *
+ * If we had a match, tail points at the start of the string.
+ * Otherwise, we want to point at the end of the line.
+ */
+ arg_mf = *mf;
+ if (mdptr->md_name == NULL)
+ arg_mf.mf_text = arg_mf.mf_next;
+ else
+ arg_mf.mf_text = arg_mf.mf_next = tail;
+
+ /*
+ * Null terminate the arguments, and advance the main mapfile
+ * state block to the next line.
+ */
+ if (*mf->mf_next == '\n') {
+ *mf->mf_next++ = '\0';
+ mf->mf_lineno++;
+ }
+
+ /* Skip leading whitespace to arguments */
+ while (isspace(*arg_mf.mf_next))
+ arg_mf.mf_next++;
+
+ /* Strip off any comment present on the line */
+ for (tail = arg_mf.mf_next; *tail; tail++)
+ if (*tail == '#') {
+ *tail = '\0';
+ break;
+ }
+
+ /*
+ * Process the arguments as necessary depending on their type.
+ * If this control directive is nested inside a surrounding context
+ * that is not currently passing text, then we skip the argument
+ * evaluation. This follows the behavior of the C preprocessor,
+ * which only examines enough to detect the operation within
+ * a disabled section, without issuing errors about the arguments.
+ */
+ if (pass || (parent_pass && (mdptr->md_op == CDIR_T_ELIF))) {
+ switch (mdptr->md_arg) {
+ case ARG_T_NONE:
+ if (*arg_mf.mf_next == '\0')
+ break;
+ /* Args are present, but not wanted */
+ mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_REQNOARG),
+ mdptr->md_name);
+ return (FALSE);
+
+ case ARG_T_EXPR:
+ /* Ensure that arguments are present */
+ if (*arg_mf.mf_next == '\0')
+ goto error_reqarg;
+ expr_eval = cexp_eval_expr(&arg_mf);
+ if (expr_eval == -1)
+ return (FALSE);
+ break;
+
+ case ARG_T_ID:
+ /* Ensure that arguments are present */
+ if (*arg_mf.mf_next == '\0')
+ goto error_reqarg;
+ if (!cexp_ident_validate(&arg_mf, NULL,
+ mdptr->md_name))
+ return (FALSE);
+ break;
+
+ case ARG_T_STR:
+ /* Ensure that arguments are present */
+ if (*arg_mf.mf_next == '\0')
+ goto error_reqarg;
+ /* Remove trailing whitespace */
+ tail = arg_mf.mf_next + strlen(arg_mf.mf_next);
+ while ((tail > arg_mf.mf_next) &&
+ isspace(*(tail -1)))
+ tail--;
+ *tail = '\0';
+ break;
+ }
+ }
+
+ /*
+ * Carry out the specified control directive:
+ */
+ if (!STACK_IS_EMPTY(lms.lms_cdir_stack))
+ level = &STACK_TOP(lms.lms_cdir_stack);
+
+ switch (mdptr->md_op) {
+ case CDIR_T_UNKNOWN: /* Unrecognized control directive */
+ if (!pass)
+ break;
+ mf_fatal0(&arg_mf, MSG_INTL(MSG_MAP_CDIR_BAD));
+ return (FALSE);
+
+ case CDIR_T_ADD:
+ if (pass && !cexp_ident_add(&arg_mf, arg_mf.mf_next))
+ return (FALSE);
+ break;
+
+ case CDIR_T_CLEAR:
+ if (pass)
+ cexp_ident_clear(&arg_mf, arg_mf.mf_next);
+ break;
+
+ case CDIR_T_ERROR:
+ if (!pass)
+ break;
+ mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_ERROR),
+ arg_mf.mf_next);
+ return (FALSE);
+
+ case CDIR_T_VERSION:
+ /*
+ * A $mapfile_version control directive can only appear
+ * as the first directive in a mapfile, and is used to
+ * determine the syntax for the rest of the file. It's
+ * too late to be using it here.
+ */
+ if (!pass)
+ break;
+ mf_fatal0(&arg_mf, MSG_INTL(MSG_MAP_CDIR_REPVER));
+ return (FALSE);
+
+ case CDIR_T_IF:
+ /* Push a new level on the conditional input stack */
+ if (STACK_RESERVE(lms.lms_cdir_stack, CDIR_STACK_INIT) == 0)
+ return (FALSE);
+ level = &lms.lms_cdir_stack.stk_s[lms.lms_cdir_stack.stk_n++];
+ level->cdl_if_lineno = arg_mf.mf_lineno;
+ level->cdl_else_lineno = 0;
+
+ /*
+ * If previous level is not passing, this level is disabled.
+ * Otherwise, the expression value determines what happens.
+ */
+ if (pass) {
+ level->cdl_done = level->cdl_pass = expr_eval;
+ } else {
+ level->cdl_done = 1;
+ level->cdl_pass = 0;
+ }
+ break;
+
+ case CDIR_T_ELIF:
+ /* $elif requires an open $if construct */
+ if (STACK_IS_EMPTY(lms.lms_cdir_stack)) {
+ mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_NOIF),
+ MSG_ORIG(MSG_STR_CDIR_ELIF));
+ return (FALSE);
+ }
+
+ /* $elif cannot follow $else */
+ if (level->cdl_else_lineno > 0) {
+ mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_ELSE),
+ MSG_ORIG(MSG_STR_CDIR_ELIF),
+ EC_LINENO(level->cdl_else_lineno));
+ return (FALSE);
+ }
+
+ /*
+ * Accept text from $elif if the level isn't already
+ * done and the expression evaluates to true.
+ */
+ level->cdl_pass = !level->cdl_done && expr_eval;
+ if (level->cdl_pass)
+ level->cdl_done = 1;
+ break;
+
+ case CDIR_T_ELSE:
+ /* $else requires an open $if construct */
+ if (STACK_IS_EMPTY(lms.lms_cdir_stack)) {
+ mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_NOIF),
+ MSG_ORIG(MSG_STR_CDIR_ELSE));
+ return (FALSE);
+ }
+
+ /* There can only be one $else in the chain */
+ if (level->cdl_else_lineno > 0) {
+ mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_ELSE),
+ MSG_ORIG(MSG_STR_CDIR_ELSE),
+ EC_LINENO(level->cdl_else_lineno));
+ return (FALSE);
+ }
+ level->cdl_else_lineno = arg_mf.mf_lineno;
+
+ /* Accept text from $else if the level isn't already done */
+ level->cdl_pass = !level->cdl_done;
+ level->cdl_done = 1;
+ break;
+
+ case CDIR_T_ENDIF:
+ /* $endif requires an open $if construct */
+ if (STACK_IS_EMPTY(lms.lms_cdir_stack)) {
+ mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_NOIF),
+ MSG_ORIG(MSG_STR_CDIR_ENDIF));
+ return (FALSE);
+ }
+ if (--lms.lms_cdir_stack.stk_n > 0)
+ level = &STACK_TOP(lms.lms_cdir_stack);
+ break;
+
+ default:
+ return (FALSE);
+ }
+
+ /* Evaluating the control directive above can change pass status */
+ expr_eval = STACK_IS_EMPTY(lms.lms_cdir_stack) ||
+ STACK_TOP(lms.lms_cdir_stack).cdl_pass;
+ if (expr_eval != pass) {
+ pass = expr_eval;
+ DBG_CALL(Dbg_map_pass(arg_mf.mf_ofl->ofl_lml, pass,
+ arg_mf.mf_name, arg_mf.mf_lineno, mdptr->md_name));
+ }
+
+ /*
+ * At this point, we have processed a control directive,
+ * updated our conditional state stack, and the input is
+ * positioned at the start of the line following the directive.
+ * If the current level is accepting input, then give control
+ * back to ld_map_gettoken() to resume its normal operation.
+ */
+ if (pass)
+ return (TRUE);
+
+ /*
+ * The current level is not accepting input. Only another
+ * control directive can change this, so read and discard input
+ * until we encounter one of the following:
+ *
+ * EOF: Return and let ld_map_gettoken() report it
+ * Control Directive: Restart this function / evaluate new directive
+ */
+ while (*mf->mf_next != '\0') {
+ /* Skip leading whitespace */
+ while (isspace_nonl(*mf->mf_next))
+ mf->mf_next++;
+
+ /*
+ * Control directives start with a '$'. If we hit
+ * one, restart the function at this point
+ */
+ if (*mf->mf_next == '$')
+ goto restart;
+
+ /* Not a control directive, so advance input to next line */
+ advance_to_eol(&mf->mf_next);
+ if (*mf->mf_next == '\n') {
+ mf->mf_lineno++;
+ mf->mf_next++;
+ }
+ }
+
+ assert(mf->mf_next == '\0');
+ return (TRUE);
+
+ /*
+ * Control directives that require an argument that is not present
+ * jump here to report the error and exit.
+ */
+error_reqarg:
+ mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_REQARG), mdptr->md_name);
+ return (FALSE);
+
+}
+
+#ifndef _ELF64
+/*
+ * Convert a string to lowercase.
+ */
+void
+ld_map_lowercase(char *str)
+{
+ while (*str = tolower(*str))
+ str++;
+}
+#endif
+
+/*
+ * Wrappper on strtoul()/strtoull(), adapted to return an Xword.
+ *
+ * entry:
+ * str - Pointer to string to be converted.
+ * endptr - As documented for strtoul(3C). Either NULL, or
+ * address of pointer to receive the address of the first
+ * unused character in str (called "final" in strtoul(3C)).
+ * ret_value - Address of Xword variable to receive result.
+ *
+ * exit:
+ * On success, *ret_value receives the result, *endptr is updated if
+ * endptr is non-NULL, and STRTOXWORD_OK is returned.
+ * On failure, STRTOXWORD_TOBIG is returned if an otherwise valid
+ * value was too large, and STRTOXWORD_BAD is returned if the string
+ * is malformed.
+ */
+ld_map_strtoxword_t
+ld_map_strtoxword(const char *restrict str, char **restrict endptr,
+ Xword *ret_value)
+{
+#if defined(_ELF64) /* _ELF64 */
+#define FUNC strtoull /* Function to use */
+#define FUNC_MAX ULLONG_MAX /* Largest value returned by FUNC */
+#define XWORD_MAX ULLONG_MAX /* Largest Xword value */
+ uint64_t value; /* Variable of FUNC return type */
+#else /* _ELF32 */
+#define FUNC strtoul
+#define FUNC_MAX ULONG_MAX
+#define XWORD_MAX UINT_MAX
+ ulong_t value;
+#endif
+
+ char *endptr_local; /* Used if endptr is NULL */
+
+ if (endptr == NULL)
+ endptr = &endptr_local;
+
+ errno = 0;
+ value = FUNC(str, endptr, 0);
+ if ((errno != 0) || (str == *endptr)) {
+ if (value == FUNC_MAX)
+ return (STRTOXWORD_TOOBIG);
+ else
+ return (STRTOXWORD_BAD);
+ }
+
+ /*
+ * If this is a 64-bit linker building an ELFCLASS32 object,
+ * the FUNC return type is a 64-bit value, while an Xword is
+ * 32-bit. It is possible for FUNC to be able to convert a value
+ * too large for our return type.
+ */
+#if FUNC_MAX != XWORD_MAX
+ if (value > XWORD_MAX)
+ return (STRTOXWORD_TOOBIG);
+#endif
+
+ *ret_value = value;
+ return (STRTOXWORD_OK);
+
+#undef FUNC
+#undef FUNC_MAX
+#undef XWORD_MAC
+}
+
+/*
+ * Convert the unsigned integer value at the current mapfile input
+ * into binary form. All numeric values in mapfiles are treated as
+ * unsigned integers of the appropriate width for an address on the
+ * given target. Values can be decimal, hex, or octal.
+ *
+ * entry:
+ * str - String to process.
+ * value - Address of variable to receive resulting value.
+ * notail - If TRUE, an error is issued if non-whitespace
+ * characters other than '#' (comment) are found following
+ * the numeric value before the end of line.
+ *
+ * exit:
+ * On success:
+ * - *str is advanced to the next character following the value
+ * - *value receives the value
+ * - Returns TRUE (1).
+ * On failure, returns FALSE (0).
+ */
+static Boolean
+ld_map_getint(Mapfile *mf, ld_map_tkval_t *value, Boolean notail)
+{
+ ld_map_strtoxword_t s2xw_ret;
+ ld_map_npatch_t np;
+ char *endptr;
+ char *errstr = mf->mf_next;
+
+ value->tkv_int.tkvi_str = mf->mf_next;
+ s2xw_ret = ld_map_strtoxword(mf->mf_next, &endptr,
+ &value->tkv_int.tkvi_value);
+ if (s2xw_ret != STRTOXWORD_OK) {
+ null_patch_eol(mf->mf_next, &np);
+ if (s2xw_ret == STRTOXWORD_TOOBIG)
+ mf_fatal(mf, MSG_INTL(MSG_MAP_VALUELIMIT), errstr);
+ else
+ mf_fatal(mf, MSG_INTL(MSG_MAP_MALVALUE), errstr);
+ null_patch_undo(&np);
+ return (FALSE);
+ }
+
+ /* Advance position to item following value, skipping whitespace */
+ value->tkv_int.tkvi_cnt = endptr - mf->mf_next;
+ mf->mf_next = endptr;
+ while (isspace_nonl(*mf->mf_next))
+ mf->mf_next++;
+
+ /* If requested, ensure there's nothing left */
+ if (notail && (*mf->mf_next != '\n') && (*mf->mf_next != '#') &&
+ (*mf->mf_next != '\0')) {
+ null_patch_eol(mf->mf_next, &np);
+ mf_fatal(mf, MSG_INTL(MSG_MAP_BADVALUETAIL), errstr);
+ null_patch_undo(&np);
+ return (FALSE);
+ }
+
+ return (TRUE);
+}
+
+/*
+ * Convert a an unquoted identifier into a TK_STRING token, using the
+ * rules for syntax version in use. Used exclusively by ld_map_gettoken().
+ *
+ * entry:
+ * mf - Mapfile descriptor, positioned to the first character of
+ * the string.
+ * flags - Bitmask of options to control ld_map_gettoken()s behavior
+ * tkv- Address of pointer to variable to receive token value.
+ *
+ * exit:
+ * On success, mf is advanced past the token, tkv is updated with
+ * the string, and TK_STRING is returned. On error, TK_ERROR is returned.
+ */
+inline static Token
+gettoken_ident(Mapfile *mf, int flags, ld_map_tkval_t *tkv)
+{
+ char *end;
+ Token tok;
+ ld_map_npatch_t np;
+
+ tkv->tkv_str = mf->mf_next;
+ if ((end = ident_delimit(mf)) == NULL)
+ return (TK_ERROR);
+ mf->mf_next = end;
+
+ /*
+ * One advantage of reading the entire mapfile into memory is that
+ * we can access the strings within it without having to allocate
+ * more memory or make copies. In order to do that, we need to NULL
+ * terminate this identifier. That is going to overwrite the
+ * following character. The problem this presents is that the next
+ * character may well be the first character of a subsequent token.
+ * The solution to this is:
+ *
+ * 1) Disallow the case where the next character is able to
+ * start a string. This is not legal mapfile syntax anyway,
+ * so catching it here simplifies matters.
+ * 2) Copy the character into the special mf->mf_next_ch
+ * 3) The next call to ld_map_gettoken() checks mf->mf_next_ch,
+ * and if it is non-0, uses it instead of dereferencing the
+ * mf_next pointer.
+ */
+ tok = (*mf->mf_next & 0x80) ?
+ TK_OP_ILLCHR : mf->mf_tokdisp[*mf->mf_next];
+ switch (tok) {
+ case TK_OP_BADCHR:
+ null_patch_eol(mf->mf_next, &np);
+ mf_fatal(mf, MSG_INTL(MSG_MAP_BADCHAR), mf->mf_next);
+ null_patch_undo(&np);
+ return (TK_ERROR);
+
+ case TK_OP_SIMQUOTE:
+ case TK_OP_CQUOTE:
+ case TK_OP_CDIR:
+ case TK_OP_NUM:
+ case TK_OP_ID:
+ null_patch_eol(mf->mf_next, &np);
+ mf_fatal(mf, MSG_INTL(MSG_MAP_WSNEEDED), mf->mf_next);
+ null_patch_undo(&np);
+ return (TK_ERROR);
+ }
+
+ /* Null terminate, saving the replaced character */
+ mf->mf_next_ch = *mf->mf_next;
+ *mf->mf_next = '\0';
+
+ if (flags & TK_F_STRLC)
+ ld_map_lowercase(tkv->tkv_str);
+ return (TK_STRING);
+}
+
+/*
+ * Convert a quoted string into a TK_STRING token, using simple
+ * quoting rules:
+ * - Start and end quotes must be present and match
+ * - There are no special characters or escape sequences.
+ * This function is used exclusively by ld_map_gettoken().
+ *
+ * entry:
+ * mf - Mapfile descriptor, positioned to the opening quote character.
+ * flags - Bitmask of options to control ld_map_gettoken()s behavior
+ * tkv- Address of pointer to variable to receive token value.
+ *
+ * exit:
+ * On success, mf is advanced past the token, tkv is updated with
+ * the string, and TK_STRING is returned. On error, TK_ERROR is returned.
+ */
+inline static Token
+gettoken_simquote_str(Mapfile *mf, int flags, ld_map_tkval_t *tkv)
+{
+ char *str, *end;
+ char quote;
+
+ str = mf->mf_next++;
+ quote = *str;
+ end = mf->mf_next;
+ while ((*end != '\0') && (*end != '\n') && (*end != quote))
+ end++;
+ if (*end != quote) {
+ ld_map_npatch_t np;
+
+ null_patch_eol(end, &np);
+ mf_fatal(mf, MSG_INTL(MSG_MAP_NOTERM), str);
+ null_patch_undo(&np);
+ return (TK_ERROR);
+ }
+
+ /*
+ * end is pointing at the closing quote. We can turn that into NULL
+ * termination for the string without needing to restore it later.
+ */
+ *end = '\0';
+ mf->mf_next = end + 1;
+ tkv->tkv_str = str + 1; /* Skip opening quote */
+ if (flags & TK_F_STRLC)
+ ld_map_lowercase(tkv->tkv_str);
+ return (TK_STRING);
+}
+
+/*
+ * Convert a quoted string into a TK_STRING token, using C string literal
+ * quoting rules:
+ * - Start and end quotes must be present and match
+ * - Backslash is an escape, used to introduce special characters
+ * This function is used exclusively by ld_map_gettoken().
+ *
+ * entry:
+ * mf - Mapfile descriptor, positioned to the opening quote character.
+ * flags - Bitmask of options to control ld_map_gettoken()s behavior
+ * tkv- Address of pointer to variable to receive token value.
+ *
+ * exit:
+ * On success, mf is advanced past the token, tkv is updated with
+ * the string, and TK_STRING is returned. On error, TK_ERROR is returned.
+ */
+inline static Token
+gettoken_cquote_str(Mapfile *mf, int flags, ld_map_tkval_t *tkv)
+{
+ char *str, *cur, *end;
+ char quote;
+ int c;
+
+ /*
+ * This function goes through the quoted string and copies
+ * it on top of itself, replacing escape sequences with the
+ * characters they denote. There is always enough room for this,
+ * because escapes are multi-character sequences that are converted
+ * to single character results.
+ */
+ str = mf->mf_next++;
+ quote = *str;
+ cur = end = mf->mf_next;
+ for (c = *end++; (c != '\0') && (c != '\n') && (c != quote);
+ c = *end++) {
+ if (c == '\\') {
+ c = conv_translate_c_esc(&end);
+ if (c == -1) {
+ mf_fatal(mf, MSG_INTL(MSG_MAP_BADCESC), *end);
+ return (TK_ERROR);
+ }
+ }
+ *cur++ = c;
+ }
+ *cur = '\0'; /* terminate the result */
+ if (c != quote) {
+ ld_map_npatch_t np;
+
+ null_patch_eol(end, &np);
+ mf_fatal(mf, MSG_INTL(MSG_MAP_NOTERM), str);
+ null_patch_undo(&np);
+ return (TK_ERROR);
+ }
+
+ /* end is pointing one character past the closing quote */
+ mf->mf_next = end;
+ tkv->tkv_str = str + 1; /* Skip opening quote */
+ if (flags & TK_F_STRLC)
+ ld_map_lowercase(tkv->tkv_str);
+ return (TK_STRING);
+}
+
+/*
+ * Get a token from the mapfile.
+ *
+ * entry:
+ * mf - Mapfile descriptor
+ * flags - Bitmask of options to control ld_map_gettoken()s behavior
+ * tkv- Address of pointer to variable to receive token value.
+ *
+ * exit:
+ * Returns one of the TK_* values, to report the result. If the resulting
+ * token has a value (TK_STRING / TK_INT), and tkv is non-NULL, tkv
+ * is filled in with the resulting value.
+ */
+Token
+ld_map_gettoken(Mapfile *mf, int flags, ld_map_tkval_t *tkv)
+{
+ int cdir_allow, ch;
+ Token tok;
+ ld_map_npatch_t np;
+
+ /*
+ * Mapfile control directives all start with a '$' character. However,
+ * they are only valid when they are the first thing on a line. That
+ * happens on the first call to ld_map_gettoken() for a new a new
+ * mapfile, as tracked with lms.lms_cdir_valid, and immediately
+ * following each newline seen in the file.
+ */
+ cdir_allow = lms.lms_cdir_valid;
+ lms.lms_cdir_valid = 0;
+
+ /* Cycle through the characters looking for tokens. */
+ for (;;) {
+ /*
+ * Process the next character. This is normally *mf->mf_next,
+ * but if mf->mf_next_ch is non-0, then it contains the
+ * character, and *mf->mf_next contains a NULL termination
+ * from the TK_STRING token returned on the previous call.
+ *
+ * gettoken_ident() ensures that this is never done to
+ * a character that starts a string.
+ */
+ if (mf->mf_next_ch == 0) {
+ ch = *mf->mf_next;
+ } else {
+ ch = mf->mf_next_ch;
+ mf->mf_next_ch = 0; /* Reset */
+ }
+
+ /* Map the character to a dispatch action */
+ tok = (ch & 0x80) ? TK_OP_ILLCHR : mf->mf_tokdisp[ch];
+
+ /*
+ * Items that require processing are identified as OP tokens.
+ * We process them, and return a result non-OP token.
+ *
+ * Non-OP tokens are single character tokens, and we return
+ * them immediately.
+ */
+ switch (tok) {
+ case TK_OP_EOF:
+ /* If EOFOK is set, quietly report it as TK_EOF */
+ if ((flags & TK_F_EOFOK) != 0)
+ return (TK_EOF);
+
+ /* Treat it as a standard error */
+ mf_fatal0(mf, MSG_INTL(MSG_MAP_PREMEOF));
+ return (TK_ERROR);
+
+ case TK_OP_ILLCHR:
+ mf_fatal(mf, MSG_INTL(MSG_MAP_ILLCHAR), ch);
+ mf->mf_next++;
+ return (TK_ERROR);
+
+ case TK_OP_BADCHR:
+ tk_op_badchr:
+ null_patch_eol(mf->mf_next, &np);
+ mf_fatal(mf, MSG_INTL(MSG_MAP_BADCHAR), mf->mf_next);
+ null_patch_undo(&np);
+ mf->mf_next++;
+ return (TK_ERROR);
+
+ case TK_OP_WS: /* White space */
+ mf->mf_next++;
+ break;
+
+ case TK_OP_NL: /* White space too, but bump line number. */
+ mf->mf_next++;
+ mf->mf_lineno++;
+ cdir_allow = 1;
+ break;
+
+ case TK_OP_SIMQUOTE:
+ if (flags & TK_F_KEYWORD)
+ goto tk_op_badkwquote;
+ return (gettoken_simquote_str(mf, flags, tkv));
+
+ case TK_OP_CQUOTE:
+ if (flags & TK_F_KEYWORD) {
+ tk_op_badkwquote:
+ null_patch_eol(mf->mf_next, &np);
+ mf_fatal(mf, MSG_INTL(MSG_MAP_BADKWQUOTE),
+ mf->mf_next);
+ null_patch_undo(&np);
+ mf->mf_next++;
+ return (TK_ERROR);
+ }
+ return (gettoken_cquote_str(mf, flags, tkv));
+
+ case TK_OP_CMT:
+ advance_to_eol(&mf->mf_next);
+ break;
+
+ case TK_OP_CDIR:
+ /*
+ * Control directives are only valid at the start
+ * of a line.
+ */
+ if (!cdir_allow) {
+ null_patch_eol(mf->mf_next, &np);
+ mf_fatal(mf, MSG_INTL(MSG_MAP_CDIR_NOTBOL),
+ mf->mf_next);
+ null_patch_undo(&np);
+ mf->mf_next++;
+ return (TK_ERROR);
+ }
+ if (!cdir_process(mf))
+ return (TK_ERROR);
+ break;
+
+ case TK_OP_NUM: /* Decimal, hex(0x...), or octal (0...) value */
+ if (!ld_map_getint(mf, tkv, FALSE))
+ return (TK_ERROR);
+ return (TK_INT);
+
+ case TK_OP_ID: /* Unquoted identifier */
+ return (gettoken_ident(mf, flags, tkv));
+
+ case TK_OP_CEQUAL: /* += or -= */
+ if (*(mf->mf_next + 1) != '=')
+ goto tk_op_badchr;
+ tok = (ch == '+') ? TK_PLUSEQ : TK_MINUSEQ;
+ mf->mf_next += 2;
+ return (tok);
+
+ default: /* Non-OP token */
+ mf->mf_next++;
+ return (tok);
+ }
+ }
+
+ /*NOTREACHED*/
+ assert(0);
+ return (TK_ERROR);
+}
+
+/*
+ * Given a token and value returned by ld_map_gettoken(), return a string
+ * representation of it suitable for use in an error message.
+ *
+ * entry:
+ * tok - Token code. Must not be an OP-token
+ * tkv - Token value
+ */
+const char *
+ld_map_tokenstr(Token tok, ld_map_tkval_t *tkv, Conv_inv_buf_t *inv_buf)
+{
+ size_t cnt;
+
+ switch (tok) {
+ case TK_ERROR:
+ return (MSG_ORIG(MSG_STR_ERROR));
+ case TK_EOF:
+ return (MSG_ORIG(MSG_STR_EOF));
+ case TK_STRING:
+ return (tkv->tkv_str);
+ case TK_COLON:
+ return (MSG_ORIG(MSG_QSTR_COLON));
+ case TK_SEMICOLON:
+ return (MSG_ORIG(MSG_QSTR_SEMICOLON));
+ case TK_EQUAL:
+ return (MSG_ORIG(MSG_QSTR_EQUAL));
+ case TK_PLUSEQ:
+ return (MSG_ORIG(MSG_QSTR_PLUSEQ));
+ case TK_MINUSEQ:
+ return (MSG_ORIG(MSG_QSTR_MINUSEQ));
+ case TK_ATSIGN:
+ return (MSG_ORIG(MSG_QSTR_ATSIGN));
+ case TK_DASH:
+ return (MSG_ORIG(MSG_QSTR_DASH));
+ case TK_LEFTBKT:
+ return (MSG_ORIG(MSG_QSTR_LEFTBKT));
+ case TK_RIGHTBKT:
+ return (MSG_ORIG(MSG_QSTR_RIGHTBKT));
+ case TK_PIPE:
+ return (MSG_ORIG(MSG_QSTR_PIPE));
+ case TK_INT:
+ cnt = tkv->tkv_int.tkvi_cnt;
+ if (cnt >= sizeof (inv_buf->buf))
+ cnt = sizeof (inv_buf->buf) - 1;
+ (void) memcpy(inv_buf->buf, tkv->tkv_int.tkvi_str, cnt);
+ inv_buf->buf[cnt] = '\0';
+ return (inv_buf->buf);
+ case TK_STAR:
+ return (MSG_ORIG(MSG_QSTR_STAR));
+ case TK_BANG:
+ return (MSG_ORIG(MSG_QSTR_BANG));
+ default:
+ assert(0);
+ break;
+ }
+
+ /*NOTREACHED*/
+ return (MSG_INTL(MSG_MAP_INTERR));
+}
+
+/*
+ * Advance the input to the first non-empty line, and determine
+ * the mapfile version. The version is specified by the mapfile
+ * using a $mapfile_version directive. The original System V
+ * syntax lacks this directive, and we use that fact to identify
+ * such files. SysV mapfile are implicitly defined to have version 1.
+ *
+ * entry:
+ * ofl - Output file descriptor
+ * mf - Mapfile block
+ *
+ * exit:
+ * On success, updates mf->mf_version, and returns TRUE (1).
+ * On failure, returns FALSE (0).
+ */
+static Boolean
+mapfile_version(Mapfile *mf)
+{
+ char *line_start = mf->mf_next;
+ Boolean cont = TRUE;
+ Boolean status = TRUE; /* Assume success */
+ Token tok;
+
+ mf->mf_version = MFV_SYSV;
+
+ /*
+ * Cycle through the characters looking for tokens. Although the
+ * true version is not known yet, we use the v2 dispatch table.
+ * It contains control directives, which we need for this search,
+ * and the other TK_OP_ tokens we will recognize and act on are the
+ * same for both tables.
+ *
+ * It is important not to process any tokens that would lead to
+ * a non-OP token:
+ *
+ * - The version is required to interpret them
+ * - Our mapfile descriptor is not fully initialized,
+ * attempts to run that code will crash the program.
+ */
+ while (cont) {
+ /* Map the character to a dispatch action */
+ tok = (*mf->mf_next & 0x80) ?
+ TK_OP_ILLCHR : gettok_dispatch_v2[*mf->mf_next];
+
+ switch (tok) {
+ case TK_OP_WS: /* White space */
+ mf->mf_next++;
+ break;
+
+ case TK_OP_NL: /* White space too, but bump line number. */
+ mf->mf_next++;
+ mf->mf_lineno++;
+ break;
+
+ case TK_OP_CMT:
+ advance_to_eol(&mf->mf_next);
+ break;
+
+ case TK_OP_CDIR:
+ /*
+ * Control directives are only valid at the start
+ * of a line. However, as we have not yet seen
+ * a token, we do not need to test for this, and
+ * can safely assume that we are at the start.
+ */
+ if (!strncasecmp(mf->mf_next,
+ MSG_ORIG(MSG_STR_CDIR_MFVER),
+ MSG_STR_CDIR_MFVER_SIZE) &&
+ isspace_nonl(*(mf->mf_next +
+ MSG_STR_CDIR_MFVER_SIZE))) {
+ ld_map_tkval_t ver;
+
+ mf->mf_next += MSG_STR_CDIR_MFVER_SIZE + 1;
+ if (!ld_map_getint(mf, &ver, TRUE)) {
+ status = cont = FALSE;
+ break;
+ }
+ /*
+ * Is it a valid version? Note that we
+ * intentionally do not allow you to
+ * specify version 1 using the $mapfile_version
+ * syntax, because that's reserved to version
+ * 2 and up.
+ */
+ if ((ver.tkv_int.tkvi_value < 2) ||
+ (ver.tkv_int.tkvi_value >= MFV_NUM)) {
+ const char *fmt;
+
+ fmt = (ver.tkv_int.tkvi_value < 2) ?
+ MSG_INTL(MSG_MAP_CDIR_BADVDIR) :
+ MSG_INTL(MSG_MAP_CDIR_BADVER);
+ mf_fatal(mf, fmt,
+ EC_WORD(ver.tkv_int.tkvi_value));
+ status = cont = FALSE;
+ break;
+ }
+ mf->mf_version = ver.tkv_int.tkvi_value;
+ cont = FALSE; /* Version recovered. All done */
+ break;
+ }
+ /*
+ * Not a version directive. Reset the current position
+ * to the start of the current line and stop here.
+ * SysV syntax applies.
+ */
+ mf->mf_next = line_start;
+ cont = FALSE;
+ break;
+
+ default:
+ /*
+ * If we see anything else, then stop at this point.
+ * The file has System V syntax (version 1), and the
+ * next token should be interpreted as such.
+ */
+ cont = FALSE;
+ break;
+ }
+ }
+
+ return (status);
+}
+
+/*
+ * Parse the mapfile.
+ */
+Boolean
+ld_map_parse(const char *mapfile, Ofl_desc *ofl)
+{
+ struct stat stat_buf; /* stat of mapfile */
+ int mapfile_fd; /* descriptor for mapfile */
+ int err;
+ Mapfile *mf; /* Mapfile descriptor */
+ size_t name_len; /* strlen(mapfile) */
+
+ /*
+ * Determine if we're dealing with a file or a directory.
+ */
+ if (stat(mapfile, &stat_buf) == -1) {
+ err = errno;
+ eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_SYS_STAT),
+ mapfile, strerror(err));
+ return (FALSE);
+ }
+ if (S_ISDIR(stat_buf.st_mode)) {
+ DIR *dirp;
+ struct dirent *denp;
+
+ /*
+ * Open the directory and interpret each visible file as a
+ * mapfile.
+ */
+ if ((dirp = opendir(mapfile)) == NULL)
+ return (TRUE);
+
+ while ((denp = readdir(dirp)) != NULL) {
+ char path[PATH_MAX];
+
+ /*
+ * Ignore any hidden filenames. Construct the full
+ * pathname to the new mapfile.
+ */
+ if (*denp->d_name == '.')
+ continue;
+ (void) snprintf(path, PATH_MAX, MSG_ORIG(MSG_STR_PATH),
+ mapfile, denp->d_name);
+ if (!ld_map_parse(path, ofl))
+ return (FALSE);
+ }
+ (void) closedir(dirp);
+ return (TRUE);
+ } else if (!S_ISREG(stat_buf.st_mode)) {
+ eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_SYS_NOTREG),
+ mapfile);
+ return (FALSE);
+ }
+
+ /* Open file */
+ if ((mapfile_fd = open(mapfile, O_RDONLY)) == -1) {
+ err = errno;
+ eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN),
+ mapfile, strerror(err));
+ return (FALSE);
+ }
+
+ /*
+ * Allocate enough memory to hold the state block, mapfile name,
+ * and mapfile text. Text has alignment 1, so it can follow the
+ * state block without padding.
+ */
+ name_len = strlen(mapfile) + 1;
+ mf = libld_malloc(sizeof (*mf) + name_len + stat_buf.st_size + 1);
+ if (mf == NULL)
+ return (FALSE);
+ mf->mf_ofl = ofl;
+ mf->mf_name = (char *)(mf + 1);
+ (void) strcpy(mf->mf_name, mapfile);
+ mf->mf_text = mf->mf_name + name_len;
+ if (read(mapfile_fd, mf->mf_text, stat_buf.st_size) !=
+ stat_buf.st_size) {
+ err = errno;
+ eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_SYS_READ),
+ mapfile, strerror(err));
+ (void) close(mapfile_fd);
+ return (FALSE);
+ }
+ (void) close(mapfile_fd);
+ mf->mf_text[stat_buf.st_size] = '\0';
+ mf->mf_next = mf->mf_text;
+ mf->mf_lineno = 1;
+ mf->mf_next_ch = 0; /* No "lookahead" character yet */
+ mf->mf_ec_insndx = 0; /* Insert entrace criteria at top */
+
+ /*
+ * Read just enough from the mapfile to determine the version,
+ * and then dispatch to the appropriate code for further processing
+ */
+ if (!mapfile_version(mf))
+ return (FALSE);
+
+ /*
+ * Start and continuation masks for unquoted identifier at this
+ * mapfile version level.
+ */
+ mf->mf_tkid_start = TKID_ATTR_START(mf->mf_version);
+ mf->mf_tkid_cont = TKID_ATTR_CONT(mf->mf_version);
+
+ DBG_CALL(Dbg_map_parse(ofl->ofl_lml, mapfile, mf->mf_version));
+
+ switch (mf->mf_version) {
+ case MFV_SYSV:
+ mf->mf_tokdisp = gettok_dispatch_v1;
+ if (!ld_map_parse_v1(mf))
+ return (FALSE);
+ break;
+
+ case MFV_SOLARIS:
+ mf->mf_tokdisp = gettok_dispatch_v2;
+ STACK_RESET(lms.lms_cdir_stack);
+
+ /*
+ * If the conditional expression identifier tree has not been
+ * initialized, set it up. This is only done on the first
+ * mapfile, because the identifier control directives accumulate
+ * across all the mapfiles.
+ */
+ if ((lms.lms_cexp_id == NULL) && !cexp_ident_init())
+ return (FALSE);
+
+ /*
+ * Tell ld_map_gettoken() we will accept a '$' as starting a
+ * control directive on the first call. Normally, they are
+ * only allowed after a newline.
+ */
+ lms.lms_cdir_valid = 1;
+
+ if (!ld_map_parse_v2(mf))
+ return (FALSE);
+
+ /* Did we leave any open $if control directives? */
+ if (!STACK_IS_EMPTY(lms.lms_cdir_stack)) {
+ while (!STACK_IS_EMPTY(lms.lms_cdir_stack)) {
+ cdir_level_t *level =
+ &STACK_POP(lms.lms_cdir_stack);
+
+ mf_fatal(mf, MSG_INTL(MSG_MAP_CDIR_NOEND),
+ EC_LINENO(level->cdl_if_lineno));
+ }
+ return (FALSE);
+ }
+ break;
+ }
+
+ return (TRUE);
+}
+
+/*
+ * Sort the segment list. This is necessary if a mapfile has set explicit
+ * virtual addresses for segments, or defined a SEGMENT_ORDER directive.
+ *
+ * Only PT_LOAD segments can be assigned a virtual address. These segments can
+ * be one of two types:
+ *
+ * - Standard segments for text, data or bss. These segments will have been
+ * inserted before the default text (first PT_LOAD) segment.
+ *
+ * - Empty (reservation) segments. These segment will have been inserted at
+ * the end of any default PT_LOAD segments.
+ *
+ * Any standard segments that are assigned a virtual address will be sorted,
+ * and as their definitions precede any default PT_LOAD segments, these segments
+ * will be assigned sections before any defaults.
+ *
+ * Any reservation segments are also sorted amoung themselves, as these segments
+ * must still follow the standard default segments.
+ */
+static Boolean
+sort_seg_list(Ofl_desc *ofl)
+{
+ APlist *sort_segs = NULL, *load_segs = NULL;
+ Sg_desc *sgp1;
+ Aliste idx1;
+ Aliste nsegs;
+
+
+ /*
+ * We know the number of elements in the sorted list will be
+ * the same as the original, so use this as the initial allocation
+ * size for the replacement aplist.
+ */
+ nsegs = aplist_nitems(ofl->ofl_segs);
+
+
+ /* Add the items below SGID_TEXT to the list */
+ for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp1)) {
+ if (sgp1->sg_id >= SGID_TEXT)
+ break;
+
+ if (aplist_append(&sort_segs, sgp1, nsegs) == NULL)
+ return (FALSE);
+ }
+
+ /*
+ * If there are any SEGMENT_ORDER items, add them, and set their
+ * FLG_SG_ORDERED flag to identify them in debug output, and to
+ * prevent them from being added again below.
+ */
+ for (APLIST_TRAVERSE(ofl->ofl_segs_order, idx1, sgp1)) {
+ if (aplist_append(&sort_segs, sgp1, nsegs) == NULL)
+ return (FALSE);
+ sgp1->sg_flags |= FLG_SG_ORDERED;
+ }
+
+ /*
+ * Add the loadable segments to another list in sorted order.
+ */
+ DBG_CALL(Dbg_map_sort_title(ofl->ofl_lml, TRUE));
+ for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp1)) {
+ DBG_CALL(Dbg_map_sort_seg(ofl->ofl_lml, ELFOSABI_SOLARIS,
+ ld_targ.t_m.m_mach, sgp1));
+
+ /* Only interested in PT_LOAD items not in SEGMENT_ORDER list */
+ if ((sgp1->sg_phdr.p_type != PT_LOAD) ||
+ (sgp1->sg_flags & FLG_SG_ORDERED))
+ continue;
+
+ /*
+ * If the loadable segment does not contain a vaddr, simply
+ * append it to the new list.
+ */
+ if ((sgp1->sg_flags & FLG_SG_P_VADDR) == 0) {
+ if (aplist_append(&load_segs, sgp1, AL_CNT_SEGMENTS) ==
+ NULL)
+ return (FALSE);
+
+ } else {
+ Aliste idx2;
+ Sg_desc *sgp2;
+ int inserted = 0;
+
+ /*
+ * Traverse the segment list we are creating, looking
+ * for a segment that defines a vaddr.
+ */
+ for (APLIST_TRAVERSE(load_segs, idx2, sgp2)) {
+ /*
+ * Any real segments that contain vaddr's need
+ * to be sorted. Any reservation segments also
+ * need to be sorted. However, any reservation
+ * segments should be placed after any real
+ * segments.
+ */
+ if (((sgp2->sg_flags &
+ (FLG_SG_P_VADDR | FLG_SG_EMPTY)) == 0) &&
+ (sgp1->sg_flags & FLG_SG_EMPTY))
+ continue;
+
+ if ((sgp2->sg_flags & FLG_SG_P_VADDR) &&
+ ((sgp2->sg_flags & FLG_SG_EMPTY) ==
+ (sgp1->sg_flags & FLG_SG_EMPTY))) {
+ if (sgp1->sg_phdr.p_vaddr ==
+ sgp2->sg_phdr.p_vaddr) {
+ eprintf(ofl->ofl_lml, ERR_FATAL,
+ MSG_INTL(MSG_MAP_SEGSAME),
+ sgp1->sg_name,
+ sgp2->sg_name);
+ return (FALSE);
+ }
+
+ if (sgp1->sg_phdr.p_vaddr >
+ sgp2->sg_phdr.p_vaddr)
+ continue;
+ }
+
+ /*
+ * Insert this segment before the segment on
+ * the load_segs list.
+ */
+ if (aplist_insert(&load_segs, sgp1,
+ AL_CNT_SEGMENTS, idx2) == NULL)
+ return (FALSE);
+ inserted = 1;
+ break;
+ }
+
+ /*
+ * If the segment being inspected has not been inserted
+ * in the segment list, simply append it to the list.
+ */
+ if ((inserted == 0) && (aplist_append(&load_segs,
+ sgp1, AL_CNT_SEGMENTS) == NULL))
+ return (FALSE);
+ }
+ }
+
+ /*
+ * Add the sorted loadable segments to our initial segment list.
+ */
+ for (APLIST_TRAVERSE(load_segs, idx1, sgp1)) {
+ if (aplist_append(&sort_segs, sgp1, AL_CNT_SEGMENTS) == NULL)
+ return (FALSE);
+ }
+
+ /*
+ * Add all other segments to our list.
+ */
+ for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp1)) {
+ if ((sgp1->sg_id < SGID_TEXT) ||
+ (sgp1->sg_phdr.p_type == PT_LOAD) ||
+ (sgp1->sg_flags & FLG_SG_ORDERED))
+ continue;
+
+ if (aplist_append(&sort_segs, sgp1, AL_CNT_SEGMENTS) == NULL)
+ return (FALSE);
+ }
+
+ /*
+ * Free the original list, and the pt_load list, and use
+ * the new list as the segment list.
+ */
+ free(ofl->ofl_segs);
+ if (load_segs) free(load_segs);
+ ofl->ofl_segs = sort_segs;
+
+ if (DBG_ENABLED) {
+ Dbg_map_sort_title(ofl->ofl_lml, FALSE);
+ for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp1)) {
+ Dbg_map_sort_seg(ofl->ofl_lml, ELFOSABI_SOLARIS,
+ ld_targ.t_m.m_mach, sgp1);
+ }
+ }
+
+ return (TRUE);
+}
+
+/*
+ * After all mapfiles have been processed, this routine is used to
+ * finish any remaining mapfile related work.
+ *
+ * exit:
+ * Returns TRUE on success, and FALSE on failure.
+ */
+Boolean
+ld_map_post_process(Ofl_desc *ofl)
+{
+ Aliste idx, idx2;
+ Is_desc *isp;
+ Sg_desc *sgp;
+ Ent_desc *enp;
+ Sg_desc *first_seg = NULL;
+
+
+ DBG_CALL(Dbg_map_post_title(ofl->ofl_lml));
+
+ /*
+ * Per-segment processing:
+ * - Identify segments with explicit virtual address
+ * - Details of input and output section order
+ */
+ for (APLIST_TRAVERSE(ofl->ofl_segs, idx, sgp)) {
+ /*
+ * We are looking for segments. Program headers that represent
+ * segments are required to have a non-NULL name pointer,
+ * while that those that do not are required to have a
+ * NULL name pointer.
+ */
+ if (sgp->sg_name == NULL)
+ continue;
+
+ /* Remember the first non-disabled segment */
+ if ((first_seg == NULL) && !(sgp->sg_flags & FLG_SG_DISABLED))
+ first_seg = sgp;
+
+ /*
+ * If a segment has an explicit virtual address, we will
+ * need to sort the segments.
+ */
+ if (sgp->sg_flags & FLG_SG_P_VADDR)
+ ofl->ofl_flags1 |= FLG_OF1_VADDR;
+
+ /*
+ * The FLG_OF_OS_ORDER flag enables the code that does
+ * output section ordering. Set if the segment has
+ * a non-empty output section order list.
+ */
+ if (alist_nitems(sgp->sg_os_order) > 0)
+ ofl->ofl_flags |= FLG_OF_OS_ORDER;
+
+ /*
+ * The version 1 and version 2 syntaxes for input section
+ * ordering are different and incompatible enough that we
+ * only allow the use of one or the other for a given segment:
+ *
+ * v1) The version 1 syntax has the user set the ?O flag on
+ * the segment. If this is done, all input sections placed
+ * via an entrance criteria that has a section name are to
+ * be sorted, using the order of the entrance criteria
+ * as the sort key.
+ *
+ * v2) The version 2 syntax has the user specify a name for
+ * the entry criteria, and then provide a list of entry
+ * criteria names via the IS_ORDER segment attribute.
+ * Sections placed via the criteria listed in IS_ORDER
+ * are sorted, and the others are not.
+ *
+ * Regardless of the syntax version used, the section sorting
+ * code expects the following:
+ *
+ * - Segments requiring input section sorting have the
+ * FLG_SG_IS_ORDER flag set
+ *
+ * - Entrance criteria referencing the segment that
+ * participate in input section sorting have a non-zero
+ * sort key in their ec_ordndx field.
+ *
+ * At this point, the following are true:
+ *
+ * - All entrance criteria have ec_ordndx set to 0.
+ * - Segments that require the version 1 behavior have
+ * the FLG_SG_IS_ORDER flag set, and the segments
+ * sg_is_order list is empty.
+ * - Segments that require the version 2 behavior do not
+ * have FLG_SG_IS_ORDER set, and the sg_is_order list is
+ * non-empty. This list contains the names of the entrance
+ * criteria that will participate in input section sorting,
+ * and their relative order in the list provides the
+ * sort key to use.
+ *
+ * We must detect these two cases, set the FLG_SG_IS_ORDER
+ * flag as necessary, and fill in all entrance criteria
+ * sort keys. If any input section sorting is to be done,
+ * we also set the FLG_OF_IS_ORDER flag on the output descriptor
+ * to enable the code that does that work.
+ */
+
+ /* Version 1: ?O flag? */
+ if (sgp->sg_flags & FLG_SG_IS_ORDER) {
+ Word index = 0;
+
+ ofl->ofl_flags |= FLG_OF_IS_ORDER;
+ DBG_CALL(Dbg_map_ent_ord_title(ofl->ofl_lml,
+ sgp->sg_name));
+
+ /*
+ * Give each user defined entrance criteria for this
+ * segment that specifies a section name a
+ * monotonically increasing sort key.
+ */
+ for (APLIST_TRAVERSE(ofl->ofl_ents, idx2, enp))
+ if ((enp->ec_segment == sgp) &&
+ (enp->ec_is_name != NULL) &&
+ ((enp->ec_flags & FLG_EC_BUILTIN) == 0))
+ enp->ec_ordndx = ++index;
+ continue;
+ }
+
+ /* Version 2: SEGMENT IS_ORDER list? */
+ if (aplist_nitems(sgp->sg_is_order) > 0) {
+ Word index = 0;
+
+ ofl->ofl_flags |= FLG_OF_IS_ORDER;
+ DBG_CALL(Dbg_map_ent_ord_title(ofl->ofl_lml,
+ sgp->sg_name));
+
+ /*
+ * Give each entrance criteria in the sg_is_order
+ * list a monotonically increasing sort key.
+ */
+ for (APLIST_TRAVERSE(sgp->sg_is_order, idx2, enp)) {
+ enp->ec_ordndx = ++index;
+ enp->ec_segment->sg_flags |= FLG_SG_IS_ORDER;
+ }
+ }
+ }
+
+ /* Sort the segment descriptors if necessary */
+ if (((ofl->ofl_flags1 & FLG_OF1_VADDR) ||
+ (aplist_nitems(ofl->ofl_segs_order) > 0)) &&
+ !sort_seg_list(ofl))
+ return (FALSE);
+
+ /*
+ * If the output file is a static file without an interpreter, and
+ * if any virtual address is specified, then set the NOHDR flag for
+ * backward compatibility.
+ */
+ if (!(ofl->ofl_flags & (FLG_OF_DYNAMIC | FLG_OF_RELOBJ)) &&
+ !(ofl->ofl_osinterp) && (ofl->ofl_flags1 & FLG_OF1_VADDR))
+ ofl->ofl_dtflags_1 |= DF_1_NOHDR;
+
+ if (ofl->ofl_flags & FLG_OF_RELOBJ) {
+ /*
+ * NOHDR has no effect on a relocatable file.
+ * Make sure this flag isn't set.
+ */
+ ofl->ofl_dtflags_1 &= ~DF_1_NOHDR;
+ } else if (first_seg != NULL) {
+ /*
+ * DF_1_NOHDR might have been set globally by the HDR_NOALLOC
+ * directive. If not, then we want to check the per-segment
+ * flag for the first loadable segment and propagate it
+ * if set.
+ */
+ if ((ofl->ofl_dtflags_1 & DF_1_NOHDR) == 0) {
+ /*
+ * If we sorted the segments, the first segment
+ * may have changed.
+ */
+ if ((ofl->ofl_flags1 & FLG_OF1_VADDR) ||
+ (aplist_nitems(ofl->ofl_segs_order) > 0)) {
+ for (APLIST_TRAVERSE(ofl->ofl_segs, idx, sgp)) {
+ if (sgp->sg_name == NULL)
+ continue;
+ if ((sgp->sg_flags & FLG_SG_DISABLED) ==
+ 0) {
+ first_seg = sgp;
+ break;
+ }
+ }
+ }
+
+ /*
+ * If the per-segment NOHDR flag is set on our first
+ * segment, then make it take effect.
+ */
+ if (first_seg->sg_flags & FLG_SG_NOHDR)
+ ofl->ofl_dtflags_1 |= DF_1_NOHDR;
+ }
+
+ /*
+ * For executable and shared objects, the first segment must
+ * be loadable unless NOHDR was specified, because the ELF
+ * header must simultaneously lie at offset 0 of the file and
+ * be included in the first loadable segment. This isn't
+ * possible if some other segment type starts the file
+ */
+ if (!(ofl->ofl_dtflags_1 & DF_1_NOHDR) &&
+ (first_seg->sg_phdr.p_type != PT_LOAD)) {
+ Conv_inv_buf_t inv_buf;
+
+ eprintf(ofl->ofl_lml, ERR_FATAL,
+ MSG_INTL(MSG_SEG_FIRNOTLOAD),
+ conv_phdr_type(ELFOSABI_SOLARIS, ld_targ.t_m.m_mach,
+ first_seg->sg_phdr.p_type, 0, &inv_buf),
+ first_seg->sg_name);
+ return (FALSE);
+ }
+ }
+
+ /*
+ * Mapfiles may have been used to create symbol definitions
+ * with backing storage. Although the backing storage is
+ * associated with an input section, the association of the
+ * section to an output section (and segment) is initially
+ * deferred. Now that all mapfile processing is complete, any
+ * entrance criteria requirements have been processed, and
+ * these backing storage sections can be associated with the
+ * appropriate output section (and segment).
+ */
+ if (ofl->ofl_maptext || ofl->ofl_mapdata)
+ DBG_CALL(Dbg_sec_backing(ofl->ofl_lml));
+
+ for (APLIST_TRAVERSE(ofl->ofl_maptext, idx, isp)) {
+ if (ld_place_section(ofl, isp, NULL,
+ ld_targ.t_id.id_text, NULL) == (Os_desc *)S_ERROR)
+ return (FALSE);
+ }
+
+ for (APLIST_TRAVERSE(ofl->ofl_mapdata, idx, isp)) {
+ if (ld_place_section(ofl, isp, NULL,
+ ld_targ.t_id.id_data, NULL) == (Os_desc *)S_ERROR)
+ return (FALSE);
+ }
+
+ return (TRUE);
+}
diff --git a/usr/src/cmd/sgs/libld/common/map_support.c b/usr/src/cmd/sgs/libld/common/map_support.c
new file mode 100644
index 0000000000..2f812aaa7b
--- /dev/null
+++ b/usr/src/cmd/sgs/libld/common/map_support.c
@@ -0,0 +1,1488 @@
+/*
+ * 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 (c) 1988 AT&T
+ * All Rights Reserved
+ *
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Map file parsing (Shared Support Code).
+ */
+#include <stdio.h>
+#include <errno.h>
+#include "msg.h"
+#include "_libld.h"
+#include "_map.h"
+
+/*
+ * Given a NULL terminated array of structures of arbitrary type, where
+ * each struct contains (among other fields) a character pointer field
+ * giving that struct a unique name, return the address of the struct
+ * that matches the given name.
+ *
+ * entry:
+ * name - "Keyword" name to be found.
+ * array - Base address of array
+ * name_offset - Offset of the name field within the struct
+ * type used by this array, as generated via
+ * SGSOFFSETOF().
+ * elt_size - sizeof the basic array element type
+ *
+ * exit:
+ * Using a case insensitive comparison, name is compared to the
+ * name of each element of the array. The address of the first
+ * match found is returned. If the desired name is not found,
+ * NULL is returned.
+ *
+ * note:
+ * This routine is completely type-unsafe. The upside is that this
+ * single routine is able to search arrays of arbitrary type, leaving
+ * the caller free to structure their array in any way that is convenient
+ * to solve the problem at hand.
+ */
+#ifndef _ELF64
+void *
+ld_map_kwfind(const char *name, void *array, size_t name_offset,
+ size_t elt_size)
+{
+ for (; ; array = elt_size + (char *)array) {
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
+ const char *arr_name = *((const char **)
+ (name_offset + (const char *) array));
+
+ if (arr_name == NULL)
+ return (NULL);
+
+ if (strcasecmp(name, arr_name) == 0)
+ return (array);
+ }
+
+ /*NOTREACHED*/
+ assert(0);
+ return (NULL);
+}
+#endif
+
+/*
+ * Given the same NULL terminated array accepted by ld_map_kwfind(), format
+ * the strings into a comma separated list of names.
+ *
+ * entry:
+ * array - Base address of array
+ * name_offset - Offset of the name field within the struct
+ * type used by this array, as generated via
+ * SGSOFFSETOF().
+ * elt_size - sizeof the basic array element type
+ * buf - Buffer to receive output
+ * bufsize - sizeof(buf)
+ *
+ * exit:
+ * As many of the names as will fit are formatted into buf. If all the
+ * names do not fit, the remainder are quietly clipped. The caller must
+ * ensure that there is sufficient room. buf is returned, for convenience
+ * in using this function as an argument for printing.
+ */
+#ifndef _ELF64
+char *
+ld_map_kwnames(void *array, size_t name_offset, size_t elt_size, char *buf,
+ size_t bufsize)
+{
+ size_t cnt = 0;
+ size_t len;
+ char *str = buf;
+
+ for (; bufsize > 1; array = elt_size + (char *)array, cnt++) {
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
+ const char *arr_name = *((const char **)
+ (name_offset + (const char *) array));
+
+ if (arr_name == NULL)
+ break;
+
+ if (cnt > 0) {
+ if (bufsize < 3)
+ break;
+ *str++ = ',';
+ *str++ = ' ';
+ bufsize -= 2;
+ *(str + 1) = '\0';
+ }
+
+ len = strlcpy(str, arr_name, bufsize);
+ if (len >= bufsize)
+ break;
+ str += len;
+ bufsize -= len;
+ }
+
+ return (buf);
+}
+#endif
+
+/*
+ * Create a pseudo input file descriptor to represent the specified Mapfile.
+ * An input descriptor is required any time a symbol is generated.
+ *
+ * entry:
+ * mf - Mapfile descriptor.
+ *
+ * exit:
+ * If an input descriptor was already created for this mapfile
+ * by a previous call, it is returned. Otherwise, a new descriptor
+ * is created, entered into the mapfile descriptor, and returned.
+ *
+ * Success is indicated by a non-NULL return value, failure by NULL.
+ */
+Ifl_desc *
+ld_map_ifl(Mapfile *mf)
+{
+ Ifl_desc *ifl;
+
+ /*
+ * If we've already created a pseudo input descriptor for this
+ * mapfile, reuse it.
+ */
+ if (mf->mf_ifl != NULL)
+ return (mf->mf_ifl);
+
+ if ((ifl = libld_calloc(sizeof (Ifl_desc), 1)) == NULL)
+ return (NULL);
+ ifl->ifl_name = mf->mf_name;
+ ifl->ifl_flags = (FLG_IF_MAPFILE | FLG_IF_NEEDED | FLG_IF_FILEREF);
+ if ((ifl->ifl_ehdr = libld_calloc(sizeof (Ehdr), 1)) == NULL)
+ return (NULL);
+ ifl->ifl_ehdr->e_type = ET_REL;
+
+ if (aplist_append(&mf->mf_ofl->ofl_objs, ifl, AL_CNT_OFL_OBJS) == NULL)
+ return (NULL);
+
+ mf->mf_ifl = ifl;
+ return (mf->mf_ifl);
+}
+
+/*
+ * Given a capability tag type, set the override bit in the output descriptor.
+ * This prevents the use of capability values of that type from the input
+ * objects.
+ */
+void
+ld_map_cap_set_ovflag(Mapfile *mf, Word type)
+{
+ /*
+ * Map capability tag to the corresponding output descriptor
+ * override flag.
+ */
+ static ofl_flag_t override_flag[CA_SUNW_NUM] = {
+ 0, /* CA_SUNW_NULL */
+ FLG_OF1_OVHWCAP1, /* CA_SUNW_HW_1 */
+ FLG_OF1_OVSFCAP1, /* CA_SUNW_SF_1 */
+ FLG_OF1_OVHWCAP2 /* CA_SUNW_HW_2 */
+ };
+#if CA_SUNW_NUM != (CA_SUNW_HW_2 + 1)
+#error "CA_SUNW_NUM has grown"
+#endif
+
+ mf->mf_ofl->ofl_flags1 |= override_flag[type];
+}
+
+/*
+ * Sanity check the given capability bitmask.
+ */
+Boolean
+ld_map_cap_sanitize(Mapfile *mf, Word type, CapMask *capmask)
+{
+ elfcap_mask_t mask;
+
+ switch (type) {
+ case CA_SUNW_SF_1:
+ /*
+ * Unlike hardware capabilities, we do not allow setting
+ * software capability bits that do not have known definitions.
+ * Software capability tokens have to be validated as a unit
+ * as the bits can affect each others meaning (see sf1_cap()
+ * in files.c).
+ */
+ if ((mask = (capmask->cm_value & ~SF1_SUNW_MASK)) != 0) {
+ mf_warn(mf, MSG_INTL(MSG_MAP_BADSF1),
+ EC_XWORD(mask));
+ capmask->cm_value &= SF1_SUNW_MASK;
+ }
+ if ((capmask->cm_value &
+ (SF1_SUNW_FPKNWN | SF1_SUNW_FPUSED)) == SF1_SUNW_FPUSED) {
+ mf_warn(mf, MSG_INTL(MSG_MAP_BADSF1),
+ EC_XWORD(SF1_SUNW_FPUSED));
+ capmask->cm_value &= ~SF1_SUNW_FPUSED;
+ }
+#if !defined(_ELF64)
+ /*
+ * The SF1_SUNW_ADDR32 software capability is only meaningful
+ * when building a 64-bit object. Warn the user, and remove the
+ * setting, if we're building a 32-bit object.
+ */
+ if (capmask->cm_value & SF1_SUNW_ADDR32) {
+ mf_warn0(mf, MSG_INTL(MSG_MAP_INADDR32SF1));
+ capmask->cm_value &= ~SF1_SUNW_ADDR32;
+ }
+#endif
+ }
+
+ return (TRUE);
+}
+
+/*
+ * Return the shared object control definition structure (ofl_socntl)
+ * for the specified object, creating one if necessary.
+ *
+ * entry:
+ * mf - Mapfile descriptor
+ * obj_name - Name of object
+ *
+ * exit:
+ * Returns the pointer to the definition structure, or NULL on error.
+ */
+Sdf_desc *
+ld_map_dv(Mapfile *mf, const char *obj_name)
+{
+ Sdf_desc *sdf;
+
+ /*
+ * If a shared object definition for this file already exists use it,
+ * otherwise allocate a new descriptor.
+ */
+ if ((sdf = sdf_find(obj_name, mf->mf_ofl->ofl_socntl)) == NULL) {
+ if ((sdf = sdf_add(obj_name, &mf->mf_ofl->ofl_socntl)) ==
+ (Sdf_desc *)S_ERROR)
+ return (NULL);
+ sdf->sdf_rfile = mf->mf_name;
+ }
+
+ DBG_CALL(Dbg_map_dv(mf->mf_ofl->ofl_lml, sdf->sdf_name,
+ mf->mf_lineno));
+ return (sdf);
+}
+
+
+Boolean
+ld_map_dv_entry(Mapfile *mf, Sdf_desc *sdf, Boolean require,
+ const char *version)
+{
+ Sdv_desc sdv;
+
+ sdv.sdv_name = version;
+ sdv.sdv_ref = mf->mf_name;
+ sdv.sdv_flags = 0;
+
+
+ if (require) {
+ /*
+ * Add a VERNEED entry for the specified version
+ * from this object:
+ *
+ * MapfileVersion Syntax
+ * ----------------------------------------
+ * 1 obj - $ADDVERS=version;
+ * 2 DEPENDENCY obj { REQUIRE=version };
+ */
+ sdf->sdf_flags |= FLG_SDF_ADDVER;
+
+ if (alist_append(&sdf->sdf_verneed, &sdv, sizeof (Sdv_desc),
+ AL_CNT_SDF_VERSIONS) == NULL)
+ return (FALSE);
+ } else { /* Allow */
+ /*
+ * Allow linking to symbols found in this version, or
+ * from the versions it inherits from.
+ *
+ * MapfileVersion Syntax
+ * ----------------------------------------
+ * 1 obj - version;
+ * 2 DEPENDENCY obj { ALLOW=version };
+ */
+ sdf->sdf_flags |= FLG_SDF_SELECT;
+
+ if (alist_append(&sdf->sdf_vers, &sdv, sizeof (Sdv_desc),
+ AL_CNT_SDF_VERSIONS) == NULL)
+ return (FALSE);
+ }
+
+ DBG_CALL(Dbg_map_dv_entry(mf->mf_ofl->ofl_lml, mf->mf_lineno,
+ require, version));
+
+ return (TRUE);
+}
+
+/*
+ * Given a segment descriptor, return its index.
+ *
+ * entry:
+ * mf - Mapfile descriptor
+ * sgp - Segment for which index is desired
+ *
+ * exit:
+ * Index of segment is returned.
+ */
+Xword
+ld_map_seg_index(Mapfile *mf, Sg_desc *sgp)
+{
+ Aliste idx;
+ Sg_desc *sgp2;
+ Ofl_desc *ofl = mf->mf_ofl;
+
+ for (APLIST_TRAVERSE(ofl->ofl_segs, idx, sgp2))
+ if (sgp == sgp2)
+ break;
+
+ return (idx);
+}
+
+/*
+ * Add a section name to the output section sort list for the given
+ * segment.
+ *
+ * entry:
+ * mf - Mapfile descriptor
+ * sgp - Segment in question
+ * sec_name - Name of section to be added.
+ *
+ * exit:
+ * Returns TRUE for success, FALSE for failure.
+ */
+Boolean
+ld_map_seg_os_order_add(Mapfile *mf, Sg_desc *sgp, const char *sec_name)
+{
+ Aliste idx;
+ Sec_order *scop;
+
+ /*
+ * Make sure it's not already on the list
+ */
+ for (ALIST_TRAVERSE(sgp->sg_os_order, idx, scop))
+ if (strcmp(scop->sco_secname, sec_name) == 0) {
+ mf_fatal(mf, MSG_INTL(MSG_MAP_DUP_OS_ORD), sec_name);
+ return (FALSE);
+ }
+
+
+ scop = alist_append(&sgp->sg_os_order, NULL, sizeof (Sec_order),
+ AL_CNT_SG_SECORDER);
+ if (scop == NULL)
+ return (FALSE);
+
+ scop->sco_secname = sec_name;
+
+ DBG_CALL(Dbg_map_seg_os_order(mf->mf_ofl->ofl_lml, sgp, sec_name,
+ alist_nitems(sgp->sg_os_order), mf->mf_lineno));
+
+ /*
+ * Output section ordering is a relatively expensive operation,
+ * and one that is generally not used. In order to avoid needless
+ * work, the FLG_OF_OS_ORDER must be set when it will be needed.
+ * The section we just added needs this flag to be set. However,
+ * it is possible that a subsequent mapfile directive may come
+ * along and clear the order list, making it unnecessary.
+ *
+ * Instead of setting it here, we do a final pass over the segments
+ * in ld_map_finalize() and set it there if a segment with sorting
+ * requirements is seen.
+ */
+
+ return (TRUE);
+}
+
+/*
+ * Add a size symbol to a segment
+ *
+ * entry:
+ * mf - Mapfile descriptor
+ * sgp - Segment descriptor
+ * eq_tol - Type of assignment: TK_EQUAL, or TK_PLUSEQ
+ * symname - Name of symbol. Must be in stable static storage
+ * that can be retained.
+ *
+ * exit:
+ * On success, the symbol has been added and TRUE is returned.
+ * Otherwise an error is reported and FALSE is returned.
+ */
+Boolean
+ld_map_seg_size_symbol(Mapfile *mf, Sg_desc *sgp, Token eq_tok,
+ const char *symname)
+{
+ Sym *sym; /* New symbol pointer */
+ Sym_desc *sdp; /* New symbol node pointer */
+ Ifl_desc *ifl; /* Dummy input file structure */
+ avl_index_t where;
+ Ofl_desc *ofl = mf->mf_ofl;
+
+ /*
+ * We don't allow resetting the list of size symbols, so if the
+ * operator is TK_EQUAL and the list is not empty, issue an error.
+ *
+ * If we want to lift this restriction, we would have to save the
+ * size symbols and enter them from ld_map_post_process(). Doing that
+ * well would require a significant overhead in saved error reporting
+ * state, and interactions with the same symbols created by symbol
+ * directives. As size symbols are of little practical use, and are
+ * maintained primarily for backward compatibility with SysV, we have
+ * decided not to do that, but to create the symbols as the mapfiles
+ * are processed, and to disallow later attempts to remove them.
+ */
+ if ((eq_tok == TK_EQUAL) && (aplist_nitems(sgp->sg_sizesym) > 0)) {
+ mf_fatal(mf, MSG_INTL(MSG_MAP_SEGSIZE), sgp->sg_name);
+ return (FALSE);
+ }
+
+ /*
+ * Make sure we have a pseudo file descriptor to associate to the
+ * symbol.
+ */
+ if ((ifl = ld_map_ifl(mf)) == NULL)
+ return (FALSE);
+
+ /*
+ * Make sure the symbol doesn't already exist. It is possible that the
+ * symbol has been scoped or versioned, in which case it does exist
+ * but we can freely update it here.
+ */
+ if ((sdp = ld_sym_find(symname, SYM_NOHASH, &where, ofl)) == NULL) {
+ Word hval;
+
+ if ((sym = libld_calloc(sizeof (Sym), 1)) == NULL)
+ return (FALSE);
+ sym->st_shndx = SHN_ABS;
+ sym->st_size = 0;
+ sym->st_info = ELF_ST_INFO(STB_GLOBAL, STT_OBJECT);
+
+ DBG_CALL(Dbg_map_size_new(ofl->ofl_lml, symname,
+ sgp->sg_name, mf->mf_lineno));
+ /* LINTED */
+ hval = (Word)elf_hash(symname);
+ if ((sdp = ld_sym_enter(symname, sym, hval, ifl, ofl, 0,
+ SHN_ABS, (FLG_SY_SPECSEC | FLG_SY_GLOBREF), &where)) ==
+ (Sym_desc *)S_ERROR)
+ return (FALSE);
+ sdp->sd_flags &= ~FLG_SY_CLEAN;
+ DBG_CALL(Dbg_map_symbol(ofl, sdp));
+ } else {
+ sym = sdp->sd_sym;
+
+ if (sym->st_shndx == SHN_UNDEF) {
+ sdp->sd_shndx = sym->st_shndx = SHN_ABS;
+ sdp->sd_flags |= FLG_SY_SPECSEC;
+ sym->st_size = 0;
+ sym->st_info = ELF_ST_INFO(STB_GLOBAL, STT_OBJECT);
+
+ sdp->sd_flags &= ~FLG_SY_MAPREF;
+
+ DBG_CALL(Dbg_map_size_old(ofl, sdp,
+ sgp->sg_name, mf->mf_lineno));
+ } else {
+ mf_fatal(mf, MSG_INTL(MSG_MAP_SYMDEF1),
+ demangle(sdp->sd_name), sdp->sd_file->ifl_name,
+ MSG_INTL(MSG_MAP_DIFF_SYMMUL));
+ return (FALSE);
+ }
+ }
+
+ /*
+ * Assign the symbol to the segment.
+ */
+ if (aplist_append(&sgp->sg_sizesym, sdp, AL_CNT_SG_SIZESYM) == NULL)
+ return (FALSE);
+
+ return (TRUE);
+}
+
+/*
+ * Allocate a zeroed segment descriptor.
+ *
+ * exit:
+ * Returns pointer to the descriptor on success, NULL on failure.
+ * The contents of the returned descriptor have been zeroed.
+ * The returned descriptor is not added to the segment list
+ * (ofl_segs). That is done using ld_map_seg_insert().
+ */
+Sg_desc *
+ld_map_seg_alloc(const char *name, Word p_type, sg_flags_t sg_flags)
+{
+ Sg_desc *sgp;
+
+ if ((sgp = libld_calloc(sizeof (Sg_desc), 1)) == NULL)
+ return (NULL);
+ sgp->sg_phdr.p_type = p_type;
+ sgp->sg_name = name;
+ sgp->sg_flags = sg_flags;
+
+ return (sgp);
+}
+
+/*
+ * Return the PT_SUNWSTACK segment descriptor from the ofl_segs list.
+ * This segment is part of the default set and cannot be removed, so
+ * this routine will always succeed.
+ *
+ * exit:
+ * The descriptor is located, a DBG_STATE_MOD_BEFORE debug
+ * message issued, the FLG_SG_DISABLED flag is cleared, and the
+ * descriptor pointer returned.
+ */
+Sg_desc *
+ld_map_seg_stack(Mapfile *mf)
+{
+ Ofl_desc *ofl = mf->mf_ofl;
+ Sg_desc *sgp;
+ Aliste idx;
+
+ /*
+ * The stack is established by exec(), using the executable's program
+ * headers, before any sharable objects are loaded. If there is a
+ * PT_SUNWSTACK program header, exec() will act on it. As such, stack
+ * program headers are normally only applicable to executables.
+ *
+ * However, ELF allows a sharable object with an interpreter to
+ * be executed directly, and in this extremely rare case, the
+ * PT_SUNWSTACK program header would have meaning. Rather than
+ * second guess user intent, we simply create it on demand for any
+ * dynamic object, trusting that the user has a good reason for it.
+ */
+ for (APLIST_TRAVERSE(ofl->ofl_segs, idx, sgp))
+ if (sgp->sg_phdr.p_type == PT_SUNWSTACK) {
+ DBG_CALL(Dbg_map_seg(mf->mf_ofl, DBG_STATE_MOD_BEFORE,
+ idx, sgp, mf->mf_lineno));
+ sgp->sg_flags &= ~FLG_SG_DISABLED;
+ return (sgp);
+ }
+
+ /*NOTREACHED*/
+ return (NULL);
+}
+
+/*
+ * Finish the initialization of a new segment descriptor allocated by
+ * ld_map_seg_alloc(), and enter it into the segment list.
+ *
+ * entry:
+ * mf - Mapfile descriptor
+ * seg_type - One of DBG_SEG_NEW or DBG_SEG_NEW_IMPLICIT
+ * ins_head - If TRUE, the new segment goes at the front of
+ * others of its type. If FALSE, it goes at the end.
+ * sgp - Segment descriptor to enter.
+ * where - Insertion point, initialized by a previous (failed) call to
+ * ld_seg_lookup(). Ignored if the segment has a NULL sg_name.
+ *
+ * exit:
+ * On success, returns SEG_INS_OK. A non-fatal error is indicated with
+ * a return value of SEG_INS_SKIP, in which case the descriptor is
+ * not entered, but the user is expected to discard it and continue
+ * running. On failure, returns SEG_INS_FAIL.
+ *
+ * note:
+ * This routine will modify the contents of the descriptor referenced
+ * by sgp_tmpl before allocating the new descriptor. The caller must
+ * not expect it to be unmodified.
+ */
+ld_map_seg_ins_t
+ld_map_seg_insert(Mapfile *mf, dbg_state_t dbg_state, Sg_desc *sgp,
+ avl_index_t where)
+{
+ Ofl_desc *ofl = mf->mf_ofl;
+ Aliste idx;
+ Sg_desc *sgp2; /* temp segment descriptor pointer */
+ int ins_head;
+ Xword sg_ndx;
+
+ /*
+ * If specific fields have not been supplied via
+ * map_equal(), make sure defaults are supplied.
+ */
+ if (((sgp->sg_flags & FLG_SG_P_TYPE) == 0) &&
+ (sgp->sg_phdr.p_type == PT_NULL)) {
+ /*
+ * Default to a loadable segment.
+ */
+ sgp->sg_phdr.p_type = PT_LOAD;
+ sgp->sg_flags |= FLG_SG_P_TYPE;
+ }
+ if (sgp->sg_phdr.p_type == PT_LOAD) {
+ if ((sgp->sg_flags & FLG_SG_P_FLAGS) == 0) {
+ /*
+ * Default to read/write and execute.
+ */
+ sgp->sg_phdr.p_flags = PF_R + PF_W + PF_X;
+ sgp->sg_flags |= FLG_SG_P_FLAGS;
+ }
+ if ((sgp->sg_flags & FLG_SG_P_ALIGN) == 0) {
+ /*
+ * Default to segment alignment
+ */
+ sgp->sg_phdr.p_align = ld_targ.t_m.m_segm_align;
+ sgp->sg_flags |= FLG_SG_P_ALIGN;
+ }
+ }
+
+ /*
+ * Determine where the new item should be inserted in
+ * the segment descriptor list.
+ */
+ switch (sgp->sg_phdr.p_type) {
+ case PT_LOAD:
+ if (sgp->sg_flags & FLG_SG_EMPTY)
+ sgp->sg_id = SGID_TEXT_EMPTY;
+ else
+ sgp->sg_id = SGID_TEXT;
+ break;
+ case PT_NULL:
+ if (sgp->sg_flags & FLG_SG_EMPTY)
+ sgp->sg_id = SGID_NULL_EMPTY;
+ else
+ sgp->sg_id = SGID_NULL;
+ break;
+ case PT_NOTE:
+ sgp->sg_id = SGID_NOTE;
+ break;
+ default:
+ mf_fatal(mf, MSG_INTL(MSG_MAP_UNKSEGTYP),
+ EC_WORD(sgp->sg_phdr.p_type));
+ return (SEG_INS_FAIL);
+ }
+
+ /*
+ * Add the descriptor to the segment list. In the v1 syntax,
+ * new sections are added at the head of their type, while in
+ * the newer syntax, they go at the end of their type.
+ */
+ sg_ndx = 0;
+ ins_head = (mf->mf_version == MFV_SYSV);
+ for (APLIST_TRAVERSE(ofl->ofl_segs, idx, sgp2)) {
+ if (ins_head) { /* Insert before the others of its type */
+ if (sgp->sg_id > sgp2->sg_id) {
+ sg_ndx++;
+ continue;
+ }
+ } else { /* Insert after the others of its type */
+ if (sgp->sg_id >= sgp2->sg_id) {
+ sg_ndx++;
+ continue;
+ }
+ }
+ break;
+ }
+ if (aplist_insert(&ofl->ofl_segs, sgp, AL_CNT_SEGMENTS, idx) == NULL)
+ return (SEG_INS_FAIL);
+ if (sgp->sg_name != NULL)
+ avl_insert(&ofl->ofl_segs_avl, sgp, where);
+
+ DBG_CALL(Dbg_map_seg(ofl, dbg_state, sg_ndx, sgp, mf->mf_lineno));
+ return (SEG_INS_OK);
+}
+
+/*
+ * Add an entrance criteria record for the specified segment
+ *
+ * entry:
+ * mf - Mapfile descriptor
+ * sgp - Segment for which a new entrance criteria record is needed
+ * name - NULL, or name by which the entrance criteria can be referenced.
+ *
+ * exit:
+ * On success, a pointer to the new entrace criteria record is
+ * returned, the contents of which have been zeroed. On failure,
+ * NULL is returned.
+ */
+Ent_desc *
+ld_map_seg_ent_add(Mapfile *mf, Sg_desc *sgp, const char *name)
+{
+ Ent_desc *enp;
+ avl_index_t where;
+ Ofl_desc *ofl = mf->mf_ofl;
+
+ if ((name != NULL) &&
+ (ld_ent_lookup(mf->mf_ofl, name, &where) != NULL)) {
+ mf_fatal(mf, MSG_INTL(MSG_MAP_DUPNAMENT), name);
+ return (NULL);
+ }
+
+ /* Allocate and initialize the entrace criteria descriptor */
+ if ((enp = libld_calloc(1, sizeof (*enp))) == NULL)
+ return (NULL);
+ enp->ec_name = name;
+ enp->ec_segment = sgp; /* Tie criteria to segment */
+
+
+ /*
+ * Insert into the APlist. The mf_ec_insndx field for each mapfile
+ * starts at 0, and is incremented with each insertion. This means
+ * that the entrance criteria for each mapfile go to the head of
+ * the list, but that within a single mapfile, they are inserted in
+ * the order they are seen.
+ */
+ if (aplist_insert(&ofl->ofl_ents, enp, AL_CNT_OFL_ENTRANCE,
+ mf->mf_ec_insndx) == NULL)
+ return (NULL);
+ mf->mf_ec_insndx++;
+
+ /*
+ * If the entrance criteria is named insert it into the AVL tree
+ * as well. This provides O(logN) lookups by name.
+ */
+ if (name != NULL)
+ avl_insert(&ofl->ofl_ents_avl, enp, where);
+
+ return (enp);
+}
+
+Boolean
+ld_map_seg_ent_files(Mapfile *mf, Ent_desc *enp, Word ecf_type, const char *str)
+{
+ Ent_desc_file edf;
+
+ /*
+ * The v1 sysv syntax can let an empty string get in, consisting of
+ * just a '*' where the '*' is interpreted as 'basename'.
+ */
+ if (str[0] == '\0') {
+ mf_fatal0(mf, MSG_INTL(MSG_MAP_MALFORM));
+ return (FALSE);
+ }
+
+ /* Basename or objname string must not contain a path separator (/) */
+ if ((ecf_type != TYP_ECF_PATH) && (strchr(str, '/') != NULL)) {
+ const char *msg = (ecf_type == TYP_ECF_BASENAME) ?
+ MSG_INTL(MSG_MAP_BADBNAME) : MSG_INTL(MSG_MAP_BADONAME);
+
+ mf_fatal(mf, msg, str);
+ return (FALSE);
+ }
+
+ edf.edf_flags = ecf_type;
+ edf.edf_name = str;
+ edf.edf_name_len = strlen(edf.edf_name);
+
+ /* Does it have an archive member suffix? */
+ if ((edf.edf_name[edf.edf_name_len - 1] == ')') &&
+ (strrchr(edf.edf_name, '(') != NULL))
+ edf.edf_flags |= FLG_ECF_ARMEMBER;
+
+ if (alist_append(&enp->ec_files, &edf, sizeof (edf),
+ AL_CNT_EC_FILES) == NULL)
+ return (FALSE);
+
+ /*
+ * Note that an entrance criteria requiring file name matching exists
+ * in the system. This is used by ld_place_path_info_init() to
+ * skip Place_pathinfo initialization in cases where there are
+ * no entrance criteria that will use the results.
+ */
+ mf->mf_ofl->ofl_flags |= FLG_OF_EC_FILES;
+
+ return (TRUE);
+}
+
+/*
+ * Prepare an ld_map_ver_t structure for a new mapfile defined version.
+ *
+ * exit:
+ * Returns TRUE for success, FALSE for failure.
+ */
+Boolean
+ld_map_sym_ver_init(Mapfile *mf, char *name, ld_map_ver_t *mv)
+{
+ Word hash;
+ Ofl_desc *ofl = mf->mf_ofl;
+
+ mv->mv_name = name;
+ mv->mv_scope = FLG_SCOPE_DFLT;
+ mv->mv_errcnt = 0;
+
+ /*
+ * If we're generating segments within the image then any symbol
+ * reductions will be processed (ie. applied to relocations and symbol
+ * table entries). Otherwise (when creating a relocatable object) any
+ * versioning information is simply recorded for use in a later
+ * (segment generating) link-edit.
+ */
+ if (ofl->ofl_flags & FLG_OF_RELOBJ)
+ ofl->ofl_flags |= FLG_OF_VERDEF;
+
+ /*
+ * If no version descriptors have yet been set up, initialize a base
+ * version to represent the output file itself. This `base' version
+ * catches any internally generated symbols (_end, _etext, etc.) and
+ * serves to initialize the output version descriptor count.
+ */
+ if (ofl->ofl_vercnt == 0) {
+ if (ld_vers_base(ofl) == (Ver_desc *)S_ERROR)
+ return (FALSE);
+ }
+
+ /*
+ * If this definition has an associated version name then generate a
+ * new version descriptor and an associated version symbol index table.
+ */
+ if (name) {
+ ofl->ofl_flags |= FLG_OF_VERDEF;
+
+ /*
+ * Traverse the present version descriptor list to see if there
+ * is already one of the same name, otherwise create a new one.
+ */
+ /* LINTED */
+ hash = (Word)elf_hash(name);
+ if (((mv->mv_vdp = ld_vers_find(name, hash,
+ ofl->ofl_verdesc)) == NULL) &&
+ ((mv->mv_vdp = ld_vers_desc(name, hash,
+ &ofl->ofl_verdesc)) == (Ver_desc *)S_ERROR))
+ return (FALSE);
+
+ /*
+ * Initialize any new version with an index, the file from
+ * which it was first referenced, and a WEAK flag (indicates
+ * that there are no symbols assigned to it yet).
+ */
+ if (mv->mv_vdp->vd_ndx == 0) {
+ /* LINTED */
+ mv->mv_vdp->vd_ndx = (Half)++ofl->ofl_vercnt;
+ mv->mv_vdp->vd_file = ld_map_ifl(mf);
+ mv->mv_vdp->vd_flags = VER_FLG_WEAK;
+ }
+ } else {
+ /*
+ * If a version definition hasn't been specified assign any
+ * symbols to the base version.
+ */
+ mv->mv_vdp = (Ver_desc *)ofl->ofl_verdesc->apl_data[0];
+ }
+
+ return (TRUE);
+}
+
+/*
+ * Change the current scope for the given version.
+ *
+ * entry:
+ * mf - Mapfile descriptor
+ * scope_name - Name for new scope
+ * mv - Information related to version being defined
+ *
+ * exit:
+ * On success, mv is updated to change the current scope.
+ * On failure, mv->errcnt is incremented, and mv is otherwise unaltered.
+ */
+void
+ld_map_sym_scope(Mapfile *mf, const char *scope_name, ld_map_ver_t *mv)
+{
+ typedef struct {
+ const char *name; /* scope keyword string */
+ ld_map_scope_t type; /* Resulting type */
+ ofl_flag_t ofl_flags; /* 0, or ofl flags to add */
+ } scope_t;
+
+ /*
+ * Valid symbol scope keywords
+ *
+ * All symbols added by a mapfile are actually global entries, and
+ * are assigned the scope that is presently in effect.
+ *
+ * If a protected/symbolic scope is detected, remember this. If
+ * a protected/symbolic scope is the only scope defined in this
+ * (or any other mapfiles), then the mode -Bsymbolic is established.
+ */
+ static scope_t scope_list[] = {
+ { MSG_ORIG(MSG_MAPKW_DEFAULT), FLG_SCOPE_DFLT, FLG_OF_MAPGLOB },
+ { MSG_ORIG(MSG_MAPKW_ELIMINATE), FLG_SCOPE_ELIM, 0 },
+ { MSG_ORIG(MSG_MAPKW_EXPORTED), FLG_SCOPE_EXPT, 0 },
+ { MSG_ORIG(MSG_MAPKW_HIDDEN), FLG_SCOPE_HIDD, 0 },
+ { MSG_ORIG(MSG_MAPKW_GLOBAL), FLG_SCOPE_DFLT, FLG_OF_MAPGLOB },
+ { MSG_ORIG(MSG_MAPKW_LOCAL), FLG_SCOPE_HIDD, 0 },
+ { MSG_ORIG(MSG_MAPKW_PROTECTED),
+ FLG_SCOPE_PROT, FLG_OF_MAPSYMB },
+ { MSG_ORIG(MSG_MAPKW_SINGLETON),
+ FLG_SCOPE_SNGL, FLG_OF_MAPGLOB },
+ { MSG_ORIG(MSG_MAPKW_SYMBOLIC),
+ FLG_SCOPE_PROT, FLG_OF_MAPSYMB },
+
+ /* List must be null terminated */
+ { 0 }
+ };
+
+ /*
+ * Size of buffer needed to format the names in scope_list[]. Must
+ * be kept in sync with scope_list.
+ */
+ static size_t scope_list_bufsize =
+ KW_NAME_SIZE(MSG_MAPKW_DEFAULT) +
+ KW_NAME_SIZE(MSG_MAPKW_ELIMINATE) +
+ KW_NAME_SIZE(MSG_MAPKW_EXPORTED) +
+ KW_NAME_SIZE(MSG_MAPKW_HIDDEN) +
+ KW_NAME_SIZE(MSG_MAPKW_GLOBAL) +
+ KW_NAME_SIZE(MSG_MAPKW_LOCAL) +
+ KW_NAME_SIZE(MSG_MAPKW_PROTECTED) +
+ KW_NAME_SIZE(MSG_MAPKW_SINGLETON) +
+ KW_NAME_SIZE(MSG_MAPKW_SYMBOLIC);
+
+ scope_t *scope;
+
+ scope = ld_map_kwfind(scope_name, scope_list,
+ SGSOFFSETOF(scope_t, name), sizeof (scope_list[0]));
+ if (scope == NULL) {
+ char buf[scope_list_bufsize];
+
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SYMSCOPE),
+ ld_map_kwnames(scope_list, SGSOFFSETOF(scope_t, name),
+ sizeof (scope[0]), buf, scope_list_bufsize), scope_name);
+ mv->mv_errcnt++;
+ return;
+ }
+
+ mv->mv_scope = scope->type;
+ mf->mf_ofl->ofl_flags |= scope->ofl_flags;
+}
+
+/*
+ * Process the special auto-reduction directive ('*'). It can be specified
+ * in hidden/local, and eliminate scope. This directive indicates that all
+ * symbols processed that are not explicitly defined to be global are to be
+ * reduced to hidden/local scope in, or eliminated from, the output image.
+ *
+ * An auto-reduction directive also implies that a version definition must
+ * be created, as the user has effectively defined an interface.
+ */
+void
+ld_map_sym_autoreduce(Mapfile *mf, ld_map_ver_t *mv)
+{
+ switch (mv->mv_scope) {
+ case FLG_SCOPE_HIDD:
+ mf->mf_ofl->ofl_flags |= (FLG_OF_VERDEF | FLG_OF_AUTOLCL);
+ break;
+ case FLG_SCOPE_ELIM:
+ mf->mf_ofl->ofl_flags |= (FLG_OF_VERDEF | FLG_OF_AUTOELM);
+ break;
+ default:
+ /*
+ * Auto reduction has been applied to a scope that doesn't
+ * support it. This should be a fatal error, but we limit
+ * it to a warning for version 1 mapfiles. For years, we
+ * quietly ignored this case, so there may be mapfiles in
+ * production use that we do not wish to break.
+ */
+ if (mf->mf_version == 1) {
+ mf_warn0(mf, MSG_INTL(MSG_MAP_BADAUTORED));
+ } else {
+ mf_fatal0(mf, MSG_INTL(MSG_MAP_BADAUTORED));
+ mv->mv_errcnt++;
+ }
+ }
+}
+
+/*
+ * Add a standard or auxiliary filter to the given symbol
+ *
+ * entry:
+ * mf - Mapfile descriptor
+ * mv - Information related to version being defined
+ * ms - Information related to symbol being defined
+ * dft_flag - One of FLG_SY_STDFLTR or FLG_SY_AUXFLTR,
+ * specifying the type of filter.
+ * filtee - String giving filtee to be added
+ *
+ * exit:
+ * On success, the filtee is added. On failure, mv->errcnt is
+ * incremented, and mv/ms are otherwise unaltered.
+ */
+void
+ld_map_sym_filtee(Mapfile *mf, ld_map_ver_t *mv, ld_map_sym_t *ms,
+ Word dft_flag, const char *filtee)
+{
+ /*
+ * A given symbol can only be tied to a single filter, be it
+ * a standard filter, or auxiliary.
+ */
+ if (ms->ms_filtee) {
+ mf_fatal0(mf, MSG_INTL(MSG_MAP_MULTFILTEE));
+ mv->mv_errcnt++;
+ return;
+ }
+
+ /* Symbol filtering is only for sharable objects */
+ if (!(mf->mf_ofl->ofl_flags & FLG_OF_SHAROBJ)) {
+ mf_fatal0(mf, MSG_INTL(MSG_MAP_FLTR_ONLYAVL));
+ mv->mv_errcnt++;
+ return;
+ }
+
+ ms->ms_filtee = filtee;
+ ms->ms_dft_flag = dft_flag;
+ ms->ms_sdflags |= dft_flag;
+ mf->mf_ofl->ofl_flags |= FLG_OF_SYMINFO;
+}
+
+/*
+ * Enter a mapfile defined symbol into the given version
+ *
+ * entry:
+ * mf - Mapfile descriptor
+ * ms - Information related to symbol being added to version
+ *
+ * exit:
+ * On success, returns TRUE. On failure that requires an immediate
+ * halt, returns FALSE.
+ *
+ * On failure that requires eventual halt, but for which it would
+ * be OK to continue parsing in hopes of flushing out additional
+ * problems, increments mv->mv_errcnt, and returns TRUE.
+ */
+Boolean
+ld_map_sym_enter(Mapfile *mf, ld_map_ver_t *mv, ld_map_sym_t *ms)
+{
+ Ofl_desc *ofl = mf->mf_ofl;
+ Word hash;
+ avl_index_t where;
+ Sym *sym;
+ Sym_desc *sdp;
+ const char *conflict;
+
+ /*
+ * Add the new symbol. It should be noted that all
+ * symbols added by the mapfile start out with global
+ * scope, thus they will fall through the normal symbol
+ * resolution process. Symbols defined as locals will
+ * be reduced in scope after all input file processing.
+ */
+ /* LINTED */
+ hash = (Word)elf_hash(ms->ms_name);
+ DBG_CALL(Dbg_map_version(ofl->ofl_lml, mv->mv_name, ms->ms_name,
+ mv->mv_scope));
+ if ((sdp = ld_sym_find(ms->ms_name, hash, &where, ofl)) == NULL) {
+ if ((sym = libld_calloc(sizeof (Sym), 1)) == NULL)
+ return (FALSE);
+
+ /*
+ * Make sure any parent or external declarations
+ * fall back to references.
+ */
+ if (ms->ms_sdflags & (FLG_SY_PARENT | FLG_SY_EXTERN)) {
+ /*
+ * Turn it into a reference by setting
+ * the section index to UNDEF.
+ */
+ sym->st_shndx = ms->ms_shndx = SHN_UNDEF;
+
+ /*
+ * It is wrong to specify size or value for an
+ * external symbol.
+ */
+ if (ms->ms_value_set || (ms->ms_size != 0)) {
+ mf_fatal0(mf, MSG_INTL(MSG_MAP_NOEXVLSZ));
+ mv->mv_errcnt++;
+ return (TRUE);
+ }
+ } else {
+ sym->st_shndx = (Half)ms->ms_shndx;
+ }
+
+ sym->st_value = ms->ms_value;
+ sym->st_size = ms->ms_size;
+ sym->st_info = ELF_ST_INFO(STB_GLOBAL, ms->ms_type);
+
+ if ((sdp = ld_sym_enter(ms->ms_name, sym, hash,
+ ld_map_ifl(mf), ofl, 0, ms->ms_shndx, ms->ms_sdflags,
+ &where)) == (Sym_desc *)S_ERROR)
+ return (FALSE);
+
+ sdp->sd_flags &= ~FLG_SY_CLEAN;
+
+ /*
+ * Identify any references. FLG_SY_MAPREF is
+ * turned off once a relocatable object with
+ * the same symbol is found, thus the existence
+ * of FLG_SY_MAPREF at symbol validation is
+ * used to flag undefined/misspelled entries.
+ */
+ if (sym->st_shndx == SHN_UNDEF)
+ sdp->sd_flags |= (FLG_SY_MAPREF | FLG_SY_GLOBREF);
+
+ } else {
+ conflict = NULL;
+ sym = sdp->sd_sym;
+
+ /*
+ * If this symbol already exists, make sure this
+ * definition doesn't conflict with the former.
+ * Provided it doesn't, multiple definitions
+ * from different mapfiles can augment each
+ * other.
+ */
+ /* BEGIN CSTYLED */
+ if (sym->st_value) {
+ if (ms->ms_value && (sym->st_value != ms->ms_value))
+ conflict = MSG_INTL(MSG_MAP_DIFF_SYMVAL);
+ } else {
+ sym->st_value = ms->ms_value;
+ }
+ if (sym->st_size) {
+ if (ms->ms_size && (sym->st_size != ms->ms_size))
+ conflict = MSG_INTL(MSG_MAP_DIFF_SYMSZ);
+ } else {
+ sym->st_size = ms->ms_size;
+ }
+ if (ELF_ST_TYPE(sym->st_info) != STT_NOTYPE) {
+ if ((ms->ms_type != STT_NOTYPE) &&
+ (ELF_ST_TYPE(sym->st_info) != ms->ms_type))
+ conflict = MSG_INTL(MSG_MAP_DIFF_SYMTYP);
+ } else {
+ sym->st_info = ELF_ST_INFO(STB_GLOBAL, ms->ms_type);
+ }
+ if (sym->st_shndx != SHN_UNDEF) {
+ if ((ms->ms_shndx != SHN_UNDEF) &&
+ (sym->st_shndx != ms->ms_shndx))
+ conflict = MSG_INTL(MSG_MAP_DIFF_SYMNDX);
+ } else {
+ sym->st_shndx = sdp->sd_shndx = ms->ms_shndx;
+ }
+ /* END CSTYLED */
+
+ if ((sdp->sd_flags & MSK_SY_GLOBAL) &&
+ (sdp->sd_aux->sa_overndx != VER_NDX_GLOBAL) &&
+ (mv->mv_vdp->vd_ndx != VER_NDX_GLOBAL) &&
+ (sdp->sd_aux->sa_overndx != mv->mv_vdp->vd_ndx)) {
+ conflict = MSG_INTL(MSG_MAP_DIFF_SYMVER);
+ }
+
+ if (conflict) {
+ mf_fatal(mf, MSG_INTL(MSG_MAP_SYMDEF1),
+ demangle(ms->ms_name),
+ sdp->sd_file->ifl_name, conflict);
+ mv->mv_errcnt++;
+ return (TRUE);
+ }
+
+ /*
+ * If this mapfile entry supplies a definition,
+ * indicate that the symbol is now used.
+ */
+ if (ms->ms_shndx != SHN_UNDEF)
+ sdp->sd_flags |= FLG_SY_MAPUSED;
+ }
+
+ /*
+ * A symbol declaration that defines a size but no
+ * value is processed as a request to create an
+ * associated backing section. The intent behind this
+ * functionality is to provide OBJT definitions within
+ * filters that are not ABS. ABS symbols don't allow
+ * copy-relocations to be established to filter OBJT
+ * definitions.
+ */
+ if ((ms->ms_shndx == SHN_ABS) && ms->ms_size && !ms->ms_value_set) {
+ /* Create backing section if not there */
+ if (sdp->sd_isc == NULL) {
+ Is_desc *isp;
+
+ if (ms->ms_type == STT_OBJECT) {
+ if ((isp = ld_make_data(ofl, ms->ms_size)) ==
+ (Is_desc *)S_ERROR)
+ return (FALSE);
+ } else {
+ if ((isp = ld_make_text(ofl, ms->ms_size)) ==
+ (Is_desc *)S_ERROR)
+ return (FALSE);
+ }
+
+ sdp->sd_isc = isp;
+ isp->is_file = ld_map_ifl(mf);
+ }
+
+ /*
+ * Now that backing storage has been created,
+ * associate the symbol descriptor. Remove the
+ * symbols special section tag so that it will
+ * be assigned the correct section index as part
+ * of update symbol processing.
+ */
+ sdp->sd_flags &= ~FLG_SY_SPECSEC;
+ ms->ms_sdflags &= ~FLG_SY_SPECSEC;
+ }
+
+ /*
+ * Indicate the new symbols scope. Although the
+ * symbols st_other field will eventually be updated as
+ * part of writing out the final symbol, update the
+ * st_other field here to trigger better diagnostics
+ * during symbol validation (for example, undefined
+ * references that are defined symbolic in a mapfile).
+ */
+ if (mv->mv_scope == FLG_SCOPE_HIDD) {
+ /*
+ * This symbol needs to be reduced to local.
+ */
+ if (ofl->ofl_flags & FLG_OF_REDLSYM) {
+ sdp->sd_flags |= (FLG_SY_HIDDEN | FLG_SY_ELIM);
+ sdp->sd_sym->st_other = STV_ELIMINATE;
+ } else {
+ sdp->sd_flags |= FLG_SY_HIDDEN;
+ sdp->sd_sym->st_other = STV_HIDDEN;
+ }
+ } else if (mv->mv_scope == FLG_SCOPE_ELIM) {
+ /*
+ * This symbol needs to be eliminated. Note,
+ * the symbol is also tagged as local to trigger
+ * any necessary relocation processing prior
+ * to the symbol being eliminated.
+ */
+ sdp->sd_flags |= (FLG_SY_HIDDEN | FLG_SY_ELIM);
+ sdp->sd_sym->st_other = STV_ELIMINATE;
+
+ } else {
+ /*
+ * This symbol is explicitly defined to remain
+ * global.
+ */
+ sdp->sd_flags |= ms->ms_sdflags;
+
+ /*
+ * Qualify any global scope.
+ */
+ if (mv->mv_scope == FLG_SCOPE_SNGL) {
+ sdp->sd_flags |= (FLG_SY_SINGLE | FLG_SY_NDIR);
+ sdp->sd_sym->st_other = STV_SINGLETON;
+ } else if (mv->mv_scope == FLG_SCOPE_PROT) {
+ sdp->sd_flags |= FLG_SY_PROTECT;
+ sdp->sd_sym->st_other = STV_PROTECTED;
+ } else if (mv->mv_scope == FLG_SCOPE_EXPT) {
+ sdp->sd_flags |= FLG_SY_EXPORT;
+ sdp->sd_sym->st_other = STV_EXPORTED;
+ } else
+ sdp->sd_flags |= FLG_SY_DEFAULT;
+
+ /*
+ * Record the present version index for later
+ * potential versioning.
+ */
+ if ((sdp->sd_aux->sa_overndx == 0) ||
+ (sdp->sd_aux->sa_overndx == VER_NDX_GLOBAL))
+ sdp->sd_aux->sa_overndx = mv->mv_vdp->vd_ndx;
+ mv->mv_vdp->vd_flags |= FLG_VER_REFER;
+ }
+
+ conflict = NULL;
+
+ /*
+ * Carry out some validity checks to ensure incompatible
+ * symbol characteristics have not been defined.
+ * These checks are carried out after symbols are added
+ * or resolved, to catch single instance, and
+ * multi-instance definition inconsistencies.
+ */
+ if ((sdp->sd_flags & (FLG_SY_HIDDEN | FLG_SY_ELIM)) &&
+ ((mv->mv_scope != FLG_SCOPE_HIDD) &&
+ (mv->mv_scope != FLG_SCOPE_ELIM))) {
+ conflict = MSG_INTL(MSG_MAP_DIFF_SYMLCL);
+
+ } else if ((sdp->sd_flags &
+ (FLG_SY_SINGLE | FLG_SY_EXPORT)) &&
+ ((mv->mv_scope != FLG_SCOPE_DFLT) &&
+ (mv->mv_scope != FLG_SCOPE_EXPT) &&
+ (mv->mv_scope != FLG_SCOPE_SNGL))) {
+ conflict = MSG_INTL(MSG_MAP_DIFF_SYMGLOB);
+
+ } else if ((sdp->sd_flags & FLG_SY_PROTECT) &&
+ ((mv->mv_scope != FLG_SCOPE_DFLT) &&
+ (mv->mv_scope != FLG_SCOPE_PROT))) {
+ conflict = MSG_INTL(MSG_MAP_DIFF_SYMPROT);
+
+ } else if ((sdp->sd_flags & FLG_SY_NDIR) &&
+ (mv->mv_scope == FLG_SCOPE_PROT)) {
+ conflict = MSG_INTL(MSG_MAP_DIFF_PROTNDIR);
+
+ } else if ((sdp->sd_flags & FLG_SY_DIR) &&
+ (mv->mv_scope == FLG_SCOPE_SNGL)) {
+ conflict = MSG_INTL(MSG_MAP_DIFF_SNGLDIR);
+ }
+
+ if (conflict) {
+ /*
+ * Select the conflict message from either a
+ * single instance or multi-instance definition.
+ */
+ if (sdp->sd_file->ifl_name == mf->mf_name) {
+ mf_fatal(mf, MSG_INTL(MSG_MAP_SYMDEF2),
+ demangle(ms->ms_name), conflict);
+ } else {
+ mf_fatal(mf, MSG_INTL(MSG_MAP_SYMDEF1),
+ demangle(ms->ms_name),
+ sdp->sd_file->ifl_name, conflict);
+ }
+ mv->mv_errcnt++;
+ return (TRUE);
+ }
+
+ /*
+ * Indicate that this symbol has been explicitly
+ * contributed from a mapfile.
+ */
+ sdp->sd_flags |= (FLG_SY_MAPFILE | FLG_SY_EXPDEF);
+
+ /*
+ * If we've encountered a symbol definition simulate
+ * that an input file has been processed - this allows
+ * things like filters to be created purely from a
+ * mapfile.
+ */
+ if (ms->ms_type != STT_NOTYPE)
+ ofl->ofl_objscnt++;
+ DBG_CALL(Dbg_map_symbol(ofl, sdp));
+
+ /*
+ * If this symbol has an associated filtee, record the
+ * filtee string and associate the string index with the
+ * symbol. This is used later to associate the syminfo
+ * information with the necessary .dynamic entry.
+ */
+ if (ms->ms_filtee) {
+ Dfltr_desc * dftp;
+ Sfltr_desc sft;
+ Aliste idx, _idx, nitems;
+
+ /*
+ * Make sure we don't duplicate any filtee
+ * strings, and create a new descriptor if
+ * necessary.
+ */
+ idx = nitems = alist_nitems(ofl->ofl_dtsfltrs);
+ for (ALIST_TRAVERSE(ofl->ofl_dtsfltrs, _idx, dftp)) {
+ if ((ms->ms_dft_flag != dftp->dft_flag) ||
+ (strcmp(dftp->dft_str, ms->ms_filtee)))
+ continue;
+ idx = _idx;
+ break;
+ }
+ if (idx == nitems) {
+ Dfltr_desc dft;
+
+ dft.dft_str = ms->ms_filtee;
+ dft.dft_flag = ms->ms_dft_flag;
+ dft.dft_ndx = 0;
+
+ /*
+ * The following append puts the new
+ * item at the offset contained in
+ * idx, because we know idx contains
+ * the index of the next available slot.
+ */
+ if (alist_append(&ofl->ofl_dtsfltrs, &dft,
+ sizeof (Dfltr_desc), AL_CNT_OFL_DTSFLTRS) == NULL)
+ return (FALSE);
+ }
+
+ /*
+ * Create a new filter descriptor for this
+ * symbol.
+ */
+ sft.sft_sdp = sdp;
+ sft.sft_idx = idx;
+
+ if (alist_append(&ofl->ofl_symfltrs, &sft, sizeof (Sfltr_desc),
+ AL_CNT_OFL_SYMFLTRS) == NULL)
+ return (FALSE);
+ }
+
+ return (TRUE);
+}
+
+/*
+ * In both the version 1 and version 2 syntaxes, a version definition
+ * can have 0 or more inherited versions following the closing '}',
+ * terminated by a ';'.
+ *
+ * Add the inherited names, and return when the terminator is seen.
+ */
+Boolean
+ld_map_sym_ver_fini(Mapfile *mf, ld_map_ver_t *mv)
+{
+ Token tok;
+ ld_map_tkval_t tkv; /* Value of token */
+ Boolean done = FALSE;
+ Conv_inv_buf_t inv_buf;
+ const char *name;
+ Ver_desc *vdp;
+ Word hash;
+
+ /*
+ * Read version names until we encounter the ';' terminator.
+ */
+ while (!done) {
+ switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
+ case TK_ERROR:
+ return (FALSE);
+
+ case TK_STRING:
+ name = tkv.tkv_str;
+
+ /* The unnamed global scope can't inherit */
+ if (mv->mv_vdp->vd_ndx == VER_NDX_GLOBAL) {
+ mf_fatal(mf, MSG_INTL(MSG_MAP_UNEXINHERIT),
+ name);
+ return (FALSE);
+ }
+
+ /*
+ * Generate a new version descriptor if it doesn't
+ * already exist.
+ */
+ /* LINTED */
+ hash = (Word)elf_hash(name);
+ vdp = ld_vers_find(name, hash, mf->mf_ofl->ofl_verdesc);
+ if ((vdp == NULL) && ((vdp = ld_vers_desc(name, hash,
+ &mf->mf_ofl->ofl_verdesc)) == (Ver_desc *)S_ERROR))
+ return (FALSE);
+
+ /*
+ * Add the new version descriptor to the parent version
+ * descriptors reference list. Indicate the version
+ * descriptors first reference (used for error diags
+ * if undefined version dependencies remain).
+ */
+ if (ld_vers_find(name, hash, mv->mv_vdp->vd_deps) ==
+ NULL)
+ if (aplist_append(&mv->mv_vdp->vd_deps, vdp,
+ AL_CNT_VERDESCS) == NULL)
+ return (FALSE);
+
+ if (vdp->vd_ref == NULL)
+ vdp->vd_ref = mv->mv_vdp;
+ break;
+
+ case TK_SEMICOLON:
+ done = TRUE;
+ break;
+
+ default:
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SYMEND),
+ ld_map_tokenstr(tok, &tkv, &inv_buf));
+ return (FALSE);
+ }
+ }
+
+ return (TRUE);
+}
diff --git a/usr/src/cmd/sgs/libld/common/map_v2.c b/usr/src/cmd/sgs/libld/common/map_v2.c
new file mode 100644
index 0000000000..3832664854
--- /dev/null
+++ b/usr/src/cmd/sgs/libld/common/map_v2.c
@@ -0,0 +1,3183 @@
+/*
+ * 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 2010 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Map file parsing, Version 2 syntax (solaris).
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/elf_amd64.h> /* SHF_AMD64_LARGE */
+#include <elfcap.h>
+#include "msg.h"
+#include "_libld.h"
+#include "_map.h"
+
+/*
+ * Use a case insensitive string match when looking up capability mask
+ * values by name, and omit the AV_ prefix.
+ */
+#define ELFCAP_STYLE ELFCAP_STYLE_LC | ELFCAP_STYLE_F_ICMP
+
+/*
+ * Signature for functions used to parse top level mapfile directives
+ */
+typedef Token (*dir_func_t)(Mapfile *mf);
+
+/*
+ * Signature for functions used to parse attribute level assignments
+ * mf - Mapfile descriptor
+ * eq_tok - One of the equal tokens (TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ)
+ * or TK_ERROR. See the comment for attr_fmt_t below.
+ * uvalue - An arbitrary pointer "user value" passed by the
+ * caller to parse_attributes() for use by the function.
+ */
+typedef Token (* attr_func_t)(Mapfile *mf, Token eq_tok, void *uvalue);
+
+/*
+ * Signature for gettoken_str() err_func argument. This is a function
+ * called to issue an appropriate error message.
+ *
+ * The gts prefix stands for "Get Token Str"
+ */
+typedef void (* gts_efunc_t)(Mapfile *mf, Token tok, ld_map_tkval_t *tkv);
+
+/*
+ * The attr_fmt_t tells parse_attributes how far to go in parsing
+ * an attribute before it calls the at_func function to take over:
+ *
+ * ATTR_FMT_NAME - Parse the name, and immediately call the function.
+ * This is useful in cases where there is more than
+ * one possible syntax for a given attribute. The value of
+ * eq_tok passed to the at_func function will be TK_ERROR,
+ * reflecting the fact that it has no meaning in this context.
+ *
+ * ATTR_FMT_EQ - Parse the name, and the following '=', and then call
+ * the function. The value passed to the at_func function for
+ * eq_tok will be TK_EQUAL.
+ *
+ * ATTR_FMT_EQ_PEQ - Parse the name, and a following equal token which
+ * can be '=' or '+=', and then call the function. The value
+ * passed to the at_func function for eq_tok will be one of
+ * TK_EQUAL, or TK_PLUSEQ.
+ *
+ * ATTR_FMT_EQ_ALL - Parse the name, and a following equal token which
+ * can be any of the three forms (=, +=, -=), and then call
+ * the function. The value passed to the at_func function for
+ * eq_tok will be one of TK_EQUAL, TK_PLUSEQ, or TK_MINUSEQ.
+ */
+typedef enum {
+ ATTR_FMT_NAME,
+ ATTR_FMT_EQ,
+ ATTR_FMT_EQ_PEQ,
+ ATTR_FMT_EQ_ALL,
+} attr_fmt_t;
+
+/*
+ * Type used to describe a set of valid attributes to parse_attributes():
+ * at_name - Name of attribute
+ * at_func - Function to call when attribute is recognized,
+ * at_all_eq - True if attribute allows the '+=' and '-=' forms of
+ * assignment token, and False to only allow '='.
+ *
+ * The array of these structs passed to parse_attributes() must be
+ * NULL terminated (the at_name field must be set to NULL).
+ */
+typedef struct {
+ const char *at_name; /* Name of attribute */
+ attr_func_t at_func; /* Function to call */
+ attr_fmt_t at_fmt; /* How much to parse before calling */
+ /* at_func */
+} attr_t;
+
+/*
+ * Mapfile version and symbol state are separate but related concepts
+ * that are best represented using two different types. However, our
+ * style of passing a single uvalue via parse_attributes() makes it
+ * convenient to be able to reference them from a single address.
+ */
+typedef struct {
+ ld_map_ver_t ss_mv;
+ ld_map_sym_t ss_ms;
+} symbol_state_t;
+
+/*
+ * Process an expected equal operator. Deals with the fact that we
+ * have three variants.
+ *
+ * entry:
+ * mf - Mapfile descriptor
+ * eq_type - Types of equal operators accepted. One of ATTR_FMT_EQ,
+ * ATTR_FMT_EQ_PEQ, or ATTR_FMT_EQ_ALL.
+ * lhs - Name that appears on the left hand side of the expected
+ * equal operator.
+ *
+ * exit:
+ * Returns one of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, or TK_ERROR.
+ */
+static Token
+gettoken_eq(Mapfile *mf, attr_fmt_t eq_type, const char *lhs)
+{
+ Token tok;
+ ld_map_tkval_t tkv;
+ const char *err;
+ Conv_inv_buf_t inv_buf;
+
+ switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
+ case TK_ERROR:
+ case TK_EQUAL:
+ return (tok);
+
+ case TK_PLUSEQ:
+ switch (eq_type) {
+ case ATTR_FMT_EQ_PEQ:
+ case ATTR_FMT_EQ_ALL:
+ return (tok);
+ }
+ break;
+
+ case TK_MINUSEQ:
+ if (eq_type == ATTR_FMT_EQ_ALL)
+ return (tok);
+ break;
+ }
+
+ switch (eq_type) {
+ case ATTR_FMT_EQ:
+ err = MSG_INTL(MSG_MAP_EXP_EQ);
+ break;
+ case ATTR_FMT_EQ_PEQ:
+ err = MSG_INTL(MSG_MAP_EXP_EQ_PEQ);
+ break;
+ case ATTR_FMT_EQ_ALL:
+ err = MSG_INTL(MSG_MAP_EXP_EQ_ALL);
+ break;
+ default:
+ /*NOTREACHED*/
+ assert(0);
+ }
+ mf_fatal(mf, err, lhs, ld_map_tokenstr(tok, &tkv, &inv_buf));
+ return (TK_ERROR);
+}
+
+/*
+ * Apply one of the three equal tokens to a bitmask value
+ *
+ * entry:
+ * dst - Address of bitmask variable to alter
+ * eq_tok - One of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, representing
+ * the operation to carry out.
+ * value - Value for right hand side
+ *
+ * exit:
+ * The operation has been carried out:
+ *
+ * TK_EQUAL - *dst is set to value
+ * TK_PLUSEQ - Bits in value have been set in *dst
+ * TK_MINUSEQ - Bits in value have been removed from *dst
+ */
+static void
+setflags_eq(Word *dst, Token eq_tok, Word value)
+{
+ switch (eq_tok) {
+ case TK_EQUAL:
+ *dst = value;
+ break;
+ case TK_PLUSEQ:
+ *dst |= value;
+ break;
+ case TK_MINUSEQ:
+ *dst &= ~value;
+ break;
+ default:
+ /*NOTREACHED*/
+ assert(0);
+ }
+}
+
+/*
+ * Apply one of the three equal tokens to a capabilities CapMask.
+ *
+ * entry:
+ * mf - Mapfile descriptor
+ * capmask - Address of CapMask variable to alter
+ * eq_tok - One of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, representing
+ * the operation to carry out.
+ * type - Capability type (CA_SUNW_*)
+ * value - Value for right hand side
+ * title - True if a title is needed, False otherwise.
+ *
+ * exit:
+ * On success, returns TRUE (1), otherwise FALSE (0)
+ */
+static Boolean
+set_capmask(Mapfile *mf, CapMask *capmask, Token eq_tok,
+ Word type, elfcap_mask_t value, Boolean title)
+{
+ if (title)
+ DBG_CALL(Dbg_cap_mapfile_title(mf->mf_ofl->ofl_lml,
+ mf->mf_lineno));
+ DBG_CALL(Dbg_cap_entry2(mf->mf_ofl->ofl_lml, DBG_STATE_CURRENT,
+ type, capmask, ld_targ.t_m.m_mach));
+
+ switch (eq_tok) {
+ case TK_EQUAL:
+ capmask->cm_value = value;
+ capmask->cm_exclude = 0;
+ ld_map_cap_set_ovflag(mf, type);
+ DBG_CALL(Dbg_cap_entry2(mf->mf_ofl->ofl_lml,
+ DBG_STATE_RESET, type, capmask, ld_targ.t_m.m_mach));
+ break;
+ case TK_PLUSEQ:
+ DBG_CALL(Dbg_cap_entry(mf->mf_ofl->ofl_lml, DBG_STATE_ADD,
+ type, value, ld_targ.t_m.m_mach));
+ capmask->cm_value |= value;
+ capmask->cm_exclude &= ~value;
+ break;
+ case TK_MINUSEQ:
+ DBG_CALL(Dbg_cap_entry(mf->mf_ofl->ofl_lml, DBG_STATE_EXCLUDE,
+ type, value, ld_targ.t_m.m_mach));
+ capmask->cm_value &= ~value;
+ capmask->cm_exclude |= value;
+ break;
+ default:
+ /*NOTREACHED*/
+ assert(0);
+ }
+
+ /* Sanity check the resulting bits */
+ if (!ld_map_cap_sanitize(mf, type, capmask))
+ return (FALSE);
+
+ /* Report the final configuration */
+ DBG_CALL(Dbg_cap_entry2(mf->mf_ofl->ofl_lml,
+ DBG_STATE_RESOLVED, type, capmask, ld_targ.t_m.m_mach));
+
+ return (TRUE);
+}
+
+/*
+ * Process the next token, which is expected to start an optional
+ * nesting of attributes (';' or '{').
+ *
+ * entry:
+ * mf - Mapfile descriptor
+ * lhs - Name of the directive or attribute being processed.
+ *
+ * exit:
+ * Returns TK_SEMICOLON or TK_LEFTBKT for success, and TK_ERROR otherwise.
+ */
+static Token
+gettoken_optattr(Mapfile *mf, const char *lhs)
+{
+ Token tok;
+ ld_map_tkval_t tkv;
+ Conv_inv_buf_t inv_buf;
+
+ switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
+ case TK_ERROR:
+ case TK_SEMICOLON:
+ case TK_LEFTBKT:
+ return (tok);
+ }
+
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEMLBKT), lhs,
+ ld_map_tokenstr(tok, &tkv, &inv_buf));
+ return (TK_ERROR);
+}
+
+/*
+ * Process the next token, which is expected to be a line terminator
+ * (';' or '}').
+ *
+ * entry:
+ * mf - Mapfile descriptor
+ * lhs - Name of the directive or attribute being processed.
+ *
+ * exit:
+ * Returns TK_SEMICOLON or TK_RIGHTBKT for success, and TK_ERROR otherwise.
+ */
+static Token
+gettoken_term(Mapfile *mf, const char *lhs)
+{
+ Token tok;
+ ld_map_tkval_t tkv;
+ Conv_inv_buf_t inv_buf;
+
+ switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
+ case TK_ERROR:
+ case TK_SEMICOLON:
+ case TK_RIGHTBKT:
+ return (tok);
+ }
+
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEMRBKT), lhs,
+ ld_map_tokenstr(tok, &tkv, &inv_buf));
+ return (TK_ERROR);
+}
+
+/*
+ * Process the next token, which is expected to be a semicolon.
+ *
+ * entry:
+ * mf - Mapfile descriptor
+ * lhs - Name of the directive or attribute being processed.
+ *
+ * exit:
+ * Returns TK_SEMICOLON for success, and TK_ERROR otherwise.
+ */
+static Token
+gettoken_semicolon(Mapfile *mf, const char *lhs)
+{
+ Token tok;
+ ld_map_tkval_t tkv;
+ Conv_inv_buf_t inv_buf;
+
+ switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
+ case TK_ERROR:
+ case TK_SEMICOLON:
+ return (tok);
+ }
+
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEM), lhs,
+ ld_map_tokenstr(tok, &tkv, &inv_buf));
+ return (TK_ERROR);
+}
+
+/*
+ * Process the next token, which is expected to be a '{'
+ *
+ * entry:
+ * mf - Mapfile descriptor
+ * lhs - Name of the item directly to the left of the expected left
+ * bracket.
+ *
+ * exit:
+ * Returns TK_LEFTBKT for success, and TK_ERROR otherwise.
+ */
+static Token
+gettoken_leftbkt(Mapfile *mf, const char *lhs)
+{
+ Token tok;
+ ld_map_tkval_t tkv;
+ Conv_inv_buf_t inv_buf;
+
+ switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
+ case TK_ERROR:
+ case TK_LEFTBKT:
+ return (tok);
+ }
+
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_LBKT), lhs,
+ ld_map_tokenstr(tok, &tkv, &inv_buf));
+ return (TK_ERROR);
+}
+
+/*
+ * Process the next token, which is expected to be an integer
+ *
+ * entry:
+ * mf - Mapfile descriptor
+ * lhs - Name of the directive or attribute being processed.
+ * tkv - Address of token value struct to be filled in
+ *
+ * exit:
+ * Updates *tkv and returns TK_INT for success, TK_ERROR otherwise.
+ */
+static Token
+gettoken_int(Mapfile *mf, const char *lhs, ld_map_tkval_t *tkv)
+{
+ Token tok;
+ Conv_inv_buf_t inv_buf;
+
+ switch (tok = ld_map_gettoken(mf, 0, tkv)) {
+ case TK_ERROR:
+ case TK_INT:
+ return (tok);
+ }
+
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_INT), lhs,
+ ld_map_tokenstr(tok, tkv, &inv_buf));
+ return (TK_ERROR);
+}
+
+/*
+ * Process the next token, which is expected to be a string
+ *
+ * entry:
+ * mf - Mapfile descriptor
+ * lhs - Name of the directive or attribute being processed.
+ * tkv - Address of token value struct to be filled in
+ * err_func - Function to call if an error occurs
+ *
+ * exit:
+ * Updates *tkv and returns TK_STRING for success. Calls the
+ * supplied err_func function and returns TK_ERROR otherwise.
+ */
+static Token
+gettoken_str(Mapfile *mf, int flags, ld_map_tkval_t *tkv, gts_efunc_t efunc)
+{
+ Token tok;
+
+ switch (tok = ld_map_gettoken(mf, flags, tkv)) {
+ case TK_ERROR:
+ case TK_STRING:
+ return (tok);
+ }
+
+ /* User supplied function reports the error */
+ (* efunc)(mf, tok, tkv);
+
+ return (TK_ERROR);
+}
+
+/*
+ * Given a construct of the following common form:
+ *
+ * item_name {
+ * attribute = ...;
+ * ...
+ * }
+ *
+ * where the caller has detected the item_name and opening bracket,
+ * parse the construct and call the attribute functions for each
+ * attribute detected, stopping when the closing '}' is seen.
+ *
+ * entry:
+ * mf - Mapfile descriptor
+ * item_name - Already detected name of item for which attributes
+ * are being parsed.
+ * attr_list - NULL terminated array of attr_t structures describing the
+ * valid attributes for the item.
+ * expect_str - Comma separated string listing the names of expected
+ * attributes.
+ * uvalue - User value, passed to the attribute functions without
+ * examination by parse_attributes(), usable for maintaining
+ * shared state between the caller and the functions.
+ *
+ * exit:
+ * parse_attributes() reads the attribute name and equality token,
+ * and then calls the attribute function given by the attr_list array
+ * to handle everything up to and including the terminating ';'.
+ * This continues until the closing '}' is seen.
+ *
+ * If everything is successful, TK_RIGHTBKT is returned. Otherwise,
+ * a suitable error is issued and TK_ERROR is returned.
+ */
+static Token
+parse_attributes(Mapfile *mf, const char *item_name, attr_t *attr_list,
+ size_t attr_list_bufsize, void *uvalue)
+{
+ attr_t *attr;
+ Token tok, op_tok;
+ ld_map_tkval_t tkv;
+ int done;
+ int attr_cnt = 0;
+ Conv_inv_buf_t inv_buf;
+
+ /* Read attributes until the closing '}' is seen */
+ for (done = 0; done == 0; ) {
+ switch (tok = ld_map_gettoken(mf, TK_F_KEYWORD, &tkv)) {
+ case TK_ERROR:
+ return (TK_ERROR);
+
+ case TK_STRING:
+ attr = ld_map_kwfind(tkv.tkv_str, attr_list,
+ SGSOFFSETOF(attr_t, at_name), sizeof (attr[0]));
+ if (attr == NULL)
+ goto bad_attr;
+
+ /*
+ * Depending on the value of at_fmt, there are
+ * fout different actions to take:
+ * ATTR_FMT_NAME - Call at_func function
+ * ATTR_FMT_EQ - Read and verify a TK_EQUAL
+ * ATTR_FMT_EQ_PEQ - Read and verify a TK_EQUAL
+ * or TK_PLUSEQ.
+ * ATTR_FMT_EQ_ALL - Read/Verify one of the
+ * three possible equal tokens
+ * (TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ).
+ */
+ if (attr->at_fmt == ATTR_FMT_NAME) {
+ /* Arbitrary value to pass to at_func */
+ op_tok = TK_ERROR;
+ } else {
+ /* Read/Verify appropriate equal operator */
+ op_tok = gettoken_eq(mf, attr->at_fmt,
+ attr->at_name);
+ if (op_tok == TK_ERROR)
+ return (TK_ERROR);
+ }
+
+ /* Call the associated function */
+ switch (tok = attr->at_func(mf, op_tok, uvalue)) {
+ default:
+ return (TK_ERROR);
+ case TK_SEMICOLON:
+ break;
+ case TK_RIGHTBKT:
+ done = 1;
+ break;
+ }
+ attr_cnt++;
+ break;
+
+ case TK_RIGHTBKT:
+ done = 1;
+ break;
+
+ case TK_SEMICOLON:
+ break; /* Ignore empty statement */
+
+ default:
+ bad_attr:
+ {
+ char buf[attr_list_bufsize];
+
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_ATTR),
+ ld_map_kwnames(attr_list,
+ SGSOFFSETOF(attr_t, at_name),
+ sizeof (attr[0]), buf, attr_list_bufsize),
+ ld_map_tokenstr(tok, &tkv, &inv_buf));
+ }
+ return (TK_ERROR);
+ }
+ }
+
+ /* Make sure there was at least one attribute between the {} brackets */
+ if (attr_cnt == 0) {
+ mf_fatal(mf, MSG_INTL(MSG_MAP_NOATTR), item_name);
+ return (TK_ERROR);
+ }
+
+ return (tok);
+}
+
+/*
+ * Read whitespace delimited segment flags from the input and convert into
+ * bitmask of PF_ values they represent. Flags are terminated by a semicolon
+ * or right bracket.
+ *
+ * entry:
+ * mf - Mapfile descriptor
+ * flags - Address of variable to be set to resulting flags value
+ *
+ * exit:
+ * Returns the terminator token (TK_SEMICOLON or TK_LEFTBKT) on success,
+ * and TK_ERROR otherwise.
+ */
+static Token
+parse_segment_flags(Mapfile *mf, Xword *flags)
+{
+ /*
+ * Map flag names to their values. Since DATA and STACK have
+ * platform dependent values, we have to determine them at runtime.
+ * We indicate this by setting the top bit.
+ */
+#define PF_DATA 0x80000000
+#define PF_STACK 0x80000001
+ typedef struct {
+ const char *name;
+ Word value;
+ } segflag_t;
+ static segflag_t flag_list[] = {
+ { MSG_ORIG(MSG_MAPKW_DATA), PF_DATA },
+ { MSG_ORIG(MSG_MAPKW_EXECUTE), PF_X },
+ { MSG_ORIG(MSG_MAPKW_READ), PF_R },
+ { MSG_ORIG(MSG_MAPKW_STACK), PF_STACK },
+ { MSG_ORIG(MSG_MAPKW_WRITE), PF_W },
+
+ /* List must be null terminated */
+ { 0 },
+ };
+
+ /*
+ * Size of buffer needed to format the names in flag_list[]. Must
+ * be kept in sync with flag_list.
+ */
+ static size_t flag_list_bufsize =
+ KW_NAME_SIZE(MSG_MAPKW_DATA) +
+ KW_NAME_SIZE(MSG_MAPKW_EXECUTE) +
+ KW_NAME_SIZE(MSG_MAPKW_READ) +
+ KW_NAME_SIZE(MSG_MAPKW_STACK) +
+ KW_NAME_SIZE(MSG_MAPKW_WRITE);
+
+ Token tok;
+ ld_map_tkval_t tkv;
+ segflag_t *flag;
+ size_t cnt = 0;
+ int done;
+ Conv_inv_buf_t inv_buf;
+
+ *flags = 0;
+
+ /* Read attributes until the ';' terminator is seen */
+ for (done = 0; done == 0; ) {
+ switch (tok = ld_map_gettoken(mf, TK_F_KEYWORD, &tkv)) {
+ case TK_ERROR:
+ return (TK_ERROR);
+
+ case TK_STRING:
+ flag = ld_map_kwfind(tkv.tkv_str, flag_list,
+ SGSOFFSETOF(segflag_t, name),
+ sizeof (flag_list[0]));
+ if (flag == NULL)
+ goto bad_flag;
+ switch (flag->value) {
+ case PF_DATA:
+ *flags |= ld_targ.t_m.m_dataseg_perm;
+ break;
+ case PF_STACK:
+ *flags |= ld_targ.t_m.m_stack_perm;
+ break;
+ default:
+ *flags |= flag->value;
+ }
+ cnt++;
+ break;
+
+ case TK_INT:
+ /*
+ * Accept 0 for notational convenience, but refuse
+ * any other value. Note that we don't actually have
+ * to set the flags to 0 here, because there are
+ * already initialized to that before the main loop.
+ */
+ if (tkv.tkv_int.tkvi_value != 0)
+ goto bad_flag;
+ cnt++;
+ break;
+
+ case TK_SEMICOLON:
+ case TK_RIGHTBKT:
+ done = 1;
+ break;
+
+ default:
+ bad_flag:
+ {
+ char buf[flag_list_bufsize];
+
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEGFLAG),
+ ld_map_kwnames(flag_list,
+ SGSOFFSETOF(segflag_t, name),
+ sizeof (flag[0]), buf, flag_list_bufsize),
+ ld_map_tokenstr(tok, &tkv, &inv_buf));
+ }
+ return (TK_ERROR);
+ }
+ }
+
+ /* Make sure there was at least one flag */
+ if (cnt == 0) {
+ mf_fatal(mf, MSG_INTL(MSG_MAP_NOVALUES),
+ MSG_ORIG(MSG_MAPKW_FLAGS));
+ return (TK_ERROR);
+ }
+
+ return (tok);
+
+#undef PF_DATA
+#undef PF_STACK
+}
+
+
+/*
+ * Parse one of the capabilities attributes that corresponds directly
+ * to a capabilities bitmask value (HW_xxx, SF_xxx). Values can be
+ * integers, or symbolic names that correspond to the capabilities mask
+ * in question.
+ *
+ * entry:
+ * mf - Mapfile descriptor
+ * eq_tok - One of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, representing
+ * the operation to carry out.
+ * capmask - CapMask from output descriptor for capability being processed.
+ * type - Capability type (CA_SUNW_*)
+ * elfcap_from_str_func - pointer to elfcap-string-to-value function
+ * for capability being processed.
+ *
+ * exit:
+ * Returns TK_SEMICOLON or TK_RIGHTBKT for success, and TK_ERROR otherwise.
+ */
+static Token
+parse_cap_mask(Mapfile *mf, Token eq_tok, CapMask *capmask,
+ Word type, elfcap_from_str_func_t *elfcap_from_str_func)
+{
+ int done;
+ Token tok;
+ ld_map_tkval_t tkv;
+ Conv_inv_buf_t inv_buf;
+ elfcap_mask_t value = 0;
+ uint64_t v;
+
+ for (done = 0; done == 0; ) {
+ switch (tok = ld_map_gettoken(mf, TK_F_KEYWORD, &tkv)) {
+ case TK_ERROR:
+ return (TK_ERROR);
+
+ case TK_STRING:
+ if ((v = (* elfcap_from_str_func)(ELFCAP_STYLE,
+ tkv.tkv_str, ld_targ.t_m.m_mach)) != 0) {
+ value |= v;
+ break;
+ }
+ goto bad_flag;
+
+ case TK_INT:
+ value |= tkv.tkv_int.tkvi_value;
+ break;
+
+ case TK_SEMICOLON:
+ case TK_RIGHTBKT:
+ done = 1;
+ break;
+
+ default:
+ bad_flag:
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_CAPMASK),
+ ld_map_tokenstr(tok, &tkv, &inv_buf));
+ return (TK_ERROR);
+ }
+ }
+
+ if (!set_capmask(mf, capmask, eq_tok, type, value, TRUE))
+ return (TK_ERROR);
+ return (tok);
+}
+
+/*
+ * XXXRIEXXX
+ *
+ * This routine is the name version of parse_cap_mask. You need to
+ * add the argument that corresponds to capmask. Also, remove the
+ * ARGSUSED lint comment.
+ */
+/*
+ * Parse one of the capabilities attributes that manages lists of names
+ * (CA_SUNW_PLATFORM, CA_SUNW_MACHINE).
+ *
+ * entry:
+ * mf - Mapfile descriptor
+ * eq_tok - One of TK_EQUAL, TK_PLUSEQ, TK_MINUSEQ, representing
+ * the operation to carry out.
+ * type - Capability type (CA_SUNW_*)
+ *
+ * exit:
+ * Returns TK_SEMICOLON or TK_RIGHTBKT for success, and TK_ERROR otherwise.
+ */
+/*ARGSUSED*/
+static Token
+parse_cap_list(Mapfile *mf, Token eq_tok, Word type)
+{
+ int done;
+ Token tok;
+ ld_map_tkval_t tkv;
+ Conv_inv_buf_t inv_buf;
+
+ /*
+ * XXXRIEXXX
+ *
+ * If eq_tok is TK_EQUAL, you must clear the value and exclude lists,
+ * and set the 'override' bit so that the capability from the input
+ * objects is ignored. See set_capmask() for the logic used for
+ * bitmasks.
+ */
+ for (done = 0; done == 0; ) {
+ switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
+ case TK_ERROR:
+ return (TK_ERROR);
+
+ case TK_STRING:
+ /*
+ * XXXRIEXXX
+ *
+ * The name is in tkv.tkv_str. If eq_tok is TK_MINUSEQ,
+ * you add the name to the exclude list, and remove it
+ * from the value list. Otherwise, you add it to the
+ * value list and remove it from the exclude list.
+ */
+ break;
+
+ case TK_SEMICOLON:
+ case TK_RIGHTBKT:
+ done = 1;
+ break;
+
+ default:
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_CAPNAME),
+ ld_map_tokenstr(tok, &tkv, &inv_buf));
+ return (TK_ERROR);
+ }
+ }
+
+ return (tok);
+}
+
+/*
+ * CAPABILITY [capid] { HW = hwcap_flags...
+ * -------------------------^
+ */
+/* ARGSUSED 2 */
+static Token
+at_cap_hw(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ int done;
+ Token tok;
+ ld_map_tkval_t tkv;
+ Conv_inv_buf_t inv_buf;
+ Word hw1 = 0, hw2 = 0;
+ uint64_t v;
+
+ for (done = 0; done == 0; ) {
+ switch (tok = ld_map_gettoken(mf, TK_F_KEYWORD, &tkv)) {
+ case TK_ERROR:
+ return (TK_ERROR);
+
+ case TK_STRING:
+ if ((v = elfcap_hw1_from_str(ELFCAP_STYLE,
+ tkv.tkv_str, ld_targ.t_m.m_mach)) != 0) {
+ hw1 |= v;
+ break;
+ }
+ if ((v = elfcap_hw2_from_str(ELFCAP_STYLE,
+ tkv.tkv_str, ld_targ.t_m.m_mach)) != 0) {
+ hw2 |= v;
+ break;
+ }
+ goto bad_flag;
+
+ case TK_SEMICOLON:
+ case TK_RIGHTBKT:
+ done = 1;
+ break;
+
+ default:
+ bad_flag:
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_CAPHW),
+ ld_map_tokenstr(tok, &tkv, &inv_buf));
+ return (TK_ERROR);
+ }
+ }
+
+ if (!set_capmask(mf, &mf->mf_ofl->ofl_ocapset.c_hw_1, eq_tok,
+ CA_SUNW_HW_1, hw1, TRUE))
+ return (TK_ERROR);
+ if (!set_capmask(mf, &mf->mf_ofl->ofl_ocapset.c_hw_2, eq_tok,
+ CA_SUNW_HW_2, hw2, FALSE))
+ return (TK_ERROR);
+ return (tok);
+}
+
+/*
+ * CAPABILITY [capid] { HW_1 = value ;
+ * ---------------------------^
+ */
+/* ARGSUSED 2 */
+static Token
+at_cap_hw_1(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ return (parse_cap_mask(mf, eq_tok, &mf->mf_ofl->ofl_ocapset.c_hw_1,
+ CA_SUNW_HW_1, elfcap_hw1_from_str));
+}
+
+/*
+ * CAPABILITY [capid] { HW_2 = value ;
+ * ---------------------------^
+ */
+/* ARGSUSED 2 */
+static Token
+at_cap_hw_2(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ return (parse_cap_mask(mf, eq_tok, &mf->mf_ofl->ofl_ocapset.c_hw_2,
+ CA_SUNW_HW_2, elfcap_hw2_from_str));
+}
+
+/*
+ * CAPABILITY [capid] { SF = sfcap_flags...
+ * -------------------------^
+ */
+/* ARGSUSED 2 */
+static Token
+at_cap_sf(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ int done;
+ Token tok;
+ ld_map_tkval_t tkv;
+ Conv_inv_buf_t inv_buf;
+ Word sf1 = 0;
+ uint64_t v;
+
+ for (done = 0; done == 0; ) {
+ switch (tok = ld_map_gettoken(mf, TK_F_KEYWORD, &tkv)) {
+ case TK_ERROR:
+ return (TK_ERROR);
+
+ case TK_STRING:
+ if ((v = elfcap_sf1_from_str(ELFCAP_STYLE,
+ tkv.tkv_str, ld_targ.t_m.m_mach)) != 0) {
+ sf1 |= v;
+ break;
+ }
+ goto bad_flag;
+
+ case TK_SEMICOLON:
+ case TK_RIGHTBKT:
+ done = 1;
+ break;
+
+ default:
+ bad_flag:
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_CAPSF),
+ ld_map_tokenstr(tok, &tkv, &inv_buf));
+ return (TK_ERROR);
+ }
+ }
+
+ if (!set_capmask(mf, &mf->mf_ofl->ofl_ocapset.c_sf_1, eq_tok,
+ CA_SUNW_SF_1, sf1, TRUE))
+ return (TK_ERROR);
+
+ return (tok);
+}
+
+/*
+ * CAPABILITY [capid] { SF_1 = value ;
+ * ---------------------------^
+ */
+/* ARGSUSED 2 */
+static Token
+at_cap_sf_1(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ return (parse_cap_mask(mf, eq_tok, &mf->mf_ofl->ofl_ocapset.c_sf_1,
+ CA_SUNW_SF_1, elfcap_sf1_from_str));
+}
+
+/*
+ * CAPABILITY [capid] { MACHINE = value ;
+ * ------------------------------^
+ */
+/* ARGSUSED 2 */
+static Token
+at_cap_mach(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ /*
+ * XXXRIEXXX
+ *
+ * Add the missing argument, and replace the 0 with
+ * CA_SUNW_MACH.
+ */
+ return (parse_cap_list(mf, eq_tok, /* cap-list-goes-here, */
+ /* CA_SUNW_MACH */0));
+}
+
+/*
+ * CAPABILITY [capid] { PLATFORM = value ;
+ * -------------------------------^
+ */
+/* ARGSUSED 2 */
+static Token
+at_cap_plat(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ /*
+ * XXXRIEXXX
+ *
+ * Add the missing argument, and replace the 0 with
+ * CA_SUNW_PLAT.
+ */
+ return (parse_cap_list(mf, eq_tok, /* cap-list-goes-here, */
+ /* CA_SUNW_PLAT */0));
+}
+
+/*
+ * Top Level Directive:
+ *
+ * CAPABILITY [capid] { ...
+ * ----------^
+ */
+static Token
+dir_capability(Mapfile *mf)
+{
+ /* CAPABILITY attributes */
+ static attr_t attr_list[] = {
+ { MSG_ORIG(MSG_MAPKW_HW), at_cap_hw, ATTR_FMT_EQ_ALL },
+ { MSG_ORIG(MSG_MAPKW_HW_1), at_cap_hw_1, ATTR_FMT_EQ_ALL },
+ { MSG_ORIG(MSG_MAPKW_HW_2), at_cap_hw_2, ATTR_FMT_EQ_ALL },
+
+ { MSG_ORIG(MSG_MAPKW_MACHINE), at_cap_mach, ATTR_FMT_EQ_ALL },
+ { MSG_ORIG(MSG_MAPKW_PLATFORM), at_cap_plat, ATTR_FMT_EQ_ALL },
+
+ { MSG_ORIG(MSG_MAPKW_SF), at_cap_sf, ATTR_FMT_EQ_ALL },
+ { MSG_ORIG(MSG_MAPKW_SF_1), at_cap_sf_1, ATTR_FMT_EQ_ALL },
+ /* List must be null terminated */
+ { 0 }
+ };
+
+ /*
+ * Size of buffer needed to format the names in attr_list[]. Must
+ * be kept in sync with attr_list.
+ */
+ static size_t attr_list_bufsize =
+ KW_NAME_SIZE(MSG_MAPKW_HW) +
+ KW_NAME_SIZE(MSG_MAPKW_HW_1) +
+ KW_NAME_SIZE(MSG_MAPKW_HW_2) +
+ KW_NAME_SIZE(MSG_MAPKW_MACHINE) +
+ KW_NAME_SIZE(MSG_MAPKW_PLATFORM) +
+ KW_NAME_SIZE(MSG_MAPKW_SF) +
+ KW_NAME_SIZE(MSG_MAPKW_SF_1);
+
+ const char *capid = NULL;
+ Token tok;
+ ld_map_tkval_t tkv;
+ Conv_inv_buf_t inv_buf;
+
+ /*
+ * The first token can be one of:
+ * - An opening '{'
+ * - A name, followed by a '{', or a ';'.
+ * Read this initial sequence.
+ */
+
+ switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
+ case TK_ERROR:
+ return (TK_ERROR);
+
+ case TK_STRING:
+ /*
+ * XXXRIEXXX
+ *
+ * The ID name is in tkv.tkv_str. It needs to be saved,
+ * and eventually converted into a CA_SUNW_ID entry.
+ */
+ capid = tkv.tkv_str;
+
+ /*
+ * The name can be followed by an opening '{', or a
+ * terminating ';'
+ */
+ switch (tok = gettoken_optattr(mf, capid)) {
+ case TK_SEMICOLON:
+ return (TK_SEMICOLON);
+ case TK_LEFTBKT:
+ break;
+ default:
+ return (TK_ERROR);
+ }
+ break;
+
+ case TK_LEFTBKT:
+ /* Directive has no capid, but does supply attributes */
+ break;
+
+ default:
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_CAPID),
+ MSG_ORIG(MSG_MAPKW_CAPABILITY),
+ ld_map_tokenstr(tok, &tkv, &inv_buf));
+ return (TK_ERROR);
+ }
+
+ /* Parse the attributes */
+ if (parse_attributes(mf, MSG_ORIG(MSG_MAPKW_CAPABILITY),
+ attr_list, attr_list_bufsize, NULL) == TK_ERROR)
+ return (TK_ERROR);
+
+ /* Terminating ';' */
+ return (gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_CAPABILITY)));
+}
+
+/*
+ * at_dv_allow(): Value for ALLOW= is not a version string
+ */
+static void
+gts_efunc_at_dv_allow(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
+{
+ Conv_inv_buf_t inv_buf;
+
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_VERSION),
+ MSG_ORIG(MSG_MAPKW_ALLOW), ld_map_tokenstr(tok, tkv, &inv_buf));
+}
+
+/*
+ * DEPEND_VERSIONS object_name { ALLOW = version
+ * -------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_dv_allow(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ ld_map_tkval_t tkv;
+
+ if (gettoken_str(mf, 0, &tkv, gts_efunc_at_dv_allow) == TK_ERROR)
+ return (TK_ERROR);
+
+ /* Enter the version. uvalue points at the Sdf_desc descriptor */
+ if (!ld_map_dv_entry(mf, uvalue, FALSE, tkv.tkv_str))
+ return (TK_ERROR);
+
+ /* terminator */
+ return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_ALLOW)));
+}
+
+/*
+ * at_dv_allow(): Value for REQUIRE= is not a version string
+ */
+static void
+gts_efunc_at_dv_require(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
+{
+ Conv_inv_buf_t inv_buf;
+
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_VERSION),
+ MSG_ORIG(MSG_MAPKW_REQUIRE), ld_map_tokenstr(tok, tkv, &inv_buf));
+}
+
+/*
+ * DEPEND_VERSIONS object_name { REQURE = version
+ * --------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_dv_require(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ ld_map_tkval_t tkv;
+
+ /* version_name */
+ if (gettoken_str(mf, 0, &tkv, gts_efunc_at_dv_require) == TK_ERROR)
+ return (TK_ERROR);
+
+ /* Enter the version. uvalue points at the Sdf_desc descriptor */
+ if (!ld_map_dv_entry(mf, uvalue, TRUE, tkv.tkv_str))
+ return (TK_ERROR);
+
+ /* terminator */
+ return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_REQUIRE)));
+}
+
+/*
+ * dir_depend_versions(): Expected object name is not present
+ */
+static void
+gts_efunc_dir_depend_versions(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
+{
+ Conv_inv_buf_t inv_buf;
+
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_OBJNAM),
+ MSG_ORIG(MSG_MAPKW_DEPEND_VERSIONS),
+ ld_map_tokenstr(tok, tkv, &inv_buf));
+}
+
+/*
+ * Top Level Directive:
+ *
+ * DEPEND_VERSIONS object_name { ATTR = ...
+ * ---------------^
+ */
+static Token
+dir_depend_versions(Mapfile *mf)
+{
+ /* DEPEND_VERSIONS attributes */
+ static attr_t attr_list[] = {
+ { MSG_ORIG(MSG_MAPKW_ALLOW), at_dv_allow, ATTR_FMT_EQ },
+ { MSG_ORIG(MSG_MAPKW_REQUIRE), at_dv_require, ATTR_FMT_EQ },
+
+ /* List must be null terminated */
+ { 0 }
+ };
+
+ /*
+ * Size of buffer needed to format the names in attr_list[]. Must
+ * be kept in sync with attr_list.
+ */
+ static size_t attr_list_bufsize =
+ KW_NAME_SIZE(MSG_MAPKW_ALLOW) +
+ KW_NAME_SIZE(MSG_MAPKW_REQUIRE);
+
+ ld_map_tkval_t tkv;
+ Sdf_desc *sdf;
+
+ /* object_name */
+ if (gettoken_str(mf, 0, &tkv, gts_efunc_dir_depend_versions) ==
+ TK_ERROR)
+ return (TK_ERROR);
+
+ /* Get descriptor for dependency */
+ if ((sdf = ld_map_dv(mf, tkv.tkv_str)) == NULL)
+ return (TK_ERROR);
+
+ /* Opening '{' token */
+ if (gettoken_leftbkt(mf, tkv.tkv_str) == TK_ERROR)
+ return (TK_ERROR);
+
+ /* Parse the attributes */
+ if (parse_attributes(mf, MSG_ORIG(MSG_MAPKW_DEPEND_VERSIONS),
+ attr_list, attr_list_bufsize, sdf) == TK_ERROR)
+ return (TK_ERROR);
+
+ /* Terminating ';' */
+ return (gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_DEPEND_VERSIONS)));
+}
+
+/*
+ * Top Level Directive:
+ *
+ * HDR_NOALLOC ;
+ * -----------^
+ */
+static Token
+dir_hdr_noalloc(Mapfile *mf)
+{
+ mf->mf_ofl->ofl_dtflags_1 |= DF_1_NOHDR;
+ DBG_CALL(Dbg_map_hdr_noalloc(mf->mf_ofl->ofl_lml, mf->mf_lineno));
+
+ /* ';' terminator token */
+ return (gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_HDR_NOALLOC)));
+}
+
+/*
+ * Top Level Directive:
+ *
+ * PHDR_ADD_NULL = cnt ;
+ * -------------^
+ */
+static Token
+dir_phdr_add_null(Mapfile *mf)
+{
+ Sg_desc *sgp;
+ ld_map_tkval_t tkv; /* Value of token */
+
+ /* '=' token */
+ if (gettoken_eq(mf, ATTR_FMT_EQ,
+ MSG_ORIG(MSG_MAPKW_PHDR_ADD_NULL)) == TK_ERROR)
+ return (TK_ERROR);
+
+ /* integer token */
+ if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_PHDR_ADD_NULL), &tkv) ==
+ TK_ERROR)
+ return (TK_ERROR);
+
+ while (tkv.tkv_int.tkvi_value-- > 0) {
+ if ((sgp = ld_map_seg_alloc(NULL, PT_NULL,
+ FLG_SG_P_TYPE | FLG_SG_EMPTY)) == NULL)
+ return (TK_ERROR);
+ if (ld_map_seg_insert(mf, DBG_STATE_NEW, sgp, 0) ==
+ SEG_INS_FAIL)
+ return (TK_ERROR);
+ }
+
+ /* ';' terminator token */
+ return (gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_PHDR_ADD_NULL)));
+}
+
+/*
+ * segment_directive segment_name { ALIGN = value
+ * ----------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_seg_align(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ Sg_desc *sgp = uvalue;
+ ld_map_tkval_t tkv;
+
+ /* value */
+ if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_ALIGN), &tkv) == TK_ERROR)
+ return (TK_ERROR);
+
+ sgp->sg_phdr.p_align = tkv.tkv_int.tkvi_value;
+ sgp->sg_flags |= FLG_SG_P_ALIGN;
+
+ /* terminator */
+ return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_ALIGN)));
+}
+
+/*
+ * at_seg_assign_file_basename(): Value for FILE_BASENAME= is not a file name
+ */
+static void
+gts_efunc_at_seg_assign_file_basename(Mapfile *mf, Token tok,
+ ld_map_tkval_t *tkv)
+{
+ Conv_inv_buf_t inv_buf;
+
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_FILNAM),
+ MSG_ORIG(MSG_MAPKW_FILE_BASENAME),
+ ld_map_tokenstr(tok, tkv, &inv_buf));
+}
+
+/*
+ * segment_directive segment_name { ASSIGN { FILE_BASENAME = file_name
+ * ---------------------------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_seg_assign_file_basename(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ Ent_desc *enp = uvalue;
+ ld_map_tkval_t tkv;
+
+ /* file_name */
+ if (gettoken_str(mf, 0, &tkv, gts_efunc_at_seg_assign_file_basename) ==
+ TK_ERROR)
+ return (TK_ERROR);
+
+ if (!ld_map_seg_ent_files(mf, enp, TYP_ECF_BASENAME, tkv.tkv_str))
+ return (TK_ERROR);
+
+ /* terminator */
+ return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_FILE_BASENAME)));
+}
+
+/*
+ * at_seg_assign_file_objname(): Value for FILE_OBJNAME= is not an object name
+ */
+static void
+gts_efunc_at_seg_assign_file_objname(Mapfile *mf, Token tok,
+ ld_map_tkval_t *tkv)
+{
+ Conv_inv_buf_t inv_buf;
+
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_OBJNAM),
+ MSG_ORIG(MSG_MAPKW_FILE_OBJNAME),
+ ld_map_tokenstr(tok, tkv, &inv_buf));
+}
+
+/*
+ * segment_directive segment_name { ASSIGN { FILE_OBJNAME = name
+ * --------------------------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_seg_assign_file_objname(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ Ent_desc *enp = uvalue;
+ ld_map_tkval_t tkv;
+
+ /* file_objname */
+ if (gettoken_str(mf, 0, &tkv, gts_efunc_at_seg_assign_file_objname) ==
+ TK_ERROR)
+ return (TK_ERROR);
+
+ if (!ld_map_seg_ent_files(mf, enp, TYP_ECF_OBJNAME, tkv.tkv_str))
+ return (TK_ERROR);
+
+ /* terminator */
+ return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_FILE_OBJNAME)));
+}
+
+/*
+ * at_seg_assign_file_path(): Value for FILE_PATH= is not a file path
+ */
+static void
+gts_efunc_at_seg_assign_file_path(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
+{
+ Conv_inv_buf_t inv_buf;
+
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_FILPATH),
+ MSG_ORIG(MSG_MAPKW_FILE_PATH),
+ ld_map_tokenstr(tok, tkv, &inv_buf));
+}
+
+/*
+ * segment_directive segment_name { ASSIGN { FILE_PATH = file_path
+ * -----------------------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_seg_assign_file_path(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ Ent_desc *enp = uvalue;
+ ld_map_tkval_t tkv;
+
+ /* file_path */
+ if (gettoken_str(mf, 0, &tkv, gts_efunc_at_seg_assign_file_path) ==
+ TK_ERROR)
+ return (TK_ERROR);
+
+ if (!ld_map_seg_ent_files(mf, enp, TYP_ECF_PATH, tkv.tkv_str))
+ return (TK_ERROR);
+
+ /* terminator */
+ return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_FILE_PATH)));
+}
+
+/*
+ * segment_directive segment_name { ASSIGN { FLAGS = ... ;
+ * -------------------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_seg_assign_flags(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ typedef struct {
+ const char *name;
+ Word value;
+ } secflag_t;
+ static secflag_t flag_list[] = {
+ { MSG_ORIG(MSG_MAPKW_ALLOC), SHF_ALLOC },
+ { MSG_ORIG(MSG_MAPKW_EXECUTE), SHF_EXECINSTR },
+ { MSG_ORIG(MSG_MAPKW_WRITE), SHF_WRITE },
+ { MSG_ORIG(MSG_MAPKW_AMD64_LARGE), SHF_AMD64_LARGE },
+
+ /* List must be null terminated */
+ { 0 },
+ };
+
+ /*
+ * Size of buffer needed to format the names in flag_list[]. Must
+ * be kept in sync with flag_list.
+ */
+ static size_t flag_list_bufsize =
+ KW_NAME_SIZE(MSG_MAPKW_ALLOC) +
+ KW_NAME_SIZE(MSG_MAPKW_EXECUTE) +
+ KW_NAME_SIZE(MSG_MAPKW_WRITE) +
+ KW_NAME_SIZE(MSG_MAPKW_AMD64_LARGE);
+
+ Ent_desc *enp = uvalue;
+ int bcnt = 0, cnt = 0;
+ secflag_t *flag;
+ int done;
+ Token tok;
+ ld_map_tkval_t tkv;
+ Conv_inv_buf_t inv_buf;
+
+ /* Read and process tokens until the closing terminator is seen */
+ for (done = 0; done == 0; ) {
+ switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
+ case TK_ERROR:
+ return (TK_ERROR);
+
+ case TK_BANG:
+ /* Ensure ! only specified once per flag */
+ if (bcnt != 0) {
+ mf_fatal0(mf, MSG_INTL(MSG_MAP_SFLG_ONEBANG));
+ return (TK_ERROR);
+ }
+ bcnt++;
+ break;
+
+ case TK_STRING:
+ flag = ld_map_kwfind(tkv.tkv_str, flag_list,
+ SGSOFFSETOF(secflag_t, name), sizeof (flag[0]));
+ if (flag == NULL)
+ goto bad_flag;
+ cnt++;
+ enp->ec_attrmask |= flag->value;
+ if (bcnt == 0)
+ enp->ec_attrbits |= flag->value;
+ bcnt = 0;
+ break;
+
+ case TK_RIGHTBKT:
+ case TK_SEMICOLON:
+ done = 1;
+ break;
+
+ default:
+ bad_flag:
+ {
+ char buf[flag_list_bufsize];
+
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SECFLAG),
+ ld_map_kwnames(flag_list,
+ SGSOFFSETOF(secflag_t, name),
+ sizeof (flag[0]), buf, flag_list_bufsize),
+ ld_map_tokenstr(tok, &tkv, &inv_buf));
+ }
+ return (TK_ERROR);
+ }
+ }
+
+ /*
+ * Ensure that a trailing '!' was not left at the end of the line
+ * without a corresponding flag to apply it to.
+ */
+ if (bcnt != 0) {
+ mf_fatal0(mf, MSG_INTL(MSG_MAP_SFLG_EXBANG));
+ return (TK_ERROR);
+ }
+
+ /* Make sure there was at least one flag */
+ if (cnt == 0) {
+ mf_fatal(mf, MSG_INTL(MSG_MAP_NOVALUES),
+ MSG_ORIG(MSG_MAPKW_FLAGS));
+ return (TK_ERROR);
+ }
+
+ return (tok); /* Either TK_SEMICOLON or TK_RIGHTBKT */
+}
+
+/*
+ * at_seg_assign_is_name(): Value for IS_NAME= is not a section name
+ */
+static void
+gts_efunc_at_seg_assign_is_name(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
+{
+ Conv_inv_buf_t inv_buf;
+
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SECNAM),
+ MSG_ORIG(MSG_MAPKW_IS_NAME), ld_map_tokenstr(tok, tkv, &inv_buf));
+}
+
+/*
+ * segment_directive segment_name { ASSIGN { IS_NAME = section_name ;
+ * ---------------------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_seg_assign_is_name(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ Ent_desc *enp = uvalue;
+ ld_map_tkval_t tkv;
+
+ /* section_name */
+ if (gettoken_str(mf, 0, &tkv, gts_efunc_at_seg_assign_is_name) ==
+ TK_ERROR)
+ return (TK_ERROR);
+ enp->ec_is_name = tkv.tkv_str;
+
+ /* terminator */
+ return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_IS_NAME)));
+}
+
+/*
+ * at_seg_assign_type(): Value for TYPE= is not a section type
+ */
+static void
+gts_efunc_at_seg_assign_type(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
+{
+ Conv_inv_buf_t inv_buf;
+
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SHTYPE),
+ ld_map_tokenstr(tok, tkv, &inv_buf));
+}
+
+/*
+ * segment_directive segment_name { ASSIGN { TYPE = section_type ;
+ * ------------------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_seg_assign_type(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ Ent_desc *enp = uvalue;
+ ld_map_tkval_t tkv;
+ conv_strtol_uvalue_t conv_uvalue;
+
+ /* section type */
+ if (gettoken_str(mf, TK_F_KEYWORD, &tkv,
+ gts_efunc_at_seg_assign_type) == TK_ERROR)
+ return (TK_ERROR);
+
+ /*
+ * Use the libconv iteration facility to map the given name to
+ * its value. This allows us to keep up with any new sections
+ * without having to change this code.
+ */
+ if (conv_iter_strtol_init(tkv.tkv_str, &conv_uvalue) != 0) {
+ conv_iter_ret_t status;
+
+ /* Look at the canonical form */
+ status = conv_iter_sec_type(CONV_OSABI_ALL, CONV_MACH_ALL,
+ CONV_FMT_ALT_CF, conv_iter_strtol, &conv_uvalue);
+
+ /* Failing that, look at the normal form */
+ if (status != CONV_ITER_DONE)
+ (void) conv_iter_sec_type(CONV_OSABI_ALL,
+ CONV_MACH_ALL, CONV_FMT_ALT_NF, conv_iter_strtol,
+ &conv_uvalue);
+
+ /* If we didn't match anything report error */
+ if (!conv_uvalue.csl_found) {
+ gts_efunc_at_seg_assign_type(mf, TK_STRING, &tkv);
+ return (TK_ERROR);
+ }
+ }
+
+ enp->ec_type = conv_uvalue.csl_value;
+
+ /* terminator */
+ return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_TYPE)));
+}
+
+/*
+ * segment_directive segment_name { ASSIGN { ...
+ * -----------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_seg_assign(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ /* segment_directive ASSIGN sub-attributes */
+ static attr_t attr_list[] = {
+ { MSG_ORIG(MSG_MAPKW_FILE_BASENAME),
+ at_seg_assign_file_basename, ATTR_FMT_EQ },
+ { MSG_ORIG(MSG_MAPKW_FILE_OBJNAME),
+ at_seg_assign_file_objname, ATTR_FMT_EQ },
+ { MSG_ORIG(MSG_MAPKW_FILE_PATH),
+ at_seg_assign_file_path, ATTR_FMT_EQ },
+ { MSG_ORIG(MSG_MAPKW_FLAGS),
+ at_seg_assign_flags, ATTR_FMT_EQ_ALL },
+ { MSG_ORIG(MSG_MAPKW_IS_NAME),
+ at_seg_assign_is_name, ATTR_FMT_EQ },
+ { MSG_ORIG(MSG_MAPKW_TYPE),
+ at_seg_assign_type, ATTR_FMT_EQ },
+
+ /* List must be null terminated */
+ { 0 }
+ };
+
+ /*
+ * Size of buffer needed to format the names in attr_list[]. Must
+ * be kept in sync with attr_list.
+ */
+ static size_t attr_list_bufsize =
+ KW_NAME_SIZE(MSG_MAPKW_FILE_BASENAME) +
+ KW_NAME_SIZE(MSG_MAPKW_FILE_PATH) +
+ KW_NAME_SIZE(MSG_MAPKW_FLAGS) +
+ KW_NAME_SIZE(MSG_MAPKW_FILE_OBJNAME) +
+ KW_NAME_SIZE(MSG_MAPKW_IS_NAME) +
+ KW_NAME_SIZE(MSG_MAPKW_TYPE);
+
+ Sg_desc *sgp = uvalue;
+ Token tok;
+ ld_map_tkval_t tkv;
+ Conv_inv_buf_t inv_buf;
+ const char *name = NULL;
+ Ent_desc *enp;
+
+ /*
+ * ASSIGN takes an optional name, plus attributes are optional,
+ * so expect a name, an opening '{', or a ';'.
+ */
+ tok = ld_map_gettoken(mf, 0, &tkv);
+ switch (tok) {
+ case TK_ERROR:
+ return (TK_ERROR);
+
+ case TK_STRING:
+ name = tkv.tkv_str;
+ tok = ld_map_gettoken(mf, 0, &tkv);
+ break;
+ }
+
+ /* Add a new entrance criteria descriptor to the segment */
+ if ((enp = ld_map_seg_ent_add(mf, sgp, name)) == NULL)
+ return (TK_ERROR);
+
+ /* Having handled the name, expect either '{' or ';' */
+ switch (tok) {
+ default:
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEMLBKT),
+ MSG_ORIG(MSG_MAPKW_ASSIGN_SECTION),
+ ld_map_tokenstr(tok, &tkv, &inv_buf));
+ return (TK_ERROR);
+ case TK_ERROR:
+ return (TK_ERROR);
+ case TK_SEMICOLON:
+ case TK_RIGHTBKT:
+ /* No attributes: It will match anything */
+ enp->ec_flags |= FLG_EC_CATCHALL;
+ break;
+ case TK_LEFTBKT:
+ /* Parse the attributes */
+ if (parse_attributes(mf, MSG_ORIG(MSG_MAPKW_ASSIGN_SECTION),
+ attr_list, attr_list_bufsize, enp) == TK_ERROR)
+ return (TK_ERROR);
+
+ /* Terminating ';', or '}' which also terminates caller */
+ tok = gettoken_term(mf, MSG_ORIG(MSG_MAPKW_ASSIGN_SECTION));
+ if (tok == TK_ERROR)
+ return (TK_ERROR);
+ break;
+ }
+
+ DBG_CALL(Dbg_map_ent(mf->mf_ofl->ofl_lml, enp, mf->mf_ofl,
+ mf->mf_lineno));
+ return (tok);
+}
+
+/*
+ * segment_directive segment_name { DISABLE ;
+ * ----------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_seg_disable(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ Sg_desc *sgp = uvalue;
+
+ /* If the segment cannot be disabled, issue error */
+ if (sgp->sg_flags & FLG_SG_NODISABLE) {
+ mf_fatal(mf, MSG_INTL(MSG_MAP_CNTDISSEG), sgp->sg_name);
+ return (TK_ERROR);
+ }
+
+ /* Disable the segment */
+ sgp->sg_flags |= FLG_SG_DISABLED;
+
+ /* terminator */
+ return (gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_DISABLE)));
+}
+
+/*
+ * segment_directive segment_name { FLAGS eq-op ...
+ * --------------------------------------------^
+ *
+ * Note that this routine is also used for the STACK directive,
+ * as STACK also manipulates a segment descriptor.
+ *
+ * STACK { FLAGS eq-op ... ;
+ * -------------------^
+ */
+/* ARGSUSED 2 */
+static Token
+at_seg_flags(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ Sg_desc *sgp = uvalue;
+ Token tok;
+ Xword flags;
+
+ tok = parse_segment_flags(mf, &flags);
+ if (tok == TK_ERROR)
+ return (TK_ERROR);
+
+ setflags_eq(&sgp->sg_phdr.p_flags, eq_tok, flags);
+ sgp->sg_flags |= FLG_SG_P_FLAGS;
+
+ return (tok);
+}
+
+/*
+ * segment_directive segment_name { IS_ORDER eq_op value
+ * -----------------------------------------------^
+ */
+/* ARGSUSED 2 */
+static Token
+at_seg_is_order(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ Sg_desc *sgp = uvalue;
+ Token tok;
+ ld_map_tkval_t tkv;
+ Conv_inv_buf_t inv_buf;
+ int done;
+ Aliste idx;
+ Ent_desc *enp, *enp2;
+
+ /*
+ * The '=' form of assignment resets the list. The list contains
+ * pointers to our mapfile text, so we do not have to free anything.
+ */
+ if (eq_tok == TK_EQUAL)
+ aplist_reset(sgp->sg_is_order);
+
+ /*
+ * One or more ASSIGN names, terminated by a semicolon.
+ */
+ for (done = 0; done == 0; ) {
+ switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
+ case TK_ERROR:
+ return (TK_ERROR);
+
+ case TK_STRING:
+ /*
+ * The referenced entrance criteria must have
+ * already been defined.
+ */
+ enp = ld_ent_lookup(mf->mf_ofl, tkv.tkv_str, NULL);
+ if (enp == NULL) {
+ mf_fatal(mf, MSG_INTL(MSG_MAP_UNKENT),
+ tkv.tkv_str);
+ return (TK_ERROR);
+ }
+
+ /*
+ * Make sure it's not already on the list
+ */
+ for (APLIST_TRAVERSE(sgp->sg_is_order, idx, enp2))
+ if (enp == enp2) {
+ mf_fatal(mf,
+ MSG_INTL(MSG_MAP_DUP_IS_ORD),
+ tkv.tkv_str);
+ return (TK_ERROR);
+ }
+
+ /* Put it at the end of the order list */
+ if (aplist_append(&sgp->sg_is_order, enp,
+ AL_CNT_SG_IS_ORDER) == NULL)
+ return (TK_ERROR);
+ break;
+
+ case TK_SEMICOLON:
+ case TK_RIGHTBKT:
+ done = 1;
+ break;
+
+ default:
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_ECNAM),
+ ld_map_tokenstr(tok, &tkv, &inv_buf));
+ return (TK_ERROR);
+ }
+ }
+
+ return (tok);
+}
+
+/*
+ * segment_directive segment_name { MAX_SIZE = value
+ * -------------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_seg_max_size(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ Sg_desc *sgp = uvalue;
+ ld_map_tkval_t tkv;
+
+ /* value */
+ if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_MAX_SIZE), &tkv) == TK_ERROR)
+ return (TK_ERROR);
+
+ sgp->sg_length = tkv.tkv_int.tkvi_value;
+ sgp->sg_flags |= FLG_SG_LENGTH;
+
+ /* terminator */
+ return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_MAX_SIZE)));
+}
+
+/*
+ * segment_directive segment_name { NOHDR ;
+ * --------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_seg_nohdr(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ Sg_desc *sgp = uvalue;
+
+ /*
+ * Set the nohdr flag on the segment. If this segment is the
+ * first loadable segment, the ELF and program headers will
+ * not be included.
+ *
+ * The HDR_NOALLOC top level directive is preferred. This feature
+ * exists to give 1:1 feature parity with version 1 mapfiles that
+ * use the ?N segment flag and expect it to only take effect
+ * if that segment ends up being first.
+ */
+ sgp->sg_flags |= FLG_SG_NOHDR;
+
+ /* terminator */
+ return (gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_NOHDR)));
+}
+
+/*
+ * segment_directive segment_name { OS_ORDER eq_op assign_name...
+ * -----------------------------------------------^
+ */
+/* ARGSUSED 2 */
+static Token
+at_seg_os_order(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ Sg_desc *sgp = uvalue;
+ Token tok;
+ ld_map_tkval_t tkv;
+ Conv_inv_buf_t inv_buf;
+ int done;
+
+ /*
+ * The '=' form of assignment resets the list. The list contains
+ * pointers to our mapfile text, so we do not have to free anything.
+ */
+ if (eq_tok == TK_EQUAL)
+ alist_reset(sgp->sg_os_order);
+
+ /*
+ * One or more section names, terminated by a semicolon.
+ */
+ for (done = 0; done == 0; ) {
+ switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
+ case TK_ERROR:
+ return (TK_ERROR);
+
+ case TK_STRING:
+ if (!ld_map_seg_os_order_add(mf, sgp, tkv.tkv_str))
+ return (TK_ERROR);
+ break;
+
+ case TK_SEMICOLON:
+ case TK_RIGHTBKT:
+ done = 1;
+ break;
+
+ default:
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SECNAM),
+ ld_map_tokenstr(tok, &tkv, &inv_buf));
+ return (TK_ERROR);
+ }
+ }
+
+ return (tok);
+}
+
+/*
+ * segment_directive segment_name { PADDR = paddr
+ * ----------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_seg_paddr(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ Sg_desc *sgp = uvalue, *sgp2;
+ Aliste idx;
+ ld_map_tkval_t tkv;
+
+ /*
+ * Ensure that the segment isn't in the segment order list.
+ */
+ for (APLIST_TRAVERSE(mf->mf_ofl->ofl_segs_order, idx, sgp2))
+ if (sgp == sgp2) {
+ mf_fatal(mf,
+ MSG_INTL(MSG_MAP_CNTADDRORDER), sgp->sg_name);
+ return (TK_ERROR);
+ }
+
+ /* value */
+ if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_PADDR), &tkv) == TK_ERROR)
+ return (TK_ERROR);
+
+ sgp->sg_phdr.p_paddr = tkv.tkv_int.tkvi_value;
+ sgp->sg_flags |= FLG_SG_P_PADDR;
+
+ /* terminator */
+ return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_PADDR)));
+}
+
+/*
+ * segment_directive segment_name { ROUND = value
+ * ----------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_seg_round(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ Sg_desc *sgp = uvalue;
+ ld_map_tkval_t tkv;
+
+ /* value */
+ if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_ROUND), &tkv) == TK_ERROR)
+ return (TK_ERROR);
+
+ sgp->sg_round = tkv.tkv_int.tkvi_value;
+ sgp->sg_flags |= FLG_SG_ROUND;
+
+ /* terminator */
+ return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_ROUND)));
+}
+
+/*
+ * segment_directive segment_name { SIZE_SYMBOL = symbol_name
+ * ----------------------------------------------^
+ */
+/* ARGSUSED 2 */
+static Token
+at_seg_size_symbol(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ Sg_desc *sgp = uvalue;
+ Token tok;
+ ld_map_tkval_t tkv;
+ Conv_inv_buf_t inv_buf;
+ int done, cnt = 0;
+
+ /*
+ * One or more symbol names, terminated by a semicolon.
+ */
+ for (done = 0; done == 0; ) {
+ switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
+ case TK_ERROR:
+ return (TK_ERROR);
+
+ case TK_STRING:
+ if (!ld_map_seg_size_symbol(mf, sgp, eq_tok,
+ tkv.tkv_str))
+ return (TK_ERROR);
+ cnt++;
+
+ /*
+ * If the operator is TK_EQUAL, turn it into
+ * TK_PLUSEQ for any symbol names after the first.
+ * These additional symbols are added, and are not
+ * replacements for the first one.
+ */
+ eq_tok = TK_PLUSEQ;
+ break;
+
+ case TK_SEMICOLON:
+ case TK_RIGHTBKT:
+ done = 1;
+ break;
+
+ default:
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SYMNAM),
+ MSG_ORIG(MSG_MAPKW_SIZE_SYMBOL),
+ ld_map_tokenstr(tok, &tkv, &inv_buf));
+ return (TK_ERROR);
+ }
+ }
+
+ /* Make sure there was at least one name */
+ if (cnt == 0) {
+ mf_fatal(mf, MSG_INTL(MSG_MAP_NOVALUES),
+ MSG_ORIG(MSG_MAPKW_SIZE_SYMBOL));
+ return (TK_ERROR);
+ }
+
+ return (tok);
+}
+
+/*
+ * segment_directive segment_name { VADDR = vaddr
+ * ----------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_seg_vaddr(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ Sg_desc *sgp = uvalue, *sgp2;
+ Aliste idx;
+ ld_map_tkval_t tkv;
+
+ /*
+ * Ensure that the segment isn't in the segment order list.
+ */
+ for (APLIST_TRAVERSE(mf->mf_ofl->ofl_segs_order, idx, sgp2))
+ if (sgp == sgp2) {
+ mf_fatal(mf,
+ MSG_INTL(MSG_MAP_CNTADDRORDER), sgp->sg_name);
+ return (TK_ERROR);
+ }
+
+ /* value */
+ if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_VADDR), &tkv) == TK_ERROR)
+ return (TK_ERROR);
+
+ sgp->sg_phdr.p_vaddr = tkv.tkv_int.tkvi_value;
+ sgp->sg_flags |= FLG_SG_P_VADDR;
+
+ /* terminator */
+ return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_VADDR)));
+}
+
+/*
+ * Top Level Directive:
+ *
+ * {LOAD|NOTE|NULL}_SEGMENT segment_name { ...
+ * ------------------------^
+ *
+ * Common implementation body for the family of segment directives. These
+ * take the same syntax, and share a common subset of attributes. They differ
+ * in the type of segments they handle and the specific attributes accepted.
+ *
+ * entry:
+ * mf - Mapfile descriptor ({LOAD|NOTE|NULL}_SEGMENT)
+ * dir_name - Name of directive.
+ * seg_type - Type of segment (PT_LOAD, PT_NOTE, PT_NULL).
+ * attr_list - NULL terminated attribute array
+ * attr_list_bufsize - Size of required buffer to format all the
+ * names in attr_list.
+ * gts_efunc - Error function to pass to gettoken_str() when trying
+ * to obtain a segment name token.
+ */
+static Token
+dir_segment_inner(Mapfile *mf, const char *dir_name, Word seg_type,
+ attr_t *attr_list, size_t attr_list_bufsize, gts_efunc_t gts_efunc)
+{
+ Token tok;
+ ld_map_tkval_t tkv;
+ Sg_desc *sgp;
+ Boolean new_segment;
+ Xword ndx;
+ avl_index_t where;
+
+ /* segment_name */
+ if (gettoken_str(mf, 0, &tkv, gts_efunc) == TK_ERROR)
+ return (TK_ERROR);
+ sgp = ld_seg_lookup(mf->mf_ofl, tkv.tkv_str, &where);
+ new_segment = (sgp == NULL);
+
+ if (new_segment) {
+ /* Allocate a descriptor for new segment */
+ if ((sgp = ld_map_seg_alloc(tkv.tkv_str, seg_type,
+ FLG_SG_P_TYPE)) == NULL)
+ return (TK_ERROR);
+ } else {
+ /* Make sure it's the right type of segment */
+ if (sgp->sg_phdr.p_type != seg_type) {
+ Conv_inv_buf_t inv_buf;
+
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXPSEGTYPE),
+ conv_phdr_type(ELFOSABI_SOLARIS, ld_targ.t_m.m_mach,
+ sgp->sg_phdr.p_type, CONV_FMT_ALT_CF, &inv_buf),
+ dir_name, tkv.tkv_str);
+ return (TK_ERROR);
+ }
+
+ /* If it was disabled, being referenced enables it */
+ sgp->sg_flags &= ~FLG_SG_DISABLED;
+
+ if (DBG_ENABLED) {
+ /*
+ * Not a new segment, so show the initial value
+ * before modifying it.
+ */
+ ndx = ld_map_seg_index(mf, sgp);
+ DBG_CALL(Dbg_map_seg(mf->mf_ofl, DBG_STATE_MOD_BEFORE,
+ ndx, sgp, mf->mf_lineno));
+ }
+ }
+
+ /*
+ * Attributes are optional, so expect an opening '{', or a ';'.
+ */
+ switch (tok = gettoken_optattr(mf, dir_name)) {
+ default:
+ tok = TK_ERROR;
+ break;
+ case TK_SEMICOLON:
+ break;
+ case TK_LEFTBKT:
+ /* Parse the attributes */
+ if (parse_attributes(mf, dir_name,
+ attr_list, attr_list_bufsize, sgp) == TK_ERROR)
+ return (TK_ERROR);
+
+ /* Terminating ';' */
+ tok = gettoken_semicolon(mf, dir_name);
+ if (tok == TK_ERROR)
+ return (TK_ERROR);
+
+ break;
+ }
+
+ /*
+ * If this is a new segment, finish its initialization
+ * and insert it into the segment list.
+ */
+ if (new_segment) {
+ if (ld_map_seg_insert(mf, DBG_STATE_NEW, sgp, where) ==
+ SEG_INS_FAIL)
+ return (TK_ERROR);
+ } else {
+ /* Not new. Show what's changed */
+ DBG_CALL(Dbg_map_seg(mf->mf_ofl, DBG_STATE_MOD_AFTER,
+ ndx, sgp, mf->mf_lineno));
+ }
+
+ return (tok);
+}
+
+/*
+ * dir_load_segment(): Expected loadable segment name is not present
+ */
+static void
+gts_efunc_dir_load_segment(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
+{
+ Conv_inv_buf_t inv_buf;
+
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEGNAM),
+ MSG_ORIG(MSG_MAPKW_LOAD_SEGMENT),
+ ld_map_tokenstr(tok, tkv, &inv_buf));
+}
+
+/*
+ * Top Level Directive:
+ *
+ * LOAD_SEGMENT segment_name { ...
+ * ------------^
+ */
+static Token
+dir_load_segment(Mapfile *mf)
+{
+ /* LOAD_SEGMENT attributes */
+ static attr_t attr_list[] = {
+ { MSG_ORIG(MSG_MAPKW_ALIGN), at_seg_align, ATTR_FMT_EQ },
+ { MSG_ORIG(MSG_MAPKW_ASSIGN_SECTION),
+ at_seg_assign, ATTR_FMT_NAME },
+ { MSG_ORIG(MSG_MAPKW_DISABLE), at_seg_disable, ATTR_FMT_NAME },
+ { MSG_ORIG(MSG_MAPKW_FLAGS), at_seg_flags,
+ ATTR_FMT_EQ_ALL },
+ { MSG_ORIG(MSG_MAPKW_IS_ORDER), at_seg_is_order,
+ ATTR_FMT_EQ_PEQ },
+ { MSG_ORIG(MSG_MAPKW_MAX_SIZE), at_seg_max_size, ATTR_FMT_EQ },
+ { MSG_ORIG(MSG_MAPKW_NOHDR), at_seg_nohdr, ATTR_FMT_NAME },
+ { MSG_ORIG(MSG_MAPKW_OS_ORDER), at_seg_os_order,
+ ATTR_FMT_EQ_PEQ },
+ { MSG_ORIG(MSG_MAPKW_PADDR), at_seg_paddr, ATTR_FMT_EQ },
+ { MSG_ORIG(MSG_MAPKW_ROUND), at_seg_round, ATTR_FMT_EQ },
+ { MSG_ORIG(MSG_MAPKW_SIZE_SYMBOL),
+ at_seg_size_symbol, ATTR_FMT_EQ_PEQ },
+ { MSG_ORIG(MSG_MAPKW_VADDR), at_seg_vaddr, ATTR_FMT_EQ },
+
+ /* List must be null terminated */
+ { 0 }
+ };
+
+ /*
+ * Size of buffer needed to format the names in attr_list[]. Must
+ * be kept in sync with attr_list.
+ */
+ static size_t attr_list_bufsize =
+ KW_NAME_SIZE(MSG_MAPKW_ALIGN) +
+ KW_NAME_SIZE(MSG_MAPKW_ASSIGN_SECTION) +
+ KW_NAME_SIZE(MSG_MAPKW_DISABLE) +
+ KW_NAME_SIZE(MSG_MAPKW_FLAGS) +
+ KW_NAME_SIZE(MSG_MAPKW_IS_ORDER) +
+ KW_NAME_SIZE(MSG_MAPKW_MAX_SIZE) +
+ KW_NAME_SIZE(MSG_MAPKW_PADDR) +
+ KW_NAME_SIZE(MSG_MAPKW_ROUND) +
+ KW_NAME_SIZE(MSG_MAPKW_OS_ORDER) +
+ KW_NAME_SIZE(MSG_MAPKW_SIZE_SYMBOL) +
+ KW_NAME_SIZE(MSG_MAPKW_VADDR);
+
+ return (dir_segment_inner(mf, MSG_ORIG(MSG_MAPKW_LOAD_SEGMENT),
+ PT_LOAD, attr_list, attr_list_bufsize, gts_efunc_dir_load_segment));
+
+}
+
+/*
+ * Common shared segment directive attributes
+ */
+static attr_t segment_core_attr_list[] = {
+ { MSG_ORIG(MSG_MAPKW_ASSIGN_SECTION), at_seg_assign, ATTR_FMT_NAME },
+ { MSG_ORIG(MSG_MAPKW_DISABLE), at_seg_disable, ATTR_FMT_NAME },
+ { MSG_ORIG(MSG_MAPKW_IS_ORDER), at_seg_is_order, ATTR_FMT_EQ_PEQ },
+ { MSG_ORIG(MSG_MAPKW_OS_ORDER), at_seg_os_order, ATTR_FMT_EQ_PEQ },
+
+ /* List must be null terminated */
+ { 0 }
+};
+
+/*
+ * Size of buffer needed to format the names in segment_core_attr_list[].
+ * Must be kept in sync with segment_core_attr_list.
+ */
+static size_t segment_core_attr_list_bufsize =
+ KW_NAME_SIZE(MSG_MAPKW_ASSIGN_SECTION) +
+ KW_NAME_SIZE(MSG_MAPKW_DISABLE) +
+ KW_NAME_SIZE(MSG_MAPKW_IS_ORDER) +
+ KW_NAME_SIZE(MSG_MAPKW_OS_ORDER);
+
+/*
+ * dir_note_segment(): Expected note segment name is not present
+ */
+static void
+gts_efunc_dir_note_segment(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
+{
+ Conv_inv_buf_t inv_buf;
+
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEGNAM),
+ MSG_ORIG(MSG_MAPKW_NOTE_SEGMENT),
+ ld_map_tokenstr(tok, tkv, &inv_buf));
+}
+
+/*
+ * Top Level Directive:
+ *
+ * NOTE_SEGMENT segment_name { ...
+ * ------------^
+ */
+static Token
+dir_note_segment(Mapfile *mf)
+{
+ return (dir_segment_inner(mf, MSG_ORIG(MSG_MAPKW_NOTE_SEGMENT),
+ PT_NOTE, segment_core_attr_list, segment_core_attr_list_bufsize,
+ gts_efunc_dir_note_segment));
+
+}
+
+/*
+ * dir_null_segment(): Expected null segment name is not present
+ */
+static void
+gts_efunc_dir_null_segment(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
+{
+ Conv_inv_buf_t inv_buf;
+
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEGNAM),
+ MSG_ORIG(MSG_MAPKW_NULL_SEGMENT),
+ ld_map_tokenstr(tok, tkv, &inv_buf));
+}
+
+/*
+ * Top Level Directive:
+ *
+ * NULL_SEGMENT segment_name { ...
+ * ------------^
+ */
+static Token
+dir_null_segment(Mapfile *mf)
+{
+ return (dir_segment_inner(mf, MSG_ORIG(MSG_MAPKW_NULL_SEGMENT),
+ PT_NULL, segment_core_attr_list, segment_core_attr_list_bufsize,
+ gts_efunc_dir_null_segment));
+
+}
+
+/*
+ * Top Level Directive:
+ *
+ * SEGMENT_ORDER segment_name ... ;
+ */
+static Token
+dir_segment_order(Mapfile *mf)
+{
+ Token tok;
+ ld_map_tkval_t tkv;
+ Conv_inv_buf_t inv_buf;
+ Aliste idx;
+ Sg_desc *sgp, *sgp2;
+ int done;
+
+ /* Expect either a '=' or '+=' */
+ tok = gettoken_eq(mf, ATTR_FMT_EQ_PEQ,
+ MSG_ORIG(MSG_MAPKW_SEGMENT_ORDER));
+ if (tok == TK_ERROR)
+ return (TK_ERROR);
+
+ DBG_CALL(Dbg_map_seg_order(mf->mf_ofl, ELFOSABI_SOLARIS,
+ ld_targ.t_m.m_mach, DBG_STATE_MOD_BEFORE, mf->mf_lineno));
+
+ /*
+ * The '=' form of assignment resets the list. The list contains
+ * pointers to our mapfile text, so we do not have to free anything.
+ */
+ if (tok == TK_EQUAL)
+ aplist_reset(mf->mf_ofl->ofl_segs_order);
+
+ /* Read segment names, and add to list until terminator (';') is seen */
+ for (done = 0; done == 0; ) {
+ switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
+ case TK_ERROR:
+ return (TK_ERROR);
+
+ case TK_STRING:
+ /*
+ * The segment must have already been defined.
+ */
+ sgp = ld_seg_lookup(mf->mf_ofl, tkv.tkv_str, NULL);
+ if (sgp == NULL) {
+ mf_fatal(mf, MSG_INTL(MSG_MAP_UNKSEG),
+ tkv.tkv_str);
+ return (TK_ERROR);
+ }
+
+ /*
+ * Make sure it's not already on the list
+ */
+ for (APLIST_TRAVERSE(mf->mf_ofl->ofl_segs_order,
+ idx, sgp2))
+ if (sgp == sgp2) {
+ mf_fatal(mf,
+ MSG_INTL(MSG_MAP_DUPORDSEG),
+ MSG_ORIG(MSG_MAPKW_SEGMENT_ORDER),
+ tkv.tkv_str);
+ return (TK_ERROR);
+ }
+
+ /*
+ * It can't be ordered and also have an explicit
+ * paddr or vaddr.
+ */
+ if (sgp->sg_flags & (FLG_SG_P_PADDR | FLG_SG_P_VADDR)) {
+ mf_fatal(mf, MSG_INTL(MSG_MAP_CNTADDRORDER),
+ sgp->sg_name);
+ return (TK_ERROR);
+ }
+
+
+ /* Put it at the end of the list */
+ if (aplist_append(&mf->mf_ofl->ofl_segs_order, sgp,
+ AL_CNT_SG_IS_ORDER) == NULL)
+ return (TK_ERROR);
+ break;
+
+ case TK_SEMICOLON:
+ done = 1;
+ break;
+
+ default:
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SEGNAM),
+ MSG_ORIG(MSG_MAPKW_SEGMENT_ORDER),
+ ld_map_tokenstr(tok, &tkv, &inv_buf));
+ return (TK_ERROR);
+ }
+ }
+
+ DBG_CALL(Dbg_map_seg_order(mf->mf_ofl, ELFOSABI_SOLARIS,
+ ld_targ.t_m.m_mach, DBG_STATE_MOD_AFTER, mf->mf_lineno));
+
+ return (tok);
+}
+
+/*
+ * Top Level Directive:
+ *
+ * STACK { ...
+ * -----^
+ */
+static Token
+dir_stack(Mapfile *mf)
+{
+ /* STACK attributes */
+ static attr_t attr_list[] = {
+ { MSG_ORIG(MSG_MAPKW_FLAGS), at_seg_flags, ATTR_FMT_EQ_ALL },
+
+ /* List must be null terminated */
+ { 0 }
+ };
+
+ /*
+ * Size of buffer needed to format the names in attr_list[]. Must
+ * be kept in sync with attr_list.
+ */
+ static size_t attr_list_bufsize =
+ KW_NAME_SIZE(MSG_MAPKW_FLAGS);
+
+ Sg_desc *sgp;
+ Token tok;
+
+
+ /* Opening '{' token */
+ if (gettoken_leftbkt(mf, MSG_ORIG(MSG_MAPKW_STACK)) == TK_ERROR)
+ return (TK_ERROR);
+
+ /* Fetch the PT_SUNWSTACK segment descriptor */
+ sgp = ld_map_seg_stack(mf);
+
+ /* Parse the attributes */
+ if (parse_attributes(mf, MSG_ORIG(MSG_MAPKW_STACK),
+ attr_list, attr_list_bufsize, sgp) == TK_ERROR)
+ return (TK_ERROR);
+
+ /* Terminating ';' */
+ tok = gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_STACK));
+ if (tok == TK_ERROR)
+ return (TK_ERROR);
+
+ if (DBG_ENABLED) {
+ Xword ndx = ld_map_seg_index(mf, sgp);
+
+ Dbg_map_seg(mf->mf_ofl, DBG_STATE_MOD_AFTER, ndx, sgp,
+ mf->mf_lineno);
+ }
+
+ return (tok);
+}
+
+/*
+ * at_sym_aux(): Value for AUXILIARY= is not an object name
+ */
+static void
+gts_efunc_at_sym_aux(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
+{
+ Conv_inv_buf_t inv_buf;
+
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_OBJNAM),
+ MSG_ORIG(MSG_MAPKW_AUX), ld_map_tokenstr(tok, tkv, &inv_buf));
+}
+
+/*
+ * SYMBOL [version_name] { symbol_name { AUXILIARY = soname
+ * -------------------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_sym_aux(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ symbol_state_t *ss = uvalue;
+ ld_map_tkval_t tkv;
+
+ /* auxiliary filter soname */
+ if (gettoken_str(mf, 0, &tkv, gts_efunc_at_sym_aux) == TK_ERROR)
+ return (TK_ERROR);
+
+ ld_map_sym_filtee(mf, &ss->ss_mv, &ss->ss_ms, FLG_SY_AUXFLTR,
+ tkv.tkv_str);
+
+ /* terminator */
+ return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_AUX)));
+}
+
+/*
+ * at_sym_filter(): Value for FILTER= is not an object name
+ */
+static void
+gts_efunc_at_sym_filter(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
+{
+ Conv_inv_buf_t inv_buf;
+
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_OBJNAM),
+ MSG_ORIG(MSG_MAPKW_FILTER), ld_map_tokenstr(tok, tkv, &inv_buf));
+}
+
+/*
+ * SYMBOL [version_name] { symbol_name { FILTER = soname
+ * ----------------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_sym_filter(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ symbol_state_t *ss = uvalue;
+ ld_map_tkval_t tkv;
+
+ /* filter soname */
+ if (gettoken_str(mf, 0, &tkv, gts_efunc_at_sym_filter) == TK_ERROR)
+ return (TK_ERROR);
+
+ ld_map_sym_filtee(mf, &ss->ss_mv, &ss->ss_ms, FLG_SY_STDFLTR,
+ tkv.tkv_str);
+
+ /* terminator */
+ return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_FILTER)));
+}
+
+/*
+ * SYMBOL [version_name] { symbol_name { FLAGS = ...
+ * ---------------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_sym_flags(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ typedef struct {
+ const char *name;
+ sd_flag_t value;
+ } symflag_t;
+
+ static symflag_t symflag_list[] = {
+ { MSG_ORIG(MSG_MAPKW_DIRECT), FLG_SY_DIR },
+ { MSG_ORIG(MSG_MAPKW_DYNSORT), FLG_SY_DYNSORT },
+ { MSG_ORIG(MSG_MAPKW_EXTERN), FLG_SY_EXTERN },
+ { MSG_ORIG(MSG_MAPKW_INTERPOSE), FLG_SY_INTPOSE },
+ { MSG_ORIG(MSG_MAPKW_NODIRECT), FLG_SY_NDIR },
+ { MSG_ORIG(MSG_MAPKW_NODYNSORT), FLG_SY_NODYNSORT },
+ { MSG_ORIG(MSG_MAPKW_PARENT), FLG_SY_PARENT },
+
+ /* List must be null terminated */
+ { 0 }
+ };
+
+ /*
+ * Size of buffer needed to format the names in flag_list[]. Must
+ * be kept in sync with flag_list.
+ */
+ static size_t symflag_list_bufsize =
+ KW_NAME_SIZE(MSG_MAPKW_DIRECT) +
+ KW_NAME_SIZE(MSG_MAPKW_DYNSORT) +
+ KW_NAME_SIZE(MSG_MAPKW_EXTERN) +
+ KW_NAME_SIZE(MSG_MAPKW_INTERPOSE) +
+ KW_NAME_SIZE(MSG_MAPKW_NODIRECT) +
+ KW_NAME_SIZE(MSG_MAPKW_NODYNSORT) +
+ KW_NAME_SIZE(MSG_MAPKW_PARENT);
+
+ symbol_state_t *ss = uvalue;
+ int done;
+ symflag_t *symflag;
+ int cnt = 0;
+ Token tok;
+ ld_map_tkval_t tkv;
+ Conv_inv_buf_t inv_buf;
+ Ofl_desc *ofl = mf->mf_ofl;
+
+ for (done = 0; done == 0; ) {
+ switch (tok = ld_map_gettoken(mf, TK_F_KEYWORD, &tkv)) {
+ case TK_ERROR:
+ return (TK_ERROR);
+
+ case TK_STRING:
+ symflag = ld_map_kwfind(tkv.tkv_str, symflag_list,
+ SGSOFFSETOF(symflag_t, name), sizeof (symflag[0]));
+ if (symflag == NULL)
+ goto bad_flag;
+ cnt++;
+ /*
+ * Apply the flag:
+ *
+ * Although tempting to make all of this table-driven
+ * via added fields in symflag_t, there's enough
+ * variation in what each flag does to make that
+ * not quite worthwhile.
+ *
+ * Similarly, it is tempting to use common code to
+ * to do this work from map_support.c. However, the
+ * v1 code mixes unrelated things (flags, symbol types,
+ * value, size, etc) in single cascading series of
+ * strcmps, whereas our parsing separates those things
+ * from each other. Merging the code would require doing
+ * two strcmps for each item, or other complexity,
+ * which I judge not to be worthwhile.
+ */
+ switch (symflag->value) {
+ case FLG_SY_DIR:
+ ss->ss_ms.ms_sdflags |= FLG_SY_DIR;
+ ofl->ofl_flags |= FLG_OF_SYMINFO;
+ break;
+ case FLG_SY_DYNSORT:
+ ss->ss_ms.ms_sdflags |= FLG_SY_DYNSORT;
+ ss->ss_ms.ms_sdflags &= ~FLG_SY_NODYNSORT;
+ break;
+ case FLG_SY_EXTERN:
+ ss->ss_ms.ms_sdflags |= FLG_SY_EXTERN;
+ ofl->ofl_flags |= FLG_OF_SYMINFO;
+ break;
+ case FLG_SY_INTPOSE:
+ if (!(ofl->ofl_flags & FLG_OF_EXEC)) {
+ mf_fatal0(mf,
+ MSG_INTL(MSG_MAP_NOINTPOSE));
+ ss->ss_mv.mv_errcnt++;
+ break;
+ }
+ ss->ss_ms.ms_sdflags |= FLG_SY_INTPOSE;
+ ofl->ofl_flags |= FLG_OF_SYMINFO;
+ ofl->ofl_dtflags_1 |= DF_1_SYMINTPOSE;
+ break;
+ case FLG_SY_NDIR:
+ ss->ss_ms.ms_sdflags |= FLG_SY_NDIR;
+ ofl->ofl_flags |= FLG_OF_SYMINFO;
+ ofl->ofl_flags1 |=
+ (FLG_OF1_NDIRECT | FLG_OF1_NGLBDIR);
+ break;
+ case FLG_SY_NODYNSORT:
+ ss->ss_ms.ms_sdflags &= ~FLG_SY_DYNSORT;
+ ss->ss_ms.ms_sdflags |= FLG_SY_NODYNSORT;
+ break;
+ case FLG_SY_PARENT:
+ ss->ss_ms.ms_sdflags |= FLG_SY_PARENT;
+ ofl->ofl_flags |= FLG_OF_SYMINFO;
+ break;
+ }
+ break;
+ case TK_RIGHTBKT:
+ case TK_SEMICOLON:
+ done = 1;
+ break;
+
+ default:
+ bad_flag:
+ {
+ char buf[symflag_list_bufsize];
+
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SYMFLAG),
+ ld_map_kwnames(symflag_list,
+ SGSOFFSETOF(symflag_t, name),
+ sizeof (symflag[0]), buf,
+ symflag_list_bufsize),
+ ld_map_tokenstr(tok, &tkv, &inv_buf));
+ }
+ return (TK_ERROR);
+ }
+ }
+
+ /* Make sure there was at least one flag specified */
+ if (cnt == 0) {
+ mf_fatal(mf, MSG_INTL(MSG_MAP_NOVALUES),
+ MSG_ORIG(MSG_MAPKW_FLAGS));
+ return (TK_ERROR);
+ }
+
+ return (tok); /* Either TK_SEMICOLON or TK_RIGHTBKT */
+}
+
+/*
+ * SYMBOL [version_name] { symbol_name { SIZE = value
+ * --------------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_sym_size(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ symbol_state_t *ss = uvalue;
+ ld_map_tkval_t tkv;
+
+ /* value */
+ if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_SIZE), &tkv) == TK_ERROR)
+ return (TK_ERROR);
+
+ ss->ss_ms.ms_size = tkv.tkv_int.tkvi_value;
+
+ /* terminator */
+ return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_SIZE)));
+}
+
+typedef struct {
+ const char *name; /* type name */
+ Word ms_shndx; /* symbol section index */
+ uchar_t ms_type; /* STT_ symbol type */
+} at_sym_type_t;
+
+static at_sym_type_t at_sym_type_list[] = {
+ { MSG_ORIG(MSG_MAPKW_COMMON), SHN_COMMON, STT_OBJECT },
+ { MSG_ORIG(MSG_MAPKW_DATA), SHN_ABS, STT_OBJECT },
+ { MSG_ORIG(MSG_MAPKW_FUNCTION), SHN_ABS, STT_FUNC },
+
+ /* List must be null terminated */
+ { 0 }
+};
+
+/*
+ * Size of buffer needed to format the names in at_sym_type_list[]. Must
+ * be kept in sync with at_sym_type_list.
+ */
+static size_t at_sym_type_list_bufsize =
+ KW_NAME_SIZE(MSG_MAPKW_COMMON) +
+ KW_NAME_SIZE(MSG_MAPKW_DATA) +
+ KW_NAME_SIZE(MSG_MAPKW_FUNCTION);
+
+/*
+ * at_sym_type(): Value for TYPE= is not a symbol type
+ */
+static void
+gts_efunc_at_sym_type(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
+{
+ Conv_inv_buf_t inv_buf;
+ char buf[at_sym_type_list_bufsize];
+
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SYMTYPE),
+ ld_map_kwnames(at_sym_type_list, SGSOFFSETOF(at_sym_type_t, name),
+ sizeof (at_sym_type_list[0]), buf, at_sym_type_list_bufsize),
+ ld_map_tokenstr(tok, tkv, &inv_buf));
+}
+
+/*
+ * SYMBOL [version_name] { symbol_name { TYPE = symbol_type
+ * --------------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_sym_type(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ symbol_state_t *ss = uvalue;
+ at_sym_type_t *type;
+ ld_map_tkval_t tkv;
+
+ /* type keyword */
+ if (gettoken_str(mf, TK_F_KEYWORD, &tkv, gts_efunc_at_sym_type) ==
+ TK_ERROR)
+ return (TK_ERROR);
+
+ type = ld_map_kwfind(tkv.tkv_str, at_sym_type_list,
+ SGSOFFSETOF(at_sym_type_t, name), sizeof (type[0]));
+ if (type == NULL) {
+ gts_efunc_at_sym_type(mf, TK_STRING, &tkv);
+ return (TK_ERROR);
+ }
+
+ ss->ss_ms.ms_shndx = type->ms_shndx;
+ ss->ss_ms.ms_sdflags |= FLG_SY_SPECSEC;
+ ss->ss_ms.ms_type = type->ms_type;
+
+ /* terminator */
+ return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_TYPE)));
+}
+
+/*
+ * SYMBOL [version_name] { symbol_name { VALUE = value
+ * ---------------------------------------------^
+ */
+/* ARGSUSED 1 */
+static Token
+at_sym_value(Mapfile *mf, Token eq_tok, void *uvalue)
+{
+ symbol_state_t *ss = uvalue;
+ ld_map_tkval_t tkv;
+
+ /* value */
+ if (gettoken_int(mf, MSG_ORIG(MSG_MAPKW_VALUE), &tkv) == TK_ERROR)
+ return (TK_ERROR);
+
+ ss->ss_ms.ms_value = tkv.tkv_int.tkvi_value;
+ ss->ss_ms.ms_value_set = TRUE;
+
+
+ /* terminator */
+ return (gettoken_term(mf, MSG_ORIG(MSG_MAPKW_VALUE)));
+}
+
+/*
+ * Parse the attributes for a SCOPE or VERSION symbol directive.
+ *
+ * entry:
+ * mf - Mapfile descriptor
+ * dir_name - Name of directive.
+ * ss - Pointer to symbol state block that has had its ss_nv
+ * member initialzed via a call to ld_map_sym_ver_init().
+ *
+ * exit:
+ * parse_symbol_attributes() returns TK_RIGHTBKT on success, and TK_ERROR
+ * on failure.
+ */
+static Token
+parse_symbol_attributes(Mapfile *mf, const char *dir_name, symbol_state_t *ss)
+{
+ /* Symbol attributes */
+ static attr_t attr_list[] = {
+ { MSG_ORIG(MSG_MAPKW_AUX), at_sym_aux, ATTR_FMT_EQ },
+ { MSG_ORIG(MSG_MAPKW_FILTER), at_sym_filter, ATTR_FMT_EQ },
+ { MSG_ORIG(MSG_MAPKW_FLAGS), at_sym_flags, ATTR_FMT_EQ },
+ { MSG_ORIG(MSG_MAPKW_SIZE), at_sym_size, ATTR_FMT_EQ },
+ { MSG_ORIG(MSG_MAPKW_TYPE), at_sym_type, ATTR_FMT_EQ },
+ { MSG_ORIG(MSG_MAPKW_VALUE), at_sym_value, ATTR_FMT_EQ },
+
+ /* List must be null terminated */
+ { 0 }
+ };
+
+ /*
+ * Size of buffer needed to format the names in attr_list[]. Must
+ * be kept in sync with attr_list.
+ */
+ static size_t attr_list_bufsize =
+ KW_NAME_SIZE(MSG_MAPKW_AUX) +
+ KW_NAME_SIZE(MSG_MAPKW_FILTER) +
+ KW_NAME_SIZE(MSG_MAPKW_FLAGS) +
+ KW_NAME_SIZE(MSG_MAPKW_SIZE) +
+ KW_NAME_SIZE(MSG_MAPKW_TYPE) +
+ KW_NAME_SIZE(MSG_MAPKW_VALUE);
+
+ Token tok;
+ ld_map_tkval_t tkv, tkv_sym;
+ int done;
+ Conv_inv_buf_t inv_buf;
+
+ /* Read attributes until the closing '}' is seen */
+ for (done = 0; done == 0; ) {
+ /*
+ * We have to allow quotes around symbol names, but the
+ * name we read may also be a symbol scope keyword. We won't
+ * know which until we read the following token, and so have
+ * to allow quotes for both. Hence, symbol scope names can
+ * be quoted --- an unlikely occurrence and not worth
+ * complicating the code.
+ */
+ switch (tok = ld_map_gettoken(mf, 0, &tkv_sym)) {
+ case TK_ERROR:
+ return (TK_ERROR);
+
+ case TK_STRING:
+ /* Default value for all symbol attributes is 0 */
+ (void) memset(&ss->ss_ms, 0, sizeof (ss->ss_ms));
+ ss->ss_ms.ms_name = tkv_sym.tkv_str;
+
+ /*
+ * Turn off the WEAK flag to indicate that definitions
+ * are associated with this version. It would probably
+ * be more accurate to only remove this flag with the
+ * specification of global symbols, however setting it
+ * here allows enough slop to compensate for the
+ * various user inputs we've seen so far. Only if a
+ * closed version is specified (i.e., "SUNW_1.x {};")
+ * will a user get a weak version (which is how we
+ * document the creation of weak versions).
+ */
+ ss->ss_mv.mv_vdp->vd_flags &= ~VER_FLG_WEAK;
+
+ /*
+ * The meaning of this name depends on the following
+ * character:
+ *
+ * : Scope
+ * ; Symbol without attributes
+ * { Symbol with attributes
+ */
+ switch (tok = ld_map_gettoken(mf, 0, &tkv)) {
+ case TK_ERROR:
+ return (TK_ERROR);
+
+ case TK_COLON:
+ ld_map_sym_scope(mf, tkv_sym.tkv_str,
+ &ss->ss_mv);
+ break;
+ case TK_LEFTBKT:
+ /* name is a symbol with attributes */
+ if (parse_attributes(mf, tkv_sym.tkv_str,
+ attr_list, attr_list_bufsize, ss) ==
+ TK_ERROR)
+ return (TK_ERROR);
+ /* Terminating ';', or '}' */
+ tok = gettoken_term(mf,
+ MSG_INTL(MSG_MAP_SYMATTR));
+ if (tok == TK_ERROR)
+ return (TK_ERROR);
+ if (tok == TK_RIGHTBKT)
+ done = 1;
+
+ /* FALLTHROUGH */
+ case TK_SEMICOLON:
+ /*
+ * Add the new symbol. It should be noted that
+ * all symbols added by the mapfile start out
+ * with global scope, thus they will fall
+ * through the normal symbol resolution
+ * process. Symbols defined as locals will
+ * be reduced in scope after all input file
+ * processing.
+ */
+ if (!ld_map_sym_enter(mf, &ss->ss_mv,
+ &ss->ss_ms))
+ return (TK_ERROR);
+ break;
+ default:
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SYMDELIM),
+ ld_map_tokenstr(tok, &tkv, &inv_buf));
+ return (TK_ERROR);
+ }
+ break;
+
+ case TK_RIGHTBKT:
+ done = 1;
+ break;
+
+ case TK_SEMICOLON:
+ break; /* Ignore empty statement */
+
+ case TK_STAR:
+ /*
+ * Turn off the WEAK flag, as explained above for
+ * TK_STRING.
+ */
+ ss->ss_mv.mv_vdp->vd_flags &= ~VER_FLG_WEAK;
+
+ ld_map_sym_autoreduce(mf, &ss->ss_mv);
+
+ /*
+ * Following token must be ';' to terminate the stmt,
+ * or '}' to terminate the whole directive.
+ */
+ switch (tok = gettoken_term(mf, dir_name)) {
+ case TK_ERROR:
+ return (TK_ERROR);
+ case TK_RIGHTBKT:
+ done = 1;
+ break;
+ }
+ break;
+
+ default:
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_SYM),
+ ld_map_tokenstr(tok, &tkv_sym, &inv_buf));
+ return (TK_ERROR);
+ }
+ }
+
+ /*
+ * In the SYMBOL directive, we keep parsing in the face of
+ * errors that don't involve resources, to maximize what we
+ * can report in a single invocation. If we encountered such
+ * an error, act on the error(s) now.
+ */
+ if (ss->ss_mv.mv_errcnt)
+ return (TK_ERROR);
+
+ return (tok);
+}
+
+
+/*
+ * Top Level Directive:
+ *
+ * SYMBOL_SCOPE { ...
+ * ------------^
+ */
+static Token
+dir_symbol_scope(Mapfile *mf)
+{
+ symbol_state_t ss;
+
+ /* The first token must be a '{' */
+ if (gettoken_leftbkt(mf, MSG_ORIG(MSG_MAPKW_SYMBOL_SCOPE)) == TK_ERROR)
+ return (TK_ERROR);
+
+ /* Establish the version descriptor and related data */
+ if (!ld_map_sym_ver_init(mf, NULL, &ss.ss_mv))
+ return (TK_ERROR);
+
+ /* Read attributes until the closing '}' is seen */
+ if (parse_symbol_attributes(mf, MSG_ORIG(MSG_MAPKW_SYMBOL_SCOPE),
+ &ss) == TK_ERROR)
+ return (TK_ERROR);
+
+ /* Terminating ';' */
+ return (gettoken_semicolon(mf, MSG_ORIG(MSG_MAPKW_SYMBOL_SCOPE)));
+}
+
+
+/*
+ * at_dv_allow(): Value for ALLOW= is not a version string
+ */
+static void
+gts_efunc_dir_symbol_version(Mapfile *mf, Token tok, ld_map_tkval_t *tkv)
+{
+ Conv_inv_buf_t inv_buf;
+
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_VERSION),
+ MSG_ORIG(MSG_MAPKW_SYMBOL_VERSION),
+ ld_map_tokenstr(tok, tkv, &inv_buf));
+}
+
+/*
+ * Top Level Directive:
+ *
+ * SYMBOL_VERSION version_name { ...
+ * --------------^
+ */
+static Token
+dir_symbol_version(Mapfile *mf)
+{
+
+ ld_map_tkval_t tkv;
+ symbol_state_t ss;
+
+ /* The first token must be a version name */
+ if (gettoken_str(mf, 0, &tkv, gts_efunc_dir_symbol_version) == TK_ERROR)
+ return (TK_ERROR);
+
+ /* The next token is expected to be '{' */
+ if (gettoken_leftbkt(mf, MSG_ORIG(MSG_MAPKW_SYMBOL_VERSION)) ==
+ TK_ERROR)
+ return (TK_ERROR);
+
+ /* Establish the version descriptor and related data */
+ if (!ld_map_sym_ver_init(mf, tkv.tkv_str, &ss.ss_mv))
+ return (TK_ERROR);
+
+ /* Read attributes until the closing '}' is seen */
+ if (parse_symbol_attributes(mf, MSG_ORIG(MSG_MAPKW_SYMBOL_VERSION),
+ &ss) == TK_ERROR)
+ return (TK_ERROR);
+
+ /*
+ * Determine if any version references are provided after the close
+ * bracket, parsing up to the terminating ';'.
+ */
+ if (!ld_map_sym_ver_fini(mf, &ss.ss_mv))
+ return (TK_ERROR);
+
+ return (TK_SEMICOLON);
+}
+
+
+/*
+ * Parse the mapfile --- Solaris syntax
+ */
+Boolean
+ld_map_parse_v2(Mapfile *mf)
+{
+ /* Valid top level mapfile directives */
+ typedef struct {
+ const char *name; /* Directive */
+ dir_func_t func; /* Function to parse directive */
+ } tldir_t;
+
+
+ tldir_t dirlist[] = {
+ { MSG_ORIG(MSG_MAPKW_CAPABILITY), dir_capability },
+ { MSG_ORIG(MSG_MAPKW_DEPEND_VERSIONS), dir_depend_versions },
+ { MSG_ORIG(MSG_MAPKW_HDR_NOALLOC), dir_hdr_noalloc },
+ { MSG_ORIG(MSG_MAPKW_LOAD_SEGMENT), dir_load_segment },
+ { MSG_ORIG(MSG_MAPKW_NOTE_SEGMENT), dir_note_segment },
+ { MSG_ORIG(MSG_MAPKW_NULL_SEGMENT), dir_null_segment },
+ { MSG_ORIG(MSG_MAPKW_PHDR_ADD_NULL), dir_phdr_add_null },
+ { MSG_ORIG(MSG_MAPKW_SEGMENT_ORDER), dir_segment_order },
+ { MSG_ORIG(MSG_MAPKW_STACK), dir_stack },
+ { MSG_ORIG(MSG_MAPKW_SYMBOL_SCOPE), dir_symbol_scope },
+ { MSG_ORIG(MSG_MAPKW_SYMBOL_VERSION), dir_symbol_version },
+
+ /* List must be null terminated */
+ { 0 }
+ };
+
+ /*
+ * Size of buffer needed to format the names in dirlist[]. Must
+ * be kept in sync with dirlist.
+ */
+ static size_t dirlist_bufsize =
+ KW_NAME_SIZE(MSG_MAPKW_CAPABILITY) +
+ KW_NAME_SIZE(MSG_MAPKW_DEPEND_VERSIONS) +
+ KW_NAME_SIZE(MSG_MAPKW_HDR_NOALLOC) +
+ KW_NAME_SIZE(MSG_MAPKW_LOAD_SEGMENT) +
+ KW_NAME_SIZE(MSG_MAPKW_NOTE_SEGMENT) +
+ KW_NAME_SIZE(MSG_MAPKW_NULL_SEGMENT) +
+ KW_NAME_SIZE(MSG_MAPKW_PHDR_ADD_NULL) +
+ KW_NAME_SIZE(MSG_MAPKW_SEGMENT_ORDER) +
+ KW_NAME_SIZE(MSG_MAPKW_STACK) +
+ KW_NAME_SIZE(MSG_MAPKW_SYMBOL_SCOPE) +
+ KW_NAME_SIZE(MSG_MAPKW_SYMBOL_VERSION);
+
+ Token tok; /* current token. */
+ ld_map_tkval_t tkv; /* Value of token */
+ tldir_t *tldir;
+ Conv_inv_buf_t inv_buf;
+
+ for (;;) {
+ tok = ld_map_gettoken(mf, TK_F_EOFOK | TK_F_KEYWORD, &tkv);
+ switch (tok) {
+ case TK_ERROR:
+ return (FALSE);
+ case TK_EOF:
+ return (TRUE);
+ case TK_SEMICOLON: /* Terminator, or empty directive: Ignore */
+ break;
+ case TK_STRING:
+ /* Map name to entry in dirlist[] */
+ tldir = ld_map_kwfind(tkv.tkv_str, dirlist,
+ SGSOFFSETOF(tldir_t, name), sizeof (dirlist[0]));
+
+ /* Not a directive we know? */
+ if (tldir == NULL)
+ goto bad_dirtok;
+
+ /* Call the function associated with this directive */
+ if (tldir->func(mf) == TK_ERROR)
+ return (FALSE);
+ break;
+ default:
+ bad_dirtok:
+ {
+ char buf[dirlist_bufsize];
+
+ mf_fatal(mf, MSG_INTL(MSG_MAP_EXP_DIR),
+ ld_map_kwnames(dirlist,
+ SGSOFFSETOF(tldir_t, name),
+ sizeof (dirlist[0]), buf, dirlist_bufsize),
+ ld_map_tokenstr(tok, &tkv, &inv_buf));
+ }
+ return (FALSE);
+ }
+ }
+
+ /*NOTREACHED*/
+ assert(0);
+ return (FALSE);
+}
diff --git a/usr/src/cmd/sgs/libld/common/order.c b/usr/src/cmd/sgs/libld/common/order.c
index dfec1092ee..fc92d6a09a 100644
--- a/usr/src/cmd/sgs/libld/common/order.c
+++ b/usr/src/cmd/sgs/libld/common/order.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -269,11 +269,11 @@ validate_shf_ordered_dest(Ofl_desc *ofl, Ifl_desc *ifl, Word ndx,
* unsorted section.
*/
static uintptr_t
-place_unordered(Ofl_desc *ofl, Is_desc *isp)
+place_unordered(Ofl_desc *ofl, Is_desc *isp, Place_path_info *path_info)
{
isp->is_flags &= ~FLG_IS_ORDERED;
if (isp->is_osdesc == NULL)
- return ((uintptr_t)ld_place_section(ofl, isp,
+ return ((uintptr_t)ld_place_section(ofl, isp, path_info,
isp->is_keyident, NULL));
return ((uintptr_t)isp->is_osdesc);
}
@@ -290,7 +290,8 @@ place_unordered(Ofl_desc *ofl, Is_desc *isp)
* exit:
*/
uintptr_t
-ld_process_ordered(Ifl_desc *ifl, Ofl_desc *ofl, Word ndx)
+ld_process_ordered(Ofl_desc *ofl, Ifl_desc *ifl, Place_path_info *path_info,
+ Word ndx)
{
Is_desc *isp2, *isp = ifl->ifl_isdesc[ndx];
Xword shflags = isp->is_shdr->sh_flags;
@@ -315,7 +316,7 @@ ld_process_ordered(Ifl_desc *ifl, Ofl_desc *ofl, Word ndx)
*/
if ((error = is_keyshndx_ok(ifl, keyshndx)) != 0) {
DBG_CALL(Dbg_sec_order_error(ofl->ofl_lml, ifl, ndx, error));
- return (place_unordered(ofl, isp));
+ return (place_unordered(ofl, isp, path_info));
}
/*
@@ -325,7 +326,7 @@ ld_process_ordered(Ifl_desc *ifl, Ofl_desc *ofl, Word ndx)
*/
if ((shflags & SHF_ORDERED) &&
(validate_shf_ordered_dest(ofl, ifl, ndx, &alt_os_name) == FALSE))
- return (place_unordered(ofl, isp));
+ return (place_unordered(ofl, isp, path_info));
/*
* Place the section into its output section. It's possible that this
@@ -333,7 +334,8 @@ ld_process_ordered(Ifl_desc *ifl, Ofl_desc *ofl, Word ndx)
* which case we're done.
*/
if ((osp = isp->is_osdesc) == NULL) {
- osp = ld_place_section(ofl, isp, isp->is_keyident, alt_os_name);
+ osp = ld_place_section(ofl, isp, path_info, isp->is_keyident,
+ alt_os_name);
if ((osp == (Os_desc *)S_ERROR) || (osp == NULL))
return ((uintptr_t)osp);
}
@@ -396,7 +398,7 @@ ld_sec_validate(Ofl_desc *ofl)
Os_desc *osp;
Aliste idx2;
- for (APLIST_TRAVERSE(sgp->sg_secorder, idx2, scop)) {
+ for (ALIST_TRAVERSE(sgp->sg_os_order, idx2, scop)) {
if ((scop->sco_flags & FLG_SGO_USED) == 0) {
eprintf(ofl->ofl_lml, ERR_WARNING,
MSG_INTL(MSG_MAP_SECORDER),
diff --git a/usr/src/cmd/sgs/libld/common/outfile.c b/usr/src/cmd/sgs/libld/common/outfile.c
index 9991848ee0..50b0d4f0ab 100644
--- a/usr/src/cmd/sgs/libld/common/outfile.c
+++ b/usr/src/cmd/sgs/libld/common/outfile.c
@@ -23,7 +23,7 @@
* Copyright (c) 1988 AT&T
* All Rights Reserved
*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -381,7 +381,7 @@ ld_create_outfile(Ofl_desc *ofl)
DBG_CALL(Dbg_basic_create(ofl->ofl_lml));
/*
- * If DF_1_NOHDR was set in map_parse() or FLG_OF1_VADDR was set,
+ * If DF_1_NOHDR or FLG_OF1_VADDR were set,
* we need to do alignment adjustment.
*/
if ((flags1 & FLG_OF1_VADDR) ||
@@ -476,6 +476,9 @@ ld_create_outfile(Ofl_desc *ofl)
} else if (ptype == PT_SUNWCAP) {
if (ofl->ofl_oscap)
nseg++;
+ } else if (ptype == PT_SUNWSTACK) {
+ if ((sgp->sg_flags & FLG_SG_DISABLED) == 0)
+ nseg++;
} else if (sgp->sg_flags & FLG_SG_EMPTY) {
nseg++;
} else if (sgp->sg_osdescs != NULL) {
@@ -499,14 +502,13 @@ ld_create_outfile(Ofl_desc *ofl)
ptloadidx++;
/*
- * If the first loadable segment has the ?N flag then
- * alignments of following segments need to be fixed,
+ * If the first loadable segment is not supposed to
+ * include the ELF or program headers, alignments
+ * of the following segments need to be fixed,
* plus a .dynamic FLAGS1 setting is required.
*/
- if (sgp->sg_flags & FLG_SG_NOHDR) {
+ if (ofl->ofl_dtflags_1 & DF_1_NOHDR)
fixalign = TRUE;
- ofl->ofl_dtflags_1 |= DF_1_NOHDR;
- }
}
shidx = 0;
@@ -606,7 +608,7 @@ ld_create_outfile(Ofl_desc *ofl)
if ((fixalign == TRUE) && (ptype == PT_LOAD) &&
(shidx == 1) && (dataidx == 1))
- data->d_align = sgp->sg_addralign;
+ data->d_align = sgp->sg_align;
/*
* Save the first TLS data buffer, as this is
diff --git a/usr/src/cmd/sgs/libld/common/place.c b/usr/src/cmd/sgs/libld/common/place.c
index b59f3deef2..b38cffaec7 100644
--- a/usr/src/cmd/sgs/libld/common/place.c
+++ b/usr/src/cmd/sgs/libld/common/place.c
@@ -23,7 +23,7 @@
* Copyright (c) 1988 AT&T
* All Rights Reserved
*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -40,11 +40,11 @@
* Each time a section is placed, the function set_addralign()
* is called. This function performs:
*
- * . if the section is from an external file, check if this is empty or not.
+ * - if the section is from an external file, check if this is empty or not.
* If not, we know the segment this section will belong needs a program
* header. (Of course, the program is needed only if this section falls
* into a loadable segment.)
- * . compute the Least Common Multiplier for setting the segment alignment.
+ * - compute the Least Common Multiplier for setting the segment alignment.
*/
static void
set_addralign(Ofl_desc *ofl, Os_desc *osp, Is_desc *isp)
@@ -67,8 +67,8 @@ set_addralign(Ofl_desc *ofl, Os_desc *osp, Is_desc *isp)
(osp->os_sgdesc->sg_phdr).p_type != PT_LOAD)
return;
- osp->os_sgdesc->sg_addralign =
- ld_lcm(osp->os_sgdesc->sg_addralign, shdr->sh_addralign);
+ osp->os_sgdesc->sg_align =
+ ld_lcm(osp->os_sgdesc->sg_align, shdr->sh_addralign);
}
/*
@@ -418,12 +418,160 @@ gnu_linkonce_sec(const char *ostr)
#undef NSTR_CH2
#undef NSTR_CH3
+
+/*
+ * Initialize a path info buffer for use with ld_place_section().
+ *
+ * entry:
+ * ofl - Output descriptor
+ * ifl - Descriptor for input file, or NULL if there is none.
+ * info - Address of buffer to be initialized.
+ *
+ * exit:
+ * If this is an input file, and if the entrance criteria list
+ * contains at least one criteria that has a non-empty file string
+ * match list (ec_files), then the block pointed at by info is
+ * initialized, and info is returned.
+ *
+ * If there is no input file, and/or no entrance criteria containing
+ * a non-empty ec_files list, then NULL is returned. This is not
+ * an error --- the NULL is simply an optimization, understood by
+ * ld_place_path(), that allows it to skip unnecessary work.
+ */
+Place_path_info *
+ld_place_path_info_init(Ofl_desc *ofl, Ifl_desc *ifl, Place_path_info *info)
+{
+ /*
+ * Return NULL if there is no input file (internally generated section)
+ * or if the entrance criteria list does not contain any items that will
+ * need to be compared to the path (all the ec_files lists are empty).
+ */
+ if ((ifl == NULL) || !(ofl->ofl_flags & FLG_OF_EC_FILES))
+ return (NULL);
+
+ info->ppi_path = ifl->ifl_name;
+ info->ppi_path_len = strlen(info->ppi_path);
+ info->ppi_isar = (ifl->ifl_flags & FLG_IF_EXTRACT) != 0;
+
+ /*
+ * The basename is the final segment of the path, equivalent to
+ * the path itself if there are no '/' delimiters.
+ */
+ info->ppi_bname = strrchr(info->ppi_path, '/');
+ if (info->ppi_bname == NULL)
+ info->ppi_bname = info->ppi_path;
+ else
+ info->ppi_bname++; /* Skip leading '/' */
+ info->ppi_bname_len =
+ info->ppi_path_len - (info->ppi_bname - info->ppi_path);
+
+ /*
+ * For an archive, the object name is the member name, which is
+ * enclosed in () at the end of the name string. Otherwise, it is
+ * the same as the basename.
+ */
+ if (info->ppi_isar) {
+ info->ppi_oname = strrchr(info->ppi_bname, '(');
+ /* There must be an archive member suffix delimited by parens */
+ assert((info->ppi_bname[info->ppi_bname_len - 1] == ')') &&
+ (info->ppi_oname != NULL));
+ info->ppi_oname++; /* skip leading '(' */
+ info->ppi_oname_len = info->ppi_bname_len -
+ (info->ppi_oname - info->ppi_bname + 1);
+ } else {
+ info->ppi_oname = info->ppi_bname;
+ info->ppi_oname_len = info->ppi_bname_len;
+ }
+
+ return (info);
+}
+
+/*
+ * Compare an input section path to the file comparison list the given
+ * entrance criteria.
+ *
+ * entry:
+ * path_info - A non-NULL Place_path_info block for the file
+ * containing the input section, initialized by
+ * ld_place_path_info_init()
+ * enp - Entrance criteria with a non-empty ec_files list of file
+ * comparisons to be carried out.
+ *
+ * exit:
+ * Return TRUE if a match is seen, and FALSE otherwise.
+ */
+static Boolean
+eval_ec_files(Place_path_info *path_info, Ent_desc *enp)
+{
+ Aliste idx;
+ Ent_desc_file *edfp;
+ size_t cmp_len;
+ const char *cmp_str;
+
+ for (ALIST_TRAVERSE(enp->ec_files, idx, edfp)) {
+ Word type = edfp->edf_flags & TYP_ECF_MASK;
+
+ /*
+ * Determine the starting character, and # of characters,
+ * from the file path to compare against this entrance criteria
+ * file string.
+ */
+ if (type == TYP_ECF_OBJNAME) {
+ cmp_str = path_info->ppi_oname;
+ cmp_len = path_info->ppi_oname_len;
+ } else {
+ int ar_stat_diff = path_info->ppi_isar !=
+ ((edfp->edf_flags & FLG_ECF_ARMEMBER) != 0);
+
+ /*
+ * If the entrance criteria specifies an archive member
+ * and the file does not, then there can be no match.
+ */
+
+ if (ar_stat_diff && !path_info->ppi_isar)
+ continue;
+
+ if (type == TYP_ECF_PATH) {
+ cmp_str = path_info->ppi_path;
+ cmp_len = path_info->ppi_path_len;
+ } else { /* TYP_ECF_BASENAME */
+ cmp_str = path_info->ppi_bname;
+ cmp_len = path_info->ppi_bname_len;
+ }
+
+ /*
+ * If the entrance criteria does not specify an archive
+ * member and the file does, then a match just requires
+ * the paths (without the archive member) to match.
+ * Reduce the length to not include the ar member or
+ * the '(' that precedes it.
+ */
+ if (ar_stat_diff && path_info->ppi_isar)
+ cmp_len = path_info->ppi_oname - cmp_str - 1;
+ }
+
+ /*
+ * Compare the resulting string to the one from the
+ * entrance criteria.
+ */
+ if ((cmp_len == edfp->edf_name_len) &&
+ (strncmp(edfp->edf_name, cmp_str, cmp_len) == 0))
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
/*
* Place a section into the appropriate segment and output section.
*
* entry:
* ofl - File descriptor
* isp - Input section descriptor of section to be placed.
+ * path_info - NULL, or pointer to Place_path_info buffer initialized
+ * by ld_place_path_info_init() for the file associated to isp,
+ * for use in processing entrance criteria with non-empty
+ * file matching string list (ec_files)
* ident - Section identifier, used to order sections relative to
* others within the output segment.
* alt_os_name - If non-NULL, the name of the output section to place
@@ -431,8 +579,8 @@ gnu_linkonce_sec(const char *ostr)
* with the same name as the input section.
*/
Os_desc *
-ld_place_section(Ofl_desc *ofl, Is_desc *isp, int ident,
- const char *alt_os_name)
+ld_place_section(Ofl_desc *ofl, Is_desc *isp, Place_path_info *path_info,
+ int ident, const char *alt_os_name)
{
Ent_desc *enp;
Sg_desc *sgp;
@@ -523,10 +671,32 @@ ld_place_section(Ofl_desc *ofl, Is_desc *isp, int ident,
* finding a segment, then sgp will be NULL.
*/
sgp = NULL;
- for (ALIST_TRAVERSE(ofl->ofl_ents, idx1, enp)) {
- if (enp->ec_segment &&
- (enp->ec_segment->sg_flags & FLG_SG_DISABLED))
+ for (APLIST_TRAVERSE(ofl->ofl_ents, idx1, enp)) {
+
+ /* Disabled segments are not available for assignment */
+ if (enp->ec_segment->sg_flags & FLG_SG_DISABLED)
continue;
+
+ /*
+ * If an entrance criteria doesn't have any of its fields
+ * set, it will match any section it is tested against.
+ * We set the FLG_EC_CATCHALL flag on these, primarily because
+ * it helps readers of our debug output to understand what
+ * the criteria means --- otherwise the user would just see
+ * that every field is 0, but might not understand the
+ * significance of that.
+ *
+ * Given that we set this flag, we can use it here as an
+ * optimization to short circuit all of the tests in this
+ * loop. Note however, that if we did not do this, the end
+ * result would be the same --- the empty criteria will sail
+ * past the following tests and reach the end of the loop.
+ */
+ if (enp->ec_flags & FLG_EC_CATCHALL) {
+ sgp = enp->ec_segment;
+ break;
+ }
+
if (enp->ec_type && (enp->ec_type != shdr->sh_type))
continue;
if (enp->ec_attrmask &&
@@ -534,52 +704,41 @@ ld_place_section(Ofl_desc *ofl, Is_desc *isp, int ident,
(enp->ec_attrmask & enp->ec_attrbits) !=
(enp->ec_attrmask & shflags))
continue;
- if (((enp->ec_flags & FLG_EC_BUILTIN) == 0) &&
- enp->ec_name && (strcmp(enp->ec_name, isp->is_name) != 0))
+ if (enp->ec_is_name &&
+ (strcmp(enp->ec_is_name, isp->is_name) != 0))
continue;
- if (enp->ec_files) {
- Aliste idx2;
- char *file;
- int found = 0;
- if (isp->is_file == NULL)
- continue;
+ if ((alist_nitems(enp->ec_files) > 0) &&
+ ((path_info == NULL) || !eval_ec_files(path_info, enp)))
+ continue;
- for (APLIST_TRAVERSE(enp->ec_files, idx2, file)) {
- const char *name = isp->is_file->ifl_name;
-
- if (file[0] == '*') {
- const char *basename;
-
- basename = strrchr(name, '/');
- if (basename == NULL)
- basename = name;
- else if (basename[1] != '\0')
- basename++;
-
- if (strcmp(&file[1], basename) == 0) {
- found++;
- break;
- }
- } else {
- if (strcmp(file, name) == 0) {
- found++;
- break;
- }
- }
- }
- if (!found)
- continue;
- }
+ /* All entrance criteria tests passed */
sgp = enp->ec_segment;
break;
}
- if (sgp == NULL) {
- enp = alist_item(ofl->ofl_ents,
- alist_nitems(ofl->ofl_ents) - 1);
- sgp = enp->ec_segment;
- }
+ /*
+ * The final entrance criteria record is a FLG_EC_CATCHALL that points
+ * at the final predefined segment "extra", and this final segment is
+ * tagged FLG_SG_NODISABLE. Therefore, the above loop must always find
+ * a segment.
+ */
+ assert(sgp != NULL);
+
+ /*
+ * Transfer the input section sorting key from the entrance criteria
+ * to the input section. A non-zero value means that the section
+ * will be sorted on this key amoung the other sections that have a
+ * non-zero key. These sorted sections are collectively placed at the
+ * head of the output section.
+ *
+ * If the sort key is 0, the section is placed after the sorted
+ * sections in the order they are encountered.
+ */
+ isp->is_ordndx = enp->ec_ordndx;
+
+ /* Remember that this entrance criteria has placed a section */
+ enp->ec_flags |= FLG_EC_USED;
/*
* If our caller has supplied an alternative name for the output
@@ -605,13 +764,13 @@ ld_place_section(Ofl_desc *ofl, Is_desc *isp, int ident,
* This convention has also been followed for COMDAT and sections
* identified though SHT_GROUP data.
*
- * Strip out the % from the section name in all cases except:
- *
- * i. when '-r' is used without '-M', and
- * ii. when '-r' is used with '-M' but without the ?O flag.
+ * Strip out the % from the section name for:
+ * - Non-relocatable objects
+ * - Relocatable objects if input section sorting is
+ * in force for the segment in question.
*/
if (((ofl->ofl_flags & FLG_OF_RELOBJ) == 0) ||
- (sgp->sg_flags & FLG_SG_ORDER)) {
+ (sgp->sg_flags & FLG_SG_IS_ORDER)) {
if ((sname = strchr(isp->is_name, '%')) != NULL) {
size_t size = sname - isp->is_name;
@@ -621,7 +780,6 @@ ld_place_section(Ofl_desc *ofl, Is_desc *isp, int ident,
oname[size] = '\0';
DBG_CALL(Dbg_sec_redirected(ofl->ofl_lml, isp, oname));
}
- isp->is_ordndx = enp->ec_ordndx;
}
/*
@@ -654,8 +812,8 @@ ld_place_section(Ofl_desc *ofl, Is_desc *isp, int ident,
isp->is_flags |= FLG_IS_COMDAT;
if ((ofl->ofl_flags1 & FLG_OF1_NRLXREL) == 0)
ofl->ofl_flags1 |= FLG_OF1_RLXREL;
- Dbg_sec_gnu_comdat(ofl->ofl_lml, isp, TRUE,
- (ofl->ofl_flags1 & FLG_OF1_RLXREL) != 0);
+ DBG_CALL(Dbg_sec_gnu_comdat(ofl->ofl_lml, isp, TRUE,
+ (ofl->ofl_flags1 & FLG_OF1_RLXREL) != 0));
}
/*
@@ -685,7 +843,8 @@ ld_place_section(Ofl_desc *ofl, Is_desc *isp, int ident,
*/
if ((ofl->ofl_flags1 & FLG_OF1_NRLXREL) == 0) {
ofl->ofl_flags1 |= FLG_OF1_RLXREL;
- Dbg_sec_gnu_comdat(ofl->ofl_lml, isp, FALSE, TRUE);
+ DBG_CALL(Dbg_sec_gnu_comdat(ofl->ofl_lml, isp,
+ FALSE, TRUE));
}
}
@@ -695,23 +854,25 @@ ld_place_section(Ofl_desc *ofl, Is_desc *isp, int ident,
*/
onamehash = sgs_str_hash(oname);
- if (sgp->sg_flags & FLG_SG_ORDER)
- enp->ec_flags |= FLG_EC_USED;
-
/*
- * Determine if section ordering is turned on. If so, return the
- * appropriate ordering index for the section. This information
- * is derived from the Sg_desc->sg_segorder list that was built
+ * Determine if output section ordering is turned on. If so, return
+ * the appropriate ordering index for the section. This information
+ * is derived from the Sg_desc->sg_os_order list that was built
* up from the Mapfile.
+ *
+ * A value of 0 for os_ndx means that the section is not sorted
+ * (i.e. is not found in the sg_os_order). The items in sg_os_order
+ * are in the desired sort order, so adding 1 to their alist index
+ * gives a suitable index for sorting.
*/
os_ndx = 0;
- if (sgp->sg_secorder) {
+ if (alist_nitems(sgp->sg_os_order) > 0) {
Sec_order *scop;
- for (APLIST_TRAVERSE(sgp->sg_secorder, idx1, scop)) {
+ for (ALIST_TRAVERSE(sgp->sg_os_order, idx1, scop)) {
if (strcmp(scop->sco_secname, oname) == 0) {
scop->sco_flags |= FLG_SGO_USED;
- os_ndx = scop->sco_index;
+ os_ndx = idx1 + 1;
break;
}
}
@@ -782,7 +943,7 @@ ld_place_section(Ofl_desc *ofl, Is_desc *isp, int ident,
*/
if (os_attach_isp(ofl, osp, isp,
- (sgp->sg_flags & FLG_SG_ORDER) != 0) == 0)
+ (sgp->sg_flags & FLG_SG_IS_ORDER) != 0) == 0)
return ((Os_desc *)S_ERROR);
/*
@@ -952,7 +1113,7 @@ ld_place_section(Ofl_desc *ofl, Is_desc *isp, int ident,
if ((sgp->sg_phdr.p_type == PT_LOAD) &&
((osp->os_shdr->sh_flags & SHF_ALLOC) == 0)) {
eprintf(ofl->ofl_lml, ERR_WARNING, MSG_INTL(MSG_SCN_NONALLOC),
- ofl->ofl_name, osp->os_name);
+ ofl->ofl_name, osp->os_name, sgp->sg_name);
osp->os_shdr->sh_flags |= SHF_ALLOC;
}
diff --git a/usr/src/cmd/sgs/libld/common/sections.c b/usr/src/cmd/sgs/libld/common/sections.c
index 5518e14502..ef98124d06 100644
--- a/usr/src/cmd/sgs/libld/common/sections.c
+++ b/usr/src/cmd/sgs/libld/common/sections.c
@@ -23,7 +23,7 @@
* Copyright (c) 1988 AT&T
* All Rights Reserved
*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -771,7 +771,7 @@ ld_make_bss(Ofl_desc *ofl, Xword size, Xword align, uint_t ident)
* Retain this .*bss input section as this will be where global symbol
* references are added.
*/
- if ((osp = ld_place_section(ofl, isec, ident, NULL)) ==
+ if ((osp = ld_place_section(ofl, isec, NULL, ident, NULL)) ==
(Os_desc *)S_ERROR)
return (S_ERROR);
@@ -829,7 +829,7 @@ make_array(Ofl_desc *ofl, Word shtype, const char *sectname, APlist *alp)
if ((data->d_buf = libld_calloc(sizeof (Addr), entcount)) == NULL)
return (S_ERROR);
- if (ld_place_section(ofl, isec, ld_targ.t_id.id_array, NULL) ==
+ if (ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_array, NULL) ==
(Os_desc *)S_ERROR)
return (S_ERROR);
@@ -909,7 +909,7 @@ make_comment(Ofl_desc *ofl)
shdr->sh_flags = 0;
shdr->sh_addralign = 1;
- return ((uintptr_t)ld_place_section(ofl, isec,
+ return ((uintptr_t)ld_place_section(ofl, isec, NULL,
ld_targ.t_id.id_note, NULL));
}
@@ -960,7 +960,7 @@ make_dynamic(Ofl_desc *ofl)
shdr->sh_flags |= SHF_ALLOC;
osp = ofl->ofl_osdynamic =
- ld_place_section(ofl, isec, ld_targ.t_id.id_dynamic, NULL);
+ ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_dynamic, NULL);
/*
* Reserve entries for any needed dependencies.
@@ -1288,7 +1288,8 @@ ld_make_got(Ofl_desc *ofl)
shdr->sh_size = (Xword)size;
shdr->sh_entsize = ld_targ.t_m.m_got_entsize;
- ofl->ofl_osgot = ld_place_section(ofl, isec, ld_targ.t_id.id_got, NULL);
+ ofl->ofl_osgot = ld_place_section(ofl, isec, NULL,
+ ld_targ.t_id.id_got, NULL);
if (ofl->ofl_osgot == (Os_desc *)S_ERROR)
return (S_ERROR);
@@ -1343,11 +1344,30 @@ make_interp(Ofl_desc *ofl)
data->d_align = shdr->sh_addralign = 1;
ofl->ofl_osinterp =
- ld_place_section(ofl, isec, ld_targ.t_id.id_interp, NULL);
+ ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_interp, NULL);
return ((uintptr_t)ofl->ofl_osinterp);
}
/*
+ * Output debugging information for the given capability mask.
+ */
+static void
+dbg_capmask(Ofl_desc *ofl, Word type, CapMask *capmask)
+{
+ /*
+ * If this capability has excluded bits, then show the current
+ * internal state. Otherwise, don't bother, because it's identical
+ * to the final output value.
+ */
+ if (capmask->cm_exclude)
+ Dbg_cap_entry2(ofl->ofl_lml, DBG_STATE_CURRENT, type,
+ capmask, ld_targ.t_m.m_mach);
+
+ Dbg_cap_entry(ofl->ofl_lml, DBG_STATE_OUT, type,
+ CAPMASK_VALUE(capmask), ld_targ.t_m.m_mach);
+}
+
+/*
* Build a hardware/software capabilities section.
*/
static uintptr_t
@@ -1359,18 +1379,36 @@ make_cap(Ofl_desc *ofl)
Os_desc *osec;
Cap *cap;
size_t size = 0;
+ elfcap_mask_t hw_1, sf_1;
+
+ /* Final capability masks with excluded bits removed */
+ hw_1 = CAPMASK_VALUE(&ofl->ofl_ocapset.c_hw_1);
+ sf_1 = CAPMASK_VALUE(&ofl->ofl_ocapset.c_sf_1);
/*
* Determine how many entries are required.
*/
- if (ofl->ofl_hwcap_1)
+ if (hw_1)
size++;
- if (ofl->ofl_sfcap_1)
+ if (sf_1)
size++;
if (size == 0)
return (1);
size++; /* Add CA_SUNW_NULL */
+ if (DBG_ENABLED) {
+ Dbg_cap_out_title(ofl->ofl_lml);
+
+ if (hw_1)
+ dbg_capmask(ofl, CA_SUNW_HW_1,
+ &ofl->ofl_ocapset.c_hw_1);
+
+ if (sf_1)
+ dbg_capmask(ofl, CA_SUNW_SF_1,
+ &ofl->ofl_ocapset.c_sf_1);
+ }
+
+
if (new_section(ofl, SHT_SUNW_cap, MSG_ORIG(MSG_SCN_SUNWCAP), size,
&isec, &shdr, &data) == S_ERROR)
return (S_ERROR);
@@ -1379,14 +1417,14 @@ make_cap(Ofl_desc *ofl)
return (S_ERROR);
cap = (Cap *)data->d_buf;
- if (ofl->ofl_hwcap_1) {
+ if (hw_1) {
cap->c_tag = CA_SUNW_HW_1;
- cap->c_un.c_val = ofl->ofl_hwcap_1;
+ cap->c_un.c_val = hw_1;
cap++;
}
- if (ofl->ofl_sfcap_1) {
+ if (sf_1) {
cap->c_tag = CA_SUNW_SF_1;
- cap->c_un.c_val = ofl->ofl_sfcap_1;
+ cap->c_un.c_val = sf_1;
cap++;
}
cap->c_tag = CA_SUNW_NULL;
@@ -1396,7 +1434,7 @@ make_cap(Ofl_desc *ofl)
* If we're not creating a relocatable object, save the output section
* to trigger the creation of an associated program header.
*/
- osec = ld_place_section(ofl, isec, ld_targ.t_id.id_cap, NULL);
+ osec = ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_cap, NULL);
if ((ofl->ofl_flags & FLG_OF_RELOBJ) == 0)
ofl->ofl_oscap = osec;
@@ -1435,7 +1473,8 @@ make_plt(Ofl_desc *ofl)
shdr->sh_addralign = ld_targ.t_m.m_plt_align;
shdr->sh_entsize = ld_targ.t_m.m_plt_entsize;
- ofl->ofl_osplt = ld_place_section(ofl, isec, ld_targ.t_id.id_plt, NULL);
+ ofl->ofl_osplt = ld_place_section(ofl, isec, NULL,
+ ld_targ.t_id.id_plt, NULL);
if (ofl->ofl_osplt == (Os_desc *)S_ERROR)
return (S_ERROR);
@@ -1472,7 +1511,7 @@ make_hash(Ofl_desc *ofl)
* count.
*/
ofl->ofl_oshash =
- ld_place_section(ofl, isec, ld_targ.t_id.id_hash, NULL);
+ ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_hash, NULL);
if (ofl->ofl_oshash == (Os_desc *)S_ERROR)
return (S_ERROR);
@@ -1529,7 +1568,7 @@ make_symtab(Ofl_desc *ofl)
* Place the section first since it will affect the local symbol
* count.
*/
- if ((ofl->ofl_ossymtab = ld_place_section(ofl, isec,
+ if ((ofl->ofl_ossymtab = ld_place_section(ofl, isec, NULL,
ld_targ.t_id.id_symtab, NULL)) == (Os_desc *)S_ERROR)
return (S_ERROR);
@@ -1547,7 +1586,7 @@ make_symtab(Ofl_desc *ofl)
&xshdr, &xdata) == S_ERROR)
return (S_ERROR);
- if ((ofl->ofl_ossymshndx = ld_place_section(ofl, xisec,
+ if ((ofl->ofl_ossymshndx = ld_place_section(ofl, xisec, NULL,
ld_targ.t_id.id_symtab_ndx, NULL)) == (Os_desc *)S_ERROR)
return (S_ERROR);
}
@@ -1632,11 +1671,11 @@ make_dynsym(Ofl_desc *ofl)
* count.
*/
if (allow_ldynsym &&
- ((ofl->ofl_osldynsym = ld_place_section(ofl, lisec,
+ ((ofl->ofl_osldynsym = ld_place_section(ofl, lisec, NULL,
ld_targ.t_id.id_ldynsym, NULL)) == (Os_desc *)S_ERROR))
return (S_ERROR);
ofl->ofl_osdynsym =
- ld_place_section(ofl, isec, ld_targ.t_id.id_dynsym, NULL);
+ ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_dynsym, NULL);
if (ofl->ofl_osdynsym == (Os_desc *)S_ERROR)
return (S_ERROR);
@@ -1689,7 +1728,7 @@ make_dynsort(Ofl_desc *ofl)
&isec, &shdr, &data) == S_ERROR)
return (S_ERROR);
- if ((ofl->ofl_osdynsymsort = ld_place_section(ofl, isec,
+ if ((ofl->ofl_osdynsymsort = ld_place_section(ofl, isec, NULL,
ld_targ.t_id.id_dynsort, NULL)) == (Os_desc *)S_ERROR)
return (S_ERROR);
}
@@ -1701,7 +1740,7 @@ make_dynsort(Ofl_desc *ofl)
ofl->ofl_dyntlssortcnt, &isec, &shdr, &data) == S_ERROR)
return (S_ERROR);
- if ((ofl->ofl_osdyntlssort = ld_place_section(ofl, isec,
+ if ((ofl->ofl_osdyntlssort = ld_place_section(ofl, isec, NULL,
ld_targ.t_id.id_dynsort, NULL)) == (Os_desc *)S_ERROR)
return (S_ERROR);
}
@@ -1731,7 +1770,7 @@ make_dyn_shndx(Ofl_desc *ofl, const char *shname, Os_desc *symtab,
&isec, &shdr, &data) == S_ERROR)
return (S_ERROR);
- if ((*ret_os = ld_place_section(ofl, isec,
+ if ((*ret_os = ld_place_section(ofl, isec, NULL,
ld_targ.t_id.id_dynsym_ndx, NULL)) == (Os_desc *)S_ERROR)
return (S_ERROR);
@@ -1785,7 +1824,7 @@ make_shstrtab(Ofl_desc *ofl)
* headers to account for.
*/
ofl->ofl_osshstrtab =
- ld_place_section(ofl, isec, ld_targ.t_id.id_note, NULL);
+ ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_note, NULL);
if (ofl->ofl_osshstrtab == (Os_desc *)S_ERROR)
return (S_ERROR);
@@ -1829,7 +1868,7 @@ make_strtab(Ofl_desc *ofl)
shdr->sh_size = (Xword)size;
ofl->ofl_osstrtab =
- ld_place_section(ofl, isec, ld_targ.t_id.id_strtab, NULL);
+ ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_strtab, NULL);
return ((uintptr_t)ofl->ofl_osstrtab);
}
@@ -1909,7 +1948,7 @@ make_dynstr(Ofl_desc *ofl)
shdr->sh_size = (Xword)size;
ofl->ofl_osdynstr =
- ld_place_section(ofl, isec, ld_targ.t_id.id_dynstr, NULL);
+ ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_dynstr, NULL);
return ((uintptr_t)ofl->ofl_osdynstr);
}
@@ -1987,7 +2026,7 @@ make_reloc(Ofl_desc *ofl, Os_desc *osp)
shdr->sh_flags |= SHF_INFO_LINK;
}
- rosp = ld_place_section(ofl, isec, ld_targ.t_id.id_rel, NULL);
+ rosp = ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_rel, NULL);
if (rosp == (Os_desc *)S_ERROR)
return (S_ERROR);
@@ -2054,7 +2093,7 @@ make_verneed(Ofl_desc *ofl)
shdr->sh_size = (Xword)ofl->ofl_verneedsz;
ofl->ofl_osverneed =
- ld_place_section(ofl, isec, ld_targ.t_id.id_version, NULL);
+ ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_version, NULL);
return ((uintptr_t)ofl->ofl_osverneed);
}
@@ -2101,7 +2140,7 @@ make_verdef(Ofl_desc *ofl)
shdr->sh_size = (Xword)ofl->ofl_verdefsz;
ofl->ofl_osverdef =
- ld_place_section(ofl, isec, ld_targ.t_id.id_version, NULL);
+ ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_version, NULL);
return ((uintptr_t)ofl->ofl_osverdef);
}
@@ -2125,7 +2164,7 @@ make_sym_sec(Ofl_desc *ofl, const char *sectname, Word stype, int ident)
S_ERROR)
return ((Os_desc *)S_ERROR);
- return (ld_place_section(ofl, isec, ident, NULL));
+ return (ld_place_section(ofl, isec, NULL, ident, NULL));
}
/*
@@ -2160,7 +2199,7 @@ ld_make_parexpn_data(Ofl_desc *ofl, size_t size, Xword align)
* such global references are added and '-z nopartial' is in effect.
*/
ofl->ofl_isparexpn = isec;
- osp = ld_place_section(ofl, isec, ld_targ.t_id.id_data, NULL);
+ osp = ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_data, NULL);
if (osp == (Os_desc *)S_ERROR)
return (S_ERROR);
@@ -2206,7 +2245,7 @@ ld_make_sunwmove(Ofl_desc *ofl, int mv_nums)
mdp->md_oidx = cnt++;
}
- if ((ofl->ofl_osmove = ld_place_section(ofl, isec, 0, NULL)) ==
+ if ((ofl->ofl_osmove = ld_place_section(ofl, isec, NULL, 0, NULL)) ==
(Os_desc *)S_ERROR)
return (S_ERROR);
@@ -2474,7 +2513,7 @@ ld_make_strmerge(Ofl_desc *ofl, Os_desc *osp, APlist **rel_alpp,
goto return_s_error;
/* Add the new section to the output image */
- if (ld_place_section(ofl, mstrsec, osp->os_identndx, NULL) ==
+ if (ld_place_section(ofl, mstrsec, NULL, osp->os_identndx, NULL) ==
(Os_desc *)S_ERROR)
goto return_s_error;
@@ -2600,8 +2639,8 @@ ld_make_strmerge(Ofl_desc *ofl, Os_desc *osp, APlist **rel_alpp,
}
/* Report how much space we saved in the output section */
- Dbg_sec_genstr_compress(ofl->ofl_lml, osp->os_name, data_size,
- mstr_data->d_size);
+ DBG_CALL(Dbg_sec_genstr_compress(ofl->ofl_lml, osp->os_name, data_size,
+ mstr_data->d_size));
st_destroy(mstrtab);
return (1);
@@ -2727,9 +2766,9 @@ ld_make_sections(Ofl_desc *ofl)
}
}
if (rel_alpp != NULL)
- free(rel_alpp);
+ libld_free(rel_alpp);
if (sym_alpp != NULL)
- free(sym_alpp);
+ libld_free(sym_alpp);
if (error_seen != 0)
return (S_ERROR);
}
diff --git a/usr/src/cmd/sgs/libld/common/syms.c b/usr/src/cmd/sgs/libld/common/syms.c
index 938fa2a008..fb768de777 100644
--- a/usr/src/cmd/sgs/libld/common/syms.c
+++ b/usr/src/cmd/sgs/libld/common/syms.c
@@ -24,7 +24,7 @@
* All Rights Reserved
*
*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -959,10 +959,6 @@ ld_sym_adjust_vis(Sym_desc *sdp, Ofl_desc *ofl)
* from any initial relocation processing that references this
* symbol, or from the symbol validation processing.
*
- * This routine is called either from any initial relocation
- * processing that references this symbol, or from the symbol
- * validation processing.
- *
* A symbol is a candidate for auto-reduction/elimination if:
*
* - the symbol wasn't explicitly defined within a mapfile
diff --git a/usr/src/cmd/sgs/libld/common/unwind.c b/usr/src/cmd/sgs/libld/common/unwind.c
index d83adcef49..b75caa3c12 100644
--- a/usr/src/cmd/sgs/libld/common/unwind.c
+++ b/usr/src/cmd/sgs/libld/common/unwind.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -363,7 +363,7 @@ ld_unwind_make_hdr(Ofl_desc *ofl)
isp->is_shdr = shdr;
isp->is_indata = elfdata;
- if ((ofl->ofl_unwindhdr = ld_place_section(ofl, isp,
+ if ((ofl->ofl_unwindhdr = ld_place_section(ofl, isp, NULL,
ld_targ.t_id.id_unwindhdr, NULL)) == (Os_desc *)S_ERROR)
return (S_ERROR);
diff --git a/usr/src/cmd/sgs/libld/common/update.c b/usr/src/cmd/sgs/libld/common/update.c
index 2c5cd62965..6effc5fa14 100644
--- a/usr/src/cmd/sgs/libld/common/update.c
+++ b/usr/src/cmd/sgs/libld/common/update.c
@@ -23,7 +23,7 @@
* Copyright (c) 1988 AT&T
* All Rights Reserved
*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -3215,7 +3215,7 @@ ld_update_outfile(Ofl_desc *ofl)
*/
if (ofl->ofl_flags & FLG_OF_EXEC) {
#if defined(_ELF64)
- if (ofl->ofl_sfcap_1 & SF1_SUNW_ADDR32)
+ if (ofl->ofl_ocapset.c_sf_1.cm_value & SF1_SUNW_ADDR32)
vaddr = ld_targ.t_m.m_segm_aorigin;
else
#endif
@@ -3228,9 +3228,10 @@ ld_update_outfile(Ofl_desc *ofl)
*/
DBG_CALL(Dbg_seg_title(ofl->ofl_lml));
for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp)) {
- Phdr *phdr = &(sgp->sg_phdr);
- Xword p_align;
- Aliste idx2;
+ Phdr *phdr = &(sgp->sg_phdr);
+ Xword p_align;
+ Aliste idx2;
+ Sym_desc *sdp;
segndx++;
@@ -3341,6 +3342,17 @@ ld_update_outfile(Ofl_desc *ofl)
}
/*
+ * The sunwstack program is used to convey non-default
+ * flags for the process stack. Only emit it if it would
+ * change the default.
+ */
+ if (phdr->p_type == PT_SUNWSTACK) {
+ if ((sgp->sg_flags & FLG_SG_DISABLED) == 0)
+ ofl->ofl_phdr[phdrndx++] = *phdr;
+ continue;
+ }
+
+ /*
* As the TLS program header occurs after the loadable
* headers in the segment descriptor table, all the address
* information for the .tls output section will have been
@@ -3506,11 +3518,11 @@ ld_update_outfile(Ofl_desc *ofl)
}
/*
- * If a segment size symbol is required (specified via a
- * mapfile) update its value.
+ * If segment size symbols are required (specified via a
+ * mapfile) update their value.
*/
- if (sgp->sg_sizesym != NULL)
- sgp->sg_sizesym->sd_sym->st_value = phdr->p_memsz;
+ for (APLIST_TRAVERSE(sgp->sg_sizesym, idx2, sdp))
+ sdp->sd_sym->st_value = phdr->p_memsz;
/*
* If no file content has been assigned to this segment (it
@@ -3522,11 +3534,11 @@ ld_update_outfile(Ofl_desc *ofl)
/*
* If a virtual address has been specified for this segment
- * (presumably from a mapfile) use it and make sure the
- * previous segment does not run into this segment.
+ * from a mapfile use it and make sure the previous segment
+ * does not run into this segment.
*/
if (phdr->p_type == PT_LOAD) {
- if ((sgp->sg_flags & FLG_SG_VADDR)) {
+ if ((sgp->sg_flags & FLG_SG_P_VADDR)) {
if (_phdr && (vaddr > phdr->p_vaddr) &&
(phdr->p_type == PT_LOAD))
eprintf(ofl->ofl_lml, ERR_WARNING,
@@ -3545,7 +3557,7 @@ ld_update_outfile(Ofl_desc *ofl)
/*
* Adjust the address offset and p_align if needed.
*/
- if (((sgp->sg_flags & FLG_SG_VADDR) == 0) &&
+ if (((sgp->sg_flags & FLG_SG_P_VADDR) == 0) &&
((ofl->ofl_dtflags_1 & DF_1_NOHDR) == 0)) {
if (phdr->p_align != 0)
vaddr += phdr->p_offset % phdr->p_align;
diff --git a/usr/src/cmd/sgs/liblddbg/common/cap.c b/usr/src/cmd/sgs/liblddbg/common/cap.c
index 7f9b0f451a..bcc1898b5d 100644
--- a/usr/src/cmd/sgs/liblddbg/common/cap.c
+++ b/usr/src/cmd/sgs/liblddbg/common/cap.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -64,36 +64,48 @@ Dbg_cap_val_hw1(Lm_list *lml, Xword val, Half mach)
Dbg_util_nl(lml, DBG_NL_FRC);
}
-static const Msg captype[] = {
- MSG_STR_INITIAL, /* MSG_INTL(MSG_STR_INITIAL) */
- MSG_STR_IGNORE, /* MSG_INTL(MSG_STR_IGNORE) */
- MSG_STR_OLD, /* MSG_INTL(MSG_STR_OLD) */
- MSG_STR_NEW, /* MSG_INTL(MSG_STR_NEW) */
- MSG_STR_RESOLVED /* MSG_INTL(MSG_STR_RESOLVED) */
-};
-
void
-Dbg_cap_mapfile(Lm_list *lml, Xword tag, Xword val, Half mach)
+Dbg_cap_entry(Lm_list *lml, dbg_state_t dbg_state, Xword tag, Xword val,
+ Half mach)
{
- if (DBG_NOTCLASS(DBG_C_MAP | DBG_C_CAP))
+ Conv_inv_buf_t inv_buf;
+ Conv_cap_val_buf_t cap_val_buf;
+
+ if (DBG_NOTCLASS(DBG_C_CAP))
return;
- dbg_print(lml, MSG_INTL(MSG_MAP_CAP));
- Dbg_cap_sec_entry(lml, DBG_CAP_INITIAL, tag, val, mach);
+ dbg_print(lml, MSG_INTL(MSG_CAP_ENTRY), Dbg_state_str(dbg_state),
+ conv_cap_tag(tag, 0, &inv_buf), conv_cap_val(tag, val, mach,
+ &cap_val_buf));
}
+/*
+ * This version takes a pointer to a CapMask, and will report the exclusion
+ * bits if they exist.
+ */
void
-Dbg_cap_sec_entry(Lm_list *lml, uint_t type, Xword tag, Xword val, Half mach)
+Dbg_cap_entry2(Lm_list *lml, dbg_state_t dbg_state, Xword tag, CapMask *cmp,
+ Half mach)
{
Conv_inv_buf_t inv_buf;
- Conv_cap_val_buf_t cap_val_buf;
+ Conv_cap_val_buf_t cap_val_buf1, cap_val_buf2;
if (DBG_NOTCLASS(DBG_C_CAP))
return;
- dbg_print(lml, MSG_INTL(MSG_CAP_SEC_ENTRY), MSG_INTL(captype[type]),
- conv_cap_tag(tag, 0, &inv_buf), conv_cap_val(tag, val, mach,
- &cap_val_buf));
+ /* If there is no exclusion mask, use the simpler format */
+ if (cmp->cm_exclude == 0) {
+ dbg_print(lml, MSG_INTL(MSG_CAP_ENTRY),
+ Dbg_state_str(dbg_state), conv_cap_tag(tag, 0, &inv_buf),
+ conv_cap_val(tag, cmp->cm_value, mach, &cap_val_buf1));
+ return;
+ }
+
+
+ dbg_print(lml, MSG_INTL(MSG_CAP_ENTRY_EXC), Dbg_state_str(dbg_state),
+ conv_cap_tag(tag, 0, &inv_buf),
+ conv_cap_val(tag, cmp->cm_value, mach, &cap_val_buf1),
+ conv_cap_val(tag, cmp->cm_exclude, mach, &cap_val_buf2));
}
void
@@ -107,6 +119,25 @@ Dbg_cap_sec_title(Lm_list *lml, const char *name)
}
void
+Dbg_cap_out_title(Lm_list *lml)
+{
+ if (DBG_NOTCLASS(DBG_C_CAP))
+ return;
+
+ Dbg_util_nl(lml, DBG_NL_STD);
+ dbg_print(lml, MSG_INTL(MSG_CAP_OUT_TITLE));
+}
+
+void
+Dbg_cap_mapfile_title(Lm_list *lml, Lineno lineno)
+{
+ if (DBG_NOTCLASS(DBG_C_MAP | DBG_C_CAP))
+ return;
+
+ dbg_print(lml, MSG_INTL(MSG_MAP_CAP), EC_LINENO(lineno));
+}
+
+void
Elf_cap_title(Lm_list *lml)
{
dbg_print(lml, MSG_INTL(MSG_CAP_ELF_TITLE));
diff --git a/usr/src/cmd/sgs/liblddbg/common/debug.c b/usr/src/cmd/sgs/liblddbg/common/debug.c
index d870cf353d..fcf17a41bb 100644
--- a/usr/src/cmd/sgs/liblddbg/common/debug.c
+++ b/usr/src/cmd/sgs/liblddbg/common/debug.c
@@ -134,7 +134,7 @@ process_options(const char *name, Boolean set, Dbg_desc *dbp,
void
Dbg_help(void)
{
- Dbg_util_nl(0, DBG_NL_FRC);
+ Dbg_util_nl(0, DBG_NL_STD);
dbg_print(0, MSG_INTL(MSG_USE_R1_A));
dbg_print(0, MSG_INTL(MSG_USE_R1_B));
dbg_print(0, MSG_INTL(MSG_USE_R1_C));
@@ -282,6 +282,17 @@ Dbg_help(void)
}
/*
+ * Provide a debugging message showing the version of the linker package
+ */
+void
+Dbg_version(void)
+{
+ Dbg_util_nl(0, DBG_NL_STD);
+ dbg_print(0, MSG_ORIG(MSG_STR_LDVER), link_ver_string);
+ Dbg_util_nl(0, DBG_NL_STD);
+}
+
+/*
* Messaging support - funnel everything through dgettext() as this provides
* the real binding to libc.
*/
@@ -535,3 +546,31 @@ dbg_print(Lm_list *lml, const char *format, ...)
(void) printf(MSG_ORIG(MSG_STR_NL));
va_end(ap);
}
+
+/*
+ * Return an internationalized state transition string. These are used by
+ * various debugging output.
+ */
+const char *
+Dbg_state_str(dbg_state_t type)
+{
+ static const Msg state[DBG_STATE_NUM] = {
+ MSG_STR_ADD, /* MSG_INTL(MSG_STR_ADD) */
+ MSG_STR_CURRENT, /* MSG_INTL(MSG_STR_CURRENT) */
+ MSG_STR_EXCLUDE, /* MSG_INTL(MSG_STR_EXCLUDE) */
+ MSG_STR_IGNORE, /* MSG_INTL(MSG_STR_IGNORE) */
+ MSG_STR_MOD_BEFORE, /* MSG_INTL(MSG_STR_MOD_BEFORE) */
+ MSG_STR_MOD_AFTER, /* MSG_INTL(MSG_STR_MOD_AFTER) */
+ MSG_STR_NEW, /* MSG_INTL(MSG_STR_NEW) */
+ MSG_STR_NEW_IMPLICIT, /* MSG_INTL(MSG_STR_NEW_IMPLICIT) */
+ MSG_STR_OUT, /* MSG_INTL(MSG_STR_OUT) */
+ MSG_STR_RESET, /* MSG_INTL(MSG_STR_RESET) */
+ MSG_STR_RESOLVED, /* MSG_INTL(MSG_STR_RESOLVED) */
+ };
+#if DBG_STATE_NUM != (DBG_STATE_RESOLVED + 1)
+#error DBG_SEG_NUM has changed. Update segtype[]
+#endif
+
+ assert(type < DBG_STATE_NUM);
+ return (MSG_INTL(state[type]));
+}
diff --git a/usr/src/cmd/sgs/liblddbg/common/entry.c b/usr/src/cmd/sgs/liblddbg/common/entry.c
index 763fe569ee..280d096e7a 100644
--- a/usr/src/cmd/sgs/liblddbg/common/entry.c
+++ b/usr/src/cmd/sgs/liblddbg/common/entry.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -34,27 +34,39 @@
void
Dbg_ent_entry(Lm_list *lml, uchar_t osabi, Half mach, Ent_desc *enp)
{
- Conv_inv_buf_t inv_buf;
- Conv_sec_flags_buf_t sec_flags_buf;
+ union {
+ Conv_inv_buf_t inv;
+ Conv_sec_flags_buf_t sec_flags;
+ Conv_ent_flags_buf_t ent_flags;
+ Conv_ent_files_flags_buf_t ent_files_flags;
+ } buf;
Aliste idx;
- char *cp;
+ Ent_desc_file *edfp;
- dbg_print(lml, MSG_ORIG(MSG_ECR_NAME),
- (enp->ec_name ? enp->ec_name : MSG_INTL(MSG_STR_NULL)),
- conv_sec_flags(osabi, mach, enp->ec_attrmask, 0, &sec_flags_buf));
+ if (enp->ec_name != NULL)
+ dbg_print(lml, MSG_ORIG(MSG_ECR_NAME), enp->ec_name);
+
+ dbg_print(lml, MSG_ORIG(MSG_ECR_FLAGS),
+ conv_ent_flags(enp->ec_flags, &buf.ent_flags));
+
+ dbg_print(lml, MSG_ORIG(MSG_ECR_IS_NAME),
+ (enp->ec_is_name ? enp->ec_is_name : MSG_INTL(MSG_STR_NULL)),
+ conv_sec_flags(osabi, mach, enp->ec_attrmask, 0, &buf.sec_flags));
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(osabi, mach, enp->ec_attrbits, 0, &sec_flags_buf));
+ conv_sec_flags(osabi, mach, enp->ec_attrbits, 0, &buf.sec_flags));
dbg_print(lml, MSG_ORIG(MSG_ECR_NDX), EC_WORD(enp->ec_ordndx),
- conv_sec_type(osabi, mach, enp->ec_type, 0, &inv_buf));
+ conv_sec_type(osabi, mach, enp->ec_type, 0, &buf.inv));
if (enp->ec_files) {
dbg_print(lml, MSG_ORIG(MSG_ECR_FILES));
- for (APLIST_TRAVERSE(enp->ec_files, idx, cp))
- dbg_print(lml, MSG_ORIG(MSG_ECR_FILE), cp);
+ for (ALIST_TRAVERSE(enp->ec_files, idx, edfp))
+ dbg_print(lml, MSG_ORIG(MSG_ECR_FILE),
+ conv_ent_files_flags(edfp->edf_flags, 0,
+ &buf.ent_files_flags), edfp->edf_name);
}
}
@@ -62,7 +74,7 @@ Dbg_ent_entry(Lm_list *lml, uchar_t osabi, Half mach, Ent_desc *enp)
* Print out all `entrance descriptor' entries.
*/
void
-Dbg_ent_print(Lm_list *lml, uchar_t osabi, Half mach, Alist *alp, Boolean dmode)
+Dbg_ent_print(Lm_list *lml, uchar_t osabi, Half mach, APlist *alp)
{
Ent_desc *enp;
Aliste ndx;
@@ -71,10 +83,9 @@ Dbg_ent_print(Lm_list *lml, uchar_t osabi, Half mach, Alist *alp, Boolean dmode)
return;
Dbg_util_nl(lml, DBG_NL_STD);
- dbg_print(lml, MSG_INTL(MSG_ECR_TITLE),
- (dmode ? MSG_INTL(MSG_ECR_DYNAMIC) : MSG_INTL(MSG_ECR_STATIC)));
+ dbg_print(lml, MSG_INTL(MSG_ECR_TITLE));
- for (ALIST_TRAVERSE(alp, ndx, enp)) {
+ for (APLIST_TRAVERSE(alp, ndx, enp)) {
dbg_print(lml, MSG_INTL(MSG_ECR_DESC), EC_WORD(ndx));
Dbg_ent_entry(lml, osabi, mach, enp);
}
diff --git a/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg b/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg
index 31b15f134b..8cdb1a822b 100644
--- a/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg
+++ b/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg
@@ -496,7 +496,7 @@
# args input arguments
# entry entrance criteria descriptors
# got GOT symbol information
-# map map file processing
+# map mapfile processing
# sections input sections
# segments output segments and address/offset processing;
# detail flag shows associated sections
@@ -518,7 +518,7 @@
@ MSG_USE_R9_C " got GOT symbol information"
# TRANSLATION_NOTE -- do not translate the first token "map".
-@ MSG_USE_R9_D " map map file processing"
+@ MSG_USE_R9_D " map mapfile processing"
# TRANSLATION_NOTE -- do not translate the first token "sections".
@ MSG_USE_R9_E " sections input sections"
@@ -567,20 +567,20 @@
# Bindings messages
# NOTE: these are used by appcert(1) and lari(1), use care when changing.
-@ MSG_BND_BASIC "binding file=%s to file=%s: symbol `%s'"
+@ MSG_BND_BASIC "binding file=%s to file=%s: symbol '%s'"
@ MSG_BND_PLT "binding file=%s (%#llx:%#llx) at plt[%lld]:%s to \
- file=%s (%#llx:%#llx): symbol `%s'%s"
+ file=%s (%#llx:%#llx): symbol '%s'%s"
@ MSG_BND_DLSYM "binding file=%s (dlsym) to file=%s \
- (%#llx:%#llx): symbol `%s'%s"
+ (%#llx:%#llx): symbol '%s'%s"
@ MSG_BND_DEFAULT "binding file=%s (%#llx:%#llx) to file=%s \
- (%#llx:%#llx): symbol `%s'%s"
-@ MSG_BND_WEAK_1 "binding file=%s to 0x0 (undefined weak): symbol `%s'"
+ (%#llx:%#llx): symbol '%s'%s"
+@ MSG_BND_WEAK_1 "binding file=%s to 0x0 (undefined weak): symbol '%s'"
@ MSG_BND_WEAK_2 "binding file=%s (%#llx:%#llx) to 0x0 \
- (undefined weak): symbol `%s'"
+ (undefined weak): symbol '%s'"
# NOTE: the rejected message is used by lari(1), use care when changing. This
# message is formatted to conform to the pattern used by the MSG_BINFO messages.
-@ MSG_BND_REJECT "binding file=%s to file=%s: symbol `%s' \
+@ MSG_BND_REJECT "binding file=%s to file=%s: symbol '%s' \
(rejected: %s)"
@ MSG_BNDREJ_DIRECT "attempt to directly bind to a NODIRECT definition"
@ MSG_BNDREJ_GROUP "attempt to bind within a group to a NODIRECT \
@@ -589,8 +589,8 @@
following default search model"
@ MSG_BND_PLTPAD_TO " pltpad: %#llx: file=%s bound to file=%s: \
- symbol `%s'"
-@ MSG_BND_PLTPAD_FROM " pltpad: %#llx: bound from file=%s: symbol `%s'"
+ symbol '%s'"
+@ MSG_BND_PLTPAD_FROM " pltpad: %#llx: bound from file=%s: symbol '%s'"
@ MSG_BND_PSUM_SPARCV9 "Summary of PLT types bound: 21d=%d, 24d=%d, u32=%d, \
u44=%d, full=%d, far=%d, Total=%d"
@@ -618,16 +618,14 @@
offset=0x%llx; symbol=%s; transitioned to: %s"
@ MSG_REL_DISCARDED "relocation against discarded section=%s from file=%s; \
relocation type=%s offset=0x%llx; relocation discarded"
-@ MSG_REL_COPY "copy data from file=%s to file=%s: symbol `%s'%s"
+@ MSG_REL_COPY "copy data from file=%s to file=%s: symbol '%s'%s"
@ MSG_REL_SLOPPYCOMDAT "the following relocation references a discarded \
section; relocation redirected to section %s in \
file %s"
# Entrance criteria messages
-@ MSG_ECR_TITLE "%s Entrance Descriptor List (available)"
-@ MSG_ECR_DYNAMIC "Dynamic"
-@ MSG_ECR_STATIC "Static"
+@ MSG_ECR_TITLE "Segment Entrance Criteria Descriptor List"
@ MSG_ECR_DESC "entrance descriptor[%u]"
@@ -776,31 +774,36 @@
# Mapfile messages
-@ MSG_MAP_MAPFILE "map file=%s"
-
-@ MSG_MAP_SEG_DECL_1 "segment declaration (=), segment added:"
-@ MSG_MAP_SEG_DECL_2 "segment declaration (=), segment updated:"
-@ MSG_MAP_SEG_DECL_3 "implicit segment declaration (:), segment added:"
-@ MSG_MAP_SEG_DECL_4 "implicit segment declaration (@), segment added:"
-@ MSG_MAP_SEG_DECL_5 "size-symbol declaration (@), segment updated:"
-
-@ MSG_MAP_CAP "hardware/software declaration (=), capabilities added:"
-
-@ MSG_MAP_MAP_DIR "mapping directive (:), entrance criteria added:"
-
-@ MSG_MAP_SEC_ORDER "map section ordering, segment: %s section: \
- %s index: %d"
-
-@ MSG_MAP_SYM_SCOPE "symbol scope definition ({})"
-@ MSG_MAP_SYM_SIZE "size-symbol declaration (@), symbol=%s; %s"
+@ MSG_MAP_MAPFILE "mapfile=%s; version=%d (%s)"
+@ MSG_MAP_SEG "segment directive; line=%llu; %s"
+@ MSG_MAP_SEG_ORDER "segment order directive; line=%llu; list_cnt=%lld; %s"
+@ MSG_MAP_CAP "capability directive; line=%llu"
+@ MSG_MAP_EC "entrance criteria; line=%llu; added"
+@ MSG_MAP_OS_ORDER "output section ordering; line=%llu; segment=%s \
+ section=%s; index=%d"
+@ MSG_MAP_HDR_NOALLOC "header noalloc directive; line=%llu; first loadable \
+ segment will not contain ELF and program headers"
+
+@ MSG_MAP_SYM_SCOPE "symbol scope definition"
+@ MSG_MAP_SYM_SIZE "size-symbol directive; line=%llu; segment=%s; \
+ symbol=%s; %s"
@ MSG_MAP_SYM_VER_1 "%s, %s; symbol=%s (%s)"
@ MSG_MAP_SYM_VER_2 "%s; symbol=%s (%s)"
-@ MSG_MAP_CNT_DEF "library control definition (-), %s; needed"
+@ MSG_MAP_DV "depend versions directive; line=%llu, object=%s"
+@ MSG_MAP_DV_ENTRY "%12.12s %s; line=%llu"
+
+@ MSG_MAP_SORT_TITLE "mapfile additions: segment sorting required"
+@ MSG_MAP_SORT_TITLE_O "before:"
+@ MSG_MAP_SORT_TITLE_S "after:"
+@ MSG_MAP_POST_TITLE "mapfile post processing"
+@ MSG_MAP_ENT_ORD_TITLE "set entrance criteria input section sort keys \
+ (ec_ordndx); segment=%s"
-@ MSG_MAP_SORT_TITLE "map file additions: segment sorting required (vaddr):"
-@ MSG_MAP_SORT_ORIG " original=%s"
-@ MSG_MAP_SORT_FINAL " sorted=%s"
+@ MSG_MAP_ID_ADD "%s: %lld: enter conditional expression id: %s"
+@ MSG_MAP_ID_CLEAR "%s: %lld: delete conditional expression id: %s"
+@ MSG_MAP_PASS "%s: %lld: input enabled by %s"
+@ MSG_MAP_NOPASS "%s: %lld: input disabled by %s"
# Move messages
@@ -841,7 +844,7 @@
# Section messages
-@ MSG_SEC_BACKING "map file symbol definitions: create backing storage:"
+@ MSG_SEC_BACKING "mapfile symbol definitions: create backing storage:"
@ MSG_SEC_INPUT "section=%s; input from file=%s"
@ MSG_SEC_INPUT_GEN "section=%s"
@@ -903,8 +906,8 @@
# Segment messages
-@ MSG_SEG_DESC_INUSE "Segment Descriptor List (in use)"
-@ MSG_SEG_DESC_AVAIL "Segment Descriptor List (available)"
+@ MSG_SEG_DESC_INUSE "Program Header / Segment Descriptor List (in use)"
+@ MSG_SEG_DESC_AVAIL "Program Header / Segment Descriptor List (available)"
# Support messages
@@ -969,7 +972,7 @@
@ MSG_SYM_LAZY_RESCAN "rescanning for lazy dependencies for symbol: %s"
-@ MSG_SYM_DUPSORTADDR "section %s: symbol `%s' and symbol `%s' have the \
+@ MSG_SYM_DUPSORTADDR "section %s: symbol '%s' and symbol '%s' have the \
same address: %#llx"
@ MSG_SYM_IGNGNUVER "symbol=%s; hash index=%d; version=%d; skipping \
@@ -1062,16 +1065,24 @@
@ MSG_STR_IGNORE "ignored"
@ MSG_STR_ENTERED "entered"
-@ MSG_STR_INITIAL "initialized"
+@ MSG_STR_EXCLUDE "exclude"
+@ MSG_STR_RESET "reset"
@ MSG_STR_IN " in"
@ MSG_STR_OUT "out"
@ MSG_STR_ACT "act"
+@ MSG_STR_CURRENT "current"
+@ MSG_STR_ADD "add"
@ MSG_STR_OLD "old"
@ MSG_STR_NEW "new"
+@ MSG_STR_NEW_IMPLICIT "new (implicit)"
@ MSG_STR_RESOLVED "resolved"
-@ MSG_STR_ADD "adding"
+@ MSG_STR_ADDING "adding"
@ MSG_STR_UP_1 "updating"
@ MSG_STR_UP_2 "updated"
+@ MSG_STR_ALLOW "allow"
+@ MSG_STR_REQUIRE "require"
+@ MSG_STR_MOD_BEFORE "modify (before)"
+@ MSG_STR_MOD_AFTER "modify (after)"
@ MSG_STR_UNKNOWN "<unknown>"
@ MSG_STR_ORPHAN "<orphan>"
@@ -1115,8 +1126,10 @@
@ MSG_CAP_VAL_HW1 "hardware capabilities - %s"
-@ MSG_CAP_SEC_TITLE "hardware/software capabilities; input file=%s"
-@ MSG_CAP_SEC_ENTRY "%12.12s %-15.15s %s"
+@ MSG_CAP_SEC_TITLE "capabilities; input file=%s"
+@ MSG_CAP_OUT_TITLE "output capabilities"
+@ MSG_CAP_ENTRY "%12.12s %-15.15s %s"
+@ MSG_CAP_ENTRY_EXC "%12.12s %-15.15s %s, exclude %s"
@ MSG_CAP_HW_CANDIDATE "obj=%s; hardware capabilities candidate"
@@ -1478,11 +1491,18 @@
# Entrance criteria messages
-@ MSG_ECR_NAME " ec_name: %-8s ec_attrmask: %s"
+@ MSG_ECR_NAME " ec_name: %s"
+@ MSG_ECR_FLAGS " ec_flags: %s"
+@ MSG_ECR_IS_NAME " ec_is_name: %-8s ec_attrmask: %s"
@ MSG_ECR_SEGMENT " ec_segment: %-8s ec_attrbits: %s"
-@ MSG_ECR_NDX " ec_ndx: %-8d ec_type: %s"
+@ MSG_ECR_NDX " ec_ordndx: %-8d ec_type: %s"
@ MSG_ECR_FILES " ec_files:"
-@ MSG_ECR_FILE " %s"
+@ MSG_ECR_FILE " %-21s %s"
+
+@ MSG_MAP_SORT_SEG " %s"
+@ MSG_MAP_SORT_SEG_NAME " %-20s %s"
+@ MSG_MAP_SORT_SEG_V " %-20s %-20s p_vaddr=0x%llx"
+@ MSG_MAP_SORT_SEG_O " %-20s %-20s order=%d"
# Libs messages
@@ -1499,12 +1519,17 @@
# Segment messages
-@ MSG_SEG_NAME "segment[%d] sg_name: %s"
+@ MSG_SEG_DESC "segment[%d]"
+@ MSG_SEG_NAME " sg_name: %s"
@ MSG_SEG_LENGTH " sg_length: %#llx"
+@ MSG_SEG_ROUND " sg_round: %#llx"
+@ MSG_SEG_ALIGN " sg_align: %#llx"
@ MSG_SEG_FLAGS " sg_flags: %s"
-@ MSG_SEG_SIZESYM " sg_sizesym: %s"
-@ MSG_SEG_ORDER " sec_order:"
-@ MSG_SEG_SECTION " sec_name: %-8s sec_index: %u"
+@ MSG_SEG_SIZESYM_TITLE " sg_sizesym:"
+@ MSG_SEG_SIZESYM " %s"
+@ MSG_SEG_IS_ORDER_TITLE " sg_is_order:"
+@ MSG_SEG_OS_ORDER_TITLE " sg_os_order:"
+@ MSG_SEG_LIST_ITEM " %s"
# Section messages (used when expanding segment information)
@@ -1563,6 +1588,7 @@
@ MSG_CNTL_ENTRY " [0x%llx] %s"
@ MSG_STR_NL "\n"
+@ MSG_STR_LDVER "Solaris Linkers: %s"
@ MSG_FMT_INDEX " [%d]"
@ MSG_FMT_ISEC_NAME "[%u]%s"
diff --git a/usr/src/cmd/sgs/liblddbg/common/llib-llddbg b/usr/src/cmd/sgs/liblddbg/common/llib-llddbg
index e5b44f8664..b515327093 100644
--- a/usr/src/cmd/sgs/liblddbg/common/llib-llddbg
+++ b/usr/src/cmd/sgs/liblddbg/common/llib-llddbg
@@ -31,6 +31,8 @@
#include <debug.h>
int Dbg_setup(dbg_setup_caller_t, const char *, Dbg_desc *, const char **);
+void Dbg_help(void);
+void Dbg_version(void);
const char *
Dbg_demangle_name(const char *);
@@ -71,16 +73,24 @@ void Dbg64_bind_reject(Rt_map *, Rt_map *, const char *, int);
void Dbg32_bind_weak(Rt_map *, Elf32_Addr, Elf32_Addr, const char *);
void Dbg64_bind_weak(Rt_map *, Elf64_Addr, Elf64_Addr, const char *);
+void Dbg32_cap_entry(Lm_list *, uint_t, Elf32_Word, Elf32_Word,
+ Elf32_Half);
+void Dbg64_cap_entry(Lm_list *, uint_t, Elf64_Xword, Elf64_Xword,
+ Elf64_Half);
+void Dbg32_cap_entry2(Lm_list *, uint_t, Elf32_Word, CapMask *,
+ Elf32_Half);
+void Dbg64_cap_entry2(Lm_list *, uint_t, Elf64_Xword, CapMask *,
+ Elf64_Half);
+void Dbg32_cap_out_title(Lm_list *);
+void Dbg64_cap_out_title(Lm_list *);
void Dbg32_cap_hw_candidate(Lm_list *, const char *);
void Dbg64_cap_hw_candidate(Lm_list *, const char *);
void Dbg32_cap_hw_filter(Lm_list *, const char *, Rt_map *);
void Dbg64_cap_hw_filter(Lm_list *, const char *, Rt_map *);
-void Dbg32_cap_mapfile(Lm_list *, Elf32_Word, Elf32_Word, Elf32_Half);
-void Dbg64_cap_mapfile(Lm_list *, Elf64_Xword, Elf64_Xword, Elf64_Half);
-void Dbg32_cap_sec_entry(Lm_list *, uint_t, Elf32_Word, Elf32_Word,
- Elf32_Half);
-void Dbg64_cap_sec_entry(Lm_list *, uint_t, Elf64_Xword, Elf64_Xword,
- Elf64_Half);
+void Dbg32_cap_mapfile_title(Lm_list *, Lineno);
+void Dbg64_cap_mapfile_title(Lm_list *, Lineno);
+void Dbg32_cap_out_title(Lm_list *);
+void Dbg64_cap_out_title(Lm_list *);
void Dbg32_cap_sec_title(Lm_list *, const char *);
void Dbg64_cap_sec_title(Lm_list *, const char *);
void Dbg32_cap_val_hw1(Lm_list *, Elf32_Word, Elf32_Half);
@@ -95,8 +105,8 @@ void Dbg64_cb_iphdr_mapchange(Lm_list *, u_longlong_t, u_longlong_t);
void Dbg32_cb_iphdr_unmap_ret(Lm_list *);
void Dbg64_cb_iphdr_unmap_ret(Lm_list *);
-void Dbg32_ent_print(Lm_list *, uchar_t, Elf32_Half, Alist *, Boolean);
-void Dbg64_ent_print(Lm_list *, uchar_t, Elf64_Half, Alist *, Boolean);
+void Dbg32_ent_print(Lm_list *, uchar_t, Elf32_Half, APlist *);
+void Dbg64_ent_print(Lm_list *, uchar_t, Elf64_Half, APlist *);
void Dbg32_file_analyze(Rt_map *);
void Dbg64_file_analyze64(Rt_map *);
@@ -203,28 +213,40 @@ void Dbg64_libs_yp(Lm_list *, const char *);
void Dbg32_libs_ylu(Lm_list *, const char *, const char *, int);
void Dbg64_libs_ylu(Lm_list *, const char *, const char *, int);
-void Dbg32_map_dash(Lm_list *, const char *);
-void Dbg64_map_dash(Lm_list *, const char *);
-void Dbg32_map_ent(Lm_list *, Boolean, Ent_desc *, Ofl_desc *);
-void Dbg64_map_ent(Lm_list *, Boolean, Ent_desc *, Ofl_desc *);
-void Dbg32_map_parse(Lm_list *, const char *);
-void Dbg64_map_parse(Lm_list *, const char *);
-void Dbg32_map_pipe(Lm_list *, Sg_desc *, const char *, Elf32_Word);
-void Dbg64_map_pipe(Lm_list *, Sg_desc *, const char *, Elf64_Word);
-void Dbg32_map_set_atsign(Boolean);
-void Dbg64_map_set_atsign(Boolean);
-void Dbg32_map_seg(Ofl_desc *, int, Sg_desc *);
-void Dbg64_map_seg(Ofl_desc *, int, Sg_desc *);
-void Dbg32_map_set_equal(Boolean);
-void Dbg64_map_set_equal(Boolean);
-void Dbg32_map_size_new(Lm_list *, const char *);
-void Dbg64_map_size_new(Lm_list *, const char *);
-void Dbg32_map_size_old(Ofl_desc *, Sym_desc *);
-void Dbg64_map_size_old(Ofl_desc *, Sym_desc *);
-void Dbg32_map_sort(Lm_list *);
-void Dbg64_map_sort(Lm_list *);
-void Dbg32_map_sort_seg(Lm_list *, Sg_desc *, int);
-void Dbg64_map_sort_seg(Lm_list *, Sg_desc *, int);
+void Dbg32_map_cexp_id(Lm_list *, Boolean, const char *, ulong_t,
+ const char *);
+void Dbg64_map_cexp_id(Lm_list *, Boolean, const char *, ulong_t,
+ const char *);
+void Dbg32_map_dv(Lm_list *, const char *, Lineno);
+void Dbg64_map_dv(Lm_list *, const char *, Lineno);
+void Dbg32_map_dv_entry(Lm_list *, Lineno, int, const char *);
+void Dbg64_map_dv_entry(Lm_list *, Lineno, int, const char *);
+void Dbg32_map_ent(Lm_list *, Ent_desc *, Ofl_desc *, Lineno);
+void Dbg64_map_ent(Lm_list *, Ent_desc *, Ofl_desc *, Lineno);
+void Dbg32_map_ent_ord_title(Lm_list *, const char *);
+void Dbg64_map_ent_ord_title(Lm_list *, const char *);
+void Dbg32_map_hdr_noalloc(Lm_list *, Lineno);
+void Dbg64_map_hdr_noalloc(Lm_list *, Lineno);
+void Dbg32_map_parse(Lm_list *, const char *, int);
+void Dbg64_map_parse(Lm_list *, const char *, int);
+void Dbg32_map_pass(Lm_list *, Boolean, const char *, ulong_t, const char *);
+void Dbg64_map_pass(Lm_list *, Boolean, const char *, ulong_t, const char *);
+void Dbg32_map_post_title(Lm_list *);
+void Dbg64_map_post_title(Lm_list *);
+void Dbg32_map_seg_os_order(Lm_list *, Sg_desc *, const char *,
+ Elf32_Word, Lineno);
+void Dbg64_map_seg_os_order(Lm_list *, Sg_desc *, const char *,
+ Elf64_Word, Lineno);
+void Dbg32_map_seg(Ofl_desc *, uint_t, int, Sg_desc *, Lineno);
+void Dbg64_map_seg(Ofl_desc *, uint_t, int, Sg_desc *, Lineno);
+void Dbg32_map_size_new(Lm_list *, const char *, const char *, Lineno);
+void Dbg64_map_size_new(Lm_list *, const char *, const char *, Lineno);
+void Dbg32_map_size_old(Ofl_desc *, Sym_desc *, const char *, Lineno);
+void Dbg64_map_size_old(Ofl_desc *, Sym_desc *, const char *, Lineno);
+void Dbg32_map_sort_title(Lm_list *, Boolean);
+void Dbg64_map_sort_title(Lm_list *, Boolean);
+void Dbg32_map_sort_seg(Lm_list *, uchar_t, Elf32_Half, Sg_desc *);
+void Dbg64_map_sort_seg(Lm_list *, uchar_t, Elf64_Half, Sg_desc *);
void Dbg32_map_symbol(Ofl_desc *, Sym_desc *);
void Dbg64_map_symbol(Ofl_desc *, Sym_desc *);
void Dbg32_map_version(Lm_list *, const char *, const char *, int);
@@ -325,8 +347,10 @@ void Dbg64_sec_redirected(Lm_list *, Is_desc *, const char *);
void Dbg32_sec_strtab(Lm_list *, Os_desc *, Str_tbl *);
void Dbg64_sec_strtab(Lm_list *, Os_desc *, Str_tbl *);
-void Dbg32_seg_desc_entry(Lm_list *, uchar_t, Elf32_Half, int, Sg_desc *);
-void Dbg64_seg_desc_entry(Lm_list *, uchar_t, Elf64_Half, int, Sg_desc *);
+void Dbg32_seg_desc_entry(Lm_list *, uchar_t, Elf32_Half, int, Sg_desc *,
+ Boolean);
+void Dbg64_seg_desc_entry(Lm_list *, uchar_t, Elf64_Half, int, Sg_desc *,
+ Boolean);
void Dbg32_seg_entry(Ofl_desc *, int, Sg_desc *);
void Dbg64_seg_entry(Ofl_desc *, int, Sg_desc *);
void Dbg32_seg_list(Lm_list *, uchar_t, Elf32_Half, APlist *);
diff --git a/usr/src/cmd/sgs/liblddbg/common/map.c b/usr/src/cmd/sgs/liblddbg/common/map.c
index cbff9c6518..7bcc5b8b2d 100644
--- a/usr/src/cmd/sgs/liblddbg/common/map.c
+++ b/usr/src/cmd/sgs/liblddbg/common/map.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -28,31 +28,39 @@
#include "_debug.h"
#include "libld.h"
-static const char
- *Dbg_decl = NULL;
+/*
+ * Report change in input enable status caused by evaluating
+ * $if/$elif control directives.
+ */
void
-Dbg_map_set_atsign(Boolean new)
+Dbg_map_pass(Lm_list *lml, Boolean enable, const char *file,
+ Lineno lineno, const char *directive)
{
+ const char *fmt;
+
if (DBG_NOTCLASS(DBG_C_MAP))
return;
- if (new)
- Dbg_decl = MSG_INTL(MSG_MAP_SEG_DECL_4);
- else
- Dbg_decl = MSG_INTL(MSG_MAP_SEG_DECL_5);
+ fmt = enable ? MSG_INTL(MSG_MAP_PASS) : MSG_INTL(MSG_MAP_NOPASS);
+ dbg_print(lml, fmt, file, EC_LINENO(lineno), directive);
}
+/*
+ * Report entry/removal of boolean identifier from conditional expression
+ * known values.
+ */
void
-Dbg_map_set_equal(Boolean new)
+Dbg_map_cexp_id(Lm_list *lml, Boolean add, const char *file,
+ Lineno lineno, const char *id)
{
+ const char *fmt;
+
if (DBG_NOTCLASS(DBG_C_MAP))
return;
- if (new)
- Dbg_decl = MSG_INTL(MSG_MAP_SEG_DECL_1);
- else
- Dbg_decl = MSG_INTL(MSG_MAP_SEG_DECL_2);
+ fmt = add ? MSG_INTL(MSG_MAP_ID_ADD) : MSG_INTL(MSG_MAP_ID_CLEAR);
+ dbg_print(lml, fmt, file, EC_LINENO(lineno), id);
}
void
@@ -78,17 +86,20 @@ Dbg_map_version(Lm_list *lml, const char *version, const char *name, int scope)
}
void
-Dbg_map_size_new(Lm_list *lml, const char *name)
+Dbg_map_size_new(Lm_list *lml, const char *symname, const char *segname,
+ Lineno lineno)
{
if (DBG_NOTCLASS(DBG_C_MAP))
return;
- dbg_print(lml, MSG_INTL(MSG_MAP_SYM_SIZE), Dbg_demangle_name(name),
- MSG_INTL(MSG_STR_ADD));
+ Dbg_util_nl(lml, DBG_NL_STD);
+ dbg_print(lml, MSG_INTL(MSG_MAP_SYM_SIZE), EC_LINENO(lineno), segname,
+ Dbg_demangle_name(symname), MSG_INTL(MSG_STR_ADDING));
}
void
-Dbg_map_size_old(Ofl_desc *ofl, Sym_desc *sdp)
+Dbg_map_size_old(Ofl_desc *ofl, Sym_desc *sdp, const char *segname,
+ Lineno lineno)
{
Conv_inv_buf_t inv_buf;
Lm_list *lml = ofl->ofl_lml;
@@ -96,8 +107,9 @@ Dbg_map_size_old(Ofl_desc *ofl, Sym_desc *sdp)
if (DBG_NOTCLASS(DBG_C_MAP))
return;
- dbg_print(lml, MSG_INTL(MSG_MAP_SYM_SIZE), sdp->sd_name,
- MSG_INTL(MSG_STR_UP_1));
+ Dbg_util_nl(lml, DBG_NL_STD);
+ dbg_print(lml, MSG_INTL(MSG_MAP_SYM_SIZE), EC_LINENO(lineno), segname,
+ sdp->sd_name, MSG_INTL(MSG_STR_UP_1));
if (DBG_NOTDETAIL())
return;
@@ -125,95 +137,195 @@ Dbg_map_symbol(Ofl_desc *ofl, Sym_desc *sdp)
conv_def_tag(sdp->sd_ref, &inv_buf));
}
+/*
+ * Object version dependency. In the v1 syntax, this is the 'dash' operator.
+ * In the v2 syntax, the DEPEND_VERSIONS directive.
+ */
void
-Dbg_map_dash(Lm_list *lml, const char *name)
+Dbg_map_dv(Lm_list *lml, const char *obj_name, Lineno lineno)
{
if (DBG_NOTCLASS(DBG_C_MAP))
return;
- dbg_print(lml, MSG_INTL(MSG_MAP_CNT_DEF), name);
+ dbg_print(lml, MSG_INTL(MSG_MAP_DV), EC_LINENO(lineno), obj_name);
}
+/*
+ * Add a version to an object dependency
+ */
void
-Dbg_map_sort(Lm_list *lml)
+Dbg_map_dv_entry(Lm_list *lml, Lineno lineno, int require, const char *version)
+{
+ const char *attr;
+
+ if (DBG_NOTCLASS(DBG_C_MAP))
+ return;
+
+ attr = require ? MSG_INTL(MSG_STR_REQUIRE) : MSG_INTL(MSG_STR_ALLOW);
+ dbg_print(lml, MSG_INTL(MSG_MAP_DV_ENTRY), attr, version,
+ EC_LINENO(lineno));
+}
+
+void
+Dbg_map_sort_title(Lm_list *lml, Boolean orig)
{
if (DBG_NOTCLASS(DBG_C_MAP))
return;
if (DBG_NOTDETAIL())
return;
- Dbg_util_nl(lml, DBG_NL_STD);
- dbg_print(lml, MSG_INTL(MSG_MAP_SORT_TITLE));
+ if (orig) {
+ Dbg_util_nl(lml, DBG_NL_STD);
+ dbg_print(lml, MSG_INTL(MSG_MAP_SORT_TITLE));
+ dbg_print(lml, MSG_INTL(MSG_MAP_SORT_TITLE_O));
+ } else {
+ dbg_print(lml, MSG_INTL(MSG_MAP_SORT_TITLE_S));
+ }
}
void
-Dbg_map_sort_seg(Lm_list *lml, Sg_desc *sgp, int orig)
+Dbg_map_sort_seg(Lm_list *lml, uchar_t osabi, Half mach, Sg_desc *sgp)
{
- const char *str;
+ const char *type_str;
+ Conv_inv_buf_t inv_buf;
if (DBG_NOTCLASS(DBG_C_MAP))
return;
if (DBG_NOTDETAIL())
return;
- if (sgp->sg_name && *sgp->sg_name)
- str = sgp->sg_name;
- else
- str = MSG_INTL(MSG_STR_NULL);
-
- if (orig)
- dbg_print(lml, MSG_INTL(MSG_MAP_SORT_ORIG), str);
- else
- dbg_print(lml, MSG_INTL(MSG_MAP_SORT_FINAL), str);
+ type_str = conv_phdr_type(osabi, mach, sgp->sg_phdr.p_type,
+ 0, &inv_buf);
+
+ if (sgp->sg_name) {
+ if (sgp->sg_flags & FLG_SG_P_VADDR) {
+ dbg_print(lml, MSG_ORIG(MSG_MAP_SORT_SEG_V),
+ type_str, sgp->sg_name,
+ EC_ADDR(sgp->sg_phdr.p_vaddr));
+ } else if (sgp->sg_flags & FLG_SG_ORDERED) {
+ /*
+ * All FLG_SG_ORDERED have adjacent sg_id values
+ * that start at SGID_TEXT. Subtract out the base
+ * in order to present the order values based at 0.
+ */
+ dbg_print(lml, MSG_ORIG(MSG_MAP_SORT_SEG_O),
+ type_str, sgp->sg_name,
+ EC_WORD(sgp->sg_id - SGID_TEXT));
+ } else {
+ dbg_print(lml, MSG_ORIG(MSG_MAP_SORT_SEG_NAME),
+ type_str, sgp->sg_name);
+ }
+ } else {
+ dbg_print(lml, MSG_ORIG(MSG_MAP_SORT_SEG), type_str);
+ }
}
void
-Dbg_map_parse(Lm_list *lml, const char *file)
+Dbg_map_parse(Lm_list *lml, const char *file, int version)
{
+ Conv_inv_buf_t inv_buf;
+
if (DBG_NOTCLASS(DBG_C_MAP))
return;
Dbg_util_nl(lml, DBG_NL_STD);
- dbg_print(lml, MSG_INTL(MSG_MAP_MAPFILE), file);
+ dbg_print(lml, MSG_INTL(MSG_MAP_MAPFILE), file, EC_WORD(version),
+ conv_mapfile_version(version, 0, &inv_buf));
}
void
-Dbg_map_ent(Lm_list *lml, Boolean new, Ent_desc *enp, Ofl_desc *ofl)
+Dbg_map_ent(Lm_list *lml, Ent_desc *enp, Ofl_desc *ofl, Lineno lineno)
{
if (DBG_NOTCLASS(DBG_C_MAP))
return;
- dbg_print(lml, MSG_INTL(MSG_MAP_MAP_DIR));
+ Dbg_util_nl(lml, DBG_NL_STD);
+ dbg_print(lml, MSG_INTL(MSG_MAP_EC), EC_LINENO(lineno));
Dbg_ent_entry(lml, ofl->ofl_dehdr->e_ident[EI_OSABI],
ofl->ofl_dehdr->e_machine, enp);
- if (new)
- Dbg_decl = MSG_INTL(MSG_MAP_SEG_DECL_3);
}
void
-Dbg_map_pipe(Lm_list *lml, Sg_desc *sgp, const char *sec_name, const Word ndx)
+Dbg_map_ent_ord_title(Lm_list *lml, const char *segname)
{
if (DBG_NOTCLASS(DBG_C_MAP))
return;
- dbg_print(lml, MSG_INTL(MSG_MAP_SEC_ORDER), sgp->sg_name, sec_name,
- EC_WORD(ndx));
+ Dbg_util_nl(lml, DBG_NL_STD);
+ dbg_print(lml, MSG_INTL(MSG_MAP_ENT_ORD_TITLE), segname);
}
void
-Dbg_map_seg(Ofl_desc *ofl, int ndx, Sg_desc *sgp)
+Dbg_map_seg_os_order(Lm_list *lml, Sg_desc *sgp, const char *sec_name,
+ Word ndx, Lineno lineno)
+{
+ if (DBG_NOTCLASS(DBG_C_MAP))
+ return;
+
+ dbg_print(lml, MSG_INTL(MSG_MAP_OS_ORDER), EC_LINENO(lineno),
+ sgp->sg_name, sec_name, EC_WORD(ndx));
+}
+
+void
+Dbg_map_seg(Ofl_desc *ofl, dbg_state_t dbg_state, int ndx, Sg_desc *sgp,
+ Lineno lineno)
{
Lm_list *lml = ofl->ofl_lml;
if (DBG_NOTCLASS(DBG_C_MAP))
return;
- if (Dbg_decl) {
- dbg_print(lml, MSG_ORIG(MSG_FMT_STR), Dbg_decl);
- Dbg_seg_desc_entry(ofl->ofl_lml,
- ofl->ofl_dehdr->e_ident[EI_OSABI],
- ofl->ofl_dehdr->e_machine, ndx, sgp);
- Dbg_util_nl(lml, DBG_NL_STD);
- Dbg_decl = NULL;
+ Dbg_util_nl(lml, DBG_NL_STD);
+ dbg_print(lml, MSG_INTL(MSG_MAP_SEG), EC_LINENO(lineno),
+ Dbg_state_str(dbg_state));
+ Dbg_seg_desc_entry(ofl->ofl_lml, ofl->ofl_dehdr->e_ident[EI_OSABI],
+ ofl->ofl_dehdr->e_machine, ndx, sgp, FALSE);
+ Dbg_util_nl(lml, DBG_NL_STD);
+}
+
+void
+Dbg_map_seg_order(Ofl_desc *ofl, uchar_t osabi, Half mach,
+ dbg_state_t dbg_state, Lineno lineno)
+{
+ Lm_list *lml = ofl->ofl_lml;
+ Aliste idx;
+ Sg_desc *sgp;
+ Conv_inv_buf_t inv_buf;
+ const char *type_str;
+
+ if (DBG_NOTCLASS(DBG_C_MAP))
+ return;
+
+ Dbg_util_nl(lml, DBG_NL_STD);
+ dbg_print(lml, MSG_INTL(MSG_MAP_SEG_ORDER), EC_LINENO(lineno),
+ EC_XWORD(aplist_nitems(ofl->ofl_segs_order)),
+ Dbg_state_str(dbg_state));
+ for (APLIST_TRAVERSE(ofl->ofl_segs_order, idx, sgp)) {
+ type_str = conv_phdr_type(osabi, mach, sgp->sg_phdr.p_type,
+ 0, &inv_buf);
+ dbg_print(lml, MSG_ORIG(MSG_MAP_SORT_SEG_NAME), type_str,
+ sgp->sg_name);
}
+ Dbg_util_nl(lml, DBG_NL_STD);
+}
+
+void
+Dbg_map_post_title(Lm_list *lml)
+{
+ if (DBG_NOTCLASS(DBG_C_MAP))
+ return;
+
+ Dbg_util_nl(lml, DBG_NL_STD);
+ dbg_print(lml, MSG_INTL(MSG_MAP_POST_TITLE));
+}
+
+
+void
+Dbg_map_hdr_noalloc(Lm_list *lml, Lineno lineno)
+{
+ if (DBG_NOTCLASS(DBG_C_MAP))
+ return;
+
+ Dbg_util_nl(lml, DBG_NL_STD);
+ dbg_print(lml, MSG_INTL(MSG_MAP_HDR_NOALLOC), EC_LINENO(lineno));
}
diff --git a/usr/src/cmd/sgs/liblddbg/common/mapfile-vers b/usr/src/cmd/sgs/liblddbg/common/mapfile-vers
index 3aeb2262ce..aa34aceda0 100644
--- a/usr/src/cmd/sgs/liblddbg/common/mapfile-vers
+++ b/usr/src/cmd/sgs/liblddbg/common/mapfile-vers
@@ -41,7 +41,7 @@
# MAPFILE HEADER END
#
-SUNWprivate_4.75 {
+SUNWprivate_4.76 {
global:
dbg_desc = NODIRECT; # interposed - ld.so.1(1)
dbg_print = NODIRECT; # interposed - ld(1) and ld.so.1(1)
@@ -69,6 +69,8 @@ SUNWprivate_4.75 {
Dbg_help;
Dbg_setup;
+ Dbg_state_str;
+ Dbg_version;
Dbg32_bind_global;
Dbg64_bind_global;
@@ -85,10 +87,14 @@ SUNWprivate_4.75 {
Dbg64_cap_hw_candidate;
Dbg32_cap_hw_filter;
Dbg64_cap_hw_filter;
- Dbg32_cap_mapfile;
- Dbg64_cap_mapfile;
- Dbg32_cap_sec_entry;
- Dbg64_cap_sec_entry;
+ Dbg32_cap_mapfile_title;
+ Dbg64_cap_mapfile_title;
+ Dbg32_cap_entry;
+ Dbg64_cap_entry;
+ Dbg32_cap_entry2;
+ Dbg64_cap_entry2;
+ Dbg32_cap_out_title;
+ Dbg64_cap_out_title;
Dbg32_cap_sec_title;
Dbg64_cap_sec_title;
Dbg32_cap_val_hw1;
@@ -208,28 +214,38 @@ SUNWprivate_4.75 {
Dbg32_libs_ylu;
Dbg64_libs_ylu;
- Dbg32_map_dash;
- Dbg64_map_dash;
+ Dbg32_map_cexp_id;
+ Dbg64_map_cexp_id;
+ Dbg32_map_dv;
+ Dbg64_map_dv;
+ Dbg32_map_dv_entry;
+ Dbg64_map_dv_entry;
Dbg32_map_ent;
Dbg64_map_ent;
+ Dbg32_map_ent_ord_title;
+ Dbg64_map_ent_ord_title;
+ Dbg32_map_hdr_noalloc;
+ Dbg64_map_hdr_noalloc;
Dbg32_map_parse;
Dbg64_map_parse;
- Dbg32_map_pipe;
- Dbg64_map_pipe;
- Dbg32_map_set_atsign;
- Dbg64_map_set_atsign;
+ Dbg32_map_pass;
+ Dbg64_map_pass;
+ Dbg32_map_post_title;
+ Dbg64_map_post_title;
Dbg32_map_seg;
Dbg64_map_seg;
- Dbg32_map_set_equal;
- Dbg64_map_set_equal;
+ Dbg32_map_seg_order;
+ Dbg64_map_seg_order;
+ Dbg32_map_seg_os_order;
+ Dbg64_map_seg_os_order;
Dbg32_map_size_new;
Dbg64_map_size_new;
Dbg32_map_size_old;
Dbg64_map_size_old;
- Dbg32_map_sort;
- Dbg64_map_sort;
Dbg32_map_sort_seg;
Dbg64_map_sort_seg;
+ Dbg32_map_sort_title;
+ Dbg64_map_sort_title;
Dbg32_map_symbol;
Dbg64_map_symbol;
Dbg32_map_version;
diff --git a/usr/src/cmd/sgs/liblddbg/common/sections.c b/usr/src/cmd/sgs/liblddbg/common/sections.c
index 2d802682e0..d883524fbe 100644
--- a/usr/src/cmd/sgs/liblddbg/common/sections.c
+++ b/usr/src/cmd/sgs/liblddbg/common/sections.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <stdio.h>
@@ -231,33 +231,21 @@ Dbg_sec_in(Lm_list *lml, Is_desc *isp)
void
Dbg_sec_added(Lm_list *lml, Os_desc *osp, Sg_desc *sgp)
{
- const char *str;
-
if (DBG_NOTCLASS(DBG_C_SECTIONS))
return;
- if (sgp->sg_name && *sgp->sg_name)
- str = sgp->sg_name;
- else
- str = MSG_INTL(MSG_STR_NULL);
-
- dbg_print(lml, MSG_INTL(MSG_SEC_ADDED), osp->os_name, str);
+ dbg_print(lml, MSG_INTL(MSG_SEC_ADDED), osp->os_name,
+ (sgp->sg_name ? sgp->sg_name : MSG_INTL(MSG_STR_NULL)));
}
void
Dbg_sec_created(Lm_list *lml, Os_desc *osp, Sg_desc *sgp)
{
- const char *str;
-
if (DBG_NOTCLASS(DBG_C_SECTIONS))
return;
- if (sgp->sg_name && *sgp->sg_name)
- str = sgp->sg_name;
- else
- str = MSG_INTL(MSG_STR_NULL);
-
- dbg_print(lml, MSG_INTL(MSG_SEC_CREATED), osp->os_name, str);
+ dbg_print(lml, MSG_INTL(MSG_SEC_CREATED), osp->os_name,
+ (sgp->sg_name ? sgp->sg_name : MSG_INTL(MSG_STR_NULL)));
}
void
diff --git a/usr/src/cmd/sgs/liblddbg/common/segments.c b/usr/src/cmd/sgs/liblddbg/common/segments.c
index 2bbabafed2..32822b3e70 100644
--- a/usr/src/cmd/sgs/liblddbg/common/segments.c
+++ b/usr/src/cmd/sgs/liblddbg/common/segments.c
@@ -20,10 +20,11 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
+#include <stdio.h>
#include "msg.h"
#include "_debug.h"
#include "libld.h"
@@ -33,39 +34,62 @@
*/
void
Dbg_seg_desc_entry(Lm_list *lml, uchar_t osabi, Half mach, int ndx,
- Sg_desc *sgp)
+ Sg_desc *sgp, Boolean space_nl)
{
Conv_seg_flags_buf_t seg_flags_buf;
- const char *str;
+ Aliste idx;
+ Sym_desc *sdp;
- if (sgp->sg_name && *sgp->sg_name)
- str = sgp->sg_name;
- else
- str = MSG_INTL(MSG_STR_NULL);
+ if (space_nl)
+ Dbg_util_nl(lml, DBG_NL_STD);
+ dbg_print(lml, MSG_ORIG(MSG_SEG_DESC), ndx);
+ if (sgp->sg_name)
+ dbg_print(lml, MSG_ORIG(MSG_SEG_NAME), sgp->sg_name);
- Dbg_util_nl(lml, DBG_NL_STD);
- dbg_print(lml, MSG_ORIG(MSG_SEG_NAME), ndx, str);
+ dbg_print(lml, MSG_ORIG(MSG_SEG_FLAGS),
+ conv_seg_flags(sgp->sg_flags, &seg_flags_buf));
Elf_phdr(lml, osabi, mach, &sgp->sg_phdr);
- dbg_print(lml, MSG_ORIG(MSG_SEG_LENGTH), EC_ADDR(sgp->sg_length));
- dbg_print(lml, MSG_ORIG(MSG_SEG_FLAGS),
- conv_seg_flags(sgp->sg_flags, &seg_flags_buf));
+ if (sgp->sg_flags & FLG_SG_P_ALIGN)
+ dbg_print(lml, MSG_ORIG(MSG_SEG_ALIGN),
+ EC_ADDR(sgp->sg_align));
+
+ if (sgp->sg_flags & FLG_SG_LENGTH)
+ dbg_print(lml, MSG_ORIG(MSG_SEG_LENGTH),
+ EC_ADDR(sgp->sg_length));
- if (sgp->sg_sizesym && sgp->sg_sizesym->sd_name)
- dbg_print(lml, MSG_ORIG(MSG_SEG_SIZESYM),
- Dbg_demangle_name(sgp->sg_sizesym->sd_name));
+ if (sgp->sg_flags & FLG_SG_ROUND)
+ dbg_print(lml, MSG_ORIG(MSG_SEG_ROUND),
+ EC_ADDR(sgp->sg_round));
- if (sgp->sg_secorder) {
+ if (aplist_nitems(sgp->sg_sizesym) > 0) {
+ dbg_print(lml, MSG_ORIG(MSG_SEG_SIZESYM_TITLE));
+ for (APLIST_TRAVERSE(sgp->sg_sizesym, idx, sdp))
+ if (sdp->sd_name)
+ dbg_print(lml, MSG_ORIG(MSG_SEG_SIZESYM),
+ Dbg_demangle_name(sdp->sd_name));
+ }
+ if (aplist_nitems(sgp->sg_is_order) > 0) {
+ Aliste idx;
+ Ent_desc *enp;
+
+ dbg_print(lml, MSG_ORIG(MSG_SEG_IS_ORDER_TITLE));
+ for (APLIST_TRAVERSE(sgp->sg_is_order, idx, enp))
+ dbg_print(lml, MSG_ORIG(MSG_SEG_LIST_ITEM),
+ enp->ec_name);
+ }
+ if (alist_nitems(sgp->sg_os_order) > 0) {
Aliste idx;
Sec_order *scop;
- dbg_print(lml, MSG_ORIG(MSG_SEG_ORDER));
- for (APLIST_TRAVERSE(sgp->sg_secorder, idx, scop))
- dbg_print(lml, MSG_ORIG(MSG_SEG_SECTION),
- scop->sco_secname, EC_WORD(scop->sco_index));
+ dbg_print(lml, MSG_ORIG(MSG_SEG_OS_ORDER_TITLE));
+ for (ALIST_TRAVERSE(sgp->sg_os_order, idx, scop))
+ dbg_print(lml, MSG_ORIG(MSG_SEG_LIST_ITEM),
+ scop->sco_secname);
}
- Dbg_util_nl(lml, DBG_NL_STD);
+ if (space_nl)
+ Dbg_util_nl(lml, DBG_NL_STD);
}
void
@@ -85,7 +109,7 @@ Dbg_seg_entry(Ofl_desc *ofl, int ndx, Sg_desc *sgp)
return;
Dbg_seg_desc_entry(ofl->ofl_lml, ofl->ofl_dehdr->e_ident[EI_OSABI],
- ofl->ofl_dehdr->e_machine, ndx, sgp);
+ ofl->ofl_dehdr->e_machine, ndx, sgp, TRUE);
}
/*
@@ -104,7 +128,7 @@ Dbg_seg_list(Lm_list *lml, uchar_t osabi, Half mach, APlist *apl)
Dbg_util_nl(lml, DBG_NL_STD);
dbg_print(lml, MSG_INTL(MSG_SEG_DESC_AVAIL));
for (APLIST_TRAVERSE(apl, idx, sgp))
- Dbg_seg_desc_entry(lml, osabi, mach, ndx++, sgp);
+ Dbg_seg_desc_entry(lml, osabi, mach, ndx++, sgp, TRUE);
}
/*
diff --git a/usr/src/cmd/sgs/libldstab/Makefile.com b/usr/src/cmd/sgs/libldstab/Makefile.com
index bd0ad2c294..446987500f 100644
--- a/usr/src/cmd/sgs/libldstab/Makefile.com
+++ b/usr/src/cmd/sgs/libldstab/Makefile.com
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
@@ -37,6 +37,8 @@ include $(SRC)/cmd/sgs/Makefile.com
SRCDIR = ../common
SRCBASE= ../../../..
+CPPFLAGS += -I$(ELFCAP)
+
LDLIBS += $(CONVLIBDIR) $(CONV_LIB) $(ELFLIBDIR) -lelf -lc
DYNFLAGS += $(VERSREF)
diff --git a/usr/src/cmd/sgs/nm/amd64/Makefile b/usr/src/cmd/sgs/nm/amd64/Makefile
index 129d878c7d..f2a8c30347 100644
--- a/usr/src/cmd/sgs/nm/amd64/Makefile
+++ b/usr/src/cmd/sgs/nm/amd64/Makefile
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
@@ -39,7 +39,7 @@ SRCS= $(COMOBJS:%.o=../common/%.c)
LDFLAGS += '-R$$ORIGIN/../../../lib/$(MACH64)'
INCLIST= -I../../include -I../../include/i386 \
-I$(SRCBASE)/uts/$(ARCH)/sys
-CPPFLAGS= $(INCLIST) $(DEFLIST) $(CPPFLAGS.master)
+CPPFLAGS= $(INCLIST) $(DEFLIST) $(CPPFLAGS.master) -I$(ELFCAP)
LDLIBS += $(CONVLIBDIR64) $(CONV_LIB) $(ELFLIBDIR) -lelf
LINTFLAGS64 += -x $(LDLIBS) -m64
LINTSRCS= $(SRCS)
diff --git a/usr/src/cmd/sgs/nm/i386/Makefile b/usr/src/cmd/sgs/nm/i386/Makefile
index c65e31848c..3a4112fb12 100644
--- a/usr/src/cmd/sgs/nm/i386/Makefile
+++ b/usr/src/cmd/sgs/nm/i386/Makefile
@@ -19,9 +19,7 @@
# CDDL HEADER END
#
#
-# ident "%Z%%M% %I% %E% SMI"
-#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# cmd/sgs/nm/i386/Makefile
@@ -46,7 +44,7 @@ LLDFLAGS = '-R$$ORIGIN/../../lib'
INCLIST= -I../../include -I../../include/i386 \
-I$(SRCBASE)/uts/$(ARCH)/sys
DEFLIST= -DTARGET=I386 -DI386=1 -D$(ARFORMAT) -DELF
-CPPFLAGS= $(INCLIST) $(DEFLIST) $(CPPFLAGS.master)
+CPPFLAGS= $(INCLIST) $(DEFLIST) $(CPPFLAGS.master) -I$(ELFCAP)
LDLIBS += $(CONVLIBDIR) $(CONV_LIB) $(ELFLIBDIR) -lelf
LINTFLAGS += -x $(LDLIBS)
LINTSRCS= $(SRCS)
diff --git a/usr/src/cmd/sgs/nm/sparc/Makefile b/usr/src/cmd/sgs/nm/sparc/Makefile
index 3fba7769c0..cd94ccfa0d 100644
--- a/usr/src/cmd/sgs/nm/sparc/Makefile
+++ b/usr/src/cmd/sgs/nm/sparc/Makefile
@@ -19,9 +19,7 @@
# CDDL HEADER END
#
#
-# ident "%Z%%M% %I% %E% SMI"
-#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# cmd/sgs/nm/sparc/Makefile
@@ -46,7 +44,7 @@ LLDFLAGS= '-R$$ORIGIN/../../lib'
INCLIST= -I../../include -I../../include/sparc \
-I$(SRCBASE)/uts/$(ARCH)/sys
DEFLIST= -DTARGET=SPARC -DSPARC=1 -D$(ARFORMAT) -DELF
-CPPFLAGS= $(INCLIST) $(DEFLIST) $(CPPFLAGS.master)
+CPPFLAGS= $(INCLIST) $(DEFLIST) $(CPPFLAGS.master) -I$(ELFCAP)
LDLIBS += $(CONVLIBDIR) $(CONV_LIB) $(ELFLIBDIR) -lelf
LINTFLAGS= -x $(LDLIBS)
LINTSRCS= $(SRCS)
diff --git a/usr/src/cmd/sgs/nm/sparcv9/Makefile b/usr/src/cmd/sgs/nm/sparcv9/Makefile
index cfa014abd0..51fbab7770 100644
--- a/usr/src/cmd/sgs/nm/sparcv9/Makefile
+++ b/usr/src/cmd/sgs/nm/sparcv9/Makefile
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# cmd/sgs/nm/sparcv9/Makefile
@@ -42,7 +42,7 @@ LDFLAGS += '-R$$ORIGIN/../../../lib/$(MACH64)'
INCLIST= -I../../include -I../../include/sparc \
-I$(SRCBASE)/uts/$(ARCH)/sys
DEFLIST= -DTARGET=SPARC -DSPARC=1 -D$(ARFORMAT) -DELF
-CPPFLAGS= $(INCLIST) $(DEFLIST) $(CPPFLAGS.master)
+CPPFLAGS= $(INCLIST) $(DEFLIST) $(CPPFLAGS.master) -I$(ELFCAP)
LDLIBS += $(CONVLIBDIR64) $(CONV_LIB) $(ELFLIBDIR) -lelf
LINTFLAGS64= -x $(LDLIBS) -m64
LINTSRCS= $(SRCS)
diff --git a/usr/src/cmd/sgs/packages/common/SUNWonld-README b/usr/src/cmd/sgs/packages/common/SUNWonld-README
index aa1316a94a..3e88be51d7 100644
--- a/usr/src/cmd/sgs/packages/common/SUNWonld-README
+++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README
@@ -1548,3 +1548,5 @@ Bugid Risk Synopsis
6923449 elfdump misinterprets _init/_fini symbols in dynamic section test
6914728 Add dl_iterate_phdr() function to ld.so.1 (D)
PSARC/2010/015 dl_iterate_phdr
+6916788 ld version 2 mapfile syntax (D)
+ PSARC/2009/688 Human readable and extensible ld mapfile syntax
diff --git a/usr/src/cmd/sgs/prof/Makefile.com b/usr/src/cmd/sgs/prof/Makefile.com
index 5d457344da..32ed03f0c5 100644
--- a/usr/src/cmd/sgs/prof/Makefile.com
+++ b/usr/src/cmd/sgs/prof/Makefile.com
@@ -19,9 +19,7 @@
# CDDL HEADER END
#
#
-# ident "%Z%%M% %I% %E% SMI"
-#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# cmd/sgs/prof/Makefile.com
@@ -41,7 +39,7 @@ SRCS= $(COMOBJS:%.o=../common/%.c)
INCLIST= -I../common -I../../include -I../../include/$(MACH)
-CPPFLAGS= $(INCLIST) $(DEFLIST) $(CPPFLAGS.master)
+CPPFLAGS= $(INCLIST) $(DEFLIST) $(CPPFLAGS.master) -I$(ELFCAP)
CFLAGS += $(CCVERBOSE)
C99MODE= $(C99_ENABLE)
LDLIBS += $(CONVLIBDIR) $(CONV_LIB) $(ELFLIBDIR) -lelf
diff --git a/usr/src/cmd/sgs/rtld/common/debug.c b/usr/src/cmd/sgs/rtld/common/debug.c
index 377a2da34a..6942ef8434 100644
--- a/usr/src/cmd/sgs/rtld/common/debug.c
+++ b/usr/src/cmd/sgs/rtld/common/debug.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -145,9 +145,11 @@ dbg_setup(const char *options, Dbg_desc *dbp)
dbg_ino = status.st_ino;
/*
- * Now that the output file is established, generate help
- * output if the user specified the debug help token.
+ * Now that the output file is established, identify the linker
+ * package, and generate help output if the user specified the
+ * debug help token.
*/
+ Dbg_version();
if (dbp->d_extra & DBG_E_HELP)
Dbg_help();
diff --git a/usr/src/cmd/sgs/rtld/common/object.c b/usr/src/cmd/sgs/rtld/common/object.c
index cc2d633424..f46dfaf12f 100644
--- a/usr/src/cmd/sgs/rtld/common/object.c
+++ b/usr/src/cmd/sgs/rtld/common/object.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -217,6 +217,7 @@ elf_obj_fini(Lm_list *lml, Rt_map *lmp, int *in_nfavl)
Fdesc fd = { 0 };
Grp_hdl *ghp;
Rej_desc rej = { 0 };
+ elfcap_mask_t cap_value;
DBG_CALL(Dbg_util_nl(lml, DBG_NL_STD));
@@ -230,7 +231,8 @@ elf_obj_fini(Lm_list *lml, Rt_map *lmp, int *in_nfavl)
* hardware or software capabilities have been established, ensure that
* they are appropriate for this platform.
*/
- if ((ofl->ofl_hwcap_1) && (hwcap_check(ofl->ofl_hwcap_1, &rej) == 0)) {
+ cap_value = CAPMASK_VALUE(&ofl->ofl_ocapset.c_hw_1);
+ if (cap_value && (hwcap_check(cap_value, &rej) == 0)) {
if ((lml_main.lm_flags & LML_FLG_TRC_LDDSTUB) && lmp &&
(FLAGS1(lmp) & FL1_RT_LDDSTUB) && (NEXT(lmp) == NULL)) {
(void) printf(MSG_INTL(MSG_LDD_GEN_HWCAP_1),
@@ -239,7 +241,8 @@ elf_obj_fini(Lm_list *lml, Rt_map *lmp, int *in_nfavl)
return (NULL);
}
- if ((ofl->ofl_sfcap_1) && (sfcap_check(ofl->ofl_sfcap_1, &rej) == 0)) {
+ cap_value = CAPMASK_VALUE(&ofl->ofl_ocapset.c_sf_1);
+ if (cap_value && (sfcap_check(cap_value, &rej) == 0)) {
if ((lml_main.lm_flags & LML_FLG_TRC_LDDSTUB) && lmp &&
(FLAGS1(lmp) & FL1_RT_LDDSTUB) && (NEXT(lmp) == NULL)) {
(void) printf(MSG_INTL(MSG_LDD_GEN_SFCAP_1),
diff --git a/usr/src/cmd/sgs/rtld/common/rtld.msg b/usr/src/cmd/sgs/rtld/common/rtld.msg
index 919009d3a3..1b2033c400 100644
--- a/usr/src/cmd/sgs/rtld/common/rtld.msg
+++ b/usr/src/cmd/sgs/rtld/common/rtld.msg
@@ -20,7 +20,7 @@
#
#
-# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
@@ -125,7 +125,7 @@
# Versioning diagnostics.
-@ MSG_VER_NFOUND "%s: version `%s' not found (required by file %s)"
+@ MSG_VER_NFOUND "%s: version '%s' not found (required by file %s)"
# Diagnostics generated under the control of ldd(1).