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 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. This implementation obviously only supports Posix, on Windows it is not possible to use it. You could probably do the same thing on Windows using https://docs.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-undecoratesymbolname I think that for MinGw it is possible to use the same function, and I have already sketched a support for Windows with MinGw however for now it is not enabled because I don't know how this platform works. Signed-off-by: Ernesto Castellotti <[email protected]>
- Loading branch information
Ernesto Castellotti
committed
Mar 26, 2020
1 parent
475c85f
commit 36d80f7
Showing
4 changed files
with
172 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,167 @@ | ||
/** | ||
* 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) | ||
*/ | ||
|
||
/** | ||
* 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. | ||
*/ | ||
version (iOS) | ||
{ | ||
// Not supported (dlopen doesn't work) | ||
// Fix me | ||
} | ||
else version (Posix) | ||
{ | ||
version = SupportCppDemangle; | ||
} | ||
|
||
char[] cppdemangle(const(char)[] buf, char[] dst, bool withPrefix = false, string prefix = "[C++]") @safe @nogc nothrow | ||
{ | ||
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"); | ||
|
||
version (SupportCppDemangle) | ||
{ | ||
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)]; | ||
} | ||
else | ||
{ | ||
return copyResult(buf, dst); | ||
} | ||
} | ||
|
||
private 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]; | ||
} | ||
|
||
version (Posix) | ||
{ | ||
private char[] _cppdemangle(const(char)[] buf, char[] dst) @trusted @nogc nothrow | ||
{ | ||
import core.memory : pureCalloc, pureFree; | ||
import core.stdc.string : strlen; | ||
|
||
int status; | ||
auto mangledName = cast(char*) pureCalloc(buf.length + 1, char.sizeof); | ||
scope(exit) pureFree(mangledName); | ||
mangledName[0..buf.length] = buf[]; | ||
|
||
auto demangle = CXADemangleAPI.instance().__cxa_demangle; | ||
if (demangle is null) return null; | ||
|
||
auto result = demangle(mangledName, null, null, &status); | ||
scope(exit) pureFree(result); | ||
|
||
if (status != 0) return null; | ||
return copyResult(result[0..strlen(result)], dst); | ||
} | ||
|
||
private static struct CXADemangleAPI | ||
{ | ||
static struct API | ||
{ | ||
@nogc nothrow extern(C): | ||
private __gshared extern(C) char* function(const char* mangled_name, char* dst_buffer, size_t* length, int* status) __cxa_demangle; | ||
} | ||
|
||
private __gshared API _api; | ||
private __gshared void* _handle; | ||
|
||
static ref API instance() @nogc nothrow | ||
{ | ||
if (_api.__cxa_demangle is null) _handle = loadAPI(); | ||
return _api; | ||
} | ||
|
||
static void* loadAPI() @nogc nothrow | ||
{ | ||
static extern(C) void cleanup() | ||
{ | ||
if (_handle is null) return; | ||
import core.sys.posix.dlfcn : dlclose; | ||
dlclose(_handle); | ||
_handle = null; | ||
_api.__cxa_demangle = null; | ||
} | ||
|
||
static void* setSym(void* handle, void* ptrSym) | ||
{ | ||
import core.stdc.stdlib : atexit; | ||
atexit(&cleanup); | ||
_api.__cxa_demangle = cast(typeof(CXADemangleAPI.API.__cxa_demangle)) ptrSym; | ||
return handle; | ||
} | ||
|
||
import core.sys.posix.dlfcn : dlsym, dlopen, dlclose, RTLD_LAZY; | ||
|
||
auto handle = dlopen(null, RTLD_LAZY); | ||
if (handle is null) return null; | ||
|
||
auto p = dlsym(handle, "__cxa_demangle"); | ||
if (p !is null) return setSym(handle, p); | ||
|
||
dlclose(handle); | ||
|
||
version (OSX) | ||
enum names = ["libc++abi.dylib", "libstdc++.dylib"]; | ||
else version (Posix) | ||
{ | ||
enum names = ["libstdc++.so", "libc++abi.so", | ||
"libc++abi.so.1"]; | ||
} | ||
else version (MinGW) | ||
enum names = ["libstdc++.dll", "libstdc++-6.dll"]; | ||
|
||
foreach (name; names) | ||
{ | ||
handle = dlopen(name.ptr, RTLD_LAZY); | ||
if (handle !is null) break; | ||
} | ||
|
||
if (handle is null) return null; | ||
p = dlsym(handle, "__cxa_demangle"); | ||
|
||
if (p is null) | ||
{ | ||
dlclose(handle); | ||
return null; | ||
} | ||
|
||
return setSym(handle, p); | ||
} | ||
} | ||
} |