blob: af25b245fdd3b20520024c93f574c82a4cb9409f [file] [log] [blame]
Alexey Samsonov1f11d312012-06-05 09:49:25 +00001//===-- sanitizer_posix.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// This file is shared between AddressSanitizer and ThreadSanitizer
11// run-time libraries and implements POSIX-specific functions from
12// sanitizer_libc.h.
13//===----------------------------------------------------------------------===//
Evgeniy Stepanov24e13722013-03-19 14:33:38 +000014
15#include "sanitizer_platform.h"
16#if SANITIZER_LINUX || SANITIZER_MAC
Alexey Samsonov1f11d312012-06-05 09:49:25 +000017
Alexey Samsonov230c3be2012-06-06 09:26:25 +000018#include "sanitizer_common.h"
Alexey Samsonov1f11d312012-06-05 09:49:25 +000019#include "sanitizer_libc.h"
Alexey Samsonovbe7420c2012-06-15 06:08:19 +000020#include "sanitizer_procmaps.h"
Sergey Matveev736cf492013-05-08 12:45:55 +000021#include "sanitizer_stacktrace.h"
Alexey Samsonov1f11d312012-06-05 09:49:25 +000022
Alexey Samsonov230c3be2012-06-06 09:26:25 +000023#include <sys/mman.h>
Alexey Samsonov1f11d312012-06-05 09:49:25 +000024
25namespace __sanitizer {
26
Alexey Samsonovbe7420c2012-06-15 06:08:19 +000027// ------------- sanitizer_common.h
Kostya Serebryanyf67ec2b2012-11-23 15:38:49 +000028uptr GetMmapGranularity() {
29 return GetPageSize();
30}
Alexey Samsonovbe7420c2012-06-15 06:08:19 +000031
Alexey Samsonova25b3462012-06-06 16:15:07 +000032void *MmapOrDie(uptr size, const char *mem_type) {
Kostya Serebryanyf67ec2b2012-11-23 15:38:49 +000033 size = RoundUpTo(size, GetPageSizeCached());
Peter Collingbourne9578a3e2013-05-08 14:43:49 +000034 uptr res = internal_mmap(0, size,
Alexey Samsonov230c3be2012-06-06 09:26:25 +000035 PROT_READ | PROT_WRITE,
36 MAP_PRIVATE | MAP_ANON, -1, 0);
Peter Collingbourne9578a3e2013-05-08 14:43:49 +000037 int reserrno;
38 if (internal_iserror(res, &reserrno)) {
Kostya Serebryanye8216fd2012-10-04 07:21:09 +000039 static int recursion_count;
40 if (recursion_count) {
41 // The Report() and CHECK calls below may call mmap recursively and fail.
42 // If we went into recursion, just die.
Dmitry Vyukovc8490e22013-01-29 09:39:58 +000043 RawWrite("ERROR: Failed to mmap\n");
Kostya Serebryanye8216fd2012-10-04 07:21:09 +000044 Die();
45 }
46 recursion_count++;
Alexander Potapenkoa8d37a02013-03-11 10:21:28 +000047 Report("ERROR: %s failed to allocate 0x%zx (%zd) bytes of %s: %d\n",
Peter Collingbourne9578a3e2013-05-08 14:43:49 +000048 SanitizerToolName, size, size, mem_type, reserrno);
Kostya Serebryany0aa04b32012-08-14 15:18:40 +000049 DumpProcessMap();
Alexey Samsonova25b3462012-06-06 16:15:07 +000050 CHECK("unable to mmap" && 0);
Alexey Samsonov230c3be2012-06-06 09:26:25 +000051 }
Peter Collingbourne9578a3e2013-05-08 14:43:49 +000052 return (void *)res;
Alexey Samsonov230c3be2012-06-06 09:26:25 +000053}
54
55void UnmapOrDie(void *addr, uptr size) {
56 if (!addr || !size) return;
Peter Collingbourne9578a3e2013-05-08 14:43:49 +000057 uptr res = internal_munmap(addr, size);
58 if (internal_iserror(res)) {
Kostya Serebryany859778a2013-01-31 14:11:21 +000059 Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
60 SanitizerToolName, size, size, addr);
Alexey Samsonova25b3462012-06-06 16:15:07 +000061 CHECK("unable to unmap" && 0);
Alexey Samsonov230c3be2012-06-06 09:26:25 +000062 }
63}
64
Alexey Samsonovf607fc12012-06-14 14:42:58 +000065void *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
Kostya Serebryanyf67ec2b2012-11-23 15:38:49 +000066 uptr PageSize = GetPageSizeCached();
Peter Collingbourne9578a3e2013-05-08 14:43:49 +000067 uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
Kostya Serebryanyf67ec2b2012-11-23 15:38:49 +000068 RoundUpTo(size, PageSize),
Dmitry Vyukov6b641c52012-11-06 16:48:46 +000069 PROT_READ | PROT_WRITE,
70 MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
71 -1, 0);
Peter Collingbourne9578a3e2013-05-08 14:43:49 +000072 int reserrno;
73 if (internal_iserror(p, &reserrno))
Kostya Serebryany859778a2013-01-31 14:11:21 +000074 Report("ERROR: "
75 "%s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
Peter Collingbourne9578a3e2013-05-08 14:43:49 +000076 SanitizerToolName, size, size, fixed_addr, reserrno);
77 return (void *)p;
Alexey Samsonovf607fc12012-06-14 14:42:58 +000078}
79
Kostya Serebryany9bfe78f2012-12-13 05:36:00 +000080void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
81 uptr PageSize = GetPageSizeCached();
Peter Collingbourne9578a3e2013-05-08 14:43:49 +000082 uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
Kostya Serebryany9bfe78f2012-12-13 05:36:00 +000083 RoundUpTo(size, PageSize),
84 PROT_READ | PROT_WRITE,
85 MAP_PRIVATE | MAP_ANON | MAP_FIXED,
86 -1, 0);
Peter Collingbourne9578a3e2013-05-08 14:43:49 +000087 int reserrno;
88 if (internal_iserror(p, &reserrno)) {
Kostya Serebryany859778a2013-01-31 14:11:21 +000089 Report("ERROR:"
90 " %s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
Peter Collingbourne9578a3e2013-05-08 14:43:49 +000091 SanitizerToolName, size, size, fixed_addr, reserrno);
Kostya Serebryany9bfe78f2012-12-13 05:36:00 +000092 CHECK("unable to mmap" && 0);
93 }
Peter Collingbourne9578a3e2013-05-08 14:43:49 +000094 return (void *)p;
Kostya Serebryany9bfe78f2012-12-13 05:36:00 +000095}
96
Alexey Samsonovf607fc12012-06-14 14:42:58 +000097void *Mprotect(uptr fixed_addr, uptr size) {
Peter Collingbourne9578a3e2013-05-08 14:43:49 +000098 return (void *)internal_mmap((void*)fixed_addr, size,
99 PROT_NONE,
100 MAP_PRIVATE | MAP_ANON | MAP_FIXED |
101 MAP_NORESERVE, -1, 0);
Alexey Samsonovf607fc12012-06-14 14:42:58 +0000102}
103
Alexey Samsonova68633f2012-07-03 08:24:14 +0000104void *MapFileToMemory(const char *file_name, uptr *buff_size) {
Peter Collingbourne9578a3e2013-05-08 14:43:49 +0000105 uptr openrv = OpenFile(file_name, false);
106 CHECK(!internal_iserror(openrv));
107 fd_t fd = openrv;
Alexey Samsonova68633f2012-07-03 08:24:14 +0000108 uptr fsize = internal_filesize(fd);
109 CHECK_NE(fsize, (uptr)-1);
110 CHECK_GT(fsize, 0);
Kostya Serebryanyf67ec2b2012-11-23 15:38:49 +0000111 *buff_size = RoundUpTo(fsize, GetPageSizeCached());
Peter Collingbourne9578a3e2013-05-08 14:43:49 +0000112 uptr map = internal_mmap(0, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0);
113 return internal_iserror(map) ? 0 : (void *)map;
Alexey Samsonova68633f2012-07-03 08:24:14 +0000114}
115
116
Alexey Samsonovdd3a9112012-06-15 07:29:14 +0000117static inline bool IntervalsAreSeparate(uptr start1, uptr end1,
118 uptr start2, uptr end2) {
119 CHECK(start1 <= end1);
120 CHECK(start2 <= end2);
121 return (end1 < start2) || (end2 < start1);
122}
123
124// FIXME: this is thread-unsafe, but should not cause problems most of the time.
125// When the shadow is mapped only a single thread usually exists (plus maybe
126// several worker threads on Mac, which aren't expected to map big chunks of
127// memory).
128bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
Alexander Potapenko9ae28832013-03-26 10:34:37 +0000129 MemoryMappingLayout proc_maps(/*cache_enabled*/true);
Alexey Samsonovdd3a9112012-06-15 07:29:14 +0000130 uptr start, end;
Alexander Potapenko9ae28832013-03-26 10:34:37 +0000131 while (proc_maps.Next(&start, &end,
132 /*offset*/0, /*filename*/0, /*filename_size*/0,
133 /*protection*/0)) {
Alexey Samsonovdd3a9112012-06-15 07:29:14 +0000134 if (!IntervalsAreSeparate(start, end, range_start, range_end))
135 return false;
136 }
137 return true;
138}
139
Alexey Samsonovbe7420c2012-06-15 06:08:19 +0000140void DumpProcessMap() {
Alexander Potapenko9ae28832013-03-26 10:34:37 +0000141 MemoryMappingLayout proc_maps(/*cache_enabled*/true);
Alexey Samsonovbe7420c2012-06-15 06:08:19 +0000142 uptr start, end;
143 const sptr kBufSize = 4095;
Alexey Samsonovb84ee022012-06-15 07:41:23 +0000144 char *filename = (char*)MmapOrDie(kBufSize, __FUNCTION__);
Alexey Samsonovbe7420c2012-06-15 06:08:19 +0000145 Report("Process memory map follows:\n");
146 while (proc_maps.Next(&start, &end, /* file_offset */0,
Alexey Samsonov45717c92013-03-13 06:51:02 +0000147 filename, kBufSize, /* protection */0)) {
Alexey Samsonovbe7420c2012-06-15 06:08:19 +0000148 Printf("\t%p-%p\t%s\n", (void*)start, (void*)end, filename);
149 }
150 Report("End of process memory map.\n");
Alexey Samsonovb84ee022012-06-15 07:41:23 +0000151 UnmapOrDie(filename, kBufSize);
Alexey Samsonovbe7420c2012-06-15 06:08:19 +0000152}
153
Alexey Samsonov0969bcf2012-06-18 08:44:30 +0000154const char *GetPwd() {
155 return GetEnv("PWD");
156}
157
Alexey Samsonov1f11d312012-06-05 09:49:25 +0000158} // namespace __sanitizer
159
Sergey Matveev736cf492013-05-08 12:45:55 +0000160#endif // SANITIZER_LINUX || SANITIZER_MAC