aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2014-07-21 14:26:38 -0700
committerAlon Zakai <alonzakai@gmail.com>2014-07-21 14:26:38 -0700
commit812f051215f469a8f26768fde343c2e464114cc1 (patch)
tree8161ee531c4265e814383557aeb8e5d94394cc1b
parentd1e74bbabb835f0a9e988ab53f37c9f4d0a29d8c (diff)
DEMANGLE_SUPPORT option to use libcxxabi's demangler in stackTrace()
-rwxr-xr-xemcc7
-rw-r--r--src/preamble.js28
-rw-r--r--src/settings.js3
-rw-r--r--tests/test_other.py26
-rw-r--r--tools/system_libs.py5
5 files changed, 64 insertions, 5 deletions
diff --git a/emcc b/emcc
index 15cfbb7b..f6180f20 100755
--- a/emcc
+++ b/emcc
@@ -1390,6 +1390,11 @@ try:
next_arg_index += 1
shared.Settings.EXPORTED_FUNCTIONS += ['_stbi_load', '_stbi_load_from_memory', '_stbi_image_free']
+ forced_stdlibs = []
+ if shared.Settings.DEMANGLE_SUPPORT:
+ shared.Settings.EXPORTED_FUNCTIONS += ['___cxa_demangle']
+ forced_stdlibs += ['libcxxabi']
+
if type(shared.Settings.EXPORTED_FUNCTIONS) in (list, tuple):
# always need malloc and free to be kept alive and exported, for internal use and other modules
for required_export in ['_malloc', '_free']:
@@ -1536,7 +1541,7 @@ try:
if not LEAVE_INPUTS_RAW and \
not shared.Settings.BUILD_AS_SHARED_LIB and \
not shared.Settings.SIDE_MODULE: # shared libraries/side modules link no C libraries, need them in parent
- extra_files_to_link = system_libs.calculate([f for _, f in sorted(temp_files)], in_temp, stdout, stderr)
+ extra_files_to_link = system_libs.calculate([f for _, f in sorted(temp_files)], in_temp, stdout, stderr, forced=forced_stdlibs)
else:
extra_files_to_link = []
diff --git a/src/preamble.js b/src/preamble.js
index 1541075e..7ac9b549 100644
--- a/src/preamble.js
+++ b/src/preamble.js
@@ -778,6 +778,25 @@ function stringToUTF32(str, outPtr) {
Module['stringToUTF32'] = stringToUTF32;
function demangle(func) {
+ var hasLibcxxabi = !!Module['___cxa_demangle'];
+ if (hasLibcxxabi) {
+ try {
+ var buf = _malloc(func.length);
+ writeStringToMemory(func.substr(1), buf);
+ var status = _malloc(4);
+ var ret = Module['___cxa_demangle'](buf, 0, 0, status);
+ if (getValue(status, 'i32') === 0 && ret) {
+ return Pointer_stringify(ret);
+ }
+ // otherwise, libcxxabi failed, we can try ours which may return a partial result
+ } catch(e) {
+ // failure when using libcxxabi, we can try ours which may return a partial result
+ } finally {
+ if (buf) _free(buf);
+ if (status) _free(status);
+ if (ret) _free(ret);
+ }
+ }
var i = 3;
// params, etc.
var basicTypes = {
@@ -909,6 +928,7 @@ function demangle(func) {
return ret + flushList();
}
}
+ var final = func;
try {
// Special-case the entry point, since its name differs from other name mangling.
if (func == 'Object._main' || func == '_main') {
@@ -922,10 +942,14 @@ function demangle(func) {
case 'n': return 'operator new()';
case 'd': return 'operator delete()';
}
- return parse();
+ final = parse();
} catch(e) {
- return func;
+ final += '?';
+ }
+ if (final.indexOf('?') >= 0 && !hasLibcxxabi) {
+ Runtime.warnOnce('A problem occurred in builtin C++ name demangling; build with -s DEMANGLE_SUPPORT=1 to link in libcxxabi demangling');
}
+ return final;
}
function demangleAll(text) {
diff --git a/src/settings.js b/src/settings.js
index 14077efd..b7947ac8 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -231,6 +231,9 @@ var LABEL_FUNCTION_FILTERS = []; // Filters for function label debug.
// When the array is empty, the filter is disabled.
var EXCEPTION_DEBUG = 0; // Print out exceptions in emscriptened code. Does not work in asm.js mode
+var DEMANGLE_SUPPORT = 0; // If 1, build in libcxxabi's full c++ demangling code, to allow stackTrace()
+ // to emit fully proper demangled c++ names
+
var LIBRARY_DEBUG = 0; // Print out when we enter a library call (library*.js). You can also unset
// Runtime.debug at runtime for logging to cease, and can set it when you
// want it back. A simple way to set it in C++ is
diff --git a/tests/test_other.py b/tests/test_other.py
index b4e6a620..398975fc 100644
--- a/tests/test_other.py
+++ b/tests/test_other.py
@@ -2191,6 +2191,32 @@ void wakaw::Cm::RasterBase<wakaw::watwat::Polocator?>(unsigned int*, unsigned in
assert 'one(int)' in output
assert 'two(char)' in output
+ # full demangle support
+
+ Popen([PYTHON, EMCC, 'src.cpp', '-s', 'LINKABLE=1', '-s', 'DEMANGLE_SUPPORT=1']).communicate()
+ output = run_js('a.out.js')
+ self.assertContained('''operator new(unsigned int)
+main()
+f2()
+abcdabcdabcd(int)
+abcdabcdabcd(int)
+test(char, short, int, float, double, void*, int*, char*)
+test::moarr(char, short, long, float, double, void*, int*, char*)
+Waka::f::a23412341234::point()
+void Foo<int>()
+void Foo<int, double>(int)
+void Foo::Bar<5>()
+__cxxabiv1::__si_class_type_info::search_below_dst(__cxxabiv1::__dynamic_cast_info*, void const*, int, bool) const
+parseword(char const*&, int, int&)
+multi(wchar_t, signed char, unsigned char, unsigned short, unsigned int, unsigned long, long long, unsigned long long, ...)
+a(int [32], char (*) [5])
+FWakaGLXFleeflsMarfoo::FWakaGLXFleeflsMarfoo(unsigned int, unsigned int, unsigned int, void const*, bool, unsigned int, unsigned int)
+void wakaw::Cm::RasterBase<wakaw::watwat::Polocator>::merbine1<wakaw::Cm::RasterBase<wakaw::watwat::Polocator>::OR>(unsigned int const*, unsigned int)
+''', output)
+ # test for multiple functions in one stack trace
+ assert 'one(int)' in output
+ assert 'two(char)' in output
+
def test_module_exports_with_closure(self):
# This test checks that module.export is retained when JavaScript is minified by compiling with --closure 1
# This is important as if module.export is not present the Module object will not be visible to node.js
diff --git a/tools/system_libs.py b/tools/system_libs.py
index 9b63af09..700f219e 100644
--- a/tools/system_libs.py
+++ b/tools/system_libs.py
@@ -13,7 +13,7 @@ def call_process(cmd):
if proc.returncode != 0:
raise CalledProcessError(proc.returncode, cmd)
-def calculate(temp_files, in_temp, stdout_, stderr_):
+def calculate(temp_files, in_temp, stdout_, stderr_, forced=[]):
global stdout, stderr
stdout = stdout_
stderr = stderr_
@@ -455,7 +455,8 @@ def calculate(temp_files, in_temp, stdout_, stderr_):
# You can provide 1 to include everything, or a comma-separated list with the ones you want
force = os.environ.get('EMCC_FORCE_STDLIBS')
force_all = force == '1'
- force = set((force or '').split(','))
+ force = set((force or '').split(',') + forced)
+ if force: logging.debug('forcing stdlibs: ' + str(force))
# Scan symbols
symbolses = map(lambda temp_file: shared.Building.llvm_nm(temp_file), temp_files)