more refactoring, still less exceptions: os

This commit is contained in:
Lephenixnoir 2022-03-27 17:32:19 +01:00
parent da69725697
commit e90ef447fc
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
9 changed files with 605 additions and 611 deletions

View File

@ -1,26 +1,30 @@
//---
// fxos.os: Operating system models and primitives
//---------------------------------------------------------------------------//
// 1100101 |_ mov #0, r4 __ //
// 11 |_ <0xb380 %5c4> / _|_ _____ ___ //
// 0110 |_ 3.50 -> 3.60 | _\ \ / _ (_-< //
// |_ base# + offset |_| /_\_\___/__/ //
//---------------------------------------------------------------------------//
// fxos/os: Operating system models and primitives
//
// This header describes a structure called [OS] which can be attached to a
// virtual space and gives information about the operating system.
//
// The OS structure can only be created for virtual spaces that have a mapping
// over ROM and if the OS is recognised. The OS structure requires the whole OS
// code to be mapped and cannot provide partial information. If a mapping is
// added to a virtual space, any existing OS structure is discarded.
// code to be mapped and cannot provide partial information.
//
// To access OS information for a virtual space, you should use
// VirtualSpace::os_analysis(), which caches results and doesn't raise
// exceptions.
// To access OS information, use VirtualSpace::os_analysis() which caches
// results instead of building OS objects directly.
//---
#ifndef LIBFXOS_OS_H
#define LIBFXOS_OS_H
#ifndef FXOS_OS_H
#define FXOS_OS_H
#include <fxos/util/Addressable.h>
#include <string>
#include <vector>
#include <map>
#include <memory>
namespace FxOS {
@ -29,78 +33,79 @@ class VirtualSpace;
class OS
{
public:
/* Create an OS interface for this virtual space. If there is no data
loaded in ROM, this raises an exception. */
OS(VirtualSpace &space);
/* Create an OS interface for this virtual space. If there is no data
loaded in ROM or the OS can't be identified, the type os OS is set to
UNKNOWN and no information is provided. */
OS(VirtualSpace &space);
/* Type of OS, determined at construction */
enum Type { FX, CG };
Type type;
/* Type of OS, determined at construction */
enum Type { UNKNOWN, FX, CG };
Type type;
/* Bootcode timestamp and checksum */
Addressable<std::string> bootcode_timestamp;
Addressable<uint32_t> bootcode_checksum;
/* Bootcode timestamp and checksum */
Addressable<std::string> bootcode_timestamp;
Addressable<uint32_t> bootcode_checksum;
/* OS version, serial number, timestamp and checksum */
Addressable<std::string> version;
Addressable<std::string> serial_number;
Addressable<std::string> timestamp;
Addressable<uint32_t> checksum;
/* OS version, serial number, timestamp and checksum */
Addressable<std::string> version;
Addressable<std::string> serial_number;
Addressable<std::string> timestamp;
Addressable<uint32_t> checksum;
/* Separated version components */
int version_major, version_minor, version_patch;
/* Recomputed checksum */
uint32_t computed_checksum;
/* Separated version components */
int version_major, version_minor, version_patch;
/* Recomputed checksum */
uint32_t computed_checksum;
/* Get number of syscalls */
int syscall_count() const noexcept;
/* Get a syscall entry */
uint32_t syscall(int id) const;
/* Find a syscall entry. Returns -1 if syscall is not found */
int find_syscall(uint32_t entry) const noexcept;
/* Get address of syscall table */
uint32_t syscall_table_address() const noexcept;
/* Get number of syscalls */
int syscall_count() const noexcept;
/* Get a syscall entry */
uint32_t syscall(int id) const;
/* Find a syscall entry. Returns -1 if syscall is not found */
int find_syscall(uint32_t entry) const noexcept;
/* Get address of syscall table */
uint32_t syscall_table_address() const noexcept;
/* Tests against the OS version */
bool version_lt(int major, int minor, int patch) const noexcept;
bool version_le(int major, int minor, int patch) const noexcept;
bool version_gt(int major, int minor, int patch) const noexcept;
bool version_ge(int major, int minor, int patch) const noexcept;
/* Tests against the OS version */
bool version_lt(int major, int minor, int patch) const noexcept;
bool version_le(int major, int minor, int patch) const noexcept;
bool version_gt(int major, int minor, int patch) const noexcept;
bool version_ge(int major, int minor, int patch) const noexcept;
/* Footer address, or -1 if not found */
uint32_t footer;
/* Number of langdata entries */
int langdata;
/* Footer address, or -1 if not found */
uint32_t footer;
/* Number of langdata entries */
int langdata;
private:
/* Virtual space being analyzed */
VirtualSpace &m_space;
/* Virtual space being analyzed */
VirtualSpace &m_space;
/* Parse the OS header. This should be the first analysis function to
be called, because it determines the type of model (ie. fx9860g vs
fxcg50) thus the location of the syscall table and many more
important parameters. */
void parse_header();
/* Parse the OS header. This should be the first analysis function to
be called, because it determines the type of model (ie. fx9860g vs
fxcg50) thus the location of the syscall table and many more
important parameters. */
void parse_header();
/* Locate and parse the syscall table. */
void parse_syscall_table();
/* Locate and parse the syscall table. */
void parse_syscall_table();
/* Locate and parse the footer. */
void parse_footer();
/* Locate and parse the footer. */
void parse_footer();
/* Compute OS checkum .*/
uint32_t compute_checksum() const;
/* Compute OS checkum .*/
uint32_t compute_checksum() const;
//---
// OS information
//---
//---
// OS information
//---
/* Syscall table, in order of syscall IDs */
std::vector<uint32_t> m_syscall_table;
/* Bimap converse, syscalls sorted by address */
std::map<uint32_t,int> m_syscall_addresses;
/* Syscall table, in order of syscall IDs */
std::vector<uint32_t> m_syscall_table;
/* Bimap converse, syscalls sorted by address */
std::map<uint32_t,int> m_syscall_addresses;
};
} /* namespace FxOS */
#endif /* LIBFXOS_OS_H */
#endif /* FXOS_OS_H */

View File

