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

Side by Side Diff: third_party/tcmalloc/chromium/src/windows/preamble_patcher.h

Issue 9667026: Revert 126020 - Experiment for updating the tcmalloc chromium branch to r144 (gperftools 2.0). (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: 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
33 * 32 *
34 * Definition of PreamblePatcher 33 * Definition of PreamblePatcher
35 */ 34 */
36 35
37 #ifndef GOOGLE_PERFTOOLS_PREAMBLE_PATCHER_H_ 36 #ifndef GOOGLE_PERFTOOLS_PREAMBLE_PATCHER_H_
38 #define GOOGLE_PERFTOOLS_PREAMBLE_PATCHER_H_ 37 #define GOOGLE_PERFTOOLS_PREAMBLE_PATCHER_H_
39 38
40 #include "config.h"
41 #include <windows.h> 39 #include <windows.h>
42 40
43 // compatibility shim 41 // compatibility shim
44 #include "base/logging.h" 42 #include "base/logging.h"
45 #define SIDESTEP_ASSERT(cond) RAW_DCHECK(cond, #cond) 43 #define SIDESTEP_ASSERT(cond) RAW_DCHECK(cond, #cond)
46 #define SIDESTEP_LOG(msg) RAW_VLOG(1, msg) 44 #define SIDESTEP_LOG(msg) RAW_VLOG(1, msg)
47 45
48 // Maximum size of the preamble stub. We overwrite at least the first 5 46 // Maximum size of the preamble stub. We overwrite at least the first 5
49 // bytes of the function. Considering the worst case scenario, we need 4 47 // bytes of the function. Considering the worst case scenario, we need 4
50 // bytes + the max instruction size + 5 more bytes for our jump back to 48 // bytes + the max instruction size + 5 more bytes for our jump back to
51 // the original code. With that in mind, 32 is a good number :) 49 // the original code. With that in mind, 32 is a good number :)
52 #ifdef _M_X64
53 // In 64-bit mode we may need more room. In 64-bit mode all jumps must be
54 // within +/-2GB of RIP. Because of this limitation we may need to use a
55 // trampoline to jump to the replacement function if it is further than 2GB
56 // away from the target. The trampoline is 14 bytes.
57 //
58 // So 4 bytes + max instruction size (17 bytes) + 5 bytes to jump back to the
59 // original code + trampoline size. 64 bytes is a nice number :-)
60 #define MAX_PREAMBLE_STUB_SIZE (64)
61 #else
62 #define MAX_PREAMBLE_STUB_SIZE (32) 50 #define MAX_PREAMBLE_STUB_SIZE (32)
63 #endif
64
65 // Determines if this is a 64-bit binary.
66 #ifdef _M_X64
67 static const bool kIs64BitBinary = true;
68 #else
69 static const bool kIs64BitBinary = false;
70 #endif
71 51
72 namespace sidestep { 52 namespace sidestep {
73 53
74 // Possible results of patching/unpatching 54 // Possible results of patching/unpatching
75 enum SideStepError { 55 enum SideStepError {
76 SIDESTEP_SUCCESS = 0, 56 SIDESTEP_SUCCESS = 0,
77 SIDESTEP_INVALID_PARAMETER, 57 SIDESTEP_INVALID_PARAMETER,
78 SIDESTEP_INSUFFICIENT_BUFFER, 58 SIDESTEP_INSUFFICIENT_BUFFER,
79 SIDESTEP_JUMP_INSTRUCTION, 59 SIDESTEP_JUMP_INSTRUCTION,
80 SIDESTEP_FUNCTION_TOO_SMALL, 60 SIDESTEP_FUNCTION_TOO_SMALL,
81 SIDESTEP_UNSUPPORTED_INSTRUCTION, 61 SIDESTEP_UNSUPPORTED_INSTRUCTION,
82 SIDESTEP_NO_SUCH_MODULE, 62 SIDESTEP_NO_SUCH_MODULE,
83 SIDESTEP_NO_SUCH_FUNCTION, 63 SIDESTEP_NO_SUCH_FUNCTION,
84 SIDESTEP_ACCESS_DENIED, 64 SIDESTEP_ACCESS_DENIED,
85 SIDESTEP_UNEXPECTED, 65 SIDESTEP_UNEXPECTED,
86 }; 66 };
87 67
88 #define SIDESTEP_TO_HRESULT(error) \ 68 #define SIDESTEP_TO_HRESULT(error) \
89 MAKE_HRESULT(SEVERITY_ERROR, FACILITY_NULL, error) 69 MAKE_HRESULT(SEVERITY_ERROR, FACILITY_NULL, error)
90 70
91 class DeleteUnsignedCharArray;
92
93 // Implements a patching mechanism that overwrites the first few bytes of 71 // Implements a patching mechanism that overwrites the first few bytes of
94 // a function preamble with a jump to our hook function, which is then 72 // a function preamble with a jump to our hook function, which is then
95 // able to call the original function via a specially-made preamble-stub 73 // able to call the original function via a specially-made preamble-stub
96 // that imitates the action of the original preamble. 74 // that imitates the action of the original preamble.
97 // 75 //
98 // NOTE: This patching mechanism should currently only be used for 76 // NOTE: This patching mechanism should currently only be used for
99 // non-production code, e.g. unit tests, because it is not threadsafe. 77 // non-production code, e.g. unit tests, because it is not threadsafe.
100 // See the TODO in preamble_patcher_with_stub.cc for instructions on what 78 // See the TODO in preamble_patcher_with_stub.cc for instructions on what
101 // we need to do before using it in production code; it's fairly simple 79 // we need to do before using it in production code; it's fairly simple
102 // but unnecessary for now since we only intend to use it in unit tests. 80 // but unnecessary for now since we only intend to use it in unit tests.
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
141 // patcher at an invalid instruction (e.g. into the middle of a multi- 119 // patcher at an invalid instruction (e.g. into the middle of a multi-
142 // byte instruction, or not at memory containing executable instructions) 120 // byte instruction, or not at memory containing executable instructions)
143 // or, there may be a bug in the disassembler we use to find 121 // or, there may be a bug in the disassembler we use to find
144 // instruction boundaries. 122 // instruction boundaries.
145 // 123 //
146 // NOTE: In optimized builds, when you have very trivial functions that 124 // NOTE: In optimized builds, when you have very trivial functions that
147 // the compiler can reason do not have side effects, the compiler may 125 // the compiler can reason do not have side effects, the compiler may
148 // reuse the result of calling the function with a given parameter, which 126 // reuse the result of calling the function with a given parameter, which
149 // may mean if you patch the function in between your patch will never get 127 // may mean if you patch the function in between your patch will never get
150 // invoked. See preamble_patcher_test.cc for an example. 128 // invoked. See preamble_patcher_test.cc for an example.
151 class PERFTOOLS_DLL_DECL PreamblePatcher { 129 class PreamblePatcher {
152 public: 130 public:
153 131
154 // This is a typesafe version of RawPatch(), identical in all other 132 // This is a typesafe version of RawPatch(), identical in all other
155 // ways than it takes a template parameter indicating the type of the 133 // ways than it takes a template parameter indicating the type of the
156 // function being patched. 134 // function being patched.
157 // 135 //
158 // @param T The type of the function you are patching. Usually 136 // @param T The type of the function you are patching. Usually
159 // you will establish this type using a typedef, as in the following 137 // you will establish this type using a typedef, as in the following
160 // example: 138 // example:
161 // @code 139 // @code
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
302 // 280 //
303 // @return Either target_function (the input parameter), or if 281 // @return Either target_function (the input parameter), or if
304 // target_function's body consists entirely of a JMP instruction, 282 // target_function's body consists entirely of a JMP instruction,
305 // the address it JMPs to (or more precisely, the address at the end 283 // the address it JMPs to (or more precisely, the address at the end
306 // of a chain of JMPs). 284 // of a chain of JMPs).
307 template <class T> 285 template <class T>
308 static T ResolveTarget(T target_function) { 286 static T ResolveTarget(T target_function) {
309 return (T)ResolveTargetImpl((unsigned char*)target_function, NULL); 287 return (T)ResolveTargetImpl((unsigned char*)target_function, NULL);
310 } 288 }
311 289
312 // Allocates a block of memory of size MAX_PREAMBLE_STUB_SIZE that is as
313 // close (within 2GB) as possible to target. This is done to ensure that
314 // we can perform a relative jump from target to a trampoline if the
315 // replacement function is > +-2GB from target. This means that we only need
316 // to patch 5 bytes in the target function.
317 //
318 // @param target Pointer to target function.
319 //
320 // @return Returns a block of memory of size MAX_PREAMBLE_STUB_SIZE that can
321 // be used to store a function preamble block.
322 static unsigned char* AllocPreambleBlockNear(void* target);
323
324 // Frees a block allocated by AllocPreambleBlockNear.
325 //
326 // @param block Block that was returned by AllocPreambleBlockNear.
327 static void FreePreambleBlock(unsigned char* block);
328
329 private: 290 private:
330 friend class DeleteUnsignedCharArray;
331
332 // Used to store data allocated for preamble stubs
333 struct PreamblePage {
334 unsigned int magic_;
335 PreamblePage* next_;
336 // This member points to a linked list of free blocks within the page
337 // or NULL if at the end
338 void* free_;
339 };
340
341 // In 64-bit mode, the replacement function must be within 2GB of the original
342 // target in order to only require 5 bytes for the function patch. To meet
343 // this requirement we're creating an allocator within this class to
344 // allocate blocks that are within 2GB of a given target. This member is the
345 // head of a linked list of pages used to allocate blocks that are within
346 // 2GB of the target.
347 static PreamblePage* preamble_pages_;
348
349 // Page granularity
350 static long granularity_;
351
352 // Page size
353 static long pagesize_;
354
355 // Determines if the patcher has been initialized.
356 static bool initialized_;
357
358 // Used to initialize static members.
359 static void Initialize();
360
361 // Patches a function by overwriting its first few bytes with 291 // Patches a function by overwriting its first few bytes with
362 // a jump to a different function. This is similar to the RawPatch 292 // a jump to a different function. This is similar to the RawPatch
363 // function except that it uses the stub allocated by the caller 293 // function except that it uses the stub allocated by the caller
364 // instead of allocating it. 294 // instead of allocating it.
365 // 295 //
366 // We call VirtualProtect to make the 296 // We call VirtualProtect to make the
367 // target function writable at least for the duration of the call. 297 // target function writable at least for the duration of the call.
368 // 298 //
369 // @param target_function A pointer to the function that should be 299 // @param target_function A pointer to the function that should be
370 // patched. 300 // patched.
(...skipping 10 matching lines...) Expand all
381 // @param stub_size Size in bytes of the buffer allocated for the 311 // @param stub_size Size in bytes of the buffer allocated for the
382 // preamble_stub 312 // preamble_stub
383 // 313 //
384 // @param bytes_needed Pointer to a variable that receives the minimum 314 // @param bytes_needed Pointer to a variable that receives the minimum
385 // number of bytes required for the stub. Can be set to NULL if you're 315 // number of bytes required for the stub. Can be set to NULL if you're
386 // not interested. 316 // not interested.
387 // 317 //
388 // @return An error code indicating the result of patching. 318 // @return An error code indicating the result of patching.
389 static SideStepError RawPatchWithStubAndProtections( 319 static SideStepError RawPatchWithStubAndProtections(
390 void* target_function, 320 void* target_function,
391 void* replacement_function, 321 void *replacement_function,
392 unsigned char* preamble_stub, 322 unsigned char* preamble_stub,
393 unsigned long stub_size, 323 unsigned long stub_size,
394 unsigned long* bytes_needed); 324 unsigned long* bytes_needed);
395 325
396 // A helper function used by RawPatchWithStubAndProtections -- it 326 // A helper function used by RawPatchWithStubAndProtections -- it
397 // does everything but the VirtualProtect work. Defined in 327 // does everything but the VirtualProtect work. Defined in
398 // preamble_patcher_with_stub.cc. 328 // preamble_patcher_with_stub.cc.
399 // 329 //
400 // @param target_function A pointer to the function that should be 330 // @param target_function A pointer to the function that should be
401 // patched. 331 // patched.
402 // 332 //
403 // @param replacement_function A pointer to the function that should 333 // @param replacement_function A pointer to the function that should
404 // replace the target function. The replacement function must have 334 // replace the target function. The replacement function must have
405 // exactly the same calling convention and parameters as the original 335 // exactly the same calling convention and parameters as the original
406 // function. 336 // function.
407 // 337 //
408 // @param preamble_stub A pointer to a buffer where the preamble stub 338 // @param preamble_stub A pointer to a buffer where the preamble stub
409 // should be copied. The size of the buffer should be sufficient to 339 // should be copied. The size of the buffer should be sufficient to
410 // hold the preamble bytes. 340 // hold the preamble bytes.
411 // 341 //
412 // @param stub_size Size in bytes of the buffer allocated for the 342 // @param stub_size Size in bytes of the buffer allocated for the
413 // preamble_stub 343 // preamble_stub
414 // 344 //
415 // @param bytes_needed Pointer to a variable that receives the minimum 345 // @param bytes_needed Pointer to a variable that receives the minimum
416 // number of bytes required for the stub. Can be set to NULL if you're 346 // number of bytes required for the stub. Can be set to NULL if you're
417 // not interested. 347 // not interested.
418 // 348 //
419 // @return An error code indicating the result of patching. 349 // @return An error code indicating the result of patching.
420 static SideStepError RawPatchWithStub(void* target_function, 350 static SideStepError RawPatchWithStub(void* target_function,
421 void* replacement_function, 351 void *replacement_function,
422 unsigned char* preamble_stub, 352 unsigned char* preamble_stub,
423 unsigned long stub_size, 353 unsigned long stub_size,
424 unsigned long* bytes_needed); 354 unsigned long* bytes_needed);
425 355
426 356
427 // A helper routine when patching, which follows jmp instructions at 357 // A helper routine when patching, which follows jmp instructions at
428 // function addresses, to get to the "actual" function contents. 358 // function addresses, to get to the "actual" function contents.
429 // This allows us to identify two functions that are at different 359 // This allows us to identify two functions that are at different
430 // addresses but actually resolve to the same code. 360 // addresses but actually resolve to the same code.
431 // 361 //
432 // @param target_function Pointer to a function. 362 // @param target_function Pointer to a function.
433 // 363 //
434 // @param stop_before If, when following JMP instructions from 364 // @param stop_before If, when following JMP instructions from
435 // target_function, we get to the address stop, we return 365 // target_function, we get to the address stop, we return
436 // immediately, the address that jumps to stop_before. 366 // immediately, the address that jumps to stop_before.
437 // 367 //
438 // @param stop_before_trampoline When following JMP instructions from
439 // target_function, stop before a trampoline is detected. See comment in
440 // PreamblePatcher::RawPatchWithStub for more information. This parameter
441 // has no effect in 32-bit mode.
442 //
443 // @return Either target_function (the input parameter), or if 368 // @return Either target_function (the input parameter), or if
444 // target_function's body consists entirely of a JMP instruction, 369 // target_function's body consists entirely of a JMP instruction,
445 // the address it JMPs to (or more precisely, the address at the end 370 // the address it JMPs to (or more precisely, the address at the end
446 // of a chain of JMPs). 371 // of a chain of JMPs).
447 static void* ResolveTargetImpl(unsigned char* target_function, 372 static void* ResolveTargetImpl(unsigned char* target_function,
448 unsigned char* stop_before, 373 unsigned char* stop_before);
449 bool stop_before_trampoline = false);
450
451 // Helper routine that attempts to allocate a page as close (within 2GB)
452 // as possible to target.
453 //
454 // @param target Pointer to target function.
455 //
456 // @return Returns an address that is within 2GB of target.
457 static void* AllocPageNear(void* target);
458
459 // Helper routine that determines if a target instruction is a short
460 // conditional jump.
461 //
462 // @param target Pointer to instruction.
463 //
464 // @param instruction_size Size of the instruction in bytes.
465 //
466 // @return Returns true if the instruction is a short conditional jump.
467 static bool IsShortConditionalJump(unsigned char* target,
468 unsigned int instruction_size);
469
470 // Helper routine that determines if a target instruction is a near
471 // conditional jump.
472 //
473 // @param target Pointer to instruction.
474 //
475 // @param instruction_size Size of the instruction in bytes.
476 //
477 // @return Returns true if the instruction is a near conditional jump.
478 static bool IsNearConditionalJump(unsigned char* target,
479 unsigned int instruction_size);
480
481 // Helper routine that determines if a target instruction is a near
482 // relative jump.
483 //
484 // @param target Pointer to instruction.
485 //
486 // @param instruction_size Size of the instruction in bytes.
487 //
488 // @return Returns true if the instruction is a near absolute jump.
489 static bool IsNearRelativeJump(unsigned char* target,
490 unsigned int instruction_size);
491
492 // Helper routine that determines if a target instruction is a near
493 // absolute call.
494 //
495 // @param target Pointer to instruction.
496 //
497 // @param instruction_size Size of the instruction in bytes.
498 //
499 // @return Returns true if the instruction is a near absolute call.
500 static bool IsNearAbsoluteCall(unsigned char* target,
501 unsigned int instruction_size);
502
503 // Helper routine that determines if a target instruction is a near
504 // absolute call.
505 //
506 // @param target Pointer to instruction.
507 //
508 // @param instruction_size Size of the instruction in bytes.
509 //
510 // @return Returns true if the instruction is a near absolute call.
511 static bool IsNearRelativeCall(unsigned char* target,
512 unsigned int instruction_size);
513
514 // Helper routine that determines if a target instruction is a 64-bit MOV
515 // that uses a RIP-relative displacement.
516 //
517 // @param target Pointer to instruction.
518 //
519 // @param instruction_size Size of the instruction in bytes.
520 //
521 // @return Returns true if the instruction is a MOV with displacement.
522 static bool IsMovWithDisplacement(unsigned char* target,
523 unsigned int instruction_size);
524
525 // Helper routine that converts a short conditional jump instruction
526 // to a near conditional jump in a target buffer. Note that the target
527 // buffer must be within 2GB of the source for the near jump to work.
528 //
529 // A short conditional jump instruction is in the format:
530 // 7x xx = Jcc rel8off
531 //
532 // @param source Pointer to instruction.
533 //
534 // @param instruction_size Size of the instruction.
535 //
536 // @param target Target buffer to write the new instruction.
537 //
538 // @param target_bytes Pointer to a buffer that contains the size
539 // of the target instruction, in bytes.
540 //
541 // @param target_size Size of the target buffer.
542 //
543 // @return Returns SIDESTEP_SUCCESS if successful, otherwise an error.
544 static SideStepError PatchShortConditionalJump(unsigned char* source,
545 unsigned int instruction_size,
546 unsigned char* target,
547 unsigned int* target_bytes,
548 unsigned int target_size);
549
550 // Helper routine that converts an instruction that will convert various
551 // jump-like instructions to corresponding instructions in the target buffer.
552 // What this routine does is fix up the relative offsets contained in jump
553 // instructions to point back to the original target routine. Like with
554 // PatchShortConditionalJump, the target buffer must be within 2GB of the
555 // source.
556 //
557 // We currently handle the following instructions:
558 //
559 // E9 xx xx xx xx = JMP rel32off
560 // 0F 8x xx xx xx xx = Jcc rel32off
561 // FF /2 xx xx xx xx = CALL reg/mem32/mem64
562 // E8 xx xx xx xx = CALL rel32off
563 //
564 // It should not be hard to update this function to support other
565 // instructions that jump to relative targets.
566 //
567 // @param source Pointer to instruction.
568 //
569 // @param instruction_size Size of the instruction.
570 //
571 // @param target Target buffer to write the new instruction.
572 //
573 // @param target_bytes Pointer to a buffer that contains the size
574 // of the target instruction, in bytes.
575 //
576 // @param target_size Size of the target buffer.
577 //
578 // @return Returns SIDESTEP_SUCCESS if successful, otherwise an error.
579 static SideStepError PatchNearJumpOrCall(unsigned char* source,
580 unsigned int instruction_size,
581 unsigned char* target,
582 unsigned int* target_bytes,
583 unsigned int target_size);
584
585 // Helper routine that patches a 64-bit MOV instruction with a RIP-relative
586 // displacement. The target buffer must be within 2GB of the source.
587 //
588 // 48 8B 0D XX XX XX XX = MOV rel32off
589 //
590 // @param source Pointer to instruction.
591 //
592 // @param instruction_size Size of the instruction.
593 //
594 // @param target Target buffer to write the new instruction.
595 //
596 // @param target_bytes Pointer to a buffer that contains the size
597 // of the target instruction, in bytes.
598 //
599 // @param target_size Size of the target buffer.
600 //
601 // @return Returns SIDESTEP_SUCCESS if successful, otherwise an error.
602 static SideStepError PatchMovWithDisplacement(unsigned char* source,
603 unsigned int instruction_size,
604 unsigned char* target,
605 unsigned int* target_bytes,
606 unsigned int target_size);
607 }; 374 };
608 375
609 }; // namespace sidestep 376 }; // namespace sidestep
610 377
611 #endif // GOOGLE_PERFTOOLS_PREAMBLE_PATCHER_H_ 378 #endif // GOOGLE_PERFTOOLS_PREAMBLE_PATCHER_H_
OLDNEW
« no previous file with comments | « third_party/tcmalloc/chromium/src/windows/port.cc ('k') | third_party/tcmalloc/chromium/src/windows/preamble_patcher.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698