1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/core/vm/sp_vm_basecontext.cpp Wed Nov 08 06:30:20 2006 +0000
1.3 @@ -0,0 +1,617 @@
1.4 +#include <string.h>
1.5 +#include <assert.h>
1.6 +#include <limits.h>
1.7 +#include "sp_vm_api.h"
1.8 +#include "sp_vm_basecontext.h"
1.9 +
1.10 +using namespace SourcePawn;
1.11 +
1.12 +#define CELLBOUNDMAX (INT_MAX/sizeof(cell_t))
1.13 +#define STACKMARGIN ((cell_t)(16*sizeof(cell_t)))
1.14 +
1.15 +BaseContext::BaseContext(sp_context_t *_ctx)
1.16 +{
1.17 + ctx = _ctx;
1.18 + ctx->context = this;
1.19 +}
1.20 +
1.21 +IVirtualMachine *BaseContext::GetVirtualMachine()
1.22 +{
1.23 + return (IVirtualMachine *)ctx->vmbase;
1.24 +}
1.25 +
1.26 +sp_context_t *BaseContext::GetContext()
1.27 +{
1.28 + return ctx;
1.29 +}
1.30 +
1.31 +bool BaseContext::IsDebugging()
1.32 +{
1.33 + return (ctx->flags & SPFLAG_PLUGIN_DEBUG);
1.34 +}
1.35 +
1.36 +int BaseContext::SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn)
1.37 +{
1.38 + if (!IsDebugging())
1.39 + {
1.40 + return SP_ERROR_NOTDEBUGGING;
1.41 + }
1.42 +
1.43 + *oldpfn = ctx->dbreak;
1.44 + ctx->dbreak = newpfn;
1.45 +
1.46 + return SP_ERROR_NONE;
1.47 +}
1.48 +
1.49 +IPluginDebugInfo *BaseContext::GetDebugInfo()
1.50 +{
1.51 + return this;
1.52 +}
1.53 +
1.54 +int BaseContext::Execute(uint32_t public_func, cell_t *result)
1.55 +{
1.56 + IVirtualMachine *vm = (IVirtualMachine *)ctx->vmbase;
1.57 +
1.58 + uint32_t pushcount = ctx->pushcount;
1.59 +
1.60 + int err;
1.61 + sp_public_t *pubfunc;
1.62 + if ((err=GetPublicByIndex(public_func, &pubfunc)) != SP_ERROR_NONE)
1.63 + {
1.64 + return err;
1.65 + }
1.66 +
1.67 + PushCell(pushcount++);
1.68 + ctx->pushcount = 0;
1.69 +
1.70 + cell_t save_sp = ctx->sp;
1.71 + cell_t save_hp = ctx->hp;
1.72 +
1.73 + err = vm->ContextExecute(ctx, pubfunc->offs, result);
1.74 +
1.75 + /**
1.76 + * :TODO: turn this into an error check
1.77 + */
1.78 +
1.79 +#if defined _DEBUG
1.80 + if (err == SP_ERROR_NONE)
1.81 + {
1.82 + assert(ctx->sp - pushcount * sizeof(cell_t) == save_sp);
1.83 + assert(ctx->hp == save_hp);
1.84 + }
1.85 +#endif
1.86 + if (err != SP_ERROR_NONE)
1.87 + {
1.88 + ctx->sp = save_sp;
1.89 + ctx->hp = save_hp;
1.90 + }
1.91 +
1.92 + return err;
1.93 +}
1.94 +
1.95 +int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr)
1.96 +{
1.97 + cell_t *addr;
1.98 + ucell_t realmem;
1.99 +
1.100 +#if 0
1.101 + if (cells > CELLBOUNDMAX)
1.102 + {
1.103 + return SP_ERROR_ARAM;
1.104 + }
1.105 +#else
1.106 + assert(cells < CELLBOUNDMAX);
1.107 +#endif
1.108 +
1.109 + realmem = cells * sizeof(cell_t);
1.110 +
1.111 + /**
1.112 + * Check if the space between the heap and stack is sufficient.
1.113 + */
1.114 + if ((cell_t)(ctx->sp - ctx->hp - realmem) < STACKMARGIN)
1.115 + {
1.116 + return SP_ERROR_HEAPLOW;
1.117 + }
1.118 +
1.119 + addr = (cell_t *)(ctx->memory + ctx->hp);
1.120 + /* store size of allocation in cells */
1.121 + *addr = (cell_t)cells;
1.122 + addr++;
1.123 + ctx->hp += sizeof(cell_t);
1.124 +
1.125 + *local_addr = ctx->hp;
1.126 +
1.127 + if (phys_addr)
1.128 + {
1.129 + *phys_addr = addr;
1.130 + }
1.131 +
1.132 + ctx->hp += realmem;
1.133 +
1.134 + return SP_ERROR_NONE;
1.135 +}
1.136 +
1.137 +int BaseContext::HeapPop(cell_t local_addr)
1.138 +{
1.139 + cell_t cellcount;
1.140 + cell_t *addr;
1.141 +
1.142 + /* check the bounds of this address */
1.143 + local_addr -= sizeof(cell_t);
1.144 + if (local_addr < ctx->heap_base || local_addr >= ctx->sp)
1.145 + {
1.146 + return SP_ERROR_INVALID_ADDRESS;
1.147 + }
1.148 +
1.149 + addr = (cell_t *)(ctx->memory + local_addr);
1.150 + cellcount = (*addr) * sizeof(cell_t);
1.151 + /* check if this memory count looks valid */
1.152 + if (ctx->hp - cellcount - sizeof(cell_t) != local_addr)
1.153 + {
1.154 + return SP_ERROR_INVALID_ADDRESS;
1.155 + }
1.156 +
1.157 + ctx->hp = local_addr;
1.158 +
1.159 + return SP_ERROR_NONE;
1.160 +}
1.161 +
1.162 +
1.163 +int BaseContext::HeapRelease(cell_t local_addr)
1.164 +{
1.165 + if (local_addr < ctx->heap_base)
1.166 + {
1.167 + return SP_ERROR_INVALID_ADDRESS;
1.168 + }
1.169 +
1.170 + ctx->hp = local_addr - sizeof(cell_t);
1.171 +
1.172 + return SP_ERROR_NONE;
1.173 +}
1.174 +
1.175 +int BaseContext::FindNativeByName(const char *name, uint32_t *index)
1.176 +{
1.177 + int diff, high, low;
1.178 + uint32_t mid;
1.179 +
1.180 + high = ctx->plugin->info.natives_num - 1;
1.181 + low = 0;
1.182 +
1.183 + while (low <= high)
1.184 + {
1.185 + mid = (low + high) / 2;
1.186 + diff = strcmp(ctx->natives[mid].name, name);
1.187 + if (diff == 0)
1.188 + {
1.189 + if (index)
1.190 + {
1.191 + *index = mid;
1.192 + }
1.193 + return SP_ERROR_NONE;
1.194 + } else if (diff < 0) {
1.195 + low = mid + 1;
1.196 + } else {
1.197 + high = mid - 1;
1.198 + }
1.199 + }
1.200 +
1.201 + return SP_ERROR_NOT_FOUND;
1.202 +}
1.203 +
1.204 +int BaseContext::GetNativeByIndex(uint32_t index, sp_native_t **native)
1.205 +{
1.206 + if (index >= ctx->plugin->info.natives_num)
1.207 + {
1.208 + return SP_ERROR_INDEX;
1.209 + }
1.210 +
1.211 + if (native)
1.212 + {
1.213 + *native = &(ctx->natives[index]);
1.214 + }
1.215 +
1.216 + return SP_ERROR_NONE;
1.217 +}
1.218 +
1.219 +
1.220 +uint32_t BaseContext::GetNativesNum()
1.221 +{
1.222 + return ctx->plugin->info.natives_num;
1.223 +}
1.224 +
1.225 +int BaseContext::FindPublicByName(const char *name, uint32_t *index)
1.226 +{
1.227 + int diff, high, low;
1.228 + uint32_t mid;
1.229 +
1.230 + high = ctx->plugin->info.publics_num - 1;
1.231 + low = 0;
1.232 +
1.233 + while (low <= high)
1.234 + {
1.235 + mid = (low + high) / 2;
1.236 + diff = strcmp(ctx->publics[mid].name, name);
1.237 + if (diff == 0)
1.238 + {
1.239 + if (index)
1.240 + {
1.241 + *index = mid;
1.242 + }
1.243 + return SP_ERROR_NONE;
1.244 + } else if (diff < 0) {
1.245 + low = mid + 1;
1.246 + } else {
1.247 + high = mid - 1;
1.248 + }
1.249 + }
1.250 +
1.251 + return SP_ERROR_NOT_FOUND;
1.252 +}
1.253 +
1.254 +int BaseContext::GetPublicByIndex(uint32_t index, sp_public_t **pblic)
1.255 +{
1.256 + if (index >= ctx->plugin->info.publics_num)
1.257 + {
1.258 + return SP_ERROR_INDEX;
1.259 + }
1.260 +
1.261 + if (pblic)
1.262 + {
1.263 + *pblic = &(ctx->publics[index]);
1.264 + }
1.265 +
1.266 + return SP_ERROR_NONE;
1.267 +}
1.268 +
1.269 +uint32_t BaseContext::GetPublicsNum()
1.270 +{
1.271 + return ctx->plugin->info.publics_num;
1.272 +}
1.273 +
1.274 +int BaseContext::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar)
1.275 +{
1.276 + if (index >= ctx->plugin->info.pubvars_num)
1.277 + {
1.278 + return SP_ERROR_INDEX;
1.279 + }
1.280 +
1.281 + if (pubvar)
1.282 + {
1.283 + *pubvar = &(ctx->pubvars[index]);
1.284 + }
1.285 +
1.286 + return SP_ERROR_NONE;
1.287 +}
1.288 +
1.289 +int BaseContext::FindPubvarByName(const char *name, uint32_t *index)
1.290 +{
1.291 + int diff, high, low;
1.292 + uint32_t mid;
1.293 +
1.294 + high = ctx->plugin->info.pubvars_num - 1;
1.295 + low = 0;
1.296 +
1.297 + while (low <= high)
1.298 + {
1.299 + mid = (low + high) / 2;
1.300 + diff = strcmp(ctx->pubvars[mid].name, name);
1.301 + if (diff == 0)
1.302 + {
1.303 + if (index)
1.304 + {
1.305 + *index = mid;
1.306 + }
1.307 + return SP_ERROR_NONE;
1.308 + } else if (diff < 0) {
1.309 + low = mid + 1;
1.310 + } else {
1.311 + high = mid - 1;
1.312 + }
1.313 + }
1.314 +
1.315 + return SP_ERROR_NOT_FOUND;
1.316 +}
1.317 +
1.318 +int BaseContext::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr)
1.319 +{
1.320 + if (index >= ctx->plugin->info.pubvars_num)
1.321 + {
1.322 + return SP_ERROR_INDEX;
1.323 + }
1.324 +
1.325 + *local_addr = ctx->plugin->info.pubvars[index].address;
1.326 + *phys_addr = ctx->pubvars[index].offs;
1.327 +
1.328 + return SP_ERROR_NONE;
1.329 +}
1.330 +
1.331 +uint32_t BaseContext::GetPubVarsNum()
1.332 +{
1.333 + return ctx->plugin->info.pubvars_num;
1.334 +}
1.335 +
1.336 +int BaseContext::BindNatives(sp_nativeinfo_t *natives, unsigned int num, int overwrite)
1.337 +{
1.338 + uint32_t i, j, max;
1.339 +
1.340 + max = ctx->plugin->info.natives_num;
1.341 +
1.342 + for (i=0; i<max; i++)
1.343 + {
1.344 + if ((ctx->natives[i].status == SP_NATIVE_OKAY) && !overwrite)
1.345 + {
1.346 + continue;
1.347 + }
1.348 +
1.349 + for (j=0; (natives[j].name) && (!num || j<num); j++)
1.350 + {
1.351 + if (!strcmp(ctx->natives[i].name, natives[j].name))
1.352 + {
1.353 + ctx->natives[i].pfn = natives[j].func;
1.354 + ctx->natives[i].status = SP_NATIVE_OKAY;
1.355 + }
1.356 + }
1.357 + }
1.358 +
1.359 + return SP_ERROR_NONE;
1.360 +}
1.361 +
1.362 +int BaseContext::BindNative(sp_nativeinfo_t *native, uint32_t status)
1.363 +{
1.364 + uint32_t index;
1.365 + int err;
1.366 +
1.367 + if ((err = FindNativeByName(native->name, &index)) != SP_ERROR_NONE)
1.368 + {
1.369 + return err;
1.370 + }
1.371 +
1.372 + ctx->natives[index].pfn = native->func;
1.373 + ctx->natives[index].status = status;
1.374 +
1.375 + return SP_ERROR_NONE;
1.376 +}
1.377 +
1.378 +int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native)
1.379 +{
1.380 + uint32_t nativesnum, i;
1.381 +
1.382 + nativesnum = ctx->plugin->info.natives_num;
1.383 +
1.384 + for (i=0; i<nativesnum; i++)
1.385 + {
1.386 + if (ctx->natives[i].status != SP_NATIVE_OKAY)
1.387 + {
1.388 + ctx->natives[i].pfn = native;
1.389 + ctx->natives[i].status = SP_NATIVE_PENDING;
1.390 + }
1.391 + }
1.392 +
1.393 + return SP_ERROR_NONE;
1.394 +}
1.395 +
1.396 +int BaseContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr)
1.397 +{
1.398 + if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
1.399 + {
1.400 + return SP_ERROR_INVALID_ADDRESS;
1.401 + }
1.402 +
1.403 + if (phys_addr)
1.404 + {
1.405 + *phys_addr = (cell_t *)(ctx->memory + local_addr);
1.406 + }
1.407 +
1.408 + return SP_ERROR_NONE;
1.409 +}
1.410 +
1.411 +int BaseContext::PushCell(cell_t value)
1.412 +{
1.413 + if ((ctx->hp + STACKMARGIN) > (cell_t)(ctx->sp - sizeof(cell_t)))
1.414 + {
1.415 + return SP_ERROR_STACKLOW;
1.416 + }
1.417 +
1.418 + ctx->sp -= sizeof(cell_t);
1.419 + *(cell_t *)(ctx->memory + ctx->sp) = value;
1.420 + ctx->pushcount++;
1.421 +
1.422 + return SP_ERROR_NONE;
1.423 +}
1.424 +
1.425 +int BaseContext::PushCellsFromArray(cell_t array[], unsigned int numcells)
1.426 +{
1.427 + unsigned int i;
1.428 + int err;
1.429 +
1.430 + for (i=0; i<numcells; i++)
1.431 + {
1.432 + if ((err = PushCell(array[i])) != SP_ERROR_NONE)
1.433 + {
1.434 + ctx->sp += (cell_t)(i * sizeof(cell_t));
1.435 + ctx->pushcount -= i;
1.436 + return err;
1.437 + }
1.438 + }
1.439 +
1.440 + return SP_ERROR_NONE;
1.441 +}
1.442 +
1.443 +int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells)
1.444 +{
1.445 + cell_t *ph_addr;
1.446 + int err;
1.447 +
1.448 + if ((err = HeapAlloc(numcells, local_addr, &ph_addr)) != SP_ERROR_NONE)
1.449 + {
1.450 + return err;
1.451 + }
1.452 +
1.453 + memcpy(ph_addr, array, numcells * sizeof(cell_t));
1.454 +
1.455 + if ((err = PushCell(*local_addr)) != SP_ERROR_NONE)
1.456 + {
1.457 + HeapRelease(*local_addr);
1.458 + return err;
1.459 + }
1.460 +
1.461 + if (phys_addr)
1.462 + {
1.463 + *phys_addr = ph_addr;
1.464 + }
1.465 +
1.466 + return SP_ERROR_NONE;
1.467 +}
1.468 +
1.469 +int BaseContext::LocalToString(cell_t local_addr, char **addr)
1.470 +{
1.471 + int len = 0;
1.472 +
1.473 + if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
1.474 + {
1.475 + return SP_ERROR_INVALID_ADDRESS;
1.476 + }
1.477 + *addr = (char *)(ctx->memory + local_addr);
1.478 +
1.479 + return SP_ERROR_NONE;
1.480 +}
1.481 +
1.482 +int BaseContext::PushString(cell_t *local_addr, cell_t **phys_addr, const char *string)
1.483 +{
1.484 + cell_t *ph_addr;
1.485 + int err;
1.486 + unsigned int i, numcells = strlen(string);
1.487 +
1.488 + if ((err = HeapAlloc(numcells+1, local_addr, &ph_addr)) != SP_ERROR_NONE)
1.489 + {
1.490 + return err;
1.491 + }
1.492 +
1.493 + for (i=0; i<numcells; i++)
1.494 + {
1.495 + ph_addr[i] = (cell_t)string[i];
1.496 + }
1.497 + ph_addr[numcells] = '\0';
1.498 +
1.499 + if ((err = PushCell(*local_addr)) != SP_ERROR_NONE)
1.500 + {
1.501 + HeapRelease(*local_addr);
1.502 + return err;
1.503 + }
1.504 +
1.505 + if (phys_addr)
1.506 + {
1.507 + *phys_addr = ph_addr;
1.508 + }
1.509 +
1.510 + return SP_ERROR_NONE;
1.511 +}
1.512 +
1.513 +int BaseContext::StringToLocal(cell_t local_addr, size_t chars, const char *source)
1.514 +{
1.515 + cell_t *dest;
1.516 + int i, len;
1.517 +
1.518 + if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
1.519 + {
1.520 + return SP_ERROR_INVALID_ADDRESS;
1.521 + }
1.522 +
1.523 + len = strlen(source);
1.524 + dest = (cell_t *)(ctx->memory + local_addr);
1.525 +
1.526 + if ((size_t)len >= chars)
1.527 + {
1.528 + len = chars - 1;
1.529 + }
1.530 +
1.531 + for (i=0; i<len; i++)
1.532 + {
1.533 + dest[i] = (cell_t)source[i];
1.534 + }
1.535 + dest[len] = '\0';
1.536 +
1.537 + return SP_ERROR_NONE;
1.538 +}
1.539 +
1.540 +#define USHR(x) ((unsigned int)(x)>>1)
1.541 +
1.542 +int BaseContext::LookupFile(ucell_t addr, const char **filename)
1.543 +{
1.544 + int high, low, mid;
1.545 +
1.546 + high = ctx->plugin->debug.files_num;
1.547 + low = -1;
1.548 +
1.549 + while (high - low > 1)
1.550 + {
1.551 + mid = USHR(low + high);
1.552 + if (ctx->files[mid].addr <= addr)
1.553 + {
1.554 + low = mid;
1.555 + } else {
1.556 + high = mid;
1.557 + }
1.558 + }
1.559 +
1.560 + if (low == -1)
1.561 + {
1.562 + return SP_ERROR_NOT_FOUND;
1.563 + }
1.564 +
1.565 + *filename = ctx->files[low].name;
1.566 +
1.567 + return SP_ERROR_NONE;
1.568 +}
1.569 +
1.570 +int BaseContext::LookupFunction(ucell_t addr, const char **name)
1.571 +{
1.572 + uint32_t iter, max = ctx->plugin->debug.syms_num;
1.573 +
1.574 + for (iter=0; iter<max; iter++)
1.575 + {
1.576 + if ((ctx->symbols[iter].sym->ident == SP_SYM_FUNCTION)
1.577 + && (ctx->symbols[iter].codestart <= addr)
1.578 + && (ctx->symbols[iter].codeend > addr))
1.579 + {
1.580 + break;
1.581 + }
1.582 + }
1.583 +
1.584 + if (iter >= max)
1.585 + {
1.586 + return SP_ERROR_NOT_FOUND;
1.587 + }
1.588 +
1.589 + *name = ctx->symbols[iter].name;
1.590 +
1.591 + return SP_ERROR_NONE;
1.592 +}
1.593 +
1.594 +int BaseContext::LookupLine(ucell_t addr, uint32_t *line)
1.595 +{
1.596 + int high, low, mid;
1.597 +
1.598 + high = ctx->plugin->debug.lines_num;
1.599 + low = -1;
1.600 +
1.601 + while (high - low > 1)
1.602 + {
1.603 + mid = USHR(low + high);
1.604 + if (ctx->lines[mid].addr <= addr)
1.605 + {
1.606 + low = mid;
1.607 + } else {
1.608 + high = mid;
1.609 + }
1.610 + }
1.611 +
1.612 + if (low == -1)
1.613 + {
1.614 + return SP_ERROR_NOT_FOUND;
1.615 + }
1.616 +
1.617 + *line = ctx->lines[low].line;
1.618 +
1.619 + return SP_ERROR_NONE;
1.620 +}