Skip to content

Commit 9dbc09d

Browse files
committed
[PDB] Remove QualifiedName state
Apart of fixes for #7827 This also makes vtable type names refer to base class vtable type name, this was the original behavior, but it should be revisited later.
1 parent f80ecd0 commit 9dbc09d

File tree

3 files changed

+58
-51
lines changed

3 files changed

+58
-51
lines changed

plugins/pdb-ng/src/parser.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ use binaryninja::platform::Platform;
3232
use binaryninja::rc::Ref;
3333
use binaryninja::settings::{QueryOptions, Settings};
3434
use binaryninja::types::{
35-
EnumerationBuilder, NamedTypeReference, NamedTypeReferenceClass, QualifiedName,
36-
StructureBuilder, StructureType, Type, TypeClass,
35+
EnumerationBuilder, NamedTypeReference, NamedTypeReferenceClass, StructureBuilder,
36+
StructureType, Type, TypeClass,
3737
};
3838
use binaryninja::variable::NamedDataVariableWithType;
3939

@@ -69,13 +69,13 @@ pub struct PDBParserInstance<'a, S: Source<'a> + 'a> {
6969
/// TypeIndex -> ParsedType enum used during parsing
7070
pub(crate) indexed_types: BTreeMap<TypeIndex, ParsedType>,
7171
/// QName -> Binja Type for finished types
72-
pub(crate) named_types: BTreeMap<QualifiedName, Ref<Type>>,
72+
pub(crate) named_types: BTreeMap<String, Ref<Type>>,
7373
/// Raw (mangled) name -> TypeIndex for resolving forward references
7474
pub(crate) full_type_indices: BTreeMap<String, TypeIndex>,
7575
/// Stack of types we're currently parsing
7676
pub(crate) type_stack: Vec<TypeIndex>,
7777
/// Stack of parent types we're parsing nested types inside of
78-
pub(crate) namespace_stack: QualifiedName,
78+
pub(crate) namespace_stack: Vec<String>,
7979
/// Type Index -> Does it return on the stack
8080
pub(crate) type_default_returnable: BTreeMap<TypeIndex, bool>,
8181

