169112eddSAli Bahrami /* 269112eddSAli Bahrami * CDDL HEADER START 369112eddSAli Bahrami * 469112eddSAli Bahrami * The contents of this file are subject to the terms of the 569112eddSAli Bahrami * Common Development and Distribution License (the "License"). 669112eddSAli Bahrami * You may not use this file except in compliance with the License. 769112eddSAli Bahrami * 869112eddSAli Bahrami * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 969112eddSAli Bahrami * or http://www.opensolaris.org/os/licensing. 1069112eddSAli Bahrami * See the License for the specific language governing permissions 1169112eddSAli Bahrami * and limitations under the License. 1269112eddSAli Bahrami * 1369112eddSAli Bahrami * When distributing Covered Code, include this CDDL HEADER in each 1469112eddSAli Bahrami * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1569112eddSAli Bahrami * If applicable, add the following below this CDDL HEADER, with the 1669112eddSAli Bahrami * fields enclosed by brackets "[]" replaced with your own identifying 1769112eddSAli Bahrami * information: Portions Copyright [yyyy] [name of copyright owner] 1869112eddSAli Bahrami * 1969112eddSAli Bahrami * CDDL HEADER END 2069112eddSAli Bahrami */ 2169112eddSAli Bahrami 2269112eddSAli Bahrami /* 2369112eddSAli Bahrami * Copyright (c) 1988 AT&T 2469112eddSAli Bahrami * All Rights Reserved 2569112eddSAli Bahrami * 261007fd6fSAli Bahrami * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 27*44bf619dSJohn Levon * 28*44bf619dSJohn Levon * Copyright 2019 Joyent, Inc. 2969112eddSAli Bahrami */ 3069112eddSAli Bahrami 3169112eddSAli Bahrami /* 3269112eddSAli Bahrami * Map file parsing (Shared Core Code). 3369112eddSAli Bahrami */ 3469112eddSAli Bahrami #include <fcntl.h> 3569112eddSAli Bahrami #include <stdio.h> 3669112eddSAli Bahrami #include <unistd.h> 3769112eddSAli Bahrami #include <sys/stat.h> 3869112eddSAli Bahrami #include <errno.h> 3969112eddSAli Bahrami #include <limits.h> 4069112eddSAli Bahrami #include <dirent.h> 4169112eddSAli Bahrami #include <ctype.h> 4269112eddSAli Bahrami #include <debug.h> 4369112eddSAli Bahrami #include "msg.h" 4469112eddSAli Bahrami #include "_libld.h" 4569112eddSAli Bahrami #include "_map.h" 4669112eddSAli Bahrami 4769112eddSAli Bahrami /* 4869112eddSAli Bahrami * There are two styles of mapfile supported by the link-editor: 4969112eddSAli Bahrami * 5069112eddSAli Bahrami * 1) The original System V defined syntax, as augmented at Sun 5169112eddSAli Bahrami * from Solaris 2.0 through Solaris 10. This style is also known 5269112eddSAli Bahrami * as version 1. 5369112eddSAli Bahrami * 5469112eddSAli Bahrami * 2) A newer syntax, currently at version 2. 5569112eddSAli Bahrami * 5669112eddSAli Bahrami * The original syntax uses special characters (=, :, -, |, etc) as 5769112eddSAli Bahrami * operators to indicate the operation being specified. Over the years, 5869112eddSAli Bahrami * this syntax has been problematic: 5969112eddSAli Bahrami * 6069112eddSAli Bahrami * 1) Too cryptic: It's hard for people to remember which character 6169112eddSAli Bahrami * means what. 6269112eddSAli Bahrami * 6369112eddSAli Bahrami * 2) Limited expansion potential: There only a few special characters 6469112eddSAli Bahrami * available on the keyboard for new features, and it is difficult to 6569112eddSAli Bahrami * add options to existing ones. 6669112eddSAli Bahrami * 6769112eddSAli Bahrami * Adding new features into this framework (2) have the effect of 6869112eddSAli Bahrami * making the syntax even more cryptic (1). The newer syntax addresses 6969112eddSAli Bahrami * these issues by moving to an extendible identifier based syntax that 7069112eddSAli Bahrami * allows new features to be added without complicating old ones. 7169112eddSAli Bahrami * 7269112eddSAli Bahrami * The new syntax uses the following terminology: 7369112eddSAli Bahrami * 7469112eddSAli Bahrami * - Control directives are the directives that start with a '$'. 7569112eddSAli Bahrami * They control how the mapfile is interpreted. We use the 'cdir_' 7669112eddSAli Bahrami * prefix on functions and variables related to these directives. 7769112eddSAli Bahrami * 7869112eddSAli Bahrami * - Conditional Expressions are the expressions found in $if and $elif 7969112eddSAli Bahrami * control directives. They evaluate to boolean true/false values. 8069112eddSAli Bahrami * We use the 'cexp_' prefix for functions and variables related to 8169112eddSAli Bahrami * these expressions. 8269112eddSAli Bahrami * 8369112eddSAli Bahrami * - Regular Directives are names (SYMBOL, VERSION, etc) that convey 8469112eddSAli Bahrami * directions to the link-editor for building the output object. 8569112eddSAli Bahrami * 8669112eddSAli Bahrami * This file contains core code used by both mapfile styles: File management, 8769112eddSAli Bahrami * lexical analysis, and other shared core functionality. It also contains 8869112eddSAli Bahrami * the code for control directives, as they are intrinsically part of 8969112eddSAli Bahrami * lexical analysis --- this is disabled when processing Sysv mapfiles. 9069112eddSAli Bahrami */ 9169112eddSAli Bahrami 9269112eddSAli Bahrami /* 9369112eddSAli Bahrami * We use a stack of cdir_level_t structs to manage $if/$elif/$else/$endif 9469112eddSAli Bahrami * processing. At each level, we keep track of the information needed to 9569112eddSAli Bahrami * determine whether or not to process nested input lines or skip them, 9669112eddSAli Bahrami * along with information needed to report errors. 9769112eddSAli Bahrami */ 9869112eddSAli Bahrami typedef struct { 9969112eddSAli Bahrami Lineno cdl_if_lineno; /* Line number of opening $if */ 10069112eddSAli Bahrami Lineno cdl_else_lineno; /* 0, or line on which $else seen */ 10169112eddSAli Bahrami int cdl_done; /* True if no longer accepts input */ 10269112eddSAli Bahrami int cdl_pass; /* True if currently accepting input */ 10369112eddSAli Bahrami } cdir_level_t; 10469112eddSAli Bahrami 10569112eddSAli Bahrami /* Operators in the expressions accepted by $if/$elif */ 10669112eddSAli Bahrami typedef enum { 10769112eddSAli Bahrami CEXP_OP_NONE, /* Not an operator */ 10869112eddSAli Bahrami CEXP_OP_AND, /* && */ 10969112eddSAli Bahrami CEXP_OP_OR, /* || */ 11069112eddSAli Bahrami CEXP_OP_NEG, /* ! */ 11169112eddSAli Bahrami CEXP_OP_OPAR, /* ( */ 11269112eddSAli Bahrami CEXP_OP_CPAR /* ) */ 11369112eddSAli Bahrami } cexp_op_t; 11469112eddSAli Bahrami 11569112eddSAli Bahrami /* 11669112eddSAli Bahrami * Type of conditional expression identifier AVL tree nodes 11769112eddSAli Bahrami */ 11869112eddSAli Bahrami typedef struct cexp_name_node { 11969112eddSAli Bahrami avl_node_t ceid_avlnode; /* AVL book-keeping */ 12069112eddSAli Bahrami const char *ceid_name; /* boolean identifier name */ 12169112eddSAli Bahrami } cexp_id_node_t; 12269112eddSAli Bahrami 12369112eddSAli Bahrami 12469112eddSAli Bahrami /* 12569112eddSAli Bahrami * Declare a "stack" type, containing a pointer to data, a count of 12669112eddSAli Bahrami * allocated, and currently used items in the stack. The data type 12769112eddSAli Bahrami * is specified as the _type argument. 12869112eddSAli Bahrami */ 12969112eddSAli Bahrami #define STACK(_type) \ 13069112eddSAli Bahrami struct { \ 13169112eddSAli Bahrami _type *stk_s; /* Stack array */ \ 13269112eddSAli Bahrami size_t stk_n; /* Current stack depth */ \ 13369112eddSAli Bahrami size_t stk_n_alloc; /* # of elements pointed at by s */ \ 13469112eddSAli Bahrami } 13569112eddSAli Bahrami 13669112eddSAli Bahrami /* 13769112eddSAli Bahrami * The following type represents a "generic" stack, where the data 13869112eddSAli Bahrami * type is (void). This type is never instantiated. However, it has 13969112eddSAli Bahrami * the same struct layout as any other STACK(), and is therefore a good 14069112eddSAli Bahrami * generic type that can be used for stack_resize(). 14169112eddSAli Bahrami */ 14269112eddSAli Bahrami typedef STACK(void) generic_stack_t; 14369112eddSAli Bahrami 14469112eddSAli Bahrami /* 14569112eddSAli Bahrami * Ensure that the stack has enough room to push one more item 14669112eddSAli Bahrami */ 14769112eddSAli Bahrami #define STACK_RESERVE(_stack, _n_default) \ 14869112eddSAli Bahrami (((_stack).stk_n < (_stack).stk_n_alloc) || \ 14969112eddSAli Bahrami stack_resize((generic_stack_t *)&(_stack).stk_s, _n_default, \ 15069112eddSAli Bahrami sizeof (*(_stack).stk_s))) 15169112eddSAli Bahrami 15269112eddSAli Bahrami /* 15369112eddSAli Bahrami * Reset a stack to empty. 15469112eddSAli Bahrami */ 15569112eddSAli Bahrami #define STACK_RESET(_stack) (_stack).stk_n = 0; 15669112eddSAli Bahrami 15769112eddSAli Bahrami /* 15869112eddSAli Bahrami * True if stack is empty, False otherwise. 15969112eddSAli Bahrami */ 16069112eddSAli Bahrami #define STACK_IS_EMPTY(_stack) ((_stack).stk_n == 0) 16169112eddSAli Bahrami 16269112eddSAli Bahrami /* 16369112eddSAli Bahrami * Push a value onto a stack. Caller must ensure that stack has room. 16469112eddSAli Bahrami * This macro is intended to be used as the LHS of an assignment, the 16569112eddSAli Bahrami * RHS of which is the value: 16669112eddSAli Bahrami * 16769112eddSAli Bahrami * STACK_PUSH(stack) = value; 16869112eddSAli Bahrami */ 16969112eddSAli Bahrami #define STACK_PUSH(_stack) (_stack).stk_s[(_stack).stk_n++] 17069112eddSAli Bahrami 17169112eddSAli Bahrami /* 17269112eddSAli Bahrami * Pop a value off a stack. Caller must ensure 17369112eddSAli Bahrami * that stack is not empty. 17469112eddSAli Bahrami */ 17569112eddSAli Bahrami #define STACK_POP(_stack) ((_stack).stk_s[--(_stack).stk_n]) 17669112eddSAli Bahrami 17769112eddSAli Bahrami /* 17869112eddSAli Bahrami * Access top element on stack without popping. Caller must ensure 17969112eddSAli Bahrami * that stack is not empty. 18069112eddSAli Bahrami */ 18169112eddSAli Bahrami #define STACK_TOP(_stack) (((_stack).stk_s)[(_stack).stk_n - 1]) 18269112eddSAli Bahrami 18369112eddSAli Bahrami /* 18469112eddSAli Bahrami * Initial sizes used for the stacks: The stacks are allocated on demand 18569112eddSAli Bahrami * to these sizes, and then doubled as necessary until they are large enough. 18669112eddSAli Bahrami * 18769112eddSAli Bahrami * The ideal size would be large enough that only a single allocation 18869112eddSAli Bahrami * occurs, and our defaults should generally have that effect. However, 18969112eddSAli Bahrami * in doing so, we run the risk of a latent error in the resize code going 19069112eddSAli Bahrami * undetected until triggered by a large task in the field. For this reason, 19169112eddSAli Bahrami * we set the sizes to the smallest size possible when compiled for debug. 19269112eddSAli Bahrami */ 19369112eddSAli Bahrami #ifdef DEBUG 19469112eddSAli Bahrami #define CDIR_STACK_INIT 1 19569112eddSAli Bahrami #define CEXP_OP_STACK_INIT 1 19669112eddSAli Bahrami #define CEXP_VAL_STACK_INIT 1 19769112eddSAli Bahrami #else 19869112eddSAli Bahrami #define CDIR_STACK_INIT 16 19969112eddSAli Bahrami #define CEXP_OP_STACK_INIT 8 20069112eddSAli Bahrami #define CEXP_VAL_STACK_INIT (CEXP_OP_STACK_INIT * 2) /* 2 vals per binop */ 20169112eddSAli Bahrami #endif 20269112eddSAli Bahrami 20369112eddSAli Bahrami 20469112eddSAli Bahrami /* 20569112eddSAli Bahrami * Persistent state maintained by map module in between calls. 20669112eddSAli Bahrami * 20769112eddSAli Bahrami * This is kept as static file scope data, because it is only used 20869112eddSAli Bahrami * when libld is called by ld, and not by rtld. If that should change, 20969112eddSAli Bahrami * the code is designed so that it can become reentrant easily: 21069112eddSAli Bahrami * 21169112eddSAli Bahrami * - Add a pointer to the output descriptor to a structure of this type, 21269112eddSAli Bahrami * allocated dynamically on the first call to ld_map_parse(). 21369112eddSAli Bahrami * - Change all references to lms to instead reference the pointer in 21469112eddSAli Bahrami * the output descriptor. 21569112eddSAli Bahrami * 21669112eddSAli Bahrami * Until then, it is simpler not to expose these details. 21769112eddSAli Bahrami */ 21869112eddSAli Bahrami typedef struct { 21969112eddSAli Bahrami int lms_cdir_valid; /* Allow control dir. on entry to gettoken() */ 22069112eddSAli Bahrami STACK(cdir_level_t) lms_cdir_stack; /* Conditional input level */ 22169112eddSAli Bahrami STACK(cexp_op_t) lms_cexp_op_stack; /* Cond. expr operators */ 22269112eddSAli Bahrami STACK(uchar_t) lms_cexp_val_stack; /* Cond. expr values */ 22369112eddSAli Bahrami avl_tree_t *lms_cexp_id; 22469112eddSAli Bahrami } ld_map_state_t; 22569112eddSAli Bahrami static ld_map_state_t lms; 22669112eddSAli Bahrami 22769112eddSAli Bahrami 22869112eddSAli Bahrami /* 22969112eddSAli Bahrami * Version 1 (SysV) syntax dispatch table for ld_map_gettoken(). For each 23069112eddSAli Bahrami * of the 7-bit ASCII characters, determine how the lexical analyzer 23169112eddSAli Bahrami * should behave. 23269112eddSAli Bahrami * 23369112eddSAli Bahrami * This table must be kept in sync with tkid_attr[] below. 23469112eddSAli Bahrami * 23569112eddSAli Bahrami * Identifier Note: 23669112eddSAli Bahrami * The Linker and Libraries Guide states that the original syntax uses 23769112eddSAli Bahrami * C identifier rules, allowing '.' to be treated as a letter. However, 23869112eddSAli Bahrami * the implementation is considerably looser than that: Any character 23969112eddSAli Bahrami * with an ASCII code (0-127) which is printable and not used to start 24069112eddSAli Bahrami * another token is allowed to start an identifier, and they are terminated 24169112eddSAli Bahrami * by any of: space, double quote, tab, newline, ':', ';', '=', or '#'. 24269112eddSAli Bahrami * The original code has been replaced, but this table encodes the same 24369112eddSAli Bahrami * rules, to ensure backward compatibility. 24469112eddSAli Bahrami */ 24569112eddSAli Bahrami static const mf_tokdisp_t gettok_dispatch_v1 = { 24669112eddSAli Bahrami TK_OP_EOF, /* 0 - NUL */ 24769112eddSAli Bahrami TK_OP_ILLCHR, /* 1 - SOH */ 24869112eddSAli Bahrami TK_OP_ILLCHR, /* 2 - STX */ 24969112eddSAli Bahrami TK_OP_ILLCHR, /* 3 - ETX */ 25069112eddSAli Bahrami TK_OP_ILLCHR, /* 4 - EOT */ 25169112eddSAli Bahrami TK_OP_ILLCHR, /* 5 - ENQ */ 25269112eddSAli Bahrami TK_OP_ILLCHR, /* 6 - ACK */ 25369112eddSAli Bahrami TK_OP_ILLCHR, /* 7 - BEL */ 25469112eddSAli Bahrami TK_OP_ILLCHR, /* 8 - BS */ 25569112eddSAli Bahrami TK_OP_WS, /* 9 - HT */ 25669112eddSAli Bahrami TK_OP_NL, /* 10 - NL */ 25769112eddSAli Bahrami TK_OP_WS, /* 11 - VT */ 25869112eddSAli Bahrami TK_OP_WS, /* 12 - FF */ 25969112eddSAli Bahrami TK_OP_WS, /* 13 - CR */ 26069112eddSAli Bahrami TK_OP_ILLCHR, /* 14 - SO */ 26169112eddSAli Bahrami TK_OP_ILLCHR, /* 15 - SI */ 26269112eddSAli Bahrami TK_OP_ILLCHR, /* 16 - DLE */ 26369112eddSAli Bahrami TK_OP_ILLCHR, /* 17 - DC1 */ 26469112eddSAli Bahrami TK_OP_ILLCHR, /* 18 - DC2 */ 26569112eddSAli Bahrami TK_OP_ILLCHR, /* 19 - DC3 */ 26669112eddSAli Bahrami TK_OP_ILLCHR, /* 20 - DC4 */ 26769112eddSAli Bahrami TK_OP_ILLCHR, /* 21 - NAK */ 26869112eddSAli Bahrami TK_OP_ILLCHR, /* 22 - SYN */ 26969112eddSAli Bahrami TK_OP_ILLCHR, /* 23 - ETB */ 27069112eddSAli Bahrami TK_OP_ILLCHR, /* 24 - CAN */ 27169112eddSAli Bahrami TK_OP_ILLCHR, /* 25 - EM */ 27269112eddSAli Bahrami TK_OP_ILLCHR, /* 26 - SUB */ 27369112eddSAli Bahrami TK_OP_ILLCHR, /* 27 - ESC */ 27469112eddSAli Bahrami TK_OP_ILLCHR, /* 28 - FS */ 27569112eddSAli Bahrami TK_OP_ILLCHR, /* 29 - GS */ 27669112eddSAli Bahrami TK_OP_ILLCHR, /* 30 - RS */ 27769112eddSAli Bahrami TK_OP_ILLCHR, /* 31 - US */ 27869112eddSAli Bahrami TK_OP_WS, /* 32 - SP */ 27969112eddSAli Bahrami TK_OP_ID, /* 33 - ! */ 28069112eddSAli Bahrami TK_OP_SIMQUOTE, /* 34 - " */ 28169112eddSAli Bahrami TK_OP_CMT, /* 35 - # */ 28269112eddSAli Bahrami TK_OP_ID, /* 36 - $ */ 28369112eddSAli Bahrami TK_OP_ID, /* 37 - % */ 28469112eddSAli Bahrami TK_OP_ID, /* 38 - & */ 28569112eddSAli Bahrami TK_OP_ID, /* 39 - ' */ 28669112eddSAli Bahrami TK_OP_ID, /* 40 - ( */ 28769112eddSAli Bahrami TK_OP_ID, /* 41 - ) */ 28869112eddSAli Bahrami TK_OP_ID, /* 42 - * */ 28969112eddSAli Bahrami TK_OP_ID, /* 43 - + */ 29069112eddSAli Bahrami TK_OP_ID, /* 44 - , */ 29169112eddSAli Bahrami TK_DASH, /* 45 - - */ 29269112eddSAli Bahrami TK_OP_ID, /* 46 - . */ 29369112eddSAli Bahrami TK_OP_ID, /* 47 - / */ 29469112eddSAli Bahrami TK_OP_ID, /* 48 - 0 */ 29569112eddSAli Bahrami TK_OP_ID, /* 49 - 1 */ 29669112eddSAli Bahrami TK_OP_ID, /* 50 - 2 */ 29769112eddSAli Bahrami TK_OP_ID, /* 51 - 3 */ 29869112eddSAli Bahrami TK_OP_ID, /* 52 - 4 */ 29969112eddSAli Bahrami TK_OP_ID, /* 53 - 5 */ 30069112eddSAli Bahrami TK_OP_ID, /* 54 - 6 */ 30169112eddSAli Bahrami TK_OP_ID, /* 55 - 7 */ 30269112eddSAli Bahrami TK_OP_ID, /* 56 - 8 */ 30369112eddSAli Bahrami TK_OP_ID, /* 57 - 9 */ 30469112eddSAli Bahrami TK_COLON, /* 58 - : */ 30569112eddSAli Bahrami TK_SEMICOLON, /* 59 - ; */ 30669112eddSAli Bahrami TK_OP_ID, /* 60 - < */ 30769112eddSAli Bahrami TK_EQUAL, /* 61 - = */ 30869112eddSAli Bahrami TK_OP_ID, /* 62 - > */ 30969112eddSAli Bahrami TK_OP_ID, /* 63 - ? */ 31069112eddSAli Bahrami TK_ATSIGN, /* 64 - @ */ 31169112eddSAli Bahrami TK_OP_ID, /* 65 - A */ 31269112eddSAli Bahrami TK_OP_ID, /* 66 - B */ 31369112eddSAli Bahrami TK_OP_ID, /* 67 - C */ 31469112eddSAli Bahrami TK_OP_ID, /* 68 - D */ 31569112eddSAli Bahrami TK_OP_ID, /* 69 - E */ 31669112eddSAli Bahrami TK_OP_ID, /* 70 - F */ 31769112eddSAli Bahrami TK_OP_ID, /* 71 - G */ 31869112eddSAli Bahrami TK_OP_ID, /* 72 - H */ 31969112eddSAli Bahrami TK_OP_ID, /* 73 - I */ 32069112eddSAli Bahrami TK_OP_ID, /* 74 - J */ 32169112eddSAli Bahrami TK_OP_ID, /* 75 - K */ 32269112eddSAli Bahrami TK_OP_ID, /* 76 - L */ 32369112eddSAli Bahrami TK_OP_ID, /* 77 - M */ 32469112eddSAli Bahrami TK_OP_ID, /* 78 - N */ 32569112eddSAli Bahrami TK_OP_ID, /* 79 - O */ 32669112eddSAli Bahrami TK_OP_ID, /* 80 - P */ 32769112eddSAli Bahrami TK_OP_ID, /* 81 - Q */ 32869112eddSAli Bahrami TK_OP_ID, /* 82 - R */ 32969112eddSAli Bahrami TK_OP_ID, /* 83 - S */ 33069112eddSAli Bahrami TK_OP_ID, /* 84 - T */ 33169112eddSAli Bahrami TK_OP_ID, /* 85 - U */ 33269112eddSAli Bahrami TK_OP_ID, /* 86 - V */ 33369112eddSAli Bahrami TK_OP_ID, /* 87 - W */ 33469112eddSAli Bahrami TK_OP_ID, /* 88 - X */ 33569112eddSAli Bahrami TK_OP_ID, /* 89 - Y */ 33669112eddSAli Bahrami TK_OP_ID, /* 90 - Z */ 33769112eddSAli Bahrami TK_OP_ID, /* 91 - [ */ 33869112eddSAli Bahrami TK_OP_ID, /* 92 - \ */ 33969112eddSAli Bahrami TK_OP_ID, /* 93 - ] */ 34069112eddSAli Bahrami TK_OP_ID, /* 94 - ^ */ 34169112eddSAli Bahrami TK_OP_ID, /* 95 - _ */ 34269112eddSAli Bahrami TK_OP_ID, /* 96 - ` */ 34369112eddSAli Bahrami TK_OP_ID, /* 97 - a */ 34469112eddSAli Bahrami TK_OP_ID, /* 98 - b */ 34569112eddSAli Bahrami TK_OP_ID, /* 99 - c */ 34669112eddSAli Bahrami TK_OP_ID, /* 100 - d */ 34769112eddSAli Bahrami TK_OP_ID, /* 101 - e */ 34869112eddSAli Bahrami TK_OP_ID, /* 102 - f */ 34969112eddSAli Bahrami TK_OP_ID, /* 103 - g */ 35069112eddSAli Bahrami TK_OP_ID, /* 104 - h */ 35169112eddSAli Bahrami TK_OP_ID, /* 105 - i */ 35269112eddSAli Bahrami TK_OP_ID, /* 106 - j */ 35369112eddSAli Bahrami TK_OP_ID, /* 107 - k */ 35469112eddSAli Bahrami TK_OP_ID, /* 108 - l */ 35569112eddSAli Bahrami TK_OP_ID, /* 109 - m */ 35669112eddSAli Bahrami TK_OP_ID, /* 110 - n */ 35769112eddSAli Bahrami TK_OP_ID, /* 111 - o */ 35869112eddSAli Bahrami TK_OP_ID, /* 112 - p */ 35969112eddSAli Bahrami TK_OP_ID, /* 113 - q */ 36069112eddSAli Bahrami TK_OP_ID, /* 114 - r */ 36169112eddSAli Bahrami TK_OP_ID, /* 115 - s */ 36269112eddSAli Bahrami TK_OP_ID, /* 116 - t */ 36369112eddSAli Bahrami TK_OP_ID, /* 117 - u */ 36469112eddSAli Bahrami TK_OP_ID, /* 118 - v */ 36569112eddSAli Bahrami TK_OP_ID, /* 119 - w */ 36669112eddSAli Bahrami TK_OP_ID, /* 120 - x */ 36769112eddSAli Bahrami TK_OP_ID, /* 121 - y */ 36869112eddSAli Bahrami TK_OP_ID, /* 122 - z */ 36969112eddSAli Bahrami TK_LEFTBKT, /* 123 - { */ 37069112eddSAli Bahrami TK_PIPE, /* 124 - | */ 37169112eddSAli Bahrami TK_RIGHTBKT, /* 125 - } */ 37269112eddSAli Bahrami TK_OP_ID, /* 126 - ~ */ 37369112eddSAli Bahrami TK_OP_ILLCHR, /* 127 - DEL */ 37469112eddSAli Bahrami }; 37569112eddSAli Bahrami 37669112eddSAli Bahrami /* 37769112eddSAli Bahrami * Version 2 syntax dispatch table for ld_map_gettoken(). For each of the 37869112eddSAli Bahrami * 7-bit ASCII characters, determine how the lexical analyzer should behave. 37969112eddSAli Bahrami * 38069112eddSAli Bahrami * This table must be kept in sync with tkid_attr[] below. 38169112eddSAli Bahrami * 38269112eddSAli Bahrami * Identifier Note: 38369112eddSAli Bahrami * We define a letter as being one of the character [A-Z], [a-z], or [_%/.] 38469112eddSAli Bahrami * A digit is the numbers [0-9], or [$-]. An unquoted identifier is defined 38569112eddSAli Bahrami * as a letter, followed by any number of letters or digits. This is a loosened 38669112eddSAli Bahrami * version of the C definition of an identifier. The extra characters not 38769112eddSAli Bahrami * allowed by C are common in section names and/or file paths. 38869112eddSAli Bahrami */ 38969112eddSAli Bahrami static const mf_tokdisp_t gettok_dispatch_v2 = { 39069112eddSAli Bahrami TK_OP_EOF, /* 0 - NUL */ 39169112eddSAli Bahrami TK_OP_ILLCHR, /* 1 - SOH */ 39269112eddSAli Bahrami TK_OP_ILLCHR, /* 2 - STX */ 39369112eddSAli Bahrami TK_OP_ILLCHR, /* 3 - ETX */ 39469112eddSAli Bahrami TK_OP_ILLCHR, /* 4 - EOT */ 39569112eddSAli Bahrami TK_OP_ILLCHR, /* 5 - ENQ */ 39669112eddSAli Bahrami TK_OP_ILLCHR, /* 6 - ACK */ 39769112eddSAli Bahrami TK_OP_ILLCHR, /* 7 - BEL */ 39869112eddSAli Bahrami TK_OP_ILLCHR, /* 8 - BS */ 39969112eddSAli Bahrami TK_OP_WS, /* 9 - HT */ 40069112eddSAli Bahrami TK_OP_NL, /* 10 - NL */ 40169112eddSAli Bahrami TK_OP_WS, /* 11 - VT */ 40269112eddSAli Bahrami TK_OP_WS, /* 12 - FF */ 40369112eddSAli Bahrami TK_OP_WS, /* 13 - CR */ 40469112eddSAli Bahrami TK_OP_ILLCHR, /* 14 - SO */ 40569112eddSAli Bahrami TK_OP_ILLCHR, /* 15 - SI */ 40669112eddSAli Bahrami TK_OP_ILLCHR, /* 16 - DLE */ 40769112eddSAli Bahrami TK_OP_ILLCHR, /* 17 - DC1 */ 40869112eddSAli Bahrami TK_OP_ILLCHR, /* 18 - DC2 */ 40969112eddSAli Bahrami TK_OP_ILLCHR, /* 19 - DC3 */ 41069112eddSAli Bahrami TK_OP_ILLCHR, /* 20 - DC4 */ 41169112eddSAli Bahrami TK_OP_ILLCHR, /* 21 - NAK */ 41269112eddSAli Bahrami TK_OP_ILLCHR, /* 22 - SYN */ 41369112eddSAli Bahrami TK_OP_ILLCHR, /* 23 - ETB */ 41469112eddSAli Bahrami TK_OP_ILLCHR, /* 24 - CAN */ 41569112eddSAli Bahrami TK_OP_ILLCHR, /* 25 - EM */ 41669112eddSAli Bahrami TK_OP_ILLCHR, /* 26 - SUB */ 41769112eddSAli Bahrami TK_OP_ILLCHR, /* 27 - ESC */ 41869112eddSAli Bahrami TK_OP_ILLCHR, /* 28 - FS */ 41969112eddSAli Bahrami TK_OP_ILLCHR, /* 29 - GS */ 42069112eddSAli Bahrami TK_OP_ILLCHR, /* 30 - RS */ 42169112eddSAli Bahrami TK_OP_ILLCHR, /* 31 - US */ 42269112eddSAli Bahrami TK_OP_WS, /* 32 - SP */ 42369112eddSAli Bahrami TK_BANG, /* 33 - ! */ 42469112eddSAli Bahrami TK_OP_CQUOTE, /* 34 - " */ 42569112eddSAli Bahrami TK_OP_CMT, /* 35 - # */ 42669112eddSAli Bahrami TK_OP_CDIR, /* 36 - $ */ 42769112eddSAli Bahrami TK_OP_ID, /* 37 - % */ 42869112eddSAli Bahrami TK_OP_BADCHR, /* 38 - & */ 42969112eddSAli Bahrami TK_OP_SIMQUOTE, /* 39 - ' */ 43069112eddSAli Bahrami TK_OP_BADCHR, /* 40 - ( */ 43169112eddSAli Bahrami TK_OP_BADCHR, /* 41 - ) */ 43269112eddSAli Bahrami TK_STAR, /* 42 - * */ 43369112eddSAli Bahrami TK_OP_CEQUAL, /* 43 - + */ 43469112eddSAli Bahrami TK_OP_BADCHR, /* 44 - , */ 43569112eddSAli Bahrami TK_OP_CEQUAL, /* 45 - - */ 43669112eddSAli Bahrami TK_OP_ID, /* 46 - . */ 43769112eddSAli Bahrami TK_OP_ID, /* 47 - / */ 43869112eddSAli Bahrami TK_OP_NUM, /* 48 - 0 */ 43969112eddSAli Bahrami TK_OP_NUM, /* 49 - 1 */ 44069112eddSAli Bahrami TK_OP_NUM, /* 50 - 2 */ 44169112eddSAli Bahrami TK_OP_NUM, /* 51 - 3 */ 44269112eddSAli Bahrami TK_OP_NUM, /* 52 - 4 */ 44369112eddSAli Bahrami TK_OP_NUM, /* 53 - 5 */ 44469112eddSAli Bahrami TK_OP_NUM, /* 54 - 6 */ 44569112eddSAli Bahrami TK_OP_NUM, /* 55 - 7 */ 44669112eddSAli Bahrami TK_OP_NUM, /* 56 - 8 */ 44769112eddSAli Bahrami TK_OP_NUM, /* 57 - 9 */ 44869112eddSAli Bahrami TK_COLON, /* 58 - : */ 44969112eddSAli Bahrami TK_SEMICOLON, /* 59 - ; */ 45069112eddSAli Bahrami TK_OP_BADCHR, /* 60 - < */ 45169112eddSAli Bahrami TK_EQUAL, /* 61 - = */ 45269112eddSAli Bahrami TK_OP_BADCHR, /* 62 - > */ 45369112eddSAli Bahrami TK_OP_BADCHR, /* 63 - ? */ 45469112eddSAli Bahrami TK_OP_BADCHR, /* 64 - @ */ 45569112eddSAli Bahrami TK_OP_ID, /* 65 - A */ 45669112eddSAli Bahrami TK_OP_ID, /* 66 - B */ 45769112eddSAli Bahrami TK_OP_ID, /* 67 - C */ 45869112eddSAli Bahrami TK_OP_ID, /* 68 - D */ 45969112eddSAli Bahrami TK_OP_ID, /* 69 - E */ 46069112eddSAli Bahrami TK_OP_ID, /* 70 - F */ 46169112eddSAli Bahrami TK_OP_ID, /* 71 - G */ 46269112eddSAli Bahrami TK_OP_ID, /* 72 - H */ 46369112eddSAli Bahrami TK_OP_ID, /* 73 - I */ 46469112eddSAli Bahrami TK_OP_ID, /* 74 - J */ 46569112eddSAli Bahrami TK_OP_ID, /* 75 - K */ 46669112eddSAli Bahrami TK_OP_ID, /* 76 - L */ 46769112eddSAli Bahrami TK_OP_ID, /* 77 - M */ 46869112eddSAli Bahrami TK_OP_ID, /* 78 - N */ 46969112eddSAli Bahrami TK_OP_ID, /* 79 - O */ 47069112eddSAli Bahrami TK_OP_ID, /* 80 - P */ 47169112eddSAli Bahrami TK_OP_ID, /* 81 - Q */ 47269112eddSAli Bahrami TK_OP_ID, /* 82 - R */ 47369112eddSAli Bahrami TK_OP_ID, /* 83 - S */ 47469112eddSAli Bahrami TK_OP_ID, /* 84 - T */ 47569112eddSAli Bahrami TK_OP_ID, /* 85 - U */ 47669112eddSAli Bahrami TK_OP_ID, /* 86 - V */ 47769112eddSAli Bahrami TK_OP_ID, /* 87 - W */ 47869112eddSAli Bahrami TK_OP_ID, /* 88 - X */ 47969112eddSAli Bahrami TK_OP_ID, /* 89 - Y */ 48069112eddSAli Bahrami TK_OP_ID, /* 90 - Z */ 48169112eddSAli Bahrami TK_OP_BADCHR, /* 91 - [ */ 48269112eddSAli Bahrami TK_OP_BADCHR, /* 92 - \ */ 48369112eddSAli Bahrami TK_OP_BADCHR, /* 93 - ] */ 48469112eddSAli Bahrami TK_OP_BADCHR, /* 94 - ^ */ 48569112eddSAli Bahrami TK_OP_ID, /* 95 - _ */ 48669112eddSAli Bahrami TK_OP_BADCHR, /* 96 - ` */ 48769112eddSAli Bahrami TK_OP_ID, /* 97 - a */ 48869112eddSAli Bahrami TK_OP_ID, /* 98 - b */ 48969112eddSAli Bahrami TK_OP_ID, /* 99 - c */ 49069112eddSAli Bahrami TK_OP_ID, /* 100 - d */ 49169112eddSAli Bahrami TK_OP_ID, /* 101 - e */ 49269112eddSAli Bahrami TK_OP_ID, /* 102 - f */ 49369112eddSAli Bahrami TK_OP_ID, /* 103 - g */ 49469112eddSAli Bahrami TK_OP_ID, /* 104 - h */ 49569112eddSAli Bahrami TK_OP_ID, /* 105 - i */ 49669112eddSAli Bahrami TK_OP_ID, /* 106 - j */ 49769112eddSAli Bahrami TK_OP_ID, /* 107 - k */ 49869112eddSAli Bahrami TK_OP_ID, /* 108 - l */ 49969112eddSAli Bahrami TK_OP_ID, /* 109 - m */ 50069112eddSAli Bahrami TK_OP_ID, /* 110 - n */ 50169112eddSAli Bahrami TK_OP_ID, /* 111 - o */ 50269112eddSAli Bahrami TK_OP_ID, /* 112 - p */ 50369112eddSAli Bahrami TK_OP_ID, /* 113 - q */ 50469112eddSAli Bahrami TK_OP_ID, /* 114 - r */ 50569112eddSAli Bahrami TK_OP_ID, /* 115 - s */ 50669112eddSAli Bahrami TK_OP_ID, /* 116 - t */ 50769112eddSAli Bahrami TK_OP_ID, /* 117 - u */ 50869112eddSAli Bahrami TK_OP_ID, /* 118 - v */ 50969112eddSAli Bahrami TK_OP_ID, /* 119 - w */ 51069112eddSAli Bahrami TK_OP_ID, /* 120 - x */ 51169112eddSAli Bahrami TK_OP_ID, /* 121 - y */ 51269112eddSAli Bahrami TK_OP_ID, /* 122 - z */ 51369112eddSAli Bahrami TK_LEFTBKT, /* 123 - { */ 51469112eddSAli Bahrami TK_OP_BADCHR, /* 124 - | */ 51569112eddSAli Bahrami TK_RIGHTBKT, /* 125 - } */ 51669112eddSAli Bahrami TK_OP_BADCHR, /* 126 - ~ */ 51769112eddSAli Bahrami TK_OP_ILLCHR, /* 127 - DEL */ 51869112eddSAli Bahrami }; 51969112eddSAli Bahrami 52069112eddSAli Bahrami 52169112eddSAli Bahrami /* 52269112eddSAli Bahrami * Table used to identify unquoted identifiers. Each element of this array 52369112eddSAli Bahrami * contains a bitmask indicating whether the character it represents starts, 52469112eddSAli Bahrami * or continues an identifier, for each supported mapfile syntax version. 52569112eddSAli Bahrami */ 52669112eddSAli Bahrami static const char tkid_attr[128] = { 52769112eddSAli Bahrami 0, /* 0 - NUL */ 52869112eddSAli Bahrami TKID_ATTR_CONT(1), /* 1 - SOH */ 52969112eddSAli Bahrami TKID_ATTR_CONT(1), /* 2 - STX */ 53069112eddSAli Bahrami TKID_ATTR_CONT(1), /* 3 - ETX */ 53169112eddSAli Bahrami TKID_ATTR_CONT(1), /* 4 - EOT */ 53269112eddSAli Bahrami TKID_ATTR_CONT(1), /* 5 - ENQ */ 53369112eddSAli Bahrami TKID_ATTR_CONT(1), /* 6 - ACK */ 53469112eddSAli Bahrami TKID_ATTR_CONT(1), /* 7 - BEL */ 53569112eddSAli Bahrami TKID_ATTR_CONT(1), /* 8 - BS */ 53669112eddSAli Bahrami 0, /* 9 - HT */ 53769112eddSAli Bahrami 0, /* 10 - NL */ 53869112eddSAli Bahrami TKID_ATTR_CONT(1), /* 11 - VT */ 53969112eddSAli Bahrami TKID_ATTR_CONT(1), /* 12 - FF */ 54069112eddSAli Bahrami TKID_ATTR_CONT(1), /* 13 - CR */ 54169112eddSAli Bahrami TKID_ATTR_CONT(1), /* 14 - SO */ 54269112eddSAli Bahrami TKID_ATTR_CONT(1), /* 15 - SI */ 54369112eddSAli Bahrami TKID_ATTR_CONT(1), /* 16 - DLE */ 54469112eddSAli Bahrami TKID_ATTR_CONT(1), /* 17 - DC1 */ 54569112eddSAli Bahrami TKID_ATTR_CONT(1), /* 18 - DC2 */ 54669112eddSAli Bahrami TKID_ATTR_CONT(1), /* 19 - DC3 */ 54769112eddSAli Bahrami TKID_ATTR_CONT(1), /* 20 - DC4 */ 54869112eddSAli Bahrami TKID_ATTR_CONT(1), /* 21 - NAK */ 54969112eddSAli Bahrami TKID_ATTR_CONT(1), /* 22 - SYN */ 55069112eddSAli Bahrami TKID_ATTR_CONT(1), /* 23 - ETB */ 55169112eddSAli Bahrami TKID_ATTR_CONT(1), /* 24 - CAN */ 55269112eddSAli Bahrami TKID_ATTR_CONT(1), /* 25 - EM */ 55369112eddSAli Bahrami TKID_ATTR_CONT(1), /* 26 - SUB */ 55469112eddSAli Bahrami TKID_ATTR_CONT(1), /* 27 - ESC */ 55569112eddSAli Bahrami TKID_ATTR_CONT(1), /* 28 - FS */ 55669112eddSAli Bahrami TKID_ATTR_CONT(1), /* 29 - GS */ 55769112eddSAli Bahrami TKID_ATTR_CONT(1), /* 30 - RS */ 55869112eddSAli Bahrami TKID_ATTR_CONT(1), /* 31 - US */ 55969112eddSAli Bahrami 0, /* 32 - SP */ 56069112eddSAli Bahrami TKID_ATTR(1), /* 33 - ! */ 56169112eddSAli Bahrami 0, /* 34 - " */ 56269112eddSAli Bahrami 0, /* 35 - # */ 56369112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR_CONT(2), /* 36 - $ */ 56469112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR_CONT(2), /* 37 - % */ 56569112eddSAli Bahrami TKID_ATTR(1), /* 38 - & */ 56669112eddSAli Bahrami TKID_ATTR(1), /* 39 - ' */ 56769112eddSAli Bahrami TKID_ATTR(1), /* 40 - ( */ 56869112eddSAli Bahrami TKID_ATTR(1), /* 41 - ) */ 56969112eddSAli Bahrami TKID_ATTR(1), /* 42 - * */ 57069112eddSAli Bahrami TKID_ATTR(1), /* 43 - + */ 57169112eddSAli Bahrami TKID_ATTR(1), /* 44 - , */ 57269112eddSAli Bahrami TKID_ATTR_CONT(1) | TKID_ATTR_CONT(2), /* 45 - - */ 57369112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 46 - . */ 57469112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 47 - / */ 57569112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR_CONT(2), /* 48 - 0 */ 57669112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR_CONT(2), /* 49 - 1 */ 57769112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR_CONT(2), /* 50 - 2 */ 57869112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR_CONT(2), /* 51 - 3 */ 57969112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR_CONT(2), /* 52 - 4 */ 58069112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR_CONT(2), /* 53 - 5 */ 58169112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR_CONT(2), /* 54 - 6 */ 58269112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR_CONT(2), /* 55 - 7 */ 58369112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR_CONT(2), /* 56 - 8 */ 58469112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR_CONT(2), /* 57 - 9 */ 58569112eddSAli Bahrami 0, /* 58 - : */ 58669112eddSAli Bahrami 0, /* 59 - ; */ 58769112eddSAli Bahrami TKID_ATTR(1), /* 60 - < */ 58869112eddSAli Bahrami 0, /* 61 - = */ 58969112eddSAli Bahrami TKID_ATTR(1), /* 62 - > */ 59069112eddSAli Bahrami TKID_ATTR(1), /* 63 - ? */ 59169112eddSAli Bahrami TKID_ATTR_CONT(1), /* 64 - @ */ 59269112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 65 - A */ 59369112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 66 - B */ 59469112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 67 - C */ 59569112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 68 - D */ 59669112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 69 - E */ 59769112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 70 - F */ 59869112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 71 - G */ 59969112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 72 - H */ 60069112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 73 - I */ 60169112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 74 - J */ 60269112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 75 - K */ 60369112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 76 - L */ 60469112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 77 - M */ 60569112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 78 - N */ 60669112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 79 - O */ 60769112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 80 - P */ 60869112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 81 - Q */ 60969112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 82 - R */ 61069112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 83 - S */ 61169112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 84 - T */ 61269112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 85 - U */ 61369112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 86 - V */ 61469112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 87 - W */ 61569112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 88 - X */ 61669112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 89 - Y */ 61769112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 90 - Z */ 61869112eddSAli Bahrami TKID_ATTR(1), /* 91 - [ */ 61969112eddSAli Bahrami TKID_ATTR(1), /* 92 - \ */ 62069112eddSAli Bahrami TKID_ATTR(1), /* 93 - ] */ 62169112eddSAli Bahrami TKID_ATTR(1), /* 94 - ^ */ 62269112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 95 - _ */ 62369112eddSAli Bahrami TKID_ATTR(1), /* 96 - ` */ 62469112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 97 - a */ 62569112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 98 - b */ 62669112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 99 - c */ 62769112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 100 - d */ 62869112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 101 - e */ 62969112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 102 - f */ 63069112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 103 - g */ 63169112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 104 - h */ 63269112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 105 - i */ 63369112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 106 - j */ 63469112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 107 - k */ 63569112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 108 - l */ 63669112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 109 - m */ 63769112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 110 - n */ 63869112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 111 - o */ 63969112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 112 - p */ 64069112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 113 - q */ 64169112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 114 - r */ 64269112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 115 - s */ 64369112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 116 - t */ 64469112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 117 - u */ 64569112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 118 - v */ 64669112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 119 - w */ 64769112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 120 - x */ 64869112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 121 - y */ 64969112eddSAli Bahrami TKID_ATTR(1) | TKID_ATTR(2), /* 122 - z */ 65069112eddSAli Bahrami TKID_ATTR_CONT(1), /* 123 - { */ 65169112eddSAli Bahrami TKID_ATTR_CONT(1), /* 124 - | */ 65269112eddSAli Bahrami TKID_ATTR_CONT(1), /* 125 - } */ 65369112eddSAli Bahrami TKID_ATTR(1), /* 126 - ~ */ 65469112eddSAli Bahrami TKID_ATTR_CONT(1), /* 127 - DEL */ 65569112eddSAli Bahrami }; 65669112eddSAli Bahrami 65769112eddSAli Bahrami 65869112eddSAli Bahrami /* 65969112eddSAli Bahrami * Advance the given string pointer to the next newline character, 66069112eddSAli Bahrami * or the terminating NULL if there is none. 66169112eddSAli Bahrami */ 66269112eddSAli Bahrami inline static void 66369112eddSAli Bahrami advance_to_eol(char **str) 66469112eddSAli Bahrami { 66569112eddSAli Bahrami char *s = *str; 66669112eddSAli Bahrami 66769112eddSAli Bahrami while ((*s != '\n') && (*s != '\0')) 66869112eddSAli Bahrami s++; 66969112eddSAli Bahrami *str = s; 67069112eddSAli Bahrami } 67169112eddSAli Bahrami 67269112eddSAli Bahrami /* 67369112eddSAli Bahrami * Insert a NULL patch at the given address 67469112eddSAli Bahrami */ 67569112eddSAli Bahrami inline static void 67669112eddSAli Bahrami null_patch_set(char *str, ld_map_npatch_t *np) 67769112eddSAli Bahrami { 67869112eddSAli Bahrami np->np_ptr = str; 67969112eddSAli Bahrami np->np_ch = *str; 68069112eddSAli Bahrami *str = '\0'; 68169112eddSAli Bahrami } 68269112eddSAli Bahrami 68369112eddSAli Bahrami /* 68469112eddSAli Bahrami * Undo a NULL patch 68569112eddSAli Bahrami */ 68669112eddSAli Bahrami inline static void 68769112eddSAli Bahrami null_patch_undo(ld_map_npatch_t *np) 68869112eddSAli Bahrami { 68969112eddSAli Bahrami *np->np_ptr = np->np_ch; 69069112eddSAli Bahrami } 69169112eddSAli Bahrami 69269112eddSAli Bahrami /* 69369112eddSAli Bahrami * Insert a NULL patch at the end of the line containing str. 69469112eddSAli Bahrami */ 69569112eddSAli Bahrami static void 69669112eddSAli Bahrami null_patch_eol(char *str, ld_map_npatch_t *np) 69769112eddSAli Bahrami { 69869112eddSAli Bahrami advance_to_eol(&str); 69969112eddSAli Bahrami null_patch_set(str, np); 70069112eddSAli Bahrami } 70169112eddSAli Bahrami 70269112eddSAli Bahrami /* 70369112eddSAli Bahrami * Locate the end of an unquoted identifier. 70469112eddSAli Bahrami * 70569112eddSAli Bahrami * entry: 70669112eddSAli Bahrami * mf - Mapfile descriptor, positioned to first character 70769112eddSAli Bahrami * of identifier. 70869112eddSAli Bahrami * 70969112eddSAli Bahrami * exit: 71069112eddSAli Bahrami * If the item pointed at by mf is not an identifier, returns NULL. 71169112eddSAli Bahrami * Otherwise, returns pointer to character after the last character 71269112eddSAli Bahrami * of the identifier. 71369112eddSAli Bahrami */ 71469112eddSAli Bahrami inline static char * 71569112eddSAli Bahrami ident_delimit(Mapfile *mf) 71669112eddSAli Bahrami { 71769112eddSAli Bahrami char *str = mf->mf_next; 71869112eddSAli Bahrami ld_map_npatch_t np; 71969112eddSAli Bahrami int c = *str++; 72069112eddSAli Bahrami 72169112eddSAli Bahrami /* If not a valid start character, report the error */ 72269112eddSAli Bahrami if ((c & 0x80) || !(tkid_attr[c] & mf->mf_tkid_start)) { 72369112eddSAli Bahrami null_patch_set(str, &np); 72469112eddSAli Bahrami mf_fatal(mf, MSG_INTL(MSG_MAP_BADCHAR), str); 72569112eddSAli Bahrami null_patch_undo(&np); 72669112eddSAli Bahrami return (NULL); 72769112eddSAli Bahrami } 72869112eddSAli Bahrami 72969112eddSAli Bahrami /* Keep going until we hit a non-continuing character */ 73069112eddSAli Bahrami for (c = *str; !(c & 0x80) && (tkid_attr[c] & mf->mf_tkid_cont); 73169112eddSAli Bahrami c = *++str) 73269112eddSAli Bahrami ; 73369112eddSAli Bahrami 73469112eddSAli Bahrami return (str); 73569112eddSAli Bahrami } 73669112eddSAli Bahrami 73769112eddSAli Bahrami /* 73869112eddSAli Bahrami * Allocate memory for a stack. 73969112eddSAli Bahrami * 74069112eddSAli Bahrami * entry: 74169112eddSAli Bahrami * stack - Pointer to stack for which memory is required, cast 74269112eddSAli Bahrami * to the generic stack type. 74369112eddSAli Bahrami * n_default - Size to use for initial allocation. 74469112eddSAli Bahrami * elt_size - sizeof(elt), where elt is the actual stack data type. 74569112eddSAli Bahrami * 74669112eddSAli Bahrami * exit: 74769112eddSAli Bahrami * Returns (1) on success. On error (memory allocation), a message 74869112eddSAli Bahrami * is printed and False (0) is returned. 74969112eddSAli Bahrami * 75069112eddSAli Bahrami * note: 75169112eddSAli Bahrami * The caller casts the pointer to their actual datatype-specific stack 75269112eddSAli Bahrami * to be a (generic_stack_t *). The C language will give all stack 75369112eddSAli Bahrami * structs the same size and layout as long as the underlying platform 75469112eddSAli Bahrami * uses a single integral type for pointers. Hence, this cast is safe, 75569112eddSAli Bahrami * and lets a generic routine modify data-specific types without being 75669112eddSAli Bahrami * aware of those types. 75769112eddSAli Bahrami */ 75869112eddSAli Bahrami static Boolean 75969112eddSAli Bahrami stack_resize(generic_stack_t *stack, size_t n_default, size_t elt_size) 76069112eddSAli Bahrami { 76169112eddSAli Bahrami size_t new_n_alloc; 76269112eddSAli Bahrami void *newaddr; 76369112eddSAli Bahrami 76469112eddSAli Bahrami /* Use initial size first, and double the allocation on each call */ 76569112eddSAli Bahrami new_n_alloc = (stack->stk_n_alloc == 0) ? 76669112eddSAli Bahrami n_default : (stack->stk_n_alloc * 2); 76769112eddSAli Bahrami 76869112eddSAli Bahrami newaddr = libld_realloc(stack->stk_s, new_n_alloc * elt_size); 76969112eddSAli Bahrami if (newaddr == NULL) 77069112eddSAli Bahrami return (FALSE); 77169112eddSAli Bahrami 77269112eddSAli Bahrami stack->stk_s = newaddr; 77369112eddSAli Bahrami stack->stk_n_alloc = new_n_alloc; 77469112eddSAli Bahrami return (TRUE); 77569112eddSAli Bahrami } 77669112eddSAli Bahrami 77769112eddSAli Bahrami /* 77869112eddSAli Bahrami * AVL comparison function for cexp_id_node_t items. 77969112eddSAli Bahrami * 78069112eddSAli Bahrami * entry: 78169112eddSAli Bahrami * n1, n2 - pointers to nodes to be compared 78269112eddSAli Bahrami * 78369112eddSAli Bahrami * exit: 78469112eddSAli Bahrami * Returns -1 if (n1 < n2), 0 if they are equal, and 1 if (n1 > n2) 78569112eddSAli Bahrami */ 78669112eddSAli Bahrami static int 78769112eddSAli Bahrami cexp_ident_cmp(const void *n1, const void *n2) 78869112eddSAli Bahrami { 78969112eddSAli Bahrami int rc; 79069112eddSAli Bahrami 79169112eddSAli Bahrami rc = strcmp(((cexp_id_node_t *)n1)->ceid_name, 79269112eddSAli Bahrami ((cexp_id_node_t *)n2)->ceid_name); 79369112eddSAli Bahrami 79469112eddSAli Bahrami if (rc > 0) 79569112eddSAli Bahrami return (1); 79669112eddSAli Bahrami if (rc < 0) 79769112eddSAli Bahrami return (-1); 79869112eddSAli Bahrami return (0); 79969112eddSAli Bahrami } 80069112eddSAli Bahrami 80169112eddSAli Bahrami 80269112eddSAli Bahrami /* 80369112eddSAli Bahrami * Returns True (1) if name is in the conditional expression identifier 80469112eddSAli Bahrami * AVL tree, and False (0) otherwise. 80569112eddSAli Bahrami */ 80669112eddSAli Bahrami static int 80769112eddSAli Bahrami cexp_ident_test(const char *name) 80869112eddSAli Bahrami { 80969112eddSAli Bahrami cexp_id_node_t node; 81069112eddSAli Bahrami 81169112eddSAli Bahrami node.ceid_name = name; 81269112eddSAli Bahrami return (avl_find(lms.lms_cexp_id, &node, 0) != NULL); 81369112eddSAli Bahrami } 81469112eddSAli Bahrami 81569112eddSAli Bahrami /* 81669112eddSAli Bahrami * Add a new boolean identifier to the conditional expression identifier 81769112eddSAli Bahrami * AVL tree. 81869112eddSAli Bahrami * 81969112eddSAli Bahrami * entry: 82069112eddSAli Bahrami * mf - If non-NULL, the mapfile descriptor for the mapfile 82169112eddSAli Bahrami * containing the $add directive. NULL if this is an 82269112eddSAli Bahrami * initialization call. 82369112eddSAli Bahrami * name - Name of identifier. Must point at stable storage that will 82469112eddSAli Bahrami * not be moved or modified by the caller following this call. 82569112eddSAli Bahrami * 82669112eddSAli Bahrami * exit: 82769112eddSAli Bahrami * On success, True (1) is returned and name has been entered. 82869112eddSAli Bahrami * On failure, False (0) is returned and an error has been printed. 82969112eddSAli Bahrami */ 83069112eddSAli Bahrami static int 83169112eddSAli Bahrami cexp_ident_add(Mapfile *mf, const char *name) 83269112eddSAli Bahrami { 83369112eddSAli Bahrami cexp_id_node_t *node; 83469112eddSAli Bahrami 83569112eddSAli Bahrami if (mf != NULL) { 83669112eddSAli Bahrami DBG_CALL(Dbg_map_cexp_id(mf->mf_ofl->ofl_lml, 1, 83769112eddSAli Bahrami mf->mf_name, mf->mf_lineno, name)); 83869112eddSAli Bahrami 83969112eddSAli Bahrami /* If is already known, don't do it again */ 84069112eddSAli Bahrami if (cexp_ident_test(name)) 84169112eddSAli Bahrami return (1); 84269112eddSAli Bahrami } 84369112eddSAli Bahrami 84469112eddSAli Bahrami if ((node = libld_calloc(sizeof (*node), 1)) == NULL) 84569112eddSAli Bahrami return (0); 84669112eddSAli Bahrami node->ceid_name = name; 84769112eddSAli Bahrami avl_add(lms.lms_cexp_id, node); 84869112eddSAli Bahrami return (1); 84969112eddSAli Bahrami } 85069112eddSAli Bahrami 85169112eddSAli Bahrami /* 85269112eddSAli Bahrami * Remove a boolean identifier from the conditional expression identifier 85369112eddSAli Bahrami * AVL tree. 85469112eddSAli Bahrami * 85569112eddSAli Bahrami * entry: 85669112eddSAli Bahrami * mf - Mapfile descriptor 85769112eddSAli Bahrami * name - Name of identifier. 85869112eddSAli Bahrami * 85969112eddSAli Bahrami * exit: 86069112eddSAli Bahrami * If the name was in the tree, it has been removed. If not, 86169112eddSAli Bahrami * then this routine quietly returns. 86269112eddSAli Bahrami */ 86369112eddSAli Bahrami static void 86469112eddSAli Bahrami cexp_ident_clear(Mapfile *mf, const char *name) 86569112eddSAli Bahrami { 86669112eddSAli Bahrami cexp_id_node_t node; 86769112eddSAli Bahrami cexp_id_node_t *real_node; 86869112eddSAli Bahrami 86969112eddSAli Bahrami DBG_CALL(Dbg_map_cexp_id(mf->mf_ofl->ofl_lml, 0, 87069112eddSAli Bahrami mf->mf_name, mf->mf_lineno, name)); 87169112eddSAli Bahrami 87269112eddSAli Bahrami node.ceid_name = name; 87369112eddSAli Bahrami real_node = avl_find(lms.lms_cexp_id, &node, 0); 87469112eddSAli Bahrami if (real_node != NULL) 87569112eddSAli Bahrami avl_remove(lms.lms_cexp_id, real_node); 87669112eddSAli Bahrami } 87769112eddSAli Bahrami 87869112eddSAli Bahrami /* 87969112eddSAli Bahrami * Initialize the AVL tree that holds the names of the currently defined 88069112eddSAli Bahrami * boolean identifiers for conditional expressions ($if/$elif). 88169112eddSAli Bahrami * 88269112eddSAli Bahrami * entry: 88369112eddSAli Bahrami * ofl - Output file descriptor 88469112eddSAli Bahrami * 88569112eddSAli Bahrami * exit: 88669112eddSAli Bahrami * On success, TRUE (1) is returned and lms.lms_cexp_id is ready for use. 88769112eddSAli Bahrami * On failure, FALSE (0) is returned. 88869112eddSAli Bahrami */ 88969112eddSAli Bahrami static Boolean 89069112eddSAli Bahrami cexp_ident_init(void) 89169112eddSAli Bahrami { 89269112eddSAli Bahrami /* If already done, use it */ 89369112eddSAli Bahrami if (lms.lms_cexp_id != NULL) 89469112eddSAli Bahrami return (TRUE); 89569112eddSAli Bahrami 89669112eddSAli Bahrami lms.lms_cexp_id = libld_calloc(sizeof (*lms.lms_cexp_id), 1); 89769112eddSAli Bahrami if (lms.lms_cexp_id == NULL) 89869112eddSAli Bahrami return (FALSE); 89969112eddSAli Bahrami avl_create(lms.lms_cexp_id, cexp_ident_cmp, sizeof (cexp_id_node_t), 90069112eddSAli Bahrami SGSOFFSETOF(cexp_id_node_t, ceid_avlnode)); 90169112eddSAli Bahrami 90269112eddSAli Bahrami 90369112eddSAli Bahrami /* ELFCLASS */ 90469112eddSAli Bahrami if (cexp_ident_add(NULL, (ld_targ.t_m.m_class == ELFCLASS32) ? 90569112eddSAli Bahrami MSG_ORIG(MSG_STR_UELF32) : MSG_ORIG(MSG_STR_UELF64)) == 0) 90669112eddSAli Bahrami return (FALSE); 90769112eddSAli Bahrami 90869112eddSAli Bahrami /* Machine */ 90969112eddSAli Bahrami switch (ld_targ.t_m.m_mach) { 91069112eddSAli Bahrami case EM_386: 91169112eddSAli Bahrami case EM_AMD64: 91269112eddSAli Bahrami if (cexp_ident_add(NULL, MSG_ORIG(MSG_STR_UX86)) == 0) 91369112eddSAli Bahrami return (FALSE); 91469112eddSAli Bahrami break; 91569112eddSAli Bahrami 91669112eddSAli Bahrami case EM_SPARC: 91769112eddSAli Bahrami case EM_SPARCV9: 91869112eddSAli Bahrami if (cexp_ident_add(NULL, MSG_ORIG(MSG_STR_USPARC)) == 0) 91969112eddSAli Bahrami return (FALSE); 92069112eddSAli Bahrami break; 92169112eddSAli Bahrami } 92269112eddSAli Bahrami 92369112eddSAli Bahrami /* true is always defined */ 92469112eddSAli Bahrami if (cexp_ident_add(NULL, MSG_ORIG(MSG_STR_TRUE)) == 0) 92569112eddSAli Bahrami return (FALSE); 92669112eddSAli Bahrami 92769112eddSAli Bahrami return (TRUE); 92869112eddSAli Bahrami } 92969112eddSAli Bahrami 93069112eddSAli Bahrami /* 93169112eddSAli Bahrami * Validate the string starting at mf->mf_next as being a 93269112eddSAli Bahrami * boolean conditional expression identifier. 93369112eddSAli Bahrami * 93469112eddSAli Bahrami * entry: 93569112eddSAli Bahrami * mf - Mapfile descriptor 93669112eddSAli Bahrami * len - NULL, or address of variable to receive strlen() of identifier 93769112eddSAli Bahrami * directive - If (len == NULL), string giving name of directive being 93869112eddSAli Bahrami * processed. Ignored if (len != NULL). 93969112eddSAli Bahrami * 94069112eddSAli Bahrami * exit: 94169112eddSAli Bahrami * On success: 94269112eddSAli Bahrami * - If len is NULL, a NULL is inserted following the final 94369112eddSAli Bahrami * character of the identifier, and the remainder of the string 94469112eddSAli Bahrami * is tested to ensure it is empty, or only contains whitespace. 94569112eddSAli Bahrami * - If len is non-NULL, *len is set to the number of characters 94669112eddSAli Bahrami * in the identifier, and the rest of the string is not modified. 94769112eddSAli Bahrami * - TRUE (1) is returned 94869112eddSAli Bahrami * 94969112eddSAli Bahrami * On failure, returns FALSE (0). 95069112eddSAli Bahrami */ 95169112eddSAli Bahrami static Boolean 95269112eddSAli Bahrami cexp_ident_validate(Mapfile *mf, size_t *len, const char *directive) 95369112eddSAli Bahrami { 95469112eddSAli Bahrami char *tail; 95569112eddSAli Bahrami 95669112eddSAli Bahrami if ((tail = ident_delimit(mf)) == NULL) 95769112eddSAli Bahrami return (FALSE); 95869112eddSAli Bahrami 95969112eddSAli Bahrami /* 96069112eddSAli Bahrami * If len is non-NULL, we simple count the number of characters 96169112eddSAli Bahrami * consumed by the identifier and are done. If len is NULL, then 96269112eddSAli Bahrami * ensure there's nothing left but whitespace, and NULL terminate 96369112eddSAli Bahrami * the identifier to remove it. 96469112eddSAli Bahrami */ 96569112eddSAli Bahrami if (len != NULL) { 96669112eddSAli Bahrami *len = tail - mf->mf_next; 96769112eddSAli Bahrami } else if (*tail != '\0') { 96869112eddSAli Bahrami *tail++ = '\0'; 96969112eddSAli Bahrami while (isspace(*tail)) 97069112eddSAli Bahrami tail++; 97169112eddSAli Bahrami if (*tail != '\0') { 97269112eddSAli Bahrami mf_fatal(mf, MSG_INTL(MSG_MAP_BADEXTRA), directive); 97369112eddSAli Bahrami return (FALSE); 97469112eddSAli Bahrami } 97569112eddSAli Bahrami } 97669112eddSAli Bahrami 97769112eddSAli Bahrami return (TRUE); 97869112eddSAli Bahrami } 97969112eddSAli Bahrami 98069112eddSAli Bahrami /* 98169112eddSAli Bahrami * Push a new operator onto the conditional expression operator stack. 98269112eddSAli Bahrami * 98369112eddSAli Bahrami * entry: 98469112eddSAli Bahrami * mf - Mapfile descriptor 98569112eddSAli Bahrami * op - Operator to push 98669112eddSAli Bahrami * 98769112eddSAli Bahrami * exit: 98869112eddSAli Bahrami * On success, TRUE (1) is returned, otherwise FALSE (0). 98969112eddSAli Bahrami */ 99069112eddSAli Bahrami static Boolean 99169112eddSAli Bahrami cexp_push_op(cexp_op_t op) 99269112eddSAli Bahrami { 99369112eddSAli Bahrami if (STACK_RESERVE(lms.lms_cexp_op_stack, CEXP_OP_STACK_INIT) == 0) 99469112eddSAli Bahrami return (FALSE); 99569112eddSAli Bahrami 99669112eddSAli Bahrami STACK_PUSH(lms.lms_cexp_op_stack) = op; 99769112eddSAli Bahrami return (TRUE); 99869112eddSAli Bahrami } 99969112eddSAli Bahrami 100069112eddSAli Bahrami /* 100169112eddSAli Bahrami * Evaluate the basic operator (non-paren) at the top of lms.lms_cexp_op_stack, 100269112eddSAli Bahrami * and push the results on lms.lms_cexp_val_stack. 100369112eddSAli Bahrami * 100469112eddSAli Bahrami * exit: 100569112eddSAli Bahrami * On success, returns TRUE (1). On error, FALSE (0) is returned, 100669112eddSAli Bahrami * and the caller is responsible for issuing the error. 100769112eddSAli Bahrami */ 100869112eddSAli Bahrami static Boolean 100969112eddSAli Bahrami cexp_eval_op(void) 101069112eddSAli Bahrami { 101169112eddSAli Bahrami cexp_op_t op; 101269112eddSAli Bahrami uchar_t val; 101369112eddSAli Bahrami 101469112eddSAli Bahrami op = STACK_POP(lms.lms_cexp_op_stack); 101569112eddSAli Bahrami switch (op) { 101669112eddSAli Bahrami case CEXP_OP_AND: 101769112eddSAli Bahrami if (lms.lms_cexp_val_stack.stk_n < 2) 101869112eddSAli Bahrami return (FALSE); 101969112eddSAli Bahrami val = STACK_POP(lms.lms_cexp_val_stack); 102069112eddSAli Bahrami STACK_TOP(lms.lms_cexp_val_stack) = val && 102169112eddSAli Bahrami STACK_TOP(lms.lms_cexp_val_stack); 102269112eddSAli Bahrami break; 102369112eddSAli Bahrami 102469112eddSAli Bahrami case CEXP_OP_OR: 102569112eddSAli Bahrami if (lms.lms_cexp_val_stack.stk_n < 2) 102669112eddSAli Bahrami return (FALSE); 102769112eddSAli Bahrami val = STACK_POP(lms.lms_cexp_val_stack); 102869112eddSAli Bahrami STACK_TOP(lms.lms_cexp_val_stack) = val || 102969112eddSAli Bahrami STACK_TOP(lms.lms_cexp_val_stack); 103069112eddSAli Bahrami break; 103169112eddSAli Bahrami 103269112eddSAli Bahrami case CEXP_OP_NEG: 103369112eddSAli Bahrami if (lms.lms_cexp_val_stack.stk_n < 1) 103469112eddSAli Bahrami return (FALSE); 103569112eddSAli Bahrami STACK_TOP(lms.lms_cexp_val_stack) = 103669112eddSAli Bahrami !STACK_TOP(lms.lms_cexp_val_stack); 103769112eddSAli Bahrami break; 103869112eddSAli Bahrami default: 103969112eddSAli Bahrami return (FALSE); 104069112eddSAli Bahrami } 104169112eddSAli Bahrami 104269112eddSAli Bahrami return (TRUE); 104369112eddSAli Bahrami } 104469112eddSAli Bahrami 104569112eddSAli Bahrami /* 104669112eddSAli Bahrami * Evaluate an expression for a $if/$elif control directive. 104769112eddSAli Bahrami * 104869112eddSAli Bahrami * entry: 104969112eddSAli Bahrami * mf - Mapfile descriptor for NULL terminated string 105069112eddSAli Bahrami * containing the expression. 105169112eddSAli Bahrami * 105269112eddSAli Bahrami * exit: 105369112eddSAli Bahrami * The contents of str are modified by this routine. 105469112eddSAli Bahrami * One of the following values are returned: 105569112eddSAli Bahrami * -1 Syntax error encountered (an error is printed) 105669112eddSAli Bahrami * 0 The expression evaluates to False 105769112eddSAli Bahrami * 1 The expression evaluates to True. 105869112eddSAli Bahrami * 105969112eddSAli Bahrami * note: 106069112eddSAli Bahrami * A simplified version of Dijkstra's Shunting Yard algorithm is used 106169112eddSAli Bahrami * to convert this syntax into postfix form and then evaluate it. 106269112eddSAli Bahrami * Our version has no functions and a tiny set of operators. 106369112eddSAli Bahrami * 106469112eddSAli Bahrami * The expressions consist of boolean identifiers, which can be 106569112eddSAli Bahrami * combined using the following operators, listed from highest 106669112eddSAli Bahrami * precedence to least: 106769112eddSAli Bahrami * 106869112eddSAli Bahrami * Operator Meaning 106969112eddSAli Bahrami * ------------------------------------------------- 107069112eddSAli Bahrami * (expr) sub-expression, non-associative 107169112eddSAli Bahrami * ! logical negation, prefix, left associative 107269112eddSAli Bahrami * && || logical and/or, binary, left associative 107369112eddSAli Bahrami * 107469112eddSAli Bahrami * The operands manipulated by these operators are names, consisting of 107569112eddSAli Bahrami * a sequence of letters and digits. The first character must be a letter. 107669112eddSAli Bahrami * Underscore (_) and period (.) are also considered to be characters. 107769112eddSAli Bahrami * An operand is considered True if it is found in our set of known 107869112eddSAli Bahrami * names (lms.lms_cexp_id), and False otherwise. 107969112eddSAli Bahrami * 108069112eddSAli Bahrami * The Shunting Yard algorithm works using two stacks, one for operators, 108169112eddSAli Bahrami * and a second for operands. The infix input expression is tokenized from 108269112eddSAli Bahrami * left to right and processed in order. Issues of associativity and 108369112eddSAli Bahrami * precedence are managed by reducing (poping and evaluating) items with 108469112eddSAli Bahrami * higer precedence before pushing additional tokens with lower precedence. 108569112eddSAli Bahrami */ 108669112eddSAli Bahrami static int 108769112eddSAli Bahrami cexp_eval_expr(Mapfile *mf) 108869112eddSAli Bahrami { 108969112eddSAli Bahrami char *ident; 109069112eddSAli Bahrami size_t len; 109169112eddSAli Bahrami cexp_op_t new_op = CEXP_OP_AND; /* to catch binop at start */ 109269112eddSAli Bahrami ld_map_npatch_t np; 109369112eddSAli Bahrami char *str = mf->mf_next; 109469112eddSAli Bahrami 109569112eddSAli Bahrami STACK_RESET(lms.lms_cexp_op_stack); 109669112eddSAli Bahrami STACK_RESET(lms.lms_cexp_val_stack); 109769112eddSAli Bahrami 109869112eddSAli Bahrami for (; *str; str++) { 109969112eddSAli Bahrami 110069112eddSAli Bahrami /* Skip whitespace */ 110169112eddSAli Bahrami while (isspace(*str)) 110269112eddSAli Bahrami str++; 110369112eddSAli Bahrami if (!*str) 110469112eddSAli Bahrami break; 110569112eddSAli Bahrami 110669112eddSAli Bahrami switch (*str) { 110769112eddSAli Bahrami case '&': 110869112eddSAli Bahrami case '|': 110969112eddSAli Bahrami if (*(str + 1) != *str) 111069112eddSAli Bahrami goto token_error; 111169112eddSAli Bahrami if ((new_op != CEXP_OP_NONE) && 111269112eddSAli Bahrami (new_op != CEXP_OP_CPAR)) { 111369112eddSAli Bahrami mf_fatal0(mf, MSG_INTL(MSG_MAP_CEXP_BADOPUSE)); 111469112eddSAli Bahrami return (-1); 111569112eddSAli Bahrami } 111669112eddSAli Bahrami str++; 111769112eddSAli Bahrami 111869112eddSAli Bahrami /* 111969112eddSAli Bahrami * As this is a left associative binary operator, we 112069112eddSAli Bahrami * need to process all operators of equal or higher 112169112eddSAli Bahrami * precedence before pushing the new operator. 112269112eddSAli Bahrami */ 112369112eddSAli Bahrami while (!STACK_IS_EMPTY(lms.lms_cexp_op_stack)) { 112469112eddSAli Bahrami cexp_op_t op = STACK_TOP(lms.lms_cexp_op_stack); 112569112eddSAli Bahrami 112669112eddSAli Bahrami 112769112eddSAli Bahrami if ((op != CEXP_OP_AND) && (op != CEXP_OP_OR) && 112869112eddSAli Bahrami (op != CEXP_OP_NEG)) 112969112eddSAli Bahrami break; 113069112eddSAli Bahrami 113169112eddSAli Bahrami if (!cexp_eval_op()) 113269112eddSAli Bahrami goto semantic_error; 113369112eddSAli Bahrami } 113469112eddSAli Bahrami 113569112eddSAli Bahrami new_op = (*str == '&') ? CEXP_OP_AND : CEXP_OP_OR; 113669112eddSAli Bahrami if (!cexp_push_op(new_op)) 113769112eddSAli Bahrami return (-1); 113869112eddSAli Bahrami break; 113969112eddSAli Bahrami 114069112eddSAli Bahrami case '!': 114169112eddSAli Bahrami new_op = CEXP_OP_NEG; 114269112eddSAli Bahrami if (!cexp_push_op(new_op)) 114369112eddSAli Bahrami return (-1); 114469112eddSAli Bahrami break; 114569112eddSAli Bahrami 114669112eddSAli Bahrami case '(': 114769112eddSAli Bahrami new_op = CEXP_OP_OPAR; 114869112eddSAli Bahrami if (!cexp_push_op(new_op)) 114969112eddSAli Bahrami return (-1); 115069112eddSAli Bahrami break; 115169112eddSAli Bahrami 115269112eddSAli Bahrami case ')': 115369112eddSAli Bahrami new_op = CEXP_OP_CPAR; 115469112eddSAli Bahrami 115569112eddSAli Bahrami /* Evaluate the operator stack until reach '(' */ 115669112eddSAli Bahrami while (!STACK_IS_EMPTY(lms.lms_cexp_op_stack) && 115769112eddSAli Bahrami (STACK_TOP(lms.lms_cexp_op_stack) != CEXP_OP_OPAR)) 115869112eddSAli Bahrami if (!cexp_eval_op()) 115969112eddSAli Bahrami goto semantic_error; 116069112eddSAli Bahrami 116169112eddSAli Bahrami /* 116269112eddSAli Bahrami * If the top of operator stack is not an open paren, 116369112eddSAli Bahrami * when we have an error. In this case, the operator 116469112eddSAli Bahrami * stack will be empty due to the loop above. 116569112eddSAli Bahrami */ 116669112eddSAli Bahrami if (STACK_IS_EMPTY(lms.lms_cexp_op_stack)) 116769112eddSAli Bahrami goto unbalpar_error; 116869112eddSAli Bahrami lms.lms_cexp_op_stack.stk_n--; /* Pop OPAR */ 116969112eddSAli Bahrami break; 117069112eddSAli Bahrami 117169112eddSAli Bahrami default: 117269112eddSAli Bahrami /* Ensure there's room to push another operand */ 117369112eddSAli Bahrami if (STACK_RESERVE(lms.lms_cexp_val_stack, 117469112eddSAli Bahrami CEXP_VAL_STACK_INIT) == 0) 117569112eddSAli Bahrami return (0); 117669112eddSAli Bahrami new_op = CEXP_OP_NONE; 117769112eddSAli Bahrami 117869112eddSAli Bahrami /* 117969112eddSAli Bahrami * Operands cannot be numbers. However, we accept two 118069112eddSAli Bahrami * special cases: '0' means false, and '1' is true. 118169112eddSAli Bahrami * This is done to support the common C idiom of 118269112eddSAli Bahrami * '#if 1' and '#if 0' to conditionalize code under 118369112eddSAli Bahrami * development. 118469112eddSAli Bahrami */ 118569112eddSAli Bahrami if ((*str == '0') || (*str == '1')) { 118669112eddSAli Bahrami STACK_PUSH(lms.lms_cexp_val_stack) = 118769112eddSAli Bahrami (*str == '1'); 118869112eddSAli Bahrami break; 118969112eddSAli Bahrami } 119069112eddSAli Bahrami 119169112eddSAli Bahrami /* Look up the identifier */ 119269112eddSAli Bahrami ident = mf->mf_next = str; 119369112eddSAli Bahrami if (!cexp_ident_validate(mf, &len, NULL)) 119469112eddSAli Bahrami return (-1); 119569112eddSAli Bahrami str += len - 1; /* loop will advance past final ch */ 119669112eddSAli Bahrami null_patch_set(&ident[len], &np); 119769112eddSAli Bahrami STACK_PUSH(lms.lms_cexp_val_stack) = 119869112eddSAli Bahrami cexp_ident_test(ident); 119969112eddSAli Bahrami null_patch_undo(&np); 120069112eddSAli Bahrami 120169112eddSAli Bahrami break; 120269112eddSAli Bahrami } 120369112eddSAli Bahrami } 120469112eddSAli Bahrami 120569112eddSAli Bahrami /* Evaluate the operator stack until empty */ 120669112eddSAli Bahrami while (!STACK_IS_EMPTY(lms.lms_cexp_op_stack)) { 120769112eddSAli Bahrami if (STACK_TOP(lms.lms_cexp_op_stack) == CEXP_OP_OPAR) 120869112eddSAli Bahrami goto unbalpar_error; 120969112eddSAli Bahrami 121069112eddSAli Bahrami if (!cexp_eval_op()) 121169112eddSAli Bahrami goto semantic_error; 121269112eddSAli Bahrami } 121369112eddSAli Bahrami 121469112eddSAli Bahrami /* There should be exactly one value left */ 121569112eddSAli Bahrami if (lms.lms_cexp_val_stack.stk_n != 1) 121669112eddSAli Bahrami goto semantic_error; 121769112eddSAli Bahrami 121869112eddSAli Bahrami /* Final value is the result */ 121969112eddSAli Bahrami return (lms.lms_cexp_val_stack.stk_s[0]); 122069112eddSAli Bahrami 122169112eddSAli Bahrami /* Errors issued more than once are handled below, accessed via goto */ 122269112eddSAli Bahrami 122369112eddSAli Bahrami token_error: /* unexpected characters in input stream */ 122469112eddSAli Bahrami mf_fatal(mf, MSG_INTL(MSG_MAP_CEXP_TOKERR), str); 122569112eddSAli Bahrami return (-1); 122669112eddSAli Bahrami 122769112eddSAli Bahrami semantic_error: /* valid tokens, but in invalid arrangement */ 122869112eddSAli Bahrami mf_fatal0(mf, MSG_INTL(MSG_MAP_CEXP_SEMERR)); 122969112eddSAli Bahrami return (-1); 123069112eddSAli Bahrami 123169112eddSAli Bahrami unbalpar_error: /* Extra or missing parenthesis */ 123269112eddSAli Bahrami mf_fatal0(mf, MSG_INTL(MSG_MAP_CEXP_UNBALPAR)); 123369112eddSAli Bahrami return (-1); 123469112eddSAli Bahrami } 123569112eddSAli Bahrami 123669112eddSAli Bahrami /* 123769112eddSAli Bahrami * Process a mapfile control directive. These directives start with 123869112eddSAli Bahrami * the dollar character, and are used to manage details of the mapfile 123969112eddSAli Bahrami * itself, such as version and conditional input. 124069112eddSAli Bahrami * 124169112eddSAli Bahrami * entry: 124269112eddSAli Bahrami * mf - Mapfile descriptor 124369112eddSAli Bahrami * 124469112eddSAli Bahrami * exit: 124569112eddSAli Bahrami * Returns TRUE (1) for success, and FALSE (0) on error. In the 124669112eddSAli Bahrami * error case, a descriptive error is issued. 124769112eddSAli Bahrami */ 124869112eddSAli Bahrami static Boolean 124969112eddSAli Bahrami cdir_process(Mapfile *mf) 125069112eddSAli Bahrami { 125169112eddSAli Bahrami typedef enum { /* Directive types */ 125269112eddSAli Bahrami CDIR_T_UNKNOWN = 0, /* Unrecognized control directive */ 125369112eddSAli Bahrami CDIR_T_ADD, /* $add */ 125469112eddSAli Bahrami CDIR_T_CLEAR, /* $clear */ 125569112eddSAli Bahrami CDIR_T_ERROR, /* $error */ 125669112eddSAli Bahrami CDIR_T_VERSION, /* $mapfile_version */ 125769112eddSAli Bahrami CDIR_T_IF, /* $if */ 125869112eddSAli Bahrami CDIR_T_ELIF, /* $elif */ 125969112eddSAli Bahrami CDIR_T_ELSE, /* $else */ 126069112eddSAli Bahrami CDIR_T_ENDIF, /* $endif */ 126169112eddSAli Bahrami } cdir_t; 126269112eddSAli Bahrami 126369112eddSAli Bahrami typedef enum { /* Types of arguments accepted by directives */ 126469112eddSAli Bahrami ARG_T_NONE, /* Directive takes no arguments */ 126569112eddSAli Bahrami ARG_T_EXPR, /* Directive takes a conditional expression */ 126669112eddSAli Bahrami ARG_T_ID, /* Conditional expression identifier */ 126769112eddSAli Bahrami ARG_T_STR, /* Non-empty string */ 126869112eddSAli Bahrami ARG_T_IGN /* Ignore the argument */ 126969112eddSAli Bahrami } cdir_arg_t; 127069112eddSAli Bahrami 127169112eddSAli Bahrami typedef struct { 127269112eddSAli Bahrami const char *md_name; /* Directive name */ 127369112eddSAli Bahrami size_t md_size; /* strlen(md_name) */ 127469112eddSAli Bahrami cdir_arg_t md_arg; /* Type of arguments */ 127569112eddSAli Bahrami cdir_t md_op; /* CDIR_T_ code */ 127669112eddSAli Bahrami } cdir_match_t; 127769112eddSAli Bahrami 127869112eddSAli Bahrami /* Control Directives: The most likely items are listed first */ 127969112eddSAli Bahrami static cdir_match_t match_data[] = { 128069112eddSAli Bahrami { MSG_ORIG(MSG_STR_CDIR_IF), MSG_STR_CDIR_IF_SIZE, 128169112eddSAli Bahrami ARG_T_EXPR, CDIR_T_IF }, 128269112eddSAli Bahrami { MSG_ORIG(MSG_STR_CDIR_ENDIF), MSG_STR_CDIR_ENDIF_SIZE, 128369112eddSAli Bahrami ARG_T_NONE, CDIR_T_ENDIF }, 128469112eddSAli Bahrami { MSG_ORIG(MSG_STR_CDIR_ELSE), MSG_STR_CDIR_ELSE_SIZE, 128569112eddSAli Bahrami ARG_T_NONE, CDIR_T_ELSE }, 128669112eddSAli Bahrami { MSG_ORIG(MSG_STR_CDIR_ELIF), MSG_STR_CDIR_ELIF_SIZE, 128769112eddSAli Bahrami ARG_T_EXPR, CDIR_T_ELIF }, 128869112eddSAli Bahrami { MSG_ORIG(MSG_STR_CDIR_ERROR), MSG_STR_CDIR_ERROR_SIZE, 128969112eddSAli Bahrami ARG_T_STR, CDIR_T_ERROR }, 129069112eddSAli Bahrami { MSG_ORIG(MSG_STR_CDIR_ADD), MSG_STR_CDIR_ADD_SIZE, 129169112eddSAli Bahrami ARG_T_ID, CDIR_T_ADD }, 129269112eddSAli Bahrami { MSG_ORIG(MSG_STR_CDIR_CLEAR), MSG_STR_CDIR_CLEAR_SIZE, 129369112eddSAli Bahrami ARG_T_ID, CDIR_T_CLEAR }, 129469112eddSAli Bahrami { MSG_ORIG(MSG_STR_CDIR_MFVER), MSG_STR_CDIR_MFVER_SIZE, 129569112eddSAli Bahrami ARG_T_IGN, CDIR_T_VERSION }, 129669112eddSAli Bahrami 129769112eddSAli Bahrami { NULL, 0, 129869112eddSAli Bahrami ARG_T_IGN, CDIR_T_UNKNOWN } 129969112eddSAli Bahrami }; 130069112eddSAli Bahrami 130169112eddSAli Bahrami cdir_match_t *mdptr; 130269112eddSAli Bahrami char *tail; 130369112eddSAli Bahrami int expr_eval; /* Result of evaluating ARG_T_EXPR */ 130469112eddSAli Bahrami Mapfile arg_mf; 130569112eddSAli Bahrami cdir_level_t *level; 130669112eddSAli Bahrami int pass, parent_pass; /* Currently accepting input */ 130769112eddSAli Bahrami 130869112eddSAli Bahrami restart: 130969112eddSAli Bahrami /* Is the immediate context passing input? */ 131069112eddSAli Bahrami pass = STACK_IS_EMPTY(lms.lms_cdir_stack) || 131169112eddSAli Bahrami STACK_TOP(lms.lms_cdir_stack).cdl_pass; 131269112eddSAli Bahrami 131369112eddSAli Bahrami /* Is the surrounding (parent) context passing input? */ 131469112eddSAli Bahrami parent_pass = (lms.lms_cdir_stack.stk_n <= 1) || 131569112eddSAli Bahrami lms.lms_cdir_stack.stk_s[lms.lms_cdir_stack.stk_n - 2].cdl_pass; 131669112eddSAli Bahrami 131769112eddSAli Bahrami 131869112eddSAli Bahrami for (mdptr = match_data; mdptr->md_name; mdptr++) { 131969112eddSAli Bahrami /* Prefix must match, or we move on */ 132069112eddSAli Bahrami if (strncmp(mf->mf_next, mdptr->md_name, 132169112eddSAli Bahrami mdptr->md_size) != 0) 132269112eddSAli Bahrami continue; 132369112eddSAli Bahrami tail = mf->mf_next + mdptr->md_size; 132469112eddSAli Bahrami 132569112eddSAli Bahrami /* 132669112eddSAli Bahrami * If there isn't whitespace, or a NULL terminator following 132769112eddSAli Bahrami * the prefix, then even though our prefix matched, the actual 132869112eddSAli Bahrami * token is longer, and we don't have a match. 132969112eddSAli Bahrami */ 133069112eddSAli Bahrami if (!isspace(*tail) && (*tail != '\0')) 133169112eddSAli Bahrami continue; 133269112eddSAli Bahrami 133369112eddSAli Bahrami /* We have matched a valid control directive */ 133469112eddSAli Bahrami break; 133569112eddSAli Bahrami } 133669112eddSAli Bahrami 133769112eddSAli Bahrami /* Advance input to end of the current line */ 133869112eddSAli Bahrami advance_to_eol(&mf->mf_next); 133969112eddSAli Bahrami 134069112eddSAli Bahrami /* 134169112eddSAli Bahrami * Set up a temporary mapfile descriptor to reference the 134269112eddSAli Bahrami * argument string. The benefit of this second block, is that 134369112eddSAli Bahrami * we can advance the real one to the next line now, which allows 134469112eddSAli Bahrami * us to return at any time knowing that the input has been moved 134569112eddSAli Bahrami * to the proper spot. This simplifies the error cases. 134669112eddSAli Bahrami * 134769112eddSAli Bahrami * If we had a match, tail points at the start of the string. 134869112eddSAli Bahrami * Otherwise, we want to point at the end of the line. 134969112eddSAli Bahrami */ 135069112eddSAli Bahrami arg_mf = *mf; 135169112eddSAli Bahrami if (mdptr->md_name == NULL) 135269112eddSAli Bahrami arg_mf.mf_text = arg_mf.mf_next; 135369112eddSAli Bahrami else 135469112eddSAli Bahrami arg_mf.mf_text = arg_mf.mf_next = tail; 135569112eddSAli Bahrami 135669112eddSAli Bahrami /* 135769112eddSAli Bahrami * Null terminate the arguments, and advance the main mapfile 135869112eddSAli Bahrami * state block to the next line. 135969112eddSAli Bahrami */ 136069112eddSAli Bahrami if (*mf->mf_next == '\n') { 136169112eddSAli Bahrami *mf->mf_next++ = '\0'; 136269112eddSAli Bahrami mf->mf_lineno++; 136369112eddSAli Bahrami } 136469112eddSAli Bahrami 136569112eddSAli Bahrami /* Skip leading whitespace to arguments */ 136669112eddSAli Bahrami while (isspace(*arg_mf.mf_next)) 136769112eddSAli Bahrami arg_mf.mf_next++; 136869112eddSAli Bahrami 136969112eddSAli Bahrami /* Strip off any comment present on the line */ 137069112eddSAli Bahrami for (tail = arg_mf.mf_next; *tail; tail++) 137169112eddSAli Bahrami if (*tail == '#') { 137269112eddSAli Bahrami *tail = '\0'; 137369112eddSAli Bahrami break; 137469112eddSAli Bahrami } 137569112eddSAli Bahrami 137669112eddSAli Bahrami /* 137769112eddSAli Bahrami * Process the arguments as necessary depending on their type. 137869112eddSAli Bahrami * If this control directive is nested inside a surrounding context 137969112eddSAli Bahrami * that is not currently passing text, then we skip the argument 138069112eddSAli Bahrami * evaluation. This follows the behavior of the C preprocessor, 138169112eddSAli Bahrami * which only examines enough to detect the operation within 138269112eddSAli Bahrami * a disabled section, without issuing errors about the arguments. 138369112eddSAli Bahrami */ 138469112eddSAli Bahrami if (pass || (parent_pass && (mdptr->md_op == CDIR_T_ELIF))) { 138569112eddSAli Bahrami switch (mdptr->md_arg) { 138669112eddSAli Bahrami case ARG_T_NONE: 138769112eddSAli Bahrami if (*arg_mf.mf_next == '\0') 138869112eddSAli Bahrami break; 138969112eddSAli Bahrami /* Args are present, but not wanted */ 139069112eddSAli Bahrami mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_REQNOARG), 139169112eddSAli Bahrami mdptr->md_name); 139269112eddSAli Bahrami return (FALSE); 139369112eddSAli Bahrami 139469112eddSAli Bahrami case ARG_T_EXPR: 139569112eddSAli Bahrami /* Ensure that arguments are present */ 139669112eddSAli Bahrami if (*arg_mf.mf_next == '\0') 139769112eddSAli Bahrami goto error_reqarg; 139869112eddSAli Bahrami expr_eval = cexp_eval_expr(&arg_mf); 139969112eddSAli Bahrami if (expr_eval == -1) 140069112eddSAli Bahrami return (FALSE); 140169112eddSAli Bahrami break; 140269112eddSAli Bahrami 140369112eddSAli Bahrami case ARG_T_ID: 140469112eddSAli Bahrami /* Ensure that arguments are present */ 140569112eddSAli Bahrami if (*arg_mf.mf_next == '\0') 140669112eddSAli Bahrami goto error_reqarg; 140769112eddSAli Bahrami if (!cexp_ident_validate(&arg_mf, NULL, 140869112eddSAli Bahrami mdptr->md_name)) 140969112eddSAli Bahrami return (FALSE); 141069112eddSAli Bahrami break; 141169112eddSAli Bahrami 141269112eddSAli Bahrami case ARG_T_STR: 141369112eddSAli Bahrami /* Ensure that arguments are present */ 141469112eddSAli Bahrami if (*arg_mf.mf_next == '\0') 141569112eddSAli Bahrami goto error_reqarg; 141669112eddSAli Bahrami /* Remove trailing whitespace */ 141769112eddSAli Bahrami tail = arg_mf.mf_next + strlen(arg_mf.mf_next); 141869112eddSAli Bahrami while ((tail > arg_mf.mf_next) && 141969112eddSAli Bahrami isspace(*(tail -1))) 142069112eddSAli Bahrami tail--; 142169112eddSAli Bahrami *tail = '\0'; 142269112eddSAli Bahrami break; 142369112eddSAli Bahrami } 142469112eddSAli Bahrami } 142569112eddSAli Bahrami 142669112eddSAli Bahrami /* 142769112eddSAli Bahrami * Carry out the specified control directive: 142869112eddSAli Bahrami */ 142969112eddSAli Bahrami if (!STACK_IS_EMPTY(lms.lms_cdir_stack)) 143069112eddSAli Bahrami level = &STACK_TOP(lms.lms_cdir_stack); 143169112eddSAli Bahrami 143269112eddSAli Bahrami switch (mdptr->md_op) { 143369112eddSAli Bahrami case CDIR_T_UNKNOWN: /* Unrecognized control directive */ 143469112eddSAli Bahrami if (!pass) 143569112eddSAli Bahrami break; 143669112eddSAli Bahrami mf_fatal0(&arg_mf, MSG_INTL(MSG_MAP_CDIR_BAD)); 143769112eddSAli Bahrami return (FALSE); 143869112eddSAli Bahrami 143969112eddSAli Bahrami case CDIR_T_ADD: 144069112eddSAli Bahrami if (pass && !cexp_ident_add(&arg_mf, arg_mf.mf_next)) 144169112eddSAli Bahrami return (FALSE); 144269112eddSAli Bahrami break; 144369112eddSAli Bahrami 144469112eddSAli Bahrami case CDIR_T_CLEAR: 144569112eddSAli Bahrami if (pass) 144669112eddSAli Bahrami cexp_ident_clear(&arg_mf, arg_mf.mf_next); 144769112eddSAli Bahrami break; 144869112eddSAli Bahrami 144969112eddSAli Bahrami case CDIR_T_ERROR: 145069112eddSAli Bahrami if (!pass) 145169112eddSAli Bahrami break; 145269112eddSAli Bahrami mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_ERROR), 145369112eddSAli Bahrami arg_mf.mf_next); 145469112eddSAli Bahrami return (FALSE); 145569112eddSAli Bahrami 145669112eddSAli Bahrami case CDIR_T_VERSION: 145769112eddSAli Bahrami /* 145869112eddSAli Bahrami * A $mapfile_version control directive can only appear 145969112eddSAli Bahrami * as the first directive in a mapfile, and is used to 146069112eddSAli Bahrami * determine the syntax for the rest of the file. It's 146169112eddSAli Bahrami * too late to be using it here. 146269112eddSAli Bahrami */ 146369112eddSAli Bahrami if (!pass) 146469112eddSAli Bahrami break; 146569112eddSAli Bahrami mf_fatal0(&arg_mf, MSG_INTL(MSG_MAP_CDIR_REPVER)); 146669112eddSAli Bahrami return (FALSE); 146769112eddSAli Bahrami 146869112eddSAli Bahrami case CDIR_T_IF: 146969112eddSAli Bahrami /* Push a new level on the conditional input stack */ 147069112eddSAli Bahrami if (STACK_RESERVE(lms.lms_cdir_stack, CDIR_STACK_INIT) == 0) 147169112eddSAli Bahrami return (FALSE); 147269112eddSAli Bahrami level = &lms.lms_cdir_stack.stk_s[lms.lms_cdir_stack.stk_n++]; 147369112eddSAli Bahrami level->cdl_if_lineno = arg_mf.mf_lineno; 147469112eddSAli Bahrami level->cdl_else_lineno = 0; 147569112eddSAli Bahrami 147669112eddSAli Bahrami /* 147769112eddSAli Bahrami * If previous level is not passing, this level is disabled. 147869112eddSAli Bahrami * Otherwise, the expression value determines what happens. 147969112eddSAli Bahrami */ 148069112eddSAli Bahrami if (pass) { 148169112eddSAli Bahrami level->cdl_done = level->cdl_pass = expr_eval; 148269112eddSAli Bahrami } else { 148369112eddSAli Bahrami level->cdl_done = 1; 148469112eddSAli Bahrami level->cdl_pass = 0; 148569112eddSAli Bahrami } 148669112eddSAli Bahrami break; 148769112eddSAli Bahrami 148869112eddSAli Bahrami case CDIR_T_ELIF: 148969112eddSAli Bahrami /* $elif requires an open $if construct */ 149069112eddSAli Bahrami if (STACK_IS_EMPTY(lms.lms_cdir_stack)) { 149169112eddSAli Bahrami mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_NOIF), 149269112eddSAli Bahrami MSG_ORIG(MSG_STR_CDIR_ELIF)); 149369112eddSAli Bahrami return (FALSE); 149469112eddSAli Bahrami } 149569112eddSAli Bahrami 149669112eddSAli Bahrami /* $elif cannot follow $else */ 149769112eddSAli Bahrami if (level->cdl_else_lineno > 0) { 149869112eddSAli Bahrami mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_ELSE), 149969112eddSAli Bahrami MSG_ORIG(MSG_STR_CDIR_ELIF), 150069112eddSAli Bahrami EC_LINENO(level->cdl_else_lineno)); 150169112eddSAli Bahrami return (FALSE); 150269112eddSAli Bahrami } 150369112eddSAli Bahrami 150469112eddSAli Bahrami /* 150569112eddSAli Bahrami * Accept text from $elif if the level isn't already 150669112eddSAli Bahrami * done and the expression evaluates to true. 150769112eddSAli Bahrami */ 150869112eddSAli Bahrami level->cdl_pass = !level->cdl_done && expr_eval; 150969112eddSAli Bahrami if (level->cdl_pass) 151069112eddSAli Bahrami level->cdl_done = 1; 151169112eddSAli Bahrami break; 151269112eddSAli Bahrami 151369112eddSAli Bahrami case CDIR_T_ELSE: 151469112eddSAli Bahrami /* $else requires an open $if construct */ 151569112eddSAli Bahrami if (STACK_IS_EMPTY(lms.lms_cdir_stack)) { 151669112eddSAli Bahrami mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_NOIF), 151769112eddSAli Bahrami MSG_ORIG(MSG_STR_CDIR_ELSE)); 151869112eddSAli Bahrami return (FALSE); 151969112eddSAli Bahrami } 152069112eddSAli Bahrami 152169112eddSAli Bahrami /* There can only be one $else in the chain */ 152269112eddSAli Bahrami if (level->cdl_else_lineno > 0) { 152369112eddSAli Bahrami mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_ELSE), 152469112eddSAli Bahrami MSG_ORIG(MSG_STR_CDIR_ELSE), 152569112eddSAli Bahrami EC_LINENO(level->cdl_else_lineno)); 152669112eddSAli Bahrami return (FALSE); 152769112eddSAli Bahrami } 152869112eddSAli Bahrami level->cdl_else_lineno = arg_mf.mf_lineno; 152969112eddSAli Bahrami 153069112eddSAli Bahrami /* Accept text from $else if the level isn't already done */ 153169112eddSAli Bahrami level->cdl_pass = !level->cdl_done; 153269112eddSAli Bahrami level->cdl_done = 1; 153369112eddSAli Bahrami break; 153469112eddSAli Bahrami 153569112eddSAli Bahrami case CDIR_T_ENDIF: 153669112eddSAli Bahrami /* $endif requires an open $if construct */ 153769112eddSAli Bahrami if (STACK_IS_EMPTY(lms.lms_cdir_stack)) { 153869112eddSAli Bahrami mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_NOIF), 153969112eddSAli Bahrami MSG_ORIG(MSG_STR_CDIR_ENDIF)); 154069112eddSAli Bahrami return (FALSE); 154169112eddSAli Bahrami } 154269112eddSAli Bahrami if (--lms.lms_cdir_stack.stk_n > 0) 154369112eddSAli Bahrami level = &STACK_TOP(lms.lms_cdir_stack); 154469112eddSAli Bahrami break; 154569112eddSAli Bahrami 154669112eddSAli Bahrami default: 154769112eddSAli Bahrami return (FALSE); 154869112eddSAli Bahrami } 154969112eddSAli Bahrami 155069112eddSAli Bahrami /* Evaluating the control directive above can change pass status */ 155169112eddSAli Bahrami expr_eval = STACK_IS_EMPTY(lms.lms_cdir_stack) || 155269112eddSAli Bahrami STACK_TOP(lms.lms_cdir_stack).cdl_pass; 155369112eddSAli Bahrami if (expr_eval != pass) { 155469112eddSAli Bahrami pass = expr_eval; 155569112eddSAli Bahrami DBG_CALL(Dbg_map_pass(arg_mf.mf_ofl->ofl_lml, pass, 155669112eddSAli Bahrami arg_mf.mf_name, arg_mf.mf_lineno, mdptr->md_name)); 155769112eddSAli Bahrami } 155869112eddSAli Bahrami 155969112eddSAli Bahrami /* 156069112eddSAli Bahrami * At this point, we have processed a control directive, 156169112eddSAli Bahrami * updated our conditional state stack, and the input is 156269112eddSAli Bahrami * positioned at the start of the line following the directive. 156369112eddSAli Bahrami * If the current level is accepting input, then give control 156469112eddSAli Bahrami * back to ld_map_gettoken() to resume its normal operation. 156569112eddSAli Bahrami */ 156669112eddSAli Bahrami if (pass) 156769112eddSAli Bahrami return (TRUE); 156869112eddSAli Bahrami 156969112eddSAli Bahrami /* 157069112eddSAli Bahrami * The current level is not accepting input. Only another 157169112eddSAli Bahrami * control directive can change this, so read and discard input 157269112eddSAli Bahrami * until we encounter one of the following: 157369112eddSAli Bahrami * 157469112eddSAli Bahrami * EOF: Return and let ld_map_gettoken() report it 157569112eddSAli Bahrami * Control Directive: Restart this function / evaluate new directive 157669112eddSAli Bahrami */ 157769112eddSAli Bahrami while (*mf->mf_next != '\0') { 157869112eddSAli Bahrami /* Skip leading whitespace */ 157969112eddSAli Bahrami while (isspace_nonl(*mf->mf_next)) 158069112eddSAli Bahrami mf->mf_next++; 158169112eddSAli Bahrami 158269112eddSAli Bahrami /* 158369112eddSAli Bahrami * Control directives start with a '$'. If we hit 158469112eddSAli Bahrami * one, restart the function at this point 158569112eddSAli Bahrami */ 158669112eddSAli Bahrami if (*mf->mf_next == '$') 158769112eddSAli Bahrami goto restart; 158869112eddSAli Bahrami 158969112eddSAli Bahrami /* Not a control directive, so advance input to next line */ 159069112eddSAli Bahrami advance_to_eol(&mf->mf_next); 159169112eddSAli Bahrami if (*mf->mf_next == '\n') { 159269112eddSAli Bahrami mf->mf_lineno++; 159369112eddSAli Bahrami mf->mf_next++; 159469112eddSAli Bahrami } 159569112eddSAli Bahrami } 159669112eddSAli Bahrami 15976f459ff5SToomas Soome assert(*mf->mf_next == '\0'); 159869112eddSAli Bahrami return (TRUE); 159969112eddSAli Bahrami 160069112eddSAli Bahrami /* 160169112eddSAli Bahrami * Control directives that require an argument that is not present 160269112eddSAli Bahrami * jump here to report the error and exit. 160369112eddSAli Bahrami */ 160469112eddSAli Bahrami error_reqarg: 160569112eddSAli Bahrami mf_fatal(&arg_mf, MSG_INTL(MSG_MAP_CDIR_REQARG), mdptr->md_name); 160669112eddSAli Bahrami return (FALSE); 160769112eddSAli Bahrami 160869112eddSAli Bahrami } 160969112eddSAli Bahrami 161069112eddSAli Bahrami #ifndef _ELF64 161169112eddSAli Bahrami /* 161269112eddSAli Bahrami * Convert a string to lowercase. 161369112eddSAli Bahrami */ 161469112eddSAli Bahrami void 161569112eddSAli Bahrami ld_map_lowercase(char *str) 161669112eddSAli Bahrami { 161769112eddSAli Bahrami while (*str = tolower(*str)) 161869112eddSAli Bahrami str++; 161969112eddSAli Bahrami } 162069112eddSAli Bahrami #endif 162169112eddSAli Bahrami 162269112eddSAli Bahrami /* 162369112eddSAli Bahrami * Wrappper on strtoul()/strtoull(), adapted to return an Xword. 162469112eddSAli Bahrami * 162569112eddSAli Bahrami * entry: 162669112eddSAli Bahrami * str - Pointer to string to be converted. 162769112eddSAli Bahrami * endptr - As documented for strtoul(3C). Either NULL, or 162869112eddSAli Bahrami * address of pointer to receive the address of the first 162969112eddSAli Bahrami * unused character in str (called "final" in strtoul(3C)). 163069112eddSAli Bahrami * ret_value - Address of Xword variable to receive result. 163169112eddSAli Bahrami * 163269112eddSAli Bahrami * exit: 163369112eddSAli Bahrami * On success, *ret_value receives the result, *endptr is updated if 163469112eddSAli Bahrami * endptr is non-NULL, and STRTOXWORD_OK is returned. 163569112eddSAli Bahrami * On failure, STRTOXWORD_TOBIG is returned if an otherwise valid 163669112eddSAli Bahrami * value was too large, and STRTOXWORD_BAD is returned if the string 163769112eddSAli Bahrami * is malformed. 163869112eddSAli Bahrami */ 163969112eddSAli Bahrami ld_map_strtoxword_t 164069112eddSAli Bahrami ld_map_strtoxword(const char *restrict str, char **restrict endptr, 164169112eddSAli Bahrami Xword *ret_value) 164269112eddSAli Bahrami { 164369112eddSAli Bahrami #if defined(_ELF64) /* _ELF64 */ 164469112eddSAli Bahrami #define FUNC strtoull /* Function to use */ 164569112eddSAli Bahrami #define FUNC_MAX ULLONG_MAX /* Largest value returned by FUNC */ 164669112eddSAli Bahrami #define XWORD_MAX ULLONG_MAX /* Largest Xword value */ 164769112eddSAli Bahrami uint64_t value; /* Variable of FUNC return type */ 164869112eddSAli Bahrami #else /* _ELF32 */ 164969112eddSAli Bahrami #define FUNC strtoul 165069112eddSAli Bahrami #define FUNC_MAX ULONG_MAX 165169112eddSAli Bahrami #define XWORD_MAX UINT_MAX 165269112eddSAli Bahrami ulong_t value; 165369112eddSAli Bahrami #endif 165469112eddSAli Bahrami 165569112eddSAli Bahrami char *endptr_local; /* Used if endptr is NULL */ 165669112eddSAli Bahrami 165769112eddSAli Bahrami if (endptr == NULL) 165869112eddSAli Bahrami endptr = &endptr_local; 165969112eddSAli Bahrami 166069112eddSAli Bahrami errno = 0; 166169112eddSAli Bahrami value = FUNC(str, endptr, 0); 166269112eddSAli Bahrami if ((errno != 0) || (str == *endptr)) { 166369112eddSAli Bahrami if (value == FUNC_MAX) 166469112eddSAli Bahrami return (STRTOXWORD_TOOBIG); 166569112eddSAli Bahrami else 166669112eddSAli Bahrami return (STRTOXWORD_BAD); 166769112eddSAli Bahrami } 166869112eddSAli Bahrami 166969112eddSAli Bahrami /* 167069112eddSAli Bahrami * If this is a 64-bit linker building an ELFCLASS32 object, 167169112eddSAli Bahrami * the FUNC return type is a 64-bit value, while an Xword is 167269112eddSAli Bahrami * 32-bit. It is possible for FUNC to be able to convert a value 167369112eddSAli Bahrami * too large for our return type. 167469112eddSAli Bahrami */ 167569112eddSAli Bahrami #if FUNC_MAX != XWORD_MAX 167669112eddSAli Bahrami if (value > XWORD_MAX) 167769112eddSAli Bahrami return (STRTOXWORD_TOOBIG); 167869112eddSAli Bahrami #endif 167969112eddSAli Bahrami 168069112eddSAli Bahrami *ret_value = value; 168169112eddSAli Bahrami return (STRTOXWORD_OK); 168269112eddSAli Bahrami 168369112eddSAli Bahrami #undef FUNC 168469112eddSAli Bahrami #undef FUNC_MAX 168569112eddSAli Bahrami #undef XWORD_MAC 168669112eddSAli Bahrami } 168769112eddSAli Bahrami 168869112eddSAli Bahrami /* 168969112eddSAli Bahrami * Convert the unsigned integer value at the current mapfile input 169069112eddSAli Bahrami * into binary form. All numeric values in mapfiles are treated as 169169112eddSAli Bahrami * unsigned integers of the appropriate width for an address on the 169269112eddSAli Bahrami * given target. Values can be decimal, hex, or octal. 169369112eddSAli Bahrami * 169469112eddSAli Bahrami * entry: 169569112eddSAli Bahrami * str - String to process. 169669112eddSAli Bahrami * value - Address of variable to receive resulting value. 169769112eddSAli Bahrami * notail - If TRUE, an error is issued if non-whitespace 169869112eddSAli Bahrami * characters other than '#' (comment) are found following 169969112eddSAli Bahrami * the numeric value before the end of line. 170069112eddSAli Bahrami * 170169112eddSAli Bahrami * exit: 170269112eddSAli Bahrami * On success: 170369112eddSAli Bahrami * - *str is advanced to the next character following the value 170469112eddSAli Bahrami * - *value receives the value 170569112eddSAli Bahrami * - Returns TRUE (1). 170669112eddSAli Bahrami * On failure, returns FALSE (0). 170769112eddSAli Bahrami */ 170869112eddSAli Bahrami static Boolean 170969112eddSAli Bahrami ld_map_getint(Mapfile *mf, ld_map_tkval_t *value, Boolean notail) 171069112eddSAli Bahrami { 171169112eddSAli Bahrami ld_map_strtoxword_t s2xw_ret; 171269112eddSAli Bahrami ld_map_npatch_t np; 171369112eddSAli Bahrami char *endptr; 171469112eddSAli Bahrami char *errstr = mf->mf_next; 171569112eddSAli Bahrami 171669112eddSAli Bahrami value->tkv_int.tkvi_str = mf->mf_next; 171769112eddSAli Bahrami s2xw_ret = ld_map_strtoxword(mf->mf_next, &endptr, 171869112eddSAli Bahrami &value->tkv_int.tkvi_value); 171969112eddSAli Bahrami if (s2xw_ret != STRTOXWORD_OK) { 172069112eddSAli Bahrami null_patch_eol(mf->mf_next, &np); 172169112eddSAli Bahrami if (s2xw_ret == STRTOXWORD_TOOBIG) 172269112eddSAli Bahrami mf_fatal(mf, MSG_INTL(MSG_MAP_VALUELIMIT), errstr); 172369112eddSAli Bahrami else 172469112eddSAli Bahrami mf_fatal(mf, MSG_INTL(MSG_MAP_MALVALUE), errstr); 172569112eddSAli Bahrami null_patch_undo(&np); 172669112eddSAli Bahrami return (FALSE); 172769112eddSAli Bahrami } 172869112eddSAli Bahrami 172969112eddSAli Bahrami /* Advance position to item following value, skipping whitespace */ 173069112eddSAli Bahrami value->tkv_int.tkvi_cnt = endptr - mf->mf_next; 173169112eddSAli Bahrami mf->mf_next = endptr; 173269112eddSAli Bahrami while (isspace_nonl(*mf->mf_next)) 173369112eddSAli Bahrami mf->mf_next++; 173469112eddSAli Bahrami 173569112eddSAli Bahrami /* If requested, ensure there's nothing left */ 173669112eddSAli Bahrami if (notail && (*mf->mf_next != '\n') && (*mf->mf_next != '#') && 173769112eddSAli Bahrami (*mf->mf_next != '\0')) { 173869112eddSAli Bahrami null_patch_eol(mf->mf_next, &np); 173969112eddSAli Bahrami mf_fatal(mf, MSG_INTL(MSG_MAP_BADVALUETAIL), errstr); 174069112eddSAli Bahrami null_patch_undo(&np); 174169112eddSAli Bahrami return (FALSE); 174269112eddSAli Bahrami } 174369112eddSAli Bahrami 174469112eddSAli Bahrami return (TRUE); 174569112eddSAli Bahrami } 174669112eddSAli Bahrami 174769112eddSAli Bahrami /* 174869112eddSAli Bahrami * Convert a an unquoted identifier into a TK_STRING token, using the 174969112eddSAli Bahrami * rules for syntax version in use. Used exclusively by ld_map_gettoken(). 175069112eddSAli Bahrami * 175169112eddSAli Bahrami * entry: 175269112eddSAli Bahrami * mf - Mapfile descriptor, positioned to the first character of 175369112eddSAli Bahrami * the string. 175469112eddSAli Bahrami * flags - Bitmask of options to control ld_map_gettoken()s behavior 175569112eddSAli Bahrami * tkv- Address of pointer to variable to receive token value. 175669112eddSAli Bahrami * 175769112eddSAli Bahrami * exit: 175869112eddSAli Bahrami * On success, mf is advanced past the token, tkv is updated with 175969112eddSAli Bahrami * the string, and TK_STRING is returned. On error, TK_ERROR is returned. 176069112eddSAli Bahrami */ 176169112eddSAli Bahrami inline static Token 176269112eddSAli Bahrami gettoken_ident(Mapfile *mf, int flags, ld_map_tkval_t *tkv) 176369112eddSAli Bahrami { 176469112eddSAli Bahrami char *end; 176569112eddSAli Bahrami Token tok; 176669112eddSAli Bahrami ld_map_npatch_t np; 176769112eddSAli Bahrami 176869112eddSAli Bahrami tkv->tkv_str = mf->mf_next; 176969112eddSAli Bahrami if ((end = ident_delimit(mf)) == NULL) 177069112eddSAli Bahrami return (TK_ERROR); 177169112eddSAli Bahrami mf->mf_next = end; 177269112eddSAli Bahrami 177369112eddSAli Bahrami /* 177469112eddSAli Bahrami * One advantage of reading the entire mapfile into memory is that 177569112eddSAli Bahrami * we can access the strings within it without having to allocate 177669112eddSAli Bahrami * more memory or make copies. In order to do that, we need to NULL 177769112eddSAli Bahrami * terminate this identifier. That is going to overwrite the 177869112eddSAli Bahrami * following character. The problem this presents is that the next 177969112eddSAli Bahrami * character may well be the first character of a subsequent token. 178069112eddSAli Bahrami * The solution to this is: 178169112eddSAli Bahrami * 178269112eddSAli Bahrami * 1) Disallow the case where the next character is able to 178369112eddSAli Bahrami * start a string. This is not legal mapfile syntax anyway, 178469112eddSAli Bahrami * so catching it here simplifies matters. 178569112eddSAli Bahrami * 2) Copy the character into the special mf->mf_next_ch 178669112eddSAli Bahrami * 3) The next call to ld_map_gettoken() checks mf->mf_next_ch, 178769112eddSAli Bahrami * and if it is non-0, uses it instead of dereferencing the 178869112eddSAli Bahrami * mf_next pointer. 178969112eddSAli Bahrami */ 179069112eddSAli Bahrami tok = (*mf->mf_next & 0x80) ? 179169112eddSAli Bahrami TK_OP_ILLCHR : mf->mf_tokdisp[*mf->mf_next]; 179269112eddSAli Bahrami switch (tok) { 179369112eddSAli Bahrami case TK_OP_BADCHR: 179469112eddSAli Bahrami null_patch_eol(mf->mf_next, &np); 179569112eddSAli Bahrami mf_fatal(mf, MSG_INTL(MSG_MAP_BADCHAR), mf->mf_next); 179669112eddSAli Bahrami null_patch_undo(&np); 179769112eddSAli Bahrami return (TK_ERROR); 179869112eddSAli Bahrami 179969112eddSAli Bahrami case TK_OP_SIMQUOTE: 180069112eddSAli Bahrami case TK_OP_CQUOTE: 180169112eddSAli Bahrami case TK_OP_CDIR: 180269112eddSAli Bahrami case TK_OP_NUM: 180369112eddSAli Bahrami case TK_OP_ID: 180469112eddSAli Bahrami null_patch_eol(mf->mf_next, &np); 180569112eddSAli Bahrami mf_fatal(mf, MSG_INTL(MSG_MAP_WSNEEDED), mf->mf_next); 180669112eddSAli Bahrami null_patch_undo(&np); 180769112eddSAli Bahrami return (TK_ERROR); 180869112eddSAli Bahrami } 180969112eddSAli Bahrami 181069112eddSAli Bahrami /* Null terminate, saving the replaced character */ 181169112eddSAli Bahrami mf->mf_next_ch = *mf->mf_next; 181269112eddSAli Bahrami *mf->mf_next = '\0'; 181369112eddSAli Bahrami 181469112eddSAli Bahrami if (flags & TK_F_STRLC) 181569112eddSAli Bahrami ld_map_lowercase(tkv->tkv_str); 181669112eddSAli Bahrami return (TK_STRING); 181769112eddSAli Bahrami } 181869112eddSAli Bahrami 181969112eddSAli Bahrami /* 182069112eddSAli Bahrami * Convert a quoted string into a TK_STRING token, using simple 182169112eddSAli Bahrami * quoting rules: 182269112eddSAli Bahrami * - Start and end quotes must be present and match 182369112eddSAli Bahrami * - There are no special characters or escape sequences. 182469112eddSAli Bahrami * This function is used exclusively by ld_map_gettoken(). 182569112eddSAli Bahrami * 182669112eddSAli Bahrami * entry: 182769112eddSAli Bahrami * mf - Mapfile descriptor, positioned to the opening quote character. 182869112eddSAli Bahrami * flags - Bitmask of options to control ld_map_gettoken()s behavior 182969112eddSAli Bahrami * tkv- Address of pointer to variable to receive token value. 183069112eddSAli Bahrami * 183169112eddSAli Bahrami * exit: 183269112eddSAli Bahrami * On success, mf is advanced past the token, tkv is updated with 183369112eddSAli Bahrami * the string, and TK_STRING is returned. On error, TK_ERROR is returned. 183469112eddSAli Bahrami */ 183569112eddSAli Bahrami inline static Token 183669112eddSAli Bahrami gettoken_simquote_str(Mapfile *mf, int flags, ld_map_tkval_t *tkv) 183769112eddSAli Bahrami { 183869112eddSAli Bahrami char *str, *end; 183969112eddSAli Bahrami char quote; 184069112eddSAli Bahrami 184169112eddSAli Bahrami str = mf->mf_next++; 184269112eddSAli Bahrami quote = *str; 184369112eddSAli Bahrami end = mf->mf_next; 184469112eddSAli Bahrami while ((*end != '\0') && (*end != '\n') && (*end != quote)) 184569112eddSAli Bahrami end++; 184669112eddSAli Bahrami if (*end != quote) { 184769112eddSAli Bahrami ld_map_npatch_t np; 184869112eddSAli Bahrami 184969112eddSAli Bahrami null_patch_eol(end, &np); 185069112eddSAli Bahrami mf_fatal(mf, MSG_INTL(MSG_MAP_NOTERM), str); 185169112eddSAli Bahrami null_patch_undo(&np); 185269112eddSAli Bahrami return (TK_ERROR); 185369112eddSAli Bahrami } 185469112eddSAli Bahrami 185569112eddSAli Bahrami /* 185669112eddSAli Bahrami * end is pointing at the closing quote. We can turn that into NULL 185769112eddSAli Bahrami * termination for the string without needing to restore it later. 185869112eddSAli Bahrami */ 185969112eddSAli Bahrami *end = '\0'; 186069112eddSAli Bahrami mf->mf_next = end + 1; 186169112eddSAli Bahrami tkv->tkv_str = str + 1; /* Skip opening quote */ 186269112eddSAli Bahrami if (flags & TK_F_STRLC) 186369112eddSAli Bahrami ld_map_lowercase(tkv->tkv_str); 186469112eddSAli Bahrami return (TK_STRING); 186569112eddSAli Bahrami } 186669112eddSAli Bahrami 186769112eddSAli Bahrami /* 186869112eddSAli Bahrami * Convert a quoted string into a TK_STRING token, using C string literal 186969112eddSAli Bahrami * quoting rules: 187069112eddSAli Bahrami * - Start and end quotes must be present and match 187169112eddSAli Bahrami * - Backslash is an escape, used to introduce special characters 187269112eddSAli Bahrami * This function is used exclusively by ld_map_gettoken(). 187369112eddSAli Bahrami * 187469112eddSAli Bahrami * entry: 187569112eddSAli Bahrami * mf - Mapfile descriptor, positioned to the opening quote character. 187669112eddSAli Bahrami * flags - Bitmask of options to control ld_map_gettoken()s behavior 187769112eddSAli Bahrami * tkv- Address of pointer to variable to receive token value. 187869112eddSAli Bahrami * 187969112eddSAli Bahrami * exit: 188069112eddSAli Bahrami * On success, mf is advanced past the token, tkv is updated with 188169112eddSAli Bahrami * the string, and TK_STRING is returned. On error, TK_ERROR is returned. 188269112eddSAli Bahrami */ 188369112eddSAli Bahrami inline static Token 188469112eddSAli Bahrami gettoken_cquote_str(Mapfile *mf, int flags, ld_map_tkval_t *tkv) 188569112eddSAli Bahrami { 188669112eddSAli Bahrami char *str, *cur, *end; 188769112eddSAli Bahrami char quote; 188869112eddSAli Bahrami int c; 188969112eddSAli Bahrami 189069112eddSAli Bahrami /* 189169112eddSAli Bahrami * This function goes through the quoted string and copies 189269112eddSAli Bahrami * it on top of itself, replacing escape sequences with the 189369112eddSAli Bahrami * characters they denote. There is always enough room for this, 189469112eddSAli Bahrami * because escapes are multi-character sequences that are converted 189569112eddSAli Bahrami * to single character results. 189669112eddSAli Bahrami */ 189769112eddSAli Bahrami str = mf->mf_next++; 189869112eddSAli Bahrami quote = *str; 189969112eddSAli Bahrami cur = end = mf->mf_next; 190069112eddSAli Bahrami for (c = *end++; (c != '\0') && (c != '\n') && (c != quote); 190169112eddSAli Bahrami c = *end++) { 190269112eddSAli Bahrami if (c == '\\') { 190369112eddSAli Bahrami c = conv_translate_c_esc(&end); 190469112eddSAli Bahrami if (c == -1) { 190569112eddSAli Bahrami mf_fatal(mf, MSG_INTL(MSG_MAP_BADCESC), *end); 190669112eddSAli Bahrami return (TK_ERROR); 190769112eddSAli Bahrami } 190869112eddSAli Bahrami } 190969112eddSAli Bahrami *cur++ = c; 191069112eddSAli Bahrami } 191169112eddSAli Bahrami *cur = '\0'; /* terminate the result */ 191269112eddSAli Bahrami if (c != quote) { 191369112eddSAli Bahrami ld_map_npatch_t np; 191469112eddSAli Bahrami 191569112eddSAli Bahrami null_patch_eol(end, &np); 191669112eddSAli Bahrami mf_fatal(mf, MSG_INTL(MSG_MAP_NOTERM), str); 191769112eddSAli Bahrami null_patch_undo(&np); 191869112eddSAli Bahrami return (TK_ERROR); 191969112eddSAli Bahrami } 192069112eddSAli Bahrami 192169112eddSAli Bahrami /* end is pointing one character past the closing quote */ 192269112eddSAli Bahrami mf->mf_next = end; 192369112eddSAli Bahrami tkv->tkv_str = str + 1; /* Skip opening quote */ 192469112eddSAli Bahrami if (flags & TK_F_STRLC) 192569112eddSAli Bahrami ld_map_lowercase(tkv->tkv_str); 192669112eddSAli Bahrami return (TK_STRING); 192769112eddSAli Bahrami } 192869112eddSAli Bahrami 192969112eddSAli Bahrami /* 193069112eddSAli Bahrami * Get a token from the mapfile. 193169112eddSAli Bahrami * 193269112eddSAli Bahrami * entry: 193369112eddSAli Bahrami * mf - Mapfile descriptor 193469112eddSAli Bahrami * flags - Bitmask of options to control ld_map_gettoken()s behavior 193569112eddSAli Bahrami * tkv- Address of pointer to variable to receive token value. 193669112eddSAli Bahrami * 193769112eddSAli Bahrami * exit: 193869112eddSAli Bahrami * Returns one of the TK_* values, to report the result. If the resulting 193969112eddSAli Bahrami * token has a value (TK_STRING / TK_INT), and tkv is non-NULL, tkv 194069112eddSAli Bahrami * is filled in with the resulting value. 194169112eddSAli Bahrami */ 194269112eddSAli Bahrami Token 194369112eddSAli Bahrami ld_map_gettoken(Mapfile *mf, int flags, ld_map_tkval_t *tkv) 194469112eddSAli Bahrami { 194569112eddSAli Bahrami int cdir_allow, ch; 194669112eddSAli Bahrami Token tok; 194769112eddSAli Bahrami ld_map_npatch_t np; 194869112eddSAli Bahrami 194969112eddSAli Bahrami /* 195069112eddSAli Bahrami * Mapfile control directives all start with a '$' character. However, 195169112eddSAli Bahrami * they are only valid when they are the first thing on a line. That 195269112eddSAli Bahrami * happens on the first call to ld_map_gettoken() for a new a new 195369112eddSAli Bahrami * mapfile, as tracked with lms.lms_cdir_valid, and immediately 195469112eddSAli Bahrami * following each newline seen in the file. 195569112eddSAli Bahrami */ 195669112eddSAli Bahrami cdir_allow = lms.lms_cdir_valid; 195769112eddSAli Bahrami lms.lms_cdir_valid = 0; 195869112eddSAli Bahrami 195969112eddSAli Bahrami /* Cycle through the characters looking for tokens. */ 196069112eddSAli Bahrami for (;;) { 196169112eddSAli Bahrami /* 196269112eddSAli Bahrami * Process the next character. This is normally *mf->mf_next, 196369112eddSAli Bahrami * but if mf->mf_next_ch is non-0, then it contains the 196469112eddSAli Bahrami * character, and *mf->mf_next contains a NULL termination 196569112eddSAli Bahrami * from the TK_STRING token returned on the previous call. 196669112eddSAli Bahrami * 196769112eddSAli Bahrami * gettoken_ident() ensures that this is never done to 196869112eddSAli Bahrami * a character that starts a string. 196969112eddSAli Bahrami */ 197069112eddSAli Bahrami if (mf->mf_next_ch == 0) { 197169112eddSAli Bahrami ch = *mf->mf_next; 197269112eddSAli Bahrami } else { 197369112eddSAli Bahrami ch = mf->mf_next_ch; 197469112eddSAli Bahrami mf->mf_next_ch = 0; /* Reset */ 197569112eddSAli Bahrami } 197669112eddSAli Bahrami 197769112eddSAli Bahrami /* Map the character to a dispatch action */ 197869112eddSAli Bahrami tok = (ch & 0x80) ? TK_OP_ILLCHR : mf->mf_tokdisp[ch]; 197969112eddSAli Bahrami 198069112eddSAli Bahrami /* 198169112eddSAli Bahrami * Items that require processing are identified as OP tokens. 198269112eddSAli Bahrami * We process them, and return a result non-OP token. 198369112eddSAli Bahrami * 198469112eddSAli Bahrami * Non-OP tokens are single character tokens, and we return 198569112eddSAli Bahrami * them immediately. 198669112eddSAli Bahrami */ 198769112eddSAli Bahrami switch (tok) { 198869112eddSAli Bahrami case TK_OP_EOF: 198969112eddSAli Bahrami /* If EOFOK is set, quietly report it as TK_EOF */ 199069112eddSAli Bahrami if ((flags & TK_F_EOFOK) != 0) 199169112eddSAli Bahrami return (TK_EOF); 199269112eddSAli Bahrami 199369112eddSAli Bahrami /* Treat it as a standard error */ 199469112eddSAli Bahrami mf_fatal0(mf, MSG_INTL(MSG_MAP_PREMEOF)); 199569112eddSAli Bahrami return (TK_ERROR); 199669112eddSAli Bahrami 199769112eddSAli Bahrami case TK_OP_ILLCHR: 199869112eddSAli Bahrami mf_fatal(mf, MSG_INTL(MSG_MAP_ILLCHAR), ch); 199969112eddSAli Bahrami mf->mf_next++; 200069112eddSAli Bahrami return (TK_ERROR); 200169112eddSAli Bahrami 200269112eddSAli Bahrami case TK_OP_BADCHR: 200369112eddSAli Bahrami tk_op_badchr: 200469112eddSAli Bahrami null_patch_eol(mf->mf_next, &np); 200569112eddSAli Bahrami mf_fatal(mf, MSG_INTL(MSG_MAP_BADCHAR), mf->mf_next); 200669112eddSAli Bahrami null_patch_undo(&np); 200769112eddSAli Bahrami mf->mf_next++; 200869112eddSAli Bahrami return (TK_ERROR); 200969112eddSAli Bahrami 201069112eddSAli Bahrami case TK_OP_WS: /* White space */ 201169112eddSAli Bahrami mf->mf_next++; 201269112eddSAli Bahrami break; 201369112eddSAli Bahrami 201469112eddSAli Bahrami case TK_OP_NL: /* White space too, but bump line number. */ 201569112eddSAli Bahrami mf->mf_next++; 201669112eddSAli Bahrami mf->mf_lineno++; 201769112eddSAli Bahrami cdir_allow = 1; 201869112eddSAli Bahrami break; 201969112eddSAli Bahrami 202069112eddSAli Bahrami case TK_OP_SIMQUOTE: 202169112eddSAli Bahrami if (flags & TK_F_KEYWORD) 202269112eddSAli Bahrami goto tk_op_badkwquote; 202369112eddSAli Bahrami return (gettoken_simquote_str(mf, flags, tkv)); 202469112eddSAli Bahrami 202569112eddSAli Bahrami case TK_OP_CQUOTE: 202669112eddSAli Bahrami if (flags & TK_F_KEYWORD) { 202769112eddSAli Bahrami tk_op_badkwquote: 202869112eddSAli Bahrami null_patch_eol(mf->mf_next, &np); 202969112eddSAli Bahrami mf_fatal(mf, MSG_INTL(MSG_MAP_BADKWQUOTE), 203069112eddSAli Bahrami mf->mf_next); 203169112eddSAli Bahrami null_patch_undo(&np); 203269112eddSAli Bahrami mf->mf_next++; 203369112eddSAli Bahrami return (TK_ERROR); 203469112eddSAli Bahrami } 203569112eddSAli Bahrami return (gettoken_cquote_str(mf, flags, tkv)); 203669112eddSAli Bahrami 203769112eddSAli Bahrami case TK_OP_CMT: 203869112eddSAli Bahrami advance_to_eol(&mf->mf_next); 203969112eddSAli Bahrami break; 204069112eddSAli Bahrami 204169112eddSAli Bahrami case TK_OP_CDIR: 204269112eddSAli Bahrami /* 204369112eddSAli Bahrami * Control directives are only valid at the start 204469112eddSAli Bahrami * of a line. 204569112eddSAli Bahrami */ 204669112eddSAli Bahrami if (!cdir_allow) { 204769112eddSAli Bahrami null_patch_eol(mf->mf_next, &np); 204869112eddSAli Bahrami mf_fatal(mf, MSG_INTL(MSG_MAP_CDIR_NOTBOL), 204969112eddSAli Bahrami mf->mf_next); 205069112eddSAli Bahrami null_patch_undo(&np); 205169112eddSAli Bahrami mf->mf_next++; 205269112eddSAli Bahrami return (TK_ERROR); 205369112eddSAli Bahrami } 205469112eddSAli Bahrami if (!cdir_process(mf)) 205569112eddSAli Bahrami return (TK_ERROR); 205669112eddSAli Bahrami break; 205769112eddSAli Bahrami 205869112eddSAli Bahrami case TK_OP_NUM: /* Decimal, hex(0x...), or octal (0...) value */ 205969112eddSAli Bahrami if (!ld_map_getint(mf, tkv, FALSE)) 206069112eddSAli Bahrami return (TK_ERROR); 206169112eddSAli Bahrami return (TK_INT); 206269112eddSAli Bahrami 206369112eddSAli Bahrami case TK_OP_ID: /* Unquoted identifier */ 206469112eddSAli Bahrami return (gettoken_ident(mf, flags, tkv)); 206569112eddSAli Bahrami 206669112eddSAli Bahrami case TK_OP_CEQUAL: /* += or -= */ 206769112eddSAli Bahrami if (*(mf->mf_next + 1) != '=') 206869112eddSAli Bahrami goto tk_op_badchr; 206969112eddSAli Bahrami tok = (ch == '+') ? TK_PLUSEQ : TK_MINUSEQ; 207069112eddSAli Bahrami mf->mf_next += 2; 207169112eddSAli Bahrami return (tok); 207269112eddSAli Bahrami 207369112eddSAli Bahrami default: /* Non-OP token */ 207469112eddSAli Bahrami mf->mf_next++; 207569112eddSAli Bahrami return (tok); 207669112eddSAli Bahrami } 207769112eddSAli Bahrami } 207869112eddSAli Bahrami } 207969112eddSAli Bahrami 208069112eddSAli Bahrami /* 208169112eddSAli Bahrami * Given a token and value returned by ld_map_gettoken(), return a string 208269112eddSAli Bahrami * representation of it suitable for use in an error message. 208369112eddSAli Bahrami * 208469112eddSAli Bahrami * entry: 208569112eddSAli Bahrami * tok - Token code. Must not be an OP-token 208669112eddSAli Bahrami * tkv - Token value 208769112eddSAli Bahrami */ 208869112eddSAli Bahrami const char * 208969112eddSAli Bahrami ld_map_tokenstr(Token tok, ld_map_tkval_t *tkv, Conv_inv_buf_t *inv_buf) 209069112eddSAli Bahrami { 209169112eddSAli Bahrami size_t cnt; 209269112eddSAli Bahrami 209369112eddSAli Bahrami switch (tok) { 209469112eddSAli Bahrami case TK_ERROR: 209569112eddSAli Bahrami return (MSG_ORIG(MSG_STR_ERROR)); 209669112eddSAli Bahrami case TK_EOF: 209769112eddSAli Bahrami return (MSG_ORIG(MSG_STR_EOF)); 209869112eddSAli Bahrami case TK_STRING: 209969112eddSAli Bahrami return (tkv->tkv_str); 210069112eddSAli Bahrami case TK_COLON: 210169112eddSAli Bahrami return (MSG_ORIG(MSG_QSTR_COLON)); 210269112eddSAli Bahrami case TK_SEMICOLON: 210369112eddSAli Bahrami return (MSG_ORIG(MSG_QSTR_SEMICOLON)); 210469112eddSAli Bahrami case TK_EQUAL: 210569112eddSAli Bahrami return (MSG_ORIG(MSG_QSTR_EQUAL)); 210669112eddSAli Bahrami case TK_PLUSEQ: 210769112eddSAli Bahrami return (MSG_ORIG(MSG_QSTR_PLUSEQ)); 210869112eddSAli Bahrami case TK_MINUSEQ: 210969112eddSAli Bahrami return (MSG_ORIG(MSG_QSTR_MINUSEQ)); 211069112eddSAli Bahrami case TK_ATSIGN: 211169112eddSAli Bahrami return (MSG_ORIG(MSG_QSTR_ATSIGN)); 211269112eddSAli Bahrami case TK_DASH: 211369112eddSAli Bahrami return (MSG_ORIG(MSG_QSTR_DASH)); 211469112eddSAli Bahrami case TK_LEFTBKT: 211569112eddSAli Bahrami return (MSG_ORIG(MSG_QSTR_LEFTBKT)); 211669112eddSAli Bahrami case TK_RIGHTBKT: 211769112eddSAli Bahrami return (MSG_ORIG(MSG_QSTR_RIGHTBKT)); 211869112eddSAli Bahrami case TK_PIPE: 211969112eddSAli Bahrami return (MSG_ORIG(MSG_QSTR_PIPE)); 212069112eddSAli Bahrami case TK_INT: 212169112eddSAli Bahrami cnt = tkv->tkv_int.tkvi_cnt; 212269112eddSAli Bahrami if (cnt >= sizeof (inv_buf->buf)) 212369112eddSAli Bahrami cnt = sizeof (inv_buf->buf) - 1; 212469112eddSAli Bahrami (void) memcpy(inv_buf->buf, tkv->tkv_int.tkvi_str, cnt); 212569112eddSAli Bahrami inv_buf->buf[cnt] = '\0'; 212669112eddSAli Bahrami return (inv_buf->buf); 212769112eddSAli Bahrami case TK_STAR: 212869112eddSAli Bahrami return (MSG_ORIG(MSG_QSTR_STAR)); 212969112eddSAli Bahrami case TK_BANG: 213069112eddSAli Bahrami return (MSG_ORIG(MSG_QSTR_BANG)); 213169112eddSAli Bahrami default: 213269112eddSAli Bahrami assert(0); 213369112eddSAli Bahrami break; 213469112eddSAli Bahrami } 213569112eddSAli Bahrami 213669112eddSAli Bahrami /*NOTREACHED*/ 213769112eddSAli Bahrami return (MSG_INTL(MSG_MAP_INTERR)); 213869112eddSAli Bahrami } 213969112eddSAli Bahrami 214069112eddSAli Bahrami /* 214169112eddSAli Bahrami * Advance the input to the first non-empty line, and determine 214269112eddSAli Bahrami * the mapfile version. The version is specified by the mapfile 214369112eddSAli Bahrami * using a $mapfile_version directive. The original System V 214469112eddSAli Bahrami * syntax lacks this directive, and we use that fact to identify 214569112eddSAli Bahrami * such files. SysV mapfile are implicitly defined to have version 1. 214669112eddSAli Bahrami * 214769112eddSAli Bahrami * entry: 214869112eddSAli Bahrami * ofl - Output file descriptor 214969112eddSAli Bahrami * mf - Mapfile block 215069112eddSAli Bahrami * 215169112eddSAli Bahrami * exit: 215269112eddSAli Bahrami * On success, updates mf->mf_version, and returns TRUE (1). 215369112eddSAli Bahrami * On failure, returns FALSE (0). 215469112eddSAli Bahrami */ 215569112eddSAli Bahrami static Boolean 215669112eddSAli Bahrami mapfile_version(Mapfile *mf) 215769112eddSAli Bahrami { 215869112eddSAli Bahrami char *line_start = mf->mf_next; 215969112eddSAli Bahrami Boolean cont = TRUE; 216069112eddSAli Bahrami Boolean status = TRUE; /* Assume success */ 216169112eddSAli Bahrami Token tok; 216269112eddSAli Bahrami 216369112eddSAli Bahrami mf->mf_version = MFV_SYSV; 216469112eddSAli Bahrami 216569112eddSAli Bahrami /* 216669112eddSAli Bahrami * Cycle through the characters looking for tokens. Although the 216769112eddSAli Bahrami * true version is not known yet, we use the v2 dispatch table. 216869112eddSAli Bahrami * It contains control directives, which we need for this search, 216969112eddSAli Bahrami * and the other TK_OP_ tokens we will recognize and act on are the 217069112eddSAli Bahrami * same for both tables. 217169112eddSAli Bahrami * 217269112eddSAli Bahrami * It is important not to process any tokens that would lead to 217369112eddSAli Bahrami * a non-OP token: 217469112eddSAli Bahrami * 217569112eddSAli Bahrami * - The version is required to interpret them 217669112eddSAli Bahrami * - Our mapfile descriptor is not fully initialized, 217769112eddSAli Bahrami * attempts to run that code will crash the program. 217869112eddSAli Bahrami */ 217969112eddSAli Bahrami while (cont) { 218069112eddSAli Bahrami /* Map the character to a dispatch action */ 218169112eddSAli Bahrami tok = (*mf->mf_next & 0x80) ? 218269112eddSAli Bahrami TK_OP_ILLCHR : gettok_dispatch_v2[*mf->mf_next]; 218369112eddSAli Bahrami 218469112eddSAli Bahrami switch (tok) { 218569112eddSAli Bahrami case TK_OP_WS: /* White space */ 218669112eddSAli Bahrami mf->mf_next++; 218769112eddSAli Bahrami break; 218869112eddSAli Bahrami 218969112eddSAli Bahrami case TK_OP_NL: /* White space too, but bump line number. */ 219069112eddSAli Bahrami mf->mf_next++; 219169112eddSAli Bahrami mf->mf_lineno++; 219269112eddSAli Bahrami break; 219369112eddSAli Bahrami 219469112eddSAli Bahrami case TK_OP_CMT: 219569112eddSAli Bahrami advance_to_eol(&mf->mf_next); 219669112eddSAli Bahrami break; 219769112eddSAli Bahrami 219869112eddSAli Bahrami case TK_OP_CDIR: 219969112eddSAli Bahrami /* 220069112eddSAli Bahrami * Control directives are only valid at the start 220169112eddSAli Bahrami * of a line. However, as we have not yet seen 220269112eddSAli Bahrami * a token, we do not need to test for this, and 220369112eddSAli Bahrami * can safely assume that we are at the start. 220469112eddSAli Bahrami */ 220569112eddSAli Bahrami if (!strncasecmp(mf->mf_next, 220669112eddSAli Bahrami MSG_ORIG(MSG_STR_CDIR_MFVER), 220769112eddSAli Bahrami MSG_STR_CDIR_MFVER_SIZE) && 220869112eddSAli Bahrami isspace_nonl(*(mf->mf_next + 220969112eddSAli Bahrami MSG_STR_CDIR_MFVER_SIZE))) { 221069112eddSAli Bahrami ld_map_tkval_t ver; 221169112eddSAli Bahrami 221269112eddSAli Bahrami mf->mf_next += MSG_STR_CDIR_MFVER_SIZE + 1; 221369112eddSAli Bahrami if (!ld_map_getint(mf, &ver, TRUE)) { 221469112eddSAli Bahrami status = cont = FALSE; 221569112eddSAli Bahrami break; 221669112eddSAli Bahrami } 221769112eddSAli Bahrami /* 221869112eddSAli Bahrami * Is it a valid version? Note that we 221969112eddSAli Bahrami * intentionally do not allow you to 222069112eddSAli Bahrami * specify version 1 using the $mapfile_version 222169112eddSAli Bahrami * syntax, because that's reserved to version 222269112eddSAli Bahrami * 2 and up. 222369112eddSAli Bahrami */ 222469112eddSAli Bahrami if ((ver.tkv_int.tkvi_value < 2) || 222569112eddSAli Bahrami (ver.tkv_int.tkvi_value >= MFV_NUM)) { 222669112eddSAli Bahrami const char *fmt; 222769112eddSAli Bahrami 222869112eddSAli Bahrami fmt = (ver.tkv_int.tkvi_value < 2) ? 222969112eddSAli Bahrami MSG_INTL(MSG_MAP_CDIR_BADVDIR) : 223069112eddSAli Bahrami MSG_INTL(MSG_MAP_CDIR_BADVER); 223169112eddSAli Bahrami mf_fatal(mf, fmt, 223269112eddSAli Bahrami EC_WORD(ver.tkv_int.tkvi_value)); 223369112eddSAli Bahrami status = cont = FALSE; 223469112eddSAli Bahrami break; 223569112eddSAli Bahrami } 223669112eddSAli Bahrami mf->mf_version = ver.tkv_int.tkvi_value; 223769112eddSAli Bahrami cont = FALSE; /* Version recovered. All done */ 223869112eddSAli Bahrami break; 223969112eddSAli Bahrami } 224069112eddSAli Bahrami /* 224169112eddSAli Bahrami * Not a version directive. Reset the current position 224269112eddSAli Bahrami * to the start of the current line and stop here. 224369112eddSAli Bahrami * SysV syntax applies. 224469112eddSAli Bahrami */ 224569112eddSAli Bahrami mf->mf_next = line_start; 224669112eddSAli Bahrami cont = FALSE; 224769112eddSAli Bahrami break; 224869112eddSAli Bahrami 224969112eddSAli Bahrami default: 225069112eddSAli Bahrami /* 225169112eddSAli Bahrami * If we see anything else, then stop at this point. 225269112eddSAli Bahrami * The file has System V syntax (version 1), and the 225369112eddSAli Bahrami * next token should be interpreted as such. 225469112eddSAli Bahrami */ 225569112eddSAli Bahrami cont = FALSE; 225669112eddSAli Bahrami break; 225769112eddSAli Bahrami } 225869112eddSAli Bahrami } 225969112eddSAli Bahrami 226069112eddSAli Bahrami return (status); 226169112eddSAli Bahrami } 226269112eddSAli Bahrami 226369112eddSAli Bahrami /* 226469112eddSAli Bahrami * Parse the mapfile. 226569112eddSAli Bahrami */ 226669112eddSAli Bahrami Boolean 226769112eddSAli Bahrami ld_map_parse(const char *mapfile, Ofl_desc *ofl) 226869112eddSAli Bahrami { 226969112eddSAli Bahrami struct stat stat_buf; /* stat of mapfile */ 227069112eddSAli Bahrami int mapfile_fd; /* descriptor for mapfile */ 227169112eddSAli Bahrami int err; 227269112eddSAli Bahrami Mapfile *mf; /* Mapfile descriptor */ 227369112eddSAli Bahrami size_t name_len; /* strlen(mapfile) */ 227469112eddSAli Bahrami 227569112eddSAli Bahrami /* 227669112eddSAli Bahrami * Determine if we're dealing with a file or a directory. 227769112eddSAli Bahrami */ 227869112eddSAli Bahrami if (stat(mapfile, &stat_buf) == -1) { 227969112eddSAli Bahrami err = errno; 22801007fd6fSAli Bahrami ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_SYS_STAT), mapfile, 22811007fd6fSAli Bahrami strerror(err)); 228269112eddSAli Bahrami return (FALSE); 228369112eddSAli Bahrami } 228469112eddSAli Bahrami if (S_ISDIR(stat_buf.st_mode)) { 228569112eddSAli Bahrami DIR *dirp; 228669112eddSAli Bahrami struct dirent *denp; 228769112eddSAli Bahrami 228869112eddSAli Bahrami /* 228969112eddSAli Bahrami * Open the directory and interpret each visible file as a 229069112eddSAli Bahrami * mapfile. 229169112eddSAli Bahrami */ 229269112eddSAli Bahrami if ((dirp = opendir(mapfile)) == NULL) 229369112eddSAli Bahrami return (TRUE); 229469112eddSAli Bahrami 229569112eddSAli Bahrami while ((denp = readdir(dirp)) != NULL) { 229669112eddSAli Bahrami char path[PATH_MAX]; 229769112eddSAli Bahrami 229869112eddSAli Bahrami /* 229969112eddSAli Bahrami * Ignore any hidden filenames. Construct the full 230069112eddSAli Bahrami * pathname to the new mapfile. 230169112eddSAli Bahrami */ 230269112eddSAli Bahrami if (*denp->d_name == '.') 230369112eddSAli Bahrami continue; 230469112eddSAli Bahrami (void) snprintf(path, PATH_MAX, MSG_ORIG(MSG_STR_PATH), 230569112eddSAli Bahrami mapfile, denp->d_name); 230669112eddSAli Bahrami if (!ld_map_parse(path, ofl)) 230769112eddSAli Bahrami return (FALSE); 230869112eddSAli Bahrami } 230969112eddSAli Bahrami (void) closedir(dirp); 231069112eddSAli Bahrami return (TRUE); 231169112eddSAli Bahrami } else if (!S_ISREG(stat_buf.st_mode)) { 23121007fd6fSAli Bahrami ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_SYS_NOTREG), mapfile); 231369112eddSAli Bahrami return (FALSE); 231469112eddSAli Bahrami } 231569112eddSAli Bahrami 231669112eddSAli Bahrami /* Open file */ 231769112eddSAli Bahrami if ((mapfile_fd = open(mapfile, O_RDONLY)) == -1) { 231869112eddSAli Bahrami err = errno; 23191007fd6fSAli Bahrami ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), mapfile, 23201007fd6fSAli Bahrami strerror(err)); 232169112eddSAli Bahrami return (FALSE); 232269112eddSAli Bahrami } 232369112eddSAli Bahrami 232469112eddSAli Bahrami /* 232569112eddSAli Bahrami * Allocate enough memory to hold the state block, mapfile name, 232669112eddSAli Bahrami * and mapfile text. Text has alignment 1, so it can follow the 232769112eddSAli Bahrami * state block without padding. 232869112eddSAli Bahrami */ 232969112eddSAli Bahrami name_len = strlen(mapfile) + 1; 233069112eddSAli Bahrami mf = libld_malloc(sizeof (*mf) + name_len + stat_buf.st_size + 1); 233169112eddSAli Bahrami if (mf == NULL) 233269112eddSAli Bahrami return (FALSE); 233369112eddSAli Bahrami mf->mf_ofl = ofl; 233469112eddSAli Bahrami mf->mf_name = (char *)(mf + 1); 233569112eddSAli Bahrami (void) strcpy(mf->mf_name, mapfile); 233669112eddSAli Bahrami mf->mf_text = mf->mf_name + name_len; 233769112eddSAli Bahrami if (read(mapfile_fd, mf->mf_text, stat_buf.st_size) != 233869112eddSAli Bahrami stat_buf.st_size) { 233969112eddSAli Bahrami err = errno; 23401007fd6fSAli Bahrami ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_SYS_READ), mapfile, 23411007fd6fSAli Bahrami strerror(err)); 234269112eddSAli Bahrami (void) close(mapfile_fd); 234369112eddSAli Bahrami return (FALSE); 234469112eddSAli Bahrami } 234569112eddSAli Bahrami (void) close(mapfile_fd); 234669112eddSAli Bahrami mf->mf_text[stat_buf.st_size] = '\0'; 234769112eddSAli Bahrami mf->mf_next = mf->mf_text; 234869112eddSAli Bahrami mf->mf_lineno = 1; 234969112eddSAli Bahrami mf->mf_next_ch = 0; /* No "lookahead" character yet */ 235069112eddSAli Bahrami mf->mf_ec_insndx = 0; /* Insert entrace criteria at top */ 235169112eddSAli Bahrami 235269112eddSAli Bahrami /* 235369112eddSAli Bahrami * Read just enough from the mapfile to determine the version, 235469112eddSAli Bahrami * and then dispatch to the appropriate code for further processing 235569112eddSAli Bahrami */ 235669112eddSAli Bahrami if (!mapfile_version(mf)) 235769112eddSAli Bahrami return (FALSE); 235869112eddSAli Bahrami 235969112eddSAli Bahrami /* 236069112eddSAli Bahrami * Start and continuation masks for unquoted identifier at this 236169112eddSAli Bahrami * mapfile version level. 236269112eddSAli Bahrami */ 236369112eddSAli Bahrami mf->mf_tkid_start = TKID_ATTR_START(mf->mf_version); 236469112eddSAli Bahrami mf->mf_tkid_cont = TKID_ATTR_CONT(mf->mf_version); 236569112eddSAli Bahrami 236669112eddSAli Bahrami DBG_CALL(Dbg_map_parse(ofl->ofl_lml, mapfile, mf->mf_version)); 236769112eddSAli Bahrami 236869112eddSAli Bahrami switch (mf->mf_version) { 236969112eddSAli Bahrami case MFV_SYSV: 23701007fd6fSAli Bahrami /* Guidance: Use newer mapfile syntax */ 23711007fd6fSAli Bahrami if (OFL_GUIDANCE(ofl, FLG_OFG_NO_MF)) 23721007fd6fSAli Bahrami ld_eprintf(ofl, ERR_GUIDANCE, 23731007fd6fSAli Bahrami MSG_INTL(MSG_GUIDE_MAPFILE), mapfile); 23741007fd6fSAli Bahrami 237569112eddSAli Bahrami mf->mf_tokdisp = gettok_dispatch_v1; 237669112eddSAli Bahrami if (!ld_map_parse_v1(mf)) 237769112eddSAli Bahrami return (FALSE); 237869112eddSAli Bahrami break; 237969112eddSAli Bahrami 238069112eddSAli Bahrami case MFV_SOLARIS: 238169112eddSAli Bahrami mf->mf_tokdisp = gettok_dispatch_v2; 238269112eddSAli Bahrami STACK_RESET(lms.lms_cdir_stack); 238369112eddSAli Bahrami 238469112eddSAli Bahrami /* 238569112eddSAli Bahrami * If the conditional expression identifier tree has not been 238669112eddSAli Bahrami * initialized, set it up. This is only done on the first 238769112eddSAli Bahrami * mapfile, because the identifier control directives accumulate 238869112eddSAli Bahrami * across all the mapfiles. 238969112eddSAli Bahrami */ 239069112eddSAli Bahrami if ((lms.lms_cexp_id == NULL) && !cexp_ident_init()) 239169112eddSAli Bahrami return (FALSE); 239269112eddSAli Bahrami 239369112eddSAli Bahrami /* 239469112eddSAli Bahrami * Tell ld_map_gettoken() we will accept a '$' as starting a 239569112eddSAli Bahrami * control directive on the first call. Normally, they are 239669112eddSAli Bahrami * only allowed after a newline. 239769112eddSAli Bahrami */ 239869112eddSAli Bahrami lms.lms_cdir_valid = 1; 239969112eddSAli Bahrami 240069112eddSAli Bahrami if (!ld_map_parse_v2(mf)) 240169112eddSAli Bahrami return (FALSE); 240269112eddSAli Bahrami 240369112eddSAli Bahrami /* Did we leave any open $if control directives? */ 240469112eddSAli Bahrami if (!STACK_IS_EMPTY(lms.lms_cdir_stack)) { 240569112eddSAli Bahrami while (!STACK_IS_EMPTY(lms.lms_cdir_stack)) { 240669112eddSAli Bahrami cdir_level_t *level = 240769112eddSAli Bahrami &STACK_POP(lms.lms_cdir_stack); 240869112eddSAli Bahrami 240969112eddSAli Bahrami mf_fatal(mf, MSG_INTL(MSG_MAP_CDIR_NOEND), 241069112eddSAli Bahrami EC_LINENO(level->cdl_if_lineno)); 241169112eddSAli Bahrami } 241269112eddSAli Bahrami return (FALSE); 241369112eddSAli Bahrami } 241469112eddSAli Bahrami break; 241569112eddSAli Bahrami } 241669112eddSAli Bahrami 241769112eddSAli Bahrami return (TRUE); 241869112eddSAli Bahrami } 241969112eddSAli Bahrami 242069112eddSAli Bahrami /* 242169112eddSAli Bahrami * Sort the segment list. This is necessary if a mapfile has set explicit 242269112eddSAli Bahrami * virtual addresses for segments, or defined a SEGMENT_ORDER directive. 242369112eddSAli Bahrami * 242469112eddSAli Bahrami * Only PT_LOAD segments can be assigned a virtual address. These segments can 242569112eddSAli Bahrami * be one of two types: 242669112eddSAli Bahrami * 242769112eddSAli Bahrami * - Standard segments for text, data or bss. These segments will have been 242869112eddSAli Bahrami * inserted before the default text (first PT_LOAD) segment. 242969112eddSAli Bahrami * 243069112eddSAli Bahrami * - Empty (reservation) segments. These segment will have been inserted at 243169112eddSAli Bahrami * the end of any default PT_LOAD segments. 243269112eddSAli Bahrami * 243369112eddSAli Bahrami * Any standard segments that are assigned a virtual address will be sorted, 243469112eddSAli Bahrami * and as their definitions precede any default PT_LOAD segments, these segments 243569112eddSAli Bahrami * will be assigned sections before any defaults. 243669112eddSAli Bahrami * 243769112eddSAli Bahrami * Any reservation segments are also sorted amoung themselves, as these segments 243869112eddSAli Bahrami * must still follow the standard default segments. 243969112eddSAli Bahrami */ 244069112eddSAli Bahrami static Boolean 244169112eddSAli Bahrami sort_seg_list(Ofl_desc *ofl) 244269112eddSAli Bahrami { 244369112eddSAli Bahrami APlist *sort_segs = NULL, *load_segs = NULL; 244469112eddSAli Bahrami Sg_desc *sgp1; 244569112eddSAli Bahrami Aliste idx1; 244669112eddSAli Bahrami Aliste nsegs; 244769112eddSAli Bahrami 244869112eddSAli Bahrami 244969112eddSAli Bahrami /* 245069112eddSAli Bahrami * We know the number of elements in the sorted list will be 245169112eddSAli Bahrami * the same as the original, so use this as the initial allocation 245269112eddSAli Bahrami * size for the replacement aplist. 245369112eddSAli Bahrami */ 245469112eddSAli Bahrami nsegs = aplist_nitems(ofl->ofl_segs); 245569112eddSAli Bahrami 245669112eddSAli Bahrami 245769112eddSAli Bahrami /* Add the items below SGID_TEXT to the list */ 245869112eddSAli Bahrami for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp1)) { 245969112eddSAli Bahrami if (sgp1->sg_id >= SGID_TEXT) 246069112eddSAli Bahrami break; 246169112eddSAli Bahrami 246269112eddSAli Bahrami if (aplist_append(&sort_segs, sgp1, nsegs) == NULL) 246369112eddSAli Bahrami return (FALSE); 246469112eddSAli Bahrami } 246569112eddSAli Bahrami 246669112eddSAli Bahrami /* 246769112eddSAli Bahrami * If there are any SEGMENT_ORDER items, add them, and set their 246869112eddSAli Bahrami * FLG_SG_ORDERED flag to identify them in debug output, and to 246969112eddSAli Bahrami * prevent them from being added again below. 247069112eddSAli Bahrami */ 247169112eddSAli Bahrami for (APLIST_TRAVERSE(ofl->ofl_segs_order, idx1, sgp1)) { 247269112eddSAli Bahrami if (aplist_append(&sort_segs, sgp1, nsegs) == NULL) 247369112eddSAli Bahrami return (FALSE); 247469112eddSAli Bahrami sgp1->sg_flags |= FLG_SG_ORDERED; 247569112eddSAli Bahrami } 247669112eddSAli Bahrami 247769112eddSAli Bahrami /* 247869112eddSAli Bahrami * Add the loadable segments to another list in sorted order. 247969112eddSAli Bahrami */ 248069112eddSAli Bahrami DBG_CALL(Dbg_map_sort_title(ofl->ofl_lml, TRUE)); 248169112eddSAli Bahrami for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp1)) { 248269112eddSAli Bahrami DBG_CALL(Dbg_map_sort_seg(ofl->ofl_lml, ELFOSABI_SOLARIS, 248369112eddSAli Bahrami ld_targ.t_m.m_mach, sgp1)); 248469112eddSAli Bahrami 248569112eddSAli Bahrami /* Only interested in PT_LOAD items not in SEGMENT_ORDER list */ 248669112eddSAli Bahrami if ((sgp1->sg_phdr.p_type != PT_LOAD) || 248769112eddSAli Bahrami (sgp1->sg_flags & FLG_SG_ORDERED)) 248869112eddSAli Bahrami continue; 248969112eddSAli Bahrami 249069112eddSAli Bahrami /* 249169112eddSAli Bahrami * If the loadable segment does not contain a vaddr, simply 249269112eddSAli Bahrami * append it to the new list. 249369112eddSAli Bahrami */ 249469112eddSAli Bahrami if ((sgp1->sg_flags & FLG_SG_P_VADDR) == 0) { 249569112eddSAli Bahrami if (aplist_append(&load_segs, sgp1, AL_CNT_SEGMENTS) == 249669112eddSAli Bahrami NULL) 249769112eddSAli Bahrami return (FALSE); 249869112eddSAli Bahrami 249969112eddSAli Bahrami } else { 250069112eddSAli Bahrami Aliste idx2; 250169112eddSAli Bahrami Sg_desc *sgp2; 250269112eddSAli Bahrami int inserted = 0; 250369112eddSAli Bahrami 250469112eddSAli Bahrami /* 250569112eddSAli Bahrami * Traverse the segment list we are creating, looking 250669112eddSAli Bahrami * for a segment that defines a vaddr. 250769112eddSAli Bahrami */ 250869112eddSAli Bahrami for (APLIST_TRAVERSE(load_segs, idx2, sgp2)) { 250969112eddSAli Bahrami /* 251069112eddSAli Bahrami * Any real segments that contain vaddr's need 251169112eddSAli Bahrami * to be sorted. Any reservation segments also 251269112eddSAli Bahrami * need to be sorted. However, any reservation 251369112eddSAli Bahrami * segments should be placed after any real 251469112eddSAli Bahrami * segments. 251569112eddSAli Bahrami */ 251669112eddSAli Bahrami if (((sgp2->sg_flags & 251769112eddSAli Bahrami (FLG_SG_P_VADDR | FLG_SG_EMPTY)) == 0) && 251869112eddSAli Bahrami (sgp1->sg_flags & FLG_SG_EMPTY)) 251969112eddSAli Bahrami continue; 252069112eddSAli Bahrami 252169112eddSAli Bahrami if ((sgp2->sg_flags & FLG_SG_P_VADDR) && 252269112eddSAli Bahrami ((sgp2->sg_flags & FLG_SG_EMPTY) == 252369112eddSAli Bahrami (sgp1->sg_flags & FLG_SG_EMPTY))) { 252469112eddSAli Bahrami if (sgp1->sg_phdr.p_vaddr == 252569112eddSAli Bahrami sgp2->sg_phdr.p_vaddr) { 25261007fd6fSAli Bahrami ld_eprintf(ofl, ERR_FATAL, 252769112eddSAli Bahrami MSG_INTL(MSG_MAP_SEGSAME), 252869112eddSAli Bahrami sgp1->sg_name, 252969112eddSAli Bahrami sgp2->sg_name); 253069112eddSAli Bahrami return (FALSE); 253169112eddSAli Bahrami } 253269112eddSAli Bahrami 253369112eddSAli Bahrami if (sgp1->sg_phdr.p_vaddr > 253469112eddSAli Bahrami sgp2->sg_phdr.p_vaddr) 253569112eddSAli Bahrami continue; 253669112eddSAli Bahrami } 253769112eddSAli Bahrami 253869112eddSAli Bahrami /* 253969112eddSAli Bahrami * Insert this segment before the segment on 254069112eddSAli Bahrami * the load_segs list. 254169112eddSAli Bahrami */ 254269112eddSAli Bahrami if (aplist_insert(&load_segs, sgp1, 254369112eddSAli Bahrami AL_CNT_SEGMENTS, idx2) == NULL) 254469112eddSAli Bahrami return (FALSE); 254569112eddSAli Bahrami inserted = 1; 254669112eddSAli Bahrami break; 254769112eddSAli Bahrami } 254869112eddSAli Bahrami 254969112eddSAli Bahrami /* 255069112eddSAli Bahrami * If the segment being inspected has not been inserted 255169112eddSAli Bahrami * in the segment list, simply append it to the list. 255269112eddSAli Bahrami */ 255369112eddSAli Bahrami if ((inserted == 0) && (aplist_append(&load_segs, 255469112eddSAli Bahrami sgp1, AL_CNT_SEGMENTS) == NULL)) 255569112eddSAli Bahrami return (FALSE); 255669112eddSAli Bahrami } 255769112eddSAli Bahrami } 255869112eddSAli Bahrami 255969112eddSAli Bahrami /* 256069112eddSAli Bahrami * Add the sorted loadable segments to our initial segment list. 256169112eddSAli Bahrami */ 256269112eddSAli Bahrami for (APLIST_TRAVERSE(load_segs, idx1, sgp1)) { 256369112eddSAli Bahrami if (aplist_append(&sort_segs, sgp1, AL_CNT_SEGMENTS) == NULL) 256469112eddSAli Bahrami return (FALSE); 256569112eddSAli Bahrami } 256669112eddSAli Bahrami 256769112eddSAli Bahrami /* 256869112eddSAli Bahrami * Add all other segments to our list. 256969112eddSAli Bahrami */ 257069112eddSAli Bahrami for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp1)) { 257169112eddSAli Bahrami if ((sgp1->sg_id < SGID_TEXT) || 257269112eddSAli Bahrami (sgp1->sg_phdr.p_type == PT_LOAD) || 257369112eddSAli Bahrami (sgp1->sg_flags & FLG_SG_ORDERED)) 257469112eddSAli Bahrami continue; 257569112eddSAli Bahrami 257669112eddSAli Bahrami if (aplist_append(&sort_segs, sgp1, AL_CNT_SEGMENTS) == NULL) 257769112eddSAli Bahrami return (FALSE); 257869112eddSAli Bahrami } 257969112eddSAli Bahrami 258069112eddSAli Bahrami /* 258169112eddSAli Bahrami * Free the original list, and the pt_load list, and use 258269112eddSAli Bahrami * the new list as the segment list. 258369112eddSAli Bahrami */ 258469112eddSAli Bahrami free(ofl->ofl_segs); 258569112eddSAli Bahrami if (load_segs) free(load_segs); 258669112eddSAli Bahrami ofl->ofl_segs = sort_segs; 258769112eddSAli Bahrami 258869112eddSAli Bahrami if (DBG_ENABLED) { 258969112eddSAli Bahrami Dbg_map_sort_title(ofl->ofl_lml, FALSE); 259069112eddSAli Bahrami for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp1)) { 259169112eddSAli Bahrami Dbg_map_sort_seg(ofl->ofl_lml, ELFOSABI_SOLARIS, 259269112eddSAli Bahrami ld_targ.t_m.m_mach, sgp1); 259369112eddSAli Bahrami } 259469112eddSAli Bahrami } 259569112eddSAli Bahrami 259669112eddSAli Bahrami return (TRUE); 259769112eddSAli Bahrami } 259869112eddSAli Bahrami 259969112eddSAli Bahrami /* 260069112eddSAli Bahrami * After all mapfiles have been processed, this routine is used to 260169112eddSAli Bahrami * finish any remaining mapfile related work. 260269112eddSAli Bahrami * 260369112eddSAli Bahrami * exit: 260469112eddSAli Bahrami * Returns TRUE on success, and FALSE on failure. 260569112eddSAli Bahrami */ 260669112eddSAli Bahrami Boolean 260769112eddSAli Bahrami ld_map_post_process(Ofl_desc *ofl) 260869112eddSAli Bahrami { 260969112eddSAli Bahrami Aliste idx, idx2; 261069112eddSAli Bahrami Is_desc *isp; 261169112eddSAli Bahrami Sg_desc *sgp; 261269112eddSAli Bahrami Ent_desc *enp; 261369112eddSAli Bahrami Sg_desc *first_seg = NULL; 261469112eddSAli Bahrami 261569112eddSAli Bahrami 261669112eddSAli Bahrami DBG_CALL(Dbg_map_post_title(ofl->ofl_lml)); 261769112eddSAli Bahrami 261869112eddSAli Bahrami /* 261969112eddSAli Bahrami * Per-segment processing: 262069112eddSAli Bahrami * - Identify segments with explicit virtual address 262169112eddSAli Bahrami * - Details of input and output section order 262269112eddSAli Bahrami */ 262369112eddSAli Bahrami for (APLIST_TRAVERSE(ofl->ofl_segs, idx, sgp)) { 262469112eddSAli Bahrami /* 262569112eddSAli Bahrami * We are looking for segments. Program headers that represent 262669112eddSAli Bahrami * segments are required to have a non-NULL name pointer, 262769112eddSAli Bahrami * while that those that do not are required to have a 262869112eddSAli Bahrami * NULL name pointer. 262969112eddSAli Bahrami */ 263069112eddSAli Bahrami if (sgp->sg_name == NULL) 263169112eddSAli Bahrami continue; 263269112eddSAli Bahrami 263369112eddSAli Bahrami /* Remember the first non-disabled segment */ 263469112eddSAli Bahrami if ((first_seg == NULL) && !(sgp->sg_flags & FLG_SG_DISABLED)) 263569112eddSAli Bahrami first_seg = sgp; 263669112eddSAli Bahrami 263769112eddSAli Bahrami /* 263869112eddSAli Bahrami * If a segment has an explicit virtual address, we will 263969112eddSAli Bahrami * need to sort the segments. 264069112eddSAli Bahrami */ 264169112eddSAli Bahrami if (sgp->sg_flags & FLG_SG_P_VADDR) 264269112eddSAli Bahrami ofl->ofl_flags1 |= FLG_OF1_VADDR; 264369112eddSAli Bahrami 264469112eddSAli Bahrami /* 264569112eddSAli Bahrami * The FLG_OF_OS_ORDER flag enables the code that does 264669112eddSAli Bahrami * output section ordering. Set if the segment has 264769112eddSAli Bahrami * a non-empty output section order list. 264869112eddSAli Bahrami */ 264969112eddSAli Bahrami if (alist_nitems(sgp->sg_os_order) > 0) 265069112eddSAli Bahrami ofl->ofl_flags |= FLG_OF_OS_ORDER; 265169112eddSAli Bahrami 265269112eddSAli Bahrami /* 265369112eddSAli Bahrami * The version 1 and version 2 syntaxes for input section 265469112eddSAli Bahrami * ordering are different and incompatible enough that we 265569112eddSAli Bahrami * only allow the use of one or the other for a given segment: 265669112eddSAli Bahrami * 265769112eddSAli Bahrami * v1) The version 1 syntax has the user set the ?O flag on 265869112eddSAli Bahrami * the segment. If this is done, all input sections placed 265969112eddSAli Bahrami * via an entrance criteria that has a section name are to 266069112eddSAli Bahrami * be sorted, using the order of the entrance criteria 266169112eddSAli Bahrami * as the sort key. 266269112eddSAli Bahrami * 266369112eddSAli Bahrami * v2) The version 2 syntax has the user specify a name for 266469112eddSAli Bahrami * the entry criteria, and then provide a list of entry 266569112eddSAli Bahrami * criteria names via the IS_ORDER segment attribute. 266669112eddSAli Bahrami * Sections placed via the criteria listed in IS_ORDER 266769112eddSAli Bahrami * are sorted, and the others are not. 266869112eddSAli Bahrami * 266969112eddSAli Bahrami * Regardless of the syntax version used, the section sorting 267069112eddSAli Bahrami * code expects the following: 267169112eddSAli Bahrami * 267269112eddSAli Bahrami * - Segments requiring input section sorting have the 267369112eddSAli Bahrami * FLG_SG_IS_ORDER flag set 267469112eddSAli Bahrami * 267569112eddSAli Bahrami * - Entrance criteria referencing the segment that 267669112eddSAli Bahrami * participate in input section sorting have a non-zero 267769112eddSAli Bahrami * sort key in their ec_ordndx field. 267869112eddSAli Bahrami * 267969112eddSAli Bahrami * At this point, the following are true: 268069112eddSAli Bahrami * 268169112eddSAli Bahrami * - All entrance criteria have ec_ordndx set to 0. 268269112eddSAli Bahrami * - Segments that require the version 1 behavior have 268369112eddSAli Bahrami * the FLG_SG_IS_ORDER flag set, and the segments 268469112eddSAli Bahrami * sg_is_order list is empty. 268569112eddSAli Bahrami * - Segments that require the version 2 behavior do not 268669112eddSAli Bahrami * have FLG_SG_IS_ORDER set, and the sg_is_order list is 268769112eddSAli Bahrami * non-empty. This list contains the names of the entrance 268869112eddSAli Bahrami * criteria that will participate in input section sorting, 268969112eddSAli Bahrami * and their relative order in the list provides the 269069112eddSAli Bahrami * sort key to use. 269169112eddSAli Bahrami * 269269112eddSAli Bahrami * We must detect these two cases, set the FLG_SG_IS_ORDER 269369112eddSAli Bahrami * flag as necessary, and fill in all entrance criteria 269469112eddSAli Bahrami * sort keys. If any input section sorting is to be done, 269569112eddSAli Bahrami * we also set the FLG_OF_IS_ORDER flag on the output descriptor 269669112eddSAli Bahrami * to enable the code that does that work. 269769112eddSAli Bahrami */ 269869112eddSAli Bahrami 269969112eddSAli Bahrami /* Version 1: ?O flag? */ 270069112eddSAli Bahrami if (sgp->sg_flags & FLG_SG_IS_ORDER) { 270169112eddSAli Bahrami Word index = 0; 270269112eddSAli Bahrami 270369112eddSAli Bahrami ofl->ofl_flags |= FLG_OF_IS_ORDER; 270469112eddSAli Bahrami DBG_CALL(Dbg_map_ent_ord_title(ofl->ofl_lml, 270569112eddSAli Bahrami sgp->sg_name)); 270669112eddSAli Bahrami 270769112eddSAli Bahrami /* 270869112eddSAli Bahrami * Give each user defined entrance criteria for this 270969112eddSAli Bahrami * segment that specifies a section name a 271069112eddSAli Bahrami * monotonically increasing sort key. 271169112eddSAli Bahrami */ 271269112eddSAli Bahrami for (APLIST_TRAVERSE(ofl->ofl_ents, idx2, enp)) 271369112eddSAli Bahrami if ((enp->ec_segment == sgp) && 271469112eddSAli Bahrami (enp->ec_is_name != NULL) && 271569112eddSAli Bahrami ((enp->ec_flags & FLG_EC_BUILTIN) == 0)) 271669112eddSAli Bahrami enp->ec_ordndx = ++index; 271769112eddSAli Bahrami continue; 271869112eddSAli Bahrami } 271969112eddSAli Bahrami 272069112eddSAli Bahrami /* Version 2: SEGMENT IS_ORDER list? */ 272169112eddSAli Bahrami if (aplist_nitems(sgp->sg_is_order) > 0) { 272269112eddSAli Bahrami Word index = 0; 272369112eddSAli Bahrami 272469112eddSAli Bahrami ofl->ofl_flags |= FLG_OF_IS_ORDER; 272569112eddSAli Bahrami DBG_CALL(Dbg_map_ent_ord_title(ofl->ofl_lml, 272669112eddSAli Bahrami sgp->sg_name)); 272769112eddSAli Bahrami 272869112eddSAli Bahrami /* 272969112eddSAli Bahrami * Give each entrance criteria in the sg_is_order 273069112eddSAli Bahrami * list a monotonically increasing sort key. 273169112eddSAli Bahrami */ 273269112eddSAli Bahrami for (APLIST_TRAVERSE(sgp->sg_is_order, idx2, enp)) { 273369112eddSAli Bahrami enp->ec_ordndx = ++index; 273469112eddSAli Bahrami enp->ec_segment->sg_flags |= FLG_SG_IS_ORDER; 273569112eddSAli Bahrami } 273669112eddSAli Bahrami } 273769112eddSAli Bahrami } 273869112eddSAli Bahrami 273969112eddSAli Bahrami /* Sort the segment descriptors if necessary */ 274069112eddSAli Bahrami if (((ofl->ofl_flags1 & FLG_OF1_VADDR) || 274169112eddSAli Bahrami (aplist_nitems(ofl->ofl_segs_order) > 0)) && 274269112eddSAli Bahrami !sort_seg_list(ofl)) 274369112eddSAli Bahrami return (FALSE); 274469112eddSAli Bahrami 274569112eddSAli Bahrami /* 274669112eddSAli Bahrami * If the output file is a static file without an interpreter, and 274769112eddSAli Bahrami * if any virtual address is specified, then set the NOHDR flag for 274869112eddSAli Bahrami * backward compatibility. 274969112eddSAli Bahrami */ 275069112eddSAli Bahrami if (!(ofl->ofl_flags & (FLG_OF_DYNAMIC | FLG_OF_RELOBJ)) && 275169112eddSAli Bahrami !(ofl->ofl_osinterp) && (ofl->ofl_flags1 & FLG_OF1_VADDR)) 275269112eddSAli Bahrami ofl->ofl_dtflags_1 |= DF_1_NOHDR; 275369112eddSAli Bahrami 275469112eddSAli Bahrami if (ofl->ofl_flags & FLG_OF_RELOBJ) { 275569112eddSAli Bahrami /* 275669112eddSAli Bahrami * NOHDR has no effect on a relocatable file. 275769112eddSAli Bahrami * Make sure this flag isn't set. 275869112eddSAli Bahrami */ 275969112eddSAli Bahrami ofl->ofl_dtflags_1 &= ~DF_1_NOHDR; 276069112eddSAli Bahrami } else if (first_seg != NULL) { 276169112eddSAli Bahrami /* 276269112eddSAli Bahrami * DF_1_NOHDR might have been set globally by the HDR_NOALLOC 276369112eddSAli Bahrami * directive. If not, then we want to check the per-segment 276469112eddSAli Bahrami * flag for the first loadable segment and propagate it 276569112eddSAli Bahrami * if set. 276669112eddSAli Bahrami */ 276769112eddSAli Bahrami if ((ofl->ofl_dtflags_1 & DF_1_NOHDR) == 0) { 276869112eddSAli Bahrami /* 276969112eddSAli Bahrami * If we sorted the segments, the first segment 277069112eddSAli Bahrami * may have changed. 277169112eddSAli Bahrami */ 277269112eddSAli Bahrami if ((ofl->ofl_flags1 & FLG_OF1_VADDR) || 277369112eddSAli Bahrami (aplist_nitems(ofl->ofl_segs_order) > 0)) { 277469112eddSAli Bahrami for (APLIST_TRAVERSE(ofl->ofl_segs, idx, sgp)) { 277569112eddSAli Bahrami if (sgp->sg_name == NULL) 277669112eddSAli Bahrami continue; 277769112eddSAli Bahrami if ((sgp->sg_flags & FLG_SG_DISABLED) == 277869112eddSAli Bahrami 0) { 277969112eddSAli Bahrami first_seg = sgp; 278069112eddSAli Bahrami break; 278169112eddSAli Bahrami } 278269112eddSAli Bahrami } 278369112eddSAli Bahrami } 278469112eddSAli Bahrami 278569112eddSAli Bahrami /* 278669112eddSAli Bahrami * If the per-segment NOHDR flag is set on our first 278769112eddSAli Bahrami * segment, then make it take effect. 278869112eddSAli Bahrami */ 278969112eddSAli Bahrami if (first_seg->sg_flags & FLG_SG_NOHDR) 279069112eddSAli Bahrami ofl->ofl_dtflags_1 |= DF_1_NOHDR; 279169112eddSAli Bahrami } 279269112eddSAli Bahrami 279369112eddSAli Bahrami /* 279469112eddSAli Bahrami * For executable and shared objects, the first segment must 279569112eddSAli Bahrami * be loadable unless NOHDR was specified, because the ELF 279669112eddSAli Bahrami * header must simultaneously lie at offset 0 of the file and 279769112eddSAli Bahrami * be included in the first loadable segment. This isn't 279869112eddSAli Bahrami * possible if some other segment type starts the file 279969112eddSAli Bahrami */ 280069112eddSAli Bahrami if (!(ofl->ofl_dtflags_1 & DF_1_NOHDR) && 280169112eddSAli Bahrami (first_seg->sg_phdr.p_type != PT_LOAD)) { 280269112eddSAli Bahrami Conv_inv_buf_t inv_buf; 280369112eddSAli Bahrami 28041007fd6fSAli Bahrami ld_eprintf(ofl, ERR_FATAL, 280569112eddSAli Bahrami MSG_INTL(MSG_SEG_FIRNOTLOAD), 280669112eddSAli Bahrami conv_phdr_type(ELFOSABI_SOLARIS, ld_targ.t_m.m_mach, 280769112eddSAli Bahrami first_seg->sg_phdr.p_type, 0, &inv_buf), 280869112eddSAli Bahrami first_seg->sg_name); 280969112eddSAli Bahrami return (FALSE); 281069112eddSAli Bahrami } 281169112eddSAli Bahrami } 281269112eddSAli Bahrami 281369112eddSAli Bahrami /* 281469112eddSAli Bahrami * Mapfiles may have been used to create symbol definitions 281569112eddSAli Bahrami * with backing storage. Although the backing storage is 281669112eddSAli Bahrami * associated with an input section, the association of the 281769112eddSAli Bahrami * section to an output section (and segment) is initially 281869112eddSAli Bahrami * deferred. Now that all mapfile processing is complete, any 281969112eddSAli Bahrami * entrance criteria requirements have been processed, and 282069112eddSAli Bahrami * these backing storage sections can be associated with the 282169112eddSAli Bahrami * appropriate output section (and segment). 282269112eddSAli Bahrami */ 282369112eddSAli Bahrami if (ofl->ofl_maptext || ofl->ofl_mapdata) 282469112eddSAli Bahrami DBG_CALL(Dbg_sec_backing(ofl->ofl_lml)); 282569112eddSAli Bahrami 282669112eddSAli Bahrami for (APLIST_TRAVERSE(ofl->ofl_maptext, idx, isp)) { 282769112eddSAli Bahrami if (ld_place_section(ofl, isp, NULL, 282869112eddSAli Bahrami ld_targ.t_id.id_text, NULL) == (Os_desc *)S_ERROR) 282969112eddSAli Bahrami return (FALSE); 283069112eddSAli Bahrami } 283169112eddSAli Bahrami 283269112eddSAli Bahrami for (APLIST_TRAVERSE(ofl->ofl_mapdata, idx, isp)) { 283369112eddSAli Bahrami if (ld_place_section(ofl, isp, NULL, 283469112eddSAli Bahrami ld_targ.t_id.id_data, NULL) == (Os_desc *)S_ERROR) 283569112eddSAli Bahrami return (FALSE); 283669112eddSAli Bahrami } 283769112eddSAli Bahrami 283869112eddSAli Bahrami return (TRUE); 283969112eddSAli Bahrami } 2840