From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-dy1-f201.google.com (mail-dy1-f201.google.com [74.125.82.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A33F333DED1 for ; Thu, 11 Jun 2026 16:41:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781196115; cv=none; b=UrYcKcDETAL8kgbR4eoHg72NYENKLL6EmzjGOvJubLuf3xHlIKEk6NwcEu8pH95Klo1F5mEGe1qbQ2flZO0fB+zLUusiGXR4m26jOjTL39PnykTfHtEgi44t2TMc4jyuSh/x36BfAUnOUQ251WXTI+BpwOm0dWNab2HFD/y/ncE= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781196115; c=relaxed/simple; bh=0m0aK0Gt9kEvVpjfMsV6zVIKKCgEjXHfK3Y48N7A4uQ=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=OuN3t0OKJt99tas2Wh2RvZaTOOUS4AdI7lZTG0I0D0QYxIcGm7x/9gHWOpHQdVkGSOKLEc4eXltUC/tB/V0+fpvs4xyMtJSRZvYjfm9Dogoc3OIehWPYNAiSPvtR6L94awqxZ9A0Vppjj5nKoRVO1EBCvSQfvGcSGpv3du1hx4g= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=rTLmHVLZ; arc=none smtp.client-ip=74.125.82.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="rTLmHVLZ" Received: by mail-dy1-f201.google.com with SMTP id 5a478bee46e88-304e7fc90b1so75969eec.1 for ; Thu, 11 Jun 2026 09:41:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1781196112; x=1781800912; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=RUgC75pE0nmpeM9E6JS5R+VG/8EhfRwI4pKBl6zjRoQ=; b=rTLmHVLZahFZPbPun7O9PwfXlegZWQuLRQd5go3t4y/sPU6kfGSklrKn5tpdKoqBds wf0m+Rtu3oZ3OUB5QiMJKdNzQIQbWwQD2AKYF0jg9wCt5htOG3NprbuuKbu+V1dhBFU7 Y1SaHcduB7fmxx8LbCV0B/IV+XHEt9BRgVNeNqgOXJo/GltTYy0V7dqwNCfrc8olo3G6 W4jNPqyw8mdYjohsmFGfzqjqCGfdo3KZ8nyi8xrAyRIFtHVr4uBq2vUDksgVgsmt7J7M wKg+3LPkIj2cWNU770IAduUlLLsFuJ3ME/SMmE3A0wQxFRgUDe8iZN7aSDiLp88c7wP1 aszw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1781196112; x=1781800912; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=RUgC75pE0nmpeM9E6JS5R+VG/8EhfRwI4pKBl6zjRoQ=; b=JrH+CfNQ9USzHiqJMYGdT+w4R6QD6Xc9//g+PT/QatNHm7rRB2GiQRRzPTdoPCjSTj caoNQGzY4WPIbJv/mfQbm2Fiuo1bQEWzzBVvrQ/Y43C2e4wi4762gFLjUCtkekMstm3i Qjyz3QgA2q+LH1JACv+M0F9JmGjBvWhErGfLtJXyosAX/q/LSxJsPD55no1ci7v0lnRz 55yNC4Ry0HZdni6hEAreNhpDC62qko0iixZyssqADAmMfl6S169wABhxg49iFEyThpNP /uv1XkFPG5ixelB15pUIDxLuvHwmz6jmyN5YSN+KmyJJYkHnjalJKX2mEX3VoL+2tGVy fqSQ== X-Forwarded-Encrypted: i=1; AFNElJ/vLaBrlhZyNtxXCp/MXm99Ce/V78CeQHrLQiAbpiLaK04vScfT0Escg8HL4xtZ0kSzoWHQlOBQhR9+MYRirS0h@vger.kernel.org X-Gm-Message-State: AOJu0Yw1ne8YJvfqVC8TrrKaiLO8MFnKHKU2RMSCGusw8pDjTZbdVlb9 /KdptY0np1x83JOFMcM6bfpBSj61rgvKIjxlcRvAK7s/J932qe3tBZ3UOnno7g8bO5zQxRYLjmw AgupwZO4cpw== X-Received: from dybdb40.prod.google.com ([2002:a05:7300:b0a8:b0:304:daec:fce7]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7300:dc85:b0:306:f474:738c with SMTP id 5a478bee46e88-308047623b7mr2193444eec.13.1781196111366; Thu, 11 Jun 2026 09:41:51 -0700 (PDT) Date: Thu, 11 Jun 2026 09:41:22 -0700 In-Reply-To: <20260611164122.3974068-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-perf-users@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260608054841.3856224-1-irogers@google.com> <20260611164122.3974068-1-irogers@google.com> X-Mailer: git-send-email 2.54.0.1099.g489fc7bff1-goog Message-ID: <20260611164122.3974068-6-irogers@google.com> Subject: [PATCH v20 5/5] perf test: Add inject ASLR test From: Ian Rogers To: irogers@google.com, acme@kernel.org, james.clark@linaro.org, namhyung@kernel.org Cc: adrian.hunter@intel.com, gmx@google.com, jolsa@kernel.org, linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, mingo@redhat.com, peterz@infradead.org Content-Type: text/plain; charset="UTF-8" Add a new shell test to verify the feature. The test covers: - Basic address remapping for user space samples. - Pipe mode coverage for piped into. - Callchain address remapping. - Consistency of output before and after injection. - Pipe mode report consistency. - Dropping of samples that leak ASLR info (physical addresses). - Kernel address remapping (utilizing a dedicated kernel-intensive VFS dd workload to guarantee continuous timer interrupts sampling flow inside kernel privilege states). - Kernel report consistency with address normalization. The test suite is hardened with global 'set -o pipefail' assertions to catch pipeline failures, stream-consuming awk processors to handle SIGPIPE signals, and a dedicated pipe output scenario validating raw 'perf inject -o -' stdout streams. Note on kernel DSO normalization in the test script: The test script deliberately normalizes all kernel DSOs to a generic [kernel] tag before diffing, as obfuscating physical kernel addresses forces perf report to occasionally shift samples between individual modules and [kernel.kallsyms] due to the lack of valid host module boundary maps. Note on ARM: Kernel-based ASLR test cases (test_kernel_aslr and test_kernel_report_aslr) are skipped on ARM architectures (aarch64 and arm*) to bypass high latency constraints (such as check_invariants() spending excessive execution time in maps__split_kallsyms() on debug builds) and symbolization inconsistencies. Signed-off-by: Ian Rogers Assisted-by: Antigravity:gemini-3.1-pro --- tools/perf/tests/shell/inject_aslr.sh | 533 ++++++++++++++++++++++++++ 1 file changed, 533 insertions(+) create mode 100755 tools/perf/tests/shell/inject_aslr.sh diff --git a/tools/perf/tests/shell/inject_aslr.sh b/tools/perf/tests/shell/inject_aslr.sh new file mode 100755 index 000000000000..c00461828ea7 --- /dev/null +++ b/tools/perf/tests/shell/inject_aslr.sh @@ -0,0 +1,533 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# perf inject --aslr test + +set -e +set -o pipefail + +shelldir=$(dirname "$0") +# shellcheck source=lib/perf_has_symbol.sh +. "${shelldir}"/lib/perf_has_symbol.sh + +sym="noploop" + +skip_test_missing_symbol ${sym} + +# Create global temp directory +temp_dir=$(mktemp -d /tmp/perf-test-aslr.XXXXXXXXXX) + +prog="perf test -w noploop" +[ "$(uname -m)" = "s390x" ] && prog="$prog 3" +err=0 +kprog="dd if=/dev/urandom of=/dev/null bs=1M count=50" + +cleanup() { + local exit_code=${1:-$?} + trap - EXIT TERM INT + if [ "${exit_code}" -ne 0 ] || [ "${err}" -ne 0 ]; then + echo "Test failed! Preserving temp directory: ${temp_dir}" + return + fi + # Check if temp_dir is set and looks sane before removing + if [[ "${temp_dir}" =~ ^/tmp/perf-test-aslr\. ]]; then + rm -rf "${temp_dir}" + fi +} + +trap_cleanup() { + local exit_code=$? + echo "Unexpected signal in ${FUNCNAME[1]}" + cleanup ${exit_code} + exit ${exit_code} +} +trap trap_cleanup EXIT TERM INT + +get_noploop_addr() { + local file=$1 + perf script -i "$file" | awk ' + BEGIN { found=0 } + { + for (i=1; i<=NF; i++) { + if ($i ~ /noploop\+/) { + if (!found) { + print $(i-1) + found=1 + } + } + } + }' +} + +test_basic_aslr() { + echo "Test basic ASLR remapping" + local data + data=$(mktemp "${temp_dir}/perf.data.basic.XXXXXX") + local data2 + data2=$(mktemp "${temp_dir}/perf.data2.basic.XXXXXX") + + perf record -e task-clock:u -o "${data}" ${prog} + perf inject -v --aslr -i "${data}" -o "${data2}" + + orig_addr=$(get_noploop_addr "${data}") + new_addr=$(get_noploop_addr "${data2}") + + echo "Basic ASLR: orig_addr=$orig_addr, new_addr=$new_addr" + + if [ -z "$orig_addr" ]; then + echo "Basic ASLR test [Failed - no noploop samples in original file]" + err=1 + elif [ -z "$new_addr" ]; then + echo "Basic ASLR test [Failed - could not find remapped address]" + err=1 + elif [ "$orig_addr" = "$new_addr" ]; then + echo "Basic ASLR test [Failed - addresses are not remapped]" + err=1 + else + echo "Basic ASLR test [Success]" + fi +} + +test_pipe_aslr() { + echo "Test pipe mode ASLR remapping" + local data + data=$(mktemp "${temp_dir}/perf.data.pipe.XXXXXX") + local data2 + data2=$(mktemp "${temp_dir}/perf.data2.pipe.XXXXXX") + + # Use tee to save the original pipe data for comparison + perf record -e task-clock:u -o - ${prog} | tee "${data}" | perf inject --aslr -o "${data2}" + + orig_addr=$(get_noploop_addr "${data}") + new_addr=$(get_noploop_addr "${data2}") + + echo "Pipe ASLR: orig_addr=$orig_addr, new_addr=$new_addr" + + if [ -z "$orig_addr" ]; then + echo "Pipe ASLR test [Failed - no noploop samples in original file]" + err=1 + elif [ -z "$new_addr" ]; then + echo "Pipe ASLR test [Failed - could not find remapped address]" + err=1 + elif [ "$orig_addr" = "$new_addr" ]; then + echo "Pipe ASLR test [Failed - addresses are not remapped]" + err=1 + else + echo "Pipe ASLR test [Success]" + fi +} + +test_callchain_aslr() { + echo "Test Callchain ASLR remapping" + local data + data=$(mktemp "${temp_dir}/perf.data.callchain.XXXXXX") + local data2 + data2=$(mktemp "${temp_dir}/perf.data2.callchain.XXXXXX") + + perf record -g -e task-clock:u -o "${data}" ${prog} + perf inject --aslr -i "${data}" -o "${data2}" + + orig_addr=$(get_noploop_addr "${data}") + new_addr=$(get_noploop_addr "${data2}") + + echo "Callchain ASLR: orig_addr=$orig_addr, new_addr=$new_addr" + + if [ -z "$orig_addr" ]; then + echo "Callchain ASLR test [Failed - no noploop samples in original file]" + err=1 + elif [ -z "$new_addr" ]; then + echo "Callchain ASLR test [Failed - could not find remapped address]" + err=1 + elif [ "$orig_addr" = "$new_addr" ]; then + echo "Callchain ASLR test [Failed - addresses are not remapped]" + err=1 + else + # Extract callchain addresses (indented lines starting with hex addresses) + orig_callchain=$(perf script -i "${data}" | awk '/^[[:space:]]+[0-9a-f]+/ {print $1}') + new_callchain=$(perf script -i "${data2}" | awk '/^[[:space:]]+[0-9a-f]+/ {print $1}') + + if [ -z "$orig_callchain" ]; then + echo "Callchain ASLR test [Failed - no callchain samples in original file]" + err=1 + elif [ -z "$new_callchain" ]; then + echo "Callchain ASLR test [Failed - callchain data was dropped]" + err=1 + elif [ "$orig_callchain" = "$new_callchain" ]; then + echo "Callchain ASLR test [Failed - callchain addresses were not remapped]" + err=1 + else + echo "Callchain ASLR test [Success]" + fi + fi +} + +test_report_aslr() { + echo "Test perf report consistency" + local data + data=$(mktemp "${temp_dir}/perf.data.report.XXXXXX") + local data2 + data2=$(mktemp "${temp_dir}/perf.data2.report.XXXXXX") + local data_clean + data_clean=$(mktemp "${temp_dir}/perf.data.clean.XXXXXX") + + perf record -e task-clock:u -o "${data}" ${prog} + # Use -b to inject build-ids and force ordered events processing in both + perf inject -b -i "${data}" -o "${data_clean}" + perf inject -v -b --aslr -i "${data}" -o "${data2}" + + local report1="${temp_dir}/report1_basic" + local report2="${temp_dir}/report2_basic" + local report1_clean="${temp_dir}/report1_basic.clean" + local report2_clean="${temp_dir}/report2_basic.clean" + local diff_file="${temp_dir}/diff_basic" + + perf report -i "${data_clean}" --stdio > "${report1}" + perf report -i "${data2}" --stdio > "${report2}" + + # Strip headers and compare lines with percentages + grep '%' "${report1}" | grep -v '^#' | \ + grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | sort > "${report1_clean}" || true + grep '%' "${report2}" | grep -v '^#' | \ + grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | sort > "${report2_clean}" || true + + diff -u -w "${report1_clean}" "${report2_clean}" > "${diff_file}" || true + + if [ ! -s "${report1_clean}" ]; then + echo "Report ASLR test [Failed - no samples captured]" + err=1 + elif [ -s "${diff_file}" ]; then + echo "Report ASLR test [Failed - reports differ]" + echo "Showing first 20 lines of diff:" + head -n 20 "${diff_file}" + err=1 + else + echo "Report ASLR test [Success]" + fi +} + +test_pipe_report_aslr() { + echo "Test pipe mode perf report consistency" + local data + data=$(mktemp "${temp_dir}/perf.data.pipe_report.XXXXXX") + local data2 + data2=$(mktemp "${temp_dir}/perf.data2.pipe_report.XXXXXX") + local data_clean + data_clean=$(mktemp "${temp_dir}/perf.data.clean.XXXXXX") + + # Use tee to save the original pipe data, then process it with inject -b + perf record -e task-clock:u -o - ${prog} | \ + tee "${data}" | \ + perf inject -b --aslr -o "${data2}" + perf inject -b -i "${data}" -o "${data_clean}" + + local report1="${temp_dir}/report1_pipe" + local report2="${temp_dir}/report2_pipe" + local report1_clean="${temp_dir}/report1_pipe.clean" + local report2_clean="${temp_dir}/report2_pipe.clean" + local diff_file="${temp_dir}/diff_pipe" + + perf report -i "${data_clean}" --stdio > "${report1}" + perf report -i "${data2}" --stdio > "${report2}" + + # Strip headers and compare lines with percentages + grep '%' "${report1}" | grep -v '^#' | \ + grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | sort > "${report1_clean}" || true + grep '%' "${report2}" | grep -v '^#' | \ + grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | sort > "${report2_clean}" || true + + diff -u -w "${report1_clean}" "${report2_clean}" > "${diff_file}" || true + + if [ ! -s "${report1_clean}" ]; then + echo "Pipe Report ASLR test [Failed - no samples captured]" + err=1 + elif [ -s "${diff_file}" ]; then + echo "Pipe Report ASLR test [Failed - reports differ]" + echo "Showing first 20 lines of diff:" + head -n 20 "${diff_file}" + err=1 + else + echo "Pipe Report ASLR test [Success]" + fi +} + +test_pipe_out_report_aslr() { + echo "Test pipe output mode perf report consistency" + local data + data=$(mktemp "${temp_dir}/perf.data.pipe_out_report.XXXXXX") + local data_clean + data_clean=$(mktemp "${temp_dir}/perf.data.clean.XXXXXX") + + perf record -e task-clock:u -o "${data}" ${prog} + perf inject -b -i "${data}" -o "${data_clean}" + + local report1="${temp_dir}/report1_pipe_out" + local report2="${temp_dir}/report2_pipe_out" + local report1_clean="${temp_dir}/report1_pipe_out.clean" + local report2_clean="${temp_dir}/report2_pipe_out.clean" + local diff_file="${temp_dir}/diff_pipe_out" + + perf report -i "${data_clean}" --stdio > "${report1}" + perf inject -b --aslr -i "${data}" -o - | perf report -i - --stdio > "${report2}" + + # Strip headers and compare lines with percentages + grep '%' "${report1}" | grep -v '^#' | \ + grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | sort > "${report1_clean}" || true + grep '%' "${report2}" | grep -v '^#' | \ + grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | sort > "${report2_clean}" || true + + diff -u -w "${report1_clean}" "${report2_clean}" > "${diff_file}" || true + + if [ ! -s "${report1_clean}" ]; then + echo "Pipe Output Report ASLR test [Failed - no samples captured]" + err=1 + elif [ -s "${diff_file}" ]; then + echo "Pipe Output Report ASLR test [Failed - reports differ]" + echo "Showing first 20 lines of diff:" + head -n 20 "${diff_file}" + err=1 + else + echo "Pipe Output Report ASLR test [Success]" + fi +} + +test_dropped_samples() { + echo "Test dropped samples (phys-data)" + local data + data=$(mktemp "${temp_dir}/perf.data.dropped.XXXXXX") + local data2 + data2=$(mktemp "${temp_dir}/perf.data2.dropped.XXXXXX") + + # Check if --phys-data is supported by recording a short run + if ! perf record -e task-clock:u --phys-data -o "${data}" -- sleep 0.1 > /dev/null 2>&1; then + echo "Skipping dropped samples test as --phys-data is not supported" + return + fi + + perf record -e task-clock:u --phys-data -o "${data}" ${prog} + perf inject --aslr -i "${data}" -o "${data2}" + + # Verify that the original file actually contained samples! + orig_samples=$(perf script -i "${data}" | wc -l) + if [ "$orig_samples" -eq 0 ]; then + echo "Dropped samples test [Failed - no samples in original file]" + err=1 + else + # Verify that samples are dropped. + samples_count=$(perf script -i "${data2}" | wc -l) + + if [ "$samples_count" -gt 0 ]; then + echo "Dropped samples test [Failed - samples were not dropped]" + err=1 + else + echo "Dropped samples test [Success]" + fi + fi +} + +test_kernel_aslr() { + echo "Test kernel ASLR remapping" + local kdata + kdata=$(mktemp "${temp_dir}/perf.data.kernel.XXXXXX") + local kdata2 + kdata2=$(mktemp "${temp_dir}/perf.data2.kernel.XXXXXX") + local log_file + log_file=$(mktemp "${temp_dir}/kernel_record.log.XXXXXX") + + # Try to record kernel samples + if ! perf record -e task-clock:k -o "${kdata}" ${kprog} > "${log_file}" 2>&1; then + echo "Skipping kernel ASLR test as recording failed (maybe no permissions)" + return + fi + + # Check for warning about kernel map restriction + if grep -q "Couldn't record kernel reference relocation symbol" "${log_file}"; then + echo "Skipping kernel ASLR test as kernel map could not be recorded (permissions restricted)" + return + fi + + perf inject -v --aslr -i "${kdata}" -o "${kdata2}" + + # Check if kernel addresses are remapped. + # Find the field that ends with :k: (the event name) and take the next field! + orig_addr=$(perf script -i "${kdata}" | awk ' + BEGIN { found=0 } + { + for (i=1; i "${log_file}" 2>&1; then + echo "Skipping kernel report test as recording failed (maybe no permissions)" + return + fi + + # Check for warning about kernel map restriction + if grep -q "Couldn't record kernel reference relocation symbol" "${log_file}"; then + echo "Skipping kernel report test as kernel map could not be recorded (permissions restricted)" + return + fi + + # Use -b to inject build-ids and force ordered events processing in both + perf inject -b -i "${kdata}" -o "${data_clean}" + perf inject -v -b --aslr -i "${kdata}" -o "${kdata2}" + + local report1="${temp_dir}/report_kernel1" + local report2="${temp_dir}/report_kernel2" + local report1_clean="${temp_dir}/report_kernel1.clean" + local report2_clean="${temp_dir}/report_kernel2.clean" + + perf report -i "${data_clean}" --stdio > "${report1}" + perf report -i "${kdata2}" --stdio > "${report2}" + + # Strip headers and compare lines with percentages + grep '%' "${report1}" | grep -v '^#' > "${report1_clean}" || true + grep '%' "${report2}" | grep -v '^#' > "${report2_clean}" || true + + # Normalize kernel DSOs and addresses in clean reports + # This allows kernel modules to be either a module or kernel.kallsyms + local report1_norm="${temp_dir}/report_kernel1.norm" + local report2_norm="${temp_dir}/report_kernel2.norm" + local diff_file="${temp_dir}/diff_kernel" + + grep -v -E '0x[0-9a-f]{8,}|0000000000000000' "${report1_clean}" | \ + awk '{gsub(/\[[a-zA-Z0-9_.-]{2,}\](\.[a-zA-Z0-9_]+)?/, "[kernel]", $0); print}' | \ + sort > "${report1_norm}" || true + grep -v -E '0x[0-9a-f]{8,}|0000000000000000' "${report2_clean}" | \ + awk '{gsub(/\[[a-zA-Z0-9_.-]{2,}\](\.[a-zA-Z0-9_]+)?/, "[kernel]", $0); print}' | \ + sort > "${report2_norm}" || true + + diff -u -w "${report1_norm}" "${report2_norm}" > "${diff_file}" || true + + if [ ! -s "${report1_norm}" ]; then + echo "Kernel Report ASLR test [Failed - no samples captured]" + err=1 + elif [ -s "${diff_file}" ]; then + echo "Kernel Report ASLR test [Failed - reports differ]" + echo "Showing first 20 lines of diff:" + head -n 20 "${diff_file}" + err=1 + else + echo "Kernel Report ASLR test [Success]" + fi +} + +test_regs_stripping() { + echo "Test user register stripping" + local rdata="${temp_dir}/perf.data.regs" + local rdata2="${temp_dir}/perf.data.regs.injected" + local rdata_clean="${temp_dir}/perf.data.regs.clean" + + if ! perf record -e cycles:u --user-regs -o "${rdata}" ${prog} > /dev/null 2>&1; then + echo "Skipping user registers test as recording failed (unsupported flag/platform)" + return + fi + + perf inject -b -i "${rdata}" -o "${rdata_clean}" + perf inject -v -b --aslr -i "${rdata}" -o "${rdata2}" + + local report1="${temp_dir}/report_regs1" + local report2="${temp_dir}/report_regs2" + local report1_clean="${temp_dir}/report_regs1.clean" + local report2_clean="${temp_dir}/report_regs2.clean" + local diff_file="${temp_dir}/diff_regs" + + perf report -i "${rdata_clean}" --stdio > "${report1}" 2>/dev/null || true + perf report -i "${rdata2}" --stdio > "${report2}" 2>/dev/null || true + + grep '%' "${report1}" | grep -v '^#' | \ + grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | \ + sort > "${report1_clean}" || true + grep '%' "${report2}" | grep -v '^#' | \ + grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | \ + sort > "${report2_clean}" || true + + diff -u -w "${report1_clean}" "${report2_clean}" > "${diff_file}" || true + + if [ ! -s "${report1_clean}" ]; then + echo "User registers stripping test [Failed - profile trace starved/empty]" + err=1 + return + elif [ -s "${diff_file}" ]; then + echo "User registers stripping test [Failed - report parsing differs]" + echo "Showing first 20 lines of diff:" + head -n 20 "${diff_file}" + err=1 + return + fi + + local script_dump="${temp_dir}/script_regs_dump" + perf script -D -i "${rdata2}" > "${script_dump}" 2>/dev/null || true + if grep -q "user regs:" "${script_dump}"; then + echo "User registers stripping test [Failed - register dumps still present]" + err=1 + else + echo "User registers stripping test [Success]" + fi +} + +test_basic_aslr +test_pipe_aslr +test_callchain_aslr +test_report_aslr +test_pipe_report_aslr +test_pipe_out_report_aslr +test_dropped_samples +case "$(uname -m)" in + aarch64*|arm*) + echo "Skipping kernel ASLR tests on ARM" + ;; + *) + test_kernel_aslr + test_kernel_report_aslr + ;; +esac + +test_regs_stripping + +cleanup ${err} +exit $err -- 2.54.0.1099.g489fc7bff1-goog