Skip to content

Commit 4e8d0d1

Browse files
committed
add CI gdb test
Signed-off-by: Doru Blânzeanu <[email protected]>
1 parent d41a4d9 commit 4e8d0d1

File tree

3 files changed

+174
-0
lines changed

3 files changed

+174
-0
lines changed

.github/workflows/dep_rust.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,13 @@ jobs:
115115
RUST_LOG: debug
116116
run: just run-rust-examples-linux ${{ matrix.config }} ${{ matrix.hypervisor == 'mshv3' && 'mshv3' || ''}}
117117

118+
- name: Run Rust Debugging examples - linux
119+
if: runner.os == 'Linux' && matrix.hypervisor == 'kvm'
120+
env:
121+
CARGO_TERM_COLOR: always
122+
RUST_LOG: debug
123+
run: just run-rust-examples-debugging ${{ matrix.config }}
124+
118125
### Benchmarks ###
119126
- name: Install github-cli (Linux mariner)
120127
if: runner.os == 'Linux' && matrix.hypervisor == 'mshv'

Justfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,10 @@ run-rust-examples-linux target=default-target features="": (build-rust target) (
159159
{{ set-trace-env-vars }} cargo run --profile={{ if target == "debug" { "dev" } else { target } }} --example tracing {{ if features =="" {''} else { "--features " + features } }}
160160
{{ set-trace-env-vars }} cargo run --profile={{ if target == "debug" { "dev" } else { target } }} --example tracing {{ if features =="" {"--features function_call_metrics" } else {"--features function_call_metrics," + features} }}
161161

162+
# Verify that the debugging works
163+
run-rust-examples-debugging target=default-target: (build-rust target)
164+
{{ set-trace-env-vars }} cargo test --profile={{ if target == "debug" { "dev" } else { target } }} --example guest-debugging --features gdb
165+
162166
# BENCHMARKING
163167

164168
# Warning: can overwrite previous local benchmarks, so run this before running benchmarks

src/hyperlight_host/examples/guest-debugging/main.rs

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,166 @@ fn main() -> hyperlight_host::Result<()> {
8080

8181
Ok(())
8282
}
83+
84+
#[cfg(gdb)]
85+
#[cfg(test)]
86+
mod tests {
87+
use std::fs::File;
88+
use std::io;
89+
use std::process::{Command, Stdio};
90+
use std::time::Duration;
91+
92+
use hyperlight_host::{new_error, Result};
93+
use io::{BufReader, BufWriter, Read, Write};
94+
95+
use super::*;
96+
97+
fn write_cmds_file(cmd_file_path: &str, out_file_path: &str) -> io::Result<()> {
98+
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("Failed to get manifest dir");
99+
let file = File::create(cmd_file_path)?;
100+
let mut writer = BufWriter::new(file);
101+
102+
// write from string to file
103+
writer.write_all(
104+
format!(
105+
"file {manifest_dir}/../tests/rust_guests/bin/debug/simpleguest
106+
target remote :8080
107+
108+
set pagination off
109+
set logging file {out_file_path}
110+
set logging enabled on
111+
112+
break hyperlight_main
113+
commands
114+
echo \"Stopped at hyperlight_main breakpoint\\n\"
115+
backtrace
116+
continue
117+
end
118+
119+
continue
120+
121+
set logging enabled off
122+
quit
123+
"
124+
)
125+
.as_bytes(),
126+
)?;
127+
128+
writer.flush()
129+
}
130+
131+
fn run_guest_and_gdb(cmd_file_path: &str, out_file_path: &str) -> Result<()> {
132+
// write gdb commands to file
133+
134+
write_cmds_file(&cmd_file_path, &out_file_path)
135+
.expect("Failed to write gdb commands to file");
136+
137+
let mut guest_child = Command::new("cargo")
138+
.arg("run")
139+
.arg("--example")
140+
.arg("guest-debugging")
141+
.arg("--features")
142+
.arg("gdb")
143+
.stdin(Stdio::piped())
144+
.stdout(Stdio::piped())
145+
.spawn()
146+
.map_err(|e| new_error!("Failed to start guest process: {}", e))?;
147+
148+
// wait 3 seconds for the gdb to connect
149+
thread::sleep(Duration::from_secs(3));
150+
151+
let mut gdb = Command::new("rust-gdb")
152+
.arg("--nw")
153+
.arg("-x")
154+
.arg(cmd_file_path)
155+
.spawn()
156+
.map_err(|e| new_error!("Failed to start gdb process: {}", e))?;
157+
158+
// wait 3 seconds for the gdb to connect
159+
thread::sleep(Duration::from_secs(10));
160+
161+
// check if the guest process has finished
162+
match guest_child.try_wait() {
163+
Ok(Some(status)) => {
164+
if !status.success() {
165+
Err(new_error!(
166+
"Guest process exited with non-zero status: {}",
167+
status
168+
))?;
169+
}
170+
}
171+
Ok(None) => {
172+
guest_child
173+
.kill()
174+
.map_err(|e| new_error!("Failed to kill child process: {}", e))?;
175+
}
176+
Err(e) => {
177+
Err(new_error!("error attempting to wait guest: {}", e))?;
178+
}
179+
}
180+
181+
// check if the gdb process has finished
182+
match gdb.try_wait() {
183+
Ok(Some(status)) => {
184+
if !status.success() {
185+
Err(new_error!(
186+
"Gdb process exited with non-zero status: {}",
187+
status
188+
))?;
189+
}
190+
}
191+
Ok(None) => {
192+
gdb.kill()
193+
.map_err(|e| new_error!("Failed to kill guest process: {}", e))?;
194+
}
195+
Err(e) => {
196+
Err(new_error!("error attempting to wait gdb: {}", e))?;
197+
}
198+
}
199+
200+
check_output(&out_file_path)
201+
}
202+
203+
fn check_output(out_file_path: &str) -> Result<()> {
204+
let results = File::open(out_file_path)
205+
.map_err(|e| new_error!("Failed to open gdb.output file: {}", e))?;
206+
let mut reader = BufReader::new(results);
207+
let mut contents = String::new();
208+
reader.read_to_string(&mut contents).unwrap();
209+
210+
if contents.contains("Stopped at hyperlight_main breakpoint") {
211+
Ok(())
212+
} else {
213+
Err(new_error!(
214+
"Failed to find expected output in gdb.output file"
215+
))
216+
}
217+
}
218+
219+
fn cleanup(out_file_path: &str, cmd_file_path: &str) -> Result<()> {
220+
let res1 = std::fs::remove_file(out_file_path)
221+
.map_err(|e| new_error!("Failed to remove gdb.output file: {}", e));
222+
let res2 = std::fs::remove_file(cmd_file_path)
223+
.map_err(|e| new_error!("Failed to remove gdb-commands.txt file: {}", e));
224+
225+
res1?;
226+
res2?;
227+
228+
Ok(())
229+
}
230+
231+
#[test]
232+
fn test_gdb_end_to_end() {
233+
let out_dir = std::env::var("OUT_DIR").expect("Failed to get out dir");
234+
let out_file_path = format!("{out_dir}/gdb.output");
235+
let cmd_file_path = format!("{out_dir}/gdb-commands.txt");
236+
237+
let result = run_guest_and_gdb(&cmd_file_path, &out_file_path);
238+
239+
// cleanup
240+
let cleanup_result = cleanup(&out_file_path, &cmd_file_path);
241+
assert!(cleanup_result.is_ok(), "{}", cleanup_result.unwrap_err());
242+
// check if the test passed - done at the end to ensure cleanup is done
243+
assert!(result.is_ok(), "{}", result.unwrap_err());
244+
}
245+
}

0 commit comments

Comments
 (0)