Skip to content
This repository has been archived by the owner on Oct 12, 2022. It is now read-only.

Add cppdemangle in druntime #3002

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open

Conversation

ErnyTech
Copy link
Contributor

@ErnyTech ErnyTech commented Mar 24, 2020

Add cppdemangle in druntime

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)

@dlang-bot
Copy link
Contributor

Thanks for your pull request and interest in making D better, @ErnyTech! We are looking forward to reviewing it, and you should be hearing from a maintainer soon.
Please verify that your PR follows this checklist:

  • My PR is fully covered with tests (you can see the coverage diff by visiting the details link of the codecov check)
  • My PR is as minimal as possible (smaller, focused PRs are easier to review than big ones)
  • I have provided a detailed rationale explaining my changes
  • New or modified functions have Ddoc comments (with Params: and Returns:)

Please see CONTRIBUTING.md for more information.


If you have addressed all reviews or aren't sure how to proceed, don't hesitate to ping us with a simple comment.

Bugzilla references

Your PR doesn't reference any Bugzilla issue.

If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog.

Testing this PR locally

If you don't have a local development environment setup, you can use Digger to test this PR:

dub run digger -- build "master + druntime#3002"

@ErnyTech ErnyTech force-pushed the cppdemangle branch 2 times, most recently from 36d80f7 to 1be511b Compare March 26, 2020 14:30
@ErnyTech ErnyTech changed the title Add cppdemangle in druntime [WIP] Add cppdemangle in druntime Mar 27, 2020
@dlang-bot dlang-bot added the WIP Work In Progress - not ready for review or pulling label Mar 27, 2020
@ErnyTech ErnyTech force-pushed the cppdemangle branch 6 times, most recently from cb69e57 to 0de39b0 Compare April 1, 2020 11:15
@ErnyTech ErnyTech changed the title [WIP] Add cppdemangle in druntime Add cppdemangle in druntime Apr 1, 2020
@ErnyTech
Copy link
Contributor Author

ErnyTech commented Apr 1, 2020

It is now ready for review.

Copy link
Member

@Geod24 Geod24 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did a first round of review

src/core/internal/cppdemangle.d Outdated Show resolved Hide resolved
src/core/internal/cppdemangle.d Outdated Show resolved Hide resolved
src/core/internal/cppdemangle.d Outdated Show resolved Hide resolved
src/core/internal/cppdemangle.d Show resolved Hide resolved
src/core/internal/cppdemangle.d Outdated Show resolved Hide resolved
src/core/internal/cppdemangle.d Outdated Show resolved Hide resolved
src/core/internal/cppdemangle.d Outdated Show resolved Hide resolved
src/core/internal/cppdemangle.d Outdated Show resolved Hide resolved
src/core/internal/cppdemangle.d Outdated Show resolved Hide resolved
version (Posix)
{
int result;
auto demangledNamePtr = _instance.__cxa_demangle(mangledName, null, null, &result);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see the point of copying the result when you could just pass the pointer to the array here ?

@Geod24 Geod24 removed the WIP Work In Progress - not ready for review or pulling label Apr 1, 2020
@ErnyTech
Copy link
Contributor Author

ErnyTech commented Apr 1, 2020

Thanks for the extensive review!

@ErnyTech ErnyTech force-pushed the cppdemangle branch 6 times, most recently from bbe2da0 to f7e3b10 Compare April 12, 2020 19:33
@ErnyTech
Copy link
Contributor Author

ErnyTech commented Apr 12, 2020

@Geod24, this is ready for second round ;-)

@ErnyTech ErnyTech requested a review from Geod24 April 12, 2020 20:38
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>
/**
* Demangles C++ mangled names.
*
* The output buffer and return will be contains the demangled name of C++ symbol if the demangling is successful.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* The output buffer and return will be contains the demangled name of C++ symbol if the demangling is successful.
* The output buffer and return value will contain the demangled name of C++ symbol if the demangling is successful.

*
* The output buffer and return will be contains the demangled name of C++ symbol if the demangling is successful.
*
* This function will fail and the mangled name in input will be returned if:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the "return input on failure" part should be mentioned in the previous sentence as it describes the general function contract

*
* Params:
* mangledName = The string to demangle.
* outputBuffer = The destination buffer, if the size of the destination buffer is <= the size of cppdemangle output the return string would be incomplete.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant size requirement, it's already mentioned above

* Returns:
* The demangled name or the original string if the name is not a mangled C++ name.
*/
char[] cppdemangle(const(char)[] mangledName, char[] outputBuffer, string prefix = "") @trusted
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think this function should accept a prefix, it's an unrelated complication and a user can always do that manually:

buffer[0..prefix.length] = prefix;
cppdemangle(mangling, buffer[prefix.length .. $]);

* Returns:
* The demangled name or the original string if the name is not a mangled C++ name.
*/
char[] cppdemangle(const(char)[] mangledName, char[] outputBuffer, string prefix = "") @trusted
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The symbol should be in camelCase: cppDemangle

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@trusted should probably be used in smaller scope(s).

Comment on lines +88 to +91
@nogc nothrow extern(System)
{
private UnDecorateSymbolNameFunc UnDecorateSymbolName;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nogc nothrow extern(System) doesn't affect the type of UnDecorateSymbolName and extern(System) is redundant anyway

}
}

version (Windows)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
version (Windows)
else version (Windows)

@ErnyTech
Copy link
Contributor Author

ErnyTech commented Jun 24, 2020

Now that my exams are over I can continue with this!
Thanks for the review @MoonlightSentinel

@MoonlightSentinel
Copy link
Contributor

Ping @ErnyTech

Copy link
Member

@ljmf00 ljmf00 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a note to tick later: Missing tests.

private static immutable names = ["libc++abi.dylib", "libstdc++.dylib"];
else
{
private static immutable names = ["libstdc++.so", "libstdc++.so.6", "libstdc++.so.5",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about fallbacks to other major versions of libstdc++? It shouldn't be required for new systems but could be good for compatibility.


@nogc nothrow extern(System)
{
private UnDecorateSymbolNameFunc UnDecorateSymbolName;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UnDecorateSymbolName is a symbol from dbghelp.dll and that doesn't come with a Windows stock installation, being instead, part of Windows Debugging Kit (WDK). Also, considering MinGW systems, aren't libstdc++ shipped anyway? Notwithstanding, we should have fallbacks for those too, just in case.

{
import core.sys.posix.dlfcn : dlsym, dlopen, dlclose, RTLD_LAZY;

auto handle = dlopen(null, RTLD_LAZY);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not add null to the fallback list instead of doing code duplication? Is there any additional logic I'm missing here?

return null;
}

auto mangledNamePtr = cast(char*) pureCalloc(mangledName.length + 1, char.sizeof);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check if the allocation succeed.

}
}

return copyResult(demangledName[0..strlen(demangledName)], outputBuffer);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't do strlen. __cxa_demangle is capable of returning the length. See https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.3/a01696.html

Why do we use a copyResult function in the first place? We shouldn't hang if the buffer is not large enough, and could return the allocated buffer directly if the provided output buffer is null.

version (Posix)
{
int status;
auto demangledName = _instance.__cxa_demangle(mangledNamePtr, null, null, &status);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please feed the output buffer to __cxa_demangle since a preallocated buffer can help avoid unnecessary reallocations.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
5 participants