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, §ion_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