1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
34use std::process::Stdio;
56pub(crate) async fn livedump() {
7// If a livedump fails we don't want to panic, just log the error.
8match livedump_core().await {
9Err(e) => tracing::error!(?e, "livedump failed"),
10Ok(()) => tracing::info!("livedump succeeded"),
11 }
12}
1314async fn livedump_core() -> anyhow::Result<()> {
15if underhill_confidentiality::confidential_filtering_enabled() {
16tracing::info!("livedump disabled due to CVM");
17return Ok(());
18 }
1920let (dump_read, dump_write) = pal::unix::pipe::pair()?;
2122// Spawn underhill-crash to forward the crash dump to the host.
23 // Give it what arguments we can, but as this is a live dump they're not quite as relevant.
24let crash_proc = std::process::Command::new("underhill-crash")
25 .stdin(dump_read)
26 .stdout(Stdio::piped())
27 .stderr(Stdio::null())
28// Don't redirect output so we can capture it.
29.env("UNDERHILL_CRASH_NO_REDIRECT", "1")
30// Don't include kmsg, since underhill-dump will do that.
31.env("UNDERHILL_CRASH_NO_KMSG", "1")
32 .arg(std::process::id().to_string()) // pid
33.arg(0.to_string()) // tid
34.arg(0.to_string()) // sig
35.arg(std::env::current_exe().unwrap_or_default()) // comm
36.spawn()?;
3738// Spawn underhill-dump to create the dump.
39 // This needs to be done after underhill-crash, as underhill-dump will pause us.
40let dump_result = std::process::Command::new("underhill-dump")
41 .arg(format!("{}", std::process::id()))
42 .stdin(Stdio::null())
43 .stdout(dump_write)
44 .stderr(Stdio::piped())
45 .output()?;
4647// underhill-dump should finish first, as it's the producer.
48let crash_result = crash_proc.wait_with_output()?;
4950// Check for errors. If both failed log both outputs, as one crashing may cause the other to fail.
51if !dump_result.status.success() {
52let dump_output = String::from_utf8_lossy(&dump_result.stderr);
53for line in dump_output.lines() {
54tracing::info!("underhill-dump output: {}", line);
55 }
56 }
5758if !crash_result.status.success() {
59let crash_output = String::from_utf8_lossy(&crash_result.stdout);
60for line in crash_output.lines() {
61tracing::info!("underhill-crash output: {}", line);
62 }
63anyhow::bail!("underhill-crash failed: {}", crash_result.status);
64 }
6566if !dump_result.status.success() {
67anyhow::bail!("underhill-dump failed: {}", dump_result.status);
68 }
6970Ok(())
71}