Skip to content

Commit 7034a4f

Browse files
authored
Added support for local and thread local guard scopes (#50)
1 parent 2f05c5c commit 7034a4f

File tree

3 files changed

+78
-29
lines changed

3 files changed

+78
-29
lines changed

src/lib.rs

Lines changed: 53 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,6 @@ bitflags! {
241241
// The kind of variable storage. In LLVM this is called storage class.
242242
#[derive(Clone, Copy, Debug, PartialEq)]
243243
pub enum VarStorageKind {
244-
None,
245244
PrivateStatic,
246245
ProtectedStatic,
247246
PublicStatic,
@@ -328,7 +327,7 @@ pub enum Operator<'a> {
328327
VBTable,
329328
VCall,
330329
Typeof,
331-
LocalStaticGuard,
330+
LocalStaticGuard(Option<u32>),
332331
String,
333332
VBaseDtor,
334333
VectorDeletingDtor,
@@ -361,7 +360,7 @@ pub enum Operator<'a> {
361360

362361
DynamicInitializer,
363362
DynamicAtexitDtor,
364-
LocalStaticThreadGuard,
363+
LocalStaticThreadGuard(Option<u32>),
365364
}
366365

367366
#[derive(Clone, Debug, PartialEq)]
@@ -520,19 +519,38 @@ impl<'a> ParserState<'a> {
520519

521520
// What follows is a main symbol name. This may include
522521
// namespaces or class names.
523-
let symbol = self.read_name(true)?;
522+
let mut symbol = self.read_name(true)?;
523+
524+
// Special case for some weird cases where extra data is tacked on
525+
// after the main symbol but belongs into the symbol.
526+
match symbol.name {
527+
Name::Operator(Operator::LocalStaticGuard(ref mut scope_index))
528+
| Name::Operator(Operator::LocalStaticThreadGuard(ref mut scope_index)) => {
529+
let _is_visible = if self.consume(b"4IA") {
530+
false
531+
} else if self.consume(b"5") {
532+
true
533+
} else {
534+
return Err(self.fail("unexpected local guard marker"));
535+
};
536+
if !self.remaining.is_empty() {
537+
*scope_index = Some(self.read_unsigned()?);
538+
};
539+
}
540+
_ => {}
541+
}
524542

525543
if let Ok(c) = self.get() {
526544
let symbol_type = match c {
527-
b'0'...b'5' => {
545+
b'0'...b'4' => {
528546
// Read a variable.
529547
let kind = match c {
530548
b'0' => VarStorageKind::PrivateStatic,
531549
b'1' => VarStorageKind::ProtectedStatic,
532550
b'2' => VarStorageKind::PublicStatic,
533551
b'3' => VarStorageKind::Global,
534552
b'4' => VarStorageKind::FunctionLocalStatic,
535-
_ => VarStorageKind::None,
553+
_ => unreachable!(),
536554
};
537555
let ty = self.read_var_type(StorageClass::empty())?;
538556
let sc = self.read_storage_class();
@@ -786,6 +804,14 @@ impl<'a> ParserState<'a> {
786804
Err(self.fail("bad number"))
787805
}
788806

807+
fn read_unsigned(&mut self) -> Result<u32> {
808+
let num = self.read_number()?;
809+
if num < 0 {
810+
return Err(self.fail("expected unsigned"));
811+
}
812+
Ok(num as u32)
813+
}
814+
789815
// Read until the next b'@'.
790816
fn read_string(&mut self) -> Result<&'a [u8]> {
791817
if let Some(pos) = self.remaining.iter().position(|&x| x == b'@') {
@@ -877,8 +903,7 @@ impl<'a> ParserState<'a> {
877903
}
878904
name
879905
} else if self.consume(b"?") {
880-
// Overloaded operator.
881-
self.read_operator()?
906+
self.read_special_name()?
882907
} else {
883908
// Non-template functions or classes.
884909
let name = self.read_string()?;
@@ -926,12 +951,8 @@ impl<'a> ParserState<'a> {
926951
))
927952
}
928953

929-
fn read_operator(&mut self) -> Result<Name<'a>> {
930-
Ok(Name::Operator(self.read_operator_name()?))
931-
}
932-
933-
fn read_operator_name(&mut self) -> Result<Operator<'a>> {
934-
Ok(match self.get()? {
954+
fn read_special_name(&mut self) -> Result<Name<'a>> {
955+
Ok(Name::Operator(match self.get()? {
935956
b'0' => Operator::Ctor,
936957
b'1' => Operator::Dtor,
937958
b'2' => Operator::New,
@@ -980,7 +1001,7 @@ impl<'a> ParserState<'a> {
9801001
b'8' => Operator::VBTable,
9811002
b'9' => Operator::VCall,
9821003
b'A' => Operator::Typeof,
983-
b'B' => Operator::LocalStaticGuard,
1004+
b'B' => Operator::LocalStaticGuard(None),
9841005
b'C' => Operator::String,
9851006
b'D' => Operator::VBaseDtor,
9861007
b'E' => Operator::VectorDeletingDtor,
@@ -1037,7 +1058,7 @@ impl<'a> ParserState<'a> {
10371058
} else if self.consume(b"F") {
10381059
Operator::DynamicAtexitDtor
10391060
} else if self.consume(b"J") {
1040-
Operator::LocalStaticThreadGuard
1061+
Operator::LocalStaticThreadGuard(None)
10411062
} else if self.consume(b"K") {
10421063
Operator::LiteralOperatorName // TODO: read <source-name>, that's the operator name
10431064
} else {
@@ -1051,7 +1072,7 @@ impl<'a> ParserState<'a> {
10511072
_ => {
10521073
return Err(self.fail("unknown operator name"));
10531074
}
1054-
})
1075+
}))
10551076
}
10561077

10571078
fn read_func_class(&mut self, c: u8) -> Result<FuncClass> {
@@ -1652,9 +1673,7 @@ impl<'a> Serializer<'a> {
16521673
VarStorageKind::PrivateStatic => write!(self.w, "private: static ")?,
16531674
VarStorageKind::ProtectedStatic => write!(self.w, "protected: static ")?,
16541675
VarStorageKind::PublicStatic => write!(self.w, "public: static ")?,
1655-
VarStorageKind::Global
1656-
| VarStorageKind::FunctionLocalStatic
1657-
| VarStorageKind::None => {}
1676+
VarStorageKind::Global | VarStorageKind::FunctionLocalStatic => {}
16581677
}
16591678
self.write_pre(inner)?;
16601679
sc
@@ -1994,7 +2013,13 @@ impl<'a> Serializer<'a> {
19942013
Operator::VBTable => "`vbtable'",
19952014
Operator::VCall => "`vcall'",
19962015
Operator::Typeof => "`typeof'",
1997-
Operator::LocalStaticGuard => "`local static guard'",
2016+
Operator::LocalStaticGuard(scope) => {
2017+
write!(self.w, "`local static guard'")?;
2018+
if let Some(scope) = scope {
2019+
write!(self.w, "{{{}}}", scope)?;
2020+
}
2021+
return Ok(());
2022+
}
19982023
Operator::String => "`string'",
19992024
Operator::VBaseDtor => "`vbase destructor'",
20002025
Operator::VectorDeletingDtor => "`vector deleting destructor'",
@@ -2045,7 +2070,13 @@ impl<'a> Serializer<'a> {
20452070

20462071
Operator::DynamicInitializer => "`dynamic initializer'",
20472072
Operator::DynamicAtexitDtor => "`dynamic atexit destructor'",
2048-
Operator::LocalStaticThreadGuard => "`local static thread guard'",
2073+
Operator::LocalStaticThreadGuard(scope) => {
2074+
write!(self.w, "`local static thread guard'")?;
2075+
if let Some(scope) = scope {
2076+
write!(self.w, "{{{}}}", scope)?;
2077+
}
2078+
return Ok(());
2079+
}
20492080
};
20502081
write!(self.w, "{}", s)?;
20512082
Ok(())

tests/llvm-cases/ms-operators.test

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,8 @@
149149
??_9Base@@$B7AA
150150
; CHECK: [thunk]: __cdecl Base::`vcall'{8, {flat}}
151151

152-
; TODO(mitsuhiko): currently broken (invalid backreference)
153-
;??_B?1??getS@@YAAAUS@@XZ@51
154-
;; CHECK: `struct S & __cdecl getS(void)'::`2'::`local static guard'{2}
152+
??_B?1??getS@@YAAAUS@@XZ@51
153+
; CHECK: `struct S & __cdecl getS(void)'::`2'::`local static guard'{2}
155154

156155
; TODO(mitsuhiko): currently broken because no string decoding
157156
;??_C@_02PCEFGMJL@hi?$AA@
@@ -247,9 +246,8 @@
247246
;; CHECK: void __cdecl `dynamic atexit destructor for `private: static class std::vector<class antlr4::dfa::DFA, class std::allocator<class antlr4::dfa::DFA>> XPathLexer::_decisionToDFA''(void)
248247
; CHECK: private: static class std::vector<class antlr4::dfa::DFA, class std::allocator<class antlr4::dfa::DFA> > XPathLexer::_decisionToDFA::`dynamic atexit destructor'
249248

250-
;??__J?1??f@@YAAAUS@@XZ@51
251-
; TODO(mitsuhiko): completely broken (bad backref)
252-
;; CHECK: `struct S & __cdecl f(void)'::`2'::`local static thread guard'{2}
249+
??__J?1??f@@YAAAUS@@XZ@51
250+
; CHECK: `struct S & __cdecl f(void)'::`2'::`local static thread guard'{2}
253251

254252
??__K_deg@@YAHO@Z
255253
; CHECK: int __cdecl operator ""_deg(long double)

tests/test_basics.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -828,5 +828,25 @@ fn upstream_tests() {
828828
expect(
829829
"??__FFLASH_TEMP_FILENAME@sandboxing@mozilla@@YAXXZ",
830830
"void __cdecl mozilla::sandboxing::FLASH_TEMP_FILENAME::`dynamic atexit destructor'(void)",
831-
)
831+
);
832+
expect(
833+
"??__J?1??f@@YAAAUS@@XZ@5BB@",
834+
"`struct S & __cdecl f(void)'::`2'::`local static thread guard'{17}",
835+
);
836+
expect(
837+
"??__J?@??f@@YAAAUS@@XZ@5BB@",
838+
"`struct S & __cdecl f(void)'::`0'::`local static thread guard'{17}",
839+
);
840+
expect(
841+
"??__J?A@??f@@YAAAUS@@XZ@5BB@",
842+
"`struct S & __cdecl f(void)'::`anonymous namespace'::`local static thread guard'{17}",
843+
);
844+
expect(
845+
"??__J?B@??f@@YAAAUS@@XZ@5BB@",
846+
"`struct S & __cdecl f(void)'::`1'::`local static thread guard'{17}",
847+
);
848+
expect(
849+
"??__J?@??f@@YAAAUS@@XZ@5BB@",
850+
"`struct S & __cdecl f(void)'::`0'::`local static thread guard'{17}",
851+
);
832852
}

0 commit comments

Comments
 (0)