summary refs log tree commit diff
path: root/src/compiletest
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-08-30 04:01:24 +0000
committerbors <bors@rust-lang.org>2014-08-30 04:01:24 +0000
commitc8e86e977f5f95bd2f533c12ebf8107fb6f21a0f (patch)
tree12e10399d982fca7a5633917f55bc0a2da3c899c /src/compiletest
parent5419b2ca2c27b4745fa1f2773719350420542c76 (diff)
parente72e4dfc74ca65d6b3e0d821b94a34764ab2c63d (diff)
downloadrust-c8e86e977f5f95bd2f533c12ebf8107fb6f21a0f.tar.gz
rust-c8e86e977f5f95bd2f533c12ebf8107fb6f21a0f.zip
auto merge of #16322 : michaelwoerister/rust/gdb-pretty, r=alexcrichton
Also extends the autotest framework to let a test case choose if pretty printing should be enabled.
Diffstat (limited to 'src/compiletest')
-rw-r--r--src/compiletest/common.rs3
-rw-r--r--src/compiletest/compiletest.rs25
-rw-r--r--src/compiletest/header.rs69
-rw-r--r--src/compiletest/runtest.rs114
4 files changed, 183 insertions, 28 deletions
diff --git a/src/compiletest/common.rs b/src/compiletest/common.rs
index ba201a4a633..afe2d071461 100644
--- a/src/compiletest/common.rs
+++ b/src/compiletest/common.rs
@@ -130,6 +130,9 @@ pub struct Config {
     // Host triple for the compiler being invoked
     pub host: String,
 
+    // Version of GDB
+    pub gdb_version: Option<String>,
+
     // Path to the android tools
     pub android_cross_path: Path,
 
diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs
index 583d9249b35..6c6cd6f610f 100644
--- a/src/compiletest/compiletest.rs
+++ b/src/compiletest/compiletest.rs
@@ -81,6 +81,7 @@ pub fn parse_config(args: Vec<String> ) -> Config {
           optflag("", "jit", "run tests under the JIT"),
           optopt("", "target", "the target to build for", "TARGET"),
           optopt("", "host", "the host to build for", "HOST"),
+          optopt("", "gdb-version", "the version of GDB used", "MAJOR.MINOR"),
           optopt("", "android-cross-path", "Android NDK standalone path", "PATH"),
           optopt("", "adb-path", "path to the android debugger", "PATH"),
           optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH"),
@@ -157,6 +158,7 @@ pub fn parse_config(args: Vec<String> ) -> Config {
         jit: matches.opt_present("jit"),
         target: opt_str2(matches.opt_str("target")),
         host: opt_str2(matches.opt_str("host")),
+        gdb_version: extract_gdb_version(matches.opt_str("gdb-version")),
         android_cross_path: opt_path(matches, "android-cross-path"),
         adb_path: opt_str2(matches.opt_str("adb-path")),
         adb_test_dir: opt_str2(matches.opt_str("adb-test-dir")),
@@ -376,3 +378,26 @@ pub fn make_metrics_test_closure(config: &Config, testfile: &Path) -> test::Test
         runtest::run_metrics(config, testfile, mm)
     })
 }
+
+fn extract_gdb_version(full_version_line: Option<String>) -> Option<String> {
+    match full_version_line {
+        Some(ref full_version_line)
+          if full_version_line.as_slice().trim().len() > 0 => {
+            let full_version_line = full_version_line.as_slice().trim();
+
+            let re = Regex::new(r"(^|[^0-9])([0-9]\.[0-9])([^0-9]|$)").unwrap();
+
+            match re.captures(full_version_line) {
+                Some(captures) => {
+                    Some(captures.at(2).to_string())
+                }
+                None => {
+                    println!("Could not extract GDB version from line '{}'",
+                             full_version_line);
+                    None
+                }
+            }
+        },
+        _ => None
+    }
+}
\ No newline at end of file
diff --git a/src/compiletest/header.rs b/src/compiletest/header.rs
index f6cd217b580..9ad2582dec8 100644
--- a/src/compiletest/header.rs
+++ b/src/compiletest/header.rs
@@ -12,6 +12,8 @@ use common::Config;
 use common;
 use util;
 
