core/vm/sp_vm_engine.cpp
author David Anderson <dvander@alliedmods.net>
Fri Nov 10 07:49:38 2006 +0000 (2006-11-10)
changeset 172 d8a8186eccbf
parent 159 43c471413f70
child 240 1360e8aa47d7
permissions -rw-r--r--
initial import of plugin loading code
little fixes to API
temporarily commented dependency iface until final
dvander@159
     1
#include <malloc.h>
dvander@159
     2
#include <string.h>
dvander@159
     3
#include "sp_file_headers.h"
dvander@159
     4
#include "sp_vm_types.h"
dvander@159
     5
#include "sp_vm_engine.h"
dvander@159
     6
#include "zlib/zlib.h"
dvander@159
     7
#include "sp_vm_basecontext.h"
dvander@159
     8
dvander@159
     9
#if defined WIN32
dvander@159
    10
 #define WIN32_LEAN_AND_MEAN
dvander@159
    11
 #include <windows.h>
dvander@159
    12
#else if defined __GNUC__
dvander@159
    13
 #include <sys/mman.h>
dvander@159
    14
#endif
dvander@159
    15
dvander@159
    16
using namespace SourcePawn;
dvander@159
    17
dvander@159
    18
void *SourcePawnEngine::ExecAlloc(size_t size)
dvander@159
    19
{
dvander@159
    20
#if defined WIN32
dvander@159
    21
	return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
dvander@159
    22
#else if defined __GNUC__
dvander@159
    23
	void *base = memalign(sysconf(_SC_PAGESIZE), size);
dvander@159
    24
	if (mprotect(base, size, PROT_READ|PROT_WRITE|PROT_EXEC) != 0)
dvander@159
    25
	{
dvander@159
    26
		free(base);
dvander@159
    27
		return NULL;
dvander@159
    28
	}
dvander@159
    29
	return base;
dvander@159
    30
#endif
dvander@159
    31
}
dvander@159
    32
dvander@159
    33
void SourcePawnEngine::ExecFree(void *address)
dvander@159
    34
{
dvander@159
    35
#if defined WIN32
dvander@159
    36
	VirtualFree(address, 0, MEM_RELEASE);
dvander@159
    37
#else if defined __GNUC__
dvander@159
    38
	free(address);
dvander@159
    39
#endif
dvander@159
    40
}
dvander@159
    41
dvander@159
    42
void *SourcePawnEngine::BaseAlloc(size_t size)
dvander@159
    43
{
dvander@159
    44
	return malloc(size);
dvander@159
    45
}
dvander@159
    46
dvander@159
    47
void SourcePawnEngine::BaseFree(void *memory)
dvander@159
    48
{
dvander@159
    49
	free(memory);
dvander@159
    50
}
dvander@159
    51
dvander@159
    52
IPluginContext *SourcePawnEngine::CreateBaseContext(sp_context_t *ctx)
dvander@159
    53
{
dvander@159
    54
	return new BaseContext(ctx);
dvander@159
    55
}
dvander@159
    56
dvander@159
    57
void SourcePawnEngine::FreeBaseContext(IPluginContext *ctx)
dvander@159
    58
{
dvander@159
    59
	delete ctx;
dvander@159
    60
}
dvander@159
    61
dvander@159
    62
