Bug 1391268 - 2. Expose mozglue linker error message to Java code; r?glandium
This patch makes us save the last message from an ERROR() statement, and
use that message when throwing an exception to Java code, in order to
make lib loading crash messages a lot more useful. This does make
ERROR() not thread-safe, but I think that is okay since it's only used
by the single-threaded linker.
MozReview-Commit-ID: fEXTYNKUUA
--- a/mozglue/android/APKOpen.cpp
+++ b/mozglue/android/APKOpen.cpp
@@ -27,16 +27,17 @@
#include <sys/time.h>
#include <sys/syscall.h>
#include <sys/resource.h>
#include <sys/prctl.h>
#include "sqlite3.h"
#include "SQLiteBridge.h"
#include "NSSBridge.h"
#include "ElfLoader.h"
+#include "Logging.h"
#include "application.ini.h"
#include "mozilla/arm.h"
#include "mozilla/Bootstrap.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/UniquePtr.h"
#include "XREChildData.h"
@@ -107,16 +108,23 @@ JNI_Throw(JNIEnv* jenv, const char* clas
int rc = jenv->ThrowNew(cls, msg);
if (rc < 0) {
__android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Error throwing exception %s\n", msg);
exit(FAILURE);
}
jenv->DeleteLocalRef(cls);
}
+static void
+JNI_ThrowLinkerError(JNIEnv* jenv, const char* classname, const char* defaultMsg)
+{
+ JNI_Throw(jenv, classname, *gLastLinkerError ? gLastLinkerError : defaultMsg);
+ *gLastLinkerError = '\0';
+}
+
namespace {
JavaVM* sJavaVM;
}
void
abortThroughJava(const char* msg)
{
struct sigaction sigact = {};
@@ -322,34 +330,34 @@ Java_org_mozilla_gecko_mozglue_GeckoLoad
// XXX: java doesn't give us true UTF8, we should figure out something
// better to do here
str = jenv->GetStringUTFChars(jApkName, nullptr);
if (str == nullptr)
return;
int res = loadGeckoLibs(str);
if (res != SUCCESS) {
- JNI_Throw(jenv, "java/lang/Exception", "Error loading gecko libraries");
+ JNI_ThrowLinkerError(jenv, "java/lang/Exception", "Error loading gecko libraries");
}
jenv->ReleaseStringUTFChars(jApkName, str);
}
extern "C" APKOPEN_EXPORT void MOZ_JNICALL
Java_org_mozilla_gecko_mozglue_GeckoLoader_loadSQLiteLibsNative(JNIEnv *jenv, jclass jGeckoAppShellClass, jstring jApkName) {
const char* str;
// XXX: java doesn't give us true UTF8, we should figure out something
// better to do here
str = jenv->GetStringUTFChars(jApkName, nullptr);
if (str == nullptr)
return;
__android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Load sqlite start\n");
mozglueresult rv = loadSQLiteLibs(str);
if (rv != SUCCESS) {
- JNI_Throw(jenv, "java/lang/Exception", "Error loading sqlite libraries");
+ JNI_ThrowLinkerError(jenv, "java/lang/Exception", "Error loading sqlite libraries");
}
__android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Load sqlite done\n");
jenv->ReleaseStringUTFChars(jApkName, str);
}
extern "C" APKOPEN_EXPORT void MOZ_JNICALL
Java_org_mozilla_gecko_mozglue_GeckoLoader_loadNSSLibsNative(JNIEnv *jenv, jclass jGeckoAppShellClass, jstring jApkName) {
const char* str;
@@ -357,17 +365,17 @@ Java_org_mozilla_gecko_mozglue_GeckoLoad
// better to do here
str = jenv->GetStringUTFChars(jApkName, nullptr);
if (str == nullptr)
return;
__android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Load nss start\n");
mozglueresult rv = loadNSSLibs(str);
if (rv != SUCCESS) {
- JNI_Throw(jenv, "java/lang/Exception", "Error loading nss libraries");
+ JNI_ThrowLinkerError(jenv, "java/lang/Exception", "Error loading nss libraries");
}
__android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Load nss done\n");
jenv->ReleaseStringUTFChars(jApkName, str);
}
static char**
CreateArgvFromObjectArray(JNIEnv *jenv, jobjectArray jargs, int* length)
{
--- a/mozglue/linker/ElfLoader.cpp
+++ b/mozglue/linker/ElfLoader.cpp
@@ -29,16 +29,18 @@
extern "C" {
inline int sigaltstack(const stack_t *ss, stack_t *oss) {
return syscall(__NR_sigaltstack, ss, oss);
}
} /* extern "C" */
#endif /* __ANDROID_API__ */
+
+char gLastLinkerError[256];
#endif /* ANDROID */
#ifdef __ARM_EABI__
extern "C" MOZ_EXPORT const void *
__gnu_Unwind_Find_exidx(void *pc, int *pcount) __attribute__((weak));
#endif
/* Ideally we'd #include <link.h>, but that's a world of pain
--- a/mozglue/linker/Logging.h
+++ b/mozglue/linker/Logging.h
@@ -5,19 +5,24 @@
#ifndef Logging_h
#define Logging_h
#include "mozilla/Likely.h"
#include "mozilla/MacroArgs.h"
#ifdef ANDROID
#include <android/log.h>
+#include <cstdio>
+extern char gLastLinkerError[256];
#define LOG(...) __android_log_print(ANDROID_LOG_INFO, "GeckoLinker", __VA_ARGS__)
#define WARN(...) __android_log_print(ANDROID_LOG_WARN, "GeckoLinker", __VA_ARGS__)
-#define ERROR(...) __android_log_print(ANDROID_LOG_ERROR, "GeckoLinker", __VA_ARGS__)
+#define ERROR(...) do { \
+ snprintf(gLastLinkerError, sizeof(gLastLinkerError), __VA_ARGS__); \
+ __android_log_write(ANDROID_LOG_ERROR, "GeckoLinker", gLastLinkerError); \
+ } while(0)
#else
#include <cstdio>
/* Expand to 1 or m depending on whether there is one argument or more
* given. */
#define MOZ_ONE_OR_MORE_ARGS_IMPL2(_1, _2, _3, _4, _5, _6, _7, _8, _9, N, ...) \
N
#define MOZ_ONE_OR_MORE_ARGS_IMPL(args) MOZ_ONE_OR_MORE_ARGS_IMPL2 args
--- a/mozglue/linker/Mappable.cpp
+++ b/mozglue/linker/Mappable.cpp
@@ -223,17 +223,17 @@ MappableExtractFile::Create(const char *
PROT_WRITE, MAP_SHARED, fd, 0));
if (buffer == MAP_FAILED) {
ERROR("Couldn't map %s to decompress library", file.get());
return nullptr;
}
const size_t written = xzStream.Decode(buffer, buffer.GetLength());
DEBUG_LOG("XZStream decoded %" PRIuPTR, written);
if (written != buffer.GetLength()) {
- ERROR("Error decoding XZ file %s", file.get());
+ ERROR("Error decoding XZ file %s", name);
return nullptr;
}
} else {
return nullptr;
}
validator.CacheChecksum();
return new MappableExtractFile(fd.forget(), file.release());