text: // Copyright 2018 The SwiftShader Authors. All Rights Reserved.
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //    http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  
  #include "Debug.hpp"
  
  #include <atomic>
  #include <cstdarg>
  #include <cstdio>
  #include <string>
  
  #if __ANDROID__
  #	include <android/log.h>
  #endif
  
  #if defined(__unix__)
  #	define PTRACE
  #	include <sys/ptrace.h>
  #	include <sys/types.h>
  #elif defined(_WIN32) || defined(_WIN64)
  #	include <windows.h>
  #elif defined(__APPLE__) || defined(__MACH__)
  #	include <sys/sysctl.h>
  #	include <unistd.h>
  #endif
  
  #ifdef ERROR
  #	undef ERROR  // b/127920555
  #endif
  
  #ifndef REACTOR_LOGGING_LEVEL
  #	define REACTOR_LOGGING_LEVEL Info
  #endif
  
  namespace {
  
  bool IsUnderDebugger()
  {
  #if defined(PTRACE) && !defined(__APPLE__) && !defined(__MACH__)
  	static bool checked = false;
  	static bool res = false;
  
  	if(!checked)
  	{
  		// If a debugger is attached then we're already being ptraced and ptrace
  		// will return a non-zero value.
  		checked = true;
  		if(ptrace(PTRACE_TRACEME, 0, 1, 0) != 0)
  		{
  			res = true;
  		}
  		else
  		{
  			ptrace(PTRACE_DETACH, 0, 1, 0);
  		}
  	}
  
  	return res;
  #elif defined(_WIN32) || defined(_WIN64)
  	return IsDebuggerPresent() != 0;
  #elif defined(__APPLE__) || defined(__MACH__)
  	// Code comes from the Apple Technical Q&A QA1361
  
  	// Tell sysctl what info we're requestion. Specifically we're asking for
  	// info about this our PID.
  	int res = 0;
  	int request[4] = {
  		CTL_KERN,
  		KERN_PROC,
  		KERN_PROC_PID,
  		getpid()
  	};
  	struct kinfo_proc info;
  	size_t size = sizeof(info);
  
  	info.kp_proc.p_flag = 0;
  
  	// Get the info we're requesting, if sysctl fails then info.kp_proc.p_flag will remain 0.
  	res = sysctl(request, sizeof(request) / sizeof(*request), &info, &size, NULL, 0);
  	ASSERT_MSG(res == 0, "syscl returned %d", res);
  
  	// We're being debugged if the P_TRACED flag is set
  	return ((info.kp_proc.p_flag & P_TRACED) != 0);
  #else
  	return false;
  #endif
  }
  
  enum class Level
  {
  	Debug,
  	Info,
  	Warn,
  	Error,
  	Fatal,
  };
  
  #ifdef __ANDROID__
  void logv_android(Level level, const char *msg)
  {
  	switch(level)
  	{
  		case Level::Debug:
  			__android_log_write(ANDROID_LOG_DEBUG, "SwiftShader", msg);
  			break;
  		case Level::Info:
  			__android_log_write(ANDROID_LOG_INFO, "SwiftShader", msg);
  			break;
  		case Level::Warn:
  			__android_log_write(ANDROID_LOG_WARN, "SwiftShader", msg);
  			break;
  		case Level::Error:
  			__android_log_write(ANDROID_LOG_ERROR, "SwiftShader", msg);
  			break;
  		case Level::Fatal:
  			__android_log_write(ANDROID_LOG_FATAL, "SwiftShader", msg);
  			break;
  	}
  }
  #else
  void logv_std(Level level, const char *msg)
  {
  	switch(level)
  	{
  		case Level::Debug:
  		case Level::Info:
  			fprintf(stdout, "%s", msg);
  			break;
  		case Level::Warn:
  		case Level::Error:
  		case Level::Fatal:
  			fprintf(stderr, "%s", msg);
  			break;
  	}
  }
  #endif
  
  void logv(Level level, const char *format, va_list args)
  {
  	if(static_cast<int>(level) < static_cast<int>(Level::REACTOR_LOGGING_LEVEL))
  	{
  		return;
  	}
  
  #ifndef SWIFTSHADER_DISABLE_TRACE
  	char buffer[2048];
  	vsnprintf(buffer, sizeof(buffer), format, args);
  
  #	if defined(__ANDROID__)
  	logv_android(level, buffer);
  #	elif defined(_WIN32)
  	logv_std(level, buffer);
  	::OutputDebugString(buffer);
  #	else
  	logv_std(level, buffer);
  #	endif
  
  	const bool traceToFile = false;
  	if(traceToFile)
  	{
  		FILE *file = fopen(TRACE_OUTPUT_FILE, "a");
  
  		if(file)
  		{
  			vfprintf(file, format, args);
  			fclose(file);
  		}
  	}
  #endif  // SWIFTSHADER_DISABLE_TRACE
  }
  
  }  // anonymous namespace
  
  namespace rr {
  
  void trace(const char *format, ...)
  {
  	va_list vararg;
  	va_start(vararg, format);
  	logv(Level::Debug, format, vararg);
  	va_end(vararg);
  }
  
  void warn(const char *format, ...)
  {
  	va_list vararg;
  	va_start(vararg, format);
  	logv(Level::Warn, format, vararg);
  	va_end(vararg);
  }
  
  void abort(const char *format, ...)
  {
  	va_list vararg;
  
  	va_start(vararg, format);
  	logv(Level::Fatal, format, vararg);
  	va_end(vararg);
  
  	::abort();
  }
  
  void trace_assert(const char *format, ...)
  {
  	static std::atomic<bool> asserted = { false };
  	if(IsUnderDebugger() && !asserted.exchange(true))
  	{
  		// Abort after tracing and printing to stderr
  		va_list vararg;
  		va_start(vararg, format);
  		logv(Level::Fatal, format, vararg);
  		va_end(vararg);
  
  		::abort();
  	}
  	else if(!asserted)
  	{
  		va_list vararg;
  		va_start(vararg, format);
  		logv(Level::Fatal, format, vararg);
  		va_end(vararg);
  	}
  }
  
  }  // namespace rr
  