Test basic DWARF generation (#931)

* Add obj generation with debug info
* Add simple transform check
This commit is contained in:
Yury Delendik
2020-02-20 11:42:36 -06:00
committed by GitHub
parent 4460e569cf
commit b96b53eafb
17 changed files with 414 additions and 129 deletions

30
tests/debug/dump.rs Normal file
View File

@@ -0,0 +1,30 @@
use anyhow::{bail, Result};
use std::env;
use std::process::Command;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(dead_code)]
pub enum DwarfDumpSection {
DebugInfo,
DebugLine,
}
pub fn get_dwarfdump(obj: &str, section: DwarfDumpSection) -> Result<String> {
let dwarfdump = env::var("DWARFDUMP").unwrap_or("llvm-dwarfdump".to_string());
let section_flag = match section {
DwarfDumpSection::DebugInfo => "-debug-info",
DwarfDumpSection::DebugLine => "-debug-line",
};
let output = Command::new(&dwarfdump)
.args(&[section_flag, obj])
.output()
.expect("success");
if !output.status.success() {
bail!(
"failed to execute {}: {}",
dwarfdump,
String::from_utf8_lossy(&output.stderr),
);
}
Ok(String::from_utf8_lossy(&output.stdout).to_string())
}

4
tests/debug/main.rs Normal file
View File

@@ -0,0 +1,4 @@
mod dump;
mod obj;
mod simulate;
mod translate;

34
tests/debug/obj.rs Normal file
View File

@@ -0,0 +1,34 @@
use anyhow::{Context as _, Result};
use std::fs::File;
use std::path::Path;
use target_lexicon::Triple;
use wasmtime::Strategy;
use wasmtime_cli::compile_to_obj;
use wasmtime_environ::CacheConfig;
pub fn compile_cranelift(
wasm: &[u8],
target: Option<Triple>,
output: impl AsRef<Path>,
) -> Result<()> {
let obj = compile_to_obj(
wasm,
target.as_ref(),
Strategy::Cranelift,
false,
false,
true,
output
.as_ref()
.file_name()
.unwrap()
.to_string_lossy()
.to_string(),
&CacheConfig::new_cache_disabled(),
)?;
let file = File::create(output).context("failed to create object file")?;
obj.write(file).context("failed to write object file")?;
Ok(())
}

55
tests/debug/simulate.rs Normal file
View File

@@ -0,0 +1,55 @@
use super::dump::{get_dwarfdump, DwarfDumpSection};
use super::obj::compile_cranelift;
use anyhow::{format_err, Result};
use filecheck::{CheckerBuilder, NO_VARIABLES};
use tempfile::NamedTempFile;
use wat::parse_str;
#[allow(dead_code)]
fn check_wat(wat: &str) -> Result<()> {
let wasm = parse_str(wat)?;
let obj_file = NamedTempFile::new()?;
let obj_path = obj_file.path().to_str().unwrap();
compile_cranelift(&wasm, None, obj_path)?;
let dump = get_dwarfdump(obj_path, DwarfDumpSection::DebugInfo)?;
let mut builder = CheckerBuilder::new();
builder
.text(wat)
.map_err(|e| format_err!("unable to build checker: {:?}", e))?;
let checker = builder.finish();
let check = checker
.explain(&dump, NO_VARIABLES)
.map_err(|e| format_err!("{:?}", e))?;
assert!(check.0, "didn't pass check {}", check.1);
Ok(())
}
#[test]
#[cfg(all(
any(target_os = "linux", target_os = "macos"),
target_pointer_width = "64"
))]
fn test_debug_dwarf_simulate_simple_x86_64() -> Result<()> {
check_wat(
r#"
;; check: DW_TAG_compile_unit
(module
;; check: DW_TAG_subprogram
;; check: DW_AT_name ("wasm-function[0]")
;; check: DW_TAG_formal_parameter
;; check: DW_AT_name ("var0")
;; check: DW_AT_type
;; sameln: "i32"
;; check: DW_TAG_variable
;; check: DW_AT_name ("var1")
;; check: DW_AT_type
;; sameln: "i32"
(func (param i32) (result i32)
(local i32)
local.get 0
local.set 1
local.get 1
)
)"#,
)
}

View File

@@ -0,0 +1,13 @@
// Compile with:
// clang --target=wasm32 fib-wasm.c -o fib-wasm.wasm -g \
// -Wl,--no-entry,--export=fib -nostdlib -fdebug-prefix-map=$PWD=.
int fib(int n) {
int i, t, a = 0, b = 1;
for (i = 0; i < n; i++) {
t = a;
a = b;
b += t;
}
return b;
}

Binary file not shown.

56
tests/debug/translate.rs Normal file
View File

@@ -0,0 +1,56 @@
use super::dump::{get_dwarfdump, DwarfDumpSection};
use super::obj::compile_cranelift;
use anyhow::{format_err, Result};
use filecheck::{CheckerBuilder, NO_VARIABLES};
use std::fs::read;
use tempfile::NamedTempFile;
#[allow(dead_code)]
fn check_wasm(wasm_path: &str, directives: &str) -> Result<()> {
let wasm = read(wasm_path)?;
let obj_file = NamedTempFile::new()?;
let obj_path = obj_file.path().to_str().unwrap();
compile_cranelift(&wasm, None, obj_path)?;
let dump = get_dwarfdump(obj_path, DwarfDumpSection::DebugInfo)?;
let mut builder = CheckerBuilder::new();
builder
.text(directives)
.map_err(|e| format_err!("unable to build checker: {:?}", e))?;
let checker = builder.finish();
let check = checker
.explain(&dump, NO_VARIABLES)
.map_err(|e| format_err!("{:?}", e))?;
assert!(check.0, "didn't pass check {}", check.1);
Ok(())
}
#[test]
#[cfg(all(
any(target_os = "linux", target_os = "macos"),
target_pointer_width = "64"
))]
fn test_debug_dwarf_translate() -> Result<()> {
check_wasm(
"tests/debug/testsuite/fib-wasm.wasm",
r##"
check: DW_TAG_compile_unit
# We have "fib" function
check: DW_TAG_subprogram
check: DW_AT_name ("fib")
# Accepts one parameter
check: DW_TAG_formal_parameter
check: DW_AT_name ("n")
check: DW_AT_decl_line (5)
# Has four locals: i, t, a, b
check: DW_TAG_variable
check: DW_AT_name ("i")
check: DW_AT_decl_line (6)
check: DW_TAG_variable
check: DW_AT_name ("t")
check: DW_TAG_variable
check: DW_AT_name ("a")
check: DW_TAG_variable
check: DW_AT_name ("b")
"##,
)
}