Mercurial > illumos > illumos-gate
changeset 11734:d29dc9c2b6c5
6916788 ld version 2 mapfile syntax
PSARC/2009/688 Human readable and extensible ld mapfile syntax
line wrap: on
line diff
--- a/usr/src/cmd/sgs/Makefile.com Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/Makefile.com Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ 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 @@ 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).
--- a/usr/src/cmd/sgs/elfdump/Makefile.com Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/elfdump/Makefile.com Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ 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)
--- a/usr/src/cmd/sgs/elfedit/Makefile.com Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/elfedit/Makefile.com Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ 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)
--- a/usr/src/cmd/sgs/elfedit/common/elfedit.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/elfedit/common/elfedit.c Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ /* - * 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 @@ } 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; }
--- a/usr/src/cmd/sgs/elfwrap/Makefile.com Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/elfwrap/Makefile.com Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ 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)
--- a/usr/src/cmd/sgs/gprof/Makefile.com Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/gprof/Makefile.com Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ 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
--- a/usr/src/cmd/sgs/include/conv.h Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/include/conv.h Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ } 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 @@ 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 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_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 @@ 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);
--- a/usr/src/cmd/sgs/include/debug.h Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/include/debug.h Mon Feb 22 09:19:31 2010 -0700 @@ -134,12 +134,6 @@ #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 @@ #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 @@ 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 @@ 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 @@ #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 @@ #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 @@ #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 @@ #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_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 @@ 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_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_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);
--- a/usr/src/cmd/sgs/include/elfedit.h Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/include/elfedit.h Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ * 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
--- a/usr/src/cmd/sgs/include/i386/machdep_x86.h Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/include/i386/machdep_x86.h Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ #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 /*
--- a/usr/src/cmd/sgs/include/libld.h Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/include/libld.h Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ /* + * 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 @@ 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 @@ 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 @@ #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 @@ #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 @@ * 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 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_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_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 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 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 @@ #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 @@ #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 @@ /* 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 @@ */ #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. */
--- a/usr/src/cmd/sgs/include/sgs.h Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/include/sgs.h Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ 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
--- a/usr/src/cmd/sgs/include/sparc/machdep_sparc.h Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/include/sparc/machdep_sparc.h Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ #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
--- a/usr/src/cmd/sgs/lari/lari.pl Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/lari/lari.pl Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ } $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; }
--- a/usr/src/cmd/sgs/ldd/common/ldd.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/ldd/common/ldd.c Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ /* * 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
--- a/usr/src/cmd/sgs/ldprof/Makefile.com Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/ldprof/Makefile.com Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ -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 =
--- a/usr/src/cmd/sgs/libconv/Makefile.com Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libconv/Makefile.com Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ 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 @@ 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 @@ 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
--- a/usr/src/cmd/sgs/libconv/common/c_literal.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libconv/common/c_literal.c Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ } } } + +/* + * 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); +}
--- a/usr/src/cmd/sgs/libconv/common/cap.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libconv/common/cap.c Mon Feb 22 09:19:31 2010 -0700 @@ -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) };
--- a/usr/src/cmd/sgs/libconv/common/cap.msg Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libconv/common/cap.msg Mon Feb 22 09:19:31 2010 -0700 @@ -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 [ "
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/sgs/libconv/common/entry.c Mon Feb 22 09:19:31 2010 -0700 @@ -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); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/sgs/libconv/common/entry.msg Mon Feb 22 09:19:31 2010 -0700 @@ -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"
--- a/usr/src/cmd/sgs/libconv/common/lintsup.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libconv/common/lintsup.c Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ 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);
--- a/usr/src/cmd/sgs/libconv/common/llib-lconv Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libconv/common/llib-lconv Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ 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,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/sgs/libconv/common/map.c Mon Feb 22 09:19:31 2010 -0700 @@ -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)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/sgs/libconv/common/map.msg Mon Feb 22 09:19:31 2010 -0700 @@ -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"
--- a/usr/src/cmd/sgs/libconv/common/segments.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libconv/common/segments.c Mon Feb 22 09:19:31 2010 -0700 @@ -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 = {
--- a/usr/src/cmd/sgs/libconv/common/segments.msg Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libconv/common/segments.msg Mon Feb 22 09:19:31 2010 -0700 @@ -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"
--- a/usr/src/cmd/sgs/libld/Makefile.com Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libld/Makefile.com Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ 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)/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 @@ 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
--- a/usr/src/cmd/sgs/libld/common/_libld.h Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libld/common/_libld.h Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ 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 @@ * 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 @@ #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 @@ } 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 @@ #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 @@ #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 @@ #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 @@ #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 @@ #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 @@ #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 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_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 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_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 **,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/sgs/libld/common/_map.h Mon Feb 22 09:19:31 2010 -0700 @@ -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 */
--- a/usr/src/cmd/sgs/libld/common/args.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libld/common/args.c Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ 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) - return (S_ERROR); - - if (ofl->ofl_flags & FLG_OF_SEGSORT) - if (ld_sort_seg_list(ofl) == S_ERROR) + if (!ld_map_parse(name, ofl)) 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 @@ 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);
--- a/usr/src/cmd/sgs/libld/common/debug.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libld/common/debug.c Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ } /* - * 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();
--- a/usr/src/cmd/sgs/libld/common/entry.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libld/common/entry.c Mon Feb 22 09:19:31 2010 -0700 @@ -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)), +/* + * 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; - SG_DESC_INIT(LD_SUNWCAP, PT_SUNWCAP, PF_R, MSG_ORIG(MSG_ENT_SUNWCAP), - (FLG_SG_TYPE | FLG_SG_FLAGS)), +static const size_t predef_seg_nelts = + (sizeof (predef_seg_t) / sizeof (Sg_desc)); - SG_DESC_INIT(LD_TEXT, PT_LOAD, PF_R + PF_X, MSG_ORIG(MSG_ENT_TEXT), - (FLG_SG_TYPE | FLG_SG_FLAGS)), +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)), - SG_DESC_INIT(LD_DATA, PT_LOAD, 0, MSG_ORIG(MSG_ENT_DATA), - (FLG_SG_TYPE | FLG_SG_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)), - SG_DESC_INIT(LD_BSS, PT_LOAD, 0, MSG_ORIG(MSG_ENT_BSS), - (FLG_SG_TYPE | FLG_SG_FLAGS | FLG_SG_DISABLED)), + /* 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)), + + /* psg_tls */ + SG_DESC_INIT(SGID_TLS, PT_TLS, PF_R, 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_unwind */ + SG_DESC_INIT(SGID_UNWIND, PT_SUNW_UNWIND, 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_sunwstack */ + SG_DESC_INIT(SGID_SUNWSTACK, PT_SUNWSTACK, 0, NULL, + (FLG_SG_P_TYPE | FLG_SG_P_FLAGS | FLG_SG_DISABLED)), + + /* psg_note */ + SG_DESC_INIT(SGID_NOTE, PT_NOTE, 0, MSG_ORIG(MSG_ENT_NOTE), + FLG_SG_P_TYPE), - SG_DESC_INIT(LD_UNWIND, PT_SUNW_UNWIND, PF_R, MSG_ORIG(MSG_ENT_UNWIND), - (FLG_SG_TYPE | FLG_SG_FLAGS)), - - SG_DESC_INIT(LD_NOTE, PT_NOTE, 0, MSG_ORIG(MSG_ENT_NOTE), FLG_SG_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) */ + EC_DESC_INIT(0, SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE, + SHF_ALLOC + SHF_AMD64_LARGE, lrodata, 0), +#endif + EC_DESC_INIT(0, SHF_ALLOC + SHF_WRITE, SHF_ALLOC, text, 0), + + 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_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(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_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 + SHF_WRITE, data, 0), + + /* + * 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 - {NULL, MSG_ORIG(MSG_ENT_BSS), SHT_NOBITS, - SHF_ALLOC + SHF_WRITE, SHF_ALLOC + SHF_WRITE, - (Sg_desc *)LD_BSS, 0, FLG_EC_BUILTIN}, +/* + * 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; -#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}, + /* + * 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; - {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}, -#endif - {NULL, MSG_ORIG(MSG_ENT_DATA), NULL, - SHF_ALLOC + SHF_WRITE, SHF_ALLOC + SHF_WRITE, - (Sg_desc *)LD_DATA, 0, FLG_EC_BUILTIN}, + sg.sg_name = name; + return (avl_find(&ofl->ofl_segs_avl, &sg, where)); +} + - {NULL, MSG_ORIG(MSG_ENT_EXTRA), 0, 0, 0, - (Sg_desc *)LD_EXTRA, 0, FLG_EC_BUILTIN} -}; +/* + * 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 @@ 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 @@ 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 @@ * 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 @@ * 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 @@ * 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);
--- a/usr/src/cmd/sgs/libld/common/files.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libld/common/files.c Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ 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 @@ 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 @@ * 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 @@ 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; + + /* + * Having processed the frame pointer bits, remove them from + * the value so they don't get OR'd in below. + */ + val &= ~FP_FLAGS; - } else if ((ofl->ofl_sfcap_1 & SF1_SUNW_FPKNWN) == 0) { + } else if ((ofl->ofl_ocapset.c_sf_1.cm_value & SF1_SUNW_FPKNWN) == 0) { /* - * If the present state is unknown, take the new relocatable - * object frame pointer usage. + * 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_sfcap_1 = val; + 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 @@ * 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 @@ 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 @@ 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 @@ * 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 @@ 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 */
--- a/usr/src/cmd/sgs/libld/common/ldentry.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libld/common/ldentry.c Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ * 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); } } }
--- a/usr/src/cmd/sgs/libld/common/ldmain.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libld/common/ldmain.c Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ 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 @@ * 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); /*
--- a/usr/src/cmd/sgs/libld/common/libld.intel.msg Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libld/common/libld.intel.msg Mon Feb 22 09:19:31 2010 -0700 @@ -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"
--- a/usr/src/cmd/sgs/libld/common/libld.msg Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libld/common/libld.msg Mon Feb 22 09:19:31 2010 -0700 @@ -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_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: %lld: empty segment must be of type LOAD or NULL" -@ MSG_MAP_SEGEMPEXE "%s: %lld: a LOAD empty segment definition is only \ +@ 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_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: 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: \ - %s: %s" -@ MSG_MAP_SYMDEF2 "%s: %lld: symbol `%s': %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_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_SYMDEF1 "%s: %llu: symbol '%s' is already defined in file: \ + %s: %s" +@ MSG_MAP_SYMDEF2 "%s: %llu: symbol '%s': %s" + +@ 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_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" -
--- a/usr/src/cmd/sgs/libld/common/libld.sparc.msg Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libld/common/libld.sparc.msg Mon Feb 22 09:19:31 2010 -0700 @@ -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 \
--- a/usr/src/cmd/sgs/libld/common/machrel.amd.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libld/common/machrel.amd.c Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ 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 */
--- a/usr/src/cmd/sgs/libld/common/machrel.intel.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libld/common/machrel.intel.c Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ 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 */
--- a/usr/src/cmd/sgs/libld/common/machrel.sparc.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libld/common/machrel.sparc.c Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ 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)
--- a/usr/src/cmd/sgs/libld/common/map.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libld/common/map.c Mon Feb 22 09:19:31 2010 -0700 @@ -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" - -#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. */ +#include "_map.h" - /* 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 @@ * * 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; - while ((tok = gettoken(ofl, mapfile, 0)) != TK_SEMICOLON) { + 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 = 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; + } + + /* 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 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; - } - } - - /* - * 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 (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 (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 (type == CA_SUNW_HW_1) - ofl->ofl_hwcap_1 |= number; - else - ofl->ofl_sfcap_1 |= number; + value |= number; used++; continue; } @@ -295,78 +127,161 @@ * 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 empty declarations */ + if (used == 0) { + mf_warn0(mf, MSG_INTL(MSG_MAP_EMPTYCAP)); + return (TRUE); + } + + 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); +} + +/* + * 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 +map_equal_flags(Mapfile *mf, Sg_desc *sgp, Boolean *b_flags, + const char *flag_tok) +{ + Word tmp_flags = 0; + + if (*b_flags) { + mf_fatal(mf, MSG_INTL(MSG_MAP_MOREONCE), + MSG_INTL(MSG_MAP_SEGFLAG)); + return (FALSE); + } + + /* 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++; } /* - * Catch any empty declarations, and indicate any software capabilities - * have been initialized if necessary. + * Warn when changing flags except when we're adding or removing "X" + * from a RW PT_LOAD segment. */ - 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; + 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); - /* - * 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 - } - return (1); + sgp->sg_flags |= FLG_SG_P_FLAGS; + sgp->sg_phdr.p_flags = tmp_flags; + *b_flags = TRUE; + + return (TRUE); } /* - * Common segment error checking. + * 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 -seg_check(const char *mapfile, Sg_desc *sgp, Ofl_desc *ofl, Boolean b_type, - Word p_type) +valuetoxword(Mapfile *mf, ld_map_tkval_t *tkv, Xword *value) { - if (b_type) { - eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_MAP_MOREONCE), - mapfile, EC_XWORD(Line_num), MSG_INTL(MSG_MAP_SEGTYP)); - return (FALSE); + 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; } - 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); - } - return (TRUE); + + return (FALSE); } /* @@ -375,10 +290,35 @@ * 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 @@ 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); - } - - 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 (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; + mf_fatal0(mf, MSG_INTL(MSG_MAP_EXPSEGATT)); + return (FALSE); } - /* 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 it is the name of a segment type, set the type + * and flags fields in the descriptor. + */ + 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); + } - /* - * 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++; - } + 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; + /* 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 ((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); - } + if (!valuetoxword(mf, &tkv, &number)) + return (FALSE); - 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); - } - - 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 @@ 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 @@ 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 @@ * 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 @@ * 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 @@ * 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 @@ 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 @@ * 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 @@ 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 @@ 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 @@ 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); + /* Add the symbol to the segment */ + if (!ld_map_seg_size_symbol(mf, sgp, TK_PLUSEQ, tkv.tkv_str)) + 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(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); - } + if (ld_map_gettoken(mf, 0, &tkv) != TK_SEMICOLON) { + if (tok != TK_ERROR) + mf_fatal0(mf, MSG_INTL(MSG_MAP_EXPSCOL)); + return (FALSE); } - /* - * Assign the symbol to the segment. - */ - sgp->sg_sizesym = sdp; - - if (gettoken(ofl, mapfile, 0) != 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); - } - - 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 (!ld_map_seg_os_order_add(mf, sgp, tkv.tkv_str)) + return (FALSE); - 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 ((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 @@ * 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 @@ * 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 @@ * 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 @@ /* * 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 @@ * } [ 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; - - /* - * 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); - } + 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 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; + while ((tok = ld_map_gettoken(mf, 0, &tkv)) != TK_RIGHTBKT) { + uint_t filter = 0; - 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++; + 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 @@ * 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 @@ * 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 @@ /* * Determine any Value or Size attributes. */ - lowercase(Start_tok); - - if (Start_tok[0] == 'v' || - Start_tok[0] == 's') { - char *end_tok; - Lword number; + ld_map_lowercase(tkv.tkv_str); - 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; + if (tkv.tkv_str[0] == 'v' || + tkv.tkv_str[0] == 's') { + Xword number; + + if (!valuetoxword(mf, &tkv, &number)) { + mv.mv_errcnt++; + return (FALSE); } - 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; - } - - 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) { + /* Next token is the filtee */ + filter = FLG_SY_STDFLTR; + continue; + } else if (strcmp(tkv.tkv_str, + MSG_ORIG(MSG_MAP_AUXILIARY)) == 0) { + /* Next token is the filtee */ + filter = FLG_SY_AUXFLTR; + continue; + } else if (strcmp(tkv.tkv_str, + MSG_ORIG(MSG_MAP_INTERPOSE)) == 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++; + if (!(ofl->ofl_flags & FLG_OF_EXEC)) { + mf_fatal0(mf, + MSG_INTL(MSG_MAP_NOINTPOSE)); + mv.mv_errcnt++; break; } /* END CSTYLED */ - dftflag = filter = FLG_SY_STDFLTR; - sdflags |= FLG_SY_STDFLTR; - ofl->ofl_flags |= FLG_OF_SYMINFO; - continue; - } else if (strcmp(Start_tok, - 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; - continue; - } else if (strcmp(Start_tok, - 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++; - 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 @@ * 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. + * bracket, parsing up to the terminating ';'. */ - 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; - } + if (!ld_map_sym_ver_fini(mf, &mv)) + return (FALSE); - /* - * 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); + return (TRUE); } /* - * 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. + * Parse the mapfile --- Sysv syntax */ -uintptr_t -ld_sort_seg_list(Ofl_desc *ofl) +Boolean +ld_map_parse_v1(Mapfile *mf) { - 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. - */ - 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 - - return (1); -} - -/* - * Parse the mapfile. - */ -uintptr_t -ld_map_parse(const char *mapfile, Ofl_desc *ofl) -{ - 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 @@ */ 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; + + } + if (strcmp(sgp1->sg_name, + MSG_ORIG(MSG_STR_SFCAP_1)) == 0) { + if (!map_cap(mf, CA_SUNW_SF_1, + &ofl->ofl_ocapset.c_sf_1)) + return (FALSE); continue; - } else 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)); - continue; + } + + /* + * If not a new segment, show the initial value + * before modifying it. + */ + 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); - } 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. + * 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 ((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 (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; } /* - * 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. + * If this is a new segment, finish its initialization + * and insert it into the segment list. */ - 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 (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; - /* - * Having completed parsing an entry in the mapfile determine - * if the segment to which it applies is new. - */ - if (new_segment) { + case TK_COLON: /* Section to segment mapping */ /* - * 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 it is not a new segment, ensure that it is + * not an empty segment reservation, as sections + * cannot be assigned to those. */ - 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 (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 ((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; - } + } else if (sgp1->sg_flags & FLG_SG_EMPTY) { + mf_fatal0(mf, MSG_INTL(MSG_MAP_SEGEMPSEC)); + return (FALSE); } /* - * 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. - * - * Note that any new segments must always be added - * after any PT_PHDR and PT_INTERP (refer Generic ABI, - * Page 5-4). + * 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. */ - 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); } + if (!map_atsign(mf, sgp1)) + return (FALSE); + break; - ndx = 0; - for (APLIST_TRAVERSE(ofl->ofl_segs, idx, sgp2)) { - if (sgp1->sg_id > sgp2->sg_id) { - ndx++; - continue; - } + case TK_ERROR: + return (FALSE); /* Error was already issued */ - if (aplist_insert(&ofl->ofl_segs, sgp1, - AL_CNT_SEGMENTS, idx) == NULL) - return (S_ERROR); - break; - } + default: + mf_fatal0(mf, MSG_INTL(MSG_MAP_EXPEQU)); + return (FALSE); } - DBG_CALL(Dbg_map_seg(ofl, ndx, sgp1)); } - /* - * 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; - - /* - * 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; - - return (1); + return (TRUE); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/sgs/libld/common/map_core.c Mon Feb 22 09:19:31 2010 -0700 @@ -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); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/sgs/libld/common/map_support.c Mon Feb 22 09:19:31 2010 -0700 @@ -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); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/cmd/sgs/libld/common/map_v2.c Mon Feb 22 09:19:31 2010 -0700 @@ -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); +}
--- a/usr/src/cmd/sgs/libld/common/order.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libld/common/order.c Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ * 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 @@ * 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 @@ */ 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 @@ */ 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 @@ * 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 @@ 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),
--- a/usr/src/cmd/sgs/libld/common/outfile.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libld/common/outfile.c Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ 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 @@ } 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 @@ 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 @@ 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
--- a/usr/src/cmd/sgs/libld/common/place.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libld/common/place.c Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ (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 @@ #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 @@ * 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 @@ * 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 @@ (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; - - 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 ((alist_nitems(enp->ec_files) > 0) && + ((path_info == NULL) || !eval_ec_files(path_info, enp))) + continue; - 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 @@ * 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 @@ oname[size] = '\0'; DBG_CALL(Dbg_sec_redirected(ofl->ofl_lml, isp, oname)); } - isp->is_ordndx = enp->ec_ordndx; } /* @@ -654,8 +812,8 @@ 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 @@ */ 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 @@ */ 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 @@ */ 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 @@ 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; }
--- a/usr/src/cmd/sgs/libld/common/sections.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libld/common/sections.c Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ * 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ * 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 @@ 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 @@ * 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 @@ * 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 @@ &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 @@ * 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 @@ &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 @@ 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 @@ &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 @@ * 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ * 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 @@ 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 @@ 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 @@ } /* 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 @@ } } 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); }
--- a/usr/src/cmd/sgs/libld/common/syms.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libld/common/syms.c Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ * 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
--- a/usr/src/cmd/sgs/libld/common/unwind.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libld/common/unwind.c Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ 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);
--- a/usr/src/cmd/sgs/libld/common/update.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libld/common/update.c Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ */ 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 @@ */ 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 @@ } /* + * 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 @@ } /* - * 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 @@ /* * 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 @@ /* * 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;
--- a/usr/src/cmd/sgs/liblddbg/common/cap.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/liblddbg/common/cap.c Mon Feb 22 09:19:31 2010 -0700 @@ -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,26 +64,9 @@ 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) -{ - if (DBG_NOTCLASS(DBG_C_MAP | DBG_C_CAP)) - return; - - dbg_print(lml, MSG_INTL(MSG_MAP_CAP)); - Dbg_cap_sec_entry(lml, DBG_CAP_INITIAL, tag, val, mach); -} - -void -Dbg_cap_sec_entry(Lm_list *lml, uint_t type, Xword tag, Xword val, Half mach) +Dbg_cap_entry(Lm_list *lml, dbg_state_t dbg_state, Xword tag, Xword val, + Half mach) { Conv_inv_buf_t inv_buf; Conv_cap_val_buf_t cap_val_buf; @@ -91,11 +74,40 @@ if (DBG_NOTCLASS(DBG_C_CAP)) return; - dbg_print(lml, MSG_INTL(MSG_CAP_SEC_ENTRY), MSG_INTL(captype[type]), + 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_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_buf1, cap_val_buf2; + + if (DBG_NOTCLASS(DBG_C_CAP)) + return; + + /* 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 Dbg_cap_sec_title(Lm_list *lml, const char *name) { @@ -107,6 +119,25 @@ } 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));
--- a/usr/src/cmd/sgs/liblddbg/common/debug.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/liblddbg/common/debug.c Mon Feb 22 09:19:31 2010 -0700 @@ -134,7 +134,7 @@ 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 @@ } /* + * 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 @@ (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])); +}
--- a/usr/src/cmd/sgs/liblddbg/common/entry.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/liblddbg/common/entry.c Mon Feb 22 09:19:31 2010 -0700 @@ -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; + + if (enp->ec_name != NULL) + dbg_print(lml, MSG_ORIG(MSG_ECR_NAME), enp->ec_name); - 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)); + 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 @@ * 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 @@ 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); }
--- a/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/liblddbg/common/liblddbg.msg Mon Feb 22 09:19:31 2010 -0700 @@ -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_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_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_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 "map file additions: segment sorting required (vaddr):" -@ MSG_MAP_SORT_ORIG " original=%s" -@ MSG_MAP_SORT_FINAL " sorted=%s" +@ 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_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"
--- a/usr/src/cmd/sgs/liblddbg/common/llib-llddbg Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/liblddbg/common/llib-llddbg Mon Feb 22 09:19:31 2010 -0700 @@ -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 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 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 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 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 *);
--- a/usr/src/cmd/sgs/liblddbg/common/map.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/liblddbg/common/map.c Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ } 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 @@ 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 @@ 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_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(Lm_list *lml) +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); + type_str = conv_phdr_type(osabi, mach, sgp->sg_phdr.p_type, + 0, &inv_buf); - if (orig) - dbg_print(lml, MSG_INTL(MSG_MAP_SORT_ORIG), str); - else - dbg_print(lml, MSG_INTL(MSG_MAP_SORT_FINAL), str); + 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, EC_WORD(version), + conv_mapfile_version(version, 0, &inv_buf)); +} + +void +Dbg_map_ent(Lm_list *lml, Ent_desc *enp, Ofl_desc *ofl, Lineno lineno) { 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_EC), EC_LINENO(lineno)); + Dbg_ent_entry(lml, ofl->ofl_dehdr->e_ident[EI_OSABI], + ofl->ofl_dehdr->e_machine, enp); } void -Dbg_map_ent(Lm_list *lml, Boolean new, Ent_desc *enp, Ofl_desc *ofl) +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_MAP_DIR)); - 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); + Dbg_util_nl(lml, DBG_NL_STD); + dbg_print(lml, MSG_INTL(MSG_MAP_ENT_ORD_TITLE), segname); } void -Dbg_map_pipe(Lm_list *lml, Sg_desc *sgp, const char *sec_name, const Word ndx) +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_SEC_ORDER), sgp->sg_name, sec_name, - EC_WORD(ndx)); + 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, int ndx, Sg_desc *sgp) +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)); +}
--- a/usr/src/cmd/sgs/liblddbg/common/mapfile-vers Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/liblddbg/common/mapfile-vers Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ Dbg_help; Dbg_setup; + Dbg_state_str; + Dbg_version; Dbg32_bind_global; Dbg64_bind_global; @@ -85,10 +87,14 @@ 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 @@ 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;
--- a/usr/src/cmd/sgs/liblddbg/common/sections.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/liblddbg/common/sections.c Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ 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
--- a/usr/src/cmd/sgs/liblddbg/common/segments.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/liblddbg/common/segments.c Mon Feb 22 09:19:31 2010 -0700 @@ -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_flags & FLG_SG_ROUND) + dbg_print(lml, MSG_ORIG(MSG_SEG_ROUND), + EC_ADDR(sgp->sg_round)); - 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 (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; - if (sgp->sg_secorder) { + 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 @@ 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_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); } /*
--- a/usr/src/cmd/sgs/libldstab/Makefile.com Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/libldstab/Makefile.com Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ SRCDIR = ../common SRCBASE= ../../../.. +CPPFLAGS += -I$(ELFCAP) + LDLIBS += $(CONVLIBDIR) $(CONV_LIB) $(ELFLIBDIR) -lelf -lc DYNFLAGS += $(VERSREF)
--- a/usr/src/cmd/sgs/nm/amd64/Makefile Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/nm/amd64/Makefile Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ 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)
--- a/usr/src/cmd/sgs/nm/i386/Makefile Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/nm/i386/Makefile Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ 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)
--- a/usr/src/cmd/sgs/nm/sparc/Makefile Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/nm/sparc/Makefile Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ 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)
--- a/usr/src/cmd/sgs/nm/sparcv9/Makefile Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/nm/sparcv9/Makefile Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ 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)
--- a/usr/src/cmd/sgs/packages/common/SUNWonld-README Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README Mon Feb 22 09:19:31 2010 -0700 @@ -1548,3 +1548,5 @@ 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
--- a/usr/src/cmd/sgs/prof/Makefile.com Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/prof/Makefile.com Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ 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
--- a/usr/src/cmd/sgs/rtld/common/debug.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/rtld/common/debug.c Mon Feb 22 09:19:31 2010 -0700 @@ -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_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();
--- a/usr/src/cmd/sgs/rtld/common/object.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/rtld/common/object.c Mon Feb 22 09:19:31 2010 -0700 @@ -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 @@ 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 @@ * 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 @@ 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),
--- a/usr/src/cmd/sgs/rtld/common/rtld.msg Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/cmd/sgs/rtld/common/rtld.msg Mon Feb 22 09:19:31 2010 -0700 @@ -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).
--- a/usr/src/common/elfcap/elfcap.c Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/common/elfcap/elfcap.c Mon Feb 22 09:19:31 2010 -0700 @@ -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. */ @@ -86,9 +86,6 @@ * Order the capabilities by their numeric value. See SF1_SUNW_ * values in sys/elf.h. */ -#if (ELFCAP_NUM_SF1 > 32) -#error ELFCAP_NUM_SF1 is limited to no more than 32 items -#endif static const elfcap_desc_t sf1[ELFCAP_NUM_SF1] = { { /* 0x00000001 */ SF1_SUNW_FPKNWN, STRDESC("SF1_SUNW_FPKNWN"), @@ -110,9 +107,6 @@ * Order the SPARC hardware capabilities to match their numeric value. See * AV_SPARC_ values in sys/auxv_SPARC.h. */ -#if (ELFCAP_NUM_HW1_SPARC > 32) -#error ELFCAP_NUM_HW1_SPARC is limited to no more than 32 items -#endif static const elfcap_desc_t hw1_sparc[ELFCAP_NUM_HW1_SPARC] = { { /* 0x00000001 */ AV_SPARC_MUL32, STRDESC("AV_SPARC_MUL32"), @@ -188,9 +182,6 @@ * Order the Intel hardware capabilities to match their numeric value. See * AV_386_ values in sys/auxv_386.h. */ -#if (ELFCAP_NUM_HW1_386 > 32) -#error ELFCAP_NUM_HW1_386 is limited to no more than 32 items -#endif static const elfcap_desc_t hw1_386[ELFCAP_NUM_HW1_386] = { { /* 0x00000001 */ AV_386_FPU, STRDESC("AV_386_FPU"), @@ -327,7 +318,7 @@ get_str_desc(elfcap_style_t style, const elfcap_desc_t *cdp, const elfcap_str_t **ret_str) { - switch (style) { + switch (ELFCAP_STYLE_MASK(style)) { case ELFCAP_STYLE_FULL: *ret_str = &cdp->c_full; break; @@ -350,7 +341,7 @@ * capabilities descriptor. */ static elfcap_err_t -expand(elfcap_style_t style, uint64_t val, const elfcap_desc_t *cdp, +expand(elfcap_style_t style, elfcap_mask_t val, const elfcap_desc_t *cdp, uint_t cnum, char *str, size_t slen, elfcap_fmt_t fmt) { uint_t cnt; @@ -386,7 +377,7 @@ ELFCAP_ERR_NONE)) return (err); - (void) snprintf(str, slen, "0x%llx", val); + (void) snprintf(str, slen, "0x%x", val); } return (ELFCAP_ERR_NONE); } @@ -395,7 +386,7 @@ * Expand a CA_SUNW_HW_1 value. */ elfcap_err_t -elfcap_hw1_to_str(elfcap_style_t style, uint64_t val, char *str, +elfcap_hw1_to_str(elfcap_style_t style, elfcap_mask_t val, char *str, size_t len, elfcap_fmt_t fmt, ushort_t mach) { /* @@ -418,6 +409,25 @@ } /* + * Expand a CA_SUNW_HW_2 value. Presently, there are no values, this routine + * is simply a place holder for future development. + */ +elfcap_err_t +/* ARGSUSED0 */ +elfcap_hw2_to_str(elfcap_style_t style, elfcap_mask_t val, char *str, + size_t len, elfcap_fmt_t fmt, ushort_t mach) +{ + /* + * Initialize the string buffer, and validate the format request. + */ + *str = '\0'; + if ((fmt < 0) || (fmt >= FORMAT_NELTS)) + return (ELFCAP_ERR_INVFMT); + + return (expand(style, val, NULL, 0, str, len, fmt)); +} + +/* * Expand a CA_SUNW_SF_1 value. Note, that at present these capabilities are * common across all platforms. The use of "mach" is therefore redundant, but * is retained for compatibility with the interface of elfcap_hw1_to_str(), and @@ -425,7 +435,7 @@ */ elfcap_err_t /* ARGSUSED4 */ -elfcap_sf1_to_str(elfcap_style_t style, uint64_t val, char *str, +elfcap_sf1_to_str(elfcap_style_t style, elfcap_mask_t val, char *str, size_t len, elfcap_fmt_t fmt, ushort_t mach) { /* @@ -442,21 +452,28 @@ * Given a capability tag type and value, map it to a string representation. */ elfcap_err_t -elfcap_tag_to_str(elfcap_style_t style, uint64_t tag, uint64_t val, +elfcap_tag_to_str(elfcap_style_t style, uint64_t tag, elfcap_mask_t val, char *str, size_t len, elfcap_fmt_t fmt, ushort_t mach) { - if (tag == CA_SUNW_HW_1) + switch (tag) { + case CA_SUNW_HW_1: return (elfcap_hw1_to_str(style, val, str, len, fmt, mach)); - if (tag == CA_SUNW_SF_1) + + case CA_SUNW_SF_1: return (elfcap_sf1_to_str(style, val, str, len, fmt, mach)); + case CA_SUNW_HW_2: + return (elfcap_hw2_to_str(style, val, str, len, fmt, mach)); + + } + return (ELFCAP_ERR_UNKTAG); } /* * Determine a capabilities value from a capabilities string. */ -static uint64_t +static elfcap_mask_t value(elfcap_style_t style, const char *str, const elfcap_desc_t *cdp, uint_t cnum) { @@ -474,19 +491,25 @@ if ((err = get_str_desc(style, &cdp[num], &nstr)) != 0) return (err); - if (strcmp(str, nstr->s_str) == 0) - return (cdp[num].c_val); + if (style & ELFCAP_STYLE_F_ICMP) { + if (strcasecmp(str, nstr->s_str) == 0) + return (cdp[num].c_val); + } else { + if (strcmp(str, nstr->s_str) == 0) + return (cdp[num].c_val); + } } + return (0); } -uint64_t +elfcap_mask_t elfcap_sf1_from_str(elfcap_style_t style, const char *str, ushort_t mach) { return (value(style, str, &sf1[0], ELFCAP_NUM_SF1)); } -uint64_t +elfcap_mask_t elfcap_hw1_from_str(elfcap_style_t style, const char *str, ushort_t mach) { if ((mach == EM_386) || (mach == EM_IA_64) || (mach == EM_AMD64)) @@ -498,6 +521,34 @@ return (0); } +elfcap_mask_t +/* ARGSUSED0 */ +elfcap_hw2_from_str(elfcap_style_t style, const char *str, ushort_t mach) +{ + return (0); +} + +/* + * Given a capability tag type and value, return the capabilities values + * contained in the string. + */ +elfcap_mask_t +elfcap_tag_from_str(elfcap_style_t style, uint64_t tag, const char *str, + ushort_t mach) +{ + switch (tag) { + case CA_SUNW_HW_1: + return (elfcap_hw1_from_str(style, str, mach)); + + case CA_SUNW_SF_1: + return (elfcap_sf1_from_str(style, str, mach)); + + case CA_SUNW_HW_2: + return (elfcap_hw2_from_str(style, str, mach)); + } + + return (0); +} /* * These functions allow the caller to get direct access to the
--- a/usr/src/common/elfcap/elfcap.h Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/common/elfcap/elfcap.h Mon Feb 22 09:19:31 2010 -0700 @@ -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,13 +34,26 @@ #endif /* + * Type used to represent capability bitmasks. This 32-bit type cannot be + * widened without breaking the ability to use them in ELFCLASS32 objects. + */ +typedef uint32_t elfcap_mask_t; + +/* * The elfcap code handles mappings to and from several string styles. * The caller uses elfcap_style_t to specify the style to use. + * + * The bottom 16 bits are used to represent styles, and the upper 16 + * bits are used for flags to modify default behavior. */ +#define ELFCAP_STYLE_MASK(_style) (_style & 0xff) + typedef enum { ELFCAP_STYLE_FULL = 1, /* Full formal name (e.g. AV_386_SSE) */ ELFCAP_STYLE_UC = 2, /* Informal upper case (e.g. SSE) */ - ELFCAP_STYLE_LC = 3 /* Informal lower case (e.g. sse) */ + ELFCAP_STYLE_LC = 3, /* Informal lower case (e.g. sse) */ + + ELFCAP_STYLE_F_ICMP = 0x0100 /* Use case insensitive strcmp */ } elfcap_style_t; /* @@ -64,7 +77,7 @@ * and are intended to be ignored by the processing code. */ typedef struct { - uint64_t c_val; /* Bit value */ + elfcap_mask_t c_val; /* Bit value */ elfcap_str_t c_full; /* ELFCAP_STYLE_FULL */ elfcap_str_t c_uc; /* ELFCAP_STYLE_UC */ elfcap_str_t c_lc; /* ELFCAP_STYLE_LC */ @@ -98,11 +111,6 @@ /* * # of each type of capability known to the system. These values * must be kept in sync with the arrays found in elfcap.c. - * - * In ELFCLASS32, capability words are 32-bit, while ELFCLASS64 has - * 64-bit words. For simplicity of code and documentation, our policy - * is to limit each mask word to no more than 32 capabilities regardless of - * the ELFCLASS. */ #define ELFCAP_NUM_SF1 3 #define ELFCAP_NUM_HW1_SPARC 17 @@ -114,26 +122,35 @@ * "to str" function to generate the string description. */ extern elfcap_err_t elfcap_tag_to_str(elfcap_style_t, uint64_t, - uint64_t, char *, size_t, elfcap_fmt_t, ushort_t); + elfcap_mask_t, char *, size_t, elfcap_fmt_t, ushort_t); /* * The functions that convert from a specific capability value to * a string representation all use the same common prototype. */ -typedef elfcap_err_t elfcap_to_str_func_t(elfcap_style_t, uint64_t, char *, +typedef elfcap_err_t elfcap_to_str_func_t(elfcap_style_t, elfcap_mask_t, char *, size_t, elfcap_fmt_t, ushort_t); extern elfcap_to_str_func_t elfcap_hw1_to_str; +extern elfcap_to_str_func_t elfcap_hw2_to_str; extern elfcap_to_str_func_t elfcap_sf1_to_str; /* * The reverse mapping: Given a string representation, turn it back into * integer form. */ -typedef uint64_t elfcap_from_str_func_t(elfcap_style_t, +typedef elfcap_mask_t elfcap_from_str_func_t(elfcap_style_t, const char *, ushort_t mach); +/* + * Given a capability section tag and string, call the proper underlying + * "from str" function to generate the numeric value. + */ +extern elfcap_mask_t elfcap_tag_from_str(elfcap_style_t, uint64_t, + const char *, ushort_t); + extern elfcap_from_str_func_t elfcap_hw1_from_str; +extern elfcap_from_str_func_t elfcap_hw2_from_str; extern elfcap_from_str_func_t elfcap_sf1_from_str; /*
--- a/usr/src/lib/libwrap/mapfile Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/lib/libwrap/mapfile Mon Feb 22 09:19:31 2010 -0700 @@ -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. # @@ -26,5 +26,4 @@ global: allow_severity = extern; deny_severity = extern; - *; };
--- a/usr/src/uts/common/sys/elf.h Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/uts/common/sys/elf.h Mon Feb 22 09:19:31 2010 -0700 @@ -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. */ @@ -720,6 +720,8 @@ #define CA_SUNW_NULL 0 #define CA_SUNW_HW_1 1 /* first hardware capabilities entry */ #define CA_SUNW_SF_1 2 /* first software capabilities entry */ +#define CA_SUNW_HW_2 3 /* second hardware capabilities entry */ +#define CA_SUNW_NUM 4 /* * Define software capabilities (CA_SUNW_SF_1 values). Note, hardware
--- a/usr/src/uts/common/sys/link.h Sun Feb 21 21:37:22 2010 -0800 +++ b/usr/src/uts/common/sys/link.h Mon Feb 22 09:19:31 2010 -0700 @@ -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. */ @@ -282,7 +282,7 @@ #define DF_1_IGNMULDEF 0x00040000 /* internal: krtld ignore muldefs */ #define DF_1_NOKSYMS 0x00080000 /* internal: don't export object's */ /* symbols via /dev/ksyms */ -#define DF_1_NOHDR 0x00100000 /* mapfile ?N:1st segment mapping */ +#define DF_1_NOHDR 0x00100000 /* mapfile: 1st segment mapping */ /* omits ELF & program headers */ #define DF_1_EDITED 0x00200000 /* object has been modified since */ /* being built by 'ld' */