core/vm/sp_vm_basecontext.cpp
author Borja Ferrer <faluco@alliedmods.net>
Mon Jan 15 00:56:39 2007 +0000 (2007-01-15)
changeset 290 da8de49409e8
parent 262 de0e374ffa47
child 313 35d47ceae36f
permissions -rw-r--r--
Added capability to toggle debug state in plugins at runtime
dvander@159
     1
#include <string.h>
dvander@240
     2
#include <stdarg.h>
dvander@159
     3
#include <assert.h>
dvander@159
     4
#include <limits.h>
dvander@159
     5
#include "sp_vm_api.h"
dvander@159
     6
#include "sp_vm_basecontext.h"
dvander@240
     7
#include "sp_vm_engine.h"
dvander@159
     8
dvander@159
     9
using namespace SourcePawn;
dvander@159
    10
dvander@240
    11
extern SourcePawnEngine g_SourcePawn;
dvander@240
    12
dvander@159
    13
#define CELLBOUNDMAX	(INT_MAX/sizeof(cell_t))
dvander@159
    14
#define STACKMARGIN		((cell_t)(16*sizeof(cell_t)))
dvander@159
    15
dvander@240
    16
int GlobalDebugBreak(sp_context_t *ctx, uint32_t frm, uint32_t cip)
dvander@240
    17
{
dvander@240
    18
	g_SourcePawn.RunTracer(ctx, frm, cip);
dvander@240
    19
dvander@240
    20
	return SP_ERROR_NONE;
dvander@240
    21
}
dvander@240
    22
dvander@159
    23
BaseContext::BaseContext(sp_context_t *_ctx)
dvander@159
    24
{
dvander@159
    25
	ctx = _ctx;
dvander@159
    26
	ctx->context = this;
dvander@240
    27
	ctx->dbreak = GlobalDebugBreak;
dvander@240
    28
	m_InExec = false;
dvander@240
    29
	m_CustomMsg = false;
dvander@159
    30
}
dvander@159
    31
faluco@290
    32
void BaseContext::SetContext(sp_context_t *_ctx)
faluco@290
    33
{
faluco@290
    34
	if (!_ctx)
faluco@290
    35
	{
faluco@290
    36
		return;
faluco@290
    37
	}
faluco@290
    38
	ctx = _ctx;
faluco@290
    39
}
faluco@290
    40
dvander@159
    41
IVirtualMachine *BaseContext::GetVirtualMachine()
dvander@159
    42
{
dvander@159
    43
	return (IVirtualMachine *)ctx->vmbase;
dvander@159
    44
}
dvander@159
    45
dvander@159
    46
sp_context_t *BaseContext::GetContext()
dvander@159
    47
{
dvander@159
    48
	return ctx;
dvander@159
    49
}
dvander@159
    50
dvander@159
    51
bool BaseContext::IsDebugging()
dvander@159
    52
{
dvander@159
    53
	return (ctx->flags & SPFLAG_PLUGIN_DEBUG);
dvander@159
    54
}
dvander@159
    55
dvander@159
    56
int BaseContext::SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn)
dvander@159
    57
{
dvander@159
    58
	if (!IsDebugging())
dvander@159
    59
	{
dvander@159
    60
		return SP_ERROR_NOTDEBUGGING;
dvander@159
    61
	}
dvander@159
    62
dvander@159
    63
	*oldpfn = ctx->dbreak;
dvander@159
    64
	ctx->dbreak = newpfn;
dvander@159
    65
dvander@159
    66
	return SP_ERROR_NONE;
dvander@159
    67
}
dvander@159
    68
dvander@159
    69
IPluginDebugInfo *BaseContext::GetDebugInfo()
dvander@159
    70
{
dvander@159
    71
	return this;
dvander@159
    72
}
dvander@159
    73
dvander@164
    74
