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.
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 §ion, |
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(§ion.section_name, 16) |
michael@0 | 461 | .CString(§ion.segment_name, 16) |
michael@0 | 462 | .Read(word_size, false, §ion.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 §ion) { |
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 |