Skip to content

Commit f3f8bf0

Browse files
committed
scripts: sof-qemu-run: add native_sim and valgrind support
Add native_sim board target to the sof-qemu-run scripts, and add an option to additionally run it under valgrind. The default build directory is set to ../build-native_sim Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
1 parent 89701c3 commit f3f8bf0

2 files changed

Lines changed: 122 additions & 41 deletions

File tree

scripts/sof-qemu-run.py

Lines changed: 82 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,12 @@ def main():
7676
parser = argparse.ArgumentParser(description="Run QEMU via west and automatically decode crashes.")
7777
parser.add_argument("--build-dir", default="build", help="Path to the build directory containing zephyr.elf, linker.cmd, etc. Defaults to 'build'.")
7878
parser.add_argument("--log-file", default="qemu-run.log", help="Path to save the QEMU output log. Defaults to 'qemu-run.log'.")
79+
parser.add_argument("--valgrind", action="store_true", help="Run the executable under Valgrind (only valid for native_sim).")
7980
args = parser.parse_args()
8081

8182
# Make absolute path just in case
83+
# The shell script cd's into `args.build_dir` before executing us, so `args.build_dir` might be relative to the shell script's pwd.
84+
# We resolve it relative to the python script's original invocation cwd.
8285
build_dir = os.path.abspath(args.build_dir)
8386

8487
print(f"Starting QEMU test runner. Monitoring for crashes (Build Dir: {args.build_dir})...")
@@ -91,7 +94,53 @@ def main():
9194
print("Please ensure you have sourced the Zephyr environment (e.g., source zephyr-env.sh).")
9295
sys.exit(1)
9396

94-
child = pexpect.spawn(west_path, ["-v", "build", "-t", "run"], encoding='utf-8')
97+
# Detect the board configuration from CMakeCache.txt
98+
is_native_sim = False
99+
100+
cmake_cache = os.path.join(build_dir, "CMakeCache.txt")
101+
102+
if os.path.isfile(cmake_cache):
103+
with open(cmake_cache, "r") as f:
104+
for line in f:
105+
if line.startswith("CACHED_BOARD:STRING=") or line.startswith("BOARD:STRING="):
106+
if "native_sim" in line.split("=", 1)[1].strip():
107+
is_native_sim = True
108+
break
109+
110+
# Determine execution command
111+
# If the user is running the python script directly from outside the workspace, we need to provide the source directory.
112+
# But if west finds it automatically (or we are in the build dir), providing `-s` might clear the CACHED_BOARD config.
113+
run_cmd = [west_path, "-v", "build", "-d", build_dir]
114+
115+
# Check if we are physically sitting inside the build directory
116+
if os.path.abspath(".") != os.path.abspath(build_dir):
117+
# We need to explicitly supply the app source to prevent west from crashing
118+
app_source_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "app"))
119+
run_cmd.extend(["-s", app_source_dir])
120+
121+
run_cmd.extend(["-t", "run"])
122+
123+
if args.valgrind:
124+
if not is_native_sim:
125+
print("[sof-qemu-run] Error: --valgrind is only supported for the native_sim board.")
126+
sys.exit(1)
127+
128+
print("[sof-qemu-run] Rebuilding before valgrind...")
129+
subprocess.run([west_path, "build", "-d", build_dir], check=True)
130+
131+
valgrind_path = shutil.which("valgrind")
132+
if not valgrind_path:
133+
print("[sof-qemu-run] Error: 'valgrind' command not found in PATH.")
134+
sys.exit(1)
135+
136+
exe_path = os.path.join(build_dir, "zephyr", "zephyr.exe")
137+
if not os.path.isfile(exe_path):
138+
print(f"[sof-qemu-run] Error: Executable not found at {exe_path}")
139+
sys.exit(1)
140+
141+
run_cmd = [valgrind_path, exe_path]
142+
143+
child = pexpect.spawn(run_cmd[0], run_cmd[1:], encoding='utf-8')
95144

96145
# We will accumulate output to check for crashes
97146
full_output = ""
@@ -157,36 +206,39 @@ def main():
157206