int BaseContext::Execute(funcid_t funcid, cell_t *result)
dvander@159
    75
{
dvander@159
    76
	IVirtualMachine *vm = (IVirtualMachine *)ctx->vmbase;
dvander@159
    77
dvander@159
    78
	uint32_t pushcount = ctx->pushcount;
dvander@164
    79
	uint32_t code_addr;
dvander@159
    80
	int err;
dvander@164
    81
dvander@164
    82
	if (funcid & 1)
dvander@159
    83
	{
dvander@164
    84
		sp_public_t *pubfunc;
dvander@164
    85
		if ((err=GetPublicByIndex((funcid>>1), &pubfunc)) != SP_ERROR_NONE)
dvander@164
    86
		{
dvander@164
    87
			return err;
dvander@164
    88
		}
dvander@164
    89
		code_addr = pubfunc->code_offs;
dvander@164
    90
	} else {
dvander@164
    91
		code_addr = funcid >> 1;
dvander@159
    92
	}
dvander@159
    93
dvander@159
    94
	PushCell(pushcount++);
dvander@159
    95
	ctx->pushcount = 0;
dvander@159
    96
dvander@159
    97
	cell_t save_sp = ctx->sp;
dvander@159
    98
	cell_t save_hp = ctx->hp;
dvander@159
    99
dvander@240
   100
	bool wasExec = m_InExec;
dvander@240
   101
dvander@240
   102
	/* Clear the error state, if any */
dvander@240
   103
	ctx->n_err = SP_ERROR_NONE;
dvander@240
   104
	ctx->n_idx = 0;
dvander@240
   105
	m_InExec = true;
dvander@240
   106
	m_MsgCache[0] = '\0';
dvander@240
   107
	m_CustomMsg = false;
dvander@240
   108
dvander@240
   109
	g_SourcePawn.PushTracer(ctx);
dvander@240
   110
dvander@164
   111
	err = vm->ContextExecute(ctx, code_addr, result);
dvander@240
   112
dvander@240
   113
	m_InExec = wasExec;
dvander@240
   114
dvander@159
   115
	/**
dvander@240
   116
	 * :TODO: Calling from a plugin in here will erase the cached message...
dvander@240
   117
	 * Should that be documented?
dvander@159
   118
	 */
dvander@240
   119
	g_SourcePawn.PopTracer(err, m_CustomMsg ? m_MsgCache : NULL);
dvander@159
   120
dvander@159
   121
#if defined _DEBUG
dvander@159
   122
	if (err == SP_ERROR_NONE)
dvander@159
   123
	{
dvander@159
   124
		assert(ctx->sp - pushcount * sizeof(cell_t) == save_sp);
dvander@159
   125
		assert(ctx->hp == save_hp);
dvander@159
   126
	}
dvander@159
   127
#endif
dvander@159
   128
	if (err != SP_ERROR_NONE)
dvander@159
   129
	{
dvander@159
   130
		ctx->sp = save_sp;
dvander@159
   131
		ctx->hp = save_hp;
dvander@159
   132
	}
dvander@159
   133
dvander@159
   134
	return err;
dvander@159
   135
}
dvander@159
   136
dvander@240
   137
void BaseContext::SetErrorMessage(const char *msg, va_list ap)
dvander@240
   138
{
dvander@240
   139
	m_CustomMsg = true;
dvander@240
   140
dvander@240
   141
	vsnprintf(m_MsgCache, sizeof(m_MsgCache), msg, ap);
dvander@240
   142
}
dvander@240
   143
dvander@240
   144
void BaseContext::ThrowNativeErrorEx(int error, const char *msg, ...)
dvander@240
   145
{
dvander@240
   146
	if (!m_InExec)
dvander@240
   147
	{
dvander@240
   148
		return;
dvander@240
   149
	}
dvander@240
   150
dvander@240
   151
	ctx->n_err = error;
dvander@240
   152
	
dvander@240
   153
	if (msg)
dvander@240
   154
	{
dvander@240
   155
		va_list ap;
dvander@240
   156
		va_start(ap, msg);
dvander@240
   157
		SetErrorMessage(msg, ap);
dvander@240
   158
		va_end(ap);
dvander@240
   159
	}
dvander@240
   160
}
dvander@240
   161
dvander@240
   162
cell_t BaseContext::ThrowNativeError(const char *msg, ...)
dvander@240
   163
{
dvander@240
   164
	if (!m_InExec)
dvander@240
   165
	{
dvander@240
   166
		return 0;
dvander@240
   167
	}
dvander@240
   168
dvander@240
   169
	ctx->n_err = SP_ERROR_NATIVE;
dvander@240
   170
dvander@240
   171
	if (msg)
dvander@240
   172
	{
dvander@240
   173
		va_list ap;
dvander@240
   174
		va_start(ap, msg);
dvander@240
   175
		SetErrorMessage(msg, ap);
dvander@240
   176
		va_end(ap);
dvander@240
   177
	}
dvander@240
   178
dvander@240
   179
	return 0;
dvander@240
   180
}
dvander@240
   181
dvander@159
   182
