Skip to content

Commit 849ae5d

Browse files
debuginfo: Emit different autotest debugger scripts depending on GDB version.
1 parent 6974b4f commit 849ae5d

9 files changed

+210
-35
lines changed

configure

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,13 @@ probe CFG_LUALATEX lualatex
515515
probe CFG_GDB gdb
516516
probe CFG_LLDB lldb
517517

518+
if [ ! -z "$CFG_GDB" ]
519+
then
520+
# Extract the version
521+
CFG_GDB_VERSION=$($CFG_GDB --version 2>/dev/null | head -1)
522+
putvar CFG_GDB_VERSION
523+
fi
524+
518525
if [ ! -z "$CFG_LLDB" ]
519526
then
520527
# If CFG_LLDB_PYTHON_DIR is not already set from the outside and valid, try to read it from

mk/tests.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,7 @@ CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) := \
623623
--stage-id stage$(1)-$(2) \
624624
--target $(2) \
625625
--host $(3) \
626+
--gdb-version="$(CFG_GDB_VERSION)" \
626627
--android-cross-path=$(CFG_ANDROID_CROSS_PATH) \
627628
--adb-path=$(CFG_ADB) \
628629
--adb-test-dir=$(CFG_ADB_TEST_DIR) \

src/compiletest/common.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ pub struct Config {
130130
// Host triple for the compiler being invoked
131131
pub host: String,
132132

133+
// Version of GDB
134+
pub gdb_version: Option<String>,
135+
133136
// Path to the android tools
134137
pub android_cross_path: Path,
135138

src/compiletest/compiletest.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ pub fn parse_config(args: Vec<String> ) -> Config {
8181
optflag("", "jit", "run tests under the JIT"),
8282
optopt("", "target", "the target to build for", "TARGET"),
8383
optopt("", "host", "the host to build for", "HOST"),
84+
optopt("", "gdb-version", "the version of GDB used", "MAJOR.MINOR"),
8485
optopt("", "android-cross-path", "Android NDK standalone path", "PATH"),
8586
optopt("", "adb-path", "path to the android debugger", "PATH"),
8687
optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH"),
@@ -157,6 +158,7 @@ pub fn parse_config(args: Vec<String> ) -> Config {
157158
jit: matches.opt_present("jit"),
158159
target: opt_str2(matches.opt_str("target")),
159160
host: opt_str2(matches.opt_str("host")),
161+
gdb_version: extract_gdb_version(matches.opt_str("gdb-version")),
160162
android_cross_path: opt_path(matches, "android-cross-path"),
161163
adb_path: opt_str2(matches.opt_str("adb-path")),
162164
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
376378
runtest::run_metrics(config, testfile, mm)
377379
})
378380
}
381+
382+
fn extract_gdb_version(full_version_line: Option<String>) -> Option<String> {
383+
match full_version_line {
384+
Some(full_version_line) => {
385+
let full_version_line = full_version_line.as_slice().trim();
386+
let re = Regex::new(r"[^0-9]([0-9]\.[0-9])([^0-9]|$)").unwrap();
387+
388+
match re.captures(full_version_line) {
389+
Some(captures) => {
390+
Some(captures.at(1).to_string())
391+
}
392+
None => None
393+
}
394+
},
395+
None => None
396+
}
397+
}

src/compiletest/header.rs

Lines changed: 54 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ use common::Config;
1212
use common;
1313
use util;
1414

