Bug 861141 - Connect Breakpad on Android to faulty.lib's mmap interface. r=glandium,ted

This commit is contained in:
Julian Seward 2013-04-15 16:46:43 +02:00
parent 3be2bb313f
commit 1f8653bbbc
3 changed files with 172 additions and 4 deletions

View File

@ -0,0 +1,50 @@
# HG changeset patch
# User Julian Seward <jseward@acm.org>
# 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 <iostream>
#include <string>
#include <vector>
#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<string>& 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<string>& debug_dirs,
+ SymbolData symbol_data,
+ Module** module);
+
} // namespace google_breakpad
#endif // COMMON_LINUX_DUMP_SYMBOLS_H__

View File

@ -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<string>& debug_dirs,
SymbolData symbol_data,
Module** module);
} // namespace google_breakpad
#endif // COMMON_LINUX_DUMP_SYMBOLS_H__

View File

@ -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 <dlfcn.h>
# include <sys/mman.h>
# 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<nsIProperties>
directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
if (!directoryService) return NULL;
nsCOMPtr<nsIFile> 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<string>& 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());