int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr)
dvander@159
   183
{
dvander@159
   184
	cell_t *addr;
dvander@159
   185
	ucell_t realmem;
dvander@159
   186
dvander@159
   187
#if 0
dvander@159
   188
	if (cells > CELLBOUNDMAX)
dvander@159
   189
	{
dvander@159
   190
		return SP_ERROR_ARAM;
dvander@159
   191
	}
dvander@159
   192
#else
dvander@159
   193
	assert(cells < CELLBOUNDMAX);
dvander@159
   194
#endif
dvander@159
   195
dvander@159
   196
	realmem = cells * sizeof(cell_t);
dvander@159
   197
dvander@159
   198
	/**
dvander@159
   199
	 * Check if the space between the heap and stack is sufficient.
dvander@159
   200
	 */
dvander@159
   201
	if ((cell_t)(ctx->sp - ctx->hp - realmem) < STACKMARGIN)
dvander@159
   202
	{
dvander@159
   203
		return SP_ERROR_HEAPLOW;
dvander@159
   204
	}
dvander@159
   205
dvander@159
   206
	addr = (cell_t *)(ctx->memory + ctx->hp);
dvander@159
   207
	/* store size of allocation in cells */
dvander@159
   208
	*addr = (cell_t)cells;
dvander@159
   209
	addr++;
dvander@159
   210
	ctx->hp += sizeof(cell_t);
dvander@159
   211
dvander@159
   212
	*local_addr = ctx->hp;
dvander@159
   213
dvander@159
   214
	if (phys_addr)
dvander@159
   215
	{
dvander@159
   216
		*phys_addr = addr;
dvander@159
   217
	}
dvander@159
   218
dvander@159
   219
	ctx->hp += realmem;
dvander@159
   220
dvander@159
   221
	return SP_ERROR_NONE;
dvander@159
   222
}
dvander@159
   223
dvander@159
   224
int BaseContext::HeapPop(cell_t local_addr)
dvander@159
   225
{
dvander@159
   226
	cell_t cellcount;
dvander@159
   227
	cell_t *addr;
dvander@159
   228
dvander@159
   229
	/* check the bounds of this address */
dvander@159
   230
	local_addr -= sizeof(cell_t);
dvander@159
   231
	if (local_addr < ctx->heap_base || local_addr >= ctx->sp)
dvander@159
   232
	{
dvander@159
   233
		return SP_ERROR_INVALID_ADDRESS;
dvander@159
   234
	}
dvander@159
   235
dvander@159
   236
	addr = (cell_t *)(ctx->memory + local_addr);
dvander@159
   237
	cellcount = (*addr) * sizeof(cell_t);
dvander@159
   238
	/* check if this memory count looks valid */
dvander@159
   239
	if (ctx->hp - cellcount - sizeof(cell_t) != local_addr)
dvander@159
   240
	{
dvander@159
   241
		return SP_ERROR_INVALID_ADDRESS;
dvander@159
   242
	}
dvander@159
   243
dvander@159
   244
	ctx->hp = local_addr;
dvander@159
   245
dvander@159
   246
	return SP_ERROR_NONE;
dvander@159
   247
}
dvander@159
   248
dvander@159
   249
dvander@159
   250
int BaseContext::HeapRelease(cell_t local_addr)
dvander@159
   251
{
dvander@159
   252
	if (local_addr < ctx->heap_base)
dvander@159
   253
	{
dvander@159
   254
		return SP_ERROR_INVALID_ADDRESS;
dvander@159
   255
	}
dvander@159
   256
dvander@159
   257
	ctx->hp = local_addr - sizeof(cell_t);
dvander@159
   258
dvander@159
   259
	return SP_ERROR_NONE;
dvander@159
   260
}
dvander@159
   261
dvander@159
   262
int BaseContext::FindNativeByName(const char *name, uint32_t *index)
dvander@159
   263
{
dvander@262
   264
	int high;
dvander@159
   265
dvander@159
   266
	high = ctx->plugin->info.natives_num - 1;
dvander@159
   267
dvander@254
   268
#if 0
dvander@159
   269
	while (low <= high)
dvander@159
   270
	{
dvander@159
   271
		mid = (low + high) / 2;
dvander@159
   272
		diff = strcmp(ctx->natives[mid].name, name);
dvander@159
   273
		if (diff == 0)
dvander@159
   274
		{
dvander@159
   275
			if (index)
dvander@159
   276
			{
dvander@159
   277
				*index = mid;
dvander@159
   278
			}
dvander@159
   279
			return SP_ERROR_NONE;
dvander@159
   280
		} else if (diff < 0) {
dvander@159
   281
			low = mid + 1;
dvander@159
   282
		} else {
dvander@159
   283
			high = mid - 1;
dvander@159
   284
		}
dvander@159
   285
	}
dvander@254
   286
#else
dvander@254
   287
	for (uint32_t i=0; i<ctx->plugin->info.natives_num; i++)
dvander@254
   288
	{
dvander@254
   289
		if (strcmp(ctx->natives[i].name, name) == 0)
dvander@254
   290
		{
dvander@254
   291
			if (index)
dvander@254
   292
			{
dvander@254
   293
				*index = i;
dvander@254
   294
			}
dvander@254
   295
			return SP_ERROR_NONE;
dvander@254
   296
		}
dvander@254
   297
	}
dvander@254
   298
#endif
dvander@159
   299
dvander@159
   300
	return SP_ERROR_NOT_FOUND;
dvander@159
   301
}
dvander@159
   302
