Merge branch 'gdb-next-gen' of https://github.com/TimNN/rust into rollup

This commit is contained in:
Alex Crichton 2016-11-05 10:51:34 -07:00
commit 18ee04b3df
77 changed files with 1213 additions and 592 deletions

View file

@ -146,8 +146,14 @@ pub struct Config {
// Host triple for the compiler being invoked
pub host: String,
// Version of GDB
pub gdb_version: Option<String>,
// Path to / name of the GDB executable
pub gdb: Option<String>,
// Version of GDB, encoded as ((major * 1000) + minor) * 1000 + patch
pub gdb_version: Option<u32>,
// Whether GDB has native rust support
pub gdb_native_rust: bool,
// Version of LLDB
pub lldb_version: Option<String>,

View file

@ -18,6 +18,8 @@ use common::Config;
use common;
use util;
use extract_gdb_version;
/// Properties which must be known very early, before actually running
/// the test.
pub struct EarlyProps {
@ -75,7 +77,7 @@ impl EarlyProps {
return true;
}
if let Some(ref actual_version) = config.gdb_version {
if let Some(actual_version) = config.gdb_version {
if line.contains("min-gdb-version") {
let min_version = line.trim()
.split(' ')
@ -83,7 +85,7 @@ impl EarlyProps {
.expect("Malformed GDB version directive");
// Ignore if actual version is smaller the minimum required
// version
gdb_version_to_int(actual_version) < gdb_version_to_int(min_version)
actual_version < extract_gdb_version(min_version).unwrap()
} else {
false
}
@ -464,23 +466,6 @@ pub fn parse_name_value_directive(line: &str, directive: &str) -> Option<String>
}
}
pub fn gdb_version_to_int(version_string: &str) -> isize {
let error_string = format!("Encountered GDB version string with unexpected format: {}",
version_string);
let error_string = error_string;
let components: Vec<&str> = version_string.trim().split('.').collect();
if components.len() != 2 {
panic!("{}", error_string);
}
let major: isize = components[0].parse().ok().expect(&error_string);
let minor: isize = components[1].parse().ok().expect(&error_string);
return major * 1000 + minor;
}
pub fn lldb_version_to_int(version_string: &str) -> isize {
let error_string = format!("Encountered LLDB version string with unexpected format: {}",
version_string);

View file

@ -12,6 +12,7 @@
#![feature(box_syntax)]
#![feature(rustc_private)]
#![feature(static_in_const)]
#![feature(test)]
#![feature(libc)]
@ -35,6 +36,7 @@ use std::ffi::OsString;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
use std::process::Command;
use getopts::{optopt, optflag, reqopt};
use common::Config;
use common::{Pretty, DebugInfoGdb, DebugInfoLldb, Mode};
@ -98,7 +100,7 @@ pub fn parse_config(args: Vec<String> ) -> Config {
optopt("", "logfile", "file to log test execution to", "FILE"),
optopt("", "target", "the target to build for", "TARGET"),
optopt("", "host", "the host to build for", "HOST"),
optopt("", "gdb-version", "the version of GDB used", "VERSION STRING"),
optopt("", "gdb", "path to GDB to use for GDB debuginfo tests", "PATH"),
optopt("", "lldb-version", "the version of LLDB used", "VERSION STRING"),
optopt("", "llvm-version", "the version of LLVM used", "VERSION STRING"),
optopt("", "android-cross-path", "Android NDK standalone path", "PATH"),
@ -149,6 +151,8 @@ pub fn parse_config(args: Vec<String> ) -> Config {
}
}
let (gdb, gdb_version, gdb_native_rust) = analyze_gdb(matches.opt_str("gdb"));
Config {
compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")),
run_lib_path: make_absolute(opt_path(matches, "run-lib-path")),
@ -171,7 +175,9 @@ pub fn parse_config(args: Vec<String> ) -> Config {
target_rustcflags: matches.opt_str("target-rustcflags"),
target: opt_str2(matches.opt_str("target")),
host: opt_str2(matches.opt_str("host")),
gdb_version: extract_gdb_version(matches.opt_str("gdb-version")),
gdb: gdb,
gdb_version: gdb_version,
gdb_native_rust: gdb_native_rust,
lldb_version: extract_lldb_version(matches.opt_str("lldb-version")),
llvm_version: matches.opt_str("llvm-version"),
android_cross_path: opt_path(matches, "android-cross-path"),
@ -470,44 +476,96 @@ pub fn make_test_closure(config: &Config, testpaths: &TestPaths) -> test::TestFn
}))
}
fn extract_gdb_version(full_version_line: Option<String>) -> Option<String> {
match full_version_line {
Some(ref full_version_line)
if !full_version_line.trim().is_empty() => {
let full_version_line = full_version_line.trim();
/// Returns (Path to GDB, GDB Version, GDB has Rust Support)
fn analyze_gdb(gdb: Option<String>) -> (Option<String>, Option<u32>, bool) {
#[cfg(not(windows))]
const GDB_FALLBACK: &str = "gdb";
#[cfg(windows)]
const GDB_FALLBACK: &str = "gdb.exe";
// used to be a regex "(^|[^0-9])([0-9]\.[0-9]+)"
for (pos, c) in full_version_line.char_indices() {
if !c.is_digit(10) {
continue
}
if pos + 2 >= full_version_line.len() {
continue
}
if full_version_line[pos + 1..].chars().next().unwrap() != '.' {
continue
}
if !full_version_line[pos + 2..].chars().next().unwrap().is_digit(10) {
continue
}
if pos > 0 && full_version_line[..pos].chars().next_back()
.unwrap().is_digit(10) {
continue
}
let mut end = pos + 3;
while end < full_version_line.len() &&
full_version_line[end..].chars().next()
.unwrap().is_digit(10) {
end += 1;
}
return Some(full_version_line[pos..end].to_owned());
}
println!("Could not extract GDB version from line '{}'",
full_version_line);
None
},
_ => None
const MIN_GDB_WITH_RUST: u32 = 7011010;
let gdb = match gdb {
None => GDB_FALLBACK,
Some(ref s) if s.is_empty() => GDB_FALLBACK, // may be empty if configure found no gdb
Some(ref s) => s,
};
let version_line = Command::new(gdb).arg("--version").output().map(|output| {
String::from_utf8_lossy(&output.stdout).lines().next().unwrap().to_string()
}).ok();
let version = match version_line {
Some(line) => extract_gdb_version(&line),
None => return (None, None, false),
};
let gdb_native_rust = version.map_or(false, |v| v >= MIN_GDB_WITH_RUST);
return (Some(gdb.to_owned()), version, gdb_native_rust);
}
fn extract_gdb_version(full_version_line: &str) -> Option<u32> {
let full_version_line = full_version_line.trim();
// GDB versions look like this: "major.minor.patch?.yyyymmdd?", with both
// of the ? sections being optional
// We will parse up to 3 digits for minor and patch, ignoring the date
// We limit major to 1 digit, otherwise, on openSUSE, we parse the openSUSE version
// don't start parsing in the middle of a number
let mut prev_was_digit = false;
for (pos, c) in full_version_line.char_indices() {
if prev_was_digit || !c.is_digit(10) {
prev_was_digit = c.is_digit(10);
continue
}
prev_was_digit = true;
let line = &full_version_line[pos..];
let next_split = match line.find(|c: char| !c.is_digit(10)) {
Some(idx) => idx,
None => continue, // no minor version
};
if line.as_bytes()[next_split] != b'.' {
continue; // no minor version
}
let major = &line[..next_split];
let line = &line[next_split + 1..];
let (minor, patch) = match line.find(|c: char| !c.is_digit(10)) {
Some(idx) => if line.as_bytes()[idx] == b'.' {
let patch = &line[idx + 1..];
let patch_len = patch.find(|c: char| !c.is_digit(10)).unwrap_or(patch.len());
let patch = &patch[..patch_len];
let patch = if patch_len > 3 || patch_len == 0 { None } else { Some(patch) };
(&line[..idx], patch)
} else {
(&line[..idx], None)
},
None => (line, None),
};
if major.len() != 1 || minor.is_empty() {
continue;
}
let major: u32 = major.parse().unwrap();
let minor: u32 = minor.parse().unwrap();
let patch: u32 = patch.unwrap_or("0").parse().unwrap();
return Some(((major * 1000) + minor) * 1000 + patch);
}
println!("Could not extract GDB version from line '{}'", full_version_line);
None
}
fn extract_lldb_version(full_version_line: Option<String>) -> Option<String> {
@ -553,3 +611,44 @@ fn extract_lldb_version(full_version_line: Option<String>) -> Option<String> {
fn is_blacklisted_lldb_version(version: &str) -> bool {
version == "350"
}
#[test]
fn test_extract_gdb_version() {
macro_rules! test { ($($expectation:tt: $input:tt,)*) => {{$(
assert_eq!(extract_gdb_version($input), Some($expectation));
)*}}}
test! {
7000001: "GNU gdb (GDB) CentOS (7.0.1-45.el5.centos)",
7002000: "GNU gdb (GDB) Red Hat Enterprise Linux (7.2-90.el6)",
7004000: "GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04",
7004001: "GNU gdb (GDB) 7.4.1-debian",
7006001: "GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-80.el7",
7007001: "GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1",
7007001: "GNU gdb (Debian 7.7.1+dfsg-5) 7.7.1",
7007001: "GNU gdb (GDB) Fedora 7.7.1-21.fc20",
7008000: "GNU gdb (GDB; openSUSE 13.2) 7.8",
7009001: "GNU gdb (GDB) Fedora 7.9.1-20.fc22",
7010001: "GNU gdb (GDB) Fedora 7.10.1-31.fc23",
7011000: "GNU gdb (Ubuntu 7.11-0ubuntu1) 7.11",
7011001: "GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1",
7011001: "GNU gdb (Debian 7.11.1-2) 7.11.1",
7011001: "GNU gdb (GDB) Fedora 7.11.1-86.fc24",
7011001: "GNU gdb (GDB; openSUSE Leap 42.1) 7.11.1",
7011001: "GNU gdb (GDB; openSUSE Tumbleweed) 7.11.1",
7011090: "7.11.90",
7011090: "GNU gdb (Ubuntu 7.11.90.20161005-0ubuntu1) 7.11.90.20161005-git",
7012000: "7.12",
7012000: "GNU gdb (GDB) 7.12",
7012000: "GNU gdb (GDB) 7.12.20161027-git",
7012050: "GNU gdb (GDB) 7.12.50.20161027-git",
}
}

View file

@ -32,6 +32,8 @@ use std::path::{Path, PathBuf};
use std::process::{Command, Output, ExitStatus};
use std::str;
use extract_gdb_version;
pub fn run(config: Config, testpaths: &TestPaths) {
match &*config.target {
@ -41,7 +43,12 @@ pub fn run(config: Config, testpaths: &TestPaths) {
}
}
_=> { }
_ => {
// android has it's own gdb handling
if config.mode == DebugInfoGdb && config.gdb.is_none() {
panic!("gdb not available but debuginfo gdb debuginfo test requested");
}
}
}
if config.verbose {
@ -430,11 +437,23 @@ actual:\n\
}
fn run_debuginfo_gdb_test_no_opt(&self) {
let prefixes = if self.config.gdb_native_rust {
// GDB with Rust
static PREFIXES: &'static [&'static str] = &["gdb", "gdbr"];
println!("NOTE: compiletest thinks it is using GDB with native rust support");
PREFIXES
} else {
// Generic GDB
static PREFIXES: &'static [&'static str] = &["gdb", "gdbg"];
println!("NOTE: compiletest thinks it is using GDB without native rust support");
PREFIXES
};
let DebuggerCommands {
commands,
check_lines,
breakpoint_lines
} = self.parse_debugger_commands("gdb");
} = self.parse_debugger_commands(prefixes);
let mut cmds = commands.join("\n");
// compile test file (it should have 'compile-flags:-g' in the header)
@ -586,19 +605,18 @@ actual:\n\
script_str.push_str("show version\n");
match self.config.gdb_version {
Some(ref version) => {
Some(version) => {
println!("NOTE: compiletest thinks it is using GDB version {}",
version);
if header::gdb_version_to_int(version) >
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.replace(r"\", r"\\"))
);
}
if version > extract_gdb_version("7.4").unwrap() {
// 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.replace(r"\", r"\\"))
);
}
}
_ => {
println!("NOTE: compiletest does not know which version of \
@ -633,11 +651,6 @@ actual:\n\
debug!("script_str = {}", script_str);
self.dump_output_file(&script_str, "debugger.script");
// run debugger script with gdb
fn debugger() -> &'static str {
if cfg!(windows) {"gdb.exe"} else {"gdb"}
}
let debugger_script = self.make_out_name("debugger.script");
// FIXME (#9639): This needs to handle non-utf8 paths
@ -648,7 +661,7 @@ actual:\n\
format!("-command={}", debugger_script.to_str().unwrap())];
let proc_args = ProcArgs {
prog: debugger().to_owned(),
prog: self.config.gdb.as_ref().unwrap().to_owned(),
args: debugger_opts,
};
@ -731,7 +744,7 @@ actual:\n\
check_lines,
breakpoint_lines,
..
} = self.parse_debugger_commands("lldb");
} = self.parse_debugger_commands(&["lldb"]);
// Write debugger script:
// We don't want to hang when calling `quit` while the process is still running
@ -826,9 +839,11 @@ actual:\n\
}
}
fn parse_debugger_commands(&self, debugger_prefix: &str) -> DebuggerCommands {
let command_directive = format!("{}-command", debugger_prefix);
let check_directive = format!("{}-check", debugger_prefix);
fn parse_debugger_commands(&self, debugger_prefixes: &[&str]) -> DebuggerCommands {
let directives = debugger_prefixes.iter().map(|prefix| (
format!("{}-command", prefix),
format!("{}-check", prefix),
)).collect::<Vec<_>>();
let mut breakpoint_lines = vec![];
let mut commands = vec![];
@ -842,17 +857,19 @@ actual:\n\
breakpoint_lines.push(counter);
}
header::parse_name_value_directive(
&line,
&command_directive).map(|cmd| {
commands.push(cmd)
});
for &(ref command_directive, ref check_directive) in &directives {
header::parse_name_value_directive(
&line,
&command_directive).map(|cmd| {
commands.push(cmd)
});
header::parse_name_value_directive(
&line,
&check_directive).map(|cmd| {
check_lines.push(cmd)
});
header::parse_name_value_directive(
&line,
&check_directive).map(|cmd| {
check_lines.push(cmd)
});
}
}
Err(e) => {
self.fatal(&format!("Error while parsing debugger commands: {}", e))