Skip to content

Commit

Permalink
Implement new commands to reconstruct modules
Browse files Browse the repository at this point in the history
  • Loading branch information
ergrelet committed Feb 25, 2024
1 parent 215a815 commit a9118e5
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 7 deletions.
64 changes: 60 additions & 4 deletions resym_core/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use crate::{
diffing::diff_type_by_name,
error::{Result, ResymCoreError},
frontend::FrontendCommand,
frontend::FrontendController,
frontend::{FrontendController, ModuleList},
pdb_file::PdbFile,
pdb_types::{include_headers_for_flavor, PrimitiveReconstructionFlavor},
PKG_VERSION,
Expand Down Expand Up @@ -72,6 +72,10 @@ pub enum BackendCommand {
/// Retrieve a list of types that match the given filter for multiple PDBs
/// and merge the result.
UpdateTypeFilterMerged(Vec<PDBSlot>, String, bool, bool),
/// Retrieve the list of all modules in a given PDB.
ListModules(PDBSlot),
/// Reconstruct a module given its index for a given PDB.
ReconstructModuleByIndex(PDBSlot, usize, PrimitiveReconstructionFlavor, bool),
/// Reconstruct a diff of a type given its name.
DiffTypeByName(
PDBSlot,
Expand Down Expand Up @@ -372,6 +376,33 @@ fn worker_thread_routine(
))?;
}

BackendCommand::ReconstructModuleByIndex(
pdb_slot,
module_index,
primitives_flavor,
print_header,
) => {
if let Some(pdb_file) = pdb_files.get_mut(&pdb_slot) {
let reconstructed_module_result = reconstruct_module_by_index_command(
pdb_file,
module_index,
primitives_flavor,
print_header,
);
frontend_controller.send_command(FrontendCommand::ReconstructModuleResult(
reconstructed_module_result,
))?;
}
}

BackendCommand::ListModules(pdb_slot) => {
if let Some(pdb_file) = pdb_files.get(&pdb_slot) {
let module_list = list_modules_command(pdb_file);
frontend_controller
.send_command(FrontendCommand::UpdateModuleList(module_list))?;
}
}

BackendCommand::DiffTypeByName(
pdb_from_slot,
pdb_to_slot,
Expand Down Expand Up @@ -412,7 +443,7 @@ fn reconstruct_type_by_index_command<'p, T>(
print_access_specifiers: bool,
) -> Result<String>
where
T: io::Seek + io::Read + 'p,
T: io::Seek + io::Read + std::fmt::Debug + 'p,
{
let data = pdb_file.reconstruct_type_by_type_index(
type_index,
Expand All @@ -437,7 +468,7 @@ fn reconstruct_type_by_name_command<'p, T>(
print_access_specifiers: bool,
) -> Result<String>
where
T: io::Seek + io::Read + 'p,
T: io::Seek + io::Read + std::fmt::Debug + 'p,
{
let data = pdb_file.reconstruct_type_by_name(
type_name,
Expand All @@ -460,7 +491,7 @@ fn reconstruct_all_types_command<'p, T>(
print_access_specifiers: bool,
) -> Result<String>
where
T: io::Seek + io::Read + 'p,
T: io::Seek + io::Read + std::fmt::Debug + 'p,
{
let data = pdb_file.reconstruct_all_types(primitives_flavor, print_access_specifiers)?;
if print_header {
Expand All @@ -471,6 +502,31 @@ where
}
}

fn list_modules_command<'p, T>(pdb_file: &PdbFile<'p, T>) -> Result<ModuleList>
where
T: io::Seek + io::Read + std::fmt::Debug + 'p,
{
pdb_file.module_list()
}

fn reconstruct_module_by_index_command<'p, T>(
pdb_file: &mut PdbFile<'p, T>,
module_index: usize,
primitives_flavor: PrimitiveReconstructionFlavor,
print_header: bool,
) -> Result<String>
where
T: io::Seek + io::Read + std::fmt::Debug + 'p,
{
let data = pdb_file.reconstruct_module_by_index(module_index, &primitives_flavor)?;
if print_header {
let file_header = generate_file_header(pdb_file, primitives_flavor, true);
Ok(format!("{file_header}\n{data}"))
} else {
Ok(data)
}
}

fn generate_file_header<T>(
pdb_file: &PdbFile<T>,
primitives_flavor: PrimitiveReconstructionFlavor,
Expand Down
2 changes: 1 addition & 1 deletion resym_core/src/diffing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub fn diff_type_by_name<'p, T>(
print_access_specifiers: bool,
) -> Result<DiffedType>
where
T: io::Seek + io::Read + 'p,
T: io::Seek + io::Read + std::fmt::Debug + 'p,
{
let diff_start = Instant::now();
// Prepend header if needed
Expand Down
5 changes: 5 additions & 0 deletions resym_core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ pub enum ResymCoreError {
#[error("type not found: {0}")]
TypeNameNotFoundError(String),

/// Error returned when querying for a module's information, that isn't available in
/// the PDB file.
#[error("module info not found: {0}")]
ModuleInfoNotFoundError(String),

/// Error returned when parsing a `PrimitiveReconstructionFlavor` from a string fails.
#[error("invalid primitive type flavor: {0}")]
ParsePrimitiveFlavorError(String),
Expand Down
3 changes: 3 additions & 0 deletions resym_core/src/frontend.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::{backend::PDBSlot, diffing::DiffedType, error::Result};

pub type TypeList = Vec<(String, pdb::TypeIndex)>;
pub type ModuleList = Vec<(String, usize)>;

pub enum FrontendCommand {
LoadPDBResult(Result<PDBSlot>),
Expand All @@ -9,6 +10,8 @@ pub enum FrontendCommand {
LoadURLResult(Result<(PDBSlot, String, Vec<u8>)>),
UpdateFilteredTypes(TypeList),
ReconstructTypeResult(Result<String>),
ReconstructModuleResult(Result<String>),
UpdateModuleList(Result<ModuleList>),
DiffTypeResult(Result<DiffedType>),
}

Expand Down
102 changes: 100 additions & 2 deletions resym_core/src/pdb_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ use std::{fs::File, path::Path, time::Instant};
use crate::{
cond_par_iter,
error::{Result, ResymCoreError},
pdb_types::{self, is_unnamed_type, DataFormatConfiguration, PrimitiveReconstructionFlavor},
frontend::ModuleList,
pdb_types::{
self, is_unnamed_type, type_name, DataFormatConfiguration, PrimitiveReconstructionFlavor,
},
};

/// Wrapper for different buffer types processed by `resym`
Expand Down Expand Up @@ -56,6 +59,7 @@ where
pub forwarder_to_complete_type: Arc<DashMap<pdb::TypeIndex, pdb::TypeIndex>>,
pub machine_type: pdb::MachineType,
pub type_information: pdb::TypeInformation<'p>,
pub debug_information: pdb::DebugInformation<'p>,
pub file_path: PathBuf,
_pdb: pdb::PDB<'p, T>,
}
Expand All @@ -67,13 +71,15 @@ impl<'p> PdbFile<'p, File> {
let file = PDBDataSource::File(File::open(pdb_file_path)?);
let mut pdb = pdb::PDB::open(file)?;
let type_information = pdb.type_information()?;
let debug_information = pdb.debug_information()?;
let machine_type = pdb.debug_information()?.machine_type()?;

let mut pdb_file = PdbFile {
complete_type_list: vec![],
forwarder_to_complete_type: Arc::new(DashMap::default()),
machine_type,
type_information,
debug_information,
file_path: pdb_file_path.to_owned(),
_pdb: pdb,
};
Expand All @@ -92,13 +98,15 @@ impl<'p> PdbFile<'p, PDBDataSource> {
let reader = PDBDataSource::Vec(io::Cursor::new(pdb_file_data));
let mut pdb = pdb::PDB::open(reader)?;
let type_information = pdb.type_information()?;
let debug_information = pdb.debug_information()?;
let machine_type = pdb.debug_information()?.machine_type()?;

let mut pdb_file = PdbFile {
complete_type_list: vec![],
forwarder_to_complete_type: Arc::new(DashMap::default()),
machine_type,
type_information,
debug_information,
file_path: pdb_file_name.into(),
_pdb: pdb,
};
Expand All @@ -115,13 +123,15 @@ impl<'p> PdbFile<'p, PDBDataSource> {
let reader = PDBDataSource::SharedArray(io::Cursor::new(pdb_file_data));
let mut pdb = pdb::PDB::open(reader)?;
let type_information = pdb.type_information()?;
let debug_information = pdb.debug_information()?;
let machine_type = pdb.debug_information()?.machine_type()?;

let mut pdb_file = PdbFile {
complete_type_list: vec![],
forwarder_to_complete_type: Arc::new(DashMap::default()),
machine_type,
type_information,
debug_information,
file_path: pdb_file_name.into(),
_pdb: pdb,
};
Expand All @@ -133,7 +143,7 @@ impl<'p> PdbFile<'p, PDBDataSource> {

impl<'p, T> PdbFile<'p, T>
where
T: io::Seek + io::Read + 'p,
T: io::Seek + io::Read + std::fmt::Debug + 'p,
{
fn load_symbols(&mut self) -> Result<()> {
// Build the list of complete types
Expand Down Expand Up @@ -345,6 +355,94 @@ where
)
}

pub fn module_list(&self) -> Result<ModuleList> {
let module_list = self
.debug_information
.modules()?
.enumerate()
.map(|(index, module)| Ok((module.module_name().into_owned(), index)));

Ok(module_list.collect()?)
}

pub fn reconstruct_module_by_index(
&mut self,
module_index: usize,
primitives_flavor: &PrimitiveReconstructionFlavor,
) -> Result<String> {
let mut modules = self.debug_information.modules()?;
let module = modules.nth(module_index)?.ok_or_else(|| {
ResymCoreError::ModuleInfoNotFoundError(format!("Module #{} not found", module_index))
})?;

let module_info = self._pdb.module_info(&module)?.ok_or_else(|| {
ResymCoreError::ModuleInfoNotFoundError(format!(
"No module information present for '{}'",
module.object_file_name()
))
})?;

// Populate our `TypeFinder`
let mut type_finder = self.type_information.finder();
{
let mut type_iter = self.type_information.iter();
while (type_iter.next()?).is_some() {
type_finder.update(&type_iter);
}
}

let mut result = String::default();
module_info.symbols()?.for_each(|symbol| {
let mut needed_types = pdb_types::TypeSet::new();

match symbol.parse()? {
pdb::SymbolData::UserDefinedType(udt) => {
if let Ok(type_name) = type_name(
&type_finder,
&self.forwarder_to_complete_type,
udt.type_index,
primitives_flavor,
&mut needed_types,
) {
if type_name.0 == "..." {
// No type
// ??
} else {
result +=
format!("using {} = {}{};\n", udt.name, type_name.0, type_name.1)
.as_str();
}
}
}
pdb::SymbolData::Procedure(procedure) => {
if let Ok(type_name) = type_name(
&type_finder,
&self.forwarder_to_complete_type,
procedure.type_index,
primitives_flavor,
&mut needed_types,
) {
if type_name.0 == "..." {
// No type
result +=
format!("void {}(); // Missing type information\n", procedure.name)
.as_str();
} else {
result +=
format!("{}{}{};\n", type_name.0, procedure.name, type_name.1)
.as_str();
}
}
}
_ => {}
}

Ok(())
})?;

Ok(result)
}

fn reconstruct_type_by_type_index_internal(
&self,
type_finder: &pdb::TypeFinder,
Expand Down

0 comments on commit a9118e5

Please sign in to comment.