aboutsummaryrefslogtreecommitdiffstats
path: root/src/3rdparty/masm/stubs/ExecutableAllocator.h
blob: 876a12fce5b178688bcc330edf87adb5c6dfb001 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef MASM_EXECUTABLEALLOCATOR_H
#define MASM_EXECUTABLEALLOCATOR_H

#include <RefPtr.h>
#include <RefCounted.h>
#include <wtf/PageBlock.h>

#include <private/qv4executableallocator_p.h>

#if OS(INTEGRITY)
#include "OSAllocator.h"
#endif

#if OS(WINDOWS)
#include <qt_windows.h>
#else
#include <sys/mman.h>
#include <unistd.h>
#endif

#ifdef __QNXNTO__
using std::perror;
#endif

namespace JSC {

class JSGlobalData;

struct ExecutableMemoryHandle : public RefCounted<ExecutableMemoryHandle> {
    ExecutableMemoryHandle(QV4::ExecutableAllocator *allocator, size_t size)
        : m_allocator(allocator)
        , m_size(size)
    {
        m_allocation = allocator->allocate(size);
    }
    ~ExecutableMemoryHandle()
    {
        m_allocation->deallocate(m_allocator);
    }

    inline void shrink(size_t) {
        // ### TODO.
    }

    inline bool isManaged() const { return true; }

    void *memoryStart() { return m_allocation->memoryStart(); }
    size_t memorySize() { return m_allocation->memorySize(); }

    void *exceptionHandlerStart() { return m_allocation->exceptionHandlerStart(); }
    size_t exceptionHandlerSize() { return m_allocation->exceptionHandlerSize(); }

    void *codeStart() { return m_allocation->codeStart(); }
    size_t codeSize() { return m_size; }

    QV4::ExecutableAllocator::ChunkOfPages *chunk() const
    { return m_allocator->chunkForAllocation(m_allocation); }

    QV4::ExecutableAllocator *m_allocator;
    QV4::ExecutableAllocator::Allocation *m_allocation;
    size_t m_size;
};

struct ExecutableAllocator {
    ExecutableAllocator(QV4::ExecutableAllocator *alloc)
        : realAllocator(alloc)
    {}

    Ref<ExecutableMemoryHandle> allocate(JSGlobalData&, size_t size, void*, int)
    {
        return adoptRef(new ExecutableMemoryHandle(realAllocator, size));
    }

    static bool makeWritable(void* addr, size_t size)
    {
        quintptr pageSize = WTF::pageSize();
        quintptr iaddr = reinterpret_cast<quintptr>(addr);
        quintptr roundAddr = iaddr & ~(pageSize - 1);
        size = size + (iaddr - roundAddr);
        addr = reinterpret_cast<void*>(roundAddr);

#if ENABLE(ASSEMBLER_WX_EXCLUSIVE) && !defined(V4_BOOTSTRAP)
#  if OS(WINDOWS)
        DWORD oldProtect;
#    if !OS(WINRT)
        VirtualProtect(addr, size, PAGE_READWRITE, &oldProtect);
#    else
        bool hr = VirtualProtectFromApp(addr, size, PAGE_READWRITE, &oldProtect);
        if (!hr) {
            return false;
        }
#    endif
#  elif OS(INTEGRITY)
         OSAllocator::setMemoryAttributes(addr, size, /*writable*/ true, /*executable*/ false);
#  else
        int mode = PROT_READ | PROT_WRITE;
        if (mprotect(addr, size, mode) != 0) {
            perror("mprotect failed in ExecutableAllocator::makeWritable");
            return false;
        }
#  endif
#else
        // We assume we already have RWX
        (void)addr; // suppress unused parameter warning
        (void)size; // suppress unused parameter warning
#endif
        return true;
    }

    static bool makeExecutable(void* addr, size_t size)
    {
        quintptr pageSize = WTF::pageSize();
        quintptr iaddr = reinterpret_cast<quintptr>(addr);
        quintptr roundAddr = iaddr & ~(pageSize - 1);
        size = size + (iaddr - roundAddr);
        addr = reinterpret_cast<void*>(roundAddr);

#if !defined(V4_BOOTSTRAP)
#if ENABLE(ASSEMBLER_WX_EXCLUSIVE)
#  if OS(WINDOWS)
        DWORD oldProtect;
#    if !OS(WINRT)
        VirtualProtect(addr, size, PAGE_EXECUTE_READ, &oldProtect);
#    else
        bool hr = VirtualProtectFromApp(addr, size, PAGE_EXECUTE_READ, &oldProtect);
        if (!hr) {
            return false;
        }
#    endif
#  elif OS(INTEGRITY)
        OSAllocator::setMemoryAttributes(addr, size, /*writable*/ false, /*executable*/ true);
#  else
        int mode = PROT_READ | PROT_EXEC;
        if (mprotect(addr, size, mode) != 0) {
            perror("mprotect failed in ExecutableAllocator::makeExecutable");
            return false;
        }
#  endif
#else
#  error "Only W^X is supported"
#endif
#else
        (void)addr; // suppress unused parameter warning
        (void)size; // suppress unused parameter warning
#endif
        return true;
    }

    QV4::ExecutableAllocator *realAllocator;
};

}

#endif // MASM_EXECUTABLEALLOCATOR_H