+use std::from_str::FromStr;
+
 pub struct TestProps {
     // Lines that should be expected, in order, on standard out
     pub error_patterns: Vec<String> ,
@@ -142,23 +144,42 @@ pub fn is_test_ignored(config: &Config, testfile: &Path) -> bool {
         format!("ignore-{}",
                 config.stage_id.as_slice().split('-').next().unwrap())
     }
+    fn ignore_gdb(config: &Config, line: &str) -> bool {
+        if config.mode != common::DebugInfoGdb {
+            return false;
+        }
 
-    let val = iter_header(testfile, |ln| {
-        if parse_name_directive(ln, "ignore-test") {
-            false
-        } else if parse_name_directive(ln, ignore_target(config).as_slice()) {
-            false
-        } else if parse_name_directive(ln, ignore_stage(config).as_slice()) {
-            false
-        } else if config.mode == common::Pretty &&
-                parse_name_directive(ln, "ignore-pretty") {
-            false
-        } else if config.target != config.host &&
-                parse_name_directive(ln, "ignore-cross-compile") {
-            false
-        } else {
-            true
+        if parse_name_directive(line, "ignore-gdb") {
+            return true;
         }
+
+        match config.gdb_version {
+            Some(ref actual_version) => {
+                if line.contains("min-gdb-version") {
+                    let min_version = line.trim()
+                                          .split(' ')
+                                          .last()
+                                          .expect("Malformed GDB version directive");
+                    // Ignore if actual version is smaller the minimum required
+                    // version
+                    gdb_version_to_int(actual_version.as_slice()) <
+                        gdb_version_to_int(min_version.as_slice())
+                } else {
+                    false
+                }
+            }
+            None => false
+        }
+    }
+
+    let val = iter_header(testfile, |ln| {
+        !parse_name_directive(ln, "ignore-test") &&
+        !parse_name_directive(ln, ignore_target(config).as_slice()) &&
+        !parse_name_directive(ln, ignore_stage(config).as_slice()) &&
+        !(config.mode == common::Pretty && parse_name_directive(ln, "ignore-pretty")) &&
+        !(config.target != config.host && parse_name_directive(ln, "ignore-cross-compile")) &&
+        !ignore_gdb(config, ln) &&
+        !(config.mode == common::DebugInfoLldb && parse_name_directive(ln, "ignore-lldb"))
     });
 
     !val
@@ -278,3 +299,21 @@ pub fn parse_name_value_directive(line: &str, directive: &str)
         None => None
     }
 }
+
+pub fn gdb_version_to_int(version_string: &str) -> int {
+    let error_string = format!(
+        "Encountered GDB version string with unexpected format: {}",
+        version_string);
+    let error_string = error_string.as_slice();
+
+    let components: Vec<&str> = version_string.trim().split('.').collect();
+
+    if components.len() != 2 {
+        fail!("{}", error_string);
+    }
+
+    let major: int = FromStr::from_str(components[0]).expect(error_string);
+    let minor: int = FromStr::from_str(components[1]).expect(error_string);
+
+    return major * 1000 + minor;
+}
diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs
index 7a0245164ec..ee787a5f0a9 100644
--- a/src/compiletest/runtest.rs
+++ b/src/compiletest/runtest.rs
@@ -323,7 +323,12 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
     };
 
     let config = &mut config;
-    let DebuggerCommands { commands, check_lines, .. } = parse_debugger_commands(testfile, "gdb");
+    let DebuggerCommands {
+        commands,
+        check_lines,
+        use_gdb_pretty_printer,
+        ..
+    } = parse_debugger_commands(testfile, "gdb");
     let mut cmds = commands.connect("\n");
 
     // compile test file (it should have 'compile-flags:-g' in the header)
@@ -334,7 +339,6 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
 
     let exe_file = make_exe_name(config, testfile);
 
-    let mut proc_args;
     let debugger_run_result;
     match config.target.as_slice() {
         "arm-linux-androideabi" => {
@@ -454,18 +458,65 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
         }
 
         _=> {
+            let rust_src_root = find_rust_src_root(config)
+                .expect("Could not find Rust source root");
+            let rust_pp_module_rel_path = Path::new("./src/etc");
+            let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path)
+                                                       .as_str()
+                                                       .unwrap()
+                                                       .to_string();
             // write debugger script
-            let script_str = [
-                "set charset UTF-8".to_string(),
-                cmds,
-                "quit\n".to_string()
-            ].connect("\n");
+            let mut script_str = String::with_capacity(2048);
+
+            script_str.push_str("set charset UTF-8\n");
+            script_str.push_str("show version\n");
+
+            match config.gdb_version {
+                Some(ref version) => {
+                    println!("NOTE: compiletest thinks it is using GDB version {}",
+                             version.as_slice());
+
+                    if header::gdb_version_to_int(version.as_slice()) >
+                        header::gdb_version_to_int("7.4") {
+                        // Add the directory containing the pretty printers to
+                        // GDB's script auto loading safe path ...
+                        script_str.push_str(
+                            format!("add-auto-load-safe-path {}\n",
+                                    rust_pp_module_abs_path.as_slice())
+                                .as_slice());
+                        // ... and also the test directory
+                        script_str.push_str(
+                            format!("add-auto-load-safe-path {}\n",
+                                    config.build_base.as_str().unwrap())
+                                .as_slice());
+                    }
+                }
+                _ => {
+                    println!("NOTE: compiletest does not know which version of \
+                              GDB it is using");
+                }
+            }
+
+            // Load the target executable
+            script_str.push_str(format!("file {}\n",
+                                        exe_file.as_str().unwrap())
+                                    .as_slice());
+
+            script_str.push_str(cmds.as_slice());
+            script_str.push_str("quit\n");
+
             debug!("script_str = {}", script_str);
             dump_output_file(config,
                              testfile,
                              script_str.as_slice(),
                              "debugger.script");
 
+            if use_gdb_pretty_printer {
+                // Only emit the gdb auto-loading script if pretty printers
+                // should actually be loaded
+                dump_gdb_autoload_script(config, testfile);
+            }
+
             // run debugger script with gdb
             #[cfg(windows)]
             fn debugger() -> String {
@@ -483,16 +534,19 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
                 vec!("-quiet".to_string(),
                      "-batch".to_string(),
                      "-nx".to_string(),
-                     format!("-command={}", debugger_script.as_str().unwrap()),
-                     exe_file.as_str().unwrap().to_string());
-            proc_args = ProcArgs {
+                     format!("-command={}", debugger_script.as_str().unwrap()));
+
+            let proc_args = ProcArgs {
                 prog: debugger(),
                 args: debugger_opts,
             };
+
+            let environment = vec![("PYTHONPATH".to_string(), rust_pp_module_abs_path)];
+
             debugger_run_result = compose_and_run(config,
                                                   testfile,
                                                   proc_args,
-                                                  Vec::new(),
+                                                  environment,
                                                   config.run_lib_path.as_slice(),
                                                   None,
                                                   None);
@@ -504,6 +558,32 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
     }
 
     check_debugger_output(&debugger_run_result, check_lines.as_slice());
+
+    fn dump_gdb_autoload_script(config: &Config, testfile: &Path) {
+        let mut script_path = output_base_name(config, testfile);
+        let mut script_file_name = script_path.filename().unwrap().to_vec();
+        script_file_name.push_all("-gdb.py".as_bytes());
+        script_path.set_filename(script_file_name.as_slice());
+
+        let script_content = "import gdb_rust_pretty_printing\n\
+                              gdb_rust_pretty_printing.register_printers(gdb.current_objfile())\n"
+                             .as_bytes();
+
+        File::create(&script_path).write(script_content).unwrap();
+    }
+}
+
+fn find_rust_src_root(config: &Config) -> Option<Path> {
+    let mut path = config.src_base.clone();
+    let path_postfix = Path::new("src/etc/lldb_batchmode.py");
+
+    while path.pop() {
+        if path.join(path_postfix.clone()).is_file() {
+            return Some(path);
+        }
+    }
+
+    return None;
 }
 
 fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path) {
@@ -533,7 +613,8 @@ fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path)
     let DebuggerCommands {
         commands,
         check_lines,
-        breakpoint_lines
+        breakpoint_lines,
+        ..
     } = parse_debugger_commands(testfile, "lldb");
 
     // Write debugger script:
