[MS Demangler] Support extern "C" functions.

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
This commit is contained in:
Zachary Turner 2018-08-10 21:09:05 +00:00
parent 66a39d919b
commit f5224914dd
2 changed files with 56 additions and 34 deletions

View File

@ -195,7 +195,7 @@ enum class PrimTy : uint8_t {
}; };
// Function classes // Function classes
enum FuncClass : uint8_t { enum FuncClass : uint16_t {
Public = 1 << 0, Public = 1 << 0,
Protected = 1 << 1, Protected = 1 << 1,
Private = 1 << 2, Private = 1 << 2,
@ -203,6 +203,8 @@ enum FuncClass : uint8_t {
Static = 1 << 4, Static = 1 << 4,
Virtual = 1 << 5, Virtual = 1 << 5,
Far = 1 << 6, Far = 1 << 6,
ExternC = 1 << 7,
NoPrototype = 1 << 8,
}; };
enum NameBackrefBehavior : uint8_t { enum NameBackrefBehavior : uint8_t {
@ -833,6 +835,9 @@ void FunctionType::outputPre(OutputStream &OS, NameResolver &Resolver) {
if (FunctionClass & Static) if (FunctionClass & Static)
OS << "static "; OS << "static ";
} }
if (FunctionClass & ExternC) {
OS << "extern \"C\" ";
}
if (ReturnType) { if (ReturnType) {
Type::outputPre(OS, *ReturnType, Resolver); Type::outputPre(OS, *ReturnType, Resolver);
@ -847,6 +852,10 @@ void FunctionType::outputPre(OutputStream &OS, NameResolver &Resolver) {
} }
void FunctionType::outputPost(OutputStream &OS, NameResolver &Resolver) { void FunctionType::outputPost(OutputStream &OS, NameResolver &Resolver) {
// extern "C" functions don't have a prototype.
if (FunctionClass & NoPrototype)
return;
OS << "("; OS << "(";
outputParameterList(OS, Params, Resolver); outputParameterList(OS, Params, Resolver);
OS << ")"; OS << ")";
@ -1059,7 +1068,9 @@ Symbol *Demangler::parse(StringView &MangledName) {
if (Error) if (Error)
return nullptr; return nullptr;
// Read a variable. // 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->Category = SymbolCategory::Variable;
S->SymbolType = demangleVariableEncoding(MangledName); S->SymbolType = demangleVariableEncoding(MangledName);
} else { } else {
@ -1517,47 +1528,53 @@ FuncClass Demangler::demangleFunctionClass(StringView &MangledName) {
SwapAndRestore<StringView> RestoreOnError(MangledName, MangledName); SwapAndRestore<StringView> RestoreOnError(MangledName, MangledName);
RestoreOnError.shouldRestore(false); RestoreOnError.shouldRestore(false);
FuncClass TempFlags = FuncClass(0);
if (MangledName.consumeFront("$$J0"))
TempFlags = ExternC;
switch (MangledName.popFront()) { switch (MangledName.popFront()) {
case '9':
return FuncClass(TempFlags | ExternC | NoPrototype);
case 'A': case 'A':
return Private; return Private;
case 'B': case 'B':
return FuncClass(Private | Far); return FuncClass(TempFlags | Private | Far);
case 'C': case 'C':
return FuncClass(Private | Static); return FuncClass(TempFlags | Private | Static);
case 'D': case 'D':
return FuncClass(Private | Static); return FuncClass(TempFlags | Private | Static);
case 'E': case 'E':
return FuncClass(Private | Virtual); return FuncClass(TempFlags | Private | Virtual);
case 'F': case 'F':
return FuncClass(Private | Virtual); return FuncClass(TempFlags | Private | Virtual);
case 'I': case 'I':
return Protected; return FuncClass(TempFlags | Protected);
case 'J': case 'J':
return FuncClass(Protected | Far); return FuncClass(TempFlags | Protected | Far);
case 'K': case 'K':
return FuncClass(Protected | Static); return FuncClass(TempFlags | Protected | Static);
case 'L': case 'L':
return FuncClass(Protected | Static | Far); return FuncClass(TempFlags | Protected | Static | Far);
case 'M': case 'M':
return FuncClass(Protected | Virtual); return FuncClass(TempFlags | Protected | Virtual);
case 'N': case 'N':
return FuncClass(Protected | Virtual | Far); return FuncClass(TempFlags | Protected | Virtual | Far);
case 'Q': case 'Q':
return Public; return FuncClass(TempFlags | Public);
case 'R': case 'R':
return FuncClass(Public | Far); return FuncClass(TempFlags | Public | Far);
case 'S': case 'S':
return FuncClass(Public | Static); return FuncClass(TempFlags | Public | Static);
case 'T': case 'T':
return FuncClass(Public | Static | Far); return FuncClass(TempFlags | Public | Static | Far);
case 'U': case 'U':
return FuncClass(Public | Virtual); return FuncClass(TempFlags | Public | Virtual);
case 'V': case 'V':
return FuncClass(Public | Virtual | Far); return FuncClass(TempFlags | Public | Virtual | Far);
case 'Y': case 'Y':
return Global; return FuncClass(TempFlags | Global);
case 'Z': case 'Z':
return FuncClass(Global | Far); return FuncClass(TempFlags | Global | Far);
} }
Error = true; Error = true;
@ -1768,9 +1785,16 @@ FunctionType *Demangler::demangleFunctionType(StringView &MangledName,
Type *Demangler::demangleFunctionEncoding(StringView &MangledName) { Type *Demangler::demangleFunctionEncoding(StringView &MangledName) {
FuncClass FC = demangleFunctionClass(MangledName); FuncClass FC = demangleFunctionClass(MangledName);
FunctionType *FTy = nullptr;
bool HasThisQuals = !(FC & (Global | Static)); if (FC & NoPrototype) {
FunctionType *FTy = demangleFunctionType(MangledName, HasThisQuals, false); // 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; FTy->FunctionClass = FC;
return FTy; return FTy;

View File

@ -268,12 +268,11 @@
?s6@PR13182@@3PBQBDB ?s6@PR13182@@3PBQBDB
; CHECK: char const *const *PR13182::s6 ; CHECK: char const *const *PR13182::s6
; FIXME: We don't properly support extern "C" functions yet. ?local@?1??extern_c_func@@9@4HA
; ?local@?1??extern_c_func@@9@4HA ; CHECK: int `extern "C" extern_c_func'::`2'::local
; FIXME: int `extern_c_func'::`2'::local
; ?local@?1??extern_c_func@@9@4HA ?local@?1??extern_c_func@@9@4HA
; FIXME: int `extern_c_func'::`2'::local ; CHECK: int `extern "C" extern_c_func'::`2'::local
?v@?1??f@@YAHXZ@4U<unnamed-type-v>@?1??1@YAHXZ@A ?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 ; CHECK: struct `int __cdecl f(void)'::`2'::<unnamed-type-v> `int __cdecl f(void)'::`2'::v
@ -331,12 +330,11 @@
?vector_func@@YQXXZ ?vector_func@@YQXXZ
; CHECK: void __vectorcall vector_func(void) ; CHECK: void __vectorcall vector_func(void)
; FIXME: We don't support extern C funcs currently. ??$fn_tmpl@$1?extern_c_func@@YAXXZ@@YAXXZ
; ??$fn_tmpl@$1?extern_c_func@@YAXXZ@@YAXXZ ; CHECK: void __cdecl fn_tmpl<&void __cdecl extern_c_func(void)>(void)
; FIXME: void __cdecl fn_tmpl<&void __cdecl extern_c_func(void)>(void)
; ?overloaded_fn@@$$J0YAXXZ ?overloaded_fn@@$$J0YAXXZ
; FIXME-EXTERNC: extern \"C\" void __cdecl overloaded_fn(void) ; CHECK: extern "C" void __cdecl overloaded_fn(void)
?f@UnnamedType@@YAXQAPAU<unnamed-type-T1>@S@1@@Z ?f@UnnamedType@@YAXQAPAU<unnamed-type-T1>@S@1@@Z
; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::S::<unnamed-type-T1> **const) ; CHECK: void __cdecl UnnamedType::f(struct UnnamedType::S::<unnamed-type-T1> **const)