1 // Copyright 2014 The Crashpad Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (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
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "snapshot/mac/mach_o_image_reader.h"
16 
17 #include <mach-o/loader.h>
18 #include <mach-o/nlist.h>
19 #include <string.h>
20 
21 #include <limits>
22 #include <utility>
23 
24 #include "base/logging.h"
25 #include "base/stl_util.h"
26 #include "base/strings/stringprintf.h"
27 #include "client/crashpad_info.h"
28 #include "snapshot/mac/mach_o_image_segment_reader.h"
29 #include "snapshot/mac/mach_o_image_symbol_table_reader.h"
30 #include "snapshot/mac/process_reader_mac.h"
31 #include "util/mac/checked_mach_address_range.h"
32 #include "util/misc/implicit_cast.h"
33 
34 namespace {
35 
36 constexpr uint32_t kInvalidSegmentIndex = std::numeric_limits<uint32_t>::max();
37 
38 }  // namespace
39 
40 namespace crashpad {
41 
MachOImageReader()42 MachOImageReader::MachOImageReader()
43     : segments_(),
44       segment_map_(),
45       module_name_(),
46       module_info_(),
47       dylinker_name_(),
48       uuid_(),
49       address_(0),
50       size_(0),
51       slide_(0),
52       source_version_(0),
53       symtab_command_(),
54       dysymtab_command_(),
55       symbol_table_(),
56       id_dylib_command_(),
57       process_reader_(nullptr),
58       file_type_(0),
59       initialized_(),
60       symbol_table_initialized_() {
61 }
62 
~MachOImageReader()63 MachOImageReader::~MachOImageReader() {
64 }
65 
Initialize(ProcessReaderMac * process_reader,mach_vm_address_t address,const std::string & name)66 bool MachOImageReader::Initialize(ProcessReaderMac* process_reader,
67                                   mach_vm_address_t address,
68                                   const std::string& name) {
69   INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
70 
71   process_reader_ = process_reader;
72   address_ = address;
73   module_name_ = name;
74 
75   module_info_ =
76       base::StringPrintf(", module %s, address 0x%llx", name.c_str(), address);
77 
78   process_types::mach_header mach_header;
79   if (!mach_header.Read(process_reader, address)) {
80     LOG(WARNING) << "could not read mach_header" << module_info_;
81     return false;
82   }
83 
84   const bool is_64_bit = process_reader->Is64Bit();
85   const uint32_t kExpectedMagic = is_64_bit ? MH_MAGIC_64 : MH_MAGIC;
86   if (mach_header.magic != kExpectedMagic) {
87     LOG(WARNING) << base::StringPrintf("unexpected mach_header::magic 0x%08x",
88                                        mach_header.magic) << module_info_;
89     return false;
90   }
91 
92   switch (mach_header.filetype) {
93     case MH_EXECUTE:
94     case MH_DYLIB:
95     case MH_DYLINKER:
96     case MH_BUNDLE:
97       file_type_ = mach_header.filetype;
98       break;
99     default:
100       LOG(WARNING) << base::StringPrintf(
101                           "unexpected mach_header::filetype 0x%08x",
102                           mach_header.filetype) << module_info_;
103       return false;
104   }
105 
106   const uint32_t kExpectedSegmentCommand =
107       is_64_bit ? LC_SEGMENT_64 : LC_SEGMENT;
108   const uint32_t kUnexpectedSegmentCommand =
109       is_64_bit ? LC_SEGMENT : LC_SEGMENT_64;
110 
111   const struct {
112     // Which method to call when encountering a load command matching |command|.
113     bool (MachOImageReader::*function)(mach_vm_address_t, const std::string&);
114 
115     // The minimum size that may be allotted to store the load command.
116     size_t size;
117 
118     // The load command to match.
119     uint32_t command;
120 
121     // True if the load command must not appear more than one time.
122     bool singleton;
123   } kLoadCommandReaders[] = {
124     {
125       &MachOImageReader::ReadSegmentCommand,
126       process_types::segment_command::ExpectedSize(process_reader),
127       kExpectedSegmentCommand,
128       false,
129     },
130     {
131       &MachOImageReader::ReadSymTabCommand,
132       process_types::symtab_command::ExpectedSize(process_reader),
133       LC_SYMTAB,
134       true,
135     },
136     {
137       &MachOImageReader::ReadDySymTabCommand,
138       process_types::symtab_command::ExpectedSize(process_reader),
139       LC_DYSYMTAB,
140       true,
141     },
142     {
143       &MachOImageReader::ReadIdDylibCommand,
144       process_types::dylib_command::ExpectedSize(process_reader),
145       LC_ID_DYLIB,
146       true,
147     },
148     {
149       &MachOImageReader::ReadDylinkerCommand,
150       process_types::dylinker_command::ExpectedSize(process_reader),
151       LC_LOAD_DYLINKER,
152       true,
153     },
154     {
155       &MachOImageReader::ReadDylinkerCommand,
156       process_types::dylinker_command::ExpectedSize(process_reader),
157       LC_ID_DYLINKER,
158       true,
159     },
160     {
161       &MachOImageReader::ReadUUIDCommand,
162       process_types::uuid_command::ExpectedSize(process_reader),
163       LC_UUID,
164       true,
165     },
166     {
167       &MachOImageReader::ReadSourceVersionCommand,
168       process_types::source_version_command::ExpectedSize(process_reader),
169       LC_SOURCE_VERSION,
170       true,
171     },
172 
173     // When reading a 64-bit process, no 32-bit segment commands should be
174     // present, and vice-versa.
175     {
176       &MachOImageReader::ReadUnexpectedCommand,
177       process_types::load_command::ExpectedSize(process_reader),
178       kUnexpectedSegmentCommand,
179       false,
180     },
181   };
182 
183   // This vector is parallel to the kLoadCommandReaders array, and tracks
184   // whether a singleton load command matching the |command| field has been
185   // found yet.
186   std::vector<uint32_t> singleton_indices(base::size(kLoadCommandReaders),
187                                           kInvalidSegmentIndex);
188 
189   size_t offset = mach_header.Size();
190   const mach_vm_address_t kLoadCommandAddressLimit =
191       address + offset + mach_header.sizeofcmds;
192 
193   for (uint32_t load_command_index = 0;
194        load_command_index < mach_header.ncmds;
195        ++load_command_index) {
196     mach_vm_address_t load_command_address = address + offset;
197     std::string load_command_info = base::StringPrintf(", load command %u/%u%s",
198                                                        load_command_index,
199                                                        mach_header.ncmds,
200                                                        module_info_.c_str());
201 
202     process_types::load_command load_command;
203 
204     // Make sure that the basic load command structure doesn’t overflow the
205     // space allotted for load commands.
206     if (load_command_address + load_command.ExpectedSize(process_reader) >
207             kLoadCommandAddressLimit) {
208       LOG(WARNING) << base::StringPrintf(
209                           "load_command at 0x%llx exceeds sizeofcmds 0x%x",
210                           load_command_address,
211                           mach_header.sizeofcmds) << load_command_info;
212       return false;
213     }
214 
215     if (!load_command.Read(process_reader, load_command_address)) {
216       LOG(WARNING) << "could not read load_command" << load_command_info;
217       return false;
218     }
219 
220     load_command_info = base::StringPrintf(", load command 0x%x %u/%u%s",
221                                            load_command.cmd,
222                                            load_command_index,
223                                            mach_header.ncmds,
224                                            module_info_.c_str());
225 
226     // Now that the load command’s stated size is known, make sure that it
227     // doesn’t overflow the space allotted for load commands.
228     if (load_command_address + load_command.cmdsize >
229             kLoadCommandAddressLimit) {
230       LOG(WARNING)
231           << base::StringPrintf(
232                  "load_command at 0x%llx cmdsize 0x%x exceeds sizeofcmds 0x%x",
233                  load_command_address,
234                  load_command.cmdsize,
235                  mach_header.sizeofcmds) << load_command_info;
236       return false;
237     }
238 
239     for (size_t reader_index = 0;
240          reader_index < base::size(kLoadCommandReaders);
241          ++reader_index) {
242       if (load_command.cmd != kLoadCommandReaders[reader_index].command) {
243         continue;
244       }
245 
246       if (load_command.cmdsize < kLoadCommandReaders[reader_index].size) {
247         LOG(WARNING) << base::StringPrintf(
248                             "load command cmdsize 0x%x insufficient for 0x%zx",
249                             load_command.cmdsize,
250                             kLoadCommandReaders[reader_index].size)
251                      << load_command_info;
252         return false;
253       }
254 
255       if (kLoadCommandReaders[reader_index].singleton) {
256         if (singleton_indices[reader_index] != kInvalidSegmentIndex) {
257           LOG(WARNING) << "duplicate load command at "
258                        << singleton_indices[reader_index] << load_command_info;
259           return false;
260         }
261 
262         singleton_indices[reader_index] = load_command_index;
263       }
264 
265       if (!((this)->*(kLoadCommandReaders[reader_index].function))(
266               load_command_address, load_command_info)) {
267         return false;
268       }
269 
270       break;
271     }
272 
273     offset += load_command.cmdsize;
274   }
275 
276   // Now that the slide is known, push it into the segments.
277   for (const auto& segment : segments_) {
278     segment->SetSlide(slide_);
279 
280     // This was already checked for the unslid values while the segments were
281     // read, but now it’s possible to check the slid values too. The individual
282     // sections don’t need to be checked because they were verified to be
283     // contained within their respective segments when the segments were read.
284     mach_vm_address_t slid_segment_address = segment->Address();
285     mach_vm_size_t slid_segment_size = segment->Size();
286     CheckedMachAddressRange slid_segment_range(
287         process_reader_->Is64Bit(), slid_segment_address, slid_segment_size);
288     if (!slid_segment_range.IsValid()) {
289       LOG(WARNING) << base::StringPrintf(
290                           "invalid slid segment range 0x%llx + 0x%llx, "
291                           "segment ",
292                           slid_segment_address,
293                           slid_segment_size) << segment->Name() << module_info_;
294       return false;
295     }
296   }
297 
298   if (!segment_map_.count(SEG_TEXT)) {
299     // The __TEXT segment is required. Even a module with no executable code
300     // will have a __TEXT segment encompassing the Mach-O header and load
301     // commands. Without a __TEXT segment, |size_| will not have been computed.
302     LOG(WARNING) << "no " SEG_TEXT " segment" << module_info_;
303     return false;
304   }
305 
306   if (mach_header.filetype == MH_DYLIB && !id_dylib_command_) {
307     // This doesn’t render a module unusable, it’s just weird and worth noting.
308     LOG(INFO) << "no LC_ID_DYLIB" << module_info_;
309   }
310 
311   INITIALIZATION_STATE_SET_VALID(initialized_);
312   return true;
313 }
314 
GetSegmentByName(const std::string & segment_name) const315 const MachOImageSegmentReader* MachOImageReader::GetSegmentByName(
316     const std::string& segment_name) const {
317   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
318 
319   const auto& iterator = segment_map_.find(segment_name);
320   if (iterator == segment_map_.end()) {
321     return nullptr;
322   }
323 
324   return segments_[iterator->second].get();
325 }
326 
GetSectionByName(const std::string & segment_name,const std::string & section_name,mach_vm_address_t * address) const327 const process_types::section* MachOImageReader::GetSectionByName(
328     const std::string& segment_name,
329     const std::string& section_name,
330     mach_vm_address_t* address) const {
331   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
332 
333   const MachOImageSegmentReader* segment = GetSegmentByName(segment_name);
334   if (!segment) {
335     return nullptr;
336   }
337 
338   return segment->GetSectionByName(section_name, address);
339 }
340 
GetSectionAtIndex(size_t index,const MachOImageSegmentReader ** containing_segment,mach_vm_address_t * address) const341 const process_types::section* MachOImageReader::GetSectionAtIndex(
342     size_t index,
343     const MachOImageSegmentReader** containing_segment,
344     mach_vm_address_t* address) const {
345   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
346 
347   static_assert(NO_SECT == 0, "NO_SECT must be zero");
348   if (index == NO_SECT) {
349     LOG(WARNING) << "section index " << index << " out of range";
350     return nullptr;
351   }
352 
353   // Switch to a more comfortable 0-based index.
354   size_t local_index = index - 1;
355 
356   for (const auto& segment : segments_) {
357     size_t nsects = segment->nsects();
358     if (local_index < nsects) {
359       const process_types::section* section =
360           segment->GetSectionAtIndex(local_index, address);
361 
362       if (containing_segment) {
363         *containing_segment = segment.get();
364       }
365 
366       return section;
367     }
368 
369     local_index -= nsects;
370   }
371 
372   LOG(WARNING) << "section index " << index << " out of range";
373   return nullptr;
374 }
375 
LookUpExternalDefinedSymbol(const std::string & name,mach_vm_address_t * value) const376 bool MachOImageReader::LookUpExternalDefinedSymbol(
377     const std::string& name,
378     mach_vm_address_t* value) const {
379   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
380 
381   if (symbol_table_initialized_.is_uninitialized()) {
382     InitializeSymbolTable();
383   }
384 
385   if (!symbol_table_initialized_.is_valid() || !symbol_table_) {
386     return false;
387   }
388 
389   const MachOImageSymbolTableReader::SymbolInformation* symbol_info =
390       symbol_table_->LookUpExternalDefinedSymbol(name);
391   if (!symbol_info) {
392     return false;
393   }
394 
395   if (symbol_info->section == NO_SECT) {
396     // This is an absolute (N_ABS) symbol, which requires no further validation
397     // or processing.
398     *value = symbol_info->value;
399     return true;
400   }
401 
402   // This is a symbol defined in a particular section, so make sure that it’s
403   // valid for that section and fix it up for any “slide” as needed.
404 
405   mach_vm_address_t section_address;
406   const MachOImageSegmentReader* segment;
407   const process_types::section* section =
408       GetSectionAtIndex(symbol_info->section, &segment, &section_address);
409   if (!section) {
410     return false;
411   }
412 
413   mach_vm_address_t slid_value =
414       symbol_info->value + (segment->SegmentSlides() ? slide_ : 0);
415 
416   // The __mh_execute_header (_MH_EXECUTE_SYM) symbol is weird. In
417   // position-independent executables, it shows up in the symbol table as a
418   // symbol in section 1, although it’s not really in that section. It points to
419   // the mach_header[_64], which is the beginning of the __TEXT segment, and the
420   // __text section normally begins after the load commands in the __TEXT
421   // segment. The range check below will fail for this symbol, because it’s not
422   // really in the section it claims to be in. See Xcode 5.1
423   // ld64-236.3/src/ld/OutputFile.cpp ld::tool::OutputFile::buildSymbolTable().
424   // There, ld takes symbols that refer to anything in the mach_header[_64] and
425   // marks them as being in section 1. Here, section 1 is treated in this same
426   // special way as long as it’s in the __TEXT segment that begins at the start
427   // of the image, which is normally the case, and as long as the symbol’s value
428   // is the base of the image.
429   //
430   // This only happens for PIE executables, because __mh_execute_header needs
431   // to slide. In non-PIE executables, __mh_execute_header is an absolute
432   // symbol.
433   CheckedMachAddressRange section_range(
434       process_reader_->Is64Bit(), section_address, section->size);
435   if (!section_range.ContainsValue(slid_value) &&
436       !(symbol_info->section == 1 && segment->Name() == SEG_TEXT &&
437         slid_value == Address())) {
438     std::string section_name_full =
439         MachOImageSegmentReader::SegmentAndSectionNameString(section->segname,
440                                                              section->sectname);
441     LOG(WARNING) << base::StringPrintf(
442                         "symbol %s (0x%llx) outside of section %s (0x%llx + "
443                         "0x%llx)",
444                         name.c_str(),
445                         slid_value,
446                         section_name_full.c_str(),
447                         section_address,
448                         section->size) << module_info_;
449     return false;
450   }
451 
452   *value = slid_value;
453   return true;
454 }
455 
DylibVersion() const456 uint32_t MachOImageReader::DylibVersion() const {
457   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
458   DCHECK_EQ(FileType(), implicit_cast<uint32_t>(MH_DYLIB));
459 
460   if (id_dylib_command_) {
461     return id_dylib_command_->dylib_current_version;
462   }
463 
464   // In case this was a weird dylib without an LC_ID_DYLIB command.
465   return 0;
466 }
467 
UUID(crashpad::UUID * uuid) const468 void MachOImageReader::UUID(crashpad::UUID* uuid) const {
469   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
470   memcpy(uuid, &uuid_, sizeof(uuid_));
471 }
472 
GetCrashpadInfo(process_types::CrashpadInfo * crashpad_info) const473 bool MachOImageReader::GetCrashpadInfo(
474     process_types::CrashpadInfo* crashpad_info) const {
475   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
476 
477   mach_vm_address_t crashpad_info_address;
478   const process_types::section* crashpad_info_section =
479       GetSectionByName(SEG_DATA, "crashpad_info", &crashpad_info_address);
480   if (!crashpad_info_section) {
481     return false;
482   }
483 
484   if (crashpad_info_section->size <
485       crashpad_info->MinimumSize(process_reader_)) {
486     LOG(WARNING) << "small crashpad info section size "
487                  << crashpad_info_section->size << module_info_;
488     return false;
489   }
490 
491   // This Read() will zero out anything beyond the structure’s declared size.
492   if (!crashpad_info->Read(process_reader_, crashpad_info_address)) {
493     LOG(WARNING) << "could not read crashpad info" << module_info_;
494     return false;
495   }
496 
497   if (crashpad_info->signature != CrashpadInfo::kSignature ||
498       crashpad_info->version != 1) {
499     LOG(WARNING) << base::StringPrintf(
500         "unexpected crashpad info signature 0x%x, version %u%s",
501         crashpad_info->signature,
502         crashpad_info->version,
503         module_info_.c_str());
504     return false;
505   }
506 
507   // Don’t require strict equality, to leave wiggle room for sloppy linkers.
508   if (crashpad_info->size > crashpad_info_section->size) {
509     LOG(WARNING) << "crashpad info struct size " << crashpad_info->size
510                  << " large for section size " << crashpad_info_section->size
511                  << module_info_;
512     return false;
513   }
514 
515   if (crashpad_info->size > crashpad_info->ExpectedSize(process_reader_)) {
516     // This isn’t strictly a problem, because unknown fields will simply be
517     // ignored, but it may be of diagnostic interest.
518     LOG(INFO) << "large crashpad info size " << crashpad_info->size
519               << module_info_;
520   }
521 
522   return true;
523 }
524 
525 template <typename T>
ReadLoadCommand(mach_vm_address_t load_command_address,const std::string & load_command_info,uint32_t expected_load_command_id,T * load_command)526 bool MachOImageReader::ReadLoadCommand(mach_vm_address_t load_command_address,
527                                        const std::string& load_command_info,
528                                        uint32_t expected_load_command_id,
529                                        T* load_command) {
530   if (!load_command->Read(process_reader_, load_command_address)) {
531     LOG(WARNING) << "could not read load command" << load_command_info;
532     return false;
533   }
534 
535   DCHECK_GE(load_command->cmdsize, load_command->Size());
536   DCHECK_EQ(load_command->cmd, expected_load_command_id);
537   return true;
538 }
539 
ReadSegmentCommand(mach_vm_address_t load_command_address,const std::string & load_command_info)540 bool MachOImageReader::ReadSegmentCommand(
541     mach_vm_address_t load_command_address,
542     const std::string& load_command_info) {
543   size_t segment_index = segments_.size();
544   segments_.push_back(std::make_unique<MachOImageSegmentReader>());
545   MachOImageSegmentReader* segment = segments_.back().get();
546 
547   if (!segment->Initialize(process_reader_,
548                            load_command_address,
549                            load_command_info,
550                            module_name_,
551                            file_type_)) {
552     segments_.pop_back();
553     return false;
554   }
555 
556   // At this point, the segment itself is considered valid, but if one of the
557   // next checks fails, it will render the module invalid. If any of the next
558   // checks fail, this method should return false, but it doesn’t need to bother
559   // removing the segment from segments_. The segment will be properly released
560   // when the image is destroyed, and the image won’t be usable because
561   // initialization won’t have completed. Most importantly, leaving the segment
562   // in segments_ means that no other structures (such as perhaps segment_map_)
563   // become inconsistent or require cleanup.
564 
565   const std::string segment_name = segment->Name();
566   const auto insert_result =
567       segment_map_.insert(std::make_pair(segment_name, segment_index));
568   if (!insert_result.second) {
569     LOG(WARNING) << base::StringPrintf("duplicate %s segment at %zu and %zu",
570                                        segment_name.c_str(),
571                                        insert_result.first->second,
572                                        segment_index) << load_command_info;
573     return false;
574   }
575 
576   if (segment_name == SEG_TEXT) {
577     mach_vm_size_t vmsize = segment->vmsize();
578 
579     if (vmsize == 0) {
580       LOG(WARNING) << "zero-sized " SEG_TEXT " segment" << load_command_info;
581       return false;
582     }
583 
584     size_ = vmsize;
585 
586     // The slide is computed as the difference between the __TEXT segment’s
587     // preferred and actual load addresses. This is the same way that dyld
588     // computes slide. See 10.9.2 dyld-239.4/src/dyldInitialization.cpp
589     // slideOfMainExecutable().
590     slide_ = address_ - segment->vmaddr();
591   }
592 
593   return true;
594 }
595 
ReadSymTabCommand(mach_vm_address_t load_command_address,const std::string & load_command_info)596 bool MachOImageReader::ReadSymTabCommand(mach_vm_address_t load_command_address,
597                                          const std::string& load_command_info) {
598   symtab_command_.reset(new process_types::symtab_command());
599   return ReadLoadCommand(load_command_address,
600                          load_command_info,
601                          LC_SYMTAB,
602                          symtab_command_.get());
603 }
604 
ReadDySymTabCommand(mach_vm_address_t load_command_address,const std::string & load_command_info)605 bool MachOImageReader::ReadDySymTabCommand(
606     mach_vm_address_t load_command_address,
607     const std::string& load_command_info) {
608   dysymtab_command_.reset(new process_types::dysymtab_command());
609   return ReadLoadCommand(load_command_address,
610                          load_command_info,
611                          LC_DYSYMTAB,
612                          dysymtab_command_.get());
613 }
614 
ReadIdDylibCommand(mach_vm_address_t load_command_address,const std::string & load_command_info)615 bool MachOImageReader::ReadIdDylibCommand(
616     mach_vm_address_t load_command_address,
617     const std::string& load_command_info) {
618   if (file_type_ != MH_DYLIB) {
619     LOG(WARNING) << base::StringPrintf(
620                         "LC_ID_DYLIB inappropriate in non-dylib file type 0x%x",
621                         file_type_) << load_command_info;
622     return false;
623   }
624 
625   DCHECK(!id_dylib_command_);
626   id_dylib_command_.reset(new process_types::dylib_command());
627   return ReadLoadCommand(load_command_address,
628                          load_command_info,
629                          LC_ID_DYLIB,
630                          id_dylib_command_.get());
631 }
632 
ReadDylinkerCommand(mach_vm_address_t load_command_address,const std::string & load_command_info)633 bool MachOImageReader::ReadDylinkerCommand(
634     mach_vm_address_t load_command_address,
635     const std::string& load_command_info) {
636   if (file_type_ != MH_EXECUTE && file_type_ != MH_DYLINKER) {
637     LOG(WARNING) << base::StringPrintf(
638                         "LC_LOAD_DYLINKER/LC_ID_DYLINKER inappropriate in file "
639                         "type 0x%x",
640                         file_type_) << load_command_info;
641     return false;
642   }
643 
644   const uint32_t kExpectedCommand =
645       file_type_ == MH_DYLINKER ? LC_ID_DYLINKER : LC_LOAD_DYLINKER;
646   process_types::dylinker_command dylinker_command;
647   if (!ReadLoadCommand(load_command_address,
648                        load_command_info,
649                        kExpectedCommand,
650                        &dylinker_command)) {
651     return false;
652   }
653 
654   if (!process_reader_->Memory()->ReadCStringSizeLimited(
655           load_command_address + dylinker_command.name,
656           dylinker_command.cmdsize - dylinker_command.name,
657           &dylinker_name_)) {
658     LOG(WARNING) << "could not read dylinker_command name" << load_command_info;
659     return false;
660   }
661 
662   return true;
663 }
664 
ReadUUIDCommand(mach_vm_address_t load_command_address,const std::string & load_command_info)665 bool MachOImageReader::ReadUUIDCommand(mach_vm_address_t load_command_address,
666                                        const std::string& load_command_info) {
667   process_types::uuid_command uuid_command;
668   if (!ReadLoadCommand(
669           load_command_address, load_command_info, LC_UUID, &uuid_command)) {
670     return false;
671   }
672 
673   uuid_.InitializeFromBytes(uuid_command.uuid);
674   return true;
675 }
676 
ReadSourceVersionCommand(mach_vm_address_t load_command_address,const std::string & load_command_info)677 bool MachOImageReader::ReadSourceVersionCommand(
678     mach_vm_address_t load_command_address,
679     const std::string& load_command_info) {
680   process_types::source_version_command source_version_command;
681   if (!ReadLoadCommand(load_command_address,
682                        load_command_info,
683                        LC_SOURCE_VERSION,
684                        &source_version_command)) {
685     return false;
686   }
687 
688   source_version_ = source_version_command.version;
689   return true;
690 }
691 
ReadUnexpectedCommand(mach_vm_address_t load_command_address,const std::string & load_command_info)692 bool MachOImageReader::ReadUnexpectedCommand(
693     mach_vm_address_t load_command_address,
694     const std::string& load_command_info) {
695   LOG(WARNING) << "unexpected load command" << load_command_info;
696   return false;
697 }
698 
InitializeSymbolTable() const699 void MachOImageReader::InitializeSymbolTable() const {
700   DCHECK(symbol_table_initialized_.is_uninitialized());
701   symbol_table_initialized_.set_invalid();
702 
703   if (!symtab_command_) {
704     // It’s technically valid for there to be no LC_SYMTAB, and in that case,
705     // any symbol lookups should fail. Mark the symbol table as valid, and
706     // LookUpExternalDefinedSymbol() will understand what it means when this is
707     // valid but symbol_table_ is not present.
708     symbol_table_initialized_.set_valid();
709     return;
710   }
711 
712   // Find the __LINKEDIT segment. Technically, the symbol table can be in any
713   // mapped segment, but by convention, it’s in the one named __LINKEDIT.
714   const MachOImageSegmentReader* linkedit_segment =
715       GetSegmentByName(SEG_LINKEDIT);
716   if (!linkedit_segment) {
717     LOG(WARNING) << "no " SEG_LINKEDIT " segment";
718     return;
719   }
720 
721   symbol_table_.reset(new MachOImageSymbolTableReader());
722   if (!symbol_table_->Initialize(process_reader_,
723                                  symtab_command_.get(),
724                                  dysymtab_command_.get(),
725                                  linkedit_segment,
726                                  module_info_)) {
727     symbol_table_.reset();
728     return;
729   }
730 
731   symbol_table_initialized_.set_valid();
732 }
733 
734 }  // namespace crashpad
735