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
--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) \
// 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,
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"),
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")),
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
+ }
+}
\ No newline at end of file
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> ,
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
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;
+}
.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,
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(),
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
#=------------------------------------------------------------------------------
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:
for field in val.type.fields():
if i == index:
return field
- return None
\ No newline at end of file
+ return None
--- /dev/null
+// 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() { () }
// 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
zzz();
}
-fn zzz() { () }
\ No newline at end of file
+fn zzz() { () }