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