Parcourir la source

integration-test: compile without touching disk

Tamir Duberstein il y a 1 an
Parent
commit
c76d5a9950
2 fichiers modifiés avec 71 ajouts et 37 suppressions
  1. 0 1
      test/integration-test/Cargo.toml
  2. 71 36
      test/integration-test/tests/btf_relocations.rs

+ 0 - 1
test/integration-test/Cargo.toml

@@ -18,7 +18,6 @@ object = { version = "0.31", default-features = false, features = [
     "elf",
 ] }
 rbpf = "0.2.0"
-tempfile = "3.3.0"
 tokio = { version = "1.24", default-features = false, features = ["time"] }
 
 [build-dependencies]

+ 71 - 36
test/integration-test/tests/btf_relocations.rs

@@ -1,6 +1,9 @@
-use anyhow::{bail, Context as _, Result};
-use std::{path::PathBuf, process::Command, thread::sleep, time::Duration};
-use tempfile::TempDir;
+use anyhow::{anyhow, bail, Context as _, Result};
+use std::{
+    process::{Child, ChildStdout, Command, Stdio},
+    thread::sleep,
+    time::Duration,
+};
 
 use aya::{maps::Array, programs::TracePoint, util::KernelVersion, BpfLoader, Btf, Endianness};
 
@@ -215,9 +218,15 @@ impl RelocationTest {
     /// - Generate the source eBPF filling a template
     /// - Compile it with clang
     fn build_ebpf(&self) -> Result<Vec<u8>> {
-        let local_definition = self.local_definition;
-        let relocation_code = self.relocation_code;
-        let (_tmp_dir, compiled_file) = compile(&format!(
+        use std::io::Read as _;
+
+        let Self {
+            local_definition,
+            relocation_code,
+            ..
+        } = self;
+
+        let mut stdout = compile(&format!(
             r#"
                 #include <linux/bpf.h>
 
@@ -250,23 +259,29 @@ impl RelocationTest {
                 char _license[] __attribute__((section("license"), used)) = "GPL";
             "#
         ))
-        .context("Failed to compile eBPF program")?;
-        let bytecode =
-            std::fs::read(compiled_file).context("Error reading compiled eBPF program")?;
-        Ok(bytecode)
+        .context("failed to compile eBPF program")?;
+        let mut output = Vec::new();
+        stdout.read_to_end(&mut output)?;
+        Ok(output)
     }
 
     /// - Generate the target BTF source with a mock main()
     /// - Compile it with clang
     /// - Extract the BTF with llvm-objcopy
     fn build_btf(&self) -> Result<Btf> {
-        let target_btf = self.target_btf;
-        let relocation_code = self.relocation_code;
+        use std::io::Read as _;
+
+        let Self {
+            target_btf,
+            relocation_code,
+            ..
+        } = self;
+
         // BTF files can be generated and inspected with these commands:
         // $ clang -c -g -O2 -target bpf target.c
         // $ pahole --btf_encode_detached=target.btf -V target.o
         // $ bpftool btf dump file ./target.btf  format c
-        let (tmp_dir, compiled_file) = compile(&format!(
+        let stdout = compile(&format!(
             r#"
                 #include <linux/bpf.h>
 
@@ -280,14 +295,20 @@ impl RelocationTest {
                 }}
             "#
         ))
-        .context("Failed to compile BTF")?;
+        .context("failed to compile BTF")?;
+
         let mut cmd = Command::new("llvm-objcopy");
-        cmd.current_dir(tmp_dir.path())
-            .args(["--dump-section", ".BTF=target.btf"])
-            .arg(compiled_file);
-        let status = cmd
-            .status()
-            .with_context(|| format!("Failed to run {cmd:?}"))?;
+        cmd.args(["--dump-section", ".BTF=-", "-"])
+            .stdin(stdout)
+            .stdout(Stdio::piped());
+        let mut child = cmd
+            .spawn()
+            .with_context(|| format!("failed to spawn {cmd:?}"))?;
+        let Child { stdout, .. } = &mut child;
+        let mut stdout = stdout.take().ok_or(anyhow!("failed to open stdout"))?;
+        let status = child
+            .wait()
+            .with_context(|| format!("failed to wait for {cmd:?}"))?;
         match status.code() {
             Some(code) => match code {
                 0 => {}
@@ -295,25 +316,39 @@ impl RelocationTest {
             },
             None => bail!("{cmd:?} terminated by signal"),
         }
-        let btf = Btf::parse_file(tmp_dir.path().join("target.btf"), Endianness::default())
-            .context("Error parsing generated BTF")?;
-        Ok(btf)
+
+        let mut output = Vec::new();
+        stdout.read_to_end(&mut output)?;
+
+        Btf::parse(output.as_slice(), Endianness::default())
+            .context("failed to parse generated BTF")
     }
 }
 
-/// Compile an eBPF program and return the path of the compiled object.
-/// Also returns a TempDir handler, dropping it will clear the created dicretory.
-fn compile(source_code: &str) -> Result<(TempDir, PathBuf)> {
-    let tmp_dir = tempfile::tempdir().context("Error making temp dir")?;
-    let source = tmp_dir.path().join("source.c");
-    std::fs::write(&source, source_code).context("Writing bpf program failed")?;
+/// Compile an eBPF program and return its bytes.
+fn compile(source_code: &str) -> Result<ChildStdout> {
+    use std::io::Write as _;
+
     let mut cmd = Command::new("clang");
-    cmd.current_dir(&tmp_dir)
-        .args(["-c", "-g", "-O2", "-target", "bpf"])
-        .arg(&source);
-    let status = cmd
-        .status()
-        .with_context(|| format!("Failed to run {cmd:?}"))?;
+    cmd.args([
+        "-c", "-g", "-O2", "-target", "bpf", "-x", "c", "-", "-o", "-",
+    ])
+    .stdin(Stdio::piped())
+    .stdout(Stdio::piped());
+    let mut child = cmd
+        .spawn()
+        .with_context(|| format!("failed to spawn {cmd:?}"))?;
+    let Child { stdin, stdout, .. } = &mut child;
+    {
+        let mut stdin = stdin.take().ok_or(anyhow!("failed to open stdin"))?;
+        stdin
+            .write_all(source_code.as_bytes())
+            .context("failed to write to stdin")?;
+    }
+    let stdout = stdout.take().ok_or(anyhow!("failed to open stdout"))?;
+    let status = child
+        .wait()
+        .with_context(|| format!("failed to wait for {cmd:?}"))?;
     match status.code() {
         Some(code) => match code {
             0 => {}
@@ -321,7 +356,7 @@ fn compile(source_code: &str) -> Result<(TempDir, PathBuf)> {
         },
         None => bail!("{cmd:?} terminated by signal"),
     }
-    Ok((tmp_dir, source.with_extension("o")))
+    Ok(stdout)
 }
 
 struct RelocationTestRunner {