Skip to main content

compiletest/
debuggers.rs

1use std::process::Command;
2
3use camino::Utf8Path;
4
5pub(crate) fn query_cdb_version(cdb: &Utf8Path) -> Option<[u16; 4]> {
6    let mut version = None;
7    if let Ok(output) = Command::new(cdb).arg("/version").output() {
8        if let Some(first_line) = String::from_utf8_lossy(&output.stdout).lines().next() {
9            version = extract_cdb_version(&first_line);
10        }
11    }
12    version
13}
14
15pub(crate) fn extract_cdb_version(full_version_line: &str) -> Option<[u16; 4]> {
16    // Example full_version_line: "cdb version 10.0.18362.1"
17    let version = full_version_line.rsplit(' ').next()?;
18    let mut components = version.split('.');
19    let major: u16 = components.next().unwrap().parse().unwrap();
20    let minor: u16 = components.next().unwrap().parse().unwrap();
21    let patch: u16 = components.next().unwrap_or("0").parse().unwrap();
22    let build: u16 = components.next().unwrap_or("0").parse().unwrap();
23    Some([major, minor, patch, build])
24}
25
26pub(crate) fn query_gdb_version(gdb: &Utf8Path) -> Option<u32> {
27    let mut version_line = None;
28    if let Ok(output) = Command::new(&gdb).arg("--version").output() {
29        if let Some(first_line) = String::from_utf8_lossy(&output.stdout).lines().next() {
30            version_line = Some(first_line.to_string());
31        }
32    }
33
34    let version = match version_line {
35        Some(line) => extract_gdb_version(&line),
36        None => return None,
37    };
38
39    version
40}
41
42pub(crate) fn extract_gdb_version(full_version_line: &str) -> Option<u32> {
43    let full_version_line = full_version_line.trim();
44
45    // GDB versions look like this: "major.minor.patch?.yyyymmdd?", with both
46    // of the ? sections being optional
47
48    // We will parse up to 3 digits for each component, ignoring the date
49
50    // We skip text in parentheses.  This avoids accidentally parsing
51    // the openSUSE version, which looks like:
52    //  GNU gdb (GDB; openSUSE Leap 15.0) 8.1
53    // This particular form is documented in the GNU coding standards:
54    // https://www.gnu.org/prep/standards/html_node/_002d_002dversion.html#g_t_002d_002dversion
55
56    let unbracketed_part = full_version_line.split('[').next().unwrap();
57    let mut splits = unbracketed_part.trim_end().rsplit(' ');
58    let version_string = splits.next().unwrap();
59
60    let mut splits = version_string.split('.');
61    let major = splits.next().unwrap();
62    let minor = splits.next().unwrap();
63    let patch = splits.next();
64
65    let major: u32 = major.parse().unwrap();
66    let (minor, patch): (u32, u32) = match minor.find(not_a_digit) {
67        None => {
68            let minor = minor.parse().unwrap();
69            let patch: u32 = match patch {
70                Some(patch) => match patch.find(not_a_digit) {
71                    None => patch.parse().unwrap(),
72                    Some(idx) if idx > 3 => 0,
73                    Some(idx) => patch[..idx].parse().unwrap(),
74                },
75                None => 0,
76            };
77            (minor, patch)
78        }
79        // There is no patch version after minor-date (e.g. "4-2012").
80        Some(idx) => {
81            let minor = minor[..idx].parse().unwrap();
82            (minor, 0)
83        }
84    };
85
86    Some(((major * 1000) + minor) * 1000 + patch)
87}
88
89/// Returns LLDB version
90pub(crate) fn extract_lldb_version(full_version_line: &str) -> Option<u32> {
91    // Extract the major LLDB version from the given version string.
92    // LLDB version strings are different for Apple and non-Apple platforms.
93    // The Apple variant looks like this:
94    //
95    // LLDB-179.5 (older versions)
96    // lldb-300.2.51 (new versions)
97    //
98    // We are only interested in the major version number, so this function
99    // will return `Some(179)` and `Some(300)` respectively.
100    //
101    // Upstream versions look like:
102    // lldb version 6.0.1
103    //
104    // There doesn't seem to be a way to correlate the Apple version
105    // with the upstream version, and since the tests were originally
106    // written against Apple versions, we make a fake Apple version by
107    // multiplying the first number by 100. This is a hack.
108
109    let full_version_line = full_version_line.trim();
110
111    if let Some(apple_ver) =
112        full_version_line.strip_prefix("LLDB-").or_else(|| full_version_line.strip_prefix("lldb-"))
113    {
114        if let Some(idx) = apple_ver.find(not_a_digit) {
115            let version: u32 = apple_ver[..idx].parse().unwrap();
116            return Some(version);
117        }
118    } else if let Some(lldb_ver) = full_version_line.strip_prefix("lldb version ") {
119        if let Some(idx) = lldb_ver.find(not_a_digit) {
120            let version: u32 = lldb_ver[..idx].parse().ok()?;
121            return Some(version * 100);
122        }
123    }
124    None
125}
126
127fn not_a_digit(c: char) -> bool {
128    !c.is_ascii_digit()
129}