From 2eabca90db6d6c348e3f9b77eae424f15f1d4810 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 21 Aug 2014 12:22:34 +0200 Subject: [PATCH] debuginfo: Allow debuginfo tests to be ignored based on GDB version. --- mk/tests.mk | 2 +- src/compiletest/header.rs | 69 +++++++++++++---- src/compiletest/runtest.rs | 22 +----- src/etc/gdb_rust_pretty_printing.py | 16 ++-- ...gdb-pretty-struct-and-enums-pre-gdb-7-7.rs | 75 +++++++++++++++++++ .../debuginfo/gdb-pretty-struct-and-enums.rs | 7 +- 6 files changed, 149 insertions(+), 42 deletions(-) create mode 100644 src/test/debuginfo/gdb-pretty-struct-and-enums-pre-gdb-7-7.rs diff --git a/mk/tests.mk b/mk/tests.mk index ceba60319347f..d95f886e07889 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -623,7 +623,7 @@ CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) := \ --stage-id stage$(1)-$(2) \ --target $(2) \ --host $(3) \ - --gdb-version=$(CFG_GDB_VERSION) \ + --gdb-version="$(CFG_GDB_VERSION)" \ --android-cross-path=$(CFG_ANDROID_CROSS_PATH) \ --adb-path=$(CFG_ADB) \ --adb-test-dir=$(CFG_ADB_TEST_DIR) \ diff --git a/src/compiletest/header.rs b/src/compiletest/header.rs index f6cd217b580cd..9ad2582dec845 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 , @@ -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 3cfa6625c4c1b..04b84d5b7b6c0 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -20,7 +20,6 @@ use util::logv; #[cfg(stage0, target_os = "win32")] // NOTE: Remove after snapshot use util; -use std::from_str::FromStr; use std::io::File; use std::io::fs; use std::io::net::tcp; @@ -318,7 +317,6 @@ actual:\n\ } fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) { - let mut config = Config { target_rustcflags: cleanup_debug_info_options(&config.target_rustcflags), host_rustcflags: cleanup_debug_info_options(&config.host_rustcflags), @@ -476,7 +474,8 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) { match config.gdb_version { Some(ref version) => { - if gdb_version_to_int(version.as_slice()) > gdb_version_to_int("7.3") { + if header::gdb_version_to_int(version.as_slice()) > + header::gdb_version_to_int("7.3") { // Add the directory containing the pretty printers to // GDB's script auto loading safe path ... script_str.push_str( @@ -567,23 +566,6 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) { File::create(&script_path).write(script_content).unwrap(); } - - fn gdb_version_to_int(version_string: &str) -> int { - let error_string = format!( - "Encountered GDB version string with unexpected format: {}", - version_string); - - let components: Vec<&str> = version_string.trim().split('.').collect(); - - if components.len() != 2 { - fatal(error_string.as_slice()); - } - - let major: int = FromStr::from_str(components[0]).expect(error_string.as_slice()); - let minor: int = FromStr::from_str(components[1]).expect(error_string.as_slice()); - - return major * 1000 + minor; - } } fn find_rust_src_root(config: &Config) -> Option { diff --git a/src/etc/gdb_rust_pretty_printing.py b/src/etc/gdb_rust_pretty_printing.py index c84dde92f8fe4..e8a6427c1d731 100644 --- a/src/etc/gdb_rust_pretty_printing.py +++ b/src/etc/gdb_rust_pretty_printing.py @@ -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 @@ def to_string(self): 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 \ No newline at end of file + return None diff --git a/src/test/debuginfo/gdb-pretty-struct-and-enums-pre-gdb-7-7.rs b/src/test/debuginfo/gdb-pretty-struct-and-enums-pre-gdb-7-7.rs new file mode 100644 index 0000000000000..e9daf31be2cd2 --- /dev/null +++ b/src/test/debuginfo/gdb-pretty-struct-and-enums-pre-gdb-7-7.rs @@ -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 or the MIT license +// , 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() { () } diff --git a/src/test/debuginfo/gdb-pretty-struct-and-enums.rs b/src/test/debuginfo/gdb-pretty-struct-and-enums.rs index 51dad709b6f53..5ef63da71af8c 100644 --- a/src/test/debuginfo/gdb-pretty-struct-and-enums.rs +++ b/src/test/debuginfo/gdb-pretty-struct-and-enums.rs @@ -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() { () } \ No newline at end of file +fn zzz() { () }