tools/profiler/local_debug_info_symbolizer.cc

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/tools/profiler/local_debug_info_symbolizer.cc	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,307 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "PlatformMacros.h"
    1.10 +#include "nsAutoPtr.h"
    1.11 +
    1.12 +#if !defined(SPS_OS_windows)
    1.13 +# include "common/module.h"
    1.14 +# include "processor/cfi_frame_info.h"
    1.15 +#endif
    1.16 +#include "google_breakpad/processor/code_module.h"
    1.17 +#include "google_breakpad/processor/code_modules.h"
    1.18 +#include "google_breakpad/processor/stack_frame.h"
    1.19 +#include "common/logging.h"
    1.20 +
    1.21 +#if defined(SPS_PLAT_amd64_linux) || defined(SPS_PLAT_arm_android) \
    1.22 +    || defined(SPS_PLAT_x86_linux) || defined(SPS_PLAT_x86_android)
    1.23 +# include "common/linux/dump_symbols.h"
    1.24 +#elif defined(SPS_PLAT_amd64_darwin) || defined(SPS_PLAT_x86_darwin)
    1.25 +# include "shim_mac_dump_syms.h"
    1.26 +#elif defined(SPS_OS_windows)
    1.27 +  /* This is all stubbed out anyway, so don't do anything. */
    1.28 +#else
    1.29 +# error "Unknown platform"
    1.30 +#endif
    1.31 +
    1.32 +#if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)
    1.33 +# include "mozilla/Types.h"
    1.34 +# include "ElfLoader.h"
    1.35 +# include <dlfcn.h>
    1.36 +# include <sys/mman.h>
    1.37 +# include "nsString.h"
    1.38 +# include "nsDirectoryServiceUtils.h"
    1.39 +# include "nsDirectoryServiceDefs.h"
    1.40 +# include <sys/stat.h>
    1.41 +# include <fcntl.h>
    1.42 +#endif
    1.43 +
    1.44 +#include "local_debug_info_symbolizer.h"
    1.45 +
    1.46 +namespace google_breakpad {
    1.47 +
    1.48 +LocalDebugInfoSymbolizer::~LocalDebugInfoSymbolizer() {
    1.49 +# if !defined(SPS_OS_windows)
    1.50 +  for (SymbolMap::iterator it = symbols_.begin();
    1.51 +       it != symbols_.end();
    1.52 +       ++it) {
    1.53 +    delete it->second;
    1.54 +  }
    1.55 +# endif
    1.56 +}
    1.57 +
    1.58 +#if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)
    1.59 +
    1.60 +// Find out where the installation's lib directory is, since we'll
    1.61 +// have to look in there to get hold of libmozglue.so.  Returned
    1.62 +// C string is heap allocated and the caller must deallocate it.
    1.63 +static char* get_installation_lib_dir ( void )
    1.64 +{
    1.65 +  nsCOMPtr<nsIProperties>
    1.66 +    directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
    1.67 +  if (!directoryService) return NULL;
    1.68 +  nsCOMPtr<nsIFile> greDir;
    1.69 +  nsresult rv = directoryService->Get(NS_GRE_DIR, NS_GET_IID(nsIFile),
    1.70 +                                      getter_AddRefs(greDir));
    1.71 +  if (NS_FAILED(rv)) return NULL;
    1.72 +  nsCString path;
    1.73 +  rv = greDir->GetNativePath(path);
    1.74 +  if (NS_FAILED(rv)) return NULL;
    1.75 +  return strdup(path.get());
    1.76 +}
    1.77 +
    1.78 +// Read symbol data from a file on Android.  OBJ_FILENAME has
    1.79 +// three possible cases:
    1.80 +//
    1.81 +// (1) /foo/bar/xyzzy/blah.apk!/libwurble.so
    1.82 +//     We hand it as-is to faulty.lib and let it fish the relevant
    1.83 +//     bits out of the APK.
    1.84 +//
    1.85 +// (2) libmozglue.so
    1.86 +//     This is part of the Fennec installation, but is not in the
    1.87 +//     APK.  Instead we have to figure out the installation path
    1.88 +//     and look for it there. Because of faulty.lib limitations,
    1.89 +//     we have to use regular open/mmap instead of faulty.lib.
    1.90 +//
    1.91 +// (3) libanythingelse.so
    1.92 +//     faulty.lib assumes this is a system library, and prepends
    1.93 +//     "/system/lib/" to the path.  So as in (1), we can give it
    1.94 +//     as-is to faulty.lib.
    1.95 +//
    1.96 +// Hence only (2) requires special-casing here.
    1.97 +//
    1.98 +static bool ReadSymbolData_ANDROID(const string& obj_filename,
    1.99 +                                   const std::vector<string>& debug_dirs,
   1.100 +                                   SymbolData symbol_data,
   1.101 +                                   Module** module)
   1.102 +{
   1.103 +  string obj_file_to_use = obj_filename;
   1.104 +
   1.105 +  // Do (2) in the comment above.
   1.106 +  if (obj_file_to_use == "libmozglue.so") {
   1.107 +    char* libdir = get_installation_lib_dir();
   1.108 +    if (libdir) {
   1.109 +      obj_file_to_use = string(libdir) + "/lib/" + obj_file_to_use;
   1.110 +      free(libdir);
   1.111 +    }
   1.112 +
   1.113 +    // Use regular open/mmap here because of faulty.lib limitations
   1.114 +    int fd = open(obj_file_to_use.c_str(), O_RDONLY);
   1.115 +    if (fd == -1) {
   1.116 +      BPLOG(INFO) << "ReadSymbolData_APK: Failed to open \'"
   1.117 +                  << obj_file_to_use << "\'";
   1.118 +      return false;
   1.119 +    }
   1.120 +
   1.121 +    struct stat st;
   1.122 +    if (fstat(fd, &st) != 0) {
   1.123 +      close(fd);
   1.124 +      BPLOG(INFO) << "ReadSymbolData_APK: Failed to fstat \'"
   1.125 +                  << obj_file_to_use << "\'";
   1.126 +      return false;
   1.127 +    }
   1.128 +
   1.129 +    void* image = mmap(nullptr, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
   1.130 +    if (image == MAP_FAILED) {
   1.131 +      close(fd);
   1.132 +      BPLOG(INFO) << "ReadSymbolData_APK: Failed to mmap \'"
   1.133 +                  << obj_file_to_use << "\'";
   1.134 +      return false;
   1.135 +    }
   1.136 +
   1.137 +    bool ok = ReadSymbolDataInternal((const uint8_t*)image,
   1.138 +                                     obj_file_to_use, debug_dirs,
   1.139 +                                     symbol_data, module);
   1.140 +    munmap(image, st.st_size);
   1.141 +    close(fd);
   1.142 +    return ok;
   1.143 +  }
   1.144 +
   1.145 +  // Regardless of whether the file is inside an APK or not, we ask
   1.146 +  // faulty.lib to map it, then call ReadSymbolDataInternal, then
   1.147 +  // unmap and dlclose it.
   1.148 +  void* hdl = dlopen(obj_file_to_use.c_str(), RTLD_GLOBAL | RTLD_LAZY);
   1.149 +  if (!hdl) {
   1.150 +    BPLOG(INFO) << "ReadSymbolData_APK: Failed to get handle for ELF file \'"
   1.151 +                << obj_file_to_use << "\'";
   1.152 +    return false;
   1.153 +  }
   1.154 +
   1.155 +  size_t sz = __dl_get_mappable_length(hdl);
   1.156 +  if (sz == 0) {
   1.157 +    dlclose(hdl);
   1.158 +    BPLOG(INFO) << "ReadSymbolData_APK: Unable to get size for ELF file \'"
   1.159 +                << obj_file_to_use << "\'";
   1.160 +    return false;
   1.161 +  }
   1.162 +
   1.163 +  void* image = __dl_mmap(hdl, NULL, sz, 0);
   1.164 +  if (image == MAP_FAILED) {
   1.165 +    dlclose(hdl);
   1.166 +    BPLOG(INFO) << "ReadSymbolData_APK: Failed to mmap ELF file \'"
   1.167 +                << obj_file_to_use << "\'";
   1.168 +    return false;
   1.169 +  }
   1.170 +
   1.171 +  bool ok = ReadSymbolDataInternal((const uint8_t*)image,
   1.172 +                                   obj_file_to_use, debug_dirs,
   1.173 +                                   symbol_data, module);
   1.174 +  __dl_munmap(hdl, image, sz);
   1.175 +  dlclose(hdl);
   1.176 +
   1.177 +  return ok;
   1.178 +}
   1.179 +#endif /* defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK) */
   1.180 +
   1.181 +
   1.182 +StackFrameSymbolizer::SymbolizerResult
   1.183 +LocalDebugInfoSymbolizer::FillSourceLineInfo(const CodeModules* modules,
   1.184 +                                             const SystemInfo* system_info,
   1.185 +                                             StackFrame* frame) {
   1.186 +  if (!modules) {
   1.187 +    return kError;
   1.188 +  }
   1.189 +  const CodeModule* module = modules->GetModuleForAddress(frame->instruction);
   1.190 +  if (!module) {
   1.191 +    return kError;
   1.192 +  }
   1.193 +  frame->module = module;
   1.194 +
   1.195 +# if !defined(SPS_OS_windows)
   1.196 +  Module* debug_info_module = NULL;
   1.197 +  SymbolMap::const_iterator it = symbols_.find(module->code_file());
   1.198 +  if (it == symbols_.end()) {
   1.199 +    if (no_symbol_modules_.find(module->code_file()) !=
   1.200 +        no_symbol_modules_.end()) {
   1.201 +      return kNoError;
   1.202 +    }
   1.203 +
   1.204 +    bool ok = false;
   1.205 +#   if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)
   1.206 +    ok = ReadSymbolData_ANDROID(module->code_file(), debug_dirs_,
   1.207 +                                ONLY_CFI, &debug_info_module);
   1.208 +#   elif defined(SPS_PLAT_amd64_darwin) || defined(SPS_PLAT_x86_darwin)
   1.209 +    ok = ReadSymbolData_DARWIN(module->code_file(), debug_dirs_,
   1.210 +                        ONLY_CFI, &debug_info_module);
   1.211 +#   else
   1.212 +    ok = ReadSymbolData(module->code_file(), debug_dirs_,
   1.213 +                        ONLY_CFI, &debug_info_module);
   1.214 +#   endif
   1.215 +
   1.216 +    if (!ok) {
   1.217 +      if (debug_info_module)
   1.218 +        delete debug_info_module;
   1.219 +      no_symbol_modules_.insert(module->code_file());
   1.220 +      return kNoError;
   1.221 +    }
   1.222 +
   1.223 +    symbols_[module->code_file()] = debug_info_module;
   1.224 +  } else {
   1.225 +    debug_info_module = it->second;
   1.226 +  }
   1.227 +
   1.228 +  u_int64_t address = frame->instruction - frame->module->base_address();
   1.229 +  Module::Function* function =
   1.230 +      debug_info_module->FindFunctionByAddress(address);
   1.231 +  if (function) {
   1.232 +    frame->function_name = function->name;
   1.233 +    //TODO: line info: function->lines
   1.234 +  } else {
   1.235 +    Module::Extern* ex = debug_info_module->FindExternByAddress(address);
   1.236 +    if (ex) {
   1.237 +      frame->function_name = ex->name;
   1.238 +    }
   1.239 +  }
   1.240 +# endif /* !defined(SPS_OS_windows) */
   1.241 +  return kNoError;
   1.242 +}
   1.243 +
   1.244 +
   1.245 +WindowsFrameInfo* LocalDebugInfoSymbolizer::FindWindowsFrameInfo(
   1.246 +    const StackFrame* frame) {
   1.247 +  // Not currently implemented, would require PDBSourceLineWriter to
   1.248 +  // implement an API to return symbol data.
   1.249 +  return NULL;
   1.250 +}
   1.251 +
   1.252 +#if !defined(SPS_OS_windows)
   1.253 +// Taken wholesale from source_line_resolver_base.cc
   1.254 +bool ParseCFIRuleSet(const string& rule_set, CFIFrameInfo* frame_info) {
   1.255 +  CFIFrameInfoParseHandler handler(frame_info);
   1.256 +  CFIRuleParser parser(&handler);
   1.257 +  return parser.Parse(rule_set);
   1.258 +}
   1.259 +
   1.260 +static void ConvertCFI(const UniqueString* name, const Module::Expr& rule,
   1.261 +                       CFIFrameInfo* frame_info) {
   1.262 +  if (name == ustr__ZDcfa()) frame_info->SetCFARule(rule);
   1.263 +  else if (name == ustr__ZDra()) frame_info->SetRARule(rule);
   1.264 +  else frame_info->SetRegisterRule(name, rule);
   1.265 +}
   1.266 +
   1.267 +
   1.268 +static void ConvertCFI(const Module::RuleMap& rule_map,
   1.269 +                       CFIFrameInfo* frame_info) {
   1.270 +  for (Module::RuleMap::const_iterator it = rule_map.begin();
   1.271 +       it != rule_map.end(); ++it) {
   1.272 +    ConvertCFI(it->first, it->second, frame_info);
   1.273 +  }
   1.274 +}
   1.275 +#endif
   1.276 +
   1.277 +CFIFrameInfo* LocalDebugInfoSymbolizer::FindCFIFrameInfo(
   1.278 +    const StackFrame* frame) {
   1.279 +#if defined(SPS_OS_windows)
   1.280 +  return NULL;
   1.281 +#else
   1.282 +  if (!frame || !frame->module) return NULL;
   1.283 +
   1.284 +  SymbolMap::const_iterator it = symbols_.find(frame->module->code_file());
   1.285 +  if (it == symbols_.end()) return NULL;
   1.286 +
   1.287 +  Module* module = it->second;
   1.288 +  u_int64_t address = frame->instruction - frame->module->base_address();
   1.289 +  Module::StackFrameEntry* entry =
   1.290 +      module->FindStackFrameEntryByAddress(address);
   1.291 +  if (!entry)
   1.292 +    return NULL;
   1.293 +
   1.294 +  //TODO: can we cache this data per-address? does that make sense?
   1.295 +  // TODO: Maybe this should use google_breakpad::scoped_ptr, since we're in
   1.296 +  // "namespace google_breakpad". Not using scoped_ptr currently, because its
   1.297 +  // header triggers build warnings -- see bug 855010.
   1.298 +  nsAutoPtr<CFIFrameInfo> rules(new CFIFrameInfo());
   1.299 +  ConvertCFI(entry->initial_rules, rules);
   1.300 +  for (Module::RuleChangeMap::const_iterator delta_it =
   1.301 +           entry->rule_changes.begin();
   1.302 +       delta_it != entry->rule_changes.end() && delta_it->first < address;
   1.303 +       ++delta_it) {
   1.304 +    ConvertCFI(delta_it->second, rules);
   1.305 +  }
   1.306 +  return rules.forget();
   1.307 +#endif /* defined(SPS_OS_windows) */
   1.308 +}
   1.309 +
   1.310 +}  // namespace google_breakpad

mercurial