.. | .. |
---|
1 | | -# Copyright © 2016 IBM Corporation |
---|
| 1 | +#!/bin/bash |
---|
| 2 | +# SPDX-License-Identifier: GPL-2.0+ |
---|
| 3 | +# Copyright © 2016,2020 IBM Corporation |
---|
2 | 4 | # |
---|
3 | | -# This program is free software; you can redistribute it and/or |
---|
4 | | -# modify it under the terms of the GNU General Public License |
---|
5 | | -# as published by the Free Software Foundation; either version |
---|
6 | | -# 2 of the License, or (at your option) any later version. |
---|
7 | | -# |
---|
8 | | -# This script checks the relocations of a vmlinux for "suspicious" |
---|
9 | | -# branches from unrelocated code (head_64.S code). |
---|
| 5 | +# This script checks the unrelocated code of a vmlinux for "suspicious" |
---|
| 6 | +# branches to relocated code (head_64.S code). |
---|
10 | 7 | |
---|
11 | | -# Turn this on if you want more debug output: |
---|
12 | | -# set -x |
---|
13 | | - |
---|
14 | | -# Have Kbuild supply the path to objdump so we handle cross compilation. |
---|
| 8 | +# Have Kbuild supply the path to objdump and nm so we handle cross compilation. |
---|
15 | 9 | objdump="$1" |
---|
16 | | -vmlinux="$2" |
---|
| 10 | +nm="$2" |
---|
| 11 | +vmlinux="$3" |
---|
17 | 12 | |
---|
18 | | -#__end_interrupts should be located within the first 64K |
---|
| 13 | +kstart=0xc000000000000000 |
---|
19 | 14 | |
---|
20 | | -end_intr=0x$( |
---|
21 | | -$objdump -R "$vmlinux" -d --start-address=0xc000000000000000 \ |
---|
22 | | - --stop-address=0xc000000000010000 | |
---|
23 | | -grep '\<__end_interrupts>:' | |
---|
24 | | -awk '{print $1}' |
---|
25 | | -) |
---|
| 15 | +end_intr=0x$($nm -p "$vmlinux" | |
---|
| 16 | + sed -E -n '/\s+[[:alpha:]]\s+__end_interrupts\s*$/{s///p;q}') |
---|
| 17 | +if [ "$end_intr" = "0x" ]; then |
---|
| 18 | + exit 0 |
---|
| 19 | +fi |
---|
26 | 20 | |
---|
27 | | -BRANCHES=$( |
---|
28 | | -$objdump -R "$vmlinux" -D --start-address=0xc000000000000000 \ |
---|
29 | | - --stop-address=${end_intr} | |
---|
30 | | -grep -e "^c[0-9a-f]*:[[:space:]]*\([0-9a-f][0-9a-f][[:space:]]\)\{4\}[[:space:]]*b" | |
---|
31 | | -grep -v '\<__start_initialization_multiplatform>' | |
---|
32 | | -grep -v -e 'b.\?.\?ctr' | |
---|
33 | | -grep -v -e 'b.\?.\?lr' | |
---|
34 | | -sed 's/://' | |
---|
35 | | -awk '{ print $1 ":" $6 ":0x" $7 ":" $8 " "}' |
---|
36 | | -) |
---|
| 21 | +# we know that there is a correct branch to |
---|
| 22 | +# __start_initialization_multiplatform, so find its address |
---|
| 23 | +# so we can exclude it. |
---|
| 24 | +sim=0x$($nm -p "$vmlinux" | |
---|
| 25 | + sed -E -n '/\s+[[:alpha:]]\s+__start_initialization_multiplatform\s*$/{s///p;q}') |
---|
37 | 26 | |
---|
38 | | -for tuple in $BRANCHES |
---|
39 | | -do |
---|
40 | | - from=`echo $tuple | cut -d':' -f1` |
---|
41 | | - branch=`echo $tuple | cut -d':' -f2` |
---|
42 | | - to=`echo $tuple | cut -d':' -f3 | sed 's/cr[0-7],//'` |
---|
43 | | - sym=`echo $tuple | cut -d':' -f4` |
---|
| 27 | +$objdump -D --no-show-raw-insn --start-address="$kstart" --stop-address="$end_intr" "$vmlinux" | |
---|
| 28 | +sed -E -n ' |
---|
| 29 | +# match lines that start with a kernel address |
---|
| 30 | +/^c[0-9a-f]*:\s*b/ { |
---|
| 31 | + # drop branches via ctr or lr |
---|
| 32 | + /\<b.?.?(ct|l)r/d |
---|
| 33 | + # cope with some differences between Clang and GNU objdumps |
---|
| 34 | + s/\<bt.?\s*[[:digit:]]+,/beq/ |
---|
| 35 | + s/\<bf.?\s*[[:digit:]]+,/bne/ |
---|
| 36 | + # tidy up |
---|
| 37 | + s/\s0x/ / |
---|
| 38 | + s/:// |
---|
| 39 | + # format for the loop below |
---|
| 40 | + s/^(\S+)\s+(\S+)\s+(\S+)\s*(\S*).*$/\1:\2:\3:\4/ |
---|
| 41 | + # strip out condition registers |
---|
| 42 | + s/:cr[0-7],/:/ |
---|
| 43 | + p |
---|
| 44 | +}' | { |
---|
44 | 45 | |
---|
45 | | - if (( $to > $end_intr )) |
---|
46 | | - then |
---|
47 | | - if [ -z "$bad_branches" ]; then |
---|
48 | | - echo "WARNING: Unrelocated relative branches" |
---|
49 | | - bad_branches="yes" |
---|
| 46 | +all_good=true |
---|
| 47 | +while IFS=: read -r from branch to sym; do |
---|
| 48 | + case "$to" in |
---|
| 49 | + c*) to="0x$to" |
---|
| 50 | + ;; |
---|
| 51 | + .+*) |
---|
| 52 | + to=${to#.+} |
---|
| 53 | + if [ "$branch" = 'b' ]; then |
---|
| 54 | + if (( to >= 0x2000000 )); then |
---|
| 55 | + to=$(( to - 0x4000000 )) |
---|
| 56 | + fi |
---|
| 57 | + elif (( to >= 0x8000 )); then |
---|
| 58 | + to=$(( to - 0x10000 )) |
---|
50 | 59 | fi |
---|
51 | | - echo "$from $branch-> $to $sym" |
---|
| 60 | + printf -v to '0x%x' $(( "0x$from" + to )) |
---|
| 61 | + ;; |
---|
| 62 | + *) printf 'Unkown branch format\n' |
---|
| 63 | + ;; |
---|
| 64 | + esac |
---|
| 65 | + if [ "$to" = "$sim" ]; then |
---|
| 66 | + continue |
---|
| 67 | + fi |
---|
| 68 | + if (( to > end_intr )); then |
---|
| 69 | + if $all_good; then |
---|
| 70 | + printf '%s\n' 'WARNING: Unrelocated relative branches' |
---|
| 71 | + all_good=false |
---|
| 72 | + fi |
---|
| 73 | + printf '%s %s-> %s %s\n' "$from" "$branch" "$to" "$sym" |
---|
52 | 74 | fi |
---|
53 | 75 | done |
---|
54 | 76 | |
---|
55 | | -if [ -z "$bad_branches" ]; then |
---|
56 | | - exit 0 |
---|
57 | | -fi |
---|
| 77 | +$all_good |
---|
| 78 | + |
---|
| 79 | +} |
---|