Skip to content

Commit 16b2b58

Browse files
authored
fix(debuginfo): Detect mangled anonymous namespaces in PDB inlinees (#261)
ID records specify the mangled format for anonymous namespaces: `?A0x<id>`, where `id` is a hex identifier of the namespace. Demanglers usually resolve this as "anonymous namespace". This also fixes an issue with demangling: If the anonymous namespace is in the beginning of the composed name, it leads the demangler to believe that this is a mangled MSVC name. However, since this is a composed demangled name, this leads to a demangle error.
1 parent 7b319e4 commit 16b2b58

File tree

5 files changed

+59
-5
lines changed

5 files changed

+59
-5
lines changed

debuginfo/src/pdb.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,15 @@ impl DebugSession for PdbDebugSession<'_> {
634634
}
635635
}
636636

637+
/// Checks whether the given name declares an anonymous namespace.
638+
///
639+
/// ID records specify the mangled format for anonymous namespaces: `?A0x<id>`, where `id` is a hex
640+
/// identifier of the namespace. Demanglers usually resolve this as "anonymous namespace".
641+
fn is_anonymous_namespace(name: &str) -> bool {
642+
name.strip_prefix("?A0x")
643+
.map_or(false, |rest| u32::from_str_radix(rest, 16).is_ok())
644+
}
645+
637646
/// Formatter for function types.
638647
///
639648
/// This formatter currently only contains the minimum implementation requried to format inline
@@ -693,7 +702,13 @@ impl<'u, 'd> TypeFormatter<'u, 'd> {
693702
write!(target, "\"")?;
694703
}
695704
Ok(pdb::IdData::String(data)) => {
696-
write!(target, "{}", data.name.to_string())?;
705+
let mut string = data.name.to_string();
706+
707+
if is_anonymous_namespace(&string) {
708+
string = Cow::Borrowed("`anonymous namespace'");
709+
}
710+
711+
write!(target, "{}", string)?;
697712
}
698713
Ok(pdb::IdData::UserDefinedTypeSource(_)) => {
699714
// nothing to do.

debuginfo/tests/test_objects.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,3 +445,29 @@ fn test_pdb_functions() -> Result<(), Error> {
445445

446446
Ok(())
447447
}
448+
449+
#[test]
450+
fn test_pdb_anonymous_namespace() -> Result<(), Error> {
451+
// Regression test for ?A0x<hash> namespaces
452+
453+
let view = ByteView::open(fixture("windows/crash.pdb"))?;
454+
let object = Object::parse(&view)?;
455+
456+
let session = object.debug_session()?;
457+
let main_function = session
458+
.functions()
459+
.filter_map(|f| f.ok())
460+
.find(|f| f.address == 0x2910)
461+
.expect("main function at 0x2910");
462+
463+
let start_function = main_function
464+
.inlinees
465+
.iter()
466+
.find(|f| f.address == 0x2a3d)
467+
.expect("start function at 0x2a3d");
468+
469+
// was: "?A0xc3a0617d::start"
470+
assert_eq!(start_function.name, "`anonymous namespace'::start");
471+
472+
Ok(())
473+
}

py/symbolic/debuginfo.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,10 @@ def make_cficache(self):
138138
)
139139

140140
def __repr__(self):
141-
return "<Object %s %r>" % (self.debug_id, self.arch,)
141+
return "<Object %s %r>" % (
142+
self.debug_id,
143+
self.arch,
144+
)
142145

143146

144147
class ObjectRef(object):
@@ -165,7 +168,10 @@ def __init__(self, data):
165168
self.name = self.code_file
166169

167170
def __repr__(self):
168-
return "<ObjectRef %s %r>" % (self.debug_id, self.arch,)
171+
return "<ObjectRef %s %r>" % (
172+
self.debug_id,
173+
self.arch,
174+
)
169175

170176

171177
class ObjectLookup(object):

py/symbolic/sourcemap.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ def __ne__(self, other):
5151
return not self.__eq__(other)
5252

5353
def __repr__(self):
54-
return "<SourceMapTokenMatch %s:%d>" % (self.src, self.src_line,)
54+
return "<SourceMapTokenMatch %s:%d>" % (
55+
self.src,
56+
self.src_line,
57+
)
5558

5659

5760
class SourceView(RustObject):

py/symbolic/symcache.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,11 @@ def rel_path(self):
7373
return strip_common_path_prefix(self.abs_path, self.comp_dir)
7474

7575
def __str__(self):
76-
return "%s:%s (%s)" % (self.function_name, self.line, self.rel_path,)
76+
return "%s:%s (%s)" % (
77+
self.function_name,
78+
self.line,
79+
self.rel_path,
80+
)
7781

7882
def __repr__(self):
7983
return "LineInfo(%s)" % (

0 commit comments

Comments
 (0)