gen-atomic-instrumented.sh 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. #!/bin/sh
  2. # SPDX-License-Identifier: GPL-2.0
  3. ATOMICDIR=$(dirname $0)
  4. . ${ATOMICDIR}/atomic-tbl.sh
  5. #gen_param_check(meta, arg)
  6. gen_param_check()
  7. {
  8. local meta="$1"; shift
  9. local arg="$1"; shift
  10. local type="${arg%%:*}"
  11. local name="$(gen_param_name "${arg}")"
  12. local rw="write"
  13. case "${type#c}" in
  14. i) return;;
  15. esac
  16. if [ ${type#c} != ${type} ]; then
  17. # We don't write to constant parameters.
  18. rw="read"
  19. elif [ "${meta}" != "s" ]; then
  20. # An atomic RMW: if this parameter is not a constant, and this atomic is
  21. # not just a 's'tore, this parameter is both read from and written to.
  22. rw="read_write"
  23. fi
  24. printf "\tinstrument_atomic_${rw}(${name}, sizeof(*${name}));\n"
  25. }
  26. #gen_params_checks(meta, arg...)
  27. gen_params_checks()
  28. {
  29. local meta="$1"; shift
  30. local order="$1"; shift
  31. if [ "${order}" = "_release" ]; then
  32. printf "\tkcsan_release();\n"
  33. elif [ -z "${order}" ] && ! meta_in "$meta" "slv"; then
  34. # RMW with return value is fully ordered
  35. printf "\tkcsan_mb();\n"
  36. fi
  37. while [ "$#" -gt 0 ]; do
  38. gen_param_check "$meta" "$1"
  39. shift;
  40. done
  41. }
  42. #gen_proto_order_variant(meta, pfx, name, sfx, order, atomic, int, arg...)
  43. gen_proto_order_variant()
  44. {
  45. local meta="$1"; shift
  46. local pfx="$1"; shift
  47. local name="$1"; shift
  48. local sfx="$1"; shift
  49. local order="$1"; shift
  50. local atomic="$1"; shift
  51. local int="$1"; shift
  52. local atomicname="${atomic}_${pfx}${name}${sfx}${order}"
  53. local ret="$(gen_ret_type "${meta}" "${int}")"
  54. local params="$(gen_params "${int}" "${atomic}" "$@")"
  55. local checks="$(gen_params_checks "${meta}" "${order}" "$@")"
  56. local args="$(gen_args "$@")"
  57. local retstmt="$(gen_ret_stmt "${meta}")"
  58. cat <<EOF
  59. static __always_inline ${ret}
  60. ${atomicname}(${params})
  61. {
  62. ${checks}
  63. ${retstmt}arch_${atomicname}(${args});
  64. }
  65. EOF
  66. printf "\n"
  67. }
  68. gen_xchg()
  69. {
  70. local xchg="$1"; shift
  71. local order="$1"; shift
  72. local mult="$1"; shift
  73. kcsan_barrier=""
  74. if [ "${xchg%_local}" = "${xchg}" ]; then
  75. case "$order" in
  76. _release) kcsan_barrier="kcsan_release()" ;;
  77. "") kcsan_barrier="kcsan_mb()" ;;
  78. esac
  79. fi
  80. if [ "${xchg%${xchg#try_cmpxchg}}" = "try_cmpxchg" ] ; then
  81. cat <<EOF
  82. #define ${xchg}${order}(ptr, oldp, ...) \\
  83. ({ \\
  84. typeof(ptr) __ai_ptr = (ptr); \\
  85. typeof(oldp) __ai_oldp = (oldp); \\
  86. EOF
  87. [ -n "$kcsan_barrier" ] && printf "\t${kcsan_barrier}; \\\\\n"
  88. cat <<EOF
  89. instrument_atomic_write(__ai_ptr, ${mult}sizeof(*__ai_ptr)); \\
  90. instrument_atomic_write(__ai_oldp, ${mult}sizeof(*__ai_oldp)); \\
  91. arch_${xchg}${order}(__ai_ptr, __ai_oldp, __VA_ARGS__); \\
  92. })
  93. EOF
  94. else
  95. cat <<EOF
  96. #define ${xchg}${order}(ptr, ...) \\
  97. ({ \\
  98. typeof(ptr) __ai_ptr = (ptr); \\
  99. EOF
  100. [ -n "$kcsan_barrier" ] && printf "\t${kcsan_barrier}; \\\\\n"
  101. cat <<EOF
  102. instrument_atomic_write(__ai_ptr, ${mult}sizeof(*__ai_ptr)); \\
  103. arch_${xchg}${order}(__ai_ptr, __VA_ARGS__); \\
  104. })
  105. EOF
  106. fi
  107. }
  108. cat << EOF
  109. // SPDX-License-Identifier: GPL-2.0
  110. // Generated by $0
  111. // DO NOT MODIFY THIS FILE DIRECTLY
  112. /*
  113. * This file provides wrappers with KASAN instrumentation for atomic operations.
  114. * To use this functionality an arch's atomic.h file needs to define all
  115. * atomic operations with arch_ prefix (e.g. arch_atomic_read()) and include
  116. * this file at the end. This file provides atomic_read() that forwards to
  117. * arch_atomic_read() for actual atomic operation.
  118. * Note: if an arch atomic operation is implemented by means of other atomic
  119. * operations (e.g. atomic_read()/atomic_cmpxchg() loop), then it needs to use
  120. * arch_ variants (i.e. arch_atomic_read()/arch_atomic_cmpxchg()) to avoid
  121. * double instrumentation.
  122. */
  123. #ifndef _LINUX_ATOMIC_INSTRUMENTED_H
  124. #define _LINUX_ATOMIC_INSTRUMENTED_H
  125. #include <linux/build_bug.h>
  126. #include <linux/compiler.h>
  127. #include <linux/instrumented.h>
  128. EOF
  129. grep '^[a-z]' "$1" | while read name meta args; do
  130. gen_proto "${meta}" "${name}" "atomic" "int" ${args}
  131. done
  132. grep '^[a-z]' "$1" | while read name meta args; do
  133. gen_proto "${meta}" "${name}" "atomic64" "s64" ${args}
  134. done
  135. grep '^[a-z]' "$1" | while read name meta args; do
  136. gen_proto "${meta}" "${name}" "atomic_long" "long" ${args}
  137. done
  138. for xchg in "xchg" "cmpxchg" "cmpxchg64" "try_cmpxchg" "try_cmpxchg64"; do
  139. for order in "" "_acquire" "_release" "_relaxed"; do
  140. gen_xchg "${xchg}" "${order}" ""
  141. printf "\n"
  142. done
  143. done
  144. for xchg in "cmpxchg_local" "cmpxchg64_local" "sync_cmpxchg"; do
  145. gen_xchg "${xchg}" "" ""
  146. printf "\n"
  147. done
  148. gen_xchg "cmpxchg_double" "" "2 * "
  149. printf "\n\n"
  150. gen_xchg "cmpxchg_double_local" "" "2 * "
  151. cat <<EOF
  152. #endif /* _LINUX_ATOMIC_INSTRUMENTED_H */
  153. EOF