toolkit/crashreporter/google-breakpad/src/common/mac/macho_reader.cc

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

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.

michael@0 1 // Copyright (c) 2010, Google Inc.
michael@0 2 // All rights reserved.
michael@0 3 //
michael@0 4 // Redistribution and use in source and binary forms, with or without
michael@0 5 // modification, are permitted provided that the following conditions are
michael@0 6 // met:
michael@0 7 //
michael@0 8 // * Redistributions of source code must retain the above copyright
michael@0 9 // notice, this list of conditions and the following disclaimer.
michael@0 10 // * Redistributions in binary form must reproduce the above
michael@0 11 // copyright notice, this list of conditions and the following disclaimer
michael@0 12 // in the documentation and/or other materials provided with the
michael@0 13 // distribution.
michael@0 14 // * Neither the name of Google Inc. nor the names of its
michael@0 15 // contributors may be used to endorse or promote products derived from
michael@0 16 // this software without specific prior written permission.
michael@0 17 //
michael@0 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
michael@0 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
michael@0 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
michael@0 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
michael@0 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
michael@0 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
michael@0 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
michael@0 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
michael@0 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
michael@0 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
michael@0 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
michael@0 29
michael@0 30 // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
michael@0 31
michael@0 32 // macho_reader.cc: Implementation of google_breakpad::Mach_O::FatReader and
michael@0 33 // google_breakpad::Mach_O::Reader. See macho_reader.h for details.
michael@0 34
michael@0 35 #include "common/mac/macho_reader.h"
michael@0 36
michael@0 37 #include <assert.h>
michael@0 38 #include <stdio.h>
michael@0 39 #include <stdlib.h>
michael@0 40
michael@0 41 // Unfortunately, CPU_TYPE_ARM is not define for 10.4.
michael@0 42 #if !defined(CPU_TYPE_ARM)
michael@0 43 #define CPU_TYPE_ARM 12
michael@0 44 #endif
michael@0 45
michael@0 46 namespace google_breakpad {
michael@0 47 namespace mach_o {
michael@0 48
michael@0 49 // If NDEBUG is #defined, then the 'assert' macro doesn't evaluate its
michael@0 50 // arguments, so you can't place expressions that do necessary work in
michael@0 51 // the argument of an assert. Nor can you assign the result of the
michael@0 52 // expression to a variable and assert that the variable's value is
michael@0 53 // true: you'll get unused variable warnings when NDEBUG is #defined.
michael@0 54 //
michael@0 55 // ASSERT_ALWAYS_EVAL always evaluates its argument, and asserts that
michael@0 56 // the result is true if NDEBUG is not #defined.
michael@0 57 #if defined(NDEBUG)
michael@0 58 #define ASSERT_ALWAYS_EVAL(x) (x)
michael@0 59 #else
michael@0 60 #define ASSERT_ALWAYS_EVAL(x) assert(x)
michael@0 61 #endif
michael@0 62
michael@0 63 void FatReader::Reporter::BadHeader() {
michael@0 64 fprintf(stderr, "%s: file is neither a fat binary file"
michael@0 65 " nor a Mach-O object file\n", filename_.c_str());
michael@0 66 }
michael@0 67
michael@0 68 void FatReader::Reporter::TooShort() {
michael@0 69 fprintf(stderr, "%s: file too short for the data it claims to contain\n",
michael@0 70 filename_.c_str());
michael@0 71 }
michael@0 72
michael@0 73 void FatReader::Reporter::MisplacedObjectFile() {
michael@0 74 fprintf(stderr, "%s: file too short for the object files it claims"
michael@0 75 " to contain\n", filename_.c_str());
michael@0 76 }
michael@0 77
michael@0 78 bool FatReader::Read(const uint8_t *buffer, size_t size) {
michael@0 79 buffer_.start = buffer;
michael@0 80 buffer_.end = buffer + size;
michael@0 81 ByteCursor cursor(&buffer_);
michael@0 82
michael@0 83 // Fat binaries always use big-endian, so read the magic number in
michael@0 84 // that endianness. To recognize Mach-O magic numbers, which can use
michael@0 85 // either endianness, check for both the proper and reversed forms
michael@0 86 // of the magic numbers.
michael@0 87 cursor.set_big_endian(true);
michael@0 88 if (cursor >> magic_) {
michael@0 89 if (magic_ == FAT_MAGIC) {
michael@0 90 // How many object files does this fat binary contain?
michael@0 91 uint32_t object_files_count;
michael@0 92 if (!(cursor >> object_files_count)) { // nfat_arch
michael@0 93 reporter_->TooShort();
michael@0 94 return false;
michael@0 95 }
michael@0 96
michael@0 97 // Read the list of object files.
michael@0 98 object_files_.resize(object_files_count);
michael@0 99 for (size_t i = 0; i < object_files_count; i++) {
michael@0 100 struct fat_arch *objfile = &object_files_[i];
michael@0 101
michael@0 102 // Read this object file entry, byte-swapping as appropriate.
michael@0 103 cursor >> objfile->cputype
michael@0 104 >> objfile->cpusubtype
michael@0 105 >> objfile->offset
michael@0 106 >> objfile->size
michael@0 107 >> objfile->align;
michael@0 108 if (!cursor) {
michael@0 109 reporter_->TooShort();
michael@0 110 return false;
michael@0 111 }
michael@0 112 // Does the file actually have the bytes this entry refers to?
michael@0 113 size_t fat_size = buffer_.Size();
michael@0 114 if (objfile->offset > fat_size ||
michael@0 115 objfile->size > fat_size - objfile->offset) {
michael@0 116 reporter_->MisplacedObjectFile();
michael@0 117 return false;
michael@0 118 }
michael@0 119 }
michael@0 120
michael@0 121 return true;
michael@0 122 } else if (magic_ == MH_MAGIC || magic_ == MH_MAGIC_64 ||
michael@0 123 magic_ == MH_CIGAM || magic_ == MH_CIGAM_64) {
michael@0 124 // If this is a little-endian Mach-O file, fix the cursor's endianness.
michael@0 125 if (magic_ == MH_CIGAM || magic_ == MH_CIGAM_64)
michael@0 126 cursor.set_big_endian(false);
michael@0 127 // Record the entire file as a single entry in the object file list.
michael@0 128 object_files_.resize(1);
michael@0 129
michael@0 130 // Get the cpu type and subtype from the Mach-O header.
michael@0 131 if (!(cursor >> object_files_[0].cputype
michael@0 132 >> object_files_[0].cpusubtype)) {
michael@0 133 reporter_->TooShort();
michael@0 134 return false;
michael@0 135 }
michael@0 136
michael@0 137 object_files_[0].offset = 0;
michael@0 138 object_files_[0].size = static_cast<uint32_t>(buffer_.Size());
michael@0 139 // This alignment is correct for 32 and 64-bit x86 and ppc.
michael@0 140 // See get_align in the lipo source for other architectures:
michael@0 141 // http://www.opensource.apple.com/source/cctools/cctools-773/misc/lipo.c
michael@0 142 object_files_[0].align = 12; // 2^12 == 4096
michael@0 143
michael@0 144 return true;
michael@0 145 }
michael@0 146 }
michael@0 147
michael@0 148 reporter_->BadHeader();
michael@0 149 return false;
michael@0 150 }
michael@0 151
michael@0 152 void Reader::Reporter::BadHeader() {
michael@0 153 fprintf(stderr, "%s: file is not a Mach-O object file\n", filename_.c_str());
michael@0 154 }
michael@0 155
michael@0 156 void Reader::Reporter::CPUTypeMismatch(cpu_type_t cpu_type,
michael@0 157 cpu_subtype_t cpu_subtype,
michael@0 158 cpu_type_t expected_cpu_type,
michael@0 159 cpu_subtype_t expected_cpu_subtype) {
michael@0 160 fprintf(stderr, "%s: CPU type %d, subtype %d does not match expected"
michael@0 161 " type %d, subtype %d\n",
michael@0 162 filename_.c_str(), cpu_type, cpu_subtype,
michael@0 163 expected_cpu_type, expected_cpu_subtype);
michael@0 164 }
michael@0 165
michael@0 166 void Reader::Reporter::HeaderTruncated() {
michael@0 167 fprintf(stderr, "%s: file does not contain a complete Mach-O header\n",
michael@0 168 filename_.c_str());
michael@0 169 }
michael@0 170
michael@0 171 void Reader::Reporter::LoadCommandRegionTruncated() {
michael@0 172 fprintf(stderr, "%s: file too short to hold load command region"
michael@0 173 " given in Mach-O header\n", filename_.c_str());
michael@0 174 }
michael@0 175
michael@0 176 void Reader::Reporter::LoadCommandsOverrun(size_t claimed, size_t i,
michael@0 177 LoadCommandType type) {
michael@0 178 fprintf(stderr, "%s: file's header claims there are %ld"
michael@0 179 " load commands, but load command #%ld",
michael@0 180 filename_.c_str(), claimed, i);
michael@0 181 if (type) fprintf(stderr, ", of type %d,", type);
michael@0 182 fprintf(stderr, " extends beyond the end of the load command region\n");
michael@0 183 }
michael@0 184
michael@0 185 void Reader::Reporter::LoadCommandTooShort(size_t i, LoadCommandType type) {
michael@0 186 fprintf(stderr, "%s: the contents of load command #%ld, of type %d,"
michael@0 187 " extend beyond the size given in the load command's header\n",
michael@0 188 filename_.c_str(), i, type);
michael@0 189 }
michael@0 190
michael@0 191 void Reader::Reporter::SectionsMissing(const string &name) {
michael@0 192 fprintf(stderr, "%s: the load command for segment '%s'"
michael@0 193 " is too short to hold the section headers it claims to have\n",
michael@0 194 filename_.c_str(), name.c_str());
michael@0 195 }
michael@0 196
michael@0 197 void Reader::Reporter::MisplacedSegmentData(const string &name) {
michael@0 198 fprintf(stderr, "%s: the segment '%s' claims its contents lie beyond"
michael@0 199 " the end of the file\n", filename_.c_str(), name.c_str());
michael@0 200 }
michael@0 201
michael@0 202 void Reader::Reporter::MisplacedSectionData(const string &section,
michael@0 203 const string &segment) {
michael@0 204 fprintf(stderr, "%s: the section '%s' in segment '%s'"
michael@0 205 " claims its contents lie outside the segment's contents\n",
michael@0 206 filename_.c_str(), section.c_str(), segment.c_str());
michael@0 207 }
michael@0 208
michael@0 209 void Reader::Reporter::MisplacedSymbolTable() {
michael@0 210 fprintf(stderr, "%s: the LC_SYMTAB load command claims that the symbol"
michael@0 211 " table's contents are located beyond the end of the file\n",
michael@0 212 filename_.c_str());
michael@0 213 }
michael@0 214
michael@0 215 void Reader::Reporter::UnsupportedCPUType(cpu_type_t cpu_type) {
michael@0 216 fprintf(stderr, "%s: CPU type %d is not supported\n",
michael@0 217 filename_.c_str(), cpu_type);
michael@0 218 }
michael@0 219
michael@0 220 bool Reader::Read(const uint8_t *buffer,
michael@0 221 size_t size,
michael@0 222 cpu_type_t expected_cpu_type,
michael@0 223 cpu_subtype_t expected_cpu_subtype) {
michael@0 224 assert(!buffer_.start);
michael@0 225 buffer_.start = buffer;
michael@0 226 buffer_.end = buffer + size;
michael@0 227 ByteCursor cursor(&buffer_, true);
michael@0 228 uint32_t magic;
michael@0 229 if (!(cursor >> magic)) {
michael@0 230 reporter_->HeaderTruncated();
michael@0 231 return false;
michael@0 232 }
michael@0 233
michael@0 234 if (expected_cpu_type != CPU_TYPE_ANY) {
michael@0 235 uint32_t expected_magic;
michael@0 236 // validate that magic matches the expected cpu type
michael@0 237 switch (expected_cpu_type) {
michael@0 238 case CPU_TYPE_ARM:
michael@0 239 case CPU_TYPE_I386:
michael@0 240 expected_magic = MH_CIGAM;
michael@0 241 break;
michael@0 242 case CPU_TYPE_POWERPC:
michael@0 243 expected_magic = MH_MAGIC;
michael@0 244 break;
michael@0 245 case CPU_TYPE_X86_64:
michael@0 246 expected_magic = MH_CIGAM_64;
michael@0 247 break;
michael@0 248 case CPU_TYPE_POWERPC64:
michael@0 249 expected_magic = MH_MAGIC_64;
michael@0 250 break;
michael@0 251 default:
michael@0 252 reporter_->UnsupportedCPUType(expected_cpu_type);
michael@0 253 return false;
michael@0 254 }
michael@0 255
michael@0 256 if (expected_magic != magic) {
michael@0 257 reporter_->BadHeader();
michael@0 258 return false;
michael@0 259 }
michael@0 260 }
michael@0 261
michael@0 262 // Since the byte cursor is in big-endian mode, a reversed magic number
michael@0 263 // always indicates a little-endian file, regardless of our own endianness.
michael@0 264 switch (magic) {
michael@0 265 case MH_MAGIC: big_endian_ = true; bits_64_ = false; break;
michael@0 266 case MH_CIGAM: big_endian_ = false; bits_64_ = false; break;
michael@0 267 case MH_MAGIC_64: big_endian_ = true; bits_64_ = true; break;
michael@0 268 case MH_CIGAM_64: big_endian_ = false; bits_64_ = true; break;
michael@0 269 default:
michael@0 270 reporter_->BadHeader();
michael@0 271 return false;
michael@0 272 }
michael@0 273 cursor.set_big_endian(big_endian_);
michael@0 274 uint32_t commands_size, reserved;
michael@0 275 cursor >> cpu_type_ >> cpu_subtype_ >> file_type_ >> load_command_count_
michael@0 276 >> commands_size >> flags_;
michael@0 277 if (bits_64_)
michael@0 278 cursor >> reserved;
michael@0 279 if (!cursor) {
michael@0 280 reporter_->HeaderTruncated();
michael@0 281 return false;
michael@0 282 }
michael@0 283
michael@0 284 if (expected_cpu_type != CPU_TYPE_ANY &&
michael@0 285 (expected_cpu_type != cpu_type_ ||
michael@0 286 expected_cpu_subtype != cpu_subtype_)) {
michael@0 287 reporter_->CPUTypeMismatch(cpu_type_, cpu_subtype_,
michael@0 288 expected_cpu_type, expected_cpu_subtype);
michael@0 289 return false;
michael@0 290 }
michael@0 291
michael@0 292 cursor
michael@0 293 .PointTo(&load_commands_.start, commands_size)
michael@0 294 .PointTo(&load_commands_.end, 0);
michael@0 295 if (!cursor) {
michael@0 296 reporter_->LoadCommandRegionTruncated();
michael@0 297 return false;
michael@0 298 }
michael@0 299
michael@0 300 return true;
michael@0 301 }
michael@0 302
michael@0 303 bool Reader::WalkLoadCommands(Reader::LoadCommandHandler *handler) const {
michael@0 304 ByteCursor list_cursor(&load_commands_, big_endian_);
michael@0 305
michael@0 306 for (size_t index = 0; index < load_command_count_; ++index) {
michael@0 307 // command refers to this load command alone, so that cursor will
michael@0 308 // refuse to read past the load command's end. But since we haven't
michael@0 309 // read the size yet, let command initially refer to the entire
michael@0 310 // remainder of the load command series.
michael@0 311 ByteBuffer command(list_cursor.here(), list_cursor.Available());
michael@0 312 ByteCursor cursor(&command, big_endian_);
michael@0 313
michael@0 314 // Read the command type and size --- fields common to all commands.
michael@0 315 uint32_t type, size;
michael@0 316 if (!(cursor >> type)) {
michael@0 317 reporter_->LoadCommandsOverrun(load_command_count_, index, 0);
michael@0 318 return false;
michael@0 319 }
michael@0 320 if (!(cursor >> size) || size > command.Size()) {
michael@0 321 reporter_->LoadCommandsOverrun(load_command_count_, index, type);
michael@0 322 return false;
michael@0 323 }
michael@0 324
michael@0 325 // Now that we've read the length, restrict command's range to this
michael@0 326 // load command only.
michael@0 327 command.end = command.start + size;
michael@0 328
michael@0 329 switch (type) {
michael@0 330 case LC_SEGMENT:
michael@0 331 case LC_SEGMENT_64: {
michael@0 332 Segment segment;
michael@0 333 segment.bits_64 = (type == LC_SEGMENT_64);
michael@0 334 size_t word_size = segment.bits_64 ? 8 : 4;
michael@0 335 cursor.CString(&segment.name, 16);
michael@0 336 size_t file_offset, file_size;
michael@0 337 cursor
michael@0 338 .Read(word_size, false, &segment.vmaddr)
michael@0 339 .Read(word_size, false, &segment.vmsize)
michael@0 340 .Read(word_size, false, &file_offset)
michael@0 341 .Read(word_size, false, &file_size);
michael@0 342 cursor >> segment.maxprot
michael@0 343 >> segment.initprot
michael@0 344 >> segment.nsects
michael@0 345 >> segment.flags;
michael@0 346 if (!cursor) {
michael@0 347 reporter_->LoadCommandTooShort(index, type);
michael@0 348 return false;
michael@0 349 }
michael@0 350 if (file_offset > buffer_.Size() ||
michael@0 351 file_size > buffer_.Size() - file_offset) {
michael@0 352 reporter_->MisplacedSegmentData(segment.name);
michael@0 353 return false;
michael@0 354 }
michael@0 355 // Mach-O files in .dSYM bundles have the contents of the loaded
michael@0 356 // segments removed, and their file offsets and file sizes zeroed
michael@0 357 // out. To help us handle this special case properly, give such
michael@0 358 // segments' contents NULL starting and ending pointers.
michael@0 359 if (file_offset == 0 && file_size == 0) {
michael@0 360 segment.contents.start = segment.contents.end = NULL;
michael@0 361 } else {
michael@0 362 segment.contents.start = buffer_.start + file_offset;
michael@0 363 segment.contents.end = segment.contents.start + file_size;
michael@0 364 }
michael@0 365 // The section list occupies the remainder of this load command's space.
michael@0 366 segment.section_list.start = cursor.here();
michael@0 367 segment.section_list.end = command.end;
michael@0 368
michael@0 369 if (!handler->SegmentCommand(segment))
michael@0 370 return false;
michael@0 371 break;
michael@0 372 }
michael@0 373
michael@0 374 case LC_SYMTAB: {
michael@0 375 uint32_t symoff, nsyms, stroff, strsize;
michael@0 376 cursor >> symoff >> nsyms >> stroff >> strsize;
michael@0 377 if (!cursor) {
michael@0 378 reporter_->LoadCommandTooShort(index, type);
michael@0 379 return false;
michael@0 380 }
michael@0 381 // How big are the entries in the symbol table?
michael@0 382 // sizeof(struct nlist_64) : sizeof(struct nlist),
michael@0 383 // but be paranoid about alignment vs. target architecture.
michael@0 384 size_t symbol_size = bits_64_ ? 16 : 12;
michael@0 385 // How big is the entire symbol array?
michael@0 386 size_t symbols_size = nsyms * symbol_size;
michael@0 387 if (symoff > buffer_.Size() || symbols_size > buffer_.Size() - symoff ||
michael@0 388 stroff > buffer_.Size() || strsize > buffer_.Size() - stroff) {
michael@0 389 reporter_->MisplacedSymbolTable();
michael@0 390 return false;
michael@0 391 }
michael@0 392 ByteBuffer entries(buffer_.start + symoff, symbols_size);
michael@0 393 ByteBuffer names(buffer_.start + stroff, strsize);
michael@0 394 if (!handler->SymtabCommand(entries, names))
michael@0 395 return false;
michael@0 396 break;
michael@0 397 }
michael@0 398
michael@0 399 default: {
michael@0 400 if (!handler->UnknownCommand(type, command))
michael@0 401 return false;
michael@0 402 break;
michael@0 403 }
michael@0 404 }
michael@0 405
michael@0 406 list_cursor.set_here(command.end);
michael@0 407 }
michael@0 408
michael@0 409 return true;
michael@0 410 }
michael@0 411
michael@0 412 // A load command handler that looks for a segment of a given name.
michael@0 413 class Reader::SegmentFinder : public LoadCommandHandler {
michael@0 414 public:
michael@0 415 // Create a load command handler that looks for a segment named NAME,
michael@0 416 // and sets SEGMENT to describe it if found.
michael@0 417 SegmentFinder(const string &name, Segment *segment)
michael@0 418 : name_(name), segment_(segment), found_() { }
michael@0 419
michael@0 420 // Return true if the traversal found the segment, false otherwise.
michael@0 421 bool found() const { return found_; }
michael@0 422
michael@0 423 bool SegmentCommand(const Segment &segment) {
michael@0 424 if (segment.name == name_) {
michael@0 425 *segment_ = segment;
michael@0 426 found_ = true;
michael@0 427 return false;
michael@0 428 }
michael@0 429 return true;
michael@0 430 }
michael@0 431
michael@0 432 private:
michael@0 433 // The name of the segment our creator is looking for.
michael@0 434 const string &name_;
michael@0 435
michael@0 436 // Where we should store the segment if found. (WEAK)
michael@0 437 Segment *segment_;
michael@0 438
michael@0 439 // True if we found the segment.
michael@0 440 bool found_;
michael@0 441 };
michael@0 442
michael@0 443 bool Reader::FindSegment(const string &name, Segment *segment) const {
michael@0 444 SegmentFinder finder(name, segment);
michael@0 445 WalkLoadCommands(&finder);
michael@0 446 return finder.found();
michael@0 447 }
michael@0 448
michael@0 449 bool Reader::WalkSegmentSections(const Segment &segment,
michael@0 450 SectionHandler *handler) const {
michael@0 451 size_t word_size = segment.bits_64 ? 8 : 4;
michael@0 452 ByteCursor cursor(&segment.section_list, big_endian_);
michael@0 453
michael@0 454 for (size_t i = 0; i < segment.nsects; i++) {
michael@0 455 Section section;
michael@0 456 section.bits_64 = segment.bits_64;
michael@0 457 uint64_t size;
michael@0 458 uint32_t offset, dummy32;
michael@0 459 cursor
michael@0 460 .CString(&section.section_name, 16)
michael@0 461 .CString(&section.segment_name, 16)
michael@0 462 .Read(word_size, false, &section.address)
michael@0 463 .Read(word_size, false, &size)
michael@0 464 >> offset
michael@0 465 >> section.align
michael@0 466 >> dummy32
michael@0 467 >> dummy32
michael@0 468 >> section.flags
michael@0 469 >> dummy32
michael@0 470 >> dummy32;
michael@0 471 if (section.bits_64)
michael@0 472 cursor >> dummy32;
michael@0 473 if (!cursor) {
michael@0 474 reporter_->SectionsMissing(segment.name);
michael@0 475 return false;
michael@0 476 }
michael@0 477 if ((section.flags & SECTION_TYPE) == S_ZEROFILL) {
michael@0 478 // Zero-fill sections have a size, but no contents.
michael@0 479 section.contents.start = section.contents.end = NULL;
michael@0 480 } else if (segment.contents.start == NULL &&
michael@0 481 segment.contents.end == NULL) {
michael@0 482 // Mach-O files in .dSYM bundles have the contents of the loaded
michael@0 483 // segments removed, and their file offsets and file sizes zeroed
michael@0 484 // out. However, the sections within those segments still have
michael@0 485 // non-zero sizes. There's no reason to call MisplacedSectionData in
michael@0 486 // this case; the caller may just need the section's load
michael@0 487 // address. But do set the contents' limits to NULL, for safety.
michael@0 488 section.contents.start = section.contents.end = NULL;
michael@0 489 } else {
michael@0 490 if (offset < size_t(segment.contents.start - buffer_.start) ||
michael@0 491 offset > size_t(segment.contents.end - buffer_.start) ||
michael@0 492 size > size_t(segment.contents.end - buffer_.start - offset)) {
michael@0 493 reporter_->MisplacedSectionData(section.section_name,
michael@0 494 section.segment_name);
michael@0 495 return false;
michael@0 496 }
michael@0 497 section.contents.start = buffer_.start + offset;
michael@0 498 section.contents.end = section.contents.start + size;
michael@0 499 }
michael@0 500 if (!handler->HandleSection(section))
michael@0 501 return false;
michael@0 502 }
michael@0 503 return true;
michael@0 504 }
michael@0 505
michael@0 506 // A SectionHandler that builds a SectionMap for the sections within a
michael@0 507 // given segment.
michael@0 508 class Reader::SectionMapper: public SectionHandler {
michael@0 509 public:
michael@0 510 // Create a SectionHandler that populates MAP with an entry for
michael@0 511 // each section it is given.
michael@0 512 SectionMapper(SectionMap *map) : map_(map) { }
michael@0 513 bool HandleSection(const Section &section) {
michael@0 514 (*map_)[section.section_name] = section;
michael@0 515 return true;
michael@0 516 }
michael@0 517 private:
michael@0 518 // The map under construction. (WEAK)
michael@0 519 SectionMap *map_;
michael@0 520 };
michael@0 521
michael@0 522 bool Reader::MapSegmentSections(const Segment &segment,
michael@0 523 SectionMap *section_map) const {
michael@0 524 section_map->clear();
michael@0 525 SectionMapper mapper(section_map);
michael@0 526 return WalkSegmentSections(segment, &mapper);
michael@0 527 }
michael@0 528
michael@0 529 } // namespace mach_o
michael@0 530 } // namespace google_breakpad

mercurial