Skip to content

Commit 2ea4b1c

Browse files
Swatinemmstange
authored andcommitted
fix: Parse MD5 mangled names
They are parsed correctly, but just returned as their mangled form.
1 parent 4e70e78 commit 2ea4b1c

File tree

2 files changed

+47
-1
lines changed

2 files changed

+47
-1
lines changed

src/lib.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ pub enum VarStorageKind {
255255
// Represents an identifier which may be a template.
256256
#[derive(Clone, PartialEq)]
257257
pub enum Name<'a> {
258+
Md5(&'a [u8]),
258259
Operator(Operator<'a>),
259260
NonTemplate(&'a [u8]),
260261
AsInterface(&'a [u8]),
@@ -267,6 +268,10 @@ pub enum Name<'a> {
267268
impl<'a> fmt::Debug for Name<'a> {
268269
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
269270
match *self {
271+
Name::Md5(s) => f
272+
.debug_tuple("Md5")
273+
.field(&String::from_utf8_lossy(s))
274+
.finish(),
270275
Name::Operator(ref op) => f.debug_tuple("Operator").field(&op).finish(),
271276
Name::NonTemplate(s) => f
272277
.debug_tuple("NonTemplate")
@@ -500,6 +505,17 @@ impl<'a> ParserState<'a> {
500505
return Err(self.fail("does not start with b'?'"));
501506
}
502507

508+
if self.consume(b"?@") {
509+
let name = self.read_md5_name()?;
510+
return Ok(ParseResult {
511+
symbol: Symbol {
512+
name,
513+
scope: NameSequence { names: Vec::new() },
514+
},
515+
symbol_type: Type::None,
516+
});
517+
}
518+
503519
if self.consume(b"$") {
504520
if self.consume(b"TSS") {
505521
let mut guard_num: i32 = i32::from(
@@ -687,6 +703,21 @@ impl<'a> ParserState<'a> {
687703
}
688704
}
689705

706+
/// An MD5 mangled name is `??@` followed by 32 characters and a terminating `@`.
707+
///
708+
/// See https://github.com/llvm/llvm-project/blob/818cf30b83305fa4a2f75821349210b0f7aff4a4/llvm/lib/Demangle/MicrosoftDemangle.cpp#L754
709+
fn read_md5_name(&mut self) -> Result<Name<'a>> {
710+
let start_offset = self.offset;
711+
712+
while self.read_hex_digit().is_some() {}
713+
let end_offset = self.offset;
714+
715+
if self.offset - start_offset != 32 || !self.consume(b"@") {
716+
return Err(self.fail("expected MD5 mangled name of length 32"));
717+
}
718+
Ok(Name::Md5(&self.input.as_bytes()[start_offset..end_offset]))
719+
}
720+
690721
fn read_digit(&mut self) -> Option<u8> {
691722
match self.peek() {
692723
Some(first) => {
@@ -2180,6 +2211,11 @@ impl<'a> Serializer<'a> {
21802211

21812212
fn write_one_name(&mut self, name: &Name) -> Result<()> {
21822213
match *name {
2214+
Name::Md5(ref name) => {
2215+
write!(self.w, "??@")?;
2216+
self.w.write_all(name)?;
2217+
write!(self.w, "@")?;
2218+
}
21832219
Name::Operator(ref op) => {
21842220
self.write_space()?;
21852221
self.write_operator_name(op)?;
@@ -2244,6 +2280,11 @@ impl<'a> Serializer<'a> {
22442280
}
22452281

22462282
match names.name {
2283+
Name::Md5(ref name) => {
2284+
write!(self.w, "??@")?;
2285+
self.w.write_all(name)?;
2286+
write!(self.w, "@")?;
2287+
}
22472288
Name::Operator(ref op) => {
22482289
match *op {
22492290
Operator::Ctor => {

tests/test_basics.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,12 @@ fn other_tests() {
184184

185185
expect(
186186
"?Present1@?QIDXGISwapChain4@@CDXGISwapChain@@UAGJIIPBUDXGI_PRESENT_PARAMETERS@@@Z",
187-
"public: virtual long __stdcall CDXGISwapChain::[IDXGISwapChain4]::Present1(unsigned int,unsigned int,struct DXGI_PRESENT_PARAMETERS const *)"
187+
"public: virtual long __stdcall CDXGISwapChain::[IDXGISwapChain4]::Present1(unsigned int,unsigned int,struct DXGI_PRESENT_PARAMETERS const *)");
188+
189+
// An MD5 mangled name is "valid" but output as-is
190+
expect(
191+
"??@8ba8d245c9eca390356129098dbe9f73@",
192+
"??@8ba8d245c9eca390356129098dbe9f73@",
188193
);
189194
}
190195

0 commit comments

Comments
 (0)