Skip to content

Commit

Permalink
druntime: Demangle C++ symbols if a standard library is already loaded
Browse files Browse the repository at this point in the history
  • Loading branch information
omerfirmak authored and Geod24 committed Oct 29, 2022
1 parent 5b4384e commit fabd062
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 19 deletions.
97 changes: 90 additions & 7 deletions druntime/src/core/demangle.d
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ else version (WatchOS)
debug(trace) import core.stdc.stdio : printf;
debug(info) import core.stdc.stdio : printf;

extern (C) alias CXX_DEMANGLER = char* function (const char* mangled_name,
char* output_buffer,
size_t* length,
int* status) nothrow pure @trusted;

private struct NoHooks
{
// supported hooks
Expand Down Expand Up @@ -2115,19 +2120,22 @@ pure @safe:


/**
* Demangles D mangled names. If it is not a D mangled name, it returns its
* argument name.
* Demangles D/C++ mangled names. If it is not a D/C++ mangled name, it
* returns its argument name.
*
* Params:
* buf = The string to demangle.
* dst = An optional destination buffer.
* __cxa_demangle = optional C++ demangler
*
* Returns:
* The demangled name or the original string if the name is not a mangled D
* name.
* The demangled name or the original string if the name is not a mangled
* D/C++ name.
*/
char[] demangle(return scope const(char)[] buf, return scope char[] dst = null ) nothrow pure @safe
char[] demangle(return scope const(char)[] buf, return scope char[] dst = null, CXX_DEMANGLER __cxa_demangle = null) nothrow pure @safe
{
if (buf.length > 2 && buf[0..2] == "_Z")
return demangleCXX(buf, __cxa_demangle, dst);
auto d = Demangle!()(buf, dst);
// fast path (avoiding throwing & catching exception) for obvious
// non-D mangled names
Expand Down Expand Up @@ -2706,8 +2714,10 @@ unittest
{
char[] buf = new char[i];
auto ds = demangle(s, buf);
assert(ds == "pure nothrow @safe char[] core.demangle.demangle(scope return const(char)[], scope return char[])" ||
ds == "pure nothrow @safe char[] core.demangle.demangle(return scope const(char)[], return scope char[])");
assert(ds == "pure nothrow @safe char[] core.demangle.demangle(scope return const(char)[], scope return char[], extern (C) char* function(const(char*), char*, ulong*, int*) pure nothrow @trusted*)" ||
ds == "pure nothrow @safe char[] core.demangle.demangle(return scope const(char)[], return scope char[], extern (C) char* function(const(char*), char*, ulong*, int*) pure nothrow @trusted*)" ||
ds == "pure nothrow @safe char[] core.demangle.demangle(scope return const(char)[], scope return char[], extern (C) char* function(const(char*), char*, uint*, int*) pure nothrow @trusted*)" ||
ds == "pure nothrow @safe char[] core.demangle.demangle(return scope const(char)[], return scope char[], extern (C) char* function(const(char*), char*, uint*, int*) pure nothrow @trusted*)", ds);
}
}

Expand Down Expand Up @@ -2901,3 +2911,76 @@ private string toStringConsume (immutable ManglingFlagInfo[] infos, ref ushort b
}
return null;
}

private shared CXX_DEMANGLER __cxa_demangle;

/**
* Returns:
* a CXX_DEMANGLER if a C++ stdlib is loaded
*/

CXX_DEMANGLER getCXXDemangler() nothrow @trusted
{
if (__cxa_demangle is null)
version (Posix)
{
import core.sys.posix.dlfcn : dlsym;
version (DragonFlyBSD) import core.sys.dragonflybsd.dlfcn : RTLD_DEFAULT;
version (FreeBSD) import core.sys.freebsd.dlfcn : RTLD_DEFAULT;
version (linux) import core.sys.linux.dlfcn : RTLD_DEFAULT;
version (NetBSD) import core.sys.netbsd.dlfcn : RTLD_DEFAULT;
version (OSX) import core.sys.darwin.dlfcn : RTLD_DEFAULT;
version (Solaris) import core.sys.solaris.dlfcn : RTLD_DEFAULT;

if (auto found = cast(CXX_DEMANGLER) dlsym(RTLD_DEFAULT, "__cxa_demangle"))
__cxa_demangle = found;
}

if (__cxa_demangle is null)
__cxa_demangle = (const char* mangled_name, char* output_buffer,
size_t* length, int* status) nothrow pure @trusted {
*status = -1;
return null;
};

return __cxa_demangle;
}

