blob: ec72423292381e3104f9b2a5f6e100f1a980f3d9 [file] [log] [blame]
/*
* Copyright (c) 2013-2017, Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
//!
//! \file mos_util_debug_specific.c
//! \brief This module implments Linux MOS debug functionalities
//!
#include "mos_util_debug.h"
#if MOS_MESSAGES_ENABLED
#include "mos_utilities_specific.h"
#include "mos_utilities.h"
#include "string.h"
#include <time.h> //get_clocktime
#include <unistd.h> //read, lseek
#include <fcntl.h> //open
#ifdef ANDROID
#include <android/log.h>
#else
#include <signal.h>
#endif // ANDROID
extern int32_t MOS_ShouldPrintMessage(
MOS_MESSAGE_LEVEL level,
MOS_COMPONENT_ID compID,
uint8_t subCompID,
const PCCHAR message);
//!
//! \brief HLT log file prefix
//!
const PCCHAR MosLogPathPrefix = "/etc/log";
const PCCHAR MosUltLogPathPrefix = "./";
extern MOS_MESSAGE_PARAMS g_MosMsgParams;
extern uint8_t MosUltFlag;
static MOS_MUTEX gMosMsgMutex = PTHREAD_MUTEX_INITIALIZER;
/*----------------------------------------------------------------------------
| Name : MOS_HltpCopyFile
| Purpose : Copy all file content from the source file to the target file.
| Arguments : szFileName - source file name to copy from
| pFile - target file
| Returns : Returns one of the MOS_STATUS error codes if failed,
| else MOS_STATUS_SUCCESS
| Comments :
\---------------------------------------------------------------------------*/
#define HLT_COPY_BUFFER_LENGTH 200
static MOS_STATUS MOS_HltpCopyFile(PFILE pFile, const PCCHAR szFileName)
{
PFILE pFileSrc;
char szBuffer[HLT_COPY_BUFFER_LENGTH];
int32_t nRead;
nRead = 0;
if( (pFileSrc = fopen(szFileName , "r" )) == nullptr)
{
printf("open file %s failed", szFileName);
return MOS_STATUS_FILE_OPEN_FAILED;
}
do
{
nRead = fread(szBuffer, 1, HLT_COPY_BUFFER_LENGTH, pFileSrc);
if( ( nRead > 0 ) && (nRead <= HLT_COPY_BUFFER_LENGTH) )
{
fwrite(szBuffer, 1, nRead, pFile);
}
} while( nRead > 0 );
fclose(pFileSrc);
return MOS_STATUS_SUCCESS;
}
/*----------------------------------------------------------------------------
| Name : MOS_HltpPreface
| Purpose : Add preface information to the HLT log when initialized
| Arguments : pFile - Pointer to the log file
| Returns : None
| Comments :
\---------------------------------------------------------------------------*/
void MOS_HltpPreface(PFILE pFile)
{
time_t rawtime;
struct tm* timeinfo;
time(&rawtime);
timeinfo = localtime(&rawtime);
if (timeinfo == nullptr)
{
printf("fail to call localtime in MOS_HltpPreface\n");
return;
}
fprintf(pFile, "//\n"
"// HLT log file: version1.0\n"
"// Logtime %d-%d-%d %d:%d:%d; Machine=",
timeinfo->tm_year,timeinfo->tm_mon, timeinfo->tm_yday,
timeinfo->tm_hour,timeinfo->tm_min,timeinfo->tm_sec);
fwrite("\n", 1, 1, pFile);
MOS_HltpCopyFile(pFile, "/etc/hosts");
// This section has been temporarily commented out because it's printing a non standard character to the logfile and corrupting it.
/*
fprintf(pFile, "\n"
"// PID=%d; Process name=",
getpid());
MOS_HltpCopyFile(pFile, "/proc/self/cmdline");
*/
fwrite("\n", 1, 1, pFile);
MOS_HltpCopyFile(pFile, "/proc/version");
// Linux version 2.6.35-22-generic (buildd@rothera) (gcc version 4.4.5 (Ubuntu/Linaro // 4.4.4-14ubuntu4) ) #33-Ubuntu SMP Sun Sep 19 20:34:50 UTC 2010
if(g_MosMsgParams.bEnableMaps)
{
fwrite("\n// Loaded modules:\n", 20, 1, pFile);
MOS_HltpCopyFile(pFile, "/proc/self/maps");
fwrite("\n", 1, 1, pFile);
}
fflush(pFile);
}
//!
//! \brief Form a string that will prefix MOS's log file name
//! \details Form a string that will prefix MOS's log file name
//! MosLogPathPrefix defines the system directory that
//! Mos uses to prefix the log filename by default.
//! \param char *fileNamePrefix
//! [out] Pointer to the string where the prefix is returned
//! \return MOS_STATUS
//! Returns one of the MOS_STATUS error codes if failed,
//! else MOS_STATUS_SUCCESS
//!
MOS_STATUS MOS_LogFileNamePrefix(char *fileNamePrefix)
{
int32_t iRet = 0;
MOS_USER_FEATURE_VALUE_DATA UserFeatureData;
MOS_USER_FEATURE_VALUE_WRITE_DATA UserFeatureWriteData;
MOS_STATUS eStatus = MOS_STATUS_UNKNOWN;
if (MosUltFlag)
{
iRet = MOS_SecureStringPrint(
fileNamePrefix,
MOS_MAX_HLT_FILENAME_LEN,
MOS_MAX_HLT_FILENAME_LEN,
MosUltLogPathPrefix);
if (iRet == 0)
{
eStatus = MOS_STATUS_SUCCESS;
}
return eStatus;
}
MOS_ZeroMemory(&UserFeatureData, sizeof(UserFeatureData));
UserFeatureData.StringData.pStringData = fileNamePrefix;
eStatus = MOS_UserFeature_ReadValue_ID(
nullptr,
__MOS_USER_FEATURE_KEY_MESSAGE_HLT_OUTPUT_DIRECTORY_ID,
&UserFeatureData);
// If the user feature key was not found, create it with the default value.
if (eStatus != MOS_STATUS_SUCCESS)
{
iRet = MOS_SecureStringPrint(
fileNamePrefix,
MOS_MAX_HLT_FILENAME_LEN,
MOS_MAX_HLT_FILENAME_LEN,
MosLogPathPrefix);
if (iRet == 0)
{
MOS_ZeroMemory(&UserFeatureWriteData, sizeof(UserFeatureWriteData));
UserFeatureWriteData.Value.StringData.pStringData = fileNamePrefix;
UserFeatureWriteData.Value.StringData.uSize = strlen(fileNamePrefix) + 1;
UserFeatureWriteData.ValueID = __MOS_USER_FEATURE_KEY_MESSAGE_HLT_OUTPUT_DIRECTORY_ID;
eStatus = MOS_UserFeature_WriteValues_ID(nullptr, &UserFeatureWriteData, 1);
}
else
{
return MOS_STATUS_UNKNOWN;
}
}
return eStatus;
}
//!
//! \brief Prints debug messages when enabled
//! \details Prints debug messages if prints are enabled and the level of the comp and sub-comp is
//! set to less than the message level.
//! \param MOS_MESSAGE_LEVEL level
//! [in] Level of the message
//! \param const PCCHAR logtag
//! [in] For Linux only, used for tagging the message.
//! \param MOS_COMPONENT_ID compID
//! [in] Indicates which component
//! \param uint8_t subCompID
//! [in] Indicates which sub-component
//! \param const char *functionName
//! [in] pointer to the function name
//! \param int32_t lineNum
//! [in] Indicates which line the message locate, -1 for no line output
//! \param const char *message
//! [in] pointer to the message format string
//! \param var_args
//! [in] variable list of arguments for the message
//! \return void
//!
void MOS_Message(
MOS_MESSAGE_LEVEL level,
const PCCHAR logtag,
MOS_COMPONENT_ID compID,
uint8_t subCompID,
const PCCHAR functionName,
int32_t lineNum,
const PCCHAR message,
...)
{
va_list var_args;
uint32_t nLen = 0;
PCCHAR func = functionName;
if (MOS_ShouldPrintMessage(level, compID, subCompID, message) == false)
{
return;
}
va_start(var_args, message);
MOS_LockMutex(&gMosMsgMutex);
// Proceed to print the message
if (functionName == nullptr)
{
MOS_SecureStringPrint(g_MosMsgParams.g_MosMsgBuffer,
MOS_MAX_MSG_BUF_SIZE,
(MOS_MAX_MSG_BUF_SIZE-1),
"%s%s - ",
MOS_ComponentName[compID],
MOS_LogLevelName[level]);
nLen = strlen(g_MosMsgParams.g_MosMsgBuffer);
}
else
{
#if USE_PRETTY_FUNCTION
PCCHAR MOS_getClassMethod(PCCHAR pcPrettyFunction);
// call MOS_getClassMethod to convert pretty function to class::function
// return string locate in static memory, mutex should be hold.
func = MOS_getClassMethod(functionName);
#endif //USE_PRETTY_FUNCTION
if (lineNum < 0)
{
// no line number output
MOS_SecureStringPrint(g_MosMsgParams.g_MosMsgBuffer,
MOS_MAX_MSG_BUF_SIZE,
(MOS_MAX_MSG_BUF_SIZE-1),
"%s%s - %s",
MOS_ComponentName[compID],
MOS_LogLevelName[level],
func);
nLen = strlen(g_MosMsgParams.g_MosMsgBuffer);
}
else
{
MOS_SecureStringPrint(g_MosMsgParams.g_MosMsgBuffer,
MOS_MAX_MSG_BUF_SIZE,
(MOS_MAX_MSG_BUF_SIZE-1),
"%s%s - %s:%d: ",
MOS_ComponentName[compID],
MOS_LogLevelName[level],
func,
lineNum);
nLen = strlen(g_MosMsgParams.g_MosMsgBuffer);
}
}
MOS_SecureVStringPrint(g_MosMsgParams.g_MosMsgBuffer + nLen,
MOS_MAX_MSG_BUF_SIZE - nLen,
(MOS_MAX_MSG_BUF_SIZE - 1 - nLen),
message,
var_args);
// Dump message to debugger if print to output window enabled
if (g_MosMsgParams.bUseOutputDebugString)
{
#ifdef ANDROID
int android_level;
switch (level)
{
case MOS_MESSAGE_LVL_CRITICAL:
android_level = ANDROID_LOG_ERROR;
break;
case MOS_MESSAGE_LVL_NORMAL:
android_level = ANDROID_LOG_DEBUG;
break;
case MOS_MESSAGE_LVL_VERBOSE:
android_level = ANDROID_LOG_VERBOSE;
break;
case MOS_MESSAGE_LVL_FUNCTION_ENTRY:
case MOS_MESSAGE_LVL_FUNCTION_EXIT:
case MOS_MESSAGE_LVL_FUNCTION_ENTRY_VERBOSE:
case MOS_MESSAGE_LVL_FUNCTION_EXIT_VERBOSE:
default:
android_level = ANDROID_LOG_INFO;
break;
}
__android_log_print(android_level, logtag, "%s\n", g_MosMsgParams.g_MosMsgBuffer);
#else // ANDROID
printf("%s\n", g_MosMsgParams.g_MosMsgBuffer);
#endif // ANDROID
}
// Write to log file if HLT enabled. File already open to add preface information
if (g_MosMsgParams.bUseHybridLogTrace)
{
if (g_MosMsgParams.pLogFile != nullptr)
{
nLen = strlen(g_MosMsgParams.g_MosMsgBuffer);
fwrite(g_MosMsgParams.g_MosMsgBuffer, nLen, 1, g_MosMsgParams.pLogFile);
fprintf(g_MosMsgParams.pLogFile, "\n");
}
else
{
#ifdef ANDROID
__android_log_print(ANDROID_LOG_ERROR, logtag, "ERROR: g_MosMsgParams.pLogFile is NULL!");
#else // ANDROID
printf("ERROR: g_MosMsgParams.pLogFile is NULL!\n");
#endif // ANDROID
}
}
MOS_UnlockMutex(&gMosMsgMutex);
va_end(var_args);
}
//!
//! When printing from a C++ class, we'd like the class and function to be printed.
//! With our current Linux compiler, __FUNCTION__ does not include the class name.
//! So we use __PRETTY_FUNCTION__ and call MOS_getClassMethod(__PRETTY_FUNCTION__) to remove extra data.
//! This is not needed for prints from C files so they will usually use __FUNCTION__.
//!
#if USE_PRETTY_FUNCTION
//!
//! gFunctionName is used to temporarily store the concatinated __PRETTY_FUNCTION__,
//! when calling MOS_getClassMethod().
//!
static char gFunctionName[256]; // 256 is an arbitrary long enough size.
//!
//! \brief Converts a __PRETTY_FUNCTION__ into Class::Method
//! \details Converts a __PRETTY_FUNCTION__ into Class::Method to allow prettier debug output
//! \param PCCHAR pcPrettyFunction
//! [in] in the form of "TYPE [CLASS::]FUNCTION(INPUT LIST)"
//! \return PCCHAR in the form of [CLASS::]FUNCTION
//!
PCCHAR MOS_getClassMethod(PCCHAR pcPrettyFunction)
{
PCCHAR end = nullptr;
uint32_t len = 0;
memset(gFunctionName, '\0', sizeof(gFunctionName));
// Find the first '(', if it exists.
end = strchr(pcPrettyFunction, '(');
// We want to copy pcPrettyFunction into gFunction, only up to the first '('.
len = end ? (uint32_t)(end - pcPrettyFunction) : strlen(pcPrettyFunction);
MOS_SecureMemcpy(gFunctionName, sizeof(gFunctionName), pcPrettyFunction, len);
// dismiss anything before the last ' '.
return strrchr(gFunctionName, ' ') ? strrchr(gFunctionName, ' ') + 1 : gFunctionName;
}
#endif // USE_PRETTY_FUNCTION
#if MOS_ASSERT_ENABLED
extern int32_t MOS_ShouldAssert(MOS_COMPONENT_ID compID, uint8_t subCompID);
//!
//! \brief MOS assert function for MOS internal use
//! \details Halts the cpu in debug mode when expression resolves to zero
//! and only if assert enabled for both comp and sub-comp.
//! Nop in release version
//! Called by MOS_ASSERT macro only
//! \param MOS_COMPONENT_ID compID
//! [in] Indicates which component
//! \param uint8_t subCompID
//! [in] Indicates which sub-component
//! \return void
//!
void _MOS_Assert(MOS_COMPONENT_ID compID, uint8_t subCompID)
{
if (MOS_ShouldAssert(compID, subCompID) == false)
{
return;
}
//! NOTE:
//! If you hit asserts here and do not want to, you can cancel them by updating user feature keys under __MEDIA_USER_FEATURE_SUBKEY_INTERNAL.
//! These keys can be found in USER_FEATURE_FILE (currently "/etc/igfx_user_feature.txt").
//! First figure out what component is asserting (check element number compID in MOS_COMPONENT_ID).
//! Then in the user feature key "<component> Message Tags", set the forth bit to zero.
raise(SIGTRAP);
}
#endif // MOS_ASSERT_ENABLED
#endif // MOS_MESSAGES_ENABLED