@ -1,9 +1,22 @@
//---
// fxos.semantics: Analyzed data types and locations (OS semantics)
// fxos/semantics: High-level data types and values, and location tracking
//
// TODO: This is a work in progress, not really tested/integrated yet.
//
// This header is intended to provide the tools needed to analyze disassembled
// code. The main idea is to assign to some *location* and *type* and possibly
// a *value*.
//
// The locations considered are defined by RelConst elements. The data types
// are 8-bit, 16-bit and 32-bit integers, arrays, strings, bit fields and
// structures.
//
// Notes:
// - Aliasing is a huge issue which might result in incorrect analysis. (!)
// - The current interface is inefficient and cumbersome. I don't like it
//---
#ifndef LIBFXOS_SEMANTICS_H
#define LIBFXOS_SEMANTICS_H
#ifndef FXOS_SEMANTICS_H
#define FXOS_SEMANTICS_H
#include <fxos/lang.h>
#include <fxos/ai/RelConst.h>
@ -30,41 +43,41 @@ class DataType;
/* Base type: common information for all types (mixin) */
struct BaseType
{
/* Type size in bytes, as would be returned by sizeof(). Must be 1, 2
or 4 for integral types and bit fields. Cannot be 0 because all
considered types are fixed-size and finite. */
size_t size;
/* Type alignment, can only be 1, 2 or 4 */
size_t align;
/* Type size in bytes, as would be returned by sizeof(). Must be 1, 2
or 4 for integral types and bit fields. Cannot be 0 because all
considered types are fixed-size and finite. */
size_t size;
/* Type alignment, can only be 1, 2 or 4 */
size_t align;
};
/* Integer type; of byte, word or longword size. Plus signedness. This kind is
so small that it is enumerated. */
struct IntegerType: public BaseType
{
static DataType const *u8, *i8, *u16, *i16, *u32, *i32;
static DataType const *u8, *i8, *u16, *i16, *u32, *i32;
IntegerType(size_t _size, bool _issigned) {
size = align = _size;
issigned = _issigned;
}
IntegerType(size_t _size, bool _issigned) {
size = align = _size;
issigned = _issigned;
}
/* Whether the type is signed */
bool issigned;
/* Whether the type is signed */
bool issigned;
};
/* Bit fields over bytes, words or longwords. This should satisfy the invariant
that the sum of the field sizes is equal to the type size. */
struct BitfieldType: public BaseType
{
/* Fields must have positive size; the name might be empty. */
using Field = std::pair<std::string, int>;
/* Fields must have positive size; the name might be empty. */
using Field = std::pair<std::string, int>;
std::string name;
std::vector<Field> fields;
std::string name;
std::vector<Field> fields;
/* Get field by name (throws if not found) */
Field named_field(std::string name) const;
/* Get field by name (throws if not found) */
Field named_field(std::string name) const;
};
/* Homogeneous fixed-size arrays. The number of elements cannot be set to
@ -72,60 +85,60 @@ struct BitfieldType: public BaseType
should equal the size of the array type. */
struct ArrayType: public BaseType
{
struct DataType *object_type;
int elements;
struct DataType *object_type;
int elements;
};
/* Fixed-length string. Size must be positive. */
struct StringType: public BaseType
{
int size;
/* Whether string stops at first NUL, or must account for all
characters up to the size regardless of NULs */
bool nul_terminated;
int size;
/* Whether string stops at first NUL, or must account for all
characters up to the size regardless of NULs */
bool nul_terminated;
};
/* Heterogeneous structure types. */
struct StructType: public BaseType
{
/* Fields can be of any type since all are fixed-size. */
using Field = std::pair<std::string, DataType>;
/* Fields can be of any type since all are fixed-size. */
using Field = std::pair<std::string, DataType>;
std::string name;
std::vector<Field> fields;
std::string name;
std::vector<Field> fields;
};
/* Sum-type-style union. Basically a variant with NAMES. Thank you. */
class DataType
{
public:
/* Variant identifier (think of it as a named sum type) */
enum DataKind { Integer=0, Bitfield=1, Array=2, String=3, Struct=4 };
DataKind kind() const noexcept;
/* Variant identifier (think of it as a named sum type) */
enum DataKind { Integer=0, Bitfield=1, Array=2, String=3, Struct=4 };
DataKind kind() const noexcept;
/* Common properties */
size_t size() const noexcept;
size_t align() const noexcept;
/* Common properties */
size_t size() const noexcept;
size_t align() const noexcept;
/* Access to type-specific data. Exactly one of these can be accessed,
depending on the type kind. */
/* Access to type-specific data. Exactly one of these can be accessed,
depending on the type kind. */
IntegerType const &integer() const;
BitfieldType const &bitfield() const;
ArrayType const &array() const;
StringType const &string() const;
StructType const &structs() const;
IntegerType const &integer() const;
BitfieldType const &bitfield() const;
ArrayType const &array() const;
StringType const &string() const;
StructType const &structs() const;
/* Converting constructors from any of these types */
/* Converting constructors from any of these types */
DataType(IntegerType t): v(t) {}
DataType(BitfieldType t): v(t) {}
DataType(ArrayType t): v(t) {}
DataType(StringType t): v(t) {}
DataType(StructType t): v(t) {}
DataType(IntegerType t): v(t) {}
DataType(BitfieldType t): v(t) {}
DataType(ArrayType t): v(t) {}
DataType(StringType t): v(t) {}
DataType(StructType t): v(t) {}
private:
std::variant<IntegerType,BitfieldType,ArrayType,StringType,StructType> v;
std::variant<IntegerType,BitfieldType,ArrayType,StringType,StructType> v;
};
//---
@ -137,37 +150,37 @@ private:
struct DataValue
{
/* Each byte in the array is stored on an int16_t so that uninitialized
bytes can be found and diagnosed. */
DataType const *type;
std::vector<int16_t> mem;
/* Each byte in the array is stored on an int16_t so that uninitialized
bytes can be found and diagnosed. */
DataType const *type;
std::vector<int16_t> mem;
/* Create value with no memory and no type */
DataValue();
/* Create value with uninitialized memory for that data type */
DataValue(DataType const *type);
/* Create value with no memory and no type */
DataValue();
/* Create value with uninitialized memory for that data type */
DataValue(DataType const *type);
/* Check whether the value is fully defined and initialized */
bool defined() const {
return std::find(mem.begin(), mem.end(), -1) == mem.end();
}
operator bool() const {
return defined();
}
/* Check whether the value is fully defined and initialized */
bool defined() const {
return std::find(mem.begin(), mem.end(), -1) == mem.end();
}
operator bool() const {
return defined();
}
/* Checks that the access is correct and fits within the value. */
void access(size_t offset, size_t size) const;
/* Read data from the value. Access must be 1, 2 or 4 bytes (possibly
unaligned) and must be in bounds. */
uint32_t read(size_t offset, size_t size) const;
/* Write data. Access must be 1, 2 or 4 bytes and in bounds. */
void write(size_t offset, size_t size, uint32_t contents);
/* Checks that the access is correct and fits within the value. */
void access(size_t offset, size_t size) const;
/* Read data from the value. Access must be 1, 2 or 4 bytes (possibly
unaligned) and must be in bounds. */
uint32_t read(size_t offset, size_t size) const;
/* Write data. Access must be 1, 2 or 4 bytes and in bounds. */
void write(size_t offset, size_t size, uint32_t contents);
/* Retrieve value as uin32_t - only valid for Integer types */
uint32_t uinteger() const;
/* Retrieve value as uin32_t - only valid for Integer types */
uint32_t uinteger() const;
/* Byte-based string representation */
std::string str() const noexcept;
/* Byte-based string representation */
std::string str() const noexcept;
};
//---
@ -182,4 +195,4 @@ using Location = RelConst;
} /* namespace FxOS */
#endif /* LIBFXOS_SEMANTICS_H */
#endif /* FXOS_SEMANTICS_H */

View File

@ -1,68 +1,61 @@
//---
// fxos.symbols: User-defined symbols for OS objects
//---------------------------------------------------------------------------//
// 1100101 |_ mov #0, r4 __ //
// 11 |_ <0xb380 %5c4> / _|_ _____ ___ //
// 0110 |_ 3.50 -> 3.60 | _\ \ / _ (_-< //
// |_ base# + offset |_| /_\_\___/__/ //
//---------------------------------------------------------------------------//
// fxos/symbols: User-extensible naming scheme for OS objects
//
// This header provides tools to define symbols, ie. names attached to fixed or
// symbolic addresses. Currently supported:
// - Address: the name maps to a fixed 32-bit virtual address.
// - Syscall: the name maps to a syscall number resolved by OS analysis.
//
// The SymbolTable structure manages a set of symbols, usually all the symbols
// in a given virtual space.
//---
#ifndef LIBFXOS_SYMBOLS_H
#define LIBFXOS_SYMBOLS_H
#ifndef FXOS_SYMBOLS_H
#define FXOS_SYMBOLS_H
#include <optional>
#include <string>
#include <vector>
#include <fxos/os.h>
namespace FxOS
{
class VirtualSpace;
namespace FxOS {
/* A named symbol that can be substituted to literal values in the code. */
struct Symbol
{
/* Syscall: The value is a syscall number. The syscall number for an
address is determined by querying the OS object.
Address: The value is a fixed 32-bit virtual address. */
enum Type { Syscall=1, Address=2 };
enum Type { Syscall=1, Address=2 };
enum Type type;
uint32_t value;
enum Type type;
uint32_t value;
/* Symbol name, no particular conventions */
std::string name;
/* Symbol name, no particular conventions */
std::string name;
};
/* A symbol table, essentially a set of symbols loaded from the same file */
class SymbolTable
/* A symbol table, usually the set of symbols of a virtual space */
struct SymbolTable
{
public:
/* Construct a new symbol table for the specified OS and MPU; the two
constraints apply simultaneously. For both, an empty string
represents no constraint. */
SymbolTable(std::string os="", std::string mpu="");
SymbolTable();
/* Allow move but disable copy */
SymbolTable(SymbolTable const &other) = delete;
SymbolTable(SymbolTable &&other) = default;
/* Allow move but disable copy */
SymbolTable(SymbolTable const &other) = delete;
SymbolTable(SymbolTable &&other) = default;
std::string table_name;
std::vector<Symbol> symbols;
std::string table_name;
std::vector<Symbol> symbols;
/* Validate constraints to see if table is usable */
bool is_usable_on(OS &os) const noexcept;
bool is_usable_on(VirtualSpace &space) const noexcept;
/* Add a symbol to the table */
void add(Symbol s);
/* Query a value for a certain type of symbol */
std::optional<std::string> query(Symbol::Type type, uint32_t value)
const;
/* Lookup the symbol behind a given name */
std::optional<Symbol> lookup(std::string name) const;
private:
std::string m_os_constraint;
std::string m_mpu_constraint;
/* Add a symbol to the table */
void add(Symbol s);
/* Query a value for a certain type of symbol */
std::optional<std::string> query(Symbol::Type type, uint32_t value) const;
/* Lookup the symbol behind a given name */
std::optional<Symbol> lookup(std::string name) const;
};
} /* namespace FxOS */
#endif /* LIBFXOS_SYMBOLS_H */
#endif /* FXOS_SYMBOLS_H */

View File

@ -1,4 +1,11 @@
%{
//---------------------------------------------------------------------------//
// 1100101 |_ mov #0, r4 __ //
// 11 |_ <0xb380 %5c4> / _|_ _____ ___ //
// 0110 |_ 3.50 -> 3.60 | _\ \ / _ (_-< //
// |_ base# + offset |_| /_\_\___/__/ //
//---------------------------------------------------------------------------//
#include <fxos/lang.h>
#include <fxos/disassembly.h>
#include <fxos/util/format.h>
@ -12,43 +19,43 @@ static char *yylval;
/* Argument tokens */
enum Token {
/* Instruction pattern and mnemonic */
PATTERN = 1, MNEMONIC,
/* General-purpose registers */
R0, RN, RM,
/* Banked registers */
R0_BANK, R1_BANK, R2_BANK, R3_BANK, R4_BANK, R5_BANK, R6_BANK, R7_BANK,
/* Control registers */
SR, PR, GBR, VBR, DBR, SSR, SPC, SGR, MACH, MACL,
/* PC-relative jumps and displacements (with 4-alignment correction) */
JUMP8, JUMP12, AT_DPC,
/* PC-relative address access (without memory access) */
DPC,
/* Immediate operands */
IMM,
/* Memory access with post-increment and pre-decrement */
AT_RN, AT_RM, AT_RMP, AT_RNP, AT_MRN,
/* Structure dereferencing */
AT_DRN, AT_DRM, AT_DGBR,
/* Array dereferencing */
AT_R0RN, AT_R0RM, AT_R0GBR,
/* Instruction pattern and mnemonic */
PATTERN = 1, MNEMONIC,
/* General-purpose registers */
R0, RN, RM,
/* Banked registers */
R0_BANK, R1_BANK, R2_BANK, R3_BANK, R4_BANK, R5_BANK, R6_BANK, R7_BANK,
/* Control registers */
SR, PR, GBR, VBR, DBR, SSR, SPC, SGR, MACH, MACL,
/* PC-relative jumps and displacements (with 4-alignment correction) */
JUMP8, JUMP12, AT_DPC,
/* PC-relative address access (without memory access) */
DPC,
/* Immediate operands */
IMM,
/* Memory access with post-increment and pre-decrement */
AT_RN, AT_RM, AT_RMP, AT_RNP, AT_MRN,
/* Structure dereferencing */
AT_DRN, AT_DRM, AT_DGBR,
/* Array dereferencing */
AT_R0RN, AT_R0RM, AT_R0GBR,
};
/* Instruction opcode pattern */
struct Pattern {
/* 16-bit opcode, bits corresponding to arguments are clear */
uint16_t bits;
/* Position of the arguments */
uint8_t n_sh, m_sh, d_sh, i_sh;
/* Length of arguments, in bits */
uint16_t n_size, m_size, d_size, i_size;
/* 16-bit opcode, bits corresponding to arguments are clear */
uint16_t bits;
/* Position of the arguments */
uint8_t n_sh, m_sh, d_sh, i_sh;
/* Length of arguments, in bits */
uint16_t n_size, m_size, d_size, i_size;
};
/* Current file name */
static std::string filename;
#define err(fmt, ...) \
FxOS_log(ERR, "%s:%d: " fmt, filename, yylineno, ##__VA_ARGS__)
FxOS_log(ERR, "%s:%d: " fmt, filename, yylineno, ##__VA_ARGS__)
%}
@ -131,29 +138,27 @@ namespace FxOS {
of the [&] operator. But this decoding method is now unused.) */
static Pattern make_pattern(char const *code)
{
Pattern p {};
Pattern p {};
for(int i = 0; i < 16; i++)
{
int c = code[i];
for(int i = 0; i < 16; i++) {
int c = code[i];
/* Constant bits */
if(c == '0' || c == '1')
{
p.bits = (p.bits << 1) | (c - '0');
continue;
}
/* Constant bits */
if(c == '0' || c == '1') {
p.bits = (p.bits << 1) | (c - '0');
continue;
}
/* Argument bits */
p.bits <<= 1;
/* Argument bits */
p.bits <<= 1;
if(c == 'n') p.n_sh = 15 - i, p.n_size++;
if(c == 'm') p.m_sh = 15 - i, p.m_size++;
if(c == 'd') p.d_sh = 15 - i, p.d_size++;
if(c == 'i') p.i_sh = 15 - i, p.i_size++;
}
if(c == 'n') p.n_sh = 15 - i, p.n_size++;
if(c == 'm') p.m_sh = 15 - i, p.m_size++;
if(c == 'd') p.d_sh = 15 - i, p.d_size++;
if(c == 'i') p.i_sh = 15 - i, p.i_size++;
}
return p;
return p;
}
/* Instantiate an argument token as an fxos language structure.
@ -163,67 +168,67 @@ static Pattern make_pattern(char const *code)
Returns a semantic FxOS::Argument. */
static Argument make_arg(int token, int opsize, int m, int n, int d, int i)
{
using Reg = CpuRegister;
static Reg general_purpose[16] = {
Reg::R0, Reg::R1, Reg::R2, Reg::R3, Reg::R4, Reg::R5,
Reg::R6, Reg::R7, Reg::R8, Reg::R9, Reg::R10, Reg::R11,
Reg::R12, Reg::R13, Reg::R14, Reg::R15,
};
using Reg = CpuRegister;
static Reg general_purpose[16] = {
Reg::R0, Reg::R1, Reg::R2, Reg::R3, Reg::R4, Reg::R5,
Reg::R6, Reg::R7, Reg::R8, Reg::R9, Reg::R10, Reg::R11,
Reg::R12, Reg::R13, Reg::R14, Reg::R15,
};
/* Registers rn and rm */
CpuRegister Rn = general_purpose[n & 0xf];
CpuRegister Rm = general_purpose[m & 0xf];
/* Sign extensions of d to 8 and 12 bits */
int32_t d8 = (int8_t)d;
int32_t d12 = (d & 0x800) ? (int32_t)(d | 0xfffff000) : (d);
/* Sign extension of i to 8 bits */
int32_t i8 = (int8_t)i;
/* Registers rn and rm */
CpuRegister Rn = general_purpose[n & 0xf];
CpuRegister Rm = general_purpose[m & 0xf];
/* Sign extensions of d to 8 and 12 bits */
int32_t d8 = (int8_t)d;
int32_t d12 = (d & 0x800) ? (int32_t)(d | 0xfffff000) : (d);
/* Sign extension of i to 8 bits */
int32_t i8 = (int8_t)i;
switch(token)
{
case R0: return Argument_Reg(Reg::R0);
case RN: return Argument_Reg(Rn);
case RM: return Argument_Reg(Rm);
case R0_BANK: return Argument_Reg(Reg::R0B);
case R1_BANK: return Argument_Reg(Reg::R1B);
case R2_BANK: return Argument_Reg(Reg::R2B);
case R3_BANK: return Argument_Reg(Reg::R3B);
case R4_BANK: return Argument_Reg(Reg::R4B);
case R5_BANK: return Argument_Reg(Reg::R5B);
case R6_BANK: return Argument_Reg(Reg::R6B);
case R7_BANK: return Argument_Reg(Reg::R7B);
case SR: return Argument_Reg(Reg::SR);
case PR: return Argument_Reg(Reg::PR);
case GBR: return Argument_Reg(Reg::GBR);
case VBR: return Argument_Reg(Reg::VBR);
case DBR: return Argument_Reg(Reg::DBR);
case SSR: return Argument_Reg(Reg::SSR);
case SPC: return Argument_Reg(Reg::SPC);
case SGR: return Argument_Reg(Reg::SGR);
case MACH: return Argument_Reg(Reg::MACH);
case MACL: return Argument_Reg(Reg::MACL);
case JUMP8: return Argument_PcJump(d8 * 2);
case JUMP12: return Argument_PcJump(d12 * 2);
case DPC: return Argument_PcAddr(d * 4);
case IMM: return Argument_Imm(i8);
case AT_RN: return Argument_Deref(Rn);
case AT_RM: return Argument_Deref(Rm);
case AT_RMP: return Argument_PostInc(Rm);
case AT_RNP: return Argument_PostInc(Rn);
case AT_MRN: return Argument_PreDec(Rn);
case AT_DRN: return Argument_StructDeref(d*opsize, opsize, Rn);
case AT_DRM: return Argument_StructDeref(d*opsize, opsize, Rm);
case AT_DGBR: return Argument_StructDeref(d*opsize, opsize, Reg::GBR);
case AT_R0RN: return Argument_ArrayDeref(Reg::R0, Rn);
case AT_R0RM: return Argument_ArrayDeref(Reg::R0, Rm);
case AT_R0GBR: return Argument_ArrayDeref(Reg::R0, Reg::GBR);
switch(token) {
case R0: return Argument_Reg(Reg::R0);
case RN: return Argument_Reg(Rn);
case RM: return Argument_Reg(Rm);
case R0_BANK: return Argument_Reg(Reg::R0B);
case R1_BANK: return Argument_Reg(Reg::R1B);
case R2_BANK: return Argument_Reg(Reg::R2B);
case R3_BANK: return Argument_Reg(Reg::R3B);
case R4_BANK: return Argument_Reg(Reg::R4B);
case R5_BANK: return Argument_Reg(Reg::R5B);
case R6_BANK: return Argument_Reg(Reg::R6B);
case R7_BANK: return Argument_Reg(Reg::R7B);
case SR: return Argument_Reg(Reg::SR);
case PR: return Argument_Reg(Reg::PR);
case GBR: return Argument_Reg(Reg::GBR);
case VBR: return Argument_Reg(Reg::VBR);
case DBR: return Argument_Reg(Reg::DBR);
case SSR: return Argument_Reg(Reg::SSR);
case SPC: return Argument_Reg(Reg::SPC);
case SGR: return Argument_Reg(Reg::SGR);
case MACH: return Argument_Reg(Reg::MACH);
case MACL: return Argument_Reg(Reg::MACL);
case JUMP8: return Argument_PcJump(d8 * 2);
case JUMP12: return Argument_PcJump(d12 * 2);
case DPC: return Argument_PcAddr(d * 4);
case IMM: return Argument_Imm(i8);
case AT_RN: return Argument_Deref(Rn);
case AT_RM: return Argument_Deref(Rm);
case AT_RMP: return Argument_PostInc(Rm);
case AT_RNP: return Argument_PostInc(Rn);
case AT_MRN: return Argument_PreDec(Rn);
case AT_DRN: return Argument_StructDeref(d*opsize, opsize, Rn);
case AT_DRM: return Argument_StructDeref(d*opsize, opsize, Rm);
case AT_DGBR: return Argument_StructDeref(d*opsize, opsize, Reg::GBR);
case AT_R0RN: return Argument_ArrayDeref(Reg::R0, Rn);
case AT_R0RM: return Argument_ArrayDeref(Reg::R0, Rm);
case AT_R0GBR: return Argument_ArrayDeref(Reg::R0, Reg::GBR);
case AT_DPC:
if(!opsize) err("@(disp,pc) must have a size (.w, .l)");
return Argument_PcRel(d*opsize, opsize);
}
case AT_DPC:
if(!opsize)
err("@(disp,pc) must have a size (.w, .l)");
return Argument_PcRel(d*opsize, opsize);
}
throw std::logic_error("lex asm builds args from bad tokens");
throw std::logic_error("lex asm builds args from bad tokens");
}
/* Record all the instances of an instruction in the disassembly table.
@ -235,110 +240,101 @@ static Argument make_arg(int token, int opsize, int m, int n, int d, int i)
Generates all the instances of the instruction, then sends them to the
disassembler for fast lookup. Returns number of instantiated opcodes. */
static int instantiate(struct Pattern p, char const *mnemonic, int argtoken1,
int argtoken2)
int argtoken2)
{
int total = 0;
int total = 0;
for(int n = 0; n < (1 << p.n_size); n++)
for(int m = 0; m < (1 << p.m_size); m++)
for(int d = 0; d < (1 << p.d_size); d++)
for(int i = 0; i < (1 << p.i_size); i++)
{
uint16_t opcode = p.bits;
opcode |= (n << p.n_sh);
opcode |= (m << p.m_sh);
opcode |= (d << p.d_sh);
opcode |= (i << p.i_sh);
for(int n = 0; n < (1 << p.n_size); n++)
for(int m = 0; m < (1 << p.m_size); m++)
for(int d = 0; d < (1 << p.d_size); d++)
for(int i = 0; i < (1 << p.i_size); i++) {
uint16_t opcode = p.bits;
opcode |= (n << p.n_sh);
opcode |= (m << p.m_sh);
opcode |= (d << p.d_sh);
opcode |= (i << p.i_sh);
Instruction ins(mnemonic);
ins.opcode = opcode;
Instruction ins(mnemonic);
ins.opcode = opcode;
if(argtoken1) {
ins.args[0] = make_arg(argtoken1, ins.opsize, m,n,d,i);
ins.arg_count = 1;
}
if(argtoken2) {
ins.args[1] = make_arg(argtoken2, ins.opsize, m,n,d,i);
ins.arg_count = 2;
}
if(argtoken1) {
ins.args[0] = make_arg(argtoken1, ins.opsize, m,n,d,i);
ins.arg_count = 1;
}
if(argtoken2) {
ins.args[1] = make_arg(argtoken2, ins.opsize, m,n,d,i);
ins.arg_count = 2;
}
register_instruction(ins);
total++;
}
register_instruction(ins);
total++;
}
return total;
return total;
}
/* Load an assembly instruction table for the disassembler. */
int load_instructions(Buffer const &file)
{
/* Lex all instructions and fill in the general assembly table */
/* Lex all instructions and fill in the general assembly table */
YY_BUFFER_STATE buf = yy_scan_bytes(file.data.get(), file.size);
yylineno = 1;
filename = file.path;
YY_BUFFER_STATE buf = yy_scan_bytes(file.data.get(), file.size);
yylineno = 1;
filename = file.path;
/* Number of instructions lexed */
int total = 0;
/* Number of instructions lexed */
int total = 0;
/* Instruction information */
char *code=nullptr, *mnemonic=nullptr;
int argtoken1=0, argtoken2=0;
/* Instruction information */
char *code=nullptr, *mnemonic=nullptr;
int argtoken1=0, argtoken2=0;
/* Current line */
int line = -1;
/* Current line */
int line = -1;
while(1)
{
int t = yylex();
while(1) {
int t = yylex();
if(line >= 0 && (yylineno != line || t == PATTERN || t == -1))
{
/* Finalize current instruction */
if(!mnemonic)
{
err("missing mnemonic at line %d", line);
break;
}
if(line >= 0 && (yylineno != line || t == PATTERN || t == -1)) {
/* Finalize current instruction */
if(!mnemonic) {
err("missing mnemonic at line %d", line);
break;
}
Pattern p = make_pattern(code);
total += instantiate(p, mnemonic, argtoken1,argtoken2);
Pattern p = make_pattern(code);
total += instantiate(p, mnemonic, argtoken1,argtoken2);
if(code) free(code);
if(mnemonic) free(mnemonic);
}
if(t == -1) break;
if(code) free(code);
if(mnemonic) free(mnemonic);
}
if(t == -1) break;
if(t == PATTERN)
{
code = yylval;
line = yylineno;
if(t == PATTERN) {
code = yylval;
line = yylineno;
mnemonic = nullptr;
argtoken1 = 0;
argtoken2 = 0;
}
else if(t == MNEMONIC && !mnemonic)
{
mnemonic = yylval;
}
else if(!mnemonic)
{
err("missing mnemonic at line %d", line);
break;
}
else if(!argtoken1)
{
argtoken1 = t;
}
else if(!argtoken2)
{
argtoken2 = t;
}
}
mnemonic = nullptr;
argtoken1 = 0;
argtoken2 = 0;
}
else if(t == MNEMONIC && !mnemonic) {
mnemonic = yylval;
}
else if(!mnemonic) {
err("missing mnemonic at line %d", line);
break;
}
else if(!argtoken1) {
argtoken1 = t;
}
else if(!argtoken2) {
argtoken2 = t;
}
}
yy_delete_buffer(buf);
return total;
yy_delete_buffer(buf);
return total;
}
} /* namespace FxOS */

View File

@ -1,230 +1,227 @@
#include <fxos/os.h>
#include <fxos/vspace.h>
#include <fxos/memory.h>
#include <fxos/util/log.h>
#include <stdexcept>
#include <cstring>
namespace FxOS {
OS::OS(VirtualSpace &space): m_space {space}
OS::OS(VirtualSpace &space): type{UNKNOWN}, m_space{space}
{
if(!space.covers(0x80000000))
throw std::runtime_error("OS requires a target with ROM");
if(!space.covers(0x80000000, (256 << 10))) {
FxOS_log(ERR, "OS analysis failed: space doesn't have at least 256 kB "
"of ROM to analyze from");
return;
}
/* OS files are all at least 1 MB large */
if(!space.covers(0x80000000, 1000000))
throw std::runtime_error("OS requires target with >1MB ROM");
/* Detect OS type by heuristic */
if(space.read_str(0x80010000, 8).value == "CASIOWIN")
this->type = FX;
else if(space.read_str(0x80020000, 8).value == "CASIOWIN")
this->type = CG;
else {
FxOS_log(ERR, "OS analysis failed: cannot determine OS type");
return;
}
/* Detect OS type by heuristic */
if(space.read_str(0x80010000, 8).value == "CASIOWIN")
this->type = FX;
else if(space.read_str(0x80020000, 8).value == "CASIOWIN")
this->type = CG;
else
throw std::runtime_error("Cannot determine OS type (FX/CG)");
parse_header();
parse_syscall_table();
parse_footer();
parse_header();
parse_syscall_table();
parse_footer();
}
void OS::parse_header()
{
VirtualSpace &s = m_space;
VirtualSpace &s = m_space;
if(this->type == FX)
{
/* Bootcode timestamp at the very end of the bootcode */
this->bootcode_timestamp = s.read_str(0x8000ffb0, 14);
this->bootcode_checksum = s.read_u32(0x8000fffc);
this->version = s.read_str(0x80010020, 10);
this->serial_number = s.read_str(0x8000ffd0, 8);
}
else if(this->type == CG)
{
this->bootcode_timestamp = s.read_str(0x8001ffb0, 14);
this->bootcode_checksum = s.read_u32(0x8001fffc);
this->version = s.read_str(0x80020020, 10);
this->serial_number = s.read_str(0x8001ffd0, 8);
}
if(this->type == FX) {
/* Bootcode timestamp at the very end of the bootcode */
this->bootcode_timestamp = s.read_str(0x8000ffb0, 14);
this->bootcode_checksum = s.read_u32(0x8000fffc);
this->version = s.read_str(0x80010020, 10);
this->serial_number = s.read_str(0x8000ffd0, 8);
}
else if(this->type == CG) {
this->bootcode_timestamp = s.read_str(0x8001ffb0, 14);
this->bootcode_checksum = s.read_u32(0x8001fffc);
this->version = s.read_str(0x80020020, 10);
this->serial_number = s.read_str(0x8001ffd0, 8);
}
/* Version has format MM.mm.pppp */
version_major = std::stoi(this->version.value.substr(0, 2));
version_minor = std::stoi(this->version.value.substr(3, 2));
version_patch = std::stoi(this->version.value.substr(6, 4));
/* Version has format MM.mm.pppp */
version_major = std::stoi(this->version.value.substr(0, 2));
version_minor = std::stoi(this->version.value.substr(3, 2));
version_patch = std::stoi(this->version.value.substr(6, 4));
}
bool OS::version_lt(int major, int minor, int patch) const noexcept
{
if(this->version_major < major) return true;
if(this->version_major > major) return false;
if(this->version_minor < minor) return true;
if(this->version_minor > minor) return false;
return (this->version_patch < patch);
if(this->version_major < major) return true;
if(this->version_major > major) return false;
if(this->version_minor < minor) return true;
if(this->version_minor > minor) return false;
return (this->version_patch < patch);
}
bool OS::version_le(int major, int minor, int patch) const noexcept
{
if(this->version_major < major) return true;
if(this->version_major > major) return false;
if(this->version_minor < minor) return true;
if(this->version_minor > minor) return false;
return (this->version_patch <= patch);
if(this->version_major < major) return true;
if(this->version_major > major) return false;
if(this->version_minor < minor) return true;
if(this->version_minor > minor) return false;
return (this->version_patch <= patch);
}
bool OS::version_gt(int major, int minor, int patch) const noexcept
{
if(this->version_major < major) return false;
if(this->version_major > major) return true;
if(this->version_minor < minor) return false;
if(this->version_minor > minor) return true;
return (this->version_patch > patch);
if(this->version_major < major) return false;
if(this->version_major > major) return true;
if(this->version_minor < minor) return false;
if(this->version_minor > minor) return true;
return (this->version_patch > patch);
}
bool OS::version_ge(int major, int minor, int patch) const noexcept
{
if(this->version_major < major) return false;
if(this->version_major > major) return true;
if(this->version_minor < minor) return false;
if(this->version_minor > minor) return true;
return (this->version_patch >= patch);
if(this->version_major < major) return false;
if(this->version_major > major) return true;
if(this->version_minor < minor) return false;
if(this->version_minor > minor) return true;
return (this->version_patch >= patch);
}
//---
// Syscall resolution
// Syscall resolution
//---
int OS::syscall_count() const noexcept
{
return m_syscall_table.size();
return m_syscall_table.size();
}
uint32_t OS::syscall(int id) const
{
return m_syscall_table[id];
return m_syscall_table[id];
}
int OS::find_syscall(uint32_t entry) const noexcept
{
try {
return m_syscall_addresses.at(entry);
}
catch(std::out_of_range &e) {
return -1;
}
try {
return m_syscall_addresses.at(entry);
}
catch(std::out_of_range &e) {
return -1;
}
}
uint32_t OS::syscall_table_address() const noexcept
{
uint32_t address = (this->type == FX) ? 0x8001007c : 0x8002007c;
return m_space.read_u32(address);
uint32_t address = (this->type == FX) ? 0x8001007c : 0x8002007c;
return m_space.read_u32(address);
}
void OS::parse_syscall_table()
{
/* Traverse the syscall table */
uint32_t syscall_table = syscall_table_address();
int id = 0;
/* Traverse the syscall table */
uint32_t syscall_table = syscall_table_address();
int id = 0;
while(1)
{
uint32_t entry = m_space.read_u32(syscall_table + 4 * id);
while(1) {
uint32_t entry = m_space.read_u32(syscall_table + 4 * id);
MemoryRegion const *r = MemoryRegion::region_for(entry);
if(!r) break;
MemoryRegion const *r = MemoryRegion::region_for(entry);
if(!r) break;
m_syscall_table.push_back(entry);
m_syscall_addresses[entry] = id;
m_syscall_table.push_back(entry);
m_syscall_addresses[entry] = id;
id++;
}
id++;
}
}
//---
// Footer search
// Footer search
//---
void OS::parse_footer()
{
VirtualSpace &s = m_space;
VirtualSpace &s = m_space;
/* Find the footer address (occurrence of "CASIOABSLangdata") */
uint32_t start = MemoryRegion::ROM.start;
uint32_t end = MemoryRegion::ROM.end;
/* Find the footer address (occurrence of "CASIOABSLangdata") */
uint32_t start = MemoryRegion::ROM.start;
uint32_t end = MemoryRegion::ROM.end;
this->footer = s.search(start, end, "CASIOABSLangdata", 16);
if(this->footer == end)
{
this->footer = -1;
this->timestamp = std::string("");
this->langdata = 0;
this->computed_checksum = -1;
return;
}
this->footer = s.search(start, end, "CASIOABSLangdata", 16);
if(this->footer == end) {
this->footer = -1;
this->timestamp = std::string("");
this->langdata = 0;
this->computed_checksum = -1;
return;
}
uint32_t addr = this->footer + 8;
this->langdata = 0;
uint32_t addr = this->footer + 8;
this->langdata = 0;
while(1)
{
void const *entry = s.translate(addr, 8);
if(!entry || memcmp(entry, "Langdata", 8) != 0)
break;
this->langdata++;
addr += 0x30;
}
while(1) {
void const *entry = s.translate(addr, 8);
if(!entry || memcmp(entry, "Langdata", 8) != 0)
break;
this->langdata++;
addr += 0x30;
}
this->timestamp = s.read_str(addr, 14);
this->checksum = s.read_u32(addr + 0x18);
this->computed_checksum = this->compute_checksum();
this->timestamp = s.read_str(addr, 14);
this->checksum = s.read_u32(addr + 0x18);
this->computed_checksum = this->compute_checksum();
}
//---
// Checksum
//---
static uint32_t accumulate_range(VirtualSpace const &m_space,
uint32_t start, uint32_t end)
static uint32_t accumulate_range(VirtualSpace const &m_space, uint32_t start,
uint32_t end)
{
uint32_t sum = 0;
uint32_t sum = 0;
/* Read from dynamically-sized bindings; read_u8() would be too slow */
while(start < end) {
int size;
uint8_t *buf = (uint8_t *)m_space.translate_dynamic(start, &size);
if(!buf || size <= 0)
break;
/* Read from dynamically-sized bindings; read_u8() would be too slow */
while(start < end) {
int size;
uint8_t *buf = (uint8_t *)m_space.translate_dynamic(start, &size);
if(!buf || size <= 0)
return -1;
if(start + size > end)
size = end - start;
if(start + size > end)
size = end - start;
for(int i = 0; i < size; i++)
sum += buf[i];
for(int i = 0; i < size; i++)
sum += buf[i];
start += size;
}
start += size;
}
return sum;
return sum;
}
uint32_t OS::compute_checksum() const
{
if(this->type == FX) {
return accumulate_range(m_space, 0x80010000, this->checksum.address);
}
else if(this->type == CG) {
if(this->version_lt(2, 2, 0)) {
return accumulate_range(m_space, 0x80020000, 0x80b5feb0)
+ accumulate_range(m_space,0x80b5fef0, 0x80b5fff8);
}
else {
return accumulate_range(m_space, 0x80020000, 0x80b20000)
+ accumulate_range(m_space, this->footer+8,
this->checksum.address);
}
}
return -1;
if(this->type == FX) {
return accumulate_range(m_space, 0x80010000, this->checksum.address);
}
else if(this->type == CG) {
if(this->version_lt(2, 2, 0)) {
return accumulate_range(m_space, 0x80020000, 0x80b5feb0)
+ accumulate_range(m_space,0x80b5fef0, 0x80b5fff8);
}
else {
return accumulate_range(m_space, 0x80020000, 0x80b20000)
+ accumulate_range(m_space, this->footer+8,
this->checksum.address);
}
}
return -1;
}
} /* namespace FxOS */

View File

@ -109,11 +109,10 @@ std::optional<std::string> PrintPass::symquery(Symbol::Type type,
for(int i = m_symtables.size() - 1; i >= 0; i--)
{
SymbolTable const &st = m_symtables[i];
if(!st.is_usable_on(m_disasm.space())) continue;
if(m_os && !st.is_usable_on(*m_os)) continue;
auto maybe_str = st.query(type, value);
if(maybe_str) return maybe_str;
if(maybe_str)
return maybe_str;
}
return std::nullopt;

View File

@ -25,52 +25,51 @@ DataType const *IntegerType::i32 = &_i32;
BitfieldType::Field BitfieldType::named_field(std::string name) const
{
for(auto &f: fields)
{
if(f.first == name) return f;
}
for(auto &f: fields) {
if(f.first == name)
return f;
}
throw std::logic_error("no such field name in bit field");
throw std::logic_error("no such field name in bit field");
}
DataType::DataKind DataType::kind() const noexcept
{
return (DataKind)v.index();
return (DataKind)v.index();
}
size_t DataType::size() const noexcept
{
switch(kind())
{
case Integer: return integer().size;
case Bitfield: return bitfield().size;
case Array: return array().size;
case String: return string().size;
case Struct: return structs().size;
}
switch(kind()) {
case Integer: return integer().size;
case Bitfield: return bitfield().size;
case Array: return array().size;
case String: return string().size;
case Struct: return structs().size;
}
return 0;
return 0;
};
IntegerType const &DataType::integer() const
{
return std::get<IntegerType>(v);
return std::get<IntegerType>(v);
}
BitfieldType const &DataType::bitfield() const
{
return std::get<BitfieldType>(v);
return std::get<BitfieldType>(v);
}
ArrayType const &DataType::array() const
{
return std::get<ArrayType>(v);
return std::get<ArrayType>(v);
}
StringType const &DataType::string() const
{
return std::get<StringType>(v);
return std::get<StringType>(v);
}
StructType const &DataType::structs() const
{
return std::get<StructType>(v);
return std::get<StructType>(v);
}
//---
@ -78,92 +77,87 @@ StructType const &DataType::structs() const
//---
DataValue::DataValue():
type {nullptr}
type {nullptr}
{
}
DataValue::DataValue(DataType const *type):
type {type}, mem(type->size(), (int16_t)-1)
type {type}, mem(type->size(), (int16_t)-1)
{
}
void DataValue::access(size_t offset, size_t size) const
{
if(size != 1 && size != 2 && size != 4)
throw std::logic_error("Invalid simulated access size");
if(offset + size > mem.size())
throw std::logic_error("Access overflows from data");
if(size != 1 && size != 2 && size != 4)
throw std::logic_error("Invalid simulated access size");
if(offset + size > mem.size())
throw std::logic_error("Access overflows from data");
}
uint32_t DataValue::read(size_t offset, size_t size) const
{
access(offset, size);
uint32_t result = 0;
access(offset, size);
uint32_t result = 0;
while(size--)
{
int16_t byte = mem[offset++];
if(byte == -1)
throw std::logic_error("Read uninitialized value");
while(size--) {
int16_t byte = mem[offset++];
if(byte == -1)
throw std::logic_error("Read uninitialized value");
result = (result << 8) | byte;
}
result = (result << 8) | byte;
}
return result;
return result;
}
void DataValue::write(size_t offset, size_t size, uint32_t contents)
{
access(offset, size);
access(offset, size);
offset += size;
while(size-- > 0)
{
mem[--offset] = contents & 0xff;
contents >>= 8;
}
offset += size;
while(size-- > 0) {
mem[--offset] = contents & 0xff;
contents >>= 8;
}
}
uint32_t DataValue::uinteger() const
{
if(!type || type->kind() != DataType::Integer)
throw std::logic_error("uinteger() on non-int DataValue");
if(!type || type->kind() != DataType::Integer)
throw std::logic_error("uinteger() on non-int DataValue");
return read(0, type->size());
return read(0, type->size());
}
std::string DataValue::str() const noexcept
{
std::string result;
std::string result;
switch(type->kind())
{
/* Format all integers in hexadecimal */
case DataType::Integer:
return format("0x%0*x", 2*type->size(), read(0,type->size()));
switch(type->kind()) {
/* Format all integers in hexadecimal */
case DataType::Integer:
return format("0x%0*x", 2*type->size(), read(0,type->size()));
/* TODO: Print data values of complex types */
case DataType::Bitfield:
case DataType::Array:
case DataType::String:
case DataType::Struct:
/* TODO: Print data values of complex types */
case DataType::Bitfield:
case DataType::Array:
case DataType::String:
case DataType::Struct:
/* If the type is not supported, use hexadecimal notation */
default:
for(size_t i = 0; i < mem.size(); i++)
{
int16_t byte = mem[i];
/* If the type is not supported, use hexadecimal notation */
default:
for(size_t i = 0; i < mem.size(); i++) {
int16_t byte = mem[i];
if(byte == -1) result += " UND";
else result += format(" %02x", byte);
}
if(byte == -1) result += " UND";
else result += format(" %02x", byte);
}
result[0] = '{';
result += '}';
}
result[0] = '{';
result += '}';
}
return result;
return result;
}
} /* namespace FxOS */

View File

@ -1,49 +1,43 @@
//---------------------------------------------------------------------------//
// 1100101 |_ mov #0, r4 __ //
// 11 |_ <0xb380 %5c4> / _|_ _____ ___ //
// 0110 |_ 3.50 -> 3.60 | _\ \ / _ (_-< //
// |_ base# + offset |_| /_\_\___/__/ //
//---------------------------------------------------------------------------//
#include <fxos/symbols.h>
#include <fxos/vspace.h>
namespace FxOS {
SymbolTable::SymbolTable(std::string os, std::string mpu):
m_os_constraint(os), m_mpu_constraint(mpu)
SymbolTable::SymbolTable()
{
}
bool SymbolTable::is_usable_on(OS &os) const noexcept
{
std::string constraint = (os.type == OS::FX) ? "fx" : "cg";
return (m_os_constraint == "" || m_os_constraint == constraint);
}
bool SymbolTable::is_usable_on(VirtualSpace &space) const noexcept
{
return m_mpu_constraint == "" || space.mpu == "" ||
m_mpu_constraint == space.mpu;
}
void SymbolTable::add(Symbol s)
{
symbols.push_back(s);
symbols.push_back(s);
}
std::optional<std::string> SymbolTable::query(Symbol::Type type,
uint32_t value) const
uint32_t value) const
{
for(auto &sym: symbols)
{
if(sym.type == type && sym.value == value) return sym.name;
}
for(auto &sym: symbols) {
if(sym.type == type && sym.value == value)
return sym.name;
}
return std::nullopt;
return std::nullopt;
}
std::optional<Symbol> SymbolTable::lookup(std::string name) const
{
for(auto &sym: symbols)
{
if(sym.name == name) return sym;
}
for(auto &sym: symbols) {
if(sym.name == name)
return sym;
}
return std::nullopt;
return std::nullopt;
}
} /* namespace FxOS */

View File

@ -153,6 +153,9 @@ OS *VirtualSpace::os_analysis(bool force)
{
if(!m_os || force) {
m_os = std::make_unique<OS>(*this);
/* We don't keep an OS analysis result that failed */
if(m_os->type == OS::UNKNOWN)
m_os = nullptr;
}
return m_os.get();
}