dvander@159
   303
int BaseContext::GetNativeByIndex(uint32_t index, sp_native_t **native)
dvander@159
   304
{
dvander@159
   305
	if (index >= ctx->plugin->info.natives_num)
dvander@159
   306
	{
dvander@159
   307
		return SP_ERROR_INDEX;
dvander@159
   308
	}
dvander@159
   309
dvander@159
   310
	if (native)
dvander@159
   311
	{
dvander@159
   312
		*native = &(ctx->natives[index]);
dvander@159
   313
	}
dvander@159
   314
dvander@159
   315
	return SP_ERROR_NONE;
dvander@159
   316
}
dvander@159
   317
dvander@159
   318
dvander@159
   319
uint32_t BaseContext::GetNativesNum()
dvander@159
   320
{
dvander@159
   321
	return ctx->plugin->info.natives_num;
dvander@159
   322
}
dvander@159
   323
dvander@159
   324
int BaseContext::FindPublicByName(const char *name, uint32_t *index)
dvander@159
   325
{
dvander@159
   326
	int diff, high, low;
dvander@159
   327
	uint32_t mid;
dvander@159
   328
dvander@159
   329
	high = ctx->plugin->info.publics_num - 1;
dvander@159
   330
	low = 0;
dvander@159
   331
dvander@159
   332
	while (low <= high)
dvander@159
   333
	{
dvander@159
   334
		mid = (low + high) / 2;
dvander@159
   335
		diff = strcmp(ctx->publics[mid].name, name);
dvander@159
   336
		if (diff == 0)
dvander@159
   337
		{
dvander@159
   338
			if (index)
dvander@159
   339
			{
dvander@159
   340
				*index = mid;
dvander@159
   341
			}
dvander@159
   342
			return SP_ERROR_NONE;
dvander@159
   343
		} else if (diff < 0) {
dvander@159
   344
			low = mid + 1;
dvander@159
   345
		} else {
dvander@159
   346
			high = mid - 1;
dvander@159
   347
		}
dvander@159
   348
	}
dvander@159
   349
dvander@159
   350
	return SP_ERROR_NOT_FOUND;
dvander@159
   351
}
dvander@159
   352
dvander@159
   353
int BaseContext::GetPublicByIndex(uint32_t index, sp_public_t **pblic)
dvander@159
   354
{
dvander@159
   355
	if (index >= ctx->plugin->info.publics_num)
dvander@159
   356
	{
dvander@159
   357
		return SP_ERROR_INDEX;
dvander@159
   358
	}
dvander@159
   359
dvander@159
   360
	if (pblic)
dvander@159
   361
	{
dvander@159
   362
		*pblic = &(ctx->publics[index]);
dvander@159
   363
	}
dvander@159
   364
dvander@159
   365
	return SP_ERROR_NONE;
dvander@159
   366
}
dvander@159
   367
dvander@159
   368
uint32_t BaseContext::GetPublicsNum()
dvander@159
   369
{
dvander@159
   370
	return ctx->plugin->info.publics_num;
dvander@159
   371
}
dvander@159
   372
dvander@159
   373
int BaseContext::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar)
dvander@159
   374
{
dvander@159
   375
	if (index >= ctx->plugin->info.pubvars_num)
dvander@159
   376
	{
dvander@159
   377
		return SP_ERROR_INDEX;
dvander@159
   378
	}
dvander@159
   379
dvander@159
   380
	if (pubvar)
dvander@159
   381
	{
dvander@159
   382
		*pubvar = &(ctx->pubvars[index]);
dvander@159
   383
	}
dvander@159
   384
dvander@159
   385
	return SP_ERROR_NONE;
dvander@159
   386
}
dvander@159
   387
dvander@159
   388
