Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: util/mac/mach_o_image_reader.cc

Issue 539263003: Add MachOImageSymbolTableReader and hook it up to MachOImageReader (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: Fix 32-bit x86 Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Crashpad Authors. All rights reserved. 1 // Copyright 2014 The Crashpad Authors. All rights reserved.
2 // 2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License. 4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at 5 // You may obtain a copy of the License at
6 // 6 //
7 // http://www.apache.org/licenses/LICENSE-2.0 7 // http://www.apache.org/licenses/LICENSE-2.0
8 // 8 //
9 // Unless required by applicable law or agreed to in writing, software 9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, 10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and 12 // See the License for the specific language governing permissions and
13 // limitations under the License. 13 // limitations under the License.
14 14
15 #include "util/mac/mach_o_image_reader.h" 15 #include "util/mac/mach_o_image_reader.h"
16 16
17 #include <mach-o/loader.h> 17 #include <mach-o/loader.h>
18 #include <mach-o/nlist.h> 18 #include <mach-o/nlist.h>
19 #include <string.h> 19 #include <string.h>
20 20
21 #include <limits> 21 #include <limits>
22 #include <vector> 22 #include <vector>
23 23
24 #include "base/logging.h" 24 #include "base/logging.h"
25 #include "base/strings/stringprintf.h" 25 #include "base/strings/stringprintf.h"
26 #include "util/mac/checked_mach_address_range.h" 26 #include "util/mac/checked_mach_address_range.h"
27 #include "util/mac/mach_o_image_segment_reader.h" 27 #include "util/mac/mach_o_image_segment_reader.h"
28 #include "util/mac/mach_o_image_symbol_table_reader.h"
28 #include "util/mac/process_reader.h" 29 #include "util/mac/process_reader.h"
29 30
30 namespace { 31 namespace {
31 32
32 const uint32_t kInvalidSegmentIndex = std::numeric_limits<uint32_t>::max(); 33 const uint32_t kInvalidSegmentIndex = std::numeric_limits<uint32_t>::max();
33 34
34 } // namespace 35 } // namespace
35 36
36 namespace crashpad { 37 namespace crashpad {
37 38
38 MachOImageReader::MachOImageReader() 39 MachOImageReader::MachOImageReader()
39 : segments_(), 40 : segments_(),
40 segment_map_(), 41 segment_map_(),
41 module_info_(), 42 module_info_(),
42 dylinker_name_(), 43 dylinker_name_(),
43 uuid_(), 44 uuid_(),
44 address_(0), 45 address_(0),
45 size_(0), 46 size_(0),
46 slide_(0), 47 slide_(0),
47 source_version_(0), 48 source_version_(0),
48 symtab_command_(), 49 symtab_command_(),
49 dysymtab_command_(), 50 dysymtab_command_(),
51 symbol_table_(),
50 id_dylib_command_(), 52 id_dylib_command_(),
51 process_reader_(NULL), 53 process_reader_(NULL),
52 file_type_(0), 54 file_type_(0),
53 initialized_() { 55 initialized_(),
56 symbol_table_initialized_() {
54 } 57 }
55 58
56 MachOImageReader::~MachOImageReader() { 59 MachOImageReader::~MachOImageReader() {
57 } 60 }
58 61
59 bool MachOImageReader::Initialize(ProcessReader* process_reader, 62 bool MachOImageReader::Initialize(ProcessReader* process_reader,
60 mach_vm_address_t address, 63 mach_vm_address_t address,
61 const std::string& name) { 64 const std::string& name) {
62 INITIALIZATION_STATE_SET_INITIALIZING(initialized_); 65 INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
63 66
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
217 } 220 }
218 221
219 for (size_t reader_index = 0; 222 for (size_t reader_index = 0;
220 reader_index < arraysize(kLoadCommandReaders); 223 reader_index < arraysize(kLoadCommandReaders);
221 ++reader_index) { 224 ++reader_index) {
222 if (load_command.cmd != kLoadCommandReaders[reader_index].command) { 225 if (load_command.cmd != kLoadCommandReaders[reader_index].command) {
223 continue; 226 continue;
224 } 227 }
225 228
226 if (load_command.cmdsize < kLoadCommandReaders[reader_index].size) { 229 if (load_command.cmdsize < kLoadCommandReaders[reader_index].size) {
227 LOG(WARNING) 230 LOG(WARNING) << base::StringPrintf(
228 << base::StringPrintf( 231 "load command cmdsize 0x%x insufficient for 0x%zx",
229 "load command cmdsize 0x%x insufficient for 0x%zx", 232 load_command.cmdsize,
230 load_command.cmdsize, 233 kLoadCommandReaders[reader_index].size)
231 kLoadCommandReaders[reader_index].size) 234 << load_command_info;
232 << load_command_info;
233 return false; 235 return false;
234 } 236 }
235 237
236 if (kLoadCommandReaders[reader_index].singleton) { 238 if (kLoadCommandReaders[reader_index].singleton) {
237 if (singleton_indices[reader_index] != kInvalidSegmentIndex) { 239 if (singleton_indices[reader_index] != kInvalidSegmentIndex) {
238 LOG(WARNING) << "duplicate load command at " 240 LOG(WARNING) << "duplicate load command at "
239 << singleton_indices[reader_index] 241 << singleton_indices[reader_index] << load_command_info;
240 << load_command_info;
241 return false; 242 return false;
242 } 243 }
243 244
244 singleton_indices[reader_index] = load_command_index; 245 singleton_indices[reader_index] = load_command_index;
245 } 246 }
246 247
247 if (!((this)->*(kLoadCommandReaders[reader_index].function))( 248 if (!((this)->*(kLoadCommandReaders[reader_index].function))(
248 load_command_address, load_command_info)) { 249 load_command_address, load_command_info)) {
249 return false; 250 return false;
250 } 251 }
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
342 343
343 if (address) { 344 if (address) {
344 *address = section->addr + (segment->SegmentSlides() ? slide_ : 0); 345 *address = section->addr + (segment->SegmentSlides() ? slide_ : 0);
345 } 346 }
346 347
347 return section; 348 return section;
348 } 349 }
349 350
350 const process_types::section* MachOImageReader::GetSectionAtIndex( 351 const process_types::section* MachOImageReader::GetSectionAtIndex(
351 size_t index, 352 size_t index,
353 const MachOImageSegmentReader** containing_segment,
352 mach_vm_address_t* address) const { 354 mach_vm_address_t* address) const {
353 INITIALIZATION_STATE_DCHECK_VALID(initialized_); 355 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
354 356
355 COMPILE_ASSERT(NO_SECT == 0, no_sect_must_be_zero); 357 COMPILE_ASSERT(NO_SECT == 0, no_sect_must_be_zero);
356 if (index == NO_SECT) { 358 if (index == NO_SECT) {
357 LOG(WARNING) << "section index " << index << " out of range"; 359 LOG(WARNING) << "section index " << index << " out of range";
358 return NULL; 360 return NULL;
359 } 361 }
360 362
361 // Switch to a more comfortable 0-based index. 363 // Switch to a more comfortable 0-based index.
362 size_t local_index = index - 1; 364 size_t local_index = index - 1;
363 365
364 for (const MachOImageSegmentReader* segment : segments_) { 366 for (const MachOImageSegmentReader* segment : segments_) {
365 size_t nsects = segment->nsects(); 367 size_t nsects = segment->nsects();
366 if (local_index < nsects) { 368 if (local_index < nsects) {
367 const process_types::section* section = 369 const process_types::section* section =
368 segment->GetSectionAtIndex(local_index); 370 segment->GetSectionAtIndex(local_index);
369 371
372 if (containing_segment) {
373 *containing_segment = segment;
374 }
370 if (address) { 375 if (address) {
371 *address = section->addr + (segment->SegmentSlides() ? slide_ : 0); 376 *address = section->addr + (segment->SegmentSlides() ? slide_ : 0);
372 } 377 }
373 378
374 return section; 379 return section;
375 } 380 }
376 381
377 local_index -= nsects; 382 local_index -= nsects;
378 } 383 }
379 384
380 LOG(WARNING) << "section index " << index << " out of range"; 385 LOG(WARNING) << "section index " << index << " out of range";
381 return NULL; 386 return NULL;
382 } 387 }
383 388
389 bool MachOImageReader::LookUpExternalDefinedSymbol(
390 const std::string& name,
391 mach_vm_address_t* value) const {
392 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
393
394 if (symbol_table_initialized_.is_uninitialized()) {
395 InitializeSymbolTable();
396 }
397
398 if (!symbol_table_initialized_.is_valid() || !symbol_table_) {
399 return false;
400 }
401
402 const MachOImageSymbolTableReader::SymbolInformation* symbol_info =
403 symbol_table_->LookUpExternalDefinedSymbol(name);
404 if (!symbol_info) {
405 return false;
406 }
407
408 if (symbol_info->section == NO_SECT) {
409 // This is an absolute (N_ABS) symbol, which requires no further validation
410 // or processing.
411 *value = symbol_info->value;
412 return true;
413 }
414
415 // This is a symbol defined in a particular section, so make sure that it’s
416 // valid for that section and fix it up for any “slide” as needed.
417
418 mach_vm_address_t section_address;
419 const MachOImageSegmentReader* segment;
420 const process_types::section* section =
421 GetSectionAtIndex(symbol_info->section, &segment, &section_address);
422 if (!section) {
423 return false;
424 }
425
426 mach_vm_address_t slid_value =
427 symbol_info->value + (segment->SegmentSlides() ? slide_ : 0);
428
429 // The __mh_execute_header (_MH_EXECUTE_SYM) symbol is weird. In
430 // position-independent executables, it shows up in the symbol table as a
431 // symbol in section 1, although it’s not really in that section. It points to
432 // the mach_header[_64], which is the beginning of the __TEXT segment, and the
433 // __text section normally begins after the load commands in the __TEXT
434 // segment. The range check below will fail for this symbol, because it’s not
435 // really in the section it claims to be in. See Xcode 5.1
436 // ld64-236.3/src/ld/OutputFile.cpp ld::tool::OutputFile::buildSymbolTable().
437 // There, ld takes symbols that refer to anything in the mach_header[_64] and
438 // marks them as being in section 1. Here, section 1 is treated in this same
439 // special way as long as it’s in the __TEXT segment that begins at the start
440 // of the image, which is normally the case, and as long as the symbol’s value
441 // is the base of the image.
442 //
443 // This only happens for PIE executables, because __mh_execute_header needs
444 // to slide. In non-PIE executables, __mh_execute_header is an absolute
445 // symbol.
446 CheckedMachAddressRange section_range(
447 process_reader_, section_address, section->size);
448 if (!section_range.ContainsValue(slid_value) &&
449 !(symbol_info->section == 1 && segment->Name() == SEG_TEXT &&
450 slid_value == Address())) {
451 std::string section_name_full =
452 MachOImageSegmentReader::SegmentAndSectionNameString(section->segname,
453 section->sectname);
454 LOG(WARNING) << base::StringPrintf(
455 "symbol %s (0x%llx) outside of section %s (0x%llx + "
456 "0x%llx)",
457 name.c_str(),
458 slid_value,
459 section_name_full.c_str(),
460 section_address,
461 section->size) << module_info_;
462 return false;
463 }
464
465 *value = slid_value;
466 return true;
467 }
468
384 uint32_t MachOImageReader::DylibVersion() const { 469 uint32_t MachOImageReader::DylibVersion() const {
385 INITIALIZATION_STATE_DCHECK_VALID(initialized_); 470 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
386 DCHECK_EQ(FileType(), static_cast<uint32_t>(MH_DYLIB)); 471 DCHECK_EQ(FileType(), static_cast<uint32_t>(MH_DYLIB));
387 472
388 if (id_dylib_command_) { 473 if (id_dylib_command_) {
389 return id_dylib_command_->dylib_current_version; 474 return id_dylib_command_->dylib_current_version;
390 } 475 }
391 476
392 // In case this was a weird dylib without an LC_ID_DYLIB command. 477 // In case this was a weird dylib without an LC_ID_DYLIB command.
393 return 0; 478 return 0;
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after
570 return true; 655 return true;
571 } 656 }
572 657
573 bool MachOImageReader::ReadUnexpectedCommand( 658 bool MachOImageReader::ReadUnexpectedCommand(
574 mach_vm_address_t load_command_address, 659 mach_vm_address_t load_command_address,
575 const std::string& load_command_info) { 660 const std::string& load_command_info) {
576 LOG(WARNING) << "unexpected load command" << load_command_info; 661 LOG(WARNING) << "unexpected load command" << load_command_info;
577 return false; 662 return false;
578 } 663 }
579 664
665 void MachOImageReader::InitializeSymbolTable() const {
666 DCHECK(symbol_table_initialized_.is_uninitialized());
667 symbol_table_initialized_.set_invalid();
668
669 if (!symtab_command_) {
670 // It’s technically valid for there to be no LC_SYMTAB, and in that case,
671 // any symbol lookups should fail. Mark the symbol table as valid, and
672 // LookUpExternalDefinedSymbol() will understand what it means when this is
673 // valid but symbol_table_ is not present.
674 symbol_table_initialized_.set_valid();
675 return;
676 }
677
678 // Find the __LINKEDIT segment. Technically, the symbol table can be in any
679 // mapped segment, but by convention, it’s in the one named __LINKEDIT.
680 mach_vm_address_t linkedit_address;
681 mach_vm_size_t linkedit_size;
682 const MachOImageSegmentReader* linkedit_segment =
683 GetSegmentByName(SEG_LINKEDIT, &linkedit_address, &linkedit_size);
684 if (!linkedit_segment) {
685 LOG(WARNING) << "no " SEG_LINKEDIT " segment";
686 return;
687 }
688
689 symbol_table_.reset(new MachOImageSymbolTableReader());
690 if (!symbol_table_->Initialize(process_reader_,
691 symtab_command_.get(),
692 dysymtab_command_.get(),
693 linkedit_segment,
694 linkedit_address,
695 linkedit_size,
696 module_info_)) {
697 symbol_table_.reset();
698 return;
699 }
700
701 symbol_table_initialized_.set_valid();
702 }
703
580 } // namespace crashpad 704 } // namespace crashpad
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698