Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(642)

Side by Side Diff: third_party/tcmalloc/chromium/src/windows/preamble_patcher_with_stub.cc

Issue 9311003: Update the tcmalloc chromium branch to r144 (gperftools 2.0), and merge chromium-specific changes. (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Rebasec Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 /* Copyright (c) 2007, Google Inc. 1 /* Copyright (c) 2007, Google Inc.
2 * All rights reserved. 2 * All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 11 matching lines...) Expand all
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 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. 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * 29 *
30 * --- 30 * ---
31 * Author: Joi Sigurdsson 31 * Author: Joi Sigurdsson
32 * Author: Scott Francis
32 * 33 *
33 * Implementation of PreamblePatcher 34 * Implementation of PreamblePatcher
34 */ 35 */
35 36
36 #include "preamble_patcher.h" 37 #include "preamble_patcher.h"
37 38
38 #include "mini_disassembler.h" 39 #include "mini_disassembler.h"
39 40
40 // Definitions of assembly statements we need 41 // Definitions of assembly statements we need
41 #define ASM_JMP32REL 0xE9 42 #define ASM_JMP32REL 0xE9
42 #define ASM_INT3 0xCC 43 #define ASM_INT3 0xCC
44 #define ASM_NOP 0x90
45 // X64 opcodes
46 #define ASM_MOVRAX_IMM 0xB8
47 #define ASM_REXW 0x48
48 #define ASM_JMP 0xFF
49 #define ASM_JMP_RAX 0xE0
50 #define ASM_PUSH 0x68
51 #define ASM_RET 0xC3
43 52
44 namespace sidestep { 53 namespace sidestep {
45 54
46 SideStepError PreamblePatcher::RawPatchWithStub( 55 SideStepError PreamblePatcher::RawPatchWithStub(
47 void* target_function, 56 void* target_function,
48 void *replacement_function, 57 void* replacement_function,
49 unsigned char* preamble_stub, 58 unsigned char* preamble_stub,
50 unsigned long stub_size, 59 unsigned long stub_size,
51 unsigned long* bytes_needed) { 60 unsigned long* bytes_needed) {
52 if ((NULL == target_function) || 61 if ((NULL == target_function) ||
53 (NULL == replacement_function) || 62 (NULL == replacement_function) ||
54 (NULL == preamble_stub)) { 63 (NULL == preamble_stub)) {
55 SIDESTEP_ASSERT(false && 64 SIDESTEP_ASSERT(false &&
56 "Invalid parameters - either pTargetFunction or " 65 "Invalid parameters - either pTargetFunction or "
57 "pReplacementFunction or pPreambleStub were NULL."); 66 "pReplacementFunction or pPreambleStub were NULL.");
58 return SIDESTEP_INVALID_PARAMETER; 67 return SIDESTEP_INVALID_PARAMETER;
59 } 68 }
60 69
61 // TODO(V7:joi) Siggi and I just had a discussion and decided that both 70 // TODO(V7:joi) Siggi and I just had a discussion and decided that both
62 // patching and unpatching are actually unsafe. We also discussed a 71 // patching and unpatching are actually unsafe. We also discussed a
63 // method of making it safe, which is to freeze all other threads in the 72 // method of making it safe, which is to freeze all other threads in the
64 // process, check their thread context to see if their eip is currently 73 // process, check their thread context to see if their eip is currently
65 // inside the block of instructions we need to copy to the stub, and if so 74 // inside the block of instructions we need to copy to the stub, and if so
66 // wait a bit and try again, then unfreeze all threads once we've patched. 75 // wait a bit and try again, then unfreeze all threads once we've patched.
67 // Not implementing this for now since we're only using SideStep for unit 76 // Not implementing this for now since we're only using SideStep for unit
68 // testing, but if we ever use it for production code this is what we 77 // testing, but if we ever use it for production code this is what we
69 // should do. 78 // should do.
70 // 79 //
71 // NOTE: Stoyan suggests we can write 8 or even 10 bytes atomically using 80 // NOTE: Stoyan suggests we can write 8 or even 10 bytes atomically using
72 // FPU instructions, and on newer processors we could use cmpxchg8b or 81 // FPU instructions, and on newer processors we could use cmpxchg8b or
73 // cmpxchg16b. So it might be possible to do the patching/unpatching 82 // cmpxchg16b. So it might be possible to do the patching/unpatching
74 // atomically and avoid having to freeze other threads. Note though, that 83 // atomically and avoid having to freeze other threads. Note though, that
75 // doing it atomically does not help if one of the other threads happens 84 // doing it atomically does not help if one of the other threads happens
76 // to have its eip in the middle of the bytes you change while you change 85 // to have its eip in the middle of the bytes you change while you change
77 // them. 86 // them.
87 unsigned char* target = reinterpret_cast<unsigned char*>(target_function);
88 unsigned int required_trampoline_bytes = 0;
89 const unsigned int kRequiredStubJumpBytes = 5;
90 const unsigned int kRequiredTargetPatchBytes = 5;
78 91
79 // First, deal with a special case that we see with functions that 92 // Initialize the stub with INT3's just in case.
80 // point into an IAT table (including functions linked statically 93 if (stub_size) {
81 // into the application): these function already starts with 94 memset(preamble_stub, 0xcc, stub_size);
82 // ASM_JMP32REL. For instance, malloc() might be implemented as a
83 // JMP to __malloc(). In that case, we replace the destination of
84 // the JMP (__malloc), rather than the JMP itself (malloc). This
85 // way we get the correct behavior no matter how malloc gets called.
86 void *new_target = ResolveTarget(target_function);
87 if (new_target != target_function) { // we're in the IAT case
88 // I'd like to just say "target = new_target", but I can't,
89 // because the new target will need to have its protections set.
90 return RawPatchWithStubAndProtections(new_target, replacement_function,
91 preamble_stub, stub_size,
92 bytes_needed);
93 } 95 }
94 unsigned char* target = reinterpret_cast<unsigned char*>(new_target); 96 if (kIs64BitBinary) {
97 // In 64-bit mode JMP instructions are always relative to RIP. If the
98 // replacement - target offset is > 2GB, we can't JMP to the replacement
99 // function. In this case, we're going to use a trampoline - that is,
100 // we're going to do a relative jump to a small chunk of code in the stub
101 // that will then do the absolute jump to the replacement function. By
102 // doing this, we only need to patch 5 bytes in the target function, as
103 // opposed to patching 12 bytes if we were to do an absolute jump.
104 //
105 // Note that the first byte of the trampoline is a NOP instruction. This
106 // is used as a trampoline signature that will be detected when unpatching
107 // the function.
108 //
109 // jmp <trampoline>
110 //
111 // trampoline:
112 // nop
113 // mov rax, <replacement_function>
114 // jmp rax
115 //
116 __int64 replacement_target_offset = reinterpret_cast<__int64>(
117 replacement_function) - reinterpret_cast<__int64>(target) - 5;
118 if (replacement_target_offset > INT_MAX
119 || replacement_target_offset < INT_MIN) {
120 // The stub needs to be within 2GB of the target for the trampoline to
121 // work!
122 __int64 trampoline_offset = reinterpret_cast<__int64>(preamble_stub)
123 - reinterpret_cast<__int64>(target) - 5;
124 if (trampoline_offset > INT_MAX || trampoline_offset < INT_MIN) {
125 // We're screwed.
126 SIDESTEP_ASSERT(false
127 && "Preamble stub is too far from target to patch.");
128 return SIDESTEP_UNEXPECTED;
129 }
130 required_trampoline_bytes = 13;
131 }
132 }
95 133
96 // Let's disassemble the preamble of the target function to see if we can 134 // Let's disassemble the preamble of the target function to see if we can
97 // patch, and to see how much of the preamble we need to take. We need 5 135 // patch, and to see how much of the preamble we need to take. We need 5
98 // bytes for our jmp instruction, so let's find the minimum number of 136 // bytes for our jmp instruction, so let's find the minimum number of
99 // instructions to get 5 bytes. 137 // instructions to get 5 bytes.
100 MiniDisassembler disassembler; 138 MiniDisassembler disassembler;
101 unsigned int preamble_bytes = 0; 139 unsigned int preamble_bytes = 0;
102 while (preamble_bytes < 5) { 140 unsigned int stub_bytes = 0;
141 while (preamble_bytes < kRequiredTargetPatchBytes) {
142 unsigned int cur_bytes = 0;
103 InstructionType instruction_type = 143 InstructionType instruction_type =
104 disassembler.Disassemble(target + preamble_bytes, preamble_bytes); 144 disassembler.Disassemble(target + preamble_bytes, cur_bytes);
105 if (IT_JUMP == instruction_type) { 145 if (IT_JUMP == instruction_type) {
106 SIDESTEP_ASSERT(false && 146 unsigned int jump_bytes = 0;
107 "Unable to patch because there is a jump instruction " 147 SideStepError jump_ret = SIDESTEP_JUMP_INSTRUCTION;
108 "in the first 5 bytes."); 148 if (IsShortConditionalJump(target + preamble_bytes, cur_bytes)) {
109 return SIDESTEP_JUMP_INSTRUCTION; 149 jump_ret = PatchShortConditionalJump(target + preamble_bytes, cur_bytes,
150 preamble_stub + stub_bytes,
151 &jump_bytes,
152 stub_size - stub_bytes);
153 } else if (IsNearConditionalJump(target + preamble_bytes, cur_bytes) ||
154 IsNearRelativeJump(target + preamble_bytes, cur_bytes) ||
155 IsNearAbsoluteCall(target + preamble_bytes, cur_bytes) ||
156 IsNearRelativeCall(target + preamble_bytes, cur_bytes)) {
157 jump_ret = PatchNearJumpOrCall(target + preamble_bytes, cur_bytes,
158 preamble_stub + stub_bytes, &jump_bytes,
159 stub_size - stub_bytes);
160 }
161 if (jump_ret != SIDESTEP_SUCCESS) {
162 SIDESTEP_ASSERT(false &&
163 "Unable to patch because there is an unhandled branch "
164 "instruction in the initial preamble bytes.");
165 return SIDESTEP_JUMP_INSTRUCTION;
166 }
167 stub_bytes += jump_bytes;
110 } else if (IT_RETURN == instruction_type) { 168 } else if (IT_RETURN == instruction_type) {
111 SIDESTEP_ASSERT(false && 169 SIDESTEP_ASSERT(false &&
112 "Unable to patch because function is too short"); 170 "Unable to patch because function is too short");
113 return SIDESTEP_FUNCTION_TOO_SMALL; 171 return SIDESTEP_FUNCTION_TOO_SMALL;
114 } else if (IT_GENERIC != instruction_type) { 172 } else if (IT_GENERIC == instruction_type) {
173 if (IsMovWithDisplacement(target + preamble_bytes, cur_bytes)) {
174 unsigned int mov_bytes = 0;
175 if (PatchMovWithDisplacement(target + preamble_bytes, cur_bytes,
176 preamble_stub + stub_bytes, &mov_bytes,
177 stub_size - stub_bytes)
178 != SIDESTEP_SUCCESS) {
179 return SIDESTEP_UNSUPPORTED_INSTRUCTION;
180 }
181 stub_bytes += mov_bytes;
182 } else {
183 memcpy(reinterpret_cast<void*>(preamble_stub + stub_bytes),
184 reinterpret_cast<void*>(target + preamble_bytes), cur_bytes);
185 stub_bytes += cur_bytes;
186 }
187 } else {
115 SIDESTEP_ASSERT(false && 188 SIDESTEP_ASSERT(false &&
116 "Disassembler encountered unsupported instruction " 189 "Disassembler encountered unsupported instruction "
117 "(either unused or unknown"); 190 "(either unused or unknown");
118 return SIDESTEP_UNSUPPORTED_INSTRUCTION; 191 return SIDESTEP_UNSUPPORTED_INSTRUCTION;
119 } 192 }
193 preamble_bytes += cur_bytes;
120 } 194 }
121 195
122 if (NULL != bytes_needed) 196 if (NULL != bytes_needed)
123 *bytes_needed = preamble_bytes + 5; 197 *bytes_needed = stub_bytes + kRequiredStubJumpBytes
198 + required_trampoline_bytes;
124 199
125 // Inv: cbPreamble is the number of bytes (at least 5) that we need to take 200 // Inv: cbPreamble is the number of bytes (at least 5) that we need to take
126 // from the preamble to have whole instructions that are 5 bytes or more 201 // from the preamble to have whole instructions that are 5 bytes or more
127 // in size total. The size of the stub required is cbPreamble + size of 202 // in size total. The size of the stub required is cbPreamble +
128 // jmp (5) 203 // kRequiredStubJumpBytes (5) + required_trampoline_bytes (0 or 13)
129 if (preamble_bytes + 5 > stub_size) { 204 if (stub_bytes + kRequiredStubJumpBytes + required_trampoline_bytes
205 > stub_size) {
130 SIDESTEP_ASSERT(false); 206 SIDESTEP_ASSERT(false);
131 return SIDESTEP_INSUFFICIENT_BUFFER; 207 return SIDESTEP_INSUFFICIENT_BUFFER;
132 } 208 }
133 209
134 // First, copy the preamble that we will overwrite.
135 memcpy(reinterpret_cast<void*>(preamble_stub),
136 reinterpret_cast<void*>(target), preamble_bytes);
137
138 // Now, make a jmp instruction to the rest of the target function (minus the 210 // Now, make a jmp instruction to the rest of the target function (minus the
139 // preamble bytes we moved into the stub) and copy it into our preamble-stub. 211 // preamble bytes we moved into the stub) and copy it into our preamble-stub.
140 // find address to jump to, relative to next address after jmp instruction 212 // find address to jump to, relative to next address after jmp instruction
141 #ifdef _MSC_VER 213 #ifdef _MSC_VER
142 #pragma warning(push) 214 #pragma warning(push)
143 #pragma warning(disable:4244) 215 #pragma warning(disable:4244)
144 #endif 216 #endif
145 int relative_offset_to_target_rest 217 int relative_offset_to_target_rest
146 = ((reinterpret_cast<unsigned char*>(target) + preamble_bytes) - 218 = ((reinterpret_cast<unsigned char*>(target) + preamble_bytes) -
147 (preamble_stub + preamble_bytes + 5)); 219 (preamble_stub + stub_bytes + kRequiredStubJumpBytes));
148 #ifdef _MSC_VER 220 #ifdef _MSC_VER
149 #pragma warning(pop) 221 #pragma warning(pop)
150 #endif 222 #endif
151 // jmp (Jump near, relative, displacement relative to next instruction) 223 // jmp (Jump near, relative, displacement relative to next instruction)
152 preamble_stub[preamble_bytes] = ASM_JMP32REL; 224 preamble_stub[stub_bytes] = ASM_JMP32REL;
153 // copy the address 225 // copy the address
154 memcpy(reinterpret_cast<void*>(preamble_stub + preamble_bytes + 1), 226 memcpy(reinterpret_cast<void*>(preamble_stub + stub_bytes + 1),
155 reinterpret_cast<void*>(&relative_offset_to_target_rest), 4); 227 reinterpret_cast<void*>(&relative_offset_to_target_rest), 4);
156 228
229 if (kIs64BitBinary && required_trampoline_bytes != 0) {
230 // Construct the trampoline
231 unsigned int trampoline_pos = stub_bytes + kRequiredStubJumpBytes;
232 preamble_stub[trampoline_pos] = ASM_NOP;
233 preamble_stub[trampoline_pos + 1] = ASM_REXW;
234 preamble_stub[trampoline_pos + 2] = ASM_MOVRAX_IMM;
235 memcpy(reinterpret_cast<void*>(preamble_stub + trampoline_pos + 3),
236 reinterpret_cast<void*>(&replacement_function),
237 sizeof(void *));
238 preamble_stub[trampoline_pos + 11] = ASM_JMP;
239 preamble_stub[trampoline_pos + 12] = ASM_JMP_RAX;
240
241 // Now update replacement_function to point to the trampoline
242 replacement_function = preamble_stub + trampoline_pos;
243 }
244
157 // Inv: preamble_stub points to assembly code that will execute the 245 // Inv: preamble_stub points to assembly code that will execute the
158 // original function by first executing the first cbPreamble bytes of the 246 // original function by first executing the first cbPreamble bytes of the
159 // preamble, then jumping to the rest of the function. 247 // preamble, then jumping to the rest of the function.
160 248
161 // Overwrite the first 5 bytes of the target function with a jump to our 249 // Overwrite the first 5 bytes of the target function with a jump to our
162 // replacement function. 250 // replacement function.
163 // (Jump near, relative, displacement relative to next instruction) 251 // (Jump near, relative, displacement relative to next instruction)
164 target[0] = ASM_JMP32REL; 252 target[0] = ASM_JMP32REL;
165 253
166 // Find offset from instruction after jmp, to the replacement function. 254 // Find offset from instruction after jmp, to the replacement function.
167 #ifdef _MSC_VER 255 #ifdef _MSC_VER
168 #pragma warning(push) 256 #pragma warning(push)
169 #pragma warning(disable:4244) 257 #pragma warning(disable:4244)
170 #endif 258 #endif
171 int offset_to_replacement_function = 259 int offset_to_replacement_function =
172 reinterpret_cast<unsigned char*>(replacement_function) - 260 reinterpret_cast<unsigned char*>(replacement_function) -
173 reinterpret_cast<unsigned char*>(target) - 5; 261 reinterpret_cast<unsigned char*>(target) - 5;
174 #ifdef _MSC_VER 262 #ifdef _MSC_VER
175 #pragma warning(pop) 263 #pragma warning(pop)
176 #endif 264 #endif
177 // complete the jmp instruction 265 // complete the jmp instruction
178 memcpy(reinterpret_cast<void*>(target + 1), 266 memcpy(reinterpret_cast<void*>(target + 1),
179 reinterpret_cast<void*>(&offset_to_replacement_function), 4); 267 reinterpret_cast<void*>(&offset_to_replacement_function), 4);
268
180 // Set any remaining bytes that were moved to the preamble-stub to INT3 so 269 // Set any remaining bytes that were moved to the preamble-stub to INT3 so
181 // as not to cause confusion (otherwise you might see some strange 270 // as not to cause confusion (otherwise you might see some strange
182 // instructions if you look at the disassembly, or even invalid 271 // instructions if you look at the disassembly, or even invalid
183 // instructions). Also, by doing this, we will break into the debugger if 272 // instructions). Also, by doing this, we will break into the debugger if
184 // some code calls into this portion of the code. If this happens, it 273 // some code calls into this portion of the code. If this happens, it
185 // means that this function cannot be patched using this patcher without 274 // means that this function cannot be patched using this patcher without
186 // further thought. 275 // further thought.
187 if (preamble_bytes > 5) { 276 if (preamble_bytes > kRequiredTargetPatchBytes) {
188 memset(reinterpret_cast<void*>(target + 5), ASM_INT3, preamble_bytes - 5); 277 memset(reinterpret_cast<void*>(target + kRequiredTargetPatchBytes),
278 ASM_INT3, preamble_bytes - kRequiredTargetPatchBytes);
189 } 279 }
190 280
191 // Inv: The memory pointed to by target_function now points to a relative 281 // Inv: The memory pointed to by target_function now points to a relative
192 // jump instruction that jumps over to the preamble_stub. The preamble 282 // jump instruction that jumps over to the preamble_stub. The preamble
193 // stub contains the first stub_size bytes of the original target 283 // stub contains the first stub_size bytes of the original target
194 // function's preamble code, followed by a relative jump back to the next 284 // function's preamble code, followed by a relative jump back to the next
195 // instruction after the first cbPreamble bytes. 285 // instruction after the first cbPreamble bytes.
196 286 //
287 // In 64-bit mode the memory pointed to by target_function *may* point to a
288 // relative jump instruction that jumps to a trampoline which will then
289 // perform an absolute jump to the replacement function. The preamble stub
290 // still contains the original target function's preamble code, followed by a
291 // jump back to the instructions after the first preamble bytes.
292 //
197 return SIDESTEP_SUCCESS; 293 return SIDESTEP_SUCCESS;
198 } 294 }
199 295
200 }; // namespace sidestep 296 }; // namespace sidestep
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698