Path: blob/master/runtime/gc_check/CheckReporterTTY.cpp
5985 views
/*******************************************************************************1* Copyright (c) 1991, 2021 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122/**23* @file24* @ingroup GC_Check25*/2627#include "CheckReporterTTY.hpp"2829#include "Base.hpp"30#include "Check.hpp"31#include "CheckBase.hpp"32#include "CheckError.hpp"33#include "ObjectModel.hpp"3435/**36* Human readable strings representing the invokee defined by #GCCheckInvokedBy.37*/38const static char *invokedByStrings[] = {39"unknown", /**<undefined */40"before global GC", /**<J9HOOK_GLOBAL_GC_START */41"after global GC", /**<J9HOOK_GLOBAL_GC_END */42"before global GC sweep", /**<J9HOOK_GLOBAL_GC_SWEEP_START */43"after global GC sweep", /**<J9HOOK_GLOBAL_GC_SWEEP_END */44"before local GC", /**<J9HOOK_LOCAL_GC_START */45"after local GC", /**<J9HOOK_LOCAL_GC_END */46"scavenger backout", /**<J9HOOK_SCAVENGER_BACK_OUT (J9HOOK_LOCAL_GC_END) */47"remembered set overflow", /**<J9HOOK_REMEMBEREDSET_OVERFLOW */48"manual invocation", /**< J9HOOK_INVOKE_GC_CHECK */49"from debugger" /**< via debugger extensions */50};5152/**53* Human readable error strings corresponding to54* @ref GCCheckWalkStageErrorCodes from the various walk stages.55* Offset into this table is determined by error code returned by methods such as GC_Check::checkJ9ObjectPointer56*/57const static char *errorTypes[] = {58"no error", /* J9MODRON_GCCHK_RC_OK (0) */59"not aligned", /* J9MODRON_GCCHK_RC_UNALIGNED (1) */60"double array not aligned", /* J9MODRON_GCCHK_RC_DOUBLE_ARRAY_UNALIGNED (2) */61"object not in an object region", /* J9MODRON_GCCHK_RC_NOT_IN_OBJECT_REGION (3) */62"not in an object segment", /* J9MODRON_GCCHK_RC_NOT_FOUND (4) */63"overlaps segment boundary", /* J9MODRON_GCCHK_RC_INVALID_RANGE (5) */64"heap object on stack", /* J9MODRON_GCCHK_RC_STACK_OBJECT (6) */65"class pointer is null", /* J9MODRON_GCCHK_RC_NULL_CLASS_POINTER (7)*/66"class pointer not aligned", /* J9MODRON_GCCHK_RC_CLASS_POINTER_UNALIGNED (8)*/67"class pointer not in a class segment", /* J9MODRON_GCCHK_RC_CLASS_NOT_FOUND (9)*/68"class pointer overlaps segment boundary", /* J9MODRON_GCCHK_RC_CLASS_INVALID_RANGE (10) */69"class pointer of class is not java.lang.Class", /* J9MODRON_GCCHK_RC_CLASS_POINTER_NOT_JLCLASS (11) */70"class pointer on stack", /* J9MODRON_GCCHK_RC_CLASS_STACK_OBJECT (12) */71"invalid flags", /* J9MODRON_GCCHK_RC_INVALID_FLAGS (13) */72"in an old segment, old bit not set", /* J9MODRON_GCCHK_RC_OLD_SEGMENT_INVALID_FLAGS (14) */73"in a new segment, old or remembered bit set", /* J9MODRON_GCCHK_RC_NEW_SEGMENT_INVALID_FLAGS (15) */74"size of hole is too large or 0", /* J9MODRON_GCCHK_RC_DEAD_OBJECT_SIZE (16) */75"new pointer in old object without remembered bit set", /* J9MODRON_GCCHK_RC_NEW_POINTER_NOT_REMEMBERED (17) */76"not in an old segment or class segment", /* J9MODRON_GCCHK_RC_REMEMBERED_SET_WRONG_SEGMENT (18) */77"old bit or remembered bit not set", /* J9MODRON_GCCHK_RC_REMEMBERED_SET_FLAGS (19) */78"not in remembered set, new object reference", /* J9MODRON_GCCHK_RC_REMEMBERED_SET_OLD_OBJECT (20) */79"unused 21", /* J9MODRON_GCCHK_RC_UNUSED_21 (21) */80"unused 22", /* J9MODRON_GCCHK_RC_UNUSED_22 (22) */81"heap object has remembered bit set when cardtable active", /* J9MODRON_GCCHK_RC_HEAP_OBJECT_REMEMBERED (23) */82"new pointer in old object without card dirtied", /* J9MODRON_GCCHK_RC_NEW_POINTER_NOT_REMEMBERED_IN_CARD_TABLE (24) */83"dead object", /* J9MODRON_GCCHK_RC_DEAD_OBJECT (25) */84"class header invalid", /* J9MODRON_GCCHK_RC_J9CLASS_HEADER_INVALID (26) */85"class object not java.lang.Class", /* J9MODRON_GCCHK_RC_CLASS_OBJECT_NOT_JLCLASS (27) */86"scope internal pointer refers outside its scope", /* J9MODRON_GCCHK_RC_INTERNAL_POINTER_NOT_IN_SCOPE (28) */87"class pointer is in an undead class segment", /* J9MODRON_GCCHK_RC_CLASS_IS_UNDEAD (29) */88"class ramStatics field points to wrong object", /* J9MODRON_GCCHK_RC_CLASS_STATICS_FIELD_POINTS_WRONG_OBJECT (30) */89"class ramStatics must be NULL for hot swapped class", /* J9MODRON_GCCHK_RC_CLASS_HOT_SWAPPED_POINTS_TO_STATICS (31) */90"class ramStatics field points to object but out of GC scan range", /* J9MODRON_GCCHK_RC_CLASS_STATICS_REFERENCE_IS_NOT_IN_SCANNING_RANGE (32) */91"class ramStatics number of references not equal specified in ROM class", /* J9MODRON_GCCHK_RC_CLASS_STATICS_WRONG_NUMBER_OF_REFERENCES (33) */92"invalid indexable data address", /* J9MODRON_GCCHK_RC_INVALID_INDEXABLE_DATA_ADDRESS (34) */93"obsolete code 35", /* obsolete code (35) */94"obsolete code 36", /* obsolete code (36) */95"obsolete code 37", /* obsolete code (37) */96"class object not a subclass of java.util.concurrent.locks.AbstractOwnableSynchronizer", /* J9MODRON_GCCHK_RC_OWNABLE_SYNCHRONIZER_INVALID_CLASS (38) */97"array class can not be hot swapped", /* J9MODRON_GCCHK_RC_CLASS_HOT_SWAPPED_FOR_ARRAY (39) */98"replaced class has no hot swapped out flag set", /* J9MODRON_GCCHK_RC_REPLACED_CLASS_HAS_NO_HOTSWAP_FLAG (40) */99"object slot appears to contain a J9Class pointer", /* J9MODRON_GCCHK_RC_OBJECT_SLOT_POINTS_TO_J9CLASS (41) */100"Ownable Synchronizer Object is not attached to the list", /* J9MODRON_GCCHK_OWNABLE_SYNCHRONIZER_OBJECT_IS_NOT_ATTACHED_TO_THE_LIST (42) */101"Ownable Synchronizer List has a circular reference", /* J9MODRON_GCCHK_OWNABLE_SYNCHRONIZER_LIST_HAS_CIRCULAR_REFERENCE (43) */102"hole size is not aligned", /* J9MODRON_GCCHK_RC_DEAD_OBJECT_SIZE_NOT_ALIGNED (44) */103"hole next is not a hole", /* J9MODRON_GCCHK_RC_DEAD_OBJECT_NEXT_IS_NOT_HOLE (45) */104"hole next is outside of current region", /* J9MODRON_GCCHK_RC_DEAD_OBJECT_NEXT_IS_NOT_IN_REGION (46) */105"hole next is pointed inside of the hole", /* J9MODRON_GCCHK_RC_DEAD_OBJECT_NEXT_IS_POINTED_INSIDE (47) */106"class is unloaded", /* J9MODRON_GCCHK_RC_CLASS_IS_UNLOADED (48)*/107};108109/**110* Create a new instance of the report object, using the specified port library.111*/112GC_CheckReporterTTY *113GC_CheckReporterTTY::newInstance(J9JavaVM *javaVM)114{115MM_Forge *forge = MM_GCExtensions::getExtensions(javaVM)->getForge();116117GC_CheckReporterTTY *reporter = (GC_CheckReporterTTY *)forge->allocate(sizeof(GC_CheckReporterTTY), MM_AllocationCategory::DIAGNOSTIC, J9_GET_CALLSITE());118if (reporter) {119reporter = new(reporter) GC_CheckReporterTTY(javaVM);120}121return reporter;122}123124/**125* Destroy the instance of the reporter.126*/127void128GC_CheckReporterTTY::kill()129{130MM_Forge *forge = MM_GCExtensions::getExtensions(_javaVM)->getForge();131forge->free(this);132}133134/**135* Report an error to the terminal.136*137* Accepts an error object and outputs a report to the terminal.138* @param error The error to be reported139*/140void141GC_CheckReporterTTY::report(GC_CheckError *error)142{143PORT_ACCESS_FROM_PORT(_portLibrary);144145if (!shouldReport(error)) {146return;147}148149/* If slot is NULL, we are not scanning the slots of an object, but looking directly at an object/class on the heap. */150if (error->_slot) {151const void *slot = error->_slot;152UDATA slotValue;153154if (error->_objectType == check_type_object) {155GC_SlotObject slotObj(_javaVM->omrVM, (fomrobject_t*)slot);156slotValue = (UDATA)slotObj.readReferenceFromSlot();157} else {158if (error->_objectType == check_type_thread) {159/* slots from thread stacks are always local */160slotValue = *((UDATA*)slot);161slot = error->_stackLocaition;162} else if(error->_objectType == check_type_unfinalized) {163slotValue = *((UDATA*)slot);164} else if(error->_objectType == check_type_finalizable) {165slotValue = *((UDATA*)slot);166} else if(error->_objectType == check_type_ownable_synchronizer) {167slotValue = *((UDATA*)slot);168} else {169slotValue = *((UDATA*)slot);170}171}172173if (invocation_manual == error->_cycle->getInvoker()) {174j9tty_printf(PORTLIB, " <gc check (%zu): %s (%zu): %s: %sslot %p(%p) -> %p: %s>\n", error->_errorNumber, invokedByStrings[error->_cycle->getInvoker()], error->_cycle->getManualCheckNumber(), error->_check->getCheckName(), error->_elementName, error->_object, slot, slotValue, errorTypes[error->_errorCode]);175} else {176j9tty_printf(PORTLIB, " <gc check (%zu): %s: %s: %sslot %p(%p) -> %p: %s>\n", error->_errorNumber, invokedByStrings[error->_cycle->getInvoker()], error->_check->getCheckName(), error->_elementName, error->_object, slot, slotValue, errorTypes[error->_errorCode]);177}178} else {179if (invocation_manual == error->_cycle->getInvoker()) {180j9tty_printf(PORTLIB, " <gc check (%zu): %s (%zu): %s: %s%p: %s>\n", error->_errorNumber, invokedByStrings[error->_cycle->getInvoker()], error->_cycle->getManualCheckNumber(), error->_check->getCheckName(), error->_elementName, error->_object, errorTypes[error->_errorCode]);181} else {182j9tty_printf(PORTLIB, " <gc check (%zu): %s: %s: %s%p: %s>\n", error->_errorNumber, invokedByStrings[error->_cycle->getInvoker()], error->_check->getCheckName(), error->_elementName, error->_object, errorTypes[error->_errorCode]);183}184185/* If the basic checks have been made (alignment, etc.) display header info. */186if (error->_objectType == check_type_object) {187reportObjectHeader(error, (J9Object*)error->_object, "");188}189}190}191192/**193* Print an object header to the terminal.194*195* @param objectPtr the object whose header to print196* @param prefix a string to prefix the object with, e.g. "Previous", or NULL197* if no prefix is desired198*/199void200GC_CheckReporterTTY::reportObjectHeader(GC_CheckError *error, J9Object *objectPtr, const char *prefix)201{202MM_GCExtensionsBase* extensions = MM_GCExtensions::getExtensions(_javaVM);203const char *prefixString = prefix ? prefix : "";204UDATA headerSize = 0;205PORT_ACCESS_FROM_PORT(_portLibrary);206207if (!shouldReport(error)) {208return;209}210211if (extensions->objectModel.isDeadObject(objectPtr)) {212j9tty_printf(PORTLIB, " <gc check (%zu): %sHole %p header:", error->_errorNumber, prefixString, objectPtr);213headerSize = (UDATA)sizeof(MM_HeapLinkedFreeHeader);214} else {215const char *elementName = (UDATA) extensions->objectModel.isIndexable(objectPtr) ? "IObject" : "Object";216j9tty_printf(PORTLIB, " <gc check (%zu): %s%s %p header:", error->_errorNumber, prefixString, elementName, objectPtr);217headerSize = extensions->objectModel.getHeaderSize(objectPtr);218}219220U_32* cursor = (U_32*) objectPtr;221for (UDATA i = 0; i < headerSize / sizeof(U_32); i++) {222j9tty_printf(PORTLIB, " %08X", *cursor);223cursor++;224}225226j9tty_printf(PORTLIB, ">\n");227}228229/**230* Print a class to the terminal.231*232* @param clazz the class to print233* @param prefix a string to prefix the class with, e.g. "Previous", or NULL234* if no prefix is desired235*/236void237GC_CheckReporterTTY::reportClass(GC_CheckError *error, J9Class *clazz, const char *prefix)238{239const char *prefixString = prefix ? prefix : "";240PORT_ACCESS_FROM_PORT(_portLibrary);241242if (!shouldReport(error)) {243return;244}245246j9tty_printf(PORTLIB, " <gc check (%zu): %sClass %p>\n",247error->_errorNumber,248prefixString,249clazz);250}251252/**253* Report the fact that a fatal error has occurred.254*/255void256GC_CheckReporterTTY::reportFatalError(GC_CheckError *error)257{258PORT_ACCESS_FROM_PORT(_portLibrary);259260j9tty_printf(PORTLIB, " <gc check (%zu): Cannot resolve problem detected on heap, aborting check>\n", error->_errorNumber);261}262263/**264* Print to the terminal that an error has occurred while walking the heap.265*/266void267GC_CheckReporterTTY::reportHeapWalkError(GC_CheckError *error, GC_CheckElement previousObjectPtr1, GC_CheckElement previousObjectPtr2, GC_CheckElement previousObjectPtr3)268{269PORT_ACCESS_FROM_PORT(_portLibrary);270271reportFatalError(error);272if (previousObjectPtr1.type != GC_CheckElement::type_none) {273reportGenericType(error, previousObjectPtr1, "Previous ");274if(previousObjectPtr2.type != GC_CheckElement::type_none) {275reportGenericType(error, previousObjectPtr2, "Previous ");276if(previousObjectPtr3.type != GC_CheckElement::type_none) {277reportGenericType(error, previousObjectPtr3, "Previous ");278}279}280} else {281j9tty_printf(PORTLIB, " <gc check (%zu): %p was first object encountered on heap>\n", error->_errorNumber, error->_object);282}283}284285286287