diff options
Diffstat (limited to 'src/xlat/gen.sh')
-rwxr-xr-x | src/xlat/gen.sh | 484 |
1 files changed, 484 insertions, 0 deletions
diff --git a/src/xlat/gen.sh b/src/xlat/gen.sh new file mode 100755 index 000000000..a952cb822 --- /dev/null +++ b/src/xlat/gen.sh @@ -0,0 +1,484 @@ +#!/bin/sh -efu +# +# Copyright (c) 2014-2015 Mike Frysinger <vapier@gentoo.org> +# Copyright (c) 2014-2015 Dmitry V. Levin <ldv@strace.io> +# Copyright (c) 2014-2020 The strace developers. +# All rights reserved. +# +# SPDX-License-Identifier: LGPL-2.1-or-later + +export LC_ALL=C + +usage() +{ + cat <<EOF +Usage: $0 <input> <output> + +Generate xlat header files from <input> (a file or dir of files) and write +the generated headers to <output>. +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 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 + printf "%s\n" \ + "#if defined($val) || (defined(HAVE_DECL_$val) && HAVE_DECL_$val)" \ + "DIAG_PUSH_IGNORE_TAUTOLOGICAL_COMPARE" \ + "static_assert(($val) == ($def), \"$val != $def\");" \ + "DIAG_POP_IGNORE_TAUTOLOGICAL_COMPARE" \ + "#else" \ + "# define $val $def" \ + "#endif" + fi +} + +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}" ]; then + printf "%s\n" \ + "#if defined(${m}) || (defined(HAVE_DECL_${m}) && HAVE_DECL_${m})" \ + " ${xlat}" \ + "#endif" + else + echo "$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 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_]*) + [ -n "$unconditional" ] || + cond_def "$line" + ;; + esac + done < "$input" + + cat <<-EOF + + #ifndef XLAT_MACROS_ONLY + + EOF + + [ "$enum" != 1 ] || ( + 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 "static const struct xlat_data ${name}_xdata[] = {" + + unconditional= val_type= + # 2nd pass: output everything. + while read 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 + if [ -n "${unconditional}" ]; then + print_xlat "${line}" + else + cond_xlat "${line}" + fi + ;; + '1<<'[A-Z_]*) # symbolic constants with shift + if [ -n "${unconditional}" ]; then + print_xlat_pair "1ULL<<${line#1<<}" "${line}" "${line#1<<}" + else + cond_xlat "${line}" + fi + ;; + [0-9]*) # numeric constants + print_xlat "${line}" + ;; + *) # verbatim lines + echo "${line}" + ;; + esac + done < "${input}" + echo '};' + + [ "$enum" != 1 ] || ( + 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 + } }; + + 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 "$@" |