1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
use std::collections::HashMap;
use std::path::PathBuf;
use symsrv::{parse_nt_symbol_path, NtSymbolPathEntry};
/// The configuration of a [`SymbolManager`](crate::SymbolManager).
///
/// Allows specifying various sources of symbol files.
#[derive(Debug, Clone, Default)]
pub struct SymbolManagerConfig {
pub(crate) redirect_paths: HashMap<PathBuf, PathBuf>,
pub(crate) respect_nt_symbol_path: bool,
pub(crate) default_nt_symbol_path: Option<String>,
pub(crate) breakpad_directories_readonly: Vec<PathBuf>,
pub(crate) breakpad_servers: Vec<(String, PathBuf)>,
pub(crate) breakpad_symindex_cache_dir: Option<PathBuf>,
pub(crate) windows_servers: Vec<(String, PathBuf)>,
pub(crate) use_debuginfod: bool,
pub(crate) use_spotlight: bool,
pub(crate) debuginfod_cache_dir_if_not_installed: Option<PathBuf>,
pub(crate) debuginfod_servers: Vec<(String, PathBuf)>,
pub(crate) extra_symbol_directories: Vec<PathBuf>,
pub(crate) simpleperf_binary_cache_directories: Vec<PathBuf>,
}
impl SymbolManagerConfig {
/// Create a new `SymbolManagerConfig` in its default state.
pub fn new() -> Self {
Self::default()
}
/// For use in tests. Add a path which, when opened, opens a file at a different path instead.
///
/// This can be used to test debug files which refer to other files on the file system with
/// absolute paths, by redirecting those absolute paths to a path in the test fixtures directory.
pub fn redirect_path_for_testing(
mut self,
redirect_path: impl Into<PathBuf>,
dest_path: impl Into<PathBuf>,
) -> Self {
self.redirect_paths
.insert(redirect_path.into(), dest_path.into());
self
}
/// Whether to import Windows symbol path configuration from the
/// `_NT_SYMBOL_PATH` environment variable.
pub fn respect_nt_symbol_path(mut self, respect: bool) -> Self {
self.respect_nt_symbol_path = respect;
self
}
/// Set a fallback value for the Windows symbol path which is used
/// if `respect_nt_symbol_path` is false or if the `_NT_SYMBOL_PATH`
/// environment variable is not set.
///
/// Example: `"srv**https://msdl.microsoft.com/download/symbols"`
pub fn default_nt_symbol_path(mut self, default_env_val: impl Into<String>) -> Self {
self.default_nt_symbol_path = Some(default_env_val.into());
self
}
pub(crate) fn effective_nt_symbol_path(&self) -> Option<Vec<NtSymbolPathEntry>> {
let respected_env_value = if self.respect_nt_symbol_path {
std::env::var("_NT_SYMBOL_PATH").ok()
} else {
None
};
let mut path = match (respected_env_value, &self.default_nt_symbol_path) {
(Some(env_var), _) => Some(parse_nt_symbol_path(&env_var)),
(None, Some(default)) => Some(parse_nt_symbol_path(default)),
(None, None) => None,
};
for (base_url, cache_dir) in &self.windows_servers {
path.get_or_insert_with(Default::default)
.push(NtSymbolPathEntry::Chain {
dll: "symsrv.dll".to_string(),
cache_paths: vec![symsrv::CachePath::Path(cache_dir.clone())],
urls: vec![base_url.clone()],
})
}
path
}
/// Add a directory to search for breakpad symbol files.
///
/// The first-added directory will be searched first. Directories added here
/// are only used for reading.
pub fn breakpad_symbols_dir(mut self, dir: impl Into<PathBuf>) -> Self {
self.breakpad_directories_readonly.push(dir.into());
self
}
/// Add a server to search for breakpad symbol files, along with a local cache directory.
///
/// This method can be called multiple times; the servers and caches will be tried in the order of those calls.
pub fn breakpad_symbols_server(
mut self,
base_url: impl Into<String>,
cache_dir: impl Into<PathBuf>,
) -> Self {
self.breakpad_servers
.push((base_url.into(), cache_dir.into()));
self
}
/// Set a directory to cache symindex files in. These files are created while
/// downloading sym files from Breakpad symbol servers, and when opening existing
/// sym files without a corresponding symindex file.
///
/// Only one directory of this type can be set. This directory is used for both
/// reading and writing.
pub fn breakpad_symindex_cache_dir(mut self, dir: impl Into<PathBuf>) -> Self {
self.breakpad_symindex_cache_dir = Some(dir.into());
self
}
/// Add a server to search for Windows symbol files (pdb / exe / dll), along with a local cache directory.
///
/// This method can be called multiple times; the servers and caches will be tried in the order of those calls.
pub fn windows_symbols_server(
mut self,
base_url: impl Into<String>,
cache_dir: impl Into<PathBuf>,
) -> Self {
self.windows_servers
.push((base_url.into(), cache_dir.into()));
self
}
/// Whether debuginfod should be used, i.e. whether the `DEBUGINFOD_URLS` environment variable should be respected.
///
/// At the moment this will only work if you specify a custom cache directory with `debuginfod_cache_dir_if_not_installed`.
// TODO: Once "official debuginfod" is supported, change this to:
// /// If debuginfod is not installed, this will only work if you specify a custom cache directory with `debuginfod_cache_dir_if_not_installed`.
pub fn use_debuginfod(mut self, flag: bool) -> Self {
self.use_debuginfod = flag;
self
}
/// If `use_debuginfod` is set, use this directory as a cache directory. At the moment
/// this is used even if debuginfod is installed, despite the function name, because
/// wholesym is still missing a way to use the installed debuginfod and currently
/// always runs its own code for downloading files from debuginfod servers.
// TODO: Once "official debuginfod" is supported, change this to:
// /// If `use_debuginfod` is set, and debuginfod is not installed (e.g. on non-Linux), use this directory as a cache directory.
pub fn debuginfod_cache_dir_if_not_installed(mut self, cache_dir: impl Into<PathBuf>) -> Self {
self.debuginfod_cache_dir_if_not_installed = Some(cache_dir.into());
self
}
/// Add a server to search for ELF debuginfo and executable files, along with a local cache directory.
/// These servers are consulted independently of `use_debuginfod`.
///
/// This method can be called multiple times; the servers and caches will be tried in the order of those calls.
pub fn extra_debuginfod_server(
mut self,
base_url: impl Into<String>,
cache_dir: impl Into<PathBuf>,
) -> Self {
self.debuginfod_servers
.push((base_url.into(), cache_dir.into()));
self
}
/// Whether to use the macOS Spotlight service (`mdfind`) to look up the location
/// of dSYM files based on a mach-O UUID. Ignored on non-macOS.
pub fn use_spotlight(mut self, use_spotlight: bool) -> Self {
self.use_spotlight = use_spotlight;
self
}
/// Add an additional directory that may contain symbol files.
/// We will check "<dir>/<binaryname>" and "<dir>/<debug_name>".
pub fn extra_symbols_directory(mut self, dir: impl Into<PathBuf>) -> Self {
self.extra_symbol_directories.push(dir.into());
self
}
/// Add a simpleperf "binary_cache" directory which will be checked for symbols.
///
/// The simpleperf scripts pull files from the Android device into this directory.
pub fn simpleperf_binary_cache_dir(mut self, dir: impl Into<PathBuf>) -> Self {
self.simpleperf_binary_cache_directories.push(dir.into());
self
}
}