sp_plugin_t *_ReadPlugin(sp_file_hdr_t *hdr, uint8_t *base, sp_plugin_t *plugin, int *err)
dvander@159
    63
{
dvander@159
    64
	char *nameptr;
dvander@159
    65
	uint8_t sectnum = 0;
dvander@159
    66
	sp_file_section_t *secptr = (sp_file_section_t *)(base + sizeof(sp_file_hdr_t));
dvander@159
    67
dvander@159
    68
	memset(plugin, 0, sizeof(sp_plugin_t));
dvander@159
    69
dvander@159
    70
	plugin->base = base;
dvander@159
    71
dvander@159
    72
	while (sectnum < hdr->sections)
dvander@159
    73
	{
dvander@159
    74
		nameptr = (char *)(base + hdr->stringtab + secptr->nameoffs);
dvander@159
    75
dvander@159
    76
		if (!(plugin->pcode) && !strcmp(nameptr, ".code"))
dvander@159
    77
		{
dvander@159
    78
			sp_file_code_t *cod = (sp_file_code_t *)(base + secptr->dataoffs);
dvander@159
    79
			plugin->pcode = base + secptr->dataoffs + cod->code;
dvander@159
    80
			plugin->pcode_size = cod->codesize;
dvander@159
    81
			plugin->flags = cod->flags;
dvander@159
    82
		}
dvander@159
    83
		else if (!(plugin->data) && !strcmp(nameptr, ".data"))
dvander@159
    84
		{
dvander@159
    85
			sp_file_data_t *dat = (sp_file_data_t *)(base + secptr->dataoffs);
dvander@159
    86
			plugin->data = base + secptr->dataoffs + dat->data;
dvander@159
    87
			plugin->data_size = dat->datasize;
dvander@159
    88
			plugin->memory = dat->memsize;
dvander@159
    89
		}
dvander@159
    90
		else if (!(plugin->info.publics) && !strcmp(nameptr, ".publics"))
dvander@159
    91
		{
dvander@159
    92
			plugin->info.publics_num = secptr->size / sizeof(sp_file_publics_t);
dvander@159
    93
			plugin->info.publics = (sp_file_publics_t *)(base + secptr->dataoffs);
dvander@159
    94
		}
dvander@159
    95
		else if (!(plugin->info.pubvars) && !strcmp(nameptr, ".pubvars"))
dvander@159
    96
		{
dvander@159
    97
			plugin->info.pubvars_num = secptr->size / sizeof(sp_file_pubvars_t);
dvander@159
    98
			plugin->info.pubvars = (sp_file_pubvars_t *)(base + secptr->dataoffs);
dvander@159
    99
		}
dvander@159
   100
		else if (!(plugin->info.natives) && !strcmp(nameptr, ".natives"))
dvander@159
   101
		{
dvander@159
   102
			plugin->info.natives_num = secptr->size / sizeof(sp_file_natives_t);
dvander@159
   103
			plugin->info.natives = (sp_file_natives_t *)(base + secptr->dataoffs);
dvander@159
   104
		}
dvander@159
   105
		else if (!(plugin->info.lib) && !strcmp(nameptr, ".libraries"))
dvander@159
   106
		{
dvander@159
   107
			plugin->info.libraries_num = secptr->size / sizeof(sp_file_libraries_t);
dvander@159
   108
			plugin->info.lib = (sp_file_libraries_t *)(base + secptr->dataoffs);
dvander@159
   109
		}
dvander@159
   110
		else if (!(plugin->info.stringbase) && !strcmp(nameptr, ".names"))
dvander@159
   111
		{
dvander@159
   112
			plugin->info.stringbase = (const char *)(base + secptr->dataoffs);
dvander@159
   113
		}
dvander@159
   114
		else if (!(plugin->debug.files) && !strcmp(nameptr, ".dbg.files"))
dvander@159
   115
		{
dvander@159
   116
			plugin->debug.files = (sp_fdbg_file_t *)(base + secptr->dataoffs);
dvander@159
   117
		}
dvander@159
   118
		else if (!(plugin->debug.lines) && !strcmp(nameptr, ".dbg.lines"))
dvander@159
   119
		{
dvander@159
   120
			plugin->debug.lines = (sp_fdbg_line_t *)(base + secptr->dataoffs);
dvander@159
   121
		}
dvander@159
   122
		else if (!(plugin->debug.symbols) && !strcmp(nameptr, ".dbg.symbols"))
dvander@159
   123
		{
dvander@159
   124
			plugin->debug.symbols = (sp_fdbg_symbol_t *)(base + secptr->dataoffs);
dvander@159
   125
		}
dvander@159
   126
		else if (!(plugin->debug.lines_num) && !strcmp(nameptr, ".dbg.info"))
dvander@159
   127
		{
dvander@159
   128
			sp_fdbg_info_t *inf = (sp_fdbg_info_t *)(base + secptr->dataoffs);
dvander@159
   129
			plugin->debug.files_num = inf->num_files;
dvander@159
   130
			plugin->debug.lines_num = inf->num_lines;
dvander@159
   131
			plugin->debug.syms_num = inf->num_syms;
dvander@159
   132
		}
dvander@159
   133
		else if (!(plugin->debug.stringbase) && !strcmp(nameptr, ".dbg.strings"))
dvander@159
   134
		{
dvander@159
   135
			plugin->debug.stringbase = (const char *)(base + secptr->dataoffs);
dvander@159
   136
		}
dvander@159
   137
dvander@159
   138
		secptr++;
dvander@159
   139
		sectnum++;
dvander@159
   140
	}
dvander@159
   141
dvander@159
   142
	if (!(plugin->pcode) || !(plugin->data) || !(plugin->info.stringbase))
dvander@159
   143
	{
dvander@159
   144
		goto return_error;
dvander@159
   145
	}
dvander@159
   146
dvander@159
   147
	if ((plugin->flags & SP_FLAG_DEBUG) && (!(plugin->debug.files) || !(plugin->debug.lines) || !(plugin->debug.symbols)))
dvander@159
   148
	{
dvander@159
   149
		goto return_error;
dvander@159
   150
	}
dvander@159
   151
dvander@159
   152
	if (err)
dvander@159
   153
	{
dvander@159
   154
		*err = SP_ERROR_NONE;
dvander@159
   155
	}
dvander@159
   156
dvander@159
   157
	return plugin;
dvander@159
   158
dvander@159
   159
return_error:
dvander@159
   160
	if (err)
dvander@159
   161
	{
dvander@159
   162
		*err = SP_ERROR_FILE_FORMAT;
dvander@159
   163
	}
dvander@159
   164
dvander@159
   165
	return NULL;
dvander@159
   166
}
dvander@159
   167
