Skip to content

Commit

Permalink
Merge pull request #123 from zyantific/error-handling
Browse files Browse the repository at this point in the history
Improve error handling
  • Loading branch information
ZehMatt authored May 14, 2024
2 parents 43d42bb + 2052a3a commit 7423b14
Show file tree
Hide file tree
Showing 41 changed files with 1,339 additions and 708 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ endif()

# Target: zasm
set(zasm_SOURCES
"src/zasm/src/core/error.cpp"
"src/zasm/src/core/filestream.cpp"
"src/zasm/src/core/memorystream.cpp"
"src/zasm/src/decoder/decoder.cpp"
Expand Down Expand Up @@ -165,6 +166,7 @@ if(ZASM_BUILD_TESTS OR CMKR_ROOT_PROJECT) # tests
"src/tests/main.cpp"
"src/tests/tests/tests.assembler.cpp"
"src/tests/tests/tests.decoder.cpp"
"src/tests/tests/tests.error.cpp"
"src/tests/tests/tests.externals.cpp"
"src/tests/tests/tests.formatter.cpp"
"src/tests/tests/tests.imports.cpp"
Expand Down
2 changes: 1 addition & 1 deletion examples/assembler_basic/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ int main()
Serializer serializer{};

auto res = serializer.serialize(program, 0x00400000);
assert(res == Error::None);
assert(res == ErrorCode::None);

std::cout << examples::utils::getDisassemblyDump(serializer, program.getMode()) << "\n";
}
2 changes: 1 addition & 1 deletion examples/assembler_sections/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ int main()
Serializer serializer{};

auto res = serializer.serialize(program, 0x00400000);
assert(res == Error::None);
assert(res == ErrorCode::None);

std::cout << examples::utils::getDisassemblyDump(serializer, program.getMode()) << "\n";
}
4 changes: 2 additions & 2 deletions examples/basic_jit/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,9 @@ int main()

// Serialize program.
Serializer serializer;
if (auto err = serializer.serialize(program, reinterpret_cast<int64_t>(pCodePage)); err != zasm::Error::None)
if (auto err = serializer.serialize(program, reinterpret_cast<int64_t>(pCodePage)); err != zasm::ErrorCode::None)
{
std::cout << "Serialization failure: " << zasm::getErrorName(err) << "\n";
std::cout << "Serialization failure: " << err.getErrorName() << "\n";
return EXIT_FAILURE;
}

Expand Down
2 changes: 1 addition & 1 deletion examples/common/examples.common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ namespace zasm::examples::utils
auto res = decoder.decode(sectBuf + sectOffset, sectLen - sectOffset, curAddress);
if (!res.hasValue())
{
std::cout << "Decoder Error: " << zasm::getErrorName(res.error()) << std::endl;
std::cout << "Decoder Error: " << res.error().getErrorName() << std::endl;
break;
}

Expand Down
6 changes: 3 additions & 3 deletions examples/decode_to_assembler/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,16 @@ int main()
const auto decoderRes = decoder.decode(code.data() + bytesDecoded, code.size() - bytesDecoded, curAddress);
if (!decoderRes)
{
std::cout << "Failed to decode at " << std::hex << curAddress << ", " << getErrorName(decoderRes.error()) << "\n";
std::cout << "Failed to decode at " << std::hex << curAddress << ", " << decoderRes.error().getErrorName() << "\n";
return EXIT_FAILURE;
}

const auto& instrInfo = *decoderRes;

const auto instr = instrInfo.getInstruction();
if (auto res = assembler.emit(instr); res != zasm::Error::None)
if (auto res = assembler.emit(instr); res != zasm::ErrorCode::None)
{
std::cout << "Failed to emit instruction " << std::hex << curAddress << ", " << getErrorName(res) << "\n";
std::cout << "Failed to emit instruction " << std::hex << curAddress << ", " << res.getErrorName() << "\n";
}

bytesDecoded += instrInfo.getLength();
Expand Down
2 changes: 1 addition & 1 deletion examples/memory_operands/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ int main()
Serializer serializer{};

auto res = serializer.serialize(program, 0x00400000);
assert(res == Error::None);
assert(res == ErrorCode::None);

std::cout << examples::utils::getDisassemblyDump(serializer, program.getMode()) << "\n";
}
102 changes: 68 additions & 34 deletions include/zasm/core/errors.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

