OLD | NEW |
| (Empty) |
1 // Copyright (c) 2009, Google Inc. | |
2 // All rights reserved. | |
3 // | |
4 // Redistribution and use in source and binary forms, with or without | |
5 // modification, are permitted provided that the following conditions are | |
6 // met: | |
7 // | |
8 // * Redistributions of source code must retain the above copyright | |
9 // notice, this list of conditions and the following disclaimer. | |
10 // * Redistributions in binary form must reproduce the above | |
11 // copyright notice, this list of conditions and the following disclaimer | |
12 // in the documentation and/or other materials provided with the | |
13 // distribution. | |
14 // * Neither the name of Google Inc. nor the names of its | |
15 // contributors may be used to endorse or promote products derived from | |
16 // this software without specific prior written permission. | |
17 // | |
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 | |
30 #ifndef CLIENT_LINUX_HANDLER_MEMORY_H_ | |
31 #define CLIENT_LINUX_HANDLER_MEMORY_H_ | |
32 | |
33 #include <stdint.h> | |
34 #include <stdlib.h> | |
35 #include <unistd.h> | |
36 #include <sys/mman.h> | |
37 | |
38 #include "common/linux/linux_syscall_support.h" | |
39 | |
40 namespace google_breakpad { | |
41 | |
42 // This is very simple allocator which fetches pages from the kernel directly. | |
43 // Thus, it can be used even when the heap may be corrupted. | |
44 // | |
45 // There is no free operation. The pages are only freed when the object is | |
46 // destroyed. | |
47 class PageAllocator { | |
48 public: | |
49 PageAllocator() | |
50 : page_size_(getpagesize()), | |
51 last_(NULL), | |
52 current_page_(NULL), | |
53 page_offset_(0) { | |
54 } | |
55 | |
56 ~PageAllocator() { | |
57 FreeAll(); | |
58 } | |
59 | |
60 void *Alloc(unsigned bytes) { | |
61 if (!bytes) | |
62 return NULL; | |
63 | |
64 if (current_page_ && page_size_ - page_offset_ >= bytes) { | |
65 uint8_t *const ret = current_page_ + page_offset_; | |
66 page_offset_ += bytes; | |
67 if (page_offset_ == page_size_) { | |
68 page_offset_ = 0; | |
69 current_page_ = NULL; | |
70 } | |
71 | |
72 return ret; | |
73 } | |
74 | |
75 const unsigned pages = | |
76 (bytes + sizeof(PageHeader) + page_size_ - 1) / page_size_; | |
77 uint8_t *const ret = GetNPages(pages); | |
78 if (!ret) | |
79 return NULL; | |
80 | |
81 page_offset_ = (page_size_ - (page_size_ * pages - (bytes + sizeof(PageHeade
r)))) % page_size_; | |
82 current_page_ = page_offset_ ? ret + page_size_ * (pages - 1) : NULL; | |
83 | |
84 return ret + sizeof(PageHeader); | |
85 } | |
86 | |
87 private: | |
88 uint8_t *GetNPages(unsigned num_pages) { | |
89 #ifdef __x86_64 | |
90 void *a = sys_mmap(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE, | |
91 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | |
92 #else | |
93 void *a = sys_mmap2(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE, | |
94 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | |
95 #endif | |
96 if (a == MAP_FAILED) | |
97 return NULL; | |
98 | |
99 struct PageHeader *header = reinterpret_cast<PageHeader*>(a); | |
100 header->next = last_; | |
101 header->num_pages = num_pages; | |
102 last_ = header; | |
103 | |
104 return reinterpret_cast<uint8_t*>(a); | |
105 } | |
106 | |
107 void FreeAll() { | |
108 PageHeader *next; | |
109 | |
110 for (PageHeader *cur = last_; cur; cur = next) { | |
111 next = cur->next; | |
112 sys_munmap(cur, cur->num_pages * page_size_); | |
113 } | |
114 } | |
115 | |
116 struct PageHeader { | |
117 PageHeader *next; // pointer to the start of the next set of pages. | |
118 unsigned num_pages; // the number of pages in this set. | |
119 }; | |
120 | |
121 const unsigned page_size_; | |
122 PageHeader *last_; | |
123 uint8_t *current_page_; | |
124 unsigned page_offset_; | |
125 }; | |
126 | |
127 // A wasteful vector is like a normal std::vector, except that it's very much | |
128 // simplier and it allocates memory from a PageAllocator. It's wasteful | |
129 // because, when resizing, it always allocates a whole new array since the | |
130 // PageAllocator doesn't support realloc. | |
131 template<class T> | |
132 class wasteful_vector { | |
133 public: | |
134 wasteful_vector(PageAllocator *allocator, unsigned size_hint = 16) | |
135 : allocator_(allocator), | |
136 a_((T*) allocator->Alloc(sizeof(T) * size_hint)), | |
137 allocated_(size_hint), | |
138 used_(0) { | |
139 } | |
140 | |
141 void push_back(const T& new_element) { | |
142 if (used_ == allocated_) | |
143 Realloc(allocated_ * 2); | |
144 a_[used_++] = new_element; | |
145 } | |
146 | |
147 size_t size() const { | |
148 return used_; | |
149 } | |
150 | |
151 T& operator[](size_t index) { | |
152 return a_[index]; | |
153 } | |
154 | |
155 const T& operator[](size_t index) const { | |
156 return a_[index]; | |
157 } | |
158 | |
159 private: | |
160 void Realloc(unsigned new_size) { | |
161 T *new_array = | |
162 reinterpret_cast<T*>(allocator_->Alloc(sizeof(T) * new_size)); | |
163 memcpy(new_array, a_, used_ * sizeof(T)); | |
164 a_ = new_array; | |
165 allocated_ = new_size; | |
166 } | |
167 | |
168 PageAllocator *const allocator_; | |
169 T *a_; // pointer to an array of |allocated_| elements. | |
170 unsigned allocated_; // size of |a_|, in elements. | |
171 unsigned used_; // number of used slots in |a_|. | |
172 }; | |
173 | |
174 } // namespace google_breakpad | |
175 | |
176 inline void* operator new(size_t nbytes, | |
177 google_breakpad::PageAllocator& allocator) { | |
178 return allocator.Alloc(nbytes); | |
179 } | |
180 | |
181 #endif // CLIENT_LINUX_HANDLER_MEMORY_H_ | |
OLD | NEW |