dvander@159
   168
sp_plugin_t *SourcePawnEngine::LoadFromFilePointer(FILE *fp, int *err)
dvander@159
   169
{
dvander@159
   170
	sp_file_hdr_t hdr;
dvander@159
   171
	sp_plugin_t *plugin;
dvander@159
   172
	uint8_t *base;
dvander@159
   173
	int z_result;
dvander@159
   174
	int error;
dvander@159
   175
dvander@159
   176
	if (!fp)
dvander@159
   177
	{
dvander@159
   178
		error = SP_ERROR_NOT_FOUND;
dvander@159
   179
		goto return_error;
dvander@159
   180
	}
dvander@159
   181
dvander@159
   182
	/* Rewind for safety */
dvander@159
   183
	rewind(fp);
dvander@159
   184
	fread(&hdr, sizeof(sp_file_hdr_t), 1, fp);
dvander@159
   185
dvander@159
   186
	if (hdr.magic != SPFILE_MAGIC)
dvander@159
   187
	{
dvander@159
   188
		error = SP_ERROR_FILE_FORMAT;
dvander@159
   189
		goto return_error;
dvander@159
   190
	}
dvander@159
   191
dvander@159
   192
	switch (hdr.compression)
dvander@159
   193
	{
dvander@159
   194
	case SPFILE_COMPRESSION_GZ:
dvander@159
   195
		{
dvander@159
   196
			uint32_t uncompsize = hdr.imagesize - hdr.dataoffs;
dvander@159
   197
			uint32_t compsize = hdr.disksize - hdr.dataoffs;
dvander@159
   198
			uint32_t sectsize = hdr.dataoffs - sizeof(sp_file_hdr_t);
dvander@159
   199
			uLongf destlen = uncompsize;
dvander@159
   200
dvander@159
   201
			char *tempbuf = (char *)malloc(compsize);
dvander@159
   202
			void *uncompdata = malloc(uncompsize);
dvander@159
   203
			void *sectheader = malloc(sectsize);
dvander@159
   204
dvander@159
   205
			fread(sectheader, sectsize, 1, fp);
dvander@159
   206
			fread(tempbuf, compsize, 1, fp);
dvander@159
   207
dvander@159
   208
			z_result = uncompress((Bytef *)uncompdata, &destlen, (Bytef *)tempbuf, compsize);
dvander@159
   209
			free(tempbuf);
dvander@159
   210
			if (z_result != Z_OK)
dvander@159
   211
			{
dvander@159
   212
				free(sectheader);
dvander@159
   213
				free(uncompdata);
dvander@159
   214
				error = SP_ERROR_DECOMPRESSOR;
dvander@159
   215
				goto return_error;
dvander@159
   216
			}
dvander@159
   217
dvander@159
   218
			base = (uint8_t *)malloc(hdr.imagesize);
dvander@159
   219
			memcpy(base, &hdr, sizeof(sp_file_hdr_t));
dvander@159
   220
			memcpy(base + sizeof(sp_file_hdr_t), sectheader, sectsize);
dvander@159
   221
			free(sectheader);
dvander@159
   222
			memcpy(base + hdr.dataoffs, uncompdata, uncompsize);
dvander@159
   223
			free(uncompdata);
dvander@159
   224
			break;
dvander@159
   225
		}
dvander@159
   226
	case SPFILE_COMPRESSION_NONE:
dvander@159
   227
		{
dvander@159
   228
			base = (uint8_t *)malloc(hdr.imagesize);
dvander@159
   229
			rewind(fp);
dvander@159
   230
			fread(base, hdr.imagesize, 1, fp);
dvander@159
   231
			break;
dvander@159
   232
		}
dvander@159
   233
	default:
dvander@159
   234
		{
dvander@159
   235
			error = SP_ERROR_DECOMPRESSOR;
dvander@159
   236
			goto return_error;
dvander@159
   237
		}
dvander@159
   238
	}
dvander@159
   239
dvander@159
   240
	plugin = (sp_plugin_t *)malloc(sizeof(sp_plugin_t));
dvander@159
   241
	if (!_ReadPlugin(&hdr, base, plugin, err))
dvander@159
   242
	{
dvander@159
   243
		free(plugin);
dvander@159
   244
		free(base);
dvander@159
   245
		return NULL;
dvander@159
   246
	}
dvander@159
   247
dvander@159
   248
	plugin->allocflags = 0;
dvander@159
   249
dvander@159
   250
	return plugin;
dvander@159
   251
dvander@159
   252
return_error:
dvander@159
   253
	if (err)
dvander@159
   254
	{
dvander@159
   255
		*err = error;
dvander@159
   256
	}
dvander@159
   257
	return NULL;
dvander@159
   258
}
dvander@159
   259
