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.
2744bf619dSJohn Levon *
2844bf619dSJohn 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
1988222814eSRichard Lowe #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 */
4818222814eSRichard Lowe TK_LEFTSQR, /* 91 - [ */
48269112eddSAli Bahrami TK_OP_BADCHR, /* 92 - \ */
4838222814eSRichard Lowe TK_RIGHTSQR, /* 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
advance_to_eol(char ** str)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
null_patch_set(char * str,ld_map_npatch_t * np)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
null_patch_undo(ld_map_npatch_t * np)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
null_patch_eol(char * str,ld_map_npatch_t * np)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 *
ident_delimit(Mapfile * mf)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
stack_resize(generic_stack_t * stack,size_t n_default,size_t elt_size)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
cexp_ident_cmp(const void * n1,const void * n2)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
cexp_ident_test(const char * name)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
cexp_ident_add(Mapfile * mf,const char * name)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
844*fb12490aSRichard Lowe if ((node = libld_calloc(1, sizeof (*node))) == 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
cexp_ident_clear(Mapfile * mf,const char * name)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
cexp_ident_init(void)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
896*fb12490aSRichard Lowe lms.lms_cexp_id = libld_calloc(1, sizeof (*lms.lms_cexp_id));
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
cexp_ident_validate(Mapfile * mf,size_t * len,const char * directive)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
cexp_push_op(cexp_op_t op)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
cexp_eval_op(void)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
cexp_eval_expr(Mapfile * mf)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
cdir_process(Mapfile * mf)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
ld_map_lowercase(char * str)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
ld_map_strtoxword(const char * restrict str,char ** restrict endptr,Xword * ret_value)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
ld_map_getint(Mapfile * mf,ld_map_tkval_t * value,Boolean notail)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;
17148222814eSRichard Lowe char *startptr = mf->mf_next;
171569112eddSAli Bahrami char *errstr = mf->mf_next;
171669112eddSAli Bahrami
171769112eddSAli Bahrami value->tkv_int.tkvi_str = mf->mf_next;
171869112eddSAli Bahrami s2xw_ret = ld_map_strtoxword(mf->mf_next, &endptr,
171969112eddSAli Bahrami &value->tkv_int.tkvi_value);
172069112eddSAli Bahrami if (s2xw_ret != STRTOXWORD_OK) {
172169112eddSAli Bahrami null_patch_eol(mf->mf_next, &np);
172269112eddSAli Bahrami if (s2xw_ret == STRTOXWORD_TOOBIG)
172369112eddSAli Bahrami mf_fatal(mf, MSG_INTL(MSG_MAP_VALUELIMIT), errstr);
172469112eddSAli Bahrami else
172569112eddSAli Bahrami mf_fatal(mf, MSG_INTL(MSG_MAP_MALVALUE), errstr);
172669112eddSAli Bahrami null_patch_undo(&np);
172769112eddSAli Bahrami return (FALSE);
172869112eddSAli Bahrami }
172969112eddSAli Bahrami
173069112eddSAli Bahrami /* Advance position to item following value, skipping whitespace */
17318222814eSRichard Lowe value->tkv_int.tkvi_cnt = endptr - startptr;
173269112eddSAli Bahrami mf->mf_next = endptr;
17338222814eSRichard Lowe
173469112eddSAli Bahrami while (isspace_nonl(*mf->mf_next))
173569112eddSAli Bahrami mf->mf_next++;
173669112eddSAli Bahrami
173769112eddSAli Bahrami /* If requested, ensure there's nothing left */
173869112eddSAli Bahrami if (notail && (*mf->mf_next != '\n') && (*mf->mf_next != '#') &&
173969112eddSAli Bahrami (*mf->mf_next != '\0')) {
174069112eddSAli Bahrami null_patch_eol(mf->mf_next, &np);
174169112eddSAli Bahrami mf_fatal(mf, MSG_INTL(MSG_MAP_BADVALUETAIL), errstr);
174269112eddSAli Bahrami null_patch_undo(&np);
174369112eddSAli Bahrami return (FALSE);
174469112eddSAli Bahrami }
174569112eddSAli Bahrami
174669112eddSAli Bahrami return (TRUE);
174769112eddSAli Bahrami }
174869112eddSAli Bahrami
174969112eddSAli Bahrami /*
175069112eddSAli Bahrami * Convert a an unquoted identifier into a TK_STRING token, using the
175169112eddSAli Bahrami * rules for syntax version in use. Used exclusively by ld_map_gettoken().
175269112eddSAli Bahrami *
175369112eddSAli Bahrami * entry:
175469112eddSAli Bahrami * mf - Mapfile descriptor, positioned to the first character of
175569112eddSAli Bahrami * the string.
175669112eddSAli Bahrami * flags - Bitmask of options to control ld_map_gettoken()s behavior
175769112eddSAli Bahrami * tkv- Address of pointer to variable to receive token value.
175869112eddSAli Bahrami *
175969112eddSAli Bahrami * exit:
176069112eddSAli Bahrami * On success, mf is advanced past the token, tkv is updated with
176169112eddSAli Bahrami * the string, and TK_STRING is returned. On error, TK_ERROR is returned.
176269112eddSAli Bahrami */
176369112eddSAli Bahrami inline static Token
gettoken_ident(Mapfile * mf,int flags,ld_map_tkval_t * tkv)176469112eddSAli Bahrami gettoken_ident(Mapfile *mf, int flags, ld_map_tkval_t *tkv)
176569112eddSAli Bahrami {
176669112eddSAli Bahrami char *end;
176769112eddSAli Bahrami Token tok;
176869112eddSAli Bahrami ld_map_npatch_t np;
176969112eddSAli Bahrami
177069112eddSAli Bahrami tkv->tkv_str = mf->mf_next;
177169112eddSAli Bahrami if ((end = ident_delimit(mf)) == NULL)
177269112eddSAli Bahrami return (TK_ERROR);
177369112eddSAli Bahrami mf->mf_next = end;
177469112eddSAli Bahrami
177569112eddSAli Bahrami /*
177669112eddSAli Bahrami * One advantage of reading the entire mapfile into memory is that
177769112eddSAli Bahrami * we can access the strings within it without having to allocate
177869112eddSAli Bahrami * more memory or make copies. In order to do that, we need to NULL
177969112eddSAli Bahrami * terminate this identifier. That is going to overwrite the
178069112eddSAli Bahrami * following character. The problem this presents is that the next
178169112eddSAli Bahrami * character may well be the first character of a subsequent token.
178269112eddSAli Bahrami * The solution to this is:
178369112eddSAli Bahrami *
178469112eddSAli Bahrami * 1) Disallow the case where the next character is able to
178569112eddSAli Bahrami * start a string. This is not legal mapfile syntax anyway,
178669112eddSAli Bahrami * so catching it here simplifies matters.
178769112eddSAli Bahrami * 2) Copy the character into the special mf->mf_next_ch
178869112eddSAli Bahrami * 3) The next call to ld_map_gettoken() checks mf->mf_next_ch,
178969112eddSAli Bahrami * and if it is non-0, uses it instead of dereferencing the
179069112eddSAli Bahrami * mf_next pointer.
179169112eddSAli Bahrami */
179269112eddSAli Bahrami tok = (*mf->mf_next & 0x80) ?
1793*fb12490aSRichard Lowe TK_OP_ILLCHR : mf->mf_tokdisp[(unsigned)*mf->mf_next];
179469112eddSAli Bahrami switch (tok) {
179569112eddSAli Bahrami case TK_OP_BADCHR:
179669112eddSAli Bahrami null_patch_eol(mf->mf_next, &np);
179769112eddSAli Bahrami mf_fatal(mf, MSG_INTL(MSG_MAP_BADCHAR), mf->mf_next);
179869112eddSAli Bahrami null_patch_undo(&np);
179969112eddSAli Bahrami return (TK_ERROR);
180069112eddSAli Bahrami
180169112eddSAli Bahrami case TK_OP_SIMQUOTE:
180269112eddSAli Bahrami case TK_OP_CQUOTE:
180369112eddSAli Bahrami case TK_OP_CDIR:
180469112eddSAli Bahrami case TK_OP_NUM:
180569112eddSAli Bahrami case TK_OP_ID:
180669112eddSAli Bahrami null_patch_eol(mf->mf_next, &np);
180769112eddSAli Bahrami mf_fatal(mf, MSG_INTL(MSG_MAP_WSNEEDED), mf->mf_next);
180869112eddSAli Bahrami null_patch_undo(&np);
180969112eddSAli Bahrami return (TK_ERROR);
181069112eddSAli Bahrami }
181169112eddSAli Bahrami
181269112eddSAli Bahrami /* Null terminate, saving the replaced character */
181369112eddSAli Bahrami mf->mf_next_ch = *mf->mf_next;
181469112eddSAli Bahrami *mf->mf_next = '\0';
181569112eddSAli Bahrami
181669112eddSAli Bahrami if (flags & TK_F_STRLC)
181769112eddSAli Bahrami ld_map_lowercase(tkv->tkv_str);
181869112eddSAli Bahrami return (TK_STRING);
181969112eddSAli Bahrami }
182069112eddSAli Bahrami
182169112eddSAli Bahrami /*
182269112eddSAli Bahrami * Convert a quoted string into a TK_STRING token, using simple
182369112eddSAli Bahrami * quoting rules:
182469112eddSAli Bahrami * - Start and end quotes must be present and match
182569112eddSAli Bahrami * - There are no special characters or escape sequences.
182669112eddSAli Bahrami * This function is used exclusively by ld_map_gettoken().
182769112eddSAli Bahrami *
182869112eddSAli Bahrami * entry:
182969112eddSAli Bahrami * mf - Mapfile descriptor, positioned to the opening quote character.
183069112eddSAli Bahrami * flags - Bitmask of options to control ld_map_gettoken()s behavior
183169112eddSAli Bahrami * tkv- Address of pointer to variable to receive token value.
183269112eddSAli Bahrami *
183369112eddSAli Bahrami * exit:
183469112eddSAli Bahrami * On success, mf is advanced past the token, tkv is updated with
183569112eddSAli Bahrami * the string, and TK_STRING is returned. On error, TK_ERROR is returned.
183669112eddSAli Bahrami */
183769112eddSAli Bahrami inline static Token
gettoken_simquote_str(Mapfile * mf,int flags,ld_map_tkval_t * tkv)183869112eddSAli Bahrami gettoken_simquote_str(Mapfile *mf, int flags, ld_map_tkval_t *tkv)
183969112eddSAli Bahrami {
184069112eddSAli Bahrami char *str, *end;
184169112eddSAli Bahrami char quote;
184269112eddSAli Bahrami
184369112eddSAli Bahrami str = mf->mf_next++;
184469112eddSAli Bahrami quote = *str;
184569112eddSAli Bahrami end = mf->mf_next;
184669112eddSAli Bahrami while ((*end != '\0') && (*end != '\n') && (*end != quote))
184769112eddSAli Bahrami end++;
184869112eddSAli Bahrami if (*end != quote) {
184969112eddSAli Bahrami ld_map_npatch_t np;
185069112eddSAli Bahrami
185169112eddSAli Bahrami null_patch_eol(end, &np);
185269112eddSAli Bahrami mf_fatal(mf, MSG_INTL(MSG_MAP_NOTERM), str);
185369112eddSAli Bahrami null_patch_undo(&np);
185469112eddSAli Bahrami return (TK_ERROR);
185569112eddSAli Bahrami }
185669112eddSAli Bahrami
185769112eddSAli Bahrami /*
185869112eddSAli Bahrami * end is pointing at the closing quote. We can turn that into NULL
185969112eddSAli Bahrami * termination for the string without needing to restore it later.
186069112eddSAli Bahrami */
186169112eddSAli Bahrami *end = '\0';
186269112eddSAli Bahrami mf->mf_next = end + 1;
186369112eddSAli Bahrami tkv->tkv_str = str + 1; /* Skip opening quote */
186469112eddSAli Bahrami if (flags & TK_F_STRLC)
186569112eddSAli Bahrami ld_map_lowercase(tkv->tkv_str);
186669112eddSAli Bahrami return (TK_STRING);
186769112eddSAli Bahrami }
186869112eddSAli Bahrami
186969112eddSAli Bahrami /*
187069112eddSAli Bahrami * Convert a quoted string into a TK_STRING token, using C string literal
187169112eddSAli Bahrami * quoting rules:
187269112eddSAli Bahrami * - Start and end quotes must be present and match
187369112eddSAli Bahrami * - Backslash is an escape, used to introduce special characters
187469112eddSAli Bahrami * This function is used exclusively by ld_map_gettoken().
187569112eddSAli Bahrami *
187669112eddSAli Bahrami * entry:
187769112eddSAli Bahrami * mf - Mapfile descriptor, positioned to the opening quote character.
187869112eddSAli Bahrami * flags - Bitmask of options to control ld_map_gettoken()s behavior
187969112eddSAli Bahrami * tkv- Address of pointer to variable to receive token value.
188069112eddSAli Bahrami *
188169112eddSAli Bahrami * exit:
188269112eddSAli Bahrami * On success, mf is advanced past the token, tkv is updated with
188369112eddSAli Bahrami * the string, and TK_STRING is returned. On error, TK_ERROR is returned.
188469112eddSAli Bahrami */
188569112eddSAli Bahrami inline static Token
gettoken_cquote_str(Mapfile * mf,int flags,ld_map_tkval_t * tkv)188669112eddSAli Bahrami gettoken_cquote_str(Mapfile *mf, int flags, ld_map_tkval_t *tkv)
188769112eddSAli Bahrami {
188869112eddSAli Bahrami char *str, *cur, *end;
188969112eddSAli Bahrami char quote;
189069112eddSAli Bahrami int c;
189169112eddSAli Bahrami
189269112eddSAli Bahrami /*
189369112eddSAli Bahrami * This function goes through the quoted string and copies
189469112eddSAli Bahrami * it on top of itself, replacing escape sequences with the
189569112eddSAli Bahrami * characters they denote. There is always enough room for this,
189669112eddSAli Bahrami * because escapes are multi-character sequences that are converted
189769112eddSAli Bahrami * to single character results.
189869112eddSAli Bahrami */
189969112eddSAli Bahrami str = mf->mf_next++;
190069112eddSAli Bahrami quote = *str;
190169112eddSAli Bahrami cur = end = mf->mf_next;
190269112eddSAli Bahrami for (c = *end++; (c != '\0') && (c != '\n') && (c != quote);
190369112eddSAli Bahrami c = *end++) {
190469112eddSAli Bahrami if (c == '\\') {
190569112eddSAli Bahrami c = conv_translate_c_esc(&end);
190669112eddSAli Bahrami if (c == -1) {
190769112eddSAli Bahrami mf_fatal(mf, MSG_INTL(MSG_MAP_BADCESC), *end);
190869112eddSAli Bahrami return (TK_ERROR);
190969112eddSAli Bahrami }
191069112eddSAli Bahrami }
191169112eddSAli Bahrami *cur++ = c;
191269112eddSAli Bahrami }
191369112eddSAli Bahrami *cur = '\0'; /* terminate the result */
191469112eddSAli Bahrami if (c != quote) {
191569112eddSAli Bahrami ld_map_npatch_t np;
191669112eddSAli Bahrami
191769112eddSAli Bahrami null_patch_eol(end, &np);
191869112eddSAli Bahrami mf_fatal(mf, MSG_INTL(MSG_MAP_NOTERM), str);
191969112eddSAli Bahrami null_patch_undo(&np);
192069112eddSAli Bahrami return (TK_ERROR);
192169112eddSAli Bahrami }
192269112eddSAli Bahrami
192369112eddSAli Bahrami /* end is pointing one character past the closing quote */
192469112eddSAli Bahrami mf->mf_next = end;
192569112eddSAli Bahrami tkv->tkv_str = str + 1; /* Skip opening quote */
192669112eddSAli Bahrami if (flags & TK_F_STRLC)
192769112eddSAli Bahrami ld_map_lowercase(tkv->tkv_str);
192869112eddSAli Bahrami return (TK_STRING);
192969112eddSAli Bahrami }
193069112eddSAli Bahrami
19318222814eSRichard Lowe /*
19328222814eSRichard Lowe * Peek ahead at the text token.
19338222814eSRichard Lowe *
19348222814eSRichard Lowe * entry:
19358222814eSRichard Lowe * mf - Mapfile descriptor
19368222814eSRichard Lowe *
19378222814eSRichard Lowe * exit:
19388222814eSRichard Lowe * Returns one of the TK_* values, including the TK_OP values (that is,
19398222814eSRichard Lowe * tokens are not processed into their necessarily final form).
19408222814eSRichard Lowe */
19418222814eSRichard Lowe Token
ld_map_peektoken(Mapfile * mf)19428222814eSRichard Lowe ld_map_peektoken(Mapfile *mf)
19438222814eSRichard Lowe {
19448222814eSRichard Lowe int ch;
19458222814eSRichard Lowe
19468222814eSRichard Lowe if (mf->mf_next_ch == 0)
19478222814eSRichard Lowe ch = *mf->mf_next;
19488222814eSRichard Lowe else
19498222814eSRichard Lowe ch = mf->mf_next_ch;
19508222814eSRichard Lowe
19518222814eSRichard Lowe return ((ch & 0x80) ? TK_OP_ILLCHR : mf->mf_tokdisp[ch]);
19528222814eSRichard Lowe }
19538222814eSRichard Lowe
195469112eddSAli Bahrami /*
195569112eddSAli Bahrami * Get a token from the mapfile.
195669112eddSAli Bahrami *
195769112eddSAli Bahrami * entry:
195869112eddSAli Bahrami * mf - Mapfile descriptor
195969112eddSAli Bahrami * flags - Bitmask of options to control ld_map_gettoken()s behavior
196069112eddSAli Bahrami * tkv- Address of pointer to variable to receive token value.
196169112eddSAli Bahrami *
196269112eddSAli Bahrami * exit:
196369112eddSAli Bahrami * Returns one of the TK_* values, to report the result. If the resulting
196469112eddSAli Bahrami * token has a value (TK_STRING / TK_INT), and tkv is non-NULL, tkv
196569112eddSAli Bahrami * is filled in with the resulting value.
196669112eddSAli Bahrami */
196769112eddSAli Bahrami Token
ld_map_gettoken(Mapfile * mf,int flags,ld_map_tkval_t * tkv)196869112eddSAli Bahrami ld_map_gettoken(Mapfile *mf, int flags, ld_map_tkval_t *tkv)
196969112eddSAli Bahrami {
197069112eddSAli Bahrami int cdir_allow, ch;
197169112eddSAli Bahrami Token tok;
197269112eddSAli Bahrami ld_map_npatch_t np;
197369112eddSAli Bahrami
197469112eddSAli Bahrami /*
197569112eddSAli Bahrami * Mapfile control directives all start with a '$' character. However,
197669112eddSAli Bahrami * they are only valid when they are the first thing on a line. That
197769112eddSAli Bahrami * happens on the first call to ld_map_gettoken() for a new a new
197869112eddSAli Bahrami * mapfile, as tracked with lms.lms_cdir_valid, and immediately
197969112eddSAli Bahrami * following each newline seen in the file.
198069112eddSAli Bahrami */
198169112eddSAli Bahrami cdir_allow = lms.lms_cdir_valid;
198269112eddSAli Bahrami lms.lms_cdir_valid = 0;
198369112eddSAli Bahrami
198469112eddSAli Bahrami /* Cycle through the characters looking for tokens. */
198569112eddSAli Bahrami for (;;) {
198669112eddSAli Bahrami /*
198769112eddSAli Bahrami * Process the next character. This is normally *mf->mf_next,
198869112eddSAli Bahrami * but if mf->mf_next_ch is non-0, then it contains the
198969112eddSAli Bahrami * character, and *mf->mf_next contains a NULL termination
199069112eddSAli Bahrami * from the TK_STRING token returned on the previous call.
199169112eddSAli Bahrami *
199269112eddSAli Bahrami * gettoken_ident() ensures that this is never done to
199369112eddSAli Bahrami * a character that starts a string.
199469112eddSAli Bahrami */
199569112eddSAli Bahrami if (mf->mf_next_ch == 0) {
199669112eddSAli Bahrami ch = *mf->mf_next;
199769112eddSAli Bahrami } else {
199869112eddSAli Bahrami ch = mf->mf_next_ch;
199969112eddSAli Bahrami mf->mf_next_ch = 0; /* Reset */
200069112eddSAli Bahrami }
200169112eddSAli Bahrami
200269112eddSAli Bahrami /* Map the character to a dispatch action */
200369112eddSAli Bahrami tok = (ch & 0x80) ? TK_OP_ILLCHR : mf->mf_tokdisp[ch];
200469112eddSAli Bahrami
200569112eddSAli Bahrami /*
200669112eddSAli Bahrami * Items that require processing are identified as OP tokens.
200769112eddSAli Bahrami * We process them, and return a result non-OP token.
200869112eddSAli Bahrami *
200969112eddSAli Bahrami * Non-OP tokens are single character tokens, and we return
201069112eddSAli Bahrami * them immediately.
201169112eddSAli Bahrami */
201269112eddSAli Bahrami switch (tok) {
201369112eddSAli Bahrami case TK_OP_EOF:
201469112eddSAli Bahrami /* If EOFOK is set, quietly report it as TK_EOF */
201569112eddSAli Bahrami if ((flags & TK_F_EOFOK) != 0)
201669112eddSAli Bahrami return (TK_EOF);
201769112eddSAli Bahrami
201869112eddSAli Bahrami /* Treat it as a standard error */
201969112eddSAli Bahrami mf_fatal0(mf, MSG_INTL(MSG_MAP_PREMEOF));
202069112eddSAli Bahrami return (TK_ERROR);
202169112eddSAli Bahrami
202269112eddSAli Bahrami case TK_OP_ILLCHR:
202369112eddSAli Bahrami mf_fatal(mf, MSG_INTL(MSG_MAP_ILLCHAR), ch);
202469112eddSAli Bahrami mf->mf_next++;
202569112eddSAli Bahrami return (TK_ERROR);
202669112eddSAli Bahrami
202769112eddSAli Bahrami case TK_OP_BADCHR:
202869112eddSAli Bahrami tk_op_badchr:
202969112eddSAli Bahrami null_patch_eol(mf->mf_next, &np);
203069112eddSAli Bahrami mf_fatal(mf, MSG_INTL(MSG_MAP_BADCHAR), mf->mf_next);
203169112eddSAli Bahrami null_patch_undo(&np);
203269112eddSAli Bahrami mf->mf_next++;
203369112eddSAli Bahrami return (TK_ERROR);
203469112eddSAli Bahrami
203569112eddSAli Bahrami case TK_OP_WS: /* White space */
203669112eddSAli Bahrami mf->mf_next++;
203769112eddSAli Bahrami break;
203869112eddSAli Bahrami
203969112eddSAli Bahrami case TK_OP_NL: /* White space too, but bump line number. */
204069112eddSAli Bahrami mf->mf_next++;
204169112eddSAli Bahrami mf->mf_lineno++;
204269112eddSAli Bahrami cdir_allow = 1;
204369112eddSAli Bahrami break;
204469112eddSAli Bahrami
204569112eddSAli Bahrami case TK_OP_SIMQUOTE:
204669112eddSAli Bahrami if (flags & TK_F_KEYWORD)
204769112eddSAli Bahrami goto tk_op_badkwquote;
204869112eddSAli Bahrami return (gettoken_simquote_str(mf, flags, tkv));
204969112eddSAli Bahrami
205069112eddSAli Bahrami case TK_OP_CQUOTE:
205169112eddSAli Bahrami if (flags & TK_F_KEYWORD) {
205269112eddSAli Bahrami tk_op_badkwquote:
205369112eddSAli Bahrami null_patch_eol(mf->mf_next, &np);
205469112eddSAli Bahrami mf_fatal(mf, MSG_INTL(MSG_MAP_BADKWQUOTE),
205569112eddSAli Bahrami mf->mf_next);
205669112eddSAli Bahrami null_patch_undo(&np);
205769112eddSAli Bahrami mf->mf_next++;
205869112eddSAli Bahrami return (TK_ERROR);
205969112eddSAli Bahrami }
206069112eddSAli Bahrami return (gettoken_cquote_str(mf, flags, tkv));
206169112eddSAli Bahrami
206269112eddSAli Bahrami case TK_OP_CMT:
206369112eddSAli Bahrami advance_to_eol(&mf->mf_next);
206469112eddSAli Bahrami break;
206569112eddSAli Bahrami
206669112eddSAli Bahrami case TK_OP_CDIR:
206769112eddSAli Bahrami /*
206869112eddSAli Bahrami * Control directives are only valid at the start
206969112eddSAli Bahrami * of a line.
207069112eddSAli Bahrami */
207169112eddSAli Bahrami if (!cdir_allow) {
207269112eddSAli Bahrami null_patch_eol(mf->mf_next, &np);
207369112eddSAli Bahrami mf_fatal(mf, MSG_INTL(MSG_MAP_CDIR_NOTBOL),
207469112eddSAli Bahrami mf->mf_next);
207569112eddSAli Bahrami null_patch_undo(&np);
207669112eddSAli Bahrami mf->mf_next++;
207769112eddSAli Bahrami return (TK_ERROR);
207869112eddSAli Bahrami }
207969112eddSAli Bahrami if (!cdir_process(mf))
208069112eddSAli Bahrami return (TK_ERROR);
208169112eddSAli Bahrami break;
208269112eddSAli Bahrami
208369112eddSAli Bahrami case TK_OP_NUM: /* Decimal, hex(0x...), or octal (0...) value */
208469112eddSAli Bahrami if (!ld_map_getint(mf, tkv, FALSE))
208569112eddSAli Bahrami return (TK_ERROR);
208669112eddSAli Bahrami return (TK_INT);
208769112eddSAli Bahrami
208869112eddSAli Bahrami case TK_OP_ID: /* Unquoted identifier */
208969112eddSAli Bahrami return (gettoken_ident(mf, flags, tkv));
209069112eddSAli Bahrami
209169112eddSAli Bahrami case TK_OP_CEQUAL: /* += or -= */
209269112eddSAli Bahrami if (*(mf->mf_next + 1) != '=')
209369112eddSAli Bahrami goto tk_op_badchr;
209469112eddSAli Bahrami tok = (ch == '+') ? TK_PLUSEQ : TK_MINUSEQ;
209569112eddSAli Bahrami mf->mf_next += 2;
209669112eddSAli Bahrami return (tok);
209769112eddSAli Bahrami
209869112eddSAli Bahrami default: /* Non-OP token */
209969112eddSAli Bahrami mf->mf_next++;
210069112eddSAli Bahrami return (tok);
210169112eddSAli Bahrami }
210269112eddSAli Bahrami }
210369112eddSAli Bahrami }
210469112eddSAli Bahrami
210569112eddSAli Bahrami /*
210669112eddSAli Bahrami * Given a token and value returned by ld_map_gettoken(), return a string
210769112eddSAli Bahrami * representation of it suitable for use in an error message.
210869112eddSAli Bahrami *
210969112eddSAli Bahrami * entry:
211069112eddSAli Bahrami * tok - Token code. Must not be an OP-token
211169112eddSAli Bahrami * tkv - Token value
211269112eddSAli Bahrami */
211369112eddSAli Bahrami const char *
ld_map_tokenstr(Token tok,ld_map_tkval_t * tkv,Conv_inv_buf_t * inv_buf)211469112eddSAli Bahrami ld_map_tokenstr(Token tok, ld_map_tkval_t *tkv, Conv_inv_buf_t *inv_buf)
211569112eddSAli Bahrami {
211669112eddSAli Bahrami size_t cnt;
211769112eddSAli Bahrami
211869112eddSAli Bahrami switch (tok) {
211969112eddSAli Bahrami case TK_ERROR:
212069112eddSAli Bahrami return (MSG_ORIG(MSG_STR_ERROR));
212169112eddSAli Bahrami case TK_EOF:
212269112eddSAli Bahrami return (MSG_ORIG(MSG_STR_EOF));
212369112eddSAli Bahrami case TK_STRING:
212469112eddSAli Bahrami return (tkv->tkv_str);
212569112eddSAli Bahrami case TK_COLON:
212669112eddSAli Bahrami return (MSG_ORIG(MSG_QSTR_COLON));
212769112eddSAli Bahrami case TK_SEMICOLON:
212869112eddSAli Bahrami return (MSG_ORIG(MSG_QSTR_SEMICOLON));
212969112eddSAli Bahrami case TK_EQUAL:
213069112eddSAli Bahrami return (MSG_ORIG(MSG_QSTR_EQUAL));
213169112eddSAli Bahrami case TK_PLUSEQ:
213269112eddSAli Bahrami return (MSG_ORIG(MSG_QSTR_PLUSEQ));
213369112eddSAli Bahrami case TK_MINUSEQ:
213469112eddSAli Bahrami return (MSG_ORIG(MSG_QSTR_MINUSEQ));
213569112eddSAli Bahrami case TK_ATSIGN:
213669112eddSAli Bahrami return (MSG_ORIG(MSG_QSTR_ATSIGN));
213769112eddSAli Bahrami case TK_DASH:
213869112eddSAli Bahrami return (MSG_ORIG(MSG_QSTR_DASH));
213969112eddSAli Bahrami case TK_LEFTBKT:
214069112eddSAli Bahrami return (MSG_ORIG(MSG_QSTR_LEFTBKT));
214169112eddSAli Bahrami case TK_RIGHTBKT:
214269112eddSAli Bahrami return (MSG_ORIG(MSG_QSTR_RIGHTBKT));
21438222814eSRichard Lowe case TK_LEFTSQR:
21448222814eSRichard Lowe return (MSG_ORIG(MSG_QSTR_LEFTSQR));
21458222814eSRichard Lowe case TK_RIGHTSQR:
21468222814eSRichard Lowe return (MSG_ORIG(MSG_QSTR_RIGHTSQR));
214769112eddSAli Bahrami case TK_PIPE:
214869112eddSAli Bahrami return (MSG_ORIG(MSG_QSTR_PIPE));
214969112eddSAli Bahrami case TK_INT:
215069112eddSAli Bahrami cnt = tkv->tkv_int.tkvi_cnt;
215169112eddSAli Bahrami if (cnt >= sizeof (inv_buf->buf))
215269112eddSAli Bahrami cnt = sizeof (inv_buf->buf) - 1;
215369112eddSAli Bahrami (void) memcpy(inv_buf->buf, tkv->tkv_int.tkvi_str, cnt);
215469112eddSAli Bahrami inv_buf->buf[cnt] = '\0';
215569112eddSAli Bahrami return (inv_buf->buf);
215669112eddSAli Bahrami case TK_STAR:
215769112eddSAli Bahrami return (MSG_ORIG(MSG_QSTR_STAR));
215869112eddSAli Bahrami case TK_BANG:
215969112eddSAli Bahrami return (MSG_ORIG(MSG_QSTR_BANG));
216069112eddSAli Bahrami default:
216169112eddSAli Bahrami assert(0);
216269112eddSAli Bahrami break;
216369112eddSAli Bahrami }
216469112eddSAli Bahrami
216569112eddSAli Bahrami /*NOTREACHED*/
216669112eddSAli Bahrami return (MSG_INTL(MSG_MAP_INTERR));
216769112eddSAli Bahrami }
216869112eddSAli Bahrami
216969112eddSAli Bahrami /*
217069112eddSAli Bahrami * Advance the input to the first non-empty line, and determine
217169112eddSAli Bahrami * the mapfile version. The version is specified by the mapfile
217269112eddSAli Bahrami * using a $mapfile_version directive. The original System V
217369112eddSAli Bahrami * syntax lacks this directive, and we use that fact to identify
217469112eddSAli Bahrami * such files. SysV mapfile are implicitly defined to have version 1.
217569112eddSAli Bahrami *
217669112eddSAli Bahrami * entry:
217769112eddSAli Bahrami * ofl - Output file descriptor
217869112eddSAli Bahrami * mf - Mapfile block
217969112eddSAli Bahrami *
218069112eddSAli Bahrami * exit:
218169112eddSAli Bahrami * On success, updates mf->mf_version, and returns TRUE (1).
218269112eddSAli Bahrami * On failure, returns FALSE (0).
218369112eddSAli Bahrami */
218469112eddSAli Bahrami static Boolean
mapfile_version(Mapfile * mf)218569112eddSAli Bahrami mapfile_version(Mapfile *mf)
218669112eddSAli Bahrami {
218769112eddSAli Bahrami char *line_start = mf->mf_next;
218869112eddSAli Bahrami Boolean cont = TRUE;
218969112eddSAli Bahrami Boolean status = TRUE; /* Assume success */
219069112eddSAli Bahrami Token tok;
219169112eddSAli Bahrami
219269112eddSAli Bahrami mf->mf_version = MFV_SYSV;
219369112eddSAli Bahrami
219469112eddSAli Bahrami /*
219569112eddSAli Bahrami * Cycle through the characters looking for tokens. Although the
219669112eddSAli Bahrami * true version is not known yet, we use the v2 dispatch table.
219769112eddSAli Bahrami * It contains control directives, which we need for this search,
219869112eddSAli Bahrami * and the other TK_OP_ tokens we will recognize and act on are the
219969112eddSAli Bahrami * same for both tables.
220069112eddSAli Bahrami *
220169112eddSAli Bahrami * It is important not to process any tokens that would lead to
220269112eddSAli Bahrami * a non-OP token:
220369112eddSAli Bahrami *
220469112eddSAli Bahrami * - The version is required to interpret them
220569112eddSAli Bahrami * - Our mapfile descriptor is not fully initialized,
220669112eddSAli Bahrami * attempts to run that code will crash the program.
220769112eddSAli Bahrami */
220869112eddSAli Bahrami while (cont) {
220969112eddSAli Bahrami /* Map the character to a dispatch action */
221069112eddSAli Bahrami tok = (*mf->mf_next & 0x80) ?
2211*fb12490aSRichard Lowe TK_OP_ILLCHR : gettok_dispatch_v2[(unsigned)*mf->mf_next];
221269112eddSAli Bahrami
221369112eddSAli Bahrami switch (tok) {
221469112eddSAli Bahrami case TK_OP_WS: /* White space */
221569112eddSAli Bahrami mf->mf_next++;
221669112eddSAli Bahrami break;
221769112eddSAli Bahrami
221869112eddSAli Bahrami case TK_OP_NL: /* White space too, but bump line number. */
221969112eddSAli Bahrami mf->mf_next++;
222069112eddSAli Bahrami mf->mf_lineno++;
222169112eddSAli Bahrami break;
222269112eddSAli Bahrami
222369112eddSAli Bahrami case TK_OP_CMT:
222469112eddSAli Bahrami advance_to_eol(&mf->mf_next);
222569112eddSAli Bahrami break;
222669112eddSAli Bahrami
222769112eddSAli Bahrami case TK_OP_CDIR:
222869112eddSAli Bahrami /*
222969112eddSAli Bahrami * Control directives are only valid at the start
223069112eddSAli Bahrami * of a line. However, as we have not yet seen
223169112eddSAli Bahrami * a token, we do not need to test for this, and
223269112eddSAli Bahrami * can safely assume that we are at the start.
223369112eddSAli Bahrami */
223469112eddSAli Bahrami if (!strncasecmp(mf->mf_next,
223569112eddSAli Bahrami MSG_ORIG(MSG_STR_CDIR_MFVER),
223669112eddSAli Bahrami MSG_STR_CDIR_MFVER_SIZE) &&
223769112eddSAli Bahrami isspace_nonl(*(mf->mf_next +
223869112eddSAli Bahrami MSG_STR_CDIR_MFVER_SIZE))) {
223969112eddSAli Bahrami ld_map_tkval_t ver;
224069112eddSAli Bahrami
224169112eddSAli Bahrami mf->mf_next += MSG_STR_CDIR_MFVER_SIZE + 1;
224269112eddSAli Bahrami if (!ld_map_getint(mf, &ver, TRUE)) {
224369112eddSAli Bahrami status = cont = FALSE;
224469112eddSAli Bahrami break;
224569112eddSAli Bahrami }
224669112eddSAli Bahrami /*
224769112eddSAli Bahrami * Is it a valid version? Note that we
224869112eddSAli Bahrami * intentionally do not allow you to
224969112eddSAli Bahrami * specify version 1 using the $mapfile_version
225069112eddSAli Bahrami * syntax, because that's reserved to version
225169112eddSAli Bahrami * 2 and up.
225269112eddSAli Bahrami */
225369112eddSAli Bahrami if ((ver.tkv_int.tkvi_value < 2) ||
225469112eddSAli Bahrami (ver.tkv_int.tkvi_value >= MFV_NUM)) {
225569112eddSAli Bahrami const char *fmt;
225669112eddSAli Bahrami
225769112eddSAli Bahrami fmt = (ver.tkv_int.tkvi_value < 2) ?
225869112eddSAli Bahrami MSG_INTL(MSG_MAP_CDIR_BADVDIR) :
225969112eddSAli Bahrami MSG_INTL(MSG_MAP_CDIR_BADVER);
226069112eddSAli Bahrami mf_fatal(mf, fmt,
226169112eddSAli Bahrami EC_WORD(ver.tkv_int.tkvi_value));
226269112eddSAli Bahrami status = cont = FALSE;
226369112eddSAli Bahrami break;
226469112eddSAli Bahrami }
226569112eddSAli Bahrami mf->mf_version = ver.tkv_int.tkvi_value;
226669112eddSAli Bahrami cont = FALSE; /* Version recovered. All done */
226769112eddSAli Bahrami break;
226869112eddSAli Bahrami }
226969112eddSAli Bahrami /*
227069112eddSAli Bahrami * Not a version directive. Reset the current position
227169112eddSAli Bahrami * to the start of the current line and stop here.
227269112eddSAli Bahrami * SysV syntax applies.
227369112eddSAli Bahrami */
227469112eddSAli Bahrami mf->mf_next = line_start;
227569112eddSAli Bahrami cont = FALSE;
227669112eddSAli Bahrami break;
227769112eddSAli Bahrami
227869112eddSAli Bahrami default:
227969112eddSAli Bahrami /*
228069112eddSAli Bahrami * If we see anything else, then stop at this point.
228169112eddSAli Bahrami * The file has System V syntax (version 1), and the
228269112eddSAli Bahrami * next token should be interpreted as such.
228369112eddSAli Bahrami */
228469112eddSAli Bahrami cont = FALSE;
228569112eddSAli Bahrami break;
228669112eddSAli Bahrami }
228769112eddSAli Bahrami }
228869112eddSAli Bahrami
228969112eddSAli Bahrami return (status);
229069112eddSAli Bahrami }
229169112eddSAli Bahrami
229269112eddSAli Bahrami /*
229369112eddSAli Bahrami * Parse the mapfile.
229469112eddSAli Bahrami */
229569112eddSAli Bahrami Boolean
ld_map_parse(const char * mapfile,Ofl_desc * ofl)229669112eddSAli Bahrami ld_map_parse(const char *mapfile, Ofl_desc *ofl)
229769112eddSAli Bahrami {
229869112eddSAli Bahrami struct stat stat_buf; /* stat of mapfile */
229969112eddSAli Bahrami int mapfile_fd; /* descriptor for mapfile */
230069112eddSAli Bahrami int err;
230169112eddSAli Bahrami Mapfile *mf; /* Mapfile descriptor */
230269112eddSAli Bahrami size_t name_len; /* strlen(mapfile) */
230369112eddSAli Bahrami
230469112eddSAli Bahrami /*
230569112eddSAli Bahrami * Determine if we're dealing with a file or a directory.
230669112eddSAli Bahrami */
230769112eddSAli Bahrami if (stat(mapfile, &stat_buf) == -1) {
230869112eddSAli Bahrami err = errno;
23091007fd6fSAli Bahrami ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_SYS_STAT), mapfile,
23101007fd6fSAli Bahrami strerror(err));
231169112eddSAli Bahrami return (FALSE);
231269112eddSAli Bahrami }
231369112eddSAli Bahrami if (S_ISDIR(stat_buf.st_mode)) {
231469112eddSAli Bahrami DIR *dirp;
231569112eddSAli Bahrami struct dirent *denp;
231669112eddSAli Bahrami
231769112eddSAli Bahrami /*
231869112eddSAli Bahrami * Open the directory and interpret each visible file as a
231969112eddSAli Bahrami * mapfile.
232069112eddSAli Bahrami */
232169112eddSAli Bahrami if ((dirp = opendir(mapfile)) == NULL)
232269112eddSAli Bahrami return (TRUE);
232369112eddSAli Bahrami
232469112eddSAli Bahrami while ((denp = readdir(dirp)) != NULL) {
232569112eddSAli Bahrami char path[PATH_MAX];
232669112eddSAli Bahrami
232769112eddSAli Bahrami /*
232869112eddSAli Bahrami * Ignore any hidden filenames. Construct the full
232969112eddSAli Bahrami * pathname to the new mapfile.
233069112eddSAli Bahrami */
233169112eddSAli Bahrami if (*denp->d_name == '.')
233269112eddSAli Bahrami continue;
233369112eddSAli Bahrami (void) snprintf(path, PATH_MAX, MSG_ORIG(MSG_STR_PATH),
233469112eddSAli Bahrami mapfile, denp->d_name);
233569112eddSAli Bahrami if (!ld_map_parse(path, ofl))
233669112eddSAli Bahrami return (FALSE);
233769112eddSAli Bahrami }
233869112eddSAli Bahrami (void) closedir(dirp);
233969112eddSAli Bahrami return (TRUE);
234069112eddSAli Bahrami } else if (!S_ISREG(stat_buf.st_mode)) {
23411007fd6fSAli Bahrami ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_SYS_NOTREG), mapfile);
234269112eddSAli Bahrami return (FALSE);
234369112eddSAli Bahrami }
234469112eddSAli Bahrami
234569112eddSAli Bahrami /* Open file */
234669112eddSAli Bahrami if ((mapfile_fd = open(mapfile, O_RDONLY)) == -1) {
234769112eddSAli Bahrami err = errno;
23481007fd6fSAli Bahrami ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN), mapfile,
23491007fd6fSAli Bahrami strerror(err));
235069112eddSAli Bahrami return (FALSE);
235169112eddSAli Bahrami }
235269112eddSAli Bahrami
235369112eddSAli Bahrami /*
235469112eddSAli Bahrami * Allocate enough memory to hold the state block, mapfile name,
235569112eddSAli Bahrami * and mapfile text. Text has alignment 1, so it can follow the
235669112eddSAli Bahrami * state block without padding.
235769112eddSAli Bahrami */
235869112eddSAli Bahrami name_len = strlen(mapfile) + 1;
235969112eddSAli Bahrami mf = libld_malloc(sizeof (*mf) + name_len + stat_buf.st_size + 1);
236069112eddSAli Bahrami if (mf == NULL)
236169112eddSAli Bahrami return (FALSE);
236269112eddSAli Bahrami mf->mf_ofl = ofl;
236369112eddSAli Bahrami mf->mf_name = (char *)(mf + 1);
236469112eddSAli Bahrami (void) strcpy(mf->mf_name, mapfile);
236569112eddSAli Bahrami mf->mf_text = mf->mf_name + name_len;
236669112eddSAli Bahrami if (read(mapfile_fd, mf->mf_text, stat_buf.st_size) !=
236769112eddSAli Bahrami stat_buf.st_size) {
236869112eddSAli Bahrami err = errno;
23691007fd6fSAli Bahrami ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_SYS_READ), mapfile,
23701007fd6fSAli Bahrami strerror(err));
237169112eddSAli Bahrami (void) close(mapfile_fd);
237269112eddSAli Bahrami return (FALSE);
237369112eddSAli Bahrami }
237469112eddSAli Bahrami (void) close(mapfile_fd);
237569112eddSAli Bahrami mf->mf_text[stat_buf.st_size] = '\0';
237669112eddSAli Bahrami mf->mf_next = mf->mf_text;
237769112eddSAli Bahrami mf->mf_lineno = 1;
237869112eddSAli Bahrami mf->mf_next_ch = 0; /* No "lookahead" character yet */
237969112eddSAli Bahrami mf->mf_ec_insndx = 0; /* Insert entrace criteria at top */
238069112eddSAli Bahrami
238169112eddSAli Bahrami /*
238269112eddSAli Bahrami * Read just enough from the mapfile to determine the version,
238369112eddSAli Bahrami * and then dispatch to the appropriate code for further processing
238469112eddSAli Bahrami */
238569112eddSAli Bahrami if (!mapfile_version(mf))
238669112eddSAli Bahrami return (FALSE);
238769112eddSAli Bahrami
238869112eddSAli Bahrami /*
238969112eddSAli Bahrami * Start and continuation masks for unquoted identifier at this
239069112eddSAli Bahrami * mapfile version level.
239169112eddSAli Bahrami */
239269112eddSAli Bahrami mf->mf_tkid_start = TKID_ATTR_START(mf->mf_version);
239369112eddSAli Bahrami mf->mf_tkid_cont = TKID_ATTR_CONT(mf->mf_version);
239469112eddSAli Bahrami
239569112eddSAli Bahrami DBG_CALL(Dbg_map_parse(ofl->ofl_lml, mapfile, mf->mf_version));
239669112eddSAli Bahrami
239769112eddSAli Bahrami switch (mf->mf_version) {
239869112eddSAli Bahrami case MFV_SYSV:
23991007fd6fSAli Bahrami /* Guidance: Use newer mapfile syntax */
24001007fd6fSAli Bahrami if (OFL_GUIDANCE(ofl, FLG_OFG_NO_MF))
24011007fd6fSAli Bahrami ld_eprintf(ofl, ERR_GUIDANCE,
24021007fd6fSAli Bahrami MSG_INTL(MSG_GUIDE_MAPFILE), mapfile);
24031007fd6fSAli Bahrami
240469112eddSAli Bahrami mf->mf_tokdisp = gettok_dispatch_v1;
240569112eddSAli Bahrami if (!ld_map_parse_v1(mf))
240669112eddSAli Bahrami return (FALSE);
240769112eddSAli Bahrami break;
240869112eddSAli Bahrami
240969112eddSAli Bahrami case MFV_SOLARIS:
241069112eddSAli Bahrami mf->mf_tokdisp = gettok_dispatch_v2;
241169112eddSAli Bahrami STACK_RESET(lms.lms_cdir_stack);
241269112eddSAli Bahrami
241369112eddSAli Bahrami /*
241469112eddSAli Bahrami * If the conditional expression identifier tree has not been
241569112eddSAli Bahrami * initialized, set it up. This is only done on the first
241669112eddSAli Bahrami * mapfile, because the identifier control directives accumulate
241769112eddSAli Bahrami * across all the mapfiles.
241869112eddSAli Bahrami */
241969112eddSAli Bahrami if ((lms.lms_cexp_id == NULL) && !cexp_ident_init())
242069112eddSAli Bahrami return (FALSE);
242169112eddSAli Bahrami
242269112eddSAli Bahrami /*
242369112eddSAli Bahrami * Tell ld_map_gettoken() we will accept a '$' as starting a
242469112eddSAli Bahrami * control directive on the first call. Normally, they are
242569112eddSAli Bahrami * only allowed after a newline.
242669112eddSAli Bahrami */
242769112eddSAli Bahrami lms.lms_cdir_valid = 1;
242869112eddSAli Bahrami
242969112eddSAli Bahrami if (!ld_map_parse_v2(mf))
243069112eddSAli Bahrami return (FALSE);
243169112eddSAli Bahrami
243269112eddSAli Bahrami /* Did we leave any open $if control directives? */
243369112eddSAli Bahrami if (!STACK_IS_EMPTY(lms.lms_cdir_stack)) {
243469112eddSAli Bahrami while (!STACK_IS_EMPTY(lms.lms_cdir_stack)) {
243569112eddSAli Bahrami cdir_level_t *level =
243669112eddSAli Bahrami &STACK_POP(lms.lms_cdir_stack);
243769112eddSAli Bahrami
243869112eddSAli Bahrami mf_fatal(mf, MSG_INTL(MSG_MAP_CDIR_NOEND),
243969112eddSAli Bahrami EC_LINENO(level->cdl_if_lineno));
244069112eddSAli Bahrami }
244169112eddSAli Bahrami return (FALSE);
244269112eddSAli Bahrami }
244369112eddSAli Bahrami break;
244469112eddSAli Bahrami }
244569112eddSAli Bahrami
244669112eddSAli Bahrami return (TRUE);
244769112eddSAli Bahrami }
244869112eddSAli Bahrami
244969112eddSAli Bahrami /*
245069112eddSAli Bahrami * Sort the segment list. This is necessary if a mapfile has set explicit
245169112eddSAli Bahrami * virtual addresses for segments, or defined a SEGMENT_ORDER directive.
245269112eddSAli Bahrami *
245369112eddSAli Bahrami * Only PT_LOAD segments can be assigned a virtual address. These segments can
245469112eddSAli Bahrami * be one of two types:
245569112eddSAli Bahrami *
245669112eddSAli Bahrami * - Standard segments for text, data or bss. These segments will have been
245769112eddSAli Bahrami * inserted before the default text (first PT_LOAD) segment.
245869112eddSAli Bahrami *
245969112eddSAli Bahrami * - Empty (reservation) segments. These segment will have been inserted at
246069112eddSAli Bahrami * the end of any default PT_LOAD segments.
246169112eddSAli Bahrami *
246269112eddSAli Bahrami * Any standard segments that are assigned a virtual address will be sorted,
246369112eddSAli Bahrami * and as their definitions precede any default PT_LOAD segments, these segments
246469112eddSAli Bahrami * will be assigned sections before any defaults.
246569112eddSAli Bahrami *
246669112eddSAli Bahrami * Any reservation segments are also sorted amoung themselves, as these segments
246769112eddSAli Bahrami * must still follow the standard default segments.
246869112eddSAli Bahrami */
246969112eddSAli Bahrami static Boolean
sort_seg_list(Ofl_desc * ofl)247069112eddSAli Bahrami sort_seg_list(Ofl_desc *ofl)
247169112eddSAli Bahrami {
247269112eddSAli Bahrami APlist *sort_segs = NULL, *load_segs = NULL;
247369112eddSAli Bahrami Sg_desc *sgp1;
247469112eddSAli Bahrami Aliste idx1;
247569112eddSAli Bahrami Aliste nsegs;
247669112eddSAli Bahrami
247769112eddSAli Bahrami
247869112eddSAli Bahrami /*
247969112eddSAli Bahrami * We know the number of elements in the sorted list will be
248069112eddSAli Bahrami * the same as the original, so use this as the initial allocation
248169112eddSAli Bahrami * size for the replacement aplist.
248269112eddSAli Bahrami */
248369112eddSAli Bahrami nsegs = aplist_nitems(ofl->ofl_segs);
248469112eddSAli Bahrami
248569112eddSAli Bahrami
248669112eddSAli Bahrami /* Add the items below SGID_TEXT to the list */
248769112eddSAli Bahrami for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp1)) {
248869112eddSAli Bahrami if (sgp1->sg_id >= SGID_TEXT)
248969112eddSAli Bahrami break;
249069112eddSAli Bahrami
249169112eddSAli Bahrami if (aplist_append(&sort_segs, sgp1, nsegs) == NULL)
249269112eddSAli Bahrami return (FALSE);
249369112eddSAli Bahrami }
249469112eddSAli Bahrami
249569112eddSAli Bahrami /*
249669112eddSAli Bahrami * If there are any SEGMENT_ORDER items, add them, and set their
249769112eddSAli Bahrami * FLG_SG_ORDERED flag to identify them in debug output, and to
249869112eddSAli Bahrami * prevent them from being added again below.
249969112eddSAli Bahrami */
250069112eddSAli Bahrami for (APLIST_TRAVERSE(ofl->ofl_segs_order, idx1, sgp1)) {
250169112eddSAli Bahrami if (aplist_append(&sort_segs, sgp1, nsegs) == NULL)
250269112eddSAli Bahrami return (FALSE);
250369112eddSAli Bahrami sgp1->sg_flags |= FLG_SG_ORDERED;
250469112eddSAli Bahrami }
250569112eddSAli Bahrami
250669112eddSAli Bahrami /*
250769112eddSAli Bahrami * Add the loadable segments to another list in sorted order.
250869112eddSAli Bahrami */
250969112eddSAli Bahrami DBG_CALL(Dbg_map_sort_title(ofl->ofl_lml, TRUE));
251069112eddSAli Bahrami for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp1)) {
251169112eddSAli Bahrami DBG_CALL(Dbg_map_sort_seg(ofl->ofl_lml, ELFOSABI_SOLARIS,
251269112eddSAli Bahrami ld_targ.t_m.m_mach, sgp1));
251369112eddSAli Bahrami
251469112eddSAli Bahrami /* Only interested in PT_LOAD items not in SEGMENT_ORDER list */
251569112eddSAli Bahrami if ((sgp1->sg_phdr.p_type != PT_LOAD) ||
251669112eddSAli Bahrami (sgp1->sg_flags & FLG_SG_ORDERED))
251769112eddSAli Bahrami continue;
251869112eddSAli Bahrami
251969112eddSAli Bahrami /*
252069112eddSAli Bahrami * If the loadable segment does not contain a vaddr, simply
252169112eddSAli Bahrami * append it to the new list.
252269112eddSAli Bahrami */
252369112eddSAli Bahrami if ((sgp1->sg_flags & FLG_SG_P_VADDR) == 0) {
252469112eddSAli Bahrami if (aplist_append(&load_segs, sgp1, AL_CNT_SEGMENTS) ==
252569112eddSAli Bahrami NULL)
252669112eddSAli Bahrami return (FALSE);
252769112eddSAli Bahrami
252869112eddSAli Bahrami } else {
252969112eddSAli Bahrami Aliste idx2;
253069112eddSAli Bahrami Sg_desc *sgp2;
253169112eddSAli Bahrami int inserted = 0;
253269112eddSAli Bahrami
253369112eddSAli Bahrami /*
253469112eddSAli Bahrami * Traverse the segment list we are creating, looking
253569112eddSAli Bahrami * for a segment that defines a vaddr.
253669112eddSAli Bahrami */
253769112eddSAli Bahrami for (APLIST_TRAVERSE(load_segs, idx2, sgp2)) {
253869112eddSAli Bahrami /*
253969112eddSAli Bahrami * Any real segments that contain vaddr's need
254069112eddSAli Bahrami * to be sorted. Any reservation segments also
254169112eddSAli Bahrami * need to be sorted. However, any reservation
254269112eddSAli Bahrami * segments should be placed after any real
254369112eddSAli Bahrami * segments.
254469112eddSAli Bahrami */
254569112eddSAli Bahrami if (((sgp2->sg_flags &
254669112eddSAli Bahrami (FLG_SG_P_VADDR | FLG_SG_EMPTY)) == 0) &&
254769112eddSAli Bahrami (sgp1->sg_flags & FLG_SG_EMPTY))
254869112eddSAli Bahrami continue;
254969112eddSAli Bahrami
255069112eddSAli Bahrami if ((sgp2->sg_flags & FLG_SG_P_VADDR) &&
255169112eddSAli Bahrami ((sgp2->sg_flags & FLG_SG_EMPTY) ==
255269112eddSAli Bahrami (sgp1->sg_flags & FLG_SG_EMPTY))) {
255369112eddSAli Bahrami if (sgp1->sg_phdr.p_vaddr ==
255469112eddSAli Bahrami sgp2->sg_phdr.p_vaddr) {
25551007fd6fSAli Bahrami ld_eprintf(ofl, ERR_FATAL,
255669112eddSAli Bahrami MSG_INTL(MSG_MAP_SEGSAME),
255769112eddSAli Bahrami sgp1->sg_name,
255869112eddSAli Bahrami sgp2->sg_name);
255969112eddSAli Bahrami return (FALSE);
256069112eddSAli Bahrami }
256169112eddSAli Bahrami
256269112eddSAli Bahrami if (sgp1->sg_phdr.p_vaddr >
256369112eddSAli Bahrami sgp2->sg_phdr.p_vaddr)
256469112eddSAli Bahrami continue;
256569112eddSAli Bahrami }
256669112eddSAli Bahrami
256769112eddSAli Bahrami /*
256869112eddSAli Bahrami * Insert this segment before the segment on
256969112eddSAli Bahrami * the load_segs list.
257069112eddSAli Bahrami */
257169112eddSAli Bahrami if (aplist_insert(&load_segs, sgp1,
257269112eddSAli Bahrami AL_CNT_SEGMENTS, idx2) == NULL)
257369112eddSAli Bahrami return (FALSE);
257469112eddSAli Bahrami inserted = 1;
257569112eddSAli Bahrami break;
257669112eddSAli Bahrami }
257769112eddSAli Bahrami
257869112eddSAli Bahrami /*
257969112eddSAli Bahrami * If the segment being inspected has not been inserted
258069112eddSAli Bahrami * in the segment list, simply append it to the list.
258169112eddSAli Bahrami */
258269112eddSAli Bahrami if ((inserted == 0) && (aplist_append(&load_segs,
258369112eddSAli Bahrami sgp1, AL_CNT_SEGMENTS) == NULL))
258469112eddSAli Bahrami return (FALSE);
258569112eddSAli Bahrami }
258669112eddSAli Bahrami }
258769112eddSAli Bahrami
258869112eddSAli Bahrami /*
258969112eddSAli Bahrami * Add the sorted loadable segments to our initial segment list.
259069112eddSAli Bahrami */
259169112eddSAli Bahrami for (APLIST_TRAVERSE(load_segs, idx1, sgp1)) {
259269112eddSAli Bahrami if (aplist_append(&sort_segs, sgp1, AL_CNT_SEGMENTS) == NULL)
259369112eddSAli Bahrami return (FALSE);
259469112eddSAli Bahrami }
259569112eddSAli Bahrami
259669112eddSAli Bahrami /*
259769112eddSAli Bahrami * Add all other segments to our list.
259869112eddSAli Bahrami */
259969112eddSAli Bahrami for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp1)) {
260069112eddSAli Bahrami if ((sgp1->sg_id < SGID_TEXT) ||
260169112eddSAli Bahrami (sgp1->sg_phdr.p_type == PT_LOAD) ||
260269112eddSAli Bahrami (sgp1->sg_flags & FLG_SG_ORDERED))
260369112eddSAli Bahrami continue;
260469112eddSAli Bahrami
260569112eddSAli Bahrami if (aplist_append(&sort_segs, sgp1, AL_CNT_SEGMENTS) == NULL)
260669112eddSAli Bahrami return (FALSE);
260769112eddSAli Bahrami }
260869112eddSAli Bahrami
260969112eddSAli Bahrami /*
261069112eddSAli Bahrami * Free the original list, and the pt_load list, and use
261169112eddSAli Bahrami * the new list as the segment list.
261269112eddSAli Bahrami */
261369112eddSAli Bahrami free(ofl->ofl_segs);
261469112eddSAli Bahrami if (load_segs) free(load_segs);
261569112eddSAli Bahrami ofl->ofl_segs = sort_segs;
261669112eddSAli Bahrami
261769112eddSAli Bahrami if (DBG_ENABLED) {
261869112eddSAli Bahrami Dbg_map_sort_title(ofl->ofl_lml, FALSE);
261969112eddSAli Bahrami for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp1)) {
262069112eddSAli Bahrami Dbg_map_sort_seg(ofl->ofl_lml, ELFOSABI_SOLARIS,
262169112eddSAli Bahrami ld_targ.t_m.m_mach, sgp1);
262269112eddSAli Bahrami }
262369112eddSAli Bahrami }
262469112eddSAli Bahrami
262569112eddSAli Bahrami return (TRUE);
262669112eddSAli Bahrami }
262769112eddSAli Bahrami
262869112eddSAli Bahrami /*
262969112eddSAli Bahrami * After all mapfiles have been processed, this routine is used to
263069112eddSAli Bahrami * finish any remaining mapfile related work.
263169112eddSAli Bahrami *
263269112eddSAli Bahrami * exit:
263369112eddSAli Bahrami * Returns TRUE on success, and FALSE on failure.
263469112eddSAli Bahrami */
263569112eddSAli Bahrami Boolean
ld_map_post_process(Ofl_desc * ofl)263669112eddSAli Bahrami ld_map_post_process(Ofl_desc *ofl)
263769112eddSAli Bahrami {
263869112eddSAli Bahrami Aliste idx, idx2;
263969112eddSAli Bahrami Is_desc *isp;
264069112eddSAli Bahrami Sg_desc *sgp;
264169112eddSAli Bahrami Ent_desc *enp;
264269112eddSAli Bahrami Sg_desc *first_seg = NULL;
264369112eddSAli Bahrami
264469112eddSAli Bahrami
264569112eddSAli Bahrami DBG_CALL(Dbg_map_post_title(ofl->ofl_lml));
264669112eddSAli Bahrami
264769112eddSAli Bahrami /*
264869112eddSAli Bahrami * Per-segment processing:
264969112eddSAli Bahrami * - Identify segments with explicit virtual address
265069112eddSAli Bahrami * - Details of input and output section order
265169112eddSAli Bahrami */
265269112eddSAli Bahrami for (APLIST_TRAVERSE(ofl->ofl_segs, idx, sgp)) {
265369112eddSAli Bahrami /*
265469112eddSAli Bahrami * We are looking for segments. Program headers that represent
265569112eddSAli Bahrami * segments are required to have a non-NULL name pointer,
265669112eddSAli Bahrami * while that those that do not are required to have a
265769112eddSAli Bahrami * NULL name pointer.
265869112eddSAli Bahrami */
265969112eddSAli Bahrami if (sgp->sg_name == NULL)
266069112eddSAli Bahrami continue;
266169112eddSAli Bahrami
266269112eddSAli Bahrami /* Remember the first non-disabled segment */
266369112eddSAli Bahrami if ((first_seg == NULL) && !(sgp->sg_flags & FLG_SG_DISABLED))
266469112eddSAli Bahrami first_seg = sgp;
266569112eddSAli Bahrami
266669112eddSAli Bahrami /*
266769112eddSAli Bahrami * If a segment has an explicit virtual address, we will
266869112eddSAli Bahrami * need to sort the segments.
266969112eddSAli Bahrami */
267069112eddSAli Bahrami if (sgp->sg_flags & FLG_SG_P_VADDR)
267169112eddSAli Bahrami ofl->ofl_flags1 |= FLG_OF1_VADDR;
267269112eddSAli Bahrami
267369112eddSAli Bahrami /*
267469112eddSAli Bahrami * The FLG_OF_OS_ORDER flag enables the code that does
267569112eddSAli Bahrami * output section ordering. Set if the segment has
267669112eddSAli Bahrami * a non-empty output section order list.
267769112eddSAli Bahrami */
267869112eddSAli Bahrami if (alist_nitems(sgp->sg_os_order) > 0)
267969112eddSAli Bahrami ofl->ofl_flags |= FLG_OF_OS_ORDER;
268069112eddSAli Bahrami
268169112eddSAli Bahrami /*
268269112eddSAli Bahrami * The version 1 and version 2 syntaxes for input section
268369112eddSAli Bahrami * ordering are different and incompatible enough that we
268469112eddSAli Bahrami * only allow the use of one or the other for a given segment:
268569112eddSAli Bahrami *
268669112eddSAli Bahrami * v1) The version 1 syntax has the user set the ?O flag on
268769112eddSAli Bahrami * the segment. If this is done, all input sections placed
268869112eddSAli Bahrami * via an entrance criteria that has a section name are to
268969112eddSAli Bahrami * be sorted, using the order of the entrance criteria
269069112eddSAli Bahrami * as the sort key.
269169112eddSAli Bahrami *
269269112eddSAli Bahrami * v2) The version 2 syntax has the user specify a name for
26938222814eSRichard Lowe * the entry criteria, and then provide a list of entry
26948222814eSRichard Lowe * criteria names via the IS_ORDER segment attribute.
26958222814eSRichard Lowe * Sections placed via the criteria listed in IS_ORDER
26968222814eSRichard Lowe * are sorted, and the others are not.
269769112eddSAli Bahrami *
269869112eddSAli Bahrami * Regardless of the syntax version used, the section sorting
269969112eddSAli Bahrami * code expects the following:
270069112eddSAli Bahrami *
270169112eddSAli Bahrami * - Segments requiring input section sorting have the
270269112eddSAli Bahrami * FLG_SG_IS_ORDER flag set
270369112eddSAli Bahrami *
270469112eddSAli Bahrami * - Entrance criteria referencing the segment that
270569112eddSAli Bahrami * participate in input section sorting have a non-zero
270669112eddSAli Bahrami * sort key in their ec_ordndx field.
270769112eddSAli Bahrami *
270869112eddSAli Bahrami * At this point, the following are true:
270969112eddSAli Bahrami *
271069112eddSAli Bahrami * - All entrance criteria have ec_ordndx set to 0.
271169112eddSAli Bahrami * - Segments that require the version 1 behavior have
271269112eddSAli Bahrami * the FLG_SG_IS_ORDER flag set, and the segments
271369112eddSAli Bahrami * sg_is_order list is empty.
271469112eddSAli Bahrami * - Segments that require the version 2 behavior do not
271569112eddSAli Bahrami * have FLG_SG_IS_ORDER set, and the sg_is_order list is
271669112eddSAli Bahrami * non-empty. This list contains the names of the entrance
271769112eddSAli Bahrami * criteria that will participate in input section sorting,
271869112eddSAli Bahrami * and their relative order in the list provides the
271969112eddSAli Bahrami * sort key to use.
272069112eddSAli Bahrami *
272169112eddSAli Bahrami * We must detect these two cases, set the FLG_SG_IS_ORDER
272269112eddSAli Bahrami * flag as necessary, and fill in all entrance criteria
272369112eddSAli Bahrami * sort keys. If any input section sorting is to be done,
272469112eddSAli Bahrami * we also set the FLG_OF_IS_ORDER flag on the output descriptor
272569112eddSAli Bahrami * to enable the code that does that work.
272669112eddSAli Bahrami */
272769112eddSAli Bahrami
272869112eddSAli Bahrami /* Version 1: ?O flag? */
272969112eddSAli Bahrami if (sgp->sg_flags & FLG_SG_IS_ORDER) {
273069112eddSAli Bahrami Word index = 0;
273169112eddSAli Bahrami
273269112eddSAli Bahrami ofl->ofl_flags |= FLG_OF_IS_ORDER;
273369112eddSAli Bahrami DBG_CALL(Dbg_map_ent_ord_title(ofl->ofl_lml,
273469112eddSAli Bahrami sgp->sg_name));
273569112eddSAli Bahrami
273669112eddSAli Bahrami /*
273769112eddSAli Bahrami * Give each user defined entrance criteria for this
273869112eddSAli Bahrami * segment that specifies a section name a
273969112eddSAli Bahrami * monotonically increasing sort key.
274069112eddSAli Bahrami */
274169112eddSAli Bahrami for (APLIST_TRAVERSE(ofl->ofl_ents, idx2, enp))
274269112eddSAli Bahrami if ((enp->ec_segment == sgp) &&
274369112eddSAli Bahrami (enp->ec_is_name != NULL) &&
274469112eddSAli Bahrami ((enp->ec_flags & FLG_EC_BUILTIN) == 0))
274569112eddSAli Bahrami enp->ec_ordndx = ++index;
274669112eddSAli Bahrami continue;
274769112eddSAli Bahrami }
274869112eddSAli Bahrami
274969112eddSAli Bahrami /* Version 2: SEGMENT IS_ORDER list? */
275069112eddSAli Bahrami if (aplist_nitems(sgp->sg_is_order) > 0) {
275169112eddSAli Bahrami Word index = 0;
275269112eddSAli Bahrami
275369112eddSAli Bahrami ofl->ofl_flags |= FLG_OF_IS_ORDER;
275469112eddSAli Bahrami DBG_CALL(Dbg_map_ent_ord_title(ofl->ofl_lml,
275569112eddSAli Bahrami sgp->sg_name));
275669112eddSAli Bahrami
275769112eddSAli Bahrami /*
275869112eddSAli Bahrami * Give each entrance criteria in the sg_is_order
275969112eddSAli Bahrami * list a monotonically increasing sort key.
276069112eddSAli Bahrami */
276169112eddSAli Bahrami for (APLIST_TRAVERSE(sgp->sg_is_order, idx2, enp)) {
276269112eddSAli Bahrami enp->ec_ordndx = ++index;
276369112eddSAli Bahrami enp->ec_segment->sg_flags |= FLG_SG_IS_ORDER;
276469112eddSAli Bahrami }
276569112eddSAli Bahrami }
276669112eddSAli Bahrami }
276769112eddSAli Bahrami
276869112eddSAli Bahrami /* Sort the segment descriptors if necessary */
276969112eddSAli Bahrami if (((ofl->ofl_flags1 & FLG_OF1_VADDR) ||
277069112eddSAli Bahrami (aplist_nitems(ofl->ofl_segs_order) > 0)) &&
277169112eddSAli Bahrami !sort_seg_list(ofl))
277269112eddSAli Bahrami return (FALSE);
277369112eddSAli Bahrami
277469112eddSAli Bahrami /*
277569112eddSAli Bahrami * If the output file is a static file without an interpreter, and
277669112eddSAli Bahrami * if any virtual address is specified, then set the NOHDR flag for
277769112eddSAli Bahrami * backward compatibility.
277869112eddSAli Bahrami */
277969112eddSAli Bahrami if (!(ofl->ofl_flags & (FLG_OF_DYNAMIC | FLG_OF_RELOBJ)) &&
278069112eddSAli Bahrami !(ofl->ofl_osinterp) && (ofl->ofl_flags1 & FLG_OF1_VADDR))
278169112eddSAli Bahrami ofl->ofl_dtflags_1 |= DF_1_NOHDR;
278269112eddSAli Bahrami
278369112eddSAli Bahrami if (ofl->ofl_flags & FLG_OF_RELOBJ) {
278469112eddSAli Bahrami /*
278569112eddSAli Bahrami * NOHDR has no effect on a relocatable file.
278669112eddSAli Bahrami * Make sure this flag isn't set.
278769112eddSAli Bahrami */
278869112eddSAli Bahrami ofl->ofl_dtflags_1 &= ~DF_1_NOHDR;
278969112eddSAli Bahrami } else if (first_seg != NULL) {
279069112eddSAli Bahrami /*
279169112eddSAli Bahrami * DF_1_NOHDR might have been set globally by the HDR_NOALLOC
279269112eddSAli Bahrami * directive. If not, then we want to check the per-segment
279369112eddSAli Bahrami * flag for the first loadable segment and propagate it
279469112eddSAli Bahrami * if set.
279569112eddSAli Bahrami */
279669112eddSAli Bahrami if ((ofl->ofl_dtflags_1 & DF_1_NOHDR) == 0) {
279769112eddSAli Bahrami /*
279869112eddSAli Bahrami * If we sorted the segments, the first segment
279969112eddSAli Bahrami * may have changed.
280069112eddSAli Bahrami */
280169112eddSAli Bahrami if ((ofl->ofl_flags1 & FLG_OF1_VADDR) ||
280269112eddSAli Bahrami (aplist_nitems(ofl->ofl_segs_order) > 0)) {
280369112eddSAli Bahrami for (APLIST_TRAVERSE(ofl->ofl_segs, idx, sgp)) {
280469112eddSAli Bahrami if (sgp->sg_name == NULL)
280569112eddSAli Bahrami continue;
280669112eddSAli Bahrami if ((sgp->sg_flags & FLG_SG_DISABLED) ==
280769112eddSAli Bahrami 0) {
280869112eddSAli Bahrami first_seg = sgp;
280969112eddSAli Bahrami break;
281069112eddSAli Bahrami }
281169112eddSAli Bahrami }
281269112eddSAli Bahrami }
281369112eddSAli Bahrami
281469112eddSAli Bahrami /*
281569112eddSAli Bahrami * If the per-segment NOHDR flag is set on our first
281669112eddSAli Bahrami * segment, then make it take effect.
281769112eddSAli Bahrami */
281869112eddSAli Bahrami if (first_seg->sg_flags & FLG_SG_NOHDR)
281969112eddSAli Bahrami ofl->ofl_dtflags_1 |= DF_1_NOHDR;
282069112eddSAli Bahrami }
282169112eddSAli Bahrami
282269112eddSAli Bahrami /*
282369112eddSAli Bahrami * For executable and shared objects, the first segment must
282469112eddSAli Bahrami * be loadable unless NOHDR was specified, because the ELF
282569112eddSAli Bahrami * header must simultaneously lie at offset 0 of the file and
282669112eddSAli Bahrami * be included in the first loadable segment. This isn't
282769112eddSAli Bahrami * possible if some other segment type starts the file
282869112eddSAli Bahrami */
282969112eddSAli Bahrami if (!(ofl->ofl_dtflags_1 & DF_1_NOHDR) &&
283069112eddSAli Bahrami (first_seg->sg_phdr.p_type != PT_LOAD)) {
283169112eddSAli Bahrami Conv_inv_buf_t inv_buf;
283269112eddSAli Bahrami
28331007fd6fSAli Bahrami ld_eprintf(ofl, ERR_FATAL,
283469112eddSAli Bahrami MSG_INTL(MSG_SEG_FIRNOTLOAD),
283569112eddSAli Bahrami conv_phdr_type(ELFOSABI_SOLARIS, ld_targ.t_m.m_mach,
283669112eddSAli Bahrami first_seg->sg_phdr.p_type, 0, &inv_buf),
283769112eddSAli Bahrami first_seg->sg_name);
283869112eddSAli Bahrami return (FALSE);
283969112eddSAli Bahrami }
284069112eddSAli Bahrami }
284169112eddSAli Bahrami
284269112eddSAli Bahrami /*
284369112eddSAli Bahrami * Mapfiles may have been used to create symbol definitions
284469112eddSAli Bahrami * with backing storage. Although the backing storage is
284569112eddSAli Bahrami * associated with an input section, the association of the
284669112eddSAli Bahrami * section to an output section (and segment) is initially
284769112eddSAli Bahrami * deferred. Now that all mapfile processing is complete, any
284869112eddSAli Bahrami * entrance criteria requirements have been processed, and
284969112eddSAli Bahrami * these backing storage sections can be associated with the
285069112eddSAli Bahrami * appropriate output section (and segment).
285169112eddSAli Bahrami */
285269112eddSAli Bahrami if (ofl->ofl_maptext || ofl->ofl_mapdata)
285369112eddSAli Bahrami DBG_CALL(Dbg_sec_backing(ofl->ofl_lml));
285469112eddSAli Bahrami
285569112eddSAli Bahrami for (APLIST_TRAVERSE(ofl->ofl_maptext, idx, isp)) {
285669112eddSAli Bahrami if (ld_place_section(ofl, isp, NULL,
285769112eddSAli Bahrami ld_targ.t_id.id_text, NULL) == (Os_desc *)S_ERROR)
285869112eddSAli Bahrami return (FALSE);
285969112eddSAli Bahrami }
286069112eddSAli Bahrami
286169112eddSAli Bahrami for (APLIST_TRAVERSE(ofl->ofl_mapdata, idx, isp)) {
286269112eddSAli Bahrami if (ld_place_section(ofl, isp, NULL,
286369112eddSAli Bahrami ld_targ.t_id.id_data, NULL) == (Os_desc *)S_ERROR)
286469112eddSAli Bahrami return (FALSE);
286569112eddSAli Bahrami }
286669112eddSAli Bahrami
286769112eddSAli Bahrami return (TRUE);
286869112eddSAli Bahrami }
2869