int BaseContext::FindPubvarByName(const char *name, uint32_t *index)
dvander@159
   389
{
dvander@159
   390
	int diff, high, low;
dvander@159
   391
	uint32_t mid;
dvander@159
   392
dvander@159
   393
	high = ctx->plugin->info.pubvars_num - 1;
dvander@159
   394
	low = 0;
dvander@159
   395
dvander@159
   396
	while (low <= high)
dvander@159
   397
	{
dvander@159
   398
		mid = (low + high) / 2;
dvander@159
   399
		diff = strcmp(ctx->pubvars[mid].name, name);
dvander@159
   400
		if (diff == 0)
dvander@159
   401
		{
dvander@159
   402
			if (index)
dvander@159
   403
			{
dvander@159
   404
				*index = mid;
dvander@159
   405
			}
dvander@159
   406
			return SP_ERROR_NONE;
dvander@159
   407
		} else if (diff < 0) {
dvander@159
   408
			low = mid + 1;
dvander@159
   409
		} else {
dvander@159
   410
			high = mid - 1;
dvander@159
   411
		}
dvander@159
   412
	}
dvander@159
   413
dvander@159
   414
	return SP_ERROR_NOT_FOUND;
dvander@159
   415
}
dvander@159
   416
dvander@159
   417
int BaseContext::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr)
dvander@159
   418
{
dvander@159
   419
	if (index >= ctx->plugin->info.pubvars_num)
dvander@159
   420
	{
dvander@159
   421
		return SP_ERROR_INDEX;
dvander@159
   422
	}
dvander@159
   423
dvander@159
   424
	*local_addr = ctx->plugin->info.pubvars[index].address;
dvander@159
   425
	*phys_addr = ctx->pubvars[index].offs;
dvander@159
   426
dvander@159
   427
	return SP_ERROR_NONE;
dvander@159
   428
}
dvander@159
   429
dvander@159
   430
uint32_t BaseContext::GetPubVarsNum()
dvander@159
   431
{
dvander@159
   432
	return ctx->plugin->info.pubvars_num;
dvander@159
   433
}
dvander@159
   434
dvander@159
   435
int BaseContext::BindNatives(sp_nativeinfo_t *natives, unsigned int num, int overwrite)
dvander@159
   436
{
dvander@159
   437
	uint32_t i, j, max;
dvander@159
   438
dvander@159
   439
	max = ctx->plugin->info.natives_num;
dvander@159
   440
dvander@159
   441
	for (i=0; i<max; i++)
dvander@159
   442
	{
dvander@164
   443
		if ((ctx->natives[i].status == SP_NATIVE_BOUND) && !overwrite)
dvander@159
   444
		{
dvander@159
   445
			continue;
dvander@159
   446
		}
dvander@159
   447
dvander@159
   448
		for (j=0; (natives[j].name) && (!num || j<num); j++)
dvander@159
   449
		{
dvander@159
   450
			if (!strcmp(ctx->natives[i].name, natives[j].name))
dvander@159
   451
			{
dvander@159
   452
				ctx->natives[i].pfn = natives[j].func;
dvander@164
   453
				ctx->natives[i].status = SP_NATIVE_BOUND;
dvander@159
   454
			}
dvander@159
   455
		}
dvander@159
   456
	}
dvander@159
   457
dvander@159
   458
	return SP_ERROR_NONE;
dvander@159
   459
}
dvander@159
   460
dvander@164
   461
int BaseContext::BindNative(sp_nativeinfo_t *native)
dvander@159
   462
{
dvander@159
   463
	uint32_t index;
dvander@159
   464
	int err;
dvander@159
   465
dvander@159
   466
	if ((err = FindNativeByName(native->name, &index)) != SP_ERROR_NONE)
dvander@159
   467
	{
dvander@159
   468
		return err;
dvander@159
   469
	}
dvander@159
   470
dvander@159
   471
	ctx->natives[index].pfn = native->func;
faluco@192
   472
	ctx->natives[index].status = SP_NATIVE_BOUND;
dvander@159
   473
dvander@159
   474
	return SP_ERROR_NONE;
dvander@159
   475
}
dvander@159
   476
dvander@159
   477
int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native)
dvander@159
   478
{
dvander@159
   479
	uint32_t nativesnum, i;
dvander@159
   480
dvander@159
   481
	nativesnum = ctx->plugin->info.natives_num;
dvander@159
   482
dvander@159
   483
	for (i=0; i<nativesnum; i++)
dvander@159
   484
	{
dvander@164
   485
		if (ctx->natives[i].status == SP_NATIVE_UNBOUND)
dvander@159
   486
		{
dvander@159
   487
			ctx->natives[i].pfn = native;
faluco@192
   488
			ctx->natives[i].status = SP_NATIVE_BOUND;
dvander@159
   489
		}
dvander@159
   490
	}
dvander@159
   491
dvander@159
   492
	return SP_ERROR_NONE;
dvander@159
   493
}
dvander@159
   494
