18c2ecf20Sopenharmony_ci#!/bin/bash
28c2ecf20Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0+
38c2ecf20Sopenharmony_ci# Copyright © 2016,2020 IBM Corporation
48c2ecf20Sopenharmony_ci#
58c2ecf20Sopenharmony_ci# This script checks the unrelocated code of a vmlinux for "suspicious"
68c2ecf20Sopenharmony_ci# branches to relocated code (head_64.S code).
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci# Have Kbuild supply the path to objdump and nm so we handle cross compilation.
98c2ecf20Sopenharmony_ciobjdump="$1"
108c2ecf20Sopenharmony_cinm="$2"
118c2ecf20Sopenharmony_civmlinux="$3"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cikstart=0xc000000000000000
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ciend_intr=0x$($nm -p "$vmlinux" |
168c2ecf20Sopenharmony_ci	sed -E -n '/\s+[[:alpha:]]\s+__end_interrupts\s*$/{s///p;q}')
178c2ecf20Sopenharmony_ciif [ "$end_intr" = "0x" ]; then
188c2ecf20Sopenharmony_ci	exit 0
198c2ecf20Sopenharmony_cifi
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci# we know that there is a correct branch to
228c2ecf20Sopenharmony_ci# __start_initialization_multiplatform, so find its address
238c2ecf20Sopenharmony_ci# so we can exclude it.
248c2ecf20Sopenharmony_cisim=0x$($nm -p "$vmlinux" |
258c2ecf20Sopenharmony_ci	sed -E -n '/\s+[[:alpha:]]\s+__start_initialization_multiplatform\s*$/{s///p;q}')
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci$objdump -D --no-show-raw-insn --start-address="$kstart" --stop-address="$end_intr" "$vmlinux" |
288c2ecf20Sopenharmony_cised -E -n '
298c2ecf20Sopenharmony_ci# match lines that start with a kernel address
308c2ecf20Sopenharmony_ci/^c[0-9a-f]*:\s*b/ {
318c2ecf20Sopenharmony_ci	# drop branches via ctr or lr
328c2ecf20Sopenharmony_ci	/\<b.?.?(ct|l)r/d
338c2ecf20Sopenharmony_ci	# cope with some differences between Clang and GNU objdumps
348c2ecf20Sopenharmony_ci	s/\<bt.?\s*[[:digit:]]+,/beq/
358c2ecf20Sopenharmony_ci	s/\<bf.?\s*[[:digit:]]+,/bne/
368c2ecf20Sopenharmony_ci	# tidy up
378c2ecf20Sopenharmony_ci	s/\s0x/ /
388c2ecf20Sopenharmony_ci	s/://
398c2ecf20Sopenharmony_ci	# format for the loop below
408c2ecf20Sopenharmony_ci	s/^(\S+)\s+(\S+)\s+(\S+)\s*(\S*).*$/\1:\2:\3:\4/
418c2ecf20Sopenharmony_ci	# strip out condition registers
428c2ecf20Sopenharmony_ci	s/:cr[0-7],/:/
438c2ecf20Sopenharmony_ci	p
448c2ecf20Sopenharmony_ci}' | {
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ciall_good=true
478c2ecf20Sopenharmony_ciwhile IFS=: read -r from branch to sym; do
488c2ecf20Sopenharmony_ci	case "$to" in
498c2ecf20Sopenharmony_ci	c*)	to="0x$to"
508c2ecf20Sopenharmony_ci		;;
518c2ecf20Sopenharmony_ci	.+*)
528c2ecf20Sopenharmony_ci		to=${to#.+}
538c2ecf20Sopenharmony_ci		if [ "$branch" = 'b' ]; then
548c2ecf20Sopenharmony_ci			if (( to >= 0x2000000 )); then
558c2ecf20Sopenharmony_ci				to=$(( to - 0x4000000 ))
568c2ecf20Sopenharmony_ci			fi
578c2ecf20Sopenharmony_ci		elif (( to >= 0x8000 )); then
588c2ecf20Sopenharmony_ci			to=$(( to - 0x10000 ))
598c2ecf20Sopenharmony_ci		fi
608c2ecf20Sopenharmony_ci		printf -v to '0x%x' $(( "0x$from" + to ))
618c2ecf20Sopenharmony_ci		;;
628c2ecf20Sopenharmony_ci	*)	printf 'Unkown branch format\n'
638c2ecf20Sopenharmony_ci		;;
648c2ecf20Sopenharmony_ci	esac
658c2ecf20Sopenharmony_ci	if [ "$to" = "$sim" ]; then
668c2ecf20Sopenharmony_ci		continue
678c2ecf20Sopenharmony_ci	fi
688c2ecf20Sopenharmony_ci	if (( to > end_intr )); then
698c2ecf20Sopenharmony_ci		if $all_good; then
708c2ecf20Sopenharmony_ci			printf '%s\n' 'WARNING: Unrelocated relative branches'
718c2ecf20Sopenharmony_ci			all_good=false
728c2ecf20Sopenharmony_ci		fi
738c2ecf20Sopenharmony_ci		printf '%s %s-> %s %s\n' "$from" "$branch" "$to" "$sym"
748c2ecf20Sopenharmony_ci	fi
758c2ecf20Sopenharmony_cidone
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci$all_good
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci}
80