view agent/src/oopUtil.cpp @ 27:24f77b8a62fe

Bug 1587: Refactor to improve the messaging and gathering the symbols. reviewed-by: yasuenag
author KUBOTA Yuji <kubota.yuji@lab.ntt.co.jp>
date Tue, 19 Nov 2013 21:22:04 +0900
parents fa4bbeb769a3
children 0a4a349799b0
line wrap: on
line source

/*!
 * \file oopUtil.cpp
 * \brief This file is used to getting information inner JVM.<br>
 * Copyright (C) 2011-2013 Nippon Telegraph and Telephone Corporation
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 */

#include <jni.h>
#include <jvmti.h>

#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <pthread.h>
#include <sys/mman.h>
#include <unistd.h>

#include "oopUtil.hpp"
#include "util.hpp"
#include "bitMapMarker.hpp"
#include "snapShotMain.hpp"
#include "libmain.hpp"


/* Macros for override functions */
#define DEFINE_OVERRIDE_FUNC_1(prefix) \
  extern "C" void *prefix##_override_func_0;

#define DEFINE_OVERRIDE_FUNC_2(prefix) \
  DEFINE_OVERRIDE_FUNC_1(prefix) \
  extern "C" void *prefix##_override_func_1;

#define DEFINE_OVERRIDE_FUNC_3(prefix) \
  DEFINE_OVERRIDE_FUNC_2(prefix) \
  extern "C" void *prefix##_override_func_2;

#define DEFINE_OVERRIDE_FUNC_4(prefix) \
  DEFINE_OVERRIDE_FUNC_3(prefix) \
  extern "C" void *prefix##_override_func_3;

#define DEFINE_OVERRIDE_FUNC_8(prefix) \
  DEFINE_OVERRIDE_FUNC_4(prefix) \
  extern "C" void *prefix##_override_func_4; \
  extern "C" void *prefix##_override_func_5; \
  extern "C" void *prefix##_override_func_6; \
  extern "C" void *prefix##_override_func_7;

#define DEFINE_OVERRIDE_FUNC_9(prefix) \
  DEFINE_OVERRIDE_FUNC_8(prefix) \
  extern "C" void *prefix##_override_func_8;


/* Function define. */

/* Override functions.                       */
/* These functions is defined in override.S. */

/*!
 * \brief Override function for instance object on parallelGC.
 */
DEFINE_OVERRIDE_FUNC_4(par)

/*!
 * \brief Override function for instance object on parallelGC for after CR6964458.
 */
DEFINE_OVERRIDE_FUNC_4(CR6964458_par)

/*!
 * \brief Override function for instance object on parallelGC for after CR8000213.
 */
DEFINE_OVERRIDE_FUNC_4(CR8000213_par)

/*!
 * \brief Override function for instance object on parallelOldGC.
 */
DEFINE_OVERRIDE_FUNC_4(parOld)

/*!
 * \brief Override function for instance object on parallelOldGC for after CR6964458.
 */
DEFINE_OVERRIDE_FUNC_4(CR6964458_parOld)

/*!
 * \brief Override function for instance object on parallelOldGC for after CR8000213.
 */
DEFINE_OVERRIDE_FUNC_4(CR8000213_parOld)

/*!
 * \brief Override function for sweep at old gen on CMSGC.
 */
DEFINE_OVERRIDE_FUNC_1(cms_sweep)

/*!
 * \brief Override function for instance object at new gen on CMSGC.
 */
DEFINE_OVERRIDE_FUNC_4(cms_new)

/*!
 * \brief Override function for instance object at new gen on CMSGC for after CR6964458.
 */
DEFINE_OVERRIDE_FUNC_4(CR6964458_cms_new)

/*!
 * \brief Override function for instance object at new gen on CMSGC for after CR8000213.
 */
DEFINE_OVERRIDE_FUNC_4(CR8000213_cms_new)

/*!
 * \brief Override function for instance object on G1GC.
 */
DEFINE_OVERRIDE_FUNC_9(g1)

/*!
 * \brief Override function for instance object on G1GC for after CR6964458.
 */
DEFINE_OVERRIDE_FUNC_9(CR6964458_g1)

/*!
 * \brief Override function for instance object on G1GC for after CR8000213.
 */
DEFINE_OVERRIDE_FUNC_9(CR8000213_g1)

/*!
 * \brief Override function for cleanup event on G1GC.
 */
DEFINE_OVERRIDE_FUNC_2(g1Event)

/*!
 * \brief Override function for adjust klassOop.
 */
DEFINE_OVERRIDE_FUNC_8(adj)

/*!
 * \brief Override function for JVMTI function.
 */
DEFINE_OVERRIDE_FUNC_1(jvmti)

/*!
 * \brief Override function for inner GC function.
 */
DEFINE_OVERRIDE_FUNC_3(innerStart)

/*!
 * \brief Override function for WatcherThread.
 */
DEFINE_OVERRIDE_FUNC_1(watcherThread)

/* Macro. */

#define SELECT_HOOK_FUNCS(result, prefix) \
  if(jvmInfo->isAfterCR8000213())       \
    result = CR8000213_##prefix##_hook; \
  else if(jvmInfo->isAfterCR6964458())  \
    result = CR6964458_##prefix##_hook; \
  else                                  \
    result = prefix##_hook;

/*!
 * \brief Symbol of "JvmtiEnv::GetObjectSize" macro.
 */
#ifdef __x86_64__
  #define SYMBOL_GETOBJCTSIZE "_ZN8JvmtiEnv13GetObjectSizeEP8_jobjectPl"
#else
  #define SYMBOL_GETOBJCTSIZE "_ZN8JvmtiEnv13GetObjectSizeEP8_jobjectPx"
#endif

/* Variable. */

/* Variable for pointer dummy. */

/*!
 * \brief Dummy zero variable.<br> This variable is always 0.
 */
int dummyZeroInt = 0;

/*!
 * \brief Dummy false flag.<br> This variable is always false.
 */
bool dummyFalseFlag = false;

/* Define JVM paramter pointer variable for calling from external. */

/*!
 * \brief Pointer to "-XX:UseCompressedOops".
 */
#ifdef __LP64__
bool *isCOOP      = NULL;
#else
bool *isCOOP      = &dummyFalseFlag;
#endif

/*!
 * \brief Pointer to "-XX:UseParallelGC".
 */
bool *useParallel = NULL;

/*!
 * \brief Pointer to "-XX:UseParallelOldGC".
 */
bool *useParOld   = NULL;

/*!
 * \brief Pointer to "-XX:UseConcMarkSweepGC".
 */
bool *useCMS      = NULL;

/*!
 * \brief Pointer to"-XX:UseG1GC".
 */
bool *useG1       = NULL;

/* Variable for CMS collector state. */

/*!
 * \brief CMS collector is idling.
 */
const int CMS_IDLING         = 2;
/*!
 * \brief CMS collector is initial-marking phase.
 */
const int CMS_INITIALMARKING = 3;
/*!
 * \brief CMS collector is marking phase.
 */
const int CMS_MARKING        = 4;
/*!
 * \brief CMS collector is final-making phase.
 */
const int CMS_FINALMARKING   = 7;
/*!
 * \brief CMS collector is sweep phase.
 */
const int CMS_SWEEPING       = 8;

/*!
 * \brief CMS collector state pointer.
 * \sa concurrentMarkSweepGeneration.hpp<br>
 *     at hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/<br>
 *     enum CollectorState
 */
int *CMS_collectorState  = NULL;

/* Define function pointer variable for calling from external. */

/*!
 * \brief Function pointer for "is_in_permanent".
 */
THeap_IsInPermanent is_in_permanent   = NULL;

/*!
 * \brief Pointer of "_collectedHeap" field in Universe.<br>
 *        Use to calling "is_in_permanent" function.
 */
void *collectedHeap                   = NULL;

/*!
 * \brief Function pointer for "JvmtiEnv::GetObjectSize".
 */
TJvmtiEnv_GetObjectSize getObjectSize = NULL;

/*!
 * \brief Function pointer for "java_lang_Class::as_klassOop".
 */
TJavaLangClass_AsKlassOop asKlassOop  = NULL;

/* Variable for inner class size. */

/*!
 * \brief Size of "oopDesc" class in JVM.
 */
uint64_t clsSizeOopDesc       = 0;

/*!
 * \brief Size of "klassOopDesc" class in JVM.
 */
uint64_t clsSizeKlassOop      = 0;

/*!
 * \brief Size of "narrowOop" class in JVM.
 */
uint64_t clsSizeNarrowOop     = 0;

/*!
 * \brief Size of "arrayOopDesc" class in JVM.
 */
uint64_t clsSizeArrayOop      = 0;

/*!
 * \brief Size of "Klass" class in JVM.
 */
uint64_t clsSizeKlass         = 0;

/*!
 * \brief Size of "instanceKlass" class in JVM.
 */
uint64_t clsSizeInstanceKlass = 0;

/* Variable for inner class field offset. */

/*!
 * \brief Offset of "oopDesc" class's "_metadata._klass" field.
 *        This field is stored class object when JVM don't using COOP.
 */
off_t ofsKlassAtOop     = -1;

/*!
 * \brief Offset of "oopDesc" class's "_metadata._compressed_klass" field.
 *        This field is stored class object when JVM is using COOP.
 */
off_t ofsCoopKlassAtOop = -1;

/*!
 * \brief Offset of "oopDesc" class's "_mark" field.
 *        This field is stored bit flags of lock information.
 */
off_t ofsMarkAtOop      = -1;

/*!
 * \brief Offset of "Klass" class's "_name" field.
 *        This field is stored symbol object that designed class name.
 */
off_t ofsNameAtKlass    = -1;

/*!
 * \brief Offset of "Symbol" class's "_length" field.
 *        This field is stored string size of class name.
 */
off_t ofsLengthAtSymbol = -1;

/*!
 * \brief Offset of "Symbol" class's "_body" field.
 *        This field is stored string of class name.
 */
off_t ofsBodyAtSymbol   = -1;

/* Variable for environment information. */

/*!
* \brief Pointer of COOP base address.
 */
ptrdiff_t narrowOffsetBase = 0;

/*!
* \brief Pointer of COOP shift bits.
 */
int *narrowOffsetShift     = &dummyZeroInt;

/*!
* \brief Pointer of Klass COOP shift bits.
 */
int *narrowKlassOffsetShift     = &dummyZeroInt;

/*!
* \brief Pointer of COOP base Klass address.
 */
ptrdiff_t narrowKlassOffsetBase = 0;

/*!
 * \brief Lock bit mask.<br>
 *        Value of "markOopDesc" class's "lock_mask_in_place" constant field.
 */
