use std::borrow::Cow;
use std::path::Path;
use std::sync::Arc;
use debugid::DebugId;
use samply_symbols::{
self, AddressInfo, Error, ExternalFileAddressInFileRef, ExternalFileAddressRef, FrameDebugInfo,
LibraryInfo, LookupAddress, MultiArchDisambiguator, SymbolMapTrait, SyncAddressInfo,
};
use crate::config::SymbolManagerConfig;
use crate::helper::{FileReadOnlyHelper, Helper, WholesymFileContents, WholesymFileLocation};
use crate::SymbolManagerObserver;
#[derive(Debug, Clone)]
pub struct SymbolFileOrigin(WholesymFileLocation);
pub struct SymbolMap(samply_symbols::SymbolMap<Helper>);
impl SymbolMap {
pub async fn lookup(&self, address: LookupAddress) -> Option<AddressInfo> {
self.0.lookup(address).await
}
pub fn lookup_sync(&self, address: LookupAddress) -> Option<SyncAddressInfo> {
self.0.lookup_sync(address)
}
pub async fn lookup_external(
&self,
external: &ExternalFileAddressRef,
) -> Option<Vec<FrameDebugInfo>> {
self.0.lookup_external(external).await
}
pub fn symbol_file_origin(&self) -> SymbolFileOrigin {
SymbolFileOrigin(self.0.debug_file_location().clone())
}
pub fn debug_id(&self) -> debugid::DebugId {
self.0.debug_id()
}
pub fn symbol_count(&self) -> usize {
self.0.symbol_count()
}
pub fn iter_symbols(&self) -> Box<dyn Iterator<Item = (u32, Cow<'_, str>)> + '_> {
self.0.iter_symbols()
}
}
pub struct ExternalFileSymbolMap(samply_symbols::ExternalFileSymbolMap<WholesymFileContents>);
impl ExternalFileSymbolMap {
pub fn file_path(&self) -> &str {
self.0.file_path()
}
pub fn lookup(
&self,
external_file_address: &ExternalFileAddressInFileRef,
) -> Option<Vec<FrameDebugInfo>> {
self.0.lookup(external_file_address)
}
}
pub struct SymbolManager {
symbol_manager: samply_symbols::SymbolManager<Helper>,
}
impl SymbolManager {
pub fn with_config(config: SymbolManagerConfig) -> Self {
let helper = Helper::with_config(config);
let symbol_manager = samply_symbols::SymbolManager::with_helper(helper);
Self { symbol_manager }
}
pub async fn load_symbol_map_for_binary_at_path(
&self,
path: &Path,
disambiguator: Option<MultiArchDisambiguator>,
) -> Result<SymbolMap, Error> {
let library_info = Self::library_info_for_binary_at_path(path, disambiguator).await?;
Ok(SymbolMap(
self.symbol_manager.load_symbol_map(&library_info).await?,
))
}
pub async fn library_info_for_binary_at_path(
path: &Path,
disambiguator: Option<MultiArchDisambiguator>,
) -> Result<LibraryInfo, Error> {
let might_be_in_dyld_shared_cache =
path.starts_with("/usr/") || path.starts_with("/System/");
let helper = FileReadOnlyHelper;
let symbol_manager = samply_symbols::SymbolManager::with_helper(helper);
let name = path
.file_name()
.and_then(|name| Some(name.to_str()?.to_owned()));
let path_str = path.to_str().map(ToOwned::to_owned);
let binary_res = symbol_manager
.load_binary_at_location(
WholesymFileLocation::LocalFile(path.to_owned()),
name,
path_str,
disambiguator.clone(),
)
.await;
let binary = match binary_res {
Ok(binary) => binary,
Err(Error::HelperErrorDuringOpenFile(_, _)) if might_be_in_dyld_shared_cache => {
symbol_manager
.load_binary_for_dyld_cache_image(&path.to_string_lossy(), disambiguator)
.await?
}
Err(e) => return Err(e),
};
Ok(binary.library_info())
}
pub fn set_observer(&mut self, observer: Option<Arc<dyn SymbolManagerObserver>>) {
self.symbol_manager.helper().set_observer(observer);
}
pub fn add_known_library(&mut self, lib_info: LibraryInfo) {
self.symbol_manager.helper().add_known_lib(lib_info);
}
pub fn add_known_library_symbols(
&mut self,
lib_info: LibraryInfo,
symbol_map: Arc<dyn SymbolMapTrait + Send + Sync>,
) {
self.symbol_manager
.helper()
.add_precog_symbol_map(lib_info, symbol_map);
}
pub async fn load_symbol_map(
&self,
debug_name: &str,
debug_id: DebugId,
) -> Result<SymbolMap, Error> {
let info = LibraryInfo {
debug_name: Some(debug_name.to_string()),
debug_id: Some(debug_id),
..Default::default()
};
Ok(SymbolMap(self.symbol_manager.load_symbol_map(&info).await?))
}
pub async fn load_external_file(
&self,
symbol_file_origin: &SymbolFileOrigin,
external_file_path: &str,
) -> Result<ExternalFileSymbolMap, Error> {
let symbol_map = self
.symbol_manager
.load_external_file(&symbol_file_origin.0, external_file_path)
.await?;
Ok(ExternalFileSymbolMap(symbol_map))
}
#[cfg(feature = "api")]
pub async fn query_json_api(&self, path: &str, request_json: &str) -> String {
let api = samply_api::Api::new(&self.symbol_manager);
api.query_api(path, request_json).await
}
}