sourcepawn/jit/BaseRuntime.cpp
author David Anderson <dvander@alliedmods.net>
Mon Oct 27 02:02:14 2008 -0500 (2008-10-27)
changeset 2378 d812052c5821
parent 2377 6ee3bbd6fbdf
child 2545 9cb1a1fefc2c
permissions -rw-r--r--
Fixed horrendous crash in the JIT from packing change in the debug table (bug 3334, r=me).
I accidentally changed the debug table packing in a commit a while ago. This explains the nonsense debug output and crashes people have been getting on the 1.1 branch. Fortunately this is (mostly) detectable via the "debug.natives" table and the JIT will unpack symbols based on that information.
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <string.h>
     4 #include <assert.h>
     5 #include "BaseRuntime.h"
     6 #include "sp_vm_engine.h"
     7 #include "x86/jit_x86.h"
     8 #include "sp_vm_basecontext.h"
     9 #include "engine2.h"
    10 
    11 using namespace SourcePawn;
    12 
    13 BaseRuntime::BaseRuntime() : m_Debug(&m_plugin), m_pPlugin(&m_plugin), m_pCtx(NULL), 
    14 m_PubFuncs(NULL), m_PubJitFuncs(NULL), m_pCo(NULL), m_CompSerial(0)
    15 {
    16 	memset(&m_plugin, 0, sizeof(m_plugin));
    17 
    18 	m_FuncCache = NULL;
    19 	m_MaxFuncs = 0;
    20 	m_NumFuncs = 0;
    21 }
    22 
    23 BaseRuntime::~BaseRuntime()
    24 {
    25 	for (uint32_t i = 0; i < m_pPlugin->num_publics; i++)
    26 	{
    27 		delete m_PubFuncs[i];
    28 		m_PubFuncs[i] = NULL;
    29 	}
    30 	delete [] m_PubFuncs;
    31 	delete [] m_PubJitFuncs;
    32 
    33 	for (unsigned int i = 0; i < m_NumFuncs; i++)
    34 	{
    35 		delete m_FuncCache[i];
    36 	}
    37 	free(m_FuncCache);
    38 
    39 	delete m_pCtx;
    40 	if (m_pCo != NULL)
    41 	{
    42 		m_pCo->Abort();
    43 	}
    44 
    45 	free(m_pPlugin->base);
    46 	delete [] m_pPlugin->memory;
    47 	delete [] m_pPlugin->publics;
    48 	delete [] m_pPlugin->pubvars;
    49 	delete [] m_pPlugin->natives;
    50 	free(m_pPlugin->name);
    51 }
    52 
    53 static cell_t InvalidNative(IPluginContext *pCtx, const cell_t *params)
    54 {
    55 	return pCtx->ThrowNativeErrorEx(SP_ERROR_INVALID_NATIVE, "Invalid native");
    56 }
    57 
    58 int BaseRuntime::CreateFromMemory(sp_file_hdr_t *hdr, uint8_t *base)
    59 {
    60 	int set_err;
    61 	char *nameptr;
    62 	uint8_t sectnum = 0;
    63 	sp_plugin_t *plugin = m_pPlugin;
    64 	sp_file_section_t *secptr = (sp_file_section_t *)(base + sizeof(sp_file_hdr_t));
    65 
    66 	memset(plugin, 0, sizeof(sp_plugin_t));
    67 
    68 	plugin->base = base;
    69 	plugin->base_size = hdr->imagesize;
    70 	set_err = SP_ERROR_NONE;
    71 
    72 	if (hdr->version == 0x0101)
    73 	{
    74 		plugin->debug.unpacked = true;
    75 	}
    76 
    77 	/* We have to read the name section first */
    78 	for (sectnum = 0; sectnum < hdr->sections; sectnum++)
    79 	{
    80 		nameptr = (char *)(base + hdr->stringtab + secptr[sectnum].nameoffs);
    81 		if (strcmp(nameptr, ".names") == 0)
    82 		{
    83 			plugin->stringbase = (const char *)(base + secptr[sectnum].dataoffs);
    84 			break;
    85 		}
    86 	}
    87 
    88 	sectnum = 0;
    89 
    90 	/* Now read the rest of the sections */
    91 	while (sectnum < hdr->sections)
    92 	{
    93 		nameptr = (char *)(base + hdr->stringtab + secptr->nameoffs);
    94 
    95 		if (!(plugin->pcode) && !strcmp(nameptr, ".code"))
    96 		{
    97 			sp_file_code_t *cod = (sp_file_code_t *)(base + secptr->dataoffs);
    98 
    99 			if (cod->codeversion < SP_CODEVERS_JIT1)
   100 			{
   101 				return SP_ERROR_CODE_TOO_OLD;
   102 			}
   103 			else if (cod->codeversion > SP_CODEVERS_JIT2)
   104 			{
   105 				return SP_ERROR_CODE_TOO_NEW;
   106 			}
   107 
   108 			plugin->pcode = base + secptr->dataoffs + cod->code;
   109 			plugin->pcode_size = cod->codesize;
   110 			plugin->flags = cod->flags;
   111 			plugin->pcode_version = cod->codeversion;
   112 		}
   113 		else if (!(plugin->data) && !strcmp(nameptr, ".data"))
   114 		{
   115 			sp_file_data_t *dat = (sp_file_data_t *)(base + secptr->dataoffs);
   116 			plugin->data = base + secptr->dataoffs + dat->data;
   117 			plugin->data_size = dat->datasize;
   118 			plugin->mem_size = dat->memsize;
   119 			plugin->memory = new uint8_t[plugin->mem_size];
   120 			memcpy(plugin->memory, plugin->data, plugin->data_size);
   121 		}
   122 		else if ((plugin->publics == NULL) && !strcmp(nameptr, ".publics"))
   123 		{
   124 			sp_file_publics_t *publics;
   125 
   126 			publics = (sp_file_publics_t *)(base + secptr->dataoffs);
   127 			plugin->num_publics = secptr->size / sizeof(sp_file_publics_t);
   128 
   129 			if (plugin->num_publics > 0)
   130 			{
   131 				plugin->publics = new sp_public_t[plugin->num_publics];
   132 
   133 				for (uint32_t i = 0; i < plugin->num_publics; i++)
   134 				{
   135 					plugin->publics[i].code_offs = publics[i].address;
   136 					plugin->publics[i].funcid = (i << 1) | 1;
   137 					plugin->publics[i].name = plugin->stringbase + publics[i].name;
   138 				}
   139 			}
   140 		}
   141 		else if ((plugin->pubvars == NULL) && !strcmp(nameptr, ".pubvars"))
   142 		{
   143 			sp_file_pubvars_t *pubvars;
   144 
   145 			pubvars = (sp_file_pubvars_t *)(base + secptr->dataoffs);
   146 			plugin->num_pubvars = secptr->size / sizeof(sp_file_pubvars_t);
   147 
   148 			if (plugin->num_pubvars > 0)
   149 			{
   150 				plugin->pubvars = new sp_pubvar_t[plugin->num_pubvars];
   151 
   152 				for (uint32_t i = 0; i < plugin->num_pubvars; i++)
   153 				{
   154 					plugin->pubvars[i].name = plugin->stringbase + pubvars[i].name;
   155 					plugin->pubvars[i].offs = (cell_t *)(plugin->memory + pubvars[i].address);
   156 				}
   157 			}
   158 		}
   159 		else if ((plugin->natives == NULL) && !strcmp(nameptr, ".natives"))
   160 		{
   161 			sp_file_natives_t *natives;
   162 
   163 			natives = (sp_file_natives_t *)(base + secptr->dataoffs);
   164 			plugin->num_natives = secptr->size / sizeof(sp_file_natives_t);
   165 
   166 			if (plugin->num_natives > 0)
   167 			{
   168 				plugin->natives = new sp_native_t[plugin->num_natives];
   169 
   170 				for (uint32_t i = 0; i < plugin->num_natives; i++)
   171 				{
   172 					plugin->natives[i].flags = 0;
   173 					plugin->natives[i].pfn = InvalidNative;
   174 					plugin->natives[i].status = SP_NATIVE_UNBOUND;
   175 					plugin->natives[i].user = NULL;
   176 					plugin->natives[i].name = plugin->stringbase + natives[i].name;
   177 				}
   178 			}
   179 		}
   180 		else if (!(plugin->debug.files) && !strcmp(nameptr, ".dbg.files"))
   181 		{
   182 			plugin->debug.files = (sp_fdbg_file_t *)(base + secptr->dataoffs);
   183 		}
   184 		else if (!(plugin->debug.lines) && !strcmp(nameptr, ".dbg.lines"))
   185 		{
   186 			plugin->debug.lines = (sp_fdbg_line_t *)(base + secptr->dataoffs);
   187 		}
   188 		else if (!(plugin->debug.symbols) && !strcmp(nameptr, ".dbg.symbols"))
   189 		{
   190 			plugin->debug.symbols = (sp_fdbg_symbol_t *)(base + secptr->dataoffs);
   191 		}
   192 		else if (!(plugin->debug.lines_num) && !strcmp(nameptr, ".dbg.info"))
   193 		{
   194 			sp_fdbg_info_t *inf = (sp_fdbg_info_t *)(base + secptr->dataoffs);
   195 			plugin->debug.files_num = inf->num_files;
   196 			plugin->debug.lines_num = inf->num_lines;
   197 			plugin->debug.syms_num = inf->num_syms;
   198 		}
   199 		else if (!(plugin->debug.stringbase) && !strcmp(nameptr, ".dbg.strings"))
   200 		{
   201 			plugin->debug.stringbase = (const char *)(base + secptr->dataoffs);
   202 		}
   203 		else if (strcmp(nameptr, ".dbg.natives") == 0)
   204 		{
   205 			plugin->debug.unpacked = false;
   206 		}
   207 
   208 		secptr++;
   209 		sectnum++;
   210 	}
   211 
   212 	if (plugin->pcode == NULL || plugin->data == NULL)
   213 	{
   214 		return SP_ERROR_FILE_FORMAT;
   215 	}
   216 
   217 	if ((plugin->flags & SP_FLAG_DEBUG) && (!(plugin->debug.files) || !(plugin->debug.lines) || !(plugin->debug.symbols)))
   218 	{
   219 		return SP_ERROR_FILE_FORMAT;
   220 	}
   221 
   222 	if (m_pPlugin->num_publics > 0)
   223 	{
   224 		m_PubFuncs = new CFunction *[m_pPlugin->num_publics];
   225 		memset(m_PubFuncs, 0, sizeof(CFunction *) * m_pPlugin->num_publics);
   226 		m_PubJitFuncs = new JitFunction *[m_pPlugin->num_publics];
   227 		memset(m_PubJitFuncs, 0, sizeof(JitFunction *) * m_pPlugin->num_publics);
   228 	}
   229 
   230 	m_pPlugin->profiler = g_engine2.GetProfiler();
   231 	m_pCtx = new BaseContext(this);
   232 	m_pCo = g_Jit.StartCompilation(this);
   233 
   234 	return SP_ERROR_NONE;
   235 }
   236 
   237 int BaseRuntime::FindNativeByName(const char *name, uint32_t *index)
   238 {
   239 	int high;
   240 
   241 	high = m_pPlugin->num_natives - 1;
   242 
   243 	for (uint32_t i=0; i<m_pPlugin->num_natives; i++)
   244 	{
   245 		if (strcmp(m_pPlugin->natives[i].name, name) == 0)
   246 		{
   247 			if (index)
   248 			{
   249 				*index = i;
   250 			}
   251 			return SP_ERROR_NONE;
   252 		}
   253 	}
   254 
   255 	return SP_ERROR_NOT_FOUND;
   256 }
   257 
   258 int BaseRuntime::GetNativeByIndex(uint32_t index, sp_native_t **native)
   259 {
   260 	if (index >= m_pPlugin->num_natives)
   261 	{
   262 		return SP_ERROR_INDEX;
   263 	}
   264 
   265 	if (native)
   266 	{
   267 		*native = &(m_pPlugin->natives[index]);
   268 	}
   269 
   270 	return SP_ERROR_NONE;
   271 }
   272 
   273 
   274 uint32_t BaseRuntime::GetNativesNum()
   275 {
   276 	return m_pPlugin->num_natives;
   277 }
   278 
   279 int BaseRuntime::FindPublicByName(const char *name, uint32_t *index)
   280 {
   281 	int diff, high, low;
   282 	uint32_t mid;
   283 
   284 	high = m_pPlugin->num_publics - 1;
   285 	low = 0;
   286 
   287 	while (low <= high)
   288 	{
   289 		mid = (low + high) / 2;
   290 		diff = strcmp(m_pPlugin->publics[mid].name, name);
   291 		if (diff == 0)
   292 		{
   293 			if (index)
   294 			{
   295 				*index = mid;
   296 			}
   297 			return SP_ERROR_NONE;
   298 		} else if (diff < 0) {
   299 			low = mid + 1;
   300 		} else {
   301 			high = mid - 1;
   302 		}
   303 	}
   304 
   305 	return SP_ERROR_NOT_FOUND;
   306 }
   307 
   308 int BaseRuntime::GetPublicByIndex(uint32_t index, sp_public_t **pblic)
   309 {
   310 	if (index >= m_pPlugin->num_publics)
   311 	{
   312 		return SP_ERROR_INDEX;
   313 	}
   314 
   315 	if (pblic)
   316 	{
   317 		*pblic = &(m_pPlugin->publics[index]);
   318 	}
   319 
   320 	return SP_ERROR_NONE;
   321 }
   322 
   323 uint32_t BaseRuntime::GetPublicsNum()
   324 {
   325 	return m_pPlugin->num_publics;
   326 }
   327 
   328 int BaseRuntime::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar)
   329 {
   330 	if (index >= m_pPlugin->num_pubvars)
   331 	{
   332 		return SP_ERROR_INDEX;
   333 	}
   334 
   335 	if (pubvar)
   336 	{
   337 		*pubvar = &(m_pPlugin->pubvars[index]);
   338 	}
   339 
   340 	return SP_ERROR_NONE;
   341 }
   342 
   343 int BaseRuntime::FindPubvarByName(const char *name, uint32_t *index)
   344 {
   345 	int diff, high, low;
   346 	uint32_t mid;
   347 
   348 	high = m_pPlugin->num_pubvars - 1;
   349 	low = 0;
   350 
   351 	while (low <= high)
   352 	{
   353 		mid = (low + high) / 2;
   354 		diff = strcmp(m_pPlugin->pubvars[mid].name, name);
   355 		if (diff == 0)
   356 		{
   357 			if (index)
   358 			{
   359 				*index = mid;
   360 			}
   361 			return SP_ERROR_NONE;
   362 		}
   363 		else if (diff < 0)
   364 		{
   365 			low = mid + 1;
   366 		}
   367 		else
   368 		{
   369 			high = mid - 1;
   370 		}
   371 	}
   372 
   373 	return SP_ERROR_NOT_FOUND;
   374 }
   375 
   376 int BaseRuntime::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr)
   377 {
   378 	if (index >= m_pPlugin->num_pubvars)
   379 	{
   380 		return SP_ERROR_INDEX;
   381 	}
   382 
   383 	*local_addr = (uint8_t *)m_pPlugin->pubvars[index].offs - m_pPlugin->memory;
   384 	*phys_addr = m_pPlugin->pubvars[index].offs;
   385 
   386 	return SP_ERROR_NONE;
   387 }
   388 
   389 uint32_t BaseRuntime::GetPubVarsNum()
   390 {
   391 	return m_pPlugin->num_pubvars;
   392 }
   393 
   394 IPluginContext *BaseRuntime::GetDefaultContext()
   395 {
   396 	return m_pCtx;
   397 }
   398 
   399 IPluginDebugInfo *BaseRuntime::GetDebugInfo()
   400 {
   401 	return &m_Debug;
   402 }
   403 
   404 IPluginFunction *BaseRuntime::GetFunctionById(funcid_t func_id)
   405 {
   406 	CFunction *pFunc = NULL;
   407 
   408 	if (func_id & 1)
   409 	{
   410 		func_id >>= 1;
   411 		if (func_id >= m_pPlugin->num_publics)
   412 		{
   413 			return NULL;
   414 		}
   415 		pFunc = m_PubFuncs[func_id];
   416 		if (!pFunc)
   417 		{
   418 			m_PubFuncs[func_id] = new CFunction(this, 
   419 				(func_id << 1) | 1,
   420 				func_id);
   421 			pFunc = m_PubFuncs[func_id];
   422 		}
   423 	}
   424 
   425 	return pFunc;
   426 }
   427 
   428 IPluginFunction *BaseRuntime::GetFunctionByName(const char *public_name)
   429 {
   430 	uint32_t index;
   431 
   432 	if (FindPublicByName(public_name, &index) != SP_ERROR_NONE)
   433 	{
   434 		return NULL;
   435 	}
   436 
   437 	CFunction *pFunc = m_PubFuncs[index];
   438 	if (!pFunc)
   439 	{
   440 		sp_public_t *pub = NULL;
   441 		GetPublicByIndex(index, &pub);
   442 		if (pub)
   443 		{
   444 			m_PubFuncs[index] = new CFunction(this, (index << 1) | 1, index);
   445 		}
   446 		pFunc = m_PubFuncs[index];
   447 	}
   448 
   449 	return pFunc;
   450 }
   451 
   452 bool BaseRuntime::IsDebugging()
   453 {
   454 	return true;
   455 }
   456 
   457 void BaseRuntime::SetPauseState(bool paused)
   458 {
   459 	if (paused)
   460 	{
   461 		m_pPlugin->run_flags |= SPFLAG_PLUGIN_PAUSED;
   462 	}
   463 	else
   464 	{
   465 		m_pPlugin->run_flags &= ~SPFLAG_PLUGIN_PAUSED;
   466 	}
   467 }
   468 
   469 bool BaseRuntime::IsPaused()
   470 {
   471 	return ((m_pPlugin->run_flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED);
   472 }
   473 
   474 size_t BaseRuntime::GetMemUsage()
   475 {
   476 	size_t mem = 0;
   477 
   478 	mem += sizeof(this);
   479 	mem += sizeof(sp_plugin_t);
   480 	mem += sizeof(BaseContext);
   481 	mem += m_pPlugin->base_size;
   482 
   483 	return mem;
   484 }
   485 
   486 BaseContext *BaseRuntime::GetBaseContext()
   487 {
   488 	return m_pCtx;
   489 }
   490 
   491 int BaseRuntime::ApplyCompilationOptions(ICompilation *co)
   492 {
   493 	if (co == NULL)
   494 	{
   495 		return SP_ERROR_NONE;
   496 	}
   497 
   498 	m_pCo = g_Jit.ApplyOptions(m_pCo, co);
   499 	m_pPlugin->prof_flags = ((CompData *)m_pCo)->profile;
   500 
   501 	return SP_ERROR_NONE;
   502 }
   503 
   504 JitFunction *BaseRuntime::GetJittedFunction(uint32_t idx)
   505 {
   506 	assert(idx <= m_NumFuncs);
   507 
   508 	if (idx == 0 || idx > m_NumFuncs)
   509 	{
   510 		return NULL;
   511 	}
   512 
   513 	return m_FuncCache[idx - 1];
   514 }
   515 
   516 uint32_t BaseRuntime::AddJittedFunction(JitFunction *fn)
   517 {
   518 	if (m_NumFuncs + 1 > m_MaxFuncs)
   519 	{
   520 		if (m_MaxFuncs == 0)
   521 		{
   522 			m_MaxFuncs = 8;
   523 		}
   524 		else
   525 		{
   526 			m_MaxFuncs *= 2;
   527 		}
   528 
   529 		m_FuncCache = (JitFunction **)realloc(
   530 			m_FuncCache,
   531 			sizeof(JitFunction *) * m_MaxFuncs);
   532 	}
   533 
   534 	m_FuncCache[m_NumFuncs++] = fn;
   535 
   536 	return m_NumFuncs;
   537 }