Skip to content

Commit

Permalink
WIP: compilable output
Browse files Browse the repository at this point in the history
  • Loading branch information
ergrelet committed Mar 18, 2024
1 parent 69e2ab2 commit d1d0ecd
Show file tree
Hide file tree
Showing 6 changed files with 367 additions and 94 deletions.
156 changes: 118 additions & 38 deletions resym_core/src/pdb_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use pdb::FallibleIterator;
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};

use std::{
collections::BTreeSet,
collections::{BTreeMap, HashMap, HashSet, VecDeque},
io::{self, Read, Seek},
path::PathBuf,
sync::{Arc, RwLock},
Expand Down Expand Up @@ -515,55 +515,131 @@ where
print_access_specifiers,
};
let mut type_data = pdb_types::Data::new();
let mut needed_types = pdb_types::TypeSet::new();

// Add the requested type first
type_data.add(
type_finder,
&self.forwarder_to_complete_type,
type_index,
&primitives_flavor,
&mut needed_types,
)?;

// If dependencies aren't needed, we're done
// If dependencies aren't needed, only process the given type index and return
if !reconstruct_dependencies {
let mut needed_types = pdb_types::TypeSet::new();
type_data.add(
type_finder,
&self.forwarder_to_complete_type,
type_index,
&primitives_flavor,
&mut needed_types,
)?;

let mut reconstruction_output = String::new();
type_data.reconstruct(&fmt_configuration, &mut reconstruction_output)?;
type_data.reconstruct(
&fmt_configuration,
&Default::default(),
&mut reconstruction_output,
)?;
return Ok(reconstruction_output);
}

// Add all the needed types iteratively until we're done
let mut dependencies_data = pdb_types::Data::new();
let mut processed_types = BTreeSet::from([type_index]);
let dep_start = Instant::now();
loop {
// Get the first element in needed_types without holding an immutable borrow
let first = needed_types.difference(&processed_types).next().copied();
match first {
None => break,
Some(needed_type_index) => {
// Add the type
dependencies_data.add(
type_finder,
&self.forwarder_to_complete_type,
needed_type_index,
&primitives_flavor,
&mut needed_types,
)?;
let mut type_dependency_map: HashMap<pdb::TypeIndex, Vec<pdb::TypeIndex>> = HashMap::new();
{
let dep_start = Instant::now();

// Add the requested type first
let mut types_to_process: VecDeque<pdb::TypeIndex> = VecDeque::from([type_index]);
let mut processed_type_set = HashSet::from([]);
// Keep processing new types until there's nothing to process
while let Some(needed_type_index) = types_to_process.pop_front() {
if processed_type_set.contains(&needed_type_index) {
// Already processed, continue
continue;
}

// Add the type
let mut needed_types = pdb_types::TypeSet::new();
type_data.add(
type_finder,
&self.forwarder_to_complete_type,
needed_type_index,
&primitives_flavor,
&mut needed_types,
)?;

// Update type dependency map
needed_types.iter().for_each(|type_index| {
if let Some(type_dependency) = type_dependency_map.get_mut(&needed_type_index) {
type_dependency.push(*type_index);
} else {
type_dependency_map.insert(needed_type_index, vec![*type_index]);
}
});
// Update the set of processed types
processed_type_set.insert(needed_type_index);
// Update the queue of type to process
types_to_process.extend(needed_types.into_iter());
}

log::debug!(
"Dependencies reconstruction took {} ms",
dep_start.elapsed().as_millis()
);
}

processed_types.insert(needed_type_index);
// Deduce type "depth" from the dependency map
let mut type_depth_map: BTreeMap<pdb::TypeIndex, usize> = BTreeMap::from([(type_index, 0)]);
{
// Perform depth-first search to determine the "depth" of each type
let mut types_to_visit: VecDeque<(usize, pdb::TypeIndex)> =
VecDeque::from([(0, type_index)]);
let mut visit_stack: VecDeque<(usize, pdb::TypeIndex)> = VecDeque::new();
while let Some((current_type_depth, current_type_index)) = types_to_visit.pop_back() {
// Update type visit stack
while let Some((type_depth, _)) = visit_stack.back() {
if *type_depth >= current_type_depth {
visit_stack.pop_back();
} else {
break;
}
}
visit_stack.push_back((current_type_depth, current_type_index));

if let Some(type_dependencies) = type_dependency_map.get(&current_type_index) {
for child_type_index in type_dependencies {
// Visit child only if it's not already on the stack, to avoid loops
if !visit_stack.iter().any(|(_, t)| t == child_type_index) {
let current_child_depth = current_type_depth + 1;
if let Some(child_type_depth) = type_depth_map.get_mut(child_type_index)
{
*child_type_depth =
std::cmp::max(*child_type_depth, current_child_depth);
} else {
type_depth_map.insert(*child_type_index, current_child_depth);
}
types_to_visit.push_back((current_child_depth, *child_type_index));
} else {
// Add a forward reference as it's most likely a pointer
type_data.add_as_forward_reference(type_finder, *child_type_index)?;
}
}
}
}
}
log::debug!(
"Dependencies reconstruction took {} ms",
dep_start.elapsed().as_millis()
);

// Invert type depth map
let inverted_type_depth_map: BTreeMap<usize, Vec<pdb::TypeIndex>> = type_depth_map
.into_iter()
.fold(BTreeMap::new(), |mut acc, (type_index, type_depth)| {
if let Some(type_indices) = acc.get_mut(&type_depth) {
type_indices.push(type_index);
} else {
acc.insert(type_depth, vec![type_index]);
}

acc
});

let mut reconstruction_output = String::new();
dependencies_data.reconstruct(&fmt_configuration, &mut reconstruction_output)?;
type_data.reconstruct(&fmt_configuration, &mut reconstruction_output)?;
type_data.reconstruct(
&fmt_configuration,
&inverted_type_depth_map,
&mut reconstruction_output,
)?;
Ok(reconstruction_output)
}

Expand Down Expand Up @@ -611,7 +687,11 @@ where
print_access_specifiers,
};
let mut reconstruction_output = String::new();
type_data.reconstruct(&fmt_configuration, &mut reconstruction_output)?;
type_data.reconstruct(
&fmt_configuration,
&Default::default(),
&mut reconstruction_output,
)?;
Ok(reconstruction_output)
}

