core/DebugReporter.cpp
author David Anderson <dvander@alliedmods.net>
Fri Aug 15 05:22:26 2008 +0000 (2008-08-15)
changeset 2226 d10b38524be3
parent 2195 5b70179559f9
child 2289 44045ead61cd
permissions -rw-r--r--
Landed sourcepawn-1.2. The big changes:

1) JIT compilation/optimization now occurs per-function, and only when functions are first used. We're now officially a whole-method JIT rather than an AOT compiler (albiet, still a simple JIT). This has two implications: Functions are now much better abstracted internally, and loading a plugin is now much less expensive. If a function contains calls to other functions, THOSE functions are only compiled when they're invoked as well.

2) I've removed debug mode. We always show full backtraces now, as there was a very cheap way to implement this which really cleaned up everything. This is great for a number of reasons -- there's less code, the JIT is better designed, we don't need to relocate debug tables, and best of all we no longer have to tell users to enable debug mode at their own expense.
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or modify it under
     9  * the terms of the GNU General Public License, version 3.0, as published by the
    10  * Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful, but WITHOUT
    13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    15  * details.
    16  *
    17  * You should have received a copy of the GNU General Public License along with
    18  * this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to link the
    21  * code of this program (as well as its derivative works) to "Half-Life 2," the
    22  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    23  * by the Valve Corporation.  You must obey the GNU General Public License in
    24  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    25  * this exception to all derivative works.  AlliedModders LLC defines further
    26  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    27  * or <http://www.sourcemod.net/license.php>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #include "DebugReporter.h"
    33 #include "Logger.h"
    34 #include "PluginSys.h"
    35 #include "sm_stringutil.h"
    36 
    37 DebugReport g_DbgReporter;
    38 
    39 void DebugReport::OnSourceModAllInitialized()
    40 {
    41 	g_pSourcePawn->SetDebugListener(this);
    42 }
    43 
    44 void DebugReport::OnDebugSpew(const char *msg, ...)
    45 {
    46 	va_list ap;
    47 	char buffer[512];
    48 
    49 	va_start(ap, msg);
    50 	UTIL_FormatArgs(buffer, sizeof(buffer), msg, ap);
    51 	va_end(ap);
    52 
    53 	g_Logger.LogMessage("[SM] %s", buffer);
    54 }
    55 
    56 void DebugReport::GenerateError(IPluginContext *ctx, cell_t func_idx, int err, const char *message, ...)
    57 {
    58 	va_list ap;
    59 	char buffer[512];
    60 
    61 	va_start(ap, message);
    62 	UTIL_FormatArgs(buffer, sizeof(buffer), message, ap);
    63 	va_end(ap);
    64 
    65 	const char *plname = g_PluginSys.FindPluginByContext(ctx->GetContext())->GetFilename();
    66 	const char *error = g_pSourcePawn2->GetErrorString(err);
    67 
    68 	if (error)
    69 	{
    70 		g_Logger.LogError("[SM] Plugin \"%s\" encountered error %d: %s", plname, err, error);
    71 	} else {
    72 		g_Logger.LogError("[SM] Plugin \"%s\" encountered unknown error %d", plname, err);
    73 	}
    74 
    75 	g_Logger.LogError("[SM] %s", buffer);
    76 
    77 	if (func_idx != -1)
    78 	{
    79 		if (func_idx & 1)
    80 		{
    81 			func_idx >>= 1;
    82 			sp_public_t *function;
    83 			if (ctx->GetRuntime()->GetPublicByIndex(func_idx, &function) == SP_ERROR_NONE)
    84 			{
    85 				g_Logger.LogError("[SM] Unable to call function \"%s\" due to above error(s).", function->name);
    86 			}
    87 		}
    88 	}
    89 }
    90 
    91 void DebugReport::GenerateCodeError(IPluginContext *pContext, uint32_t code_addr, int err, const char *message, ...)
    92 {
    93 	va_list ap;
    94 	char buffer[512];
    95 
    96 	va_start(ap, message);
    97 	UTIL_FormatArgs(buffer, sizeof(buffer), message, ap);
    98 	va_end(ap);
    99 
   100 	const char *plname = g_PluginSys.FindPluginByContext(pContext->GetContext())->GetFilename();
   101 	const char *error = g_pSourcePawn2->GetErrorString(err);
   102 
   103 	if (error)
   104 	{
   105 		g_Logger.LogError("[SM] Plugin \"%s\" encountered error %d: %s", plname, err, error);
   106 	} else {
   107 		g_Logger.LogError("[SM] Plugin \"%s\" encountered unknown error %d", plname, err);
   108 	}
   109 
   110 	g_Logger.LogError("[SM] %s", buffer);
   111 
   112 	IPluginDebugInfo *pDebug;
   113 	if ((pDebug = pContext->GetRuntime()->GetDebugInfo()) == NULL)
   114 	{
   115 		g_Logger.LogError("[SM] Debug mode is not enabled for \"%s\"", plname);
   116 		g_Logger.LogError("[SM] To enable debug mode, edit plugin_settings.cfg, or type: sm plugins debug %d on",
   117 			_GetPluginIndex(pContext));
   118 		return;
   119 	}
   120 
   121 	const char *name;
   122 	if (pDebug->LookupFunction(code_addr, &name) == SP_ERROR_NONE)
   123 	{
   124 		g_Logger.LogError("[SM] Unable to call function \"%s\" due to above error(s).", name);
   125 	} else {
   126 		g_Logger.LogError("[SM] Unable to call function (name unknown, address \"%x\").", code_addr);
   127 	}
   128 }
   129 
   130 void DebugReport::OnContextExecuteError(IPluginContext *ctx, IContextTrace *error)
   131 {
   132 	const char *lastname;
   133 	const char *plname = g_PluginSys.FindPluginByContext(ctx->GetContext())->GetFilename();
   134 	int n_err = error->GetErrorCode();
   135 
   136 	if (n_err != SP_ERROR_NATIVE)
   137 	{
   138 		g_Logger.LogError("[SM] Plugin encountered error %d: %s",
   139 			n_err,
   140 			error->GetErrorString());
   141 	}
   142 
   143 	if ((lastname=error->GetLastNative(NULL)) != NULL)
   144 	{
   145 		const char *custerr;
   146 		if ((custerr=error->GetCustomErrorString()) != NULL)
   147 		{
   148 			g_Logger.LogError("[SM] Native \"%s\" reported: %s", lastname, custerr);
   149 		} else {
   150 			g_Logger.LogError("[SM] Native \"%s\" encountered a generic error.", lastname);
   151 		}
   152 	}
   153 
   154 	if (!error->DebugInfoAvailable())
   155 	{
   156 		g_Logger.LogError("[SM] Debug mode is not enabled for \"%s\"", plname);
   157 		g_Logger.LogError("[SM] To enable debug mode, edit plugin_settings.cfg, or type: sm plugins debug %d on",
   158 			_GetPluginIndex(ctx));
   159 		return;
   160 	}
   161 
   162 	CallStackInfo stk_info;
   163 	int i = 0;
   164 	g_Logger.LogError("[SM] Displaying call stack trace for plugin \"%s\":", plname);
   165 	while (error->GetTraceInfo(&stk_info))
   166 	{
   167 		g_Logger.LogError("[SM]   [%d]  Line %d, %s::%s()",
   168 			i++,
   169 			stk_info.line,
   170 			stk_info.filename,
   171 			stk_info.function);
   172 	}
   173 }
   174 
   175 int DebugReport::_GetPluginIndex(IPluginContext *ctx)
   176 {
   177 	int id = 1;
   178 	IPluginIterator *iter = g_PluginSys.GetPluginIterator();
   179 
   180 	for (; iter->MorePlugins(); iter->NextPlugin(), id++)
   181 	{
   182 		IPlugin *pl = iter->GetPlugin();
   183 		if (pl->GetBaseContext() == ctx)
   184 		{
   185 			iter->Release();
   186 			return id;
   187 		}
   188 	}
   189 
   190 	iter->Release();
   191 
   192 	/* If we don't know which plugin this is, it's one being loaded.  Fake its index for now. */
   193 
   194 	return g_PluginSys.GetPluginCount() + 1;
   195 }
   196