unrel_branch_check.sh 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. #!/bin/bash
  2. # SPDX-License-Identifier: GPL-2.0+
  3. # Copyright © 2016,2020 IBM Corporation
  4. #
  5. # This script checks the unrelocated code of a vmlinux for "suspicious"
  6. # branches to relocated code (head_64.S code).
  7. # Have Kbuild supply the path to objdump and nm so we handle cross compilation.
  8. objdump="$1"
  9. nm="$2"
  10. vmlinux="$3"
  11. kstart=0xc000000000000000
  12. end_intr=0x$($nm -p "$vmlinux" |
  13. sed -E -n '/\s+[[:alpha:]]\s+__end_interrupts\s*$/{s///p;q}')
  14. if [ "$end_intr" = "0x" ]; then
  15. exit 0
  16. fi
  17. # we know that there is a correct branch to
  18. # __start_initialization_multiplatform, so find its address
  19. # so we can exclude it.
  20. sim=0x$($nm -p "$vmlinux" |
  21. sed -E -n '/\s+[[:alpha:]]\s+__start_initialization_multiplatform\s*$/{s///p;q}')
  22. $objdump -D --no-show-raw-insn --start-address="$kstart" --stop-address="$end_intr" "$vmlinux" |
  23. sed -E -n '
  24. # match lines that start with a kernel address
  25. /^c[0-9a-f]*:\s*b/ {
  26. # drop branches via ctr or lr
  27. /\<b.?.?(ct|l)r/d
  28. # cope with some differences between Clang and GNU objdumps
  29. s/\<bt.?\s*[[:digit:]]+,/beq/
  30. s/\<bf.?\s*[[:digit:]]+,/bne/
  31. # tidy up
  32. s/\s0x/ /
  33. s/://
  34. # format for the loop below
  35. s/^(\S+)\s+(\S+)\s+(\S+)\s*(\S*).*$/\1:\2:\3:\4/
  36. # strip out condition registers
  37. s/:cr[0-7],/:/
  38. p
  39. }' | {
  40. all_good=true
  41. while IFS=: read -r from branch to sym; do
  42. case "$to" in
  43. c*) to="0x$to"
  44. ;;
  45. .+*)
  46. to=${to#.+}
  47. if [ "$branch" = 'b' ]; then
  48. if (( to >= 0x2000000 )); then
  49. to=$(( to - 0x4000000 ))
  50. fi
  51. elif (( to >= 0x8000 )); then
  52. to=$(( to - 0x10000 ))
  53. fi
  54. printf -v to '0x%x' $(( "0x$from" + to ))
  55. ;;
  56. *) printf 'Unkown branch format\n'
  57. ;;
  58. esac
  59. if [ "$to" = "$sim" ]; then
  60. continue
  61. fi
  62. if (( to > end_intr )); then
  63. if $all_good; then
  64. printf '%s\n' 'WARNING: Unrelocated relative branches'
  65. all_good=false
  66. fi
  67. printf '%s %s-> %s %s\n' "$from" "$branch" "$to" "$sym"
  68. fi
  69. done
  70. $all_good
  71. }