15+
use std::from_str::FromStr;
16+
1517
pub struct TestProps {
1618
// Lines that should be expected, in order, on standard out
1719
pub error_patterns: Vec<String> ,
@@ -142,23 +144,42 @@ pub fn is_test_ignored(config: &Config, testfile: &Path) -> bool {
142144
format!("ignore-{}",
143145
config.stage_id.as_slice().split('-').next().unwrap())
144146
}
147+
fn ignore_gdb(config: &Config, line: &str) -> bool {
148+
if config.mode != common::DebugInfoGdb {
149+
return false;
150+
}
145151

146-
let val = iter_header(testfile, |ln| {
147-
if parse_name_directive(ln, "ignore-test") {
148-
false
149-
} else if parse_name_directive(ln, ignore_target(config).as_slice()) {
150-
false
151-
} else if parse_name_directive(ln, ignore_stage(config).as_slice()) {
152-
false
153-
} else if config.mode == common::Pretty &&
154-
parse_name_directive(ln, "ignore-pretty") {
155-
false
156-
} else if config.target != config.host &&
157-
parse_name_directive(ln, "ignore-cross-compile") {
158-
false
159-
} else {
160-
true
152+
if parse_name_directive(line, "ignore-gdb") {
153+
return true;
161154
}
155+
156+
match config.gdb_version {
157+
Some(ref actual_version) => {
158+
if line.contains("min-gdb-version") {
159+
let min_version = line.trim()
160+
.split(' ')
161+
.last()
162+
.expect("Malformed GDB version directive");
163+
// Ignore if actual version is smaller the minimum required
164+
// version
165+
gdb_version_to_int(actual_version.as_slice()) <
166+
gdb_version_to_int(min_version.as_slice())
167+
} else {
168+
false
169+
}
170+
}
171+
None => false
172+
}
173+
}
174+
175+
let val = iter_header(testfile, |ln| {
176+
!parse_name_directive(ln, "ignore-test") &&
177+
!parse_name_directive(ln, ignore_target(config).as_slice()) &&
178+
!parse_name_directive(ln, ignore_stage(config).as_slice()) &&
179+
!(config.mode == common::Pretty && parse_name_directive(ln, "ignore-pretty")) &&
180+
!(config.target != config.host && parse_name_directive(ln, "ignore-cross-compile")) &&
181+
!ignore_gdb(config, ln) &&
182+
!(config.mode == common::DebugInfoLldb && parse_name_directive(ln, "ignore-lldb"))
162183
});
163184

164185
!val
@@ -278,3 +299,21 @@ pub fn parse_name_value_directive(line: &str, directive: &str)
278299
None => None
279300
}
280301
}
302+
303+
pub fn gdb_version_to_int(version_string: &str) -> int {
304+
let error_string = format!(
305+
"Encountered GDB version string with unexpected format: {}",
306+
version_string);
307+
let error_string = error_string.as_slice();
308+
309+
let components: Vec<&str> = version_string.trim().split('.').collect();
310+
311+
if components.len() != 2 {
312+
fail!("{}", error_string);
313+
}
314+
315+
let major: int = FromStr::from_str(components[0]).expect(error_string);
316+
let minor: int = FromStr::from_str(components[1]).expect(error_string);
317+
318+
return major * 1000 + minor;
319+
}

src/compiletest/runtest.rs

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -466,11 +466,39 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
466466
.unwrap()
467467
.to_string();
468468
// write debugger script
469-
let script_str = [
470-
"set charset UTF-8".to_string(),
471-
cmds,
472-
"quit\n".to_string()
473-
].connect("\n");
469+
let mut script_str = String::with_capacity(2048);
470+
471+
script_str.push_str("set charset UTF-8\n");
472+
script_str.push_str("show version\n");
473+
474+
match config.gdb_version {
475+
Some(ref version) => {
476+
if header::gdb_version_to_int(version.as_slice()) >
477+
header::gdb_version_to_int("7.4") {
478+
// Add the directory containing the pretty printers to
479+
// GDB's script auto loading safe path ...
480+
script_str.push_str(
481+
format!("add-auto-load-safe-path {}\n",
482+
rust_pp_module_abs_path.as_slice())
483+
.as_slice());
484+
// ... and also the test directory
485+
script_str.push_str(
486+
format!("add-auto-load-safe-path {}\n",
487+
config.build_base.as_str().unwrap())
488+
.as_slice());
489+
}
490+
}
491+
_ => { /* nothing to do */ }
492+
}
493+
494+
// Load the target executable
495+
script_str.push_str(format!("file {}\n",
496+
exe_file.as_str().unwrap())
497+
.as_slice());
498+
499+
script_str.push_str(cmds.as_slice());
500+
script_str.push_str("quit\n");
501+
474502
debug!("script_str = {}", script_str);
475503
dump_output_file(config,
476504
testfile,
@@ -500,15 +528,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
500528
vec!("-quiet".to_string(),
501529
"-batch".to_string(),
502530
"-nx".to_string(),
503-
// Add the directory containing the pretty printers to
504-
// GDB's script auto loading safe path ...
505-
format!("-iex=add-auto-load-safe-path {}",
506-
rust_pp_module_abs_path.as_slice()),
507-
// ... and also the test directory
508-
format!("-iex=add-auto-load-safe-path {}",
509-
config.build_base.as_str().unwrap()),
510-
format!("-command={}", debugger_script.as_str().unwrap()),
511-
exe_file.as_str().unwrap().to_string());
531+
format!("-command={}", debugger_script.as_str().unwrap()));
512532

513533
let proc_args = ProcArgs {
514534
prog: debugger(),

src/etc/gdb_rust_pretty_printing.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,7 @@ def rust_pretty_printer_lookup_function(val):
8080
discriminant_name, discriminant_val = extract_discriminant_value(val)
8181
return rust_pretty_printer_lookup_function(val[enum_members[discriminant_val]])
8282

83-
84-
83+
# No pretty printer has been found
8584
return None
8685

8786
#=------------------------------------------------------------------------------
@@ -99,10 +98,17 @@ def to_string(self):
9998
def children(self):
10099
cs = []
101100
for field in self.val.type.fields():
102-
field_name = field.name;
101+
field_name = field.name
102+
# Normally the field name is used as a key to access the field value,
103+
# because that's also supported in older versions of GDB...
104+
field_key = field_name
103105
if field_name == None:
104106
field_name = ""
105-
name_value_tuple = ( field_name, self.val[field] )
107+
# ... but for fields without a name (as in tuples), we have to fall back
108+
# to the newer method of using the field object directly as key. In
109+
# older versions of GDB, this will just fail.
110+
field_key = field
111+
name_value_tuple = ( field_name, self.val[field_key] )
106112
cs.append( name_value_tuple )
107113

108114
if self.hide_first_field:
@@ -222,4 +228,4 @@ def get_field_at_index(val, index):
222228
for field in val.type.fields():
223229
if i == index:
224230
return field
225-
return None
231+
return None
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// This test uses only GDB Python API features which should be available in
12+
// older versions of GDB too. A more extensive test can be found in
13+
// gdb-pretty-struct-and-enums.rs
14+
15+
// ignore-tidy-linelength
16+
// ignore-lldb
17+
// ignore-android: FIXME(#10381)
18+
// compile-flags:-g
19+
// gdb-use-pretty-printer
20+
21+
// The following line actually doesn't have to do anything with pretty printing,
22+
// it just tells GDB to print values on one line:
23+
// gdb-command: set print pretty off
24+
25+
// gdb-command: rbreak zzz
26+
// gdb-command: run
27+
// gdb-command: finish
28+
29+
// gdb-command: print regular_struct
30+
// gdb-check:$1 = RegularStruct = {the_first_field = 101, the_second_field = 102.5, the_third_field = false}
31+
32+
// gdb-command: print empty_struct
33+
// gdb-check:$2 = EmptyStruct
34+
35+
// gdb-command: print c_style_enum1
36+
// gdb-check:$3 = CStyleEnumVar1
37+
38+
// gdb-command: print c_style_enum2
39+
// gdb-check:$4 = CStyleEnumVar2
40+
41+
// gdb-command: print c_style_enum3
42+
// gdb-check:$5 = CStyleEnumVar3
43+
44+
struct RegularStruct {
45+
the_first_field: int,
46+
the_second_field: f64,
47+
the_third_field: bool,
48+
}
49+
50+
struct EmptyStruct;
51+
52+
enum CStyleEnum {
53+
CStyleEnumVar1,
54+
CStyleEnumVar2,
55+
CStyleEnumVar3,
56+
}
57+
58+
fn main() {
59+
60+
let regular_struct = RegularStruct {
61+
the_first_field: 101,
62+
the_second_field: 102.5,
63+
the_third_field: false
64+
};
65+
66+
let empty_struct = EmptyStruct;
67+
68+
let c_style_enum1 = CStyleEnumVar1;
69+
let c_style_enum2 = CStyleEnumVar2;
70+
let c_style_enum3 = CStyleEnumVar3;
71+
72+
zzz();
73+
}
74+
75+
fn zzz() { () }

src/test/debuginfo/gdb-pretty-struct-and-enums.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414
// compile-flags:-g
1515
// gdb-use-pretty-printer
1616

17+
// This test uses some GDB Python API features (e.g. accessing anonymous fields)
18+
// which are only available in newer GDB version. The following directive will
19+
// case the test runner to ignore this test if an older GDB version is used:
20+
// min-gdb-version 7.7
21+
1722
// The following line actually doesn't have to do anything with pretty printing,
1823
// it just tells GDB to print values on one line:
1924
// gdb-command: set print pretty off
@@ -164,4 +169,4 @@ fn main() {
164169
zzz();
165170
}
166171

167-
fn zzz() { () }
172+
fn zzz() { () }

0 commit comments

Comments
 (0)