sanitizer_procmaps_mac.cc 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. //===-- sanitizer_procmaps_mac.cc -----------------------------------------===//
  2. //
  3. // This file is distributed under the University of Illinois Open Source
  4. // License. See LICENSE.TXT for details.
  5. //
  6. //===----------------------------------------------------------------------===//
  7. //
  8. // Information about the process mappings (Mac-specific parts).
  9. //===----------------------------------------------------------------------===//
  10. #include "sanitizer_platform.h"
  11. #if SANITIZER_MAC
  12. #include "sanitizer_common.h"
  13. #include "sanitizer_placement_new.h"
  14. #include "sanitizer_procmaps.h"
  15. #include <mach-o/dyld.h>
  16. #include <mach-o/loader.h>
  17. namespace __sanitizer {
  18. MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) {
  19. Reset();
  20. }
  21. MemoryMappingLayout::~MemoryMappingLayout() {
  22. }
  23. // More information about Mach-O headers can be found in mach-o/loader.h
  24. // Each Mach-O image has a header (mach_header or mach_header_64) starting with
  25. // a magic number, and a list of linker load commands directly following the
  26. // header.
  27. // A load command is at least two 32-bit words: the command type and the
  28. // command size in bytes. We're interested only in segment load commands
  29. // (LC_SEGMENT and LC_SEGMENT_64), which tell that a part of the file is mapped
  30. // into the task's address space.
  31. // The |vmaddr|, |vmsize| and |fileoff| fields of segment_command or
  32. // segment_command_64 correspond to the memory address, memory size and the
  33. // file offset of the current memory segment.
  34. // Because these fields are taken from the images as is, one needs to add
  35. // _dyld_get_image_vmaddr_slide() to get the actual addresses at runtime.
  36. void MemoryMappingLayout::Reset() {
  37. // Count down from the top.
  38. // TODO(glider): as per man 3 dyld, iterating over the headers with
  39. // _dyld_image_count is thread-unsafe. We need to register callbacks for
  40. // adding and removing images which will invalidate the MemoryMappingLayout
  41. // state.
  42. current_image_ = _dyld_image_count();
  43. current_load_cmd_count_ = -1;
  44. current_load_cmd_addr_ = 0;
  45. current_magic_ = 0;
  46. current_filetype_ = 0;
  47. }
  48. // static
  49. void MemoryMappingLayout::CacheMemoryMappings() {
  50. // No-op on Mac for now.
  51. }
  52. void MemoryMappingLayout::LoadFromCache() {
  53. // No-op on Mac for now.
  54. }
  55. // Next and NextSegmentLoad were inspired by base/sysinfo.cc in
  56. // Google Perftools, http://code.google.com/p/google-perftools.
  57. // NextSegmentLoad scans the current image for the next segment load command
  58. // and returns the start and end addresses and file offset of the corresponding
  59. // segment.
  60. // Note that the segment addresses are not necessarily sorted.
  61. template<u32 kLCSegment, typename SegmentCommand>
  62. bool MemoryMappingLayout::NextSegmentLoad(
  63. uptr *start, uptr *end, uptr *offset,
  64. char filename[], uptr filename_size, uptr *protection) {
  65. const char* lc = current_load_cmd_addr_;
  66. current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize;
  67. if (((const load_command *)lc)->cmd == kLCSegment) {
  68. const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_);
  69. const SegmentCommand* sc = (const SegmentCommand *)lc;
  70. if (start) *start = sc->vmaddr + dlloff;
  71. if (protection) {
  72. // Return the initial protection.
  73. *protection = sc->initprot;
  74. }
  75. if (end) *end = sc->vmaddr + sc->vmsize + dlloff;
  76. if (offset) {
  77. if (current_filetype_ == /*MH_EXECUTE*/ 0x2) {
  78. *offset = sc->vmaddr;
  79. } else {
  80. *offset = sc->fileoff;
  81. }
  82. }
  83. if (filename) {
  84. internal_strncpy(filename, _dyld_get_image_name(current_image_),
  85. filename_size);
  86. }
  87. return true;
  88. }
  89. return false;
  90. }
  91. bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
  92. char filename[], uptr filename_size,
  93. uptr *protection) {
  94. for (; current_image_ >= 0; current_image_--) {
  95. const mach_header* hdr = _dyld_get_image_header(current_image_);
  96. if (!hdr) continue;
  97. if (current_load_cmd_count_ < 0) {
  98. // Set up for this image;
  99. current_load_cmd_count_ = hdr->ncmds;
  100. current_magic_ = hdr->magic;
  101. current_filetype_ = hdr->filetype;
  102. switch (current_magic_) {
  103. #ifdef MH_MAGIC_64
  104. case MH_MAGIC_64: {
  105. current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header_64);
  106. break;
  107. }
  108. #endif
  109. case MH_MAGIC: {
  110. current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header);
  111. break;
  112. }
  113. default: {
  114. continue;
  115. }
  116. }
  117. }
  118. for (; current_load_cmd_count_ >= 0; current_load_cmd_count_--) {
  119. switch (current_magic_) {
  120. // current_magic_ may be only one of MH_MAGIC, MH_MAGIC_64.
  121. #ifdef MH_MAGIC_64
  122. case MH_MAGIC_64: {
  123. if (NextSegmentLoad<LC_SEGMENT_64, struct segment_command_64>(
  124. start, end, offset, filename, filename_size, protection))
  125. return true;
  126. break;
  127. }
  128. #endif
  129. case MH_MAGIC: {
  130. if (NextSegmentLoad<LC_SEGMENT, struct segment_command>(
  131. start, end, offset, filename, filename_size, protection))
  132. return true;
  133. break;
  134. }
  135. }
  136. }
  137. // If we get here, no more load_cmd's in this image talk about
  138. // segments. Go on to the next image.
  139. }
  140. return false;
  141. }
  142. uptr MemoryMappingLayout::DumpListOfModules(LoadedModule *modules,
  143. uptr max_modules,
  144. string_predicate_t filter) {
  145. Reset();
  146. uptr cur_beg, cur_end, prot;
  147. InternalScopedBuffer<char> module_name(kMaxPathLength);
  148. uptr n_modules = 0;
  149. for (uptr i = 0; n_modules < max_modules &&
  150. Next(&cur_beg, &cur_end, 0, module_name.data(),
  151. module_name.size(), &prot);
  152. i++) {
  153. const char *cur_name = module_name.data();
  154. if (cur_name[0] == '\0')
  155. continue;
  156. if (filter && !filter(cur_name))
  157. continue;
  158. LoadedModule *cur_module = 0;
  159. if (n_modules > 0 &&
  160. 0 == internal_strcmp(cur_name, modules[n_modules - 1].full_name())) {
  161. cur_module = &modules[n_modules - 1];
  162. } else {
  163. void *mem = &modules[n_modules];
  164. cur_module = new(mem) LoadedModule(cur_name, cur_beg);
  165. n_modules++;
  166. }
  167. cur_module->addAddressRange(cur_beg, cur_end, prot & kProtectionExecute);
  168. }
  169. return n_modules;
  170. }
  171. } // namespace __sanitizer
  172. #endif // SANITIZER_MAC