[MS Demangler] Support extern "C" functions.
authorZachary Turner <zturner@google.com>
Fri, 10 Aug 2018 21:09:05 +0000 (21:09 +0000)
committerZachary Turner <zturner@google.com>
Fri, 10 Aug 2018 21:09:05 +0000 (21:09 +0000)
There are two cases we need to support with extern "C"
functions.  The first is the case of a '9' indicating that
the function has no prototype.  This occurs when we mangle
a symbol inside of an extern "C" function, but not the
function itself.

The second case is when we have an overloaded extern "C"
functions.  In this case we emit $$J0 to indicate this.
This patch adds support for both of these cases.

llvm-svn: 339471

llvm/lib/Demangle/MicrosoftDemangle.cpp
llvm/test/Demangle/ms-mangle.test

index d9aed6499fbd82c780a20a50feb91b19b3f0f896..cab662f98e8c1596b15a087e22300a5310d9ade9 100644 (file)
@@ -195,7 +195,7 @@ enum class PrimTy : uint8_t {
 };
 
 // Function classes
-enum FuncClass : uint8_t {
+enum FuncClass : uint16_t {
   Public = 1 << 0,
   Protected = 1 << 1,
   Private = 1 << 2,
@@ -203,6 +203,8 @@ enum FuncClass : uint8_t {
   Static = 1 << 4,
   Virtual = 1 << 5,
   Far = 1 << 6,
+  ExternC = 1 << 7,
+  NoPrototype = 1 << 8,
 };
 
 enum NameBackrefBehavior : uint8_t {
@@ -833,6 +835,9 @@ void FunctionType::outputPre(OutputStream &OS, NameResolver &Resolver) {
     if (FunctionClass & Static)
       OS << "static ";
   }
+  if (FunctionClass & ExternC) {
+    OS << "extern \"C\" ";
+  }
 
   if (ReturnType) {
     Type::outputPre(OS, *ReturnType, Resolver);
@@ -847,6 +852,10 @@ void FunctionType::outputPre(OutputStream &OS, NameResolver &Resolver) {
 }
 
 void FunctionType::outputPost(OutputStream &OS, NameResolver &Resolver) {
+  // extern "C" functions don't have a prototype.
+  if (FunctionClass & NoPrototype)
+    return;
+
   OS << "(";
   outputParameterList(OS, Params, Resolver);
   OS << ")";
@@ -1059,7 +1068,9 @@ Symbol *Demangler::parse(StringView &MangledName) {
   if (Error)
     return nullptr;
   // Read a variable.
-  if (startsWithDigit(MangledName)) {
+  if (startsWithDigit(MangledName) && !MangledName.startsWith('9')) {
+    // 9 is a special marker for an extern "C" function with
+    // no prototype.
     S->Category = SymbolCategory::Variable;
     S->SymbolType = demangleVariableEncoding(MangledName);
   } else {
@@ -1517,47 +1528,53 @@ FuncClass Demangler::demangleFunctionClass(StringView &MangledName) {
   SwapAndRestore<StringView> RestoreOnError(MangledName, MangledName);
   RestoreOnError.shouldRestore(false);
 
+  FuncClass TempFlags = FuncClass(0);
+  if (MangledName.consumeFront("$$J0"))
+    TempFlags = ExternC;
+
   switch (MangledName.popFront()) {
+  case '9':
+    return FuncClass(TempFlags | ExternC | NoPrototype);
   case 'A':
     return Private;
   case 'B':
-    return FuncClass(Private | Far);
+    return FuncClass(TempFlags | Private | Far);
   case 'C':
-    return FuncClass(Private | Static);
+    return FuncClass(TempFlags | Private | Static);
   case 'D':
-    return FuncClass(Private | Static);
+    return FuncClass(TempFlags | Private | Static);
   case 'E':
-    return FuncClass(Private | Virtual);
+    return FuncClass(TempFlags | Private | Virtual);
   case 'F':
-    return FuncClass(Private | Virtual);
+    return FuncClass(TempFlags | Private | Virtual);
   case 'I':
-    return Protected;
+    return FuncClass(TempFlags | Protected);
   case 'J':
-    return FuncClass(Protected | Far);
+    return FuncClass(TempFlags | Protected | Far);
   case 'K':
-    return FuncClass(Protected | Static);
+    return FuncClass(TempFlags | Protected | Static);
   case 'L':
-    return FuncClass(Protected | Static | Far);
+    return FuncClass(TempFlags | Protected | Static | Far);
   case 'M':
-    return FuncClass(Protected | Virtual);
+    return FuncClass(TempFlags | Protected | Virtual);
   case 'N':
-    return FuncClass(Protected | Virtual | Far);
+    return FuncClass(TempFlags | Protected | Virtual | Far);
   case 'Q':
-    return Public;
+    return FuncClass(TempFlags | Public);
   case 'R':
-    return FuncClass(Public | Far);
+    return FuncClass(TempFlags | Public | Far);
   case 'S':
-    return FuncClass(Public | Static);
+    return FuncClass(TempFlags | Public | Static);
   case 'T':
-    return FuncClass(Public | Static | Far);
+    return FuncClass(TempFlags | Public | Static | Far);
   case 'U':
-    return FuncClass(Public | Virtual);
+    return FuncClass(TempFlags | Public | Virtual);
   case 'V':
-    return FuncClass(Public | Virtual | Far);
+    return FuncClass(TempFlags | Public | Virtual | Far);
   case 'Y':
-    return Global;
+    return FuncClass(TempFlags | Global);
   case 'Z':
-    return FuncClass(Global | Far);
+    return FuncClass(TempFlags | Global | Far);
   }
 
   Error = true;
@@ -1768,9 +1785,16 @@ FunctionType *Demangler::demangleFunctionType(StringView &MangledName,
 
 Type *Demangler::demangleFunctionEncoding(StringView &MangledName) {
   FuncClass FC = demangleFunctionClass(MangledName);
-
-  bool HasThisQuals = !(FC & (Global | Static));
-  FunctionType *FTy = demangleFunctionType(MangledName, HasThisQuals, false);
+  FunctionType *FTy = nullptr;
+  if (FC & NoPrototype) {
+    // This is an extern "C" function whose full signature hasn't been mangled.
+    // This happens when we need to mangle a local symbol inside of an extern
+    // "C" function.
+    FTy = Arena.alloc<FunctionType>();
+  } else {
+    bool HasThisQuals = !(FC & (Global | Static));
+    FTy = demangleFunctionType(MangledName, HasThisQuals, false);
+  }
   FTy->FunctionClass = FC;
 
   return FTy;
index 981f557a2075c88d05030617f3d94e2e5aa00eea..b3fe67f4759e09d22a5ab1623d78266492cbdda0 100644 (file)
 ?s6@PR13182@@3PBQBDB
 ; CHECK: char const *const *PR13182::s6
 
-; FIXME: We don't properly support extern "C" functions yet.
-; ?local@?1??extern_c_func@@9@4HA
-; FIXME: int `extern_c_func'::`2'::local
+?local@?1??extern_c_func@@9@4HA
+; CHECK: int `extern "C" extern_c_func'::`2'::local
 
-?local@?1??extern_c_func@@9@4HA
-; FIXME: int `extern_c_func'::`2'::local
+?local@?1??extern_c_func@@9@4HA
+; CHECK: int `extern "C" extern_c_func'::`2'::local
 
 ?v@?1??f@@YAHXZ@4U<unnamed-type-v>@?1??1@YAHXZ@A
 ; CHECK: struct `int __cdecl f(void)'::`2'::<unnamed-type-v> `int __cdecl f(void)'::`2'::v
 ?vector_func@@YQXXZ
 ; CHECK: void __vectorcall vector_func(void)
 
-; FIXME: We don't support extern C funcs currently.
-; ??$fn_tmpl@$1?extern_c_func@@YAXXZ@@YAXXZ
-; FIXME: void __cdecl fn_tmpl<&void __cdecl extern_c_func(void)>(void)
+??$fn_tmpl@$1?extern_c_func@@YAXXZ@@YAXXZ
+; CHECK: void __cdecl fn_tmpl<&void __cdecl extern_c_func(void)>(void)
 
-?overloaded_fn@@$$J0YAXXZ
-; FIXME-EXTERNC: extern \"C\" void __cdecl overloaded_fn(void)
+?overloaded_fn@@$$J0YAXXZ
+; CHECK: extern "C" void __cdecl overloaded_fn(void)
 
 ?f@UnnamedType@@YAXQAPAU<unnamed-type-T1>@S@1@@Z
 ; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::S::<unnamed-type-T1> **const)