dvander@159
   495
int BaseContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr)
dvander@159
   496
{
dvander@159
   497
	if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
dvander@159
   498
	{
dvander@159
   499
		return SP_ERROR_INVALID_ADDRESS;
dvander@159
   500
	}
dvander@159
   501
dvander@159
   502
	if (phys_addr)
dvander@159
   503
	{
dvander@159
   504
		*phys_addr = (cell_t *)(ctx->memory + local_addr);
dvander@159
   505
	}
dvander@159
   506
dvander@159
   507
	return SP_ERROR_NONE;
dvander@159
   508
}
dvander@159
   509
dvander@159
   510
int BaseContext::PushCell(cell_t value)
dvander@159
   511
{
dvander@159
   512
	if ((ctx->hp + STACKMARGIN) > (cell_t)(ctx->sp - sizeof(cell_t)))
dvander@159
   513
	{
dvander@159
   514
		return SP_ERROR_STACKLOW;
dvander@159
   515
	}
dvander@159
   516
dvander@159
   517
	ctx->sp -= sizeof(cell_t);
dvander@159
   518
	*(cell_t *)(ctx->memory + ctx->sp) = value;
dvander@159
   519
	ctx->pushcount++;
dvander@159
   520
dvander@159
   521
	return SP_ERROR_NONE;
dvander@159
   522
}
dvander@159
   523
dvander@159
   524
int BaseContext::PushCellsFromArray(cell_t array[], unsigned int numcells)
dvander@159
   525
{
dvander@159
   526
	unsigned int i;
dvander@159
   527
	int err;
dvander@159
   528
dvander@159
   529
	for (i=0; i<numcells; i++)
dvander@159
   530
	{
dvander@159
   531
		if ((err = PushCell(array[i])) != SP_ERROR_NONE)
dvander@159
   532
		{
dvander@159
   533
			ctx->sp += (cell_t)(i * sizeof(cell_t));
dvander@159
   534
			ctx->pushcount -= i;
dvander@159
   535
			return err;
dvander@159
   536
		}
dvander@159
   537
	}
dvander@159
   538
dvander@159
   539
	return SP_ERROR_NONE;
dvander@159
   540
}
dvander@159
   541
dvander@159
   542
int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells)
dvander@159
   543
{
dvander@159
   544
	cell_t *ph_addr;
dvander@159
   545
	int err;
dvander@159
   546
dvander@159
   547
	if ((err = HeapAlloc(numcells, local_addr, &ph_addr)) != SP_ERROR_NONE)
dvander@159
   548
	{
dvander@159
   549
		return err;
dvander@159
   550
	}
dvander@159
   551
dvander@159
   552
	memcpy(ph_addr, array, numcells * sizeof(cell_t));
dvander@159
   553
dvander@159
   554
	if ((err = PushCell(*local_addr)) != SP_ERROR_NONE)
dvander@159
   555
	{
dvander@159
   556
		HeapRelease(*local_addr);
dvander@159
   557
		return err;
dvander@159
   558
	}
dvander@159
   559
dvander@159
   560
	if (phys_addr)
dvander@159
   561
	{
dvander@159
   562
		*phys_addr = ph_addr;
dvander@159
   563
	}
dvander@159
   564
dvander@159
   565
	return SP_ERROR_NONE;
dvander@159
   566
}
dvander@159
   567
dvander@159
   568
int BaseContext::LocalToString(cell_t local_addr, char **addr)
dvander@159
   569
{
dvander@159
   570
	int len = 0;
dvander@159
   571
dvander@159
   572
	if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
dvander@159
   573
	{
dvander@159
   574
		return SP_ERROR_INVALID_ADDRESS;
dvander@159
   575
	}
dvander@159
   576
	*addr = (char *)(ctx->memory + local_addr);
dvander@159
   577
dvander@159
   578
	return SP_ERROR_NONE;
dvander@159
   579
}
dvander@159
   580
faluco@179
   581