dvander@159
   260
sp_plugin_t *SourcePawnEngine::LoadFromMemory(void *base, sp_plugin_t *plugin, int *err)
dvander@159
   261
{
dvander@159
   262
	sp_file_hdr_t hdr;
dvander@159
   263
	uint8_t noptr = 0;
dvander@159
   264
dvander@159
   265
	memcpy(&hdr, base, sizeof(sp_file_hdr_t));
dvander@159
   266
dvander@159
   267
	if (!plugin)
dvander@159
   268
	{
dvander@159
   269
		plugin = (sp_plugin_t *)malloc(sizeof(sp_plugin_t));
dvander@159
   270
		noptr = 1;
dvander@159
   271
	}
dvander@159
   272
dvander@159
   273
	if (!_ReadPlugin(&hdr, (uint8_t *)base, plugin, err))
dvander@159
   274
	{
dvander@159
   275
		if (noptr)
dvander@159
   276
		{
dvander@159
   277
			free(plugin);
dvander@159
   278
		}
dvander@159
   279
		return NULL;
dvander@159
   280
	}
dvander@159
   281
dvander@159
   282
	if (!noptr)
dvander@159
   283
	{
dvander@159
   284
		plugin->allocflags |= SP_FA_SELF_EXTERNAL;
dvander@159
   285
	}
dvander@159
   286
	plugin->allocflags |= SP_FA_BASE_EXTERNAL;
dvander@159
   287
dvander@159
   288
	return plugin;
dvander@159
   289
}
dvander@159
   290
dvander@159
   291
int SourcePawnEngine::FreeFromMemory(sp_plugin_t *plugin)
dvander@159
   292
{
dvander@159
   293
	if (!(plugin->allocflags & SP_FA_BASE_EXTERNAL))
dvander@159
   294
	{
dvander@159
   295
		free(plugin->base);
dvander@159
   296
		plugin->base = NULL;
dvander@159
   297
	}
dvander@159
   298
	if (!(plugin->allocflags & SP_FA_SELF_EXTERNAL))
dvander@159
   299
	{
dvander@159
   300
		free(plugin);
dvander@159
   301
	}
dvander@159
   302
dvander@159
   303
	return SP_ERROR_NONE;
dvander@159
   304
}