diff options
Diffstat (limited to 'scripts/check-localplt-2.sh')
-rwxr-xr-x | scripts/check-localplt-2.sh | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/scripts/check-localplt-2.sh b/scripts/check-localplt-2.sh new file mode 100755 index 0000000000..d51b7e7387 --- /dev/null +++ b/scripts/check-localplt-2.sh @@ -0,0 +1,171 @@ +#! /bin/sh + +# This shell script performs a fine-grained test for unwanted calls +# through the PLT. It expects its first command line argument to +# be a specification of expected results, in the same format that +# check-localplt.awk uses, and the rest of the arguments to be _pic.a +# archives which should be checked. AWK should be set in the +# environment. + +set -e +if [ -n "$BASH_VERSION" ]; then + set -o pipefail +fi + +LC_ALL=C +export LC_ALL + +all_expectations="$(mktemp)" +unsorted_output="$(mktemp)" +trap "rm -f '$all_expectations' '$unsorted_output'" 0 + +# Preprocess the expected PLT calls. +while [ x"$1" != x-- ]; do + grep -Ev '^($|#)' "$1" >> "$all_expectations" + shift +done +shift + +for lib in "$@"; do + readelf -WSrs "$lib" | tr -s ' ' ' ' | "${AWK-awk}" ' +BEGIN { + # Whitelist of relocation types that are allowed to appear in a text + # section, regardless of the name of the symbol. Since the ELF R_* + # constants already contain an architecture label, we can use just + # one big whitelist and each architecture will only notice the + # values that are relevant to it. + # + # For most architectures, the relocation types that are OK are those + # used for a reference, from within a shared object, to a symbol + # that was visible as external, but hidden, when the object file was + # compiled. There are usually at least three, one for functions, + # one for ordinary data, and one for thread-local data. + # + # Please keep this list in alphabetical order. + + ok_relocs["R_X86_64_GOTPC32"] = 1; + ok_relocs["R_X86_64_GOTPCREL"] = 1; + ok_relocs["R_X86_64_GOTPCRELX"] = 1; + ok_relocs["R_X86_64_GOTTPOFF"] = 1; + ok_relocs["R_X86_64_PC32"] = 1; + ok_relocs["R_X86_64_REX_GOTPCRELX"] = 1; + + # The state machine is reset every time we see a "File:" line, but + # set it up here anyway as a backstop. + in_section_headers = 0; + in_text_relocs = 0; + in_symbol_table = 0; + delete text_sections; +} +$1 == "File:" { + fname = $0; + sub(/^File: */, "", fname); + sub(/\(/, " ", fname); + sub(/\)/, "", fname); + + in_section_headers = 0; + in_text_relocs = 0; + in_symbol_table = 0; + delete text_sections; + next; +} +$0 == "" { + in_text_relocs = 0; + in_section_headers = 0; + in_symbol_table = 0; + next; +} + +# We only care about relocations against code, but there may be a lot of +# code sections with weird names, so we parse the section headers to +# find them all. This is trickier than it ought to be because readelf -S +# output is not precisely space-separated columns. +# We rely on "readelf -WSrs" to print the section headers first and the +# relocation entries second. +$0 == "Section Headers:" { in_section_headers = 1; delete text_sections; next; } +$0 == "Key to Flags:" { in_section_headers = 0; next; } +in_section_headers { + if (/ PROGBITS / && / AX / && !/\[Nr\]/) { + sub(/^ *\[[ 0-9]*\] */, ""); + text_sections[$1] = 1; + } + next; +} + +/^Relocation section '\''/ { + section = $3 + gsub(/'\''/, "", section) + sub(/^\.rela?/, "", section) + in_text_relocs = (section in text_sections); + next; +} + +# Relocation section dumps _are_ space-separated columns, or close enough +# for what we need. Print the relocation type and the symbol name for +# each relocation that addresses a symbol. +in_text_relocs && $1 ~ /^[0-9a-f]/ && $5 !~ /^\./ && !($3 in ok_relocs) { + print fname " " $3 " " $5 +} + +# Also print out all of the symbols that are defined by this library. +# Cross-library references have to go through the PLT regardless. +/^Symbol table '\''/ { + in_symbol_table = 1; + next; +} +in_symbol_table && $7 != "UND" \ + && ($5 == "GLOBAL" || $5 == "WEAK") \ + && ($4 != "NOTYPE" && $4 != "FILE" && $4 != "SECTION") \ +{ + print fname " _DEFINITION_ " $8 +} +' +done | ${AWK-awk} ' +FILENAME != "-" { + # Note: unlike check-localplt.awk, this program ignores +/? and relocation + # type annotations in the whitelist file. + # Comments were already stripped above. + library = $1; + symbol = $2; + sub(/:$/, "", library); + sub(/\.so$/, "", library); + ok_symbols[library,symbol] = 1; +} +FILENAME == "-" { + library = $1; + symbol = $4; + sub(/^.*\//, "", library); + sub(/\.so$/, "", library); + sub(/\.a$/, "", library); + sub(/_pic$/, "", library); + sub(/@.*$/, "", symbol); + + if ($3 == "_DEFINITION_") { + defined_syms[library,symbol] = 1; + } else { + if (!((library,symbol) in ok_symbols) && !(("*",symbol) in ok_symbols)) { + if ((library,symbol) in maybe_bad_syms) { + maybe_bad_syms[library,symbol] = maybe_bad_syms[library,symbol] "\n" $0; + } else { + maybe_bad_syms[library,symbol] = $0; + } + } + } +} +END { + for (libsym in maybe_bad_syms) { + if (libsym in defined_syms) { + print maybe_bad_syms[libsym]; + result = 1; + } + } +} +' "$all_expectations" - > "$unsorted_output" + +if [ -s "$unsorted_output" ]; then + echo "*** Undesirable relocations:" + sed -e 's:^[^ ]*/::' < "$unsorted_output" | sort -u + exit 1 +else + exit 0 +fi |