@@ -619,6 +700,7 @@ struct DebuggerCommands {
     commands: Vec<String>,
     check_lines: Vec<String>,
     breakpoint_lines: Vec<uint>,
+    use_gdb_pretty_printer: bool
 }
 
 fn parse_debugger_commands(file_path: &Path, debugger_prefix: &str)
@@ -631,6 +713,7 @@ fn parse_debugger_commands(file_path: &Path, debugger_prefix: &str)
     let mut breakpoint_lines = vec!();
     let mut commands = vec!();
     let mut check_lines = vec!();
+    let mut use_gdb_pretty_printer = false;
     let mut counter = 1;
     let mut reader = BufferedReader::new(File::open(file_path).unwrap());
     for line in reader.lines() {
@@ -640,6 +723,10 @@ fn parse_debugger_commands(file_path: &Path, debugger_prefix: &str)
                     breakpoint_lines.push(counter);
                 }
 
+                if line.as_slice().contains("gdb-use-pretty-printer") {
+                    use_gdb_pretty_printer = true;
+                }
+
                 header::parse_name_value_directive(
                         line.as_slice(),
                         command_directive.as_slice()).map(|cmd| {
@@ -663,7 +750,8 @@ fn parse_debugger_commands(file_path: &Path, debugger_prefix: &str)
     DebuggerCommands {
         commands: commands,
         check_lines: check_lines,
-        breakpoint_lines: breakpoint_lines
+        breakpoint_lines: breakpoint_lines,
+        use_gdb_pretty_printer: use_gdb_pretty_printer,
     }
 }