namespace zasm
{
enum class Error : std::uint32_t
enum class ErrorCode : std::uint32_t
{
None = 0,
// Generic.
Expand All @@ -28,47 +28,81 @@ namespace zasm
// Decoder.
InvalidInstruction,
OutOfBounds,
InstructionTooLong,
// Encoder.
ImpossibleInstruction,
AddressOutOfRange,
// Serialization.
EmptyState,
ImpossibleRelocation,
};

static constexpr const char* getErrorName(Error err) noexcept
/// <summary>
/// The Error class represents an error code and can have additionally a message attached.
/// If the object is constructed with an error message additional memory will be allocated.
/// If the object is constructed only with an error code there will be no extra allocation.
/// </summary>
class Error
{
#define ERROR_STRING(e) \
case e: \
return #e
std::uintptr_t _data{};

switch (err)
{
ERROR_STRING(Error::None);
ERROR_STRING(Error::InvalidMode);
ERROR_STRING(Error::NotInitialized);
ERROR_STRING(Error::InvalidOperation);
ERROR_STRING(Error::InvalidParameter);
ERROR_STRING(Error::FileNotFound);
ERROR_STRING(Error::AccessDenied);
ERROR_STRING(Error::OutOfMemory);
ERROR_STRING(Error::LabelNotFound);
ERROR_STRING(Error::UnresolvedLabel);
ERROR_STRING(Error::InvalidLabel);
ERROR_STRING(Error::LabelAlreadyBound);
ERROR_STRING(Error::SectionNotFound);
ERROR_STRING(Error::SectionAlreadyBound);
ERROR_STRING(Error::SignatureMismatch);
ERROR_STRING(Error::InvalidInstruction);
ERROR_STRING(Error::OutOfBounds);
ERROR_STRING(Error::ImpossibleInstruction);
ERROR_STRING(Error::EmptyState);
ERROR_STRING(Error::ImpossibleRelocation);
default:
assert(false);
break;
}
#undef ERROR_STRING
return nullptr;
}
public:
constexpr Error() noexcept = default;
Error(const Error& other);
Error(Error&& other) noexcept;

/// <summary>
/// Construct an Error object with the given error code.
/// </summary>
/// <param name="code">Error Code</param>
Error(ErrorCode code) noexcept;

/// <summary>
/// Construct an Error object with the given error code and an additional message.
/// The message will be copied so it is safe to pass a temporary string.
/// </summary>
/// <param name="code">Error Code</param>
/// <param name="message">Additional information</param>
Error(ErrorCode code, const char* message);

~Error() noexcept;

/// <summary>
/// Returns the assigned error code.
/// </summary>
/// <returns>Error code</returns>
ErrorCode getCode() const noexcept;

/// <summary>
/// Returns the error code name as a string.
/// The return value is never nullptr.
/// </summary>
/// <returns>Error name</returns>
const char* getErrorName() const noexcept;

/// <summary>
/// Get the error message if it was set. If the object was constructed without a message
/// this function will translate the error code into a generic message.
/// The return value is never nullptr.
/// </summary>
/// <returns>Error message</returns>
const char* getErrorMessage() const noexcept;

/// <summary>
/// Clears the error object which means that the error code will be set to ErrorCode::None.
/// If the object has an additional message it will be deallocated.
/// </summary>
void clear();

/// <summary>
/// Returns true if the error object is empty.
/// </summary>
bool empty() const noexcept;

bool operator==(ErrorCode code) const noexcept;
bool operator!=(ErrorCode code) const noexcept;
Error& operator=(Error&& other) noexcept;
Error& operator=(const Error& other) noexcept;
};

} // namespace zasm
11 changes: 8 additions & 3 deletions include/zasm/core/expected.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,15 @@ namespace zasm
// Internal wrapper type for unexpected.
template<typename T> struct Unexpected
{
const T failure;
T failure;

constexpr Unexpected(const T& val) noexcept
: failure{ val }
constexpr Unexpected(T&& arg) noexcept
: failure{ std::move(arg) }
{
}

constexpr Unexpected(const T& arg) noexcept
: failure{ arg }
{
}
};
Expand Down
36 changes: 18 additions & 18 deletions include/zasm/core/stringpool.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,48 +129,48 @@ namespace zasm
const auto entryCount = static_cast<std::uint32_t>(_entries.size());
if (auto len = stream.write(&entryCount, sizeof(entryCount)); len == 0)
{
return Error::InvalidParameter;
return ErrorCode::InvalidParameter;
}

for (const auto& entry : _entries)
{
if (auto len = stream.write(entry.hash); len == 0)
{
return Error::InvalidParameter;
return ErrorCode::InvalidParameter;
}
if (auto len = stream.write(entry.offset); len == 0)
{
return Error::InvalidParameter;
return ErrorCode::InvalidParameter;
}
if (auto len = stream.write(entry.len); len == 0)
{
return Error::InvalidParameter;
return ErrorCode::InvalidParameter;
}
if (auto len = stream.write(entry.capacity); len == 0)
{
return Error::InvalidParameter;
return ErrorCode::InvalidParameter;
}
if (auto len = stream.write(entry.refCount); len == 0)
{
return Error::InvalidParameter;
return ErrorCode::InvalidParameter;
}
}

