1#! /bin/bash 2# SPDX-License-Identifier: GPL-2.0 3# (c) 2015, Quentin Casasnovas <quentin.casasnovas@oracle.com> 4 5obj=$1 6 7file ${obj} | grep -q ELF || (echo "${obj} is not an ELF file." 1>&2 ; exit 0) 8 9# Bail out early if there isn't an __ex_table section in this object file. 10objdump -hj __ex_table ${obj} 2> /dev/null > /dev/null 11[ $? -ne 0 ] && exit 0 12 13white_list=.text,.fixup 14 15suspicious_relocs=$(objdump -rj __ex_table ${obj} | tail -n +6 | 16 grep -v $(eval echo -e{${white_list}}) | awk '{print $3}') 17 18# No suspicious relocs in __ex_table, jobs a good'un 19[ -z "${suspicious_relocs}" ] && exit 0 20 21 22# After this point, something is seriously wrong since we just found out we 23# have some relocations in __ex_table which point to sections which aren't 24# white listed. If you're adding a new section in the Linux kernel, and 25# you're expecting this section to contain code which can fault (i.e. the 26# __ex_table relocation to your new section is expected), simply add your 27# new section to the white_list variable above. If not, you're probably 28# doing something wrong and the rest of this code is just trying to print 29# you more information about it. 30 31function find_section_offset_from_symbol() 32{ 33 eval $(objdump -t ${obj} | grep ${1} | sed 's/\([0-9a-f]\+\) .\{7\} \([^ \t]\+\).*/section="\2"; section_offset="0x\1" /') 34 35 # addr2line takes addresses in hexadecimal... 36 section_offset=$(printf "0x%016x" $(( ${section_offset} + $2 )) ) 37} 38 39function find_symbol_and_offset_from_reloc() 40{ 41 # Extract symbol and offset from the objdump output 42 eval $(echo $reloc | sed 's/\([^+]\+\)+\?\(0x[0-9a-f]\+\)\?/symbol="\1"; symbol_offset="\2"/') 43 44 # When the relocation points to the begining of a symbol or section, it 45 # won't print the offset since it is zero. 46 if [ -z "${symbol_offset}" ]; then 47 symbol_offset=0x0 48 fi 49} 50 51function find_alt_replacement_target() 52{ 53 # The target of the .altinstr_replacement is the relocation just before 54 # the .altinstr_replacement one. 55 eval $(objdump -rj .altinstructions ${obj} | grep -B1 "${section}+${section_offset}" | head -n1 | awk '{print $3}' | 56 sed 's/\([^+]\+\)+\(0x[0-9a-f]\+\)/alt_target_section="\1"; alt_target_offset="\2"/') 57} 58 59function handle_alt_replacement_reloc() 60{ 61 # This will define alt_target_section and alt_target_section_offset 62 find_alt_replacement_target ${section} ${section_offset} 63 64 echo "Error: found a reference to .altinstr_replacement in __ex_table:" 65 addr2line -fip -j ${alt_target_section} -e ${obj} ${alt_target_offset} | awk '{print "\t" $0}' 66 67 error=true 68} 69 70function is_executable_section() 71{ 72 objdump -hwj ${section} ${obj} | grep -q CODE 73 return $? 74} 75 76function handle_suspicious_generic_reloc() 77{ 78 if is_executable_section ${section}; then 79 # We've got a relocation to a non white listed _executable_ 80 # section, print a warning so the developper adds the section to 81 # the white list or fix his code. We try to pretty-print the file 82 # and line number where that relocation was added. 83 echo "Warning: found a reference to section \"${section}\" in __ex_table:" 84 addr2line -fip -j ${section} -e ${obj} ${section_offset} | awk '{print "\t" $0}' 85 else 86 # Something is definitively wrong here since we've got a relocation 87 # to a non-executable section, there's no way this would ever be 88 # running in the kernel. 89 echo "Error: found a reference to non-executable section \"${section}\" in __ex_table at offset ${section_offset}" 90 error=true 91 fi 92} 93 94function handle_suspicious_reloc() 95{ 96 case "${section}" in 97 ".altinstr_replacement") 98 handle_alt_replacement_reloc ${section} ${section_offset} 99 ;; 100 *) 101 handle_suspicious_generic_reloc ${section} ${section_offset} 102 ;; 103 esac 104} 105 106function diagnose() 107{ 108 109 for reloc in ${suspicious_relocs}; do 110 # Let's find out where the target of the relocation in __ex_table 111 # is, this will define ${symbol} and ${symbol_offset} 112 find_symbol_and_offset_from_reloc ${reloc} 113 114 # When there's a global symbol at the place of the relocation, 115 # objdump will use it instead of giving us a section+offset, so 116 # let's find out which section is this symbol in and the total 117 # offset withing that section. 118 find_section_offset_from_symbol ${symbol} ${symbol_offset} 119 120 # In this case objdump was presenting us with a reloc to a symbol 121 # rather than a section. Now that we've got the actual section, 122 # we can skip it if it's in the white_list. 123 if [ -z "$( echo $section | grep -v $(eval echo -e{${white_list}}))" ]; then 124 continue; 125 fi 126 127 # Will either print a warning if the relocation happens to be in a 128 # section we do not know but has executable bit set, or error out. 129 handle_suspicious_reloc 130 done 131} 132 133function check_debug_info() { 134 objdump -hj .debug_info ${obj} 2> /dev/null > /dev/null || 135 echo -e "${obj} does not contain debug information, the addr2line output will be limited.\n" \ 136 "Recompile ${obj} with CONFIG_DEBUG_INFO to get a more useful output." 137} 138 139check_debug_info 140 141diagnose 142 143if [ "${error}" ]; then 144 exit 1 145fi 146 147exit 0 148