int BaseContext::PushString(cell_t *local_addr, char **phys_addr, const char *string)
dvander@159
   582
{
faluco@179
   583
	char *ph_addr;
dvander@159
   584
	int err;
faluco@179
   585
	unsigned int len, numcells = ((len=strlen(string)) + sizeof(cell_t)) / sizeof(cell_t);
dvander@159
   586
faluco@179
   587
	if ((err = HeapAlloc(numcells, local_addr, (cell_t **)&ph_addr)) != SP_ERROR_NONE)
dvander@159
   588
	{
dvander@159
   589
		return err;
dvander@159
   590
	}
dvander@159
   591
faluco@179
   592
	memcpy(ph_addr, string, len);
faluco@179
   593
	ph_addr[len] = '\0';
dvander@159
   594
dvander@159
   595
	if ((err = PushCell(*local_addr)) != SP_ERROR_NONE)
dvander@159
   596
	{
dvander@159
   597
		HeapRelease(*local_addr);
dvander@159
   598
		return err;
dvander@159
   599
	}
dvander@159
   600
dvander@159
   601
	if (phys_addr)
dvander@159
   602
	{
dvander@159
   603
		*phys_addr = ph_addr;
dvander@159
   604
	}
dvander@159
   605
dvander@159
   606
	return SP_ERROR_NONE;
dvander@159
   607
}
dvander@159
   608
dvander@159
   609
int BaseContext::StringToLocal(cell_t local_addr, size_t chars, const char *source)
dvander@159
   610
{
faluco@179
   611
	char *dest;
faluco@179
   612
	int len;
dvander@159
   613
dvander@159
   614
	if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
dvander@159
   615
	{
dvander@159
   616
		return SP_ERROR_INVALID_ADDRESS;
dvander@159
   617
	}
dvander@159
   618
dvander@159
   619
	len = strlen(source);
faluco@179
   620
	dest = (char *)(ctx->memory + local_addr);
dvander@159
   621
dvander@159
   622
	if ((size_t)len >= chars)
dvander@159
   623
	{
dvander@159
   624
		len = chars - 1;
dvander@159
   625
	}
faluco@179
   626
	if (len <= 0)
faluco@179
   627
	{
faluco@179
   628
		return SP_ERROR_NONE;
faluco@179
   629
	}
dvander@159
   630
faluco@179
   631
	memcpy(dest, source, len);
faluco@179
   632
	dest[len] = '\0';
faluco@179
   633
faluco@179
   634
	return SP_ERROR_NONE;
faluco@179
   635
}
faluco@179
   636
faluco@179
   637
inline int __CheckValidChar(char *c)
faluco@179
   638
{
faluco@179
   639
	int count;
faluco@179
   640
	int bytecount = 0;
faluco@179
   641
faluco@184
   642
	for (count=1; (*c & 0xC0) == 0x80; count++)
faluco@179
   643
	{
faluco@179
   644
		c--;
faluco@179
   645
	}
faluco@179
   646
faluco@179
   647
	switch (*c & 0xF0)
dvander@159
   648
	{
faluco@179
   649
	case 0xC0:
faluco@179
   650
	case 0xD0:
faluco@179
   651
		{
faluco@179
   652
			bytecount = 2;
faluco@179
   653
			break;
faluco@179
   654
		}
faluco@179
   655
	case 0xE0:
faluco@179
   656
		{
faluco@179
   657
			bytecount = 3;
faluco@179
   658
			break;
faluco@179
   659
		}
faluco@179
   660
	case 0xF0:
faluco@179
   661
		{
faluco@179
   662
			bytecount = 4;
faluco@179
   663
			break;
faluco@179
   664
		}
faluco@179
   665
	}
faluco@179
   666
faluco@179
   667
	if (bytecount != count)
faluco@179
   668
	{
faluco@179
   669
		return count;
faluco@179
   670
	}
faluco@179
   671
faluco@179
   672
	return 0;
faluco@179
   673
}
faluco@179
   674
faluco@179
   675
int BaseContext::StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes)
faluco@179
   676
{
faluco@179
   677
	char *dest;
faluco@179
   678
	int len;
faluco@179
   679
	bool needtocheck = false;
faluco@179
   680
faluco@179
   681
	if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
faluco@179
   682
	{
faluco@179
   683
		return SP_ERROR_INVALID_ADDRESS;
faluco@179
   684
	}
faluco@179
   685
faluco@179
   686
	len = strlen(source);
faluco@179
   687
	dest = (char *)(ctx->memory + local_addr);
faluco@179
   688
faluco@179
   689
	if ((size_t)len >= maxbytes)
faluco@179
   690
	{
faluco@179
   691
		len = maxbytes - 1;
faluco@179
   692
		needtocheck = true;
faluco@179
   693
	}
faluco@179
   694
	if (len <= 0)
faluco@179
   695
	{
faluco@179
   696
		return SP_ERROR_NONE;
faluco@179
   697
	}
faluco@179
   698
faluco@179
   699
	memcpy(dest, source, len);
faluco@184
   700
	if ((dest[len-1] & 1<<7) && needtocheck)
faluco@179
   701
	{
faluco@179
   702
		len -= __CheckValidChar(dest+len-1);
dvander@159
   703
	}
dvander@159
   704
	dest[len] = '\0';
dvander@159
   705
faluco@179
   706
	if (wrtnbytes)
faluco@179
   707
	{
faluco@179
   708
		*wrtnbytes = len;
faluco@179
   709
	}
faluco@179
   710
dvander@159
   711
	return SP_ERROR_NONE;
dvander@159
   712
}
dvander@159
   713