/**
* Demangles C++ mangled names. If it is not a C++ mangled name, it
* returns its argument name.
*
* Params:
* buf = The string to demangle.
* __cxa_demangle = C++ demangler
* dst = An optional destination buffer.
*
* Returns:
* The demangled name or the original string if the name is not a mangled
* C++ name.
*/
private char[] demangleCXX(return scope const(char)[] buf, CXX_DEMANGLER __cxa_demangle, return scope char[] dst = null,) nothrow pure @trusted
{
char[] c_string = dst; // temporarily use dst buffer if possible
c_string.length = buf.length + 1;
c_string[0 .. buf.length] = buf[0 .. buf.length];
c_string[buf.length] = '\0';

int status;
size_t demangled_length;
auto demangled = __cxa_demangle(&c_string[0], null, &demangled_length, &status);
scope (exit) {
import core.memory;
pureFree(cast(void*) demangled);
}
if (status == 0)
{
dst.length = demangled_length;
dst[] = demangled[0 .. demangled_length];
return dst;
}

dst.length = buf.length;
dst[] = buf[];
return dst;
}
2 changes: 1 addition & 1 deletion druntime/src/core/internal/backtrace/dwarf.d
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ struct Location
if (this.procedure.length)
{
sink(" ");
sink(demangle(this.procedure, symbolBuffer));
sink(demangle(this.procedure, symbolBuffer, getCXXDemangler()));
}