uint64_t lockMaskInPlaceMarkOop = 0;

/* Variable for CMS marking bitmap. */

/*!
 * \brief Pointer of CMS marking bitmap start word.
 */
void *cmsBitMap_startWord    = NULL;
/*!
 * \brief Pointer to shifter of CMS bitmap.
 */
int *cmsBitMap_shifter       = NULL;
/*!
 * \brief Pointer to CMS Marking bitmap start memory address.
 */
size_t *cmsBitMap_startAddr  = NULL;

/*!
 * \brief Size of integer(regular integer register) on now environment.<br>
 *        BitsPerWord is used by CMS GC mark bitmap.<br>
 *        This value is default. At "setupForCMS", read from VMIntConstant.
 */
int32_t HeapWordSize = 
#ifdef __LP64__
  8
#else
  4
#endif
;

/*!
 * \brief Number of bit to need expressing integer size of "HeapWordSize".
 *        HeapWordSize = 2 ^ LogHeapWordSize.<br>
 *        BitsPerWord is used by CMS GC mark bitmap.<br>
 *        This value is default. At "setupForCMS", read from VMIntConstant.
 */
int32_t LogHeapWordSize = 
#ifdef __LP64__
  3
#else
  2
#endif
;

/*!
 * \brief It's integer's number to need for expressing 64bit integer
 *        on now environment.<br>
 *        BitsPerWord is used by CMS GC mark bitmap.<br>
 *        This value is default. At "setupForCMS", read from JVM symbol.
 */
int HeapWordsPerLong = 
#ifdef __LP64__
  1
#else
  2
#endif
;

/*!
 * \brief Number of bit to need expressing a integer register.<br>
 *        LogBitsPerWord = 2 ^ LogBitsPerWord.<br>
 *        BitsPerWord is used by CMS GC mark bitmap.<br>
 *        This value is default. At "setupForCMS", read from JVM symbol.
 */
int LogBitsPerWord = 
#ifdef __LP64__
  6
#else
  5
#endif
;

/*!
 * \brief Number of bit to expressable max integer by single register
 *        on now environment.<br>
 *        LogBitsPerWord = sizeof(long) * 8.<br>
 *        BitsPerWord is used by CMS GC mark bitmap.<br>
 *        This value is default. At "setupForCMS", read from JVM symbol.
 */
int BitsPerWord = 
#ifdef __LP64__
  64
#else
  32
#endif
;

int BitsPerWordMask;

/*!
 * \brief JVM safepoint state pointer.
 */
int *safePointState = NULL;

/* Variable for class object. */

/*!
 * \brief Symbol finder object about "libjvm.so" shared library.
 */
TSymbolFinder    *symFinder = NULL;

/*!
 * \brief JVM inner structure scanner.
 */
TVMStructScanner *vmScanner = NULL;

/*!
 * \brief Bitmap object for G1 GC.
 */
TBitMapMarker    *checkObjectMap = NULL;


/* Variable for override information. */

/*!
 * \brief Pointer of hook information on parallelGC.
 */
