* configure.ac: Change target-libasan to target-libsanitizer.
[official-gcc.git] / libsanitizer / sanitizer_common / sanitizer_mac.cc
blob400cd21842b2bbe369c6bfe950a17af877d51c31
1 //===-- sanitizer_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 // This file is shared between AddressSanitizer and ThreadSanitizer
9 // run-time libraries and implements mac-specific functions from
10 // sanitizer_libc.h.
11 //===----------------------------------------------------------------------===//
13 #ifdef __APPLE__
15 #include "sanitizer_common.h"
16 #include "sanitizer_internal_defs.h"
17 #include "sanitizer_libc.h"
18 #include "sanitizer_procmaps.h"
20 #include <crt_externs.h> // for _NSGetEnviron
21 #include <fcntl.h>
22 #include <mach-o/dyld.h>
23 #include <mach-o/loader.h>
24 #include <pthread.h>
25 #include <sched.h>
26 #include <sys/mman.h>
27 #include <sys/resource.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <unistd.h>
32 namespace __sanitizer {
34 // ---------------------- sanitizer_libc.h
35 void *internal_mmap(void *addr, size_t length, int prot, int flags,
36 int fd, u64 offset) {
37 return mmap(addr, length, prot, flags, fd, offset);
40 int internal_munmap(void *addr, uptr length) {
41 return munmap(addr, length);
44 int internal_close(fd_t fd) {
45 return close(fd);
48 fd_t internal_open(const char *filename, bool write) {
49 return open(filename,
50 write ? O_WRONLY | O_CREAT : O_RDONLY, 0660);
53 uptr internal_read(fd_t fd, void *buf, uptr count) {
54 return read(fd, buf, count);
57 uptr internal_write(fd_t fd, const void *buf, uptr count) {
58 return write(fd, buf, count);
61 uptr internal_filesize(fd_t fd) {
62 struct stat st;
63 if (fstat(fd, &st))
64 return -1;
65 return (uptr)st.st_size;
68 int internal_dup2(int oldfd, int newfd) {
69 return dup2(oldfd, newfd);
72 uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
73 return readlink(path, buf, bufsize);
76 int internal_sched_yield() {
77 return sched_yield();
80 // ----------------- sanitizer_common.h
81 uptr GetTid() {
82 return reinterpret_cast<uptr>(pthread_self());
85 void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
86 uptr *stack_bottom) {
87 CHECK(stack_top);
88 CHECK(stack_bottom);
89 uptr stacksize = pthread_get_stacksize_np(pthread_self());
90 void *stackaddr = pthread_get_stackaddr_np(pthread_self());
91 *stack_top = (uptr)stackaddr;
92 *stack_bottom = *stack_top - stacksize;
95 const char *GetEnv(const char *name) {
96 char ***env_ptr = _NSGetEnviron();
97 CHECK(env_ptr);
98 char **environ = *env_ptr;
99 CHECK(environ);
100 uptr name_len = internal_strlen(name);
101 while (*environ != 0) {
102 uptr len = internal_strlen(*environ);
103 if (len > name_len) {
104 const char *p = *environ;
105 if (!internal_memcmp(p, name, name_len) &&
106 p[name_len] == '=') { // Match.
107 return *environ + name_len + 1; // String starting after =.
110 environ++;
112 return 0;
115 void ReExec() {
116 UNIMPLEMENTED();
119 // ----------------- sanitizer_procmaps.h
121 MemoryMappingLayout::MemoryMappingLayout() {
122 Reset();
125 MemoryMappingLayout::~MemoryMappingLayout() {
128 // More information about Mach-O headers can be found in mach-o/loader.h
129 // Each Mach-O image has a header (mach_header or mach_header_64) starting with
130 // a magic number, and a list of linker load commands directly following the
131 // header.
132 // A load command is at least two 32-bit words: the command type and the
133 // command size in bytes. We're interested only in segment load commands
134 // (LC_SEGMENT and LC_SEGMENT_64), which tell that a part of the file is mapped
135 // into the task's address space.
136 // The |vmaddr|, |vmsize| and |fileoff| fields of segment_command or
137 // segment_command_64 correspond to the memory address, memory size and the
138 // file offset of the current memory segment.
139 // Because these fields are taken from the images as is, one needs to add
140 // _dyld_get_image_vmaddr_slide() to get the actual addresses at runtime.
142 void MemoryMappingLayout::Reset() {
143 // Count down from the top.
144 // TODO(glider): as per man 3 dyld, iterating over the headers with
145 // _dyld_image_count is thread-unsafe. We need to register callbacks for
146 // adding and removing images which will invalidate the MemoryMappingLayout
147 // state.
148 current_image_ = _dyld_image_count();
149 current_load_cmd_count_ = -1;
150 current_load_cmd_addr_ = 0;
151 current_magic_ = 0;
152 current_filetype_ = 0;
155 // Next and NextSegmentLoad were inspired by base/sysinfo.cc in
156 // Google Perftools, http://code.google.com/p/google-perftools.
158 // NextSegmentLoad scans the current image for the next segment load command
159 // and returns the start and end addresses and file offset of the corresponding
160 // segment.
161 // Note that the segment addresses are not necessarily sorted.
162 template<u32 kLCSegment, typename SegmentCommand>
163 bool MemoryMappingLayout::NextSegmentLoad(
164 uptr *start, uptr *end, uptr *offset,
165 char filename[], uptr filename_size) {
166 const char* lc = current_load_cmd_addr_;
167 current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize;
168 if (((const load_command *)lc)->cmd == kLCSegment) {
169 const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_);
170 const SegmentCommand* sc = (const SegmentCommand *)lc;
171 if (start) *start = sc->vmaddr + dlloff;
172 if (end) *end = sc->vmaddr + sc->vmsize + dlloff;
173 if (offset) {
174 if (current_filetype_ == /*MH_EXECUTE*/ 0x2) {
175 *offset = sc->vmaddr;
176 } else {
177 *offset = sc->fileoff;
180 if (filename) {
181 internal_strncpy(filename, _dyld_get_image_name(current_image_),
182 filename_size);
184 return true;
186 return false;
189 bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
190 char filename[], uptr filename_size) {
191 for (; current_image_ >= 0; current_image_--) {
192 const mach_header* hdr = _dyld_get_image_header(current_image_);
193 if (!hdr) continue;
194 if (current_load_cmd_count_ < 0) {
195 // Set up for this image;
196 current_load_cmd_count_ = hdr->ncmds;
197 current_magic_ = hdr->magic;
198 current_filetype_ = hdr->filetype;
199 switch (current_magic_) {
200 #ifdef MH_MAGIC_64
201 case MH_MAGIC_64: {
202 current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header_64);
203 break;
205 #endif
206 case MH_MAGIC: {
207 current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header);
208 break;
210 default: {
211 continue;
216 for (; current_load_cmd_count_ >= 0; current_load_cmd_count_--) {
217 switch (current_magic_) {
218 // current_magic_ may be only one of MH_MAGIC, MH_MAGIC_64.
219 #ifdef MH_MAGIC_64
220 case MH_MAGIC_64: {
221 if (NextSegmentLoad<LC_SEGMENT_64, struct segment_command_64>(
222 start, end, offset, filename, filename_size))
223 return true;
224 break;
226 #endif
227 case MH_MAGIC: {
228 if (NextSegmentLoad<LC_SEGMENT, struct segment_command>(
229 start, end, offset, filename, filename_size))
230 return true;
231 break;
235 // If we get here, no more load_cmd's in this image talk about
236 // segments. Go on to the next image.
238 return false;
241 bool MemoryMappingLayout::GetObjectNameAndOffset(uptr addr, uptr *offset,
242 char filename[],
243 uptr filename_size) {
244 return IterateForObjectNameAndOffset(addr, offset, filename, filename_size);
247 } // namespace __sanitizer
249 #endif // __APPLE__