sink(" [0x");
Expand Down
2 changes: 1 addition & 1 deletion druntime/src/core/runtime.d
Original file line number Diff line number Diff line change
Expand Up @@ -845,7 +845,7 @@ private:
{
fixbuf[0 .. symBeg] = buf[0 .. symBeg];

auto sym = demangle(buf[symBeg .. symEnd], fixbuf[symBeg .. $]);
auto sym = demangle(buf[symBeg .. symEnd], fixbuf[symBeg .. $], getCXXDemangler());

if (sym.ptr !is fixbuf.ptr + symBeg)
{
Expand Down
2 changes: 1 addition & 1 deletion druntime/test/common.mak
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ ifneq (default,$(MODEL))
MODEL_FLAG:=-m$(MODEL)
endif
CFLAGS_BASE:= $(MODEL_FLAG) $(PIC) -Wall
DFLAGS:=$(MODEL_FLAG) $(PIC) -w -I../../src -I../../import -I$(SRC) -defaultlib= -debuglib= -preview=dip1000 -L-lpthread -L-lm
DFLAGS:=$(MODEL_FLAG) $(PIC) -w -I../../src -I../../import -I$(SRC) -defaultlib= -debuglib= -preview=dip1000 -L-lpthread -L-lm $(LINKDL)
# LINK_SHARED may be set by importing makefile
DFLAGS+=$(if $(LINK_SHARED),-L$(DRUNTIMESO),-L$(DRUNTIME))
ifeq ($(BUILD),debug)
Expand Down
12 changes: 7 additions & 5 deletions druntime/test/exceptions/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,22 @@ TESTS=stderr_msg unittest_assert invalid_memory_operation unknown_gc static_dtor
message_with_null

ifeq ($(OS)-$(BUILD),linux-debug)
TESTS+=line_trace line_trace_21656 long_backtrace_trunc rt_trap_exceptions
TESTS+=line_trace line_trace_21656 long_backtrace_trunc rt_trap_exceptions cpp_demangle
LINE_TRACE_DFLAGS:=-L--export-dynamic
endif
ifeq ($(OS),linux)
TESTS+=rt_trap_exceptions_drt_gdb
TESTS+=rt_trap_exceptions_drt_gdb cpp_demangle
endif
ifeq ($(OS)-$(BUILD),freebsd-debug)
TESTS+=line_trace line_trace_21656 long_backtrace_trunc
TESTS+=line_trace line_trace_21656 long_backtrace_trunc cpp_demangle
LINE_TRACE_DFLAGS:=-L--export-dynamic
endif
ifeq ($(OS)-$(BUILD),dragonflybsd-debug)
TESTS+=line_trace line_trace_21656 long_backtrace_trunc
TESTS+=line_trace line_trace_21656 long_backtrace_trunc cpp_demangle
LINE_TRACE_DFLAGS:=-L--export-dynamic
endif
ifeq ($(OS)-$(BUILD),osx-debug)
TESTS+=line_trace line_trace_21656 long_backtrace_trunc
TESTS+=line_trace line_trace_21656 long_backtrace_trunc cpp_demangle
LINE_TRACE_DFLAGS:=
endif

Expand Down Expand Up @@ -78,6 +78,7 @@ $(ROOT)/catch_in_finally.done: STDERR_EXP="success."
$(ROOT)/rt_trap_exceptions.done: STDERR_EXP="object.Exception@src/rt_trap_exceptions.d(12): this will abort"
$(ROOT)/rt_trap_exceptions.done: STDERR_EXP2="src/rt_trap_exceptions.d:8 main"
$(ROOT)/assert_fail.done: STDERR_EXP="success."
$(ROOT)/cpp_demangle.done: STDERR_EXP="thrower(int)"

$(ROOT)/message_with_null.done: STDERR_EXP=" world"

Expand Down Expand Up @@ -128,6 +129,7 @@ $(ROOT)/long_backtrace_trunc: DFLAGS+=$(LINE_TRACE_DFLAGS)
$(ROOT)/rt_trap_exceptions: DFLAGS+=$(LINE_TRACE_DFLAGS)
$(ROOT)/rt_trap_exceptions_drt: DFLAGS+=-g
$(ROOT)/refcounted: DFLAGS+=-dip1008
$(ROOT)/cpp_demangle: DFLAGS+=-L-lstdc++

$(ROOT)/%: $(SRC)/%.d $(DMD) $(DRUNTIME)
$(QUIET)$(DMD) $(DFLAGS) -of$@ $<
Expand Down
19 changes: 19 additions & 0 deletions druntime/test/exceptions/src/cpp_demangle.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import core.demangle;

extern(C) char* __cxa_demangle (const char* mangled_name,
char* output_buffer,
size_t* length,
int* status) nothrow pure @trusted;

extern (C++) void thrower(int a) {
throw new Exception("C++ ex");
}
void caller() {
thrower(42);
}

void main()
{
caller();
__cxa_demangle(null, null, null, null); // make sure __cxa_demangle is linked
}
8 changes: 4 additions & 4 deletions druntime/test/stdcpp/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -59,22 +59,22 @@ $(ROOT)/%_old.done : $(ROOT)/%_old
$(ROOT)/%: $(SRC)/%.cpp $(SRC)/%_test.d
mkdir -p $(dir $@)
$(QUIET)$(DMD) $(DFLAGS) -extern-std=c++98 -main -unittest -version=CoreUnittest -c -of=$(ROOT)/$*_d.o $(SRC)/$*_test.d
$(QUIET)$(CXX) $(CXXFLAGS_BASE) -std=c++98 -o $@ $< $(ROOT)/$*_d.o $(DRUNTIME) -lpthread
$(QUIET)$(CXX) $(CXXFLAGS_BASE) -std=c++98 -o $@ $< $(ROOT)/$*_d.o $(DRUNTIME) -lpthread $(LDL)
# build C++11 tests
$(ROOT)/%_11: $(SRC)/%.cpp $(SRC)/%_test.d
mkdir -p $(dir $@)
$(QUIET)$(DMD) $(DFLAGS) -extern-std=c++11 -main -unittest -version=CoreUnittest -c -of=$(ROOT)/$*_11_d.o $(SRC)/$*_test.d
$(QUIET)$(CXX) $(CXXFLAGS_BASE) -std=c++11 -o $@ $< $(ROOT)/$*_11_d.o $(DRUNTIME) -lpthread
$(QUIET)$(CXX) $(CXXFLAGS_BASE) -std=c++11 -o $@ $< $(ROOT)/$*_11_d.o $(DRUNTIME) -lpthread $(LDL)
# build C++17 tests
$(ROOT)/%_17: $(SRC)/%.cpp $(SRC)/%_test.d
mkdir -p $(dir $@)
$(QUIET)$(DMD) $(DFLAGS) -extern-std=c++17 -main -unittest -version=CoreUnittest -c -of=$(ROOT)/$*_17_d.o $(SRC)/$*_test.d
$(QUIET)$(CXX) $(CXXFLAGS_BASE) -std=c++17 -o $@ $< $(ROOT)/$*_17_d.o $(DRUNTIME) -lpthread
$(QUIET)$(CXX) $(CXXFLAGS_BASE) -std=c++17 -o $@ $< $(ROOT)/$*_17_d.o $(DRUNTIME) -lpthread $(LDL)
# build libstdc++ _GLIBCXX_USE_CXX11_ABI=0 tests
$(ROOT)/%_old: $(SRC)/%.cpp $(SRC)/%_test.d
mkdir -p $(dir $@)
$(QUIET)$(DMD) $(DFLAGS) -version=_GLIBCXX_USE_CXX98_ABI -main -unittest -version=CoreUnittest -c -of=$(ROOT)/$*_old_d.o $(SRC)/$*_test.d
$(QUIET)$(CXX) $(CXXFLAGS_BASE) -D_GLIBCXX_USE_CXX11_ABI=0 -o $@ $< $(ROOT)/$*_old_d.o $(DRUNTIME) -lpthread
$(QUIET)$(CXX) $(CXXFLAGS_BASE) -D_GLIBCXX_USE_CXX11_ABI=0 -o $@ $< $(ROOT)/$*_old_d.o $(DRUNTIME) -lpthread $(LDL)

clean:
rm -rf $(GENERATED)

0 comments on commit fabd062

Please sign in to comment.