Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
1 // -*- mode: c++ -*-
3 // Copyright (c) 2011, Google Inc.
4 // All rights reserved.
5 //
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are
8 // met:
9 //
10 // * Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 // * Redistributions in binary form must reproduce the above
13 // copyright notice, this list of conditions and the following disclaimer
14 // in the documentation and/or other materials provided with the
15 // distribution.
16 // * Neither the name of Google Inc. nor the names of its
17 // contributors may be used to endorse or promote products derived from
18 // this software without specific prior written permission.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 // Author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
34 // dump_syms.mm: Create a symbol file for use with minidumps
36 #include "common/mac/dump_syms.h"
38 #include <Foundation/Foundation.h>
39 #include <mach-o/arch.h>
40 #include <mach-o/fat.h>
41 #include <stdio.h>
43 #include <ostream>
44 #include <string>
45 #include <vector>
47 #include "common/dwarf/bytereader-inl.h"
48 #include "common/dwarf/dwarf2reader.h"
49 #include "common/dwarf_cfi_to_module.h"
50 #include "common/dwarf_cu_to_module.h"
51 #include "common/dwarf_line_to_module.h"
52 #include "common/mac/file_id.h"
53 #include "common/mac/arch_utilities.h"
54 #include "common/mac/macho_reader.h"
55 #include "common/module.h"
56 #include "common/scoped_ptr.h"
57 #include "common/stabs_reader.h"
58 #include "common/stabs_to_module.h"
59 #include "common/symbol_data.h"
61 #ifndef CPU_TYPE_ARM
62 #define CPU_TYPE_ARM (static_cast<cpu_type_t>(12))
63 #endif // CPU_TYPE_ARM
65 using dwarf2reader::ByteReader;
66 using google_breakpad::DwarfCUToModule;
67 using google_breakpad::DwarfLineToModule;
68 using google_breakpad::FileID;
69 using google_breakpad::mach_o::FatReader;
70 using google_breakpad::mach_o::Section;
71 using google_breakpad::mach_o::Segment;
72 using google_breakpad::Module;
73 using google_breakpad::StabsReader;
74 using google_breakpad::StabsToModule;
75 using google_breakpad::scoped_ptr;
76 using std::make_pair;
77 using std::pair;
78 using std::string;
79 using std::vector;
81 namespace google_breakpad {
83 bool DumpSymbols::Read(NSString *filename) {
84 if (![[NSFileManager defaultManager] fileExistsAtPath:filename]) {
85 fprintf(stderr, "Object file does not exist: %s\n",
86 [filename fileSystemRepresentation]);
87 return false;
88 }
90 input_pathname_ = [filename retain];
92 // Does this filename refer to a dSYM bundle?
93 NSBundle *bundle = [NSBundle bundleWithPath:input_pathname_];
95 if (bundle) {
96 // Filenames referring to bundles usually have names of the form
97 // "<basename>.dSYM"; however, if the user has specified a wrapper
98 // suffix (the WRAPPER_SUFFIX and WRAPPER_EXTENSION build settings),
99 // then the name may have the form "<basename>.<extension>.dSYM". In
100 // either case, the resource name for the file containing the DWARF
101 // info within the bundle is <basename>.
102 //
103 // Since there's no way to tell how much to strip off, remove one
104 // extension at a time, and use the first one that
105 // pathForResource:ofType:inDirectory likes.
106 NSString *base_name = [input_pathname_ lastPathComponent];
107 NSString *dwarf_resource;
109 do {
110 NSString *new_base_name = [base_name stringByDeletingPathExtension];
112 // If stringByDeletingPathExtension returned the name unchanged, then
113 // there's nothing more for us to strip off --- lose.
114 if ([new_base_name isEqualToString:base_name]) {
115 fprintf(stderr, "Unable to find DWARF-bearing file in bundle: %s\n",
116 [input_pathname_ fileSystemRepresentation]);
117 return false;
118 }
120 // Take the shortened result as our new base_name.
121 base_name = new_base_name;
123 // Try to find a DWARF resource in the bundle under the new base_name.
124 dwarf_resource = [bundle pathForResource:base_name
125 ofType:nil inDirectory:@"DWARF"];
126 } while (!dwarf_resource);
128 object_filename_ = [dwarf_resource retain];
129 } else {
130 object_filename_ = [input_pathname_ retain];
131 }
133 // Read the file's contents into memory.
134 //
135 // The documentation for dataWithContentsOfMappedFile says:
136 //
137 // Because of file mapping restrictions, this method should only be
138 // used if the file is guaranteed to exist for the duration of the
139 // data object’s existence. It is generally safer to use the
140 // dataWithContentsOfFile: method.
141 //
142 // I gather this means that OS X doesn't have (or at least, that method
143 // doesn't use) a form of mapping like Linux's MAP_PRIVATE, where the
144 // process appears to get its own copy of the data, and changes to the
145 // file don't affect memory and vice versa).
146 NSError *error;
147 contents_ = [NSData dataWithContentsOfFile:object_filename_
148 options:0
149 error:&error];
150 if (!contents_) {
151 fprintf(stderr, "Error reading object file: %s: %s\n",
152 [object_filename_ fileSystemRepresentation],
153 [[error localizedDescription] UTF8String]);
154 return false;
155 }
156 [contents_ retain];
158 // Get the list of object files present in the file.
159 FatReader::Reporter fat_reporter([object_filename_
160 fileSystemRepresentation]);
161 FatReader fat_reader(&fat_reporter);
162 if (!fat_reader.Read(reinterpret_cast<const uint8_t *>([contents_ bytes]),
163 [contents_ length])) {
164 return false;
165 }
167 // Get our own copy of fat_reader's object file list.
168 size_t object_files_count;
169 const struct fat_arch *object_files =
170 fat_reader.object_files(&object_files_count);
171 if (object_files_count == 0) {
172 fprintf(stderr, "Fat binary file contains *no* architectures: %s\n",
173 [object_filename_ fileSystemRepresentation]);
174 return false;
175 }
176 object_files_.resize(object_files_count);
177 memcpy(&object_files_[0], object_files,
178 sizeof(struct fat_arch) * object_files_count);
180 return true;
181 }
183 bool DumpSymbols::SetArchitecture(cpu_type_t cpu_type,
184 cpu_subtype_t cpu_subtype) {
185 // Find the best match for the architecture the user requested.
186 const struct fat_arch *best_match
187 = NXFindBestFatArch(cpu_type, cpu_subtype, &object_files_[0],
188 static_cast<uint32_t>(object_files_.size()));
189 if (!best_match) return false;
191 // Record the selected object file.
192 selected_object_file_ = best_match;
193 return true;
194 }
196 bool DumpSymbols::SetArchitecture(const std::string &arch_name) {
197 bool arch_set = false;
198 const NXArchInfo *arch_info =
199 google_breakpad::BreakpadGetArchInfoFromName(arch_name.c_str());
200 if (arch_info) {
201 arch_set = SetArchitecture(arch_info->cputype, arch_info->cpusubtype);
202 }
203 return arch_set;
204 }
206 string DumpSymbols::Identifier() {
207 FileID file_id([object_filename_ fileSystemRepresentation]);
208 unsigned char identifier_bytes[16];
209 cpu_type_t cpu_type = selected_object_file_->cputype;
210 cpu_subtype_t cpu_subtype = selected_object_file_->cpusubtype;
211 if (!file_id.MachoIdentifier(cpu_type, cpu_subtype, identifier_bytes)) {
212 fprintf(stderr, "Unable to calculate UUID of mach-o binary %s!\n",
213 [object_filename_ fileSystemRepresentation]);
214 return "";
215 }
217 char identifier_string[40];
218 FileID::ConvertIdentifierToString(identifier_bytes, identifier_string,
219 sizeof(identifier_string));
221 string compacted(identifier_string);
222 for(size_t i = compacted.find('-'); i != string::npos;
223 i = compacted.find('-', i))
224 compacted.erase(i, 1);
226 return compacted;
227 }
229 // A line-to-module loader that accepts line number info parsed by
230 // dwarf2reader::LineInfo and populates a Module and a line vector
231 // with the results.
232 class DumpSymbols::DumperLineToModule:
233 public DwarfCUToModule::LineToModuleHandler {
234 public:
235 // Create a line-to-module converter using BYTE_READER.
236 DumperLineToModule(dwarf2reader::ByteReader *byte_reader)
237 : byte_reader_(byte_reader) { }
239 void StartCompilationUnit(const string& compilation_dir) {
240 compilation_dir_ = compilation_dir;
241 }
243 void ReadProgram(const char *program, uint64 length,
244 Module *module, vector<Module::Line> *lines) {
245 DwarfLineToModule handler(module, compilation_dir_, lines);
246 dwarf2reader::LineInfo parser(program, length, byte_reader_, &handler);
247 parser.Start();
248 }
249 private:
250 string compilation_dir_;
251 dwarf2reader::ByteReader *byte_reader_; // WEAK
252 };
254 bool DumpSymbols::ReadDwarf(google_breakpad::Module *module,
255 const mach_o::Reader &macho_reader,
256 const mach_o::SectionMap &dwarf_sections) const {
257 // Build a byte reader of the appropriate endianness.
258 ByteReader byte_reader(macho_reader.big_endian()
259 ? dwarf2reader::ENDIANNESS_BIG
260 : dwarf2reader::ENDIANNESS_LITTLE);
262 // Construct a context for this file.
263 DwarfCUToModule::FileContext file_context(selected_object_name_,
264 module);
266 // Build a dwarf2reader::SectionMap from our mach_o::SectionMap.
267 for (mach_o::SectionMap::const_iterator it = dwarf_sections.begin();
268 it != dwarf_sections.end(); it++) {
269 file_context.section_map[it->first] =
270 make_pair(reinterpret_cast<const char *>(it->second.contents.start),
271 it->second.contents.Size());
272 }
274 // Find the __debug_info section.
275 std::pair<const char *, uint64> debug_info_section
276 = file_context.section_map["__debug_info"];
277 // There had better be a __debug_info section!
278 if (!debug_info_section.first) {
279 fprintf(stderr, "%s: __DWARF segment of file has no __debug_info section\n",
280 selected_object_name_.c_str());
281 return false;
282 }
284 // Build a line-to-module loader for the root handler to use.
285 DumperLineToModule line_to_module(&byte_reader);
287 // Walk the __debug_info section, one compilation unit at a time.
288 uint64 debug_info_length = debug_info_section.second;
289 for (uint64 offset = 0; offset < debug_info_length;) {
290 // Make a handler for the root DIE that populates MODULE with the
291 // debug info.
292 DwarfCUToModule::WarningReporter reporter(selected_object_name_,
293 offset);
294 DwarfCUToModule root_handler(&file_context, &line_to_module, &reporter);
295 // Make a Dwarf2Handler that drives our DIEHandler.
296 dwarf2reader::DIEDispatcher die_dispatcher(&root_handler);
297 // Make a DWARF parser for the compilation unit at OFFSET.
298 dwarf2reader::CompilationUnit dwarf_reader(file_context.section_map,
299 offset,
300 &byte_reader,
301 &die_dispatcher);
302 // Process the entire compilation unit; get the offset of the next.
303 offset += dwarf_reader.Start();
304 }
306 return true;
307 }
309 bool DumpSymbols::ReadCFI(google_breakpad::Module *module,
310 const mach_o::Reader &macho_reader,
311 const mach_o::Section §ion,
312 bool eh_frame) const {
313 // Find the appropriate set of register names for this file's
314 // architecture.
315 vector<const UniqueString*> register_names;
316 switch (macho_reader.cpu_type()) {
317 case CPU_TYPE_X86:
318 register_names = DwarfCFIToModule::RegisterNames::I386();
319 break;
320 case CPU_TYPE_X86_64:
321 register_names = DwarfCFIToModule::RegisterNames::X86_64();
322 break;
323 case CPU_TYPE_ARM:
324 register_names = DwarfCFIToModule::RegisterNames::ARM();
325 break;
326 default: {
327 const NXArchInfo *arch = google_breakpad::BreakpadGetArchInfoFromCpuType(
328 macho_reader.cpu_type(), macho_reader.cpu_subtype());
329 fprintf(stderr, "%s: cannot convert DWARF call frame information for ",
330 selected_object_name_.c_str());
331 if (arch)
332 fprintf(stderr, "architecture '%s'", arch->name);
333 else
334 fprintf(stderr, "architecture %d,%d",
335 macho_reader.cpu_type(), macho_reader.cpu_subtype());
336 fprintf(stderr, " to Breakpad symbol file: no register name table\n");
337 return false;
338 }
339 }
341 // Find the call frame information and its size.
342 const char *cfi = reinterpret_cast<const char *>(section.contents.start);
343 size_t cfi_size = section.contents.Size();
345 // Plug together the parser, handler, and their entourages.
346 DwarfCFIToModule::Reporter module_reporter(selected_object_name_,
347 section.section_name);
348 DwarfCFIToModule handler(module, register_names, &module_reporter);
349 dwarf2reader::ByteReader byte_reader(macho_reader.big_endian() ?
350 dwarf2reader::ENDIANNESS_BIG :
351 dwarf2reader::ENDIANNESS_LITTLE);
352 byte_reader.SetAddressSize(macho_reader.bits_64() ? 8 : 4);
353 // At the moment, according to folks at Apple and some cursory
354 // investigation, Mac OS X only uses DW_EH_PE_pcrel-based pointers, so
355 // this is the only base address the CFI parser will need.
356 byte_reader.SetCFIDataBase(section.address, cfi);
358 dwarf2reader::CallFrameInfo::Reporter dwarf_reporter(selected_object_name_,
359 section.section_name);
360 dwarf2reader::CallFrameInfo parser(cfi, cfi_size,
361 &byte_reader, &handler, &dwarf_reporter,
362 eh_frame);
363 parser.Start();
364 return true;
365 }
367 // A LoadCommandHandler that loads whatever debugging data it finds into a
368 // Module.
369 class DumpSymbols::LoadCommandDumper:
370 public mach_o::Reader::LoadCommandHandler {
371 public:
372 // Create a load command dumper handling load commands from READER's
373 // file, and adding data to MODULE.
374 LoadCommandDumper(const DumpSymbols &dumper,
375 google_breakpad::Module *module,
376 const mach_o::Reader &reader,
377 SymbolData symbol_data)
378 : dumper_(dumper),
379 module_(module),
380 reader_(reader),
381 symbol_data_(symbol_data) { }
383 bool SegmentCommand(const mach_o::Segment &segment);
384 bool SymtabCommand(const ByteBuffer &entries, const ByteBuffer &strings);
386 private:
387 const DumpSymbols &dumper_;
388 google_breakpad::Module *module_; // WEAK
389 const mach_o::Reader &reader_;
390 const SymbolData symbol_data_;
391 };
393 bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment &segment) {
394 mach_o::SectionMap section_map;
395 if (!reader_.MapSegmentSections(segment, §ion_map))
396 return false;
398 if (segment.name == "__TEXT" && symbol_data_ != NO_CFI) {
399 module_->SetLoadAddress(segment.vmaddr);
400 mach_o::SectionMap::const_iterator eh_frame =
401 section_map.find("__eh_frame");
402 if (eh_frame != section_map.end()) {
403 // If there is a problem reading this, don't treat it as a fatal error.
404 dumper_.ReadCFI(module_, reader_, eh_frame->second, true);
405 }
406 return true;
407 }
409 if (segment.name == "__DWARF") {
410 if (symbol_data_ != ONLY_CFI) {
411 if (!dumper_.ReadDwarf(module_, reader_, section_map))
412 return false;
413 }
414 if (symbol_data_ != NO_CFI) {
415 mach_o::SectionMap::const_iterator debug_frame
416 = section_map.find("__debug_frame");
417 if (debug_frame != section_map.end()) {
418 // If there is a problem reading this, don't treat it as a fatal error.
419 dumper_.ReadCFI(module_, reader_, debug_frame->second, false);
420 }
421 }
422 }
424 return true;
425 }
427 bool DumpSymbols::LoadCommandDumper::SymtabCommand(const ByteBuffer &entries,
428 const ByteBuffer &strings) {
429 StabsToModule stabs_to_module(module_);
430 // Mac OS X STABS are never "unitized", and the size of the 'value' field
431 // matches the address size of the executable.
432 StabsReader stabs_reader(entries.start, entries.Size(),
433 strings.start, strings.Size(),
434 reader_.big_endian(),
435 reader_.bits_64() ? 8 : 4,
436 true,
437 &stabs_to_module);
438 if (!stabs_reader.Process())
439 return false;
440 stabs_to_module.Finalize();
441 return true;
442 }
444 bool DumpSymbols::ReadSymbolData(Module** out_module) {
445 // Select an object file, if SetArchitecture hasn't been called to set one
446 // explicitly.
447 if (!selected_object_file_) {
448 // If there's only one architecture, that's the one.
449 if (object_files_.size() == 1)
450 selected_object_file_ = &object_files_[0];
451 else {
452 // Look for an object file whose architecture matches our own.
453 const NXArchInfo *local_arch = NXGetLocalArchInfo();
454 if (!SetArchitecture(local_arch->cputype, local_arch->cpusubtype)) {
455 fprintf(stderr, "%s: object file contains more than one"
456 " architecture, none of which match the current"
457 " architecture; specify an architecture explicitly"
458 " with '-a ARCH' to resolve the ambiguity\n",
459 [object_filename_ fileSystemRepresentation]);
460 return false;
461 }
462 }
463 }
465 assert(selected_object_file_);
467 // Find the name of the selected file's architecture, to appear in
468 // the MODULE record and in error messages.
469 const NXArchInfo *selected_arch_info =
470 google_breakpad::BreakpadGetArchInfoFromCpuType(
471 selected_object_file_->cputype, selected_object_file_->cpusubtype);
473 const char *selected_arch_name = selected_arch_info->name;
474 if (strcmp(selected_arch_name, "i386") == 0)
475 selected_arch_name = "x86";
477 // Produce a name to use in error messages that includes the
478 // filename, and the architecture, if there is more than one.
479 selected_object_name_ = [object_filename_ UTF8String];
480 if (object_files_.size() > 1) {
481 selected_object_name_ += ", architecture ";
482 selected_object_name_ + selected_arch_name;
483 }
485 // Compute a module name, to appear in the MODULE record.
486 NSString *module_name = [object_filename_ lastPathComponent];
488 // Choose an identifier string, to appear in the MODULE record.
489 string identifier = Identifier();
490 if (identifier.empty())
491 return false;
492 identifier += "0";
494 // Create a module to hold the debugging information.
495 scoped_ptr<Module> module(new Module([module_name UTF8String],
496 "mac",
497 selected_arch_name,
498 identifier));
500 // Parse the selected object file.
501 mach_o::Reader::Reporter reporter(selected_object_name_);
502 mach_o::Reader reader(&reporter);
503 if (!reader.Read(reinterpret_cast<const uint8_t *>([contents_ bytes])
504 + selected_object_file_->offset,
505 selected_object_file_->size,
506 selected_object_file_->cputype,
507 selected_object_file_->cpusubtype))
508 return false;
510 // Walk its load commands, and deal with whatever is there.
511 LoadCommandDumper load_command_dumper(*this, module.get(), reader,
512 symbol_data_);
513 if (!reader.WalkLoadCommands(&load_command_dumper))
514 return false;
516 *out_module = module.release();
518 return true;
519 }
521 bool DumpSymbols::WriteSymbolFile(std::ostream &stream) {
522 Module* module = NULL;
524 if (ReadSymbolData(&module) && module) {
525 bool res = module->Write(stream, symbol_data_);
526 delete module;
527 return res;
528 }
530 return false;
531 }
533 } // namespace google_breakpad