xref: /linux/tools/perf/tests/shell/inject_aslr.sh (revision 3d5e48944e824bddc20d7b874e784f7b279636fe)
1*190c4546SIan Rogers#!/bin/bash
2*190c4546SIan Rogers# SPDX-License-Identifier: GPL-2.0
3*190c4546SIan Rogers# perf inject --aslr test
4*190c4546SIan Rogers
5*190c4546SIan Rogersset -e
6*190c4546SIan Rogersset -o pipefail
7*190c4546SIan Rogers
8*190c4546SIan Rogersshelldir=$(dirname "$0")
9*190c4546SIan Rogers# shellcheck source=lib/perf_has_symbol.sh
10*190c4546SIan Rogers. "${shelldir}"/lib/perf_has_symbol.sh
11*190c4546SIan Rogers
12*190c4546SIan Rogerssym="noploop"
13*190c4546SIan Rogers
14*190c4546SIan Rogersskip_test_missing_symbol ${sym}
15*190c4546SIan Rogers
16*190c4546SIan Rogers# Create global temp directory
17*190c4546SIan Rogerstemp_dir=$(mktemp -d /tmp/perf-test-aslr.XXXXXXXXXX)
18*190c4546SIan Rogers
19*190c4546SIan Rogersprog="perf test -w noploop"
20*190c4546SIan Rogers[ "$(uname -m)" = "s390x" ] && prog="$prog 3"
21*190c4546SIan Rogerserr=0
22*190c4546SIan Rogerskprog="dd if=/dev/urandom of=/dev/null bs=1M count=50"
23*190c4546SIan Rogers
24*190c4546SIan Rogerscleanup() {
25*190c4546SIan Rogers  local exit_code=${1:-$?}
26*190c4546SIan Rogers  trap - EXIT TERM INT
27*190c4546SIan Rogers  if [ "${exit_code}" -ne 0 ] || [ "${err}" -ne 0 ]; then
28*190c4546SIan Rogers    echo "Test failed! Preserving temp directory: ${temp_dir}"
29*190c4546SIan Rogers    return
30*190c4546SIan Rogers  fi
31*190c4546SIan Rogers  # Check if temp_dir is set and looks sane before removing
32*190c4546SIan Rogers  if [[ "${temp_dir}" =~ ^/tmp/perf-test-aslr\. ]]; then
33*190c4546SIan Rogers    rm -rf "${temp_dir}"
34*190c4546SIan Rogers  fi
35*190c4546SIan Rogers}
36*190c4546SIan Rogers
37*190c4546SIan Rogerstrap_cleanup() {
38*190c4546SIan Rogers  local exit_code=$?
39*190c4546SIan Rogers  echo "Unexpected signal in ${FUNCNAME[1]}"
40*190c4546SIan Rogers  cleanup ${exit_code}
41*190c4546SIan Rogers  exit ${exit_code}
42*190c4546SIan Rogers}
43*190c4546SIan Rogerstrap trap_cleanup EXIT TERM INT
44*190c4546SIan Rogers
45*190c4546SIan Rogersget_noploop_addr() {
46*190c4546SIan Rogers  local file=$1
47*190c4546SIan Rogers  perf script -i "$file" | awk '
48*190c4546SIan Rogers    BEGIN { found=0 }
49*190c4546SIan Rogers    {
50*190c4546SIan Rogers      for (i=1; i<=NF; i++) {
51*190c4546SIan Rogers        if ($i ~ /noploop\+/) {
52*190c4546SIan Rogers          if (!found) {
53*190c4546SIan Rogers            print $(i-1)
54*190c4546SIan Rogers            found=1
55*190c4546SIan Rogers          }
56*190c4546SIan Rogers        }
57*190c4546SIan Rogers      }
58*190c4546SIan Rogers    }'
59*190c4546SIan Rogers}
60*190c4546SIan Rogers
61*190c4546SIan Rogerstest_basic_aslr() {
62*190c4546SIan Rogers  echo "Test basic ASLR remapping"
63*190c4546SIan Rogers  local data
64*190c4546SIan Rogers  data=$(mktemp "${temp_dir}/perf.data.basic.XXXXXX")
65*190c4546SIan Rogers  local data2
66*190c4546SIan Rogers  data2=$(mktemp "${temp_dir}/perf.data2.basic.XXXXXX")
67*190c4546SIan Rogers
68*190c4546SIan Rogers  perf record -e task-clock:u -o "${data}" ${prog}
69*190c4546SIan Rogers  perf inject -v --aslr -i "${data}" -o "${data2}"
70*190c4546SIan Rogers
71*190c4546SIan Rogers  orig_addr=$(get_noploop_addr "${data}")
72*190c4546SIan Rogers  new_addr=$(get_noploop_addr "${data2}")
73*190c4546SIan Rogers
74*190c4546SIan Rogers  echo "Basic ASLR: orig_addr=$orig_addr, new_addr=$new_addr"
75*190c4546SIan Rogers
76*190c4546SIan Rogers  if [ -z "$orig_addr" ]; then
77*190c4546SIan Rogers    echo "Basic ASLR test [Failed - no noploop samples in original file]"
78*190c4546SIan Rogers    err=1
79*190c4546SIan Rogers  elif [ -z "$new_addr" ]; then
80*190c4546SIan Rogers    echo "Basic ASLR test [Failed - could not find remapped address]"
81*190c4546SIan Rogers    err=1
82*190c4546SIan Rogers  elif [ "$orig_addr" = "$new_addr" ]; then
83*190c4546SIan Rogers    echo "Basic ASLR test [Failed - addresses are not remapped]"
84*190c4546SIan Rogers    err=1
85*190c4546SIan Rogers  else
86*190c4546SIan Rogers    echo "Basic ASLR test [Success]"
87*190c4546SIan Rogers  fi
88*190c4546SIan Rogers}
89*190c4546SIan Rogers
90*190c4546SIan Rogerstest_pipe_aslr() {
91*190c4546SIan Rogers  echo "Test pipe mode ASLR remapping"
92*190c4546SIan Rogers  local data
93*190c4546SIan Rogers  data=$(mktemp "${temp_dir}/perf.data.pipe.XXXXXX")
94*190c4546SIan Rogers  local data2
95*190c4546SIan Rogers  data2=$(mktemp "${temp_dir}/perf.data2.pipe.XXXXXX")
96*190c4546SIan Rogers
97*190c4546SIan Rogers  # Use tee to save the original pipe data for comparison
98*190c4546SIan Rogers  perf record -e task-clock:u -o - ${prog} | tee "${data}" | perf inject --aslr -o "${data2}"
99*190c4546SIan Rogers
100*190c4546SIan Rogers  orig_addr=$(get_noploop_addr "${data}")
101*190c4546SIan Rogers  new_addr=$(get_noploop_addr "${data2}")
102*190c4546SIan Rogers
103*190c4546SIan Rogers  echo "Pipe ASLR: orig_addr=$orig_addr, new_addr=$new_addr"
104*190c4546SIan Rogers
105*190c4546SIan Rogers  if [ -z "$orig_addr" ]; then
106*190c4546SIan Rogers    echo "Pipe ASLR test [Failed - no noploop samples in original file]"
107*190c4546SIan Rogers    err=1
108*190c4546SIan Rogers  elif [ -z "$new_addr" ]; then
109*190c4546SIan Rogers    echo "Pipe ASLR test [Failed - could not find remapped address]"
110*190c4546SIan Rogers    err=1
111*190c4546SIan Rogers  elif [ "$orig_addr" = "$new_addr" ]; then
112*190c4546SIan Rogers    echo "Pipe ASLR test [Failed - addresses are not remapped]"
113*190c4546SIan Rogers    err=1
114*190c4546SIan Rogers  else
115*190c4546SIan Rogers    echo "Pipe ASLR test [Success]"
116*190c4546SIan Rogers  fi
117*190c4546SIan Rogers}
118*190c4546SIan Rogers
119*190c4546SIan Rogerstest_callchain_aslr() {
120*190c4546SIan Rogers  echo "Test Callchain ASLR remapping"
121*190c4546SIan Rogers  local data
122*190c4546SIan Rogers  data=$(mktemp "${temp_dir}/perf.data.callchain.XXXXXX")
123*190c4546SIan Rogers  local data2
124*190c4546SIan Rogers  data2=$(mktemp "${temp_dir}/perf.data2.callchain.XXXXXX")
125*190c4546SIan Rogers
126*190c4546SIan Rogers  perf record -g -e task-clock:u -o "${data}" ${prog}
127*190c4546SIan Rogers  perf inject --aslr -i "${data}" -o "${data2}"
128*190c4546SIan Rogers
129*190c4546SIan Rogers  orig_addr=$(get_noploop_addr "${data}")
130*190c4546SIan Rogers  new_addr=$(get_noploop_addr "${data2}")
131*190c4546SIan Rogers
132*190c4546SIan Rogers  echo "Callchain ASLR: orig_addr=$orig_addr, new_addr=$new_addr"
133*190c4546SIan Rogers
134*190c4546SIan Rogers  if [ -z "$orig_addr" ]; then
135*190c4546SIan Rogers    echo "Callchain ASLR test [Failed - no noploop samples in original file]"
136*190c4546SIan Rogers    err=1
137*190c4546SIan Rogers  elif [ -z "$new_addr" ]; then
138*190c4546SIan Rogers    echo "Callchain ASLR test [Failed - could not find remapped address]"
139*190c4546SIan Rogers    err=1
140*190c4546SIan Rogers  elif [ "$orig_addr" = "$new_addr" ]; then
141*190c4546SIan Rogers    echo "Callchain ASLR test [Failed - addresses are not remapped]"
142*190c4546SIan Rogers    err=1
143*190c4546SIan Rogers  else
144*190c4546SIan Rogers    # Extract callchain addresses (indented lines starting with hex addresses)
145*190c4546SIan Rogers    orig_callchain=$(perf script -i "${data}" | awk '/^[[:space:]]+[0-9a-f]+/ {print $1}')
146*190c4546SIan Rogers    new_callchain=$(perf script -i "${data2}" | awk '/^[[:space:]]+[0-9a-f]+/ {print $1}')
147*190c4546SIan Rogers
148*190c4546SIan Rogers    if [ -z "$orig_callchain" ]; then
149*190c4546SIan Rogers      echo "Callchain ASLR test [Failed - no callchain samples in original file]"
150*190c4546SIan Rogers      err=1
151*190c4546SIan Rogers    elif [ -z "$new_callchain" ]; then
152*190c4546SIan Rogers      echo "Callchain ASLR test [Failed - callchain data was dropped]"
153*190c4546SIan Rogers      err=1
154*190c4546SIan Rogers    elif [ "$orig_callchain" = "$new_callchain" ]; then
155*190c4546SIan Rogers      echo "Callchain ASLR test [Failed - callchain addresses were not remapped]"
156*190c4546SIan Rogers      err=1
157*190c4546SIan Rogers    else
158*190c4546SIan Rogers      echo "Callchain ASLR test [Success]"
159*190c4546SIan Rogers    fi
160*190c4546SIan Rogers  fi
161*190c4546SIan Rogers}
162*190c4546SIan Rogers
163*190c4546SIan Rogerstest_report_aslr() {
164*190c4546SIan Rogers  echo "Test perf report consistency"
165*190c4546SIan Rogers  local data
166*190c4546SIan Rogers  data=$(mktemp "${temp_dir}/perf.data.report.XXXXXX")
167*190c4546SIan Rogers  local data2
168*190c4546SIan Rogers  data2=$(mktemp "${temp_dir}/perf.data2.report.XXXXXX")
169*190c4546SIan Rogers  local data_clean
170*190c4546SIan Rogers  data_clean=$(mktemp "${temp_dir}/perf.data.clean.XXXXXX")
171*190c4546SIan Rogers
172*190c4546SIan Rogers  perf record -e task-clock:u -o "${data}" ${prog}
173*190c4546SIan Rogers  # Use -b to inject build-ids and force ordered events processing in both
174*190c4546SIan Rogers  perf inject -b -i "${data}" -o "${data_clean}"
175*190c4546SIan Rogers  perf inject -v -b --aslr -i "${data}" -o "${data2}"
176*190c4546SIan Rogers
177*190c4546SIan Rogers  local report1="${temp_dir}/report1_basic"
178*190c4546SIan Rogers  local report2="${temp_dir}/report2_basic"
179*190c4546SIan Rogers  local report1_clean="${temp_dir}/report1_basic.clean"
180*190c4546SIan Rogers  local report2_clean="${temp_dir}/report2_basic.clean"
181*190c4546SIan Rogers  local diff_file="${temp_dir}/diff_basic"
182*190c4546SIan Rogers
183*190c4546SIan Rogers  perf report -i "${data_clean}" --stdio > "${report1}"
184*190c4546SIan Rogers  perf report -i "${data2}" --stdio > "${report2}"
185*190c4546SIan Rogers
186*190c4546SIan Rogers  # Strip headers and compare lines with percentages
187*190c4546SIan Rogers  grep '%' "${report1}" | grep -v '^#' | \
188*190c4546SIan Rogers    grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | sort > "${report1_clean}" || true
189*190c4546SIan Rogers  grep '%' "${report2}" | grep -v '^#' | \
190*190c4546SIan Rogers    grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | sort > "${report2_clean}" || true
191*190c4546SIan Rogers
192*190c4546SIan Rogers  diff -u -w "${report1_clean}" "${report2_clean}" > "${diff_file}" || true
193*190c4546SIan Rogers
194*190c4546SIan Rogers  if [ ! -s "${report1_clean}" ]; then
195*190c4546SIan Rogers    echo "Report ASLR test [Failed - no samples captured]"
196*190c4546SIan Rogers    err=1
197*190c4546SIan Rogers  elif [ -s "${diff_file}" ]; then
198*190c4546SIan Rogers    echo "Report ASLR test [Failed - reports differ]"
199*190c4546SIan Rogers    echo "Showing first 20 lines of diff:"
200*190c4546SIan Rogers    head -n 20 "${diff_file}"
201*190c4546SIan Rogers    err=1
202*190c4546SIan Rogers  else
203*190c4546SIan Rogers    echo "Report ASLR test [Success]"
204*190c4546SIan Rogers  fi
205*190c4546SIan Rogers}
206*190c4546SIan Rogers
207*190c4546SIan Rogerstest_pipe_report_aslr() {
208*190c4546SIan Rogers  echo "Test pipe mode perf report consistency"
209*190c4546SIan Rogers  local data
210*190c4546SIan Rogers  data=$(mktemp "${temp_dir}/perf.data.pipe_report.XXXXXX")
211*190c4546SIan Rogers  local data2
212*190c4546SIan Rogers  data2=$(mktemp "${temp_dir}/perf.data2.pipe_report.XXXXXX")
213*190c4546SIan Rogers  local data_clean
214*190c4546SIan Rogers  data_clean=$(mktemp "${temp_dir}/perf.data.clean.XXXXXX")
215*190c4546SIan Rogers
216*190c4546SIan Rogers  # Use tee to save the original pipe data, then process it with inject -b
217*190c4546SIan Rogers  perf record -e task-clock:u -o - ${prog} | \
218*190c4546SIan Rogers    tee "${data}" | \
219*190c4546SIan Rogers    perf inject -b --aslr -o "${data2}"
220*190c4546SIan Rogers  perf inject -b -i "${data}" -o "${data_clean}"
221*190c4546SIan Rogers
222*190c4546SIan Rogers  local report1="${temp_dir}/report1_pipe"
223*190c4546SIan Rogers  local report2="${temp_dir}/report2_pipe"
224*190c4546SIan Rogers  local report1_clean="${temp_dir}/report1_pipe.clean"
225*190c4546SIan Rogers  local report2_clean="${temp_dir}/report2_pipe.clean"
226*190c4546SIan Rogers  local diff_file="${temp_dir}/diff_pipe"
227*190c4546SIan Rogers
228*190c4546SIan Rogers  perf report -i "${data_clean}" --stdio > "${report1}"
229*190c4546SIan Rogers  perf report -i "${data2}" --stdio > "${report2}"
230*190c4546SIan Rogers
231*190c4546SIan Rogers  # Strip headers and compare lines with percentages
232*190c4546SIan Rogers  grep '%' "${report1}" | grep -v '^#' | \
233*190c4546SIan Rogers    grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | sort > "${report1_clean}" || true
234*190c4546SIan Rogers  grep '%' "${report2}" | grep -v '^#' | \
235*190c4546SIan Rogers    grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | sort > "${report2_clean}" || true
236*190c4546SIan Rogers
237*190c4546SIan Rogers  diff -u -w "${report1_clean}" "${report2_clean}" > "${diff_file}" || true
238*190c4546SIan Rogers
239*190c4546SIan Rogers  if [ ! -s "${report1_clean}" ]; then
240*190c4546SIan Rogers    echo "Pipe Report ASLR test [Failed - no samples captured]"
241*190c4546SIan Rogers    err=1
242*190c4546SIan Rogers  elif [ -s "${diff_file}" ]; then
243*190c4546SIan Rogers    echo "Pipe Report ASLR test [Failed - reports differ]"
244*190c4546SIan Rogers    echo "Showing first 20 lines of diff:"
245*190c4546SIan Rogers    head -n 20 "${diff_file}"
246*190c4546SIan Rogers    err=1
247*190c4546SIan Rogers  else
248*190c4546SIan Rogers    echo "Pipe Report ASLR test [Success]"
249*190c4546SIan Rogers  fi
250*190c4546SIan Rogers}
251*190c4546SIan Rogers
252*190c4546SIan Rogerstest_pipe_out_report_aslr() {
253*190c4546SIan Rogers  echo "Test pipe output mode perf report consistency"
254*190c4546SIan Rogers  local data
255*190c4546SIan Rogers  data=$(mktemp "${temp_dir}/perf.data.pipe_out_report.XXXXXX")
256*190c4546SIan Rogers  local data_clean
257*190c4546SIan Rogers  data_clean=$(mktemp "${temp_dir}/perf.data.clean.XXXXXX")
258*190c4546SIan Rogers
259*190c4546SIan Rogers  perf record -e task-clock:u -o "${data}" ${prog}
260*190c4546SIan Rogers  perf inject -b -i "${data}" -o "${data_clean}"
261*190c4546SIan Rogers
262*190c4546SIan Rogers  local report1="${temp_dir}/report1_pipe_out"
263*190c4546SIan Rogers  local report2="${temp_dir}/report2_pipe_out"
264*190c4546SIan Rogers  local report1_clean="${temp_dir}/report1_pipe_out.clean"
265*190c4546SIan Rogers  local report2_clean="${temp_dir}/report2_pipe_out.clean"
266*190c4546SIan Rogers  local diff_file="${temp_dir}/diff_pipe_out"
267*190c4546SIan Rogers
268*190c4546SIan Rogers  perf report -i "${data_clean}" --stdio > "${report1}"
269*190c4546SIan Rogers  perf inject -b --aslr -i "${data}" -o - | perf report -i - --stdio > "${report2}"
270*190c4546SIan Rogers
271*190c4546SIan Rogers  # Strip headers and compare lines with percentages
272*190c4546SIan Rogers  grep '%' "${report1}" | grep -v '^#' | \
273*190c4546SIan Rogers    grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | sort > "${report1_clean}" || true
274*190c4546SIan Rogers  grep '%' "${report2}" | grep -v '^#' | \
275*190c4546SIan Rogers    grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | sort > "${report2_clean}" || true
276*190c4546SIan Rogers
277*190c4546SIan Rogers  diff -u -w "${report1_clean}" "${report2_clean}" > "${diff_file}" || true
278*190c4546SIan Rogers
279*190c4546SIan Rogers  if [ ! -s "${report1_clean}" ]; then
280*190c4546SIan Rogers    echo "Pipe Output Report ASLR test [Failed - no samples captured]"
281*190c4546SIan Rogers    err=1
282*190c4546SIan Rogers  elif [ -s "${diff_file}" ]; then
283*190c4546SIan Rogers    echo "Pipe Output Report ASLR test [Failed - reports differ]"
284*190c4546SIan Rogers    echo "Showing first 20 lines of diff:"
285*190c4546SIan Rogers    head -n 20 "${diff_file}"
286*190c4546SIan Rogers    err=1
287*190c4546SIan Rogers  else
288*190c4546SIan Rogers    echo "Pipe Output Report ASLR test [Success]"
289*190c4546SIan Rogers  fi
290*190c4546SIan Rogers}
291*190c4546SIan Rogers
292*190c4546SIan Rogerstest_dropped_samples() {
293*190c4546SIan Rogers  echo "Test dropped samples (phys-data)"
294*190c4546SIan Rogers  local data
295*190c4546SIan Rogers  data=$(mktemp "${temp_dir}/perf.data.dropped.XXXXXX")
296*190c4546SIan Rogers  local data2
297*190c4546SIan Rogers  data2=$(mktemp "${temp_dir}/perf.data2.dropped.XXXXXX")
298*190c4546SIan Rogers
299*190c4546SIan Rogers  # Check if --phys-data is supported by recording a short run
300*190c4546SIan Rogers  if ! perf record -e task-clock:u --phys-data -o "${data}" -- sleep 0.1 > /dev/null 2>&1; then
301*190c4546SIan Rogers    echo "Skipping dropped samples test as --phys-data is not supported"
302*190c4546SIan Rogers    return
303*190c4546SIan Rogers  fi
304*190c4546SIan Rogers
305*190c4546SIan Rogers  perf record -e task-clock:u --phys-data -o "${data}" ${prog}
306*190c4546SIan Rogers  perf inject --aslr -i "${data}" -o "${data2}"
307*190c4546SIan Rogers
308*190c4546SIan Rogers  # Verify that the original file actually contained samples!
309*190c4546SIan Rogers  orig_samples=$(perf script -i "${data}" | wc -l)
310*190c4546SIan Rogers  if [ "$orig_samples" -eq 0 ]; then
311*190c4546SIan Rogers    echo "Dropped samples test [Failed - no samples in original file]"
312*190c4546SIan Rogers    err=1
313*190c4546SIan Rogers  else
314*190c4546SIan Rogers    # Verify that samples are dropped.
315*190c4546SIan Rogers    samples_count=$(perf script -i "${data2}" | wc -l)
316*190c4546SIan Rogers
317*190c4546SIan Rogers    if [ "$samples_count" -gt 0 ]; then
318*190c4546SIan Rogers      echo "Dropped samples test [Failed - samples were not dropped]"
319*190c4546SIan Rogers      err=1
320*190c4546SIan Rogers    else
321*190c4546SIan Rogers      echo "Dropped samples test [Success]"
322*190c4546SIan Rogers    fi
323*190c4546SIan Rogers  fi
324*190c4546SIan Rogers}
325*190c4546SIan Rogers
326*190c4546SIan Rogerstest_kernel_aslr() {
327*190c4546SIan Rogers  echo "Test kernel ASLR remapping"
328*190c4546SIan Rogers  local kdata
329*190c4546SIan Rogers  kdata=$(mktemp "${temp_dir}/perf.data.kernel.XXXXXX")
330*190c4546SIan Rogers  local kdata2
331*190c4546SIan Rogers  kdata2=$(mktemp "${temp_dir}/perf.data2.kernel.XXXXXX")
332*190c4546SIan Rogers  local log_file
333*190c4546SIan Rogers  log_file=$(mktemp "${temp_dir}/kernel_record.log.XXXXXX")
334*190c4546SIan Rogers
335*190c4546SIan Rogers  # Try to record kernel samples
336*190c4546SIan Rogers  if ! perf record -e task-clock:k -o "${kdata}" ${kprog} > "${log_file}" 2>&1; then
337*190c4546SIan Rogers    echo "Skipping kernel ASLR test as recording failed (maybe no permissions)"
338*190c4546SIan Rogers    return
339*190c4546SIan Rogers  fi
340*190c4546SIan Rogers
341*190c4546SIan Rogers  # Check for warning about kernel map restriction
342*190c4546SIan Rogers  if grep -q "Couldn't record kernel reference relocation symbol" "${log_file}"; then
343*190c4546SIan Rogers    echo "Skipping kernel ASLR test as kernel map could not be recorded (permissions restricted)"
344*190c4546SIan Rogers    return
345*190c4546SIan Rogers  fi
346*190c4546SIan Rogers
347*190c4546SIan Rogers  perf inject -v --aslr -i "${kdata}" -o "${kdata2}"
348*190c4546SIan Rogers
349*190c4546SIan Rogers  # Check if kernel addresses are remapped.
350*190c4546SIan Rogers  # Find the field that ends with :k: (the event name) and take the next field!
351*190c4546SIan Rogers  orig_addr=$(perf script -i "${kdata}" | awk '
352*190c4546SIan Rogers    BEGIN { found=0 }
353*190c4546SIan Rogers    {
354*190c4546SIan Rogers      for (i=1; i<NF; i++) {
355*190c4546SIan Rogers        if ($i ~ /:[k]+:?$/) {
356*190c4546SIan Rogers          if (!found) {
357*190c4546SIan Rogers            print $(i+1)
358*190c4546SIan Rogers            found=1
359*190c4546SIan Rogers          }
360*190c4546SIan Rogers        }
361*190c4546SIan Rogers      }
362*190c4546SIan Rogers    }')
363*190c4546SIan Rogers  new_addr=$(perf script -i "${kdata2}" | awk '
364*190c4546SIan Rogers    BEGIN { found=0 }
365*190c4546SIan Rogers    {
366*190c4546SIan Rogers      for (i=1; i<NF; i++) {
367*190c4546SIan Rogers        if ($i ~ /:[k]+:?$/) {
368*190c4546SIan Rogers          if (!found) {
369*190c4546SIan Rogers            print $(i+1)
370*190c4546SIan Rogers            found=1
371*190c4546SIan Rogers          }
372*190c4546SIan Rogers        }
373*190c4546SIan Rogers      }
374*190c4546SIan Rogers    }')
375*190c4546SIan Rogers
376*190c4546SIan Rogers  echo "Kernel ASLR: orig_addr=$orig_addr, new_addr=$new_addr"
377*190c4546SIan Rogers
378*190c4546SIan Rogers  if [ -z "$orig_addr" ]; then
379*190c4546SIan Rogers    echo "Kernel ASLR test [Failed - no kernel samples in original file]"
380*190c4546SIan Rogers    err=1
381*190c4546SIan Rogers  elif [ -z "$new_addr" ]; then
382*190c4546SIan Rogers    echo "Kernel ASLR test [Failed - could not find remapped address]"
383*190c4546SIan Rogers    err=1
384*190c4546SIan Rogers  elif [ "$orig_addr" = "$new_addr" ]; then
385*190c4546SIan Rogers    echo "Kernel ASLR test [Failed - addresses are not remapped]"
386*190c4546SIan Rogers    err=1
387*190c4546SIan Rogers  else
388*190c4546SIan Rogers    echo "Kernel ASLR test [Success]"
389*190c4546SIan Rogers  fi
390*190c4546SIan Rogers}
391*190c4546SIan Rogers
392*190c4546SIan Rogerstest_kernel_report_aslr() {
393*190c4546SIan Rogers  echo "Test kernel perf report consistency"
394*190c4546SIan Rogers  local kdata
395*190c4546SIan Rogers  kdata=$(mktemp "${temp_dir}/perf.data.kernel_report.XXXXXX")
396*190c4546SIan Rogers  local kdata2
397*190c4546SIan Rogers  kdata2=$(mktemp "${temp_dir}/perf.data2.kernel_report.XXXXXX")
398*190c4546SIan Rogers  local data_clean
399*190c4546SIan Rogers  data_clean=$(mktemp "${temp_dir}/perf.data.clean.XXXXXX")
400*190c4546SIan Rogers  local log_file
401*190c4546SIan Rogers  log_file=$(mktemp "${temp_dir}/kernel_report_record.log.XXXXXX")
402*190c4546SIan Rogers
403*190c4546SIan Rogers  # Try to record kernel samples
404*190c4546SIan Rogers  if ! perf record -e task-clock:k -o "${kdata}" ${kprog} > "${log_file}" 2>&1; then
405*190c4546SIan Rogers    echo "Skipping kernel report test as recording failed (maybe no permissions)"
406*190c4546SIan Rogers    return
407*190c4546SIan Rogers  fi
408*190c4546SIan Rogers
409*190c4546SIan Rogers  # Check for warning about kernel map restriction
410*190c4546SIan Rogers  if grep -q "Couldn't record kernel reference relocation symbol" "${log_file}"; then
411*190c4546SIan Rogers    echo "Skipping kernel report test as kernel map could not be recorded (permissions restricted)"
412*190c4546SIan Rogers    return
413*190c4546SIan Rogers  fi
414*190c4546SIan Rogers
415*190c4546SIan Rogers  # Use -b to inject build-ids and force ordered events processing in both
416*190c4546SIan Rogers  perf inject -b -i "${kdata}" -o "${data_clean}"
417*190c4546SIan Rogers  perf inject -v -b --aslr -i "${kdata}" -o "${kdata2}"
418*190c4546SIan Rogers
419*190c4546SIan Rogers  local report1="${temp_dir}/report_kernel1"
420*190c4546SIan Rogers  local report2="${temp_dir}/report_kernel2"
421*190c4546SIan Rogers  local report1_clean="${temp_dir}/report_kernel1.clean"
422*190c4546SIan Rogers  local report2_clean="${temp_dir}/report_kernel2.clean"
423*190c4546SIan Rogers
424*190c4546SIan Rogers  perf report -i "${data_clean}" --stdio > "${report1}"
425*190c4546SIan Rogers  perf report -i "${kdata2}" --stdio > "${report2}"
426*190c4546SIan Rogers
427*190c4546SIan Rogers  # Strip headers and compare lines with percentages
428*190c4546SIan Rogers  grep '%' "${report1}" | grep -v '^#' > "${report1_clean}" || true
429*190c4546SIan Rogers  grep '%' "${report2}" | grep -v '^#' > "${report2_clean}" || true
430*190c4546SIan Rogers
431*190c4546SIan Rogers  # Normalize kernel DSOs and addresses in clean reports
432*190c4546SIan Rogers  # This allows kernel modules to be either a module or kernel.kallsyms
433*190c4546SIan Rogers  local report1_norm="${temp_dir}/report_kernel1.norm"
434*190c4546SIan Rogers  local report2_norm="${temp_dir}/report_kernel2.norm"
435*190c4546SIan Rogers  local diff_file="${temp_dir}/diff_kernel"
436*190c4546SIan Rogers
437*190c4546SIan Rogers  grep -v -E '0x[0-9a-f]{8,}|0000000000000000' "${report1_clean}" | \
438*190c4546SIan Rogers    awk '{gsub(/\[[a-zA-Z0-9_.-]{2,}\](\.[a-zA-Z0-9_]+)?/, "[kernel]", $0); print}' | \
439*190c4546SIan Rogers    sort > "${report1_norm}" || true
440*190c4546SIan Rogers  grep -v -E '0x[0-9a-f]{8,}|0000000000000000' "${report2_clean}" | \
441*190c4546SIan Rogers    awk '{gsub(/\[[a-zA-Z0-9_.-]{2,}\](\.[a-zA-Z0-9_]+)?/, "[kernel]", $0); print}' | \
442*190c4546SIan Rogers    sort > "${report2_norm}" || true
443*190c4546SIan Rogers
444*190c4546SIan Rogers  diff -u -w "${report1_norm}" "${report2_norm}" > "${diff_file}" || true
445*190c4546SIan Rogers
446*190c4546SIan Rogers  if [ ! -s "${report1_norm}" ]; then
447*190c4546SIan Rogers    echo "Kernel Report ASLR test [Failed - no samples captured]"
448*190c4546SIan Rogers    err=1
449*190c4546SIan Rogers  elif [ -s "${diff_file}" ]; then
450*190c4546SIan Rogers    echo "Kernel Report ASLR test [Failed - reports differ]"
451*190c4546SIan Rogers    echo "Showing first 20 lines of diff:"
452*190c4546SIan Rogers    head -n 20 "${diff_file}"
453*190c4546SIan Rogers    err=1
454*190c4546SIan Rogers  else
455*190c4546SIan Rogers    echo "Kernel Report ASLR test [Success]"
456*190c4546SIan Rogers  fi
457*190c4546SIan Rogers}
458*190c4546SIan Rogers
459*190c4546SIan Rogerstest_regs_stripping() {
460*190c4546SIan Rogers  echo "Test user register stripping"
461*190c4546SIan Rogers  local rdata="${temp_dir}/perf.data.regs"
462*190c4546SIan Rogers  local rdata2="${temp_dir}/perf.data.regs.injected"
463*190c4546SIan Rogers  local rdata_clean="${temp_dir}/perf.data.regs.clean"
464*190c4546SIan Rogers
465*190c4546SIan Rogers  if ! perf record -e cycles:u --user-regs -o "${rdata}" ${prog} > /dev/null 2>&1; then
466*190c4546SIan Rogers    echo "Skipping user registers test as recording failed (unsupported flag/platform)"
467*190c4546SIan Rogers    return
468*190c4546SIan Rogers  fi
469*190c4546SIan Rogers
470*190c4546SIan Rogers  perf inject -b -i "${rdata}" -o "${rdata_clean}"
471*190c4546SIan Rogers  perf inject -v -b --aslr -i "${rdata}" -o "${rdata2}"
472*190c4546SIan Rogers
473*190c4546SIan Rogers  local report1="${temp_dir}/report_regs1"
474*190c4546SIan Rogers  local report2="${temp_dir}/report_regs2"
475*190c4546SIan Rogers  local report1_clean="${temp_dir}/report_regs1.clean"
476*190c4546SIan Rogers  local report2_clean="${temp_dir}/report_regs2.clean"
477*190c4546SIan Rogers  local diff_file="${temp_dir}/diff_regs"
478*190c4546SIan Rogers
479*190c4546SIan Rogers  perf report -i "${rdata_clean}" --stdio > "${report1}" 2>/dev/null || true
480*190c4546SIan Rogers  perf report -i "${rdata2}" --stdio > "${report2}" 2>/dev/null || true
481*190c4546SIan Rogers
482*190c4546SIan Rogers  grep '%' "${report1}" | grep -v '^#' | \
483*190c4546SIan Rogers    grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | \
484*190c4546SIan Rogers    sort > "${report1_clean}" || true
485*190c4546SIan Rogers  grep '%' "${report2}" | grep -v '^#' | \
486*190c4546SIan Rogers    grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | \
487*190c4546SIan Rogers    sort > "${report2_clean}" || true
488*190c4546SIan Rogers
489*190c4546SIan Rogers  diff -u -w "${report1_clean}" "${report2_clean}" > "${diff_file}" || true
490*190c4546SIan Rogers
491*190c4546SIan Rogers  if [ ! -s "${report1_clean}" ]; then
492*190c4546SIan Rogers    echo "User registers stripping test [Failed - profile trace starved/empty]"
493*190c4546SIan Rogers    err=1
494*190c4546SIan Rogers    return
495*190c4546SIan Rogers  elif [ -s "${diff_file}" ]; then
496*190c4546SIan Rogers    echo "User registers stripping test [Failed - report parsing differs]"
497*190c4546SIan Rogers    echo "Showing first 20 lines of diff:"
498*190c4546SIan Rogers    head -n 20 "${diff_file}"
499*190c4546SIan Rogers    err=1
500*190c4546SIan Rogers    return
501*190c4546SIan Rogers  fi
502*190c4546SIan Rogers
503*190c4546SIan Rogers  local script_dump="${temp_dir}/script_regs_dump"
504*190c4546SIan Rogers  perf script -D -i "${rdata2}" > "${script_dump}" 2>/dev/null || true
505*190c4546SIan Rogers  if grep -q "user regs:" "${script_dump}"; then
506*190c4546SIan Rogers    echo "User registers stripping test [Failed - register dumps still present]"
507*190c4546SIan Rogers    err=1
508*190c4546SIan Rogers  else
509*190c4546SIan Rogers    echo "User registers stripping test [Success]"
510*190c4546SIan Rogers  fi
511*190c4546SIan Rogers}
512*190c4546SIan Rogers
513*190c4546SIan Rogerstest_basic_aslr
514*190c4546SIan Rogerstest_pipe_aslr
515*190c4546SIan Rogerstest_callchain_aslr
516*190c4546SIan Rogerstest_report_aslr
517*190c4546SIan Rogerstest_pipe_report_aslr
518*190c4546SIan Rogerstest_pipe_out_report_aslr
519*190c4546SIan Rogerstest_dropped_samples
520*190c4546SIan Rogerscase "$(uname -m)" in
521*190c4546SIan Rogers  aarch64*|arm*)
522*190c4546SIan Rogers    echo "Skipping kernel ASLR tests on ARM"
523*190c4546SIan Rogers    ;;
524*190c4546SIan Rogers  *)
525*190c4546SIan Rogers    test_kernel_aslr
526*190c4546SIan Rogers    test_kernel_report_aslr
527*190c4546SIan Rogers    ;;
528*190c4546SIan Rogersesac
529*190c4546SIan Rogers
530*190c4546SIan Rogerstest_regs_stripping
531*190c4546SIan Rogers
532*190c4546SIan Rogerscleanup ${err}
533*190c4546SIan Rogersexit $err
534