1 use crate::common::Config;
2 use std::env;
3 use std::ffi::OsStr;
4 use std::path::PathBuf;
5 
6 use tracing::*;
7 
8 #[cfg(test)]
9 mod tests;
10 
11 /// Conversion table from triple OS name to Rust SYSNAME
12 const OS_TABLE: &[(&str, &str)] = &[
13     ("android", "android"),
14     ("androideabi", "android"),
15     ("cuda", "cuda"),
16     ("darwin", "macos"),
17     ("dragonfly", "dragonfly"),
18     ("emscripten", "emscripten"),
19     ("freebsd", "freebsd"),
20     ("fuchsia", "fuchsia"),
21     ("haiku", "haiku"),
22     ("hermit", "hermit"),
23     ("illumos", "illumos"),
24     ("ios", "ios"),
25     ("l4re", "l4re"),
26     ("linux", "linux"),
27     ("mingw32", "windows"),
28     ("none", "none"),
29     ("netbsd", "netbsd"),
30     ("openbsd", "openbsd"),
31     ("redox", "redox"),
32     ("sgx", "sgx"),
33     ("solaris", "solaris"),
34     ("win32", "windows"),
35     ("windows", "windows"),
36     ("vxworks", "vxworks"),
37 ];
38 
39 const ARCH_TABLE: &[(&str, &str)] = &[
40     ("aarch64", "aarch64"),
41     ("aarch64_be", "aarch64"),
42     ("amd64", "x86_64"),
43     ("arm", "arm"),
44     ("arm64", "aarch64"),
45     ("armv4t", "arm"),
46     ("armv5te", "arm"),
47     ("armv7", "arm"),
48     ("armv7s", "arm"),
49     ("asmjs", "asmjs"),
50     ("avr", "avr"),
51     ("bpfeb", "bpf"),
52     ("bpfel", "bpf"),
53     ("hexagon", "hexagon"),
54     ("i386", "x86"),
55     ("i586", "x86"),
56     ("i686", "x86"),
57     ("m68k", "m68k"),
58     ("mips", "mips"),
59     ("mips64", "mips64"),
60     ("mips64el", "mips64"),
61     ("mipsisa32r6", "mips"),
62     ("mipsisa32r6el", "mips"),
63     ("mipsisa64r6", "mips64"),
64     ("mipsisa64r6el", "mips64"),
65     ("mipsel", "mips"),
66     ("mipsisa32r6", "mips"),
67     ("mipsisa32r6el", "mips"),
68     ("mipsisa64r6", "mips64"),
69     ("mipsisa64r6el", "mips64"),
70     ("msp430", "msp430"),
71     ("nvptx64", "nvptx64"),
72     ("powerpc", "powerpc"),
73     ("powerpc64", "powerpc64"),
74     ("powerpc64le", "powerpc64"),
75     ("riscv64gc", "riscv64"),
76     ("s390x", "s390x"),
77     ("sparc", "sparc"),
78     ("sparc64", "sparc64"),
79     ("sparcv9", "sparc64"),
80     ("thumbv6m", "thumb"),
81     ("thumbv7em", "thumb"),
82     ("thumbv7m", "thumb"),
83     ("wasm32", "wasm32"),
84     ("x86_64", "x86_64"),
85     ("xcore", "xcore"),
86 ];
87 
88 pub const ASAN_SUPPORTED_TARGETS: &[&str] = &[
89     "aarch64-apple-darwin",
90     "aarch64-fuchsia",
91     "aarch64-unknown-linux-gnu",
92     "x86_64-apple-darwin",
93     "x86_64-fuchsia",
94     "x86_64-unknown-freebsd",
95     "x86_64-unknown-linux-gnu",
96 ];
97 
98 pub const LSAN_SUPPORTED_TARGETS: &[&str] = &[
99     // FIXME: currently broken, see #88132
100     // "aarch64-apple-darwin",
101     "aarch64-unknown-linux-gnu",
102     "x86_64-apple-darwin",
103     "x86_64-unknown-linux-gnu",
104 ];
105 
106 pub const MSAN_SUPPORTED_TARGETS: &[&str] =
107     &["aarch64-unknown-linux-gnu", "x86_64-unknown-freebsd", "x86_64-unknown-linux-gnu"];
108 
109 pub const TSAN_SUPPORTED_TARGETS: &[&str] = &[
110     "aarch64-apple-darwin",
111     "aarch64-unknown-linux-gnu",
112     "x86_64-apple-darwin",
113     "x86_64-unknown-freebsd",
114     "x86_64-unknown-linux-gnu",
115 ];
116 
117 pub const HWASAN_SUPPORTED_TARGETS: &[&str] =
118     &["aarch64-linux-android", "aarch64-unknown-linux-gnu"];
119 
120 const BIG_ENDIAN: &[&str] = &[
121     "aarch64_be",
122     "armebv7r",
123     "mips",
124     "mips64",
125     "mipsisa32r6",
126     "mipsisa64r6",
127     "powerpc",
128     "powerpc64",
129     "s390x",
130     "sparc",
131     "sparc64",
132     "sparcv9",
133 ];
134 
135 static ASM_SUPPORTED_ARCHS: &[&str] = &[
136     "x86", "x86_64", "arm", "aarch64", "riscv32",
137     "riscv64",
138     // These targets require an additional asm_experimental_arch feature.
139     // "nvptx64", "hexagon", "mips", "mips64", "spirv", "wasm32",
140 ];
141 
has_asm_support(triple: &str) -> bool142 pub fn has_asm_support(triple: &str) -> bool {
143     ASM_SUPPORTED_ARCHS.contains(&get_arch(triple))
144 }
145 
matches_os(triple: &str, name: &str) -> bool146 pub fn matches_os(triple: &str, name: &str) -> bool {
147     // For the wasm32 bare target we ignore anything also ignored on emscripten
148     // and then we also recognize `wasm32-bare` as the os for the target
149     if triple == "wasm32-unknown-unknown" {
150         return name == "emscripten" || name == "wasm32-bare";
151     }
152     let triple: Vec<_> = triple.split('-').collect();
153     for &(triple_os, os) in OS_TABLE {
154         if triple.contains(&triple_os) {
155             return os == name;
156         }
157     }
158     panic!("Cannot determine OS from triple");
159 }
160 
161 /// Determine the architecture from `triple`
get_arch(triple: &str) -> &'static str162 pub fn get_arch(triple: &str) -> &'static str {
163     let triple: Vec<_> = triple.split('-').collect();
164     for &(triple_arch, arch) in ARCH_TABLE {
165         if triple.contains(&triple_arch) {
166             return arch;
167         }
168     }
169     panic!("Cannot determine Architecture from triple");
170 }
171 
172 /// Determine the endianness from `triple`
is_big_endian(triple: &str) -> bool173 pub fn is_big_endian(triple: &str) -> bool {
174     let triple_arch = triple.split('-').next().unwrap();
175     BIG_ENDIAN.contains(&triple_arch)
176 }
177 
matches_env(triple: &str, name: &str) -> bool178 pub fn matches_env(triple: &str, name: &str) -> bool {
179     if let Some(env) = triple.split('-').nth(3) { env.starts_with(name) } else { false }
180 }
181 
get_pointer_width(triple: &str) -> &'static str182 pub fn get_pointer_width(triple: &str) -> &'static str {
183     if (triple.contains("64") && !triple.ends_with("gnux32") && !triple.ends_with("gnu_ilp32"))
184         || triple.starts_with("s390x")
185     {
186         "64bit"
187     } else if triple.starts_with("avr") {
188         "16bit"
189     } else {
190         "32bit"
191     }
192 }
193 
make_new_path(path: &str) -> String194 pub fn make_new_path(path: &str) -> String {
195     assert!(cfg!(windows));
196     // Windows just uses PATH as the library search path, so we have to
197     // maintain the current value while adding our own
198     match env::var(lib_path_env_var()) {
199         Ok(curr) => format!("{}{}{}", path, path_div(), curr),
200         Err(..) => path.to_owned(),
201     }
202 }
203 
lib_path_env_var() -> &'static str204 pub fn lib_path_env_var() -> &'static str {
205     "PATH"
206 }
path_div() -> &'static str207 fn path_div() -> &'static str {
208     ";"
209 }
210 
logv(config: &Config, s: String)211 pub fn logv(config: &Config, s: String) {
212     debug!("{}", s);
213     if config.verbose {
214         println!("{}", s);
215     }
216 }
217 
218 pub trait PathBufExt {
219     /// Append an extension to the path, even if it already has one.
with_extra_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf220     fn with_extra_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf;
221 }
222 
223 impl PathBufExt for PathBuf {
with_extra_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf224     fn with_extra_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
225         if extension.as_ref().is_empty() {
226             self.clone()
227         } else {
228             let mut fname = self.file_name().unwrap().to_os_string();
229             if !extension.as_ref().to_str().unwrap().starts_with('.') {
230                 fname.push(".");
231             }
232             fname.push(extension);
233             self.with_file_name(fname)
234         }
235     }
236 }
237