dvander@159
   714
#define USHR(x) ((unsigned int)(x)>>1)
dvander@159
   715
dvander@159
   716
int BaseContext::LookupFile(ucell_t addr, const char **filename)
dvander@159
   717
{
dvander@159
   718
	int high, low, mid;
dvander@159
   719
dvander@159
   720
	high = ctx->plugin->debug.files_num;
dvander@159
   721
	low = -1;
dvander@159
   722
dvander@159
   723
	while (high - low > 1)
dvander@159
   724
	{
dvander@159
   725
		mid = USHR(low + high);
dvander@159
   726
		if (ctx->files[mid].addr <= addr)
dvander@159
   727
		{
dvander@159
   728
			low = mid;
dvander@159
   729
		} else {
dvander@159
   730
			high = mid;
dvander@159
   731
		}
dvander@159
   732
	}
dvander@159
   733
dvander@159
   734
	if (low == -1)
dvander@159
   735
	{
dvander@159
   736
		return SP_ERROR_NOT_FOUND;
dvander@159
   737
	}
dvander@159
   738
dvander@159
   739
	*filename = ctx->files[low].name;
dvander@159
   740
dvander@159
   741
	return SP_ERROR_NONE;
dvander@159
   742
}
dvander@159
   743
dvander@159
   744
int BaseContext::LookupFunction(ucell_t addr, const char **name)
dvander@159
   745
{
dvander@159
   746
	uint32_t iter, max = ctx->plugin->debug.syms_num;
dvander@159
   747
dvander@159
   748
	for (iter=0; iter<max; iter++)
dvander@159
   749
	{
dvander@159
   750
		if ((ctx->symbols[iter].sym->ident == SP_SYM_FUNCTION) 
dvander@159
   751
			&& (ctx->symbols[iter].codestart <= addr) 
dvander@159
   752
			&& (ctx->symbols[iter].codeend > addr))
dvander@159
   753
		{
dvander@159
   754
			break;
dvander@159
   755
		}
dvander@159
   756
	}
dvander@159
   757
dvander@159
   758
	if (iter >= max)
dvander@159
   759
	{
dvander@159
   760
		return SP_ERROR_NOT_FOUND;
dvander@159
   761
	}
dvander@159
   762
dvander@159
   763
	*name = ctx->symbols[iter].name;
dvander@159
   764
dvander@159
   765
	return SP_ERROR_NONE;
dvander@159
   766
}
dvander@159
   767
dvander@159
   768
int BaseContext::LookupLine(ucell_t addr, uint32_t *line)
dvander@159
   769
{
dvander@159
   770
	int high, low, mid;
dvander@159
   771
dvander@159
   772
	high = ctx->plugin->debug.lines_num;
dvander@159
   773
	low = -1;
dvander@159
   774
dvander@159
   775
	while (high - low > 1)
dvander@159
   776
	{
dvander@159
   777
		mid = USHR(low + high);
dvander@159
   778
		if (ctx->lines[mid].addr <= addr)
dvander@159
   779
		{
dvander@159
   780
			low = mid;
dvander@159
   781
		} else {
dvander@159
   782
			high = mid;
dvander@159
   783
		}
dvander@159
   784
	}
dvander@159
   785
dvander@159
   786
	if (low == -1)
dvander@159
   787
	{
dvander@159
   788
		return SP_ERROR_NOT_FOUND;
dvander@159
   789
	}
dvander@159
   790
dvander@246
   791
	/* Since the CIP occurs BEFORE the line, we have to add one */
dvander@246
   792
	*line = ctx->lines[low].line + 1;
dvander@159
   793
dvander@159
   794
	return SP_ERROR_NONE;
dvander@159
   795
}
dvander@262
   796
dvander@262
   797
#if defined SOURCEMOD_BUILD
dvander@262
   798
SourceMod::IdentityToken_t *BaseContext::GetIdentity()
dvander@262
   799
{
dvander@262
   800
	return m_pToken;
dvander@262
   801
}
dvander@262
   802
dvander@262
   803
void BaseContext::SetIdentity(SourceMod::IdentityToken_t *token)
dvander@262
   804
{
dvander@262
   805
	m_pToken = token;
dvander@262
   806
}
dvander@262
   807
#endif