use std::path::Path;
use symbolic::{common::DebugId, debuginfo::pe::PeObject};
#[cfg(feature = "http")]
use crate::cache::{self, SymbolServer};
use crate::utils;
#[cfg(feature = "http")]
fn try_to_find_pdb(path: &Path, pdb_filename: &str) -> Option<Vec<u8>> {
let pdb = path.with_file_name(pdb_filename);
let pdb_cab = pdb.with_extension("pd_");
for pdb in vec![pdb, pdb_cab].into_iter() {
if pdb.is_file() {
return Some(utils::read_file(pdb));
}
}
let mut pdb = std::env::current_dir().expect("Unable to get the current working directory");
pdb.set_file_name(pdb_filename);
if pdb.is_file() {
Some(utils::read_file(pdb))
} else {
None
}
}
#[cfg(feature = "http")]
fn os_specific_try_to_find_pdb(path: &Path, pdb_filename: &str) -> (Option<Vec<u8>>, String) {
#[cfg(unix)]
let pdb_filename = pdb_filename.replace('\\', "/");
let pdb_path = Path::new(&pdb_filename);
if let Some(file_name) = pdb_path.file_name() {
let pdb_name = file_name.to_str().unwrap().to_string();
if pdb_path.is_file() {
(Some(utils::read_file(pdb_path)), pdb_name)
} else {
(try_to_find_pdb(path, &pdb_name), pdb_name)
}
} else {
(None, "".to_string())
}
}
#[cfg(feature = "http")]
pub fn get_pe_pdb_buf<'a>(
path: &Path,
buf: &'a [u8],
symbol_server: Option<&Vec<SymbolServer>>,
) -> Option<(PeObject<'a>, Vec<u8>, String)> {
let pe = PeObject::parse(buf)
.unwrap_or_else(|_| panic!("Unable to parse the PE file {}", path.to_str().unwrap()));
if let Some(pdb_filename) = pe.debug_file_name() {
let pdb_filename = pdb_filename.into_owned();
let (pdb, pdb_name) = os_specific_try_to_find_pdb(path, &pdb_filename);
if pdb_name.is_empty() {
log::warn!("Invalid pdb filename in PE file: \"{pdb_filename}\"");
None
} else if let Some(pdb_buf) = pdb {
Some((pe, pdb_buf, pdb_name))
} else {
let debug_id = pe.debug_id().breakpad().to_string();
let (pdb, pdb_name) = cache::search_file(pdb_name, &debug_id, symbol_server);
pdb.map(|pdb_buf| (pe, pdb_buf, pdb_name))
}
} else {
None
}
}
fn fix_extension(ext: &str) -> &str {
match ext {
"dl_" => "dll",
"ex_" => "exe",
_ => ext,
}
}
pub(crate) fn find_pe_for_pdb(path: &Path, pdb_debug_id: &DebugId) -> Option<(String, Vec<u8>)> {
let mut path = path.to_path_buf();
for ext in vec!["dll", "dl_", "exe", "ex_"].drain(..) {
path.set_extension(ext);
if path.is_file() {
let buf = utils::read_file(&path);
if let Ok(pe) = PeObject::parse(&buf) {
if ext.ends_with('_') {
path.set_extension(fix_extension(ext));
}
let filename = utils::get_filename(&path);
if &pe.debug_id() == pdb_debug_id {
return Some((filename, buf));
}
}
}
}
None
}