1// Copyright (c) 2011, 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// Override mmap/munmap/mremap/sbrk to provide support for calling the
31// related hooks (in addition, of course, to doing what these
32// functions normally do).
33
34#ifndef __FreeBSD__
35# error Should only be including malloc_hook_mmap_freebsd.h on FreeBSD systems.
36#endif
37
38#include <unistd.h>
39#include <sys/syscall.h>
40#include <sys/mman.h>
41#include <errno.h>
42
43// Make sure mmap doesn't get #define'd away by <sys/mman.h>
44#undef mmap
45
46// According to the FreeBSD documentation, use syscall if you do not
47// need 64-bit alignment otherwise use __syscall. Indeed, syscall
48// doesn't work correctly in most situations on 64-bit. It's return
49// type is 'int' so for things like SYS_mmap, it actually truncates
50// the returned address to 32-bits.
51#if defined(__amd64__) || defined(__x86_64__)
52# define MALLOC_HOOK_SYSCALL __syscall
53#else
54# define MALLOC_HOOK_SYSCALL syscall
55#endif
56
57
58extern "C" {
59  void* mmap(void *start, size_t length,int prot, int flags,
60             int fd, off_t offset) __THROW
61    ATTRIBUTE_SECTION(malloc_hook);
62  int munmap(void* start, size_t length) __THROW
63    ATTRIBUTE_SECTION(malloc_hook);
64  void* sbrk(intptr_t increment) __THROW
65    ATTRIBUTE_SECTION(malloc_hook);
66}
67
68static inline void* do_mmap(void *start, size_t length,
69                            int prot, int flags,
70                            int fd, off_t offset) __THROW {
71  return (void *)MALLOC_HOOK_SYSCALL(SYS_mmap,
72                                     start, length, prot, flags, fd, offset);
73}
74
75static inline void* do_sbrk(intptr_t increment) {
76  void* curbrk = 0;
77
78#if defined(__x86_64__) || defined(__amd64__)
79# ifdef PIC
80  __asm__ __volatile__(
81      "movq .curbrk@GOTPCREL(%%rip), %%rdx;"
82      "movq (%%rdx), %%rax;"
83      "movq %%rax, %0;"
84      : "=r" (curbrk)
85      :: "%rdx", "%rax");
86# else
87  __asm__ __volatile__(
88      "movq .curbrk(%%rip), %%rax;"
89      "movq %%rax, %0;"
90      : "=r" (curbrk)
91      :: "%rax");
92# endif
93#else
94  __asm__ __volatile__(
95      "movl .curbrk, %%eax;"
96      "movl %%eax, %0;"
97      : "=r" (curbrk)
98      :: "%eax");
99#endif
100
101  if (increment == 0) {
102    return curbrk;
103  }
104
105  char* prevbrk = static_cast<char*>(curbrk);
106  void* newbrk = prevbrk + increment;
107
108  if (brk(newbrk) == -1) {
109    return reinterpret_cast<void*>(static_cast<intptr_t>(-1));
110  }
111
112  return prevbrk;
113}
114
115
116extern "C" void* mmap(void *start, size_t length, int prot, int flags,
117                      int fd, off_t offset) __THROW {
118  MallocHook::InvokePreMmapHook(start, length, prot, flags, fd, offset);
119  void *result;
120  if (!MallocHook::InvokeMmapReplacement(
121          start, length, prot, flags, fd, offset, &result)) {
122    result = do_mmap(start, length, prot, flags, fd,
123                       static_cast<size_t>(offset)); // avoid sign extension
124  }
125  MallocHook::InvokeMmapHook(result, start, length, prot, flags, fd, offset);
126  return result;
127}
128
129extern "C" int munmap(void* start, size_t length) __THROW {
130  MallocHook::InvokeMunmapHook(start, length);
131  int result;
132  if (!MallocHook::InvokeMunmapReplacement(start, length, &result)) {
133    result = MALLOC_HOOK_SYSCALL(SYS_munmap, start, length);
134  }
135
136  return result;
137}
138
139extern "C" void* sbrk(intptr_t increment) __THROW {
140  MallocHook::InvokePreSbrkHook(increment);
141  void *result = do_sbrk(increment);
142  MallocHook::InvokeSbrkHook(result, increment);
143  return result;
144}
145
146/*static*/void* MallocHook::UnhookedMMap(void *start, size_t length, int prot,
147                                         int flags, int fd, off_t offset) {
148  void* result;
149  if (!MallocHook::InvokeMmapReplacement(
150	  start, length, prot, flags, fd, offset, &result)) {
151    result = do_mmap(start, length, prot, flags, fd, offset);
152  }
153
154  return result;
155}
156
157/*static*/int MallocHook::UnhookedMUnmap(void *start, size_t length) {
158  int result;
159  if (!MallocHook::InvokeMunmapReplacement(start, length, &result)) {
160    result = MALLOC_HOOK_SYSCALL(SYS_munmap, start, length);
161  }
162  return result;
163}
164
165#undef MALLOC_HOOK_SYSCALL
166