162306a36Sopenharmony_ci#!/bin/bash
262306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0+
362306a36Sopenharmony_ci# Copyright © 2016,2020 IBM Corporation
462306a36Sopenharmony_ci#
562306a36Sopenharmony_ci# This script checks the unrelocated code of a vmlinux for "suspicious"
662306a36Sopenharmony_ci# branches to relocated code (head_64.S code).
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci# Have Kbuild supply the path to objdump and nm so we handle cross compilation.
962306a36Sopenharmony_ciobjdump="$1"
1062306a36Sopenharmony_cinm="$2"
1162306a36Sopenharmony_civmlinux="$3"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cikstart=0xc000000000000000
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ciend_intr=0x$($nm -p "$vmlinux" |
1662306a36Sopenharmony_ci	sed -E -n '/\s+[[:alpha:]]\s+__end_interrupts\s*$/{s///p;q}')
1762306a36Sopenharmony_ciif [ "$end_intr" = "0x" ]; then
1862306a36Sopenharmony_ci	exit 0
1962306a36Sopenharmony_cifi
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci# we know that there is a correct branch to
2262306a36Sopenharmony_ci# __start_initialization_multiplatform, so find its address
2362306a36Sopenharmony_ci# so we can exclude it.
2462306a36Sopenharmony_cisim=0x$($nm -p "$vmlinux" |
2562306a36Sopenharmony_ci	sed -E -n '/\s+[[:alpha:]]\s+__start_initialization_multiplatform\s*$/{s///p;q}')
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci$objdump -D --no-show-raw-insn --start-address="$kstart" --stop-address="$end_intr" "$vmlinux" |
2862306a36Sopenharmony_cised -E -n '
2962306a36Sopenharmony_ci# match lines that start with a kernel address
3062306a36Sopenharmony_ci/^c[0-9a-f]*:\s*b/ {
3162306a36Sopenharmony_ci	# drop branches via ctr or lr
3262306a36Sopenharmony_ci	/\<b.?.?(ct|l)r/d
3362306a36Sopenharmony_ci	# cope with some differences between Clang and GNU objdumps
3462306a36Sopenharmony_ci	s/\<bt.?\s*[[:digit:]]+,/beq/
3562306a36Sopenharmony_ci	s/\<bf.?\s*[[:digit:]]+,/bne/
3662306a36Sopenharmony_ci	# tidy up
3762306a36Sopenharmony_ci	s/\s0x/ /
3862306a36Sopenharmony_ci	s/://
3962306a36Sopenharmony_ci	# format for the loop below
4062306a36Sopenharmony_ci	s/^(\S+)\s+(\S+)\s+(\S+)\s*(\S*).*$/\1:\2:\3:\4/
4162306a36Sopenharmony_ci	# strip out condition registers
4262306a36Sopenharmony_ci	s/:cr[0-7],/:/
4362306a36Sopenharmony_ci	p
4462306a36Sopenharmony_ci}' | {
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ciall_good=true
4762306a36Sopenharmony_ciwhile IFS=: read -r from branch to sym; do
4862306a36Sopenharmony_ci	case "$to" in
4962306a36Sopenharmony_ci	c*)	to="0x$to"
5062306a36Sopenharmony_ci		;;
5162306a36Sopenharmony_ci	.+*)
5262306a36Sopenharmony_ci		to=${to#.+}
5362306a36Sopenharmony_ci		if [ "$branch" = 'b' ]; then
5462306a36Sopenharmony_ci			if (( to >= 0x2000000 )); then
5562306a36Sopenharmony_ci				to=$(( to - 0x4000000 ))
5662306a36Sopenharmony_ci			fi
5762306a36Sopenharmony_ci		elif (( to >= 0x8000 )); then
5862306a36Sopenharmony_ci			to=$(( to - 0x10000 ))
5962306a36Sopenharmony_ci		fi
6062306a36Sopenharmony_ci		printf -v to '0x%x' $(( "0x$from" + to ))
6162306a36Sopenharmony_ci		;;
6262306a36Sopenharmony_ci	*)	printf 'Unkown branch format\n'
6362306a36Sopenharmony_ci		;;
6462306a36Sopenharmony_ci	esac
6562306a36Sopenharmony_ci	if [ "$to" = "$sim" ]; then
6662306a36Sopenharmony_ci		continue
6762306a36Sopenharmony_ci	fi
6862306a36Sopenharmony_ci	if (( to > end_intr )); then
6962306a36Sopenharmony_ci		if $all_good; then
7062306a36Sopenharmony_ci			printf '%s\n' 'WARNING: Unrelocated relative branches'
7162306a36Sopenharmony_ci			all_good=false
7262306a36Sopenharmony_ci		fi
7362306a36Sopenharmony_ci		printf '%s %s-> %s %s\n' "$from" "$branch" "$to" "$sym"
7462306a36Sopenharmony_ci	fi
7562306a36Sopenharmony_cidone
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci$all_good
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci}
80