debuginfo: Emit different autotest debugger scripts depending on GDB version.

This commit is contained in:
Michael Woerister 2014-08-20 12:53:50 +02:00
parent 6974b4f1b5
commit 849ae5d881
9 changed files with 210 additions and 35 deletions

7
configure vendored
View file

@ -515,6 +515,13 @@ probe CFG_LUALATEX lualatex
probe CFG_GDB gdb probe CFG_GDB gdb
probe CFG_LLDB lldb 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" ] if [ ! -z "$CFG_LLDB" ]
then then
# If CFG_LLDB_PYTHON_DIR is not already set from the outside and valid, try to read it from # If CFG_LLDB_PYTHON_DIR is not already set from the outside and valid, try to read it from

View file

@ -623,6 +623,7 @@ CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) := \
--stage-id stage$(1)-$(2) \ --stage-id stage$(1)-$(2) \
--target $(2) \ --target $(2) \
--host $(3) \ --host $(3) \
--gdb-version="$(CFG_GDB_VERSION)" \
--android-cross-path=$(CFG_ANDROID_CROSS_PATH) \ --android-cross-path=$(CFG_ANDROID_CROSS_PATH) \
--adb-path=$(CFG_ADB) \ --adb-path=$(CFG_ADB) \
--adb-test-dir=$(CFG_ADB_TEST_DIR) \ --adb-test-dir=$(CFG_ADB_TEST_DIR) \

View file

@ -130,6 +130,9 @@ pub struct Config {
// Host triple for the compiler being invoked // Host triple for the compiler being invoked
pub host: String, pub host: String,
// Version of GDB
pub gdb_version: Option<String>,
// Path to the android tools // Path to the android tools
pub android_cross_path: Path, pub android_cross_path: Path,

View file

@ -81,6 +81,7 @@ pub fn parse_config(args: Vec<String> ) -> Config {
optflag("", "jit", "run tests under the JIT"), optflag("", "jit", "run tests under the JIT"),
optopt("", "target", "the target to build for", "TARGET"), optopt("", "target", "the target to build for", "TARGET"),
optopt("", "host", "the host to build for", "HOST"), 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("", "android-cross-path", "Android NDK standalone path", "PATH"),
optopt("", "adb-path", "path to the android debugger", "PATH"), optopt("", "adb-path", "path to the android debugger", "PATH"),
optopt("", "adb-test-dir", "path to tests for 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"), jit: matches.opt_present("jit"),
target: opt_str2(matches.opt_str("target")), target: opt_str2(matches.opt_str("target")),
host: opt_str2(matches.opt_str("host")), 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"), android_cross_path: opt_path(matches, "android-cross-path"),
adb_path: opt_str2(matches.opt_str("adb-path")), adb_path: opt_str2(matches.opt_str("adb-path")),
adb_test_dir: opt_str2(matches.opt_str("adb-test-dir")), 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) 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
}
}

View file

@ -12,6 +12,8 @@ use common::Config;
use common; use common;
use util; use util;
use std::from_str::FromStr;
pub struct TestProps { pub struct TestProps {
// Lines that should be expected, in order, on standard out // Lines that should be expected, in order, on standard out
pub error_patterns: Vec<String> , pub error_patterns: Vec<String> ,
@ -142,23 +144,42 @@ pub fn is_test_ignored(config: &Config, testfile: &Path) -> bool {
format!("ignore-{}", format!("ignore-{}",
config.stage_id.as_slice().split('-').next().unwrap()) 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| { let val = iter_header(testfile, |ln| {
if parse_name_directive(ln, "ignore-test") { !parse_name_directive(ln, "ignore-test") &&
false !parse_name_directive(ln, ignore_target(config).as_slice()) &&
} else if parse_name_directive(ln, ignore_target(config).as_slice()) { !parse_name_directive(ln, ignore_stage(config).as_slice()) &&
false !(config.mode == common::Pretty && parse_name_directive(ln, "ignore-pretty")) &&
} else if parse_name_directive(ln, ignore_stage(config).as_slice()) { !(config.target != config.host && parse_name_directive(ln, "ignore-cross-compile")) &&
false !ignore_gdb(config, ln) &&
} else if config.mode == common::Pretty && !(config.mode == common::DebugInfoLldb && parse_name_directive(ln, "ignore-lldb"))
parse_name_directive(ln, "ignore-pretty") {
false
} else if config.target != config.host &&
parse_name_directive(ln, "ignore-cross-compile") {
false
} else {
true
}
}); });
!val !val
@ -278,3 +299,21 @@ pub fn parse_name_value_directive(line: &str, directive: &str)
None => None 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;
}

View file

@ -466,11 +466,39 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
.unwrap() .unwrap()
.to_string(); .to_string();
// write debugger script // write debugger script
let script_str = [ let mut script_str = String::with_capacity(2048);
"set charset UTF-8".to_string(),
cmds, script_str.push_str("set charset UTF-8\n");
"quit\n".to_string() script_str.push_str("show version\n");
].connect("\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); debug!("script_str = {}", script_str);
dump_output_file(config, dump_output_file(config,
testfile, testfile,
@ -500,15 +528,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
vec!("-quiet".to_string(), vec!("-quiet".to_string(),
"-batch".to_string(), "-batch".to_string(),
"-nx".to_string(), "-nx".to_string(),
// Add the directory containing the pretty printers to format!("-command={}", debugger_script.as_str().unwrap()));
// 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());
let proc_args = ProcArgs { let proc_args = ProcArgs {
prog: debugger(), prog: debugger(),

View file

@ -80,8 +80,7 @@ def rust_pretty_printer_lookup_function(val):
discriminant_name, discriminant_val = extract_discriminant_value(val) discriminant_name, discriminant_val = extract_discriminant_value(val)
return rust_pretty_printer_lookup_function(val[enum_members[discriminant_val]]) return rust_pretty_printer_lookup_function(val[enum_members[discriminant_val]])
# No pretty printer has been found
return None return None
#=------------------------------------------------------------------------------ #=------------------------------------------------------------------------------
@ -99,10 +98,17 @@ class RustStructPrinter:
def children(self): def children(self):
cs = [] cs = []
for field in self.val.type.fields(): 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: if field_name == None:
field_name = "" 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 ) cs.append( name_value_tuple )
if self.hide_first_field: if self.hide_first_field:
@ -222,4 +228,4 @@ def get_field_at_index(val, index):
for field in val.type.fields(): for field in val.type.fields():
if i == index: if i == index:
return field return field
return None return None

View file

@ -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() { () }

View file

@ -14,6 +14,11 @@
// compile-flags:-g // compile-flags:-g
// gdb-use-pretty-printer // 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, // The following line actually doesn't have to do anything with pretty printing,
// it just tells GDB to print values on one line: // it just tells GDB to print values on one line:
// gdb-command: set print pretty off // gdb-command: set print pretty off
@ -164,4 +169,4 @@ fn main() {
zzz(); zzz();
} }
fn zzz() { () } fn zzz() { () }