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