This repository has been archived by the owner on Oct 12, 2022. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 421
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Having a C++ symbol demangler is very useful, with this it will be possible to implement the C++ symbol demangle in the stacktrace. The demangling is done in Posix platform by function __cxa_demangle presents in Itanium C++ ABI (https://itanium-cxx-abi.github.io/cxx-abi/abi.html#demangler). Itanium C++ ABI is used practically in all modern C++ compilers on Posix, however old compilers (like GCC < 3.0) used a different name mangling, this is not a problem because DMD in fact only supports Itanium C++ ABI on Posix. For Windows instead the implementation it is provided by the UnDecorateSymbolName function present in the Debug Help Library. (https://docs.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-undecoratesymbolname) Signed-off-by: Ernesto Castellotti <mail@ernestocastellotti.it>
- Loading branch information
Ernesto Castellotti
committed
Mar 31, 2020
1 parent
475c85f
commit cb69e57
Showing
4 changed files
with
273 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,268 @@ | ||
/** | ||
* This module provides routines to demangle C++ symbols | ||
* | ||
* For Posix platform the demangling is done by function `__cxa_demangle` presents in Itanium C++ ABI. | ||
* If the function is not found or something fails, the original mangled C++ name will be returned. | ||
* This module currently only supports POSIX. | ||
* | ||
* Copyright: Copyright © 2019, The D Language Foundation | ||
* License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). | ||
* Authors: Ernesto Castellotti | ||
* Source: $(DRUNTIMESRC core/internal/_cppdemangle.d) | ||
*/ | ||
module core.internal.cppdemangle; | ||
|
||
version (Windows) | ||
{ | ||
version (ANSI) {} else version = Unicode; | ||
} | ||
|
||
/** | ||
* Demangles C++ mangled names. | ||
* | ||
* If it is not a C++ mangled name or cppdemangle is not supported by your platform, the original mangled C++ name will be returned. | ||
* The optional destination buffer and return will be contains the same string if the demangle is successful. | ||
* | ||
* Params: | ||
* buf = The string to demangle. | ||
* dst = The destination buffer, if the size of the destination buffer is <= the size of cppdemangle output the return string would be incomplete. | ||
* withPrefix = If true, add the prefix (followed by a space) before the C++ demangled name, make sure the target buffer is at least large to contain the prefix. | ||
* prefix = Specifies the prefix to be added to the beginning of the string containing the demangled name | ||
* | ||
* Returns: | ||
* The demangled name or the original string if the name is not a mangled C++ name. | ||
*/ | ||
char[] cppdemangle(const(char)[] buf, char[] dst, bool withPrefix = false, string prefix = "[C++]") @safe | ||
{ | ||
CPPDemangle.inizialize(); | ||
return CPPDemangle.instance.cppdemangle(buf, dst, withPrefix, prefix); | ||
} | ||
|
||
package struct CPPDemangle | ||
{ | ||
private static CPPDemangle _instance; | ||
private static bool isInizialized; | ||
|
||
version (Posix) | ||
{ | ||
@nogc nothrow extern(C) | ||
{ | ||
private extern(C) char* function(const char* mangled_name, char* dst_buffer, size_t* length, int* status) __cxa_demangle; | ||
} | ||
|
||
private static void* _handle; | ||
} | ||
else version (Windows) | ||
{ | ||
import core.sys.windows.dbghelp : UnDecorateSymbolNameFunc; | ||
|
||
@nogc nothrow extern(System) | ||
{ | ||
private UnDecorateSymbolNameFunc UnDecorateSymbolName; | ||
} | ||
} | ||
|
||
version (Posix) | ||
{ | ||
static ~this() { | ||
import core.sys.posix.dlfcn : dlclose; | ||
|
||
if (isInizialized) | ||
{ | ||
dlclose(_handle); | ||
_handle = null; | ||
isInizialized = false; | ||
} | ||
} | ||
} | ||
|
||
char[] cppdemangle(const(char)[] buf, char[] dst, bool withPrefix, string prefix) @safe | ||
{ | ||
auto dstStart = withPrefix ? prefix.length + 1 : 0; // Add prefix + space | ||
assert(dst !is null && dst.length > dstStart, "The destination buffer is null or too small for perform demangle"); | ||
|
||
auto demangle = _cppdemangle(buf, dst[dstStart..$]); | ||
|
||
if (demangle is null) | ||
{ | ||
return copyResult(buf, dst); | ||
} | ||
|
||
if (withPrefix) | ||
{ | ||
dst[0..dstStart - 1] = prefix; | ||
dst[dstStart - 1] = ' '; | ||
} | ||
|
||
return dst[0..(demangle.length + dstStart)]; | ||
} | ||
|
||
static CPPDemangleStatus inizialize() @trusted | ||
{ | ||
if (isInizialized) | ||
{ | ||
return CPPDemangleStatus.INIZIALIZED; | ||
} | ||
|
||
version (iOS) | ||
{ | ||
// Not supported (dlopen doesn't work) | ||
// Fix me | ||
} | ||
else version (Posix) | ||
{ | ||
import core.sys.posix.dlfcn : dlsym, dlopen, dlclose, RTLD_LAZY; | ||
|
||
auto handle = dlopen(null, RTLD_LAZY); | ||
assert(handle !is null); | ||
auto p = dlsym(handle, "__cxa_demangle"); | ||
|
||
if (p !is null) | ||
{ | ||
_handle = handle; | ||
_instance.__cxa_demangle = cast(typeof(CPPDemangle.__cxa_demangle)) p; | ||
isInizialized = true; | ||
return CPPDemangleStatus.INIZIALIZED; | ||
} | ||
|
||
dlclose(handle); | ||
|
||
version (OSX) | ||
enum names = ["libc++abi.dylib", "libstdc++.dylib"]; | ||
else version (Posix) | ||
{ | ||
enum names = ["libstdc++.so", "libstdc++.so.6", "libstdc++.so.5", | ||
"libc++abi.so", "libc++abi.so.1"]; | ||
} | ||
|
||
foreach (name; names) | ||
{ | ||
handle = dlopen(name.ptr, RTLD_LAZY); | ||
|
||
if (handle !is null) | ||
{ | ||
break; | ||
} | ||
} | ||
|
||
if (handle is null) | ||
{ | ||
return CPPDemangleStatus.LOAD_ERROR; | ||
} | ||
|
||
p = dlsym(handle, "__cxa_demangle"); | ||
|
||
if (p !is null) | ||
{ | ||
_handle = handle; | ||
_instance.__cxa_demangle = cast(typeof(CPPDemangle.__cxa_demangle)) p; | ||
isInizialized = true; | ||
return CPPDemangleStatus.INIZIALIZED; | ||
} | ||
} | ||
|
||
version (Windows) | ||
{ | ||
import core.sys.windows.dbghelp : DbgHelp; | ||
|
||
auto dbgHelp = DbgHelp.get(); | ||
|
||
if (dbgHelp is null) | ||
{ | ||
return CPPDemangleStatus.LOAD_ERROR; | ||
} | ||
|
||
auto func = dbgHelp.UnDecorateSymbolName; | ||
|
||
if (dbgHelp.UnDecorateSymbolName !is null) | ||
{ | ||
_instance.UnDecorateSymbolName = dbgHelp.UnDecorateSymbolName; | ||
isInizialized = true; | ||
return CPPDemangleStatus.INIZIALIZED; | ||
} | ||
} | ||
|
||
return CPPDemangleStatus.SYMBOL_ERROR; | ||
} | ||
|
||
static CPPDemangle instance() @trusted @nogc nothrow | ||
{ | ||
return _instance; | ||
} | ||
|
||
private char[] _cppdemangle(const(char)[] buf, char[] dst) @trusted | ||
{ | ||
import core.memory : pureCalloc, pureFree; | ||
import core.stdc.string : strlen; | ||
|
||
if (!isInizialized) | ||
{ | ||
return null; | ||
} | ||
|
||
version (Unicode) | ||
{ | ||
import core.internal.utf : toUTF16z, toUTF8; | ||
auto mangledName = toUTF16z(buf); | ||
} | ||
else | ||
{ | ||
auto mangledName = cast(char*) pureCalloc(buf.length + 1, char.sizeof); | ||
scope(exit) pureFree(mangledName); | ||
mangledName[0..buf.length] = buf[]; | ||
} | ||
|
||
version (Posix) | ||
{ | ||
int result; | ||
auto demangledNamePtr = _instance.__cxa_demangle(mangledName, null, null, &result); | ||
|
||
if (result != 0) | ||
{ | ||
return null; | ||
} | ||
|
||
auto demangledName = demangledNamePtr[0..strlen(demangledNamePtr)]; | ||
scope(exit) pureFree(demangledNamePtr); | ||
} | ||
|
||
version (Windows) | ||
{ | ||
import core.sys.windows.winnt : TCHAR; | ||
|
||
TCHAR[2048] outBuf; | ||
auto result = _instance.UnDecorateSymbolName(mangledName, outBuf.ptr, outBuf.length, 0); | ||
|
||
if (result <= 0) | ||
{ | ||
return null; | ||
} | ||
|
||
version (Unicode) | ||
{ | ||
auto demangledName = toUTF8(outBuf[0..result]); | ||
} | ||
else | ||
{ | ||
auto demangleName = outBuf[0..result]; | ||
} | ||
} | ||
|
||
return copyResult(demangledName, dst); | ||
} | ||
} | ||
|
||
package enum CPPDemangleStatus | ||
{ | ||
INIZIALIZED = 1, | ||
LOAD_ERROR = -1, | ||
SYMBOL_ERROR = -2 | ||
} | ||
|
||
package char[] copyResult(const(char)[] input, char[] dst) @safe @nogc nothrow | ||
{ | ||
auto len = input.length <= dst.length ? input.length : dst.length; | ||
dst[0..len] = input[0..len]; | ||
dst[len..$] = '\0'; | ||
return dst[0..len]; | ||
} |