Path: blob/master/src/java.desktop/share/native/common/awt/debug/debug_trace.c
41171 views
/*1* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include "debug_util.h"2627static void JNICALL DTrace_PrintStdErr(const char *msg);2829#if defined(DEBUG)30enum {31MAX_TRACES = 200, /* max number of defined trace points allowed */32MAX_TRACE_BUFFER = 512, /* maximum size of a given trace output */33MAX_LINE = 100000, /* reasonable upper limit on line number in source file */34MAX_ARGC = 8 /* maximum number of arguments to print functions */35};3637typedef enum dtrace_scope {38DTRACE_FILE,39DTRACE_LINE40} dtrace_scope;4142typedef struct dtrace_info {43char file[FILENAME_MAX+1];44int line;45int enabled;46dtrace_scope scope;47} dtrace_info, * p_dtrace_info;4849static dtrace_info DTraceInfo[MAX_TRACES];50static char DTraceBuffer[MAX_TRACE_BUFFER*2+1]; /* double the buffer size to catch overruns */51static dmutex_t DTraceMutex = NULL;52static dbool_t GlobalTracingEnabled = FALSE;53static int NumTraces = 0;5455static DTRACE_OUTPUT_CALLBACK PfnTraceCallback = DTrace_PrintStdErr;5657static p_dtrace_info DTrace_GetInfo(dtrace_id tid) {58DASSERT(tid < MAX_TRACES);59return &DTraceInfo[tid];60}6162static dtrace_id DTrace_CreateTraceId(const char * file, int line, dtrace_scope scope) {63dtrace_id tid = NumTraces++;64p_dtrace_info info = &DTraceInfo[tid];65DASSERT(NumTraces < MAX_TRACES);6667strcpy(info->file, file);68info->line = line;69info->enabled = FALSE;70info->scope = scope;71return tid;72}7374/*75* Compares the trailing characters in a filename to see if they match76* e.g. "src\win32\foobar.c" and "foobar.c" would be considered equal77* but "src\win32\foo.c" and "src\win32\bar.c" would not.78*/79static dbool_t FileNamesSame(const char * fileOne, const char * fileTwo) {80size_t lengthOne = strlen(fileOne);81size_t lengthTwo = strlen(fileTwo);82size_t numCompareChars;83dbool_t tailsEqual;8485if (fileOne == fileTwo) {86return TRUE;87} else if (fileOne == NULL || fileTwo == NULL) {88return FALSE;89}90/* compare the tail ends of the strings for equality */91numCompareChars = lengthOne < lengthTwo ? lengthOne : lengthTwo;92tailsEqual = strcmp(fileOne + lengthOne - numCompareChars,93fileTwo + lengthTwo - numCompareChars) == 0;94return tailsEqual;95}9697/*98* Finds the trace id for a given file/line location or creates one99* if it doesn't exist100*/101static dtrace_id DTrace_GetTraceId(const char * file, int line, dtrace_scope scope) {102dtrace_id tid;103p_dtrace_info info;104105/* check to see if the trace point has already been created */106for ( tid = 0; tid < NumTraces; tid++ ) {107info = DTrace_GetInfo(tid);108if ( info->scope == scope ) {109dbool_t sameFile = FileNamesSame(file, info->file);110dbool_t sameLine = info->line == line;111112if ( (info->scope == DTRACE_FILE && sameFile) ||113(info->scope == DTRACE_LINE && sameFile && sameLine) ) {114goto Exit;115}116}117}118119/* trace point wasn't created, so force it's creation */120tid = DTrace_CreateTraceId(file, line, scope);121Exit:122return tid;123}124125126static dbool_t DTrace_IsEnabledAt(dtrace_id * pfileid, dtrace_id * plineid, const char * file, int line) {127DASSERT(pfileid != NULL && plineid != NULL);128129if ( *pfileid == UNDEFINED_TRACE_ID ) {130/* first time calling the trace for this file, so obtain a trace id */131*pfileid = DTrace_GetTraceId(file, -1, DTRACE_FILE);132}133if ( *plineid == UNDEFINED_TRACE_ID ) {134/* first time calling the trace for this line, so obtain a trace id */135*plineid = DTrace_GetTraceId(file, line, DTRACE_LINE);136}137138return GlobalTracingEnabled || DTraceInfo[*pfileid].enabled || DTraceInfo[*plineid].enabled;139}140141/*142* Initialize trace functionality. This MUST BE CALLED before any143* tracing function is called.144*/145void DTrace_Initialize() {146DTraceMutex = DMutex_Create();147}148149/*150* Cleans up tracing system. Should be called when tracing functionality151* is no longer needed.152*/153void DTrace_Shutdown() {154DMutex_Destroy(DTraceMutex);155}156157void DTrace_DisableMutex() {158DTraceMutex = NULL;159}160161/*162* Enable tracing for all modules.163*/164void DTrace_EnableAll(dbool_t enabled) {165DMutex_Enter(DTraceMutex);166GlobalTracingEnabled = enabled;167DMutex_Exit(DTraceMutex);168}169170/*171* Enable tracing for a specific module. Filename may172* be fully or partially qualified.173* e.g. awt_Component.cpp174* or175* src\win32\native\sun\windows\awt_Component.cpp176*/177void DTrace_EnableFile(const char * file, dbool_t enabled) {178dtrace_id tid;179p_dtrace_info info;180181DASSERT(file != NULL);182DMutex_Enter(DTraceMutex);183tid = DTrace_GetTraceId(file, -1, DTRACE_FILE);184info = DTrace_GetInfo(tid);185info->enabled = enabled;186DMutex_Exit(DTraceMutex);187}188189/*190* Enable tracing for a specific line in a specific module.191* See comments above regarding filename argument.192*/193void DTrace_EnableLine(const char * file, int line, dbool_t enabled) {194dtrace_id tid;195p_dtrace_info info;196197DASSERT(file != NULL && (line > 0 && line < MAX_LINE));198DMutex_Enter(DTraceMutex);199tid = DTrace_GetTraceId(file, line, DTRACE_LINE);200info = DTrace_GetInfo(tid);201info->enabled = enabled;202DMutex_Exit(DTraceMutex);203}204205static void DTrace_ClientPrint(const char * msg) {206DASSERT(msg != NULL && PfnTraceCallback != NULL);207(*PfnTraceCallback)(msg);208}209210/*211* Print implementation for the use of client defined trace macros. Unsynchronized so it must212* be used from within a DTRACE_PRINT_CALLBACK function.213*/214void DTrace_VPrintImpl(const char * fmt, va_list arglist) {215DASSERT(fmt != NULL);216217/* format the trace message */218vsprintf(DTraceBuffer, fmt, arglist);219/* not a real great overflow check (memory would already be hammered) but better than nothing */220DASSERT(strlen(DTraceBuffer) < MAX_TRACE_BUFFER);221/* output the trace message */222DTrace_ClientPrint(DTraceBuffer);223}224225/*226* Print implementation for the use of client defined trace macros. Unsynchronized so it must227* be used from within a DTRACE_PRINT_CALLBACK function.228*/229void DTrace_PrintImpl(const char * fmt, ...) {230va_list arglist;231232va_start(arglist, fmt);233DTrace_VPrintImpl(fmt, arglist);234va_end(arglist);235}236237/*238* Called via DTRACE_PRINT macro. Outputs printf style formatted text.239* JNIEXPORT because these functions are also called from libawt_xawt.240*/241JNIEXPORT void JNICALL242DTrace_VPrint( const char * file, int line, int argc, const char * fmt, va_list arglist ) {243DASSERT(fmt != NULL);244DTrace_VPrintImpl(fmt, arglist);245}246247/*248* Called via DTRACE_PRINTLN macro. Outputs printf style formatted text with an automatic newline.249* JNIEXPORT because these functions are also called from libawt_xawt.250*/251JNIEXPORT void JNICALL252DTrace_VPrintln( const char * file, int line, int argc, const char * fmt, va_list arglist ) {253DTrace_VPrintImpl(fmt, arglist);254DTrace_PrintImpl("\n");255}256257/*258* Called via DTRACE_ macros. If tracing is enabled at the given location, it enters259* the trace mutex and invokes the callback function to output the trace.260* JNIEXPORT because these functions are also called from libawt_xawt.261*/262JNIEXPORT void JNICALL263DTrace_PrintFunction( DTRACE_PRINT_CALLBACK pfn, dtrace_id * pFileTraceId, dtrace_id * pLineTraceId,264const char * file, int line,265int argc, const char * fmt, ... ) {266va_list arglist;267268DASSERT(file != NULL);269DASSERT(line > 0 && line < MAX_LINE);270DASSERT(argc <= MAX_ARGC);271DASSERT(fmt != NULL);272273DMutex_Enter(DTraceMutex);274if ( DTrace_IsEnabledAt(pFileTraceId, pLineTraceId, file, line) ) {275va_start(arglist, fmt);276(*pfn)(file, line, argc, fmt, arglist);277va_end(arglist);278}279DMutex_Exit(DTraceMutex);280}281282/*283* Sets a callback function to be used to output284* trace statements.285*/286void DTrace_SetOutputCallback(DTRACE_OUTPUT_CALLBACK pfn) {287DASSERT(pfn != NULL);288289DMutex_Enter(DTraceMutex);290PfnTraceCallback = pfn;291DMutex_Exit(DTraceMutex);292}293294#endif /* DEBUG */295296/**********************************************************************************297* Support for Java tracing in release or debug mode builds298*/299300static void JNICALL DTrace_PrintStdErr(const char *msg) {301fprintf(stderr, "%s", msg);302fflush(stderr);303}304305static void DTrace_JavaPrint(const char * msg) {306#if defined(DEBUG)307DMutex_Enter(DTraceMutex);308DTrace_ClientPrint(msg);309DMutex_Exit(DTraceMutex);310#else311DTrace_PrintStdErr(msg);312#endif313}314315static void DTrace_JavaPrintln(const char * msg) {316#if defined(DEBUG)317DMutex_Enter(DTraceMutex);318DTrace_ClientPrint(msg);319DTrace_ClientPrint("\n");320DMutex_Exit(DTraceMutex);321#else322DTrace_PrintStdErr(msg);323DTrace_PrintStdErr("\n");324#endif325}326327/*********************************************************************************328* Native method implementations. Java print trace calls are functional in329* release builds, but functions to enable/disable native tracing are not.330*/331332/* Implementation of DebugSettings.setCTracingOn*/333JNIEXPORT void JNICALL334Java_sun_awt_DebugSettings_setCTracingOn__Z(JNIEnv *env, jobject self, jboolean enabled) {335#if defined(DEBUG)336DTrace_EnableAll(enabled == JNI_TRUE);337#endif338}339340/* Implementation of DebugSettings.setCTracingOn*/341JNIEXPORT void JNICALL342Java_sun_awt_DebugSettings_setCTracingOn__ZLjava_lang_String_2(343JNIEnv *env,344jobject self,345jboolean enabled,346jstring file ) {347#if defined(DEBUG)348const char * cfile;349cfile = JNU_GetStringPlatformChars(env, file, NULL);350if ( cfile == NULL ) {351return;352}353DTrace_EnableFile(cfile, enabled == JNI_TRUE);354JNU_ReleaseStringPlatformChars(env, file, cfile);355#endif356}357358/* Implementation of DebugSettings.setCTracingOn*/359JNIEXPORT void JNICALL360Java_sun_awt_DebugSettings_setCTracingOn__ZLjava_lang_String_2I(361JNIEnv *env,362jobject self,363jboolean enabled,364jstring file,365jint line ) {366#if defined(DEBUG)367const char * cfile;368cfile = JNU_GetStringPlatformChars(env, file, NULL);369if ( cfile == NULL ) {370return;371}372DTrace_EnableLine(cfile, line, enabled == JNI_TRUE);373JNU_ReleaseStringPlatformChars(env, file, cfile);374#endif375}376377378