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 id16462
push userblassey@mozilla.com
push dateThu, 21 Oct 2010 00:44:42 +0000
treeherdermozilla-central@8fc42e3e185f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersted, blocking-fennec
bugs603592
milestone2.0b8pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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();