Expand Down
29 changes: 25 additions & 4 deletions resym_core/src/pdb_types/class.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::fmt;
use std::{collections::BTreeMap, fmt};

use super::{
enumeration::Enum,
Expand All @@ -7,7 +7,8 @@ use super::{
primitive_types::PrimitiveReconstructionFlavor,
resolve_complete_type_index, type_bitfield_info, type_name, type_size,
union::Union,
DataFormatConfiguration, Field, Method, Result, ResymCoreError, TypeForwarder, TypeSet,
DataFormatConfiguration, Field, Method, ReconstructibleTypeData, Result, ResymCoreError,
TypeForwarder, TypeSet,
};

#[derive(Debug, Clone, PartialEq, Eq)]
Expand Down Expand Up @@ -52,6 +53,7 @@ pub struct BaseClass {

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Class<'p> {
pub index: pdb::TypeIndex,
pub kind: pdb::ClassKind,
pub name: String,
pub size: u64,
Expand Down Expand Up @@ -122,6 +124,7 @@ impl<'p> Class<'p> {
};

let mut class = Class {
index: type_index,
kind: data.kind,
name,
size: data.size,
Expand Down Expand Up @@ -162,6 +165,7 @@ impl<'p> Class<'p> {
};

let mut u = Union {
index: type_index,
name,
size: data.size,
fields: Vec::new(),
Expand Down Expand Up @@ -194,6 +198,7 @@ impl<'p> Class<'p> {
};

let mut e = Enum {
index: type_index,
name,
underlying_type_name: type_name(
type_finder,
Expand Down Expand Up @@ -410,8 +415,10 @@ impl<'p> Class<'p> {

Ok(())
}
}

pub fn reconstruct(
impl ReconstructibleTypeData for Class<'_> {
fn reconstruct(
&self,
fmt_configuration: &DataFormatConfiguration,
f: &mut impl std::fmt::Write,
Expand Down Expand Up @@ -464,7 +471,7 @@ impl<'p> Class<'p> {
if !self.nested_enums.is_empty() {
writeln!(f, " ")?;
for e in &self.nested_enums {
e.reconstruct(f)?;
e.reconstruct(fmt_configuration, f)?;
}
}

Expand Down Expand Up @@ -559,4 +566,18 @@ impl<'p> Class<'p> {

Ok(())
}

fn reconstruct_compilable(
&self,
fmt_configuration: &DataFormatConfiguration,
type_map: &mut BTreeMap<u32, String>,
) -> Result<()> {
// Reconstruct type in String
let mut reconstructed_type = String::default();
self.reconstruct(fmt_configuration, &mut reconstructed_type)?;
// Insert reconstructed type in map
type_map.insert(self.index.0, reconstructed_type);

Ok(())
}
}
27 changes: 24 additions & 3 deletions resym_core/src/pdb_types/enumeration.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use std::fmt;
use std::{collections::BTreeMap, fmt};

use super::TypeSet;
use super::{DataFormatConfiguration, ReconstructibleTypeData, TypeSet};
use crate::error::Result;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Enum<'p> {
pub index: pdb::TypeIndex,
pub name: String,
pub underlying_type_name: String,
pub values: Vec<EnumValue<'p>>,
Expand Down Expand Up @@ -49,8 +50,14 @@ impl<'p> Enum<'p> {
});
}
}
}

pub fn reconstruct(&self, f: &mut impl std::fmt::Write) -> fmt::Result {
impl ReconstructibleTypeData for Enum<'_> {
fn reconstruct(
&self,
_fmt_configuration: &DataFormatConfiguration,
f: &mut impl std::fmt::Write,
) -> fmt::Result {
writeln!(f, "enum {} : {} {{", self.name, self.underlying_type_name)?;

for value in &self.values {
Expand All @@ -74,6 +81,20 @@ impl<'p> Enum<'p> {

Ok(())
}

fn reconstruct_compilable(
&self,
fmt_configuration: &DataFormatConfiguration,
type_map: &mut BTreeMap<u32, String>,
) -> Result<()> {
// Reconstruct type in String
let mut reconstructed_type = String::default();
self.reconstruct(fmt_configuration, &mut reconstructed_type)?;
// Insert reconstructed type in map
type_map.insert(self.index.0, reconstructed_type);

Ok(())
}
}

#[derive(Debug, Clone, PartialEq, Eq)]
Expand Down
44 changes: 44 additions & 0 deletions resym_core/src/pdb_types/forward_reference.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use std::{collections::BTreeMap, fmt};

use super::{DataFormatConfiguration, ReconstructibleTypeData};
use crate::error::Result;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ForwardReference {
pub index: pdb::TypeIndex,
pub kind: pdb::ClassKind,
pub name: String,
}

impl ReconstructibleTypeData for ForwardReference {
fn reconstruct(
&self,
_fmt_configuration: &DataFormatConfiguration,
f: &mut impl std::fmt::Write,
) -> fmt::Result {
writeln!(
f,
"{} {};",
match self.kind {
pdb::ClassKind::Class => "class",
pdb::ClassKind::Struct => "struct",
pdb::ClassKind::Interface => "interface", // when can this happen?
},
self.name
)
}

fn reconstruct_compilable(
&self,
fmt_configuration: &DataFormatConfiguration,
type_map: &mut BTreeMap<u32, String>,
) -> Result<()> {
// Reconstruct type in String
let mut reconstructed_type = String::default();
self.reconstruct(fmt_configuration, &mut reconstructed_type)?;
// Insert reconstructed type in map
type_map.insert(self.index.0, reconstructed_type);

Ok(())
}
}
Loading

0 comments on commit d1d0ecd

Please sign in to comment.