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