tools/profiler/local_debug_info_symbolizer.cc

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial