sourcemod/sourcepawn/jit/smx-v1-image.h
David Anderson 04827466b0 Rewrite the .smx parser.
This removes one the last remnants of the SourceMod 1.0 VM implementation.

The new parser introduces a number of design changes in the VM. First, the VM now takes greater responsibility for validating and sanity checking the structure of the SMX container format. Previously, malformed SMX files could easily crash SourcePawn. The loader now rejects files that have out-of-bounds offsets or incomplete sections. Complex sections, like debug info or the code stream, are verified lazily.

Internally, the sp_plugin_t structure has been removed. It has been replaced by a new LegacyImage class, designed to be independent from the SPVM API. This potentially lets us load code streams from non-.smx containers. More importantly, it removes a lot of bookkeeping and pre-computed state from PluginRuntime. The LegacyImage class is now responsible for handling debug info as well.

PluginRuntime is now intended to hold only cached or immutable data, and PluginContext holds all VM state. As such PluginContext is now responsible for allocating a plugin's runtime memory, not PluginRuntime.

Finally, some aspects of the loading process have been cleaned up. The
decompression and image handoff logic should now be easier to
understand.
2015-02-25 22:28:10 -08:00

205 lines
4.9 KiB
C++

// vim: set sts=2 ts=8 sw=2 tw=99 et:
//
// Copyright (C) 2004-2015 AlliedModers LLC
//
// This file is part of SourcePawn. SourcePawn is licensed under the GNU
// General Public License, version 3.0 (GPL). If a copy of the GPL was not
// provided with this file, you can obtain it here:
// http://www.gnu.org/licenses/gpl.html
//
#ifndef _include_sourcepawn_smx_parser_h_
#define _include_sourcepawn_smx_parser_h_
#include <stdio.h>
#include <smx/smx-headers.h>
#include <smx/smx-v1.h>
#include <am-utility.h>
#include <am-string.h>
#include <am-vector.h>
#include "file-utils.h"
#include "legacy-image.h"
namespace sp {
class SmxV1Image
: public FileReader,
public LegacyImage
{
public:
SmxV1Image(FILE *fp);
// This must be called to initialize the reader.
bool validate();
const sp_file_hdr_t *hdr() const {
return hdr_;
}
const char *errorMessage() const {
return error_.chars();
}
public:
Code DescribeCode() const KE_OVERRIDE;
Data DescribeData() const KE_OVERRIDE;
size_t NumNatives() const KE_OVERRIDE;
const char *GetNative(size_t index) const KE_OVERRIDE;
bool FindNative(const char *name, size_t *indexp) const KE_OVERRIDE;
size_t NumPublics() const KE_OVERRIDE;
void GetPublic(size_t index, uint32_t *offsetp, const char **namep) const KE_OVERRIDE;
bool FindPublic(const char *name, size_t *indexp) const KE_OVERRIDE;
size_t NumPubvars() const KE_OVERRIDE;
void GetPubvar(size_t index, uint32_t *offsetp, const char **namep) const KE_OVERRIDE;
bool FindPubvar(const char *name, size_t *indexp) const KE_OVERRIDE;
size_t HeapSize() const KE_OVERRIDE;
size_t ImageSize() const KE_OVERRIDE;
const char *LookupFile(uint32_t code_offset) KE_OVERRIDE;
const char *LookupFunction(uint32_t code_offset) KE_OVERRIDE;
bool LookupLine(uint32_t code_offset, uint32_t *line) KE_OVERRIDE;
private:
struct Section
{
const char *name;
uint32_t dataoffs;
uint32_t size;
};
const Section *findSection(const char *name);
public:
template <typename T>
class Blob
{
public:
Blob()
: header_(nullptr),
section_(nullptr),
blob_(nullptr),
length_(0)
{}
Blob(const Section *header,
const T *section,
const uint8_t *blob,
size_t length)
: header_(header),
section_(section),
blob_(blob),
length_(length)
{}
size_t size() const {
return section_->size;
}
const T * operator ->() const {
return section_;
}
const uint8_t *blob() const {
return blob_;
}
size_t length() const {
return length_;
}
bool exists() const {
return !!header_;
}
private:
const Section *header_;
const T *section_;
const uint8_t *blob_;
size_t length_;
};
template <typename T>
class List
{
public:
List()
: section_(nullptr),
length_(0)
{}
List(const T *section, size_t length)
: section_(section),
length_(length)
{}
size_t length() const {
return length_;
}
const T &operator[](size_t index) const {
assert(index < length());
return section_[index];
}
bool exists() const {
return !!section_;
}
private:
const T *section_;
size_t length_;
};
public:
const Blob<sp_file_code_t> &code() const {
return code_;
}
const Blob<sp_file_data_t> &data() const {
return data_;
}
const List<sp_file_publics_t> &publics() const {
return publics_;
}
const List<sp_file_natives_t> &natives() const {
return natives_;
}
const List<sp_file_pubvars_t> &pubvars() const {
return pubvars_;
}
protected:
bool error(const char *msg) {
error_ = msg;
return false;
}
bool validateName(size_t offset);
bool validateSection(const Section *section);
bool validateCode();
bool validateData();
bool validatePublics();
bool validatePubvars();
bool validateNatives();
bool validateDebugInfo();
private:
template <typename SymbolType, typename DimType>
const char *lookupFunction(const SymbolType *syms, uint32_t addr);
private:
sp_file_hdr_t *hdr_;
ke::AString error_;
const char *header_strings_;
ke::Vector<Section> sections_;
const Section *names_section_;
const char *names_;
Blob<sp_file_code_t> code_;
Blob<sp_file_data_t> data_;
List<sp_file_publics_t> publics_;
List<sp_file_natives_t> natives_;
List<sp_file_pubvars_t> pubvars_;
const Section *debug_names_section_;
const char *debug_names_;
const sp_fdbg_info_t *debug_info_;
List<sp_fdbg_file_t> debug_files_;
List<sp_fdbg_line_t> debug_lines_;
const Section *debug_symbols_section_;
const sp_fdbg_symbol_t *debug_syms_;
const sp_u_fdbg_symbol_t *debug_syms_unpacked_;
};
} // namespace sp
#endif // _include_sourcepawn_smx_parser_h_