diff --git a/toolkit/crashreporter/breakpad-patches/11-readsymboldatainternal-proto.patch b/toolkit/crashreporter/breakpad-patches/11-readsymboldatainternal-proto.patch new file mode 100644 index 000000000000..b91f9dced067 --- /dev/null +++ b/toolkit/crashreporter/breakpad-patches/11-readsymboldatainternal-proto.patch @@ -0,0 +1,50 @@ +# HG changeset patch +# User Julian Seward +# Date 1365953823 -7200 +# Node ID 21d2964d1337c0fce7375025610298a818ddbd0f +# Parent ef802a6418f25841880359e6dab3e8240bfd0821 +Bug 861141 - Connect Breakpad on Android to faulty.lib's mmap interface. r=ted. +Adds a prototype for ReadSymbolDataInternal so it can be called from +outside breakpad. + +diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.h b/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.h +--- a/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.h ++++ b/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.h +@@ -36,16 +36,17 @@ + #define COMMON_LINUX_DUMP_SYMBOLS_H__ + + #include + #include + #include + + #include "common/symbol_data.h" + #include "common/using_std_string.h" ++#include "google_breakpad/common/breakpad_types.h" + + namespace google_breakpad { + + class Module; + + // Find all the debugging information in OBJ_FILE, an ELF executable + // or shared library, and write it to SYM_STREAM in the Breakpad symbol + // file format. +@@ -60,11 +61,19 @@ bool WriteSymbolFile(const string &obj_f + // As above, but simply return the debugging information in MODULE + // instead of writing it to a stream. The caller owns the resulting + // Module object and must delete it when finished. + bool ReadSymbolData(const string& obj_file, + const std::vector& debug_dirs, + SymbolData symbol_data, + Module** module); + ++// Same as ReadSymbolData, except don't try to open the file; instead ++// just use the in-memory data (mapped image of it) located at OBJ_FILE. ++bool ReadSymbolDataInternal(const uint8_t* obj_file, ++ const string& obj_filename, ++ const std::vector& debug_dirs, ++ SymbolData symbol_data, ++ Module** module); ++ + } // namespace google_breakpad + + #endif // COMMON_LINUX_DUMP_SYMBOLS_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.h b/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.h index f3c92cd5005c..229657117361 100644 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.h +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.h @@ -41,6 +41,7 @@ #include "common/symbol_data.h" #include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" namespace google_breakpad { @@ -65,6 +66,14 @@ bool ReadSymbolData(const string& obj_file, SymbolData symbol_data, Module** module); +// Same as ReadSymbolData, except don't try to open the file; instead +// just use the in-memory data (mapped image of it) located at OBJ_FILE. +bool ReadSymbolDataInternal(const uint8_t* obj_file, + const string& obj_filename, + const std::vector& debug_dirs, + SymbolData symbol_data, + Module** module); + } // namespace google_breakpad #endif // COMMON_LINUX_DUMP_SYMBOLS_H__ diff --git a/tools/profiler/local_debug_info_symbolizer.cc b/tools/profiler/local_debug_info_symbolizer.cc index cbe8520aa4ba..650b9599378e 100644 --- a/tools/profiler/local_debug_info_symbolizer.cc +++ b/tools/profiler/local_debug_info_symbolizer.cc @@ -26,6 +26,16 @@ # error "Unknown platform" #endif +#if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK) +# include "mozilla/Types.h" +# include "ElfLoader.h" +# include +# include +# include "nsString.h" +# include "nsDirectoryServiceUtils.h" +# include "nsDirectoryServiceDefs.h" +#endif + #include "local_debug_info_symbolizer.h" namespace google_breakpad { @@ -40,6 +50,98 @@ LocalDebugInfoSymbolizer::~LocalDebugInfoSymbolizer() { # endif } +#if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK) + +// Find out where the installation's lib directory is, since we'll +// have to look in there to get hold of libmozglue.so. Returned +// C string is heap allocated and the caller must deallocate it. +static char* get_installation_lib_dir ( void ) +{ + nsCOMPtr + directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID)); + if (!directoryService) return NULL; + nsCOMPtr greDir; + nsresult rv = directoryService->Get(NS_GRE_DIR, NS_GET_IID(nsIFile), + getter_AddRefs(greDir)); + if (NS_FAILED(rv)) return NULL; + nsCString path; + rv = greDir->GetNativePath(path); + if (NS_FAILED(rv)) return NULL; + return strdup(path.get()); +} + +// Read symbol data from a file on Android. OBJ_FILENAME has +// three possible cases: +// +// (1) /foo/bar/xyzzy/blah.apk!/libwurble.so +// We hand it as-is to faulty.lib and let it fish the relevant +// bits out of the APK. +// +// (2) libmozglue.so +// This is part of the Fennec installation, but is not in the +// APK. Instead we have to figure out the installation path +// and look for it there. +// +// (3) libanythingelse.so +// faulty.lib assumes this is a system library, and prepends +// "/system/lib/" to the path. So as in (1), we can give it +// as-is to faulty.lib. +// +// Hence only (2) requires special-casing here. +// +static bool ReadSymbolData_ANDROID(const string& obj_filename, + const std::vector& debug_dirs, + SymbolData symbol_data, + Module** module) +{ + string obj_file_to_use = obj_filename; + + // Do (2) in the comment above. + if (obj_file_to_use == "libmozglue.so") { + char* libdir = get_installation_lib_dir(); + if (libdir) { + obj_file_to_use = string(libdir) + "/lib/" + obj_file_to_use; + free(libdir); + } + } + + // Regardless of whether the file is inside an APK or not, we ask + // faulty.lib to map it, then call ReadSymbolDataInternal, then + // unmap and dlclose it. + void* hdl = dlopen(obj_file_to_use.c_str(), RTLD_GLOBAL | RTLD_LAZY); + if (!hdl) { + BPLOG(INFO) << "ReadSymbolData_APK: Failed to get handle for ELF file \'" + << obj_file_to_use << "\'"; + return false; + } + + size_t sz = __dl_get_mappable_length(hdl); + if (sz == 0) { + dlclose(hdl); + BPLOG(INFO) << "ReadSymbolData_APK: Unable to get size for ELF file \'" + << obj_file_to_use << "\'"; + return false; + } + + void* image = __dl_mmap(hdl, NULL, sz, 0); + if (image == MAP_FAILED) { + dlclose(hdl); + BPLOG(INFO) << "ReadSymbolData_APK: Failed to mmap ELF file \'" + << obj_file_to_use << "\'"; + return false; + } + + bool ok = ReadSymbolDataInternal((const uint8_t*)image, + obj_file_to_use, debug_dirs, + symbol_data, module); + __dl_munmap(hdl, image, sz); + dlclose(hdl); + + return ok; +} +#endif /* defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK) */ + + StackFrameSymbolizer::SymbolizerResult LocalDebugInfoSymbolizer::FillSourceLineInfo(const CodeModules* modules, const SystemInfo* system_info, @@ -61,10 +163,17 @@ LocalDebugInfoSymbolizer::FillSourceLineInfo(const CodeModules* modules, no_symbol_modules_.end()) { return kNoError; } - if (!ReadSymbolData(module->code_file(), - debug_dirs_, - ONLY_CFI, - &debug_info_module)) { + + bool ok = false; +# if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK) + ok = ReadSymbolData_ANDROID(module->code_file(), debug_dirs_, + ONLY_CFI, &debug_info_module); +# else + ok = ReadSymbolData(module->code_file(), debug_dirs_, + ONLY_CFI, &debug_info_module); +# endif + + if (!ok) { if (debug_info_module) delete debug_info_module; no_symbol_modules_.insert(module->code_file());