tools/profiler/local_debug_info_symbolizer.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "PlatformMacros.h"
     7 #include "nsAutoPtr.h"
     9 #if !defined(SPS_OS_windows)
    10 # include "common/module.h"
    11 # include "processor/cfi_frame_info.h"
    12 #endif
    13 #include "google_breakpad/processor/code_module.h"
    14 #include "google_breakpad/processor/code_modules.h"
    15 #include "google_breakpad/processor/stack_frame.h"
    16 #include "common/logging.h"
    18 #if defined(SPS_PLAT_amd64_linux) || defined(SPS_PLAT_arm_android) \
    19     || defined(SPS_PLAT_x86_linux) || defined(SPS_PLAT_x86_android)
    20 # include "common/linux/dump_symbols.h"
    21 #elif defined(SPS_PLAT_amd64_darwin) || defined(SPS_PLAT_x86_darwin)
    22 # include "shim_mac_dump_syms.h"
    23 #elif defined(SPS_OS_windows)
    24   /* This is all stubbed out anyway, so don't do anything. */
    25 #else
    26 # error "Unknown platform"
    27 #endif
    29 #if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)
    30 # include "mozilla/Types.h"
    31 # include "ElfLoader.h"
    32 # include <dlfcn.h>
    33 # include <sys/mman.h>
    34 # include "nsString.h"
    35 # include "nsDirectoryServiceUtils.h"
    36 # include "nsDirectoryServiceDefs.h"
    37 # include <sys/stat.h>
    38 # include <fcntl.h>
    39 #endif
    41 #include "local_debug_info_symbolizer.h"
    43 namespace google_breakpad {
    45 LocalDebugInfoSymbolizer::~LocalDebugInfoSymbolizer() {
    46 # if !defined(SPS_OS_windows)
    47   for (SymbolMap::iterator it = symbols_.begin();
    48        it != symbols_.end();
    49        ++it) {
    50     delete it->second;
    51   }
    52 # endif
    53 }
    55 #if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)
    57 // Find out where the installation's lib directory is, since we'll
    58 // have to look in there to get hold of libmozglue.so.  Returned
    59 // C string is heap allocated and the caller must deallocate it.
    60 static char* get_installation_lib_dir ( void )
    61 {
    62   nsCOMPtr<nsIProperties>
    63     directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
    64   if (!directoryService) return NULL;
    65   nsCOMPtr<nsIFile> greDir;
    66   nsresult rv = directoryService->Get(NS_GRE_DIR, NS_GET_IID(nsIFile),
    67                                       getter_AddRefs(greDir));
    68   if (NS_FAILED(rv)) return NULL;
    69   nsCString path;
    70   rv = greDir->GetNativePath(path);
    71   if (NS_FAILED(rv)) return NULL;
    72   return strdup(path.get());
    73 }
    75 // Read symbol data from a file on Android.  OBJ_FILENAME has
    76 // three possible cases:
    77 //
    78 // (1) /foo/bar/xyzzy/blah.apk!/libwurble.so
    79 //     We hand it as-is to faulty.lib and let it fish the relevant
    80 //     bits out of the APK.
    81 //
    82 // (2) libmozglue.so
    83 //     This is part of the Fennec installation, but is not in the
    84 //     APK.  Instead we have to figure out the installation path
    85 //     and look for it there. Because of faulty.lib limitations,
    86 //     we have to use regular open/mmap instead of faulty.lib.
    87 //
    88 // (3) libanythingelse.so
    89 //     faulty.lib assumes this is a system library, and prepends
    90 //     "/system/lib/" to the path.  So as in (1), we can give it
    91 //     as-is to faulty.lib.
    92 //
    93 // Hence only (2) requires special-casing here.
    94 //
    95 static bool ReadSymbolData_ANDROID(const string& obj_filename,
    96                                    const std::vector<string>& debug_dirs,
    97                                    SymbolData symbol_data,
    98                                    Module** module)
    99 {
   100   string obj_file_to_use = obj_filename;
   102   // Do (2) in the comment above.
   103   if (obj_file_to_use == "libmozglue.so") {
   104     char* libdir = get_installation_lib_dir();
   105     if (libdir) {
   106       obj_file_to_use = string(libdir) + "/lib/" + obj_file_to_use;
   107       free(libdir);
   108     }
   110     // Use regular open/mmap here because of faulty.lib limitations
   111     int fd = open(obj_file_to_use.c_str(), O_RDONLY);
   112     if (fd == -1) {
   113       BPLOG(INFO) << "ReadSymbolData_APK: Failed to open \'"
   114                   << obj_file_to_use << "\'";
   115       return false;
   116     }
   118     struct stat st;
   119     if (fstat(fd, &st) != 0) {
   120       close(fd);
   121       BPLOG(INFO) << "ReadSymbolData_APK: Failed to fstat \'"
   122                   << obj_file_to_use << "\'";
   123       return false;
   124     }
   126     void* image = mmap(nullptr, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
   127     if (image == MAP_FAILED) {
   128       close(fd);
   129       BPLOG(INFO) << "ReadSymbolData_APK: Failed to mmap \'"
   130                   << obj_file_to_use << "\'";
   131       return false;
   132     }
   134     bool ok = ReadSymbolDataInternal((const uint8_t*)image,
   135                                      obj_file_to_use, debug_dirs,
   136                                      symbol_data, module);
   137     munmap(image, st.st_size);
   138     close(fd);
   139     return ok;
   140   }
   142   // Regardless of whether the file is inside an APK or not, we ask
   143   // faulty.lib to map it, then call ReadSymbolDataInternal, then
   144   // unmap and dlclose it.
   145   void* hdl = dlopen(obj_file_to_use.c_str(), RTLD_GLOBAL | RTLD_LAZY);
   146   if (!hdl) {
   147     BPLOG(INFO) << "ReadSymbolData_APK: Failed to get handle for ELF file \'"
   148                 << obj_file_to_use << "\'";
   149     return false;
   150   }
   152   size_t sz = __dl_get_mappable_length(hdl);
   153   if (sz == 0) {
   154     dlclose(hdl);
   155     BPLOG(INFO) << "ReadSymbolData_APK: Unable to get size for ELF file \'"
   156                 << obj_file_to_use << "\'";
   157     return false;
   158   }
   160   void* image = __dl_mmap(hdl, NULL, sz, 0);
   161   if (image == MAP_FAILED) {
   162     dlclose(hdl);
   163     BPLOG(INFO) << "ReadSymbolData_APK: Failed to mmap ELF file \'"
   164                 << obj_file_to_use << "\'";
   165     return false;
   166   }
   168   bool ok = ReadSymbolDataInternal((const uint8_t*)image,
   169                                    obj_file_to_use, debug_dirs,
   170                                    symbol_data, module);
   171   __dl_munmap(hdl, image, sz);
   172   dlclose(hdl);
   174   return ok;
   175 }
   176 #endif /* defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK) */
   179 StackFrameSymbolizer::SymbolizerResult
   180 LocalDebugInfoSymbolizer::FillSourceLineInfo(const CodeModules* modules,
   181                                              const SystemInfo* system_info,
   182                                              StackFrame* frame) {
   183   if (!modules) {
   184     return kError;
   185   }
   186   const CodeModule* module = modules->GetModuleForAddress(frame->instruction);
   187   if (!module) {
   188     return kError;
   189   }
   190   frame->module = module;
   192 # if !defined(SPS_OS_windows)
   193   Module* debug_info_module = NULL;
   194   SymbolMap::const_iterator it = symbols_.find(module->code_file());
   195   if (it == symbols_.end()) {
   196     if (no_symbol_modules_.find(module->code_file()) !=
   197         no_symbol_modules_.end()) {
   198       return kNoError;
   199     }
   201     bool ok = false;
   202 #   if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)
   203     ok = ReadSymbolData_ANDROID(module->code_file(), debug_dirs_,
   204                                 ONLY_CFI, &debug_info_module);
   205 #   elif defined(SPS_PLAT_amd64_darwin) || defined(SPS_PLAT_x86_darwin)
   206     ok = ReadSymbolData_DARWIN(module->code_file(), debug_dirs_,
   207                         ONLY_CFI, &debug_info_module);
   208 #   else
   209     ok = ReadSymbolData(module->code_file(), debug_dirs_,
   210                         ONLY_CFI, &debug_info_module);
   211 #   endif
   213     if (!ok) {
   214       if (debug_info_module)
   215         delete debug_info_module;
   216       no_symbol_modules_.insert(module->code_file());
   217       return kNoError;
   218     }
   220     symbols_[module->code_file()] = debug_info_module;
   221   } else {
   222     debug_info_module = it->second;
   223   }
   225   u_int64_t address = frame->instruction - frame->module->base_address();
   226   Module::Function* function =
   227       debug_info_module->FindFunctionByAddress(address);
   228   if (function) {
   229     frame->function_name = function->name;
   230     //TODO: line info: function->lines
   231   } else {
   232     Module::Extern* ex = debug_info_module->FindExternByAddress(address);
   233     if (ex) {
   234       frame->function_name = ex->name;
   235     }
   236   }
   237 # endif /* !defined(SPS_OS_windows) */
   238   return kNoError;
   239 }
   242 WindowsFrameInfo* LocalDebugInfoSymbolizer::FindWindowsFrameInfo(
   243     const StackFrame* frame) {
   244   // Not currently implemented, would require PDBSourceLineWriter to
   245   // implement an API to return symbol data.
   246   return NULL;
   247 }
   249 #if !defined(SPS_OS_windows)
   250 // Taken wholesale from source_line_resolver_base.cc
   251 bool ParseCFIRuleSet(const string& rule_set, CFIFrameInfo* frame_info) {
   252   CFIFrameInfoParseHandler handler(frame_info);
   253   CFIRuleParser parser(&handler);
   254   return parser.Parse(rule_set);
   255 }
   257 static void ConvertCFI(const UniqueString* name, const Module::Expr& rule,
   258                        CFIFrameInfo* frame_info) {
   259   if (name == ustr__ZDcfa()) frame_info->SetCFARule(rule);
   260   else if (name == ustr__ZDra()) frame_info->SetRARule(rule);
   261   else frame_info->SetRegisterRule(name, rule);
   262 }
   265 static void ConvertCFI(const Module::RuleMap& rule_map,
   266                        CFIFrameInfo* frame_info) {
   267   for (Module::RuleMap::const_iterator it = rule_map.begin();
   268        it != rule_map.end(); ++it) {
   269     ConvertCFI(it->first, it->second, frame_info);
   270   }
   271 }
   272 #endif
   274 CFIFrameInfo* LocalDebugInfoSymbolizer::FindCFIFrameInfo(
   275     const StackFrame* frame) {
   276 #if defined(SPS_OS_windows)
   277   return NULL;
   278 #else
   279   if (!frame || !frame->module) return NULL;
   281   SymbolMap::const_iterator it = symbols_.find(frame->module->code_file());
   282   if (it == symbols_.end()) return NULL;
   284   Module* module = it->second;
   285   u_int64_t address = frame->instruction - frame->module->base_address();
   286   Module::StackFrameEntry* entry =
   287       module->FindStackFrameEntryByAddress(address);
   288   if (!entry)
   289     return NULL;
   291   //TODO: can we cache this data per-address? does that make sense?
   292   // TODO: Maybe this should use google_breakpad::scoped_ptr, since we're in
   293   // "namespace google_breakpad". Not using scoped_ptr currently, because its
   294   // header triggers build warnings -- see bug 855010.
   295   nsAutoPtr<CFIFrameInfo> rules(new CFIFrameInfo());
   296   ConvertCFI(entry->initial_rules, rules);
   297   for (Module::RuleChangeMap::const_iterator delta_it =
   298            entry->rule_changes.begin();
   299        delta_it != entry->rule_changes.end() && delta_it->first < address;
   300        ++delta_it) {
   301     ConvertCFI(delta_it->second, rules);
   302   }
   303   return rules.forget();
   304 #endif /* defined(SPS_OS_windows) */
   305 }
   307 }  // namespace google_breakpad

mercurial