const auto dataSize = static_cast<std::uint32_t>(_data.size());
if (auto len = stream.write(dataSize); len == 0)
{
return Error::InvalidParameter;
return ErrorCode::InvalidParameter;
}

if (dataSize > 0)
{
if (auto len = stream.write(_data.data(), dataSize); len == 0)
{
return Error::InvalidParameter;
return ErrorCode::InvalidParameter;
}
}

return Error::None;
return ErrorCode::None;
}

Error load(IStream& stream)
Expand All @@ -180,7 +180,7 @@ namespace zasm
std::uint32_t entryCount{};
if (auto len = stream.read(&entryCount, sizeof(entryCount)); len == 0)
{
return Error::InvalidParameter;
return ErrorCode::InvalidParameter;
}

std::vector<Entry> loadedEntries;
Expand All @@ -189,30 +189,30 @@ namespace zasm
{
if (auto len = stream.read(entry.hash); len == 0)
{
return Error::InvalidParameter;
return ErrorCode::InvalidParameter;
}
if (auto len = stream.read(entry.offset); len == 0)
{
return Error::InvalidParameter;
return ErrorCode::InvalidParameter;
}
if (auto len = stream.read(entry.len); len == 0)
{
return Error::InvalidParameter;
return ErrorCode::InvalidParameter;
}
if (auto len = stream.read(entry.capacity); len == 0)
{
return Error::InvalidParameter;
return ErrorCode::InvalidParameter;
}
if (auto len = stream.read(entry.refCount); len == 0)
{
return Error::InvalidParameter;
return ErrorCode::InvalidParameter;
}
}

std::uint32_t dataSize{};
if (auto len = stream.read(&dataSize, sizeof(dataSize)); len == 0)
{
return Error::InvalidParameter;
return ErrorCode::InvalidParameter;
}

std::vector<char> loadedData;
Expand All @@ -221,14 +221,14 @@ namespace zasm
loadedData.resize(dataSize);
if (auto len = stream.read(loadedData.data(), dataSize); len == 0)
{
return Error::InvalidParameter;
return ErrorCode::InvalidParameter;
}
}

_entries = std::move(loadedEntries);
_data = std::move(loadedData);

return Error::None;
return ErrorCode::None;
}

private:
Expand Down
4 changes: 4 additions & 0 deletions include/zasm/decoder/decoder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ namespace zasm

Result decode(const void* data, std::size_t len, std::uint64_t address) noexcept;

MachineMode getMode() const;

const Error& getLastError() const;

private:
ZydisDecoder _decoder{};
MachineMode _mode{};
Expand Down
8 changes: 4 additions & 4 deletions include/zasm/formatter/formatter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,15 @@ namespace zasm::formatter
/// </summary>
/// <param name="program">The program to print as text</param>
/// <param name="options">Format options</param>
std::string toString(Program& program, Options options = kDefaultOptions);
std::string toString(const Program& program, Options options = kDefaultOptions);

/// <summary>
/// Formats a single node and results the text.
/// </summary>
/// <param name="program">The program to print as text</param>
/// <param name="node">Formats only the specified node</param>
/// <param name="options">Format options</param>
std::string toString(Program& program, const Node* node, Options options = kDefaultOptions);
std::string toString(const Program& program, const Node* node, Options options = kDefaultOptions);

/// <summary>
/// Formats the specified range, 'to' is not inclusive.
Expand All @@ -53,15 +53,15 @@ namespace zasm::formatter
/// <param name="nodeFrom">First node</param>
/// <param name="nodeTo">Last node</param>
/// <param name="options">Format options</param>
std::string toString(Program& program, const Node* nodeFrom, const Node* nodeTo, Options options = kDefaultOptions);
std::string toString(const Program& program, const Node* nodeFrom, const Node* nodeTo, Options options = kDefaultOptions);

/// <summary>
/// Formats a single instruction and results the text.
/// </summary>
/// <param name="program">The program to print as text</param>
/// <param name="instr">Instruction to format</param>
/// <param name="options">Format options</param>
std::string toString(Program& program, const Instruction* instr, Options options = kDefaultOptions);
std::string toString(const Program& program, const Instruction* instr, Options options = kDefaultOptions);

/// <summary>
/// Formats a single instruction and results the text.
Expand Down
Loading

0 comments on commit 7423b14

Please sign in to comment.