@@ -291,9 +291,9 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
291291
fn collect_name(
292292
&self,
293293
name: &NamedTypeReference,
294-
unknown_names: &mut HashMap<QualifiedName, NamedTypeReferenceClass>,
294+
unknown_names: &mut HashMap<String, NamedTypeReferenceClass>,
295295
) {
296-
let used_name = name.name();
296+
let used_name = name.name().to_string();
297297
if let Some(&found) = unknown_names.get(&used_name) {
298298
if found != name.class() {
299299
// Interesting case, not sure we care
@@ -314,7 +314,7 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
314314
fn collect_names(
315315
&self,
316316
ty: &Type,
317-
unknown_names: &mut HashMap<QualifiedName, NamedTypeReferenceClass>,
317+
unknown_names: &mut HashMap<String, NamedTypeReferenceClass>,
318318
) {
319319
match ty.type_class() {
320320
TypeClass::StructureTypeClass => {
@@ -366,7 +366,7 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
366366
.bv
367367
.types()
368368
.iter()
369-
.map(|qnat| qnat.name)
369+
.map(|qnat| qnat.name.to_string())
370370
.collect::<HashSet<_>>();
371371

372372
for ty in &self.named_types {

plugins/pdb-ng/src/symbol_parser.rs

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1849,8 +1849,7 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
18491849
for (search_name, search_types) in name_to_type.iter() {
18501850
if last_name.contains(search_name) {
18511851
for search_type in search_types {
1852-
let qualified_search_type = QualifiedName::from(search_type);
1853-
if let Some(ty) = self.named_types.get(&qualified_search_type) {
1852+
if let Some(ty) = self.named_types.get(search_type) {
18541853
// Fallback in case we don't find a specific one
18551854
t = Some(Conf::new(
18561855
Type::named_type_from_type(search_type, ty.as_ref()),
@@ -1865,8 +1864,8 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
18651864
self.make_lengthy_type(ty, self.bv.start() + rva.0 as u64)?
18661865
{
18671866
// See if we have a type with this length
1868-
let lengthy_name: QualifiedName =
1869-
format!("${}$_extraBytes_{}", search_type, length).into();
1867+
let lengthy_name =
1868+
format!("${}$_extraBytes_{}", search_type, length);
18701869

18711870
if let Some(ty) = self.named_types.get(&lengthy_name) {
18721871
// Wow!
@@ -2008,7 +2007,7 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
20082007
/// Parse a vtable symbol name and return the parts for the vtable type.
20092008
/// Takes the last element of (e.g., `"ClassName::`vftable'{for `BaseClass'}"`)
20102009
/// and converts it to a vtable type name (e.g., `["ClassName", "BaseClass", "VTable"]`).
2011-
fn parse_vtable_type_name(name: &QualifiedName) -> Option<QualifiedName> {
2010+
fn parse_vtable_type_name(name: &QualifiedName) -> Option<String> {
20122011
let (last, qualified_name_base) = name.items.split_last()?;
20132012
let (class_name, rest) = last.split_once("::`vftable'")?;
20142013

@@ -2026,11 +2025,12 @@ fn parse_vtable_type_name(name: &QualifiedName) -> Option<QualifiedName> {
20262025
.and_then(|(_, base_start)| base_start.split_once("'}"))
20272026
.map(|(base, _)| base)
20282027
{
2029-
parts.push(clean(base_class));
2028+
parts = vec![clean(base_class)];
20302029
}
20312030

2032-
parts.push("VTable".to_string());
2033-
Some(QualifiedName::new(parts))
2031+
// We want only the last class name referenced in "parts", this is because the type we construct
2032+
// for the vtable will want to use the existing base vt defined in the binary view.
2033+
Some(format!("{}::VTable", parts.join("::")))
20342034
}
20352035

20362036
#[cfg(test)]
@@ -2043,7 +2043,7 @@ mod tests {
20432043
// Simple vtables
20442044
("Base::`vftable'", &["Base", "VTable"]),
20452045
// Multiple inheritance with {for}
2046-
("MultiDerived::`vftable'{for `InterfaceA'}", &["MultiDerived", "InterfaceA", "VTable"]),
2046+
("MultiDerived::`vftable'{for `InterfaceA'}", &["InterfaceA", "VTable"]),
20472047
// Simple templates
20482048
("Container<int32_t>::`vftable'", &["Container<int32_t>", "VTable"]),
20492049
("Pair<int32_t,char>::`vftable'", &["Pair<int32_t,char>", "VTable"]),
@@ -2053,8 +2053,8 @@ mod tests {
20532053
// Nested class inside template
20542054
("complex::HasNested<int32_t>::Nested::`vftable'", &["complex", "HasNested<int32_t>", "Nested", "VTable"]),
20552055
// Template with {for} clause
2056-
("TemplateMultiDerived<int32_t>::`vftable'{for `TemplateInterfaceA<int32_t>'}", &["TemplateMultiDerived<int32_t>", "TemplateInterfaceA<int32_t>", "VTable"]),
2057-
("TemplateDiamond<int32_t>::`vftable'{for `TemplateLeftVirtual<int32_t>'}", &["TemplateDiamond<int32_t>", "TemplateLeftVirtual<int32_t>", "VTable"]),
2056+
("TemplateMultiDerived<int32_t>::`vftable'{for `TemplateInterfaceA<int32_t>'}", &["TemplateInterfaceA<int32_t>", "VTable"]),
2057+
("TemplateDiamond<int32_t>::`vftable'{for `TemplateLeftVirtual<int32_t>'}", &["TemplateLeftVirtual<int32_t>", "VTable"]),
20582058
// Nested templates - note: "class " prefix gets stripped
20592059
("Wrapper<class Container<int32_t> >::`vftable'", &["Wrapper<Container<int32_t> >", "VTable"]),
20602060
// Class/struct/enum keyword removal
@@ -2068,8 +2068,12 @@ mod tests {
20682068
for (input, expected) in VTABLE_TEST_CASES {
20692069
let name = QualifiedName::new(vec![input.to_string()]);
20702070
let result = parse_vtable_type_name(&name);
2071-
let expected_qn = QualifiedName::new(expected.into_iter().cloned());
2072-
assert_eq!(result, Some(expected_qn), "Failed for input: {}", input);
2071+
assert_eq!(
2072+
result,
2073+
Some(expected.join("::")),
2074+
"Failed for input: {}",
2075+
input
2076+
);
20732077
}
20742078
}
20752079
}

plugins/pdb-ng/src/type_parser.rs

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ use binaryninja::platform::Platform;
2626
use binaryninja::rc::Ref;
2727
use binaryninja::types::{
2828
BaseStructure, EnumerationBuilder, EnumerationMember, FunctionParameter, MemberAccess,
29-
MemberScope, NamedTypeReference, NamedTypeReferenceClass, QualifiedName, StructureBuilder,
30-
StructureMember, StructureType, Type, TypeBuilder, TypeClass,
29+
MemberScope, NamedTypeReference, NamedTypeReferenceClass, StructureBuilder, StructureMember,
30+
StructureType, Type, TypeBuilder, TypeClass,
3131
};
3232
use log::warn;
3333
use pdb::Error::UnimplementedTypeKind;
@@ -136,7 +136,7 @@ pub struct ParsedMemberFunction {
136136
#[derive(Debug, Clone)]
137137
pub struct VirtualBaseClass {
138138
/// Base class name
139-
pub base_name: QualifiedName,
139+
pub base_name: String,
140140
/// Base class type
141141
pub base_type: Ref<Type>,
142142
/// Offset in this class where the base's fields are located
@@ -153,7 +153,7 @@ pub enum ParsedType {
153153
/// No info other than type data
154154
Bare(Ref<Type>),
155155
/// Named fully parsed class/enum/union/etc type
156-
Named(QualifiedName, Ref<Type>),
156+
Named(String, Ref<Type>),
157157
/// Function procedure
158158
Procedure(ParsedProcedureType),
159159
/// Bitfield entries
@@ -163,7 +163,7 @@ pub enum ParsedType {
163163
/// One member in a structure/union
164164
Member(ParsedMember),
165165
/// Base class name and offset details
166-
BaseClass(QualifiedName, StructureMember),
166+
BaseClass(String, StructureMember),
167167
/// One member in an enumeration
168168
Enumerate(EnumerationMember),
169169
/// List of arguments to a function
@@ -352,7 +352,8 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
352352
let name = ty
353353
.get_named_type_reference()
354354
.ok_or(anyhow!("expected ntr"))?
355-
.name();
355+
.name()
356+
.to_string();
356357
if Self::is_name_anonymous(&name) {
357358
continue;
358359
}
@@ -405,9 +406,8 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
405406

406407
// Cleanup a couple builtin names
407408
for &name in BUILTIN_NAMES {
408-
let builtin_qualified_name = QualifiedName::from(name);
409-
if self.named_types.contains_key(&builtin_qualified_name) {
410-
self.named_types.remove(&builtin_qualified_name);
409+
if self.named_types.contains_key(name) {
410+
self.named_types.remove(name);
411411
self.log(|| format!("Remove builtin type {}", name));
412412
}
413413
}
@@ -742,7 +742,7 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
742742
self.log(|| format!("Got Class type: {:x?}", data));
743743

744744
let raw_class_name = data.name.to_string();
745-
let class_name = QualifiedName::from(raw_class_name);
745+
let class_name = raw_class_name.to_string();
746746

747747
self.log(|| format!("Named: {}", class_name));
748748

@@ -776,7 +776,7 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
776776
structure.packed(data.properties.packed());
777777

778778
if let Some(fields) = data.fields {
779-
self.namespace_stack.push(class_name.to_string());
779+
self.namespace_stack.push(class_name.clone());
780780
let success = self.parse_structure_fields(&mut structure, fields, finder);
781781
self.namespace_stack.pop();
782782
let _ = success?;
@@ -852,7 +852,6 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
852852
&format!(
853853
"`{}`",
854854
self.namespace_stack
855-
.items
856855
.last()
857856
.ok_or_else(|| anyhow!("Expected class in ns stack"))?
858857
),
@@ -925,7 +924,6 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
925924
warn!(
926925
"Class `{}` uses virtual inheritance. Type information may be inaccurate.",
927926
self.namespace_stack
928-
.items
929927
.last()
930928
.ok_or_else(|| anyhow!("Expected class in ns stack"))?
931929
);
@@ -938,7 +936,6 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
938936
warn!(
939937
"Class `{}` has multiple base classes. Type information may be inaccurate.",
940938
self.namespace_stack
941-
.items
942939
.last()
943940
.ok_or_else(|| anyhow!("Expected class in ns stack"))?
944941
);
@@ -957,8 +954,7 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
957954
for base_class in &base_classes {
958955
match base_class {
959956
ParsedType::BaseClass(base_name, _base_type) => {
960-
let mut vt_base_name = base_name.clone();
961-
vt_base_name.items.push("VTable".to_string());
957+
let vt_base_name = format!("{}::VTable", base_name);
962958

963959
match self.named_types.get(&vt_base_name) {
964960
Some(vt_base_type)
@@ -1034,8 +1030,8 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
10341030
return Err(anyhow!("Expected class in ns stack"));
10351031
}
10361032

1037-
let mut vt_name = self.namespace_stack.clone();
1038-
vt_name.items.push("VTable".to_string());
1033+
let class_name = self.namespace_stack.last().cloned().unwrap_or_default();
1034+
let vt_name = format!("{}::VTable", class_name);
10391035
self.named_types.insert(vt_name.clone(), vt_type.clone());
10401036

10411037
let vt_pointer = Type::pointer(
@@ -1268,9 +1264,12 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
12681264
) -> Result<Option<Box<ParsedType>>> {
12691265
self.log(|| format!("Got Nested type: {:x?}", data));
12701266
let mut class_name_ns = self.namespace_stack.clone();
1271-
class_name_ns.push(data.name.to_string().into());
1267+
class_name_ns.push(data.name.to_string().to_string());
12721268
let ty = self.type_index_to_bare(data.nested_type, finder, false)?;
1273-
Ok(Some(Box::new(ParsedType::Named(class_name_ns, ty))))
1269+
Ok(Some(Box::new(ParsedType::Named(
1270+
class_name_ns.join("::"),
1271+
ty,
1272+
))))
12741273
}
12751274

12761275
fn handle_base_class_type(
@@ -1289,15 +1288,16 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
12891288
let name = t
12901289
.get_named_type_reference()
12911290
.ok_or(anyhow!("Expected NTR to have NTR"))?
1292-
.name();
1291+
.name()
1292+
.to_string();
12931293
(name, t.clone())
12941294
}
12951295
e => return Err(anyhow!("Unexpected base class type: {:x?}", e)),
12961296
};
12971297

12981298
// Try to resolve the full base type
12991299
let resolved_type = match self.try_type_index_to_bare(data.base_class, finder, true)? {
1300-
Some(ty) => Type::named_type_from_type(member_name.clone(), ty.as_ref()),
1300+
Some(ty) => Type::named_type_from_type(&member_name, ty.as_ref()),
13011301
None => t.clone(),
13021302
};
13031303

@@ -1313,7 +1313,7 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
13131313
member_name.clone(),
13141314
StructureMember::new(
13151315
Conf::new(resolved_type, MAX_CONFIDENCE),
1316-
member_name.to_string(),
1316+
member_name,
13171317
base_offset as u64,
13181318
access,
13191319
scope,
@@ -1334,7 +1334,8 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
13341334
let name = t
13351335
.get_named_type_reference()
13361336
.ok_or(anyhow!("Expected NTR to have NTR"))?
1337-
.name();
1337+
.name()
1338+
.to_string();
13381339
(name, t.clone())
13391340
}
13401341
e => return Err(anyhow!("Unexpected base class type: {:x?}", e)),
@@ -1523,7 +1524,7 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
15231524
self.log(|| format!("Got Enumeration type: {:x?}", data));
15241525

15251526
let raw_enum_name = data.name.to_string();
1526-
let enum_name = QualifiedName::from(raw_enum_name);
1527+
let enum_name = raw_enum_name.to_string();
15271528
self.log(|| format!("Named: {}", enum_name));
15281529

15291530
if data.properties.forward_reference() {
@@ -1651,7 +1652,7 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
16511652
self.log(|| format!("Got Union type: {:x?}", data));
16521653

16531654
let raw_union_name = data.name.to_string();
1654-
let union_name = QualifiedName::from(raw_union_name);
1655+
let union_name = raw_union_name.to_string();
16551656
self.log(|| format!("Named: {}", union_name));
16561657

16571658
if data.properties.forward_reference() {
@@ -1908,7 +1909,8 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
19081909
let name = type_
19091910
.get_named_type_reference()
19101911
.ok_or(anyhow!("expected ntr"))?
1911-
.name();
1912+
.name()
1913+
.to_string();
19121914
if let Some(full_ntr) = self.named_types.get(&name) {
19131915
type_ = Type::named_type_from_type(name, full_ntr.as_ref());
19141916
}
@@ -1955,7 +1957,8 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
19551957
let name = type_
19561958
.get_named_type_reference()
19571959
.ok_or(anyhow!("expected ntr"))?
1958-
.name();
1960+
.name()
1961+
.to_string();
19591962
if Self::is_name_anonymous(&name) {
19601963
if let Some(inner) = inner.as_ref() {
19611964
type_ = inner.clone();
@@ -1992,8 +1995,8 @@ impl<'a, S: Source<'a> + 'a> PDBParserInstance<'a, S> {
19921995
}
19931996

19941997
/// Is this name one of the stupid microsoft unnamed type names
1995-
fn is_name_anonymous(name: &QualifiedName) -> bool {
1996-
match name.items.last() {
1998+
fn is_name_anonymous(name: &String) -> bool {
1999+
match name.split("::").last() {
19972000
Some(item) if item == "<anonymous-tag>" => true,
19982001
Some(item) if item.contains("<unnamed-") => true,
19992002
_ => false,

0 commit comments

Comments
 (0)