mirror of https://github.com/rust-lang/rust.git
debuginfo: Emit different autotest debugger scripts depending on GDB version.
This commit is contained in:
parent
6974b4f1b5
commit
849ae5d881
|
@ -515,6 +515,13 @@ probe CFG_LUALATEX lualatex
|
|||
probe CFG_GDB gdb
|
||||
probe CFG_LLDB lldb
|
||||
|
||||
if [ ! -z "$CFG_GDB" ]
|
||||
then
|
||||
# Extract the version
|
||||
CFG_GDB_VERSION=$($CFG_GDB --version 2>/dev/null | head -1)
|
||||
putvar CFG_GDB_VERSION
|
||||
fi
|
||||
|
||||
if [ ! -z "$CFG_LLDB" ]
|
||||
then
|
||||
# If CFG_LLDB_PYTHON_DIR is not already set from the outside and valid, try to read it from
|
||||
|
|
|
@ -623,6 +623,7 @@ CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) := \
|
|||
--stage-id stage$(1)-$(2) \
|
||||
--target $(2) \
|
||||
--host $(3) \
|
||||
--gdb-version="$(CFG_GDB_VERSION)" \
|
||||
--android-cross-path=$(CFG_ANDROID_CROSS_PATH) \
|
||||
--adb-path=$(CFG_ADB) \
|
||||
--adb-test-dir=$(CFG_ADB_TEST_DIR) \
|
||||
|
|
|
@ -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,
|
||||
|
||||
|
|
|
@ -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,20 @@ 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(full_version_line) => {
|
||||
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(1).to_string())
|
||||
}
|
||||
None => None
|
||||
}
|
||||
},
|
||||
None => None
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
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| {
|
||||
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
|
||||
}
|
||||
!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;
|
||||
}
|
||||
|
|
|
@ -466,11 +466,39 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
|
|||
.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) => {
|
||||
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());
|
||||
}
|
||||
}
|
||||
_ => { /* nothing to do */ }
|
||||
}
|
||||
|
||||
// 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,
|
||||
|
@ -500,15 +528,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
|
|||
vec!("-quiet".to_string(),
|
||||
"-batch".to_string(),
|
||||
"-nx".to_string(),
|
||||
// Add the directory containing the pretty printers to
|
||||
// GDB's script auto loading safe path ...
|
||||
format!("-iex=add-auto-load-safe-path {}",
|
||||
rust_pp_module_abs_path.as_slice()),
|
||||
// ... and also the test directory
|
||||
format!("-iex=add-auto-load-safe-path {}",
|
||||
config.build_base.as_str().unwrap()),
|
||||
format!("-command={}", debugger_script.as_str().unwrap()),
|
||||
exe_file.as_str().unwrap().to_string());
|
||||
format!("-command={}", debugger_script.as_str().unwrap()));
|
||||
|
||||
let proc_args = ProcArgs {
|
||||
prog: debugger(),
|
||||
|
|
|
@ -80,8 +80,7 @@ def rust_pretty_printer_lookup_function(val):
|
|||
discriminant_name, discriminant_val = extract_discriminant_value(val)
|
||||
return rust_pretty_printer_lookup_function(val[enum_members[discriminant_val]])
|
||||
|
||||
|
||||
|
||||
# No pretty printer has been found
|
||||
return None
|
||||
|
||||
#=------------------------------------------------------------------------------
|
||||
|
@ -99,10 +98,17 @@ class RustStructPrinter:
|
|||
def children(self):
|
||||
cs = []
|
||||
for field in self.val.type.fields():
|
||||
field_name = field.name;
|
||||
field_name = field.name
|
||||
# Normally the field name is used as a key to access the field value,
|
||||
# because that's also supported in older versions of GDB...
|
||||
field_key = field_name
|
||||
if field_name == None:
|
||||
field_name = ""
|
||||
name_value_tuple = ( field_name, self.val[field] )
|
||||
# ... but for fields without a name (as in tuples), we have to fall back
|
||||
# to the newer method of using the field object directly as key. In
|
||||
# older versions of GDB, this will just fail.
|
||||
field_key = field
|
||||
name_value_tuple = ( field_name, self.val[field_key] )
|
||||
cs.append( name_value_tuple )
|
||||
|
||||
if self.hide_first_field:
|
||||
|
@ -222,4 +228,4 @@ def get_field_at_index(val, index):
|
|||
for field in val.type.fields():
|
||||
if i == index:
|
||||
return field
|
||||
return None
|
||||
return None
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// This test uses only GDB Python API features which should be available in
|
||||
// older versions of GDB too. A more extensive test can be found in
|
||||
// gdb-pretty-struct-and-enums.rs
|
||||
|
||||
// ignore-tidy-linelength
|
||||
// ignore-lldb
|
||||
// ignore-android: FIXME(#10381)
|
||||
// compile-flags:-g
|
||||
// gdb-use-pretty-printer
|
||||
|
||||
// The following line actually doesn't have to do anything with pretty printing,
|
||||
// it just tells GDB to print values on one line:
|
||||
// gdb-command: set print pretty off
|
||||
|
||||
// gdb-command: rbreak zzz
|
||||
// gdb-command: run
|
||||
// gdb-command: finish
|
||||
|
||||
// gdb-command: print regular_struct
|
||||
// gdb-check:$1 = RegularStruct = {the_first_field = 101, the_second_field = 102.5, the_third_field = false}
|
||||
|
||||
// gdb-command: print empty_struct
|
||||
// gdb-check:$2 = EmptyStruct
|
||||
|
||||
// gdb-command: print c_style_enum1
|
||||
// gdb-check:$3 = CStyleEnumVar1
|
||||
|
||||
// gdb-command: print c_style_enum2
|
||||
// gdb-check:$4 = CStyleEnumVar2
|
||||
|
||||
// gdb-command: print c_style_enum3
|
||||
// gdb-check:$5 = CStyleEnumVar3
|
||||
|
||||
struct RegularStruct {
|
||||
the_first_field: int,
|
||||
the_second_field: f64,
|
||||
the_third_field: bool,
|
||||
}
|
||||
|
||||
struct EmptyStruct;
|
||||
|
||||
enum CStyleEnum {
|
||||
CStyleEnumVar1,
|
||||
CStyleEnumVar2,
|
||||
CStyleEnumVar3,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
||||
let regular_struct = RegularStruct {
|
||||
the_first_field: 101,
|
||||
the_second_field: 102.5,
|
||||
the_third_field: false
|
||||
};
|
||||
|
||||
let empty_struct = EmptyStruct;
|
||||
|
||||
let c_style_enum1 = CStyleEnumVar1;
|
||||
let c_style_enum2 = CStyleEnumVar2;
|
||||
let c_style_enum3 = CStyleEnumVar3;
|
||||
|
||||
zzz();
|
||||
}
|
||||
|
||||
fn zzz() { () }
|
|
@ -14,6 +14,11 @@
|
|||
// compile-flags:-g
|
||||
// gdb-use-pretty-printer
|
||||
|
||||
// This test uses some GDB Python API features (e.g. accessing anonymous fields)
|
||||
// which are only available in newer GDB version. The following directive will
|
||||
// case the test runner to ignore this test if an older GDB version is used:
|
||||
// min-gdb-version 7.7
|
||||
|
||||
// The following line actually doesn't have to do anything with pretty printing,
|
||||
// it just tells GDB to print values on one line:
|
||||
// gdb-command: set print pretty off
|
||||
|
@ -164,4 +169,4 @@ fn main() {
|
|||
zzz();
|
||||
}
|
||||
|
||||
fn zzz() { () }
|
||||
fn zzz() { () }
|
||||
|
|
Loading…
Reference in New Issue