Bug 603592 - Report mapping to crash reporter, r=ted a=blocking-fennec
authorMichael Wu <mwu@mozilla.com>
Wed, 20 Oct 2010 20:44:03 -0400
changeset 56285 8fc42e3e185f22dbfbb13944f61c19d0f45e74c7
parent 56284 781d0b2374705e2863cbf147fa16f7fe75251a35
child 56286 a72ca32bac1d7e071fa21c526d2fc8fdd193981f
push idunknown
push userunknown
push dateunknown
reviewersted, blocking-fennec
bugs603592
milestone2.0b8pre
Bug 603592 - Report mapping to crash reporter, r=ted a=blocking-fennec
other-licenses/android/APKOpen.cpp
other-licenses/android/APKOpen.h
other-licenses/android/Makefile.in
other-licenses/android/linker.c
toolkit/mozapps/installer/packager.mk
toolkit/xre/nsAndroidStartup.cpp
--- a/other-licenses/android/APKOpen.cpp
+++ b/other-licenses/android/APKOpen.cpp
@@ -43,22 +43,25 @@
 #include <errno.h>
 #include <string.h>
 #include <stdio.h>
 #include <fcntl.h>
 #include <endian.h>
 #include <unistd.h>
 #include <zlib.h>
 #include "dlfcn.h"
+#include "APKOpen.h"
 
 /* compression methods */
 #define STORE    0
 #define DEFLATE  8
 #define LZMA    14
 
+#define NS_EXPORT __attribute__ ((visibility("default")))
+
 struct local_file_header {
   uint32_t signature;
   uint16_t min_version;
   uint16_t general_flag;
   uint16_t compression;
   uint16_t lastmod_time;
   uint16_t lastmod_date;
   uint32_t crc32;
@@ -101,16 +104,17 @@ struct cdir_end {
   uint32_t cdir_size;
   uint32_t cdir_offset;
   uint16_t comment_size;
   char     comment[0];
 } __attribute__((__packed__));
 
 static size_t zip_size;
 static int zip_fd;
+NS_EXPORT struct mapping_info * lib_mapping;
 
 static void * map_file (const char *file)
 {
   int fd = open(file, O_RDONLY);
   if (fd == -1) {
     __android_log_print(ANDROID_LOG_ERROR, "GeckoMapFile", "map_file open %s", strerror(errno));
     return NULL;
   }
@@ -168,18 +172,16 @@ static uint32_t simple_write(int fd, con
       }
     }
 
     out_offset += written;
   }
   return out_offset;
 }
 
-#define NS_EXPORT __attribute__ ((visibility("default")))
-
 #define SHELL_WRAPPER0(name) \
 typedef void (*name ## _t)(JNIEnv *, jclass); \
 static name ## _t f_ ## name; \
 extern "C" NS_EXPORT void JNICALL \
 Java_org_mozilla_gecko_GeckoAppShell_ ## name(JNIEnv *jenv, jclass jc) \
 { \
   f_ ## name(jenv, jc); \
 }
@@ -388,24 +390,67 @@ static void * mozload(const char * path,
   gettimeofday(&t1, 0);
   __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "%s: spent %d", path, (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) -
                (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec));
 #endif
 
   return handle;
 }
 
