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