blob: 2a529167d45ff4c31224de053a8cd2809219b4c3 [file] [log] [blame]
Kostya Serebryany019b76f2011-11-30 01:07:021//===-- asan_linux.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 a part of AddressSanitizer, an address sanity checker.
11//
12// Linux-specific details.
13//===----------------------------------------------------------------------===//
Kostya Serebryany5dfa4da2011-12-01 21:40:5214#ifdef __linux__
Kostya Serebryany019b76f2011-11-30 01:07:0215
Kostya Serebryanycd271f52012-01-05 00:44:3316#include "asan_interceptors.h"
Kostya Serebryany019b76f2011-11-30 01:07:0217#include "asan_internal.h"
Kostya Serebryanycd271f52012-01-05 00:44:3318#include "asan_procmaps.h"
Kostya Serebryany019b76f2011-11-30 01:07:0219
20#include <sys/mman.h>
21#include <sys/syscall.h>
Kostya Serebryany6c4bd802011-12-28 22:58:0122#include <sys/types.h>
23#include <fcntl.h>
Kostya Serebryanycd271f52012-01-05 00:44:3324#include <stdio.h>
Kostya Serebryany019b76f2011-11-30 01:07:0225#include <unistd.h>
26
27extern char _DYNAMIC[];
28
29namespace __asan {
30
31void *AsanDoesNotSupportStaticLinkage() {
32 // This will fail to link with -static.
33 return &_DYNAMIC;
34}
35
Kostya Serebryanya7720962011-12-28 23:28:5436static void *asan_mmap(void *addr, size_t length, int prot, int flags,
Kostya Serebryany019b76f2011-11-30 01:07:0237 int fd, uint64_t offset) {
38# if __WORDSIZE == 64
Kostya Serebryany6c4bd802011-12-28 22:58:0139 return (void *)syscall(__NR_mmap, addr, length, prot, flags, fd, offset);
Kostya Serebryany019b76f2011-11-30 01:07:0240# else
Kostya Serebryany6c4bd802011-12-28 22:58:0141 return (void *)syscall(__NR_mmap2, addr, length, prot, flags, fd, offset);
Kostya Serebryany019b76f2011-11-30 01:07:0242# endif
43}
44
Kostya Serebryany6c4bd802011-12-28 22:58:0145void *AsanMmapSomewhereOrDie(size_t size, const char *mem_type) {
46 size = RoundUpTo(size, kPageSize);
47 void *res = asan_mmap(0, size,
48 PROT_READ | PROT_WRITE,
49 MAP_PRIVATE | MAP_ANON, -1, 0);
50 if (res == (void*)-1) {
51 OutOfMemoryMessageAndDie(mem_type, size);
52 }
53 return res;
54}
55
Kostya Serebryanya7720962011-12-28 23:28:5456void *AsanMmapFixedNoReserve(uintptr_t fixed_addr, size_t size) {
57 return asan_mmap((void*)fixed_addr, size,
58 PROT_READ | PROT_WRITE,
59 MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
60 0, 0);
61}
62
63void *AsanMmapFixedReserve(uintptr_t fixed_addr, size_t size) {
64 return asan_mmap((void*)fixed_addr, size,
65 PROT_READ | PROT_WRITE,
66 MAP_PRIVATE | MAP_ANON | MAP_FIXED,
67 0, 0);
68}
69
70void *AsanMprotect(uintptr_t fixed_addr, size_t size) {
71 return asan_mmap((void*)fixed_addr, size,
72 PROT_NONE,
73 MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
74 0, 0);
75}
76
Kostya Serebryany6c4bd802011-12-28 22:58:0177void AsanUnmapOrDie(void *addr, size_t size) {
78 if (!addr || !size) return;
79 int res = syscall(__NR_munmap, addr, size);
80 if (res != 0) {
81 Report("Failed to unmap\n");
82 ASAN_DIE;
83 }
84}
85
86ssize_t AsanWrite(int fd, const void *buf, size_t count) {
87 return (ssize_t)syscall(__NR_write, fd, buf, count);
88}
89
90int AsanOpenReadonly(const char* filename) {
91 return open(filename, O_RDONLY);
92}
93
94ssize_t AsanRead(int fd, void *buf, size_t count) {
95 return (ssize_t)syscall(__NR_read, fd, buf, count);
96}
97
98int AsanClose(int fd) {
99 return close(fd);
Kostya Serebryany019b76f2011-11-30 01:07:02100}
101
Kostya Serebryanycd271f52012-01-05 00:44:33102AsanProcMaps::AsanProcMaps() {
103 proc_self_maps_buff_len_ =
104 ReadFileToBuffer("/proc/self/maps", &proc_self_maps_buff_,
105 &proc_self_maps_buff_mmaped_size_, 1 << 20);
106 CHECK(proc_self_maps_buff_len_ > 0);
107 // AsanWrite(2, proc_self_maps_buff_, proc_self_maps_buff_len_);
108 Reset();
109}
110
111AsanProcMaps::~AsanProcMaps() {
112 AsanUnmapOrDie(proc_self_maps_buff_, proc_self_maps_buff_mmaped_size_);
113}
114
115void AsanProcMaps::Reset() {
116 current_ = proc_self_maps_buff_;
117}
118
119bool AsanProcMaps::Next(uint64_t *start, uint64_t *end,
120 uint64_t *offset, char filename[],
121 size_t filename_size) {
122 char *last = proc_self_maps_buff_ + proc_self_maps_buff_len_;
123 if (current_ >= last) return false;
124 int consumed = 0;
125 char flags[10];
126 int major, minor;
127 uint64_t inode;
128 char *next_line = (char*)internal_memchr(current_, '\n', last - current_);
129 if (next_line == NULL)
130 next_line = last;
131 if (SScanf(current_,
132 "%llx-%llx %4s %llx %x:%x %lld %n",
133 start, end, flags, offset, &major, &minor,
134 &inode, &consumed) != 7)
135 return false;
136 current_ += consumed;
137 // Skip spaces.
138 while (current_ < next_line && *current_ == ' ')
139 current_++;
140 // Fill in the filename.
141 size_t i = 0;
142 while (current_ < next_line) {
143 if (filename && i < filename_size - 1)
144 filename[i++] = *current_;
145 current_++;
146 }
147 if (filename && i < filename_size)
148 filename[i] = 0;
149 current_ = next_line + 1;
150 return true;
151}
152
Kostya Serebryany019b76f2011-11-30 01:07:02153} // namespace __asan
Kostya Serebryany5dfa4da2011-12-01 21:40:52154
155#endif // __linux__