+static void *
+extractBuf(const char * path, void *zip,
+           struct cdir_entry *cdir_start, uint16_t cdir_entries)
+{
+  struct cdir_entry *entry = find_cdir_entry(cdir_start, cdir_entries, path);
+  struct local_file_header *file = (struct local_file_header *)(zip + letoh32(entry->offset));
+  void * data = ((void *)&file->data) + letoh16(file->filename_size) + letoh16(file->extra_field_size);
+
+  void * buf = malloc(letoh32(entry->uncompressed_size));
+  if (buf == (void *)-1) {
+    __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't alloc decompression buffer for %s", path);
+    return NULL;
+  }
+  if (letoh16(file->compression) == DEFLATE)
+    extractLib(entry, data, buf);
+  else
+    memcpy(buf, data, letoh32(entry->uncompressed_size));
+
+  return buf;
+}
+
+static int mapping_count = 0;
+static char *file_ids = NULL;
+
+#define MAX_MAPPING_INFO 32
+
+extern "C" void
+report_mapping(char *name, void *base, uint32_t len, uint32_t offset)
+{
+  if (!file_ids || mapping_count >= MAX_MAPPING_INFO)
+    return;
+
+  struct mapping_info *info = &lib_mapping[mapping_count++];
+  info->name = strdup(name);
+  info->base = (uintptr_t)base;
+  info->len = len;
+  info->offset = offset;
+
+  char * entry = strstr(file_ids, name);
+  if (entry)
+    info->file_id = strndup(entry + strlen(name) + 1, 32);
+}
+
 extern "C" void simple_linker_init(void);
 
 static void
 loadLibs(const char *apkName)
 {
-  simple_linker_init();
+  chdir("/data/data/org.mozilla.fennec");
 
-  chdir("/data/data/org.mozilla.fennec");
+  simple_linker_init();
 
   struct stat status;
   if (!stat(apkName, &status))
     apk_mtime = status.st_mtime;
 
 #ifdef DEBUG
   struct timeval t0, t1;
   gettimeofday(&t0, 0);
@@ -421,16 +466,21 @@ loadLibs(const char *apkName)
     return;
   }
 
   uint32_t cdir_offset = letoh32(dirend->cdir_offset);
   uint16_t cdir_entries = letoh16(dirend->cdir_entries);
 
   struct cdir_entry *cdir_start = (struct cdir_entry *)(zip + cdir_offset);
 
+#ifdef MOZ_CRASHREPORTER
+  lib_mapping = (struct mapping_info *)calloc(MAX_MAPPING_INFO, sizeof(*lib_mapping));
+  file_ids = (char *)extractBuf("lib.id", zip, cdir_start, cdir_entries);
+#endif
+
 #define MOZLOAD(name) mozload("lib/lib" name ".so", zip, cdir_start, cdir_entries)
   MOZLOAD("mozalloc");
   MOZLOAD("nspr4");
   MOZLOAD("plc4");
   MOZLOAD("plds4");
   MOZLOAD("mozsqlite3");
   MOZLOAD("nssutil3");
   MOZLOAD("nss3");
@@ -440,31 +490,35 @@ loadLibs(const char *apkName)
   MOZLOAD("xpcom");
   MOZLOAD("nssckbi");
   MOZLOAD("freebl3");
   MOZLOAD("softokn3");
 #undef MOZLOAD
 
   close(zip_fd);
 
+#ifdef MOZ_CRASHREPORTER
+  free(file_ids);
+  file_ids = NULL;
+#endif
+
   if (!xul_handle)
     __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't get a handle to libxul!");
 
 #define GETFUNC(name) f_ ## name = (name ## _t) __wrap_dlsym(xul_handle, "Java_org_mozilla_gecko_GeckoAppShell_" #name)
   GETFUNC(nativeInit);
   GETFUNC(nativeRun);
   GETFUNC(notifyGeckoOfEvent);
   GETFUNC(setSurfaceView);
   GETFUNC(setInitialSize);
   GETFUNC(onResume);
   GETFUNC(onLowMemory);
   GETFUNC(callObserver);
   GETFUNC(removeObserver);
 #undef GETFUNC
-
 #ifdef DEBUG
   gettimeofday(&t1, 0);
   __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "spent %d total",
              (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) -
              (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec));
   __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "All libraries loaded!");
 #endif
 }
new file mode 100644
--- /dev/null
+++ b/other-licenses/android/APKOpen.h
@@ -0,0 +1,50 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Michael Wu <mwu@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef APKOpen_h
+#define APKOpen_h
+
+struct mapping_info {
+  char * name;
+  char * file_id;
+  uintptr_t base;
+  size_t len;
+  size_t offset;
+};
+
+extern struct mapping_info * lib_mapping;
+
+#endif /* APKOpen_h */
--- a/other-licenses/android/Makefile.in
+++ b/other-licenses/android/Makefile.in
@@ -64,14 +64,16 @@ CSRCS = \
   ba.c \
   debugger.c \
   dlfcn.c \
   linker.c \
   linker_format.c \
   rt.c \
   $(NULL)
 