THookFunctionInfo par_hook[] = {
  HOOK_FUNC("_ZTV13instanceKlass",
    "_ZN13instanceKlass19oop_follow_contentsEP7oopDesc",
    &par_override_func_0, NULL),
  HOOK_FUNC("_ZTV13objArrayKlass",
    "_ZN13objArrayKlass19oop_follow_contentsEP7oopDesc",
    &par_override_func_1, NULL),
  HOOK_FUNC("_ZTV14typeArrayKlass",
    "_ZN14typeArrayKlass19oop_follow_contentsEP7oopDesc",
    &par_override_func_2, NULL),
  HOOK_FUNC("_ZTV16instanceRefKlass",
    "_ZN16instanceRefKlass19oop_follow_contentsEP7oopDesc",
    &par_override_func_3, NULL),
  HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook information on parallelGC for after CR6964458.
 */
THookFunctionInfo CR6964458_par_hook[] = {
  HOOK_FUNC("_ZTV13InstanceKlass",
    "_ZN13InstanceKlass19oop_follow_contentsEP7oopDesc",
    &CR6964458_par_override_func_0, NULL),
  HOOK_FUNC("_ZTV13objArrayKlass",
    "_ZN13objArrayKlass19oop_follow_contentsEP7oopDesc",
    &CR6964458_par_override_func_1, NULL),
  HOOK_FUNC("_ZTV14typeArrayKlass",
    "_ZN14typeArrayKlass19oop_follow_contentsEP7oopDesc",
    &CR6964458_par_override_func_2, NULL),
  HOOK_FUNC("_ZTV16InstanceRefKlass",
    "_ZN16InstanceRefKlass19oop_follow_contentsEP7oopDesc",
    &CR6964458_par_override_func_3, NULL),
  HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook information on parallelGC for after CR8000213.
 */
THookFunctionInfo CR8000213_par_hook[] = {
  HOOK_FUNC("_ZTV13InstanceKlass",
    "_ZN13InstanceKlass19oop_follow_contentsEP7oopDesc",
    &CR8000213_par_override_func_0, NULL),
  HOOK_FUNC("_ZTV13ObjArrayKlass",
    "_ZN13ObjArrayKlass19oop_follow_contentsEP7oopDesc",
    &CR8000213_par_override_func_1, NULL),
  HOOK_FUNC("_ZTV14TypeArrayKlass",
    "_ZN14TypeArrayKlass19oop_follow_contentsEP7oopDesc",
    &CR8000213_par_override_func_2, NULL),
  HOOK_FUNC("_ZTV16InstanceRefKlass",
    "_ZN16InstanceRefKlass19oop_follow_contentsEP7oopDesc",
    &CR8000213_par_override_func_3, NULL),
  HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook information on parallelOldGC.
 */
THookFunctionInfo parOld_hook[] = {
  HOOK_FUNC("_ZTV13instanceKlass",
    "_ZN13instanceKlass19oop_follow_contents"
    "EP20ParCompactionManagerP7oopDesc",
    &parOld_override_func_0, NULL),
  HOOK_FUNC("_ZTV13objArrayKlass",
    "_ZN13objArrayKlass19oop_follow_contents"
    "EP20ParCompactionManagerP7oopDesc",
    &parOld_override_func_1, NULL),
  HOOK_FUNC("_ZTV14typeArrayKlass",
    "_ZN14typeArrayKlass19oop_follow_contents"
    "EP20ParCompactionManagerP7oopDesc",
    &parOld_override_func_2, NULL),
  HOOK_FUNC("_ZTV16instanceRefKlass",
    "_ZN16instanceRefKlass19oop_follow_contents"
    "EP20ParCompactionManagerP7oopDesc",
    &parOld_override_func_3, NULL),
  HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook information on parallelOldGC for after CR6964458.
 */
THookFunctionInfo CR6964458_parOld_hook[] = {
  HOOK_FUNC("_ZTV13InstanceKlass",
    "_ZN13InstanceKlass19oop_follow_contents"
    "EP20ParCompactionManagerP7oopDesc",
    &CR6964458_parOld_override_func_0, NULL),
  HOOK_FUNC("_ZTV13objArrayKlass",
    "_ZN13objArrayKlass19oop_follow_contents"
    "EP20ParCompactionManagerP7oopDesc",
    &CR6964458_parOld_override_func_1, NULL),
  HOOK_FUNC("_ZTV14typeArrayKlass",
    "_ZN14typeArrayKlass19oop_follow_contents"
    "EP20ParCompactionManagerP7oopDesc",
    &CR6964458_parOld_override_func_2, NULL),
  HOOK_FUNC("_ZTV16InstanceRefKlass",
    "_ZN16InstanceRefKlass19oop_follow_contents"
    "EP20ParCompactionManagerP7oopDesc",
    &CR6964458_parOld_override_func_3, NULL),
  HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook information on parallelOldGC for after CR8000213.
 */
THookFunctionInfo CR8000213_parOld_hook[] = {
  HOOK_FUNC("_ZTV13InstanceKlass",
    "_ZN13InstanceKlass19oop_follow_contents"
    "EP20ParCompactionManagerP7oopDesc",
    &CR8000213_parOld_override_func_0, NULL),
  HOOK_FUNC("_ZTV13ObjArrayKlass",
    "_ZN13ObjArrayKlass19oop_follow_contents"
    "EP20ParCompactionManagerP7oopDesc",
    &CR8000213_parOld_override_func_1, NULL),
  HOOK_FUNC("_ZTV14TypeArrayKlass",
    "_ZN14TypeArrayKlass19oop_follow_contents"
    "EP20ParCompactionManagerP7oopDesc",
    &CR8000213_parOld_override_func_2, NULL),
  HOOK_FUNC("_ZTV16InstanceRefKlass",
    "_ZN16InstanceRefKlass19oop_follow_contents"
    "EP20ParCompactionManagerP7oopDesc",
    &CR8000213_parOld_override_func_3, NULL),
  HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook information on CMSGC.
 */
THookFunctionInfo cms_sweep_hook[] = {
  HOOK_FUNC("_ZTV12SweepClosure",
    "_ZN12SweepClosure14do_blk_carefulEP8HeapWord",
    &cms_sweep_override_func_0, NULL),
  HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook information on CMSGC.
 */
THookFunctionInfo cms_new_hook[] = {
  HOOK_FUNC("_ZTV13instanceKlass",
    "_ZN13instanceKlass18oop_oop_iterate_nv"
    "EP7oopDescP30Par_MarkRefsIntoAndScanClosure",
    &cms_new_override_func_0, NULL),
  HOOK_FUNC("_ZTV13objArrayKlass",
    "_ZN13objArrayKlass18oop_oop_iterate_nv"
    "EP7oopDescP30Par_MarkRefsIntoAndScanClosure",
    &cms_new_override_func_1, NULL),
  HOOK_FUNC("_ZTV14typeArrayKlass",
    "_ZN14typeArrayKlass15oop_oop_iterate"
    "EP7oopDescP10OopClosure",
    &cms_new_override_func_2, NULL),
  HOOK_FUNC("_ZTV16instanceRefKlass",
    "_ZN16instanceRefKlass18oop_oop_iterate_nv"
    "EP7oopDescP30Par_MarkRefsIntoAndScanClosure",
    &cms_new_override_func_3, NULL),
  HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook information on CMSGC for after CR6964458.
 */
THookFunctionInfo CR6964458_cms_new_hook[] = {
  HOOK_FUNC("_ZTV13InstanceKlass",
    "_ZN13InstanceKlass18oop_oop_iterate_nv"
    "EP7oopDescP30Par_MarkRefsIntoAndScanClosure",
    &CR6964458_cms_new_override_func_0, NULL),
  HOOK_FUNC("_ZTV13objArrayKlass",
    "_ZN13objArrayKlass18oop_oop_iterate_nv"
    "EP7oopDescP30Par_MarkRefsIntoAndScanClosure",
    &CR6964458_cms_new_override_func_1, NULL),
  HOOK_FUNC("_ZTV14typeArrayKlass",
    "_ZN14typeArrayKlass15oop_oop_iterate"
    "EP7oopDescP18ExtendedOopClosure",
    &CR6964458_cms_new_override_func_2, NULL),
  HOOK_FUNC("_ZTV16InstanceRefKlass",
    "_ZN16InstanceRefKlass18oop_oop_iterate_nv"
    "EP7oopDescP30Par_MarkRefsIntoAndScanClosure",
    &CR6964458_cms_new_override_func_3, NULL),
  HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook information on CMSGC for after CR8000213.
 */
THookFunctionInfo CR8000213_cms_new_hook[] = {
  HOOK_FUNC("_ZTV13InstanceKlass",
    "_ZN13InstanceKlass18oop_oop_iterate_nv"
    "EP7oopDescP30Par_MarkRefsIntoAndScanClosure",
    &CR8000213_cms_new_override_func_0, NULL),
  HOOK_FUNC("_ZTV13ObjArrayKlass",
    "_ZN13ObjArrayKlass18oop_oop_iterate_nv"
    "EP7oopDescP30Par_MarkRefsIntoAndScanClosure",
    &CR8000213_cms_new_override_func_1, NULL),
  HOOK_FUNC("_ZTV14TypeArrayKlass",
    "_ZN14TypeArrayKlass15oop_oop_iterate"
    "EP7oopDescP18ExtendedOopClosure",
    &CR8000213_cms_new_override_func_2, NULL),
  HOOK_FUNC("_ZTV16InstanceRefKlass",
    "_ZN16InstanceRefKlass18oop_oop_iterate_nv"
    "EP7oopDescP30Par_MarkRefsIntoAndScanClosure",
    &CR8000213_cms_new_override_func_3, NULL),
  HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook information on G1GC.
 */
THookFunctionInfo g1_hook[] = {
  HOOK_FUNC("_ZTV16G1ParCopyClosureILb0EL9G1Barrier0ELb1EE",
    "_ZN16G1ParCopyClosureILb0EL9G1Barrier0ELb1EE6do_oopEPP7oopDesc",
    &g1_override_func_0, NULL),
  HOOK_FUNC("_ZTV16G1ParCopyClosureILb0EL9G1Barrier0ELb1EE",
    "_ZN16G1ParCopyClosureILb0EL9G1Barrier0ELb1EE6do_oopEPj",
    &g1_override_func_1, NULL),
  HOOK_FUNC("_ZTV13instanceKlass",
    "_ZN13instanceKlass18oop_oop_iterate_nvEP7oopDescP23G1RootRegionScanClosure",
    &g1_override_func_2, NULL),
  HOOK_FUNC("_ZTV13objArrayKlass",
    "_ZN13objArrayKlass18oop_oop_iterate_nvEP7oopDescP23G1RootRegionScanClosure",
    &g1_override_func_3, NULL),
  HOOK_FUNC("_ZTV16instanceRefKlass",
    "_ZN16instanceRefKlass18oop_oop_iterate_nvEP7oopDescP23G1RootRegionScanClosure",
    &g1_override_func_4, NULL),

  HOOK_FUNC("_ZTV13instanceKlass",
    "_ZN13instanceKlass18oop_oop_iterate_nvEP7oopDescP14G1CMOopClosure",
    &g1_override_func_5, NULL),
  HOOK_FUNC("_ZTV13objArrayKlass",
    "_ZN13objArrayKlass18oop_oop_iterate_nvEP7oopDescP14G1CMOopClosure",
    &g1_override_func_6, NULL),
  HOOK_FUNC("_ZTV14typeArrayKlass",
    "_ZN14typeArrayKlass15oop_oop_iterateEP7oopDescP10OopClosure",
    &g1_override_func_7, NULL),
  HOOK_FUNC("_ZTV16instanceRefKlass",
    "_ZN16instanceRefKlass18oop_oop_iterate_nvEP7oopDescP14G1CMOopClosure",
    &g1_override_func_8, NULL),
  HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook information on G1GC for after CR6964458.
 */
THookFunctionInfo CR6964458_g1_hook[] = {
  HOOK_FUNC("_ZTV16G1ParCopyClosureILb0EL9G1Barrier0ELb1EE",
    "_ZN16G1ParCopyClosureILb0EL9G1Barrier0ELb1EE6do_oopEPP7oopDesc",
    &CR6964458_g1_override_func_0, NULL),
  HOOK_FUNC("_ZTV16G1ParCopyClosureILb0EL9G1Barrier0ELb1EE",
    "_ZN16G1ParCopyClosureILb0EL9G1Barrier0ELb1EE6do_oopEPj",
    &CR6964458_g1_override_func_1, NULL),
  HOOK_FUNC("_ZTV13InstanceKlass",
    "_ZN13InstanceKlass18oop_oop_iterate_nvEP7oopDescP23G1RootRegionScanClosure",
    &CR6964458_g1_override_func_2, NULL),
  HOOK_FUNC("_ZTV13objArrayKlass",
    "_ZN13objArrayKlass18oop_oop_iterate_nvEP7oopDescP23G1RootRegionScanClosure",
    &CR6964458_g1_override_func_3, NULL),
  HOOK_FUNC("_ZTV16InstanceRefKlass",
    "_ZN16InstanceRefKlass18oop_oop_iterate_nvEP7oopDescP23G1RootRegionScanClosure",
    &CR6964458_g1_override_func_4, NULL),

  HOOK_FUNC("_ZTV13InstanceKlass",
    "_ZN13InstanceKlass18oop_oop_iterate_nvEP7oopDescP14G1CMOopClosure",
    &CR6964458_g1_override_func_5, NULL),
  HOOK_FUNC("_ZTV13objArrayKlass",
    "_ZN13objArrayKlass18oop_oop_iterate_nvEP7oopDescP14G1CMOopClosure",
    &CR6964458_g1_override_func_6, NULL),
  HOOK_FUNC("_ZTV14typeArrayKlass",
    "_ZN14typeArrayKlass15oop_oop_iterateEP7oopDescP18ExtendedOopClosure",
    &CR6964458_g1_override_func_7, NULL),
  HOOK_FUNC("_ZTV16InstanceRefKlass",
    "_ZN16InstanceRefKlass18oop_oop_iterate_nvEP7oopDescP14G1CMOopClosure",
    &CR6964458_g1_override_func_8, NULL),
  HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook information on G1GC for after CR8000213.
 */
THookFunctionInfo CR8000213_g1_hook[] = {
  HOOK_FUNC("_ZTV16G1ParCopyClosureILb0EL9G1Barrier0ELb1EE",
    "_ZN16G1ParCopyClosureILb0EL9G1Barrier0ELb1EE6do_oopEPP7oopDesc",
    &CR8000213_g1_override_func_0, NULL),
  HOOK_FUNC("_ZTV16G1ParCopyClosureILb0EL9G1Barrier0ELb1EE",
    "_ZN16G1ParCopyClosureILb0EL9G1Barrier0ELb1EE6do_oopEPj",
    &CR8000213_g1_override_func_1, NULL),
  HOOK_FUNC("_ZTV13InstanceKlass",
    "_ZN13InstanceKlass18oop_oop_iterate_nvEP7oopDescP23G1RootRegionScanClosure",
    &CR8000213_g1_override_func_2, NULL),
  HOOK_FUNC("_ZTV13ObjArrayKlass",
    "_ZN13ObjArrayKlass18oop_oop_iterate_nvEP7oopDescP23G1RootRegionScanClosure",
    &CR8000213_g1_override_func_3, NULL),
  HOOK_FUNC("_ZTV16InstanceRefKlass",
    "_ZN16InstanceRefKlass18oop_oop_iterate_nvEP7oopDescP23G1RootRegionScanClosure",
    &CR8000213_g1_override_func_4, NULL),

  HOOK_FUNC("_ZTV13InstanceKlass",
    "_ZN13InstanceKlass18oop_oop_iterate_nvEP7oopDescP14G1CMOopClosure",
    &CR8000213_g1_override_func_5, NULL),
  HOOK_FUNC("_ZTV13ObjArrayKlass",
    "_ZN13ObjArrayKlass18oop_oop_iterate_nvEP7oopDescP14G1CMOopClosure",
    &CR8000213_g1_override_func_6, NULL),
  HOOK_FUNC("_ZTV14TypeArrayKlass",
    "_ZN14TypeArrayKlass15oop_oop_iterateEP7oopDescP18ExtendedOopClosure",
    &CR8000213_g1_override_func_7, NULL),
  HOOK_FUNC("_ZTV16InstanceRefKlass",
    "_ZN16InstanceRefKlass18oop_oop_iterate_nvEP7oopDescP14G1CMOopClosure",
    &CR8000213_g1_override_func_8, NULL),
  HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook information on G1GC cleanup event.
 */
THookFunctionInfo g1Event_hook[] = {
  HOOK_FUNC("_ZTV9CMCleanUp",
    "_ZN9CMCleanUp7do_voidEv",
    &g1Event_override_func_0, NULL),
  HOOK_FUNC("_ZTV16VM_G1CollectFull",
    "_ZN16VM_G1CollectFull4doitEv",
    &g1Event_override_func_1, (void*)&callbackForG1FullReturn),
  HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook change and adjust oop with GC.
 */
THookFunctionInfo adj_hook[] = {
  HOOK_FUNC("_ZTV18instanceKlassKlass",
    "_ZN18instanceKlassKlass19oop_adjust_pointersEP7oopDesc",
    &adj_override_func_0, NULL),
  HOOK_FUNC("_ZTV18objArrayKlassKlass",
    "_ZN18objArrayKlassKlass19oop_adjust_pointersEP7oopDesc",
    &adj_override_func_1, NULL),
  HOOK_FUNC("_ZTV15arrayKlassKlass",
    "_ZN15arrayKlassKlass19oop_adjust_pointersEP7oopDesc",
    &adj_override_func_2, NULL),
  HOOK_FUNC("_ZTV20MoveAndUpdateClosure",
#ifdef __LP64__
    "_ZN20MoveAndUpdateClosure7do_addrEP8HeapWordm",
#else
    "_ZN20MoveAndUpdateClosure7do_addrEP8HeapWordj",
#endif
  &adj_override_func_3, NULL),
  HOOK_FUNC("_ZTV17UpdateOnlyClosure",
#ifdef __LP64__
    "_ZN17UpdateOnlyClosure7do_addrEP8HeapWordm",
#else
    "_ZN17UpdateOnlyClosure7do_addrEP8HeapWordj",
#endif
    &adj_override_func_4, NULL),
  HOOK_FUNC("_ZTV18instanceKlassKlass",
    "_ZN18instanceKlassKlass19oop_update_pointers"
    "EP20ParCompactionManagerP7oopDesc",
    &adj_override_func_5, NULL),
  HOOK_FUNC("_ZTV18objArrayKlassKlass",
    "_ZN18objArrayKlassKlass19oop_update_pointers"
    "EP20ParCompactionManagerP7oopDesc",
    &adj_override_func_6, NULL),
  HOOK_FUNC("_ZTV15arrayKlassKlass",
    "_ZN15arrayKlassKlass19oop_update_pointers"
    "EP20ParCompactionManagerP7oopDesc",
    &adj_override_func_7, NULL),
  HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook oop iterate with JVMTI HeapOverIterate.
 */
THookFunctionInfo jvmti_hook[] = {
  HOOK_FUNC("_ZTV28IterateOverHeapObjectClosure",
    "_ZN28IterateOverHeapObjectClosure9do_objectEP7oopDesc",
    &jvmti_override_func_0, NULL),
  HOOK_FUNC_END
};

/*!
 * \brief Pointer of hook inner GC function for default.
 */
THookFunctionInfo innerStart_hook[] = {
    HOOK_FUNC("_ZTV20ParallelScavengeHeap",
        "_ZN20ParallelScavengeHeap31accumulate_statistics_all_tlabsEv",
        &innerStart_override_func_0, NULL),
    HOOK_FUNC("_ZTV13CollectedHeap",
        "_ZN13CollectedHeap31accumulate_statistics_all_tlabsEv",
        &innerStart_override_func_1, NULL),
    HOOK_FUNC("_ZTV16GenCollectedHeap",
        "_ZN16GenCollectedHeap11gc_prologueEb",
        &innerStart_override_func_2, NULL),
    HOOK_FUNC_END
};

/*!
 * \brief Pointer of WatcherThread hook.
 */
THookFunctionInfo watcherThread_hook[] = {
  HOOK_FUNC("_ZTV13WatcherThread",
    "_ZN13WatcherThread3runEv",
    &watcherThread_override_func_0, (void *)callbackForWatcherThreadRun),
  HOOK_FUNC_END
};

/* Event callback for outter. */

/*!
 * \brief Callback function for GC function hooking.
 */
THeapObjectCallback gcCallbackFunc = NULL;

/*!
 * \brief Callback function for JVMTI iterate hooking.
 */
THeapObjectCallback jvmtiIteCallbackFunc = NULL;

/*!
 * \brief Callback function for adjust oop function hooking.
 */
TKlassAdjustCallback adjustCallbackFunc = NULL;

/*!
 * \brief Callback function for finished G1GC.
 */
TCommonCallback g1FinishCallbackFunc = NULL;

/*!
 * \brief Callback function for interrupt GC.
 */
TCommonCallback gcInterruptCallbackFunc = NULL;


/* Variable for inner work. */

/*!
 * \brief flag of snapshot with CMS phase.
 */
bool needSnapShotByCMSPhase = false;

/*!
 * \brief flag of GC hooking enable.
 */
bool isEnableGCHooking = false;

/*!
 * \brief flag of JVMTI hooking enable.
 */
bool isEnableJvmtiHooking = false;

/*!
 * \brief Pthread key to store old klassOop.
 */
pthread_key_t oldKlassOopKey;

/*!
 * \brief flag of inner GC function is called many times.
 */
bool isInvokeGCManyTimes = false;

/*!
 * \brief VTable list which should be hooked.
 */
void *VTableForTypeArrayOopClosure[2] __attribute__((aligned(16)));


/* Function. */

/* Function for utilities. */

/*!
 * \brief Convert COOP(narrowOop) to wide Oop(normally Oop).
 * \param narrowOop [in] Java heap object(compressed format Oop).
 * \return Wide OopDesc object.
 */
inline void *getWideOop(unsigned int narrowOop) {
  
  /*
   * narrow oop decoding is defined in
   * inline oop oopDesc::decode_heap_oop_not_null(narrowOop v)
   * hotspot/src/share/vm/oops/oop.inline.hpp
   */
  
  return (void*)(narrowOffsetBase +
                      ((ptrdiff_t)narrowOop << (*narrowOffsetShift)));
}

/*!
 * \brief Convert COOP(narrowKlass) to wide Klass(normally Klass).
 * \param narrowKlass [in] Java Klass object(compressed Klass pointer).
 * \return Wide Klass object.
 */
inline void *getWideKlass(unsigned int narrowKlass) {
  
  /*
   * narrowKlass decoding is defined in
   * inline Klass* Klass::decode_klass_not_null(narrowKlass v)
   * hotspot/src/share/vm/oops/klass.inline.hpp
   */
  
  return (void*)(narrowKlassOffsetBase +
                      ((ptrdiff_t)narrowKlass << (*narrowKlassOffsetShift)));
}

/*!
 * \brief Getting oop's class information(It's "Klass", not "KlassOop").
 * \param klassOop [in] Java heap object(Inner "KlassOop" class).
 * \return Class information object(Inner "Klass" class).
 */
void *getKlassFromKlassOop(void *klassOop) {

  if(klassOop == NULL){
    return NULL;
  }
  else if(jvmInfo->isAfterCR6964458()){
    return klassOop;
  }
  else{
    return incAddress(klassOop, clsSizeKlassOop);
  }

}

/*!
 * \brief Getting oop's class information(It's "Klass", not "KlassOop").
 * \param oop [in] Java heap object(Inner class format).
 * \return Class information object.
 * \sa oopDesc::klass()<br>
 *     at hotspot/src/share/vm/oops/oop.inline.hpp in JDK.
 */
void *getKlassOopFromOop(void *oop) {
  
  void *tempAddr = NULL;
  /* Sanity check. */
  if (unlikely(oop == NULL)) {
    return NULL;
  }
  
  /* If JVM use "C"ompressed "OOP". */
  if (*isCOOP) {
    /* Get oop's klassOop from "_compressed_klass" field. */
    unsigned int* testAddr =
                      (unsigned int*)((ptrdiff_t)oop + ofsCoopKlassAtOop);
    
    if (likely(testAddr != NULL)) {
      /* Decode COOP. */
      tempAddr = getWideKlass(*testAddr);
    }
  } else {
    /* Get oop's klassOop from "_klass" field. */
    void **testAddr = (void**)incAddress(oop, ofsKlassAtOop);
    
    if (likely(testAddr != NULL)) {
      tempAddr = (*testAddr);
    }
  }
  
  return tempAddr;
}

/*!
 * \brief Getting class's name form java inner class.
 * \param klass [in] Java class object(Inner class format).
 * \return String of object class name.<br>
 *         Don't forget deallocate if value isn't null.
 */
char *getClassName(void *klass) {
  
  /* Sanity check. */
  if (unlikely(klass == NULL)) {
    return NULL;
  }
  
  /* Get class symbol information. */
  void **klassSymbol = (void**)incAddress(klass, ofsNameAtKlass);
  if (unlikely(klassSymbol == NULL || (*klassSymbol) == NULL)) {
    return NULL;
  }
  
  /* Get class name pointer. */
  char *name = (char*)incAddress((*klassSymbol), ofsBodyAtSymbol);
  if (unlikely(name == NULL)) {
    return NULL;
  }
  
  bool isInstanceClass = (*name != '[');
  
  /* Get class name size. */
  unsigned short len = *(unsigned short*)
                              incAddress((*klassSymbol), ofsLengthAtSymbol);
  
  char *str = NULL;
  /* If class is instance class. */
  if (isInstanceClass) {
    
    /* Add length of "L" and ";". */
    str = (char*)malloc(len + 3);
  } else {
    
    /* Get string memory. */
    str = (char*)malloc(len + 1);
  }
  
  if (likely(str != NULL)) {
    
    /* Get class name. */
    if (isInstanceClass) {
      
      /* Copy class name if class is instance class. */
      /* As like "instanceKlass::signature_name()".  */
      str[0] = 'L';
      //memcpy(&str[1], name, len);
      __builtin_memcpy(&str[1], name, len);
      str[len + 1] = ';';
      str[len + 2] = '\0';
    } else {
      
      /* Copy class name if class is other. */
      //memcpy(str, name, len);
      __builtin_memcpy(str, name, len);
      str[len] = '\0';
    }
  }
  
  return str;
}

/*!
 * \brief Get oop forward address.
 * \param oop [in] Java heap object.
 * \return Wide OopDesc object.
 */
inline void *getForwardAddr(void *oop) {
  
  /* Sanity check. */
  if (unlikely(oop == NULL)) {
    return NULL;
  }
  
  /* Get OopDesc::_mark field. */
  ptrdiff_t markOop = *(ptrdiff_t*)incAddress(oop, ofsMarkAtOop);
  return (void*)(markOop & ~lockMaskInPlaceMarkOop);
}

/*!
 * \brief Is marked object on CMS bitmap.
 * \param oop [in] Java heap object(Inner class format).
 * \return Value is true, if object is marked.
 */
inline bool isMarkedObject(void *oop) {
  size_t idx  = (((ptrdiff_t)oop - (ptrdiff_t)cmsBitMap_startWord)
                 >> ((unsigned)LogHeapWordSize + (unsigned)*cmsBitMap_shifter));
  size_t mask = (size_t)1 << (idx & BitsPerWordMask);
  return (((size_t*)cmsBitMap_startAddr)[(idx >> LogBitsPerWord)] & mask) != 0;
}

/*!
 * \brief Switching override function enable state.
 * \param list   [in] List of hooking information.
 * \param enable [in] Enable of override function.
 * \return Process result.
 */
bool switchOverrideFunction(THookFunctionInfo *list, bool enable) {
  /* Variable for list pointer. */
  THookFunctionInfo *arr = list;
  /* Variable for list item count. */
  int listCnt = 0;
  /* Variable for succeed count. */
  int doneCnt = 0;

  /* Search class and function symbol. */
  for(; arr->originalFunc != NULL; listCnt++){
    /* Variable for store vtable. */
    void **vtable = arr->vtable;
    /* Variable for store function pointer. */
    void *targetFunc = NULL;
    void *destFunc = NULL;

    /* Setting swap target and swap dest. */
    if(enable){
      targetFunc = arr->originalFunc;
      destFunc   = arr->overrideFunc;
    }
    else{
      targetFunc = arr->overrideFunc;
      destFunc   = arr->originalFunc;
    }

    if(unlikely(vtable == NULL || targetFunc == NULL || destFunc == NULL)){
      /* Skip illegal. */
      arr++;
      continue;
    }

    const int VTABLE_SKIP_LIMIT = 1000;
    for(int i = 0; i < VTABLE_SKIP_LIMIT && *vtable == NULL; i++){
      /* Skip null entry. */
      vtable++;
    }

    while(*vtable != NULL){

      /* If target function. */
      if(*vtable == targetFunc){

        if(unlikely(!arr->isVTableWritable)){
          /* Avoid memory protection for vtable
           *   libstdc++ may remove write permission from vtable
           *   http://gcc.gnu.org/ml/gcc-patches/2012-11/txt00001.txt
           */
          ptrdiff_t start_page = (ptrdiff_t)vtable & ~(systemPageSize - 1);
          ptrdiff_t end_page =
                    ((ptrdiff_t)vtable + sizeof(void *)) & ~(systemPageSize - 1);
          size_t len = systemPageSize + (end_page - start_page);
          mprotect((void *)start_page, len, PROT_READ | PROT_WRITE);
          arr->isVTableWritable = true;
        }

        *vtable = destFunc;
        doneCnt++;
        break;
      }

      /* Move next vtable entry. */
      vtable++;
    }
    
    /* Move next list item. */
    arr++;
  }
  
  return (listCnt == doneCnt);
}

/* Function for callback. */

/*!
 * \brief Callback function for snapshot.
 * \param oop [in] Java heap object(OopDesc format).
 * \warning Param "oop" isn't usable for JVMTI and JNI.
 */
inline void callbackForSnapshot(void *oop) {
  
  if (likely(gcCallbackFunc != NULL)) {
    void *klassOop = NULL;
    jlong size = 0;
    
    /* Get class. */
    klassOop = getKlassOopFromOop(oop);
    
    /* Get object size. */
    if (likely(getObjectSize != NULL)) {
      getObjectSize(NULL, (jobject)&oop, &size);
    }
    
    /* Invoke callback. */
    gcCallbackFunc(klassOop, size);
  }
}

/*!
 * \brief Callback function for parallel GC and user's GC.<br>
 *        E.g. System.gc() in java code, JVMTI and etc..
 * \param oop [in] Java heap object(OopDesc format).
 * \warning Param "oop" isn't usable for JVMTI and JNI.
 */
extern "C" void callbackForParallel(void *oop) {
  
  /* Invoke snapshot callback. */
  callbackForSnapshot(oop);
}

/*!
 * \brief Callback function for parallel Old GC.
 * \param oop [in] Java heap object(OopDesc format).
 * \warning Param "oop" isn't usable for JVMTI and JNI.
 */
extern "C" void callbackForParOld(void *oop) {
  
  /* Invoke snapshot callback. */
  callbackForSnapshot(oop);
}

/*!
 * \brief Callback function for OopClosure::do_oop(oop *).<br>
 *        This function is targeted for G1ParScanAndMarkExtRootClosure.
 *        (initial-mark for G1)
 * \param oop [in] Java heap object(OopDesc format).
 */
extern "C" void callbackForDoOop(void **oop) {

  if((oop == NULL) || (*oop == NULL) ||
    is_in_permanent(collectedHeap, *oop)) return;
  
  if (checkObjectMap->checkAndMark(*oop)) {
    
    /* Object is already collected by G1GC collector. */
    return;
  }

  /* Invoke snapshot callback. */
  callbackForSnapshot(*oop);
}

/*!
 * \brief Callback function for OopClosure::do_oop(narrowOop *).<br>
 *        This function is targeted for G1ParScanAndMarkExtRootClosure.
 *        (initial-mark for G1)
 * \param oop [in] Java heap object(OopDesc format).
 */
extern "C" void callbackForDoNarrowOop(unsigned int *narrowOop) {
  void *oop = getWideOop(*narrowOop);
  callbackForDoOop(&oop);
}

/*!
 * \brief Callback function for CMS GC and G1 GC.<br>
 *        This function is targeted for Young Gen only.
 * \param oop [in] Java heap object(OopDesc format).
 * \warning Param "oop" isn't usable for JVMTI and JNI.
 * \sa CMSParRemarkTask::do_young_space_rescan()<br>
 *     ContiguousSpace::par_oop_iterate()
 */
extern "C" void callbackForIterate(void *oop) {
  
  if (*useCMS) {
    
    /* If object is in CMS gen.  */
    if ((ptrdiff_t)oop >= (ptrdiff_t)cmsBitMap_startWord) {
      
      /* Skip. because collect object in CMS gen by callbackForSweep. */
      return;
    }
  } else if (*useG1 && checkObjectMap->checkAndMark(oop)) {
    
    /* Object is already collected by G1GC collector. */
    return;
  }
  
  /* Invoke snapshot callback. */
  callbackForSnapshot(oop);
}

/*!
 * \brief Callback function for CMS sweep.<br>
 *        This function is targeted for CMS Gen only.
 * \param oop [in] Java heap object(OopDesc format).
 * \warning Param "oop" isn't usable for JVMTI and JNI.
 */
extern "C" void callbackForSweep(void *oop) {
  
  /* If object isn't GC target. */
  if (likely(isMarkedObject(oop))) {
    
    /* Invoke snapshot callback. */
    callbackForSnapshot(oop);
  }
}

/*!
 * \brief Callback function for klassOop.
 * \param oldOop [in] Old java class object.
 * \param newOop [in] New java class object.
 * \warning Param "oop" isn't usable for JVMTI and JNI.
 */
inline void callbackForAdjustKlass(void *oldOop, void *newOop) {
  if (likely(adjustCallbackFunc != NULL)) {
    adjustCallbackFunc(oldOop, newOop);
  }
}

/*!
 * \brief Callback function for oop_adjust_pointers.
 * \param oop [in] Java heap object(OopDesc format).
 * \warning Param "oop" isn't usable for JVMTI and JNI.
 */
extern "C" void callbackForAdjustPtr(void *oop) {
  
  /* Get new class oop. */
  void *newOop = getForwardAddr(oop);
  if (newOop != NULL) {
    
    /* Invoke callback. */
    callbackForAdjustKlass(oop, newOop);
  }
}

/*!
 * \brief Callback function for do_addr.
 * \param oop [in] Java heap object(OopDesc format).
 * \warning Param "oop" isn't usable for JVMTI and JNI.
 */
extern "C" void callbackForDoAddr(void *oop) {
  
  /* Get store memory. */
  void **oldOop = (void**)pthread_getspecific(oldKlassOopKey);
  if (unlikely(oldOop == NULL)) {
    
    /* Allocate and set store memory. */
    oldOop = (void**)malloc(sizeof(void*));
    pthread_setspecific(oldKlassOopKey, oldOop);
  }
  
  /* Store old klassOop. */
  if (likely(oldOop != NULL)) {
    (*oldOop) = oop;
  }
}

/*!
 * \brief Callback function for oop_update_pointers.
 * \param oop [in] Java heap object(OopDesc format).
 * \warning Param "oop" isn't usable for JVMTI and JNI.
 */
extern "C" void callbackForUpdatePtr(void *oop) {
  
  /* Get old class oop. */
  void **oldOop = (void**)pthread_getspecific(oldKlassOopKey);
  
  if (likely(oldOop != NULL && (*oldOop) != NULL)) {
    
    /* Invoke callback. */
    callbackForAdjustKlass(oldOop, oop);
    
    /* Cleanup old data. */
    (*oldOop) = NULL;
  }
}

/*!
 * \brief Callback function for snapshot with data dump or interval.
 * \param oop [in] Java heap object(OopDesc format).
 * \warning Param "oop" isn't usable for JVMTI and JNI.
 */
extern "C" void callbackForJvmtiIterate(void *oop) {
  
  if (likely(jvmtiIteCallbackFunc != NULL)) {
    void *klassOop = NULL;
    jlong size = 0;
    
    /* Get class name. */
    klassOop = getKlassOopFromOop(oop);
    
    /* Get object size. */
    if (likely(getObjectSize != NULL)) {
      getObjectSize(NULL, (jobject)&oop, &size);
    }
    
    /* Invoke callback. */
    jvmtiIteCallbackFunc(klassOop, size);
  }
}

/*!
 * \brief Callback function for before G1 GC cleanup.
 */
extern "C" void callbackForG1Cleanup(void) {
  
  if (likely(g1FinishCallbackFunc != NULL)) {
    
    /* Invoke callback. */
    g1FinishCallbackFunc();
  }
  
  /* Clear bitmap. */
  checkObjectMap->clear();
}

/*!
 * \brief Callback function for before System.gc() on using G1GC.
 */
extern "C" void callbackForG1Full(void) {
  THookFunctionInfo *funcs;
  SELECT_HOOK_FUNCS(funcs, g1)

  /*
   * Disable G1 callback function:
   *  OopClosure for typeArrayKlass is called by G1 FullCollection.
   */
  switchOverrideFunction(funcs, false);

  /* Discard existed snapshot data */
  snapshotByGC->clear();
  checkObjectMap->clear();
}

/*!
 * \brief Callback function for after System.gc() on using G1GC.
 */
extern "C" void callbackForG1FullReturn(void) {
  THookFunctionInfo *funcs;
  SELECT_HOOK_FUNCS(funcs, g1)
  
  /* Restore G1 callback. */
  switchOverrideFunction(funcs, true);
  
  if(likely(g1FinishCallbackFunc != NULL)){
    /* Invoke callback. */
    g1FinishCallbackFunc();
  }
  
  /* Clear bitmap. */
  checkObjectMap->clear();
}

/*!
 * \brief Callback function for starting inner GC.
 */
extern "C" void callbackForInnerGCStart(void) {

  /* If call GC function more one. */
  if(unlikely(isInvokeGCManyTimes)){
    /* Invoke GC interrupt callback. */
    if(likely(gcInterruptCallbackFunc != NULL)){
      gcInterruptCallbackFunc();
    }
  }
  else{
    /* Update state. */
    isInvokeGCManyTimes = true;
  }

  /* Get current GCCause. */
  jvmInfo->loadGCCause();
}

/*!
 * \brief Callback function for WatcherThread.
 */
extern "C" void callbackForWatcherThreadRun(void){
  jvmInfo->detectDelayInfoAddress();
}

/* Function for pthread. */

/*!
 * \brief Callback for pthread key destructor.
 * \param data [in] Data related to pthread key.
 */
void pThreadKeyDestructor(void *data) {
  if (likely(data != NULL)) {
    
    /* Cleanup allocated memory on "callbackForDoAddr". */
    free(data);
  }
}

/* Function for init/final. */

/*!
 * \brief Search common JVM information structures at "OnVMInit".
 * \return Process result.
 */
bool searchCommonInformation(void) {
  
  /* List of common field offset. */
  TOffsetNameMap ofsMap[] = {
    {"Universe", "_collectedHeap",              NULL,
      &collectedHeap},
    {"Universe", "_narrow_oop._base",           NULL,
      (void **)&narrowOffsetBase},
    {"Universe", "_narrow_oop._shift",          NULL,
      (void **)&narrowOffsetShift},
    {"Universe", "_narrow_klass._base",         NULL,
      (void **)&narrowKlassOffsetBase},
    {"Universe", "_narrow_klass._shift",        NULL,
      (void **)&narrowKlassOffsetShift},
    {"oopDesc",  "_metadata._klass",            &ofsKlassAtOop,
      NULL},
    {"oopDesc",  "_metadata._compressed_klass", &ofsCoopKlassAtOop,
      NULL},
    {"oopDesc",  "_mark",                       &ofsMarkAtOop,
      NULL},
    {"Klass",    "_name",                       &ofsNameAtKlass,
      NULL},
    
    /*
     * See 6990754:
     * Use native memory and reference counting to implement SymbolTable.
     * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6990754
     * http://hg.openjdk.java.net/hsx/hotspot-rt-gate/hotspot/rev/3582bf76420e
     */
    {"symbolOopDesc", "_length", &ofsLengthAtSymbol, NULL},
    {"symbolOopDesc", "_body",   &ofsBodyAtSymbol,   NULL},
    {"Symbol",        "_length", &ofsLengthAtSymbol, NULL},
    {"Symbol",        "_body",   &ofsBodyAtSymbol,   NULL},
    
    /* End flag. */
    {NULL, NULL, NULL, NULL}
  };
  
  vmScanner->GetDataFromVMStructs(ofsMap);
  
  /* If failure getting common field offset information. */
  if (unlikely(collectedHeap == NULL || narrowOffsetBase == 0
    || narrowOffsetShift   == NULL || ofsKlassAtOop    == -1
    || ofsCoopKlassAtOop   == -1   || ofsNameAtKlass   == -1
    || ofsLengthAtSymbol   == -1   || ofsBodyAtSymbol  == -1)) {
    
    PRINT_WARN_MSG("Failure getting information form JVM."
      " info:Common from:VMStructs");
    return false;
  }

  if(!jvmInfo->isAfterCR8003424()){
    narrowKlassOffsetBase = narrowOffsetBase;
    narrowKlassOffsetShift = narrowOffsetShift;
  }

  if(!jvmInfo->isAfterCR6964458()){
    /* List of common class size. */
    TTypeSizeMap typeMap[] = {
      {"klassOopDesc",  &clsSizeKlassOop},
      /* End flag. */
      {NULL, NULL}
    };

    vmScanner->GetDataFromVMTypes(typeMap);

    /* If failure getting common class size information. */
    if (unlikely(clsSizeKlassOop == 0)) {
      PRINT_WARN_MSG("Failure getting information form JVM."
        " info:Common from:VMTypes");
      return false;
    }

  }
  
  /* List of common long constant. */
  TLongConstMap longMap[] = {
    {"markOopDesc::lock_mask_in_place", &lockMaskInPlaceMarkOop},
    /* End flag. */
    {NULL, NULL}
  };
  
  vmScanner->GetDataFromVMLongConstants(longMap);
  
  /* If failure getting common class size information. */
  if (unlikely(lockMaskInPlaceMarkOop == 0)) {
    
    PRINT_WARN_MSG("Failure getting information form JVM."
      " info:Common from:VMLongConstants");
    return false;
  }
  
  return true;
}

/*!
 * \brief Search common flag.
 * \return Process result.
 */
bool searchCommonFlags(void) {
  
  /* Search flag symbols. */
  struct {
    const char *symbolStr;
    bool** flagPtr;
  } flagList[] = {
#ifdef __LP64__
    {"UseCompressedOops",  &isCOOP},
#endif
    {"UseParallelGC",      &useParallel},
    {"UseParallelOldGC",   &useParOld},
    {"UseConcMarkSweepGC", &useCMS},
    {"UseG1GC",            &useG1},
    /* End flag. */
    {NULL, NULL}
  };
  
  for (int i = 0; flagList[i].flagPtr != NULL; i++) {
    bool *tempPtr = NULL;
    
    /* Search symbol. */
    tempPtr = (bool*)symFinder->findSymbol(flagList[i].symbolStr);
    
    /* If symbol not found. */
    if (unlikely(tempPtr == NULL)) {
      PRINT_WARN_MSG_HEADER << "Java symbol not found."
        << " symbol:\"" << flagList[i].symbolStr << "\"" << NEWLINE;
      
      return false;
    }
    
    (*flagList[i].flagPtr) = tempPtr;
  }

#ifdef __LP64__
  if(jvmInfo->isAfterCR6964458()){
    bool *tempPtr = NULL;
    const char *target_sym = jvmInfo->isAfterCR8015107()
                                     ? "UseCompressedClassPointers"
                                     : "UseCompressedKlassPointers";
    
    /* Search symbol. */
    tempPtr = (bool*)symFinder->findSymbol(target_sym);
    
    /* If symbol not found. */
    if (unlikely(tempPtr == NULL)) {
      PRINT_WARN_MSG_HEADER << target_sym << " not found." << NEWLINE;
    }
    else{
      isCOOP = tempPtr;
    }

  }
#endif

  if(*isCOOP){
    PRINT_DEBUG_MSG("Compressed Class = true");
  }
  else{
    PRINT_DEBUG_MSG("Compressed Class = false");
  }

  if(*useG1){
    /* Add vtable offset */
#ifdef __LP64__
    VTableForTypeArrayOopClosure[0] =
          incAddress(symFinder->findSymbol("_ZTV14G1CMOopClosure"), 16);
    VTableForTypeArrayOopClosure[1] =
          incAddress(symFinder->findSymbol("_ZTV23G1RootRegionScanClosure"), 16);
#else
    VTableForTypeArrayOopClosure[0] =
          incAddress(symFinder->findSymbol("_ZTV14G1CMOopClosure"), 8);
    VTableForTypeArrayOopClosure[1] =
          incAddress(symFinder->findSymbol("_ZTV23G1RootRegionScanClosure"), 8);
#endif
  }
  
  return true;
}

/*!
 * \brief Search common function.
 * \return Process result.
 */
bool searchCommonFunction(void) {

  if(jvmInfo->isAfterCR6964458()){
    is_in_permanent = &is_in_permanent_AfterCR6964458;
  }
  else{

    /* Search "is_in_permanent" function symbol. */
    if(*useParallel || *useParOld){
      is_in_permanent = (THeap_IsInPermanent)symFinder->findSymbol(
                              "_ZNK20ParallelScavengeHeap15is_in_permanentEPKv");
    }
    else{
      is_in_permanent = (THeap_IsInPermanent)symFinder->findSymbol(
                                        "_ZNK10SharedHeap15is_in_permanentEPKv");
    }

    /* If not found "is_in_permanent" function symbol. */
    if(unlikely(is_in_permanent == NULL)){
      PRINT_WARN_MSG("Java symbol not found. symbol:\"is_in_permanent\"");
      return false;
    }

  }

  /* Search "GetObjectSize" function symbol. */
  getObjectSize = (TJvmtiEnv_GetObjectSize)symFinder->findSymbol(SYMBOL_GETOBJCTSIZE);
  /* If not found "GetObjectSize" function symbol. */
  if(unlikely(getObjectSize == NULL)){
    PRINT_WARN_MSG("Java symbol not found. symbol:\"GetObjectSize\"");
    return false;
  }
  
  /* Search "as_klassOop" function symbol. */
  if(jvmInfo->isAfterCR6964458()){
    /* Search "as_Klass" function symbol. */
    asKlassOop = (TJavaLangClass_AsKlassOop)symFinder->findSymbol(
                                      "_ZN15java_lang_Class8as_KlassEP7oopDesc");
    /* If not found "as_klassOop" function symbol. */
    if(unlikely(asKlassOop == NULL)){
      PRINT_WARN_MSG("Java symbol not found. symbol:\"as_Klass\"");
      return false;
    }

  }
  else{
    /* Search "as_klassOop" function symbol. */
    asKlassOop = (TJavaLangClass_AsKlassOop)symFinder->findSymbol(
                                  "_ZN15java_lang_Class11as_klassOopEP7oopDesc");

    /* If not found "as_klassOop" function symbol. */
    if(unlikely(asKlassOop == NULL)){
      PRINT_WARN_MSG("Java symbol not found. symbol:\"as_klassOop\"");
      return false;
    }

  }

  /* Search symbol of variable stored safepoint state. */
  safePointState = (int*)symFinder->findSymbol("_ZN20SafepointSynchronize6_stateE");
  /* If not found "_state" variable symbol. */
  if (unlikely(safePointState == NULL)) {
    PRINT_WARN_MSG("Java symbol not found. symbol:\"safepoint_state\"");
    return false;
  }
  
  return true;
}

/*!
 * \brief Setup override funtion.
 * \param list [in] List of hooking information.
 * \return Process result.
 */
bool setupOverrideFunction(THookFunctionInfo *list) {
  /* Variable for list pointer. */
  THookFunctionInfo *arr = list;
  
  /* Search class and function symbol. */
  for (int i = 0; arr->vtableSymbol != NULL; i++) {
    
    /* Search class(vtable) symbol. */
    arr->vtable = (void**)symFinder->findSymbol(arr->vtableSymbol);
    if (unlikely(arr->vtable == NULL)) {
      PRINT_WARN_MSG_HEADER << "Java symbol not found."
        << " symbol:\"" << arr->vtableSymbol << "\"" << NEWLINE;
      return false;
    }

    /* Search function symbol. */
    arr->originalFunc = symFinder->findSymbol(arr->funcSymbol);
    if (unlikely(arr->originalFunc == NULL)) {
      PRINT_WARN_MSG_HEADER << "Java symbol not found."
        << " symbol:\"" << arr->funcSymbol << "\"" << NEWLINE;
      return false;
    }
    
    /* Move next list item. */
    arr++;
  }
  
  return true;
}

/*!
 * \brief Setup GC hooking for parallel.
 * \return Process result.
 */
bool setupForParallel(void) {
  THookFunctionInfo *funcs;
  SELECT_HOOK_FUNCS(funcs, par)
  
  /* If failure getting function information. */
  if(unlikely(!setupOverrideFunction(funcs))){
    PRINT_WARN_MSG("Can't override function. func:parallel");
    return false;
  }
  
  return true;
}

/*!
 * \brief Setup GC hooking for parallel old GC.
 * \return Process result.
 */
bool setupForParallelOld(void) {
  THookFunctionInfo *funcs;
  SELECT_HOOK_FUNCS(funcs, parOld)
  
  /* If failure getting function information. */
  if(unlikely(!setupOverrideFunction(funcs))){
    PRINT_WARN_MSG("Can't override function. func:par_old");
    return false;
  }
  
  return true;
}

/*!
 * \brief Setup GC hooking for CMSGC.
 * \return Process result.
 */
bool setupForCMS(void) {
  
  void *cmsCollector            = NULL;
  off_t offsetLowAtVirtualSpace = -1;
  off_t offsetCmsStartWord      = -1;
  off_t offsetCmsShifter        = -1;
  off_t offsetCmsMapAtCollector = -1;
  off_t offsetCmsVirtualSpace   = -1;
  TOffsetNameMap ofsMap[] = {
    {"CMSBitMap",                 "_virtual_space",
      &offsetCmsVirtualSpace,   NULL},
    {"CMSBitMap",                 "_bmStartWord",
      &offsetCmsStartWord,      NULL},
    {"CMSBitMap",                 "_shifter",
      &offsetCmsShifter,        NULL},
    {"CMSCollector",              "_markBitMap",
      &offsetCmsMapAtCollector, NULL},
    {"ConcurrentMarkSweepThread", "_collector",
      NULL,                     &cmsCollector},
    {"VirtualSpace",              "_low",
      &offsetLowAtVirtualSpace, NULL},
    /* End flag. */
    {NULL, NULL, NULL, NULL}
  };
  
  vmScanner->GetDataFromVMStructs(ofsMap);
  
  /* If failure getting offset. */
  if (unlikely(offsetCmsVirtualSpace == -1
    || offsetCmsShifter ==   -1 || offsetCmsMapAtCollector == -1
    || cmsCollector     == NULL || offsetLowAtVirtualSpace == -1
    || *(void**)cmsCollector    == NULL)) {
    
    PRINT_WARN_MSG("Failure getting information form JVM."
      " info:CMS from:vmStructs");
    return false;
  }

  if(jvmInfo->isAfterCR6964458()){
    off_t bmWordSizeOfs = -1;

    TOffsetNameMap bmWordSizeMap[] = {
      {"CMSBitMap", "_bmWordSize", &bmWordSizeOfs, NULL},
      {NULL, NULL, NULL, NULL}
    };

    vmScanner->GetDataFromVMStructs(bmWordSizeMap);

    if(bmWordSizeOfs == -1){
      PRINT_WARN_MSG("Failure getting information form JVM."
        " info:CMS from:vmStructs");
      return false;
    }

    /* CMSBitMap::_bmStartWord is appeared before _bmWordSize.
     * See CMSBitMap definition in
     * hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp
     */
    offsetCmsStartWord = bmWordSizeOfs - sizeof(void *);
  }
  else if(offsetCmsStartWord == -1){
    PRINT_WARN_MSG("Failure getting information form JVM."
      " info:CMS from:vmStructs");
    return false;
  }
  
  /* Calculate about CMS bitmap information. */
  cmsCollector = *(void**)cmsCollector;
  ptrdiff_t cmsBitmapPtr = (ptrdiff_t)cmsCollector + offsetCmsMapAtCollector;
  cmsBitMap_startWord = *(void**)(cmsBitmapPtr + offsetCmsStartWord);
  cmsBitMap_shifter   = (int*)(cmsBitmapPtr + offsetCmsShifter);
  
  ptrdiff_t virtSpace = cmsBitmapPtr + offsetCmsVirtualSpace;
  cmsBitMap_startAddr = *(size_t**)(virtSpace + offsetLowAtVirtualSpace);
  
  /* If failure getting CMS bitmap information. */
  if (unlikely(cmsBitMap_startWord == NULL || cmsBitMap_shifter == NULL
                                         || cmsBitMap_startAddr == NULL)) {
    
    PRINT_WARN_MSG("Failure getting information form JVM."
      " info:CMS from:calculate");
    return false;
  }
  
  /* List of integer constant data target. */
  TIntConstMap intMap[] = {
    {"HeapWordSize",    &HeapWordSize},
    {"LogHeapWordSize", &LogHeapWordSize},
    /* End flag. */
    {NULL, NULL}
  };
  
  vmScanner->GetDataFromVMIntConstants(intMap);
  
  /* Search symbol for CMS bitmap. */
  struct {
    const char *symbol;
    const char *subSymbol;
    int *pointer;
  } intSymList[] = {
    {"HeapWordsPerLong", "_ZL16HeapWordsPerLong", &HeapWordsPerLong},
    {"LogBitsPerWord",   "_ZL14LogBitsPerWord",   &LogBitsPerWord},
    {"BitsPerWord",      "_ZL11BitsPerWord",      &BitsPerWord},
    /* End flag. */
    {NULL, NULL, NULL}
  };
  
  for (int i = 0; intSymList[i].pointer != NULL; i++) {
    int *intPos = NULL;
    intPos = (int*)symFinder->findSymbol(intSymList[i].symbol);
    
    /* If integer symbol not found, search sub-symbol. */
    if (unlikely(intPos == NULL)) {
      intPos = (int*)symFinder->findSymbol(intSymList[i].subSymbol);
    }
    
    /* If integer symbol and sub-symbol not found. */
    if (unlikely(intPos == NULL)) {
      PRINT_DEBUG_MSG_HEADER
        << "Java symbol not found, using default value instead."
        << " symbol:\"" << intSymList[i].symbol << "\""
        << NEWLINE;
    } else {
      (*intSymList[i].pointer) = (*intPos);
    }
  }
  
  /* Search symbol for CMS state. */
  CMS_collectorState = (int*)symFinder->findSymbol(
    "_ZN12CMSCollector15_collectorStateE");
  /* If not found "CMS_collectorState" function symbol. */
  if (unlikely(CMS_collectorState == NULL)) {
    PRINT_WARN_MSG("Java symbol not found. symbol:\"CollectorState\"");
    return false;
  }
  
  THookFunctionInfo *funcs;
  SELECT_HOOK_FUNCS(funcs, cms_new)
  /* If failure getting function information. */
  if (unlikely(!setupOverrideFunction(funcs))) {
    PRINT_WARN_MSG("Can't override function. func:CMS_new");
    return false;
  }
  
  /* If failure getting function information. */
  if (unlikely(!setupOverrideFunction(cms_sweep_hook))) {
    
    PRINT_WARN_MSG("Can't override function. func:CMS_sweep");
    return false;
  }

  BitsPerWordMask = BitsPerWord - 1;
  
  return true;
}

/*!
 * \brief Setup GC hooking for G1GC
 * \return Process result.
 */
bool setupForG1GC(size_t maxMemSize) {
  
  off_t offsetG1Committed    = -1;
  off_t offsetMemRegionStart = -1;
  TOffsetNameMap ofsMap[] = {
    {"G1CollectedHeap",        "_g1_committed",
      &offsetG1Committed,    NULL},
    {"MemRegion",              "_start",
      &offsetMemRegionStart, NULL},
    /* End flag. */
    {NULL, NULL, NULL, NULL}
  };
  
  vmScanner->GetDataFromVMStructs(ofsMap);
  
  /* If failure getting offset. */
  if (unlikely(offsetG1Committed == -1 || offsetMemRegionStart == -1
    || collectedHeap == NULL)) {
    
    PRINT_WARN_MSG("Failure getting information form JVM."
      " info:G1 from:vmStructs");
    return false;
  }
  
  /* Calculate about G1GC memory information. */
  void *g1Committed = *(void**)incAddress(collectedHeap, offsetG1Committed);
  void *g1StartAddr = incAddress(g1Committed, offsetMemRegionStart);
  if (unlikely(g1Committed == NULL || g1StartAddr == NULL)) {
    
    PRINT_WARN_MSG("Failure getting information form JVM."
      " info:G1 from:calculate");
    return false;
  }
  
  try {
    /* Sanity check. */
    if (unlikely(maxMemSize <= 0)) {
      throw 1;
    }
    
    /* Create bitmap to check object collected flag. */
    checkObjectMap = new TBitMapMarker(g1StartAddr, maxMemSize);
    
  } catch(...) {
    PRINT_WARN_MSG("Failure allocate object marker bitmap.");
    return false;
  }
  
  THookFunctionInfo *funcs;
  SELECT_HOOK_FUNCS(funcs, g1)
  /* If failure getting function information. */
  if (unlikely(!setupOverrideFunction(funcs)
    || !setupOverrideFunction(g1Event_hook))) {
    
    PRINT_WARN_MSG("Can't override function. func:g1");
    return false;
  }
  
  return true;
}

/*!
 * \brief Setting GC hooking enable.
 * \param enable [in] Is GC hook enable.
 * \return Process result.
 */
bool setGCHookState(bool enable) {
  
  /* Sanity check. */
  if (unlikely(isEnableGCHooking == enable)) {
    
    /* Already set state. */
    return true;
  }
  /* Change state. */
  isEnableGCHooking = enable;
  
  /* Setting hooking target. */
  THookFunctionInfo *list = NULL;
  if (*useParOld) {
    SELECT_HOOK_FUNCS(list, parOld)
  } else if (*useCMS) {
    
    /* Switch CMS hooking at new generation. */
    THookFunctionInfo *funcs;
    SELECT_HOOK_FUNCS(funcs, cms_new)

    switchOverrideFunction(funcs, enable);
    
    list = cms_sweep_hook;
  } else if (*useG1) {

    /* If users select G1, we prepare TSnapShotContainer NOW! */
    snapshotByGC = TSnapShotContainer::getInstance();
    
    /* Switch G1GC event hooking. */
    switchOverrideFunction(g1Event_hook, enable);
    
    SELECT_HOOK_FUNCS(list, g1)
    checkObjectMap->clear();
  }
  
  /* Switch common hooking. */
  THookFunctionInfo *parFuncs;
  SELECT_HOOK_FUNCS(parFuncs, par)
  if (unlikely(!switchOverrideFunction(parFuncs, enable))) {
    PRINT_WARN_MSG("Failure switch function overriding. func:par");
    return false;
  }
 
  /* Switch adjust pointer hooking. */
  if(!jvmInfo->isAfterCR6964458()){
    if(unlikely(!switchOverrideFunction(adj_hook, enable))){
      PRINT_WARN_MSG("Failure switch function overriding. func:adj-ptr");
      return false;
    }
  }

  if (list != NULL) {
    
    /* Switch hooking for each GC type. */
    if (unlikely(!switchOverrideFunction(list, enable))) {
      
      PRINT_WARN_MSG("Failure switch function overriding. func:usingGC");
      return false;
    }
  }
  
  return true;
}

/*!
 * \brief Setting JVMTI hooking enable.
 * \param enable [in] Is JVMTI hook enable.
 * \return Process result.
 */
bool setJvmtiHookState(bool enable) {
  
  /* Sanity check. */
  if (unlikely(isEnableJvmtiHooking == enable)) {
    
    /* Already set state. */
    return true;
  }
  /* Change state. */
  isEnableJvmtiHooking = enable;
  
  /* Switch JVMTI hooking. */
  if (unlikely(!switchOverrideFunction(jvmti_hook, enable))) {
    
    PRINT_WARN_MSG("Failure switch function overriding. func:JVMTI");
    return false;
  }
  
  return true;
}

/*!
 * \brief Initialization of this util.
 * \param jvmti [in] JVMTI environment object.
 * \return Process result.
 */
bool oopUtilInitialize(jvmtiEnv *jvmti) {
  
  /* Search symbol in libjvm. */
  char *libPath = NULL;
  jvmti->GetSystemProperty("sun.boot.library.path", &libPath);
  try{
    /* Create symbol finder instance. */
    symFinder = new TSymbolFinder();
    if(unlikely(!symFinder->loadLibrary(libPath))){
      throw 0;
    }
    
    /* Cretae VMStruct scanner instance. */
    vmScanner = new TVMStructScanner(symFinder);
  }
  catch(...){
    PRINT_CRIT_MSG("Failure getting symbol information.");
    jvmti->Deallocate((unsigned char *)libPath);
    return false;
  }
  jvmti->Deallocate((unsigned char *)libPath);
  
  /* Setup HotSpot version */
  char *versionStr = NULL;
  if(unlikely(isError(jvmti,
                   jvmti->GetSystemProperty("java.vm.version", &versionStr)))){
    
    PRINT_CRIT_MSG("Failure getting JVM version.");
    return false;
  }
  else{
    unsigned char major  = 0;
    unsigned char minor  = 0;
    unsigned short build = 0;
    int result = 0;
    
    /* Parse version string. */
    result = sscanf(versionStr, "%hhu.%hhu-b%hu", &major, &minor, &build);
    jvmti->Deallocate((unsigned char *)versionStr);
    
    /* If failure parse version string. */
    if(unlikely(result != 3)){
      PRINT_CRIT_MSG("Unsupported JVM version.");
      return false;
    }
    jvmInfo->setHSVersion(MAKE_HS_VERSION(major, minor, build));
  }
  
  /* Search flag symbol in libjvm. */
  if (unlikely(!searchCommonFlags())) {
    PRINT_CRIT_MSG("Failure getting java symbol information.");
    return false;
  }

  /* Search common function symbol in libjvm. */
  if(unlikely(!searchCommonFunction())){
    PRINT_CRIT_MSG("Failure getting java symbol information.");
    return false;
  }
  
  /* Create pthred key for klassOop. */
  if(unlikely(pthread_key_create(&oldKlassOopKey, pThreadKeyDestructor) != 0)){
    PRINT_CRIT_MSG("Failure create pthread key.");
    return false;
  }
  
  if(*useG1){
    if(unlikely(!jvmInfo->isAfterCR7046558())){
      /* Heapstats agent is unsupported G1GC on JDK6. */
      PRINT_CRIT_MSG("Sorry, G1GC isn't supported in this HotSpot version.");
      PRINT_CRIT_MSG("You should use >= 22.0-b03");
      return false;
    }
  }

  return true;
}

/*!
 * \brief Finailization of this util.
 */
void oopUtilFinalize(void) {
  
  /* Cleanup. */
  if (*useG1) {
    delete checkObjectMap;
    checkObjectMap = NULL;
  }
  
  delete vmScanner;
  vmScanner = NULL;
  
  delete symFinder;
  symFinder = NULL;
}

/*!
 * \brief Setup hooking.
 * \warning Please this function call at after Agent_OnLoad.
 * \param funcOnGC     [in] Pointer of GC callback function.
 * \param funcOnJVMTI  [in] Pointer of JVMTI callback function.
 * \param funcOnAdjust [in] Pointer of adjust class callback function.
 * \param funcOnG1GC   [in] Pointer of event callback on G1GC finished.
 * \param maxMemSize   [in] Allocatable maximum memory size of JVM.
 * \return Process result.
 */
bool setupHook(THeapObjectCallback funcOnGC, THeapObjectCallback funcOnJVMTI,
  TKlassAdjustCallback funcOnAdjust, TCommonCallback funcOnG1GC,
  size_t maxMemSize) {
  
  /* Set function. */
  gcCallbackFunc       = funcOnGC;
  jvmtiIteCallbackFunc = funcOnJVMTI;
  adjustCallbackFunc   = funcOnAdjust;
  g1FinishCallbackFunc = funcOnG1GC;
  
  /* Get common function, variable and offset. */
  if (unlikely(!searchCommonInformation())) {
    return false;
  }
  
  /* Get object. */
  collectedHeap = (*(void**)collectedHeap);
  narrowOffsetBase = (ptrdiff_t)*(void**)narrowOffsetBase;
  narrowKlassOffsetBase = (ptrdiff_t)*(void**)narrowKlassOffsetBase;
  
  /* Setup for WatcherThread. */
  if(unlikely(!setupOverrideFunction(watcherThread_hook))){
    PRINT_WARN_MSG("Can't override function. func:WatcherThread");
    return false;
  }
  switchOverrideFunction(watcherThread_hook, true);

   /* Setup for JVMTI. */
  if (unlikely(!setupOverrideFunction(jvmti_hook))) {
    
    PRINT_WARN_MSG("Can't override function. func:JVMTI");
    return false;
  }

  /* Setup for pointer adjustment. */
  if(!jvmInfo->isAfterCR6964458()){
    if(unlikely(!setupOverrideFunction(adj_hook))){
      PRINT_WARN_MSG("Can't override function. func:adj-ptr");
      return false;
    }
  }

  /* Setup by using GC type. */
  
  /* Setup parallel GC and GC by user. */
  if (unlikely(!setupForParallel())) {
    return false;
  }

  /* Setup for inner GC function. */
  if(unlikely(!setupOverrideFunction(innerStart_hook))){
    PRINT_WARN_MSG("Can't override function. func:common");
    return false;
  }
  
  /* Setup each GC type. */
  bool result = (*useParallel);
  if (*useParOld) {
    result = setupForParallelOld();
  } else if (*useCMS) {
    result = setupForCMS();
  } else if (*useG1) {
    result = setupForG1GC(maxMemSize);
  }
  
  return result;
}

/*!
 * \brief Check CMS garbage collector state.
 * \param state        [in]  State of CMS garbage collector.
 * \param gcCause      [in]  String of GC cause.
 * \param needSnapShot [out] Is need snapshot now.
 * \warning Please don't forget call on JVM death.
 */
void checkCMSState(TGCState state, char *gcCause, bool *needSnapShot) {
  
  /* Sanity check. */
  if (unlikely(needSnapShot == NULL)) {
    PRINT_WARN_MSG("Illegal paramter!");
    return;
  }
  
  *needSnapShot = false;
  switch (state) {
    case gcStart:
      /* Call on JVMTI GC start. */
      
      if (*CMS_collectorState <= CMS_IDLING) {
        
        /* Set stored flag of passed sweep phase. */
        *needSnapShot = needSnapShotByCMSPhase;
        needSnapShotByCMSPhase = false;
        
      } else if (*CMS_collectorState == CMS_FINALMARKING) {
        /* switch hooking for CMS new generation. */
        THookFunctionInfo *funcs;
        SELECT_HOOK_FUNCS(funcs, cms_new)
        switchOverrideFunction(funcs, true);
      }
      break;
      
    case gcFinish:
      /* Call on JVMTI GC finished. */
      switch (*CMS_collectorState) {
        case CMS_MARKING:
          /* CMS marking phase. */
          break;
          
        case CMS_SWEEPING:
          /* CMS sweep phase. */
          THookFunctionInfo *funcs;
          SELECT_HOOK_FUNCS(funcs, cms_new)
          switchOverrideFunction(funcs, false);
          needSnapShotByCMSPhase = true;
          
          break;
          
        default:
          /* CMS other phase. */
          const char *notCMSGCCause[] = {
            /* Call by Java.Lang.System. */
            "System.gc()",
            /* Call by JVMTI.            */
            "JvmtiEnv ForceGarbageCollection",
            /* End flag.                 */
            NULL
          };
          
          if (likely(gcCause != NULL)) {
            /* Check this GC. */
            for (int i = 0; notCMSGCCause[i] != NULL; i++) {
              if (strcmp(gcCause, notCMSGCCause[i]) == 0) {
                
                /* GC invoke by user or service without CMS. */
                *needSnapShot = true;
                break;
              }
            }
          }
      }
      break;
      
    case gcLast:
      /* Call on JVM is terminating. */
      
      /* Set stored flag of passed sweep phase. */
      *needSnapShot = needSnapShotByCMSPhase;
      needSnapShotByCMSPhase = false;
      break;
      
    default:
      /* Not reached here. */
      PRINT_WARN_MSG("Illegal GC state.");
  }
}

/*!
 * \brief Setup hooking for inner GC event.
 * \warning Please this function call at after Agent_OnLoad.
 * \param enableHook     [in] Flag of enable hooking to function.
 * \param interruptEvent [in] Event callback on many times GC interupt.
 * \return Process result.
 */
bool setupHookForInnerGCEvent(bool enableHook, TCommonCallback interruptEvent){
  isInvokeGCManyTimes = false;
  gcInterruptCallbackFunc = interruptEvent;

  return switchOverrideFunction(innerStart_hook, enableHook);
}

/*!
 * \brief "is_in_permanent" for after CR6964458.
 *        This function always return false because this CR means PermGen Removal.
 * \param thisptr [in] G1CollectedHeap/GenCollectedHeap/ParallelScavengeHeap
 *                     class instance.
 * \param oop     [in] (C++) Java object.
 * \return always false.
 */
bool is_in_permanent_AfterCR6964458(void *thisptr, void *oop){
  return false;
}