#!/bin/sh -efu # # Copyright (c) 2014-2015 Mike Frysinger # Copyright (c) 2014-2015 Dmitry V. Levin # Copyright (c) 2014-2021 The strace developers. # All rights reserved. # # SPDX-License-Identifier: LGPL-2.1-or-later export LC_ALL=C usage() { cat < Generate xlat header files from (a file or dir of files) and write the generated headers to . EOF exit 1 } print_m4_record() { local val output val="$1"; shift output="$1"; shift [ -n "$output" ] || return 0 if [ "$first_enum" = 1 ]; then printf '%s' "$val" else printf ',\n%s' "$val" fi >> "$output" first_enum=0 } cond_def() { local line line="$1"; shift local xlat_type xlat_type="$1"; shift local val val="${line%%[!A-Za-z0-9_]*}" local t def= t="${line#*[ ]}" if [ "$line" != "$t" ]; then while [ "$def" != "$t" ]; do def="$t" t="${t##[ ]}" done fi if [ -n "$def" ]; then [ -n "$unconditional" ] || printf '%s\n' \ "#if defined($val) || (defined(HAVE_DECL_$val) && HAVE_DECL_$val)" printf '%s\n' \ "DIAG_PUSH_IGNORE_TAUTOLOGICAL_COMPARE" \ "static_assert(($val) == ($def), \"$val != $def\");" \ "DIAG_POP_IGNORE_TAUTOLOGICAL_COMPARE" [ -n "$unconditional" ] || printf '%s\n' \ "#else" \ "# define $val $def" \ "#endif" fi if [ XT_SORTED = "$xlat_type" ]; then [ -n "$unconditional" ] || printf '%s\n' \ "#if defined($val) || (defined(HAVE_DECL_$val) && HAVE_DECL_$val)" check_sort_order "$val" [ -n "$unconditional" ] || printf '%s\n' "#endif" fi } check_sort_order() { local val val="$1"; shift cat <<-EOF #if defined XLAT_PREV_VAL static_assert((unsigned long long) ($val) > (unsigned long long) (XLAT_PREV_VAL), "Incorrect order in #sorted xlat: $val" " is not larger than the previous value"); #endif #undef XLAT_PREV_VAL #define XLAT_PREV_VAL ($val) EOF } print_xlat() { local val val="$1"; shift [ 1 = "$value_indexed" ] && printf " [%s] =" "${val}" if [ -z "${val_type-}" ]; then echo " XLAT(${val})," else echo " XLAT_TYPE(${val_type}, ${val})," fi echo " #define XLAT_VAL_$xlat_flag_cnt ((${val_type:-unsigned}) (${val}))" echo " #define XLAT_STR_$xlat_flag_cnt STRINGIFY(${val})" xlat_flag_cnt=$((xlat_flag_cnt + 1)) [ -z "$enum" ] || print_m4_record "$val" "$output_m4" } print_xlat_pair() { local val str macro val="$1"; shift str="$1"; shift macro="$1"; shift [ 1 = "$value_indexed" ] && printf " [%s] =" "${val}" if [ -z "${val_type-}" ]; then echo " XLAT_PAIR(${val}, \"${str}\")," else echo " XLAT_TYPE_PAIR(${val_type}, ${val}, \"${str}\")," fi echo " #define XLAT_VAL_$xlat_flag_cnt ((${val_type:-unsigned}) (${val}))" echo " #define XLAT_STR_$xlat_flag_cnt \"${str}\"" xlat_flag_cnt=$((xlat_flag_cnt + 1)) [ -z "$enum" ] || print_m4_record "$macro" "$output_m4" } cond_xlat() { echo "$1" | { local val def m xlat read val def m="${val%%|*}" if [ "${m}" = "${m#1<<}" ]; then xlat="$(print_xlat "${val}")" else m="${m#1<<}" xlat="$(print_xlat_pair "1ULL<<${val#1<<}" "${val}" "$m")" fi if [ -z "${def}${unconditional}" ]; then printf '%s\n' \ "#if defined(${m}) || (defined(HAVE_DECL_${m}) && HAVE_DECL_${m})" \ " ${xlat}" \ "#endif" else printf '%s\n' "$xlat" fi } # Since we're calling print_xlat/print_xlat_pair in subprocess xlat_flag_cnt=$((xlat_flag_cnt + 1)) first_enum=0 } gen_header() { local input="$1" output="$2" name="$3" output_m4="$4" exec 3>&1 echo "generating ${output}" >&2 ( local defs="${0%/*}/../defs.h" local mpers="${0%/*}/../mpers_xlat.h" local decl="extern const struct xlat ${name}[];" local in_defs= in_mpers= local xlat_type="XT_NORMAL" local includes="" local enum="" first_enum=1 value_indexed=0 xlat_flag_cnt=0 if grep -F -q -x "$decl" "$defs"; then in_defs=1 elif grep -F -q -x "$decl" "$mpers"; then in_mpers=1 fi cat <<-EOF /* Generated by $0 from $1; do not edit. */ #include "gcc_compat.h" #include "static_assert.h" EOF local unconditional= line # 1st pass: output directives. while read -r line; do case "$line" in */\**) line=$(printf "%s" "$line" | sed "s|[[:space:]]*/\*.*\*/[[:space:]]*||") ;; esac case $line in '#conditional') unconditional= ;; '#unconditional') unconditional=1 ;; '#val_type '*) # to be processed during 2nd pass ;; '#sorted'|'#sorted '*) xlat_type="XT_SORTED" ;; '#value_indexed') value_indexed=1 xlat_type="XT_INDEXED" ;; '#enum') [ -z "$output_m4" ] || enum=1 ;; '#include '*) includes="${includes} ${line###include }" ;; '#'*) echo "${line}" ;; [A-Z_]*) cond_def "$line" "$xlat_type" ;; '1<<'[A-Z_]*) # symbolic constants with shift [ XT_SORTED != "$xlat_type" ] || check_sort_order "1ULL<<${line#1<<}" ;; [0-9]*) # numeric constants [ XT_SORTED != "$xlat_type" ] || check_sort_order "${line}" ;; esac done < "$input" cat <<-EOF #undef XLAT_PREV_VAL #ifndef XLAT_MACROS_ONLY EOF [ -z "$unconditional" -o -z "$enum" ] || { echo "ignoring #enum due to #unconditional for ${input}" >&2 enum="" } [ 1 != "$enum" ] || ( echo "generating ${output_m4}" >&2 printf 'dnl Generated by %s from %s; do not edit.\n' \ "$0" "$input" printf 'AC_DEFUN([st_CHECK_ENUMS_%s],[\n' "$name" printf 'AC_CHECK_DECLS(m4_normalize([\n' ) > "${output_m4}" if [ -n "$in_defs" ]; then cat <<-EOF # ifndef IN_MPERS EOF elif [ -n "$in_mpers" ]; then cat <<-EOF # ifdef IN_MPERS ${decl} # else EOF else cat <<-EOF # ifdef IN_MPERS # error static const struct xlat ${name} in mpers mode # else EOF fi echo "DIAG_PUSH_IGNORE_TAUTOLOGICAL_CONSTANT_COMPARE" echo "static const struct xlat_data ${name}_xdata[] = {" unconditional= val_type= # 2nd pass: output everything. while read -r line; do case "$line" in */\**) line=$(printf "%s" "$line" | sed "s|[[:space:]]*/\*.*\*/[[:space:]]*||") ;; esac case ${line} in '#conditional') unconditional= ;; '#unconditional') unconditional=1 ;; '#sorted'|'#sorted '*) ;; '#value_indexed') ;; '#enum') ;; '#include '*) ;; '#val_type '*) val_type="${line#\#val_type }" ;; [A-Z_!]*) # symbolic constants cond_xlat "${line}" ;; '1<<'[A-Z_]*) # symbolic constants with shift cond_xlat "${line}" ;; [0-9]*) # numeric constants print_xlat "${line}" ;; *) # verbatim lines echo "${line}" ;; esac done < "${input}" echo '};' [ 1 != "$enum" ] || ( printf '\n]),,, [\n' [ -z "$includes" ] || printf '#include %s\n' $includes printf '])])])\n' # Providing macro name to main echo "st_CHECK_ENUMS_${name}" >&3 ) >> "${output_m4}" if [ -n "$in_defs" ]; then : elif [ -n "$in_mpers" ]; then cat <<-EOF # if !(defined HAVE_M32_MPERS || defined HAVE_MX32_MPERS) static # endif EOF else cat <<-EOF static EOF fi cat <<-EOF const struct xlat ${name}[1] = { { .data = ${name}_xdata, .size = ARRAY_SIZE(${name}_xdata), .type = ${xlat_type}, EOF echo " .flags_mask = 0" for i in $(seq 0 "$((xlat_flag_cnt - 1))"); do cat <<-EOF # ifdef XLAT_VAL_${i} | XLAT_VAL_${i} # endif EOF done echo " ," echo " .flags_strsz = 0" for i in $(seq 0 "$((xlat_flag_cnt - 1))"); do cat <<-EOF # ifdef XLAT_STR_${i} + sizeof(XLAT_STR_${i}) # endif EOF done echo " ," cat <<-EOF } }; DIAG_POP_IGNORE_TAUTOLOGICAL_CONSTANT_COMPARE EOF for i in $(seq 0 "$((xlat_flag_cnt - 1))"); do cat <<-EOF # undef XLAT_STR_${i} # undef XLAT_VAL_${i} EOF done cat <<-EOF # endif /* !IN_MPERS */ #endif /* !XLAT_MACROS_ONLY */ EOF ) >"${output}" exec 3>&- } gen_make() { local output="$1" local name shift echo "generating ${output}" >&2 ( printf "XLAT_INPUT_FILES = " printf 'xlat/%s.in ' "$@" echo printf "XLAT_HEADER_FILES = " printf 'xlat/%s.h ' "$@" echo for name; do printf '$(top_srcdir)/src/xlat/%s.h: $(top_srcdir)/src/xlat/%s.in $(top_srcdir)/src/xlat/gen.sh\n' \ "${name}" "${name}" echo ' $(AM_V_GEN)$(top_srcdir)/src/xlat/gen.sh $< $@' done ) >"${output}" } gen_git() { local output="$1" shift echo "generating ${output}" >&2 ( printf '/%s\n' .gitignore Makemodule.am st_check_enums.m4 printf '/%s.h\n' "$@" printf '/%s.m4\n' "$@" ) >"${output}" } gen_m4_entry() { local output output="$1"; shift echo "generating $output" >&2 { printf 'AC_DEFUN([st_CHECK_ENUMS],[\n' while read fun; do printf '\t%s\n' "$fun" done printf '])\n' } >"$output" } main() { case $# in 0) set -- "${0%/*}" "${0%/*}" ;; 2) ;; 3) ;; *) usage ;; esac local input="$1" local output="$2" local output_m4="${3:-}" local name local jobs=0 local ncpus="$(getconf _NPROCESSORS_ONLN)" local pids= [ "${ncpus}" -ge 1 ] || ncpus=1 if [ -d "${input}" ]; then ( local f names= set +f set -- "${input}"/*.in set -f for f; do [ -f "${f}" ] || continue name=${f##*/} name=${name%.in} gen_header "${f}" "${output}/${name}.h" "${name}" \ "${output}/${name}.m4" & pids="$pids $!" names="${names} ${name}" : $(( jobs += 1 )) if [ "${jobs}" -gt "$(( ncpus * 2 ))" ]; then read wait_pid rest pids="$rest" wait -n 2>/dev/null || wait "$wait_pid" : $(( jobs -= 1 )) fi <<- EOF $pids EOF done gen_git "${output}/.gitignore" ${names} & gen_make "${output}/Makemodule.am" ${names} & wait ) | sort | gen_m4_entry "${output}/st_check_enums.m4" else name=${input##*/} name=${name%.in} gen_header "${input}" "${output}" "${name}" "${output_m4}" \ > /dev/null fi } main "$@"