+EXPORTS = APKOpen.h
+
 EXTRA_DSO_LDOPTS += $(ZLIB_LIBS)
 
 WRAP_MALLOC_LIB =
 WRAP_MALLOC_CFLAGS =
 
 include $(topsrcdir)/config/rules.mk
--- a/other-licenses/android/linker.c
+++ b/other-licenses/android/linker.c
@@ -77,16 +77,18 @@
  * - after linking, set as much stuff as possible to READONLY
  *   and NOEXEC
  * - linker hardcodes PAGE_SIZE and PAGE_MASK because the kernel
  *   headers provide versions that are negative...
  * - allocate space for soinfo structs dynamically instead of
  *   having a hard limit (64)
 */
 
+/* Implemented in APKOpen */
+extern void report_mapping(char *name, void *base, uint32_t len, uint32_t offset);
 
 static int link_image(soinfo *si, unsigned wr_offset);
 
 static int socount = 0;
 static soinfo sopool[SO_MAX];
 static soinfo *freelist = NULL;
 static soinfo *solist = &libdl_info;
 static soinfo *sonext = &libdl_info;
@@ -130,27 +132,29 @@ struct _link_stats linker_stats;
 #if COUNT_PAGES
 unsigned bitmask[4096];
 #endif
 
 #ifndef PT_ARM_EXIDX
 #define PT_ARM_EXIDX    0x70000001      /* .ARM.exidx segment */
 #endif
 
+#ifndef MOZ_LINKER
 #define HOODLUM(name, ret, ...)                                               \
     ret name __VA_ARGS__                                                      \
     {                                                                         \
         char errstr[] = "ERROR: " #name " called from the dynamic linker!\n"; \
         write(2, errstr, sizeof(errstr));                                     \
         abort();                                                              \
     }
 HOODLUM(malloc, void *, (size_t size));
 HOODLUM(free, void, (void *ptr));
 HOODLUM(realloc, void *, (void *ptr, size_t size));
 HOODLUM(calloc, void *, (size_t cnt, size_t size));