158207
run_sof_crash_decode(build_dir, full_output)
159208
else:
160-
print("\n[sof-qemu-run] No crash detected. Interacting with QEMU Monitor to grab registers...")
161-
162-
# We need to send Ctrl-A c to enter the monitor
163-
if child.isalive():
164-
child.send("\x01c") # Ctrl-A c
165-
try:
166-
# Wait for (qemu) prompt
167-
child.expect(r"\(qemu\)", timeout=5)
168-
# Send "info registers"
169-
child.sendline("info registers")
170-
# Wait for the next prompt
171-
child.expect(r"\(qemu\)", timeout=5)
172-
173-
info_regs_output = child.before
174-
print("\n[sof-qemu-run] Successfully extracted registers from QEMU monitor.\n")
175-
176-
# Quit qemu safely
177-
child.sendline("quit")
178-
child.expect(pexpect.EOF, timeout=2)
179-
child.close()
180-
181-
# Run the decoder on the intercepted register output
182-
run_sof_crash_decode(build_dir, info_regs_output)
183-
except pexpect.TIMEOUT:
184-
print("\n[sof-qemu-run] Timed out waiting for QEMU monitor. Is it running?")
185-
child.close(force=True)
186-
except pexpect.EOF:
187-
print("\n[sof-qemu-run] QEMU terminated before we could run monitor commands.")
209+
if is_native_sim:
210+
print("\n[sof-qemu-run] No crash detected. (Skipping QEMU monitor interaction for native_sim)")
188211
else:
189-
print("\n[sof-qemu-run] Process is no longer alive, cannot extract registers.")
212+
print("\n[sof-qemu-run] No crash detected. Interacting with QEMU Monitor to grab registers...")
213+
214+
# We need to send Ctrl-A c to enter the monitor
215+
if child.isalive():
216+
child.send("\x01c") # Ctrl-A c
217+
try:
218+
# Wait for (qemu) prompt
219+
child.expect(r"\(qemu\)", timeout=5)
220+
# Send "info registers"
221+
child.sendline("info registers")
222+
# Wait for the next prompt
223+
child.expect(r"\(qemu\)", timeout=5)
224+
225+
info_regs_output = child.before
226+
print("\n[sof-qemu-run] Successfully extracted registers from QEMU monitor.\n")
227+
228+
# Quit qemu safely
229+
child.sendline("quit")
230+
child.expect(pexpect.EOF, timeout=2)
231+
child.close()
232+
233+
# Run the decoder on the intercepted register output
234+
run_sof_crash_decode(build_dir, info_regs_output)
235+
except pexpect.TIMEOUT:
236+
print("\n[sof-qemu-run] Timed out waiting for QEMU monitor. Is it running?")
237+
child.close(force=True)
238+
except pexpect.EOF:
239+
print("\n[sof-qemu-run] QEMU terminated before we could run monitor commands.")
240+
else:
241+
print("\n[sof-qemu-run] Process is no longer alive, cannot extract registers.")
190242

191243
if __name__ == "__main__":
192244
main()

scripts/sof-qemu-run.sh

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,56 @@
22
# SPDX-License-Identifier: BSD-3-Clause
33
# Copyright(c) 2026 Intel Corporation. All rights reserved.
44

5-
# Define the build directory from the first argument (or default)
6-
BUILD_DIR="${1:-build}"
5+
# Get the directory of this script
6+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7+
SOF_WORKSPACE="$(dirname "$(dirname "$SCRIPT_DIR")")"
8+
9+
BUILD_DIR="build-native_sim"
10+
VALGRIND_ARG=""
11+
12+
usage() {
13+
cat <<EOF
14+
Usage: $0 [OPTIONS] [BUILD_DIR]
15+
16+
Options:
17+
-h, --help Show this help message and exit
18+
--valgrind Run under valgrind
19+
20+
BUILD_DIR The build directory relative to the workspace (default: build-native_sim)
21+
EOF
22+
exit 0
23+
}
24+
25+
while [[ $# -gt 0 ]]; do
26+
case $1 in
27+
-h|--help)
28+
usage
29+
;;
30+
--valgrind)
31+
VALGRIND_ARG="--valgrind"
32+
;;
33+
*)
34+
BUILD_DIR="$1"
35+
;;
36+
esac
37+
shift
38+
done
39+
40+
# Ensure BUILD_DIR is resolved relative to the workspace, if it's not absolute
41+
if [[ "$BUILD_DIR" != /* ]]; then
42+
BUILD_DIR="${SOF_WORKSPACE}/${BUILD_DIR}"
43+
fi
744

845
# Find and source the zephyr environment script, typically via the sof-venv wrapper
946
# or directly if running in a known zephyrproject layout.
1047
# We will use the existing helper sof-venv.sh to get the right environment.
1148

12-
# Get the directory of this script
13-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
14-
SOF_WORKSPACE="$(dirname "$(dirname "$SCRIPT_DIR")")"
15-
1649
# Use the SOF workspace to locate the virtual environment
1750
VENV_DIR="$SOF_WORKSPACE/.venv"
1851
echo "Using SOF environment at $SOF_WORKSPACE"
1952

2053
# start the virtual environment
2154
source ${VENV_DIR}/bin/activate
2255

23-
# Execute the QEMU runner from within the correct build directory
24-
cd "${BUILD_DIR}" || exit 1
25-
2656
# Finally run the python script which will now correctly inherit 'west' from the sourced environment.
27-
python3 "${SCRIPT_DIR}/sof-qemu-run.py" --build-dir "${BUILD_DIR}"
28-
57+
python3 "${SCRIPT_DIR}/sof-qemu-run.py" --build-dir "${BUILD_DIR}" $VALGRIND_ARG

0 commit comments

Comments
 (0)