1#!/bin/sh -eu 2# 3# Copyright (c) 2014-2015 Mike Frysinger <vapier@gentoo.org> 4# Copyright (c) 2014-2015 Dmitry V. Levin <ldv@altlinux.org> 5# Copyright (c) 2014-2018 The strace developers. 6# All rights reserved. 7# 8# Redistribution and use in source and binary forms, with or without 9# modification, are permitted provided that the following conditions 10# are met: 11# 1. Redistributions of source code must retain the above copyright 12# notice, this list of conditions and the following disclaimer. 13# 2. Redistributions in binary form must reproduce the above copyright 14# notice, this list of conditions and the following disclaimer in the 15# documentation and/or other materials provided with the distribution. 16# 3. The name of the author may not be used to endorse or promote products 17# derived from this software without specific prior written permission. 18# 19# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 30usage() 31{ 32 cat <<EOF 33Usage: $0 <input> <output> 34 35Generate xlat header files from <input> (a file or dir of files) and write 36the generated headers to <output>. 37EOF 38 exit 1 39} 40 41cond_def() 42{ 43 local line 44 line="$1"; shift 45 46 local val 47 val="$(printf %s "$line" | 48 LC_ALL=C sed -r -n 's/^([[:alpha:]_][[:alnum:]_]*).*$/\1/p')" 49 50 local def 51 def="$(printf %s "${line}" | 52 sed -r -n 's/^[^[:space:]]+[[:space:]]+([^[:space:]].*)$/\1/p')" 53 54 if [ -n "$def" ]; then 55 cat <<-EOF 56 #if defined($val) || (defined(HAVE_DECL_$val) && HAVE_DECL_$val) 57 DIAG_PUSH_IGNORE_TAUTOLOGICAL_COMPARE 58 static_assert(($val) == ($def), "$val != $def"); 59 DIAG_POP_IGNORE_TAUTOLOGICAL_COMPARE 60 #else 61 # define $val $def 62 #endif 63 EOF 64 fi 65} 66 67print_xlat() 68{ 69 local val 70 val="$1"; shift 71 72 [ 1 = "$value_indexed" ] && printf " [%s] =" "${val}" 73 if [ -z "${val_type-}" ]; then 74 echo " XLAT(${val})," 75 else 76 echo " XLAT_TYPE(${val_type}, ${val})," 77 fi 78} 79 80print_xlat_pair() 81{ 82 local val str 83 val="$1"; shift 84 str="$1"; shift 85 86 [ 1 = "$value_indexed" ] && printf " [%s] =" "${val}" 87 if [ -z "${val_type-}" ]; then 88 echo " XLAT_PAIR(${val}, \"${str}\")," 89 else 90 echo " XLAT_TYPE_PAIR(${val_type}, ${val}, \"${str}\")," 91 fi 92} 93 94cond_xlat() 95{ 96 local line val m def xlat 97 line="$1"; shift 98 99 val="$(printf %s "${line}" | sed -r -n 's/^([^[:space:]]+).*$/\1/p')" 100 m="${val%%|*}" 101 def="$(printf %s "${line}" | 102 sed -r -n 's/^[^[:space:]]+[[:space:]]+([^[:space:]].*)$/\1/p')" 103 104 if [ "${m}" = "${m#1<<}" ]; then 105 xlat="$(print_xlat "${val}")" 106 else 107 xlat="$(print_xlat_pair "1ULL<<${val#1<<}" "${val}")" 108 m="${m#1<<}" 109 fi 110 111 if [ -z "${def}" ]; then 112 cat <<-EOF 113 #if defined(${m}) || (defined(HAVE_DECL_${m}) && HAVE_DECL_${m}) 114 ${xlat} 115 #endif 116 EOF 117 else 118 echo "$xlat" 119 fi 120} 121 122gen_header() 123{ 124 local input="$1" output="$2" name="$3" 125 echo "generating ${output}" 126 ( 127 local defs="${0%/*}/../defs.h" 128 local mpers="${0%/*}/../mpers_xlat.h" 129 local decl="extern const struct xlat ${name}[];" 130 local in_defs= in_mpers= 131 132 value_indexed=0 133 134 if grep -F -x "$decl" "$defs" > /dev/null; then 135 in_defs=1 136 elif grep -F -x "$decl" "$mpers" > /dev/null; then 137 in_mpers=1 138 fi 139 140 cat <<-EOF 141 /* Generated by $0 from $1; do not edit. */ 142 143 #include "gcc_compat.h" 144 #include "static_assert.h" 145 146 EOF 147 148 local unconditional= line 149 # 1st pass: output directives. 150 while read line; do 151 LC_COLLATE=C 152 line=$(printf "%s" "$line" | \ 153 sed "s|[[:space:]]*/\*.*\*/[[:space:]]*||") 154 155 case $line in 156 '#stop') 157 exit 0 158 ;; 159 '#conditional') 160 unconditional= 161 ;; 162 '#unconditional') 163 unconditional=1 164 ;; 165 '#val_type '*) 166 # to be processed during 2nd pass 167 ;; 168 '#value_indexed') 169 value_indexed=1 170 ;; 171 '#'*) 172 echo "${line}" 173 ;; 174 [A-Z_]*) 175 [ -n "$unconditional" ] || 176 cond_def "$line" 177 ;; 178 esac 179 done < "$input" 180 181 cat <<-EOF 182 183 #ifndef XLAT_MACROS_ONLY 184 185 EOF 186 187 if [ -n "$in_defs" ]; then 188 cat <<-EOF 189 # ifndef IN_MPERS 190 191 EOF 192 elif [ -n "$in_mpers" ]; then 193 cat <<-EOF 194 # ifdef IN_MPERS 195 196 ${decl} 197 198 # else 199 200 # if !(defined HAVE_M32_MPERS || defined HAVE_MX32_MPERS) 201 static 202 # endif 203 EOF 204 else 205 cat <<-EOF 206 # ifdef IN_MPERS 207 208 # error static const struct xlat ${name} in mpers mode 209 210 # else 211 212 static 213 EOF 214 fi 215 216 echo "const struct xlat ${name}[] = {" 217 218 unconditional= val_type= 219 # 2nd pass: output everything. 220 while read line; do 221 LC_COLLATE=C 222 line=$(printf "%s" "$line" | \ 223 sed "s|[[:space:]]*/\*.*\*/[[:space:]]*||") 224 225 case ${line} in 226 '#conditional') 227 unconditional= 228 ;; 229 '#unconditional') 230 unconditional=1 231 ;; 232 '#value_indexed') 233 ;; 234 '#val_type '*) 235 val_type="${line#\#val_type }" 236 ;; 237 [A-Z_]*) # symbolic constants 238 if [ -n "${unconditional}" ]; then 239 print_xlat "${line}" 240 else 241 cond_xlat "${line}" 242 fi 243 ;; 244 '1<<'[A-Z_]*) # symbolic constants with shift 245 if [ -n "${unconditional}" ]; then 246 print_xlat_pair "1ULL<<${line#1<<}" "${line}" 247 else 248 cond_xlat "${line}" 249 fi 250 ;; 251 [0-9]*) # numeric constants 252 print_xlat "${line}" 253 ;; 254 *) # verbatim lines 255 echo "${line}" 256 ;; 257 esac 258 done < "${input}" 259 echo ' XLAT_END' 260 261 cat <<-EOF 262 }; 263 264 # endif /* !IN_MPERS */ 265 266 #endif /* !XLAT_MACROS_ONLY */ 267 EOF 268 ) >"${output}" 269} 270 271gen_make() 272{ 273 local output="$1" 274 local name 275 shift 276 echo "generating ${output}" 277 ( 278 printf "XLAT_INPUT_FILES = " 279 printf 'xlat/%s.in ' "$@" 280 echo 281 printf "XLAT_HEADER_FILES = " 282 printf 'xlat/%s.h ' "$@" 283 echo 284 for name; do 285 printf '$(top_srcdir)/xlat/%s.h: $(top_srcdir)/xlat/%s.in $(top_srcdir)/xlat/gen.sh\n' \ 286 "${name}" "${name}" 287 echo ' $(AM_V_GEN)$(top_srcdir)/xlat/gen.sh $< $@' 288 done 289 ) >"${output}" 290} 291 292gen_git() 293{ 294 local output="$1" 295 shift 296 echo "generating ${output}" 297 ( 298 printf '/%s\n' .gitignore Makemodule.am 299 printf '/%s.h\n' "$@" 300 ) >"${output}" 301} 302 303main() 304{ 305 case $# in 306 0) set -- "${0%/*}" "${0%/*}" ;; 307 2) ;; 308 *) usage ;; 309 esac 310 311 local input="$1" 312 local output="$2" 313 local name 314 local jobs=0 315 local ncpus="$(getconf _NPROCESSORS_ONLN)" 316 local pids= 317 [ "${ncpus}" -ge 1 ] || 318 ncpus=1 319 320 if [ -d "${input}" ]; then 321 local f names= 322 for f in "${input}"/*.in; do 323 [ -f "${f}" ] || continue 324 name=${f##*/} 325 name=${name%.in} 326 gen_header "${f}" "${output}/${name}.h" "${name}" & 327 pids="$pids $!" 328 names="${names} ${name}" 329 : $(( jobs += 1 )) 330 if [ "${jobs}" -gt "$(( ncpus * 2 ))" ]; then 331 read wait_pid rest 332 pids="$rest" 333 wait -n 2>/dev/null || wait "$wait_pid" 334 : $(( jobs -= 1 )) 335 fi <<- EOF 336 $pids 337 EOF 338 done 339 gen_git "${output}/.gitignore" ${names} & 340 gen_make "${output}/Makemodule.am" ${names} & 341 wait 342 else 343 name=${input##*/} 344 name=${name%.in} 345 gen_header "${input}" "${output}" "${name}" 346 fi 347} 348 349main "$@" 350