Improve DYLINK_DEBUG. NFC (#15164)

Debugging improvements split out from a PR I'm working on for dlopen +
threads.
diff --git a/src/compiler.js b/src/compiler.js
index 6e6147e..670bec9 100755
--- a/src/compiler.js
+++ b/src/compiler.js
@@ -70,7 +70,7 @@
 SIDE_MODULE_EXPORTS = set(SIDE_MODULE_EXPORTS);
 INCOMING_MODULE_JS_API = set(INCOMING_MODULE_JS_API);
 
-RUNTIME_DEBUG = LIBRARY_DEBUG || GL_DEBUG;
+RUNTIME_DEBUG = LIBRARY_DEBUG || GL_DEBUG || DYLINK_DEBUG;
 
 // Side modules are pure wasm and have no JS
 assert(!SIDE_MODULE, "JS compiler should not run on side modules");
diff --git a/src/library_dylink.js b/src/library_dylink.js
index 0193ac5..a18d30d 100644
--- a/src/library_dylink.js
+++ b/src/library_dylink.js
@@ -58,7 +58,12 @@
       '__cpp_exception',
       '__wasm_apply_data_relocs',
       '__dso_handle',
-      '__set_stack_limits'
+      '__tls_size',
+      '__tls_align',
+      '__set_stack_limits',
+      'emscripten_tls_init',
+      '__wasm_init_tls',
+      '__wasm_call_ctors',
     ].includes(symName)
 #if SPLIT_MODULE
         // Exports synthesized by wasm-split should be prefixed with '%'
@@ -70,7 +75,7 @@
   $updateGOT__deps: ['$GOT', '$isInternalSym'],
   $updateGOT: function(exports, replace) {
 #if DYLINK_DEBUG
-    err("updateGOT: " + Object.keys(exports).length);
+    err("updateGOT: adding " + Object.keys(exports).length + " symbols");
 #endif
     for (var symName in exports) {
       if (isInternalSym(symName)) {
@@ -92,7 +97,7 @@
         if (typeof value === 'function') {
           GOT[symName].value = addFunctionWasm(value);
 #if DYLINK_DEBUG
-          err("updateGOT FUNC: " + symName + ' : ' + GOT[symName].value);
+          err("updateGOT: FUNC: " + symName + ' : ' + GOT[symName].value);
 #endif
         } else if (typeof value === 'number') {
           GOT[symName].value = value;
@@ -154,7 +159,7 @@
         assert(value, 'undefined symbol `' + symName + '`. perhaps a side module was not linked in? if this global was expected to arrive from a system library, try to build the MAIN_MODULE with EMCC_FORCE_STDLIBS=1 in the environment');
 #endif
 #if DYLINK_DEBUG
-        err('assigning dynamic symbol from main module: ' + symName + ' -> ' + value);
+        err('assigning dynamic symbol from main module: ' + symName + ' -> ' + prettyPrint(value));
 #endif
         if (typeof value === 'function') {
           GOT[symName].value = addFunctionWasm(value, value.sig);
@@ -615,6 +620,9 @@
   // Once a library becomes "global" or "nodelete", it cannot be removed or unloaded.
   $loadDynamicLibrary__deps: ['$LDSO', '$loadWebAssemblyModule', '$asmjsMangle', '$isInternalSym', '$mergeLibSymbols'],
   $loadDynamicLibrary: function(lib, flags) {
+#if DYLINK_DEBUG
+    err("loadDynamicLibrary: " + lib);
+#endif
     if (lib == '__main__' && !LDSO.loadedLibNames[lib]) {
       LDSO.loadedLibs[-1] = {
         refcount: Infinity,   // = nodelete
@@ -714,6 +722,9 @@
     }
 
     if (flags.loadAsync) {
+#if DYLINK_DEBUG
+      err("loadDynamicLibrary: done (async)");
+#endif
       return getLibModule().then(function(libModule) {
         moduleLoaded(libModule);
         return handle;
@@ -721,6 +732,9 @@
     }
 
     moduleLoaded(getLibModule());
+#if DYLINK_DEBUG
+    err("loadDynamicLibrary: done");
+#endif
     return handle;
   },
 
diff --git a/src/library_pthread.js b/src/library_pthread.js
index 23eab2f..3432e1d 100644
--- a/src/library_pthread.js
+++ b/src/library_pthread.js
@@ -510,6 +510,13 @@
 #if DYLINK_DEBUG
       err('tlsInit -> ' + __tls_base);
 #endif
+      if (!__tls_base) {
+#if ASSERTIONS
+        // __tls_base should never be zero if there are tls exports
+        assert(__tls_base || Object.keys(metadata.tlsExports).length == 0);
+#endif
+        return;
+      }
       for (var sym in metadata.tlsExports) {
         metadata.tlsExports[sym] = moduleExports[sym];
       }
diff --git a/src/runtime_debug.js b/src/runtime_debug.js
index 5482b43..dbe4ba4 100644
--- a/src/runtime_debug.js
+++ b/src/runtime_debug.js
@@ -45,11 +45,12 @@
     ret += 'f32:' + arr.toString().replace(/,/g, ',') + '}';
     return ret;
   }
-  if (typeof arg == 'object') {
+  if (typeof arg === 'function') {
+    return '<function>';
+  } else if (typeof arg === 'object') {
     printObjectList.push(arg);
     return '<' + arg + '|' + (printObjectList.length-1) + '>';
-  }
-  if (typeof arg == 'number') {
+  } else if (typeof arg === 'number') {
     if (arg > 0) return '0x' + arg.toString(16) + ' (' + arg + ')';
   }
   return arg;