mirror of https://github.com/intel/gmmlib.git
366 lines
13 KiB
C++
366 lines
13 KiB
C++
/*==============================================================================
|
|
Copyright(c) 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 Name: AssertTracer.cpp
|
|
|
|
Abstract:
|
|
These functions enables reporting asserts to system log in the debug
|
|
driver build.
|
|
|
|
Notes:
|
|
|
|
\*****************************************************************************/
|
|
|
|
#if defined( _WIN32 ) && (defined( _DEBUG ) || defined( _RELEASE_INTERNAL ))
|
|
#include "AssertTracer.h"
|
|
#ifndef NOMINMAX
|
|
#define NOMINMAX
|
|
#endif
|
|
#include <windows.h>
|
|
|
|
// Windows.h defines MemoryFence as _mm_mfence, but this conflicts with llvm::sys::MemoryFence
|
|
#undef MemoryFence
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#if defined( __GMM_KMD__ ) || defined( STATIC_DRIVER_MODEL )
|
|
#include"BufferedDbg.h"
|
|
#include "igdKrnlEtwMacros.h"
|
|
#endif //__GMM_KMD__ || STATIC_DRIVER_MODEL
|
|
|
|
#if _DEBUG
|
|
/*****************************************************************************\
|
|
|
|
Function:
|
|
ReportAsserts
|
|
|
|
Description:
|
|
Sends message to the system log.
|
|
|
|
Input:
|
|
const char *expr -
|
|
The expression passed to function.
|
|
const char *file -
|
|
The name of the file that is the origin of the expression.
|
|
const char *func -
|
|
The function from which call to this function was made.
|
|
const unsigned long line -
|
|
The line number from file, which caused this function call.
|
|
const char *msg -
|
|
Message passed to the system log.
|
|
Output:
|
|
void - None.
|
|
|
|
\*****************************************************************************/
|
|
void __stdcall ReportAssert(
|
|
const char *expr,
|
|
const char *file,
|
|
const char *func,
|
|
const unsigned long line,
|
|
const char *msg )
|
|
{
|
|
#if !defined( __GMM_KMD__ ) && !defined( STATIC_DRIVER_MODEL )//We are in UMD, use the UMD implementation
|
|
|
|
#if 0
|
|
|
|
HANDLE hEventLog = RegisterEventSourceA( NULL, "GFX Driver AssertTracer" );
|
|
char *wideMessage;
|
|
if ( hEventLog != NULL )
|
|
{
|
|
// Calculate length with hard coded max unsigned long length plus some safe space.
|
|
size_t length = strlen( expr ) + strlen( file ) + strlen( func ) + strlen( msg ) + 15;
|
|
|
|
// Checks against maximum string size for ReportEvent lpStrings parameter.
|
|
// Cuts string to the limit size.
|
|
uint32_t maxSizeReached = 0;
|
|
if ( length > 31839 )
|
|
{
|
|
length = 31839;
|
|
maxSizeReached = 1;
|
|
}
|
|
|
|
wideMessage = ( char * ) malloc( sizeof( char ) * length );
|
|
if( wideMessage != NULL )
|
|
{
|
|
// snprintf spec: "The resulting character string will be terminated with a null character"
|
|
_snprintf_s( wideMessage, length, length / sizeof( char ), "%s:%lu\n%s\n%s\n%s", file, line, expr, func, msg);
|
|
|
|
ReportEventA( hEventLog, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ( LPCSTR* ) &wideMessage, NULL );
|
|
free( wideMessage );
|
|
}
|
|
|
|
DeregisterEventSource( hEventLog );
|
|
}
|
|
|
|
#endif //!define( WINDOWS_MOBILE )
|
|
|
|
// Windows Mobile has no implementation. Reference the parameters to remove the unreference param warnings.
|
|
(void)expr;
|
|
(void)file;
|
|
(void)func;
|
|
(void)line;
|
|
(void)msg;
|
|
|
|
#else //We are in KMD, use the KMD implementation
|
|
BufDbgPrint("ASSERT_TRACE: %s::%s:%i : %s : %s\n", file, func, line, expr, msg);
|
|
#endif //!defined( __GMM_KMD__ ) && !defined( STATIC_DRIVER_MODEL )
|
|
}
|
|
#endif
|
|
|
|
/*****************************************************************************\
|
|
|
|
Function:
|
|
ReportAssertsETW
|
|
|
|
Description:
|
|
Sends message to the system log.
|
|
|
|
Input:
|
|
const unsigned long ComponentMask
|
|
Contains the component id for which raised assert (KMD, MINIPORT..)
|
|
const char *expr -
|
|
The expression passed to function.
|
|
const char *file -
|
|
The name of the file that is the origin of the expression.
|
|
const char *func -
|
|
The function from which call to this function was made.
|
|
const unsigned long line -
|
|
The line number from file, which caused this function call.
|
|
const char *msg -
|
|
Message passed to the system log.
|
|
Output:
|
|
void - None.
|
|
|
|
\*****************************************************************************/
|
|
|
|
void __stdcall ReportAssertETW( const unsigned short compId,
|
|
const unsigned long compMsk,
|
|
const char *expr,
|
|
const char *file,
|
|
const char *func,
|
|
const unsigned long line,
|
|
const char *msg)
|
|
{
|
|
#if !defined( __GMM_KMD__ ) && !defined( STATIC_DRIVER_MODEL ) //We are in UMD, use the UMD implementation
|
|
// TODO: Add UMD code for ETW here.
|
|
// Reference the parameters to remove the unreference param warnings.
|
|
(void)compId;
|
|
(void)compMsk;
|
|
(void)expr;
|
|
(void)file;
|
|
(void)func;
|
|
(void)line;
|
|
(void)msg;
|
|
#else //We are in KMD, use the KMD implementation
|
|
// Log event if ETW session is active
|
|
if (g_ulHDGraphics_SessionActive)
|
|
{
|
|
EtwAssertPrint(compId, compMsk, expr, file, func, line, msg);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#elif defined( __linux__ ) && defined( _RELEASE_INTERNAL ) && !defined( __ANDROID__ )
|
|
#include <algorithm>
|
|
#include <syslog.h>
|
|
#include <execinfo.h>
|
|
#include <string>
|
|
#include <cxxabi.h>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <sstream>
|
|
#include <fstream>
|
|
#define CALL_STACK_REPORT_SIZE 50 // maximal limit of call stack to be reported in case of assertion
|
|
#define MAX_FUNCTION_NAME_LENGTH 100 // no worries it can be extended (relocated by driver if needed)
|
|
#define MAX_SYSLOG_ENTRY_LENGTH 1000 // Syslog protocol recommends minimum entry length 1KB (ubuntu rsyslog message limit is about 2K)
|
|
void LogAssertion( const char *function_name, const char *file_name, unsigned int line_number, const char *expr )
|
|
{
|
|
std::string stack;
|
|
std::string part1;
|
|
std::string part2;
|
|
std::size_t pos;
|
|
void *buffer[CALL_STACK_REPORT_SIZE];
|
|
char *function_name_buffer = NULL;
|
|
int nframes; // numer of frames to be returned
|
|
char **strings;
|
|
int i;
|
|
int status;
|
|
size_t length;
|
|
const size_t stringLength = 4096;
|
|
std::string oclAppCmdLine;
|
|
|
|
nframes = backtrace( buffer, CALL_STACK_REPORT_SIZE );
|
|
|
|
strings = backtrace_symbols( buffer, nframes );
|
|
if( strings == NULL )
|
|
{
|
|
perror( "Getting backtrace symbols error:" );
|
|
nframes = 0;
|
|
}
|
|
else
|
|
{
|
|
// Get Commandline of process (in that case OCL app)
|
|
// from process info itself eg. /proc/self/cmdline
|
|
|
|
oclAppCmdLine.reserve( stringLength );
|
|
std::ifstream fileCmdline( "/proc/self/cmdline", std::ifstream::binary );
|
|
if( fileCmdline.is_open() )
|
|
{
|
|
oclAppCmdLine = std::string( std::istreambuf_iterator< char >( fileCmdline ), std::istreambuf_iterator< char >() );
|
|
if( oclAppCmdLine.size() > 0 )
|
|
{
|
|
// Trim last \0 character
|
|
oclAppCmdLine.resize( oclAppCmdLine.size() - 1 );
|
|
// Format of /proc/self/cmdline is that args are separated with '\0'
|
|
// so for nicer printing we replace zeros with spaces (without terminating 0)
|
|
std::replace( oclAppCmdLine.begin(), oclAppCmdLine.end(), '\0', ' ' );
|
|
}
|
|
else
|
|
{
|
|
fprintf( stderr, "Getting Commandline of OCL app error: Error reading /proc/self/cmdline\n" );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fprintf( stderr, "Getting Commandline of OCL app error:" );
|
|
}
|
|
}
|
|
|
|
// allocation by malloc is suggessted by documentation as abi function may do some relocation
|
|
function_name_buffer = ( char * )malloc( MAX_FUNCTION_NAME_LENGTH );
|
|
if( function_name_buffer == NULL )
|
|
{
|
|
// Not enough memory to get small allocation then do not print stack
|
|
nframes = 0;
|
|
}
|
|
else
|
|
{
|
|
length = MAX_FUNCTION_NAME_LENGTH;
|
|
memset( function_name_buffer, 0, length );
|
|
}
|
|
|
|
for( i = 0; i < nframes; ++i )
|
|
{
|
|
// Generate signature of given stack frame eg. #0 #1 etc...
|
|
std::stringstream framePromptBuilder;
|
|
framePromptBuilder << "#" << i << " ";
|
|
const std::string &framePrompt = framePromptBuilder.str();
|
|
// demangle name eg. split stack frame into two pieces
|
|
part1 = strings[i];
|
|
pos = part1.find( "(" );
|
|
if( pos != std::string::npos )
|
|
{
|
|
// For final level instead of binary print whole commandline
|
|
// if were able to get one
|
|
if( ( i == nframes - 1 ) && ( !oclAppCmdLine.empty() ) )
|
|
{
|
|
//..call stack's part1 contains "(" so we add it here manualy
|
|
stack.append( ( oclAppCmdLine.insert( 0, "COMMANDLINE(" ) ).c_str() );
|
|
}
|
|
else
|
|
{
|
|
// part1 contains everything before section to be demangled
|
|
part1 = part1.substr( 0, pos + 1 );
|
|
stack.append(framePrompt);
|
|
stack.append( part1 );
|
|
}
|
|
// part2 contains string to be demangled
|
|
part2 = strings[i];
|
|
part2 = part2.substr( pos + 1 );
|
|
pos = part2.find( "+" );
|
|
// Final level may not have any function (static functions are not exposed)
|
|
if( pos != std::string::npos )
|
|
{
|
|
part2 = part2.substr( 0, pos );
|
|
function_name_buffer = abi::__cxa_demangle( part2.c_str(), function_name_buffer, &length, &status );
|
|
// in case of error during demangling attach mangled name
|
|
if( status != 0 )
|
|
{
|
|
stack.append( part2 );
|
|
}
|
|
else
|
|
{
|
|
stack.append( function_name_buffer );
|
|
}
|
|
stack.append( "())" );
|
|
free( function_name_buffer );
|
|
function_name_buffer = NULL;
|
|
|
|
}
|
|
else
|
|
{
|
|
// if there was no function then attach ")"
|
|
stack.append( ")" );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( ( i == nframes - 1 ) && ( !oclAppCmdLine.empty() ) )
|
|
{
|
|
stack.append( ( oclAppCmdLine.insert( 0, "COMMANDLINE(" ) ).c_str() );
|
|
stack.append( ")" );
|
|
}
|
|
else
|
|
{
|
|
stack.append(framePrompt);
|
|
stack.append( strings[i] );
|
|
}
|
|
}
|
|
stack.append( " " );
|
|
}
|
|
//Compose full message..
|
|
std::string fullMsg = "File: ";
|
|
std::string syslogEntry;
|
|
fullMsg += file_name;
|
|
fullMsg += " line: ";
|
|
std::stringstream lineStr;
|
|
lineStr << line_number;
|
|
fullMsg += lineStr.str();
|
|
fullMsg += " function: ";
|
|
fullMsg += function_name;
|
|
fullMsg += " expr: ";
|
|
fullMsg += expr;
|
|
fullMsg += " ";
|
|
fullMsg += stack.c_str();
|
|
|
|
// split it into chunks we can send
|
|
openlog( "OpenCL", LOG_PID, LOG_USER );
|
|
pos = 0;
|
|
int numberOfChunks = ( fullMsg.length() / MAX_SYSLOG_ENTRY_LENGTH ) + 1;
|
|
while( pos < fullMsg.length() )
|
|
{
|
|
syslogEntry = fullMsg.substr( pos, MAX_SYSLOG_ENTRY_LENGTH );
|
|
// Add chunk ID / part number and send to syslog
|
|
syslog( LOG_MAKEPRI( LOG_USER,
|
|
LOG_ERR ), "[%zd/%d]%s", ( pos / MAX_SYSLOG_ENTRY_LENGTH + 1 ), numberOfChunks,
|
|
syslogEntry.c_str() );
|
|
pos += MAX_SYSLOG_ENTRY_LENGTH;
|
|
}
|
|
closelog();
|
|
|
|
// backtrace_symbols allocates memory in a malloc like way sop it should be freed
|
|
free( strings );
|
|
strings = NULL;
|
|
}
|
|
#endif //defined( _WIN32 ) && defined( _DEBUG )
|