Skip to content

debuginfo: Add GDB pretty printers for structs and enums. #16322

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 30, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions mk/tests.mk
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
Expand Down
3 changes: 3 additions & 0 deletions src/compiletest/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,

Expand Down
25 changes: 25 additions & 0 deletions src/compiletest/compiletest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down Expand Up @@ -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")),
Expand Down Expand Up @@ -376,3 +378,26 @@ 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(ref full_version_line)
if full_version_line.as_slice().trim().len() > 0 => {
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(2).to_string())
}
None => {
println!("Could not extract GDB version from line '{}'",
full_version_line);
None
}
}
},
_ => None
}
}
69 changes: 54 additions & 15 deletions src/compiletest/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> ,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
114 changes: 101 additions & 13 deletions src/compiletest/runtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,12 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
};

let config = &mut config;
let DebuggerCommands { commands, check_lines, .. } = parse_debugger_commands(testfile, "gdb");
let DebuggerCommands {
commands,
check_lines,
use_gdb_pretty_printer,
..
} = parse_debugger_commands(testfile, "gdb");
let mut cmds = commands.connect("\n");

// compile test file (it should have 'compile-flags:-g' in the header)
Expand All @@ -334,7 +339,6 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {

let exe_file = make_exe_name(config, testfile);

let mut proc_args;
let debugger_run_result;
match config.target.as_slice() {
"arm-linux-androideabi" => {
Expand Down Expand Up @@ -454,18 +458,65 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
}

_=> {
let rust_src_root = find_rust_src_root(config)
.expect("Could not find Rust source root");
let rust_pp_module_rel_path = Path::new("./src/etc");
let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path)
.as_str()
.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) => {
println!("NOTE: compiletest thinks it is using GDB version {}",
version.as_slice());

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());
}
}
_ => {
println!("NOTE: compiletest does not know which version of \
GDB it is using");
}
}

// 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,
script_str.as_slice(),
"debugger.script");

if use_gdb_pretty_printer {
// Only emit the gdb auto-loading script if pretty printers
// should actually be loaded
dump_gdb_autoload_script(config, testfile);
}

// run debugger script with gdb
#[cfg(windows)]
fn debugger() -> String {
Expand All @@ -483,16 +534,19 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
vec!("-quiet".to_string(),
"-batch".to_string(),
"-nx".to_string(),
format!("-command={}", debugger_script.as_str().unwrap()),
exe_file.as_str().unwrap().to_string());
proc_args = ProcArgs {
format!("-command={}", debugger_script.as_str().unwrap()));

let proc_args = ProcArgs {
prog: debugger(),
args: debugger_opts,
};

let environment = vec![("PYTHONPATH".to_string(), rust_pp_module_abs_path)];

debugger_run_result = compose_and_run(config,
testfile,
proc_args,
Vec::new(),
environment,
config.run_lib_path.as_slice(),
None,
None);
Expand All @@ -504,6 +558,32 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
}

check_debugger_output(&debugger_run_result, check_lines.as_slice());

fn dump_gdb_autoload_script(config: &Config, testfile: &Path) {
let mut script_path = output_base_name(config, testfile);
let mut script_file_name = script_path.filename().unwrap().to_vec();
script_file_name.push_all("-gdb.py".as_bytes());
script_path.set_filename(script_file_name.as_slice());

let script_content = "import gdb_rust_pretty_printing\n\
gdb_rust_pretty_printing.register_printers(gdb.current_objfile())\n"
.as_bytes();

File::create(&script_path).write(script_content).unwrap();
}
}

fn find_rust_src_root(config: &Config) -> Option<Path> {
let mut path = config.src_base.clone();
let path_postfix = Path::new("src/etc/lldb_batchmode.py");

while path.pop() {
if path.join(path_postfix.clone()).is_file() {
return Some(path);
}
}

return None;
}

fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path) {
Expand Down Expand Up @@ -533,7 +613,8 @@ fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path)
let DebuggerCommands {
commands,
check_lines,
breakpoint_lines
breakpoint_lines,
..
} = parse_debugger_commands(testfile, "lldb");

// Write debugger script:
Expand Down Expand Up @@ -619,6 +700,7 @@ struct DebuggerCommands {
commands: Vec<String>,
check_lines: Vec<String>,
breakpoint_lines: Vec<uint>,
use_gdb_pretty_printer: bool
}

fn parse_debugger_commands(file_path: &Path, debugger_prefix: &str)
Expand All @@ -631,6 +713,7 @@ fn parse_debugger_commands(file_path: &Path, debugger_prefix: &str)
let mut breakpoint_lines = vec!();
let mut commands = vec!();
let mut check_lines = vec!();
let mut use_gdb_pretty_printer = false;
let mut counter = 1;
let mut reader = BufferedReader::new(File::open(file_path).unwrap());
for line in reader.lines() {
Expand All @@ -640,6 +723,10 @@ fn parse_debugger_commands(file_path: &Path, debugger_prefix: &str)
breakpoint_lines.push(counter);
}

if line.as_slice().contains("gdb-use-pretty-printer") {
use_gdb_pretty_printer = true;
}

header::parse_name_value_directive(
line.as_slice(),
command_directive.as_slice()).map(|cmd| {
Expand All @@ -663,7 +750,8 @@ fn parse_debugger_commands(file_path: &Path, debugger_prefix: &str)
DebuggerCommands {
commands: commands,
check_lines: check_lines,
breakpoint_lines: breakpoint_lines
breakpoint_lines: breakpoint_lines,
use_gdb_pretty_printer: use_gdb_pretty_printer,
}
}

Expand Down
Loading