2 This file is part of GammaRay, the Qt application inspection and
5 Copyright (C) 2010-2011 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
6 Author: Andreas Holzammer <andreas.holzammer@kdab.com>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "abstractfunctionoverwriter.h"
26 const long worstSizeForLongJump
= 10;
27 #elif defined(ARCH_64)
28 const long worstSizeForLongJump
= 14;
30 # error "Unsupported hardware architecture!"
33 using namespace GammaRay
;
35 bool AbstractFunctionOverwriter::writeShortJump(void *target
, void *const func
)
37 quint8
*cur
= (quint8
*) target
;
39 //E9 relative short jump is 5 bytes long
40 bool ret
= unprotectMemory(page_align(target
), roundToNextPage(5));
43 std::cerr
<< "Failed to unprotect memory: " << page_align(target
);
49 *((quint32
*)cur
) = (unsigned long)func
- (unsigned long)(cur
+ 4);
51 ret
= reprotectMemory(page_align(target
), roundToNextPage(5));
54 std::cerr
<< "Failed to reprotect memory: " << page_align(target
);
61 bool AbstractFunctionOverwriter::writeLongJump(void *target
, void *const func
)
63 quint8
*cur
= (quint8
*) target
;
65 bool ret
= unprotectMemory(page_align(target
), roundToNextPage(worstSizeForLongJump
));
68 std::cerr
<< "Failed to unprotect memory: " << page_align(target
);
76 *((quint32
*) ++cur
) = (quint32
)(((quint32
) cur
) + sizeof (quint32
));
77 cur
+= sizeof (quint32
);
78 *((quint32
*)cur
) = (quint32
)func
;
79 #elif defined(ARCH_64)
80 *((quint32
*) ++cur
) = 0;
81 cur
+= sizeof (quint32
);
82 *((quint64
*)cur
) = (quint64
)func
;
84 # error "Unsupported hardware architecture!"
87 ret
= reprotectMemory(page_align(target
), roundToNextPage(worstSizeForLongJump
));
90 std::cerr
<< "Failed to reprotect memory: " << page_align(target
);
97 void *AbstractFunctionOverwriter::getMemoryNearAddress(void *const addr
, size_t size
)
99 Q_ASSERT(blocksize() > size
);
105 getAddressRange(minAddr
, maxAddr
);
107 minAddr
= std::max
<intptr_t>(minAddr
, reinterpret_cast<intptr_t>(addr
) - 0x20000000);
108 maxAddr
= std::min
<intptr_t>(maxAddr
, reinterpret_cast<intptr_t>(addr
) + 0x20000000);
111 for (QList
<MemorySegment
>::Iterator it
= memoryPool
.begin(); it
!= memoryPool
.end(); ++it
) {
112 if (it
->free
>= size
) {
114 if (!((intptr_t)it
->mem
> minAddr
&& (intptr_t)it
->mem
< maxAddr
)) {
118 quint8
*mem
= (quint8
*)it
->mem
+ (it
->size
- it
->free
);
127 mem
= reserveMemory(0, blocksize());
128 #elif defined(ARCH_64)
129 intptr_t min
= minAddr
/ blocksize();
130 intptr_t max
= maxAddr
/ blocksize();
132 for (int i
= 0; i
< (max
- min
+ 1); ++i
) {
133 rel
= -rel
+ (i
& 1);
134 void* query
= reinterpret_cast<void*>(((min
+ max
) / 2 + rel
) * blocksize());
136 Q_ASSERT(!((size_t)query
& (pagesize() - 1)));
138 if (isMemoryFree(query
, blocksize())) {
139 mem
= reserveMemory(query
, blocksize());
141 reinterpret_cast<intptr_t>(mem
) > minAddr
&&
142 reinterpret_cast<intptr_t>(mem
) < maxAddr
) {
148 #error "Unsupported hardware architecture!"
151 std::cerr
<< "Error could not find memory close to: " << addr
;
154 if (!commitMemory(mem
, blocksize())) {
157 MemorySegment memSegment
;
158 memSegment
.mem
= mem
;
159 memSegment
.size
= blocksize();
160 memSegment
.free
= blocksize() - size
;
161 memoryPool
.append(memSegment
);
165 void *AbstractFunctionOverwriter::createTrampoline(void *const func
, void *const replacement
)
167 void *mem
= getMemoryNearAddress(func
, worstSizeForLongJump
);
171 bool ret
= writeLongJump(mem
, replacement
);
178 AbstractFunctionOverwriter::~AbstractFunctionOverwriter()
182 bool AbstractFunctionOverwriter::overwriteFunction(const QString
&orignalFunc
,
183 void * const replacementFunc
)
185 void *func
= qtCoreFunctionLookup(orignalFunc
);
187 std::cerr
<< "Failed to lookup: " << orignalFunc
.toLatin1().data();
190 void *mem
= createTrampoline(func
, replacementFunc
);
195 bool ret
= writeShortJump(func
, mem
);
200 void *AbstractFunctionOverwriter::page_align(void *addr
) const
203 return (void *)((size_t)addr
& ~(pagesize() - 1));
206 size_t AbstractFunctionOverwriter::roundToNextPage(size_t addr
) const
209 return (size_t)page_align((void*)(addr
+ (pagesize() - 1)));
212 size_t GammaRay::AbstractFunctionOverwriter::blocksize()
214 return roundToNextPage(std::max((worstSizeForLongJump
* 4), pagesize()));