+#endif
 
 static char tmp_err_buf[768];
 static char __linker_dl_err_buf[768];
 #define DL_ERR(fmt, x...)                                                     \
     do {                                                                      \
         format_buffer(__linker_dl_err_buf, sizeof(__linker_dl_err_buf),            \
                  "%s[%d]: " fmt, __func__, __LINE__, ##x);                    \
         ERROR(fmt "\n", ##x);                                                      \
@@ -940,16 +944,18 @@ load_segments(int fd, size_t offset, voi
                              offset + ((phdr->p_offset) & (~PAGE_MASK)));
             if (pbase == MAP_FAILED) {
                 DL_ERR("%d failed to map segment from '%s' @ 0x%08x (0x%08x). "
                       "p_vaddr=0x%08x p_offset=0x%08x", pid, si->name,
                       (unsigned)tmp, len, phdr->p_vaddr, phdr->p_offset);
                 goto fail;
             }
 
+            report_mapping(si->name, pbase, len, phdr->p_offset & (~PAGE_MASK));
+
             /* If 'len' didn't end on page boundary, and it's a writable
              * segment, zero-fill the rest. */
             if ((len & PAGE_MASK) && (phdr->p_flags & PF_W))
                 memset((void *)(pbase + len), 0, PAGE_SIZE - (len & PAGE_MASK));
 
             /* Check to see if we need to extend the map for this segment to
              * cover the diff between filesz and memsz (i.e. for bss).
              *
--- a/toolkit/mozapps/installer/packager.mk
+++ b/toolkit/mozapps/installer/packager.mk
@@ -165,16 +165,17 @@ DIST_FILES = \
   resources.arsc \
   AndroidManifest.xml \
   chrome \
   components \
   defaults \
   modules \
   res \
   lib \
+  lib.id \
   extensions \
   application.ini \
   platform.ini \
   greprefs.js \
   browserconfig.properties \
   blocklist.xml \
   chrome.manifest \
   update.locale \
@@ -195,16 +196,21 @@ endif
 PKG_SUFFIX      = .apk
 INNER_MAKE_PACKAGE	= \
   rm -f $(_ABS_DIST)/gecko.ap_ && \
   ( cd $(STAGEPATH)$(MOZ_PKG_DIR)$(_BINPATH) && \
     rm -rf lib && \
     mkdir -p lib/armeabi && \
     cp lib*.so lib && \
     mv lib/libmozutils.so lib/armeabi && \
+    rm -f lib.id && \
+    for SOMELIB in lib/*.so ; \
+    do \
+      printf "`basename $$SOMELIB`:`$(_ABS_DIST)/host/bin/file_id $$SOMELIB`\n" >> lib.id ; \
+    done && \
     $(ZIP) -r9D $(_ABS_DIST)/gecko.ap_ $(DIST_FILES) -x $(NON_DIST_FILES) ) && \
   rm -f $(_ABS_DIST)/gecko.apk && \
   $(APKBUILDER) $(_ABS_DIST)/gecko.apk -v $(APKBUILDER_FLAGS) -z $(_ABS_DIST)/gecko.ap_ -f $(STAGEPATH)$(MOZ_PKG_DIR)$(_BINPATH)/classes.dex && \
   cp $(_ABS_DIST)/gecko.apk $(_ABS_DIST)/gecko-unsigned-unaligned.apk && \
   $(JARSIGNER) $(_ABS_DIST)/gecko.apk && \
   $(ZIPALIGN) -f -v 4 $(_ABS_DIST)/gecko.apk $(PACKAGE)
 INNER_UNMAKE_PACKAGE	= \
   mkdir $(MOZ_PKG_DIR) && \
--- a/toolkit/xre/nsAndroidStartup.cpp
+++ b/toolkit/xre/nsAndroidStartup.cpp
@@ -47,16 +47,18 @@
 #include <string.h>
 #include <pthread.h>
 
 #include "nsTArray.h"
 #include "nsString.h"
 #include "nsILocalFile.h"
 #include "nsAppRunner.h"
 #include "AndroidBridge.h"
+#include "APKOpen.h"
+#include "nsExceptionHandler.h"
 
 #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, MOZ_APP_NAME, args)
 
 static pthread_t gGeckoThread = 0;
 
 struct AutoAttachJavaThread {
     AutoAttachJavaThread() {
         attached = mozilla_AndroidBridge_SetMainThread((void*)pthread_self());
@@ -67,16 +69,25 @@ struct AutoAttachJavaThread {
     }
 
     PRBool attached;
 };
 
 static void*
 GeckoStart(void *data)
 {
+#ifdef MOZ_CRASHREPORTER
+    struct mapping_info *info = lib_mapping;
+    while (info->name) {
+      CrashReporter::AddLibraryMapping(info->name, info->file_id, info->base,
+                                       info->len, info->offset);
+      info++;
+    }
+#endif
+
     AutoAttachJavaThread attacher;
     if (!attacher.attached)
         return 0;
 
     if (!data) {
         LOG("Failed to get arguments for GeckoStart\n");
         return 0;
     }
@@ -104,25 +115,24 @@ GeckoStart(void *data)
                          getter_AddRefs(xreDir));
     if (NS_FAILED(rv)) {
         LOG("Failed to create nsIFile for xreDirectory");
         return 0;
     }
 
     appData->xreDirectory = xreDir.get();
 
-
     nsTArray<char *> targs;
     char *arg = strtok(static_cast<char *>(data), " ");
     while (arg) {
         targs.AppendElement(arg);
         arg = strtok(NULL, " ");
     }
     targs.AppendElement(static_cast<char *>(nsnull));
-    
+
     int result = XRE_main(targs.Length() - 1, targs.Elements(), appData);
 
     if (result)
         LOG("XRE_main returned %d", result);
 
     XRE_FreeAppData(appData);
 
     mozilla::AndroidBridge::Bridge()->NotifyXreExit();