| 1 | #!/bin/sh |
| 2 | # SPDX-License-Identifier: GPL-2.0-only |
| 3 | # |
| 4 | # Copyright (C) 2022 Masahiro Yamada <[email protected]> |
| 5 | # Copyright (C) 2022 Owen Rafferty <[email protected]> |
| 6 | # |
| 7 | # Exit with error if a local exported symbol is found. |
| 8 | # EXPORT_SYMBOL should be used for global symbols. |
| 9 | |
| 10 | set -e |
| 11 | pid=$$ |
| 12 | |
| 13 | # If there is no symbol in the object, ${NM} (both GNU nm and llvm-nm) shows |
| 14 | # 'no symbols' diagnostic (but exits with 0). It is harmless and hidden by |
| 15 | # '2>/dev/null'. However, it suppresses real error messages as well. Add a |
| 16 | # hand-crafted error message here. |
| 17 | # |
| 18 | # TODO: |
| 19 | # Use --quiet instead of 2>/dev/null when we upgrade the minimum version of |
| 20 | # binutils to 2.37, llvm to 13.0.0. |
| 21 | # Then, the following line will be simpler: |
| 22 | # { ${NM} --quiet ${1} || kill 0; } | |
| 23 | |
| 24 | { ${NM} ${1} 2>/dev/null || { echo "${0}: ${NM} failed" >&2; kill $pid; } } | |
| 25 | ${AWK} -v "file=${1}" ' |
| 26 | BEGIN { |
| 27 | i = 0 |
| 28 | } |
| 29 | |
| 30 | # Skip the line if the number of fields is less than 3. |
| 31 | # |
| 32 | # case 1) |
| 33 | # For undefined symbols, the first field (value) is empty. |
| 34 | # The outout looks like this: |
| 35 | # " U _printk" |
| 36 | # It is unneeded to record undefined symbols. |
| 37 | # |
| 38 | # case 2) |
| 39 | # For Clang LTO, llvm-nm outputs a line with type t but empty name: |
| 40 | # "---------------- t" |
| 41 | !length($3) { |
| 42 | next |
| 43 | } |
| 44 | |
| 45 | # save (name, type) in the associative array |
| 46 | { symbol_types[$3]=$2 } |
| 47 | |
| 48 | # append the exported symbol to the array |
| 49 | ($3 ~ /^__ksymtab_/) { |
| 50 | export_symbols[i] = $3 |
| 51 | sub(/^__ksymtab_/, "", export_symbols[i]) |
| 52 | i++ |
| 53 | } |
| 54 | |
| 55 | END { |
| 56 | exit_code = 0 |
| 57 | for (j = 0; j < i; ++j) { |
| 58 | name = export_symbols[j] |
| 59 | # nm(3) says "If lowercase, the symbol is usually local" |
| 60 | if (symbol_types[name] ~ /[a-z]/) { |
| 61 | printf "%s: error: local symbol %s was exported\n", |
| 62 | file, name | "cat 1>&2" |
| 63 | exit_code = 1 |
| 64 | } |
| 65 | } |
| 66 | |
| 67 | exit exit_code |
| 68 | }' |
| 69 | |
| 70 | exit $? |