sbpf_coverage/
toolchain.rs1use crate::{DebugPath, util::execute_cmd};
2use std::path::PathBuf;
3
4pub fn get_toolchain_sysroot(debug_path: &DebugPath) -> Option<String> {
9 if debug_path.lang == Some("DW_LANG_Rust".into())
10 && let Some(producer) = debug_path.producer.as_ref()
11 {
12 let (toolchain, platform_tools) =
13 rustc_toolchain_from_producer(producer).or_else(|| {
14 eprintln!("Failed to extract toolchain from DW_AT_producer");
15 None
16 })?;
17 let file_name = debug_path
18 .path
19 .file_name()
20 .map(|n| n.to_string_lossy())
21 .unwrap_or_default();
22 let pt = platform_tools
23 .as_ref()
24 .map(|v| format!(", platform-tools {v}"))
25 .unwrap_or_default();
26 eprintln!("{file_name} likely: compiler {producer}{pt}, toolchain {toolchain}");
27 let sysroot = execute_cmd(
28 &PathBuf::from("rustc"),
29 [&format!("+{toolchain}"), "--print", "sysroot"],
30 )
31 .or_else(|| {
32 eprintln!("Failed to extract sysroot for toolchain {toolchain}");
33 None
34 });
35
36 return sysroot.map(|s| format!("{}/lib/rustlib/src/rust", s.trim()));
39 }
40
41 None
42}
43
44pub fn rustc_toolchain_from_producer(producer: &str) -> Option<(String, Option<String>)> {
48 let after = producer.split("rustc version ").nth(1)?;
49
50 if !after.contains("-dev") {
54 let date = after
58 .split('(')
59 .nth(1)?
60 .split(')')
61 .next()?
62 .split_whitespace()
63 .nth(1)?;
64 Some((format!("nightly-{date}"), None))
65 } else {
66 let version_dev = after.split(')').next()?;
72 let rustc_version = version_dev.split('-').next()?;
73 let producer_rustc_commit_hash = version_dev
74 .split('(')
75 .nth(1)
76 .and_then(|inner| inner.split_whitespace().next())
77 .map(String::from);
78 let platform_tools_version =
79 get_platform_tools_version(rustc_version, producer_rustc_commit_hash.as_deref())?;
80 Some((
81 format!("{rustc_version}-sbpf-solana-{platform_tools_version}"),
83 Some(platform_tools_version),
84 ))
85 }
86}
87
88pub fn cargo_home() -> String {
91 std::env::var("CARGO_HOME")
92 .unwrap_or_else(|_| format!("{}/.cargo", std::env::var("HOME").unwrap()))
93}
94
95pub fn get_platform_tools_version(
99 binary_rustc_version: &str,
100 producer_rustc_commit_hash: Option<&str>,
101) -> Option<String> {
102 let home_dir = std::env::var("HOME").ok()?;
103 let base_line = format!("{}/.cache/solana", home_dir);
104 let paths = std::fs::read_dir(&base_line).ok()?;
105
106 let mut platform_tools_dirs = Vec::new();
107 for path in paths {
108 let Ok(path) = path else { continue };
109 let Ok(file_type) = path.file_type() else {
111 continue;
112 };
113 if !file_type.is_dir() {
114 continue;
115 }
116 let dir_name = path.file_name();
117 if !dir_name.to_string_lossy().starts_with("v") {
119 continue;
120 }
121 platform_tools_dirs.push(dir_name.to_string_lossy().to_string());
122 }
123
124 platform_tools_dirs.sort();
125
126 platform_tools_dirs
130 .iter()
131 .rev()
132 .map(|ver| {
133 (
134 ver.clone(),
135 format!("{}/{}/platform-tools/rust/bin/rustc", base_line, ver),
136 )
137 })
138 .filter(|(ver, rustc_path)| {
139 if !PathBuf::from(&rustc_path).is_file() {
140 return false;
141 }
142 let Some(platform_tools_rustc_version) =
143 execute_cmd(&PathBuf::from(rustc_path), ["--version"])
144 else {
145 return false;
146 };
147 let rustc_commit_hash =
148 std::fs::read_to_string(format!("{base_line}/{ver}/platform-tools/version.md"))
149 .ok()
150 .and_then(|version_file_content| {
151 version_file_content
152 .lines()
153 .find(|line| line.contains("rust.git"))
154 .and_then(|line| line.split(' ').next())
155 .map(String::from)
156 });
157 if let (Some(rch), Some(ch)) = (rustc_commit_hash, producer_rustc_commit_hash)
158 && !rch.starts_with(ch)
159 {
160 return false;
161 }
162
163 platform_tools_rustc_version.contains(binary_rustc_version)
164 })
165 .map(|(ver, _)| ver)
166 .next()
167}
168
169pub fn map_dwarf_path(dwarf_path: &str, rust_src_root: Option<&str>, cargo_root: &str) -> String {
173 if let (Some(rust_src_root), Some(pos)) = (rust_src_root, dwarf_path.find("/library/")) {
174 let suffix = &dwarf_path[pos..];
175 format!("{}/{}", rust_src_root, suffix)
176 } else if let Some(pos) = dwarf_path
177 .find(".cargo/registry/")
178 .or_else(|| dwarf_path.find(".cargo/git/"))
179 {
180 let suffix = &dwarf_path[pos + ".cargo/".len()..];
181 format!("{}/{}", cargo_root, suffix)
182 } else {
183 dwarf_path.to_string()
185 }
186}