mirror of
https://github.com/Vith0r/StackSentry
synced 2026-06-21 13:46:19 +00:00
Vendor third-party libraries
This commit is contained in:
Vendored
+25
@@ -0,0 +1,25 @@
|
||||
krabsetw
|
||||
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
All rights reserved.
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the ""Software""), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "compiler_check.hpp"
|
||||
#include "ut.hpp"
|
||||
#include "kt.hpp"
|
||||
#include "trace.hpp"
|
||||
|
||||
namespace krabs {
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Specialization of the base trace class for user traces.
|
||||
* </summary>
|
||||
*/
|
||||
typedef krabs::trace<krabs::details::ut> user_trace;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Specialization of the base trace class for kernel traces.
|
||||
* </summary>
|
||||
*/
|
||||
typedef krabs::trace<krabs::details::kt> kernel_trace;
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "compiler_check.hpp"
|
||||
|
||||
namespace krabs {
|
||||
|
||||
/**
|
||||
* Wraps a range of a collection starting at the location
|
||||
* specified by the begin iterator and ending a the location
|
||||
* specified by the end iterator. The underlying items are
|
||||
* left in-place and should be considered const
|
||||
*/
|
||||
template <typename T>
|
||||
struct collection_view
|
||||
{
|
||||
private:
|
||||
const T beg_;
|
||||
const T end_;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Construct a new view for the range specified by the
|
||||
* iterators 'begin' and 'end'
|
||||
*/
|
||||
collection_view(const T begin, const T end)
|
||||
: beg_(begin)
|
||||
, end_(end)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* Get the iterator for the beginning of the view range
|
||||
*/
|
||||
const T begin() const
|
||||
{
|
||||
return beg_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the iterator for the end of the view range
|
||||
*/
|
||||
const T end() const
|
||||
{
|
||||
return end_;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a view over the range specified by iterators 'begin' and 'end'
|
||||
*/
|
||||
template <typename T>
|
||||
inline collection_view<T> view(const T& begin, const T& end)
|
||||
{
|
||||
return{ begin, end };
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a const_iterator view over the specified string
|
||||
*/
|
||||
template <typename T>
|
||||
inline collection_view<typename std::basic_string<T>::const_iterator> view(const std::basic_string<T>& string)
|
||||
{
|
||||
return{ string.cbegin(), string.cend() };
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a const view over the range starting at 'begin' extending 'length' items
|
||||
*/
|
||||
template <typename T>
|
||||
inline collection_view<const T*> view(const T* begin, size_t length)
|
||||
{
|
||||
return{ begin, begin + length };
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a const view over the specified array
|
||||
*/
|
||||
template <typename T, size_t n>
|
||||
inline collection_view<const T*> view(const T(&arr)[n])
|
||||
{
|
||||
return{ arr, arr + n };
|
||||
}
|
||||
|
||||
} /* namespace krabs */
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if (_MSC_VER < 1900)
|
||||
#error "krabsetw is only supported with Visual Studio 2015 and above (MSVC++ 14.0)"
|
||||
#endif
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "compiler_check.hpp"
|
||||
|
||||
namespace krabs {
|
||||
|
||||
class trace_already_registered : public std::runtime_error {
|
||||
public:
|
||||
trace_already_registered()
|
||||
: std::runtime_error("The trace session has already been registered")
|
||||
{}
|
||||
};
|
||||
|
||||
class invalid_parameter : public std::logic_error {
|
||||
public:
|
||||
invalid_parameter()
|
||||
: std::logic_error("Invalid parameter given")
|
||||
{}
|
||||
};
|
||||
|
||||
class open_trace_failure : public std::runtime_error {
|
||||
public:
|
||||
open_trace_failure()
|
||||
: std::runtime_error("Failure to open trace")
|
||||
{}
|
||||
};
|
||||
|
||||
class need_to_be_admin_failure : public std::runtime_error {
|
||||
public:
|
||||
need_to_be_admin_failure()
|
||||
: std::runtime_error("Need to be an admin")
|
||||
{}
|
||||
};
|
||||
|
||||
class could_not_find_schema : public std::runtime_error {
|
||||
public:
|
||||
could_not_find_schema()
|
||||
: std::runtime_error("Could not find the schema")
|
||||
{}
|
||||
|
||||
could_not_find_schema(const std::string& context)
|
||||
: std::runtime_error(std::string("Could not find the schema: ") + context)
|
||||
{}
|
||||
};
|
||||
|
||||
class type_mismatch_assert : public std::runtime_error {
|
||||
public:
|
||||
type_mismatch_assert(
|
||||
const char* property,
|
||||
const char* actual,
|
||||
const char* requested)
|
||||
: std::runtime_error(std::string("Attempt to read property '") +
|
||||
property + "' type " + actual + " as " + requested)
|
||||
{}
|
||||
};
|
||||
|
||||
class no_trace_sessions_remaining : public std::runtime_error {
|
||||
public:
|
||||
no_trace_sessions_remaining()
|
||||
: std::runtime_error("No more trace sessions available.")
|
||||
{}
|
||||
};
|
||||
|
||||
class function_not_supported : public std::runtime_error {
|
||||
public:
|
||||
function_not_supported()
|
||||
: std::runtime_error("This function is not supported on this system.")
|
||||
{}
|
||||
};
|
||||
|
||||
class unexpected_error : public std::runtime_error {
|
||||
public:
|
||||
unexpected_error(ULONG status)
|
||||
: std::runtime_error(std::string("An unexpected error occurred: status_code=") +
|
||||
std::to_string(status))
|
||||
{}
|
||||
|
||||
unexpected_error(const std::string &context)
|
||||
: std::runtime_error(std::string("An unexpected error occurred: ") + context)
|
||||
{}
|
||||
};
|
||||
|
||||
inline std::string get_status_and_record_context(ULONG status, const EVENT_RECORD& record)
|
||||
{
|
||||
std::stringstream message;
|
||||
message << "status_code="
|
||||
<< status
|
||||
<< " provider_id="
|
||||
<< std::to_string(record.EventHeader.ProviderId)
|
||||
<< " event_id="
|
||||
<< record.EventHeader.EventDescriptor.Id;
|
||||
|
||||
return message.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Checks for common ETW API error codes.</summary>
|
||||
*/
|
||||
inline void error_check_common_conditions(ULONG status)
|
||||
{
|
||||
if (status == ERROR_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (status) {
|
||||
case ERROR_ALREADY_EXISTS:
|
||||
throw krabs::trace_already_registered();
|
||||
case ERROR_INVALID_PARAMETER:
|
||||
throw krabs::invalid_parameter();
|
||||
case ERROR_ACCESS_DENIED:
|
||||
throw krabs::need_to_be_admin_failure();
|
||||
case ERROR_NOT_FOUND:
|
||||
throw krabs::could_not_find_schema();
|
||||
case ERROR_NO_SYSTEM_RESOURCES:
|
||||
throw krabs::no_trace_sessions_remaining();
|
||||
case ERROR_NOT_SUPPORTED:
|
||||
throw krabs::function_not_supported();
|
||||
default:
|
||||
throw krabs::unexpected_error(status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>Checks for common ETW API error codes and includes properties from the event record.</summary>
|
||||
*/
|
||||
inline void error_check_common_conditions(ULONG status, const EVENT_RECORD &record)
|
||||
{
|
||||
if (status == ERROR_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto context = get_status_and_record_context(status, record);
|
||||
|
||||
switch (status) {
|
||||
case ERROR_ALREADY_EXISTS:
|
||||
throw krabs::trace_already_registered();
|
||||
case ERROR_INVALID_PARAMETER:
|
||||
throw krabs::invalid_parameter();
|
||||
case ERROR_ACCESS_DENIED:
|
||||
throw krabs::need_to_be_admin_failure();
|
||||
case ERROR_NOT_FOUND:
|
||||
throw krabs::could_not_find_schema(context);
|
||||
case ERROR_NO_SYSTEM_RESOURCES:
|
||||
throw krabs::no_trace_sessions_remaining();
|
||||
case ERROR_NOT_SUPPORTED:
|
||||
throw krabs::function_not_supported();
|
||||
default:
|
||||
throw krabs::unexpected_error(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
+403
@@ -0,0 +1,403 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
// Interface for ETW.
|
||||
|
||||
#pragma once
|
||||
|
||||
#define INITGUID
|
||||
|
||||
#include "compiler_check.hpp"
|
||||
#include "trace.hpp"
|
||||
#include "errors.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
|
||||
#include <evntrace.h>
|
||||
#include <evntcons.h>
|
||||
|
||||
namespace krabs { namespace details {
|
||||
|
||||
// The ETW API requires that we reserve enough memory behind
|
||||
// an EVENT_TRACE_PROPERTIES buffer in order to store an ETW trace name
|
||||
// and an optional ETW log file name. The easiest way to do this is to
|
||||
// use a struct to reserve this space -- the alternative is to malloc
|
||||
// the bytes at runtime (ew).
|
||||
class trace_info {
|
||||
public:
|
||||
EVENT_TRACE_PROPERTIES properties;
|
||||
wchar_t traceName[MAX_PATH];
|
||||
wchar_t logfileName[MAX_PATH];
|
||||
};
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Used to implement starting and stopping traces.
|
||||
* </summary>
|
||||
*/
|
||||
template <typename T>
|
||||
class trace_manager {
|
||||
public:
|
||||
trace_manager(T &trace);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Starts the ETW trace identified by the info in the trace type.
|
||||
* </summary>
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Stops the ETW trace identified by the info in the trace type.
|
||||
* </summary>
|
||||
*/
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Opens the ETW trace identified by the info in the trace type.
|
||||
* </summary>
|
||||
*/
|
||||
EVENT_TRACE_LOGFILE open();
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Starts processing the ETW trace identified by the info in the trace type.
|
||||
* open() needs to called for this to work first.
|
||||
* </summary>
|
||||
*/
|
||||
void process();
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Queries the ETW trace identified by the info in the trace type.
|
||||
* </summary>
|
||||
*/
|
||||
EVENT_TRACE_PROPERTIES query();
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Configures the ETW trace session settings.
|
||||
* See https://docs.microsoft.com/en-us/windows/win32/api/evntrace/nf-evntrace-tracesetinformation.
|
||||
* </summary>
|
||||
*/
|
||||
void set_trace_information(
|
||||
TRACE_INFO_CLASS information_class,
|
||||
PVOID trace_information,
|
||||
ULONG information_length);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Notifies the underlying trace of the buffers that were processed.
|
||||
* </summary>
|
||||
*/
|
||||
void set_buffers_processed(size_t processed);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Notifies the underlying trace that an event occurred.
|
||||
* </summary>
|
||||
*/
|
||||
void on_event(const EVENT_RECORD &record);
|
||||
|
||||
private:
|
||||
trace_info fill_trace_info();
|
||||
EVENT_TRACE_LOGFILE fill_logfile();
|
||||
void close_trace();
|
||||
void register_trace();
|
||||
EVENT_TRACE_PROPERTIES query_trace();
|
||||
void stop_trace();
|
||||
EVENT_TRACE_LOGFILE open_trace();
|
||||
void process_trace();
|
||||
void enable_providers();
|
||||
|
||||
private:
|
||||
T &trace_;
|
||||
};
|
||||
|
||||
// Implementation
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Called by ETW when an event occurs, forwards calls to the
|
||||
* appropriate instance.
|
||||
* </summary>
|
||||
* <remarks>
|
||||
* A pointer to the instance is stored in the UserContext
|
||||
* field of the EVENT_RECORD. This is set via the Context field of the
|
||||
* EVENT_TRACE_LOGFILE structure.
|
||||
* </remarks>
|
||||
*/
|
||||
template <typename T>
|
||||
static void __stdcall trace_callback_thunk(EVENT_RECORD *pRecord)
|
||||
{
|
||||
auto *pUserTrace = (T*)(pRecord->UserContext);
|
||||
trace_manager<T> trace(*pUserTrace);
|
||||
trace.on_event(*pRecord);
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Called by ETW after the events for each buffer are delivered, gives
|
||||
* statistics like the number of buffers processed and the number of
|
||||
* events dropped.
|
||||
* </summary>
|
||||
* <remarks>
|
||||
* A pointer to the instance is stored in the UserContext
|
||||
* field of the EVENT_RECORD. This is set via the Context field of the
|
||||
* EVENT_TRACE_LOGFILE structure.
|
||||
* </remarks>
|
||||
*/
|
||||
template <typename T>
|
||||
static ULONG __stdcall trace_buffer_callback(EVENT_TRACE_LOGFILE *pLogFile)
|
||||
{
|
||||
auto *pTrace = (T*)(pLogFile->Context);
|
||||
trace_manager<T> trace(*pTrace);
|
||||
|
||||
// NOTE: EventsLost is not set on this type
|
||||
trace.set_buffers_processed(pLogFile->BuffersRead);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
trace_manager<T>::trace_manager(T &trace)
|
||||
: trace_(trace)
|
||||
{}
|
||||
|
||||
template <typename T>
|
||||
void trace_manager<T>::start()
|
||||
{
|
||||
if (trace_.sessionHandle_ == INVALID_PROCESSTRACE_HANDLE) {
|
||||
(void)open();
|
||||
}
|
||||
process_trace();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
EVENT_TRACE_LOGFILE trace_manager<T>::open()
|
||||
{
|
||||
register_trace();
|
||||
enable_providers();
|
||||
return open_trace();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void trace_manager<T>::process()
|
||||
{
|
||||
process_trace();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
EVENT_TRACE_PROPERTIES trace_manager<T>::query()
|
||||
{
|
||||
return query_trace();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void trace_manager<T>::set_trace_information(
|
||||
TRACE_INFO_CLASS information_class,
|
||||
PVOID trace_information,
|
||||
ULONG information_length)
|
||||
{
|
||||
ULONG status = TraceSetInformation(
|
||||
trace_.registrationHandle_,
|
||||
information_class,
|
||||
trace_information,
|
||||
information_length);
|
||||
|
||||
error_check_common_conditions(status);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void trace_manager<T>::stop()
|
||||
{
|
||||
stop_trace();
|
||||
close_trace();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void trace_manager<T>::set_buffers_processed(size_t processed)
|
||||
{
|
||||
trace_.buffersRead_ = processed;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void trace_manager<T>::on_event(const EVENT_RECORD &record)
|
||||
{
|
||||
trace_.on_event(record);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
trace_info trace_manager<T>::fill_trace_info()
|
||||
{
|
||||
trace_info info = {};
|
||||
info.properties.Wnode.BufferSize = sizeof(trace_info);
|
||||
info.properties.Wnode.Guid = T::trace_type::get_trace_guid();
|
||||
info.properties.Wnode.Flags = WNODE_FLAG_TRACED_GUID;
|
||||
info.properties.Wnode.ClientContext = 1; // QPC clock resolution
|
||||
info.properties.BufferSize = trace_.properties_.BufferSize;
|
||||
info.properties.MinimumBuffers = trace_.properties_.MinimumBuffers;
|
||||
info.properties.MaximumBuffers = trace_.properties_.MaximumBuffers;
|
||||
info.properties.FlushTimer = trace_.properties_.FlushTimer;
|
||||
|
||||
if (trace_.properties_.LogFileMode)
|
||||
info.properties.LogFileMode = trace_.properties_.LogFileMode;
|
||||
else
|
||||
info.properties.LogFileMode = EVENT_TRACE_REAL_TIME_MODE
|
||||
| EVENT_TRACE_NO_PER_PROCESSOR_BUFFERING;
|
||||
|
||||
info.properties.LogFileMode |= T::trace_type::augment_file_mode();
|
||||
info.properties.LoggerNameOffset = offsetof(trace_info, logfileName);
|
||||
info.properties.EnableFlags = T::trace_type::construct_enable_flags(trace_);
|
||||
assert(info.traceName[0] == '\0');
|
||||
assert(info.logfileName[0] == '\0');
|
||||
trace_.name_._Copy_s(info.traceName, ARRAYSIZE(info.traceName), trace_.name_.length());
|
||||
return info;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
EVENT_TRACE_LOGFILE trace_manager<T>::fill_logfile()
|
||||
{
|
||||
EVENT_TRACE_LOGFILE file = {};
|
||||
|
||||
if (!trace_.logFilename_.empty())
|
||||
{
|
||||
file.LogFileName = const_cast<wchar_t*>(trace_.logFilename_.c_str());
|
||||
file.ProcessTraceMode = PROCESS_TRACE_MODE_EVENT_RECORD;
|
||||
}
|
||||
else
|
||||
{
|
||||
file.LoggerName = const_cast<wchar_t*>(trace_.name_.c_str());
|
||||
file.ProcessTraceMode = PROCESS_TRACE_MODE_EVENT_RECORD |
|
||||
PROCESS_TRACE_MODE_REAL_TIME;
|
||||
}
|
||||
file.Context = (void *)&trace_;
|
||||
file.EventRecordCallback = trace_callback_thunk<T>;
|
||||
file.BufferCallback = trace_buffer_callback<T>;
|
||||
return file;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void trace_manager<T>::stop_trace()
|
||||
{
|
||||
trace_info info = fill_trace_info();
|
||||
ULONG status = ControlTrace(
|
||||
NULL,
|
||||
trace_.name_.c_str(),
|
||||
&info.properties,
|
||||
EVENT_TRACE_CONTROL_STOP);
|
||||
|
||||
if (status != ERROR_WMI_INSTANCE_NOT_FOUND) {
|
||||
error_check_common_conditions(status);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
EVENT_TRACE_PROPERTIES trace_manager<T>::query_trace()
|
||||
{
|
||||
trace_info info = fill_trace_info();
|
||||
ULONG status = ControlTrace(
|
||||
NULL,
|
||||
trace_.name_.c_str(),
|
||||
&info.properties,
|
||||
EVENT_TRACE_CONTROL_QUERY);
|
||||
|
||||
if (status != ERROR_WMI_INSTANCE_NOT_FOUND) {
|
||||
error_check_common_conditions(status);
|
||||
|
||||
return info.properties;
|
||||
}
|
||||
|
||||
return { };
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void trace_manager<T>::register_trace()
|
||||
{
|
||||
trace_info info = fill_trace_info();
|
||||
|
||||
ULONG status = StartTrace(&trace_.registrationHandle_,
|
||||
trace_.name_.c_str(),
|
||||
&info.properties);
|
||||
if (status == ERROR_ALREADY_EXISTS) {
|
||||
try {
|
||||
stop_trace();
|
||||
status = StartTrace(&trace_.registrationHandle_,
|
||||
trace_.name_.c_str(),
|
||||
&info.properties);
|
||||
}
|
||||
catch (need_to_be_admin_failure) {
|
||||
(void)open_trace();
|
||||
close_trace();
|
||||
// insufficient privilege to stop/configure
|
||||
// but if open/close didn't throw also
|
||||
// then we're okay to process events
|
||||
status = ERROR_SUCCESS;
|
||||
// we also invalidate the registrationHandle_
|
||||
// StartTrace() actually sets this to 0 on failure
|
||||
trace_.registrationHandle_ = INVALID_PROCESSTRACE_HANDLE;
|
||||
}
|
||||
catch (invalid_parameter) {
|
||||
// In some versions, the error code is 87 when using
|
||||
// SystemTraceControlGuid session. If open/close doesn't
|
||||
// throw, then we can continually processing events.
|
||||
(void)open_trace();
|
||||
close_trace();
|
||||
status = ERROR_SUCCESS;
|
||||
trace_.registrationHandle_ = INVALID_PROCESSTRACE_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
error_check_common_conditions(status);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
EVENT_TRACE_LOGFILE trace_manager<T>::open_trace()
|
||||
{
|
||||
auto file = fill_logfile();
|
||||
trace_.sessionHandle_ = OpenTrace(&file);
|
||||
if (trace_.sessionHandle_ == INVALID_PROCESSTRACE_HANDLE) {
|
||||
throw open_trace_failure();
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void trace_manager<T>::process_trace()
|
||||
{
|
||||
if (trace_.sessionHandle_ == INVALID_PROCESSTRACE_HANDLE) {
|
||||
throw open_trace_failure();
|
||||
}
|
||||
|
||||
// Refactoring warning.
|
||||
// During the testing of the (slower) C++/CLI implementation it became evident that
|
||||
// EnableTraceEx2(EVENT_CONTROL_CODE_CAPTURE_STATE) must be called very shortly
|
||||
// before ProcessTrace() in order for the rundown events to be generated.
|
||||
T::trace_type::enable_rundown(trace_);
|
||||
|
||||
ULONG status = ProcessTrace(&trace_.sessionHandle_, 1, NULL, NULL);
|
||||
error_check_common_conditions(status);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void trace_manager<T>::close_trace()
|
||||
{
|
||||
if (trace_.sessionHandle_ != INVALID_PROCESSTRACE_HANDLE) {
|
||||
ULONG status = CloseTrace(trace_.sessionHandle_);
|
||||
trace_.sessionHandle_ = INVALID_PROCESSTRACE_HANDLE;
|
||||
|
||||
if (status != ERROR_CTX_CLOSE_PENDING) {
|
||||
error_check_common_conditions(status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void trace_manager<T>::enable_providers()
|
||||
{
|
||||
T::trace_type::enable_providers(trace_);
|
||||
}
|
||||
} /* namespace details */ } /* namespace krabs */
|
||||
@@ -0,0 +1,124 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "../compiler_check.hpp"
|
||||
|
||||
namespace krabs { namespace predicates {
|
||||
|
||||
namespace comparers {
|
||||
|
||||
// Algorithms
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Iterator based equals
|
||||
*/
|
||||
template <typename Comparer>
|
||||
struct equals
|
||||
{
|
||||
template <typename Iter1, typename Iter2>
|
||||
bool operator()(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2) const
|
||||
{
|
||||
return std::equal(first1, last1, first2, last2, Comparer());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Iterator based search
|
||||
*/
|
||||
template <typename Comparer>
|
||||
struct contains
|
||||
{
|
||||
template <typename Iter1, typename Iter2>
|
||||
bool operator()(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2) const
|
||||
{
|
||||
// empty test range always contained, even when input range empty
|
||||
return first2 == last2
|
||||
|| std::search(first1, last1, first2, last2, Comparer()) != last1;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Iterator based starts_with
|
||||
*/
|
||||
template <typename Comparer>
|
||||
struct starts_with
|
||||
{
|
||||
template <typename Iter1, typename Iter2>
|
||||
bool operator()(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2) const
|
||||
{
|
||||
const auto first_nonequal = std::mismatch(first1, last1, first2, last2, Comparer());
|
||||
return first_nonequal.second == last2;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Iterator based ends_with
|
||||
*/
|
||||
template <typename Comparer>
|
||||
struct ends_with
|
||||
{
|
||||
template <typename Iter1, typename Iter2>
|
||||
bool operator()(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2) const
|
||||
{
|
||||
const auto dist1 = std::distance(first1, last1);
|
||||
const auto dist2 = std::distance(first2, last2);
|
||||
|
||||
if (dist2 > dist1)
|
||||
return false;
|
||||
|
||||
const auto suffix_begin = std::next(first1, dist1 - dist2);
|
||||
return std::equal(suffix_begin, last1, first2, last2, Comparer());
|
||||
}
|
||||
};
|
||||
|
||||
// Custom Comparison
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
template <typename T>
|
||||
struct iequal_to
|
||||
{
|
||||
bool operator()(const T& a, const T& b) const
|
||||
{
|
||||
static_assert(sizeof(T) == 0,
|
||||
"iequal_to needs a specialized overload for type");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Binary predicate for comparing two wide characters case insensitively
|
||||
* Does not handle all locales
|
||||
* </summary>
|
||||
*/
|
||||
template <>
|
||||
struct iequal_to<wchar_t>
|
||||
{
|
||||
bool operator()(const wchar_t& a, const wchar_t& b) const
|
||||
{
|
||||
return towupper(a) == towupper(b);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Binary predicate for comparing two characters case insensitively
|
||||
* Does not handle all locales
|
||||
* </summary>
|
||||
*/
|
||||
template <>
|
||||
struct iequal_to<char>
|
||||
{
|
||||
bool operator()(const char& a, const char& b) const
|
||||
{
|
||||
return toupper(a) == toupper(b);
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace comparers */
|
||||
|
||||
} /* namespace predicates */ } /* namespace krabs */
|
||||
@@ -0,0 +1,234 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <evntcons.h>
|
||||
#include <functional>
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
|
||||
#include "../compiler_check.hpp"
|
||||
#include "../trace_context.hpp"
|
||||
|
||||
namespace krabs { namespace testing {
|
||||
class event_filter_proxy;
|
||||
} /* namespace testing */} /* namespace krabs */
|
||||
|
||||
namespace krabs { namespace details {
|
||||
template <typename T> class base_provider;
|
||||
} /* namespace details */} /* namespace krabs */
|
||||
|
||||
|
||||
namespace krabs {
|
||||
|
||||
typedef void(*c_provider_callback)(const EVENT_RECORD &, const krabs::trace_context &);
|
||||
typedef void(*c_provider_error_callback)(const EVENT_RECORD&, const std::string&);
|
||||
typedef std::function<void(const EVENT_RECORD &, const krabs::trace_context &)> provider_event_callback;
|
||||
typedef std::function<void(const EVENT_RECORD&, const std::string&)> provider_error_callback;
|
||||
typedef std::function<bool(const EVENT_RECORD &, const krabs::trace_context &)> filter_predicate;
|
||||
|
||||
template <typename T> class provider;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Use this to provide event filtering before an event bubbles to
|
||||
* specific callbacks.
|
||||
* </summary>
|
||||
* <remarks>
|
||||
* Each event_filter has a single predicate (which can do complicated
|
||||
* checks and logic on the event). All callbacks registered under the
|
||||
* filter are invoked only if the predicate returns true for a given
|
||||
* event.
|
||||
* </remarks>
|
||||
*/
|
||||
class event_filter {
|
||||
public:
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Constructs an event_filter that applies the given predicate to all
|
||||
* events.
|
||||
* </summary>
|
||||
*/
|
||||
event_filter(filter_predicate predicate);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Constructs an event_filter that applies event id filtering by event_id
|
||||
* which will be added to list of filtered event ids in ETW API.
|
||||
* This way is more effective from performance point of view.
|
||||
* Given optional predicate will be applied to ETW API filtered results
|
||||
* </summary>
|
||||
*/
|
||||
event_filter(unsigned short event_id, filter_predicate predicate = nullptr);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Constructs an event_filter that applies event id filtering by event_id
|
||||
* which will be added to list of filtered event ids in ETW API.
|
||||
* This way is more effective from performance point of view.
|
||||
* Given optional predicate will be applied to ETW API filtered results
|
||||
* </summary>
|
||||
*/
|
||||
event_filter(std::vector<unsigned short> event_ids, filter_predicate predicate = nullptr);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Adds a function to call when an event for this filter is fired.
|
||||
* </summary>
|
||||
*/
|
||||
void add_on_event_callback(c_provider_callback callback);
|
||||
|
||||
template <typename U>
|
||||
void add_on_event_callback(U &callback);
|
||||
|
||||
template <typename U>
|
||||
void add_on_event_callback(const U &callback);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Adds a function to call when an error occurs.
|
||||
* </summary>
|
||||
*/
|
||||
void add_on_error_callback(c_provider_error_callback callback);
|
||||
|
||||
template <typename U>
|
||||
void add_on_error_callback(U& callback);
|
||||
|
||||
template <typename U>
|
||||
void add_on_error_callback(const U& callback);
|
||||
|
||||
const std::vector<unsigned short>& provider_filter_event_ids() const
|
||||
{
|
||||
return provider_filter_event_ids_;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Called when an event occurs, forwards to callbacks if the event
|
||||
* satisfies the predicate.
|
||||
* </summary>
|
||||
*/
|
||||
void on_event(const EVENT_RECORD &record, const krabs::trace_context &trace_context) const;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Called when an error occurs, forwards to the error callback
|
||||
* </summary>
|
||||
*/
|
||||
void on_error(const EVENT_RECORD& record, const std::string& error_message) const;
|
||||
|
||||
private:
|
||||
std::deque<provider_event_callback> event_callbacks_;
|
||||
std::deque<provider_error_callback> error_callbacks_;
|
||||
filter_predicate predicate_{ nullptr };
|
||||
std::vector<unsigned short> provider_filter_event_ids_;
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
friend class details::base_provider;
|
||||
|
||||
friend class krabs::testing::event_filter_proxy;
|
||||
};
|
||||
|
||||
// Implementation
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
inline event_filter::event_filter(filter_predicate predicate)
|
||||
: predicate_(predicate)
|
||||
{}
|
||||
|
||||
inline event_filter::event_filter(std::vector<unsigned short> event_ids, filter_predicate predicate/*=nullptr*/)
|
||||
: provider_filter_event_ids_{ event_ids },
|
||||
predicate_(predicate)
|
||||
{}
|
||||
|
||||
inline event_filter::event_filter(unsigned short event_id, filter_predicate predicate/*=nullptr*/)
|
||||
: provider_filter_event_ids_{ event_id },
|
||||
predicate_(predicate)
|
||||
{}
|
||||
|
||||
inline void event_filter::add_on_event_callback(c_provider_callback callback)
|
||||
{
|
||||
// C function pointers don't interact well with std::ref, so we
|
||||
// overload to take care of this scenario.
|
||||
event_callbacks_.push_back(callback);
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
void event_filter::add_on_event_callback(U &callback)
|
||||
{
|
||||
// std::function copies its argument -- because our callbacks list
|
||||
// is a list of std::function, this causes problems when a user
|
||||
// intended for their particular instance to be called.
|
||||
// std::ref lets us get around this and point to a specific instance
|
||||
// that they handed us.
|
||||
event_callbacks_.push_back(std::ref(callback));
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
void event_filter::add_on_event_callback(const U &callback)
|
||||
{
|
||||
// This is where temporaries bind to. Temporaries can't be wrapped in
|
||||
// a std::ref because they'll go away very quickly. We are forced to
|
||||
// actually copy these.
|
||||
event_callbacks_.push_back(callback);
|
||||
}
|
||||
|
||||
inline void event_filter::add_on_error_callback(c_provider_error_callback callback)
|
||||
{
|
||||
// C function pointers don't interact well with std::ref, so we
|
||||
// overload to take care of this scenario.
|
||||
error_callbacks_.push_back(callback);
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
void event_filter::add_on_error_callback(U& callback)
|
||||
{
|
||||
// std::function copies its argument -- because our callbacks list
|
||||
// is a list of std::function, this causes problems when a user
|
||||
// intended for their particular instance to be called.
|
||||
// std::ref lets us get around this and point to a specific instance
|
||||
// that they handed us.
|
||||
error_callbacks_.push_back(std::ref(callback));
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
void event_filter::add_on_error_callback(const U& callback)
|
||||
{
|
||||
// This is where temporaries bind to. Temporaries can't be wrapped in
|
||||
// a std::ref because they'll go away very quickly. We are forced to
|
||||
// actually copy these.
|
||||
error_callbacks_.push_back(callback);
|
||||
}
|
||||
|
||||
inline void event_filter::on_event(const EVENT_RECORD &record, const krabs::trace_context &trace_context) const
|
||||
{
|
||||
if (event_callbacks_.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (predicate_ != nullptr && !predicate_(record, trace_context)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& callback : event_callbacks_) {
|
||||
callback(record, trace_context);
|
||||
}
|
||||
}
|
||||
catch (const krabs::could_not_find_schema& ex)
|
||||
{
|
||||
// this occurs when a predicate is applied to an event for which
|
||||
// no schema exists. instead of allowing the exception to halt
|
||||
// the entire trace, send a notification to the filter's error callback
|
||||
for (auto& error_callback : error_callbacks_) {
|
||||
error_callback(record, ex.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* namespace krabs */
|
||||
@@ -0,0 +1,552 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <evntcons.h>
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include "../compiler_check.hpp"
|
||||
#include "comparers.hpp"
|
||||
#include "../trace_context.hpp"
|
||||
#include "view_adapters.hpp"
|
||||
|
||||
using namespace krabs::predicates::adapters;
|
||||
using namespace krabs::predicates::comparers;
|
||||
|
||||
namespace krabs { namespace predicates {
|
||||
|
||||
namespace details {
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* The base predicate struct, use to create a vector or list of
|
||||
* Arbitrary predicate types
|
||||
* </summary>
|
||||
*/
|
||||
struct predicate_base
|
||||
{
|
||||
virtual bool operator()(const EVENT_RECORD&, const krabs::trace_context&) const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Returns true for any event.
|
||||
* </summary>
|
||||
*/
|
||||
struct any_event : predicate_base {
|
||||
bool operator()(const EVENT_RECORD &, const krabs::trace_context &) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Returns false for any event.
|
||||
* </summary>
|
||||
*/
|
||||
struct no_event : predicate_base {
|
||||
bool operator()(const EVENT_RECORD &, const krabs::trace_context &) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Performs a logical AND on two filters.
|
||||
* </summary>
|
||||
*/
|
||||
template <typename T1, typename T2>
|
||||
struct and_filter : predicate_base {
|
||||
and_filter(const T1 &t1, const T2 &t2)
|
||||
: t1_(t1)
|
||||
, t2_(t2)
|
||||
{}
|
||||
|
||||
bool operator()(const EVENT_RECORD &record, const krabs::trace_context &trace_context) const
|
||||
{
|
||||
return (t1_(record, trace_context) && t2_(record, trace_context));
|
||||
}
|
||||
|
||||
private:
|
||||
const T1 t1_;
|
||||
const T2 t2_;
|
||||
};
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Performs a logical OR on two filters.
|
||||
* </summary>
|
||||
*/
|
||||
template <typename T1, typename T2>
|
||||
struct or_filter : predicate_base {
|
||||
or_filter(const T1 &t1, const T2 &t2)
|
||||
: t1_(t1)
|
||||
, t2_(t2)
|
||||
{}
|
||||
|
||||
bool operator()(const EVENT_RECORD &record, const krabs::trace_context &trace_context) const
|
||||
{
|
||||
return (t1_(record, trace_context) || t2_(record, trace_context));
|
||||
}
|
||||
|
||||
private:
|
||||
const T1 t1_;
|
||||
const T2 t2_;
|
||||
};
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Performs a logical NOT on a filter.
|
||||
* </summary>
|
||||
*/
|
||||
template <typename T1>
|
||||
struct not_filter : predicate_base {
|
||||
not_filter(const T1 &t1)
|
||||
: t1_(t1)
|
||||
{}
|
||||
|
||||
bool operator()(const EVENT_RECORD &record, const krabs::trace_context &trace_context) const
|
||||
{
|
||||
return !t1_(record, trace_context);
|
||||
}
|
||||
|
||||
private:
|
||||
const T1 t1_;
|
||||
};
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Returns true if the event property matches the expected value.
|
||||
* </summary>
|
||||
*/
|
||||
template <typename T>
|
||||
struct property_is : predicate_base {
|
||||
property_is(const std::wstring &property, const T &expected)
|
||||
: property_(property)
|
||||
, expected_(expected)
|
||||
{}
|
||||
|
||||
bool operator()(const EVENT_RECORD &record, const krabs::trace_context &trace_context) const
|
||||
{
|
||||
krabs::schema schema(record, trace_context.schema_locator);
|
||||
krabs::parser parser(schema);
|
||||
|
||||
try {
|
||||
return (expected_ == parser.parse<T>(property_));
|
||||
}
|
||||
catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const std::wstring property_;
|
||||
const T expected_;
|
||||
};
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Gets a collection_view of a property using the specified adapter
|
||||
* and executes the specified predicate against the view.
|
||||
* This is used to provide type-specialization for properties
|
||||
* that can be represented by the collection_view.
|
||||
* </summary>
|
||||
*/
|
||||
template <typename T, typename Adapter, typename Predicate>
|
||||
struct property_view_predicate : details::predicate_base
|
||||
{
|
||||
property_view_predicate(
|
||||
const std::wstring &property,
|
||||
const T &expected,
|
||||
Adapter adapter,
|
||||
Predicate predicate)
|
||||
: property_(property)
|
||||
, expected_(expected)
|
||||
, adapter_(adapter)
|
||||
, predicate_(predicate)
|
||||
{ }
|
||||
|
||||
//bool operator()(const EVENT_RECORD &record, const krabs::trace_context &trace_context)
|
||||
bool operator()(const EVENT_RECORD& record, const krabs::trace_context& trace_context) const
|
||||
{
|
||||
krabs::schema schema(record, trace_context.schema_locator);
|
||||
krabs::parser parser(schema);
|
||||
|
||||
try {
|
||||
auto view = parser.view_of(property_, adapter_);
|
||||
return predicate_(view.begin(), view.end(), expected_.begin(), expected_.end());
|
||||
}
|
||||
catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const std::wstring property_;
|
||||
const T expected_;
|
||||
Adapter adapter_;
|
||||
Predicate predicate_;
|
||||
};
|
||||
} /* namespace details */
|
||||
|
||||
// Filter factory functions
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* A simple filter that accepts any event.
|
||||
* </summary>
|
||||
*/
|
||||
static details::any_event any_event;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* A simple filter that accepts no events.
|
||||
* </summary>
|
||||
*/
|
||||
static details::no_event no_event;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Accepts an event if its ID matches the expected value.
|
||||
* </summary>
|
||||
*/
|
||||
struct id_is : details::predicate_base {
|
||||
id_is(size_t expected)
|
||||
: expected_(USHORT(expected))
|
||||
{}
|
||||
|
||||
bool operator()(const EVENT_RECORD &record, const krabs::trace_context &) const
|
||||
{
|
||||
return (record.EventHeader.EventDescriptor.Id == expected_);
|
||||
}
|
||||
|
||||
private:
|
||||
USHORT expected_;
|
||||
};
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Accepts an event if its opcode matches the expected value.
|
||||
* </summary>
|
||||
*/
|
||||
struct opcode_is : details::predicate_base {
|
||||
opcode_is(size_t expected)
|
||||
: expected_(USHORT(expected))
|
||||
{}
|
||||
|
||||
bool operator()(const EVENT_RECORD &record, const krabs::trace_context &) const
|
||||
{
|
||||
return (record.EventHeader.EventDescriptor.Opcode == expected_);
|
||||
}
|
||||
|
||||
private:
|
||||
USHORT expected_;
|
||||
};
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Accepts an event if any of the predicates in the vector matches
|
||||
* </summary>
|
||||
*/
|
||||
struct any_of : details::predicate_base {
|
||||
any_of(std::vector<details::predicate_base*> list)
|
||||
: list_(list)
|
||||
{}
|
||||
|
||||
bool operator()(const EVENT_RECORD &record, const krabs::trace_context &trace_context) const
|
||||
{
|
||||
for (auto &item : list_) {
|
||||
if (item->operator()(record, trace_context)) {
|
||||
return true;
|
||||
};
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
std::vector<details::predicate_base*> list_;
|
||||
};
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Accepts an event if all of the predicates in the vector matches
|
||||
* </summary>
|
||||
*/
|
||||
struct all_of : details::predicate_base {
|
||||
all_of(std::vector<details::predicate_base*> list)
|
||||
: list_(list)
|
||||
{}
|
||||
|
||||
bool operator()(const EVENT_RECORD& record, const krabs::trace_context& trace_context) const
|
||||
{
|
||||
if (list_.empty()) {
|
||||
return false;
|
||||
}
|
||||
for (auto& item : list_) {
|
||||
if (!item->operator()(record, trace_context)) {
|
||||
return false;
|
||||
};
|
||||
}
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
std::vector<details::predicate_base*> list_;
|
||||
};
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Accepts an event only if none of the predicates in the vector match
|
||||
* </summary>
|
||||
*/
|
||||
struct none_of : details::predicate_base {
|
||||
none_of(std::vector<details::predicate_base*> list)
|
||||
: list_(list)
|
||||
{}
|
||||
|
||||
bool operator()(const EVENT_RECORD& record, const krabs::trace_context& trace_context) const
|
||||
{
|
||||
for (auto& item : list_) {
|
||||
if (item->operator()(record, trace_context)) {
|
||||
return false;
|
||||
};
|
||||
}
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
std::vector<details::predicate_base*> list_;
|
||||
};
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Accepts an event if its version matches the expected value.
|
||||
* </summary>
|
||||
*/
|
||||
struct version_is : details::predicate_base {
|
||||
version_is(size_t expected)
|
||||
: expected_(USHORT(expected))
|
||||
{}
|
||||
|
||||
bool operator()(const EVENT_RECORD &record, const krabs::trace_context &) const
|
||||
{
|
||||
return (record.EventHeader.EventDescriptor.Version == expected_);
|
||||
}
|
||||
|
||||
private:
|
||||
USHORT expected_;
|
||||
};
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Accepts an event if its PID matches the expected value.
|
||||
* </summary>
|
||||
*/
|
||||
struct process_id_is : details::predicate_base {
|
||||
process_id_is(size_t expected)
|
||||
: expected_(ULONG(expected))
|
||||
{}
|
||||
|
||||
bool operator()(const EVENT_RECORD &record, const krabs::trace_context &) const
|
||||
{
|
||||
return (record.EventHeader.ProcessId == expected_);
|
||||
}
|
||||
|
||||
private:
|
||||
ULONG expected_;
|
||||
};
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Accepts an event if the named property matches the expected value.
|
||||
* </summary>
|
||||
*/
|
||||
template <typename T>
|
||||
details::property_is<T> property_is(
|
||||
const std::wstring &prop,
|
||||
const T &expected)
|
||||
{
|
||||
return details::property_is<T>(prop, expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Explicit specialization for string arrays, because C++.
|
||||
* </summary>
|
||||
*/
|
||||
inline details::property_is<std::wstring> property_is(
|
||||
const std::wstring &prop,
|
||||
const wchar_t *expected)
|
||||
{
|
||||
return details::property_is<std::wstring>(prop, std::wstring(expected));
|
||||
}
|
||||
|
||||
inline details::property_is<std::string> property_is(
|
||||
const std::wstring &prop,
|
||||
const char *expected)
|
||||
{
|
||||
return details::property_is<std::string>(prop, std::string(expected));
|
||||
}
|
||||
|
||||
// View-based filters
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* View based filters work on ranges of data in-place in the etw record.
|
||||
* By default, these expect a null terminated string property in the
|
||||
* record, but if an adapter is specified, any range of data can be
|
||||
* compared. The comparison functor must support taking two iterator
|
||||
* pairs that iterate the value_type specified by the adapter. Because
|
||||
* comparisons use iterators, it's possible to compare various flavors
|
||||
* of strings as well as arrays and binary data.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Accepts events if property exactly matches the expected value
|
||||
*/
|
||||
template <
|
||||
typename Adapter = adapters::generic_string<wchar_t>,
|
||||
typename T,
|
||||
typename Comparer = equals<std::equal_to<typename Adapter::value_type>>>
|
||||
details::property_view_predicate<T, Adapter, Comparer> property_equals(
|
||||
const std::wstring &prop,
|
||||
const T& expected)
|
||||
{
|
||||
return { prop, expected, Adapter(), Comparer() };
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts events if property case insensitive matches the expected value
|
||||
*/
|
||||
template <
|
||||
typename Adapter = adapters::generic_string<wchar_t>,
|
||||
typename T,
|
||||
typename Comparer = equals<iequal_to<typename Adapter::value_type>>>
|
||||
details::property_view_predicate<T, Adapter, Comparer> property_iequals(
|
||||
const std::wstring &prop,
|
||||
const T& expected)
|
||||
{
|
||||
return{ prop, expected, Adapter(), Comparer() };
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts events if property contains expected value
|
||||
*/
|
||||
template <
|
||||
typename Adapter = adapters::generic_string<wchar_t>,
|
||||
typename T,
|
||||
typename Comparer = contains<std::equal_to<typename Adapter::value_type>>>
|
||||
details::property_view_predicate<T, Adapter, Comparer> property_contains(
|
||||
const std::wstring &prop,
|
||||
const T& expected)
|
||||
{
|
||||
return {prop, expected, Adapter(), Comparer()};
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts events if property case insensitive contains expected value
|
||||
*/
|
||||
template <
|
||||
typename Adapter = adapters::generic_string<wchar_t>,
|
||||
typename T,
|
||||
typename Comparer = contains<iequal_to<typename Adapter::value_type>>>
|
||||
details::property_view_predicate<T, Adapter, Comparer> property_icontains(
|
||||
const std::wstring &prop,
|
||||
const T& expected)
|
||||
{
|
||||
return{ prop, expected, Adapter(), Comparer() };
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts events if property starts with expected value
|
||||
*/
|
||||
template <
|
||||
typename Adapter = adapters::generic_string<wchar_t>,
|
||||
typename T,
|
||||
typename Comparer = starts_with<std::equal_to<typename Adapter::value_type>>>
|
||||
details::property_view_predicate<T, Adapter, Comparer> property_starts_with(
|
||||
const std::wstring &prop,
|
||||
const T& expected)
|
||||
{
|
||||
return{ prop, expected, Adapter(), Comparer() };
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts events if property case insensitive starts with expected value
|
||||
*/
|
||||
template <
|
||||
typename Adapter = adapters::generic_string<wchar_t>,
|
||||
typename T,
|
||||
typename Comparer = starts_with<iequal_to<typename Adapter::value_type>>>
|
||||
details::property_view_predicate<T, Adapter, Comparer> property_istarts_with(
|
||||
const std::wstring &prop,
|
||||
const T& expected)
|
||||
{
|
||||
return{ prop, expected, Adapter(), Comparer() };
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts events if property ends with expected value
|
||||
*/
|
||||
template <
|
||||
typename Adapter = adapters::generic_string<wchar_t>,
|
||||
typename T,
|
||||
typename Comparer = ends_with<std::equal_to<typename Adapter::value_type>>>
|
||||
details::property_view_predicate<T, Adapter, Comparer> property_ends_with(
|
||||
const std::wstring &prop,
|
||||
const T& expected)
|
||||
{
|
||||
return{ prop, expected, Adapter(), Comparer() };
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts events if property case insensitive ends with expected value
|
||||
*/
|
||||
template <
|
||||
typename Adapter = adapters::generic_string<wchar_t>,
|
||||
typename T,
|
||||
typename Comparer = ends_with<iequal_to<typename Adapter::value_type>>>
|
||||
details::property_view_predicate<T, Adapter, Comparer> property_iends_with(
|
||||
const std::wstring &prop,
|
||||
const T& expected)
|
||||
{
|
||||
return{ prop, expected, Adapter(), Comparer() };
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Accepts an event if its two component filters both accept the event.
|
||||
* </summary>
|
||||
*/
|
||||
template <typename T1, typename T2>
|
||||
details::and_filter<T1, T2> and_filter(const T1 &t1, const T2 &t2)
|
||||
{
|
||||
return details::and_filter<T1, T2>(t1, t2);
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Accepts an event if either of its two component filters accept the event.
|
||||
* </summary>
|
||||
*/
|
||||
template <typename T1, typename T2>
|
||||
details::or_filter<T1, T2> or_filter(const T1 &t1, const T2 &t2)
|
||||
{
|
||||
return details::or_filter<T1, T2>(t1, t2);
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Negates the filter that is given to it.
|
||||
* </summary>
|
||||
*/
|
||||
template <typename T1>
|
||||
details::not_filter<T1> not_filter(const T1 &t1)
|
||||
{
|
||||
return details::not_filter<T1>(t1);
|
||||
}
|
||||
|
||||
} /* namespace predicates */ } /* namespace krabs */
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "../compiler_check.hpp"
|
||||
#include "../parser.hpp"
|
||||
|
||||
namespace krabs { namespace predicates {
|
||||
|
||||
namespace adapters {
|
||||
|
||||
/**
|
||||
* View adapter for counted_string strings
|
||||
*/
|
||||
struct counted_string
|
||||
{
|
||||
using value_type = krabs::counted_string::value_type;
|
||||
using const_iterator = krabs::counted_string::const_iterator;
|
||||
|
||||
collection_view<const_iterator> operator()(const property_info& propInfo) const
|
||||
{
|
||||
auto cs_ptr = reinterpret_cast<const krabs::counted_string*>(propInfo.pPropertyIndex_);
|
||||
return krabs::view(cs_ptr->string(), cs_ptr->length());
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* View adapter for fixed width and null-terminated strings
|
||||
*/
|
||||
template <typename ElemT>
|
||||
struct generic_string
|
||||
{
|
||||
using value_type = ElemT;
|
||||
using const_iterator = const value_type*;
|
||||
|
||||
collection_view<const_iterator> operator()(const property_info& propInfo) const
|
||||
{
|
||||
auto pString = reinterpret_cast<const value_type*>(propInfo.pPropertyIndex_);
|
||||
auto length = get_string_content_length(pString, propInfo.length_);
|
||||
|
||||
return krabs::view(pString, length);
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace adapters */
|
||||
|
||||
} /* namespace predicates */ } /* namespace krabs */
|
||||
+345
@@ -0,0 +1,345 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <objbase.h>
|
||||
|
||||
#include <new>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <cassert>
|
||||
|
||||
#include "compiler_check.hpp"
|
||||
|
||||
namespace krabs {
|
||||
|
||||
/** <summary>
|
||||
* Represents a GUID, allowing simplified construction from a string or
|
||||
* Windows GUID structure.
|
||||
* </summary>
|
||||
*/
|
||||
class guid {
|
||||
public:
|
||||
guid(GUID guid);
|
||||
guid(const std::wstring &guid);
|
||||
|
||||
bool operator==(const guid &rhs) const;
|
||||
bool operator==(const GUID &rhs) const;
|
||||
|
||||
bool operator<(const guid &rhs) const;
|
||||
bool operator<(const GUID &rhs) const;
|
||||
|
||||
operator GUID() const;
|
||||
operator const GUID*() const;
|
||||
|
||||
/** <summary>
|
||||
* Constructs a new random guid.
|
||||
* </summary>
|
||||
*/
|
||||
static inline guid random_guid();
|
||||
|
||||
private:
|
||||
GUID guid_;
|
||||
|
||||
friend struct std::hash<guid>;
|
||||
};
|
||||
|
||||
/** <summary>
|
||||
* Helper functions for parsing GUID's.
|
||||
* </summary>
|
||||
*/
|
||||
class guid_parser {
|
||||
// Implementing in Krabs instead of Lobsters so that we can test it in unmanaged code.
|
||||
private:
|
||||
// Number of characters in the UUID's 8-4-4-4-12 string format.
|
||||
static const size_t UUID_STRING_LENGTH = 36;
|
||||
|
||||
static const unsigned char DELIMITER = '-';
|
||||
|
||||
// Expected character positions of runs of hex digits in 8-4-4-4-12 format, e.g.
|
||||
// 00000000-0000-0000-0000-000000000000
|
||||
// Names correspond to struct members of GUID.
|
||||
static const size_t STR_POSITION_DATA1 = 0;
|
||||
static const size_t STR_POSITION_DATA2 = 8 + 1;
|
||||
static const size_t STR_POSITION_DATA3 = STR_POSITION_DATA2 + 4 + 1;
|
||||
static const size_t STR_POSITION_DATA4_PART1 = STR_POSITION_DATA3 + 4 + 1;
|
||||
static const size_t STR_POSITION_DATA4_PART2 = STR_POSITION_DATA4_PART1 + 4 + 1;
|
||||
|
||||
public:
|
||||
// str_input must have at least 2 valid chars in allocated buffer
|
||||
static bool hex_octet_to_byte(const char* str_input, unsigned char& byte_output);
|
||||
// str_input must have at least 2*sizeof(T) valid chars in allocated buffer
|
||||
template<typename T>
|
||||
static bool hex_string_to_number(const char* str_input, T& int_output);
|
||||
// str_input must have at least 2*byte_count valid chars in allocated buffer,
|
||||
// and byte_output must have at least byte_count bytes in allocated buffer
|
||||
static bool hex_string_to_bytes(const char* str_input, unsigned char* byte_output, size_t byte_count);
|
||||
|
||||
/** <summary>
|
||||
* Parses GUID of "D" format. For example, the nil GUID would be "00000000-0000-0000-0000-000000000000".
|
||||
* See: https://docs.microsoft.com/en-us/dotnet/api/system.guid.tostring?view=netframework-4.8
|
||||
*
|
||||
* (str) must have at least (length) valid characters for memory safety. A null terminator is not
|
||||
* required. Instead, (length) is used for the bounds check.
|
||||
*
|
||||
* Returns the parsed GUID. Throws a std::runtime_error if there is a bounds error or format error.
|
||||
*
|
||||
* This function is for performance, to help deal with container ID extended data, which has no null
|
||||
* terminator, which would force us to clone the data to append a null terminator in order to use
|
||||
* existing GUID parsing functions.
|
||||
* </summary>
|
||||
*/
|
||||
static GUID parse_guid(const char* str, unsigned int length);
|
||||
};
|
||||
|
||||
// Implementation
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
inline guid::guid(GUID guid)
|
||||
: guid_(guid)
|
||||
{}
|
||||
|
||||
inline guid::guid(const std::wstring &guid)
|
||||
{
|
||||
HRESULT hr = CLSIDFromString(guid.c_str(), &guid_);
|
||||
if (FAILED(hr)) {
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4244) // narrowing guid wchar_t to char for this error message
|
||||
std::string guidStr(guid.begin(), guid.end());
|
||||
#pragma warning(pop)
|
||||
std::stringstream stream;
|
||||
stream << "Error in constructing guid from string (";
|
||||
stream << guidStr;
|
||||
stream << "), hr = 0x";
|
||||
stream << std::hex << hr;
|
||||
throw std::runtime_error(stream.str());
|
||||
}
|
||||
}
|
||||
|
||||
inline bool guid::operator==(const guid &rhs) const
|
||||
{
|
||||
return (0 == memcmp(&guid_, &rhs.guid_, sizeof(GUID)));
|
||||
}
|
||||
|
||||
inline bool guid::operator==(const GUID &rhs) const
|
||||
{
|
||||
return (0 == memcmp(&guid_, &rhs, sizeof(GUID)));
|
||||
}
|
||||
|
||||
inline bool guid::operator<(const guid &rhs) const
|
||||
{
|
||||
return (memcmp(&guid_, &rhs.guid_, sizeof(guid_)) < 0);
|
||||
}
|
||||
|
||||
inline bool guid::operator<(const GUID &rhs) const
|
||||
{
|
||||
return (memcmp(&guid_, &rhs, sizeof(guid_)) < 0);
|
||||
}
|
||||
|
||||
inline guid::operator GUID() const
|
||||
{
|
||||
return guid_;
|
||||
}
|
||||
|
||||
inline guid::operator const GUID*() const
|
||||
{
|
||||
return &guid_;
|
||||
}
|
||||
|
||||
inline guid guid::random_guid()
|
||||
{
|
||||
GUID tmpGuid;
|
||||
CoCreateGuid(&tmpGuid);
|
||||
return guid(tmpGuid);
|
||||
}
|
||||
|
||||
struct CoTaskMemDeleter {
|
||||
void operator()(wchar_t *mem) {
|
||||
CoTaskMemFree(mem);
|
||||
}
|
||||
};
|
||||
|
||||
inline bool guid_parser::hex_octet_to_byte(const char* str_input, unsigned char& byte_output)
|
||||
{
|
||||
// Accepts chars '0' through '9' (0x30 to 0x39),
|
||||
// 'A' through 'F' (0x41 to 0x46)
|
||||
// 'a' through 'f' (0x61 to 0x66)
|
||||
|
||||
// Narrow the value later, for safety checking.
|
||||
auto value = 0;
|
||||
// most significant digit in the octet
|
||||
auto msd = str_input[0];
|
||||
// least significant digit in the octet
|
||||
auto lsd = str_input[1];
|
||||
|
||||
if (msd >= '0' && msd <= '9')
|
||||
{
|
||||
value |= ((int)msd & 0x0F) << 4;
|
||||
}
|
||||
else if ((msd >= 'A' && msd <= 'F') || (msd >= 'a' && msd <= 'f'))
|
||||
{
|
||||
value |= (((int)msd & 0x0F) + 9) << 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lsd >= '0' && lsd <= '9')
|
||||
{
|
||||
value |= ((int)lsd & 0x0F);
|
||||
}
|
||||
else if ((lsd >= 'A' && lsd <= 'F') || (lsd >= 'a' && lsd <= 'f'))
|
||||
{
|
||||
value |= (((int)lsd & 0x0F) + 9);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(value >= 0 && value <= UCHAR_MAX);
|
||||
byte_output = static_cast<unsigned char>(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool guid_parser::hex_string_to_number(const char* str_input, T& int_output)
|
||||
{
|
||||
auto byte_count = sizeof(T);
|
||||
T value = 0;
|
||||
unsigned char byte = 0;
|
||||
|
||||
for (size_t i = 0; i < byte_count; i++)
|
||||
{
|
||||
if (!guid_parser::hex_octet_to_byte(str_input + i * 2, byte))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
value = (value << 8) | static_cast<T>(byte);
|
||||
}
|
||||
|
||||
int_output = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool guid_parser::hex_string_to_bytes(const char* str_input, unsigned char* byte_output, size_t byte_count)
|
||||
{
|
||||
for (size_t i = 0; i < byte_count; i++)
|
||||
{
|
||||
if (!hex_octet_to_byte(str_input + (i * 2), byte_output[i]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** <summary>
|
||||
* Parses GUID of "D" format. For example, the nil GUID would be "00000000-0000-0000-0000-000000000000".
|
||||
* See: https://docs.microsoft.com/en-us/dotnet/api/system.guid.tostring?view=netframework-4.8
|
||||
*
|
||||
* (str) must have at least (length) valid characters for memory safety. A null terminator is not
|
||||
* required. Instead, (length) is used for the bounds check.
|
||||
*
|
||||
* Returns the parsed GUID. Throws a std::runtime_error if there is a bounds error or format error.
|
||||
*
|
||||
* This function is for performance, to help deal with container ID extended data, which has no null
|
||||
* terminator, which would force us to clone the data to append a null terminator in order to use
|
||||
* existing GUID parsing functions.
|
||||
* </summary>
|
||||
*/
|
||||
inline GUID guid_parser::parse_guid(const char* str, unsigned int length)
|
||||
{
|
||||
if (length != UUID_STRING_LENGTH)
|
||||
{
|
||||
std::stringstream message;
|
||||
message << "Input data has incorrect length. Expected "
|
||||
<< UUID_STRING_LENGTH
|
||||
<< ", got "
|
||||
<< length;
|
||||
throw std::runtime_error(message.str());
|
||||
}
|
||||
|
||||
GUID guid = { 0 };
|
||||
|
||||
// Check that hyphens are in expected places as a formatting issue.
|
||||
if (str[STR_POSITION_DATA2 - 1] != DELIMITER ||
|
||||
str[STR_POSITION_DATA3 - 1] != DELIMITER ||
|
||||
str[STR_POSITION_DATA4_PART1 - 1] != DELIMITER ||
|
||||
str[STR_POSITION_DATA4_PART2 - 1] != DELIMITER)
|
||||
{
|
||||
throw std::runtime_error("Missing a hyphen where one was expected.");
|
||||
}
|
||||
|
||||
// Use from_hex_string for Data1, Data2, and Data3 because of endianness of the data
|
||||
// Use hex_string_to_bytes for Data4's array elements because it's byte by byte instead
|
||||
auto success = guid_parser::hex_string_to_number(str + STR_POSITION_DATA1, guid.Data1)
|
||||
&& guid_parser::hex_string_to_number(str + STR_POSITION_DATA2, guid.Data2)
|
||||
&& guid_parser::hex_string_to_number(str + STR_POSITION_DATA3, guid.Data3)
|
||||
&& guid_parser::hex_string_to_bytes(str + STR_POSITION_DATA4_PART1, reinterpret_cast<unsigned char*>(&guid.Data4[0]), 2)
|
||||
&& guid_parser::hex_string_to_bytes(str + STR_POSITION_DATA4_PART2, reinterpret_cast<unsigned char*>(&guid.Data4[2]), 6);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
throw std::runtime_error("GUID string contains non-hex digits where hex digits are expected.");
|
||||
}
|
||||
|
||||
return guid;
|
||||
}
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
/*
|
||||
* Converts a krabs GUID to a wide string
|
||||
*/
|
||||
inline std::wstring to_wstring(const krabs::guid& guid)
|
||||
{
|
||||
wchar_t* guidString;
|
||||
HRESULT hr = StringFromCLSID(guid, &guidString);
|
||||
|
||||
if (FAILED(hr)) throw std::bad_alloc();
|
||||
|
||||
std::unique_ptr<wchar_t, krabs::CoTaskMemDeleter> managed(guidString);
|
||||
|
||||
return { managed.get() };
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts a Windows GUID to a C string
|
||||
*/
|
||||
inline std::string to_string(const GUID& guid)
|
||||
{
|
||||
char guid_string[37]; // 32 hex chars + 4 hyphens + null terminator
|
||||
snprintf(
|
||||
guid_string, sizeof(guid_string),
|
||||
"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||
guid.Data1, guid.Data2, guid.Data3,
|
||||
guid.Data4[0], guid.Data4[1], guid.Data4[2],
|
||||
guid.Data4[3], guid.Data4[4], guid.Data4[5],
|
||||
guid.Data4[6], guid.Data4[7]);
|
||||
return guid_string;
|
||||
}
|
||||
|
||||
template<>
|
||||
struct std::hash<krabs::guid>
|
||||
{
|
||||
size_t operator()(const krabs::guid& guid) const
|
||||
{
|
||||
// This algorithm comes from .NET's reference source for Guid.GetHashCode()
|
||||
return guid.guid_.Data1 ^
|
||||
((guid.guid_.Data2 << 16) | guid.guid_.Data3 ) ^
|
||||
((guid.guid_.Data4[2] << 24) | guid.guid_.Data4[7]);
|
||||
}
|
||||
};
|
||||
}
|
||||
+194
@@ -0,0 +1,194 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <guiddef.h>
|
||||
|
||||
#include "compiler_check.hpp"
|
||||
|
||||
namespace krabs { namespace guids {
|
||||
|
||||
DEFINE_GUID ( /* 45d8cccd-539f-4b72-a8b7-5c683142609a */
|
||||
alpc,
|
||||
0x45d8cccd,
|
||||
0x539f,
|
||||
0x4b72,
|
||||
0xa8, 0xb7, 0x5c, 0x68, 0x31, 0x42, 0x60, 0x9a
|
||||
);
|
||||
|
||||
DEFINE_GUID ( /* 13976d09-a327-438c-950b-7f03192815c7 */
|
||||
debug,
|
||||
0x13976d09,
|
||||
0xa327,
|
||||
0x438c,
|
||||
0x95, 0x0b, 0x7f, 0x03, 0x19, 0x28, 0x15, 0xc7
|
||||
);
|
||||
|
||||
DEFINE_GUID ( /* 3d6fa8d4-fe05-11d0-9dda-00c04fd7ba7c */
|
||||
disk_io,
|
||||
0x3d6fa8d4,
|
||||
0xfe05,
|
||||
0x11d0,
|
||||
0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c
|
||||
);
|
||||
|
||||
DEFINE_GUID ( /* 01853a65-418f-4f36-aefc-dc0f1d2fd235 */
|
||||
event_trace_config,
|
||||
0x01853a65,
|
||||
0x418f,
|
||||
0x4f36,
|
||||
0xae, 0xfc, 0xdc, 0x0f, 0x1d, 0x2f, 0xd2, 0x35
|
||||
);
|
||||
|
||||
DEFINE_GUID ( /* 90cbdc39-4a3e-11d1-84f4-0000f80464e3 */
|
||||
file_io,
|
||||
0x90cbdc39,
|
||||
0x4a3e,
|
||||
0x11d1,
|
||||
0x84, 0xf4, 0x00, 0x00, 0xf8, 0x04, 0x64, 0xe3
|
||||
);
|
||||
|
||||
DEFINE_GUID ( /* 2cb15d1d-5fc1-11d2-abe1-00a0c911f518 */
|
||||
image_load,
|
||||
0x2cb15d1d,
|
||||
0x5fc1,
|
||||
0x11d2,
|
||||
0xab, 0xe1, 0x00, 0xa0, 0xc9, 0x11, 0xf5, 0x18
|
||||
);
|
||||
|
||||
DEFINE_GUID ( /* 3d6fa8d3-fe05-11d0-9dda-00c04fd7ba7c */
|
||||
page_fault,
|
||||
0x3d6fa8d3,
|
||||
0xfe05,
|
||||
0x11d0,
|
||||
0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c
|
||||
);
|
||||
|
||||
DEFINE_GUID ( /* ce1dbfb4-137e-4da6-87b0-3f59aa102cbc */
|
||||
perf_info,
|
||||
0xce1dbfb4,
|
||||
0x137e,
|
||||
0x4da6,
|
||||
0x87, 0xb0, 0x3f, 0x59, 0xaa, 0x10, 0x2c, 0xbc
|
||||
);
|
||||
|
||||
DEFINE_GUID ( /* 3d6fa8d0-fe05-11d0-9dda-00c04fd7ba7c */
|
||||
process,
|
||||
0x3d6fa8d0,
|
||||
0xfe05,
|
||||
0x11d0,
|
||||
0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c
|
||||
);
|
||||
|
||||
DEFINE_GUID ( /* AE53722E-C863-11d2-8659-00C04FA321A1 */
|
||||
registry,
|
||||
0xae53722e,
|
||||
0xc863,
|
||||
0x11d2,
|
||||
0x86, 0x59, 0x0, 0xc0, 0x4f, 0xa3, 0x21, 0xa1
|
||||
);
|
||||
|
||||
DEFINE_GUID ( /* d837ca92-12b9-44a5-ad6a-3a65b3578aa8 */
|
||||
split_io,
|
||||
0xd837ca92,
|
||||
0x12b9,
|
||||
0x44a5,
|
||||
0xad, 0x6a, 0x3a, 0x65, 0xb3, 0x57, 0x8a, 0xa8
|
||||
);
|
||||
|
||||
DEFINE_GUID ( /* 9a280ac0-c8e0-11d1-84e2-00c04fb998a2 */
|
||||
tcp_ip,
|
||||
0x9a280ac0,
|
||||
0xc8e0,
|
||||
0x11d1,
|
||||
0x84, 0xe2, 0x00, 0xc0, 0x4f, 0xb9, 0x98, 0xa2
|
||||
);
|
||||
|
||||
DEFINE_GUID ( /* 3d6fa8d1-fe05-11d0-9dda-00c04fd7ba7c */
|
||||
thread,
|
||||
0x3d6fa8d1,
|
||||
0xfe05,
|
||||
0x11d0,
|
||||
0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c
|
||||
);
|
||||
|
||||
DEFINE_GUID ( /* bf3a50c5-a9c9-4988-a005-2df0b7c80f80 */
|
||||
udp_ip,
|
||||
0xbf3a50c5,
|
||||
0xa9c9,
|
||||
0x4988,
|
||||
0xa0, 0x05, 0x2d, 0xf0, 0xb7, 0xc8, 0x0f, 0x80
|
||||
);
|
||||
|
||||
DEFINE_GUID ( /* 9e814aad-3204-11d2-9a82-006008a86939 */
|
||||
system_trace,
|
||||
0x9e814aad,
|
||||
0x3204,
|
||||
0x11d2,
|
||||
0x9a, 0x82, 0x00, 0x60, 0x08, 0xa8, 0x69, 0x39);
|
||||
|
||||
DEFINE_GUID( /* 89497f50-effe-4440-8cf2-ce6b1cdcaca7 */
|
||||
ob_trace,
|
||||
0x89497f50,
|
||||
0xeffe,
|
||||
0x4440,
|
||||
0x8c, 0xf2, 0xce, 0x6b, 0x1c, 0xdc, 0xac, 0xa7);
|
||||
|
||||
DEFINE_GUID( /* 0268a8b6-74fd-4302-9dd0-6e8f1795c0cf */
|
||||
pool_trace,
|
||||
0x0268a8b6,
|
||||
0x74fd,
|
||||
0x4302,
|
||||
0x9d, 0xd0, 0x6e, 0x8f, 0x17, 0x95, 0xc0, 0xcf);
|
||||
|
||||
DEFINE_GUID( /* 68fdd900-4a3e-11d1-84f4-0000f80464e3 */
|
||||
event_trace,
|
||||
0x68fdd900,
|
||||
0x4a3e,
|
||||
0x11d1,
|
||||
0x84, 0xf4, 0x00, 0x00, 0xf8, 0x04, 0x64, 0xe3);
|
||||
|
||||
DEFINE_GUID( /* 6a399ae0-4bc6-4de9-870b-3657f8947e7e */
|
||||
lost_event,
|
||||
0x6a399ae0,
|
||||
0x4bc6,
|
||||
0x4de9,
|
||||
0x87, 0x0b, 0x36, 0x57, 0xf8, 0x94, 0x7e, 0x7e);
|
||||
|
||||
DEFINE_GUID( /* 9aec974b-5b8e-4118-9b92-3186d8002ce5 */
|
||||
ums_event,
|
||||
0x9aec974b,
|
||||
0x5b8e,
|
||||
0x4118,
|
||||
0x9b, 0x92, 0x31, 0x86, 0xd8, 0x00, 0x2c, 0xe5);
|
||||
|
||||
DEFINE_GUID( /* def2fe46-7bd6-4b80-bd94-f57fe20d0ce3 */
|
||||
stack_walk,
|
||||
0xdef2fe46,
|
||||
0x7bd6,
|
||||
0x4b80,
|
||||
0xbd, 0x94, 0xf5, 0x7f, 0xe2, 0x0d, 0x0c, 0xe3);
|
||||
|
||||
DEFINE_GUID( /* e43445e0-0903-48c3-b878-ff0fccebdd04 */
|
||||
power,
|
||||
0xe43445e0,
|
||||
0x0903,
|
||||
0x48c3,
|
||||
0xb8, 0x78, 0xff, 0x0f, 0xcc, 0xeb, 0xdd, 0x04);
|
||||
|
||||
DEFINE_GUID( /* f8f10121-b617-4a56-868b-9df1b27fe32c */
|
||||
mmcss_trace,
|
||||
0xf8f10121,
|
||||
0xb617,
|
||||
0x4a56,
|
||||
0x86, 0x8b, 0x9d, 0xf1, 0xb2, 0x7f, 0xe3, 0x2c);
|
||||
|
||||
DEFINE_GUID( /* 3b9c9951-3480-4220-9377-9c8e5184f5cd */
|
||||
rundown,
|
||||
0x3b9c9951,
|
||||
0x3480,
|
||||
0x4220,
|
||||
0x93, 0x77, 0x9c, 0x8e, 0x51, 0x84, 0xf5, 0xcd);
|
||||
|
||||
} /* namespace guids */ } /* namespace krabs */
|
||||
@@ -0,0 +1,243 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "compiler_check.hpp"
|
||||
#include "kernel_guids.hpp"
|
||||
#include "perfinfo_groupmask.hpp"
|
||||
#include "provider.hpp"
|
||||
|
||||
#define INITGUID
|
||||
#include <Evntrace.h>
|
||||
|
||||
namespace krabs { namespace kernel {
|
||||
|
||||
#define CREATE_CONVENIENCE_KERNEL_PROVIDER(__name__, __value__, __guid__) \
|
||||
struct __name__ : public krabs::kernel_provider \
|
||||
{ \
|
||||
__name__() \
|
||||
: krabs::kernel_provider(__value__, __guid__) \
|
||||
{} \
|
||||
};
|
||||
|
||||
#define CREATE_CONVENIENCE_KERNEL_PROVIDER_MASK(__name__, __guid__, __mask__) \
|
||||
struct __name__ : public krabs::kernel_provider \
|
||||
{ \
|
||||
__name__() \
|
||||
: krabs::kernel_provider(__guid__, __mask__) \
|
||||
{} \
|
||||
};
|
||||
|
||||
/**
|
||||
* <summary>A provider that enables ALPC events.</summary>
|
||||
*/
|
||||
CREATE_CONVENIENCE_KERNEL_PROVIDER(
|
||||
alpc_provider,
|
||||
EVENT_TRACE_FLAG_ALPC,
|
||||
krabs::guids::alpc);
|
||||
|
||||
/**
|
||||
* <summary>A provider that enables context switch events.</summary>
|
||||
*/
|
||||
CREATE_CONVENIENCE_KERNEL_PROVIDER(
|
||||
context_switch_provider,
|
||||
EVENT_TRACE_FLAG_CSWITCH,
|
||||
krabs::guids::thread);
|
||||
|
||||
/**
|
||||
* <summary>A provider that enables debug print events.</summary>
|
||||
*/
|
||||
CREATE_CONVENIENCE_KERNEL_PROVIDER(
|
||||
debug_print_provider,
|
||||
EVENT_TRACE_FLAG_DBGPRINT,
|
||||
krabs::guids::debug);
|
||||
|
||||
/**
|
||||
* <summary>A provider that enables file I/O name events.</summary>
|
||||
*/
|
||||
CREATE_CONVENIENCE_KERNEL_PROVIDER(
|
||||
disk_file_io_provider,
|
||||
EVENT_TRACE_FLAG_DISK_FILE_IO,
|
||||
krabs::guids::file_io);
|
||||
|
||||
/**
|
||||
* <summary>A provider that enables disk I/O completion events.</summary>
|
||||
*/
|
||||
CREATE_CONVENIENCE_KERNEL_PROVIDER(
|
||||
disk_io_provider,
|
||||
EVENT_TRACE_FLAG_DISK_IO,
|
||||
krabs::guids::disk_io);
|
||||
|
||||
/**
|
||||
* <summary>A provider that enables disk I/O start events.</summary>
|
||||
*/
|
||||
CREATE_CONVENIENCE_KERNEL_PROVIDER(
|
||||
disk_init_io_provider,
|
||||
EVENT_TRACE_FLAG_DISK_IO_INIT,
|
||||
krabs::guids::disk_io);
|
||||
|
||||
/**
|
||||
* <summary>A provider that enables file I/O completion events.</summary>
|
||||
*/
|
||||
CREATE_CONVENIENCE_KERNEL_PROVIDER(
|
||||
file_io_provider,
|
||||
EVENT_TRACE_FLAG_FILE_IO,
|
||||
krabs::guids::file_io);
|
||||
|
||||
/**
|
||||
* <summary>A provider that enables file I/O start events.</summary>
|
||||
*/
|
||||
CREATE_CONVENIENCE_KERNEL_PROVIDER(
|
||||
file_init_io_provider,
|
||||
EVENT_TRACE_FLAG_FILE_IO_INIT,
|
||||
krabs::guids::file_io);
|
||||
|
||||
/**
|
||||
* <summary>A provider that enables thread dispatch events.</summary>
|
||||
*/
|
||||
CREATE_CONVENIENCE_KERNEL_PROVIDER(
|
||||
thread_dispatch_provider,
|
||||
EVENT_TRACE_FLAG_DISPATCHER,
|
||||
krabs::guids::thread);
|
||||
|
||||
/**
|
||||
* <summary>A provider that enables device deferred procedure call events.</summary>
|
||||
*/
|
||||
CREATE_CONVENIENCE_KERNEL_PROVIDER(
|
||||
dpc_provider,
|
||||
EVENT_TRACE_FLAG_DPC,
|
||||
krabs::guids::perf_info);
|
||||
|
||||
/**
|
||||
* <summary>A provider that enables driver events.</summary>
|
||||
*/
|
||||
CREATE_CONVENIENCE_KERNEL_PROVIDER(
|
||||
driver_provider,
|
||||
EVENT_TRACE_FLAG_DRIVER,
|
||||
krabs::guids::disk_io);
|
||||
|
||||
/**
|
||||
* <summary>A provider that enables image load events.</summary>
|
||||
*/
|
||||
CREATE_CONVENIENCE_KERNEL_PROVIDER(
|
||||
image_load_provider,
|
||||
EVENT_TRACE_FLAG_IMAGE_LOAD,
|
||||
krabs::guids::image_load);
|
||||
|
||||
/**
|
||||
* <summary>A provider that enables interrupt events.</summary>
|
||||
*/
|
||||
CREATE_CONVENIENCE_KERNEL_PROVIDER(
|
||||
interrupt_provider,
|
||||
EVENT_TRACE_FLAG_INTERRUPT,
|
||||
krabs::guids::perf_info);
|
||||
|
||||
/**
|
||||
* <summary>A provider that enables memory hard fault events.</summary>
|
||||
*/
|
||||
CREATE_CONVENIENCE_KERNEL_PROVIDER(
|
||||
memory_hard_fault_provider,
|
||||
EVENT_TRACE_FLAG_MEMORY_HARD_FAULTS,
|
||||
krabs::guids::page_fault);
|
||||
|
||||
/**
|
||||
* <summary>A provider that enables memory page fault events.</summary>
|
||||
*/
|
||||
CREATE_CONVENIENCE_KERNEL_PROVIDER(
|
||||
memory_page_fault_provider,
|
||||
EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS,
|
||||
krabs::guids::page_fault);
|
||||
|
||||
/**
|
||||
* <summary>A provider that enables network tcp/ip events.</summary>
|
||||
*/
|
||||
CREATE_CONVENIENCE_KERNEL_PROVIDER(
|
||||
network_tcpip_provider,
|
||||
EVENT_TRACE_FLAG_NETWORK_TCPIP,
|
||||
krabs::guids::tcp_ip);
|
||||
|
||||
/**
|
||||
* <summary>A provider that enables process events.</summary>
|
||||
*/
|
||||
CREATE_CONVENIENCE_KERNEL_PROVIDER(
|
||||
process_provider,
|
||||
EVENT_TRACE_FLAG_PROCESS,
|
||||
krabs::guids::process);
|
||||
|
||||
/**
|
||||
* <summary>A provider that enables process counter events.</summary>
|
||||
*/
|
||||
CREATE_CONVENIENCE_KERNEL_PROVIDER(
|
||||
process_counter_provider,
|
||||
EVENT_TRACE_FLAG_PROCESS_COUNTERS,
|
||||
krabs::guids::process);
|
||||
|
||||
/**
|
||||
* <summary>A provider that enables profiling events.</summary>
|
||||
*/
|
||||
CREATE_CONVENIENCE_KERNEL_PROVIDER(
|
||||
profile_provider,
|
||||
EVENT_TRACE_FLAG_PROFILE,
|
||||
krabs::guids::perf_info);
|
||||
|
||||
/**
|
||||
* <summary>A provider that enables registry events.</summary>
|
||||
*/
|
||||
CREATE_CONVENIENCE_KERNEL_PROVIDER(
|
||||
registry_provider,
|
||||
EVENT_TRACE_FLAG_REGISTRY,
|
||||
krabs::guids::registry);
|
||||
|
||||
/**
|
||||
* <summary>A provider that enables split I/O events.</summary>
|
||||
*/
|
||||
CREATE_CONVENIENCE_KERNEL_PROVIDER(
|
||||
split_io_provider,
|
||||
EVENT_TRACE_FLAG_SPLIT_IO,
|
||||
krabs::guids::split_io);
|
||||
|
||||
/**
|
||||
* <summary>A provider that enables system call events.</summary>
|
||||
*/
|
||||
CREATE_CONVENIENCE_KERNEL_PROVIDER(
|
||||
system_call_provider,
|
||||
EVENT_TRACE_FLAG_SYSTEMCALL,
|
||||
krabs::guids::perf_info);
|
||||
|
||||
/**
|
||||
* <summary>A provider that enables thread start and stop events.</summary>
|
||||
*/
|
||||
CREATE_CONVENIENCE_KERNEL_PROVIDER(
|
||||
thread_provider,
|
||||
EVENT_TRACE_FLAG_THREAD,
|
||||
krabs::guids::thread);
|
||||
|
||||
/**
|
||||
* <summary>A provider that enables file map and unmap (excluding images) events.</summary>
|
||||
*/
|
||||
CREATE_CONVENIENCE_KERNEL_PROVIDER(
|
||||
vamap_provider,
|
||||
EVENT_TRACE_FLAG_VAMAP,
|
||||
krabs::guids::file_io);
|
||||
|
||||
/**
|
||||
* <summary>A provider that enables VirtualAlloc and VirtualFree events.</summary>
|
||||
*/
|
||||
CREATE_CONVENIENCE_KERNEL_PROVIDER(
|
||||
virtual_alloc_provider,
|
||||
EVENT_TRACE_FLAG_VIRTUAL_ALLOC,
|
||||
krabs::guids::page_fault);
|
||||
|
||||
/**
|
||||
* <summary>A provider that enables Object Manager events.</summary>
|
||||
*/
|
||||
CREATE_CONVENIENCE_KERNEL_PROVIDER_MASK(
|
||||
object_manager_provider,
|
||||
krabs::guids::ob_trace,
|
||||
PERF_OB_HANDLE);
|
||||
|
||||
#undef CREATE_CONVENIENCE_KERNEL_PROVIDER
|
||||
#undef CREATE_CONVENIENCE_KERNEL_PROVIDER_MASK
|
||||
|
||||
} /* namespace kernel */ } /* namespace krabs */
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "compiler_check.hpp"
|
||||
#include "kernel_guids.hpp"
|
||||
#include "perfinfo_groupmask.hpp"
|
||||
#include "provider.hpp"
|
||||
#include "trace.hpp"
|
||||
#include "ut.hpp"
|
||||
#include "version_helpers.hpp"
|
||||
|
||||
#include <Evntrace.h>
|
||||
|
||||
namespace krabs { namespace details {
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Used as a template argument to a trace instance. This class implements
|
||||
* code paths for kernel traces. Should never be used or seen by client
|
||||
* code.
|
||||
* </summary>
|
||||
*/
|
||||
struct kt {
|
||||
|
||||
typedef krabs::kernel_provider provider_type;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Used to assign a name to the trace instance that is being
|
||||
* instantiated.
|
||||
* </summary>
|
||||
* <remarks>
|
||||
* In pre-Win8 days, there could only be a single kernel trace
|
||||
* instance on an entire machine, and that instance had to be named
|
||||
* a particular name. This restriction was loosened in Win8, but
|
||||
* the trace still needs to do the right thing on older OSes.
|
||||
* </remarks>
|
||||
*/
|
||||
static const std::wstring enforce_name_policy(
|
||||
const std::wstring &name);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Generates a value that fills the EnableFlags field in an
|
||||
* EVENT_TRACE_PROPERTIES structure. This controls the providers that
|
||||
* get enabled for a kernel trace.
|
||||
* </summary>
|
||||
*/
|
||||
static const unsigned long construct_enable_flags(
|
||||
const krabs::trace<krabs::details::kt> &trace);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Enables the providers that are attached to the given trace.
|
||||
* </summary>
|
||||
*/
|
||||
static void enable_providers(
|
||||
const krabs::trace<krabs::details::kt> &trace);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Enables the configured kernel rundown flags.
|
||||
* </summary>
|
||||
* <remarks>
|
||||
* This ETW feature is undocumented and should be used with caution.
|
||||
* </remarks>
|
||||
*/
|
||||
static void enable_rundown(
|
||||
const krabs::trace<krabs::details::kt>& trace);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Decides to forward an event to any of the providers in the trace.
|
||||
* </summary>
|
||||
*/
|
||||
static void forward_events(
|
||||
const EVENT_RECORD &record,
|
||||
const krabs::trace<krabs::details::kt> &trace);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Sets the ETW trace log file mode.
|
||||
* </summary>
|
||||
*/
|
||||
static unsigned long augment_file_mode();
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Returns the GUID of the trace session.
|
||||
* </summary>
|
||||
*/
|
||||
static krabs::guid get_trace_guid();
|
||||
|
||||
};
|
||||
|
||||
// Implementation
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
inline const std::wstring kt::enforce_name_policy(
|
||||
const std::wstring &name_hint)
|
||||
{
|
||||
if (IsWindows8OrGreater()) {
|
||||
return krabs::details::ut::enforce_name_policy(name_hint);
|
||||
}
|
||||
|
||||
return KERNEL_LOGGER_NAME;
|
||||
}
|
||||
|
||||
inline const unsigned long kt::construct_enable_flags(
|
||||
const krabs::trace<krabs::details::kt> &trace)
|
||||
{
|
||||
unsigned long flags = 0;
|
||||
for (auto &provider : trace.providers_) {
|
||||
flags |= provider.get().flags();
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
inline void kt::enable_providers(
|
||||
const krabs::trace<krabs::details::kt> &trace)
|
||||
{
|
||||
EVENT_TRACE_GROUPMASK_INFORMATION gmi = {};
|
||||
gmi.EventTraceInformationClass = EventTraceGroupMaskInformation;
|
||||
gmi.TraceHandle = trace.registrationHandle_;
|
||||
|
||||
// initialise EventTraceGroupMasks to the values that have been enabled via the trace flags
|
||||
ULONG status = NtQuerySystemInformation(SystemPerformanceTraceInformation, &gmi, sizeof(gmi), nullptr);
|
||||
error_check_common_conditions(status);
|
||||
|
||||
auto group_mask_set = false;
|
||||
for (auto& provider : trace.providers_) {
|
||||
auto group = provider.get().group_mask();
|
||||
PERFINFO_OR_GROUP_WITH_GROUPMASK(group, &(gmi.EventTraceGroupMasks));
|
||||
group_mask_set |= (group != 0);
|
||||
}
|
||||
|
||||
if (group_mask_set) {
|
||||
// This will fail on Windows 7, so only call it if truly neccessary
|
||||
status = NtSetSystemInformation(SystemPerformanceTraceInformation, &gmi, sizeof(gmi));
|
||||
error_check_common_conditions(status);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
inline void kt::enable_rundown(
|
||||
const krabs::trace<krabs::details::kt>& trace)
|
||||
{
|
||||
bool rundown_enabled = false;
|
||||
ULONG rundown_flags = 0;
|
||||
for (auto& provider : trace.providers_) {
|
||||
rundown_enabled |= provider.get().rundown_enabled();
|
||||
rundown_flags |= provider.get().rundown_flags();
|
||||
}
|
||||
|
||||
if (rundown_enabled) {
|
||||
ULONG status = EnableTraceEx2(trace.registrationHandle_,
|
||||
&krabs::guids::rundown,
|
||||
EVENT_CONTROL_CODE_ENABLE_PROVIDER,
|
||||
0,
|
||||
rundown_flags,
|
||||
0,
|
||||
0,
|
||||
NULL);
|
||||
error_check_common_conditions(status);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline void kt::forward_events(
|
||||
const EVENT_RECORD &record,
|
||||
const krabs::trace<krabs::details::kt> &trace)
|
||||
{
|
||||
for (auto &provider : trace.providers_) {
|
||||
if (provider.get().id() == record.EventHeader.ProviderId) {
|
||||
provider.get().on_event(record, trace.context_);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (trace.default_callback_ != nullptr)
|
||||
trace.default_callback_(record, trace.context_);
|
||||
}
|
||||
|
||||
inline unsigned long kt::augment_file_mode()
|
||||
{
|
||||
if (IsWindows8OrGreater()) {
|
||||
return EVENT_TRACE_SYSTEM_LOGGER_MODE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline krabs::guid kt::get_trace_guid()
|
||||
{
|
||||
if (IsWindows8OrGreater()) {
|
||||
return krabs::guid::random_guid();
|
||||
}
|
||||
|
||||
return krabs::guid(SystemTraceControlGuid);
|
||||
}
|
||||
|
||||
} /* namespace details */ } /* namespace krabs */
|
||||
+330
@@ -0,0 +1,330 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <sddl.h>
|
||||
|
||||
#include <vector>
|
||||
#include <type_traits>
|
||||
|
||||
#include "compiler_check.hpp"
|
||||
|
||||
namespace krabs {
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Provided entirely for code clarity purposes.
|
||||
* Indicates that the number is intended to be used as an ID
|
||||
* </summary>
|
||||
* <remarks>
|
||||
* This should be turned into an _id user defined literal when our
|
||||
* compiler decides to catch up to the times.
|
||||
* </remarks>
|
||||
* <example>
|
||||
* id(1000);
|
||||
* </example>
|
||||
*/
|
||||
template <typename T>
|
||||
T id(T n)
|
||||
{
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Provided entirely for code clarity purposes.
|
||||
* Indicates that the number is intended to be used as a version
|
||||
* </summary>
|
||||
* <remarks>
|
||||
* This should be turned into a _vers user defined literal when our
|
||||
* compiler decides to catch up to the times.
|
||||
* </remarks>
|
||||
* <example>
|
||||
* id(1000);
|
||||
* </example>
|
||||
*/
|
||||
template <typename T>
|
||||
T version(T n)
|
||||
{
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Provided entirely for code clarity purposes.
|
||||
* Indicates that the number is intended to be used as an opcode
|
||||
* </summary>
|
||||
* <remarks>
|
||||
* This should be turned into a _opcode user defined literal when our
|
||||
* compiler decides to catch up to the times.
|
||||
* </remarks>
|
||||
* <example>
|
||||
* opcode(1000);
|
||||
* </example>
|
||||
*/
|
||||
template <typename T>
|
||||
T opcode(T n)
|
||||
{
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Used to discriminate between hex ints and regular ints in ETW events.
|
||||
* </summary>
|
||||
* <remarks>
|
||||
* Q: Why in the world? I can't even.
|
||||
* A: ETW differentiates between hexints and regular ints. When
|
||||
* record_builder validates that the input type matches the type
|
||||
* specified in the schema, getting this wrong will cause an
|
||||
* exception. A quick little type wrapper like this lets us
|
||||
* discriminate based on the type and everything turns out better.
|
||||
* </remarks>
|
||||
*/
|
||||
struct hexint32 {
|
||||
hexint32(int v)
|
||||
: value(v)
|
||||
{}
|
||||
|
||||
int value;
|
||||
};
|
||||
|
||||
struct hexint64 {
|
||||
hexint64(long long v)
|
||||
: value(v)
|
||||
{}
|
||||
|
||||
long long value;
|
||||
};
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Used to support parsing and creation of binary ETW fields.
|
||||
* </summary>
|
||||
*/
|
||||
struct binary {
|
||||
public:
|
||||
binary() : bytes_() { }
|
||||
|
||||
binary(const BYTE* start, size_t n)
|
||||
: bytes_(start, start + n)
|
||||
{ }
|
||||
|
||||
const std::vector<BYTE>& bytes() const
|
||||
{
|
||||
return bytes_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<BYTE> bytes_;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
binary make_binary(const T& value, size_t n)
|
||||
{
|
||||
const auto start = (BYTE*)&value;
|
||||
return binary(start, n);
|
||||
}
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Used to handle parsing of IPv4 and IPv6 fields in an ETW record.
|
||||
* This is used in the parser class in a template specialization.
|
||||
* </summary>
|
||||
*/
|
||||
struct ip_address {
|
||||
union {
|
||||
DWORD v4;
|
||||
BYTE v6[16];
|
||||
};
|
||||
bool is_ipv6;
|
||||
|
||||
static ip_address from_ipv6(const BYTE* bytes)
|
||||
{
|
||||
ip_address addr;
|
||||
addr.is_ipv6 = true;
|
||||
memcpy_s(addr.v6, 16, bytes, 16);
|
||||
return addr;
|
||||
}
|
||||
|
||||
static ip_address from_ipv4(DWORD val)
|
||||
{
|
||||
ip_address addr;
|
||||
addr.is_ipv6 = false;
|
||||
addr.v4 = val;
|
||||
return addr;
|
||||
}
|
||||
|
||||
ip_address() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Used to handle parsing of socket addresses in
|
||||
* network order. This union is a convenient wrapper
|
||||
* around the type IPv4 and IPv6 types provided by
|
||||
* the Winsock (v2) APIs.
|
||||
* </summary>
|
||||
*/
|
||||
struct socket_address {
|
||||
union {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in sa_in;
|
||||
struct sockaddr_in6 sa_in6;
|
||||
struct sockaddr_storage sa_stor;
|
||||
};
|
||||
size_t size;
|
||||
|
||||
static socket_address from_bytes(const BYTE* bytes, size_t size_in_bytes)
|
||||
{
|
||||
socket_address sa;
|
||||
memcpy_s(&(sa.sa_stor), sizeof sa.sa_stor, bytes, size_in_bytes);
|
||||
sa.size = size_in_bytes;
|
||||
return sa;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Holds information about an property extracted from the etw schema
|
||||
* </summary>
|
||||
*/
|
||||
struct property_info {
|
||||
const BYTE *pPropertyIndex_;
|
||||
const EVENT_PROPERTY_INFO *pEventPropertyInfo_;
|
||||
ULONG length_;
|
||||
|
||||
property_info(
|
||||
const BYTE *offset,
|
||||
const EVENT_PROPERTY_INFO &evtPropInfo,
|
||||
ULONG length)
|
||||
: pPropertyIndex_(offset)
|
||||
, pEventPropertyInfo_(&evtPropInfo)
|
||||
, length_(length)
|
||||
{ }
|
||||
|
||||
property_info()
|
||||
: pPropertyIndex_(nullptr)
|
||||
, pEventPropertyInfo_(nullptr)
|
||||
, length_(0)
|
||||
{ }
|
||||
|
||||
inline bool found() const
|
||||
{
|
||||
return pPropertyIndex_ != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Used to handle parsing of SIDs from either a
|
||||
* SID or WBEMSID property
|
||||
* </summary>
|
||||
*/
|
||||
struct sid {
|
||||
// SIDs are variable-length
|
||||
// So the 'best' way to store them is to convert to a string
|
||||
// The other-end can either print the string or call ConvertStringSidToSidA
|
||||
// to get the SID back
|
||||
std::string sid_string;
|
||||
|
||||
static sid from_bytes(const BYTE* bytes, size_t size_in_bytes)
|
||||
{
|
||||
sid ws;
|
||||
LPSTR temp_sid_string;
|
||||
UNREFERENCED_PARAMETER(size_in_bytes);
|
||||
|
||||
if (!ConvertSidToStringSidA((PSID)bytes, &temp_sid_string)) {
|
||||
throw std::runtime_error(
|
||||
"Failed to get a SID from a property");
|
||||
}
|
||||
ws.sid_string = temp_sid_string;
|
||||
LocalFree(temp_sid_string);
|
||||
return ws;
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Used to handle parsing of Pointer Address types.
|
||||
* </summary>
|
||||
*/
|
||||
struct pointer {
|
||||
/**
|
||||
* We store the pointer as an uint64_t, as it is highly unlikley
|
||||
* to be pointing to somewhere accessible to our process
|
||||
*/
|
||||
uint64_t address;
|
||||
|
||||
static pointer from_bytes(const BYTE* bytes, size_t size_in_bytes)
|
||||
{
|
||||
pointer pt;
|
||||
|
||||
// If 32-Bit, first parse as a uint32
|
||||
// Then we can 'cast' that to our uint64_t
|
||||
if (size_in_bytes == sizeof(uint32_t)) {
|
||||
pt.address = *reinterpret_cast<const uint32_t*>(bytes);
|
||||
}
|
||||
else if (size_in_bytes == sizeof(uint64_t)) {
|
||||
pt.address = *reinterpret_cast<const uint64_t*>(bytes);
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error(
|
||||
"Failed to get a POINTER from a property");
|
||||
}
|
||||
|
||||
return pt;
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Used to handle parsing of CountedStrings in an ETW Record.
|
||||
* This is used in the parser class in a template specialization.
|
||||
* </summary>
|
||||
*/
|
||||
#pragma pack(push,1)
|
||||
struct counted_string {
|
||||
using value_type = wchar_t;
|
||||
using reference = value_type&;
|
||||
using pointer = value_type*;
|
||||
using const_reference = const value_type&;
|
||||
using const_pointer = const value_type*;
|
||||
using iterator = value_type*;
|
||||
using const_iterator = const value_type*;
|
||||
|
||||
/**
|
||||
* size of the string in bytes
|
||||
*/
|
||||
uint16_t size_;
|
||||
wchar_t string_[1];
|
||||
|
||||
const_pointer string() const
|
||||
{
|
||||
return string_;
|
||||
}
|
||||
|
||||
size_t length() const
|
||||
{
|
||||
return size_ / sizeof(value_type);
|
||||
}
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
static_assert(std::is_trivial<counted_string>::value && std::is_standard_layout<counted_string>::value , "Do not modify counted_string");
|
||||
|
||||
} /* namespace krabs */
|
||||
+495
@@ -0,0 +1,495 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "compiler_check.hpp"
|
||||
#include "collection_view.hpp"
|
||||
#include "property.hpp"
|
||||
#include "parse_types.hpp"
|
||||
#include "size_provider.hpp"
|
||||
#include "tdh_helpers.hpp"
|
||||
|
||||
namespace krabs {
|
||||
|
||||
class schema;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Used to parse specific properties out of an event schema.
|
||||
* </summary>
|
||||
* <remarks>
|
||||
* The parser class dodges the task of trying to validate that the expected
|
||||
* type of a field matches the actual type of a field -- the onus is on
|
||||
* client code to get this right.
|
||||
* </remarks>
|
||||
*/
|
||||
class parser {
|
||||
public:
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Constructs an event parser from an event schema.
|
||||
* </summary>
|
||||
* <example>
|
||||
* void on_event(const EVENT_RECORD &record)
|
||||
* {
|
||||
* krabs::schema schema(record);
|
||||
* krabs::parser parser(schema);
|
||||
* }
|
||||
* </example>
|
||||
*/
|
||||
parser(const schema &);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Returns an iterator that returns each property in the event.
|
||||
* </summary>
|
||||
* <example>
|
||||
* void on_event(const EVENT_RECORD &record)
|
||||
* {
|
||||
* krabs::schema schema(record);
|
||||
* krabs::parser parser(schema);
|
||||
* for (property &property : parser.properties())
|
||||
* {
|
||||
* // ...
|
||||
* }
|
||||
* }
|
||||
* </example>
|
||||
*/
|
||||
property_iterator properties() const;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Attempts to retrieve the given property by name and type.
|
||||
* </summary>
|
||||
* <remarks>
|
||||
* Type hinting here is taken as the authoritative source. There is no
|
||||
* validation that the request for type is correct.
|
||||
* </remarks>
|
||||
*/
|
||||
template <typename T>
|
||||
bool try_parse(std::wstring_view name, T &out);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Attempts to retrieve the given property by name and type,
|
||||
* starting the name scan at the given hint index.
|
||||
* </summary>
|
||||
*/
|
||||
template <typename T>
|
||||
bool try_parse(std::wstring_view name, T &out, ULONG hint);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Attempts to parse the given property by name and type. If the
|
||||
* property does not exist, an exception is thrown.
|
||||
* </summary>
|
||||
*/
|
||||
template <typename T>
|
||||
T parse(std::wstring_view name);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Attempts to parse the given property by name and type,
|
||||
* starting the name scan at the given hint index.
|
||||
* </summary>
|
||||
*/
|
||||
template <typename T>
|
||||
T parse(std::wstring_view name, ULONG hint);
|
||||
|
||||
template <typename Adapter>
|
||||
auto view_of(std::wstring_view name, Adapter &adapter) -> collection_view<typename Adapter::const_iterator>;
|
||||
|
||||
template <typename Adapter>
|
||||
auto view_of(std::wstring_view name, ULONG hint, Adapter &adapter) -> collection_view<typename Adapter::const_iterator>;
|
||||
|
||||
private:
|
||||
property_info find_property(std::wstring_view name);
|
||||
property_info find_property(std::wstring_view name, ULONG hint);
|
||||
void cache_property(ULONG index, property_info info);
|
||||
|
||||
private:
|
||||
const schema &schema_;
|
||||
const BYTE *pEndBuffer_;
|
||||
BYTE *pBufferIndex_;
|
||||
ULONG lastPropertyIndex_;
|
||||
ULONG nextHint_;
|
||||
// Maintain a mapping from property index to blob data location.
|
||||
std::vector<property_info> propertyCache_;
|
||||
};
|
||||
|
||||
// Implementation
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
inline parser::parser(const schema &s)
|
||||
: schema_(s)
|
||||
, pEndBuffer_((BYTE*)s.record_.UserData + s.record_.UserDataLength)
|
||||
, pBufferIndex_((BYTE*)s.record_.UserData)
|
||||
, lastPropertyIndex_(0)
|
||||
, nextHint_(0)
|
||||
, propertyCache_(s.pSchema_->PropertyCount)
|
||||
{}
|
||||
|
||||
inline property_iterator parser::properties() const
|
||||
{
|
||||
return property_iterator(schema_);
|
||||
}
|
||||
|
||||
inline property_info parser::find_property(std::wstring_view name)
|
||||
{
|
||||
return find_property(name, nextHint_);
|
||||
}
|
||||
|
||||
inline property_info parser::find_property(std::wstring_view name, ULONG hint)
|
||||
{
|
||||
// A schema contains a collection of properties that are keyed by name.
|
||||
// These properties are stored in a blob of bytes that needs to be
|
||||
// interpreted according to information that is packaged up in the
|
||||
// schema and that can be retrieved using the Tdh* APIs.
|
||||
|
||||
const ULONG totalPropCount = schema_.pSchema_->PropertyCount;
|
||||
if (totalPropCount == 0) {
|
||||
return property_info();
|
||||
}
|
||||
|
||||
// Resolve property name to index via hinted linear scan.
|
||||
// Optimistically start at hint, then wrap around if not found.
|
||||
// ** This assumes that callers typically access properties in event order. **
|
||||
// An alternative is to maintain a static name->index map, but this was slower
|
||||
// in practice for events with < ~12 properties.
|
||||
|
||||
if (hint >= totalPropCount) hint = 0;
|
||||
|
||||
ULONG index = totalPropCount; // sentinel = not found
|
||||
for (ULONG n = 0; n < totalPropCount; ++n) {
|
||||
const ULONG i = (hint + n) % totalPropCount;
|
||||
const auto &propInfo = schema_.pSchema_->EventPropertyInfoArray[i];
|
||||
const wchar_t *pName = reinterpret_cast<const wchar_t*>(
|
||||
reinterpret_cast<const BYTE*>(schema_.pSchema_) +
|
||||
propInfo.NameOffset);
|
||||
if (name == pName) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index >= totalPropCount) { // not found
|
||||
return property_info();
|
||||
}
|
||||
|
||||
nextHint_ = (index + 1) % totalPropCount;
|
||||
|
||||
// The first step is to use our cache for the property to see if we've
|
||||
// discovered it already.
|
||||
if (index < lastPropertyIndex_) {
|
||||
return propertyCache_[index];
|
||||
}
|
||||
|
||||
assert((pBufferIndex_ <= pEndBuffer_ && pBufferIndex_ >= schema_.record_.UserData) &&
|
||||
"invariant: we should've already thrown for falling off the edge");
|
||||
|
||||
// accept that last property can be omitted from buffer. this happens if last property
|
||||
// is string but empty and the provider strips the null terminator
|
||||
assert((pBufferIndex_ == pEndBuffer_ ? ((totalPropCount - lastPropertyIndex_) <= 1)
|
||||
: true)
|
||||
&& "invariant: if we've exhausted our buffer, then we must've"
|
||||
"exhausted the properties as well");
|
||||
|
||||
// We've not looked up this property before, so we have to do the work
|
||||
// to find it. While we're going through the blob to find it, we'll
|
||||
// remember what we've seen to save time later.
|
||||
// The blob walk is lazy per-event -- we only walk forward to the
|
||||
// requested index, avoiding overhead when only a subset of properties
|
||||
// are needed.
|
||||
while (lastPropertyIndex_ <= index) {
|
||||
|
||||
auto ¤tPropInfo = schema_.pSchema_->EventPropertyInfoArray[lastPropertyIndex_];
|
||||
const wchar_t *pName = reinterpret_cast<const wchar_t*>(
|
||||
reinterpret_cast<const BYTE*>(schema_.pSchema_) +
|
||||
currentPropInfo.NameOffset);
|
||||
|
||||
ULONG propertyLength = size_provider::get_property_size(
|
||||
pBufferIndex_,
|
||||
pName,
|
||||
schema_.record_,
|
||||
currentPropInfo);
|
||||
|
||||
// verify that the length of the property doesn't exceed the buffer
|
||||
if (pBufferIndex_ + propertyLength > pEndBuffer_) {
|
||||
throw std::out_of_range("Property length past end of property buffer");
|
||||
}
|
||||
|
||||
property_info propInfo(pBufferIndex_, currentPropInfo, propertyLength);
|
||||
cache_property(lastPropertyIndex_, propInfo);
|
||||
|
||||
// advance the buffer index since we've already processed this property
|
||||
pBufferIndex_ += propertyLength;
|
||||
lastPropertyIndex_++;
|
||||
}
|
||||
|
||||
return propertyCache_[index];
|
||||
}
|
||||
|
||||
inline void parser::cache_property(ULONG index, property_info info)
|
||||
{
|
||||
propertyCache_[index] = info;
|
||||
}
|
||||
|
||||
inline void throw_if_property_not_found(const property_info &propInfo)
|
||||
{
|
||||
if (!propInfo.found()) {
|
||||
throw std::runtime_error("Property with the given name does not exist");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
size_t get_string_content_length(const T* string, size_t lengthBytes)
|
||||
{
|
||||
// for some string types the length includes the null terminator
|
||||
// so we need to find the length of just the content part
|
||||
|
||||
T nullChar {0};
|
||||
auto length = lengthBytes / sizeof(T);
|
||||
|
||||
for (auto i = length; i >= 1; --i)
|
||||
if (string[i - 1] != nullChar) return i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// try_parse
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
template <typename T>
|
||||
bool parser::try_parse(std::wstring_view name, T &out, ULONG hint)
|
||||
{
|
||||
nextHint_ = hint;
|
||||
return try_parse(name, out);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool parser::try_parse(std::wstring_view name, T &out)
|
||||
{
|
||||
try {
|
||||
out = parse<T>(name);
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
// in debug builds we want any mismatch asserts
|
||||
// to get back to the caller. This is removed
|
||||
// in release builds.
|
||||
catch (const krabs::type_mismatch_assert&) {
|
||||
throw;
|
||||
}
|
||||
#endif // NDEBUG
|
||||
|
||||
catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// parse
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
template <typename T>
|
||||
T parser::parse(std::wstring_view name, ULONG hint)
|
||||
{
|
||||
nextHint_ = hint;
|
||||
return parse<T>(name);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T parser::parse(std::wstring_view name)
|
||||
{
|
||||
auto propInfo = find_property(name);
|
||||
throw_if_property_not_found(propInfo);
|
||||
|
||||
krabs::debug::assert_valid_assignment<T>(name, propInfo);
|
||||
|
||||
// ensure that size of the type we are requesting is
|
||||
// the same size of the property in the event
|
||||
if (sizeof(T) != propInfo.length_)
|
||||
throw std::runtime_error("Property size doesn't match requested size");
|
||||
|
||||
return *(T*)propInfo.pPropertyIndex_;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool parser::parse<bool>(std::wstring_view name)
|
||||
{
|
||||
auto propInfo = find_property(name);
|
||||
throw_if_property_not_found(propInfo);
|
||||
|
||||
krabs::debug::assert_valid_assignment<bool>(name, propInfo);
|
||||
|
||||
// Boolean in ETW is 4 bytes long
|
||||
return static_cast<bool>(*(unsigned*)propInfo.pPropertyIndex_);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::wstring parser::parse<std::wstring>(std::wstring_view name)
|
||||
{
|
||||
auto propInfo = find_property(name);
|
||||
throw_if_property_not_found(propInfo);
|
||||
|
||||
krabs::debug::assert_valid_assignment<std::wstring>(name, propInfo);
|
||||
|
||||
auto string = reinterpret_cast<const wchar_t*>(propInfo.pPropertyIndex_);
|
||||
auto length = get_string_content_length(string, propInfo.length_);
|
||||
|
||||
return std::wstring(string, length);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string parser::parse<std::string>(std::wstring_view name)
|
||||
{
|
||||
auto propInfo = find_property(name);
|
||||
throw_if_property_not_found(propInfo);
|
||||
|
||||
krabs::debug::assert_valid_assignment<std::string>(name, propInfo);
|
||||
|
||||
auto string = reinterpret_cast<const char*>(propInfo.pPropertyIndex_);
|
||||
auto length = get_string_content_length(string, propInfo.length_);
|
||||
|
||||
return std::string(string, length);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline const counted_string* parser::parse<const counted_string*>(std::wstring_view name)
|
||||
{
|
||||
auto propInfo = find_property(name);
|
||||
throw_if_property_not_found(propInfo);
|
||||
|
||||
krabs::debug::assert_valid_assignment<const counted_string*>(name, propInfo);
|
||||
|
||||
return reinterpret_cast<const counted_string*>(propInfo.pPropertyIndex_);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline binary parser::parse<binary>(std::wstring_view name)
|
||||
{
|
||||
auto propInfo = find_property(name);
|
||||
throw_if_property_not_found(propInfo);
|
||||
|
||||
// no type asserts for binary - anything can be read as binary
|
||||
|
||||
return binary(propInfo.pPropertyIndex_, propInfo.length_);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline ip_address parser::parse<ip_address>(
|
||||
std::wstring_view name)
|
||||
{
|
||||
auto propInfo = find_property(name);
|
||||
throw_if_property_not_found(propInfo);
|
||||
|
||||
krabs::debug::assert_valid_assignment<ip_address>(name, propInfo);
|
||||
|
||||
auto outType = propInfo.pEventPropertyInfo_->nonStructType.OutType;
|
||||
|
||||
switch (outType) {
|
||||
case TDH_OUTTYPE_IPV6:
|
||||
return ip_address::from_ipv6(propInfo.pPropertyIndex_);
|
||||
|
||||
case TDH_OUTTYPE_IPV4:
|
||||
return ip_address::from_ipv4(*(DWORD*)propInfo.pPropertyIndex_);
|
||||
|
||||
default:
|
||||
throw std::runtime_error("IP Address was not IPV4 or IPV6");
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
inline socket_address parser::parse<socket_address>(
|
||||
std::wstring_view name)
|
||||
{
|
||||
auto propInfo = find_property(name);
|
||||
throw_if_property_not_found(propInfo);
|
||||
|
||||
krabs::debug::assert_valid_assignment<socket_address>(name, propInfo);
|
||||
|
||||
return socket_address::from_bytes(propInfo.pPropertyIndex_, propInfo.length_);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline sid parser::parse<sid>(
|
||||
std::wstring_view name)
|
||||
{
|
||||
auto propInfo = find_property(name);
|
||||
throw_if_property_not_found(propInfo);
|
||||
|
||||
krabs::debug::assert_valid_assignment<sid>(name, propInfo);
|
||||
auto InType = propInfo.pEventPropertyInfo_->nonStructType.InType;
|
||||
|
||||
// A WBEMSID is actually a TOKEN_USER structure followed by the SID.
|
||||
// We only care about the SID. From MSDN:
|
||||
//
|
||||
// The size of the TOKEN_USER structure differs
|
||||
// depending on whether the events were generated on a 32 - bit
|
||||
// or 64 - bit architecture. Also the structure is aligned
|
||||
// on an 8 - byte boundary, so its size is 8 bytes on a
|
||||
// 32 - bit computer and 16 bytes on a 64 - bit computer.
|
||||
// Doubling the pointer size handles both cases.
|
||||
ULONG sid_start = 16;
|
||||
if (EVENT_HEADER_FLAG_32_BIT_HEADER == (schema_.record_.EventHeader.Flags & EVENT_HEADER_FLAG_32_BIT_HEADER)) {
|
||||
sid_start = 8;
|
||||
}
|
||||
switch (InType) {
|
||||
case TDH_INTYPE_SID:
|
||||
return sid::from_bytes(propInfo.pPropertyIndex_, propInfo.length_);
|
||||
case TDH_INTYPE_WBEMSID:
|
||||
// Safety measure to make sure we don't overflow
|
||||
if (propInfo.length_ <= sid_start) {
|
||||
throw std::runtime_error(
|
||||
"Requested a WBEMSID property but data is too small");
|
||||
}
|
||||
return sid::from_bytes(propInfo.pPropertyIndex_ + sid_start, propInfo.length_ - sid_start);
|
||||
|
||||
default:
|
||||
throw std::runtime_error("SID was not a SID or WBEMSID");
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
inline pointer parser::parse<pointer>(std::wstring_view name)
|
||||
{
|
||||
auto propInfo = find_property(name);
|
||||
throw_if_property_not_found(propInfo);
|
||||
|
||||
krabs::debug::assert_valid_assignment<pointer>(name, propInfo);
|
||||
|
||||
return pointer::from_bytes(propInfo.pPropertyIndex_, propInfo.length_);
|
||||
}
|
||||
|
||||
// view_of
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
template <typename Adapter>
|
||||
auto parser::view_of(std::wstring_view name, ULONG hint, Adapter &adapter)
|
||||
-> collection_view<typename Adapter::const_iterator>
|
||||
{
|
||||
nextHint_ = hint;
|
||||
return view_of(name, adapter);
|
||||
}
|
||||
|
||||
template <typename Adapter>
|
||||
auto parser::view_of(std::wstring_view name, Adapter &adapter)
|
||||
-> collection_view<typename Adapter::const_iterator>
|
||||
{
|
||||
auto propInfo = find_property(name);
|
||||
throw_if_property_not_found(propInfo);
|
||||
|
||||
// TODO: type asserts?
|
||||
|
||||
return adapter(propInfo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#ifndef PERFINFO_GROUPMASK_HPP
|
||||
#define PERFINFO_GROUPMASK_HPP
|
||||
|
||||
#include <Windows.h>
|
||||
#pragma comment(lib, "ntdll")
|
||||
|
||||
// https://geoffchappell.com/studies/windows/km/ntoskrnl/api/etw/tracesup/perfinfo_groupmask.htm
|
||||
|
||||
#define PERF_MASK_INDEX (0xe0000000)
|
||||
#define PERF_MASK_GROUP (~PERF_MASK_INDEX)
|
||||
#define PERF_NUM_MASKS 8
|
||||
|
||||
typedef ULONG PERFINFO_MASK;
|
||||
typedef struct _PERFINFO_GROUPMASK {
|
||||
ULONG Masks[PERF_NUM_MASKS];
|
||||
} PERFINFO_GROUPMASK, *PPERFINFO_GROUPMASK;
|
||||
|
||||
#define PERF_GET_MASK_INDEX(GM) (((GM) & PERF_MASK_INDEX) >> 29)
|
||||
#define PERF_GET_MASK_GROUP(GM) ((GM) & PERF_MASK_GROUP)
|
||||
#define PERFINFO_OR_GROUP_WITH_GROUPMASK(Group, pGroupMask) \
|
||||
(pGroupMask)->Masks[PERF_GET_MASK_INDEX(Group)] |= PERF_GET_MASK_GROUP(Group);
|
||||
|
||||
// Masks[0]
|
||||
#define PERF_PROCESS EVENT_TRACE_FLAG_PROCESS
|
||||
#define PERF_THREAD EVENT_TRACE_FLAG_THREAD
|
||||
#define PERF_PROC_THREAD EVENT_TRACE_FLAG_PROCESS | EVENT_TRACE_FLAG_THREAD
|
||||
#define PERF_LOADER EVENT_TRACE_FLAG_IMAGE_LOAD
|
||||
#define PERF_PERF_COUNTER EVENT_TRACE_FLAG_PROCESS_COUNTERS
|
||||
#define PERF_FILENAME EVENT_TRACE_FLAG_DISK_FILE_IO
|
||||
#define PERF_DISK_IO EVENT_TRACE_FLAG_DISK_FILE_IO | EVENT_TRACE_FLAG_DISK_IO
|
||||
#define PERF_DISK_IO_INIT EVENT_TRACE_FLAG_DISK_IO_INIT
|
||||
#define PERF_ALL_FAULTS EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS
|
||||
#define PERF_HARD_FAULTS EVENT_TRACE_FLAG_MEMORY_HARD_FAULTS
|
||||
#define PERF_VAMAP EVENT_TRACE_FLAG_VAMAP
|
||||
#define PERF_NETWORK EVENT_TRACE_FLAG_NETWORK_TCPIP
|
||||
#define PERF_REGISTRY EVENT_TRACE_FLAG_REGISTRY
|
||||
#define PERF_DBGPRINT EVENT_TRACE_FLAG_DBGPRINT
|
||||
#define PERF_JOB EVENT_TRACE_FLAG_JOB
|
||||
#define PERF_ALPC EVENT_TRACE_FLAG_ALPC
|
||||
#define PERF_SPLIT_IO EVENT_TRACE_FLAG_SPLIT_IO
|
||||
#define PERF_DEBUG_EVENTS EVENT_TRACE_FLAG_DEBUG_EVENTS
|
||||
#define PERF_FILE_IO EVENT_TRACE_FLAG_FILE_IO
|
||||
#define PERF_FILE_IO_INIT EVENT_TRACE_FLAG_FILE_IO_INIT
|
||||
#define PERF_NO_SYSCONFIG EVENT_TRACE_FLAG_NO_SYSCONFIG
|
||||
|
||||
// Masks[1]
|
||||
#define PERF_MEMORY 0x20000001
|
||||
#define PERF_PROFILE 0x20000002 // equivalent to EVENT_TRACE_FLAG_PROFILE
|
||||
#define PERF_CONTEXT_SWITCH 0x20000004 // equivalent to EVENT_TRACE_FLAG_CSWITCH
|
||||
#define PERF_FOOTPRINT 0x20000008
|
||||
#define PERF_DRIVERS 0x20000010 // equivalent to EVENT_TRACE_FLAG_DRIVER
|
||||
#define PERF_REFSET 0x20000020
|
||||
#define PERF_POOL 0x20000040
|
||||
#define PERF_POOLTRACE 0x20000041
|
||||
#define PERF_DPC 0x20000080 // equivalent to EVENT_TRACE_FLAG_DPC
|
||||
#define PERF_COMPACT_CSWITCH 0x20000100
|
||||
#define PERF_DISPATCHER 0x20000200 // equivalent to EVENT_TRACE_FLAG_DISPATCHER
|
||||
#define PERF_PMC_PROFILE 0x20000400
|
||||
#define PERF_PROFILING 0x20000402
|
||||
#define PERF_PROCESS_INSWAP 0x20000800
|
||||
#define PERF_AFFINITY 0x20001000
|
||||
#define PERF_PRIORITY 0x20002000
|
||||
#define PERF_INTERRUPT 0x20004000 // equivalent to EVENT_TRACE_FLAG_INTERRUPT
|
||||
#define PERF_VIRTUAL_ALLOC 0x20008000 // equivalent to EVENT_TRACE_FLAG_VIRTUAL_ALLOC
|
||||
#define PERF_SPINLOCK 0x20010000
|
||||
#define PERF_SYNC_OBJECTS 0x20020000
|
||||
#define PERF_DPC_QUEUE 0x20040000
|
||||
#define PERF_MEMINFO 0x20080000
|
||||
#define PERF_CONTMEM_GEN 0x20100000
|
||||
#define PERF_SPINLOCK_CNTRS 0x20200000
|
||||
#define PERF_SPININSTR 0x20210000
|
||||
#define PERF_SESSION 0x20400000
|
||||
#define PERF_PFSECTION 0x20400000
|
||||
#define PERF_MEMINFO_WS 0x20800000
|
||||
#define PERF_KERNEL_QUEUE 0x21000000
|
||||
#define PERF_INTERRUPT_STEER 0x22000000
|
||||
#define PERF_SHOULD_YIELD 0x24000000
|
||||
#define PERF_WS 0x28000000
|
||||
|
||||
// Masks[2]
|
||||
#define PERF_ANTI_STARVATION 0x40000001
|
||||
#define PERF_PROCESS_FREEZE 0x40000002
|
||||
#define PERF_PFN_LIST 0x40000004
|
||||
#define PERF_WS_DETAIL 0x40000008
|
||||
#define PERF_WS_ENTRY 0x40000010
|
||||
#define PERF_HEAP 0x40000020
|
||||
#define PERF_SYSCALL 0x40000040 // equivalent to EVENT_TRACE_FLAG_SYSTEMCALL
|
||||
#define PERF_UMS 0x40000080
|
||||
#define PERF_BACKTRACE 0x40000100
|
||||
#define PERF_VULCAN 0x40000200
|
||||
#define PERF_OBJECTS 0x40000400
|
||||
#define PERF_EVENTS 0x40000800
|
||||
#define PERF_FULLTRACE 0x40001000
|
||||
#define PERF_DFSS 0x40002000
|
||||
#define PERF_PREFETCH 0x40004000
|
||||
#define PERF_PROCESSOR_IDLE 0x40008000
|
||||
#define PERF_CPU_CONFIG 0x40010000
|
||||
#define PERF_TIMER 0x40020000
|
||||
#define PERF_CLOCK_INTERRUPT 0x40040000
|
||||
#define PERF_LOAD_BALANCER 0x40080000
|
||||
#define PERF_CLOCK_TIMER 0x40100000
|
||||
#define PERF_IDLE_SELECTION 0x40200000
|
||||
#define PERF_IPI 0x40400000
|
||||
#define PERF_IO_TIMER 0x40800000
|
||||
#define PERF_REG_HIVE 0x41000000
|
||||
#define PERF_REG_NOTIF 0x42000000
|
||||
#define PERF_PPM_EXIT_LATENCY 0x44000000
|
||||
#define PERF_WORKER_THREAD 0x48000000
|
||||
|
||||
// Masks[4]
|
||||
#define PERF_OPTICAL_IO 0x80000001
|
||||
#define PERF_OPTICAL_IO_INIT 0x80000002
|
||||
#define PERF_DLL_INFO 0x80000008
|
||||
#define PERF_DLL_FLUSH_WS 0x80000010
|
||||
#define PERF_OB_HANDLE 0x80000040
|
||||
#define PERF_OB_OBJECT 0x80000080
|
||||
#define PERF_WAKE_DROP 0x80000200
|
||||
#define PERF_WAKE_EVENT 0x80000400
|
||||
#define PERF_DEBUGGER 0x80000800
|
||||
#define PERF_PROC_ATTACH 0x80001000
|
||||
#define PERF_WAKE_COUNTER 0x80002000
|
||||
#define PERF_POWER 0x80008000
|
||||
#define PERF_SOFT_TRIM 0x80010000
|
||||
#define PERF_CC 0x80020000
|
||||
#define PERF_FLT_IO_INIT 0x80080000
|
||||
#define PERF_FLT_IO 0x80100000
|
||||
#define PERF_FLT_FASTIO 0x80200000
|
||||
#define PERF_FLT_IO_FAILURE 0x80400000
|
||||
#define PERF_HV_PROFILE 0x80800000
|
||||
#define PERF_WDF_DPC 0x81000000
|
||||
#define PERF_WDF_INTERRUPT 0x82000000
|
||||
#define PERF_CACHE_FLUSH 0x84000000
|
||||
|
||||
// Masks[5]
|
||||
#define PERF_HIBER_RUNDOWN 0xA0000001
|
||||
|
||||
// Masks[6]
|
||||
#define PERF_SYSCFG_SYSTEM 0xC0000001
|
||||
#define PERF_SYSCFG_GRAPHICS 0xC0000002
|
||||
#define PERF_SYSCFG_STORAGE 0xC0000004
|
||||
#define PERF_SYSCFG_NETWORK 0xC0000008
|
||||
#define PERF_SYSCFG_SERVICES 0xC0000010
|
||||
#define PERF_SYSCFG_PNP 0xC0000020
|
||||
#define PERF_SYSCFG_OPTICAL 0xC0000040
|
||||
#define PERF_SYSCFG_ALL 0xDFFFFFFF
|
||||
|
||||
// Masks[7] - Control Mask. All flags that change system behavior go here.
|
||||
#define PERF_CLUSTER_OFF 0xE0000001
|
||||
#define PERF_MEMORY_CONTROL 0xE0000002
|
||||
|
||||
// TraceQueryInformation wasn't introduced until Windows 8, so we need to use
|
||||
// NtQuerySystemInformation instead in order to maintain support for Windows 7.
|
||||
// This requires the below additional definitions.
|
||||
|
||||
typedef enum _EVENT_TRACE_INFORMATION_CLASS {
|
||||
EventTraceKernelVersionInformation,
|
||||
EventTraceGroupMaskInformation,
|
||||
EventTracePerformanceInformation,
|
||||
EventTraceTimeProfileInformation,
|
||||
EventTraceSessionSecurityInformation,
|
||||
EventTraceSpinlockInformation,
|
||||
EventTraceStackTracingInformation,
|
||||
EventTraceExecutiveResourceInformation,
|
||||
EventTraceHeapTracingInformation,
|
||||
EventTraceHeapSummaryTracingInformation,
|
||||
EventTracePoolTagFilterInformation,
|
||||
EventTracePebsTracingInformation,
|
||||
EventTraceProfileConfigInformation,
|
||||
EventTraceProfileSourceListInformation,
|
||||
EventTraceProfileEventListInformation,
|
||||
EventTraceProfileCounterListInformation,
|
||||
EventTraceStackCachingInformation,
|
||||
EventTraceObjectTypeFilterInformation,
|
||||
MaxEventTraceInfoClass
|
||||
} EVENT_TRACE_INFORMATION_CLASS;
|
||||
|
||||
typedef struct _EVENT_TRACE_GROUPMASK_INFORMATION {
|
||||
EVENT_TRACE_INFORMATION_CLASS EventTraceInformationClass;
|
||||
TRACEHANDLE TraceHandle;
|
||||
PERFINFO_GROUPMASK EventTraceGroupMasks;
|
||||
} EVENT_TRACE_GROUPMASK_INFORMATION, * PEVENT_TRACE_GROUPMASK_INFORMATION;
|
||||
|
||||
#ifndef _WINTERNL_
|
||||
|
||||
typedef enum _SYSTEM_INFORMATION_CLASS {
|
||||
SystemPerformanceTraceInformation = 0x1f,
|
||||
} SYSTEM_INFORMATION_CLASS;
|
||||
|
||||
typedef LONG NTSTATUS;
|
||||
|
||||
extern "C" NTSTATUS NTAPI NtQuerySystemInformation(
|
||||
_In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,
|
||||
_Out_writes_bytes_to_opt_(SystemInformationLength, *ReturnLength) PVOID SystemInformation,
|
||||
_In_ ULONG SystemInformationLength,
|
||||
_Out_opt_ PULONG ReturnLength
|
||||
);
|
||||
|
||||
#endif // _WINTERNL_
|
||||
|
||||
extern "C" NTSTATUS NTAPI NtSetSystemInformation(
|
||||
_In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,
|
||||
_In_reads_bytes_opt_(SystemInformationLength) PVOID SystemInformation,
|
||||
_In_ ULONG SystemInformationLength
|
||||
);
|
||||
|
||||
#endif // PERFINFO_GROUPMASK_HPP
|
||||
+216
@@ -0,0 +1,216 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#define INITGUID
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "compiler_check.hpp"
|
||||
#include "schema.hpp"
|
||||
#include "errors.hpp"
|
||||
|
||||
#include <windows.h>
|
||||
#include <tdh.h>
|
||||
#include <evntrace.h>
|
||||
|
||||
#pragma comment(lib, "tdh.lib")
|
||||
|
||||
namespace krabs {
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Represents a single property of the record schema.
|
||||
* </summary>
|
||||
* <remarks>
|
||||
* Noticeably absent from this property is the ability to ask what its
|
||||
* value is. The reason for this is that this property instance is
|
||||
* intended to work with synth_records, which don't always have data to
|
||||
* correspond with properties. This class *cannot* return a value because
|
||||
* there isn't always a value to return.
|
||||
* </remarks>
|
||||
*/
|
||||
class property {
|
||||
public:
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Constructs a property.
|
||||
* </summary>
|
||||
* <remarks>
|
||||
* This should be instantiated by client code -- let the parser
|
||||
* object do this for you with its `properties` method.
|
||||
* </remarks>
|
||||
*/
|
||||
property(const std::wstring &name, _TDH_IN_TYPE type, _TDH_OUT_TYPE outType);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Retrieves the name of the property.
|
||||
* </summary>
|
||||
*/
|
||||
const std::wstring &name() const;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Retrieves the Tdh type of the property.
|
||||
* </summary>
|
||||
*/
|
||||
_TDH_IN_TYPE type() const;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Retrieves the Tdh type of the property.
|
||||
* </summary>
|
||||
*/
|
||||
_TDH_OUT_TYPE out_type() const;
|
||||
|
||||
private:
|
||||
std::wstring name_;
|
||||
_TDH_IN_TYPE type_;
|
||||
_TDH_OUT_TYPE outType_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Iterates the properties in a given event record.
|
||||
* </summary>
|
||||
*/
|
||||
class property_iterator {
|
||||
public:
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Constructs a new iterator that lazily retrieves the properties of
|
||||
* the given event record.
|
||||
* </summary>
|
||||
* <remarks>
|
||||
* Don't construct this yourself. Let the `parser` class do it for you.
|
||||
* </remarks>
|
||||
*/
|
||||
property_iterator(const schema &s);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Returns an iterator that hasn't yielded any properties yet.
|
||||
* </summary>
|
||||
*/
|
||||
std::vector<property>::iterator begin();
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Returns an iterator that has yielded all properties.
|
||||
* </summary>
|
||||
*/
|
||||
std::vector<property>::iterator end();
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Constructs a property instance out of the raw data of the
|
||||
* given property.
|
||||
* </summary>
|
||||
*/
|
||||
property get_property(size_t index) const;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Collects the names of the properties in the schema.
|
||||
* </summary>
|
||||
* <remarks>
|
||||
* This is a little lazy of us, as we end up iterating the properties
|
||||
* entirely before allowing enumeration by the client. Because this
|
||||
* code is most likely called in a non-critical path, there's not
|
||||
* much to worry about here.
|
||||
*/
|
||||
std::vector<property> enum_properties() const;
|
||||
|
||||
|
||||
private:
|
||||
const krabs::schema &schema_;
|
||||
size_t numProperties_;
|
||||
std::vector<property> properties_;
|
||||
std::vector<property>::iterator beg_;
|
||||
std::vector<property>::iterator end_;
|
||||
std::vector<property>::iterator curr_;
|
||||
};
|
||||
|
||||
// Implementation
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
inline property::property(const std::wstring &name, _TDH_IN_TYPE type, _TDH_OUT_TYPE outType)
|
||||
: name_(name)
|
||||
, type_(type)
|
||||
, outType_(outType)
|
||||
{}
|
||||
|
||||
inline const std::wstring &property::name() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
inline _TDH_IN_TYPE property::type() const
|
||||
{
|
||||
return type_;
|
||||
}
|
||||
|
||||
inline _TDH_OUT_TYPE property::out_type() const
|
||||
{
|
||||
return outType_;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
inline property_iterator::property_iterator(const schema &s)
|
||||
: schema_(s)
|
||||
, numProperties_(s.pSchema_->TopLevelPropertyCount)
|
||||
, properties_(enum_properties())
|
||||
, beg_(properties_.begin())
|
||||
, end_(properties_.end())
|
||||
, curr_(properties_.begin())
|
||||
{}
|
||||
|
||||
inline std::vector<property>::iterator property_iterator::begin()
|
||||
{
|
||||
return beg_;
|
||||
}
|
||||
|
||||
inline std::vector<property>::iterator property_iterator::end()
|
||||
{
|
||||
return end_;
|
||||
}
|
||||
|
||||
inline property property_iterator::get_property(size_t index) const
|
||||
{
|
||||
const auto &curr_prop = schema_.pSchema_->EventPropertyInfoArray[index];
|
||||
|
||||
const wchar_t *pName = reinterpret_cast<const wchar_t*>(
|
||||
reinterpret_cast<const BYTE*>(schema_.pSchema_) +
|
||||
curr_prop.NameOffset);
|
||||
|
||||
auto tdh_type = (_TDH_IN_TYPE)curr_prop.nonStructType.InType;
|
||||
auto tdh_out_type = (_TDH_OUT_TYPE)curr_prop.nonStructType.OutType;
|
||||
|
||||
return property(pName, tdh_type, tdh_out_type);
|
||||
}
|
||||
|
||||
inline std::vector<property> property_iterator::enum_properties() const
|
||||
{
|
||||
std::vector<property> props;
|
||||
for (size_t i = 0; i < numProperties_; ++i) {
|
||||
props.emplace_back(get_property(i));
|
||||
}
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
|
||||
} /* namespace krabs */
|
||||
+609
@@ -0,0 +1,609 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#define INITGUID
|
||||
|
||||
#include <deque>
|
||||
#include <functional>
|
||||
|
||||
#include "compiler_check.hpp"
|
||||
#include "filtering/event_filter.hpp"
|
||||
#include "perfinfo_groupmask.hpp"
|
||||
#include "trace_context.hpp"
|
||||
#include "wstring_convert.hpp"
|
||||
|
||||
#include <evntcons.h>
|
||||
#include <guiddef.h>
|
||||
|
||||
#ifdef _DEBUG
|
||||
#pragma comment(lib, "comsuppwd.lib")
|
||||
#else
|
||||
#pragma comment(lib, "comsuppw.lib")
|
||||
#endif
|
||||
|
||||
namespace krabs { namespace details {
|
||||
template <typename T> class trace_manager;
|
||||
|
||||
struct kt;
|
||||
struct ut;
|
||||
|
||||
} /* namespace details */ } /* namespace krabs */
|
||||
|
||||
namespace krabs {
|
||||
|
||||
template <typename T>
|
||||
class trace;
|
||||
|
||||
typedef void(*c_provider_callback)(const EVENT_RECORD &, const krabs::trace_context &);
|
||||
typedef void(*c_provider_error_callback)(const EVENT_RECORD&, const std::string&);
|
||||
typedef std::function<void(const EVENT_RECORD &, const krabs::trace_context &)> provider_callback;
|
||||
typedef std::function<void(const EVENT_RECORD&, const std::string&)> provider_error_callback;
|
||||
|
||||
namespace details {
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Serves as a base for providers and kernel_providers. Handles event
|
||||
* registration and forwarding.
|
||||
* </summary>
|
||||
*/
|
||||
template <typename T>
|
||||
class base_provider {
|
||||
public:
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Adds a function to call when an event for this provider is fired.
|
||||
* </summary>
|
||||
*
|
||||
* <param name="callback">the function to call into</param>
|
||||
* <example>
|
||||
* void my_fun(const EVENT_RECORD &record, const krabs::trace_context &trace_context) { ... }
|
||||
* // ...
|
||||
* krabs::guid id(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}");
|
||||
* provider<> powershell(id);
|
||||
* provider.add_on_event_callback(my_fun);
|
||||
* </example>
|
||||
*
|
||||
* <example>
|
||||
* auto fun = [&](const EVENT_RECORD &record, const krabs::trace_context &trace_context) {...}
|
||||
* krabs::guid id(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}");
|
||||
* provider<> powershell(id);
|
||||
* provider.add_on_event_callback(fun);
|
||||
* </example>
|
||||
*/
|
||||
void add_on_event_callback(c_provider_callback callback);
|
||||
|
||||
template <typename U>
|
||||
void add_on_event_callback(U &callback);
|
||||
|
||||
template <typename U>
|
||||
void add_on_event_callback(const U &callback);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Adds a function to call when an error occurs when this provider handles an event.
|
||||
* </summary>
|
||||
*/
|
||||
void add_on_error_callback(c_provider_error_callback callback);
|
||||
|
||||
template <typename U>
|
||||
void add_on_error_callback(U& callback);
|
||||
|
||||
template <typename U>
|
||||
void add_on_error_callback(const U& callback);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Adds a new filter to a provider, where the filter is expected
|
||||
* to have callbacks attached to it.
|
||||
* </summary>
|
||||
* <example>
|
||||
* krabs::guid id(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}");
|
||||
* krabs::provider<> powershell(id);
|
||||
* krabs::event_filter filter(krabs::filtering::any_event);
|
||||
* filter.add_on_event_callback([&](const EVENT_RECORD &record, const krabs::trace_context &trace_context) {...});
|
||||
* powershell.add_filter(filter);
|
||||
* </example>
|
||||
*/
|
||||
void add_filter(const event_filter &f);
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Called when an event occurs, forwards to callbacks and filters.
|
||||
* </summary>
|
||||
*/
|
||||
void on_event(const EVENT_RECORD &record, const krabs::trace_context &context) const;
|
||||
|
||||
protected:
|
||||
std::deque<provider_callback> callbacks_;
|
||||
std::deque<provider_error_callback> error_callbacks_;
|
||||
std::deque<event_filter> filters_;
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
friend class details::trace_manager;
|
||||
|
||||
template <typename T>
|
||||
friend class krabs::trace;
|
||||
|
||||
template <typename S>
|
||||
friend class base_provider;
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Used to enable specific types of events from specific event sources in
|
||||
* ETW. Corresponds tightly with the concept of an ETW provider. Used for
|
||||
* user trace instances (not kernel trace instances).
|
||||
* </summary>
|
||||
*
|
||||
* <param name='T'>
|
||||
* The type of flags to use when filtering event types via any and all.
|
||||
* There is an implicitly requirement that T can be downcasted to a
|
||||
* ULONGLONG.
|
||||
* </param>
|
||||
*/
|
||||
template <typename T = ULONGLONG>
|
||||
class provider : public details::base_provider<T> {
|
||||
public:
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Constructs a provider with the given guid identifier.
|
||||
* </summary>
|
||||
*
|
||||
* <param name="id">the GUID that identifies the provider.</param>
|
||||
* <example>
|
||||
* krabs::guid id(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}");
|
||||
* provider<> powershell(id);
|
||||
* </example>
|
||||
*/
|
||||
provider(GUID id);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Constructs a provider with the given a provider name.
|
||||
* </summary>
|
||||
*
|
||||
* <param name="id">the provider name.</param>
|
||||
* <example>
|
||||
* krabs::guid id(L"Microsoft-Windows-WinINet");
|
||||
* provider<> winINet(id);
|
||||
* </example>
|
||||
*/
|
||||
provider(const std::wstring &providerName);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Sets the "any" flag of the provider.
|
||||
* </summary>
|
||||
*
|
||||
* <param name="value">the value to set <c>any</c> to.</param>
|
||||
* <example>
|
||||
* krabs::guid id(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}");
|
||||
* provider<> powershell(id);
|
||||
* powershell.any(0xFF00);
|
||||
* </example>
|
||||
*/
|
||||
void any(T any);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Sets the "all" flag of the provider.
|
||||
* </summary>
|
||||
*
|
||||
* <param name="value">the value to set <c>all</c> to.</param>
|
||||
* <example>
|
||||
* krabs::guid id(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}");
|
||||
* provider<> powershell(id);
|
||||
* powershell.all(0xFF00);
|
||||
* </example>
|
||||
*/
|
||||
void all(T all);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Sets the "level" flag of the provider. Valid values are 0~255 (0xFF).
|
||||
* </summary>
|
||||
*
|
||||
* <param name="value">the value to set <c>level</c> to.</param>
|
||||
* <example>
|
||||
* krabs::guid id(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}");
|
||||
* provider<> powershell(id);
|
||||
* powershell.level(0x00);
|
||||
* </example>
|
||||
*/
|
||||
void level(T level);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Sets the "EnableProperty" flag on the ENABLE_TRACE_PARAMETER struct.
|
||||
* These properties configure behaviours for a specified user-mode provider.
|
||||
* Valid values can be found here:
|
||||
* https://msdn.microsoft.com/en-us/library/windows/desktop/dd392306(v=vs.85).aspx
|
||||
* </summary>
|
||||
*
|
||||
* <param name="value">the value to set</param>
|
||||
* <example>
|
||||
* krabs::guid id(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}");
|
||||
* provider<> powershell(id);
|
||||
* powershell.trace_flags(EVENT_ENABLE_PROPERTY_STACK_TRACE);
|
||||
* </example>
|
||||
*/
|
||||
void trace_flags(T trace_flags);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Gets the configured value for the "EnableProperty" flag on the
|
||||
* ENABLE_TRACE_PARAMETER struct. See void trace_flags(T trace_flags)
|
||||
* for details on what the values mean.
|
||||
* </summary>
|
||||
* <returns>The value to set when the provider is enabled.</returns>
|
||||
* <example>
|
||||
* krabs::guid id(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}");
|
||||
* provider<> powershell(id);
|
||||
* powershell.trace_flags(EVENT_ENABLE_PROPERTY_STACK_TRACE);
|
||||
* auto flags = powershell.get_trace_flags();
|
||||
* assert(flags == EVENT_ENABLE_PROPERTY_STACK_TRACE);
|
||||
* </example>
|
||||
*/
|
||||
T trace_flags() const;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Requests that the provider log its state information. See:
|
||||
* https://docs.microsoft.com/en-us/windows/win32/api/evntrace/nf-evntrace-enabletraceex2
|
||||
* </summary>
|
||||
*
|
||||
* <example>
|
||||
* krabs::provider<> process_provider(L"Microsoft-Windows-Kernel-Process");
|
||||
* process_provider.any(0x10); // WINEVENT_KEYWORD_PROCESS
|
||||
* process_provider.enable_rundown_events();
|
||||
* </example>
|
||||
*/
|
||||
void enable_rundown_events();
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Turns a strongly typed provider<T> to provider<> (useful for
|
||||
* creating collections of providers).
|
||||
* </summary>
|
||||
*
|
||||
* <example>
|
||||
* krabs::guid id(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}");
|
||||
* provider<CustomFlagType> powershell(id);
|
||||
* provider<> blah(powershell);
|
||||
* </example>
|
||||
*/
|
||||
operator provider<>() const;
|
||||
|
||||
private:
|
||||
GUID guid_;
|
||||
T any_;
|
||||
T all_;
|
||||
T level_;
|
||||
T trace_flags_;
|
||||
bool rundown_enabled_;
|
||||
|
||||
GUID provider_name_to_guid(const std::wstring& name);
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
friend class details::trace_manager;
|
||||
|
||||
template <typename T>
|
||||
friend class krabs::trace;
|
||||
|
||||
template <typename S>
|
||||
friend class base_provider;
|
||||
|
||||
friend struct details::ut;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Used to enable specific types of event sources from an ETW kernel
|
||||
* trace.
|
||||
* </summary>
|
||||
*/
|
||||
class kernel_provider : public details::base_provider<ULONGLONG> {
|
||||
public:
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Constructs a kernel_provider that enables events of the given
|
||||
* flags.
|
||||
* </summary>
|
||||
*/
|
||||
kernel_provider(unsigned long flags, const GUID &id)
|
||||
: p_(flags)
|
||||
, id_(id)
|
||||
, gm_(0)
|
||||
, r_(0)
|
||||
, rundown_enabled_(false)
|
||||
{}
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Constructs a kernel_provider that enables events of the given
|
||||
* group mask.
|
||||
* </summary>
|
||||
* <remarks>
|
||||
* Only supported on Windows 8 and newer.
|
||||
* </remarks>
|
||||
*/
|
||||
kernel_provider(const GUID& id, PERFINFO_MASK group_mask)
|
||||
: p_(0)
|
||||
, id_(id)
|
||||
, gm_(group_mask)
|
||||
, r_(0)
|
||||
, rundown_enabled_(false)
|
||||
{}
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Retrieves the GUID associated with this provider.
|
||||
* </summary>
|
||||
*/
|
||||
const krabs::guid &id() const;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Sets flags to be enabled for the kernel rundown GUID.
|
||||
* </summary>
|
||||
* <remarks>
|
||||
* This ETW feature is undocumented and should be used with caution.
|
||||
* </remarks>
|
||||
*/
|
||||
void set_rundown_flags(unsigned long rundown_flags) {
|
||||
r_ = rundown_flags;
|
||||
rundown_enabled_ = true;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Retrieves the flag value associated with this provider.
|
||||
* </summary>
|
||||
*/
|
||||
unsigned long flags() const { return p_; }
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Retrieves the group mask value associated with this provider.
|
||||
* </summary>
|
||||
*/
|
||||
PERFINFO_MASK group_mask() const { return gm_; }
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Retrieves the rundown flag value associated with this provider.
|
||||
* </summary>
|
||||
*/
|
||||
unsigned long rundown_flags() const { return r_; }
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Have rundown flags been set for this this provider?
|
||||
* </summary>
|
||||
*/
|
||||
bool rundown_enabled() const { return rundown_enabled_; }
|
||||
|
||||
private:
|
||||
unsigned long p_;
|
||||
const krabs::guid id_;
|
||||
PERFINFO_MASK gm_;
|
||||
unsigned long r_;
|
||||
bool rundown_enabled_;
|
||||
|
||||
private:
|
||||
friend struct details::kt;
|
||||
};
|
||||
|
||||
|
||||
// Implementation
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
namespace details {
|
||||
|
||||
template <typename T>
|
||||
void base_provider<T>::add_on_event_callback(c_provider_callback callback)
|
||||
{
|
||||
// C function pointers don't interact well with std::ref, so we
|
||||
// overload to take care of this scenario.
|
||||
callbacks_.push_back(callback);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename U>
|
||||
void base_provider<T>::add_on_event_callback(U &callback)
|
||||
{
|
||||
// std::function copies its argument -- because our callbacks list
|
||||
// is a list of std::function, this causes problems when a user
|
||||
// intended for their particular instance to be called.
|
||||
// std::ref lets us get around this and point to a specific instance
|
||||
// that they handed us.
|
||||
callbacks_.push_back(std::ref(callback));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename U>
|
||||
void base_provider<T>::add_on_event_callback(const U &callback)
|
||||
{
|
||||
// This is where temporaries bind to. Temporaries can't be wrapped in
|
||||
// a std::ref because they'll go away very quickly. We are forced to
|
||||
// actually copy these.
|
||||
callbacks_.push_back(callback);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void base_provider<T>::add_on_error_callback(c_provider_error_callback callback)
|
||||
{
|
||||
// C function pointers don't interact well with std::ref, so we
|
||||
// overload to take care of this scenario.
|
||||
error_callbacks_.push_back(callback);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename U>
|
||||
void base_provider<T>::add_on_error_callback(U& callback)
|
||||
{
|
||||
// std::function copies its argument -- because our callbacks list
|
||||
// is a list of std::function, this causes problems when a user
|
||||
// intended for their particular instance to be called.
|
||||
// std::ref lets us get around this and point to a specific instance
|
||||
// that they handed us.
|
||||
error_callbacks_.push_back(std::ref(callback));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename U>
|
||||
void base_provider<T>::add_on_error_callback(const U& callback)
|
||||
{
|
||||
// This is where temporaries bind to. Temporaries can't be wrapped in
|
||||
// a std::ref because they'll go away very quickly. We are forced to
|
||||
// actually copy these.
|
||||
error_callbacks_.push_back(callback);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void base_provider<T>::add_filter(const event_filter &f)
|
||||
{
|
||||
filters_.push_back(f);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void base_provider<T>::on_event(const EVENT_RECORD &record, const krabs::trace_context &trace_context) const
|
||||
{
|
||||
try
|
||||
{
|
||||
for (auto& callback : callbacks_) {
|
||||
callback(record, trace_context);
|
||||
}
|
||||
|
||||
for (auto& filter : filters_) {
|
||||
filter.on_event(record, trace_context);
|
||||
}
|
||||
}
|
||||
catch (krabs::could_not_find_schema& ex)
|
||||
{
|
||||
for (auto& error_callback : error_callbacks_) {
|
||||
error_callback(record, ex.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace details
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
static const GUID emptyGuid = { 0 };
|
||||
|
||||
template <typename T>
|
||||
provider<T>::provider(GUID id)
|
||||
: guid_(id)
|
||||
, any_(0)
|
||||
, all_(0)
|
||||
, level_(5)
|
||||
, trace_flags_(0)
|
||||
, rundown_enabled_(false)
|
||||
{}
|
||||
|
||||
template <typename T>
|
||||
provider<T>::provider(const std::wstring &providerName)
|
||||
: provider(provider_name_to_guid(providerName))
|
||||
{}
|
||||
|
||||
template <typename T>
|
||||
void provider<T>::any(T any)
|
||||
{
|
||||
any_ = any;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void provider<T>::all(T all)
|
||||
{
|
||||
all_ = all;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void provider<T>::level(T level)
|
||||
{
|
||||
level_ = level;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void provider<T>::trace_flags(T trace_flags)
|
||||
{
|
||||
trace_flags_ = trace_flags;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T provider<T>::trace_flags() const
|
||||
{
|
||||
return static_cast<T>(trace_flags_);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void provider<T>::enable_rundown_events()
|
||||
{
|
||||
rundown_enabled_ = true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
provider<T>::operator provider<>() const
|
||||
{
|
||||
provider<> tmp(guid_);
|
||||
tmp.any_ = static_cast<ULONGLONG>(any_);
|
||||
tmp.all_ = static_cast<ULONGLONG>(all_);
|
||||
tmp.level_ = static_cast<UCHAR>(level_);
|
||||
tmp.trace_flags_ = static_cast<ULONG>(trace_flags_);
|
||||
tmp.callbacks_ = this->callbacks_;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline GUID provider<T>::provider_name_to_guid(const std::wstring& name)
|
||||
{
|
||||
ULONG bufferSize = 0;
|
||||
TDHSTATUS status = TdhEnumerateProviders(NULL, &bufferSize);
|
||||
if (status != ERROR_INSUFFICIENT_BUFFER) {
|
||||
error_check_common_conditions(status);
|
||||
return {};
|
||||
}
|
||||
|
||||
auto buffer = std::unique_ptr<char[]>(new char[bufferSize]);
|
||||
status = TdhEnumerateProviders((PPROVIDER_ENUMERATION_INFO)buffer.get(), &bufferSize);
|
||||
error_check_common_conditions(status);
|
||||
|
||||
auto providers = (PPROVIDER_ENUMERATION_INFO)buffer.get();
|
||||
for (ULONG i = 0; i < providers->NumberOfProviders; i++)
|
||||
{
|
||||
auto provider = providers->TraceProviderInfoArray[i];
|
||||
std::wstring_view provider_name((wchar_t*)((char*)providers + provider.ProviderNameOffset));
|
||||
if (provider_name == name)
|
||||
return provider.ProviderGuid;
|
||||
}
|
||||
|
||||
std::stringstream stream;
|
||||
stream << "Provider name does not exist. (";
|
||||
stream << from_wstring(name);
|
||||
stream << ")";
|
||||
throw std::runtime_error(stream.str());
|
||||
}
|
||||
|
||||
inline const krabs::guid &kernel_provider::id() const
|
||||
{
|
||||
return id_;
|
||||
}
|
||||
|
||||
}
|
||||
+503
@@ -0,0 +1,503 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#define INITGUID
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <windows.h>
|
||||
#include <tdh.h>
|
||||
#include <evntrace.h>
|
||||
|
||||
#include "compiler_check.hpp"
|
||||
#include "schema_locator.hpp"
|
||||
|
||||
// Windows SDK may not define this constant on older SDK versions.
|
||||
#ifndef EVENT_HEADER_EXT_TYPE_PROCESS_START_KEY
|
||||
#define EVENT_HEADER_EXT_TYPE_PROCESS_START_KEY 0x000B
|
||||
#endif
|
||||
|
||||
#pragma comment(lib, "tdh.lib")
|
||||
|
||||
|
||||
namespace krabs { namespace testing {
|
||||
class record_builder;
|
||||
} /* namespace testing */ } /* namespace krabs */
|
||||
|
||||
|
||||
namespace krabs {
|
||||
|
||||
class schema;
|
||||
class parser;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Used to query events for detailed information. Creation is rather
|
||||
* costly, so client code should try hard to delay creation of this.
|
||||
* </summary>
|
||||
*/
|
||||
class schema {
|
||||
public:
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Constructs a schema from an event record instance
|
||||
* using the provided schema_locator.
|
||||
* </summary>
|
||||
*
|
||||
* <example>
|
||||
* void on_event(const EVENT_RECORD &record, const krabs::trace_context &trace_context)
|
||||
* {
|
||||
* krabs::schema schema(record, trace_context.schema_locator);
|
||||
* }
|
||||
* </example>
|
||||
*/
|
||||
schema(const EVENT_RECORD &, const krabs::schema_locator &);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Constructs a schema from an event record instance
|
||||
* using the provided TRACE_EVENT_INFO pointer.
|
||||
* </summary>
|
||||
*
|
||||
* <example>
|
||||
* void on_event(const EVENT_RECORD &record, const krabs::trace_context &trace_context)
|
||||
* {
|
||||
* TDHSTATUS status = ERROR_SUCCESS;
|
||||
* const PTRACE_EVENT_INFO info = trace_context.schema_locator.get_event_schema_no_throw(record, status);
|
||||
* if (status != ERROR_SUCCESS) {
|
||||
* // fallback logic here...
|
||||
* }
|
||||
* krabs::schema schema(record, info);
|
||||
* }
|
||||
* </example>
|
||||
*/
|
||||
schema(const EVENT_RECORD &, const PTRACE_EVENT_INFO);
|
||||
|
||||
/**
|
||||
* <summary>Compares two schemas for equality.<summary>
|
||||
*
|
||||
* <example>
|
||||
* schema1 == schema2;
|
||||
* schema1 != schema2;
|
||||
* </example>
|
||||
*/
|
||||
bool operator==(const schema &other) const;
|
||||
bool operator!=(const schema &other) const;
|
||||
|
||||
/*
|
||||
* <summary>
|
||||
* Returns the name of an event via its schema.
|
||||
* </summary>
|
||||
* <example>
|
||||
* void on_event(const EVENT_RECORD &record, const krabs::trace_context &trace_context)
|
||||
* {
|
||||
* krabs::schema schema(record, trace_context.schema_locator);
|
||||
* std::wstring name = krabs::event_name(schema);
|
||||
* }
|
||||
* </example>
|
||||
*/
|
||||
const wchar_t *event_name() const;
|
||||
|
||||
/*
|
||||
* <summary>
|
||||
* Returns the name of an opcode via its schema.
|
||||
* </summary>
|
||||
* <example>
|
||||
* void on_event(const EVENT_RECORD &record, const krabs::trace_context &trace_context)
|
||||
* {
|
||||
* krabs::schema schema(record, trace_context.schema_locator);
|
||||
* std::wstring name = krabs::opcode_name(schema);
|
||||
* }
|
||||
* </example>
|
||||
*/
|
||||
const wchar_t* opcode_name() const;
|
||||
|
||||
/*
|
||||
* <summary>
|
||||
* Returns the taskname of an event via its schema.
|
||||
* </summary>
|
||||
* <example>
|
||||
* void on_event(const EVENT_RECORD &record, const krabs::trace_context &trace_context)
|
||||
* {
|
||||
* krabs::schema schema(record, trace_context.schema_locator);
|
||||
* std::wstring name = krabs::task_name(schema);
|
||||
* }
|
||||
* </example>
|
||||
*/
|
||||
const wchar_t *task_name() const;
|
||||
|
||||
/*
|
||||
* <summary>
|
||||
* Returns the DECODING_SOURCE of an event via its schema.
|
||||
* </summary>
|
||||
* <example>
|
||||
* void on_event(const EVENT_RECORD &record, const krabs::trace_context &trace_context)
|
||||
* {
|
||||
* krabs::schema schema(record, trace_context.schema_locator);
|
||||
* DECODING_SOURCE source = krabs::decoding_source(schema);
|
||||
* }
|
||||
* </example>
|
||||
*/
|
||||
DECODING_SOURCE decoding_source() const;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Returns the event ID via its schema.
|
||||
* </summary>
|
||||
* <example>
|
||||
* void on_event(const EVENT_RECORD &record, const krabs::trace_context &trace_context)
|
||||
* {
|
||||
* krabs::schema schema(record, trace_context.schema_locator);
|
||||
* int id = schema.event_id();
|
||||
* }
|
||||
* </example>
|
||||
*/
|
||||
int event_id() const;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Returns the event opcode.
|
||||
* </summary>
|
||||
* <example>
|
||||
* void on_event(const EVENT_RECORD &record, const krabs::trace_context &trace_context)
|
||||
* {
|
||||
* krabs::schema schema(record, trace_context.schema_locator);
|
||||
* int opcode = schema.event_opcode();
|
||||
* }
|
||||
* </example>
|
||||
*/
|
||||
int event_opcode() const;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Returns the version of the event.
|
||||
* </summary>
|
||||
*/
|
||||
unsigned int event_version() const;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Returns the flags of the event.
|
||||
* </summary>
|
||||
*/
|
||||
unsigned int event_flags() const;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Returns the provider GUID of an event via its schema.
|
||||
* </summary>
|
||||
* <example>
|
||||
* void on_event(const EVENT_RECORD &record, const krabs::trace_context &trace_context)
|
||||
* {
|
||||
* krabs::schema schema(record, trace_context.schema_locator);
|
||||
* GUID guid = krabs::provider_id(schema);
|
||||
* }
|
||||
* </example>
|
||||
*/
|
||||
GUID provider_id() const;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Returns the provider name of an event via its schema.
|
||||
* </summary>
|
||||
* <example>
|
||||
* void on_event(const EVENT_RECORD &record, const krabs::trace_context &trace_context)
|
||||
* {
|
||||
* krabs::schema schema(record, trace_context.schema_locator);
|
||||
* std::wstring name = krabs::provider_name(schema);
|
||||
* }
|
||||
* </example>
|
||||
*/
|
||||
const wchar_t *provider_name() const;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Returns the PID associated with the event via its schema.
|
||||
* </summary>
|
||||
* <example>
|
||||
* void on_event(const EVENT_RECORD &record, const krabs::trace_context &trace_context)
|
||||
* {
|
||||
* krabs::schema schema(record, trace_context.schema_locator);
|
||||
* unsigned int name = krabs::process_id(schema);
|
||||
* }
|
||||
* </example>
|
||||
*/
|
||||
unsigned int process_id() const;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Returns the Thread ID associated with the event via its schema.
|
||||
* </summary>
|
||||
* <example>
|
||||
* void on_event(const EVENT_RECORD &record, const krabs::trace_context &trace_context)
|
||||
* {
|
||||
* krabs::schema schema(record, trace_context.schema_locator);
|
||||
* unsigned int name = krabs::thread_id(schema);
|
||||
* }
|
||||
* </example>
|
||||
*/
|
||||
unsigned int thread_id() const;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Returns the timestamp associated with the event via its schema.
|
||||
* </summary>
|
||||
* <example>
|
||||
* void on_event(const EVENT_RECORD &record, const krabs::trace_context &trace_context)
|
||||
* {
|
||||
* krabs::schema schema(record, trace_context.schema_locator);
|
||||
* LARGE_INTEGER time = krabs::timestamp(schema);
|
||||
* }
|
||||
* </example>
|
||||
*/
|
||||
LARGE_INTEGER timestamp() const;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Returns the Activity ID associated with the event via its schema.
|
||||
* </summary>
|
||||
* <example>
|
||||
* void on_event(const EVENT_RECORD &record, const krabs::trace_context &trace_context)
|
||||
* {
|
||||
* krabs::schema schema(record, trace_context.schema_locator);
|
||||
* GUID activity_id = krabs::activity_id(schema);
|
||||
* }
|
||||
* </example>
|
||||
*/
|
||||
GUID activity_id() const;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Retrieves the call stack associated with the record, if enabled.
|
||||
* </summary>
|
||||
* <example>
|
||||
* void on_event(const EVENT_RECORD &record, const krabs::trace_context &trace_context)
|
||||
* {
|
||||
* krabs::schema schema(record, trace_context.schema_locator);
|
||||
* std::vector<ULONG64> stack_trace = schema.stack_trace();
|
||||
* }
|
||||
* </example>
|
||||
*/
|
||||
std::vector<ULONG64> stack_trace() const;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Retrieves the process start key from the extended data, if enabled.
|
||||
* The process start key is a ULONG64 that uniquely identifies a process
|
||||
* instance across the lifetime of a boot session (unlike PID which can
|
||||
* be recycled). Requires EVENT_ENABLE_PROPERTY_PROCESS_START_KEY.
|
||||
* Returns 0 if the extended data item is not present.
|
||||
* </summary>
|
||||
* <example>
|
||||
* void on_event(const EVENT_RECORD &record, const krabs::trace_context &trace_context)
|
||||
* {
|
||||
* krabs::schema schema(record, trace_context.schema_locator);
|
||||
* ULONG64 psk = schema.process_start_key();
|
||||
* }
|
||||
* </example>
|
||||
*/
|
||||
ULONG64 process_start_key() const;
|
||||
|
||||
private:
|
||||
const EVENT_RECORD &record_;
|
||||
const TRACE_EVENT_INFO *pSchema_;
|
||||
|
||||
private:
|
||||
friend std::wstring event_name(const schema &);
|
||||
friend std::wstring opcode_name(const schema &);
|
||||
friend std::wstring task_name(const schema &);
|
||||
friend DECODING_SOURCE decoding_source(const schema &);
|
||||
friend std::wstring provider_name(const schema &);
|
||||
friend unsigned int process_id(const schema &);
|
||||
friend LARGE_INTEGER timestamp(const schema &);
|
||||
friend GUID activity_id(const schema&);
|
||||
friend int event_id(const EVENT_RECORD &);
|
||||
friend int event_id(const schema &);
|
||||
friend std::vector<ULONG64> stack_trace(const schema&);
|
||||
friend std::vector<ULONG64> stack_trace(const EVENT_RECORD&);
|
||||
friend ULONG64 process_start_key(const schema&);
|
||||
friend ULONG64 process_start_key(const EVENT_RECORD&);
|
||||
|
||||
friend class parser;
|
||||
friend class property_iterator;
|
||||
friend class record_builder;
|
||||
};
|
||||
|
||||
|
||||
// Implementation
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
inline schema::schema(const EVENT_RECORD &record, const krabs::schema_locator &schema_locator)
|
||||
: record_(record)
|
||||
, pSchema_(schema_locator.get_event_schema(record))
|
||||
{ }
|
||||
|
||||
inline schema::schema(const EVENT_RECORD &record, const PTRACE_EVENT_INFO pSchema)
|
||||
: record_(record)
|
||||
, pSchema_(pSchema)
|
||||
{ }
|
||||
|
||||
inline bool schema::operator==(const schema &other) const
|
||||
{
|
||||
return (pSchema_->ProviderGuid == other.pSchema_->ProviderGuid &&
|
||||
pSchema_->EventDescriptor.Id == other.pSchema_->EventDescriptor.Id &&
|
||||
pSchema_->EventDescriptor.Version == other.pSchema_->EventDescriptor.Version);
|
||||
}
|
||||
|
||||
inline bool schema::operator!=(const schema &other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
inline const wchar_t *schema::event_name() const
|
||||
{
|
||||
/*
|
||||
EventNameOffset will be 0 if the event does not have an assigned name or
|
||||
if this event is decoded on a system that does not support decoding
|
||||
manifest event names. Event name decoding is supported on Windows
|
||||
10 Fall Creators Update (2017) and later.
|
||||
*/
|
||||
if (pSchema_->EventNameOffset != 0) {
|
||||
return reinterpret_cast<const wchar_t*>(
|
||||
reinterpret_cast<const char*>(pSchema_) +
|
||||
pSchema_->EventNameOffset);
|
||||
}
|
||||
else {
|
||||
return L"";
|
||||
}
|
||||
}
|
||||
|
||||
inline const wchar_t* schema::opcode_name() const
|
||||
{
|
||||
/*
|
||||
In WPP Traces OpcodeName is not used
|
||||
*/
|
||||
if (pSchema_->OpcodeNameOffset != 0) {
|
||||
return reinterpret_cast<const wchar_t*>(
|
||||
reinterpret_cast<const char*>(pSchema_) +
|
||||
pSchema_->OpcodeNameOffset);
|
||||
}
|
||||
else {
|
||||
return L"";
|
||||
}
|
||||
}
|
||||
|
||||
inline const wchar_t *schema::task_name() const
|
||||
{
|
||||
if (pSchema_->TaskNameOffset != 0) {
|
||||
return reinterpret_cast<const wchar_t*>(
|
||||
reinterpret_cast<const char*>(pSchema_) +
|
||||
pSchema_->TaskNameOffset);
|
||||
}
|
||||
else {
|
||||
return L"";
|
||||
}
|
||||
}
|
||||
|
||||
inline DECODING_SOURCE schema::decoding_source() const
|
||||
{
|
||||
return pSchema_->DecodingSource;
|
||||
}
|
||||
|
||||
inline int schema::event_id() const
|
||||
{
|
||||
return record_.EventHeader.EventDescriptor.Id;
|
||||
}
|
||||
|
||||
inline int schema::event_opcode() const
|
||||
{
|
||||
return record_.EventHeader.EventDescriptor.Opcode;
|
||||
}
|
||||
|
||||
inline unsigned int schema::event_version() const
|
||||
{
|
||||
return record_.EventHeader.EventDescriptor.Version;
|
||||
}
|
||||
|
||||
inline unsigned int schema::event_flags() const
|
||||
{
|
||||
return record_.EventHeader.Flags;
|
||||
}
|
||||
|
||||
inline GUID schema::provider_id() const
|
||||
{
|
||||
return record_.EventHeader.ProviderId;
|
||||
}
|
||||
|
||||
inline const wchar_t *schema::provider_name() const
|
||||
{
|
||||
return reinterpret_cast<const wchar_t*>(
|
||||
reinterpret_cast<const char*>(pSchema_) +
|
||||
pSchema_->ProviderNameOffset);
|
||||
}
|
||||
|
||||
inline unsigned int schema::process_id() const
|
||||
{
|
||||
return record_.EventHeader.ProcessId;
|
||||
}
|
||||
|
||||
inline unsigned int schema::thread_id() const
|
||||
{
|
||||
return record_.EventHeader.ThreadId;
|
||||
}
|
||||
|
||||
inline LARGE_INTEGER schema::timestamp() const
|
||||
{
|
||||
return record_.EventHeader.TimeStamp;
|
||||
}
|
||||
|
||||
inline GUID schema::activity_id() const
|
||||
{
|
||||
return record_.EventHeader.ActivityId;
|
||||
}
|
||||
|
||||
inline std::vector<ULONG64> schema::stack_trace() const
|
||||
{
|
||||
std::vector<ULONG64> call_stack;
|
||||
if (record_.ExtendedDataCount != 0) {
|
||||
for (USHORT i = 0; i < record_.ExtendedDataCount; i++)
|
||||
{
|
||||
auto item = record_.ExtendedData[i];
|
||||
if (item.ExtType == EVENT_HEADER_EXT_TYPE_STACK_TRACE64) {
|
||||
auto stacktrace = reinterpret_cast<PEVENT_EXTENDED_ITEM_STACK_TRACE64>(item.DataPtr);
|
||||
auto stack_length = (item.DataSize - sizeof(ULONG64)) / sizeof(ULONG64);
|
||||
for (size_t j = 0; j < stack_length; j++)
|
||||
{
|
||||
call_stack.push_back(stacktrace->Address[j]);
|
||||
}
|
||||
}
|
||||
else if (item.ExtType == EVENT_HEADER_EXT_TYPE_STACK_TRACE32) {
|
||||
auto stacktrace = reinterpret_cast<PEVENT_EXTENDED_ITEM_STACK_TRACE32>(item.DataPtr);
|
||||
auto stack_length = (item.DataSize - sizeof(ULONG64)) / sizeof(ULONG);
|
||||
for (size_t j = 0; j < stack_length; j++)
|
||||
{
|
||||
call_stack.push_back(stacktrace->Address[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return call_stack;
|
||||
}
|
||||
|
||||
inline ULONG64 schema::process_start_key() const
|
||||
{
|
||||
for (USHORT i = 0; i < record_.ExtendedDataCount; i++)
|
||||
{
|
||||
auto& item = record_.ExtendedData[i];
|
||||
if (item.ExtType == EVENT_HEADER_EXT_TYPE_PROCESS_START_KEY)
|
||||
{
|
||||
if (item.DataPtr != 0)
|
||||
return *reinterpret_cast<const ULONG64*>(item.DataPtr);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
+368
@@ -0,0 +1,368 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#define INITGUID
|
||||
|
||||
#include <windows.h>
|
||||
#include <tdh.h>
|
||||
#include <evntrace.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <variant>
|
||||
#include <cassert>
|
||||
|
||||
#include "compiler_check.hpp"
|
||||
#include "errors.hpp"
|
||||
#include "guid.hpp"
|
||||
|
||||
#pragma comment(lib, "tdh.lib")
|
||||
|
||||
namespace krabs {
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Type used as the key for cache lookup in a schema_locator.
|
||||
* </summary>
|
||||
*/
|
||||
struct schema_key
|
||||
{
|
||||
guid provider;
|
||||
|
||||
/**
|
||||
* Using a string_view for name so that keys can be constructed from
|
||||
* EVENT_RECORD pointers without allocation. If the key instance is
|
||||
* added to the cache, 'internalize_name' must be called first so that
|
||||
* the name points to owned memory and doesn't dangle.
|
||||
* Only events logged with the TraceLogger API will have a name set
|
||||
* in the key because it's available as part of the EVENT_RECORD.
|
||||
* Other events are uniquely distinguished by their event Id.
|
||||
*/
|
||||
std::string_view name;
|
||||
|
||||
uint16_t id;
|
||||
uint8_t version;
|
||||
uint8_t opcode;
|
||||
uint8_t level;
|
||||
uint64_t keyword;
|
||||
|
||||
private:
|
||||
/**
|
||||
* See note on 'name', this is only set when internalized and
|
||||
* provides memory ownership for the string_view.
|
||||
*/
|
||||
std::unique_ptr<std::string> backing_name;
|
||||
|
||||
public:
|
||||
schema_key(const EVENT_RECORD &record, std::string_view name)
|
||||
: provider(record.EventHeader.ProviderId)
|
||||
, name(name)
|
||||
, id(record.EventHeader.EventDescriptor.Id)
|
||||
, version(record.EventHeader.EventDescriptor.Version)
|
||||
, opcode(record.EventHeader.EventDescriptor.Opcode)
|
||||
, level(record.EventHeader.EventDescriptor.Level)
|
||||
, keyword(record.EventHeader.EventDescriptor.Keyword) { }
|
||||
|
||||
schema_key(const schema_key &rhs)
|
||||
: provider(rhs.provider)
|
||||
, name(rhs.name)
|
||||
, id(rhs.id)
|
||||
, version(rhs.version)
|
||||
, opcode(rhs.opcode)
|
||||
, level(rhs.level)
|
||||
, keyword(rhs.keyword)
|
||||
{
|
||||
internalize_name();
|
||||
}
|
||||
|
||||
schema_key& operator=(const schema_key &rhs)
|
||||
{
|
||||
schema_key temp(rhs);
|
||||
std::swap(*this, temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const schema_key &rhs) const
|
||||
{
|
||||
// NB: Compare 'name' last for perf. Do not compare 'backing_name'.
|
||||
return provider == rhs.provider &&
|
||||
id == rhs.id &&
|
||||
version == rhs.version &&
|
||||
opcode == rhs.opcode &&
|
||||
level == rhs.level &&
|
||||
keyword == rhs.keyword &&
|
||||
name == rhs.name;
|
||||
}
|
||||
|
||||
bool operator!=(const schema_key &rhs) const { return !(*this == rhs); }
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Allocate the 'backing_name' and set 'name' to point at it. This must be
|
||||
* called before adding the key to a cache so that the lifetime of the
|
||||
* 'name' string_view matches the lifetime of the cached instance.
|
||||
* </summary>
|
||||
*/
|
||||
void internalize_name()
|
||||
{
|
||||
if (!name.empty()) {
|
||||
backing_name = std::make_unique<std::string>(name);
|
||||
name = *backing_name;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace std {
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Builds a hash code for a schema_key
|
||||
* </summary>
|
||||
*/
|
||||
template<>
|
||||
struct std::hash<krabs::schema_key>
|
||||
{
|
||||
size_t operator()(const krabs::schema_key &key) const
|
||||
{
|
||||
// Shift-Add-XOR hash - good enough for the small sets we deal with
|
||||
size_t h = 2166136261;
|
||||
|
||||
h ^= (h << 5) + (h >> 2) + std::hash<krabs::guid>()(key.provider);
|
||||
h ^= (h << 5) + (h >> 2) + std::hash<std::string_view>()(key.name);
|
||||
h ^= (h << 5) + (h >> 2) + key.id;
|
||||
h ^= (h << 5) + (h >> 2) + key.version;
|
||||
h ^= (h << 5) + (h >> 2) + key.opcode;
|
||||
h ^= (h << 5) + (h >> 2) + key.level;
|
||||
h ^= (h << 5) + (h >> 2) + key.keyword;
|
||||
|
||||
return h;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace krabs {
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Get event schema from TDH.
|
||||
* </summary>
|
||||
*/
|
||||
std::unique_ptr<char[]> get_event_schema_from_tdh(const EVENT_RECORD &);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Get event schema from TDH without throwing exceptions.
|
||||
* If the schema is not found, the function returns an empty unique_ptr and sets the status.
|
||||
* </summary>
|
||||
*/
|
||||
std::unique_ptr<char[]> get_event_schema_from_tdh_no_throw(const EVENT_RECORD&, TDHSTATUS&);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Returns a string_view to the event name if the specified event was logged
|
||||
* with the TraceLogger API otherwise returns an empty string_view.
|
||||
* </summary>
|
||||
*/
|
||||
std::string_view get_trace_logger_event_name(const EVENT_RECORD &);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Fetches and caches schemas from TDH.
|
||||
* NOTE: this cache also reduces the number of managed to native transitions
|
||||
* when krabs is compiled into a managed assembly.
|
||||
* </summary>
|
||||
*/
|
||||
class schema_locator {
|
||||
public:
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Retrieves the event schema from the cache or falls back to
|
||||
* TDH to load the schema.
|
||||
* </summary>
|
||||
*/
|
||||
const PTRACE_EVENT_INFO get_event_schema(const EVENT_RECORD &record) const;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Retrieves the event schema from the cache or falls back to
|
||||
* TDH to load the schema without throwing exceptions.
|
||||
* If the schema is not found, the function returns nullptr and sets the status.
|
||||
* </summary>
|
||||
*/
|
||||
const PTRACE_EVENT_INFO get_event_schema_no_throw(const EVENT_RECORD& record, TDHSTATUS& status) const;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Returns true if the event schema can be found in the cache or TDH.
|
||||
* </summary>
|
||||
*/
|
||||
bool has_event_schema(const EVENT_RECORD& record) const;
|
||||
|
||||
private:
|
||||
mutable std::unordered_map<schema_key, std::variant<std::unique_ptr<char[]>, TDHSTATUS>> cache_;
|
||||
};
|
||||
|
||||
// Implementation
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
inline std::string_view get_trace_logger_event_name(const EVENT_RECORD & record)
|
||||
{
|
||||
/**
|
||||
* This implements part of the parsing that TDH would normally do so that
|
||||
* a schema_key can be built without calling TDH (which is expensive).
|
||||
* Here's pseudo code from the TraceLogger header describing the layout.
|
||||
*
|
||||
* // EventMetadata:
|
||||
* // This pseudo-structure is the layout of the "event metadata" referenced by
|
||||
* // EVENT_DATA_DESCRIPTOR_TYPE_EVENT_METADATA.
|
||||
* // It provides the event's name, event tags, and field information.
|
||||
* struct EventMetadata // Variable-length pseudo-structure, byte-aligned, tightly-packed.
|
||||
* {
|
||||
* UINT16 Size; // = sizeof(EventMetadata)
|
||||
* UINT8 Extension[]; // 1 or more bytes. Read until you hit a byte with high bit unset.
|
||||
* char Name[]; // UTF-8 nul-terminated event name
|
||||
* FieldMetadata Fields[]; // 0 or more field definitions.
|
||||
* };
|
||||
*/
|
||||
|
||||
char* metadataPtr = nullptr;
|
||||
USHORT metadataSize = 0;
|
||||
|
||||
// Look for a TraceLogger event schema in the extended data.
|
||||
for (USHORT i = 0; i < record.ExtendedDataCount; ++i) {
|
||||
auto& dataItem = record.ExtendedData[i];
|
||||
if (dataItem.ExtType == EVENT_HEADER_EXT_TYPE_EVENT_SCHEMA_TL) {
|
||||
metadataSize = dataItem.DataSize;
|
||||
metadataPtr = (char*)dataItem.DataPtr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Didn't find one or it was too small.
|
||||
if (metadataPtr == nullptr || metadataSize < sizeof(USHORT)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Ensure that the sizes match to prevent reading off the buffer.
|
||||
USHORT structSize = *(USHORT*)metadataPtr;
|
||||
if (structSize != metadataSize) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Skipping over the 'Extension' field of the block to find the name offset.
|
||||
// Per code comment: Read until you hit a byte with high bit unset.
|
||||
USHORT nameOffset = sizeof(USHORT);
|
||||
while (nameOffset < structSize) {
|
||||
char c = *(metadataPtr + nameOffset);
|
||||
nameOffset++; // NB: always consume the character.
|
||||
|
||||
// High-bit set?
|
||||
if ((c & 0x80) != 0x80) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the offset found is valid.
|
||||
if (nameOffset >= structSize) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return {metadataPtr + nameOffset};
|
||||
}
|
||||
|
||||
inline const PTRACE_EVENT_INFO schema_locator::get_event_schema(const EVENT_RECORD &record) const
|
||||
{
|
||||
TDHSTATUS status = ERROR_SUCCESS;
|
||||
auto buffer = get_event_schema_no_throw(record, status);
|
||||
error_check_common_conditions(status, record);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
inline const PTRACE_EVENT_INFO schema_locator::get_event_schema_no_throw(const EVENT_RECORD& record, TDHSTATUS& status) const
|
||||
{
|
||||
status = ERROR_SUCCESS;
|
||||
|
||||
auto eventName = get_trace_logger_event_name(record);
|
||||
auto key = schema_key(record, eventName);
|
||||
|
||||
// Check the cache...
|
||||
auto it = cache_.find(key);
|
||||
if (it != cache_.end()) {
|
||||
auto& value = it->second;
|
||||
if (std::holds_alternative<TDHSTATUS>(value)) {
|
||||
status = std::get<TDHSTATUS>(value);
|
||||
return nullptr;
|
||||
}
|
||||
return (PTRACE_EVENT_INFO)std::get<std::unique_ptr<char[]>>(value).get();
|
||||
}
|
||||
|
||||
// Cache miss. Fetch the schema...
|
||||
auto buffer = get_event_schema_from_tdh_no_throw(record, status);
|
||||
auto returnVal = (PTRACE_EVENT_INFO)buffer.get();
|
||||
|
||||
// Add the new instance to the cache.
|
||||
// NB: key's 'internalize_name' gets called by the cctor here.
|
||||
if (status == ERROR_SUCCESS)
|
||||
cache_.emplace(key, std::move(buffer));
|
||||
else
|
||||
cache_.emplace(key, status);
|
||||
|
||||
return returnVal;
|
||||
}
|
||||
|
||||
inline bool schema_locator::has_event_schema(const EVENT_RECORD& record) const
|
||||
{
|
||||
TDHSTATUS status = ERROR_SUCCESS;
|
||||
get_event_schema_no_throw(record, status);
|
||||
return status == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
inline std::unique_ptr<char[]> get_event_schema_from_tdh(const EVENT_RECORD &record)
|
||||
{
|
||||
TDHSTATUS status = ERROR_SUCCESS;
|
||||
auto buffer = get_event_schema_from_tdh_no_throw(record, status);
|
||||
error_check_common_conditions(status, record);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
inline std::unique_ptr<char[]> get_event_schema_from_tdh_no_throw(const EVENT_RECORD& record, TDHSTATUS& status)
|
||||
{
|
||||
// get required size
|
||||
ULONG bufferSize = 0;
|
||||
status = TdhGetEventInformation(
|
||||
(PEVENT_RECORD)&record,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
&bufferSize);
|
||||
|
||||
if (status != ERROR_INSUFFICIENT_BUFFER) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// allocate and fill the schema from TDH
|
||||
auto buffer = std::unique_ptr<char[]>(new char[bufferSize]);
|
||||
|
||||
status = TdhGetEventInformation(
|
||||
(PEVENT_RECORD)&record,
|
||||
0,
|
||||
NULL,
|
||||
(PTRACE_EVENT_INFO)buffer.get(),
|
||||
&bufferSize);
|
||||
|
||||
if (status != ERROR_SUCCESS) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <tdh.h>
|
||||
#include <evntrace.h>
|
||||
|
||||
#include "compiler_check.hpp"
|
||||
|
||||
namespace krabs {
|
||||
|
||||
// TODO: I don't like this interface - it's too tightly
|
||||
// coupled to parser.hpp mainly because the code was
|
||||
// lifted directly out of parser::find_property.
|
||||
|
||||
class size_provider {
|
||||
public:
|
||||
/**
|
||||
* <summary>
|
||||
* Get the size of the specified property from the specified record.
|
||||
* </summary>
|
||||
* BYTE* offset into the user data buffer where the property starts
|
||||
* wchar_t* name of the property to query
|
||||
* EVENT_RECORD& record to query
|
||||
* EVENT_PROPERTY_INFO& property info for the property to query
|
||||
*/
|
||||
static ULONG get_property_size(
|
||||
const BYTE*,
|
||||
const wchar_t*,
|
||||
const EVENT_RECORD&,
|
||||
const EVENT_PROPERTY_INFO&);
|
||||
|
||||
private:
|
||||
static ULONG get_heuristic_size(
|
||||
const BYTE*,
|
||||
const EVENT_PROPERTY_INFO&,
|
||||
const EVENT_RECORD&);
|
||||
|
||||
static ULONG get_tdh_size(
|
||||
const wchar_t*,
|
||||
const EVENT_RECORD&);
|
||||
};
|
||||
|
||||
// Implementation
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
inline ULONG size_provider::get_property_size(
|
||||
const BYTE* propertyStart,
|
||||
const wchar_t* propertyName,
|
||||
const EVENT_RECORD& record,
|
||||
const EVENT_PROPERTY_INFO& propertyInfo)
|
||||
{
|
||||
// The values of the event are essentially stored as an ad-hoc
|
||||
// variant. In order to determine how far we need to advance the
|
||||
// seeking pointer, we need to know the size of the property that
|
||||
// we've just looked at. For certain variable-sized types (like a
|
||||
// string), we need to ask Tdh* to determine the length of the
|
||||
// property. For others, the size is immediately accessible in
|
||||
// the schema structure.
|
||||
|
||||
if ((propertyInfo.Flags & PropertyParamLength) == 0 &&
|
||||
propertyInfo.length > 0)
|
||||
{
|
||||
// length is a union that may refer to another field for a length
|
||||
// value. In that case, defer to TDH for the value otherwise
|
||||
// use the length value directly.
|
||||
|
||||
// For pointers check header instead of size, see PointerSize at
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/tdh/nf-tdh-tdhformatproperty
|
||||
// for details
|
||||
if (propertyInfo.nonStructType.InType == TDH_INTYPE_POINTER)
|
||||
{
|
||||
return record.EventHeader.Flags & EVENT_HEADER_FLAG_32_BIT_HEADER ? 4 : 8;
|
||||
}
|
||||
|
||||
return propertyInfo.length;
|
||||
}
|
||||
|
||||
ULONG propertyLength = 0;
|
||||
|
||||
// If no flags are set on the property, attempt to use the length
|
||||
// field. If that field is 0, try using our heuristic.
|
||||
if (propertyInfo.Flags == 0)
|
||||
{
|
||||
if (propertyInfo.length > 0)
|
||||
propertyLength = propertyInfo.length;
|
||||
else
|
||||
propertyLength = get_heuristic_size(propertyStart, propertyInfo, record);
|
||||
}
|
||||
|
||||
// Couldn't get the length from the 'length' field or
|
||||
// the heuristic for size failed -> ask Tdh.
|
||||
if (propertyLength == 0)
|
||||
propertyLength = get_tdh_size(propertyName, record);
|
||||
|
||||
return propertyLength;
|
||||
}
|
||||
|
||||
inline ULONG size_provider::get_heuristic_size(
|
||||
const BYTE* propertyStart,
|
||||
const EVENT_PROPERTY_INFO& propertyInfo,
|
||||
const EVENT_RECORD& record)
|
||||
{
|
||||
ULONG propertyLength = 0;
|
||||
PBYTE pRecordEnd = (PBYTE)record.UserData + record.UserDataLength;
|
||||
|
||||
// The calls to Tdh are kind of expensive, especially when krabs is
|
||||
// included in a managed assembly as this call will be a thunk.
|
||||
// The following _very_ common property types can be short-circuited
|
||||
// to prevent the expensive call.
|
||||
|
||||
// Be careful! Check IN and OUT types before making an assumption.
|
||||
|
||||
// Strings that appear at the end of a record may not be null-terminated.
|
||||
// If a string is null-terminated, propertyLength includes the null character.
|
||||
// If a string is not-null terminated, propertyLength includes all bytes up
|
||||
// to the end of the record buffer.
|
||||
|
||||
if (propertyInfo.nonStructType.OutType == TDH_OUTTYPE_STRING)
|
||||
{
|
||||
if (propertyInfo.nonStructType.InType == TDH_INTYPE_UNICODESTRING)
|
||||
{
|
||||
auto p = (const wchar_t*)propertyStart;
|
||||
auto pEnd = (const wchar_t*)pRecordEnd;
|
||||
while (p < pEnd) {
|
||||
if (!*p++) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
propertyLength = static_cast<ULONG>(((PBYTE)p) - propertyStart);
|
||||
}
|
||||
else if (propertyInfo.nonStructType.InType == TDH_INTYPE_ANSISTRING)
|
||||
{
|
||||
auto p = (const char*)propertyStart;
|
||||
auto pEnd = (const char*)pRecordEnd;
|
||||
while (p < pEnd) {
|
||||
if (!*p++) {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
propertyLength = static_cast<ULONG>(((PBYTE)p) - propertyStart);
|
||||
}
|
||||
}
|
||||
|
||||
return propertyLength;
|
||||
}
|
||||
|
||||
inline ULONG size_provider::get_tdh_size(
|
||||
const wchar_t* propertyName,
|
||||
const EVENT_RECORD& record)
|
||||
{
|
||||
ULONG propertyLength = 0;
|
||||
|
||||
PROPERTY_DATA_DESCRIPTOR desc;
|
||||
desc.PropertyName = (ULONGLONG)propertyName;
|
||||
desc.ArrayIndex = ULONG_MAX;
|
||||
|
||||
TdhGetPropertySize((PEVENT_RECORD)&record, 0, NULL, 1, &desc, &propertyLength);
|
||||
|
||||
return propertyLength;
|
||||
}
|
||||
}
|
||||
+226
@@ -0,0 +1,226 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#define INITGUID
|
||||
|
||||
#include <tdh.h>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "compiler_check.hpp"
|
||||
#include "parse_types.hpp"
|
||||
|
||||
namespace krabs {
|
||||
|
||||
#define CASE_TYPE(enum) case TDH_INTYPE_##enum: return #enum
|
||||
|
||||
inline const char* in_type_to_string(_TDH_IN_TYPE type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
CASE_TYPE(NULL);
|
||||
CASE_TYPE(UNICODESTRING);
|
||||
CASE_TYPE(ANSISTRING);
|
||||
CASE_TYPE(INT8);
|
||||
CASE_TYPE(UINT8);
|
||||
CASE_TYPE(INT16);
|
||||
CASE_TYPE(UINT16);
|
||||
CASE_TYPE(INT32);
|
||||
CASE_TYPE(UINT32);
|
||||
CASE_TYPE(INT64);
|
||||
CASE_TYPE(UINT64);
|
||||
CASE_TYPE(FLOAT);
|
||||
CASE_TYPE(DOUBLE);
|
||||
CASE_TYPE(BOOLEAN);
|
||||
CASE_TYPE(BINARY);
|
||||
CASE_TYPE(GUID);
|
||||
CASE_TYPE(POINTER);
|
||||
CASE_TYPE(FILETIME);
|
||||
CASE_TYPE(SYSTEMTIME);
|
||||
CASE_TYPE(SID);
|
||||
CASE_TYPE(HEXINT32);
|
||||
CASE_TYPE(HEXINT64);
|
||||
CASE_TYPE(COUNTEDSTRING);
|
||||
CASE_TYPE(COUNTEDANSISTRING);
|
||||
CASE_TYPE(REVERSEDCOUNTEDSTRING);
|
||||
CASE_TYPE(REVERSEDCOUNTEDANSISTRING);
|
||||
CASE_TYPE(NONNULLTERMINATEDSTRING);
|
||||
CASE_TYPE(NONNULLTERMINATEDANSISTRING);
|
||||
CASE_TYPE(UNICODECHAR);
|
||||
CASE_TYPE(ANSICHAR);
|
||||
CASE_TYPE(SIZET);
|
||||
CASE_TYPE(HEXDUMP);
|
||||
CASE_TYPE(WBEMSID);
|
||||
default: return "<INVALID VALUE>";
|
||||
}
|
||||
}
|
||||
|
||||
#undef CASE_TYPE
|
||||
|
||||
namespace debug {
|
||||
|
||||
// this function provides a user-friendly compiler error
|
||||
// which shows the type in question in the error message.
|
||||
template <typename T>
|
||||
inline void missing_assert_specialization_for()
|
||||
{
|
||||
static_assert(sizeof(T) == 0, __FUNCSIG__);
|
||||
}
|
||||
|
||||
// The "catch-all" implementation of assert_valid_assignment just
|
||||
// throws in debug to let us know that we are trying to parse a
|
||||
// type that does not have any assignment validation. This compiles
|
||||
// to a no-op in release.
|
||||
template <typename T>
|
||||
inline void assert_valid_assignment(std::wstring_view, const property_info&)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
|
||||
// NOTE: if you want compile time assignment assertion define TYPEASSERT
|
||||
// in the preprocessor or undefine it to disable compilation errors
|
||||
|
||||
#ifdef TYPEASSERT
|
||||
missing_assert_specialization_for<T>();
|
||||
#endif // TYPEASSERT
|
||||
#endif // NDEBUG
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
// These specializations will be removed in release builds and compilation
|
||||
// will fall back to the unspecialized version which is a no-op in release.
|
||||
|
||||
inline void throw_if_invalid(
|
||||
std::wstring_view name,
|
||||
const property_info& info,
|
||||
_TDH_IN_TYPE requested)
|
||||
{
|
||||
auto actual = (_TDH_IN_TYPE)info.pEventPropertyInfo_->nonStructType.InType;
|
||||
|
||||
if (requested == actual) return;
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4244) // narrowing property name wchar_t to char for this error message
|
||||
std::string ansiName(name.begin(), name.end());
|
||||
#pragma warning(pop)
|
||||
|
||||
throw type_mismatch_assert(
|
||||
ansiName.c_str(),
|
||||
in_type_to_string(actual),
|
||||
in_type_to_string(requested));
|
||||
}
|
||||
|
||||
// The macro below generates a specialized version of assert_valid_assignment
|
||||
// only in debug builds. The specialized overload will be selected instead
|
||||
// of the unspecialized version defined above. This allows us to have
|
||||
// type-driven assertions only in debug builds.
|
||||
|
||||
#define BUILD_ASSERT(type, tdh_type) \
|
||||
template <> \
|
||||
inline void assert_valid_assignment<type>( \
|
||||
std::wstring_view name, const property_info& info) \
|
||||
{ \
|
||||
throw_if_invalid(name, info, tdh_type); \
|
||||
}
|
||||
|
||||
// NOTE: don't just blindly add assertions here, some types
|
||||
// that seem trivial (e.g. bool) are not because of differences
|
||||
// between the representation in C++ and the representation in ETW.
|
||||
// Ensure that type sizes match and that the ETW form isn't
|
||||
// a variant or variable length. A type that requires a specialized
|
||||
// assertion will also require a specialized parser.
|
||||
|
||||
// strings
|
||||
BUILD_ASSERT(std::wstring, TDH_INTYPE_UNICODESTRING);
|
||||
BUILD_ASSERT(std::string, TDH_INTYPE_ANSISTRING);
|
||||
BUILD_ASSERT(const counted_string*, TDH_INTYPE_COUNTEDSTRING);
|
||||
|
||||
// integers
|
||||
BUILD_ASSERT(int8_t, TDH_INTYPE_INT8);
|
||||
BUILD_ASSERT(uint8_t, TDH_INTYPE_UINT8);
|
||||
BUILD_ASSERT(int16_t, TDH_INTYPE_INT16);
|
||||
BUILD_ASSERT(uint16_t, TDH_INTYPE_UINT16);
|
||||
BUILD_ASSERT(int32_t, TDH_INTYPE_INT32);
|
||||
BUILD_ASSERT(uint32_t, TDH_INTYPE_UINT32);
|
||||
BUILD_ASSERT(int64_t, TDH_INTYPE_INT64);
|
||||
BUILD_ASSERT(uint64_t, TDH_INTYPE_UINT64);
|
||||
|
||||
// floating
|
||||
BUILD_ASSERT(float, TDH_INTYPE_FLOAT);
|
||||
BUILD_ASSERT(double, TDH_INTYPE_DOUBLE);
|
||||
|
||||
// FILETIME
|
||||
BUILD_ASSERT(::FILETIME, TDH_INTYPE_FILETIME);
|
||||
BUILD_ASSERT(::SYSTEMTIME, TDH_INTYPE_SYSTEMTIME);
|
||||
|
||||
#undef BUILD_ASSERT
|
||||
|
||||
template <>
|
||||
inline void assert_valid_assignment<ip_address>(
|
||||
std::wstring_view, const property_info& info)
|
||||
{
|
||||
auto outType = info.pEventPropertyInfo_->nonStructType.OutType;
|
||||
|
||||
if (outType != TDH_OUTTYPE_IPV6 &&
|
||||
outType != TDH_OUTTYPE_IPV4) {
|
||||
throw std::runtime_error(
|
||||
"Requested an IP address from non-IP address property");
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void assert_valid_assignment<socket_address>(
|
||||
std::wstring_view, const property_info& info)
|
||||
{
|
||||
auto outType = info.pEventPropertyInfo_->nonStructType.OutType;
|
||||
|
||||
if (outType != TDH_OUTTYPE_SOCKETADDRESS) {
|
||||
throw std::runtime_error(
|
||||
"Requested a socket address from property that does not contain a socket address");
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void assert_valid_assignment<sid>(
|
||||
std::wstring_view, const property_info& info)
|
||||
{
|
||||
auto inType = info.pEventPropertyInfo_->nonStructType.InType;
|
||||
|
||||
if (inType != TDH_INTYPE_WBEMSID && inType != TDH_INTYPE_SID) {
|
||||
throw std::runtime_error(
|
||||
"Requested a SID but was neither a SID nor WBEMSID");
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void assert_valid_assignment<pointer>(
|
||||
std::wstring_view, const property_info& info)
|
||||
{
|
||||
auto inType = info.pEventPropertyInfo_->nonStructType.InType;
|
||||
|
||||
if (inType != TDH_INTYPE_POINTER) {
|
||||
throw std::runtime_error(
|
||||
"Requested a POINTER from property that is not one");
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void assert_valid_assignment<bool>(
|
||||
std::wstring_view, const property_info& info)
|
||||
{
|
||||
auto inType = info.pEventPropertyInfo_->nonStructType.InType;
|
||||
|
||||
if (inType != TDH_INTYPE_BOOLEAN) {
|
||||
throw std::runtime_error(
|
||||
"Requested a BOOLEAN from property that is not one");
|
||||
}
|
||||
}
|
||||
|
||||
#endif // NDEBUG
|
||||
|
||||
} /* namespace debug */
|
||||
|
||||
} /* namespace krabs */
|
||||
+521
@@ -0,0 +1,521 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <deque>
|
||||
|
||||
#include "compiler_check.hpp"
|
||||
#include "guid.hpp"
|
||||
#include "provider.hpp"
|
||||
#include "trace_context.hpp"
|
||||
#include "etw.hpp"
|
||||
|
||||
|
||||
namespace krabs { namespace details {
|
||||
template <typename T> class trace_manager;
|
||||
} /* namespace details */ } /* namespace krabs */
|
||||
|
||||
namespace krabs { namespace testing {
|
||||
template <typename T> class trace_proxy;
|
||||
} /* namespace testing */ } /* namespace krabs */
|
||||
|
||||
|
||||
namespace krabs {
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Returns the type of the event record.
|
||||
* DecodingSourceXMLFile - The event was emitted by a manifest-based provider.
|
||||
* DecodingSourceWbem - The event was emitted by a MOF-based provider.
|
||||
* DecodingSourceWPP - The event was emitted by a WPP software tracing provider.
|
||||
* DecodingSourceTlg - The event was emitted by a TraceLogging provider.
|
||||
* </summary>
|
||||
*/
|
||||
DECODING_SOURCE get_event_type(const EVENT_RECORD &record);
|
||||
|
||||
template <typename T>
|
||||
class provider;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Selected statistics about an ETW trace
|
||||
* </summary>
|
||||
*/
|
||||
class trace_stats
|
||||
{
|
||||
public:
|
||||
const uint32_t buffersCount;
|
||||
const uint32_t buffersFree;
|
||||
const uint32_t buffersWritten;
|
||||
const uint32_t buffersLost;
|
||||
const uint64_t eventsTotal;
|
||||
const uint64_t eventsHandled;
|
||||
const uint32_t eventsLost;
|
||||
|
||||
trace_stats(uint64_t eventsHandled, const EVENT_TRACE_PROPERTIES& props)
|
||||
: buffersCount(props.NumberOfBuffers)
|
||||
, buffersFree(props.FreeBuffers)
|
||||
, buffersWritten(props.BuffersWritten)
|
||||
, buffersLost(props.RealTimeBuffersLost)
|
||||
, eventsTotal(eventsHandled + props.EventsLost)
|
||||
, eventsHandled(eventsHandled)
|
||||
, eventsLost(props.EventsLost)
|
||||
{ }
|
||||
};
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Represents a single trace session that can have multiple
|
||||
* enabled providers. Ideally, there should only need to be a
|
||||
* single trace instance for all ETW user traces.
|
||||
* </summary>
|
||||
*/
|
||||
template <typename T>
|
||||
class trace {
|
||||
public:
|
||||
|
||||
typedef T trace_type;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Constructs a trace with an optional trace name, which can be
|
||||
* any arbitrary, unique name.
|
||||
* </summary>
|
||||
*
|
||||
* <example>
|
||||
* trace trace;
|
||||
* trace namedTrace(L"Some special name");
|
||||
* </example>
|
||||
*/
|
||||
trace(const std::wstring &name);
|
||||
trace(const wchar_t *name = L"");
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Destructs the trace session and unregisters the session, if
|
||||
* applicable.
|
||||
* </summary>
|
||||
*
|
||||
* <example>
|
||||
* trace trace;
|
||||
* // ~trace implicitly called
|
||||
* </example>
|
||||
*/
|
||||
~trace();
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Sets the trace properties for a session.
|
||||
* Must be called before open()/start().
|
||||
* See https://docs.microsoft.com/en-us/windows/win32/etw/event-trace-properties
|
||||
* for important details and restrictions.
|
||||
* Configurable properties are ->
|
||||
* - BufferSize. In KB. The maximum buffer size is 1024 KB.
|
||||
* - MinimumBuffers. Minimum number of buffers is two per processor*.
|
||||
* - MaximumBuffers.
|
||||
* - FlushTimer. How often, in seconds, the trace buffers are forcibly flushed.
|
||||
* - LogFileMode. EVENT_TRACE_NO_PER_PROCESSOR_BUFFERING simulates a *single* sequential processor.
|
||||
* </summary>
|
||||
* <example>
|
||||
* krabs::trace trace;
|
||||
* EVENT_TRACE_PROPERTIES properties = { 0 };
|
||||
* properties.BufferSize = 256;
|
||||
* properties.MinimumBuffers = 12;
|
||||
* properties.MaximumBuffers = 48;
|
||||
* properties.FlushTimer = 1;
|
||||
* properties.LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
|
||||
* trace.set_trace_properties(&properties);
|
||||
* krabs::guid id(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}");
|
||||
* provider<> powershell(id);
|
||||
* trace.enable(powershell);
|
||||
* trace.start();
|
||||
* </example>
|
||||
*/
|
||||
void set_trace_properties(const PEVENT_TRACE_PROPERTIES properties);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Configures trace session settings.
|
||||
* Must be called after open().
|
||||
* See https://docs.microsoft.com/en-us/windows/win32/api/evntrace/nf-evntrace-tracesetinformation
|
||||
* for more information.
|
||||
* </summary>
|
||||
* <example>
|
||||
* krabs::trace trace;
|
||||
* // Adjust SE_SYSTEM_PROFILE_NAME token privilege through AdjustTokenPrivileges(...)
|
||||
* // to enable stack tracing (not done in this example). Then:
|
||||
* STACK_TRACING_EVENT_ID event_id = {0};
|
||||
* event_id.EventGuid = krabs::guids::perf_info;
|
||||
* event_id.Type = 46; // SampleProfile
|
||||
* trace.open();
|
||||
* trace.set_trace_information(TraceStackTracingInfo, &event_id, sizeof(STACK_TRACING_EVENT_ID));
|
||||
* krabs::kernel_provider stack_walk_provider(EVENT_TRACE_FLAG_PROFILE, krabs::guids::stack_walk);
|
||||
* trace.enable(stack_walk_provider);
|
||||
* trace.process();
|
||||
* </example>
|
||||
*/
|
||||
void set_trace_information(
|
||||
TRACE_INFO_CLASS information_class,
|
||||
PVOID trace_information,
|
||||
ULONG information_length);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Configures trace to read from a file instead of realtime
|
||||
* Must be called before open().
|
||||
* See https://docs.microsoft.com/en-us/windows/win32/api/evntrace/nf-evntrace-tracesetinformation
|
||||
* for more information.
|
||||
* </summary>
|
||||
* <example>
|
||||
* krabs::trace trace;
|
||||
* trace.set_trace_filename(L"C:\merged.etl");
|
||||
* trace.process();
|
||||
* </example>
|
||||
*/
|
||||
void set_trace_filename(const std::wstring& filename);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Enables the provider on the given user trace.
|
||||
* </summary>
|
||||
* <example>
|
||||
* krabs::trace trace;
|
||||
* krabs::guid id(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}");
|
||||
* provider<> powershell(id);
|
||||
* trace.enable(powershell);
|
||||
* </example>
|
||||
*/
|
||||
void enable(const typename T::provider_type &p);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Starts a trace session.
|
||||
* </summary>
|
||||
* <example>
|
||||
* krabs::trace trace;
|
||||
* krabs::guid id(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}");
|
||||
* provider<> powershell(id);
|
||||
* trace.enable(powershell);
|
||||
* trace.start();
|
||||
* </example>
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Closes a trace session.
|
||||
* </summary>
|
||||
* <example>
|
||||
* krabs::trace trace;
|
||||
* krabs::guid id(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}");
|
||||
* provider<> powershell(id);
|
||||
* trace.enable(powershell);
|
||||
* trace.start();
|
||||
* trace.stop();
|
||||
* </example>
|
||||
*/
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Opens a trace session.
|
||||
* This is an optional call before start() if you need the trace
|
||||
* registered with the ETW subsystem before you start processing events.
|
||||
* </summary>
|
||||
* <example>
|
||||
* krabs::trace trace;
|
||||
* krabs::guid id(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}");
|
||||
* provider<> powershell(id);
|
||||
* trace.enable(powershell);
|
||||
* auto logfile = trace.open();
|
||||
* </example>
|
||||
*/
|
||||
EVENT_TRACE_LOGFILE open();
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Start processing events for an already opened session.
|
||||
* </summary>
|
||||
* <example>
|
||||
* krabs::trace trace;
|
||||
* krabs::guid id(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}");
|
||||
* provider<> powershell(id);
|
||||
* trace.enable(powershell);
|
||||
* trace.open();
|
||||
* trace.process();
|
||||
* </example>
|
||||
*/
|
||||
void process();
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Queries the trace session to get stats about
|
||||
* events lost and buffers handled.
|
||||
* </summary>
|
||||
*/
|
||||
trace_stats query_stats();
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Returns the number of buffers that were processed.
|
||||
* </summary>
|
||||
* <example>
|
||||
* krabs::trace trace;
|
||||
* krabs::guid id(L"{A0C1853B-5C40-4B15-8766-3CF1C58F985A}");
|
||||
* provider<> powershell(id);
|
||||
* trace.enable(powershell);
|
||||
* trace.start();
|
||||
* trace.stop();
|
||||
* std::wcout << trace.buffers_processed() << std::endl;
|
||||
* </example>
|
||||
*/
|
||||
size_t buffers_processed() const;
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Adds a function to call when an event is fired which has no corresponding provider.
|
||||
* </summary>
|
||||
*
|
||||
* <param name="callback">the function to call into</param>
|
||||
* <example>
|
||||
* void my_fun(const EVENT_RECORD &record) { ... }
|
||||
* // ...
|
||||
* krabs::trace trace;
|
||||
* trace.set_default_event_callback(my_fun);
|
||||
* </example>
|
||||
*
|
||||
* <example>
|
||||
* auto fun = [&](const EVENT_RECORD &record) {...}
|
||||
* krabs::trace trace;
|
||||
* trace.set_default_event_callback(fun);
|
||||
* </example>
|
||||
*/
|
||||
void set_default_event_callback(c_provider_callback callback);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Sets whether to enable getting schema information for MOF events.
|
||||
* Default behavior is to get schema information for MOF events.
|
||||
* </summary>
|
||||
*
|
||||
* <param name="mof_events_enabled">false to disable MOF events</param>
|
||||
* <example>
|
||||
* krabs::trace trace;
|
||||
* trace.set_mof_event_processing_enabled(false);
|
||||
* </example>
|
||||
*/
|
||||
void set_mof_event_processing_enabled(bool mof_events_enabled);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Sets whether to enable getting schema information for WPP events.
|
||||
* Default behavior is to get schema information for WPP events.
|
||||
* </summary>
|
||||
*
|
||||
* <param name="wpp_events_enabled">false to disable WPP events</param>
|
||||
* <example>
|
||||
* krabs::trace trace;
|
||||
* trace.set_wpp_event_processing_enabled(false);
|
||||
* </example>
|
||||
*/
|
||||
void set_wpp_event_processing_enabled(bool wpp_events_enabled);
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Invoked when an event occurs in the underlying ETW session.
|
||||
* </summary>
|
||||
*/
|
||||
void on_event(const EVENT_RECORD &);
|
||||
|
||||
private:
|
||||
std::wstring name_;
|
||||
std::wstring logFilename_;
|
||||
std::deque<std::reference_wrapper<const typename T::provider_type>> providers_;
|
||||
|
||||
TRACEHANDLE registrationHandle_;
|
||||
TRACEHANDLE sessionHandle_;
|
||||
|
||||
size_t buffersRead_;
|
||||
uint64_t eventsHandled_;
|
||||
|
||||
EVENT_TRACE_PROPERTIES properties_;
|
||||
|
||||
const trace_context context_;
|
||||
|
||||
provider_callback default_callback_ = nullptr;
|
||||
|
||||
bool mof_events_enabled_ = true;
|
||||
bool wpp_events_enabled_ = true;
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
friend class details::trace_manager;
|
||||
|
||||
template <typename T>
|
||||
friend class testing::trace_proxy;
|
||||
|
||||
friend typename T;
|
||||
};
|
||||
|
||||
// Implementation
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
inline DECODING_SOURCE get_event_type(const EVENT_RECORD& record)
|
||||
{
|
||||
// The logic is reverse-engineered from tdh!TdhGetEventInformation
|
||||
auto has_ext_event_schema_tl = [](const EVENT_RECORD& record) {
|
||||
if (record.ExtendedDataCount) {
|
||||
for (USHORT i = 0; i < record.ExtendedDataCount; i++) {
|
||||
if (record.ExtendedData[i].ExtType == EVENT_HEADER_EXT_TYPE_EVENT_SCHEMA_TL)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
if (record.EventHeader.Flags & EVENT_HEADER_FLAG_TRACE_MESSAGE)
|
||||
return DecodingSourceWPP;
|
||||
else if (record.EventHeader.EventDescriptor.Channel == 11 || has_ext_event_schema_tl(record))
|
||||
return DecodingSourceTlg;
|
||||
else if (record.EventHeader.Flags & EVENT_HEADER_FLAG_CLASSIC_HEADER)
|
||||
return DecodingSourceWbem;
|
||||
else
|
||||
return DecodingSourceXMLFile;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
trace<T>::trace(const std::wstring &name)
|
||||
: registrationHandle_(INVALID_PROCESSTRACE_HANDLE)
|
||||
, sessionHandle_(INVALID_PROCESSTRACE_HANDLE)
|
||||
, eventsHandled_(0)
|
||||
, buffersRead_(0)
|
||||
, context_()
|
||||
{
|
||||
name_ = T::enforce_name_policy(name);
|
||||
ZeroMemory(&properties_, sizeof(EVENT_TRACE_PROPERTIES));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
trace<T>::trace(const wchar_t *name)
|
||||
: registrationHandle_(INVALID_PROCESSTRACE_HANDLE)
|
||||
, sessionHandle_(INVALID_PROCESSTRACE_HANDLE)
|
||||
, eventsHandled_(0)
|
||||
, buffersRead_(0)
|
||||
, context_()
|
||||
{
|
||||
name_ = T::enforce_name_policy(name);
|
||||
ZeroMemory(&properties_, sizeof(EVENT_TRACE_PROPERTIES));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
trace<T>::~trace()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void trace<T>::set_trace_properties(const PEVENT_TRACE_PROPERTIES properties)
|
||||
{
|
||||
properties_.BufferSize = properties->BufferSize;
|
||||
properties_.MinimumBuffers = properties->MinimumBuffers;
|
||||
properties_.MaximumBuffers = properties->MaximumBuffers;
|
||||
properties_.FlushTimer = properties->FlushTimer;
|
||||
properties_.LogFileMode = properties->LogFileMode;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void trace<T>::set_trace_information(
|
||||
TRACE_INFO_CLASS information_class,
|
||||
PVOID trace_information,
|
||||
ULONG information_length)
|
||||
{
|
||||
details::trace_manager<trace> manager(*this);
|
||||
manager.set_trace_information(information_class, trace_information, information_length);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void trace<T>::set_trace_filename(const std::wstring& filename)
|
||||
{
|
||||
logFilename_ = filename;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void trace<T>::on_event(const EVENT_RECORD &record)
|
||||
{
|
||||
++eventsHandled_;
|
||||
T::forward_events(record, *this);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void trace<T>::enable(const typename T::provider_type &p)
|
||||
{
|
||||
providers_.push_back(std::ref(p));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void trace<T>::start()
|
||||
{
|
||||
eventsHandled_ = 0;
|
||||
|
||||
details::trace_manager<trace> manager(*this);
|
||||
manager.start();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void trace<T>::stop()
|
||||
{
|
||||
details::trace_manager<trace> manager(*this);
|
||||
manager.stop();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
EVENT_TRACE_LOGFILE trace<T>::open()
|
||||
{
|
||||
eventsHandled_ = 0;
|
||||
|
||||
details::trace_manager<trace> manager(*this);
|
||||
return manager.open();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void trace<T>::process()
|
||||
{
|
||||
eventsHandled_ = 0;
|
||||
|
||||
details::trace_manager<trace> manager(*this);
|
||||
manager.process();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
trace_stats trace<T>::query_stats()
|
||||
{
|
||||
details::trace_manager<trace> manager(*this);
|
||||
return { eventsHandled_, manager.query() };
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
size_t trace<T>::buffers_processed() const
|
||||
{
|
||||
return buffersRead_;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void trace<T>::set_default_event_callback(c_provider_callback callback)
|
||||
{
|
||||
default_callback_ = callback;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void trace<T>::set_mof_event_processing_enabled(bool mof_events_enabled)
|
||||
{
|
||||
mof_events_enabled_ = mof_events_enabled;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void trace<T>::set_wpp_event_processing_enabled(bool wpp_events_enabled)
|
||||
{
|
||||
wpp_events_enabled_ = wpp_events_enabled;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "schema_locator.hpp"
|
||||
|
||||
namespace krabs {
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Additional ETW trace context passed to event callbacks
|
||||
* to enable processing.
|
||||
* </summary>
|
||||
*/
|
||||
struct trace_context
|
||||
{
|
||||
const schema_locator schema_locator;
|
||||
/* Add additional trace context here. */
|
||||
};
|
||||
|
||||
}
|
||||
+272
@@ -0,0 +1,272 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "compiler_check.hpp"
|
||||
#include "trace.hpp"
|
||||
#include "provider.hpp"
|
||||
|
||||
namespace krabs { namespace details {
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Used as a template argument to a trace instance. This class implements
|
||||
* code paths for user traces. Should never be used or seen by client
|
||||
* code.
|
||||
* </summary>
|
||||
*/
|
||||
struct ut {
|
||||
|
||||
typedef krabs::provider<> provider_type;
|
||||
|
||||
struct filter_flags {
|
||||
UCHAR level_;
|
||||
ULONGLONG any_;
|
||||
ULONGLONG all_;
|
||||
ULONG trace_flags_;
|
||||
};
|
||||
|
||||
struct filter_settings{
|
||||
std::set<unsigned short> provider_filter_event_ids_;
|
||||
filter_flags filter_flags_{};
|
||||
bool rundown_enabled_ = false;
|
||||
};
|
||||
|
||||
typedef std::map<krabs::guid, filter_settings> provider_filter_settings;
|
||||
/**
|
||||
* <summary>
|
||||
* Used to assign a name to the trace instance that is being
|
||||
* instantiated.
|
||||
* </summary>
|
||||
* <remarks>
|
||||
* There really isn't a name policy to enforce with user traces, but
|
||||
* kernel traces do have specific naming requirements.
|
||||
* </remarks>
|
||||
*/
|
||||
static const std::wstring enforce_name_policy(
|
||||
const std::wstring &name);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Generates a value that fills the EnableFlags field in an
|
||||
* EVENT_TRACE_PROPERTIES structure. This controls the providers that
|
||||
* get enabled for a kernel trace. For a user trace, it doesn't do
|
||||
* much of anything.
|
||||
* </summary>
|
||||
*/
|
||||
static const unsigned long construct_enable_flags(
|
||||
const krabs::trace<krabs::details::ut> &trace);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Enables the providers that are attached to the given trace.
|
||||
* </summary>
|
||||
*/
|
||||
static void enable_providers(
|
||||
const krabs::trace<krabs::details::ut> &trace);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Enables the configured rundown events for each provider.
|
||||
* Should be called immediately prior to ProcessTrace.
|
||||
* </summary>
|
||||
*/
|
||||
static void enable_rundown(
|
||||
const krabs::trace<krabs::details::ut>& trace);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Decides to forward an event to any of the providers in the trace.
|
||||
* </summary>
|
||||
*/
|
||||
static void forward_events(
|
||||
const EVENT_RECORD &record,
|
||||
const krabs::trace<krabs::details::ut> &trace);
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Sets the ETW trace log file mode.
|
||||
* </summary>
|
||||
*/
|
||||
static unsigned long augment_file_mode();
|
||||
|
||||
/**
|
||||
* <summary>
|
||||
* Returns the GUID of the trace session.
|
||||
* </summary>
|
||||
*/
|
||||
static krabs::guid get_trace_guid();
|
||||
};
|
||||
|
||||
|
||||
// Implementation
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
inline const std::wstring ut::enforce_name_policy(
|
||||
const std::wstring &name_hint)
|
||||
{
|
||||
if (name_hint.empty()) {
|
||||
return std::to_wstring(krabs::guid::random_guid());
|
||||
}
|
||||
|
||||
return name_hint;
|
||||
}
|
||||
|
||||
inline const unsigned long ut::construct_enable_flags(
|
||||
const krabs::trace<krabs::details::ut> &)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void ut::enable_providers(
|
||||
const krabs::trace<krabs::details::ut> &trace)
|
||||
{
|
||||
if (trace.registrationHandle_ == INVALID_PROCESSTRACE_HANDLE)
|
||||
return;
|
||||
|
||||
provider_filter_settings provider_flags;
|
||||
|
||||
// This function essentially takes the union of all the provider flags
|
||||
// for a given provider GUID. This comes about when multiple providers
|
||||
// for the same GUID are provided and request different provider flags.
|
||||
// TODO: Only forward the calls that are requested to each provider.
|
||||
for (auto &provider : trace.providers_) {
|
||||
auto& settings = provider_flags[provider.get().guid_];
|
||||
settings.filter_flags_.level_ |= provider.get().level_;
|
||||
settings.filter_flags_.any_ |= provider.get().any_;
|
||||
settings.filter_flags_.all_ |= provider.get().all_;
|
||||
settings.filter_flags_.trace_flags_ |= provider.get().trace_flags_;
|
||||
settings.rundown_enabled_ |= provider.get().rundown_enabled_;
|
||||
|
||||
for (const auto& filter : provider.get().filters_) {
|
||||
settings.provider_filter_event_ids_.insert(
|
||||
filter.provider_filter_event_ids().begin(),
|
||||
filter.provider_filter_event_ids().end());
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &provider : provider_flags) {
|
||||
ENABLE_TRACE_PARAMETERS parameters;
|
||||
parameters.ControlFlags = 0;
|
||||
parameters.Version = ENABLE_TRACE_PARAMETERS_VERSION_2;
|
||||
parameters.SourceId = provider.first;
|
||||
|
||||
GUID guid = provider.first;
|
||||
auto& settings = provider.second;
|
||||
|
||||
parameters.EnableProperty = settings.filter_flags_.trace_flags_;
|
||||
parameters.EnableFilterDesc = nullptr;
|
||||
parameters.FilterDescCount = 0;
|
||||
EVENT_FILTER_DESCRIPTOR filterDesc{};
|
||||
std::vector<BYTE> filterEventIdBuffer;
|
||||
auto filterEventIdCount = settings.provider_filter_event_ids_.size();
|
||||
|
||||
if (filterEventIdCount > 0) {
|
||||
//event filters existing, set native filters using API
|
||||
parameters.FilterDescCount = 1;
|
||||
filterDesc.Type = EVENT_FILTER_TYPE_EVENT_ID;
|
||||
|
||||
//allocate + size of expected events in filter
|
||||
DWORD size = FIELD_OFFSET(EVENT_FILTER_EVENT_ID, Events[filterEventIdCount]);
|
||||
filterEventIdBuffer.resize(size, 0);
|
||||
|
||||
auto filterEventIds = reinterpret_cast<PEVENT_FILTER_EVENT_ID>(&(filterEventIdBuffer[0]));
|
||||
filterEventIds->FilterIn = TRUE;
|
||||
filterEventIds->Count = static_cast<USHORT>(filterEventIdCount);
|
||||
|
||||
auto index = 0;
|
||||
for (auto filter : settings.provider_filter_event_ids_) {
|
||||
filterEventIds->Events[index] = filter;
|
||||
index++;
|
||||
}
|
||||
|
||||
filterDesc.Ptr = reinterpret_cast<ULONGLONG>(filterEventIds);
|
||||
filterDesc.Size = size;
|
||||
|
||||
parameters.EnableFilterDesc = &filterDesc;
|
||||
}
|
||||
|
||||
ULONG status = EnableTraceEx2(trace.registrationHandle_,
|
||||
&guid,
|
||||
EVENT_CONTROL_CODE_ENABLE_PROVIDER,
|
||||
settings.filter_flags_.level_,
|
||||
settings.filter_flags_.any_,
|
||||
settings.filter_flags_.all_,
|
||||
0,
|
||||
¶meters);
|
||||
error_check_common_conditions(status);
|
||||
}
|
||||
}
|
||||
|
||||
inline void ut::enable_rundown(
|
||||
const krabs::trace<krabs::details::ut>& trace)
|
||||
{
|
||||
if (trace.registrationHandle_ == INVALID_PROCESSTRACE_HANDLE)
|
||||
return;
|
||||
|
||||
for (auto& provider : trace.providers_) {
|
||||
if (!provider.get().rundown_enabled_)
|
||||
continue;
|
||||
|
||||
ULONG status = EnableTraceEx2(trace.registrationHandle_,
|
||||
&provider.get().guid_,
|
||||
EVENT_CONTROL_CODE_CAPTURE_STATE,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
NULL);
|
||||
error_check_common_conditions(status);
|
||||
}
|
||||
}
|
||||
|
||||
inline void ut::forward_events(
|
||||
const EVENT_RECORD &record,
|
||||
const krabs::trace<krabs::details::ut> &trace)
|
||||
{
|
||||
auto type = get_event_type(record);
|
||||
|
||||
if (type == DecodingSourceXMLFile || type == DecodingSourceTlg) {
|
||||
// for manifest/TraceLogging providers, EventHeader.ProviderId is the Provider GUID
|
||||
for (auto& provider : trace.providers_) {
|
||||
if (record.EventHeader.ProviderId == provider.get().guid_) {
|
||||
provider.get().on_event(record, trace.context_);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((type == DecodingSourceWbem && trace.mof_events_enabled_) ||
|
||||
(type == DecodingSourceWPP && trace.wpp_events_enabled_)) {
|
||||
// for MOF/WPP providers, EventHeader.Provider is the *Message* GUID
|
||||
// we need to ask TDH for event information in order to determine the
|
||||
// correct provider to pass this event to
|
||||
TDHSTATUS status = ERROR_SUCCESS;
|
||||
auto schema = trace.context_.schema_locator.get_event_schema_no_throw(record, status);
|
||||
if (status == ERROR_SUCCESS) {
|
||||
for (auto& provider : trace.providers_) {
|
||||
if (schema->ProviderGuid == provider.get().guid_) {
|
||||
provider.get().on_event(record, trace.context_);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (trace.default_callback_ != nullptr)
|
||||
trace.default_callback_(record, trace.context_);
|
||||
}
|
||||
|
||||
inline unsigned long ut::augment_file_mode()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline krabs::guid ut::get_trace_guid()
|
||||
{
|
||||
return krabs::guid::random_guid();
|
||||
}
|
||||
|
||||
} /* namespace details */ } /* namespace krabs */
|
||||
@@ -0,0 +1,142 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
// We manually include this file because it doesn't exist for VS2012.
|
||||
|
||||
#ifndef _versionhelpers_H_INCLUDED_
|
||||
#define _versionhelpers_H_INCLUDED_
|
||||
|
||||
#include <winapifamily.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma once
|
||||
#endif // _MSC_VER
|
||||
|
||||
#pragma region Application Family
|
||||
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
|
||||
|
||||
#include <specstrings.h> // for _In_, etc.
|
||||
|
||||
#if !defined(__midl) && !defined(SORTPP_PASS)
|
||||
|
||||
#if (NTDDI_VERSION >= NTDDI_WINXP)
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#define VERSIONHELPERAPI inline bool
|
||||
|
||||
#else // __cplusplus
|
||||
|
||||
#define VERSIONHELPERAPI FORCEINLINE BOOL
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
#ifndef NTDDI_WINBLUE
|
||||
#define NTDDI_WINBLUE 0x06030000
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32_WINNT_WINBLUE
|
||||
#define _WIN32_WINNT_WINBLUE 0x0602
|
||||
#endif
|
||||
|
||||
VERSIONHELPERAPI
|
||||
IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)
|
||||
{
|
||||
OSVERSIONINFOEXW osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 };
|
||||
DWORDLONG const dwlConditionMask = VerSetConditionMask(
|
||||
VerSetConditionMask(
|
||||
VerSetConditionMask(
|
||||
0, VER_MAJORVERSION, VER_GREATER_EQUAL),
|
||||
VER_MINORVERSION, VER_GREATER_EQUAL),
|
||||
VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
|
||||
|
||||
osvi.dwMajorVersion = wMajorVersion;
|
||||
osvi.dwMinorVersion = wMinorVersion;
|
||||
osvi.wServicePackMajor = wServicePackMajor;
|
||||
|
||||
return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE;
|
||||
}
|
||||
|
||||
VERSIONHELPERAPI
|
||||
IsWindowsXPOrGreater()
|
||||
{
|
||||
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 0);
|
||||
}
|
||||
|
||||
VERSIONHELPERAPI
|
||||
IsWindowsXPSP1OrGreater()
|
||||
{
|
||||
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 1);
|
||||
}
|
||||
|
||||
VERSIONHELPERAPI
|
||||
IsWindowsXPSP2OrGreater()
|
||||
{
|
||||
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 2);
|
||||
}
|
||||
|
||||
VERSIONHELPERAPI
|
||||
IsWindowsXPSP3OrGreater()
|
||||
{
|
||||
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 3);
|
||||
}
|
||||
|
||||
VERSIONHELPERAPI
|
||||
IsWindowsVistaOrGreater()
|
||||
{
|
||||
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 0);
|
||||
}
|
||||
|
||||
VERSIONHELPERAPI
|
||||
IsWindowsVistaSP1OrGreater()
|
||||
{
|
||||
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 1);
|
||||
}
|
||||
|
||||
VERSIONHELPERAPI
|
||||
IsWindowsVistaSP2OrGreater()
|
||||
{
|
||||
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 2);
|
||||
}
|
||||
|
||||
VERSIONHELPERAPI
|
||||
IsWindows7OrGreater()
|
||||
{
|
||||
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 0);
|
||||
}
|
||||
|
||||
VERSIONHELPERAPI
|
||||
IsWindows7SP1OrGreater()
|
||||
{
|
||||
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 1);
|
||||
}
|
||||
|
||||
VERSIONHELPERAPI
|
||||
IsWindows8OrGreater()
|
||||
{
|
||||
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN8), LOBYTE(_WIN32_WINNT_WIN8), 0);
|
||||
}
|
||||
|
||||
VERSIONHELPERAPI
|
||||
IsWindows8Point1OrGreater()
|
||||
{
|
||||
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINBLUE), LOBYTE(_WIN32_WINNT_WINBLUE), 0);
|
||||
}
|
||||
|
||||
VERSIONHELPERAPI
|
||||
IsWindowsServer()
|
||||
{
|
||||
OSVERSIONINFOEXW osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0, 0, VER_NT_WORKSTATION };
|
||||
DWORDLONG const dwlConditionMask = VerSetConditionMask( 0, VER_PRODUCT_TYPE, VER_EQUAL );
|
||||
|
||||
return !VerifyVersionInfoW(&osvi, VER_PRODUCT_TYPE, dwlConditionMask);
|
||||
}
|
||||
|
||||
#endif // NTDDI_VERSION
|
||||
|
||||
#endif // defined(__midl)
|
||||
|
||||
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) */
|
||||
#pragma endregion
|
||||
|
||||
#endif // _VERSIONHELPERS_H_INCLUDED_
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace krabs {
|
||||
|
||||
/** <summary>
|
||||
* Converts std::wstring argument to std::string using UTF-8 codepage
|
||||
* Returns empty string if translation fails or input string is empty
|
||||
* </summary>
|
||||
*/
|
||||
inline std::string from_wstring(const std::wstring& wstr, UINT codePage = CP_UTF8)
|
||||
{
|
||||
if (wstr.empty())
|
||||
return {};
|
||||
|
||||
const auto requiredLen = WideCharToMultiByte(codePage, 0, wstr.data(), static_cast<int>(wstr.size()),
|
||||
nullptr, 0, nullptr, nullptr);
|
||||
if (0 == requiredLen)
|
||||
return {};
|
||||
|
||||
std::string result(requiredLen, 0);
|
||||
const auto convertedLen = WideCharToMultiByte(codePage, 0, wstr.data(), static_cast<int>(wstr.size()),
|
||||
&result[0], requiredLen, nullptr, nullptr);
|
||||
if (0 == convertedLen)
|
||||
return {};
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+185
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||
* Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !(defined _M_IX86) && !(defined _M_X64) && !(defined __i386__) && !(defined __x86_64__)
|
||||
#error MinHook supports only x86 and x64 systems.
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
// MinHook Error Codes.
|
||||
typedef enum MH_STATUS
|
||||
{
|
||||
// Unknown error. Should not be returned.
|
||||
MH_UNKNOWN = -1,
|
||||
|
||||
// Successful.
|
||||
MH_OK = 0,
|
||||
|
||||
// MinHook is already initialized.
|
||||
MH_ERROR_ALREADY_INITIALIZED,
|
||||
|
||||
// MinHook is not initialized yet, or already uninitialized.
|
||||
MH_ERROR_NOT_INITIALIZED,
|
||||
|
||||
// The hook for the specified target function is already created.
|
||||
MH_ERROR_ALREADY_CREATED,
|
||||
|
||||
// The hook for the specified target function is not created yet.
|
||||
MH_ERROR_NOT_CREATED,
|
||||
|
||||
// The hook for the specified target function is already enabled.
|
||||
MH_ERROR_ENABLED,
|
||||
|
||||
// The hook for the specified target function is not enabled yet, or already
|
||||
// disabled.
|
||||
MH_ERROR_DISABLED,
|
||||
|
||||
// The specified pointer is invalid. It points the address of non-allocated
|
||||
// and/or non-executable region.
|
||||
MH_ERROR_NOT_EXECUTABLE,
|
||||
|
||||
// The specified target function cannot be hooked.
|
||||
MH_ERROR_UNSUPPORTED_FUNCTION,
|
||||
|
||||
// Failed to allocate memory.
|
||||
MH_ERROR_MEMORY_ALLOC,
|
||||
|
||||
// Failed to change the memory protection.
|
||||
MH_ERROR_MEMORY_PROTECT,
|
||||
|
||||
// The specified module is not loaded.
|
||||
MH_ERROR_MODULE_NOT_FOUND,
|
||||
|
||||
// The specified function is not found.
|
||||
MH_ERROR_FUNCTION_NOT_FOUND
|
||||
}
|
||||
MH_STATUS;
|
||||
|
||||
// Can be passed as a parameter to MH_EnableHook, MH_DisableHook,
|
||||
// MH_QueueEnableHook or MH_QueueDisableHook.
|
||||
#define MH_ALL_HOOKS NULL
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Initialize the MinHook library. You must call this function EXACTLY ONCE
|
||||
// at the beginning of your program.
|
||||
MH_STATUS WINAPI MH_Initialize(VOID);
|
||||
|
||||
// Uninitialize the MinHook library. You must call this function EXACTLY
|
||||
// ONCE at the end of your program.
|
||||
MH_STATUS WINAPI MH_Uninitialize(VOID);
|
||||
|
||||
// Creates a hook for the specified target function, in disabled state.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function, which will be
|
||||
// overridden by the detour function.
|
||||
// pDetour [in] A pointer to the detour function, which will override
|
||||
// the target function.
|
||||
// ppOriginal [out] A pointer to the trampoline function, which will be
|
||||
// used to call the original target function.
|
||||
// This parameter can be NULL.
|
||||
MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal);
|
||||
|
||||
// Creates a hook for the specified API function, in disabled state.
|
||||
// Parameters:
|
||||
// pszModule [in] A pointer to the loaded module name which contains the
|
||||
// target function.
|
||||
// pszProcName [in] A pointer to the target function name, which will be
|
||||
// overridden by the detour function.
|
||||
// pDetour [in] A pointer to the detour function, which will override
|
||||
// the target function.
|
||||
// ppOriginal [out] A pointer to the trampoline function, which will be
|
||||
// used to call the original target function.
|
||||
// This parameter can be NULL.
|
||||
MH_STATUS WINAPI MH_CreateHookApi(
|
||||
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal);
|
||||
|
||||
// Creates a hook for the specified API function, in disabled state.
|
||||
// Parameters:
|
||||
// pszModule [in] A pointer to the loaded module name which contains the
|
||||
// target function.
|
||||
// pszProcName [in] A pointer to the target function name, which will be
|
||||
// overridden by the detour function.
|
||||
// pDetour [in] A pointer to the detour function, which will override
|
||||
// the target function.
|
||||
// ppOriginal [out] A pointer to the trampoline function, which will be
|
||||
// used to call the original target function.
|
||||
// This parameter can be NULL.
|
||||
// ppTarget [out] A pointer to the target function, which will be used
|
||||
// with other functions.
|
||||
// This parameter can be NULL.
|
||||
MH_STATUS WINAPI MH_CreateHookApiEx(
|
||||
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal, LPVOID *ppTarget);
|
||||
|
||||
// Removes an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget);
|
||||
|
||||
// Enables an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||
// enabled in one go.
|
||||
MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget);
|
||||
|
||||
// Disables an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||
// disabled in one go.
|
||||
MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget);
|
||||
|
||||
// Queues to enable an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||
// queued to be enabled.
|
||||
MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget);
|
||||
|
||||
// Queues to disable an already created hook.
|
||||
// Parameters:
|
||||
// pTarget [in] A pointer to the target function.
|
||||
// If this parameter is MH_ALL_HOOKS, all created hooks are
|
||||
// queued to be disabled.
|
||||
MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget);
|
||||
|
||||
// Applies all queued changes in one go.
|
||||
MH_STATUS WINAPI MH_ApplyQueued(VOID);
|
||||
|
||||
// Translates the MH_STATUS to its name as a string.
|
||||
const char *WINAPI MH_StatusToString(MH_STATUS status);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
Vendored
+312
@@ -0,0 +1,312 @@
|
||||
/*
|
||||
* MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||
* Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include "buffer.h"
|
||||
|
||||
// Size of each memory block. (= page size of VirtualAlloc)
|
||||
#define MEMORY_BLOCK_SIZE 0x1000
|
||||
|
||||
// Max range for seeking a memory block. (= 1024MB)
|
||||
#define MAX_MEMORY_RANGE 0x40000000
|
||||
|
||||
// Memory protection flags to check the executable address.
|
||||
#define PAGE_EXECUTE_FLAGS \
|
||||
(PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)
|
||||
|
||||
// Memory slot.
|
||||
typedef struct _MEMORY_SLOT
|
||||
{
|
||||
union
|
||||
{
|
||||
struct _MEMORY_SLOT *pNext;
|
||||
UINT8 buffer[MEMORY_SLOT_SIZE];
|
||||
};
|
||||
} MEMORY_SLOT, *PMEMORY_SLOT;
|
||||
|
||||
// Memory block info. Placed at the head of each block.
|
||||
typedef struct _MEMORY_BLOCK
|
||||
{
|
||||
struct _MEMORY_BLOCK *pNext;
|
||||
PMEMORY_SLOT pFree; // First element of the free slot list.
|
||||
UINT usedCount;
|
||||
} MEMORY_BLOCK, *PMEMORY_BLOCK;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Global Variables:
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
// First element of the memory block list.
|
||||
static PMEMORY_BLOCK g_pMemoryBlocks;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
VOID InitializeBuffer(VOID)
|
||||
{
|
||||
// Nothing to do for now.
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
VOID UninitializeBuffer(VOID)
|
||||
{
|
||||
PMEMORY_BLOCK pBlock = g_pMemoryBlocks;
|
||||
g_pMemoryBlocks = NULL;
|
||||
|
||||
while (pBlock)
|
||||
{
|
||||
PMEMORY_BLOCK pNext = pBlock->pNext;
|
||||
VirtualFree(pBlock, 0, MEM_RELEASE);
|
||||
pBlock = pNext;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
static LPVOID FindPrevFreeRegion(LPVOID pAddress, LPVOID pMinAddr, DWORD dwAllocationGranularity)
|
||||
{
|
||||
ULONG_PTR tryAddr = (ULONG_PTR)pAddress;
|
||||
|
||||
// Round down to the allocation granularity.
|
||||
tryAddr -= tryAddr % dwAllocationGranularity;
|
||||
|
||||
// Start from the previous allocation granularity multiply.
|
||||
tryAddr -= dwAllocationGranularity;
|
||||
|
||||
while (tryAddr >= (ULONG_PTR)pMinAddr)
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0)
|
||||
break;
|
||||
|
||||
if (mbi.State == MEM_FREE)
|
||||
return (LPVOID)tryAddr;
|
||||
|
||||
if ((ULONG_PTR)mbi.AllocationBase < dwAllocationGranularity)
|
||||
break;
|
||||
|
||||
tryAddr = (ULONG_PTR)mbi.AllocationBase - dwAllocationGranularity;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
static LPVOID FindNextFreeRegion(LPVOID pAddress, LPVOID pMaxAddr, DWORD dwAllocationGranularity)
|
||||
{
|
||||
ULONG_PTR tryAddr = (ULONG_PTR)pAddress;
|
||||
|
||||
// Round down to the allocation granularity.
|
||||
tryAddr -= tryAddr % dwAllocationGranularity;
|
||||
|
||||
// Start from the next allocation granularity multiply.
|
||||
tryAddr += dwAllocationGranularity;
|
||||
|
||||
while (tryAddr <= (ULONG_PTR)pMaxAddr)
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
if (VirtualQuery((LPVOID)tryAddr, &mbi, sizeof(mbi)) == 0)
|
||||
break;
|
||||
|
||||
if (mbi.State == MEM_FREE)
|
||||
return (LPVOID)tryAddr;
|
||||
|
||||
tryAddr = (ULONG_PTR)mbi.BaseAddress + mbi.RegionSize;
|
||||
|
||||
// Round up to the next allocation granularity.
|
||||
tryAddr += dwAllocationGranularity - 1;
|
||||
tryAddr -= tryAddr % dwAllocationGranularity;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static PMEMORY_BLOCK GetMemoryBlock(LPVOID pOrigin)
|
||||
{
|
||||
PMEMORY_BLOCK pBlock;
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
ULONG_PTR minAddr;
|
||||
ULONG_PTR maxAddr;
|
||||
|
||||
SYSTEM_INFO si;
|
||||
GetSystemInfo(&si);
|
||||
minAddr = (ULONG_PTR)si.lpMinimumApplicationAddress;
|
||||
maxAddr = (ULONG_PTR)si.lpMaximumApplicationAddress;
|
||||
|
||||
// pOrigin ± 512MB
|
||||
if ((ULONG_PTR)pOrigin > MAX_MEMORY_RANGE && minAddr < (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE)
|
||||
minAddr = (ULONG_PTR)pOrigin - MAX_MEMORY_RANGE;
|
||||
|
||||
if (maxAddr > (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE)
|
||||
maxAddr = (ULONG_PTR)pOrigin + MAX_MEMORY_RANGE;
|
||||
|
||||
// Make room for MEMORY_BLOCK_SIZE bytes.
|
||||
maxAddr -= MEMORY_BLOCK_SIZE - 1;
|
||||
#endif
|
||||
|
||||
// Look the registered blocks for a reachable one.
|
||||
for (pBlock = g_pMemoryBlocks; pBlock != NULL; pBlock = pBlock->pNext)
|
||||
{
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
// Ignore the blocks too far.
|
||||
if ((ULONG_PTR)pBlock < minAddr || (ULONG_PTR)pBlock >= maxAddr)
|
||||
continue;
|
||||
#endif
|
||||
// The block has at least one unused slot.
|
||||
if (pBlock->pFree != NULL)
|
||||
return pBlock;
|
||||
}
|
||||
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
// Alloc a new block above if not found.
|
||||
{
|
||||
LPVOID pAlloc = pOrigin;
|
||||
while ((ULONG_PTR)pAlloc >= minAddr)
|
||||
{
|
||||
pAlloc = FindPrevFreeRegion(pAlloc, (LPVOID)minAddr, si.dwAllocationGranularity);
|
||||
if (pAlloc == NULL)
|
||||
break;
|
||||
|
||||
pBlock = (PMEMORY_BLOCK)VirtualAlloc(
|
||||
pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||
if (pBlock != NULL)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Alloc a new block below if not found.
|
||||
if (pBlock == NULL)
|
||||
{
|
||||
LPVOID pAlloc = pOrigin;
|
||||
while ((ULONG_PTR)pAlloc <= maxAddr)
|
||||
{
|
||||
pAlloc = FindNextFreeRegion(pAlloc, (LPVOID)maxAddr, si.dwAllocationGranularity);
|
||||
if (pAlloc == NULL)
|
||||
break;
|
||||
|
||||
pBlock = (PMEMORY_BLOCK)VirtualAlloc(
|
||||
pAlloc, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||
if (pBlock != NULL)
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
// In x86 mode, a memory block can be placed anywhere.
|
||||
pBlock = (PMEMORY_BLOCK)VirtualAlloc(
|
||||
NULL, MEMORY_BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||
#endif
|
||||
|
||||
if (pBlock != NULL)
|
||||
{
|
||||
// Build a linked list of all the slots.
|
||||
PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBlock + 1;
|
||||
pBlock->pFree = NULL;
|
||||
pBlock->usedCount = 0;
|
||||
do
|
||||
{
|
||||
pSlot->pNext = pBlock->pFree;
|
||||
pBlock->pFree = pSlot;
|
||||
pSlot++;
|
||||
} while ((ULONG_PTR)pSlot - (ULONG_PTR)pBlock <= MEMORY_BLOCK_SIZE - MEMORY_SLOT_SIZE);
|
||||
|
||||
pBlock->pNext = g_pMemoryBlocks;
|
||||
g_pMemoryBlocks = pBlock;
|
||||
}
|
||||
|
||||
return pBlock;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
LPVOID AllocateBuffer(LPVOID pOrigin)
|
||||
{
|
||||
PMEMORY_SLOT pSlot;
|
||||
PMEMORY_BLOCK pBlock = GetMemoryBlock(pOrigin);
|
||||
if (pBlock == NULL)
|
||||
return NULL;
|
||||
|
||||
// Remove an unused slot from the list.
|
||||
pSlot = pBlock->pFree;
|
||||
pBlock->pFree = pSlot->pNext;
|
||||
pBlock->usedCount++;
|
||||
#ifdef _DEBUG
|
||||
// Fill the slot with INT3 for debugging.
|
||||
memset(pSlot, 0xCC, sizeof(MEMORY_SLOT));
|
||||
#endif
|
||||
return pSlot;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
VOID FreeBuffer(LPVOID pBuffer)
|
||||
{
|
||||
PMEMORY_BLOCK pBlock = g_pMemoryBlocks;
|
||||
PMEMORY_BLOCK pPrev = NULL;
|
||||
ULONG_PTR pTargetBlock = ((ULONG_PTR)pBuffer / MEMORY_BLOCK_SIZE) * MEMORY_BLOCK_SIZE;
|
||||
|
||||
while (pBlock != NULL)
|
||||
{
|
||||
if ((ULONG_PTR)pBlock == pTargetBlock)
|
||||
{
|
||||
PMEMORY_SLOT pSlot = (PMEMORY_SLOT)pBuffer;
|
||||
#ifdef _DEBUG
|
||||
// Clear the released slot for debugging.
|
||||
memset(pSlot, 0x00, sizeof(MEMORY_SLOT));
|
||||
#endif
|
||||
// Restore the released slot to the list.
|
||||
pSlot->pNext = pBlock->pFree;
|
||||
pBlock->pFree = pSlot;
|
||||
pBlock->usedCount--;
|
||||
|
||||
// Free if unused.
|
||||
if (pBlock->usedCount == 0)
|
||||
{
|
||||
if (pPrev)
|
||||
pPrev->pNext = pBlock->pNext;
|
||||
else
|
||||
g_pMemoryBlocks = pBlock->pNext;
|
||||
|
||||
VirtualFree(pBlock, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
pPrev = pBlock;
|
||||
pBlock = pBlock->pNext;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
BOOL IsExecutableAddress(LPVOID pAddress)
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION mi;
|
||||
VirtualQuery(pAddress, &mi, sizeof(mi));
|
||||
|
||||
return (mi.State == MEM_COMMIT && (mi.Protect & PAGE_EXECUTE_FLAGS));
|
||||
}
|
||||
Vendored
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||
* Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Size of each memory slot.
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
#define MEMORY_SLOT_SIZE 64
|
||||
#else
|
||||
#define MEMORY_SLOT_SIZE 32
|
||||
#endif
|
||||
|
||||
VOID InitializeBuffer(VOID);
|
||||
VOID UninitializeBuffer(VOID);
|
||||
LPVOID AllocateBuffer(LPVOID pOrigin);
|
||||
VOID FreeBuffer(LPVOID pBuffer);
|
||||
BOOL IsExecutableAddress(LPVOID pAddress);
|
||||
Vendored
+335
@@ -0,0 +1,335 @@
|
||||
/*
|
||||
* Hacker Disassembler Engine 64 C
|
||||
* Copyright (c) 2008-2009, Vyacheslav Patkov.
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
|
||||
#include <string.h>
|
||||
#include "hde64.h"
|
||||
#include "table64.h"
|
||||
|
||||
unsigned int hde64_disasm(const void *code, hde64s *hs)
|
||||
{
|
||||
uint8_t x, c, *p = (uint8_t *)code, cflags, opcode, pref = 0;
|
||||
uint8_t *ht = hde64_table, m_mod, m_reg, m_rm, disp_size = 0;
|
||||
uint8_t op64 = 0;
|
||||
|
||||
memset(hs, 0, sizeof(hde64s));
|
||||
|
||||
for (x = 16; x; x--)
|
||||
switch (c = *p++) {
|
||||
case 0xf3:
|
||||
hs->p_rep = c;
|
||||
pref |= PRE_F3;
|
||||
break;
|
||||
case 0xf2:
|
||||
hs->p_rep = c;
|
||||
pref |= PRE_F2;
|
||||
break;
|
||||
case 0xf0:
|
||||
hs->p_lock = c;
|
||||
pref |= PRE_LOCK;
|
||||
break;
|
||||
case 0x26: case 0x2e: case 0x36:
|
||||
case 0x3e: case 0x64: case 0x65:
|
||||
hs->p_seg = c;
|
||||
pref |= PRE_SEG;
|
||||
break;
|
||||
case 0x66:
|
||||
hs->p_66 = c;
|
||||
pref |= PRE_66;
|
||||
break;
|
||||
case 0x67:
|
||||
hs->p_67 = c;
|
||||
pref |= PRE_67;
|
||||
break;
|
||||
default:
|
||||
goto pref_done;
|
||||
}
|
||||
pref_done:
|
||||
|
||||
hs->flags = (uint32_t)pref << 23;
|
||||
|
||||
if (!pref)
|
||||
pref |= PRE_NONE;
|
||||
|
||||
if ((c & 0xf0) == 0x40) {
|
||||
hs->flags |= F_PREFIX_REX;
|
||||
if ((hs->rex_w = (c & 0xf) >> 3) && (*p & 0xf8) == 0xb8)
|
||||
op64++;
|
||||
hs->rex_r = (c & 7) >> 2;
|
||||
hs->rex_x = (c & 3) >> 1;
|
||||
hs->rex_b = c & 1;
|
||||
if (((c = *p++) & 0xf0) == 0x40) {
|
||||
opcode = c;
|
||||
goto error_opcode;
|
||||
}
|
||||
}
|
||||
|
||||
if ((hs->opcode = c) == 0x0f) {
|
||||
hs->opcode2 = c = *p++;
|
||||
ht += DELTA_OPCODES;
|
||||
} else if (c >= 0xa0 && c <= 0xa3) {
|
||||
op64++;
|
||||
if (pref & PRE_67)
|
||||
pref |= PRE_66;
|
||||
else
|
||||
pref &= ~PRE_66;
|
||||
}
|
||||
|
||||
opcode = c;
|
||||
cflags = ht[ht[opcode / 4] + (opcode % 4)];
|
||||
|
||||
if (cflags == C_ERROR) {
|
||||
error_opcode:
|
||||
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
||||
cflags = 0;
|
||||
if ((opcode & -3) == 0x24)
|
||||
cflags++;
|
||||
}
|
||||
|
||||
x = 0;
|
||||
if (cflags & C_GROUP) {
|
||||
uint16_t t;
|
||||
t = *(uint16_t *)(ht + (cflags & 0x7f));
|
||||
cflags = (uint8_t)t;
|
||||
x = (uint8_t)(t >> 8);
|
||||
}
|
||||
|
||||
if (hs->opcode2) {
|
||||
ht = hde64_table + DELTA_PREFIXES;
|
||||
if (ht[ht[opcode / 4] + (opcode % 4)] & pref)
|
||||
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
||||
}
|
||||
|
||||
if (cflags & C_MODRM) {
|
||||
hs->flags |= F_MODRM;
|
||||
hs->modrm = c = *p++;
|
||||
hs->modrm_mod = m_mod = c >> 6;
|
||||
hs->modrm_rm = m_rm = c & 7;
|
||||
hs->modrm_reg = m_reg = (c & 0x3f) >> 3;
|
||||
|
||||
if (x && ((x << m_reg) & 0x80))
|
||||
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
||||
|
||||
if (!hs->opcode2 && opcode >= 0xd9 && opcode <= 0xdf) {
|
||||
uint8_t t = opcode - 0xd9;
|
||||
if (m_mod == 3) {
|
||||
ht = hde64_table + DELTA_FPU_MODRM + t*8;
|
||||
t = ht[m_reg] << m_rm;
|
||||
} else {
|
||||
ht = hde64_table + DELTA_FPU_REG;
|
||||
t = ht[t] << m_reg;
|
||||
}
|
||||
if (t & 0x80)
|
||||
hs->flags |= F_ERROR | F_ERROR_OPCODE;
|
||||
}
|
||||
|
||||
if (pref & PRE_LOCK) {
|
||||
if (m_mod == 3) {
|
||||
hs->flags |= F_ERROR | F_ERROR_LOCK;
|
||||
} else {
|
||||
uint8_t *table_end, op = opcode;
|
||||
if (hs->opcode2) {
|
||||
ht = hde64_table + DELTA_OP2_LOCK_OK;
|
||||
table_end = ht + DELTA_OP_ONLY_MEM - DELTA_OP2_LOCK_OK;
|
||||
} else {
|
||||
ht = hde64_table + DELTA_OP_LOCK_OK;
|
||||
table_end = ht + DELTA_OP2_LOCK_OK - DELTA_OP_LOCK_OK;
|
||||
op &= -2;
|
||||
}
|
||||
for (; ht != table_end; ht++)
|
||||
if (*ht++ == op) {
|
||||
if (!((*ht << m_reg) & 0x80))
|
||||
goto no_lock_error;
|
||||
else
|
||||
break;
|
||||
}
|
||||
hs->flags |= F_ERROR | F_ERROR_LOCK;
|
||||
no_lock_error:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
if (hs->opcode2) {
|
||||
switch (opcode) {
|
||||
case 0x20: case 0x22:
|
||||
m_mod = 3;
|
||||
if (m_reg > 4 || m_reg == 1)
|
||||
goto error_operand;
|
||||
else
|
||||
goto no_error_operand;
|
||||
case 0x21: case 0x23:
|
||||
m_mod = 3;
|
||||
if (m_reg == 4 || m_reg == 5)
|
||||
goto error_operand;
|
||||
else
|
||||
goto no_error_operand;
|
||||
}
|
||||
} else {
|
||||
switch (opcode) {
|
||||
case 0x8c:
|
||||
if (m_reg > 5)
|
||||
goto error_operand;
|
||||
else
|
||||
goto no_error_operand;
|
||||
case 0x8e:
|
||||
if (m_reg == 1 || m_reg > 5)
|
||||
goto error_operand;
|
||||
else
|
||||
goto no_error_operand;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_mod == 3) {
|
||||
uint8_t *table_end;
|
||||
if (hs->opcode2) {
|
||||
ht = hde64_table + DELTA_OP2_ONLY_MEM;
|
||||
table_end = ht + sizeof(hde64_table) - DELTA_OP2_ONLY_MEM;
|
||||
} else {
|
||||
ht = hde64_table + DELTA_OP_ONLY_MEM;
|
||||
table_end = ht + DELTA_OP2_ONLY_MEM - DELTA_OP_ONLY_MEM;
|
||||
}
|
||||
for (; ht != table_end; ht += 2)
|
||||
if (*ht++ == opcode) {
|
||||
if ((*ht++ & pref) && !((*ht << m_reg) & 0x80))
|
||||
goto error_operand;
|
||||
else
|
||||
break;
|
||||
}
|
||||
goto no_error_operand;
|
||||
} else if (hs->opcode2) {
|
||||
switch (opcode) {
|
||||
case 0x50: case 0xd7: case 0xf7:
|
||||
if (pref & (PRE_NONE | PRE_66))
|
||||
goto error_operand;
|
||||
break;
|
||||
case 0xd6:
|
||||
if (pref & (PRE_F2 | PRE_F3))
|
||||
goto error_operand;
|
||||
break;
|
||||
case 0xc5:
|
||||
goto error_operand;
|
||||
}
|
||||
goto no_error_operand;
|
||||
} else
|
||||
goto no_error_operand;
|
||||
|
||||
error_operand:
|
||||
hs->flags |= F_ERROR | F_ERROR_OPERAND;
|
||||
no_error_operand:
|
||||
|
||||
c = *p++;
|
||||
if (m_reg <= 1) {
|
||||
if (opcode == 0xf6)
|
||||
cflags |= C_IMM8;
|
||||
else if (opcode == 0xf7)
|
||||
cflags |= C_IMM_P66;
|
||||
}
|
||||
|
||||
switch (m_mod) {
|
||||
case 0:
|
||||
if (pref & PRE_67) {
|
||||
if (m_rm == 6)
|
||||
disp_size = 2;
|
||||
} else
|
||||
if (m_rm == 5)
|
||||
disp_size = 4;
|
||||
break;
|
||||
case 1:
|
||||
disp_size = 1;
|
||||
break;
|
||||
case 2:
|
||||
disp_size = 2;
|
||||
if (!(pref & PRE_67))
|
||||
disp_size <<= 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_mod != 3 && m_rm == 4) {
|
||||
hs->flags |= F_SIB;
|
||||
p++;
|
||||
hs->sib = c;
|
||||
hs->sib_scale = c >> 6;
|
||||
hs->sib_index = (c & 0x3f) >> 3;
|
||||
if ((hs->sib_base = c & 7) == 5 && !(m_mod & 1))
|
||||
disp_size = 4;
|
||||
}
|
||||
|
||||
p--;
|
||||
switch (disp_size) {
|
||||
case 1:
|
||||
hs->flags |= F_DISP8;
|
||||
hs->disp.disp8 = *p;
|
||||
break;
|
||||
case 2:
|
||||
hs->flags |= F_DISP16;
|
||||
hs->disp.disp16 = *(uint16_t *)p;
|
||||
break;
|
||||
case 4:
|
||||
hs->flags |= F_DISP32;
|
||||
hs->disp.disp32 = *(uint32_t *)p;
|
||||
break;
|
||||
}
|
||||
p += disp_size;
|
||||
} else if (pref & PRE_LOCK)
|
||||
hs->flags |= F_ERROR | F_ERROR_LOCK;
|
||||
|
||||
if (cflags & C_IMM_P66) {
|
||||
if (cflags & C_REL32) {
|
||||
if (pref & PRE_66) {
|
||||
hs->flags |= F_IMM16 | F_RELATIVE;
|
||||
hs->imm.imm16 = *(uint16_t *)p;
|
||||
p += 2;
|
||||
goto disasm_done;
|
||||
}
|
||||
goto rel32_ok;
|
||||
}
|
||||
if (op64) {
|
||||
hs->flags |= F_IMM64;
|
||||
hs->imm.imm64 = *(uint64_t *)p;
|
||||
p += 8;
|
||||
} else if (!(pref & PRE_66)) {
|
||||
hs->flags |= F_IMM32;
|
||||
hs->imm.imm32 = *(uint32_t *)p;
|
||||
p += 4;
|
||||
} else
|
||||
goto imm16_ok;
|
||||
}
|
||||
|
||||
|
||||
if (cflags & C_IMM16) {
|
||||
imm16_ok:
|
||||
hs->flags |= F_IMM16;
|
||||
hs->imm.imm16 = *(uint16_t *)p;
|
||||
p += 2;
|
||||
}
|
||||
if (cflags & C_IMM8) {
|
||||
hs->flags |= F_IMM8;
|
||||
hs->imm.imm8 = *p++;
|
||||
}
|
||||
|
||||
if (cflags & C_REL32) {
|
||||
rel32_ok:
|
||||
hs->flags |= F_IMM32 | F_RELATIVE;
|
||||
hs->imm.imm32 = *(uint32_t *)p;
|
||||
p += 4;
|
||||
} else if (cflags & C_REL8) {
|
||||
hs->flags |= F_IMM8 | F_RELATIVE;
|
||||
hs->imm.imm8 = *p++;
|
||||
}
|
||||
|
||||
disasm_done:
|
||||
|
||||
if ((hs->len = (uint8_t)(p-(uint8_t *)code)) > 15) {
|
||||
hs->flags |= F_ERROR | F_ERROR_LENGTH;
|
||||
hs->len = 15;
|
||||
}
|
||||
|
||||
return (unsigned int)hs->len;
|
||||
}
|
||||
|
||||
#endif // defined(_M_X64) || defined(__x86_64__)
|
||||
Vendored
+112
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Hacker Disassembler Engine 64
|
||||
* Copyright (c) 2008-2009, Vyacheslav Patkov.
|
||||
* All rights reserved.
|
||||
*
|
||||
* hde64.h: C/C++ header file
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HDE64_H_
|
||||
#define _HDE64_H_
|
||||
|
||||
/* stdint.h - C99 standard header
|
||||
* http://en.wikipedia.org/wiki/stdint.h
|
||||
*
|
||||
* if your compiler doesn't contain "stdint.h" header (for
|
||||
* example, Microsoft Visual C++), you can download file:
|
||||
* http://www.azillionmonkeys.com/qed/pstdint.h
|
||||
* and change next line to:
|
||||
* #include "pstdint.h"
|
||||
*/
|
||||
#include "pstdint.h"
|
||||
|
||||
#define F_MODRM 0x00000001
|
||||
#define F_SIB 0x00000002
|
||||
#define F_IMM8 0x00000004
|
||||
#define F_IMM16 0x00000008
|
||||
#define F_IMM32 0x00000010
|
||||
#define F_IMM64 0x00000020
|
||||
#define F_DISP8 0x00000040
|
||||
#define F_DISP16 0x00000080
|
||||
#define F_DISP32 0x00000100
|
||||
#define F_RELATIVE 0x00000200
|
||||
#define F_ERROR 0x00001000
|
||||
#define F_ERROR_OPCODE 0x00002000
|
||||
#define F_ERROR_LENGTH 0x00004000
|
||||
#define F_ERROR_LOCK 0x00008000
|
||||
#define F_ERROR_OPERAND 0x00010000
|
||||
#define F_PREFIX_REPNZ 0x01000000
|
||||
#define F_PREFIX_REPX 0x02000000
|
||||
#define F_PREFIX_REP 0x03000000
|
||||
#define F_PREFIX_66 0x04000000
|
||||
#define F_PREFIX_67 0x08000000
|
||||
#define F_PREFIX_LOCK 0x10000000
|
||||
#define F_PREFIX_SEG 0x20000000
|
||||
#define F_PREFIX_REX 0x40000000
|
||||
#define F_PREFIX_ANY 0x7f000000
|
||||
|
||||
#define PREFIX_SEGMENT_CS 0x2e
|
||||
#define PREFIX_SEGMENT_SS 0x36
|
||||
#define PREFIX_SEGMENT_DS 0x3e
|
||||
#define PREFIX_SEGMENT_ES 0x26
|
||||
#define PREFIX_SEGMENT_FS 0x64
|
||||
#define PREFIX_SEGMENT_GS 0x65
|
||||
#define PREFIX_LOCK 0xf0
|
||||
#define PREFIX_REPNZ 0xf2
|
||||
#define PREFIX_REPX 0xf3
|
||||
#define PREFIX_OPERAND_SIZE 0x66
|
||||
#define PREFIX_ADDRESS_SIZE 0x67
|
||||
|
||||
#pragma pack(push,1)
|
||||
|
||||
typedef struct {
|
||||
uint8_t len;
|
||||
uint8_t p_rep;
|
||||
uint8_t p_lock;
|
||||
uint8_t p_seg;
|
||||
uint8_t p_66;
|
||||
uint8_t p_67;
|
||||
uint8_t rex;
|
||||
uint8_t rex_w;
|
||||
uint8_t rex_r;
|
||||
uint8_t rex_x;
|
||||
uint8_t rex_b;
|
||||
uint8_t opcode;
|
||||
uint8_t opcode2;
|
||||
uint8_t modrm;
|
||||
uint8_t modrm_mod;
|
||||
uint8_t modrm_reg;
|
||||
uint8_t modrm_rm;
|
||||
uint8_t sib;
|
||||
uint8_t sib_scale;
|
||||
uint8_t sib_index;
|
||||
uint8_t sib_base;
|
||||
union {
|
||||
uint8_t imm8;
|
||||
uint16_t imm16;
|
||||
uint32_t imm32;
|
||||
uint64_t imm64;
|
||||
} imm;
|
||||
union {
|
||||
uint8_t disp8;
|
||||
uint16_t disp16;
|
||||
uint32_t disp32;
|
||||
} disp;
|
||||
uint32_t flags;
|
||||
} hde64s;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* __cdecl */
|
||||
unsigned int hde64_disasm(const void *code, hde64s *hs);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _HDE64_H_ */
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||
* Copyright (C) 2009-2017 Tsuda Kageyu. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
// Integer types for HDE.
|
||||
typedef INT8 int8_t;
|
||||
typedef INT16 int16_t;
|
||||
typedef INT32 int32_t;
|
||||
typedef INT64 int64_t;
|
||||
typedef UINT8 uint8_t;
|
||||
typedef UINT16 uint16_t;
|
||||
typedef UINT32 uint32_t;
|
||||
typedef UINT64 uint64_t;
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Hacker Disassembler Engine 64 C
|
||||
* Copyright (c) 2008-2009, Vyacheslav Patkov.
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#define C_NONE 0x00
|
||||
#define C_MODRM 0x01
|
||||
#define C_IMM8 0x02
|
||||
#define C_IMM16 0x04
|
||||
#define C_IMM_P66 0x10
|
||||
#define C_REL8 0x20
|
||||
#define C_REL32 0x40
|
||||
#define C_GROUP 0x80
|
||||
#define C_ERROR 0xff
|
||||
|
||||
#define PRE_ANY 0x00
|
||||
#define PRE_NONE 0x01
|
||||
#define PRE_F2 0x02
|
||||
#define PRE_F3 0x04
|
||||
#define PRE_66 0x08
|
||||
#define PRE_67 0x10
|
||||
#define PRE_LOCK 0x20
|
||||
#define PRE_SEG 0x40
|
||||
#define PRE_ALL 0xff
|
||||
|
||||
#define DELTA_OPCODES 0x4a
|
||||
#define DELTA_FPU_REG 0xfd
|
||||
#define DELTA_FPU_MODRM 0x104
|
||||
#define DELTA_PREFIXES 0x13c
|
||||
#define DELTA_OP_LOCK_OK 0x1ae
|
||||
#define DELTA_OP2_LOCK_OK 0x1c6
|
||||
#define DELTA_OP_ONLY_MEM 0x1d8
|
||||
#define DELTA_OP2_ONLY_MEM 0x1e7
|
||||
|
||||
unsigned char hde64_table[] = {
|
||||
0xa5,0xaa,0xa5,0xb8,0xa5,0xaa,0xa5,0xaa,0xa5,0xb8,0xa5,0xb8,0xa5,0xb8,0xa5,
|
||||
0xb8,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xac,0xc0,0xcc,0xc0,0xa1,0xa1,
|
||||
0xa1,0xa1,0xb1,0xa5,0xa5,0xa6,0xc0,0xc0,0xd7,0xda,0xe0,0xc0,0xe4,0xc0,0xea,
|
||||
0xea,0xe0,0xe0,0x98,0xc8,0xee,0xf1,0xa5,0xd3,0xa5,0xa5,0xa1,0xea,0x9e,0xc0,
|
||||
0xc0,0xc2,0xc0,0xe6,0x03,0x7f,0x11,0x7f,0x01,0x7f,0x01,0x3f,0x01,0x01,0xab,
|
||||
0x8b,0x90,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x92,0x5b,0x5b,0x76,0x90,0x92,0x92,
|
||||
0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x6a,0x73,0x90,
|
||||
0x5b,0x52,0x52,0x52,0x52,0x5b,0x5b,0x5b,0x5b,0x77,0x7c,0x77,0x85,0x5b,0x5b,
|
||||
0x70,0x5b,0x7a,0xaf,0x76,0x76,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,
|
||||
0x5b,0x5b,0x86,0x01,0x03,0x01,0x04,0x03,0xd5,0x03,0xd5,0x03,0xcc,0x01,0xbc,
|
||||
0x03,0xf0,0x03,0x03,0x04,0x00,0x50,0x50,0x50,0x50,0xff,0x20,0x20,0x20,0x20,
|
||||
0x01,0x01,0x01,0x01,0xc4,0x02,0x10,0xff,0xff,0xff,0x01,0x00,0x03,0x11,0xff,
|
||||
0x03,0xc4,0xc6,0xc8,0x02,0x10,0x00,0xff,0xcc,0x01,0x01,0x01,0x00,0x00,0x00,
|
||||
0x00,0x01,0x01,0x03,0x01,0xff,0xff,0xc0,0xc2,0x10,0x11,0x02,0x03,0x01,0x01,
|
||||
0x01,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0xff,0xff,0xff,0x10,
|
||||
0x10,0x10,0x10,0x02,0x10,0x00,0x00,0xc6,0xc8,0x02,0x02,0x02,0x02,0x06,0x00,
|
||||
0x04,0x00,0x02,0xff,0x00,0xc0,0xc2,0x01,0x01,0x03,0x03,0x03,0xca,0x40,0x00,
|
||||
0x0a,0x00,0x04,0x00,0x00,0x00,0x00,0x7f,0x00,0x33,0x01,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0xff,0xbf,0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0xff,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,
|
||||
0x00,0x00,0x00,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x00,0x00,
|
||||
0xff,0x40,0x40,0x40,0x40,0x41,0x49,0x40,0x40,0x40,0x40,0x4c,0x42,0x40,0x40,
|
||||
0x40,0x40,0x40,0x40,0x40,0x40,0x4f,0x44,0x53,0x40,0x40,0x40,0x44,0x57,0x43,
|
||||
0x5c,0x40,0x60,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
|
||||
0x40,0x40,0x64,0x66,0x6e,0x6b,0x40,0x40,0x6a,0x46,0x40,0x40,0x44,0x46,0x40,
|
||||
0x40,0x5b,0x44,0x40,0x40,0x00,0x00,0x00,0x00,0x06,0x06,0x06,0x06,0x01,0x06,
|
||||
0x06,0x02,0x06,0x06,0x00,0x06,0x00,0x0a,0x0a,0x00,0x00,0x00,0x02,0x07,0x07,
|
||||
0x06,0x02,0x0d,0x06,0x06,0x06,0x0e,0x05,0x05,0x02,0x02,0x00,0x00,0x04,0x04,
|
||||
0x04,0x04,0x05,0x06,0x06,0x06,0x00,0x00,0x00,0x0e,0x00,0x00,0x08,0x00,0x10,
|
||||
0x00,0x18,0x00,0x20,0x00,0x28,0x00,0x30,0x00,0x80,0x01,0x82,0x01,0x86,0x00,
|
||||
0xf6,0xcf,0xfe,0x3f,0xab,0x00,0xb0,0x00,0xb1,0x00,0xb3,0x00,0xba,0xf8,0xbb,
|
||||
0x00,0xc0,0x00,0xc1,0x00,0xc7,0xbf,0x62,0xff,0x00,0x8d,0xff,0x00,0xc4,0xff,
|
||||
0x00,0xc5,0xff,0x00,0xff,0xff,0xeb,0x01,0xff,0x0e,0x12,0x08,0x00,0x13,0x09,
|
||||
0x00,0x16,0x08,0x00,0x17,0x09,0x00,0x2b,0x09,0x00,0xae,0xff,0x07,0xb2,0xff,
|
||||
0x00,0xb4,0xff,0x00,0xb5,0xff,0x00,0xc3,0x01,0x00,0xc7,0xff,0xbf,0xe7,0x08,
|
||||
0x00,0xf0,0x02,0x00
|
||||
};
|
||||
Vendored
+939
@@ -0,0 +1,939 @@
|
||||
/*
|
||||
* MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||
* Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <tlhelp32.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "../include/MinHook.h"
|
||||
#include "buffer.h"
|
||||
#include "trampoline.h"
|
||||
|
||||
#ifndef ARRAYSIZE
|
||||
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
|
||||
#endif
|
||||
|
||||
// Initial capacity of the HOOK_ENTRY buffer.
|
||||
#define INITIAL_HOOK_CAPACITY 32
|
||||
|
||||
// Initial capacity of the thread IDs buffer.
|
||||
#define INITIAL_THREAD_CAPACITY 128
|
||||
|
||||
// Special hook position values.
|
||||
#define INVALID_HOOK_POS UINT_MAX
|
||||
#define ALL_HOOKS_POS UINT_MAX
|
||||
|
||||
// Freeze() action argument defines.
|
||||
#define ACTION_DISABLE 0
|
||||
#define ACTION_ENABLE 1
|
||||
#define ACTION_APPLY_QUEUED 2
|
||||
|
||||
// Thread access rights for suspending/resuming threads.
|
||||
#define THREAD_ACCESS \
|
||||
(THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION | THREAD_SET_CONTEXT)
|
||||
|
||||
// Hook information.
|
||||
typedef struct _HOOK_ENTRY
|
||||
{
|
||||
LPVOID pTarget; // Address of the target function.
|
||||
LPVOID pDetour; // Address of the detour or relay function.
|
||||
LPVOID pTrampoline; // Address of the trampoline function.
|
||||
UINT8 backup[8]; // Original prologue of the target function.
|
||||
|
||||
UINT8 patchAbove : 1; // Uses the hot patch area.
|
||||
UINT8 isEnabled : 1; // Enabled.
|
||||
UINT8 queueEnable : 1; // Queued for enabling/disabling when != isEnabled.
|
||||
|
||||
UINT nIP : 4; // Count of the instruction boundaries.
|
||||
UINT8 oldIPs[8]; // Instruction boundaries of the target function.
|
||||
UINT8 newIPs[8]; // Instruction boundaries of the trampoline function.
|
||||
} HOOK_ENTRY, *PHOOK_ENTRY;
|
||||
|
||||
// Suspended threads for Freeze()/Unfreeze().
|
||||
typedef struct _FROZEN_THREADS
|
||||
{
|
||||
LPDWORD pItems; // Data heap
|
||||
UINT capacity; // Size of allocated data heap, items
|
||||
UINT size; // Actual number of data items
|
||||
} FROZEN_THREADS, *PFROZEN_THREADS;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Global Variables:
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
// Spin lock flag for EnterSpinLock()/LeaveSpinLock().
|
||||
static volatile LONG g_isLocked = FALSE;
|
||||
|
||||
// Private heap handle. If not NULL, this library is initialized.
|
||||
static HANDLE g_hHeap = NULL;
|
||||
|
||||
// Hook entries.
|
||||
static struct
|
||||
{
|
||||
PHOOK_ENTRY pItems; // Data heap
|
||||
UINT capacity; // Size of allocated data heap, items
|
||||
UINT size; // Actual number of data items
|
||||
} g_hooks;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Returns INVALID_HOOK_POS if not found.
|
||||
static UINT FindHookEntry(LPVOID pTarget)
|
||||
{
|
||||
UINT i;
|
||||
for (i = 0; i < g_hooks.size; ++i)
|
||||
{
|
||||
if ((ULONG_PTR)pTarget == (ULONG_PTR)g_hooks.pItems[i].pTarget)
|
||||
return i;
|
||||
}
|
||||
|
||||
return INVALID_HOOK_POS;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static PHOOK_ENTRY AddHookEntry()
|
||||
{
|
||||
if (g_hooks.pItems == NULL)
|
||||
{
|
||||
g_hooks.capacity = INITIAL_HOOK_CAPACITY;
|
||||
g_hooks.pItems = (PHOOK_ENTRY)HeapAlloc(
|
||||
g_hHeap, 0, g_hooks.capacity * sizeof(HOOK_ENTRY));
|
||||
if (g_hooks.pItems == NULL)
|
||||
return NULL;
|
||||
}
|
||||
else if (g_hooks.size >= g_hooks.capacity)
|
||||
{
|
||||
PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc(
|
||||
g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity * 2) * sizeof(HOOK_ENTRY));
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
|
||||
g_hooks.capacity *= 2;
|
||||
g_hooks.pItems = p;
|
||||
}
|
||||
|
||||
return &g_hooks.pItems[g_hooks.size++];
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static VOID DeleteHookEntry(UINT pos)
|
||||
{
|
||||
if (pos < g_hooks.size - 1)
|
||||
g_hooks.pItems[pos] = g_hooks.pItems[g_hooks.size - 1];
|
||||
|
||||
g_hooks.size--;
|
||||
|
||||
if (g_hooks.capacity / 2 >= INITIAL_HOOK_CAPACITY && g_hooks.capacity / 2 >= g_hooks.size)
|
||||
{
|
||||
PHOOK_ENTRY p = (PHOOK_ENTRY)HeapReAlloc(
|
||||
g_hHeap, 0, g_hooks.pItems, (g_hooks.capacity / 2) * sizeof(HOOK_ENTRY));
|
||||
if (p == NULL)
|
||||
return;
|
||||
|
||||
g_hooks.capacity /= 2;
|
||||
g_hooks.pItems = p;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static DWORD_PTR FindOldIP(PHOOK_ENTRY pHook, DWORD_PTR ip)
|
||||
{
|
||||
UINT i;
|
||||
|
||||
if (pHook->patchAbove && ip == ((DWORD_PTR)pHook->pTarget - sizeof(JMP_REL)))
|
||||
return (DWORD_PTR)pHook->pTarget;
|
||||
|
||||
for (i = 0; i < pHook->nIP; ++i)
|
||||
{
|
||||
if (ip == ((DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i]))
|
||||
return (DWORD_PTR)pHook->pTarget + pHook->oldIPs[i];
|
||||
}
|
||||
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
// Check relay function.
|
||||
if (ip == (DWORD_PTR)pHook->pDetour)
|
||||
return (DWORD_PTR)pHook->pTarget;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static DWORD_PTR FindNewIP(PHOOK_ENTRY pHook, DWORD_PTR ip)
|
||||
{
|
||||
UINT i;
|
||||
for (i = 0; i < pHook->nIP; ++i)
|
||||
{
|
||||
if (ip == ((DWORD_PTR)pHook->pTarget + pHook->oldIPs[i]))
|
||||
return (DWORD_PTR)pHook->pTrampoline + pHook->newIPs[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static VOID ProcessThreadIPs(HANDLE hThread, UINT pos, UINT action)
|
||||
{
|
||||
// If the thread suspended in the overwritten area,
|
||||
// move IP to the proper address.
|
||||
|
||||
CONTEXT c;
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
DWORD64 *pIP = &c.Rip;
|
||||
#else
|
||||
DWORD *pIP = &c.Eip;
|
||||
#endif
|
||||
UINT count;
|
||||
|
||||
c.ContextFlags = CONTEXT_CONTROL;
|
||||
if (!GetThreadContext(hThread, &c))
|
||||
return;
|
||||
|
||||
if (pos == ALL_HOOKS_POS)
|
||||
{
|
||||
pos = 0;
|
||||
count = g_hooks.size;
|
||||
}
|
||||
else
|
||||
{
|
||||
count = pos + 1;
|
||||
}
|
||||
|
||||
for (; pos < count; ++pos)
|
||||
{
|
||||
PHOOK_ENTRY pHook = &g_hooks.pItems[pos];
|
||||
BOOL enable;
|
||||
DWORD_PTR ip;
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case ACTION_DISABLE:
|
||||
enable = FALSE;
|
||||
break;
|
||||
|
||||
case ACTION_ENABLE:
|
||||
enable = TRUE;
|
||||
break;
|
||||
|
||||
default: // ACTION_APPLY_QUEUED
|
||||
enable = pHook->queueEnable;
|
||||
break;
|
||||
}
|
||||
if (pHook->isEnabled == enable)
|
||||
continue;
|
||||
|
||||
if (enable)
|
||||
ip = FindNewIP(pHook, *pIP);
|
||||
else
|
||||
ip = FindOldIP(pHook, *pIP);
|
||||
|
||||
if (ip != 0)
|
||||
{
|
||||
*pIP = ip;
|
||||
SetThreadContext(hThread, &c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static BOOL EnumerateThreads(PFROZEN_THREADS pThreads)
|
||||
{
|
||||
BOOL succeeded = FALSE;
|
||||
|
||||
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
|
||||
if (hSnapshot != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
THREADENTRY32 te;
|
||||
te.dwSize = sizeof(THREADENTRY32);
|
||||
if (Thread32First(hSnapshot, &te))
|
||||
{
|
||||
succeeded = TRUE;
|
||||
do
|
||||
{
|
||||
if (te.dwSize >= (FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(DWORD))
|
||||
&& te.th32OwnerProcessID == GetCurrentProcessId()
|
||||
&& te.th32ThreadID != GetCurrentThreadId())
|
||||
{
|
||||
if (pThreads->pItems == NULL)
|
||||
{
|
||||
pThreads->capacity = INITIAL_THREAD_CAPACITY;
|
||||
pThreads->pItems
|
||||
= (LPDWORD)HeapAlloc(g_hHeap, 0, pThreads->capacity * sizeof(DWORD));
|
||||
if (pThreads->pItems == NULL)
|
||||
{
|
||||
succeeded = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (pThreads->size >= pThreads->capacity)
|
||||
{
|
||||
LPDWORD p;
|
||||
pThreads->capacity *= 2;
|
||||
p = (LPDWORD)HeapReAlloc(
|
||||
g_hHeap, 0, pThreads->pItems, pThreads->capacity * sizeof(DWORD));
|
||||
if (p == NULL)
|
||||
{
|
||||
succeeded = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
pThreads->pItems = p;
|
||||
}
|
||||
pThreads->pItems[pThreads->size++] = te.th32ThreadID;
|
||||
}
|
||||
|
||||
te.dwSize = sizeof(THREADENTRY32);
|
||||
} while (Thread32Next(hSnapshot, &te));
|
||||
|
||||
if (succeeded && GetLastError() != ERROR_NO_MORE_FILES)
|
||||
succeeded = FALSE;
|
||||
|
||||
if (!succeeded && pThreads->pItems != NULL)
|
||||
{
|
||||
HeapFree(g_hHeap, 0, pThreads->pItems);
|
||||
pThreads->pItems = NULL;
|
||||
}
|
||||
}
|
||||
CloseHandle(hSnapshot);
|
||||
}
|
||||
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static MH_STATUS Freeze(PFROZEN_THREADS pThreads, UINT pos, UINT action)
|
||||
{
|
||||
MH_STATUS status = MH_OK;
|
||||
|
||||
pThreads->pItems = NULL;
|
||||
pThreads->capacity = 0;
|
||||
pThreads->size = 0;
|
||||
if (!EnumerateThreads(pThreads))
|
||||
{
|
||||
status = MH_ERROR_MEMORY_ALLOC;
|
||||
}
|
||||
else if (pThreads->pItems != NULL)
|
||||
{
|
||||
UINT i;
|
||||
for (i = 0; i < pThreads->size; ++i)
|
||||
{
|
||||
HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, pThreads->pItems[i]);
|
||||
BOOL suspended = FALSE;
|
||||
if (hThread != NULL)
|
||||
{
|
||||
DWORD result = SuspendThread(hThread);
|
||||
if (result != 0xFFFFFFFF)
|
||||
{
|
||||
suspended = TRUE;
|
||||
ProcessThreadIPs(hThread, pos, action);
|
||||
}
|
||||
CloseHandle(hThread);
|
||||
}
|
||||
|
||||
if (!suspended)
|
||||
{
|
||||
// Mark thread as not suspended, so it's not resumed later on.
|
||||
pThreads->pItems[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static VOID Unfreeze(PFROZEN_THREADS pThreads)
|
||||
{
|
||||
if (pThreads->pItems != NULL)
|
||||
{
|
||||
UINT i;
|
||||
for (i = 0; i < pThreads->size; ++i)
|
||||
{
|
||||
DWORD threadId = pThreads->pItems[i];
|
||||
if (threadId != 0)
|
||||
{
|
||||
HANDLE hThread = OpenThread(THREAD_ACCESS, FALSE, threadId);
|
||||
if (hThread != NULL)
|
||||
{
|
||||
ResumeThread(hThread);
|
||||
CloseHandle(hThread);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HeapFree(g_hHeap, 0, pThreads->pItems);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static MH_STATUS EnableHookLL(UINT pos, BOOL enable)
|
||||
{
|
||||
PHOOK_ENTRY pHook = &g_hooks.pItems[pos];
|
||||
DWORD oldProtect;
|
||||
SIZE_T patchSize = sizeof(JMP_REL);
|
||||
LPBYTE pPatchTarget = (LPBYTE)pHook->pTarget;
|
||||
|
||||
if (pHook->patchAbove)
|
||||
{
|
||||
pPatchTarget -= sizeof(JMP_REL);
|
||||
patchSize += sizeof(JMP_REL_SHORT);
|
||||
}
|
||||
|
||||
if (!VirtualProtect(pPatchTarget, patchSize, PAGE_EXECUTE_READWRITE, &oldProtect))
|
||||
return MH_ERROR_MEMORY_PROTECT;
|
||||
|
||||
if (enable)
|
||||
{
|
||||
PJMP_REL pJmp = (PJMP_REL)pPatchTarget;
|
||||
pJmp->opcode = 0xE9;
|
||||
pJmp->operand = (INT32)((LPBYTE)pHook->pDetour - (pPatchTarget + sizeof(JMP_REL)));
|
||||
|
||||
if (pHook->patchAbove)
|
||||
{
|
||||
PJMP_REL_SHORT pShortJmp = (PJMP_REL_SHORT)pHook->pTarget;
|
||||
pShortJmp->opcode = 0xEB;
|
||||
pShortJmp->operand = (INT8)(0 - (sizeof(JMP_REL_SHORT) + sizeof(JMP_REL)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pHook->patchAbove)
|
||||
memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL) + sizeof(JMP_REL_SHORT));
|
||||
else
|
||||
memcpy(pPatchTarget, pHook->backup, sizeof(JMP_REL));
|
||||
}
|
||||
|
||||
VirtualProtect(pPatchTarget, patchSize, oldProtect, &oldProtect);
|
||||
|
||||
// Just-in-case measure.
|
||||
FlushInstructionCache(GetCurrentProcess(), pPatchTarget, patchSize);
|
||||
|
||||
pHook->isEnabled = enable;
|
||||
pHook->queueEnable = enable;
|
||||
|
||||
return MH_OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static MH_STATUS EnableAllHooksLL(BOOL enable)
|
||||
{
|
||||
MH_STATUS status = MH_OK;
|
||||
UINT i, first = INVALID_HOOK_POS;
|
||||
|
||||
for (i = 0; i < g_hooks.size; ++i)
|
||||
{
|
||||
if (g_hooks.pItems[i].isEnabled != enable)
|
||||
{
|
||||
first = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (first != INVALID_HOOK_POS)
|
||||
{
|
||||
FROZEN_THREADS threads;
|
||||
status = Freeze(&threads, ALL_HOOKS_POS, enable ? ACTION_ENABLE : ACTION_DISABLE);
|
||||
if (status == MH_OK)
|
||||
{
|
||||
for (i = first; i < g_hooks.size; ++i)
|
||||
{
|
||||
if (g_hooks.pItems[i].isEnabled != enable)
|
||||
{
|
||||
status = EnableHookLL(i, enable);
|
||||
if (status != MH_OK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Unfreeze(&threads);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static VOID EnterSpinLock(VOID)
|
||||
{
|
||||
SIZE_T spinCount = 0;
|
||||
|
||||
// Wait until the flag is FALSE.
|
||||
while (InterlockedCompareExchange(&g_isLocked, TRUE, FALSE) != FALSE)
|
||||
{
|
||||
// No need to generate a memory barrier here, since InterlockedCompareExchange()
|
||||
// generates a full memory barrier itself.
|
||||
|
||||
// Prevent the loop from being too busy.
|
||||
if (spinCount < 32)
|
||||
Sleep(0);
|
||||
else
|
||||
Sleep(1);
|
||||
|
||||
spinCount++;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static VOID LeaveSpinLock(VOID)
|
||||
{
|
||||
// No need to generate a memory barrier here, since InterlockedExchange()
|
||||
// generates a full memory barrier itself.
|
||||
|
||||
InterlockedExchange(&g_isLocked, FALSE);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_Initialize(VOID)
|
||||
{
|
||||
MH_STATUS status = MH_OK;
|
||||
|
||||
EnterSpinLock();
|
||||
|
||||
if (g_hHeap == NULL)
|
||||
{
|
||||
g_hHeap = HeapCreate(0, 0, 0);
|
||||
if (g_hHeap != NULL)
|
||||
{
|
||||
// Initialize the internal function buffer.
|
||||
InitializeBuffer();
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_MEMORY_ALLOC;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_ALREADY_INITIALIZED;
|
||||
}
|
||||
|
||||
LeaveSpinLock();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_Uninitialize(VOID)
|
||||
{
|
||||
MH_STATUS status = MH_OK;
|
||||
|
||||
EnterSpinLock();
|
||||
|
||||
if (g_hHeap != NULL)
|
||||
{
|
||||
status = EnableAllHooksLL(FALSE);
|
||||
if (status == MH_OK)
|
||||
{
|
||||
// Free the internal function buffer.
|
||||
|
||||
// HeapFree is actually not required, but some tools detect a false
|
||||
// memory leak without HeapFree.
|
||||
|
||||
UninitializeBuffer();
|
||||
|
||||
HeapFree(g_hHeap, 0, g_hooks.pItems);
|
||||
HeapDestroy(g_hHeap);
|
||||
|
||||
g_hHeap = NULL;
|
||||
|
||||
g_hooks.pItems = NULL;
|
||||
g_hooks.capacity = 0;
|
||||
g_hooks.size = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
LeaveSpinLock();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal)
|
||||
{
|
||||
MH_STATUS status = MH_OK;
|
||||
|
||||
EnterSpinLock();
|
||||
|
||||
if (g_hHeap != NULL)
|
||||
{
|
||||
if (IsExecutableAddress(pTarget) && IsExecutableAddress(pDetour))
|
||||
{
|
||||
UINT pos = FindHookEntry(pTarget);
|
||||
if (pos == INVALID_HOOK_POS)
|
||||
{
|
||||
LPVOID pBuffer = AllocateBuffer(pTarget);
|
||||
if (pBuffer != NULL)
|
||||
{
|
||||
TRAMPOLINE ct;
|
||||
|
||||
ct.pTarget = pTarget;
|
||||
ct.pDetour = pDetour;
|
||||
ct.pTrampoline = pBuffer;
|
||||
if (CreateTrampolineFunction(&ct))
|
||||
{
|
||||
PHOOK_ENTRY pHook = AddHookEntry();
|
||||
if (pHook != NULL)
|
||||
{
|
||||
pHook->pTarget = ct.pTarget;
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
pHook->pDetour = ct.pRelay;
|
||||
#else
|
||||
pHook->pDetour = ct.pDetour;
|
||||
#endif
|
||||
pHook->pTrampoline = ct.pTrampoline;
|
||||
pHook->patchAbove = ct.patchAbove;
|
||||
pHook->isEnabled = FALSE;
|
||||
pHook->queueEnable = FALSE;
|
||||
pHook->nIP = ct.nIP;
|
||||
memcpy(pHook->oldIPs, ct.oldIPs, ARRAYSIZE(ct.oldIPs));
|
||||
memcpy(pHook->newIPs, ct.newIPs, ARRAYSIZE(ct.newIPs));
|
||||
|
||||
// Back up the target function.
|
||||
|
||||
if (ct.patchAbove)
|
||||
{
|
||||
memcpy(
|
||||
pHook->backup,
|
||||
(LPBYTE)pTarget - sizeof(JMP_REL),
|
||||
sizeof(JMP_REL) + sizeof(JMP_REL_SHORT));
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(pHook->backup, pTarget, sizeof(JMP_REL));
|
||||
}
|
||||
|
||||
if (ppOriginal != NULL)
|
||||
*ppOriginal = pHook->pTrampoline;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_MEMORY_ALLOC;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
if (status != MH_OK)
|
||||
{
|
||||
FreeBuffer(pBuffer);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_MEMORY_ALLOC;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_ALREADY_CREATED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_NOT_EXECUTABLE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
LeaveSpinLock();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget)
|
||||
{
|
||||
MH_STATUS status = MH_OK;
|
||||
|
||||
EnterSpinLock();
|
||||
|
||||
if (g_hHeap != NULL)
|
||||
{
|
||||
UINT pos = FindHookEntry(pTarget);
|
||||
if (pos != INVALID_HOOK_POS)
|
||||
{
|
||||
if (g_hooks.pItems[pos].isEnabled)
|
||||
{
|
||||
FROZEN_THREADS threads;
|
||||
status = Freeze(&threads, pos, ACTION_DISABLE);
|
||||
if (status == MH_OK)
|
||||
{
|
||||
status = EnableHookLL(pos, FALSE);
|
||||
|
||||
Unfreeze(&threads);
|
||||
}
|
||||
}
|
||||
|
||||
if (status == MH_OK)
|
||||
{
|
||||
FreeBuffer(g_hooks.pItems[pos].pTrampoline);
|
||||
DeleteHookEntry(pos);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_NOT_CREATED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
LeaveSpinLock();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static MH_STATUS EnableHook(LPVOID pTarget, BOOL enable)
|
||||
{
|
||||
MH_STATUS status = MH_OK;
|
||||
|
||||
EnterSpinLock();
|
||||
|
||||
if (g_hHeap != NULL)
|
||||
{
|
||||
if (pTarget == MH_ALL_HOOKS)
|
||||
{
|
||||
status = EnableAllHooksLL(enable);
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT pos = FindHookEntry(pTarget);
|
||||
if (pos != INVALID_HOOK_POS)
|
||||
{
|
||||
if (g_hooks.pItems[pos].isEnabled != enable)
|
||||
{
|
||||
FROZEN_THREADS threads;
|
||||
status = Freeze(&threads, pos, ACTION_ENABLE);
|
||||
if (status == MH_OK)
|
||||
{
|
||||
status = EnableHookLL(pos, enable);
|
||||
|
||||
Unfreeze(&threads);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = enable ? MH_ERROR_ENABLED : MH_ERROR_DISABLED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_NOT_CREATED;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
LeaveSpinLock();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_EnableHook(LPVOID pTarget)
|
||||
{
|
||||
return EnableHook(pTarget, TRUE);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_DisableHook(LPVOID pTarget)
|
||||
{
|
||||
return EnableHook(pTarget, FALSE);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static MH_STATUS QueueHook(LPVOID pTarget, BOOL queueEnable)
|
||||
{
|
||||
MH_STATUS status = MH_OK;
|
||||
|
||||
EnterSpinLock();
|
||||
|
||||
if (g_hHeap != NULL)
|
||||
{
|
||||
if (pTarget == MH_ALL_HOOKS)
|
||||
{
|
||||
UINT i;
|
||||
for (i = 0; i < g_hooks.size; ++i)
|
||||
g_hooks.pItems[i].queueEnable = queueEnable;
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT pos = FindHookEntry(pTarget);
|
||||
if (pos != INVALID_HOOK_POS)
|
||||
{
|
||||
g_hooks.pItems[pos].queueEnable = queueEnable;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_NOT_CREATED;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
LeaveSpinLock();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_QueueEnableHook(LPVOID pTarget)
|
||||
{
|
||||
return QueueHook(pTarget, TRUE);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_QueueDisableHook(LPVOID pTarget)
|
||||
{
|
||||
return QueueHook(pTarget, FALSE);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_ApplyQueued(VOID)
|
||||
{
|
||||
MH_STATUS status = MH_OK;
|
||||
UINT i, first = INVALID_HOOK_POS;
|
||||
|
||||
EnterSpinLock();
|
||||
|
||||
if (g_hHeap != NULL)
|
||||
{
|
||||
for (i = 0; i < g_hooks.size; ++i)
|
||||
{
|
||||
if (g_hooks.pItems[i].isEnabled != g_hooks.pItems[i].queueEnable)
|
||||
{
|
||||
first = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (first != INVALID_HOOK_POS)
|
||||
{
|
||||
FROZEN_THREADS threads;
|
||||
status = Freeze(&threads, ALL_HOOKS_POS, ACTION_APPLY_QUEUED);
|
||||
if (status == MH_OK)
|
||||
{
|
||||
for (i = first; i < g_hooks.size; ++i)
|
||||
{
|
||||
PHOOK_ENTRY pHook = &g_hooks.pItems[i];
|
||||
if (pHook->isEnabled != pHook->queueEnable)
|
||||
{
|
||||
status = EnableHookLL(i, pHook->queueEnable);
|
||||
if (status != MH_OK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Unfreeze(&threads);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = MH_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
LeaveSpinLock();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_CreateHookApiEx(
|
||||
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour,
|
||||
LPVOID *ppOriginal, LPVOID *ppTarget)
|
||||
{
|
||||
HMODULE hModule;
|
||||
LPVOID pTarget;
|
||||
|
||||
hModule = GetModuleHandleW(pszModule);
|
||||
if (hModule == NULL)
|
||||
return MH_ERROR_MODULE_NOT_FOUND;
|
||||
|
||||
pTarget = (LPVOID)GetProcAddress(hModule, pszProcName);
|
||||
if (pTarget == NULL)
|
||||
return MH_ERROR_FUNCTION_NOT_FOUND;
|
||||
|
||||
if (ppTarget != NULL)
|
||||
*ppTarget = pTarget;
|
||||
|
||||
return MH_CreateHook(pTarget, pDetour, ppOriginal);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
MH_STATUS WINAPI MH_CreateHookApi(
|
||||
LPCWSTR pszModule, LPCSTR pszProcName, LPVOID pDetour, LPVOID *ppOriginal)
|
||||
{
|
||||
return MH_CreateHookApiEx(pszModule, pszProcName, pDetour, ppOriginal, NULL);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
const char *WINAPI MH_StatusToString(MH_STATUS status)
|
||||
{
|
||||
#define MH_ST2STR(x) \
|
||||
case x: \
|
||||
return #x;
|
||||
|
||||
switch (status) {
|
||||
MH_ST2STR(MH_UNKNOWN)
|
||||
MH_ST2STR(MH_OK)
|
||||
MH_ST2STR(MH_ERROR_ALREADY_INITIALIZED)
|
||||
MH_ST2STR(MH_ERROR_NOT_INITIALIZED)
|
||||
MH_ST2STR(MH_ERROR_ALREADY_CREATED)
|
||||
MH_ST2STR(MH_ERROR_NOT_CREATED)
|
||||
MH_ST2STR(MH_ERROR_ENABLED)
|
||||
MH_ST2STR(MH_ERROR_DISABLED)
|
||||
MH_ST2STR(MH_ERROR_NOT_EXECUTABLE)
|
||||
MH_ST2STR(MH_ERROR_UNSUPPORTED_FUNCTION)
|
||||
MH_ST2STR(MH_ERROR_MEMORY_ALLOC)
|
||||
MH_ST2STR(MH_ERROR_MEMORY_PROTECT)
|
||||
MH_ST2STR(MH_ERROR_MODULE_NOT_FOUND)
|
||||
MH_ST2STR(MH_ERROR_FUNCTION_NOT_FOUND)
|
||||
}
|
||||
|
||||
#undef MH_ST2STR
|
||||
|
||||
return "(unknown)";
|
||||
}
|
||||
Vendored
+320
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
* MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||
* Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#if defined(_MSC_VER) && !defined(MINHOOK_DISABLE_INTRINSICS)
|
||||
#define ALLOW_INTRINSICS
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#ifndef ARRAYSIZE
|
||||
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
|
||||
#endif
|
||||
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
#include "./hde/hde64.h"
|
||||
typedef hde64s HDE;
|
||||
#define HDE_DISASM(code, hs) hde64_disasm(code, hs)
|
||||
#else
|
||||
#include "./hde/hde32.h"
|
||||
typedef hde32s HDE;
|
||||
#define HDE_DISASM(code, hs) hde32_disasm(code, hs)
|
||||
#endif
|
||||
|
||||
#include "trampoline.h"
|
||||
#include "buffer.h"
|
||||
|
||||
// Maximum size of a trampoline function.
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
#define TRAMPOLINE_MAX_SIZE (MEMORY_SLOT_SIZE - sizeof(JMP_ABS))
|
||||
#else
|
||||
#define TRAMPOLINE_MAX_SIZE MEMORY_SLOT_SIZE
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static BOOL IsCodePadding(LPBYTE pInst, UINT size)
|
||||
{
|
||||
UINT i;
|
||||
|
||||
if (pInst[0] != 0x00 && pInst[0] != 0x90 && pInst[0] != 0xCC)
|
||||
return FALSE;
|
||||
|
||||
for (i = 1; i < size; ++i)
|
||||
{
|
||||
if (pInst[i] != pInst[0])
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
BOOL CreateTrampolineFunction(PTRAMPOLINE ct)
|
||||
{
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
CALL_ABS call = {
|
||||
0xFF, 0x15, 0x00000002, // FF15 00000002: CALL [RIP+8]
|
||||
0xEB, 0x08, // EB 08: JMP +10
|
||||
0x0000000000000000ULL // Absolute destination address
|
||||
};
|
||||
JMP_ABS jmp = {
|
||||
0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6]
|
||||
0x0000000000000000ULL // Absolute destination address
|
||||
};
|
||||
JCC_ABS jcc = {
|
||||
0x70, 0x0E, // 7* 0E: J** +16
|
||||
0xFF, 0x25, 0x00000000, // FF25 00000000: JMP [RIP+6]
|
||||
0x0000000000000000ULL // Absolute destination address
|
||||
};
|
||||
#else
|
||||
CALL_REL call = {
|
||||
0xE8, // E8 xxxxxxxx: CALL +5+xxxxxxxx
|
||||
0x00000000 // Relative destination address
|
||||
};
|
||||
JMP_REL jmp = {
|
||||
0xE9, // E9 xxxxxxxx: JMP +5+xxxxxxxx
|
||||
0x00000000 // Relative destination address
|
||||
};
|
||||
JCC_REL jcc = {
|
||||
0x0F, 0x80, // 0F8* xxxxxxxx: J** +6+xxxxxxxx
|
||||
0x00000000 // Relative destination address
|
||||
};
|
||||
#endif
|
||||
|
||||
UINT8 oldPos = 0;
|
||||
UINT8 newPos = 0;
|
||||
ULONG_PTR jmpDest = 0; // Destination address of an internal jump.
|
||||
BOOL finished = FALSE; // Is the function completed?
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
UINT8 instBuf[16];
|
||||
#endif
|
||||
|
||||
ct->patchAbove = FALSE;
|
||||
ct->nIP = 0;
|
||||
|
||||
do
|
||||
{
|
||||
HDE hs;
|
||||
UINT copySize;
|
||||
LPVOID pCopySrc;
|
||||
ULONG_PTR pOldInst = (ULONG_PTR)ct->pTarget + oldPos;
|
||||
ULONG_PTR pNewInst = (ULONG_PTR)ct->pTrampoline + newPos;
|
||||
|
||||
copySize = HDE_DISASM((LPVOID)pOldInst, &hs);
|
||||
if (hs.flags & F_ERROR)
|
||||
return FALSE;
|
||||
|
||||
pCopySrc = (LPVOID)pOldInst;
|
||||
if (oldPos >= sizeof(JMP_REL))
|
||||
{
|
||||
// The trampoline function is long enough.
|
||||
// Complete the function with the jump to the target function.
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
jmp.address = pOldInst;
|
||||
#else
|
||||
jmp.operand = (INT32)(pOldInst - (pNewInst + sizeof(jmp)));
|
||||
#endif
|
||||
pCopySrc = &jmp;
|
||||
copySize = sizeof(jmp);
|
||||
|
||||
finished = TRUE;
|
||||
}
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
else if ((hs.modrm & 0xC7) == 0x05)
|
||||
{
|
||||
// Instructions using RIP relative addressing. (ModR/M = 00???101B)
|
||||
|
||||
// Modify the RIP relative address.
|
||||
PUINT32 pRelAddr;
|
||||
|
||||
// Avoid using memcpy to reduce the footprint.
|
||||
#ifndef ALLOW_INTRINSICS
|
||||
memcpy(instBuf, (LPBYTE)pOldInst, copySize);
|
||||
#else
|
||||
__movsb(instBuf, (LPBYTE)pOldInst, copySize);
|
||||
#endif
|
||||
pCopySrc = instBuf;
|
||||
|
||||
// Relative address is stored at (instruction length - immediate value length - 4).
|
||||
pRelAddr = (PUINT32)(instBuf + hs.len - ((hs.flags & 0x3C) >> 2) - 4);
|
||||
*pRelAddr
|
||||
= (UINT32)((pOldInst + hs.len + (INT32)hs.disp.disp32) - (pNewInst + hs.len));
|
||||
|
||||
// Complete the function if JMP (FF /4).
|
||||
if (hs.opcode == 0xFF && hs.modrm_reg == 4)
|
||||
finished = TRUE;
|
||||
}
|
||||
#endif
|
||||
else if (hs.opcode == 0xE8)
|
||||
{
|
||||
// Direct relative CALL
|
||||
ULONG_PTR dest = pOldInst + hs.len + (INT32)hs.imm.imm32;
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
call.address = dest;
|
||||
#else
|
||||
call.operand = (INT32)(dest - (pNewInst + sizeof(call)));
|
||||
#endif
|
||||
pCopySrc = &call;
|
||||
copySize = sizeof(call);
|
||||
}
|
||||
else if ((hs.opcode & 0xFD) == 0xE9)
|
||||
{
|
||||
// Direct relative JMP (EB or E9)
|
||||
ULONG_PTR dest = pOldInst + hs.len;
|
||||
|
||||
if (hs.opcode == 0xEB) // isShort jmp
|
||||
dest += (INT8)hs.imm.imm8;
|
||||
else
|
||||
dest += (INT32)hs.imm.imm32;
|
||||
|
||||
// Simply copy an internal jump.
|
||||
if ((ULONG_PTR)ct->pTarget <= dest
|
||||
&& dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL)))
|
||||
{
|
||||
if (jmpDest < dest)
|
||||
jmpDest = dest;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
jmp.address = dest;
|
||||
#else
|
||||
jmp.operand = (INT32)(dest - (pNewInst + sizeof(jmp)));
|
||||
#endif
|
||||
pCopySrc = &jmp;
|
||||
copySize = sizeof(jmp);
|
||||
|
||||
// Exit the function if it is not in the branch.
|
||||
finished = (pOldInst >= jmpDest);
|
||||
}
|
||||
}
|
||||
else if ((hs.opcode & 0xF0) == 0x70
|
||||
|| (hs.opcode & 0xFC) == 0xE0
|
||||
|| (hs.opcode2 & 0xF0) == 0x80)
|
||||
{
|
||||
// Direct relative Jcc
|
||||
ULONG_PTR dest = pOldInst + hs.len;
|
||||
|
||||
if ((hs.opcode & 0xF0) == 0x70 // Jcc
|
||||
|| (hs.opcode & 0xFC) == 0xE0) // LOOPNZ/LOOPZ/LOOP/JECXZ
|
||||
dest += (INT8)hs.imm.imm8;
|
||||
else
|
||||
dest += (INT32)hs.imm.imm32;
|
||||
|
||||
// Simply copy an internal jump.
|
||||
if ((ULONG_PTR)ct->pTarget <= dest
|
||||
&& dest < ((ULONG_PTR)ct->pTarget + sizeof(JMP_REL)))
|
||||
{
|
||||
if (jmpDest < dest)
|
||||
jmpDest = dest;
|
||||
}
|
||||
else if ((hs.opcode & 0xFC) == 0xE0)
|
||||
{
|
||||
// LOOPNZ/LOOPZ/LOOP/JCXZ/JECXZ to the outside are not supported.
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT8 cond = ((hs.opcode != 0x0F ? hs.opcode : hs.opcode2) & 0x0F);
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
// Invert the condition in x64 mode to simplify the conditional jump logic.
|
||||
jcc.opcode = 0x71 ^ cond;
|
||||
jcc.address = dest;
|
||||
#else
|
||||
jcc.opcode1 = 0x80 | cond;
|
||||
jcc.operand = (INT32)(dest - (pNewInst + sizeof(jcc)));
|
||||
#endif
|
||||
pCopySrc = &jcc;
|
||||
copySize = sizeof(jcc);
|
||||
}
|
||||
}
|
||||
else if ((hs.opcode & 0xFE) == 0xC2)
|
||||
{
|
||||
// RET (C2 or C3)
|
||||
|
||||
// Complete the function if not in a branch.
|
||||
finished = (pOldInst >= jmpDest);
|
||||
}
|
||||
|
||||
// Can't alter the instruction length in a branch.
|
||||
if (pOldInst < jmpDest && copySize != hs.len)
|
||||
return FALSE;
|
||||
|
||||
// Trampoline function is too large.
|
||||
if ((newPos + copySize) > TRAMPOLINE_MAX_SIZE)
|
||||
return FALSE;
|
||||
|
||||
// Trampoline function has too many instructions.
|
||||
if (ct->nIP >= ARRAYSIZE(ct->oldIPs))
|
||||
return FALSE;
|
||||
|
||||
ct->oldIPs[ct->nIP] = oldPos;
|
||||
ct->newIPs[ct->nIP] = newPos;
|
||||
ct->nIP++;
|
||||
|
||||
// Avoid using memcpy to reduce the footprint.
|
||||
#ifndef ALLOW_INTRINSICS
|
||||
memcpy((LPBYTE)ct->pTrampoline + newPos, pCopySrc, copySize);
|
||||
#else
|
||||
__movsb((LPBYTE)ct->pTrampoline + newPos, (LPBYTE)pCopySrc, copySize);
|
||||
#endif
|
||||
newPos += copySize;
|
||||
oldPos += hs.len;
|
||||
} while (!finished);
|
||||
|
||||
// Is there enough place for a long jump?
|
||||
if (oldPos < sizeof(JMP_REL)
|
||||
&& !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL) - oldPos))
|
||||
{
|
||||
// Is there enough place for a short jump?
|
||||
if (oldPos < sizeof(JMP_REL_SHORT)
|
||||
&& !IsCodePadding((LPBYTE)ct->pTarget + oldPos, sizeof(JMP_REL_SHORT) - oldPos))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Can we place the long jump above the function?
|
||||
if (!IsExecutableAddress((LPBYTE)ct->pTarget - sizeof(JMP_REL)))
|
||||
return FALSE;
|
||||
|
||||
if (!IsCodePadding((LPBYTE)ct->pTarget - sizeof(JMP_REL), sizeof(JMP_REL)))
|
||||
return FALSE;
|
||||
|
||||
ct->patchAbove = TRUE;
|
||||
}
|
||||
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
// Create a relay function.
|
||||
jmp.address = (ULONG_PTR)ct->pDetour;
|
||||
|
||||
ct->pRelay = (LPBYTE)ct->pTrampoline + newPos;
|
||||
memcpy(ct->pRelay, &jmp, sizeof(jmp));
|
||||
#endif
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
Vendored
+105
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* MinHook - The Minimalistic API Hooking Library for x64/x86
|
||||
* Copyright (C) 2009-2017 Tsuda Kageyu.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
// Structs for writing x86/x64 instructions.
|
||||
|
||||
// 8-bit relative jump.
|
||||
typedef struct _JMP_REL_SHORT
|
||||
{
|
||||
UINT8 opcode; // EB xx: JMP +2+xx
|
||||
INT8 operand; // Relative destination address
|
||||
} JMP_REL_SHORT, *PJMP_REL_SHORT;
|
||||
|
||||
// 32-bit direct relative jump/call.
|
||||
typedef struct _JMP_REL
|
||||
{
|
||||
UINT8 opcode; // E9/E8 xxxxxxxx: JMP/CALL +5+xxxxxxxx
|
||||
INT32 operand; // Relative destination address
|
||||
} JMP_REL, *PJMP_REL, CALL_REL;
|
||||
|
||||
// 64-bit indirect absolute jump.
|
||||
typedef struct _JMP_ABS
|
||||
{
|
||||
UINT8 opcode0; // FF25 00000000: JMP [+6]
|
||||
UINT8 opcode1;
|
||||
UINT32 dummy;
|
||||
UINT64 address; // Absolute destination address
|
||||
} JMP_ABS, *PJMP_ABS;
|
||||
|
||||
// 64-bit indirect absolute call.
|
||||
typedef struct _CALL_ABS
|
||||
{
|
||||
UINT8 opcode0; // FF15 00000002: CALL [+6]
|
||||
UINT8 opcode1;
|
||||
UINT32 dummy0;
|
||||
UINT8 dummy1; // EB 08: JMP +10
|
||||
UINT8 dummy2;
|
||||
UINT64 address; // Absolute destination address
|
||||
} CALL_ABS;
|
||||
|
||||
// 32-bit direct relative conditional jumps.
|
||||
typedef struct _JCC_REL
|
||||
{
|
||||
UINT8 opcode0; // 0F8* xxxxxxxx: J** +6+xxxxxxxx
|
||||
UINT8 opcode1;
|
||||
INT32 operand; // Relative destination address
|
||||
} JCC_REL;
|
||||
|
||||
// 64bit indirect absolute conditional jumps that x64 lacks.
|
||||
typedef struct _JCC_ABS
|
||||
{
|
||||
UINT8 opcode; // 7* 0E: J** +16
|
||||
UINT8 dummy0;
|
||||
UINT8 dummy1; // FF25 00000000: JMP [+6]
|
||||
UINT8 dummy2;
|
||||
UINT32 dummy3;
|
||||
UINT64 address; // Absolute destination address
|
||||
} JCC_ABS;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct _TRAMPOLINE
|
||||
{
|
||||
LPVOID pTarget; // [In] Address of the target function.
|
||||
LPVOID pDetour; // [In] Address of the detour function.
|
||||
LPVOID pTrampoline; // [In] Buffer address for the trampoline and relay function.
|
||||
|
||||
#if defined(_M_X64) || defined(__x86_64__)
|
||||
LPVOID pRelay; // [Out] Address of the relay function.
|
||||
#endif
|
||||
BOOL patchAbove; // [Out] Should use the hot patch area?
|
||||
UINT nIP; // [Out] Number of the instruction boundaries.
|
||||
UINT8 oldIPs[8]; // [Out] Instruction boundaries of the target function.
|
||||
UINT8 newIPs[8]; // [Out] Instruction boundaries of the trampoline function.
|
||||
} TRAMPOLINE, *PTRAMPOLINE;
|
||||
|
||||
BOOL CreateTrampolineFunction(PTRAMPOLINE ct);
|
||||
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2024 Florian Bernd
|
||||
Copyright (c) 2014-2024 Joel Höner
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018-2024 Florian Bernd
|
||||
Copyright (c) 2018-2024 Joel Höner
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zycore-C)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#ifndef ZYCORE_API_MEMORY_H
|
||||
#define ZYCORE_API_MEMORY_H
|
||||
|
||||
#include <Zycore/Defines.h>
|
||||
#include <Zycore/Status.h>
|
||||
#include <Zycore/Types.h>
|
||||
|
||||
#ifndef ZYAN_NO_LIBC
|
||||
|
||||
#if defined(ZYAN_WINDOWS)
|
||||
# include <windows.h>
|
||||
#elif defined(ZYAN_POSIX)
|
||||
# include <sys/mman.h>
|
||||
#else
|
||||
# error "Unsupported platform detected"
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Enums and types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* Defines the `ZyanMemoryPageProtection` enum.
|
||||
*/
|
||||
typedef enum ZyanMemoryPageProtection_
|
||||
{
|
||||
#if defined(ZYAN_WINDOWS)
|
||||
|
||||
ZYAN_PAGE_READONLY = PAGE_READONLY,
|
||||
ZYAN_PAGE_READWRITE = PAGE_READWRITE,
|
||||
ZYAN_PAGE_EXECUTE = PAGE_EXECUTE,
|
||||
ZYAN_PAGE_EXECUTE_READ = PAGE_EXECUTE_READ,
|
||||
ZYAN_PAGE_EXECUTE_READWRITE = PAGE_EXECUTE_READWRITE
|
||||
|
||||
#elif defined(ZYAN_POSIX)
|
||||
|
||||
ZYAN_PAGE_READONLY = PROT_READ,
|
||||
ZYAN_PAGE_READWRITE = PROT_READ | PROT_WRITE,
|
||||
ZYAN_PAGE_EXECUTE = PROT_EXEC,
|
||||
ZYAN_PAGE_EXECUTE_READ = PROT_EXEC | PROT_READ,
|
||||
ZYAN_PAGE_EXECUTE_READWRITE = PROT_EXEC | PROT_READ | PROT_WRITE
|
||||
|
||||
#endif
|
||||
} ZyanMemoryPageProtection;
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* General */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Returns the system page size.
|
||||
*
|
||||
* @return The system page size.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanU32 ZyanMemoryGetSystemPageSize(void);
|
||||
|
||||
/**
|
||||
* Returns the system allocation granularity.
|
||||
*
|
||||
* The system allocation granularity specifies the minimum amount of bytes which can be allocated
|
||||
* at a specific address by a single call of `ZyanMemoryVirtualAlloc`.
|
||||
*
|
||||
* This value is typically 64KiB on Windows systems and equal to the page size on most POSIX
|
||||
* platforms.
|
||||
*
|
||||
* @return The system allocation granularity.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanU32 ZyanMemoryGetSystemAllocationGranularity(void);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Memory management */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Changes the memory protection value of one or more pages.
|
||||
*
|
||||
* @param address The start address aligned to a page boundary.
|
||||
* @param size The size.
|
||||
* @param protection The new page protection value.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanMemoryVirtualProtect(void* address, ZyanUSize size,
|
||||
ZyanMemoryPageProtection protection);
|
||||
|
||||
/**
|
||||
* Releases one or more memory pages starting at the given address.
|
||||
*
|
||||
* @param address The start address aligned to a page boundary.
|
||||
* @param size The size.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanMemoryVirtualFree(void* address, ZyanUSize size);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#endif /* ZYAN_NO_LIBC */
|
||||
|
||||
#endif /* ZYCORE_API_MEMORY_H */
|
||||
@@ -0,0 +1,70 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zycore-C)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#ifndef ZYCORE_API_PROCESS_H
|
||||
#define ZYCORE_API_PROCESS_H
|
||||
|
||||
#include <Zycore/Status.h>
|
||||
#include <Zycore/Types.h>
|
||||
|
||||
#ifndef ZYAN_NO_LIBC
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Enums and types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* General */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief Flushes the process instruction cache.
|
||||
*
|
||||
* @param address The address.
|
||||
* @param size The size.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanProcessFlushInstructionCache(void* address, ZyanUSize size);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#endif /* ZYAN_NO_LIBC */
|
||||
|
||||
#endif /* ZYCORE_API_PROCESS_H */
|
||||
@@ -0,0 +1,132 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zycore-C)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#ifndef ZYCORE_API_SYNCHRONIZATION_H
|
||||
#define ZYCORE_API_SYNCHRONIZATION_H
|
||||
|
||||
#include <Zycore/Defines.h>
|
||||
#include <Zycore/Status.h>
|
||||
|
||||
#ifndef ZYAN_NO_LIBC
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Enums and types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
#if defined(ZYAN_POSIX)
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Critical Section */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
typedef pthread_mutex_t ZyanCriticalSection;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#elif defined(ZYAN_WINDOWS)
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Critical Section */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
typedef CRITICAL_SECTION ZyanCriticalSection;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#else
|
||||
# error "Unsupported platform detected"
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Critical Section */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Initializes a critical section.
|
||||
*
|
||||
* @param critical_section A pointer to the `ZyanCriticalSection` struct.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanCriticalSectionInitialize(ZyanCriticalSection* critical_section);
|
||||
|
||||
/**
|
||||
* Enters a critical section.
|
||||
*
|
||||
* @param critical_section A pointer to the `ZyanCriticalSection` struct.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanCriticalSectionEnter(ZyanCriticalSection* critical_section);
|
||||
|
||||
/**
|
||||
* Tries to enter a critical section.
|
||||
*
|
||||
* @param critical_section A pointer to the `ZyanCriticalSection` struct.
|
||||
*
|
||||
* @return Returns `ZYAN_TRUE` if the critical section was successfully entered or `ZYAN_FALSE`,
|
||||
* if not.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanBool ZyanCriticalSectionTryEnter(ZyanCriticalSection* critical_section);
|
||||
|
||||
/**
|
||||
* Leaves a critical section.
|
||||
*
|
||||
* @param critical_section A pointer to the `ZyanCriticalSection` struct.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanCriticalSectionLeave(ZyanCriticalSection* critical_section);
|
||||
|
||||
/**
|
||||
* Deletes a critical section.
|
||||
*
|
||||
* @param critical_section A pointer to the `ZyanCriticalSection` struct.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanCriticalSectionDelete(ZyanCriticalSection* critical_section);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZYAN_NO_LIBC */
|
||||
|
||||
#endif /* ZYCORE_API_SYNCHRONIZATION_H */
|
||||
@@ -0,0 +1,162 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zycore-C)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file Provides cross-platform terminal helper functions.
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#ifndef ZYCORE_API_TERMINAL_H
|
||||
#define ZYCORE_API_TERMINAL_H
|
||||
|
||||
#include <Zycore/LibC.h>
|
||||
#include <Zycore/Status.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef ZYAN_NO_LIBC
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* VT100 CSI SGR sequences */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* General */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#define ZYAN_VT100SGR_RESET "\033[0m"
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Foreground colors */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#define ZYAN_VT100SGR_FG_DEFAULT "\033[39m"
|
||||
|
||||
#define ZYAN_VT100SGR_FG_BLACK "\033[30m"
|
||||
#define ZYAN_VT100SGR_FG_RED "\033[31m"
|
||||
#define ZYAN_VT100SGR_FG_GREEN "\033[32m"
|
||||
#define ZYAN_VT100SGR_FG_YELLOW "\033[33m"
|
||||
#define ZYAN_VT100SGR_FG_BLUE "\033[34m"
|
||||
#define ZYAN_VT100SGR_FG_MAGENTA "\033[35m"
|
||||
#define ZYAN_VT100SGR_FG_CYAN "\033[36m"
|
||||
#define ZYAN_VT100SGR_FG_WHITE "\033[37m"
|
||||
#define ZYAN_VT100SGR_FG_BRIGHT_BLACK "\033[90m"
|
||||
#define ZYAN_VT100SGR_FG_BRIGHT_RED "\033[91m"
|
||||
#define ZYAN_VT100SGR_FG_BRIGHT_GREEN "\033[92m"
|
||||
#define ZYAN_VT100SGR_FG_BRIGHT_YELLOW "\033[93m"
|
||||
#define ZYAN_VT100SGR_FG_BRIGHT_BLUE "\033[94m"
|
||||
#define ZYAN_VT100SGR_FG_BRIGHT_MAGENTA "\033[95m"
|
||||
#define ZYAN_VT100SGR_FG_BRIGHT_CYAN "\033[96m"
|
||||
#define ZYAN_VT100SGR_FG_BRIGHT_WHITE "\033[97m"
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Background color */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#define ZYAN_VT100SGR_BG_DEFAULT "\033[49m"
|
||||
|
||||
#define ZYAN_VT100SGR_BG_BLACK "\033[40m"
|
||||
#define ZYAN_VT100SGR_BG_RED "\033[41m"
|
||||
#define ZYAN_VT100SGR_BG_GREEN "\033[42m"
|
||||
#define ZYAN_VT100SGR_BG_YELLOW "\033[43m"
|
||||
#define ZYAN_VT100SGR_BG_BLUE "\033[44m"
|
||||
#define ZYAN_VT100SGR_BG_MAGENTA "\033[45m"
|
||||
#define ZYAN_VT100SGR_BG_CYAN "\033[46m"
|
||||
#define ZYAN_VT100SGR_BG_WHITE "\033[47m"
|
||||
#define ZYAN_VT100SGR_BG_BRIGHT_BLACK "\033[100m"
|
||||
#define ZYAN_VT100SGR_BG_BRIGHT_RED "\033[101m"
|
||||
#define ZYAN_VT100SGR_BG_BRIGHT_GREEN "\033[102m"
|
||||
#define ZYAN_VT100SGR_BG_BRIGHT_YELLOW "\033[103m"
|
||||
#define ZYAN_VT100SGR_BG_BRIGHT_BLUE "\033[104m"
|
||||
#define ZYAN_VT100SGR_BG_BRIGHT_MAGENTA "\033[105m"
|
||||
#define ZYAN_VT100SGR_BG_BRIGHT_CYAN "\033[106m"
|
||||
#define ZYAN_VT100SGR_BG_BRIGHT_WHITE "\033[107m"
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Enums and types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* Declares the `ZyanStandardStream` enum.
|
||||
*/
|
||||
typedef enum ZyanStandardStream_
|
||||
{
|
||||
/**
|
||||
* The default input stream.
|
||||
*/
|
||||
ZYAN_STDSTREAM_IN,
|
||||
/**
|
||||
* The default output stream.
|
||||
*/
|
||||
ZYAN_STDSTREAM_OUT,
|
||||
/**
|
||||
* The default error stream.
|
||||
*/
|
||||
ZYAN_STDSTREAM_ERR
|
||||
} ZyanStandardStream;
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* Enables VT100 ansi escape codes for the given stream.
|
||||
*
|
||||
* @param stream Either `ZYAN_STDSTREAM_OUT` or `ZYAN_STDSTREAM_ERR`.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* This functions returns `ZYAN_STATUS_SUCCESS` on all non-Windows systems without performing any
|
||||
* operations, assuming that VT100 is supported by default.
|
||||
*
|
||||
* On Windows systems, VT100 functionality is only supported on Windows 10 build 1607 (anniversary
|
||||
* update) and later.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanTerminalEnableVT100(ZyanStandardStream stream);
|
||||
|
||||
/**
|
||||
* Checks, if the given standard stream reads from or writes to a terminal.
|
||||
*
|
||||
* @param stream The standard stream to check.
|
||||
*
|
||||
* @return `ZYAN_STATUS_TRUE`, if the stream is bound to a terminal, `ZYAN_STATUS_FALSE` if not,
|
||||
* or another zyan status code if an error occured.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanTerminalIsTTY(ZyanStandardStream stream);
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#endif // ZYAN_NO_LIBC
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZYCORE_API_TERMINAL_H */
|
||||
@@ -0,0 +1,243 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zycore-C)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#ifndef ZYCORE_API_THREAD_H
|
||||
#define ZYCORE_API_THREAD_H
|
||||
|
||||
#include <Zycore/Defines.h>
|
||||
#include <Zycore/Status.h>
|
||||
|
||||
#ifndef ZYAN_NO_LIBC
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Enums and types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
#if defined(ZYAN_POSIX)
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* General */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZyanThread` data-type.
|
||||
*/
|
||||
typedef pthread_t ZyanThread;
|
||||
|
||||
/**
|
||||
* Defines the `ZyanThreadId` data-type.
|
||||
*/
|
||||
typedef ZyanU64 ZyanThreadId;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Thread Local Storage (TLS) */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZyanThreadTlsIndex` data-type.
|
||||
*/
|
||||
typedef pthread_key_t ZyanThreadTlsIndex;
|
||||
|
||||
/**
|
||||
* Defines the `ZyanThreadTlsCallback` function prototype.
|
||||
*/
|
||||
typedef void(*ZyanThreadTlsCallback)(void* data);
|
||||
|
||||
/**
|
||||
* Declares a Thread Local Storage (TLS) callback function.
|
||||
*
|
||||
* @param name The callback function name.
|
||||
* @param param_type The callback data parameter type.
|
||||
* @param param_name The callback data parameter name.
|
||||
*/
|
||||
#define ZYAN_THREAD_DECLARE_TLS_CALLBACK(name, param_type, param_name) \
|
||||
void name(param_type* param_name)
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#elif defined(ZYAN_WINDOWS)
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* General */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZyanThread` data-type.
|
||||
*/
|
||||
typedef HANDLE ZyanThread;
|
||||
|
||||
/**
|
||||
* Defines the `ZyanThreadId` data-type.
|
||||
*/
|
||||
typedef DWORD ZyanThreadId;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Thread Local Storage (TLS) */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZyanThreadTlsIndex` data-type.
|
||||
*/
|
||||
typedef DWORD ZyanThreadTlsIndex;
|
||||
|
||||
/**
|
||||
* Defines the `ZyanThreadTlsCallback` function prototype.
|
||||
*/
|
||||
typedef PFLS_CALLBACK_FUNCTION ZyanThreadTlsCallback;
|
||||
|
||||
/**
|
||||
* Declares a Thread Local Storage (TLS) callback function.
|
||||
*
|
||||
* @param name The callback function name.
|
||||
* @param param_type The callback data parameter type.
|
||||
* @param param_name The callback data parameter name.
|
||||
*/
|
||||
#define ZYAN_THREAD_DECLARE_TLS_CALLBACK(name, param_type, param_name) \
|
||||
VOID NTAPI name(param_type* param_name)
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#else
|
||||
# error "Unsupported platform detected"
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* General */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Returns the handle of the current thread.
|
||||
*
|
||||
* @param thread Receives the handle of the current thread.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanThreadGetCurrentThread(ZyanThread* thread);
|
||||
|
||||
/**
|
||||
* Returns the unique id of the current thread.
|
||||
*
|
||||
* @param thread_id Receives the unique id of the current thread.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanThreadGetCurrentThreadId(ZyanThreadId* thread_id);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Thread Local Storage (TLS) */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Allocates a new Thread Local Storage (TLS) slot.
|
||||
*
|
||||
* @param index Receives the TLS slot index.
|
||||
* @param destructor A pointer to a destructor callback which is invoked to finalize the data
|
||||
* in the TLS slot or `ZYAN_NULL`, if not needed.
|
||||
*
|
||||
* The maximum available number of TLS slots is implementation specific and different on each
|
||||
* platform:
|
||||
* - Windows
|
||||
* - A total amount of 128 slots per process are guaranteed
|
||||
* - POSIX
|
||||
* - A total amount of 128 slots per process are guaranteed
|
||||
* - Some systems guarantee larger amounts like e.g. 1024 slots per process
|
||||
*
|
||||
* Note that the invocation rules for the destructor callback are implementation specific and
|
||||
* different on each platform:
|
||||
* - Windows
|
||||
* - The callback is invoked when a thread exits
|
||||
* - The callback is invoked when the process exits
|
||||
* - The callback is invoked when the TLS slot is released
|
||||
* - POSIX
|
||||
* - The callback is invoked when a thread exits and the stored value is not null
|
||||
* - The callback is NOT invoked when the process exits
|
||||
* - The callback is NOT invoked when the TLS slot is released
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanThreadTlsAlloc(ZyanThreadTlsIndex* index,
|
||||
ZyanThreadTlsCallback destructor);
|
||||
|
||||
/**
|
||||
* Releases a Thread Local Storage (TLS) slot.
|
||||
*
|
||||
* @param index The TLS slot index.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanThreadTlsFree(ZyanThreadTlsIndex index);
|
||||
|
||||
/**
|
||||
* Returns the value inside the given Thread Local Storage (TLS) slot for the
|
||||
* calling thread.
|
||||
*
|
||||
* @param index The TLS slot index.
|
||||
* @param data Receives the value inside the given Thread Local Storage
|
||||
* (TLS) slot for the calling thread.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanThreadTlsGetValue(ZyanThreadTlsIndex index, void** data);
|
||||
|
||||
/**
|
||||
* Set the value of the given Thread Local Storage (TLS) slot for the calling thread.
|
||||
*
|
||||
* @param index The TLS slot index.
|
||||
* @param data The value to store inside the given Thread Local Storage (TLS) slot for the
|
||||
* calling thread
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanThreadTlsSetValue(ZyanThreadTlsIndex index, void* data);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZYAN_NO_LIBC */
|
||||
|
||||
#endif /* ZYCORE_API_THREAD_H */
|
||||
@@ -0,0 +1,142 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zycore-C)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#ifndef ZYCORE_ALLOCATOR_H
|
||||
#define ZYCORE_ALLOCATOR_H
|
||||
|
||||
#include <Zycore/Status.h>
|
||||
#include <Zycore/Types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Enums and types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
struct ZyanAllocator_;
|
||||
|
||||
/**
|
||||
* Defines the `ZyanAllocatorAllocate` function prototype.
|
||||
*
|
||||
* @param allocator A pointer to the `ZyanAllocator` instance.
|
||||
* @param p Receives a pointer to the first memory block sufficient to hold an
|
||||
* array of `n` elements with a size of `element_size`.
|
||||
* @param element_size The size of a single element.
|
||||
* @param n The number of elements to allocate storage for.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* This prototype is used for the `allocate()` and `reallocate()` functions.
|
||||
*
|
||||
* The result of the `reallocate()` function is undefined, if `p` does not point to a memory block
|
||||
* previously obtained by `(re-)allocate()`.
|
||||
*/
|
||||
typedef ZyanStatus (*ZyanAllocatorAllocate)(struct ZyanAllocator_* allocator, void** p,
|
||||
ZyanUSize element_size, ZyanUSize n);
|
||||
|
||||
/**
|
||||
* Defines the `ZyanAllocatorDeallocate` function prototype.
|
||||
*
|
||||
* @param allocator A pointer to the `ZyanAllocator` instance.
|
||||
* @param p The pointer obtained from `(re-)allocate()`.
|
||||
* @param element_size The size of a single element.
|
||||
* @param n The number of elements earlier passed to `(re-)allocate()`.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
typedef ZyanStatus (*ZyanAllocatorDeallocate)(struct ZyanAllocator_* allocator, void* p,
|
||||
ZyanUSize element_size, ZyanUSize n);
|
||||
|
||||
/**
|
||||
* Defines the `ZyanAllocator` struct.
|
||||
*
|
||||
* This is the base class for all custom allocator implementations.
|
||||
*
|
||||
* All fields in this struct should be considered as "private". Any changes may lead to unexpected
|
||||
* behavior.
|
||||
*/
|
||||
typedef struct ZyanAllocator_
|
||||
{
|
||||
/**
|
||||
* The allocate function.
|
||||
*/
|
||||
ZyanAllocatorAllocate allocate;
|
||||
/**
|
||||
* The reallocate function.
|
||||
*/
|
||||
ZyanAllocatorAllocate reallocate;
|
||||
/**
|
||||
* The deallocate function.
|
||||
*/
|
||||
ZyanAllocatorDeallocate deallocate;
|
||||
} ZyanAllocator;
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* Initializes the given `ZyanAllocator` instance.
|
||||
*
|
||||
* @param allocator A pointer to the `ZyanAllocator` instance.
|
||||
* @param allocate The allocate function.
|
||||
* @param reallocate The reallocate function.
|
||||
* @param deallocate The deallocate function.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanAllocatorInit(ZyanAllocator* allocator, ZyanAllocatorAllocate allocate,
|
||||
ZyanAllocatorAllocate reallocate, ZyanAllocatorDeallocate deallocate);
|
||||
|
||||
#ifndef ZYAN_NO_LIBC
|
||||
|
||||
/**
|
||||
* Returns the default `ZyanAllocator` instance.
|
||||
*
|
||||
* @return A pointer to the default `ZyanAllocator` instance.
|
||||
*
|
||||
* The default allocator uses the default memory manager to allocate memory on the heap.
|
||||
*
|
||||
* You should in no case modify the returned allocator instance to avoid unexpected behavior.
|
||||
*/
|
||||
ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanAllocator* ZyanAllocatorDefault(void);
|
||||
|
||||
#endif // ZYAN_NO_LIBC
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZYCORE_ALLOCATOR_H */
|
||||
@@ -0,0 +1,173 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zycore-C)
|
||||
|
||||
Original Author : Joel Hoener
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Implements command-line argument parsing.
|
||||
*/
|
||||
|
||||
#ifndef ZYCORE_ARGPARSE_H
|
||||
#define ZYCORE_ARGPARSE_H
|
||||
|
||||
#include <Zycore/Types.h>
|
||||
#include <Zycore/Status.h>
|
||||
#include <Zycore/Vector.h>
|
||||
#include <Zycore/String.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Structs and other types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* Definition of a single argument.
|
||||
*/
|
||||
typedef struct ZyanArgParseDefinition_
|
||||
{
|
||||
/**
|
||||
* The argument name, e.g. `--help`.
|
||||
*
|
||||
* Must start with either one or two dashes. Single dash arguments must consist of a single
|
||||
* character, (e.g. `-n`), double-dash arguments can be of arbitrary length.
|
||||
*/
|
||||
const char* name;
|
||||
/**
|
||||
* Whether the argument is boolean or expects a value.
|
||||
*/
|
||||
ZyanBool boolean;
|
||||
/**
|
||||
* Whether this argument is required (error if missing).
|
||||
*/
|
||||
ZyanBool required;
|
||||
} ZyanArgParseDefinition;
|
||||
|
||||
/**
|
||||
* Configuration for argument parsing.
|
||||
*/
|
||||
typedef struct ZyanArgParseConfig_
|
||||
{
|
||||
/**
|
||||
* `argv` argument passed to `main` by LibC.
|
||||
*/
|
||||
const char** argv;
|
||||
/**
|
||||
* `argc` argument passed to `main` by LibC.
|
||||
*/
|
||||
ZyanUSize argc;
|
||||
/**
|
||||
* Minimum # of accepted unnamed / anonymous arguments.
|
||||
*/
|
||||
ZyanUSize min_unnamed_args;
|
||||
/**
|
||||
* Maximum # of accepted unnamed / anonymous arguments.
|
||||
*/
|
||||
ZyanUSize max_unnamed_args;
|
||||
/**
|
||||
* Argument definition array, or `ZYAN_NULL`.
|
||||
*
|
||||
* Expects a pointer to an array of `ZyanArgParseDefinition` instances. The array is
|
||||
* terminated by setting the `.name` field of the last element to `ZYAN_NULL`. If no named
|
||||
* arguments should be parsed, you can also set this to `ZYAN_NULL`.
|
||||
*/
|
||||
ZyanArgParseDefinition* args;
|
||||
} ZyanArgParseConfig;
|
||||
|
||||
/**
|
||||
* Information about a parsed argument.
|
||||
*/
|
||||
typedef struct ZyanArgParseArg_
|
||||
{
|
||||
/**
|
||||
* Corresponding argument definition, or `ZYAN_NULL` for unnamed args.
|
||||
*
|
||||
* This pointer is borrowed from the `cfg` pointer passed to `ZyanArgParse`.
|
||||
*/
|
||||
const ZyanArgParseDefinition* def;
|
||||
/**
|
||||
* Whether the argument has a value (is non-boolean).
|
||||
*/
|
||||
ZyanBool has_value;
|
||||
/**
|
||||
* If `has_value == true`, then the argument value.
|
||||
*
|
||||
* This is a view into the `argv` string array passed to `ZyanArgParse` via the `cfg` argument.
|
||||
*/
|
||||
ZyanStringView value;
|
||||
} ZyanArgParseArg;
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifndef ZYAN_NO_LIBC
|
||||
|
||||
/**
|
||||
* Parse arguments according to a `ZyanArgParseConfig` definition.
|
||||
*
|
||||
* @param cfg Argument parser config to use.
|
||||
* @param parsed Receives the parsed output. Vector of `ZyanArgParseArg`. Ownership is
|
||||
* transferred to the user. Input is expected to be uninitialized. On error,
|
||||
* the vector remains uninitialized.
|
||||
* @param error_token On error, if it makes sense, receives the argument fragment causing the
|
||||
* error. Optional, may be `ZYAN_NULL`. The pointer borrows into the `cfg`
|
||||
* struct and doesn't have to be freed by the user.
|
||||
*
|
||||
* @return A `ZyanStatus` status determining whether the parsing succeeded.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanArgParse(const ZyanArgParseConfig *cfg, ZyanVector* parsed,
|
||||
const char** error_token);
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Parse arguments according to a `ZyanArgParseConfig` definition.
|
||||
*
|
||||
* This version allows specification of a custom memory allocator and thus supports no-libc.
|
||||
*
|
||||
* @param cfg Argument parser config to use.
|
||||
* @param parsed Receives the parsed output. Vector of `ZyanArgParseArg`. Ownership is
|
||||
* transferred to the user. Input is expected to be uninitialized. On error,
|
||||
* the vector remains uninitialized.
|
||||
* @param error_token On error, if it makes sense, receives the argument fragment causing the
|
||||
* error. Optional, may be `ZYAN_NULL`. The pointer borrows into the `cfg`
|
||||
* struct and doesn't have to be freed by the user.
|
||||
* @param allocator The `ZyanAllocator` to be used for allocating the output vector's data.
|
||||
*
|
||||
* @return A `ZyanStatus` status determining whether the parsing succeeded.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanArgParseEx(const ZyanArgParseConfig *cfg, ZyanVector* parsed,
|
||||
const char** error_token, ZyanAllocator* allocator);
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZYCORE_ARGPARSE_H */
|
||||
@@ -0,0 +1,236 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zyan-C)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Cross compiler atomic intrinsics.
|
||||
*/
|
||||
|
||||
#ifndef ZYCORE_ATOMIC_H
|
||||
#define ZYCORE_ATOMIC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <Zycore/Defines.h>
|
||||
#include <Zycore/Types.h>
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Enums and Types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/*
|
||||
* Wraps a 32-bit value to provide atomic access.
|
||||
*/
|
||||
typedef struct ZyanAtomic32_
|
||||
{
|
||||
ZyanU32 volatile value;
|
||||
} ZyanAtomic32;
|
||||
|
||||
/*
|
||||
* Wraps a 64-bit value to provide atomic access.
|
||||
*/
|
||||
typedef struct ZyanAtomic64_
|
||||
{
|
||||
ZyanU64 volatile value;
|
||||
} ZyanAtomic64;
|
||||
|
||||
/*
|
||||
* Wraps a pointer-sized value to provide atomic access.
|
||||
*/
|
||||
typedef struct ZyanAtomicPointer_
|
||||
{
|
||||
ZyanVoidPointer volatile value;
|
||||
} ZyanAtomicPointer;
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Macros */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Pointer sized */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @copydoc ZyanAtomicCompareExchange
|
||||
*/
|
||||
#define ZYAN_ATOMIC_COMPARE_EXCHANGE(destination, comparand, value) \
|
||||
ZyanAtomicCompareExchange((ZyanAtomicPointer*)&(destination), (comparand), (value))
|
||||
|
||||
/**
|
||||
* @copydoc ZyanAtomicIncrement
|
||||
*/
|
||||
#define ZYAN_ATOMIC_INCREMENT(destination) \
|
||||
ZyanAtomicIncrement((ZyanAtomicPointer*)&(destination));
|
||||
|
||||
/**
|
||||
* @copydoc ZyanAtomicDecrement
|
||||
*/
|
||||
#define ZYAN_ATOMIC_DECREMENT(destination) \
|
||||
ZyanAtomicDecrement((ZyanAtomicPointer*)&(destination));
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* 32-bit */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @copydoc ZyanAtomicCompareExchange
|
||||
*/
|
||||
#define ZYAN_ATOMIC_COMPARE_EXCHANGE32(destination, comparand, value) \
|
||||
ZyanAtomicCompareExchange32((ZyanAtomic32*)&(destination), (comparand), (value))
|
||||
|
||||
/**
|
||||
* @copydoc ZyanAtomicIncrement
|
||||
*/
|
||||
#define ZYAN_ATOMIC_INCREMENT32(destination) \
|
||||
ZyanAtomicIncrement32((ZyanAtomic32*)&(destination));
|
||||
|
||||
/**
|
||||
* @copydoc ZyanAtomicDecrement
|
||||
*/
|
||||
#define ZYAN_ATOMIC_DECREMENT32(destination) \
|
||||
ZyanAtomicDecrement32((ZyanAtomic32*)&(destination));
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* 64-bit */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @copydoc ZyanAtomicCompareExchange
|
||||
*/
|
||||
#define ZYAN_ATOMIC_COMPARE_EXCHANGE64(destination, comparand, value) \
|
||||
ZyanAtomicCompareExchange64((ZyanAtomic64*)&(destination), (comparand), (value))
|
||||
|
||||
/**
|
||||
* @copydoc ZyanAtomicIncrement
|
||||
*/
|
||||
#define ZYAN_ATOMIC_INCREMENT64(destination) \
|
||||
ZyanAtomicIncrement64((ZyanAtomic64*)&(destination));
|
||||
|
||||
/**
|
||||
* @copydoc ZyanAtomicDecrement
|
||||
*/
|
||||
#define ZYAN_ATOMIC_DECREMENT64(destination) \
|
||||
ZyanAtomicDecrement64((ZyanAtomic64*)&(destination));
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Pointer sized */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Compares two values for equality and, if they are equal, replaces the first value.
|
||||
*
|
||||
* @param destination A pointer to the destination value.
|
||||
* @param comparand The value to compare with.
|
||||
* @param value The replacement value.
|
||||
*
|
||||
* @return The original value.
|
||||
*/
|
||||
static ZyanUPointer ZyanAtomicCompareExchange(ZyanAtomicPointer* destination,
|
||||
ZyanUPointer comparand, ZyanUPointer value);
|
||||
|
||||
/**
|
||||
* Increments the given value and stores the result, as an atomic operation.
|
||||
*
|
||||
* @param destination A pointer to the destination value.
|
||||
*
|
||||
* @return The incremented value.
|
||||
*/
|
||||
static ZyanUPointer ZyanAtomicIncrement(ZyanAtomicPointer* destination);
|
||||
|
||||
/**
|
||||
* Decrements the given value and stores the result, as an atomic operation.
|
||||
*
|
||||
* @param destination A pointer to the destination value.
|
||||
*
|
||||
* @return The decremented value.
|
||||
*/
|
||||
static ZyanUPointer ZyanAtomicDecrement(ZyanAtomicPointer* destination);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* 32-bit */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @copydoc ZyanAtomicCompareExchange
|
||||
*/
|
||||
static ZyanU32 ZyanAtomicCompareExchange32(ZyanAtomic32* destination,
|
||||
ZyanU32 comparand, ZyanU32 value);
|
||||
|
||||
/**
|
||||
* @copydoc ZyanAtomicIncrement
|
||||
*/
|
||||
static ZyanU32 ZyanAtomicIncrement32(ZyanAtomic32* destination);
|
||||
|
||||
/**
|
||||
* @copydoc ZyanAtomicDecrement
|
||||
*/
|
||||
static ZyanU32 ZyanAtomicDecrement32(ZyanAtomic32* destination);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* 64-bit */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @copydoc ZyanAtomicCompareExchange
|
||||
*/
|
||||
static ZyanU64 ZyanAtomicCompareExchange64(ZyanAtomic64* destination,
|
||||
ZyanU64 comparand, ZyanU64 value);
|
||||
|
||||
/**
|
||||
* @copydoc ZyanAtomicIncrement
|
||||
*/
|
||||
static ZyanU64 ZyanAtomicIncrement64(ZyanAtomic64* destination);
|
||||
|
||||
/**
|
||||
* @copydoc ZyanAtomicDecrement
|
||||
*/
|
||||
static ZyanU64 ZyanAtomicDecrement64(ZyanAtomic64* destination);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#if defined(ZYAN_CLANG) || defined(ZYAN_GCC) || defined(ZYAN_ICC)
|
||||
# include <Zycore/Internal/AtomicGNU.h>
|
||||
#elif defined(ZYAN_MSVC)
|
||||
# include <Zycore/Internal/AtomicMSVC.h>
|
||||
#else
|
||||
# error "Unsupported compiler detected"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZYCORE_ATOMIC_H */
|
||||
@@ -0,0 +1,483 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zycore-C)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Implements the bitset class.
|
||||
*/
|
||||
|
||||
#ifndef ZYCORE_BITSET_H
|
||||
#define ZYCORE_BITSET_H
|
||||
|
||||
#include <Zycore/Allocator.h>
|
||||
#include <Zycore/Status.h>
|
||||
#include <Zycore/Types.h>
|
||||
#include <Zycore/Vector.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Enums and types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* Defines the `ZyanVector` struct.
|
||||
*
|
||||
* All fields in this struct should be considered as "private". Any changes may lead to unexpected
|
||||
* behavior.
|
||||
*/
|
||||
typedef struct ZyanBitset_
|
||||
{
|
||||
/**
|
||||
* The bitset size.
|
||||
*/
|
||||
ZyanUSize size;
|
||||
/**
|
||||
* The bitset data.
|
||||
*/
|
||||
ZyanVector bits;
|
||||
} ZyanBitset;
|
||||
|
||||
/**
|
||||
* Defines the `ZyanBitsetByteOperation` function prototype.
|
||||
*
|
||||
* @param v1 A pointer to the first byte. This value receives the result after performing the
|
||||
* desired operation.
|
||||
* @param v2 A pointer to the second byte.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* This function is used to perform byte-wise operations on two `ZyanBitset` instances.
|
||||
*/
|
||||
typedef ZyanStatus (*ZyanBitsetByteOperation)(ZyanU8* v1, const ZyanU8* v2);
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Constructor and destructor */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef ZYAN_NO_LIBC
|
||||
|
||||
/**
|
||||
* Initializes the given `ZyanBitset` instance.
|
||||
*
|
||||
* @param bitset A pointer to the `ZyanBitset` instance.
|
||||
* @param count The initial amount of bits.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* The space for the bitset is dynamically allocated by the default allocator using the default
|
||||
* growth factor and the default shrink threshold.
|
||||
*/
|
||||
ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanBitsetInit(ZyanBitset* bitset, ZyanUSize count);
|
||||
|
||||
#endif // ZYAN_NO_LIBC
|
||||
|
||||
/**
|
||||
* Initializes the given `ZyanBitset` instance and sets a custom `allocator` and memory
|
||||
* allocation/deallocation parameters.
|
||||
*
|
||||
* @param bitset A pointer to the `ZyanBitset` instance.
|
||||
* @param count The initial amount of bits.
|
||||
* @param allocator A pointer to a `ZyanAllocator` instance.
|
||||
* @param growth_factor The growth factor.
|
||||
* @param shrink_threshold The shrink threshold.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* A growth factor of `1` disables overallocation and a shrink threshold of `0` disables
|
||||
* dynamic shrinking.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanBitsetInitEx(ZyanBitset* bitset, ZyanUSize count,
|
||||
ZyanAllocator* allocator, ZyanU8 growth_factor, ZyanU8 shrink_threshold);
|
||||
|
||||
/**
|
||||
* Initializes the given `ZyanBitset` instance and configures it to use a custom user
|
||||
* defined buffer with a fixed size.
|
||||
*
|
||||
* @param bitset A pointer to the `ZyanBitset` instance.
|
||||
* @param count The initial amount of bits.
|
||||
* @param buffer A pointer to the buffer that is used as storage for the bits.
|
||||
* @param capacity The maximum capacity (number of bytes) of the buffer.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanBitsetInitBuffer(ZyanBitset* bitset, ZyanUSize count, void* buffer,
|
||||
ZyanUSize capacity);
|
||||
|
||||
/**
|
||||
* Destroys the given `ZyanBitset` instance.
|
||||
*
|
||||
* @param bitset A pointer to the `ZyanBitset` instance.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanBitsetDestroy(ZyanBitset* bitset);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Logical operations */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Performs a byte-wise `operation` for every byte in the given `ZyanBitset` instances.
|
||||
*
|
||||
* @param destination A pointer to the `ZyanBitset` instance that is used as the first input and
|
||||
* as the destination.
|
||||
* @param source A pointer to the `ZyanBitset` instance that is used as the second input.
|
||||
* @param operation A pointer to the function that performs the desired operation.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* The `operation` callback is invoked once for every byte in the smallest of the `ZyanBitset`
|
||||
* instances.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanBitsetPerformByteOperation(ZyanBitset* destination,
|
||||
const ZyanBitset* source, ZyanBitsetByteOperation operation);
|
||||
|
||||
/**
|
||||
* Performs a logical `AND` operation on the given `ZyanBitset` instances.
|
||||
*
|
||||
* @param destination A pointer to the `ZyanBitset` instance that is used as the first input and
|
||||
* as the destination.
|
||||
* @param source A pointer to the `ZyanBitset` instance that is used as the second input.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* If the destination bitmask contains more bits than the source one, the state of the remaining
|
||||
* bits will be undefined.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanBitsetAND(ZyanBitset* destination, const ZyanBitset* source);
|
||||
|
||||
/**
|
||||
* Performs a logical `OR` operation on the given `ZyanBitset` instances.
|
||||
*
|
||||
* @param destination A pointer to the `ZyanBitset` instance that is used as the first input and
|
||||
* as the destination.
|
||||
* @param source A pointer to the `ZyanBitset` instance that is used as the second input.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* If the destination bitmask contains more bits than the source one, the state of the remaining
|
||||
* bits will be undefined.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanBitsetOR (ZyanBitset* destination, const ZyanBitset* source);
|
||||
|
||||
/**
|
||||
* Performs a logical `XOR` operation on the given `ZyanBitset` instances.
|
||||
*
|
||||
* @param destination A pointer to the `ZyanBitset` instance that is used as the first input and
|
||||
* as the destination.
|
||||
* @param source A pointer to the `ZyanBitset` instance that is used as the second input.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* If the destination bitmask contains more bits than the source one, the state of the remaining
|
||||
* bits will be undefined.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanBitsetXOR(ZyanBitset* destination, const ZyanBitset* source);
|
||||
|
||||
/**
|
||||
* Flips all bits of the given `ZyanBitset` instance.
|
||||
*
|
||||
* @param bitset A pointer to the `ZyanBitset` instance.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanBitsetFlip(ZyanBitset* bitset);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Bit access */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Sets the bit at `index` of the given `ZyanBitset` instance to `1`.
|
||||
*
|
||||
* @param bitset A pointer to the `ZyanBitset` instance.
|
||||
* @param index The bit index.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanBitsetSet(ZyanBitset* bitset, ZyanUSize index);
|
||||
|
||||
/**
|
||||
* Sets the bit at `index` of the given `ZyanBitset` instance to `0`.
|
||||
*
|
||||
* @param bitset A pointer to the `ZyanBitset` instance.
|
||||
* @param index The bit index.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanBitsetReset(ZyanBitset* bitset, ZyanUSize index);
|
||||
|
||||
/**
|
||||
* Sets the bit at `index` of the given `ZyanBitset` instance to the specified `value`.
|
||||
*
|
||||
* @param bitset A pointer to the `ZyanBitset` instance.
|
||||
* @param index The bit index.
|
||||
* @param value The new value.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanBitsetAssign(ZyanBitset* bitset, ZyanUSize index, ZyanBool value);
|
||||
|
||||
/**
|
||||
* Toggles the bit at `index` of the given `ZyanBitset` instance.
|
||||
*
|
||||
* @param bitset A pointer to the `ZyanBitset` instance.
|
||||
* @param index The bit index.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanBitsetToggle(ZyanBitset* bitset, ZyanUSize index);
|
||||
|
||||
/**
|
||||
* Returns the value of the bit at `index`.
|
||||
*
|
||||
* @param bitset A pointer to the `ZyanBitset` instance.
|
||||
* @param index The bit index.
|
||||
*
|
||||
* @return `ZYAN_STATUS_TRUE`, if the bit is set or `ZYAN_STATUS_FALSE`, if not, Another zyan
|
||||
* status code, if an error occurred.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanBitsetTest(ZyanBitset* bitset, ZyanUSize index);
|
||||
|
||||
/**
|
||||
* Returns the value of the most significant bit.
|
||||
*
|
||||
* @param bitset A pointer to the `ZyanBitset` instance.
|
||||
*
|
||||
* @return `ZYAN_STATUS_TRUE`, if the bit is set or `ZYAN_STATUS_FALSE`, if not. Another zyan
|
||||
* status code, if an error occurred.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanBitsetTestMSB(ZyanBitset* bitset);
|
||||
|
||||
/**
|
||||
* Returns the value of the least significant bit.
|
||||
*
|
||||
* @param bitset A pointer to the `ZyanBitset` instance.
|
||||
*
|
||||
* @return `ZYAN_STATUS_TRUE`, if the bit is set or `ZYAN_STATUS_FALSE`, if not. Another zyan
|
||||
* status code, if an error occurred.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanBitsetTestLSB(ZyanBitset* bitset);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Sets all bits of the given `ZyanBitset` instance to `1`.
|
||||
*
|
||||
* @param bitset A pointer to the `ZyanBitset` instance.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanBitsetSetAll(ZyanBitset* bitset);
|
||||
|
||||
/**
|
||||
* Sets all bits of the given `ZyanBitset` instance to `0`.
|
||||
*
|
||||
* @param bitset A pointer to the `ZyanBitset` instance.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanBitsetResetAll(ZyanBitset* bitset);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Size management */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Adds a new bit at the end of the bitset.
|
||||
*
|
||||
* @param bitset A pointer to the `ZyanBitset` instance.
|
||||
* @param value The value of the new bit.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanBitsetPush(ZyanBitset* bitset, ZyanBool value);
|
||||
|
||||
/**
|
||||
* Removes the last bit of the bitset.
|
||||
*
|
||||
* @param bitset A pointer to the `ZyanBitset` instance.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanBitsetPop(ZyanBitset* bitset);
|
||||
|
||||
/**
|
||||
* Deletes all bits of the given `ZyanBitset` instance.
|
||||
*
|
||||
* @param bitset A pointer to the `ZyanBitset` instance.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanBitsetClear(ZyanBitset* bitset);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Memory management */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Changes the capacity of the given `ZyanBitset` instance.
|
||||
*
|
||||
* @param bitset A pointer to the `ZyanBitset` instance.
|
||||
* @param count The new capacity (number of bits).
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanBitsetReserve(ZyanBitset* bitset, ZyanUSize count);
|
||||
|
||||
/**
|
||||
* Shrinks the capacity of the given bitset to match it's size.
|
||||
*
|
||||
* @param bitset A pointer to the `ZyanBitset` instance.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanBitsetShrinkToFit(ZyanBitset* bitset);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Information */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Returns the current size of the bitset in bits.
|
||||
*
|
||||
* @param bitset A pointer to the `ZyanBitset` instance.
|
||||
* @param size Receives the size of the bitset in bits.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanBitsetGetSize(const ZyanBitset* bitset, ZyanUSize* size);
|
||||
|
||||
/**
|
||||
* Returns the current capacity of the bitset in bits.
|
||||
*
|
||||
* @param bitset A pointer to the `ZyanBitset` instance.
|
||||
* @param capacity Receives the size of the bitset in bits.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanBitsetGetCapacity(const ZyanBitset* bitset, ZyanUSize* capacity);
|
||||
|
||||
/**
|
||||
* Returns the current size of the bitset in bytes.
|
||||
*
|
||||
* @param bitset A pointer to the `ZyanBitset` instance.
|
||||
* @param size Receives the size of the bitset in bytes.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanBitsetGetSizeBytes(const ZyanBitset* bitset, ZyanUSize* size);
|
||||
|
||||
/**
|
||||
* Returns the current capacity of the bitset in bytes.
|
||||
*
|
||||
* @param bitset A pointer to the `ZyanBitset` instance.
|
||||
* @param capacity Receives the size of the bitset in bytes.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanBitsetGetCapacityBytes(const ZyanBitset* bitset, ZyanUSize* capacity);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Returns the amount of bits set in the given bitset.
|
||||
*
|
||||
* @param bitset A pointer to the `ZyanBitset` instance.
|
||||
* @param count Receives the amount of bits set in the given bitset.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanBitsetCount(const ZyanBitset* bitset, ZyanUSize* count);
|
||||
|
||||
/**
|
||||
* Checks, if all bits of the given bitset are set.
|
||||
*
|
||||
* @param bitset A pointer to the `ZyanBitset` instance.
|
||||
*
|
||||
* @return `ZYAN_STATUS_TRUE`, if all bits are set, `ZYAN_STATUS_FALSE`, if not. Another zyan
|
||||
* status code, if an error occurred.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanBitsetAll(const ZyanBitset* bitset);
|
||||
|
||||
/**
|
||||
* Checks, if at least one bit of the given bitset is set.
|
||||
*
|
||||
* @param bitset A pointer to the `ZyanBitset` instance.
|
||||
*
|
||||
* @return `ZYAN_STATUS_TRUE`, if at least one bit is set, `ZYAN_STATUS_FALSE`, if not. Another
|
||||
* zyan status code, if an error occurred.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanBitsetAny(const ZyanBitset* bitset);
|
||||
|
||||
/**
|
||||
* Checks, if none bits of the given bitset are set.
|
||||
*
|
||||
* @param bitset A pointer to the `ZyanBitset` instance.
|
||||
*
|
||||
* @return `ZYAN_STATUS_TRUE`, if none bits are set, `ZYAN_STATUS_FALSE`, if not. Another zyan
|
||||
* status code, if an error occurred.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanBitsetNone(const ZyanBitset* bitset);
|
||||
|
||||
///* ---------------------------------------------------------------------------------------------- */
|
||||
//
|
||||
///**
|
||||
// * Returns a 32-bit unsigned integer representation of the data.
|
||||
// *
|
||||
// * @param bitset A pointer to the `ZyanBitset` instance.
|
||||
// * @param value Receives the 32-bit unsigned integer representation of the data.
|
||||
// *
|
||||
// * @return A zyan status code.
|
||||
// */
|
||||
//ZYCORE_EXPORT ZyanStatus ZyanBitsetToU32(const ZyanBitset* bitset, ZyanU32* value);
|
||||
//
|
||||
///**
|
||||
// * Returns a 64-bit unsigned integer representation of the data.
|
||||
// *
|
||||
// * @param bitset A pointer to the `ZyanBitset` instance.
|
||||
// * @param value Receives the 64-bit unsigned integer representation of the data.
|
||||
// *
|
||||
// * @return A zyan status code.
|
||||
// */
|
||||
//ZYCORE_EXPORT ZyanStatus ZyanBitsetToU64(const ZyanBitset* bitset, ZyanU64* value);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZYCORE_BITSET_H */
|
||||
@@ -0,0 +1,316 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zycore-C)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Defines prototypes of general-purpose comparison functions.
|
||||
*/
|
||||
|
||||
#ifndef ZYCORE_COMPARISON_H
|
||||
#define ZYCORE_COMPARISON_H
|
||||
|
||||
#include <Zycore/Defines.h>
|
||||
#include <Zycore/Types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Enums and types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* Defines the `ZyanEqualityComparison` function prototype.
|
||||
*
|
||||
* @param left A pointer to the first element.
|
||||
* @param right A pointer to the second element.
|
||||
*
|
||||
* @return This function should return `ZYAN_TRUE` if the `left` element equals the `right` one
|
||||
* or `ZYAN_FALSE`, if not.
|
||||
*/
|
||||
typedef ZyanBool (*ZyanEqualityComparison)(const void* left, const void* right);
|
||||
|
||||
/**
|
||||
* Defines the `ZyanComparison` function prototype.
|
||||
*
|
||||
* @param left A pointer to the first element.
|
||||
* @param right A pointer to the second element.
|
||||
*
|
||||
* @return This function should return values in the following range:
|
||||
* `left == right -> result == 0`
|
||||
* `left < right -> result < 0`
|
||||
* `left > right -> result > 0`
|
||||
*/
|
||||
typedef ZyanI32 (*ZyanComparison)(const void* left, const void* right);
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Macros */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Equality comparison functions */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Declares a generic equality comparison function for an integral data-type.
|
||||
*
|
||||
* @param name The name of the function.
|
||||
* @param type The name of the integral data-type.
|
||||
*/
|
||||
#define ZYAN_DECLARE_EQUALITY_COMPARISON(name, type) \
|
||||
ZyanBool name(const type* left, const type* right) \
|
||||
{ \
|
||||
ZYAN_ASSERT(left); \
|
||||
ZYAN_ASSERT(right); \
|
||||
\
|
||||
return (*left == *right) ? ZYAN_TRUE : ZYAN_FALSE; \
|
||||
}
|
||||
|
||||
/**
|
||||
* Declares a generic equality comparison function that compares a single integral
|
||||
* data-type field of a struct.
|
||||
*
|
||||
* @param name The name of the function.
|
||||
* @param type The name of the integral data-type.
|
||||
* @param field_name The name of the struct field.
|
||||
*/
|
||||
#define ZYAN_DECLARE_EQUALITY_COMPARISON_FOR_FIELD(name, type, field_name) \
|
||||
ZyanBool name(const type* left, const type* right) \
|
||||
{ \
|
||||
ZYAN_ASSERT(left); \
|
||||
ZYAN_ASSERT(right); \
|
||||
\
|
||||
return (left->field_name == right->field_name) ? ZYAN_TRUE : ZYAN_FALSE; \
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Comparison functions */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Declares a generic comparison function for an integral data-type.
|
||||
*
|
||||
* @param name The name of the function.
|
||||
* @param type The name of the integral data-type.
|
||||
*/
|
||||
#define ZYAN_DECLARE_COMPARISON(name, type) \
|
||||
ZyanI32 name(const type* left, const type* right) \
|
||||
{ \
|
||||
ZYAN_ASSERT(left); \
|
||||
ZYAN_ASSERT(right); \
|
||||
\
|
||||
if (*left < *right) \
|
||||
{ \
|
||||
return -1; \
|
||||
} \
|
||||
if (*left > *right) \
|
||||
{ \
|
||||
return 1; \
|
||||
} \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
/**
|
||||
* Declares a generic comparison function that compares a single integral data-type field
|
||||
* of a struct.
|
||||
*
|
||||
* @param name The name of the function.
|
||||
* @param type The name of the integral data-type.
|
||||
* @param field_name The name of the struct field.
|
||||
*/
|
||||
#define ZYAN_DECLARE_COMPARISON_FOR_FIELD(name, type, field_name) \
|
||||
ZyanI32 name(const type* left, const type* right) \
|
||||
{ \
|
||||
ZYAN_ASSERT(left); \
|
||||
ZYAN_ASSERT(right); \
|
||||
\
|
||||
if (left->field_name < right->field_name) \
|
||||
{ \
|
||||
return -1; \
|
||||
} \
|
||||
if (left->field_name > right->field_name) \
|
||||
{ \
|
||||
return 1; \
|
||||
} \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Default equality comparison functions */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines a default equality comparison function for pointer values.
|
||||
*
|
||||
* @param left A pointer to the first value.
|
||||
* @param right A pointer to the second value.
|
||||
*
|
||||
* @return Returns `ZYAN_TRUE` if the `left` value equals the `right` one or `ZYAN_FALSE`, if
|
||||
* not.
|
||||
*/
|
||||
ZYAN_INLINE ZYAN_DECLARE_EQUALITY_COMPARISON(ZyanEqualsPointer, void* const)
|
||||
|
||||
/**
|
||||
* Defines a default equality comparison function for `ZyanBool` values.
|
||||
*
|
||||
* @param left A pointer to the first value.
|
||||
* @param right A pointer to the second value.
|
||||
*
|
||||
* @return Returns `ZYAN_TRUE` if the `left` value equals the `right` one or `ZYAN_FALSE`, if
|
||||
* not.
|
||||
*/
|
||||
ZYAN_INLINE ZYAN_DECLARE_EQUALITY_COMPARISON(ZyanEqualsBool, ZyanBool)
|
||||
|
||||
/**
|
||||
* Defines a default equality comparison function for 8-bit numeric values.
|
||||
*
|
||||
* @param left A pointer to the first value.
|
||||
* @param right A pointer to the second value.
|
||||
*
|
||||
* @return Returns `ZYAN_TRUE` if the `left` value equals the `right` one or `ZYAN_FALSE`, if
|
||||
* not.
|
||||
*/
|
||||
ZYAN_INLINE ZYAN_DECLARE_EQUALITY_COMPARISON(ZyanEqualsNumeric8, ZyanU8)
|
||||
|
||||
/**
|
||||
* Defines a default equality comparison function for 16-bit numeric values.
|
||||
*
|
||||
* @param left A pointer to the first value.
|
||||
* @param right A pointer to the second value.
|
||||
*
|
||||
* @return Returns `ZYAN_TRUE` if the `left` value equals the `right` one or `ZYAN_FALSE`, if
|
||||
* not.
|
||||
*/
|
||||
ZYAN_INLINE ZYAN_DECLARE_EQUALITY_COMPARISON(ZyanEqualsNumeric16, ZyanU16)
|
||||
|
||||
/**
|
||||
* Defines a default equality comparison function for 32-bit numeric values.
|
||||
*
|
||||
* @param left A pointer to the first value.
|
||||
* @param right A pointer to the second value.
|
||||
*
|
||||
* @return Returns `ZYAN_TRUE` if the `left` value equals the `right` one or `ZYAN_FALSE`, if
|
||||
* not.
|
||||
*/
|
||||
ZYAN_INLINE ZYAN_DECLARE_EQUALITY_COMPARISON(ZyanEqualsNumeric32, ZyanU32)
|
||||
|
||||
/**
|
||||
* Defines a default equality comparison function for 64-bit numeric values.
|
||||
*
|
||||
* @param left A pointer to the first value.
|
||||
* @param right A pointer to the second value.
|
||||
*
|
||||
* @return Returns `ZYAN_TRUE` if the `left` value equals the `right` one or `ZYAN_FALSE`, if
|
||||
* not.
|
||||
*/
|
||||
ZYAN_INLINE ZYAN_DECLARE_EQUALITY_COMPARISON(ZyanEqualsNumeric64, ZyanU64)
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Default comparison functions */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines a default comparison function for pointer values.
|
||||
*
|
||||
* @param left A pointer to the first value.
|
||||
* @param right A pointer to the second value.
|
||||
*
|
||||
* @return Returns `0` if the `left` value equals the `right` one, `-1` if the `left` value is
|
||||
* less than the `right` one, or `1` if the `left` value is greater than the `right` one.
|
||||
*/
|
||||
ZYAN_INLINE ZYAN_DECLARE_COMPARISON(ZyanComparePointer, void* const)
|
||||
|
||||
/**
|
||||
* Defines a default comparison function for `ZyanBool` values.
|
||||
*
|
||||
* @param left A pointer to the first value.
|
||||
* @param right A pointer to the second value.
|
||||
*
|
||||
* @return Returns `0` if the `left` value equals the `right` one, `-1` if the `left` value is
|
||||
* less than the `right` one, or `1` if the `left` value is greater than the `right` one.
|
||||
*/
|
||||
ZYAN_INLINE ZYAN_DECLARE_COMPARISON(ZyanCompareBool, ZyanBool)
|
||||
|
||||
/**
|
||||
* Defines a default comparison function for 8-bit numeric values.
|
||||
*
|
||||
* @param left A pointer to the first value.
|
||||
* @param right A pointer to the second value.
|
||||
*
|
||||
* @return Returns `0` if the `left` value equals the `right` one, `-1` if the `left` value is
|
||||
* less than the `right` one, or `1` if the `left` value is greater than the `right` one.
|
||||
*/
|
||||
ZYAN_INLINE ZYAN_DECLARE_COMPARISON(ZyanCompareNumeric8, ZyanU8)
|
||||
|
||||
/**
|
||||
* Defines a default comparison function for 16-bit numeric values.
|
||||
*
|
||||
* @param left A pointer to the first value.
|
||||
* @param right A pointer to the second value.
|
||||
*
|
||||
* @return Returns `0` if the `left` value equals the `right` one, `-1` if the `left` value is
|
||||
* less than the `right` one, or `1` if the `left` value is greater than the `right` one.
|
||||
*/
|
||||
ZYAN_INLINE ZYAN_DECLARE_COMPARISON(ZyanCompareNumeric16, ZyanU16)
|
||||
|
||||
/**
|
||||
* Defines a default comparison function for 32-bit numeric values.
|
||||
*
|
||||
* @param left A pointer to the first value.
|
||||
* @param right A pointer to the second value.
|
||||
*
|
||||
* @return Returns `0` if the `left` value equals the `right` one, `-1` if the `left` value is
|
||||
* less than the `right` one, or `1` if the `left` value is greater than the `right` one.
|
||||
*/
|
||||
ZYAN_INLINE ZYAN_DECLARE_COMPARISON(ZyanCompareNumeric32, ZyanU32)
|
||||
|
||||
/**
|
||||
* Defines a default comparison function for 64-bit numeric values.
|
||||
*
|
||||
* @param left A pointer to the first value.
|
||||
* @param right A pointer to the second value.
|
||||
*
|
||||
* @return Returns `0` if the `left` value equals the `right` one, `-1` if the `left` value is
|
||||
* less than the `right` one, or `1` if the `left` value is greater than the `right` one.
|
||||
*/
|
||||
ZYAN_INLINE ZYAN_DECLARE_COMPARISON(ZyanCompareNumeric64, ZyanU64)
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZYCORE_COMPARISON_H */
|
||||
@@ -0,0 +1,565 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zycore-C)
|
||||
|
||||
Original Author : Florian Bernd, Joel Hoener
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* General helper and platform detection macros.
|
||||
*/
|
||||
|
||||
#ifndef ZYCORE_DEFINES_H
|
||||
#define ZYCORE_DEFINES_H
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Meta macros */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* Concatenates two values using the stringify operator (`##`).
|
||||
*
|
||||
* @param x The first value.
|
||||
* @param y The second value.
|
||||
*
|
||||
* @return The combined string of the given values.
|
||||
*/
|
||||
#define ZYAN_MACRO_CONCAT(x, y) x ## y
|
||||
|
||||
/**
|
||||
* Concatenates two values using the stringify operator (`##`) and expands the value to
|
||||
* be used in another macro.
|
||||
*
|
||||
* @param x The first value.
|
||||
* @param y The second value.
|
||||
*
|
||||
* @return The combined string of the given values.
|
||||
*/
|
||||
#define ZYAN_MACRO_CONCAT_EXPAND(x, y) ZYAN_MACRO_CONCAT(x, y)
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Compiler detection */
|
||||
/* ============================================================================================== */
|
||||
|
||||
#if defined(__clang__)
|
||||
# define ZYAN_CLANG
|
||||
# define ZYAN_GNUC
|
||||
# if defined(_MSC_VER)
|
||||
# define ZYAN_CLANG_CL
|
||||
# define ZYAN_MSVC
|
||||
# endif
|
||||
#elif defined(__ICC) || defined(__INTEL_COMPILER)
|
||||
# define ZYAN_ICC
|
||||
#elif defined(__GNUC__) || defined(__GNUG__)
|
||||
# define ZYAN_GCC
|
||||
# define ZYAN_GNUC
|
||||
#elif defined(_MSC_VER)
|
||||
# define ZYAN_MSVC
|
||||
#elif defined(__BORLANDC__)
|
||||
# define ZYAN_BORLAND
|
||||
#else
|
||||
# define ZYAN_UNKNOWN_COMPILER
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Platform detection */
|
||||
/* ============================================================================================== */
|
||||
|
||||
#if defined(_WIN32)
|
||||
# define ZYAN_WINDOWS
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
# define ZYAN_EMSCRIPTEN
|
||||
#elif defined(__wasi__) || defined(__WASI__)
|
||||
// via: https://reviews.llvm.org/D57155
|
||||
# define ZYAN_WASI
|
||||
#elif defined(__APPLE__)
|
||||
# define ZYAN_APPLE
|
||||
# define ZYAN_POSIX
|
||||
#elif defined(__linux)
|
||||
# define ZYAN_LINUX
|
||||
# define ZYAN_POSIX
|
||||
#elif defined(__FreeBSD__)
|
||||
# define ZYAN_FREEBSD
|
||||
# define ZYAN_POSIX
|
||||
#elif defined(__NetBSD__)
|
||||
# define ZYAN_NETBSD
|
||||
# define ZYAN_POSIX
|
||||
#elif defined(sun) || defined(__sun)
|
||||
# define ZYAN_SOLARIS
|
||||
# define ZYAN_POSIX
|
||||
#elif defined(__HAIKU__)
|
||||
# define ZYAN_HAIKU
|
||||
# define ZYAN_POSIX
|
||||
#elif defined(__unix) || defined(__unix__)
|
||||
# define ZYAN_UNIX
|
||||
# define ZYAN_POSIX
|
||||
#elif defined(__posix)
|
||||
# define ZYAN_POSIX
|
||||
#else
|
||||
# define ZYAN_UNKNOWN_PLATFORM
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Kernel mode detection */
|
||||
/* ============================================================================================== */
|
||||
|
||||
#if (defined(ZYAN_WINDOWS) && defined(_KERNEL_MODE)) || \
|
||||
(defined(ZYAN_APPLE) && defined(KERNEL)) || \
|
||||
(defined(ZYAN_LINUX) && defined(__KERNEL__)) || \
|
||||
(defined(__FreeBSD_kernel__))
|
||||
# define ZYAN_KERNEL
|
||||
#else
|
||||
# define ZYAN_USER
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Architecture detection */
|
||||
/* ============================================================================================== */
|
||||
|
||||
#if defined(_M_AMD64) || defined(__x86_64__)
|
||||
# define ZYAN_X64
|
||||
#elif defined(_M_IX86) || defined(__i386__)
|
||||
# define ZYAN_X86
|
||||
#elif defined(_M_ARM64) || defined(__aarch64__)
|
||||
# define ZYAN_AARCH64
|
||||
#elif defined(_M_ARM) || defined(_M_ARMT) || defined(__arm__) || defined(__thumb__)
|
||||
# define ZYAN_ARM
|
||||
#elif defined(__EMSCRIPTEN__) || defined(__wasm__) || defined(__WASM__)
|
||||
# define ZYAN_WASM
|
||||
#elif defined(__loongarch__)
|
||||
# define ZYAN_LOONGARCH
|
||||
#elif defined(__powerpc64__)
|
||||
# define ZYAN_PPC64
|
||||
#elif defined(__powerpc__)
|
||||
# define ZYAN_PPC
|
||||
#elif defined(__riscv) && __riscv_xlen == 64
|
||||
# define ZYAN_RISCV64
|
||||
#else
|
||||
# error "Unsupported architecture detected"
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Debug/Release detection */
|
||||
/* ============================================================================================== */
|
||||
|
||||
#if defined(ZYAN_MSVC) || defined(ZYAN_BORLAND)
|
||||
# ifdef _DEBUG
|
||||
# define ZYAN_DEBUG
|
||||
# else
|
||||
# define ZYAN_RELEASE
|
||||
# endif
|
||||
#elif defined(ZYAN_GNUC) || defined(ZYAN_ICC)
|
||||
# ifdef NDEBUG
|
||||
# define ZYAN_RELEASE
|
||||
# else
|
||||
# define ZYAN_DEBUG
|
||||
# endif
|
||||
#else
|
||||
# define ZYAN_RELEASE
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Deprecation hint */
|
||||
/* ============================================================================================== */
|
||||
|
||||
#if defined(ZYAN_GCC) || defined(ZYAN_CLANG)
|
||||
# define ZYAN_DEPRECATED __attribute__((__deprecated__))
|
||||
#elif defined(ZYAN_MSVC)
|
||||
# define ZYAN_DEPRECATED __declspec(deprecated)
|
||||
#else
|
||||
# define ZYAN_DEPRECATED
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Generic DLL import/export helpers */
|
||||
/* ============================================================================================== */
|
||||
|
||||
#if defined(ZYAN_MSVC) || (defined(ZYAN_WINDOWS) && defined(ZYAN_GNUC))
|
||||
# define ZYAN_DLLEXPORT __declspec(dllexport)
|
||||
# define ZYAN_DLLIMPORT __declspec(dllimport)
|
||||
#else
|
||||
# if defined(ZYAN_GNUC)
|
||||
# define ZYAN_DLLEXPORT __attribute__((__visibility__("default")))
|
||||
# define ZYAN_DLLIMPORT extern
|
||||
# else
|
||||
# define ZYAN_DLLEXPORT
|
||||
# define ZYAN_DLLIMPORT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Zycore dll{export,import} */
|
||||
/* ============================================================================================== */
|
||||
|
||||
// This is a cut-down version of what CMake's `GenerateExportHeader` would usually generate. To
|
||||
// simplify builds without CMake, we define these things manually instead of relying on CMake
|
||||
// to generate the header.
|
||||
//
|
||||
// For static builds, our CMakeList will define `ZYCORE_STATIC_BUILD`. For shared library builds,
|
||||
// our CMake will define `ZYCORE_SHOULD_EXPORT` depending on whether the target is being imported or
|
||||
// exported. If CMake isn't used, users can manually define these to fit their use-case.
|
||||
|
||||
// Backward compatibility: CMake would previously generate these variables names. However, because
|
||||
// they have pretty cryptic names, we renamed them when we got rid of `GenerateExportHeader`. For
|
||||
// backward compatibility for users that don't use CMake and previously manually defined these, we
|
||||
// translate the old defines here and print a warning.
|
||||
#if defined(ZYCORE_STATIC_DEFINE)
|
||||
# pragma message("ZYCORE_STATIC_DEFINE was renamed to ZYCORE_STATIC_BUILD.")
|
||||
# define ZYCORE_STATIC_BUILD
|
||||
#endif
|
||||
#if defined(Zycore_EXPORTS)
|
||||
# pragma message("Zycore_EXPORTS was renamed to ZYCORE_SHOULD_EXPORT.")
|
||||
# define ZYCORE_SHOULD_EXPORT
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Symbol is exported in shared library builds.
|
||||
*/
|
||||
#if defined(ZYCORE_STATIC_BUILD)
|
||||
# define ZYCORE_EXPORT
|
||||
#else
|
||||
# if defined(ZYCORE_SHOULD_EXPORT)
|
||||
# define ZYCORE_EXPORT ZYAN_DLLEXPORT
|
||||
# else
|
||||
# define ZYCORE_EXPORT ZYAN_DLLIMPORT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Symbol is not exported and for internal use only.
|
||||
*/
|
||||
#if defined(ZYAN_GNUC)
|
||||
# define ZYCORE_NO_EXPORT __attribute__((__visibility__("hidden")))
|
||||
#else
|
||||
# define ZYCORE_NO_EXPORT
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Misc compatibility macros */
|
||||
/* ============================================================================================== */
|
||||
|
||||
#if defined(ZYAN_CLANG)
|
||||
# define ZYAN_NO_SANITIZE(what) __attribute__((no_sanitize(what)))
|
||||
#else
|
||||
# define ZYAN_NO_SANITIZE(what)
|
||||
#endif
|
||||
|
||||
#if defined(ZYAN_MSVC) || defined(ZYAN_BORLAND)
|
||||
# define ZYAN_INLINE __inline
|
||||
#else
|
||||
# define ZYAN_INLINE static inline
|
||||
#endif
|
||||
|
||||
#if defined(ZYAN_MSVC)
|
||||
# define ZYAN_NOINLINE __declspec(noinline)
|
||||
#elif defined(ZYAN_GCC) || defined(ZYAN_CLANG)
|
||||
# define ZYAN_NOINLINE __attribute__((noinline))
|
||||
#else
|
||||
# define ZYAN_NOINLINE
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Debugging and optimization macros */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* Runtime debug assertion.
|
||||
*/
|
||||
#if defined(ZYAN_NO_LIBC)
|
||||
# define ZYAN_ASSERT(condition) (void)(condition)
|
||||
#elif defined(ZYAN_WINDOWS) && defined(ZYAN_KERNEL)
|
||||
# include <wdm.h>
|
||||
# define ZYAN_ASSERT(condition) NT_ASSERT(condition)
|
||||
#else
|
||||
# include <assert.h>
|
||||
# define ZYAN_ASSERT(condition) assert(condition)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Compiler-time assertion.
|
||||
*/
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__cplusplus)
|
||||
# define ZYAN_STATIC_ASSERT(x) _Static_assert(x, #x)
|
||||
#elif (defined(__cplusplus) && __cplusplus >= 201103L) || \
|
||||
(defined(__cplusplus) && defined (_MSC_VER) && (_MSC_VER >= 1600)) || \
|
||||
(defined (_MSC_VER) && (_MSC_VER >= 1800))
|
||||
# define ZYAN_STATIC_ASSERT(x) static_assert(x, #x)
|
||||
#elif defined(ZYAN_GNUC)
|
||||
# define ZYAN_STATIC_ASSERT(x) \
|
||||
__attribute__((unused)) typedef int ZYAN_MACRO_CONCAT_EXPAND(ZYAN_SASSERT_, __COUNTER__) [(x) ? 1 : -1]
|
||||
#else
|
||||
# define ZYAN_STATIC_ASSERT(x) \
|
||||
typedef int ZYAN_MACRO_CONCAT_EXPAND(ZYAN_SASSERT_, __COUNTER__) [(x) ? 1 : -1]
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Marks the current code path as unreachable.
|
||||
*/
|
||||
#if defined(ZYAN_RELEASE)
|
||||
# if defined(ZYAN_CLANG) // GCC eagerly evals && RHS, we have to use nested ifs.
|
||||
# if __has_builtin(__builtin_unreachable)
|
||||
# define ZYAN_UNREACHABLE __builtin_unreachable()
|
||||
# else
|
||||
# define ZYAN_UNREACHABLE for(;;)
|
||||
# endif
|
||||
# elif defined(ZYAN_GCC) && ((__GNUC__ == 4 && __GNUC_MINOR__ > 4) || __GNUC__ > 4)
|
||||
# define ZYAN_UNREACHABLE __builtin_unreachable()
|
||||
# elif defined(ZYAN_ICC)
|
||||
# ifdef ZYAN_WINDOWS
|
||||
# include <stdlib.h> // "missing return statement" workaround
|
||||
# define ZYAN_UNREACHABLE __assume(0); (void)abort()
|
||||
# else
|
||||
# define ZYAN_UNREACHABLE __builtin_unreachable()
|
||||
# endif
|
||||
# elif defined(ZYAN_MSVC)
|
||||
# define ZYAN_UNREACHABLE __assume(0)
|
||||
# else
|
||||
# define ZYAN_UNREACHABLE for(;;)
|
||||
# endif
|
||||
#elif defined(ZYAN_NO_LIBC)
|
||||
# define ZYAN_UNREACHABLE for(;;)
|
||||
#elif defined(ZYAN_WINDOWS) && defined(ZYAN_KERNEL)
|
||||
# define ZYAN_UNREACHABLE { __fastfail(0); for(;;){} }
|
||||
#else
|
||||
# include <stdlib.h>
|
||||
# define ZYAN_UNREACHABLE { assert(0); abort(); }
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Utils */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* General purpose */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Marks the specified parameter as unused.
|
||||
*
|
||||
* @param x The name of the unused parameter.
|
||||
*/
|
||||
#define ZYAN_UNUSED(x) (void)(x)
|
||||
|
||||
/**
|
||||
* Intentional fallthrough.
|
||||
*/
|
||||
#if defined(ZYAN_GCC) && __GNUC__ >= 7
|
||||
# define ZYAN_FALLTHROUGH ; __attribute__((__fallthrough__))
|
||||
#else
|
||||
# define ZYAN_FALLTHROUGH
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Declares a bitfield.
|
||||
*
|
||||
* @param x The size (in bits) of the bitfield.
|
||||
*/
|
||||
#define ZYAN_BITFIELD(x) : x
|
||||
|
||||
/**
|
||||
* Marks functions that require libc (cannot be used with `ZYAN_NO_LIBC`).
|
||||
*/
|
||||
#define ZYAN_REQUIRES_LIBC
|
||||
|
||||
/**
|
||||
* Decorator for `printf`-style functions.
|
||||
*
|
||||
* @param format_index The 1-based index of the format string parameter.
|
||||
* @param first_to_check The 1-based index of the format arguments parameter.
|
||||
*/
|
||||
#if defined(__RESHARPER__)
|
||||
# define ZYAN_PRINTF_ATTR(format_index, first_to_check) \
|
||||
[[gnu::format(printf, format_index, first_to_check)]]
|
||||
#elif defined(ZYAN_GCC)
|
||||
# define ZYAN_PRINTF_ATTR(format_index, first_to_check) \
|
||||
__attribute__((format(printf, format_index, first_to_check)))
|
||||
#else
|
||||
# define ZYAN_PRINTF_ATTR(format_index, first_to_check)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Decorator for `wprintf`-style functions.
|
||||
*
|
||||
* @param format_index The 1-based index of the format string parameter.
|
||||
* @param first_to_check The 1-based index of the format arguments parameter.
|
||||
*/
|
||||
#if defined(__RESHARPER__)
|
||||
# define ZYAN_WPRINTF_ATTR(format_index, first_to_check) \
|
||||
[[rscpp::format(wprintf, format_index, first_to_check)]]
|
||||
#else
|
||||
# define ZYAN_WPRINTF_ATTR(format_index, first_to_check)
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Arrays */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Returns the length (number of elements) of an array.
|
||||
*
|
||||
* @param a The name of the array.
|
||||
*
|
||||
* @return The number of elements of the given array.
|
||||
*/
|
||||
#define ZYAN_ARRAY_LENGTH(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Arithmetic */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Returns the smaller value of `a` or `b`.
|
||||
*
|
||||
* @param a The first value.
|
||||
* @param b The second value.
|
||||
*
|
||||
* @return The smaller value of `a` or `b`.
|
||||
*/
|
||||
#define ZYAN_MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
/**
|
||||
* Returns the bigger value of `a` or `b`.
|
||||
*
|
||||
* @param a The first value.
|
||||
* @param b The second value.
|
||||
*
|
||||
* @return The bigger value of `a` or `b`.
|
||||
*/
|
||||
#define ZYAN_MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
/**
|
||||
* Returns the absolute value of `a`.
|
||||
*
|
||||
* @param a The value.
|
||||
*
|
||||
* @return The absolute value of `a`.
|
||||
*/
|
||||
#define ZYAN_ABS(a) (((a) < 0) ? -(a) : (a))
|
||||
|
||||
/**
|
||||
* Checks, if the given value is a power of 2.
|
||||
*
|
||||
* @param x The value.
|
||||
*
|
||||
* @return `ZYAN_TRUE`, if the given value is a power of 2 or `ZYAN_FALSE`, if not.
|
||||
*
|
||||
* Note that this macro always returns `ZYAN_TRUE` for `x == 0`.
|
||||
*/
|
||||
#define ZYAN_IS_POWER_OF_2(x) (((x) & ((x) - 1)) == 0)
|
||||
|
||||
/**
|
||||
* Checks, if the given value is properly aligned.
|
||||
*
|
||||
* Note that this macro only works for powers of 2.
|
||||
*/
|
||||
#define ZYAN_IS_ALIGNED_TO(x, align) (((x) & ((align) - 1)) == 0)
|
||||
|
||||
/**
|
||||
* Aligns the value to the nearest given alignment boundary (by rounding it up).
|
||||
*
|
||||
* @param x The value.
|
||||
* @param align The desired alignment.
|
||||
*
|
||||
* @return The aligned value.
|
||||
*
|
||||
* Note that this macro only works for powers of 2.
|
||||
*/
|
||||
#define ZYAN_ALIGN_UP(x, align) (((x) + (align) - 1) & ~((align) - 1))
|
||||
|
||||
/**
|
||||
* Aligns the value to the nearest given alignment boundary (by rounding it down).
|
||||
*
|
||||
* @param x The value.
|
||||
* @param align The desired alignment.
|
||||
*
|
||||
* @return The aligned value.
|
||||
*
|
||||
* Note that this macro only works for powers of 2.
|
||||
*/
|
||||
#define ZYAN_ALIGN_DOWN(x, align) (((x) - 1) & ~((align) - 1))
|
||||
|
||||
/**
|
||||
* Divide the 64bit integer value by the given divisor.
|
||||
*
|
||||
* @param n Variable containing the dividend that will be updated with the result of the
|
||||
* division.
|
||||
* @param divisor The divisor.
|
||||
*/
|
||||
#if defined(ZYAN_LINUX) && defined(ZYAN_KERNEL)
|
||||
# include <asm/div64.h> /* do_div */
|
||||
# define ZYAN_DIV64(n, divisor) do_div(n, divisor)
|
||||
#else
|
||||
# define ZYAN_DIV64(n, divisor) (n /= divisor)
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Bit operations */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Checks, if the bit at index `b` is required to present the ordinal value `n`.
|
||||
*
|
||||
* @param n The ordinal value.
|
||||
* @param b The bit index.
|
||||
*
|
||||
* @return `ZYAN_TRUE`, if the bit at index `b` is required to present the ordinal value `n` or
|
||||
* `ZYAN_FALSE`, if not.
|
||||
*
|
||||
* Note that this macro always returns `ZYAN_FALSE` for `n == 0`.
|
||||
*/
|
||||
#define ZYAN_NEEDS_BIT(n, b) (((unsigned long)(n) >> (b)) > 0)
|
||||
|
||||
/*
|
||||
* Returns the number of bits required to represent the ordinal value `n`.
|
||||
*
|
||||
* @param n The ordinal value.
|
||||
*
|
||||
* @return The number of bits required to represent the ordinal value `n`.
|
||||
*
|
||||
* Note that this macro returns `0` for `n == 0`.
|
||||
*/
|
||||
#define ZYAN_BITS_TO_REPRESENT(n) \
|
||||
( \
|
||||
ZYAN_NEEDS_BIT(n, 0) + ZYAN_NEEDS_BIT(n, 1) + \
|
||||
ZYAN_NEEDS_BIT(n, 2) + ZYAN_NEEDS_BIT(n, 3) + \
|
||||
ZYAN_NEEDS_BIT(n, 4) + ZYAN_NEEDS_BIT(n, 5) + \
|
||||
ZYAN_NEEDS_BIT(n, 6) + ZYAN_NEEDS_BIT(n, 7) + \
|
||||
ZYAN_NEEDS_BIT(n, 8) + ZYAN_NEEDS_BIT(n, 9) + \
|
||||
ZYAN_NEEDS_BIT(n, 10) + ZYAN_NEEDS_BIT(n, 11) + \
|
||||
ZYAN_NEEDS_BIT(n, 12) + ZYAN_NEEDS_BIT(n, 13) + \
|
||||
ZYAN_NEEDS_BIT(n, 14) + ZYAN_NEEDS_BIT(n, 15) + \
|
||||
ZYAN_NEEDS_BIT(n, 16) + ZYAN_NEEDS_BIT(n, 17) + \
|
||||
ZYAN_NEEDS_BIT(n, 18) + ZYAN_NEEDS_BIT(n, 19) + \
|
||||
ZYAN_NEEDS_BIT(n, 20) + ZYAN_NEEDS_BIT(n, 21) + \
|
||||
ZYAN_NEEDS_BIT(n, 22) + ZYAN_NEEDS_BIT(n, 23) + \
|
||||
ZYAN_NEEDS_BIT(n, 24) + ZYAN_NEEDS_BIT(n, 25) + \
|
||||
ZYAN_NEEDS_BIT(n, 26) + ZYAN_NEEDS_BIT(n, 27) + \
|
||||
ZYAN_NEEDS_BIT(n, 28) + ZYAN_NEEDS_BIT(n, 29) + \
|
||||
ZYAN_NEEDS_BIT(n, 30) + ZYAN_NEEDS_BIT(n, 31) \
|
||||
)
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#endif /* ZYCORE_DEFINES_H */
|
||||
@@ -0,0 +1,285 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zycore-C)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Provides helper functions for performant number to string conversion.
|
||||
*/
|
||||
|
||||
#ifndef ZYCORE_FORMAT_H
|
||||
#define ZYCORE_FORMAT_H
|
||||
|
||||
#include <Zycore/Status.h>
|
||||
#include <Zycore/String.h>
|
||||
#include <Zycore/Types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Helpers */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Get the absolute value of a 64 bit int.
|
||||
*
|
||||
* @param x The value to process.
|
||||
* @return The absolute, unsigned value.
|
||||
*
|
||||
* This gracefully deals with the special case of `x` being `INT_MAX`.
|
||||
*/
|
||||
ZYAN_INLINE ZyanU64 ZyanAbsI64(ZyanI64 x)
|
||||
{
|
||||
// INT_MIN special case. Can't use the value directly because GCC thinks
|
||||
// it's too big for an INT64 literal, however is perfectly happy to accept
|
||||
// this expression. This is also hit INT64_MIN is defined in `stdint.h`.
|
||||
if (x == (-0x7fffffffffffffff - 1))
|
||||
{
|
||||
return 0x8000000000000000u;
|
||||
}
|
||||
|
||||
return (ZyanU64)(x < 0 ? -x : x);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Insertion */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Inserts formatted text in the destination string at the given `index`.
|
||||
*
|
||||
* @param string The destination string.
|
||||
* @param index The insert index.
|
||||
* @param format The format string.
|
||||
* @param ... The format arguments.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified
|
||||
* `ZyanString` instance.
|
||||
*/
|
||||
ZYAN_PRINTF_ATTR(3, 4)
|
||||
ZYCORE_EXPORT ZyanStatus ZyanStringInsertFormat(ZyanString* string, ZyanUSize index,
|
||||
const char* format, ...);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Formats the given unsigned ordinal `value` to its decimal text-representation and
|
||||
* inserts it to the `string`.
|
||||
*
|
||||
* @param string A pointer to the `ZyanString` instance.
|
||||
* @param index The insert index.
|
||||
* @param value The value.
|
||||
* @param padding_length Padds the converted value with leading zeros, if the number of chars is
|
||||
* less than the `padding_length`.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified
|
||||
* `ZyanString` instance.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanStringInsertDecU(ZyanString* string, ZyanUSize index, ZyanU64 value,
|
||||
ZyanU8 padding_length);
|
||||
|
||||
/**
|
||||
* Formats the given signed ordinal `value` to its decimal text-representation and
|
||||
* inserts it to the `string`.
|
||||
*
|
||||
* @param string A pointer to the `ZyanString` instance.
|
||||
* @param index The insert index.
|
||||
* @param value The value.
|
||||
* @param padding_length Padds the converted value with leading zeros, if the number of chars is
|
||||
* less than the `padding_length`.
|
||||
* @param force_sign Set `ZYAN_TRUE`, to force printing of the `+` sign for positive numbers.
|
||||
* @param prefix The string to use as prefix or `ZYAN_NULL`, if not needed.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified
|
||||
* `ZyanString` instance.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanStringInsertDecS(ZyanString* string, ZyanUSize index, ZyanI64 value,
|
||||
ZyanU8 padding_length, ZyanBool force_sign, const ZyanString* prefix);
|
||||
|
||||
/**
|
||||
* Formats the given unsigned ordinal `value` to its hexadecimal text-representation and
|
||||
* inserts it to the `string`.
|
||||
*
|
||||
* @param string A pointer to the `ZyanString` instance.
|
||||
* @param index The insert index.
|
||||
* @param value The value.
|
||||
* @param padding_length Padds the converted value with leading zeros, if the number of chars is
|
||||
* less than the `padding_length`.
|
||||
* @param uppercase Set `ZYAN_TRUE` to use uppercase letters ('A'-'F') instead of lowercase
|
||||
* ones ('a'-'f').
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified
|
||||
* `ZyanString` instance.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanStringInsertHexU(ZyanString* string, ZyanUSize index, ZyanU64 value,
|
||||
ZyanU8 padding_length, ZyanBool uppercase);
|
||||
|
||||
/**
|
||||
* Formats the given signed ordinal `value` to its hexadecimal text-representation and
|
||||
* inserts it to the `string`.
|
||||
*
|
||||
* @param string A pointer to the `ZyanString` instance.
|
||||
* @param index The insert index.
|
||||
* @param value The value.
|
||||
* @param padding_length Padds the converted value with leading zeros, if the number of chars is
|
||||
* less than the `padding_length`.
|
||||
* @param uppercase Set `ZYAN_TRUE` to use uppercase letters ('A'-'F') instead of lowercase
|
||||
* ones ('a'-'f').
|
||||
* @param force_sign Set `ZYAN_TRUE`, to force printing of the `+` sign for positive numbers.
|
||||
* @param prefix The string to use as prefix or `ZYAN_NULL`, if not needed.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified
|
||||
* `ZyanString` instance.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanStringInsertHexS(ZyanString* string, ZyanUSize index, ZyanI64 value,
|
||||
ZyanU8 padding_length, ZyanBool uppercase, ZyanBool force_sign, const ZyanString* prefix);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Appending */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef ZYAN_NO_LIBC
|
||||
|
||||
/**
|
||||
* Appends formatted text to the destination string.
|
||||
*
|
||||
* @param string The destination string.
|
||||
* @param format The format string.
|
||||
* @param ... The format arguments.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified
|
||||
* `ZyanString` instance.
|
||||
*/
|
||||
ZYAN_PRINTF_ATTR(2, 3)
|
||||
ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanStringAppendFormat(
|
||||
ZyanString* string, const char* format, ...);
|
||||
|
||||
#endif // ZYAN_NO_LIBC
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Formats the given unsigned ordinal `value` to its decimal text-representation and
|
||||
* appends it to the `string`.
|
||||
*
|
||||
* @param string A pointer to the `ZyanString` instance.
|
||||
* @param value The value.
|
||||
* @param padding_length Padds the converted value with leading zeros, if the number of chars is
|
||||
* less than the `padding_length`.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified
|
||||
* `ZyanString` instance.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanStringAppendDecU(ZyanString* string, ZyanU64 value,
|
||||
ZyanU8 padding_length);
|
||||
|
||||
/**
|
||||
* Formats the given signed ordinal `value` to its decimal text-representation and
|
||||
* appends it to the `string`.
|
||||
*
|
||||
* @param string A pointer to the `ZyanString` instance.
|
||||
* @param value The value.
|
||||
* @param padding_length Padds the converted value with leading zeros, if the number of chars is
|
||||
* less than the `padding_length`.
|
||||
* @param force_sign Set `ZYAN_TRUE`, to force printing of the `+` sign for positive numbers.
|
||||
* @param prefix The string to use as prefix or `ZYAN_NULL`, if not needed.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified
|
||||
* `ZyanString` instance.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanStringAppendDecS(ZyanString* string, ZyanI64 value,
|
||||
ZyanU8 padding_length, ZyanBool force_sign, const ZyanStringView* prefix);
|
||||
|
||||
/**
|
||||
* Formats the given unsigned ordinal `value` to its hexadecimal text-representation and
|
||||
* appends it to the `string`.
|
||||
*
|
||||
* @param string A pointer to the `ZyanString` instance.
|
||||
* @param value The value.
|
||||
* @param padding_length Padds the converted value with leading zeros, if the number of chars is
|
||||
* less than the `padding_length`.
|
||||
* @param uppercase Set `ZYAN_TRUE` to use uppercase letters ('A'-'F') instead of lowercase
|
||||
* ones ('a'-'f').
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified
|
||||
* `ZyanString` instance.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanStringAppendHexU(ZyanString* string, ZyanU64 value,
|
||||
ZyanU8 padding_length, ZyanBool uppercase);
|
||||
|
||||
/**
|
||||
* Formats the given signed ordinal `value` to its hexadecimal text-representation and
|
||||
* appends it to the `string`.
|
||||
*
|
||||
* @param string A pointer to the `ZyanString` instance.
|
||||
* @param value The value.
|
||||
* @param padding_length Padds the converted value with leading zeros, if the number of chars is
|
||||
* less than the `padding_length`.
|
||||
* @param uppercase Set `ZYAN_TRUE` to use uppercase letters ('A'-'F') instead of lowercase
|
||||
* ones ('a'-'f').
|
||||
* @param force_sign Set `ZYAN_TRUE`, to force printing of the `+` sign for positive numbers.
|
||||
* @param prefix The string to use as prefix or `ZYAN_NULL`, if not needed.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified
|
||||
* `ZyanString` instance.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanStringAppendHexS(ZyanString* string, ZyanI64 value,
|
||||
ZyanU8 padding_length, ZyanBool uppercase, ZyanBool force_sign, const ZyanStringView* prefix);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // ZYCORE_FORMAT_H
|
||||
@@ -0,0 +1,117 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zyan-C)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
#ifndef ZYCORE_ATOMIC_GNU_H
|
||||
#define ZYCORE_ATOMIC_GNU_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <Zycore/Defines.h>
|
||||
#include <Zycore/Types.h>
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
#if defined(ZYAN_CLANG) || defined(ZYAN_GCC) || defined(ZYAN_ICC)
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Pointer sized */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZYAN_INLINE ZyanUPointer ZyanAtomicCompareExchange(ZyanAtomicPointer* destination,
|
||||
ZyanUPointer comparand, ZyanUPointer value)
|
||||
{
|
||||
return (ZyanUPointer)(__sync_val_compare_and_swap(
|
||||
&destination->value, (void*)comparand, (void*)value, &destination->value));
|
||||
}
|
||||
|
||||
ZYAN_INLINE ZyanUPointer ZyanAtomicIncrement(ZyanAtomicPointer* destination)
|
||||
{
|
||||
return (ZyanUPointer)(__sync_fetch_and_add(&destination->value, (void*)1,
|
||||
&destination->value)) + 1;
|
||||
}
|
||||
|
||||
ZYAN_INLINE ZyanUPointer ZyanAtomicDecrement(ZyanAtomicPointer* destination)
|
||||
{
|
||||
return (ZyanUPointer)(__sync_sub_and_fetch(&destination->value, (void*)1, &destination->value));
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* 32-bit */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZYAN_INLINE ZyanU32 ZyanAtomicCompareExchange32(ZyanAtomic32* destination,
|
||||
ZyanU32 comparand, ZyanU32 value)
|
||||
{
|
||||
return (ZyanU32)(__sync_val_compare_and_swap(&destination->value, comparand, value,
|
||||
&destination->value));
|
||||
}
|
||||
|
||||
ZYAN_INLINE ZyanU32 ZyanAtomicIncrement32(ZyanAtomic32* destination)
|
||||
{
|
||||
return (ZyanU32)(__sync_fetch_and_add(&destination->value, 1, &destination->value)) + 1;
|
||||
}
|
||||
|
||||
ZYAN_INLINE ZyanU32 ZyanAtomicDecrement32(ZyanAtomic32* destination)
|
||||
{
|
||||
return (ZyanU32)(__sync_sub_and_fetch(&destination->value, 1, &destination->value));
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* 64-bit */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZYAN_INLINE ZyanU64 ZyanAtomicCompareExchange64(ZyanAtomic64* destination,
|
||||
ZyanU64 comparand, ZyanU64 value)
|
||||
{
|
||||
return (ZyanU64)(__sync_val_compare_and_swap(&destination->value, comparand, value,
|
||||
&destination->value));
|
||||
}
|
||||
|
||||
ZYAN_INLINE ZyanU64 ZyanAtomicIncrement64(ZyanAtomic64* destination)
|
||||
{
|
||||
return (ZyanU64)(__sync_fetch_and_add(&destination->value, 1, &destination->value)) + 1;
|
||||
}
|
||||
|
||||
ZYAN_INLINE ZyanU64 ZyanAtomicDecrement64(ZyanAtomic64* destination)
|
||||
{
|
||||
return (ZyanU64)(__sync_sub_and_fetch(&destination->value, 1, &destination->value));
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZYCORE_ATOMIC_GNU_H */
|
||||
@@ -0,0 +1,141 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zyan-C)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
#ifndef ZYCORE_ATOMIC_MSVC_H
|
||||
#define ZYCORE_ATOMIC_MSVC_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <Zycore/Defines.h>
|
||||
#include <Zycore/Types.h>
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
#if defined(ZYAN_MSVC)
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Pointer sized */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#if defined(ZYAN_X86)
|
||||
|
||||
static ZYAN_INLINE ZyanUPointer ZyanAtomicCompareExchange(ZyanAtomicPointer* destination,
|
||||
ZyanUPointer comparand, ZyanUPointer value)
|
||||
{
|
||||
return (ZyanUPointer)ZyanAtomicCompareExchange32((ZyanAtomic32*)destination, comparand, value);
|
||||
}
|
||||
|
||||
static ZYAN_INLINE ZyanUPointer ZyanAtomicIncrement(ZyanAtomicPointer* destination)
|
||||
{
|
||||
return (ZyanUPointer)ZyanAtomicIncrement32((ZyanAtomic32*)destination);
|
||||
}
|
||||
|
||||
static ZYAN_INLINE ZyanUPointer ZyanAtomicDecrement(ZyanAtomicPointer* destination)
|
||||
{
|
||||
return (ZyanUPointer)ZyanAtomicDecrement32((ZyanAtomic32*)destination);
|
||||
}
|
||||
|
||||
#elif defined(ZYAN_X64)
|
||||
|
||||
static ZYAN_INLINE ZyanUPointer ZyanAtomicCompareExchange(ZyanAtomicPointer* destination,
|
||||
ZyanUPointer comparand, ZyanUPointer value)
|
||||
{
|
||||
return (ZyanUPointer)ZyanAtomicCompareExchange64((ZyanAtomic64*)destination, comparand, value);
|
||||
}
|
||||
|
||||
static ZYAN_INLINE ZyanUPointer ZyanAtomicIncrement(ZyanAtomicPointer* destination)
|
||||
{
|
||||
return (ZyanUPointer)ZyanAtomicIncrement64((ZyanAtomic64*)destination);
|
||||
}
|
||||
|
||||
static ZYAN_INLINE ZyanUPointer ZyanAtomicDecrement(ZyanAtomicPointer* destination)
|
||||
{
|
||||
return (ZyanUPointer)ZyanAtomicDecrement64((ZyanAtomic64*)destination);
|
||||
}
|
||||
|
||||
#else
|
||||
# error "Unsupported architecture detected"
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* 32-bit */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
static ZYAN_INLINE ZyanU32 ZyanAtomicCompareExchange32(ZyanAtomic32* destination,
|
||||
ZyanU32 comparand, ZyanU32 value)
|
||||
{
|
||||
return (ZyanU32)(_InterlockedCompareExchange((volatile LONG*)&(destination->value),
|
||||
(LONG)value, (LONG)comparand));
|
||||
}
|
||||
|
||||
static ZYAN_INLINE ZyanU32 ZyanAtomicIncrement32(ZyanAtomic32* destination)
|
||||
{
|
||||
return (ZyanU32)(_InterlockedIncrement((volatile LONG*)&(destination->value)));
|
||||
}
|
||||
|
||||
static ZYAN_INLINE ZyanU32 ZyanAtomicDecrement32(ZyanAtomic32* destination)
|
||||
{
|
||||
return (ZyanU32)(_InterlockedDecrement((volatile LONG*)&(destination->value)));
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* 64-bit */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
static ZYAN_INLINE ZyanU64 ZyanAtomicCompareExchange64(ZyanAtomic64* destination,
|
||||
ZyanU64 comparand, ZyanU64 value)
|
||||
{
|
||||
return (ZyanU64)(_InterlockedCompareExchange64((volatile LONG64*)&(destination->value),
|
||||
(LONG64)value, (LONG64)comparand));
|
||||
}
|
||||
|
||||
static ZYAN_INLINE ZyanU64 ZyanAtomicIncrement64(ZyanAtomic64* destination)
|
||||
{
|
||||
return (ZyanU64)(_InterlockedIncrement64((volatile LONG64*)&(destination->value)));
|
||||
}
|
||||
|
||||
static ZYAN_INLINE ZyanU64 ZyanAtomicDecrement64(ZyanAtomic64* destination)
|
||||
{
|
||||
return (ZyanU64)(_InterlockedDecrement64((volatile LONG64*)&(destination->value)));
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZYCORE_ATOMIC_MSVC_H */
|
||||
@@ -0,0 +1,512 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zycore-C)
|
||||
|
||||
Original Author : Florian Bernd, Joel Hoener
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Provides a simple LibC abstraction and fallback routines.
|
||||
*/
|
||||
|
||||
#ifndef ZYCORE_LIBC_H
|
||||
#define ZYCORE_LIBC_H
|
||||
|
||||
#ifndef ZYAN_CUSTOM_LIBC
|
||||
|
||||
// Include a custom LibC header and define `ZYAN_CUSTOM_LIBC` to provide your own LibC
|
||||
// replacement functions
|
||||
|
||||
#ifndef ZYAN_NO_LIBC
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* LibC is available */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* errno.h */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#define ZYAN_ERRNO errno
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* stdarg.h */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
/**
|
||||
* Defines the `ZyanVAList` datatype.
|
||||
*/
|
||||
typedef va_list ZyanVAList;
|
||||
|
||||
#define ZYAN_VA_START va_start
|
||||
#define ZYAN_VA_ARG va_arg
|
||||
#define ZYAN_VA_END va_end
|
||||
#define ZYAN_VA_COPY(dest, source) va_copy((dest), (source))
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* stdio.h */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define ZYAN_FPUTS fputs
|
||||
#define ZYAN_FPUTC fputc
|
||||
#define ZYAN_FPRINTF fprintf
|
||||
#define ZYAN_PRINTF printf
|
||||
#define ZYAN_PUTC putc
|
||||
#define ZYAN_PUTS puts
|
||||
#define ZYAN_SCANF scanf
|
||||
#define ZYAN_SSCANF sscanf
|
||||
#define ZYAN_VSNPRINTF vsnprintf
|
||||
|
||||
/**
|
||||
* Defines the `ZyanFile` datatype.
|
||||
*/
|
||||
typedef FILE ZyanFile;
|
||||
|
||||
#define ZYAN_STDIN stdin
|
||||
#define ZYAN_STDOUT stdout
|
||||
#define ZYAN_STDERR stderr
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* stdlib.h */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#include <stdlib.h>
|
||||
#define ZYAN_CALLOC calloc
|
||||
#define ZYAN_FREE free
|
||||
#define ZYAN_GETENV getenv
|
||||
#define ZYAN_MALLOC malloc
|
||||
#define ZYAN_REALLOC realloc
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* string.h */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#include <string.h>
|
||||
#define ZYAN_MEMCHR memchr
|
||||
#define ZYAN_MEMCMP memcmp
|
||||
#define ZYAN_MEMCPY memcpy
|
||||
#define ZYAN_MEMMOVE memmove
|
||||
#define ZYAN_MEMSET memset
|
||||
#define ZYAN_STRCAT strcat
|
||||
#define ZYAN_STRCHR strchr
|
||||
#define ZYAN_STRCMP strcmp
|
||||
#define ZYAN_STRCOLL strcoll
|
||||
#define ZYAN_STRCPY strcpy
|
||||
#define ZYAN_STRCSPN strcspn
|
||||
#define ZYAN_STRLEN strlen
|
||||
#define ZYAN_STRNCAT strncat
|
||||
#define ZYAN_STRNCMP strncmp
|
||||
#define ZYAN_STRNCPY strncpy
|
||||
#define ZYAN_STRPBRK strpbrk
|
||||
#define ZYAN_STRRCHR strrchr
|
||||
#define ZYAN_STRSPN strspn
|
||||
#define ZYAN_STRSTR strstr
|
||||
#define ZYAN_STRTOK strtok
|
||||
#define ZYAN_STRXFRM strxfrm
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#else // if ZYAN_NO_LIBC
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* No LibC available, use our own functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
#include <Zycore/Defines.h>
|
||||
#include <Zycore/Types.h>
|
||||
|
||||
/*
|
||||
* These implementations are by no means optimized and will be outperformed by pretty much any
|
||||
* libc implementation out there. We do not aim towards providing competetive implementations here,
|
||||
* but towards providing a last resort fallback for environments without a working libc.
|
||||
*/
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* stdarg.h */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#if defined(ZYAN_MSVC) || defined(ZYAN_ICC)
|
||||
|
||||
/**
|
||||
* Defines the `ZyanVAList` datatype.
|
||||
*/
|
||||
typedef char* ZyanVAList;
|
||||
|
||||
# define ZYAN_VA_START __crt_va_start
|
||||
# define ZYAN_VA_ARG __crt_va_arg
|
||||
# define ZYAN_VA_END __crt_va_end
|
||||
# define ZYAN_VA_COPY(destination, source) ((destination) = (source))
|
||||
|
||||
#elif defined(ZYAN_GNUC)
|
||||
|
||||
/**
|
||||
* Defines the `ZyanVAList` datatype.
|
||||
*/
|
||||
typedef __builtin_va_list ZyanVAList;
|
||||
|
||||
# define ZYAN_VA_START(v, l) __builtin_va_start(v, l)
|
||||
# define ZYAN_VA_END(v) __builtin_va_end(v)
|
||||
# define ZYAN_VA_ARG(v, l) __builtin_va_arg(v, l)
|
||||
# define ZYAN_VA_COPY(d, s) __builtin_va_copy(d, s)
|
||||
|
||||
#else
|
||||
# error "Unsupported compiler for no-libc mode."
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* stdio.h */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
// ZYAN_INLINE int ZYAN_VSNPRINTF (char* const buffer, ZyanUSize const count,
|
||||
// char const* const format, ZyanVAList args)
|
||||
// {
|
||||
// // We cant provide a fallback implementation for this function
|
||||
// ZYAN_UNUSED(buffer);
|
||||
// ZYAN_UNUSED(count);
|
||||
// ZYAN_UNUSED(format);
|
||||
// ZYAN_UNUSED(args);
|
||||
// return ZYAN_NULL;
|
||||
// }
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* stdlib.h */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
// ZYAN_INLINE void* ZYAN_CALLOC(ZyanUSize nitems, ZyanUSize size)
|
||||
// {
|
||||
// // We cant provide a fallback implementation for this function
|
||||
// ZYAN_UNUSED(nitems);
|
||||
// ZYAN_UNUSED(size);
|
||||
// return ZYAN_NULL;
|
||||
// }
|
||||
//
|
||||
// ZYAN_INLINE void ZYAN_FREE(void *p)
|
||||
// {
|
||||
// // We cant provide a fallback implementation for this function
|
||||
// ZYAN_UNUSED(p);
|
||||
// }
|
||||
//
|
||||
// ZYAN_INLINE void* ZYAN_MALLOC(ZyanUSize n)
|
||||
// {
|
||||
// // We cant provide a fallback implementation for this function
|
||||
// ZYAN_UNUSED(n);
|
||||
// return ZYAN_NULL;
|
||||
// }
|
||||
//
|
||||
// ZYAN_INLINE void* ZYAN_REALLOC(void* p, ZyanUSize n)
|
||||
// {
|
||||
// // We cant provide a fallback implementation for this function
|
||||
// ZYAN_UNUSED(p);
|
||||
// ZYAN_UNUSED(n);
|
||||
// return ZYAN_NULL;
|
||||
// }
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* string.h */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZYAN_INLINE void* ZYAN_MEMCHR(const void* str, int c, ZyanUSize n)
|
||||
{
|
||||
const ZyanU8* p = (ZyanU8*)str;
|
||||
while (n--)
|
||||
{
|
||||
if (*p != (ZyanU8)c)
|
||||
{
|
||||
p++;
|
||||
} else
|
||||
{
|
||||
return (void*)p;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZYAN_INLINE int ZYAN_MEMCMP(const void* s1, const void* s2, ZyanUSize n)
|
||||
{
|
||||
const ZyanU8* p1 = s1, *p2 = s2;
|
||||
while (n--)
|
||||
{
|
||||
if (*p1 != *p2)
|
||||
{
|
||||
return *p1 - *p2;
|
||||
}
|
||||
p1++, p2++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZYAN_INLINE void* ZYAN_MEMCPY(void* dst, const void* src, ZyanUSize n)
|
||||
{
|
||||
volatile ZyanU8* dp = dst;
|
||||
const ZyanU8* sp = src;
|
||||
while (n--)
|
||||
{
|
||||
*dp++ = *sp++;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
ZYAN_INLINE void* ZYAN_MEMMOVE(void* dst, const void* src, ZyanUSize n)
|
||||
{
|
||||
volatile ZyanU8* pd = dst;
|
||||
const ZyanU8* ps = src;
|
||||
if (ps < pd)
|
||||
{
|
||||
for (pd += n, ps += n; n--;)
|
||||
{
|
||||
*--pd = *--ps;
|
||||
}
|
||||
} else
|
||||
{
|
||||
while (n--)
|
||||
{
|
||||
*pd++ = *ps++;
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
ZYAN_INLINE void* ZYAN_MEMSET(void* dst, int val, ZyanUSize n)
|
||||
{
|
||||
volatile ZyanU8* p = dst;
|
||||
while (n--)
|
||||
{
|
||||
*p++ = (unsigned char)val;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
ZYAN_INLINE char* ZYAN_STRCAT(char* dest, const char* src)
|
||||
{
|
||||
char* ret = dest;
|
||||
while (*dest)
|
||||
{
|
||||
dest++;
|
||||
}
|
||||
while ((*dest++ = *src++));
|
||||
return ret;
|
||||
}
|
||||
|
||||
ZYAN_INLINE char* ZYAN_STRCHR(const char* s, int c)
|
||||
{
|
||||
while (*s != (char)c)
|
||||
{
|
||||
if (!*s++)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return (char*)s;
|
||||
}
|
||||
|
||||
ZYAN_INLINE int ZYAN_STRCMP(const char* s1, const char* s2)
|
||||
{
|
||||
while (*s1 && (*s1 == *s2))
|
||||
{
|
||||
s1++, s2++;
|
||||
}
|
||||
return *(const ZyanU8*)s1 - *(const ZyanU8*)s2;
|
||||
}
|
||||
|
||||
ZYAN_INLINE int ZYAN_STRCOLL(const char *s1, const char *s2)
|
||||
{
|
||||
// TODO: Implement
|
||||
|
||||
ZYAN_UNUSED(s1);
|
||||
ZYAN_UNUSED(s2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZYAN_INLINE char* ZYAN_STRCPY(char* dest, const char* src)
|
||||
{
|
||||
char* ret = dest;
|
||||
while ((*dest++ = *src++));
|
||||
return ret;
|
||||
}
|
||||
|
||||
ZYAN_INLINE ZyanUSize ZYAN_STRCSPN(const char *s1, const char *s2)
|
||||
{
|
||||
ZyanUSize ret = 0;
|
||||
while (*s1)
|
||||
{
|
||||
if (ZYAN_STRCHR(s2, *s1))
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
s1++, ret++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ZYAN_INLINE ZyanUSize ZYAN_STRLEN(const char* str)
|
||||
{
|
||||
const char* p = str;
|
||||
while (*str)
|
||||
{
|
||||
++str;
|
||||
}
|
||||
return str - p;
|
||||
}
|
||||
|
||||
ZYAN_INLINE char* ZYAN_STRNCAT(char* dest, const char* src, ZyanUSize n)
|
||||
{
|
||||
char* ret = dest;
|
||||
while (*dest)
|
||||
{
|
||||
dest++;
|
||||
}
|
||||
while (n--)
|
||||
{
|
||||
if (!(*dest++ = *src++))
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
*dest = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ZYAN_INLINE int ZYAN_STRNCMP(const char* s1, const char* s2, ZyanUSize n)
|
||||
{
|
||||
while (n--)
|
||||
{
|
||||
if (*s1++ != *s2++)
|
||||
{
|
||||
return *(unsigned char*)(s1 - 1) - *(unsigned char*)(s2 - 1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZYAN_INLINE char* ZYAN_STRNCPY(char* dest, const char* src, ZyanUSize n)
|
||||
{
|
||||
char* ret = dest;
|
||||
do
|
||||
{
|
||||
if (!n--)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
} while ((*dest++ = *src++));
|
||||
while (n--)
|
||||
{
|
||||
*dest++ = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ZYAN_INLINE char* ZYAN_STRPBRK(const char* s1, const char* s2)
|
||||
{
|
||||
while (*s1)
|
||||
{
|
||||
if(ZYAN_STRCHR(s2, *s1++))
|
||||
{
|
||||
return (char*)--s1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZYAN_INLINE char* ZYAN_STRRCHR(const char* s, int c)
|
||||
{
|
||||
char* ret = 0;
|
||||
do
|
||||
{
|
||||
if (*s == (char)c)
|
||||
{
|
||||
ret = (char*)s;
|
||||
}
|
||||
} while (*s++);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ZYAN_INLINE ZyanUSize ZYAN_STRSPN(const char* s1, const char* s2)
|
||||
{
|
||||
ZyanUSize ret = 0;
|
||||
while (*s1 && ZYAN_STRCHR(s2, *s1++))
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ZYAN_INLINE char* ZYAN_STRSTR(const char* s1, const char* s2)
|
||||
{
|
||||
const ZyanUSize n = ZYAN_STRLEN(s2);
|
||||
while (*s1)
|
||||
{
|
||||
if (!ZYAN_MEMCMP(s1++, s2, n))
|
||||
{
|
||||
return (char*)(s1 - 1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZYAN_INLINE char* ZYAN_STRTOK(char* str, const char* delim)
|
||||
{
|
||||
static char* p = 0;
|
||||
if (str)
|
||||
{
|
||||
p = str;
|
||||
} else
|
||||
if (!p)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
str = p + ZYAN_STRSPN(p, delim);
|
||||
p = str + ZYAN_STRCSPN(str, delim);
|
||||
if (p == str)
|
||||
{
|
||||
return p = 0;
|
||||
}
|
||||
p = *p ? *p = 0, p + 1 : 0;
|
||||
return str;
|
||||
}
|
||||
|
||||
ZYAN_INLINE ZyanUSize ZYAN_STRXFRM(char* dest, const char* src, ZyanUSize n)
|
||||
{
|
||||
const ZyanUSize n2 = ZYAN_STRLEN(src);
|
||||
if (n > n2)
|
||||
{
|
||||
ZYAN_STRCPY(dest, src);
|
||||
}
|
||||
return n2;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#endif /* ZYCORE_LIBC_H */
|
||||
@@ -0,0 +1,573 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zycore-C)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Implements a doubly linked list.
|
||||
*/
|
||||
|
||||
#ifndef ZYCORE_LIST_H
|
||||
#define ZYCORE_LIST_H
|
||||
|
||||
#include <Zycore/Allocator.h>
|
||||
#include <Zycore/Object.h>
|
||||
#include <Zycore/Status.h>
|
||||
#include <Zycore/Types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Enums and types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* Defines the `ZyanListNode` struct.
|
||||
*
|
||||
* All fields in this struct should be considered as "private". Any changes may lead to unexpected
|
||||
* behavior.
|
||||
*/
|
||||
typedef struct ZyanListNode_
|
||||
{
|
||||
/**
|
||||
* A pointer to the previous list node.
|
||||
*/
|
||||
struct ZyanListNode_* prev;
|
||||
/**
|
||||
* A pointer to the next list node.
|
||||
*/
|
||||
struct ZyanListNode_* next;
|
||||
} ZyanListNode;
|
||||
|
||||
/**
|
||||
* Defines the `ZyanList` struct.
|
||||
*
|
||||
* All fields in this struct should be considered as "private". Any changes may lead to unexpected
|
||||
* behavior.
|
||||
*/
|
||||
typedef struct ZyanList_
|
||||
{
|
||||
/**
|
||||
* The memory allocator.
|
||||
*/
|
||||
ZyanAllocator* allocator;
|
||||
/**
|
||||
* The current number of elements in the list.
|
||||
*/
|
||||
ZyanUSize size;
|
||||
/**
|
||||
* The size of a single element in bytes.
|
||||
*/
|
||||
ZyanUSize element_size;
|
||||
/**
|
||||
* The element destructor callback.
|
||||
*/
|
||||
ZyanMemberProcedure destructor;
|
||||
/**
|
||||
* The head node.
|
||||
*/
|
||||
ZyanListNode* head;
|
||||
/**
|
||||
* The tail node.
|
||||
*/
|
||||
ZyanListNode* tail;
|
||||
/**
|
||||
* The data buffer.
|
||||
*
|
||||
* Only used for instances created by `ZyanListInitCustomBuffer`.
|
||||
*/
|
||||
void* buffer;
|
||||
/**
|
||||
* The data buffer capacity (number of bytes).
|
||||
*
|
||||
* Only used for instances created by `ZyanListInitCustomBuffer`.
|
||||
*/
|
||||
ZyanUSize capacity;
|
||||
/**
|
||||
* The first unused node.
|
||||
*
|
||||
* When removing a node, the first-unused value is updated to point at the removed node and the
|
||||
* next node of the removed node will be updated to point at the old first-unused node.
|
||||
*
|
||||
* When appending the memory of the first unused-node is recycled to store the new node. The
|
||||
* value of the first-unused node is then updated to point at the reused nodes next node.
|
||||
*
|
||||
* If the first-unused value is `ZYAN_NULL`, any new node will be "allocated" behind the tail
|
||||
* node (if there is enough space left in the fixed size buffer).
|
||||
*
|
||||
* Only used for instances created by `ZyanListInitCustomBuffer`.
|
||||
*/
|
||||
ZyanListNode* first_unused;
|
||||
} ZyanList;
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Macros */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* General */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines an uninitialized `ZyanList` instance.
|
||||
*/
|
||||
#define ZYAN_LIST_INITIALIZER \
|
||||
{ \
|
||||
/* allocator */ ZYAN_NULL, \
|
||||
/* size */ 0, \
|
||||
/* element_size */ 0, \
|
||||
/* head */ ZYAN_NULL, \
|
||||
/* destructor */ ZYAN_NULL, \
|
||||
/* tail */ ZYAN_NULL, \
|
||||
/* buffer */ ZYAN_NULL, \
|
||||
/* capacity */ 0, \
|
||||
/* first_unused */ ZYAN_NULL \
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Helper macros */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Returns the data value of the given `node`.
|
||||
*
|
||||
* @param type The desired value type.
|
||||
* @param node A pointer to the `ZyanListNode` struct.
|
||||
*
|
||||
* @result The data value of the given `node`.
|
||||
*
|
||||
* Note that this function is unsafe and might dereference a null-pointer.
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
#define ZYAN_LIST_GET(type, node) \
|
||||
(*reinterpret_cast<const type*>(ZyanListGetNodeData(node)))
|
||||
#else
|
||||
#define ZYAN_LIST_GET(type, node) \
|
||||
(*(const type*)ZyanListGetNodeData(node))
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Constructor and destructor */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef ZYAN_NO_LIBC
|
||||
|
||||
/**
|
||||
* Initializes the given `ZyanList` instance.
|
||||
*
|
||||
* @param list A pointer to the `ZyanList` instance.
|
||||
* @param element_size The size of a single element in bytes.
|
||||
* @param destructor A destructor callback that is invoked every time an item is deleted, or
|
||||
* `ZYAN_NULL` if not needed.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* The memory for the list elements is dynamically allocated by the default allocator.
|
||||
*
|
||||
* Finalization with `ZyanListDestroy` is required for all instances created by this function.
|
||||
*/
|
||||
ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanListInit(ZyanList* list, ZyanUSize element_size,
|
||||
ZyanMemberProcedure destructor);
|
||||
|
||||
#endif // ZYAN_NO_LIBC
|
||||
|
||||
/**
|
||||
* Initializes the given `ZyanList` instance and sets a custom `allocator`.
|
||||
*
|
||||
* @param list A pointer to the `ZyanList` instance.
|
||||
* @param element_size The size of a single element in bytes.
|
||||
* @param destructor A destructor callback that is invoked every time an item is deleted, or
|
||||
* `ZYAN_NULL` if not needed.
|
||||
* @param allocator A pointer to a `ZyanAllocator` instance.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* Finalization with `ZyanListDestroy` is required for all instances created by this function.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanListInitEx(ZyanList* list, ZyanUSize element_size,
|
||||
ZyanMemberProcedure destructor, ZyanAllocator* allocator);
|
||||
|
||||
/**
|
||||
* Initializes the given `ZyanList` instance and configures it to use a custom user
|
||||
* defined buffer with a fixed size.
|
||||
*
|
||||
* @param list A pointer to the `ZyanList` instance.
|
||||
* @param element_size The size of a single element in bytes.
|
||||
* @param destructor A destructor callback that is invoked every time an item is deleted, or
|
||||
* `ZYAN_NULL` if not needed.
|
||||
* @param buffer A pointer to the buffer that is used as storage for the elements.
|
||||
* @param capacity The maximum capacity (number of bytes) of the buffer including the
|
||||
* space required for the list-nodes.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* The buffer capacity required to store `n` elements of type `T` is be calculated by:
|
||||
* `size = n * sizeof(ZyanListNode) + n * sizeof(T)`
|
||||
*
|
||||
* Finalization is not required for instances created by this function.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanListInitCustomBuffer(ZyanList* list, ZyanUSize element_size,
|
||||
ZyanMemberProcedure destructor, void* buffer, ZyanUSize capacity);
|
||||
|
||||
/**
|
||||
* Destroys the given `ZyanList` instance.
|
||||
*
|
||||
* @param list A pointer to the `ZyanList` instance.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanListDestroy(ZyanList* list);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Duplication */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef ZYAN_NO_LIBC
|
||||
|
||||
/**
|
||||
* Initializes a new `ZyanList` instance by duplicating an existing list.
|
||||
*
|
||||
* @param destination A pointer to the (uninitialized) destination `ZyanList` instance.
|
||||
* @param source A pointer to the source list.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* The memory for the list is dynamically allocated by the default allocator.
|
||||
*
|
||||
* Finalization with `ZyanListDestroy` is required for all instances created by this function.
|
||||
*/
|
||||
ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanListDuplicate(ZyanList* destination,
|
||||
const ZyanList* source);
|
||||
|
||||
#endif // ZYAN_NO_LIBC
|
||||
|
||||
/**
|
||||
* Initializes a new `ZyanList` instance by duplicating an existing list and sets a
|
||||
* custom `allocator`.
|
||||
*
|
||||
* @param destination A pointer to the (uninitialized) destination `ZyanList` instance.
|
||||
* @param source A pointer to the source list.
|
||||
* @param allocator A pointer to a `ZyanAllocator` instance.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
|
||||
* Finalization with `ZyanListDestroy` is required for all instances created by this function.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanListDuplicateEx(ZyanList* destination, const ZyanList* source,
|
||||
ZyanAllocator* allocator);
|
||||
|
||||
/**
|
||||
* Initializes a new `ZyanList` instance by duplicating an existing list and
|
||||
* configures it to use a custom user defined buffer with a fixed size.
|
||||
*
|
||||
* @param destination A pointer to the (uninitialized) destination `ZyanList` instance.
|
||||
* @param source A pointer to the source list.
|
||||
* @param buffer A pointer to the buffer that is used as storage for the elements.
|
||||
* @param capacity The maximum capacity (number of bytes) of the buffer including the
|
||||
* space required for the list-nodes.
|
||||
|
||||
* This function will fail, if the capacity of the buffer is not sufficient
|
||||
* to store all elements of the source list.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* The buffer capacity required to store `n` elements of type `T` is be calculated by:
|
||||
* `size = n * sizeof(ZyanListNode) + n * sizeof(T)`
|
||||
*
|
||||
* Finalization is not required for instances created by this function.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanListDuplicateCustomBuffer(ZyanList* destination,
|
||||
const ZyanList* source, void* buffer, ZyanUSize capacity);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Item access */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Returns a pointer to the first `ZyanListNode` struct of the given list.
|
||||
*
|
||||
* @param list A pointer to the `ZyanList` instance.
|
||||
* @param node Receives a pointer to the first `ZyanListNode` struct of the list.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanListGetHeadNode(const ZyanList* list, const ZyanListNode** node);
|
||||
|
||||
/**
|
||||
* Returns a pointer to the last `ZyanListNode` struct of the given list.
|
||||
*
|
||||
* @param list A pointer to the `ZyanList` instance.
|
||||
* @param node Receives a pointer to the last `ZyanListNode` struct of the list.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanListGetTailNode(const ZyanList* list, const ZyanListNode** node);
|
||||
|
||||
/**
|
||||
* Receives a pointer to the previous `ZyanListNode` struct linked to the passed one.
|
||||
*
|
||||
* @param node Receives a pointer to the previous `ZyanListNode` struct linked to the passed
|
||||
* one.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanListGetPrevNode(const ZyanListNode** node);
|
||||
|
||||
/**
|
||||
* Receives a pointer to the next `ZyanListNode` struct linked to the passed one.
|
||||
*
|
||||
* @param node Receives a pointer to the next `ZyanListNode` struct linked to the passed one.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanListGetNextNode(const ZyanListNode** node);
|
||||
|
||||
/**
|
||||
* Returns a constant pointer to the data of the given `node`.
|
||||
*
|
||||
* @param node A pointer to the `ZyanListNode` struct.
|
||||
*
|
||||
* @return A constant pointer to the the data of the given `node` or `ZYAN_NULL`, if an error
|
||||
* occured.
|
||||
*
|
||||
* Take a look at `ZyanListGetNodeDataEx`, if you need a function that returns a zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT const void* ZyanListGetNodeData(const ZyanListNode* node);
|
||||
|
||||
/**
|
||||
* Returns a constant pointer to the data of the given `node`..
|
||||
*
|
||||
* @param node A pointer to the `ZyanListNode` struct.
|
||||
* @param value Receives a constant pointer to the data of the given `node`.
|
||||
*
|
||||
* Take a look at `ZyanListGetNodeData`, if you need a function that directly returns a pointer.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanListGetNodeDataEx(const ZyanListNode* node, const void** value);
|
||||
|
||||
/**
|
||||
* Returns a mutable pointer to the data of the given `node`.
|
||||
*
|
||||
* @param node A pointer to the `ZyanListNode` struct.
|
||||
*
|
||||
* @return A mutable pointer to the the data of the given `node` or `ZYAN_NULL`, if an error
|
||||
* occured.
|
||||
*
|
||||
* Take a look at `ZyanListGetPointerMutableEx` instead, if you need a function that returns a
|
||||
* zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT void* ZyanListGetNodeDataMutable(const ZyanListNode* node);
|
||||
|
||||
/**
|
||||
* Returns a mutable pointer to the data of the given `node`..
|
||||
*
|
||||
* @param node A pointer to the `ZyanListNode` struct.
|
||||
* @param value Receives a mutable pointer to the data of the given `node`.
|
||||
*
|
||||
* Take a look at `ZyanListGetNodeDataMutable`, if you need a function that directly returns a
|
||||
* pointer.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanListGetNodeDataMutableEx(const ZyanListNode* node, void** value);
|
||||
|
||||
/**
|
||||
* Assigns a new data value to the given `node`.
|
||||
*
|
||||
* @param list A pointer to the `ZyanList` instance.
|
||||
* @param node A pointer to the `ZyanListNode` struct.
|
||||
* @param value The value to assign.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanListSetNodeData(const ZyanList* list, const ZyanListNode* node,
|
||||
const void* value);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Insertion */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Adds a new `item` to the end of the list.
|
||||
*
|
||||
* @param list A pointer to the `ZyanList` instance.
|
||||
* @param item A pointer to the item to add.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanListPushBack(ZyanList* list, const void* item);
|
||||
|
||||
/**
|
||||
* Adds a new `item` to the beginning of the list.
|
||||
*
|
||||
* @param list A pointer to the `ZyanList` instance.
|
||||
* @param item A pointer to the item to add.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanListPushFront(ZyanList* list, const void* item);
|
||||
|
||||
/**
|
||||
* Constructs an `item` in-place at the end of the list.
|
||||
*
|
||||
* @param list A pointer to the `ZyanList` instance.
|
||||
* @param item Receives a pointer to the new item.
|
||||
* @param constructor The constructor callback or `ZYAN_NULL`. The new item will be in
|
||||
* undefined state, if no constructor was passed.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanListEmplaceBack(ZyanList* list, void** item,
|
||||
ZyanMemberFunction constructor);
|
||||
|
||||
/**
|
||||
* Constructs an `item` in-place at the beginning of the list.
|
||||
*
|
||||
* @param list A pointer to the `ZyanList` instance.
|
||||
* @param item Receives a pointer to the new item.
|
||||
* @param constructor The constructor callback or `ZYAN_NULL`. The new item will be in
|
||||
* undefined state, if no constructor was passed.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanListEmplaceFront(ZyanList* list, void** item,
|
||||
ZyanMemberFunction constructor);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Deletion */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Removes the last element of the list.
|
||||
*
|
||||
* @param list A pointer to the `ZyanList` instance.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanListPopBack(ZyanList* list);
|
||||
|
||||
/**
|
||||
* Removes the firstelement of the list.
|
||||
*
|
||||
* @param list A pointer to the `ZyanList` instance.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanListPopFront(ZyanList* list);
|
||||
|
||||
/**
|
||||
* Removes the given `node` from the list.
|
||||
*
|
||||
* @param list A pointer to the `ZyanList` instance.
|
||||
* @param node A pointer to the `ZyanListNode` struct.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanListRemove(ZyanList* list, const ZyanListNode* node);
|
||||
|
||||
/**
|
||||
* Removes multiple nodes from the list.
|
||||
*
|
||||
* @param list A pointer to the `ZyanList` instance.
|
||||
* @param first A pointer to the first node.
|
||||
* @param last A pointer to the last node.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanListRemoveRange(ZyanList* list, const ZyanListNode* first,
|
||||
const ZyanListNode* last);
|
||||
|
||||
/**
|
||||
* Erases all elements of the list.
|
||||
*
|
||||
* @param list A pointer to the `ZyanList` instance.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanListClear(ZyanList* list);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Searching */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
// TODO:
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Memory management */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Resizes the given `ZyanList` instance.
|
||||
*
|
||||
* @param list A pointer to the `ZyanList` instance.
|
||||
* @param size The new size of the list.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanListResize(ZyanList* list, ZyanUSize size);
|
||||
|
||||
/**
|
||||
* Resizes the given `ZyanList` instance.
|
||||
*
|
||||
* @param list A pointer to the `ZyanList` instance.
|
||||
* @param size The new size of the list.
|
||||
* @param initializer A pointer to a value to be used as initializer for new items.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanListResizeEx(ZyanList* list, ZyanUSize size, const void* initializer);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Information */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Returns the current size of the list.
|
||||
*
|
||||
* @param list A pointer to the `ZyanList` instance.
|
||||
* @param size Receives the size of the list.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanListGetSize(const ZyanList* list, ZyanUSize* size);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZYCORE_VECTOR_H */
|
||||
@@ -0,0 +1,84 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zycore-C)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Defines some generic object-related datatypes.
|
||||
*/
|
||||
|
||||
#ifndef ZYCORE_OBJECT_H
|
||||
#define ZYCORE_OBJECT_H
|
||||
|
||||
#include <Zycore/Status.h>
|
||||
#include <Zycore/Types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Enums and types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* Defines the `ZyanMemberProcedure` function prototype.
|
||||
*
|
||||
* @param object A pointer to the object.
|
||||
*/
|
||||
typedef void (*ZyanMemberProcedure)(void* object);
|
||||
|
||||
/**
|
||||
* Defines the `ZyanConstMemberProcedure` function prototype.
|
||||
*
|
||||
* @param object A pointer to the object.
|
||||
*/
|
||||
typedef void (*ZyanConstMemberProcedure)(const void* object);
|
||||
|
||||
/**
|
||||
* Defines the `ZyanMemberFunction` function prototype.
|
||||
*
|
||||
* @param object A pointer to the object.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
typedef ZyanStatus (*ZyanMemberFunction)(void* object);
|
||||
|
||||
/**
|
||||
* Defines the `ZyanConstMemberFunction` function prototype.
|
||||
*
|
||||
* @param object A pointer to the object.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
typedef ZyanStatus (*ZyanConstMemberFunction)(const void* object);
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZYCORE_OBJECT_H */
|
||||
@@ -0,0 +1,287 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zyan-C)
|
||||
|
||||
Original Author : Florian Bernd, Joel Hoener
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Status code definitions and check macros.
|
||||
*/
|
||||
|
||||
#ifndef ZYCORE_STATUS_H
|
||||
#define ZYCORE_STATUS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <Zycore/Types.h>
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Enums and types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* Defines the `ZyanStatus` data type.
|
||||
*/
|
||||
typedef ZyanU32 ZyanStatus;
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Macros */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Definition */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines a zyan status code.
|
||||
*
|
||||
* @param error `1`, if the status code signals an error or `0`, if not.
|
||||
* @param module The module id.
|
||||
* @param code The actual code.
|
||||
*
|
||||
* @return The zyan status code.
|
||||
*/
|
||||
#define ZYAN_MAKE_STATUS(error, module, code) \
|
||||
(ZyanStatus)((((error) & 0x01u) << 31u) | (((module) & 0x7FFu) << 20u) | ((code) & 0xFFFFFu))
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Checks */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Checks if a zyan operation was successful.
|
||||
*
|
||||
* @param status The zyan status-code to check.
|
||||
*
|
||||
* @return `ZYAN_TRUE`, if the operation succeeded or `ZYAN_FALSE`, if not.
|
||||
*/
|
||||
#define ZYAN_SUCCESS(status) \
|
||||
(!((status) & 0x80000000u))
|
||||
|
||||
/**
|
||||
* Checks if a zyan operation failed.
|
||||
*
|
||||
* @param status The zyan status-code to check.
|
||||
*
|
||||
* @return `ZYAN_TRUE`, if the operation failed or `ZYAN_FALSE`, if not.
|
||||
*/
|
||||
#define ZYAN_FAILED(status) \
|
||||
((status) & 0x80000000u)
|
||||
|
||||
/**
|
||||
* Checks if a zyan operation was successful and returns with the status-code, if not.
|
||||
*
|
||||
* @param status The zyan status-code to check.
|
||||
*/
|
||||
#define ZYAN_CHECK(status) \
|
||||
do \
|
||||
{ \
|
||||
const ZyanStatus status_047620348 = (status); \
|
||||
if (!ZYAN_SUCCESS(status_047620348)) \
|
||||
{ \
|
||||
return status_047620348; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Information */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Returns the module id of a zyan status-code.
|
||||
*
|
||||
* @param status The zyan status-code.
|
||||
*
|
||||
* @return The module id of the zyan status-code.
|
||||
*/
|
||||
#define ZYAN_STATUS_MODULE(status) \
|
||||
(((status) >> 20) & 0x7FFu)
|
||||
|
||||
/**
|
||||
* Returns the code of a zyan status-code.
|
||||
*
|
||||
* @param status The zyan status-code.
|
||||
*
|
||||
* @return The code of the zyan status-code.
|
||||
*/
|
||||
#define ZYAN_STATUS_CODE(status) \
|
||||
((status) & 0xFFFFFu)
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Status codes */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Module IDs */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* The zycore generic module id.
|
||||
*/
|
||||
#define ZYAN_MODULE_ZYCORE 0x001u
|
||||
|
||||
/**
|
||||
* The zycore arg-parse submodule id.
|
||||
*/
|
||||
#define ZYAN_MODULE_ARGPARSE 0x003u
|
||||
|
||||
/**
|
||||
* The base module id for user-defined status codes.
|
||||
*/
|
||||
#define ZYAN_MODULE_USER 0x3FFu
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Status codes (general purpose) */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* The operation completed successfully.
|
||||
*/
|
||||
#define ZYAN_STATUS_SUCCESS \
|
||||
ZYAN_MAKE_STATUS(0u, ZYAN_MODULE_ZYCORE, 0x00u)
|
||||
|
||||
/**
|
||||
* The operation failed with an generic error.
|
||||
*/
|
||||
#define ZYAN_STATUS_FAILED \
|
||||
ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x01u)
|
||||
|
||||
/**
|
||||
* The operation completed successfully and returned `ZYAN_TRUE`.
|
||||
*/
|
||||
#define ZYAN_STATUS_TRUE \
|
||||
ZYAN_MAKE_STATUS(0u, ZYAN_MODULE_ZYCORE, 0x02u)
|
||||
|
||||
/**
|
||||
* The operation completed successfully and returned `ZYAN_FALSE`.
|
||||
*/
|
||||
#define ZYAN_STATUS_FALSE \
|
||||
ZYAN_MAKE_STATUS(0u, ZYAN_MODULE_ZYCORE, 0x03u)
|
||||
|
||||
/**
|
||||
* An invalid argument was passed to a function.
|
||||
*/
|
||||
#define ZYAN_STATUS_INVALID_ARGUMENT \
|
||||
ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x04u)
|
||||
|
||||
/**
|
||||
* An attempt was made to perform an invalid operation.
|
||||
*/
|
||||
#define ZYAN_STATUS_INVALID_OPERATION \
|
||||
ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x05u)
|
||||
|
||||
/**
|
||||
* Insufficient privileges to perform the requested operation.
|
||||
*/
|
||||
#define ZYAN_STATUS_ACCESS_DENIED \
|
||||
ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x06u)
|
||||
|
||||
/**
|
||||
* The requested entity was not found.
|
||||
*/
|
||||
#define ZYAN_STATUS_NOT_FOUND \
|
||||
ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x07u)
|
||||
|
||||
/**
|
||||
* An index passed to a function was out of bounds.
|
||||
*/
|
||||
#define ZYAN_STATUS_OUT_OF_RANGE \
|
||||
ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x08u)
|
||||
|
||||
/**
|
||||
* A buffer passed to a function was too small to complete the requested operation.
|
||||
*/
|
||||
#define ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE \
|
||||
ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x09u)
|
||||
|
||||
/**
|
||||
* Insufficient memory to perform the operation.
|
||||
*/
|
||||
#define ZYAN_STATUS_NOT_ENOUGH_MEMORY \
|
||||
ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x0Au)
|
||||
|
||||
/**
|
||||
* An unknown error occurred during a system function call.
|
||||
*/
|
||||
#define ZYAN_STATUS_BAD_SYSTEMCALL \
|
||||
ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x0Bu)
|
||||
|
||||
/**
|
||||
* The process ran out of resources while performing an operation.
|
||||
*/
|
||||
#define ZYAN_STATUS_OUT_OF_RESOURCES \
|
||||
ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x0Cu)
|
||||
|
||||
/**
|
||||
* A dependency library was not found or does have an unexpected version number or
|
||||
* feature-set.
|
||||
*/
|
||||
#define ZYAN_STATUS_MISSING_DEPENDENCY \
|
||||
ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ZYCORE, 0x0Du)
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Status codes (arg parse) */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Argument was not expected.
|
||||
*/
|
||||
#define ZYAN_STATUS_ARG_NOT_UNDERSTOOD \
|
||||
ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ARGPARSE, 0x00u)
|
||||
|
||||
/**
|
||||
* Too few arguments were provided.
|
||||
*/
|
||||
#define ZYAN_STATUS_TOO_FEW_ARGS \
|
||||
ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ARGPARSE, 0x01u)
|
||||
|
||||
/**
|
||||
* Too many arguments were provided.
|
||||
*/
|
||||
#define ZYAN_STATUS_TOO_MANY_ARGS \
|
||||
ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ARGPARSE, 0x02u)
|
||||
|
||||
/**
|
||||
* An argument that expected a value misses its value.
|
||||
*/
|
||||
#define ZYAN_STATUS_ARG_MISSES_VALUE \
|
||||
ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ARGPARSE, 0x03u)
|
||||
|
||||
/**
|
||||
* A required argument is missing.
|
||||
*/
|
||||
#define ZYAN_STATUS_REQUIRED_ARG_MISSING \
|
||||
ZYAN_MAKE_STATUS(1u, ZYAN_MODULE_ARGPARSE, 0x04u)
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZYCORE_STATUS_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,340 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zyan-C)
|
||||
|
||||
Original Author : Florian Bernd, Joel Hoener
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Includes and defines some default data types.
|
||||
*/
|
||||
|
||||
#ifndef ZYCORE_TYPES_H
|
||||
#define ZYCORE_TYPES_H
|
||||
|
||||
#include <Zycore/Defines.h>
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Integer types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
#if defined(ZYAN_NO_LIBC) || \
|
||||
(defined(ZYAN_MSVC) && defined(ZYAN_KERNEL)) // The WDK LibC lacks stdint.h.
|
||||
// No LibC mode, use compiler built-in types / macros.
|
||||
# if defined(ZYAN_MSVC) || defined(ZYAN_ICC)
|
||||
typedef unsigned __int8 ZyanU8;
|
||||
typedef unsigned __int16 ZyanU16;
|
||||
typedef unsigned __int32 ZyanU32;
|
||||
typedef unsigned __int64 ZyanU64;
|
||||
typedef signed __int8 ZyanI8;
|
||||
typedef signed __int16 ZyanI16;
|
||||
typedef signed __int32 ZyanI32;
|
||||
typedef signed __int64 ZyanI64;
|
||||
# if _WIN64
|
||||
typedef ZyanU64 ZyanUSize;
|
||||
typedef ZyanI64 ZyanISize;
|
||||
typedef ZyanU64 ZyanUPointer;
|
||||
typedef ZyanI64 ZyanIPointer;
|
||||
# else
|
||||
typedef ZyanU32 ZyanUSize;
|
||||
typedef ZyanI32 ZyanISize;
|
||||
typedef ZyanU32 ZyanUPointer;
|
||||
typedef ZyanI32 ZyanIPointer;
|
||||
# endif
|
||||
# elif defined(ZYAN_GNUC)
|
||||
# ifdef __UINT8_TYPE__
|
||||
typedef __UINT8_TYPE__ ZyanU8;
|
||||
# else
|
||||
typedef unsigned char ZyanU8;
|
||||
# endif
|
||||
# ifdef __UINT16_TYPE__
|
||||
typedef __UINT16_TYPE__ ZyanU16;
|
||||
# else
|
||||
typedef unsigned short int ZyanU16;
|
||||
# endif
|
||||
# ifdef __UINT32_TYPE__
|
||||
typedef __UINT32_TYPE__ ZyanU32;
|
||||
# else
|
||||
typedef unsigned int ZyanU32;
|
||||
# endif
|
||||
# ifdef __UINT64_TYPE__
|
||||
typedef __UINT64_TYPE__ ZyanU64;
|
||||
# else
|
||||
# if defined(__x86_64__) && !defined(__ILP32__)
|
||||
typedef unsigned long int ZyanU64;
|
||||
# else
|
||||
typedef unsigned long long int ZyanU64;
|
||||
# endif
|
||||
# endif
|
||||
# ifdef __INT8_TYPE__
|
||||
typedef __INT8_TYPE__ ZyanI8;
|
||||
# else
|
||||
typedef signed char ZyanI8;
|
||||
# endif
|
||||
# ifdef __INT16_TYPE__
|
||||
typedef __INT16_TYPE__ ZyanI16;
|
||||
# else
|
||||
typedef signed short int ZyanI16;
|
||||
# endif
|
||||
# ifdef __INT32_TYPE__
|
||||
typedef __INT32_TYPE__ ZyanI32;
|
||||
# else
|
||||
typedef signed int ZyanI32;
|
||||
# endif
|
||||
# ifdef __INT64_TYPE__
|
||||
typedef __INT64_TYPE__ ZyanI64;
|
||||
# else
|
||||
# if defined(__x86_64__) && !defined( __ILP32__)
|
||||
typedef signed long int ZyanI64;
|
||||
# else
|
||||
typedef signed long long int ZyanI64;
|
||||
# endif
|
||||
# endif
|
||||
# ifdef __SIZE_TYPE__
|
||||
typedef __SIZE_TYPE__ ZyanUSize;
|
||||
# else
|
||||
typedef long unsigned int ZyanUSize;
|
||||
# endif
|
||||
# ifdef __PTRDIFF_TYPE__
|
||||
typedef __PTRDIFF_TYPE__ ZyanISize;
|
||||
# else
|
||||
typedef long int ZyanISize;
|
||||
# endif
|
||||
# ifdef __UINTPTR_TYPE__
|
||||
typedef __UINTPTR_TYPE__ ZyanUPointer;
|
||||
# else
|
||||
# if defined(__x86_64__) && !defined( __ILP32__)
|
||||
typedef unsigned long int ZyanUPointer;
|
||||
# else
|
||||
typedef unsigned int ZyanUPointer;
|
||||
# endif
|
||||
# endif
|
||||
# ifdef __INTPTR_TYPE__
|
||||
typedef __INTPTR_TYPE__ ZyanIPointer;
|
||||
# else
|
||||
# if defined(__x86_64__) && !defined( __ILP32__)
|
||||
typedef long int ZyanIPointer;
|
||||
# else
|
||||
typedef int ZyanIPointer;
|
||||
# endif
|
||||
# endif
|
||||
# else
|
||||
# error "Unsupported compiler for no-libc mode."
|
||||
# endif
|
||||
|
||||
# if defined(ZYAN_MSVC)
|
||||
# define ZYAN_INT8_MIN (-127i8 - 1)
|
||||
# define ZYAN_INT16_MIN (-32767i16 - 1)
|
||||
# define ZYAN_INT32_MIN (-2147483647i32 - 1)
|
||||
# define ZYAN_INT64_MIN (-9223372036854775807i64 - 1)
|
||||
# define ZYAN_INT8_MAX 127i8
|
||||
# define ZYAN_INT16_MAX 32767i16
|
||||
# define ZYAN_INT32_MAX 2147483647i32
|
||||
# define ZYAN_INT64_MAX 9223372036854775807i64
|
||||
# define ZYAN_UINT8_MAX 0xffui8
|
||||
# define ZYAN_UINT16_MAX 0xffffui16
|
||||
# define ZYAN_UINT32_MAX 0xffffffffui32
|
||||
# define ZYAN_UINT64_MAX 0xffffffffffffffffui64
|
||||
# else
|
||||
# ifdef __INT8_MAX__
|
||||
# define ZYAN_INT8_MAX __INT8_MAX__
|
||||
# else
|
||||
# define ZYAN_INT8_MAX (127)
|
||||
# endif
|
||||
# define ZYAN_INT8_MIN (-ZYAN_INT8_MAX - 1)
|
||||
# ifdef __INT16_MAX__
|
||||
# define ZYAN_INT16_MAX __INT16_MAX__
|
||||
# else
|
||||
# define ZYAN_INT16_MAX (32767)
|
||||
# endif
|
||||
# define ZYAN_INT16_MIN (-ZYAN_INT16_MAX - 1)
|
||||
# ifdef __INT32_MAX__
|
||||
# define ZYAN_INT32_MAX __INT32_MAX__
|
||||
# else
|
||||
# define ZYAN_INT32_MAX (2147483647)
|
||||
# endif
|
||||
# define ZYAN_INT32_MIN (-ZYAN_INT32_MAX - 1)
|
||||
# ifdef __INT64_MAX__
|
||||
# define ZYAN_INT64_MAX __INT64_MAX__
|
||||
# else
|
||||
# if defined(__x86_64__) && !defined( __ILP32__)
|
||||
# define ZYAN_INT64_MAX (9223372036854775807L)
|
||||
# else
|
||||
# define ZYAN_INT64_MAX (9223372036854775807LL)
|
||||
# endif
|
||||
# endif
|
||||
# define ZYAN_INT64_MIN (-ZYAN_INT64_MAX - 1)
|
||||
# ifdef __UINT8_MAX__
|
||||
# define ZYAN_UINT8_MAX __UINT8_MAX__
|
||||
# else
|
||||
# define ZYAN_UINT8_MAX (255)
|
||||
# endif
|
||||
# ifdef __UINT16_MAX__
|
||||
# define ZYAN_UINT16_MAX __UINT16_MAX__
|
||||
# else
|
||||
# define ZYAN_UINT16_MAX (65535)
|
||||
# endif
|
||||
# ifdef __UINT32_MAX__
|
||||
# define ZYAN_UINT32_MAX __UINT32_MAX__
|
||||
# else
|
||||
# define ZYAN_UINT32_MAX (4294967295U)
|
||||
# endif
|
||||
# ifdef __UINT64_MAX__
|
||||
# define ZYAN_UINT64_MAX __UINT64_MAX__
|
||||
# else
|
||||
# if defined(__x86_64__) && !defined( __ILP32__)
|
||||
# define ZYAN_UINT64_MAX (18446744073709551615UL)
|
||||
# else
|
||||
# define ZYAN_UINT64_MAX (18446744073709551615ULL)
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
#else
|
||||
// If is LibC present, we use stdint types.
|
||||
# include <stdint.h>
|
||||
# include <stddef.h>
|
||||
typedef uint8_t ZyanU8;
|
||||
typedef uint16_t ZyanU16;
|
||||
typedef uint32_t ZyanU32;
|
||||
typedef uint64_t ZyanU64;
|
||||
typedef int8_t ZyanI8;
|
||||
typedef int16_t ZyanI16;
|
||||
typedef int32_t ZyanI32;
|
||||
typedef int64_t ZyanI64;
|
||||
typedef size_t ZyanUSize;
|
||||
typedef ptrdiff_t ZyanISize;
|
||||
typedef uintptr_t ZyanUPointer;
|
||||
typedef intptr_t ZyanIPointer;
|
||||
|
||||
# define ZYAN_INT8_MIN INT8_MIN
|
||||
# define ZYAN_INT16_MIN INT16_MIN
|
||||
# define ZYAN_INT32_MIN INT32_MIN
|
||||
# define ZYAN_INT64_MIN INT64_MIN
|
||||
# define ZYAN_INT8_MAX INT8_MAX
|
||||
# define ZYAN_INT16_MAX INT16_MAX
|
||||
# define ZYAN_INT32_MAX INT32_MAX
|
||||
# define ZYAN_INT64_MAX INT64_MAX
|
||||
# define ZYAN_UINT8_MAX UINT8_MAX
|
||||
# define ZYAN_UINT16_MAX UINT16_MAX
|
||||
# define ZYAN_UINT32_MAX UINT32_MAX
|
||||
# define ZYAN_UINT64_MAX UINT64_MAX
|
||||
#endif
|
||||
|
||||
// Verify size assumptions.
|
||||
ZYAN_STATIC_ASSERT(sizeof(ZyanU8 ) == 1 );
|
||||
ZYAN_STATIC_ASSERT(sizeof(ZyanU16 ) == 2 );
|
||||
ZYAN_STATIC_ASSERT(sizeof(ZyanU32 ) == 4 );
|
||||
ZYAN_STATIC_ASSERT(sizeof(ZyanU64 ) == 8 );
|
||||
ZYAN_STATIC_ASSERT(sizeof(ZyanI8 ) == 1 );
|
||||
ZYAN_STATIC_ASSERT(sizeof(ZyanI16 ) == 2 );
|
||||
ZYAN_STATIC_ASSERT(sizeof(ZyanI32 ) == 4 );
|
||||
ZYAN_STATIC_ASSERT(sizeof(ZyanI64 ) == 8 );
|
||||
ZYAN_STATIC_ASSERT(sizeof(ZyanUSize ) == sizeof(void*)); // TODO: This one is incorrect!
|
||||
ZYAN_STATIC_ASSERT(sizeof(ZyanISize ) == sizeof(void*)); // TODO: This one is incorrect!
|
||||
ZYAN_STATIC_ASSERT(sizeof(ZyanUPointer) == sizeof(void*));
|
||||
ZYAN_STATIC_ASSERT(sizeof(ZyanIPointer) == sizeof(void*));
|
||||
|
||||
// Verify signedness assumptions (relies on size checks above).
|
||||
ZYAN_STATIC_ASSERT((ZyanI8 )-1 >> 1 < (ZyanI8 )((ZyanU8 )-1 >> 1));
|
||||
ZYAN_STATIC_ASSERT((ZyanI16)-1 >> 1 < (ZyanI16)((ZyanU16)-1 >> 1));
|
||||
ZYAN_STATIC_ASSERT((ZyanI32)-1 >> 1 < (ZyanI32)((ZyanU32)-1 >> 1));
|
||||
ZYAN_STATIC_ASSERT((ZyanI64)-1 >> 1 < (ZyanI64)((ZyanU64)-1 >> 1));
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Pointer */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* Defines the `ZyanVoidPointer` data-type.
|
||||
*/
|
||||
typedef void* ZyanVoidPointer;
|
||||
|
||||
/**
|
||||
* Defines the `ZyanConstVoidPointer` data-type.
|
||||
*/
|
||||
typedef const void* ZyanConstVoidPointer;
|
||||
|
||||
#define ZYAN_NULL ((void*)0)
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Logic types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Boolean */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#define ZYAN_FALSE 0u
|
||||
#define ZYAN_TRUE 1u
|
||||
|
||||
/**
|
||||
* Defines the `ZyanBool` data-type.
|
||||
*
|
||||
* Represents a default boolean data-type where `0` is interpreted as `false` and all other values
|
||||
* as `true`.
|
||||
*/
|
||||
typedef ZyanU8 ZyanBool;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Ternary */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZyanTernary` data-type.
|
||||
*
|
||||
* The `ZyanTernary` is a balanced ternary type that uses three truth values indicating `true`,
|
||||
* `false` and an indeterminate third value.
|
||||
*/
|
||||
typedef ZyanI8 ZyanTernary;
|
||||
|
||||
#define ZYAN_TERNARY_FALSE (-1)
|
||||
#define ZYAN_TERNARY_UNKNOWN 0x00
|
||||
#define ZYAN_TERNARY_TRUE 0x01
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* String types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* C-style strings */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZyanCharPointer` data-type.
|
||||
*
|
||||
* This type is most often used to represent null-terminated strings aka. C-style strings.
|
||||
*/
|
||||
typedef char* ZyanCharPointer;
|
||||
|
||||
/**
|
||||
* Defines the `ZyanConstCharPointer` data-type.
|
||||
*
|
||||
* This type is most often used to represent null-terminated strings aka. C-style strings.
|
||||
*/
|
||||
typedef const char* ZyanConstCharPointer;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#endif /* ZYCORE_TYPES_H */
|
||||
@@ -0,0 +1,722 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zycore-C)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Implements the vector container class.
|
||||
*/
|
||||
|
||||
#ifndef ZYCORE_VECTOR_H
|
||||
#define ZYCORE_VECTOR_H
|
||||
|
||||
#include <Zycore/Allocator.h>
|
||||
#include <Zycore/Comparison.h>
|
||||
#include <Zycore/Object.h>
|
||||
#include <Zycore/Status.h>
|
||||
#include <Zycore/Types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Constants */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* The initial minimum capacity (number of elements) for all dynamically allocated vector
|
||||
* instances.
|
||||
*/
|
||||
#define ZYAN_VECTOR_MIN_CAPACITY 1
|
||||
|
||||
/**
|
||||
* The default growth factor for all vector instances.
|
||||
*/
|
||||
#define ZYAN_VECTOR_DEFAULT_GROWTH_FACTOR 2
|
||||
|
||||
/**
|
||||
* The default shrink threshold for all vector instances.
|
||||
*/
|
||||
#define ZYAN_VECTOR_DEFAULT_SHRINK_THRESHOLD 4
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Enums and types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* Defines the `ZyanVector` struct.
|
||||
*
|
||||
* All fields in this struct should be considered as "private". Any changes may lead to unexpected
|
||||
* behavior.
|
||||
*/
|
||||
typedef struct ZyanVector_
|
||||
{
|
||||
/**
|
||||
* The memory allocator.
|
||||
*/
|
||||
ZyanAllocator* allocator;
|
||||
/**
|
||||
* The growth factor.
|
||||
*/
|
||||
ZyanU8 growth_factor;
|
||||
/**
|
||||
* The shrink threshold.
|
||||
*/
|
||||
ZyanU8 shrink_threshold;
|
||||
/**
|
||||
* The current number of elements in the vector.
|
||||
*/
|
||||
ZyanUSize size;
|
||||
/**
|
||||
* The maximum capacity (number of elements).
|
||||
*/
|
||||
ZyanUSize capacity;
|
||||
/**
|
||||
* The size of a single element in bytes.
|
||||
*/
|
||||
ZyanUSize element_size;
|
||||
/**
|
||||
* The element destructor callback.
|
||||
*/
|
||||
ZyanMemberProcedure destructor;
|
||||
/**
|
||||
* The data pointer.
|
||||
*/
|
||||
void* data;
|
||||
} ZyanVector;
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Macros */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* General */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines an uninitialized `ZyanVector` instance.
|
||||
*/
|
||||
#define ZYAN_VECTOR_INITIALIZER \
|
||||
{ \
|
||||
/* allocator */ ZYAN_NULL, \
|
||||
/* growth_factor */ 0, \
|
||||
/* shrink_threshold */ 0, \
|
||||
/* size */ 0, \
|
||||
/* capacity */ 0, \
|
||||
/* element_size */ 0, \
|
||||
/* destructor */ ZYAN_NULL, \
|
||||
/* data */ ZYAN_NULL \
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Helper macros */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Returns the value of the element at the given `index`.
|
||||
*
|
||||
* @param type The desired value type.
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param index The element index.
|
||||
*
|
||||
* @result The value of the desired element in the vector.
|
||||
*
|
||||
* Note that this function is unsafe and might dereference a null-pointer.
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
#define ZYAN_VECTOR_GET(type, vector, index) \
|
||||
(*reinterpret_cast<const type*>(ZyanVectorGet(vector, index)))
|
||||
#else
|
||||
#define ZYAN_VECTOR_GET(type, vector, index) \
|
||||
(*(const type*)ZyanVectorGet(vector, index))
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Loops through all elements of the vector.
|
||||
*
|
||||
* @param type The desired value type.
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param item_name The name of the iterator item.
|
||||
* @param body The body to execute for each item in the vector.
|
||||
*/
|
||||
#define ZYAN_VECTOR_FOREACH(type, vector, item_name, body) \
|
||||
{ \
|
||||
const ZyanUSize ZYAN_MACRO_CONCAT_EXPAND(size_d50d3303, item_name) = (vector)->size; \
|
||||
for (ZyanUSize ZYAN_MACRO_CONCAT_EXPAND(i_bfd62679, item_name) = 0; \
|
||||
ZYAN_MACRO_CONCAT_EXPAND(i_bfd62679, item_name) < \
|
||||
ZYAN_MACRO_CONCAT_EXPAND(size_d50d3303, item_name); \
|
||||
++ZYAN_MACRO_CONCAT_EXPAND(i_bfd62679, item_name)) \
|
||||
{ \
|
||||
const type item_name = ZYAN_VECTOR_GET(type, vector, \
|
||||
ZYAN_MACRO_CONCAT_EXPAND(i_bfd62679, item_name)); \
|
||||
body \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
* Loops through all elements of the vector.
|
||||
*
|
||||
* @param type The desired value type.
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param item_name The name of the iterator item.
|
||||
* @param body The body to execute for each item in the vector.
|
||||
*/
|
||||
#define ZYAN_VECTOR_FOREACH_MUTABLE(type, vector, item_name, body) \
|
||||
{ \
|
||||
const ZyanUSize ZYAN_MACRO_CONCAT_EXPAND(size_d50d3303, item_name) = (vector)->size; \
|
||||
for (ZyanUSize ZYAN_MACRO_CONCAT_EXPAND(i_bfd62679, item_name) = 0; \
|
||||
ZYAN_MACRO_CONCAT_EXPAND(i_bfd62679, item_name) < \
|
||||
ZYAN_MACRO_CONCAT_EXPAND(size_d50d3303, item_name); \
|
||||
++ZYAN_MACRO_CONCAT_EXPAND(i_bfd62679, item_name)) \
|
||||
{ \
|
||||
type* const item_name = ZyanVectorGetMutable(vector, \
|
||||
ZYAN_MACRO_CONCAT_EXPAND(i_bfd62679, item_name)); \
|
||||
body \
|
||||
} \
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Constructor and destructor */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef ZYAN_NO_LIBC
|
||||
|
||||
/**
|
||||
* Initializes the given `ZyanVector` instance.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param element_size The size of a single element in bytes.
|
||||
* @param capacity The initial capacity (number of elements).
|
||||
* @param destructor A destructor callback that is invoked every time an item is deleted, or
|
||||
* `ZYAN_NULL` if not needed.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* The memory for the vector elements is dynamically allocated by the default allocator using the
|
||||
* default growth factor and the default shrink threshold.
|
||||
*
|
||||
* Finalization with `ZyanVectorDestroy` is required for all instances created by this function.
|
||||
*/
|
||||
ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanVectorInit(ZyanVector* vector,
|
||||
ZyanUSize element_size, ZyanUSize capacity, ZyanMemberProcedure destructor);
|
||||
|
||||
#endif // ZYAN_NO_LIBC
|
||||
|
||||
/**
|
||||
* Initializes the given `ZyanVector` instance and sets a custom `allocator` and memory
|
||||
* allocation/deallocation parameters.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param element_size The size of a single element in bytes.
|
||||
* @param capacity The initial capacity (number of elements).
|
||||
* @param destructor A destructor callback that is invoked every time an item is deleted,
|
||||
* or `ZYAN_NULL` if not needed.
|
||||
* @param allocator A pointer to a `ZyanAllocator` instance.
|
||||
* @param growth_factor The growth factor.
|
||||
* @param shrink_threshold The shrink threshold.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* A growth factor of `1` disables overallocation and a shrink threshold of `0` disables
|
||||
* dynamic shrinking.
|
||||
*
|
||||
* Finalization with `ZyanVectorDestroy` is required for all instances created by this function.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanVectorInitEx(ZyanVector* vector, ZyanUSize element_size,
|
||||
ZyanUSize capacity, ZyanMemberProcedure destructor, ZyanAllocator* allocator,
|
||||
ZyanU8 growth_factor, ZyanU8 shrink_threshold);
|
||||
|
||||
/**
|
||||
* Initializes the given `ZyanVector` instance and configures it to use a custom user
|
||||
* defined buffer with a fixed size.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param element_size The size of a single element in bytes.
|
||||
* @param buffer A pointer to the buffer that is used as storage for the elements.
|
||||
* @param capacity The maximum capacity (number of elements) of the buffer.
|
||||
* @param destructor A destructor callback that is invoked every time an item is deleted, or
|
||||
* `ZYAN_NULL` if not needed.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* Finalization is not required for instances created by this function.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanVectorInitCustomBuffer(ZyanVector* vector, ZyanUSize element_size,
|
||||
void* buffer, ZyanUSize capacity, ZyanMemberProcedure destructor);
|
||||
|
||||
/**
|
||||
* Destroys the given `ZyanVector` instance.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance..
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanVectorDestroy(ZyanVector* vector);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Duplication */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef ZYAN_NO_LIBC
|
||||
|
||||
/**
|
||||
* Initializes a new `ZyanVector` instance by duplicating an existing vector.
|
||||
*
|
||||
* @param destination A pointer to the (uninitialized) destination `ZyanVector` instance.
|
||||
* @param source A pointer to the source vector.
|
||||
* @param capacity The initial capacity (number of elements).
|
||||
*
|
||||
* This value is automatically adjusted to the size of the source vector, if
|
||||
* a smaller value was passed.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* The memory for the vector is dynamically allocated by the default allocator using the default
|
||||
* growth factor and the default shrink threshold.
|
||||
*
|
||||
* Finalization with `ZyanVectorDestroy` is required for all instances created by this function.
|
||||
*/
|
||||
ZYCORE_EXPORT ZYAN_REQUIRES_LIBC ZyanStatus ZyanVectorDuplicate(ZyanVector* destination,
|
||||
const ZyanVector* source, ZyanUSize capacity);
|
||||
|
||||
#endif // ZYAN_NO_LIBC
|
||||
|
||||
/**
|
||||
* Initializes a new `ZyanVector` instance by duplicating an existing vector and sets a
|
||||
* custom `allocator` and memory allocation/deallocation parameters.
|
||||
*
|
||||
* @param destination A pointer to the (uninitialized) destination `ZyanVector` instance.
|
||||
* @param source A pointer to the source vector.
|
||||
* @param capacity The initial capacity (number of elements).
|
||||
|
||||
* This value is automatically adjusted to the size of the source
|
||||
* vector, if a smaller value was passed.
|
||||
* @param allocator A pointer to a `ZyanAllocator` instance.
|
||||
* @param growth_factor The growth factor.
|
||||
* @param shrink_threshold The shrink threshold.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* A growth factor of `1` disables overallocation and a shrink threshold of `0` disables
|
||||
* dynamic shrinking.
|
||||
*
|
||||
* Finalization with `ZyanVectorDestroy` is required for all instances created by this function.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanVectorDuplicateEx(ZyanVector* destination, const ZyanVector* source,
|
||||
ZyanUSize capacity, ZyanAllocator* allocator, ZyanU8 growth_factor, ZyanU8 shrink_threshold);
|
||||
|
||||
/**
|
||||
* Initializes a new `ZyanVector` instance by duplicating an existing vector and
|
||||
* configures it to use a custom user defined buffer with a fixed size.
|
||||
*
|
||||
* @param destination A pointer to the (uninitialized) destination `ZyanVector` instance.
|
||||
* @param source A pointer to the source vector.
|
||||
* @param buffer A pointer to the buffer that is used as storage for the elements.
|
||||
* @param capacity The maximum capacity (number of elements) of the buffer.
|
||||
|
||||
* This function will fail, if the capacity of the buffer is less than the
|
||||
* size of the source vector.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* Finalization is not required for instances created by this function.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanVectorDuplicateCustomBuffer(ZyanVector* destination,
|
||||
const ZyanVector* source, void* buffer, ZyanUSize capacity);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Element access */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Returns a constant pointer to the element at the given `index`.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param index The element index.
|
||||
*
|
||||
* @return A constant pointer to the desired element in the vector or `ZYAN_NULL`, if an error
|
||||
* occurred.
|
||||
*
|
||||
* Note that the returned pointer might get invalid when the vector is resized by either a manual
|
||||
* call to the memory-management functions or implicitly by inserting or removing elements.
|
||||
*
|
||||
* Take a look at `ZyanVectorGetPointer` instead, if you need a function that returns a zyan status
|
||||
* code.
|
||||
*/
|
||||
ZYCORE_EXPORT const void* ZyanVectorGet(const ZyanVector* vector, ZyanUSize index);
|
||||
|
||||
/**
|
||||
* Returns a mutable pointer to the element at the given `index`.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param index The element index.
|
||||
*
|
||||
* @return A mutable pointer to the desired element in the vector or `ZYAN_NULL`, if an error
|
||||
* occurred.
|
||||
*
|
||||
* Note that the returned pointer might get invalid when the vector is resized by either a manual
|
||||
* call to the memory-management functions or implicitly by inserting or removing elements.
|
||||
*
|
||||
* Take a look at `ZyanVectorGetPointerMutable` instead, if you need a function that returns a
|
||||
* zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT void* ZyanVectorGetMutable(const ZyanVector* vector, ZyanUSize index);
|
||||
|
||||
/**
|
||||
* Returns a constant pointer to the element at the given `index`.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param index The element index.
|
||||
* @param value Receives a constant pointer to the desired element in the vector.
|
||||
*
|
||||
* Note that the returned pointer might get invalid when the vector is resized by either a manual
|
||||
* call to the memory-management functions or implicitly by inserting or removing elements.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanVectorGetPointer(const ZyanVector* vector, ZyanUSize index,
|
||||
const void** value);
|
||||
|
||||
/**
|
||||
* Returns a mutable pointer to the element at the given `index`.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param index The element index.
|
||||
* @param value Receives a mutable pointer to the desired element in the vector.
|
||||
*
|
||||
* Note that the returned pointer might get invalid when the vector is resized by either a manual
|
||||
* call to the memory-management functions or implicitly by inserting or removing elements.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanVectorGetPointerMutable(const ZyanVector* vector, ZyanUSize index,
|
||||
void** value);
|
||||
|
||||
/**
|
||||
* Assigns a new value to the element at the given `index`.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param index The value index.
|
||||
* @param value The value to assign.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanVectorSet(ZyanVector* vector, ZyanUSize index,
|
||||
const void* value);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Insertion */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Adds a new `element` to the end of the vector.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param element A pointer to the element to add.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanVectorPushBack(ZyanVector* vector, const void* element);
|
||||
|
||||
/**
|
||||
* Inserts an `element` at the given `index` of the vector.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param index The insert index.
|
||||
* @param element A pointer to the element to insert.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanVectorInsert(ZyanVector* vector, ZyanUSize index,
|
||||
const void* element);
|
||||
|
||||
/**
|
||||
* Inserts multiple `elements` at the given `index` of the vector.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param index The insert index.
|
||||
* @param elements A pointer to the first element.
|
||||
* @param count The number of elements to insert.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanVectorInsertRange(ZyanVector* vector, ZyanUSize index,
|
||||
const void* elements, ZyanUSize count);
|
||||
|
||||
/**
|
||||
* Constructs an `element` in-place at the end of the vector.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param element Receives a pointer to the new element.
|
||||
* @param constructor The constructor callback or `ZYAN_NULL`. The new element will be in
|
||||
* undefined state, if no constructor was passed.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanVectorEmplace(ZyanVector* vector, void** element,
|
||||
ZyanMemberFunction constructor);
|
||||
|
||||
/**
|
||||
* Constructs an `element` in-place and inserts it at the given `index` of the vector.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param index The insert index.
|
||||
* @param element Receives a pointer to the new element.
|
||||
* @param constructor The constructor callback or `ZYAN_NULL`. The new element will be in
|
||||
* undefined state, if no constructor was passed.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanVectorEmplaceEx(ZyanVector* vector, ZyanUSize index,
|
||||
void** element, ZyanMemberFunction constructor);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Utils */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Swaps the element at `index_first` with the element at `index_second`.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param index_first The index of the first element.
|
||||
* @param index_second The index of the second element.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* This function requires the vector to have spare capacity for one temporary element. Call
|
||||
* `ZyanVectorReserve` before this function to increase capacity, if needed.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanVectorSwapElements(ZyanVector* vector, ZyanUSize index_first,
|
||||
ZyanUSize index_second);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Deletion */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Deletes the element at the given `index` of the vector.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param index The element index.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanVectorDelete(ZyanVector* vector, ZyanUSize index);
|
||||
|
||||
/**
|
||||
* Deletes multiple elements from the given vector, starting at `index`.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param index The index of the first element to delete.
|
||||
* @param count The number of elements to delete.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanVectorDeleteRange(ZyanVector* vector, ZyanUSize index,
|
||||
ZyanUSize count);
|
||||
|
||||
/**
|
||||
* Removes the last element of the vector.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanVectorPopBack(ZyanVector* vector);
|
||||
|
||||
/**
|
||||
* Erases all elements of the given vector.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanVectorClear(ZyanVector* vector);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Searching */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Sequentially searches for the first occurrence of `element` in the given vector.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param element A pointer to the element to search for.
|
||||
* @param found_index A pointer to a variable that receives the index of the found element.
|
||||
* @param comparison The comparison function to use.
|
||||
*
|
||||
* @return `ZYAN_STATUS_TRUE` if the element was found, `ZYAN_STATUS_FALSE` if not or a generic
|
||||
* zyan status code if an error occurred.
|
||||
*
|
||||
* The `found_index` is set to `-1`, if the element was not found.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanVectorFind(const ZyanVector* vector, const void* element,
|
||||
ZyanISize* found_index, ZyanEqualityComparison comparison);
|
||||
|
||||
/**
|
||||
* Sequentially searches for the first occurrence of `element` in the given vector.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param element A pointer to the element to search for.
|
||||
* @param found_index A pointer to a variable that receives the index of the found element.
|
||||
* @param comparison The comparison function to use.
|
||||
* @param index The start index.
|
||||
* @param count The maximum number of elements to iterate, beginning from the start `index`.
|
||||
*
|
||||
* @return `ZYAN_STATUS_TRUE` if the element was found, `ZYAN_STATUS_FALSE` if not or a generic
|
||||
* zyan status code if an error occurred.
|
||||
*
|
||||
* The `found_index` is set to `-1`, if the element was not found.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanVectorFindEx(const ZyanVector* vector, const void* element,
|
||||
ZyanISize* found_index, ZyanEqualityComparison comparison, ZyanUSize index, ZyanUSize count);
|
||||
|
||||
/**
|
||||
* Searches for the first occurrence of `element` in the given vector using a binary-
|
||||
* search algorithm.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param element A pointer to the element to search for.
|
||||
* @param found_index A pointer to a variable that receives the index of the found element.
|
||||
* @param comparison The comparison function to use.
|
||||
*
|
||||
* @return `ZYAN_STATUS_TRUE` if the element was found, `ZYAN_STATUS_FALSE` if not or a generic
|
||||
* zyan status code if an error occurred.
|
||||
*
|
||||
* If found, `found_index` contains the zero-based index of `element`. If not found, `found_index`
|
||||
* contains the index of the first entry larger than `element`.
|
||||
*
|
||||
* This function requires all elements in the vector to be strictly ordered (sorted).
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanVectorBinarySearch(const ZyanVector* vector, const void* element,
|
||||
ZyanUSize* found_index, ZyanComparison comparison);
|
||||
|
||||
/**
|
||||
* Searches for the first occurrence of `element` in the given vector using a binary-
|
||||
* search algorithm.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param element A pointer to the element to search for.
|
||||
* @param found_index A pointer to a variable that receives the index of the found element.
|
||||
* @param comparison The comparison function to use.
|
||||
* @param index The start index.
|
||||
* @param count The maximum number of elements to iterate, beginning from the start `index`.
|
||||
*
|
||||
* @return `ZYAN_STATUS_TRUE` if the element was found, `ZYAN_STATUS_FALSE` if not or a generic
|
||||
* zyan status code if an error occurred.
|
||||
*
|
||||
* If found, `found_index` contains the zero-based index of `element`. If not found, `found_index`
|
||||
* contains the index of the first entry larger than `element`.
|
||||
*
|
||||
* This function requires all elements in the vector to be strictly ordered (sorted).
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanVectorBinarySearchEx(const ZyanVector* vector, const void* element,
|
||||
ZyanUSize* found_index, ZyanComparison comparison, ZyanUSize index, ZyanUSize count);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Memory management */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Resizes the given `ZyanVector` instance.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param size The new size of the vector.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanVectorResize(ZyanVector* vector, ZyanUSize size);
|
||||
|
||||
/**
|
||||
* Resizes the given `ZyanVector` instance.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param size The new size of the vector.
|
||||
* @param initializer A pointer to a value to be used as initializer for new items.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanVectorResizeEx(ZyanVector* vector, ZyanUSize size,
|
||||
const void* initializer);
|
||||
|
||||
/**
|
||||
* Changes the capacity of the given `ZyanVector` instance.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param capacity The new minimum capacity of the vector.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanVectorReserve(ZyanVector* vector, ZyanUSize capacity);
|
||||
|
||||
/**
|
||||
* Shrinks the capacity of the given vector to match it's size.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanVectorShrinkToFit(ZyanVector* vector);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Information */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Returns the current capacity of the vector.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param capacity Receives the size of the vector.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanVectorGetCapacity(const ZyanVector* vector, ZyanUSize* capacity);
|
||||
|
||||
/**
|
||||
* Returns the current size of the vector.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param size Receives the size of the vector.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanStatus ZyanVectorGetSize(const ZyanVector* vector, ZyanUSize* size);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZYCORE_VECTOR_H */
|
||||
@@ -0,0 +1,110 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zycore-C)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Master include file, including everything else.
|
||||
*/
|
||||
|
||||
#ifndef ZYCORE_H
|
||||
#define ZYCORE_H
|
||||
|
||||
#include <Zycore/Types.h>
|
||||
|
||||
// TODO:
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Macros */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Constants */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* A macro that defines the zycore version.
|
||||
*/
|
||||
#define ZYCORE_VERSION 0x0001000500020000ULL
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Helper macros */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Extracts the major-part of the zycore version.
|
||||
*
|
||||
* @param version The zycore version value
|
||||
*/
|
||||
#define ZYCORE_VERSION_MAJOR(version) ((version & 0xFFFF000000000000) >> 48)
|
||||
|
||||
/**
|
||||
* Extracts the minor-part of the zycore version.
|
||||
*
|
||||
* @param version The zycore version value
|
||||
*/
|
||||
#define ZYCORE_VERSION_MINOR(version) ((version & 0x0000FFFF00000000) >> 32)
|
||||
|
||||
/**
|
||||
* Extracts the patch-part of the zycore version.
|
||||
*
|
||||
* @param version The zycore version value
|
||||
*/
|
||||
#define ZYCORE_VERSION_PATCH(version) ((version & 0x00000000FFFF0000) >> 16)
|
||||
|
||||
/**
|
||||
* Extracts the build-part of the zycore version.
|
||||
*
|
||||
* @param version The zycore version value
|
||||
*/
|
||||
#define ZYCORE_VERSION_BUILD(version) (version & 0x000000000000FFFF)
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* Returns the zycore version.
|
||||
*
|
||||
* @return The zycore version.
|
||||
*
|
||||
* Use the macros provided in this file to extract the major, minor, patch and build part from the
|
||||
* returned version value.
|
||||
*/
|
||||
ZYCORE_EXPORT ZyanU64 ZycoreGetVersion(void);
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZYCORE_H */
|
||||
@@ -0,0 +1,132 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zycore-C)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
#include <Zycore/API/Memory.h>
|
||||
|
||||
#ifndef ZYAN_NO_LIBC
|
||||
|
||||
#if defined(ZYAN_WINDOWS)
|
||||
|
||||
#elif defined(ZYAN_POSIX)
|
||||
# include <unistd.h>
|
||||
#else
|
||||
# error "Unsupported platform detected"
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* General */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanU32 ZyanMemoryGetSystemPageSize(void)
|
||||
{
|
||||
#if defined(ZYAN_WINDOWS)
|
||||
|
||||
SYSTEM_INFO system_info;
|
||||
GetSystemInfo(&system_info);
|
||||
|
||||
return system_info.dwPageSize;
|
||||
|
||||
#elif defined(ZYAN_POSIX)
|
||||
|
||||
return sysconf(_SC_PAGE_SIZE);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
ZyanU32 ZyanMemoryGetSystemAllocationGranularity(void)
|
||||
{
|
||||
#if defined(ZYAN_WINDOWS)
|
||||
|
||||
SYSTEM_INFO system_info;
|
||||
GetSystemInfo(&system_info);
|
||||
|
||||
return system_info.dwAllocationGranularity;
|
||||
|
||||
#elif defined(ZYAN_POSIX)
|
||||
|
||||
return sysconf(_SC_PAGE_SIZE);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Memory management */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanMemoryVirtualProtect(void* address, ZyanUSize size,
|
||||
ZyanMemoryPageProtection protection)
|
||||
{
|
||||
#if defined(ZYAN_WINDOWS)
|
||||
|
||||
DWORD old;
|
||||
if (!VirtualProtect(address, size, protection, &old))
|
||||
{
|
||||
return ZYAN_STATUS_BAD_SYSTEMCALL;
|
||||
}
|
||||
|
||||
#elif defined(ZYAN_POSIX)
|
||||
|
||||
if (mprotect(address, size, protection))
|
||||
{
|
||||
return ZYAN_STATUS_BAD_SYSTEMCALL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanMemoryVirtualFree(void* address, ZyanUSize size)
|
||||
{
|
||||
#if defined(ZYAN_WINDOWS)
|
||||
|
||||
ZYAN_UNUSED(size);
|
||||
if (!VirtualFree(address, 0, MEM_RELEASE))
|
||||
{
|
||||
return ZYAN_STATUS_BAD_SYSTEMCALL;
|
||||
}
|
||||
|
||||
#elif defined(ZYAN_POSIX)
|
||||
|
||||
if (munmap(address, size))
|
||||
{
|
||||
return ZYAN_STATUS_BAD_SYSTEMCALL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#endif /* ZYAN_NO_LIBC */
|
||||
@@ -0,0 +1,77 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zycore-C)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
#include <Zycore/Defines.h>
|
||||
#include <Zycore/API/Process.h>
|
||||
|
||||
#ifndef ZYAN_NO_LIBC
|
||||
|
||||
#if defined(ZYAN_WINDOWS)
|
||||
#if defined(ZYAN_KERNEL)
|
||||
# include <wdm.h>
|
||||
#else
|
||||
# include <windows.h>
|
||||
#endif
|
||||
#elif defined(ZYAN_POSIX)
|
||||
# include <sys/mman.h>
|
||||
#else
|
||||
# error "Unsupported platform detected"
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* General */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanProcessFlushInstructionCache(void* address, ZyanUSize size)
|
||||
{
|
||||
#if defined(ZYAN_WINDOWS)
|
||||
|
||||
if (!FlushInstructionCache(GetCurrentProcess(), address, size))
|
||||
{
|
||||
return ZYAN_STATUS_BAD_SYSTEMCALL;
|
||||
}
|
||||
|
||||
#elif defined(ZYAN_POSIX)
|
||||
|
||||
if (msync(address, size, MS_SYNC | MS_INVALIDATE))
|
||||
{
|
||||
return ZYAN_STATUS_BAD_SYSTEMCALL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#endif /* ZYAN_NO_LIBC */
|
||||
@@ -0,0 +1,204 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zycore-C)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
#include <Zycore/API/Synchronization.h>
|
||||
|
||||
#ifndef ZYAN_NO_LIBC
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Internal functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
#if defined(ZYAN_POSIX)
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Critical Section */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanCriticalSectionInitialize(ZyanCriticalSection* critical_section)
|
||||
{
|
||||
pthread_mutexattr_t attribute;
|
||||
|
||||
int error = pthread_mutexattr_init(&attribute);
|
||||
if (error != 0)
|
||||
{
|
||||
if (error == ENOMEM)
|
||||
{
|
||||
return ZYAN_STATUS_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
return ZYAN_STATUS_BAD_SYSTEMCALL;
|
||||
}
|
||||
pthread_mutexattr_settype(&attribute, PTHREAD_MUTEX_RECURSIVE);
|
||||
|
||||
error = pthread_mutex_init(critical_section, &attribute);
|
||||
pthread_mutexattr_destroy(&attribute);
|
||||
if (error != 0)
|
||||
{
|
||||
if (error == EAGAIN)
|
||||
{
|
||||
return ZYAN_STATUS_OUT_OF_RESOURCES;
|
||||
}
|
||||
if (error == ENOMEM)
|
||||
{
|
||||
return ZYAN_STATUS_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
if (error == EPERM)
|
||||
{
|
||||
return ZYAN_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
if ((error == EBUSY) || (error == EINVAL))
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
return ZYAN_STATUS_BAD_SYSTEMCALL;
|
||||
}
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanCriticalSectionEnter(ZyanCriticalSection* critical_section)
|
||||
{
|
||||
const int error = pthread_mutex_lock(critical_section);
|
||||
if (error != 0)
|
||||
{
|
||||
if (error == EINVAL)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if (error == EAGAIN)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_OPERATION;
|
||||
}
|
||||
return ZYAN_STATUS_BAD_SYSTEMCALL;
|
||||
}
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanBool ZyanCriticalSectionTryEnter(ZyanCriticalSection* critical_section)
|
||||
{
|
||||
// No fine grained error handling for this one
|
||||
return pthread_mutex_trylock(critical_section) ? ZYAN_FALSE : ZYAN_TRUE;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanCriticalSectionLeave(ZyanCriticalSection* critical_section)
|
||||
{
|
||||
const int error = pthread_mutex_unlock(critical_section);
|
||||
if (error != 0)
|
||||
{
|
||||
if (error == EINVAL)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if (error == EPERM)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_OPERATION;
|
||||
}
|
||||
return ZYAN_STATUS_BAD_SYSTEMCALL;
|
||||
}
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanCriticalSectionDelete(ZyanCriticalSection* critical_section)
|
||||
{
|
||||
const int error = pthread_mutex_destroy(critical_section);
|
||||
if (error != 0)
|
||||
{
|
||||
if ((error == EBUSY) || (error == EINVAL))
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
return ZYAN_STATUS_BAD_SYSTEMCALL;
|
||||
}
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#elif defined(ZYAN_WINDOWS)
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* General */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanCriticalSectionInitialize(ZyanCriticalSection* critical_section)
|
||||
{
|
||||
InitializeCriticalSection(critical_section);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanCriticalSectionEnter(ZyanCriticalSection* critical_section)
|
||||
{
|
||||
EnterCriticalSection(critical_section);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanBool ZyanCriticalSectionTryEnter(ZyanCriticalSection* critical_section)
|
||||
{
|
||||
return TryEnterCriticalSection(critical_section) ? ZYAN_TRUE : ZYAN_FALSE;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanCriticalSectionLeave(ZyanCriticalSection* critical_section)
|
||||
{
|
||||
LeaveCriticalSection(critical_section);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanCriticalSectionDelete(ZyanCriticalSection* critical_section)
|
||||
{
|
||||
DeleteCriticalSection(critical_section);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#else
|
||||
# error "Unsupported platform detected"
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#endif /* ZYAN_NO_LIBC */
|
||||
@@ -0,0 +1,160 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zycore-C)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
#include <Zycore/API/Terminal.h>
|
||||
|
||||
#ifndef ZYAN_NO_LIBC
|
||||
|
||||
#if defined(ZYAN_POSIX)
|
||||
# include <unistd.h>
|
||||
#elif defined(ZYAN_WINDOWS)
|
||||
# include <windows.h>
|
||||
# include <io.h>
|
||||
#else
|
||||
# error "Unsupported platform detected"
|
||||
#endif
|
||||
|
||||
// Provide fallback for old SDK versions
|
||||
#ifdef ZYAN_WINDOWS
|
||||
# ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||
# define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
ZyanStatus ZyanTerminalEnableVT100(ZyanStandardStream stream)
|
||||
{
|
||||
if ((stream != ZYAN_STDSTREAM_OUT) && (stream != ZYAN_STDSTREAM_ERR))
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
#ifdef ZYAN_WINDOWS
|
||||
// Get file descriptor
|
||||
int file;
|
||||
switch (stream)
|
||||
{
|
||||
case ZYAN_STDSTREAM_OUT:
|
||||
file = _fileno(ZYAN_STDOUT);
|
||||
break;
|
||||
case ZYAN_STDSTREAM_ERR:
|
||||
file = _fileno(ZYAN_STDERR);
|
||||
break;
|
||||
default:
|
||||
ZYAN_UNREACHABLE;
|
||||
}
|
||||
if (file < 0)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
HANDLE const handle = (HANDLE)_get_osfhandle(file);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
DWORD mode;
|
||||
if (!GetConsoleMode(handle, &mode))
|
||||
{
|
||||
// The given standard stream is not bound to a terminal
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||
if (!SetConsoleMode(handle, mode))
|
||||
{
|
||||
return ZYAN_STATUS_BAD_SYSTEMCALL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanTerminalIsTTY(ZyanStandardStream stream)
|
||||
{
|
||||
// Get file descriptor
|
||||
int file;
|
||||
#ifdef ZYAN_WINDOWS
|
||||
switch (stream)
|
||||
{
|
||||
case ZYAN_STDSTREAM_IN:
|
||||
file = _fileno(ZYAN_STDIN);
|
||||
break;
|
||||
case ZYAN_STDSTREAM_OUT:
|
||||
file = _fileno(ZYAN_STDOUT);
|
||||
break;
|
||||
case ZYAN_STDSTREAM_ERR:
|
||||
file = _fileno(ZYAN_STDERR);
|
||||
break;
|
||||
default:
|
||||
ZYAN_UNREACHABLE;
|
||||
}
|
||||
if (file < 0)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
#else
|
||||
switch (stream)
|
||||
{
|
||||
case ZYAN_STDSTREAM_IN:
|
||||
file = STDIN_FILENO;
|
||||
break;
|
||||
case ZYAN_STDSTREAM_OUT:
|
||||
file = STDOUT_FILENO;
|
||||
break;
|
||||
case ZYAN_STDSTREAM_ERR:
|
||||
file = STDERR_FILENO;
|
||||
break;
|
||||
default:
|
||||
ZYAN_UNREACHABLE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ZYAN_WINDOWS
|
||||
if (_isatty(file))
|
||||
#else
|
||||
if ( isatty(file))
|
||||
#endif
|
||||
{
|
||||
return ZYAN_STATUS_TRUE;
|
||||
}
|
||||
if (ZYAN_ERRNO == EBADF)
|
||||
{
|
||||
// Invalid file descriptor
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
//ZYAN_ASSERT((errno == EINVAL) || (errno == ENOTTY));
|
||||
|
||||
return ZYAN_STATUS_FALSE;
|
||||
}
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#endif /* ZYAN_NO_LIBC */
|
||||
@@ -0,0 +1,244 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zycore-C)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
#include <Zycore/API/Thread.h>
|
||||
|
||||
#ifndef ZYAN_NO_LIBC
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Internal functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Legacy Windows import declarations */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#if defined(ZYAN_WINDOWS) && defined(_WIN32_WINNT) && \
|
||||
(_WIN32_WINNT >= 0x0501) && (_WIN32_WINNT < 0x0600)
|
||||
|
||||
/**
|
||||
* The Windows SDK conditionally declares the following prototypes: the target OS must be Vista
|
||||
* (0x0600) or above. MSDN states the same incorrect minimum requirement for the Fls* functions.
|
||||
*
|
||||
* However, these functions exist and work perfectly fine on XP (SP3) and Server 2003.
|
||||
* Preserve backward compatibility with these OSes by declaring the prototypes here if needed.
|
||||
*/
|
||||
|
||||
#ifndef FLS_OUT_OF_INDEXES
|
||||
#define FLS_OUT_OF_INDEXES ((DWORD)0xFFFFFFFF)
|
||||
#endif
|
||||
|
||||
WINBASEAPI
|
||||
DWORD
|
||||
WINAPI
|
||||
FlsAlloc(
|
||||
_In_opt_ PFLS_CALLBACK_FUNCTION lpCallback
|
||||
);
|
||||
|
||||
WINBASEAPI
|
||||
PVOID
|
||||
WINAPI
|
||||
FlsGetValue(
|
||||
_In_ DWORD dwFlsIndex
|
||||
);
|
||||
|
||||
WINBASEAPI
|
||||
BOOL
|
||||
WINAPI
|
||||
FlsSetValue(
|
||||
_In_ DWORD dwFlsIndex,
|
||||
_In_opt_ PVOID lpFlsData
|
||||
);
|
||||
|
||||
WINBASEAPI
|
||||
BOOL
|
||||
WINAPI
|
||||
FlsFree(
|
||||
_In_ DWORD dwFlsIndex
|
||||
);
|
||||
|
||||
#endif /* (_WIN32_WINNT >= 0x0501) && (_WIN32_WINNT < 0x0600)*/
|
||||
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
#if defined(ZYAN_POSIX)
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* General */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanThreadGetCurrentThread(ZyanThread* thread)
|
||||
{
|
||||
*thread = pthread_self();
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZYAN_STATIC_ASSERT(sizeof(ZyanThreadId) <= sizeof(ZyanU64));
|
||||
ZyanStatus ZyanThreadGetCurrentThreadId(ZyanThreadId* thread_id)
|
||||
{
|
||||
// TODO: Use `pthread_getthreadid_np` on platforms where it is available
|
||||
|
||||
pthread_t ptid = pthread_self();
|
||||
*thread_id = *(ZyanThreadId*)ptid;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Thread Local Storage */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanThreadTlsAlloc(ZyanThreadTlsIndex* index, ZyanThreadTlsCallback destructor)
|
||||
{
|
||||
ZyanThreadTlsIndex value;
|
||||
const int error = pthread_key_create(&value, destructor);
|
||||
if (error != 0)
|
||||
{
|
||||
if (error == EAGAIN)
|
||||
{
|
||||
return ZYAN_STATUS_OUT_OF_RESOURCES;
|
||||
}
|
||||
if (error == ENOMEM)
|
||||
{
|
||||
return ZYAN_STATUS_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
return ZYAN_STATUS_BAD_SYSTEMCALL;
|
||||
}
|
||||
|
||||
*index = value;
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanThreadTlsFree(ZyanThreadTlsIndex index)
|
||||
{
|
||||
return !pthread_key_delete(index) ? ZYAN_STATUS_SUCCESS : ZYAN_STATUS_BAD_SYSTEMCALL;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanThreadTlsGetValue(ZyanThreadTlsIndex index, void** data)
|
||||
{
|
||||
*data = pthread_getspecific(index);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanThreadTlsSetValue(ZyanThreadTlsIndex index, void* data)
|
||||
{
|
||||
const int error = pthread_setspecific(index, data);
|
||||
if (error != 0)
|
||||
{
|
||||
if (error == EINVAL)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
return ZYAN_STATUS_BAD_SYSTEMCALL;
|
||||
}
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#elif defined(ZYAN_WINDOWS)
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* General */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanThreadGetCurrentThread(ZyanThread* thread)
|
||||
{
|
||||
*thread = GetCurrentThread();
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanThreadGetCurrentThreadId(ZyanThreadId* thread_id)
|
||||
{
|
||||
*thread_id = GetCurrentThreadId();
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Thread Local Storage (TLS) */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanThreadTlsAlloc(ZyanThreadTlsIndex* index, ZyanThreadTlsCallback destructor)
|
||||
{
|
||||
const ZyanThreadTlsIndex value = FlsAlloc(destructor);
|
||||
if (value == FLS_OUT_OF_INDEXES)
|
||||
{
|
||||
return ZYAN_STATUS_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
*index = value;
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanThreadTlsFree(ZyanThreadTlsIndex index)
|
||||
{
|
||||
return FlsFree(index) ? ZYAN_STATUS_SUCCESS : ZYAN_STATUS_BAD_SYSTEMCALL;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanThreadTlsGetValue(ZyanThreadTlsIndex index, void** data)
|
||||
{
|
||||
*data = FlsGetValue(index);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanThreadTlsSetValue(ZyanThreadTlsIndex index, void* data)
|
||||
{
|
||||
if (!FlsSetValue(index, data))
|
||||
{
|
||||
const DWORD error = GetLastError();
|
||||
if (error == ERROR_INVALID_PARAMETER)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
return ZYAN_STATUS_BAD_SYSTEMCALL;
|
||||
}
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#else
|
||||
# error "Unsupported platform detected"
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#endif /* ZYAN_NO_LIBC */
|
||||
@@ -0,0 +1,134 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zycore-C)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
#include <Zycore/Allocator.h>
|
||||
#include <Zycore/LibC.h>
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Internal functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Default allocator */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef ZYAN_NO_LIBC
|
||||
|
||||
static ZyanStatus ZyanAllocatorDefaultAllocate(ZyanAllocator* allocator, void** p,
|
||||
ZyanUSize element_size, ZyanUSize n)
|
||||
{
|
||||
ZYAN_ASSERT(allocator);
|
||||
ZYAN_ASSERT(p);
|
||||
ZYAN_ASSERT(element_size);
|
||||
ZYAN_ASSERT(n);
|
||||
|
||||
ZYAN_UNUSED(allocator);
|
||||
|
||||
*p = ZYAN_MALLOC(element_size * n);
|
||||
if (!*p)
|
||||
{
|
||||
return ZYAN_STATUS_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static ZyanStatus ZyanAllocatorDefaultReallocate(ZyanAllocator* allocator, void** p,
|
||||
ZyanUSize element_size, ZyanUSize n)
|
||||
{
|
||||
ZYAN_ASSERT(allocator);
|
||||
ZYAN_ASSERT(p);
|
||||
ZYAN_ASSERT(element_size);
|
||||
ZYAN_ASSERT(n);
|
||||
|
||||
ZYAN_UNUSED(allocator);
|
||||
|
||||
void* const x = ZYAN_REALLOC(*p, element_size * n);
|
||||
if (!x)
|
||||
{
|
||||
return ZYAN_STATUS_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
*p = x;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static ZyanStatus ZyanAllocatorDefaultDeallocate(ZyanAllocator* allocator, void* p,
|
||||
ZyanUSize element_size, ZyanUSize n)
|
||||
{
|
||||
ZYAN_ASSERT(allocator);
|
||||
ZYAN_ASSERT(p);
|
||||
ZYAN_ASSERT(element_size);
|
||||
ZYAN_ASSERT(n);
|
||||
|
||||
ZYAN_UNUSED(allocator);
|
||||
ZYAN_UNUSED(element_size);
|
||||
ZYAN_UNUSED(n);
|
||||
|
||||
ZYAN_FREE(p);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#endif // ZYAN_NO_LIBC
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
ZyanStatus ZyanAllocatorInit(ZyanAllocator* allocator, ZyanAllocatorAllocate allocate,
|
||||
ZyanAllocatorAllocate reallocate, ZyanAllocatorDeallocate deallocate)
|
||||
{
|
||||
if (!allocator || !allocate || !reallocate || !deallocate)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
allocator->allocate = allocate;
|
||||
allocator->reallocate = reallocate;
|
||||
allocator->deallocate = deallocate;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#ifndef ZYAN_NO_LIBC
|
||||
|
||||
ZyanAllocator* ZyanAllocatorDefault(void)
|
||||
{
|
||||
static ZyanAllocator allocator =
|
||||
{
|
||||
&ZyanAllocatorDefaultAllocate,
|
||||
&ZyanAllocatorDefaultReallocate,
|
||||
&ZyanAllocatorDefaultDeallocate
|
||||
};
|
||||
return &allocator;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
@@ -0,0 +1,279 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zycore-C)
|
||||
|
||||
Original Author : Joel Hoener
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
#include <Zycore/ArgParse.h>
|
||||
#include <Zycore/LibC.h>
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifndef ZYAN_NO_LIBC
|
||||
|
||||
ZyanStatus ZyanArgParse(const ZyanArgParseConfig *cfg, ZyanVector* parsed,
|
||||
const char** error_token)
|
||||
{
|
||||
return ZyanArgParseEx(cfg, parsed, error_token, ZyanAllocatorDefault());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
ZyanStatus ZyanArgParseEx(const ZyanArgParseConfig *cfg, ZyanVector* parsed,
|
||||
const char** error_token, ZyanAllocator* allocator)
|
||||
{
|
||||
# define ZYAN_ERR_TOK(tok) if (error_token) { *error_token = tok; }
|
||||
|
||||
ZYAN_ASSERT(cfg);
|
||||
ZYAN_ASSERT(parsed);
|
||||
|
||||
// TODO: Once we have a decent hash map impl, refactor this to use it. The majority of for
|
||||
// loops through the argument list could be avoided.
|
||||
|
||||
if (cfg->min_unnamed_args > cfg->max_unnamed_args)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
// Check argument syntax.
|
||||
for (const ZyanArgParseDefinition* def = cfg->args; def && def->name; ++def)
|
||||
{
|
||||
// TODO: Duplicate check
|
||||
|
||||
if (!def->name)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
ZyanUSize arg_len = ZYAN_STRLEN(def->name);
|
||||
if (arg_len < 2 || def->name[0] != '-')
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
// Single dash arguments only accept a single char name.
|
||||
if (def->name[1] != '-' && arg_len != 2)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize output vector.
|
||||
ZYAN_CHECK(ZyanVectorInitEx(parsed, sizeof(ZyanArgParseArg), cfg->argc, ZYAN_NULL, allocator,
|
||||
ZYAN_VECTOR_DEFAULT_GROWTH_FACTOR, ZYAN_VECTOR_DEFAULT_SHRINK_THRESHOLD));
|
||||
|
||||
ZyanStatus err;
|
||||
ZyanBool accept_dash_args = ZYAN_TRUE;
|
||||
ZyanUSize num_unnamed_args = 0;
|
||||
for (ZyanUSize i = 1; i < cfg->argc; ++i)
|
||||
{
|
||||
const char* cur_arg = cfg->argv[i];
|
||||
ZyanUSize arg_len = ZYAN_STRLEN(cfg->argv[i]);
|
||||
|
||||
// Double-dash argument?
|
||||
if (accept_dash_args && arg_len >= 2 && ZYAN_MEMCMP(cur_arg, "--", 2) == 0)
|
||||
{
|
||||
// GNU style end of argument parsing.
|
||||
if (arg_len == 2)
|
||||
{
|
||||
accept_dash_args = ZYAN_FALSE;
|
||||
}
|
||||
// Regular double-dash argument.
|
||||
else
|
||||
{
|
||||
// Allocate parsed argument struct.
|
||||
ZyanArgParseArg* parsed_arg;
|
||||
ZYAN_CHECK(ZyanVectorEmplace(parsed, (void**)&parsed_arg, ZYAN_NULL));
|
||||
ZYAN_MEMSET(parsed_arg, 0, sizeof(*parsed_arg));
|
||||
|
||||
// Find corresponding argument definition.
|
||||
for (const ZyanArgParseDefinition* def = cfg->args; def && def->name; ++def)
|
||||
{
|
||||
if (ZYAN_STRCMP(def->name, cur_arg) == 0)
|
||||
{
|
||||
parsed_arg->def = def;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Search exhausted & argument not found. RIP.
|
||||
if (!parsed_arg->def)
|
||||
{
|
||||
err = ZYAN_STATUS_ARG_NOT_UNDERSTOOD;
|
||||
ZYAN_ERR_TOK(cur_arg);
|
||||
goto failure;
|
||||
}
|
||||
|
||||
// Does the argument expect a value? If yes, consume next token.
|
||||
if (!parsed_arg->def->boolean)
|
||||
{
|
||||
if (i == cfg->argc - 1)
|
||||
{
|
||||
err = ZYAN_STATUS_ARG_MISSES_VALUE;
|
||||
ZYAN_ERR_TOK(cur_arg);
|
||||
goto failure;
|
||||
}
|
||||
parsed_arg->has_value = ZYAN_TRUE;
|
||||
ZYAN_CHECK(ZyanStringViewInsideBuffer(&parsed_arg->value, cfg->argv[++i]));
|
||||
}
|
||||
}
|
||||
|
||||
// Continue parsing at next token.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Single-dash argument?
|
||||
// TODO: How to deal with just dashes? Current code treats it as unnamed arg.
|
||||
if (accept_dash_args && arg_len > 1 && cur_arg[0] == '-')
|
||||
{
|
||||
// Iterate argument token chars until there are either no more chars left
|
||||
// or we encounter a non-boolean argument, in which case we consume the
|
||||
// remaining chars as its value.
|
||||
for (const char* read_ptr = cur_arg + 1; *read_ptr; ++read_ptr)
|
||||
{
|
||||
// Allocate parsed argument struct.
|
||||
ZyanArgParseArg* parsed_arg;
|
||||
ZYAN_CHECK(ZyanVectorEmplace(parsed, (void**)&parsed_arg, ZYAN_NULL));
|
||||
ZYAN_MEMSET(parsed_arg, 0, sizeof(*parsed_arg));
|
||||
|
||||
// Find corresponding argument definition.
|
||||
for (const ZyanArgParseDefinition* def = cfg->args; def && def->name; ++def)
|
||||
{
|
||||
if (ZYAN_STRLEN(def->name) == 2 &&
|
||||
def->name[0] == '-' &&
|
||||
def->name[1] == *read_ptr)
|
||||
{
|
||||
parsed_arg->def = def;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Search exhausted, no match found?
|
||||
if (!parsed_arg->def)
|
||||
{
|
||||
err = ZYAN_STATUS_ARG_NOT_UNDERSTOOD;
|
||||
ZYAN_ERR_TOK(cur_arg);
|
||||
goto failure;
|
||||
}
|
||||
|
||||
// Requires value?
|
||||
if (!parsed_arg->def->boolean)
|
||||
{
|
||||
// If there are chars left, consume them (e.g. `-n1000`).
|
||||
if (read_ptr[1])
|
||||
{
|
||||
parsed_arg->has_value = ZYAN_TRUE;
|
||||
ZYAN_CHECK(ZyanStringViewInsideBuffer(&parsed_arg->value, read_ptr + 1));
|
||||
}
|
||||
// If not, consume next token (e.g. `-n 1000`).
|
||||
else
|
||||
{
|
||||
if (i == cfg->argc - 1)
|
||||
{
|
||||
err = ZYAN_STATUS_ARG_MISSES_VALUE;
|
||||
ZYAN_ERR_TOK(cur_arg)
|
||||
goto failure;
|
||||
}
|
||||
|
||||
parsed_arg->has_value = ZYAN_TRUE;
|
||||
ZYAN_CHECK(ZyanStringViewInsideBuffer(&parsed_arg->value, cfg->argv[++i]));
|
||||
}
|
||||
|
||||
// Either way, continue with next argument.
|
||||
goto continue_main_loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Still here? We're looking at an unnamed argument.
|
||||
++num_unnamed_args;
|
||||
if (num_unnamed_args > cfg->max_unnamed_args)
|
||||
{
|
||||
err = ZYAN_STATUS_TOO_MANY_ARGS;
|
||||
ZYAN_ERR_TOK(cur_arg);
|
||||
goto failure;
|
||||
}
|
||||
|
||||
// Allocate parsed argument struct.
|
||||
ZyanArgParseArg* parsed_arg;
|
||||
ZYAN_CHECK(ZyanVectorEmplace(parsed, (void**)&parsed_arg, ZYAN_NULL));
|
||||
ZYAN_MEMSET(parsed_arg, 0, sizeof(*parsed_arg));
|
||||
parsed_arg->has_value = ZYAN_TRUE;
|
||||
ZYAN_CHECK(ZyanStringViewInsideBuffer(&parsed_arg->value, cur_arg));
|
||||
|
||||
continue_main_loop:;
|
||||
}
|
||||
|
||||
// All tokens processed. Do we have enough unnamed arguments?
|
||||
if (num_unnamed_args < cfg->min_unnamed_args)
|
||||
{
|
||||
err = ZYAN_STATUS_TOO_FEW_ARGS;
|
||||
// No sensible error token for this error type.
|
||||
goto failure;
|
||||
}
|
||||
|
||||
// Check whether all required arguments are present.
|
||||
ZyanUSize num_parsed_args;
|
||||
ZYAN_CHECK(ZyanVectorGetSize(parsed, &num_parsed_args));
|
||||
for (const ZyanArgParseDefinition* def = cfg->args; def && def->name; ++def)
|
||||
{
|
||||
if (!def->required) continue;
|
||||
|
||||
ZyanBool arg_found = ZYAN_FALSE;
|
||||
for (ZyanUSize i = 0; i < num_parsed_args; ++i)
|
||||
{
|
||||
const ZyanArgParseArg* arg = ZYAN_NULL;
|
||||
ZYAN_CHECK(ZyanVectorGetPointer(parsed, i, (const void**)&arg));
|
||||
|
||||
// Skip unnamed args.
|
||||
if (!arg->def) continue;
|
||||
|
||||
if (arg->def == def)
|
||||
{
|
||||
arg_found = ZYAN_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!arg_found)
|
||||
{
|
||||
err = ZYAN_STATUS_REQUIRED_ARG_MISSING;
|
||||
ZYAN_ERR_TOK(def->name);
|
||||
goto failure;
|
||||
}
|
||||
}
|
||||
|
||||
// Yay!
|
||||
ZYAN_ERR_TOK(ZYAN_NULL);
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
|
||||
failure:
|
||||
ZYAN_CHECK(ZyanVectorDestroy(parsed));
|
||||
return err;
|
||||
|
||||
# undef ZYAN_ERR_TOK
|
||||
}
|
||||
|
||||
/* ============================================================================================== */
|
||||
+670
@@ -0,0 +1,670 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zycore-C)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
#include <Zycore/Bitset.h>
|
||||
#include <Zycore/LibC.h>
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Internal constants */
|
||||
/* ============================================================================================== */
|
||||
|
||||
#define ZYAN_BITSET_GROWTH_FACTOR 2
|
||||
#define ZYAN_BITSET_SHRINK_THRESHOLD 2
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Internal macros */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* Computes the smallest integer value not less than `x`.
|
||||
*
|
||||
* @param x The value.
|
||||
*
|
||||
* @return The smallest integer value not less than `x`.
|
||||
*/
|
||||
#define ZYAN_BITSET_CEIL(x) \
|
||||
(((x) == ((ZyanU32)(x))) ? (ZyanU32)(x) : ((ZyanU32)(x)) + 1)
|
||||
|
||||
/**
|
||||
* Converts bits to bytes.
|
||||
*
|
||||
* @param x The value in bits.
|
||||
*
|
||||
* @return The amount of bytes needed to fit `x` bits.
|
||||
*/
|
||||
#define ZYAN_BITSET_BITS_TO_BYTES(x) \
|
||||
ZYAN_BITSET_CEIL((x) / 8)
|
||||
|
||||
/**
|
||||
* Returns the offset of the given bit.
|
||||
*
|
||||
* @param index The bit index.
|
||||
*
|
||||
* @return The offset of the given bit.
|
||||
*/
|
||||
#define ZYAN_BITSET_BIT_OFFSET(index) \
|
||||
(7 - ((index) % 8))
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Internal functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Helper functions */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Initializes the given `vector` with `count` "zero"-bytes.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param count The number of bytes.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
static ZyanStatus ZyanBitsetInitVectorElements(ZyanVector* vector, ZyanUSize count)
|
||||
{
|
||||
ZYAN_ASSERT(vector);
|
||||
|
||||
static const ZyanU8 zero = 0;
|
||||
for (ZyanUSize i = 0; i < count; ++i)
|
||||
{
|
||||
ZYAN_CHECK(ZyanVectorPushBack(vector, &zero));
|
||||
}
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Byte operations */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
static ZyanStatus ZyanBitsetOperationAND(ZyanU8* b1, const ZyanU8* b2)
|
||||
{
|
||||
*b1 &= *b2;
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static ZyanStatus ZyanBitsetOperationOR (ZyanU8* b1, const ZyanU8* b2)
|
||||
{
|
||||
*b1 |= *b2;
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static ZyanStatus ZyanBitsetOperationXOR(ZyanU8* b1, const ZyanU8* b2)
|
||||
{
|
||||
*b1 ^= *b2;
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Constructor and destructor */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef ZYAN_NO_LIBC
|
||||
|
||||
ZyanStatus ZyanBitsetInit(ZyanBitset* bitset, ZyanUSize count)
|
||||
{
|
||||
return ZyanBitsetInitEx(bitset, count, ZyanAllocatorDefault(), ZYAN_BITSET_GROWTH_FACTOR,
|
||||
ZYAN_BITSET_SHRINK_THRESHOLD);
|
||||
}
|
||||
|
||||
#endif // ZYAN_NO_LIBC
|
||||
|
||||
ZyanStatus ZyanBitsetInitEx(ZyanBitset* bitset, ZyanUSize count, ZyanAllocator* allocator,
|
||||
ZyanU8 growth_factor, ZyanU8 shrink_threshold)
|
||||
{
|
||||
if (!bitset)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
const ZyanU32 bytes = ZYAN_BITSET_BITS_TO_BYTES(count);
|
||||
|
||||
bitset->size = count;
|
||||
ZYAN_CHECK(ZyanVectorInitEx(&bitset->bits, sizeof(ZyanU8), bytes, ZYAN_NULL, allocator,
|
||||
growth_factor, shrink_threshold));
|
||||
ZYAN_CHECK(ZyanBitsetInitVectorElements(&bitset->bits, bytes));
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanBitsetInitBuffer(ZyanBitset* bitset, ZyanUSize count, void* buffer,
|
||||
ZyanUSize capacity)
|
||||
{
|
||||
if (!bitset)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
const ZyanU32 bytes = ZYAN_BITSET_BITS_TO_BYTES(count);
|
||||
if (capacity < bytes)
|
||||
{
|
||||
return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
bitset->size = count;
|
||||
ZYAN_CHECK(ZyanVectorInitCustomBuffer(&bitset->bits, sizeof(ZyanU8), buffer, capacity,
|
||||
ZYAN_NULL));
|
||||
ZYAN_CHECK(ZyanBitsetInitVectorElements(&bitset->bits, bytes));
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanBitsetDestroy(ZyanBitset* bitset)
|
||||
{
|
||||
if (!bitset)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return ZyanVectorDestroy(&bitset->bits);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Logical operations */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanBitsetPerformByteOperation(ZyanBitset* destination, const ZyanBitset* source,
|
||||
ZyanBitsetByteOperation operation)
|
||||
{
|
||||
if (!destination || !source || !operation)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
ZyanUSize s1;
|
||||
ZyanUSize s2;
|
||||
ZYAN_CHECK(ZyanVectorGetSize(&destination->bits, &s1));
|
||||
ZYAN_CHECK(ZyanVectorGetSize(&source->bits, &s2));
|
||||
|
||||
const ZyanUSize min = ZYAN_MIN(s1, s2);
|
||||
for (ZyanUSize i = 0; i < min; ++i)
|
||||
{
|
||||
ZyanU8* v1;
|
||||
const ZyanU8* v2;
|
||||
ZYAN_CHECK(ZyanVectorGetPointerMutable(&destination->bits, i, (void**)&v1));
|
||||
ZYAN_CHECK(ZyanVectorGetPointer(&source->bits, i, (const void**)&v2));
|
||||
|
||||
ZYAN_ASSERT(v1);
|
||||
ZYAN_ASSERT(v2);
|
||||
|
||||
ZYAN_CHECK(operation(v1, v2));
|
||||
}
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanBitsetAND(ZyanBitset* destination, const ZyanBitset* source)
|
||||
{
|
||||
return ZyanBitsetPerformByteOperation(destination, source, ZyanBitsetOperationAND);
|
||||
}
|
||||
|
||||
ZyanStatus ZyanBitsetOR (ZyanBitset* destination, const ZyanBitset* source)
|
||||
{
|
||||
return ZyanBitsetPerformByteOperation(destination, source, ZyanBitsetOperationOR );
|
||||
}
|
||||
|
||||
ZyanStatus ZyanBitsetXOR(ZyanBitset* destination, const ZyanBitset* source)
|
||||
{
|
||||
return ZyanBitsetPerformByteOperation(destination, source, ZyanBitsetOperationXOR);
|
||||
}
|
||||
|
||||
ZyanStatus ZyanBitsetFlip(ZyanBitset* bitset)
|
||||
{
|
||||
if (!bitset)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
ZyanUSize size;
|
||||
ZYAN_CHECK(ZyanVectorGetSize(&bitset->bits, &size));
|
||||
for (ZyanUSize i = 0; i < size; ++i)
|
||||
{
|
||||
ZyanU8* value;
|
||||
ZYAN_CHECK(ZyanVectorGetPointerMutable(&bitset->bits, i, (void**)&value));
|
||||
*value = ~(*value);
|
||||
}
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Bit access */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanBitsetSet(ZyanBitset* bitset, ZyanUSize index)
|
||||
{
|
||||
if (!bitset)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if (index >= bitset->size)
|
||||
{
|
||||
return ZYAN_STATUS_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
ZyanU8* value;
|
||||
ZYAN_CHECK(ZyanVectorGetPointerMutable(&bitset->bits, index / 8, (void**)&value));
|
||||
|
||||
*value |= (1 << ZYAN_BITSET_BIT_OFFSET(index));
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanBitsetReset(ZyanBitset* bitset, ZyanUSize index)
|
||||
{
|
||||
if (!bitset)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if (index >= bitset->size)
|
||||
{
|
||||
return ZYAN_STATUS_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
ZyanU8* value;
|
||||
ZYAN_CHECK(ZyanVectorGetPointerMutable(&bitset->bits, index / 8, (void**)&value));
|
||||
*value &= ~(1 << ZYAN_BITSET_BIT_OFFSET(index));
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanBitsetAssign(ZyanBitset* bitset, ZyanUSize index, ZyanBool value)
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
return ZyanBitsetSet(bitset, index);
|
||||
}
|
||||
return ZyanBitsetReset(bitset, index);
|
||||
}
|
||||
|
||||
ZyanStatus ZyanBitsetToggle(ZyanBitset* bitset, ZyanUSize index)
|
||||
{
|
||||
if (!bitset)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if (index >= bitset->size)
|
||||
{
|
||||
return ZYAN_STATUS_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
ZyanU8* value;
|
||||
ZYAN_CHECK(ZyanVectorGetPointerMutable(&bitset->bits, index / 8, (void**)&value));
|
||||
*value ^= (1 << ZYAN_BITSET_BIT_OFFSET(index));
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanBitsetTest(ZyanBitset* bitset, ZyanUSize index)
|
||||
{
|
||||
if (!bitset)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if (index >= bitset->size)
|
||||
{
|
||||
return ZYAN_STATUS_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
const ZyanU8* value;
|
||||
ZYAN_CHECK(ZyanVectorGetPointer(&bitset->bits, index / 8, (const void**)&value));
|
||||
if ((*value & (1 << ZYAN_BITSET_BIT_OFFSET(index))) == 0)
|
||||
{
|
||||
return ZYAN_STATUS_FALSE;
|
||||
}
|
||||
return ZYAN_STATUS_TRUE;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanBitsetTestMSB(ZyanBitset* bitset)
|
||||
{
|
||||
if (!bitset)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return ZyanBitsetTest(bitset, bitset->size - 1);
|
||||
}
|
||||
|
||||
ZyanStatus ZyanBitsetTestLSB(ZyanBitset* bitset)
|
||||
{
|
||||
return ZyanBitsetTest(bitset, 0);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanBitsetSetAll(ZyanBitset* bitset)
|
||||
{
|
||||
if (!bitset)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
ZyanUSize size;
|
||||
ZYAN_CHECK(ZyanVectorGetSize(&bitset->bits, &size));
|
||||
for (ZyanUSize i = 0; i < size; ++i)
|
||||
{
|
||||
ZyanU8* value;
|
||||
ZYAN_CHECK(ZyanVectorGetPointerMutable(&bitset->bits, i, (void**)&value));
|
||||
*value = 0xFF;
|
||||
}
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanBitsetResetAll(ZyanBitset* bitset)
|
||||
{
|
||||
if (!bitset)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
ZyanUSize size;
|
||||
ZYAN_CHECK(ZyanVectorGetSize(&bitset->bits, &size));
|
||||
for (ZyanUSize i = 0; i < size; ++i)
|
||||
{
|
||||
ZyanU8* value;
|
||||
ZYAN_CHECK(ZyanVectorGetPointerMutable(&bitset->bits, i, (void**)&value));
|
||||
*value = 0x00;
|
||||
}
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Size management */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanBitsetPush(ZyanBitset* bitset, ZyanBool value)
|
||||
{
|
||||
if (!bitset)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if ((bitset->size++ % 8) == 0)
|
||||
{
|
||||
static const ZyanU8 zero = 0;
|
||||
ZYAN_CHECK(ZyanVectorPushBack(&bitset->bits, &zero));
|
||||
}
|
||||
|
||||
return ZyanBitsetAssign(bitset, bitset->size - 1, value);
|
||||
}
|
||||
|
||||
ZyanStatus ZyanBitsetPop(ZyanBitset* bitset)
|
||||
{
|
||||
if (!bitset)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if ((--bitset->size % 8) == 0)
|
||||
{
|
||||
return ZyanVectorPopBack(&bitset->bits);
|
||||
}
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanBitsetClear(ZyanBitset* bitset)
|
||||
{
|
||||
if (!bitset)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
bitset->size = 0;
|
||||
return ZyanVectorClear(&bitset->bits);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Memory management */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanBitsetReserve(ZyanBitset* bitset, ZyanUSize count)
|
||||
{
|
||||
return ZyanVectorReserve(&bitset->bits, ZYAN_BITSET_BITS_TO_BYTES(count));
|
||||
}
|
||||
|
||||
ZyanStatus ZyanBitsetShrinkToFit(ZyanBitset* bitset)
|
||||
{
|
||||
return ZyanVectorShrinkToFit(&bitset->bits);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Information */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanBitsetGetSize(const ZyanBitset* bitset, ZyanUSize* size)
|
||||
{
|
||||
if (!bitset)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
*size = bitset->size;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanBitsetGetCapacity(const ZyanBitset* bitset, ZyanUSize* capacity)
|
||||
{
|
||||
ZYAN_CHECK(ZyanBitsetGetCapacityBytes(bitset, capacity));
|
||||
*capacity *= 8;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanBitsetGetSizeBytes(const ZyanBitset* bitset, ZyanUSize* size)
|
||||
{
|
||||
if (!bitset)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return ZyanVectorGetSize(&bitset->bits, size);
|
||||
}
|
||||
|
||||
ZyanStatus ZyanBitsetGetCapacityBytes(const ZyanBitset* bitset, ZyanUSize* capacity)
|
||||
{
|
||||
if (!bitset)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return ZyanVectorGetCapacity(&bitset->bits, capacity);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanBitsetCount(const ZyanBitset* bitset, ZyanUSize* count)
|
||||
{
|
||||
if (!bitset || !count)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
*count = 0;
|
||||
|
||||
ZyanUSize size;
|
||||
ZYAN_CHECK(ZyanVectorGetSize(&bitset->bits, &size));
|
||||
for (ZyanUSize i = 0; i < size; ++i)
|
||||
{
|
||||
ZyanU8* value;
|
||||
ZYAN_CHECK(ZyanVectorGetPointer(&bitset->bits, i, (const void**)&value));
|
||||
|
||||
ZyanU8 popcnt = *value;
|
||||
popcnt = (popcnt & 0x55) + ((popcnt >> 1) & 0x55);
|
||||
popcnt = (popcnt & 0x33) + ((popcnt >> 2) & 0x33);
|
||||
popcnt = (popcnt & 0x0F) + ((popcnt >> 4) & 0x0F);
|
||||
|
||||
*count += popcnt;
|
||||
}
|
||||
|
||||
*count = ZYAN_MIN(*count, bitset->size);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanBitsetAll(const ZyanBitset* bitset)
|
||||
{
|
||||
if (!bitset)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
ZyanUSize size;
|
||||
ZYAN_CHECK(ZyanVectorGetSize(&bitset->bits, &size));
|
||||
for (ZyanUSize i = 0; i < size; ++i)
|
||||
{
|
||||
ZyanU8* value;
|
||||
ZYAN_CHECK(ZyanVectorGetPointer(&bitset->bits, i, (const void**)&value));
|
||||
if (i < (size - 1))
|
||||
{
|
||||
if (*value != 0xFF)
|
||||
{
|
||||
return ZYAN_STATUS_FALSE;
|
||||
}
|
||||
} else
|
||||
{
|
||||
const ZyanU8 mask = ~(8 - (bitset->size % 8));
|
||||
if ((*value & mask) != mask)
|
||||
{
|
||||
return ZYAN_STATUS_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ZYAN_STATUS_TRUE;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanBitsetAny(const ZyanBitset* bitset)
|
||||
{
|
||||
if (!bitset)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
ZyanUSize size;
|
||||
ZYAN_CHECK(ZyanVectorGetSize(&bitset->bits, &size));
|
||||
for (ZyanUSize i = 0; i < size; ++i)
|
||||
{
|
||||
ZyanU8* value;
|
||||
ZYAN_CHECK(ZyanVectorGetPointer(&bitset->bits, i, (const void**)&value));
|
||||
if (i < (size - 1))
|
||||
{
|
||||
if (*value != 0x00)
|
||||
{
|
||||
return ZYAN_STATUS_TRUE;
|
||||
}
|
||||
} else
|
||||
{
|
||||
const ZyanU8 mask = ~(8 - (bitset->size % 8));
|
||||
if ((*value & mask) != 0x00)
|
||||
{
|
||||
return ZYAN_STATUS_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ZYAN_STATUS_FALSE;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanBitsetNone(const ZyanBitset* bitset)
|
||||
{
|
||||
if (!bitset)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
ZyanUSize size;
|
||||
ZYAN_CHECK(ZyanVectorGetSize(&bitset->bits, &size));
|
||||
for (ZyanUSize i = 0; i < size; ++i)
|
||||
{
|
||||
ZyanU8* value;
|
||||
ZYAN_CHECK(ZyanVectorGetPointer(&bitset->bits, i, (const void**)&value));
|
||||
if (i < (size - 1))
|
||||
{
|
||||
if (*value != 0x00)
|
||||
{
|
||||
return ZYAN_STATUS_FALSE;
|
||||
}
|
||||
} else
|
||||
{
|
||||
const ZyanU8 mask = ~(8 - (bitset->size % 8));
|
||||
if ((*value & mask) != 0x00)
|
||||
{
|
||||
return ZYAN_STATUS_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ZYAN_STATUS_TRUE;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
//ZyanStatus ZyanBitsetToU32(const ZyanBitset* bitset, ZyanU32* value)
|
||||
//{
|
||||
// if (!bitset)
|
||||
// {
|
||||
// return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
// }
|
||||
// if (bitset->size > 32)
|
||||
// {
|
||||
// return ZYAN_STATUS_INVALID_OPERATION;
|
||||
// }
|
||||
//
|
||||
// // TODO:
|
||||
//
|
||||
// return ZYAN_STATUS_SUCCESS;
|
||||
//}
|
||||
//
|
||||
//ZyanStatus ZyanBitsetToU64(const ZyanBitset* bitset, ZyanU64* value)
|
||||
//{
|
||||
// if (!bitset)
|
||||
// {
|
||||
// return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
// }
|
||||
// if (bitset->size > 64)
|
||||
// {
|
||||
// return ZYAN_STATUS_INVALID_OPERATION;
|
||||
// }
|
||||
//
|
||||
// // TODO:
|
||||
//
|
||||
// return ZYAN_STATUS_SUCCESS;
|
||||
//}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
+507
@@ -0,0 +1,507 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zycore-C)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
#include <Zycore/Format.h>
|
||||
#include <Zycore/LibC.h>
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Constants */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Defines */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#define ZYCORE_MAXCHARS_DEC_32 10
|
||||
#define ZYCORE_MAXCHARS_DEC_64 20
|
||||
#define ZYCORE_MAXCHARS_HEX_32 8
|
||||
#define ZYCORE_MAXCHARS_HEX_64 16
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Lookup Tables */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
static const char* const DECIMAL_LOOKUP =
|
||||
"00010203040506070809"
|
||||
"10111213141516171819"
|
||||
"20212223242526272829"
|
||||
"30313233343536373839"
|
||||
"40414243444546474849"
|
||||
"50515253545556575859"
|
||||
"60616263646566676869"
|
||||
"70717273747576777879"
|
||||
"80818283848586878889"
|
||||
"90919293949596979899";
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Static strings */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
static const ZyanStringView STR_ADD = ZYAN_DEFINE_STRING_VIEW("+");
|
||||
static const ZyanStringView STR_SUB = ZYAN_DEFINE_STRING_VIEW("-");
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Internal macros */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* Writes a terminating '\0' character at the end of the string data.
|
||||
*/
|
||||
#define ZYCORE_STRING_NULLTERMINATE(string) \
|
||||
*(char*)((ZyanU8*)(string)->vector.data + (string)->vector.size - 1) = '\0';
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Internal functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Decimal */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#if defined(ZYAN_X86) || defined(ZYAN_ARM) || defined(ZYAN_EMSCRIPTEN) || defined(ZYAN_WASM) || defined(ZYAN_PPC)
|
||||
ZyanStatus ZyanStringAppendDecU32(ZyanString* string, ZyanU32 value, ZyanU8 padding_length)
|
||||
{
|
||||
if (!string)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
char buffer[ZYCORE_MAXCHARS_DEC_32];
|
||||
char *buffer_end = &buffer[ZYCORE_MAXCHARS_DEC_32];
|
||||
char *buffer_write_pointer = buffer_end;
|
||||
while (value >= 100)
|
||||
{
|
||||
const ZyanU32 value_old = value;
|
||||
buffer_write_pointer -= 2;
|
||||
value /= 100;
|
||||
ZYAN_MEMCPY(buffer_write_pointer, &DECIMAL_LOOKUP[(value_old - (value * 100)) * 2], 2);
|
||||
}
|
||||
buffer_write_pointer -= 2;
|
||||
ZYAN_MEMCPY(buffer_write_pointer, &DECIMAL_LOOKUP[value * 2], 2);
|
||||
|
||||
const ZyanUSize offset_odd = (ZyanUSize)(value < 10);
|
||||
const ZyanUSize length_number = buffer_end - buffer_write_pointer - offset_odd;
|
||||
const ZyanUSize length_total = ZYAN_MAX(length_number, padding_length);
|
||||
const ZyanUSize length_target = string->vector.size;
|
||||
|
||||
if (string->vector.size + length_total > string->vector.capacity)
|
||||
{
|
||||
ZYAN_CHECK(ZyanStringResize(string, string->vector.size + length_total - 1));
|
||||
}
|
||||
|
||||
ZyanUSize offset_write = 0;
|
||||
if (padding_length > length_number)
|
||||
{
|
||||
offset_write = padding_length - length_number;
|
||||
ZYAN_MEMSET((char*)string->vector.data + length_target - 1, '0', offset_write);
|
||||
}
|
||||
|
||||
ZYAN_MEMCPY((char*)string->vector.data + length_target + offset_write - 1,
|
||||
buffer_write_pointer + offset_odd, length_number);
|
||||
string->vector.size = length_target + length_total;
|
||||
ZYCORE_STRING_NULLTERMINATE(string);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
ZyanStatus ZyanStringAppendDecU64(ZyanString* string, ZyanU64 value, ZyanU8 padding_length)
|
||||
{
|
||||
if (!string)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
char buffer[ZYCORE_MAXCHARS_DEC_64];
|
||||
char *buffer_end = &buffer[ZYCORE_MAXCHARS_DEC_64];
|
||||
char *buffer_write_pointer = buffer_end;
|
||||
while (value >= 100)
|
||||
{
|
||||
const ZyanU64 value_old = value;
|
||||
buffer_write_pointer -= 2;
|
||||
value /= 100;
|
||||
ZYAN_MEMCPY(buffer_write_pointer, &DECIMAL_LOOKUP[(value_old - (value * 100)) * 2], 2);
|
||||
}
|
||||
buffer_write_pointer -= 2;
|
||||
ZYAN_MEMCPY(buffer_write_pointer, &DECIMAL_LOOKUP[value * 2], 2);
|
||||
|
||||
const ZyanUSize offset_odd = (ZyanUSize)(value < 10);
|
||||
const ZyanUSize length_number = buffer_end - buffer_write_pointer - offset_odd;
|
||||
const ZyanUSize length_total = ZYAN_MAX(length_number, padding_length);
|
||||
const ZyanUSize length_target = string->vector.size;
|
||||
|
||||
if (string->vector.size + length_total > string->vector.capacity)
|
||||
{
|
||||
ZYAN_CHECK(ZyanStringResize(string, string->vector.size + length_total - 1));
|
||||
}
|
||||
|
||||
ZyanUSize offset_write = 0;
|
||||
if (padding_length > length_number)
|
||||
{
|
||||
offset_write = padding_length - length_number;
|
||||
ZYAN_MEMSET((char*)string->vector.data + length_target - 1, '0', offset_write);
|
||||
}
|
||||
|
||||
ZYAN_MEMCPY((char*)string->vector.data + length_target + offset_write - 1,
|
||||
buffer_write_pointer + offset_odd, length_number);
|
||||
string->vector.size = length_target + length_total;
|
||||
ZYCORE_STRING_NULLTERMINATE(string);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Hexadecimal */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#if defined(ZYAN_X86) || defined(ZYAN_ARM) || defined(ZYAN_EMSCRIPTEN) || defined(ZYAN_WASM) || defined(ZYAN_PPC)
|
||||
ZyanStatus ZyanStringAppendHexU32(ZyanString* string, ZyanU32 value, ZyanU8 padding_length,
|
||||
ZyanBool uppercase)
|
||||
{
|
||||
if (!string)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
const ZyanUSize len = string->vector.size;
|
||||
ZyanUSize remaining = string->vector.capacity - string->vector.size;
|
||||
|
||||
if (remaining < (ZyanUSize)padding_length)
|
||||
{
|
||||
ZYAN_CHECK(ZyanStringResize(string, len + padding_length - 1));
|
||||
remaining = padding_length;
|
||||
}
|
||||
|
||||
if (!value)
|
||||
{
|
||||
const ZyanU8 n = (padding_length ? padding_length : 1);
|
||||
|
||||
if (remaining < (ZyanUSize)n)
|
||||
{
|
||||
ZYAN_CHECK(ZyanStringResize(string, string->vector.size + n - 1));
|
||||
}
|
||||
|
||||
ZYAN_MEMSET((char*)string->vector.data + len - 1, '0', n);
|
||||
string->vector.size = len + n;
|
||||
ZYCORE_STRING_NULLTERMINATE(string);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanU8 n = 0;
|
||||
char* buffer = ZYAN_NULL;
|
||||
for (ZyanI8 i = ZYCORE_MAXCHARS_HEX_32 - 1; i >= 0; --i)
|
||||
{
|
||||
const ZyanU8 v = (value >> i * 4) & 0x0F;
|
||||
if (!n)
|
||||
{
|
||||
if (!v)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (remaining <= (ZyanU8)i)
|
||||
{
|
||||
ZYAN_CHECK(ZyanStringResize(string, string->vector.size + i));
|
||||
}
|
||||
buffer = (char*)string->vector.data + len - 1;
|
||||
if (padding_length > i)
|
||||
{
|
||||
n = padding_length - i - 1;
|
||||
ZYAN_MEMSET(buffer, '0', n);
|
||||
}
|
||||
}
|
||||
ZYAN_ASSERT(buffer);
|
||||
if (uppercase)
|
||||
{
|
||||
buffer[n++] = "0123456789ABCDEF"[v];
|
||||
} else
|
||||
{
|
||||
buffer[n++] = "0123456789abcdef"[v];
|
||||
}
|
||||
}
|
||||
string->vector.size = len + n;
|
||||
ZYCORE_STRING_NULLTERMINATE(string);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
ZyanStatus ZyanStringAppendHexU64(ZyanString* string, ZyanU64 value, ZyanU8 padding_length,
|
||||
ZyanBool uppercase)
|
||||
{
|
||||
if (!string)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
const ZyanUSize len = string->vector.size;
|
||||
ZyanUSize remaining = string->vector.capacity - string->vector.size;
|
||||
|
||||
if (remaining < (ZyanUSize)padding_length)
|
||||
{
|
||||
ZYAN_CHECK(ZyanStringResize(string, len + padding_length - 1));
|
||||
remaining = padding_length;
|
||||
}
|
||||
|
||||
if (!value)
|
||||
{
|
||||
const ZyanU8 n = (padding_length ? padding_length : 1);
|
||||
|
||||
if (remaining < (ZyanUSize)n)
|
||||
{
|
||||
ZYAN_CHECK(ZyanStringResize(string, string->vector.size + n - 1));
|
||||
}
|
||||
|
||||
ZYAN_MEMSET((char*)string->vector.data + len - 1, '0', n);
|
||||
string->vector.size = len + n;
|
||||
ZYCORE_STRING_NULLTERMINATE(string);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanU8 n = 0;
|
||||
char* buffer = ZYAN_NULL;
|
||||
for (ZyanI8 i = ((value & 0xFFFFFFFF00000000) ?
|
||||
ZYCORE_MAXCHARS_HEX_64 : ZYCORE_MAXCHARS_HEX_32) - 1; i >= 0; --i)
|
||||
{
|
||||
const ZyanU8 v = (value >> i * 4) & 0x0F;
|
||||
if (!n)
|
||||
{
|
||||
if (!v)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (remaining <= (ZyanU8)i)
|
||||
{
|
||||
ZYAN_CHECK(ZyanStringResize(string, string->vector.size + i));
|
||||
}
|
||||
buffer = (char*)string->vector.data + len - 1;
|
||||
if (padding_length > i)
|
||||
{
|
||||
n = padding_length - i - 1;
|
||||
ZYAN_MEMSET(buffer, '0', n);
|
||||
}
|
||||
}
|
||||
ZYAN_ASSERT(buffer);
|
||||
if (uppercase)
|
||||
{
|
||||
buffer[n++] = "0123456789ABCDEF"[v];
|
||||
} else
|
||||
{
|
||||
buffer[n++] = "0123456789abcdef"[v];
|
||||
}
|
||||
}
|
||||
string->vector.size = len + n;
|
||||
ZYCORE_STRING_NULLTERMINATE(string);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Insertion */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
//ZyanStatus ZyanStringInsertFormat(ZyanString* string, ZyanUSize index, const char* format, ...)
|
||||
//{
|
||||
//
|
||||
//}
|
||||
//
|
||||
///* ---------------------------------------------------------------------------------------------- */
|
||||
//
|
||||
//ZyanStatus ZyanStringInsertDecU(ZyanString* string, ZyanUSize index, ZyanU64 value,
|
||||
// ZyanUSize padding_length)
|
||||
//{
|
||||
//
|
||||
//}
|
||||
//
|
||||
//ZyanStatus ZyanStringInsertDecS(ZyanString* string, ZyanUSize index, ZyanI64 value,
|
||||
// ZyanUSize padding_length, ZyanBool force_sign, const ZyanString* prefix)
|
||||
//{
|
||||
//
|
||||
//}
|
||||
//
|
||||
//ZyanStatus ZyanStringInsertHexU(ZyanString* string, ZyanUSize index, ZyanU64 value,
|
||||
// ZyanUSize padding_length, ZyanBool uppercase)
|
||||
//{
|
||||
//
|
||||
//}
|
||||
//
|
||||
//ZyanStatus ZyanStringInsertHexS(ZyanString* string, ZyanUSize index, ZyanI64 value,
|
||||
// ZyanUSize padding_length, ZyanBool uppercase, ZyanBool force_sign, const ZyanString* prefix)
|
||||
//{
|
||||
//
|
||||
//}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Appending */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef ZYAN_NO_LIBC
|
||||
|
||||
ZyanStatus ZyanStringAppendFormat(ZyanString* string, const char* format, ...)
|
||||
{
|
||||
if (!string || !format)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
ZyanVAList arglist;
|
||||
ZYAN_VA_START(arglist, format);
|
||||
|
||||
const ZyanUSize len = string->vector.size;
|
||||
|
||||
ZyanI32 w = ZYAN_VSNPRINTF((char*)string->vector.data + len - 1,
|
||||
string->vector.capacity - len + 1, format, arglist);
|
||||
if (w < 0)
|
||||
{
|
||||
ZYAN_VA_END(arglist);
|
||||
return ZYAN_STATUS_FAILED;
|
||||
}
|
||||
if (w <= (ZyanI32)(string->vector.capacity - len))
|
||||
{
|
||||
string->vector.size = len + w;
|
||||
|
||||
ZYAN_VA_END(arglist);
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// The remaining capacity was not sufficent to fit the formatted string. Trying to resize ..
|
||||
const ZyanStatus status = ZyanStringResize(string, string->vector.size + w - 1);
|
||||
if (!ZYAN_SUCCESS(status))
|
||||
{
|
||||
ZYAN_VA_END(arglist);
|
||||
return status;
|
||||
}
|
||||
|
||||
w = ZYAN_VSNPRINTF((char*)string->vector.data + len - 1,
|
||||
string->vector.capacity - string->vector.size + 1, format, arglist);
|
||||
if (w < 0)
|
||||
{
|
||||
ZYAN_VA_END(arglist);
|
||||
return ZYAN_STATUS_FAILED;
|
||||
}
|
||||
ZYAN_ASSERT(w <= (ZyanI32)(string->vector.capacity - string->vector.size));
|
||||
|
||||
ZYAN_VA_END(arglist);
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#endif // ZYAN_NO_LIBC
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanStringAppendDecU(ZyanString* string, ZyanU64 value, ZyanU8 padding_length)
|
||||
{
|
||||
#if defined(ZYAN_X64) || defined(ZYAN_AARCH64) || defined(ZYAN_PPC64) || defined(ZYAN_RISCV64) || defined(ZYAN_LOONGARCH)
|
||||
return ZyanStringAppendDecU64(string, value, padding_length);
|
||||
#else
|
||||
// Working with 64-bit values is slow on non 64-bit systems
|
||||
if (value & 0xFFFFFFFF00000000)
|
||||
{
|
||||
return ZyanStringAppendDecU64(string, value, padding_length);
|
||||
}
|
||||
return ZyanStringAppendDecU32(string, (ZyanU32)value, padding_length);
|
||||
#endif
|
||||
}
|
||||
|
||||
ZyanStatus ZyanStringAppendDecS(ZyanString* string, ZyanI64 value, ZyanU8 padding_length,
|
||||
ZyanBool force_sign, const ZyanStringView* prefix)
|
||||
{
|
||||
if (value < 0)
|
||||
{
|
||||
ZYAN_CHECK(ZyanStringAppend(string, &STR_SUB));
|
||||
if (prefix)
|
||||
{
|
||||
ZYAN_CHECK(ZyanStringAppend(string, prefix));
|
||||
}
|
||||
return ZyanStringAppendDecU(string, ZyanAbsI64(value), padding_length);
|
||||
}
|
||||
|
||||
if (force_sign)
|
||||
{
|
||||
ZYAN_ASSERT(value >= 0);
|
||||
ZYAN_CHECK(ZyanStringAppend(string, &STR_ADD));
|
||||
}
|
||||
|
||||
if (prefix)
|
||||
{
|
||||
ZYAN_CHECK(ZyanStringAppend(string, prefix));
|
||||
}
|
||||
return ZyanStringAppendDecU(string, value, padding_length);
|
||||
}
|
||||
|
||||
ZyanStatus ZyanStringAppendHexU(ZyanString* string, ZyanU64 value, ZyanU8 padding_length,
|
||||
ZyanBool uppercase)
|
||||
{
|
||||
#if defined(ZYAN_X64) || defined(ZYAN_AARCH64) || defined(ZYAN_PPC64) || defined(ZYAN_RISCV64) || defined(ZYAN_LOONGARCH)
|
||||
return ZyanStringAppendHexU64(string, value, padding_length, uppercase);
|
||||
#else
|
||||
// Working with 64-bit values is slow on non 64-bit systems
|
||||
if (value & 0xFFFFFFFF00000000)
|
||||
{
|
||||
return ZyanStringAppendHexU64(string, value, padding_length, uppercase);
|
||||
}
|
||||
return ZyanStringAppendHexU32(string, (ZyanU32)value, padding_length, uppercase);
|
||||
#endif
|
||||
}
|
||||
|
||||
ZyanStatus ZyanStringAppendHexS(ZyanString* string, ZyanI64 value, ZyanU8 padding_length,
|
||||
ZyanBool uppercase, ZyanBool force_sign, const ZyanStringView* prefix)
|
||||
{
|
||||
if (value < 0)
|
||||
{
|
||||
ZYAN_CHECK(ZyanStringAppend(string, &STR_SUB));
|
||||
if (prefix)
|
||||
{
|
||||
ZYAN_CHECK(ZyanStringAppend(string, prefix));
|
||||
}
|
||||
return ZyanStringAppendHexU(string, ZyanAbsI64(value), padding_length, uppercase);
|
||||
}
|
||||
|
||||
if (force_sign)
|
||||
{
|
||||
ZYAN_ASSERT(value >= 0);
|
||||
ZYAN_CHECK(ZyanStringAppend(string, &STR_ADD));
|
||||
}
|
||||
|
||||
if (prefix)
|
||||
{
|
||||
ZYAN_CHECK(ZyanStringAppend(string, prefix));
|
||||
}
|
||||
return ZyanStringAppendHexU(string, value, padding_length, uppercase);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
+673
@@ -0,0 +1,673 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zycore-C)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
#include <Zycore/LibC.h>
|
||||
#include <Zycore/List.h>
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Internal macros */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* Returns a pointer to the data of the given `node`.
|
||||
*
|
||||
* @param node A pointer to the `ZyanNodeData` struct.
|
||||
*
|
||||
* @return A pointer to the data of the given `node`.
|
||||
*/
|
||||
#define ZYCORE_LIST_GET_NODE_DATA(node) \
|
||||
((void*)(node + 1))
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Internal functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Helper functions */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Allocates memory for a new list node.
|
||||
*
|
||||
* @param list A pointer to the `ZyanList` instance.
|
||||
* @param node Receives a pointer to the new `ZyanListNode` struct.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
static ZyanStatus ZyanListAllocateNode(ZyanList* list, ZyanListNode** node)
|
||||
{
|
||||
ZYAN_ASSERT(list);
|
||||
ZYAN_ASSERT(node);
|
||||
|
||||
const ZyanBool is_dynamic = (list->allocator != ZYAN_NULL);
|
||||
if (is_dynamic)
|
||||
{
|
||||
ZYAN_ASSERT(list->allocator->allocate);
|
||||
ZYAN_CHECK(list->allocator->allocate(list->allocator, (void**)node,
|
||||
sizeof(ZyanListNode) + list->element_size, 1));
|
||||
} else
|
||||
{
|
||||
if (list->first_unused)
|
||||
{
|
||||
*node = list->first_unused;
|
||||
list->first_unused = (*node)->next;
|
||||
} else
|
||||
{
|
||||
const ZyanUSize size = list->size * (sizeof(ZyanListNode) + list->element_size);
|
||||
if (size + (sizeof(ZyanListNode) + list->element_size) > list->capacity)
|
||||
{
|
||||
return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
*node = (ZyanListNode*)((ZyanU8*)list->buffer + size);
|
||||
}
|
||||
}
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees memory of a node.
|
||||
*
|
||||
* @param list A pointer to the `ZyanList` instance.
|
||||
* @param node A pointer to the `ZyanListNode` struct.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
static ZyanStatus ZyanListDeallocateNode(ZyanList* list, ZyanListNode* node)
|
||||
{
|
||||
ZYAN_ASSERT(list);
|
||||
ZYAN_ASSERT(node);
|
||||
|
||||
const ZyanBool is_dynamic = (list->allocator != ZYAN_NULL);
|
||||
if (is_dynamic)
|
||||
{
|
||||
ZYAN_ASSERT(list->allocator->deallocate);
|
||||
ZYAN_CHECK(list->allocator->deallocate(list->allocator, (void*)node,
|
||||
sizeof(ZyanListNode) + list->element_size, 1));
|
||||
} else
|
||||
{
|
||||
node->next = list->first_unused;
|
||||
list->first_unused = node;
|
||||
}
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Constructor and destructor */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef ZYAN_NO_LIBC
|
||||
|
||||
ZYAN_REQUIRES_LIBC ZyanStatus ZyanListInit(ZyanList* list, ZyanUSize element_size,
|
||||
ZyanMemberProcedure destructor)
|
||||
{
|
||||
return ZyanListInitEx(list, element_size, destructor, ZyanAllocatorDefault());
|
||||
}
|
||||
|
||||
#endif // ZYAN_NO_LIBC
|
||||
|
||||
ZyanStatus ZyanListInitEx(ZyanList* list, ZyanUSize element_size, ZyanMemberProcedure destructor,
|
||||
ZyanAllocator* allocator)
|
||||
{
|
||||
if (!list || !element_size || !allocator)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
list->allocator = allocator;
|
||||
list->size = 0;
|
||||
list->element_size = element_size;
|
||||
list->destructor = destructor;
|
||||
list->head = ZYAN_NULL;
|
||||
list->tail = ZYAN_NULL;
|
||||
list->buffer = ZYAN_NULL;
|
||||
list->capacity = 0;
|
||||
list->first_unused = ZYAN_NULL;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanListInitCustomBuffer(ZyanList* list, ZyanUSize element_size,
|
||||
ZyanMemberProcedure destructor, void* buffer, ZyanUSize capacity)
|
||||
{
|
||||
if (!list || !element_size || !buffer || !capacity)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
list->allocator = ZYAN_NULL;
|
||||
list->size = 0;
|
||||
list->element_size = element_size;
|
||||
list->destructor = destructor;
|
||||
list->head = ZYAN_NULL;
|
||||
list->tail = ZYAN_NULL;
|
||||
list->buffer = buffer;
|
||||
list->capacity = capacity;
|
||||
list->first_unused = ZYAN_NULL;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanListDestroy(ZyanList* list)
|
||||
{
|
||||
if (!list)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
ZYAN_ASSERT(list->element_size);
|
||||
|
||||
const ZyanBool is_dynamic = (list->allocator != ZYAN_NULL);
|
||||
ZyanListNode* node = (is_dynamic || list->destructor) ? list->head : ZYAN_NULL;
|
||||
while (node)
|
||||
{
|
||||
if (list->destructor)
|
||||
{
|
||||
list->destructor(ZYCORE_LIST_GET_NODE_DATA(node));
|
||||
}
|
||||
|
||||
ZyanListNode* const next = node->next;
|
||||
|
||||
if (is_dynamic)
|
||||
{
|
||||
ZYAN_CHECK(list->allocator->deallocate(list->allocator, node,
|
||||
sizeof(ZyanListNode) + list->element_size, 1));
|
||||
}
|
||||
|
||||
node = next;
|
||||
}
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Duplication */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Item access */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanListGetHeadNode(const ZyanList* list, const ZyanListNode** node)
|
||||
{
|
||||
if (!list)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
*node = list->head;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanListGetTailNode(const ZyanList* list, const ZyanListNode** node)
|
||||
{
|
||||
if (!list)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
*node = list->tail;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanListGetPrevNode(const ZyanListNode** node)
|
||||
{
|
||||
if (!node || !*node)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
*node = (*node)->prev;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanListGetNextNode(const ZyanListNode** node)
|
||||
{
|
||||
if (!node || !*node)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
*node = (*node)->next;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
const void* ZyanListGetNodeData(const ZyanListNode* node)
|
||||
{
|
||||
if (!node)
|
||||
{
|
||||
return ZYAN_NULL;
|
||||
}
|
||||
|
||||
return (const void*)ZYCORE_LIST_GET_NODE_DATA(node);
|
||||
}
|
||||
|
||||
ZyanStatus ZyanListGetNodeDataEx(const ZyanListNode* node, const void** value)
|
||||
{
|
||||
if (!node)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
*value = (const void*)ZYCORE_LIST_GET_NODE_DATA(node);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void* ZyanListGetNodeDataMutable(const ZyanListNode* node)
|
||||
{
|
||||
if (!node)
|
||||
{
|
||||
return ZYAN_NULL;
|
||||
}
|
||||
|
||||
return ZYCORE_LIST_GET_NODE_DATA(node);
|
||||
}
|
||||
|
||||
ZyanStatus ZyanListGetNodeDataMutableEx(const ZyanListNode* node, void** value)
|
||||
{
|
||||
if (!node)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
*value = ZYCORE_LIST_GET_NODE_DATA(node);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanListSetNodeData(const ZyanList* list, const ZyanListNode* node, const void* value)
|
||||
{
|
||||
if (!list || !node || !value)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (list->destructor)
|
||||
{
|
||||
list->destructor(ZYCORE_LIST_GET_NODE_DATA(node));
|
||||
}
|
||||
|
||||
ZYAN_ASSERT(list->element_size);
|
||||
ZYAN_MEMCPY(ZYCORE_LIST_GET_NODE_DATA(node), value, list->element_size);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Insertion */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanListPushBack(ZyanList* list, const void* item)
|
||||
{
|
||||
if (!list || !item)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
ZyanListNode* node;
|
||||
ZYAN_CHECK(ZyanListAllocateNode(list, &node));
|
||||
node->prev = list->tail;
|
||||
node->next = ZYAN_NULL;
|
||||
|
||||
ZYAN_MEMCPY(ZYCORE_LIST_GET_NODE_DATA(node), item, list->element_size);
|
||||
|
||||
if (!list->head)
|
||||
{
|
||||
list->head = node;
|
||||
list->tail = node;
|
||||
} else
|
||||
{
|
||||
list->tail->next = node;
|
||||
list->tail = node;
|
||||
}
|
||||
++list->size;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanListPushFront(ZyanList* list, const void* item)
|
||||
{
|
||||
if (!list || !item)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
ZyanListNode* node;
|
||||
ZYAN_CHECK(ZyanListAllocateNode(list, &node));
|
||||
node->prev = ZYAN_NULL;
|
||||
node->next = list->head;
|
||||
|
||||
ZYAN_MEMCPY(ZYCORE_LIST_GET_NODE_DATA(node), item, list->element_size);
|
||||
|
||||
if (!list->head)
|
||||
{
|
||||
list->head = node;
|
||||
list->tail = node;
|
||||
} else
|
||||
{
|
||||
list->head->prev= node;
|
||||
list->head = node;
|
||||
}
|
||||
++list->size;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanListEmplaceBack(ZyanList* list, void** item, ZyanMemberFunction constructor)
|
||||
{
|
||||
if (!list || !item)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
ZyanListNode* node;
|
||||
ZYAN_CHECK(ZyanListAllocateNode(list, &node));
|
||||
node->prev = list->tail;
|
||||
node->next = ZYAN_NULL;
|
||||
|
||||
*item = ZYCORE_LIST_GET_NODE_DATA(node);
|
||||
if (constructor)
|
||||
{
|
||||
constructor(*item);
|
||||
}
|
||||
|
||||
if (!list->head)
|
||||
{
|
||||
list->head = node;
|
||||
list->tail = node;
|
||||
} else
|
||||
{
|
||||
list->tail->next = node;
|
||||
list->tail = node;
|
||||
}
|
||||
++list->size;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanListEmplaceFront(ZyanList* list, void** item, ZyanMemberFunction constructor)
|
||||
{
|
||||
if (!list || !item)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
ZyanListNode* node;
|
||||
ZYAN_CHECK(ZyanListAllocateNode(list, &node));
|
||||
node->prev = ZYAN_NULL;
|
||||
node->next = list->head;
|
||||
|
||||
*item = ZYCORE_LIST_GET_NODE_DATA(node);
|
||||
if (constructor)
|
||||
{
|
||||
constructor(*item);
|
||||
}
|
||||
|
||||
if (!list->head)
|
||||
{
|
||||
list->head = node;
|
||||
list->tail = node;
|
||||
} else
|
||||
{
|
||||
list->head->prev= node;
|
||||
list->head = node;
|
||||
}
|
||||
++list->size;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Deletion */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanListPopBack(ZyanList* list)
|
||||
{
|
||||
if (!list)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if (!list->tail)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
ZyanListNode* const node = list->tail;
|
||||
|
||||
if (list->destructor)
|
||||
{
|
||||
list->destructor(ZYCORE_LIST_GET_NODE_DATA(node));
|
||||
}
|
||||
|
||||
list->tail = node->prev;
|
||||
if (list->tail)
|
||||
{
|
||||
list->tail->next = ZYAN_NULL;
|
||||
}
|
||||
if (list->head == node)
|
||||
{
|
||||
list->head = list->tail;
|
||||
}
|
||||
--list->size;
|
||||
|
||||
return ZyanListDeallocateNode(list, node);
|
||||
}
|
||||
|
||||
ZyanStatus ZyanListPopFront(ZyanList* list)
|
||||
{
|
||||
if (!list)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if (!list->head)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
ZyanListNode* const node = list->head;
|
||||
|
||||
if (list->destructor)
|
||||
{
|
||||
list->destructor(ZYCORE_LIST_GET_NODE_DATA(node));
|
||||
}
|
||||
|
||||
list->head = node->next;
|
||||
if (list->head)
|
||||
{
|
||||
list->head->prev = ZYAN_NULL;
|
||||
}
|
||||
if (list->tail == node)
|
||||
{
|
||||
list->tail = list->head;
|
||||
}
|
||||
--list->size;
|
||||
|
||||
return ZyanListDeallocateNode(list, node);
|
||||
}
|
||||
|
||||
ZyanStatus ZyanListRemove(ZyanList* list, const ZyanListNode* node)
|
||||
{
|
||||
ZYAN_UNUSED(list);
|
||||
ZYAN_UNUSED(node);
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanListRemoveRange(ZyanList* list, const ZyanListNode* first, const ZyanListNode* last)
|
||||
{
|
||||
ZYAN_UNUSED(list);
|
||||
ZYAN_UNUSED(first);
|
||||
ZYAN_UNUSED(last);
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanListClear(ZyanList* list)
|
||||
{
|
||||
return ZyanListResizeEx(list, 0, ZYAN_NULL);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Searching */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Memory management */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanListResize(ZyanList* list, ZyanUSize size)
|
||||
{
|
||||
return ZyanListResizeEx(list, size, ZYAN_NULL);
|
||||
}
|
||||
|
||||
ZyanStatus ZyanListResizeEx(ZyanList* list, ZyanUSize size, const void* initializer)
|
||||
{
|
||||
if (!list)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if (size == list->size)
|
||||
{
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
const ZyanBool is_dynamic = (list->allocator != ZYAN_NULL);
|
||||
ZyanListNode* node = (is_dynamic || list->destructor) ? list->head : ZYAN_NULL;
|
||||
while (node)
|
||||
{
|
||||
if (list->destructor)
|
||||
{
|
||||
list->destructor(ZYCORE_LIST_GET_NODE_DATA(node));
|
||||
}
|
||||
|
||||
ZyanListNode* const next = node->next;
|
||||
|
||||
if (is_dynamic)
|
||||
{
|
||||
ZYAN_CHECK(list->allocator->deallocate(list->allocator, node,
|
||||
sizeof(ZyanListNode) + list->element_size, 1));
|
||||
}
|
||||
|
||||
node = next;
|
||||
}
|
||||
|
||||
list->size = 0;
|
||||
list->head = 0;
|
||||
list->tail = 0;
|
||||
list->first_unused = ZYAN_NULL;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (size > list->size)
|
||||
{
|
||||
ZyanListNode* node;
|
||||
for (ZyanUSize i = list->size; i < size; ++i)
|
||||
{
|
||||
ZYAN_CHECK(ZyanListAllocateNode(list, &node));
|
||||
node->prev = list->tail;
|
||||
node->next = ZYAN_NULL;
|
||||
|
||||
if (initializer)
|
||||
{
|
||||
ZYAN_MEMCPY(ZYCORE_LIST_GET_NODE_DATA(node), initializer, list->element_size);
|
||||
}
|
||||
|
||||
if (!list->head)
|
||||
{
|
||||
list->head = node;
|
||||
list->tail = node;
|
||||
} else
|
||||
{
|
||||
list->tail->next = node;
|
||||
list->tail = node;
|
||||
}
|
||||
|
||||
// `ZyanListAllocateNode` needs the list size
|
||||
++list->size;
|
||||
}
|
||||
} else
|
||||
{
|
||||
for (ZyanUSize i = size; i < list->size; ++i)
|
||||
{
|
||||
ZyanListNode* const node = list->tail;
|
||||
|
||||
if (list->destructor)
|
||||
{
|
||||
list->destructor(ZYCORE_LIST_GET_NODE_DATA(node));
|
||||
}
|
||||
|
||||
list->tail = node->prev;
|
||||
if (list->tail)
|
||||
{
|
||||
list->tail->next = ZYAN_NULL;
|
||||
}
|
||||
|
||||
ZYAN_CHECK(ZyanListDeallocateNode(list, node));
|
||||
}
|
||||
|
||||
list->size = size;
|
||||
}
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Information */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanListGetSize(const ZyanList* list, ZyanUSize* size)
|
||||
{
|
||||
if (!list)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
*size = list->size;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
+1098
File diff suppressed because it is too large
Load Diff
+846
@@ -0,0 +1,846 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zycore-C)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
#include <Zycore/LibC.h>
|
||||
#include <Zycore/Vector.h>
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Internal macros */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* Checks, if the passed vector should grow.
|
||||
*
|
||||
* @param size The desired size of the vector.
|
||||
* @param capacity The current capacity of the vector.
|
||||
*
|
||||
* @return `ZYAN_TRUE`, if the vector should grow or `ZYAN_FALSE`, if not.
|
||||
*/
|
||||
#define ZYCORE_VECTOR_SHOULD_GROW(size, capacity) \
|
||||
((size) > (capacity))
|
||||
|
||||
/**
|
||||
* Checks, if the passed vector should shrink.
|
||||
*
|
||||
* @param size The desired size of the vector.
|
||||
* @param capacity The current capacity of the vector.
|
||||
* @param threshold The shrink threshold.
|
||||
*
|
||||
* @return `ZYAN_TRUE`, if the vector should shrink or `ZYAN_FALSE`, if not.
|
||||
*/
|
||||
#define ZYCORE_VECTOR_SHOULD_SHRINK(size, capacity, threshold) \
|
||||
(((threshold) != 0) && ((size) * (threshold) < (capacity)))
|
||||
|
||||
/**
|
||||
* Returns the offset of the element at the given `index`.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param index The element index.
|
||||
*
|
||||
* @return The offset of the element at the given `index`.
|
||||
*/
|
||||
#define ZYCORE_VECTOR_OFFSET(vector, index) \
|
||||
((void*)((ZyanU8*)(vector)->data + ((index) * (vector)->element_size)))
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Internal functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Helper functions */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Reallocates the internal buffer of the vector.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param capacity The new capacity.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
static ZyanStatus ZyanVectorReallocate(ZyanVector* vector, ZyanUSize capacity)
|
||||
{
|
||||
ZYAN_ASSERT(vector);
|
||||
ZYAN_ASSERT(vector->capacity >= ZYAN_VECTOR_MIN_CAPACITY);
|
||||
ZYAN_ASSERT(vector->element_size);
|
||||
ZYAN_ASSERT(vector->data);
|
||||
|
||||
if (!vector->allocator)
|
||||
{
|
||||
if (vector->capacity < capacity)
|
||||
{
|
||||
return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
|
||||
}
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZYAN_ASSERT(vector->allocator);
|
||||
ZYAN_ASSERT(vector->allocator->reallocate);
|
||||
|
||||
if (capacity < ZYAN_VECTOR_MIN_CAPACITY)
|
||||
{
|
||||
if (vector->capacity > ZYAN_VECTOR_MIN_CAPACITY)
|
||||
{
|
||||
capacity = ZYAN_VECTOR_MIN_CAPACITY;
|
||||
} else
|
||||
{
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
vector->capacity = capacity;
|
||||
ZYAN_CHECK(vector->allocator->reallocate(vector->allocator, &vector->data,
|
||||
vector->element_size, vector->capacity));
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shifts all elements starting at the specified `index` by the amount of `count` to the left.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param index The start index.
|
||||
* @param count The amount of shift operations.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
static ZyanStatus ZyanVectorShiftLeft(ZyanVector* vector, ZyanUSize index, ZyanUSize count)
|
||||
{
|
||||
ZYAN_ASSERT(vector);
|
||||
ZYAN_ASSERT(vector->element_size);
|
||||
ZYAN_ASSERT(vector->data);
|
||||
ZYAN_ASSERT(count > 0);
|
||||
//ZYAN_ASSERT((ZyanISize)count - (ZyanISize)index + 1 >= 0);
|
||||
|
||||
const void* const source = ZYCORE_VECTOR_OFFSET(vector, index + count);
|
||||
void* const dest = ZYCORE_VECTOR_OFFSET(vector, index);
|
||||
const ZyanUSize size = (vector->size - index - count) * vector->element_size;
|
||||
ZYAN_MEMMOVE(dest, source, size);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shifts all elements starting at the specified `index` by the amount of `count` to the right.
|
||||
*
|
||||
* @param vector A pointer to the `ZyanVector` instance.
|
||||
* @param index The start index.
|
||||
* @param count The amount of shift operations.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
static ZyanStatus ZyanVectorShiftRight(ZyanVector* vector, ZyanUSize index, ZyanUSize count)
|
||||
{
|
||||
ZYAN_ASSERT(vector);
|
||||
ZYAN_ASSERT(vector->element_size);
|
||||
ZYAN_ASSERT(vector->data);
|
||||
ZYAN_ASSERT(count > 0);
|
||||
ZYAN_ASSERT(vector->size + count <= vector->capacity);
|
||||
|
||||
const void* const source = ZYCORE_VECTOR_OFFSET(vector, index);
|
||||
void* const dest = ZYCORE_VECTOR_OFFSET(vector, index + count);
|
||||
const ZyanUSize size = (vector->size - index) * vector->element_size;
|
||||
ZYAN_MEMMOVE(dest, source, size);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Constructor and destructor */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef ZYAN_NO_LIBC
|
||||
|
||||
ZyanStatus ZyanVectorInit(ZyanVector* vector, ZyanUSize element_size, ZyanUSize capacity,
|
||||
ZyanMemberProcedure destructor)
|
||||
{
|
||||
return ZyanVectorInitEx(vector, element_size, capacity, destructor, ZyanAllocatorDefault(),
|
||||
ZYAN_VECTOR_DEFAULT_GROWTH_FACTOR, ZYAN_VECTOR_DEFAULT_SHRINK_THRESHOLD);
|
||||
}
|
||||
|
||||
#endif // ZYAN_NO_LIBC
|
||||
|
||||
ZyanStatus ZyanVectorInitEx(ZyanVector* vector, ZyanUSize element_size, ZyanUSize capacity,
|
||||
ZyanMemberProcedure destructor, ZyanAllocator* allocator, ZyanU8 growth_factor,
|
||||
ZyanU8 shrink_threshold)
|
||||
{
|
||||
if (!vector || !element_size || !allocator || (growth_factor < 1))
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
ZYAN_ASSERT(allocator->allocate);
|
||||
|
||||
vector->allocator = allocator;
|
||||
vector->growth_factor = growth_factor;
|
||||
vector->shrink_threshold = shrink_threshold;
|
||||
vector->size = 0;
|
||||
vector->capacity = ZYAN_MAX(ZYAN_VECTOR_MIN_CAPACITY, capacity);
|
||||
vector->element_size = element_size;
|
||||
vector->destructor = destructor;
|
||||
vector->data = ZYAN_NULL;
|
||||
|
||||
return allocator->allocate(vector->allocator, &vector->data, vector->element_size,
|
||||
vector->capacity);
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorInitCustomBuffer(ZyanVector* vector, ZyanUSize element_size,
|
||||
void* buffer, ZyanUSize capacity, ZyanMemberProcedure destructor)
|
||||
{
|
||||
if (!vector || !element_size || !buffer || !capacity)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
vector->allocator = ZYAN_NULL;
|
||||
vector->growth_factor = 1;
|
||||
vector->shrink_threshold = 0;
|
||||
vector->size = 0;
|
||||
vector->capacity = capacity;
|
||||
vector->element_size = element_size;
|
||||
vector->destructor = destructor;
|
||||
vector->data = buffer;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorDestroy(ZyanVector* vector)
|
||||
{
|
||||
if (!vector)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
ZYAN_ASSERT(vector->element_size);
|
||||
ZYAN_ASSERT(vector->data);
|
||||
|
||||
if (vector->destructor)
|
||||
{
|
||||
for (ZyanUSize i = 0; i < vector->size; ++i)
|
||||
{
|
||||
vector->destructor(ZYCORE_VECTOR_OFFSET(vector, i));
|
||||
}
|
||||
}
|
||||
|
||||
if (vector->allocator && vector->capacity)
|
||||
{
|
||||
ZYAN_ASSERT(vector->allocator->deallocate);
|
||||
ZYAN_CHECK(vector->allocator->deallocate(vector->allocator, vector->data,
|
||||
vector->element_size, vector->capacity));
|
||||
}
|
||||
|
||||
vector->data = ZYAN_NULL;
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Duplication */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef ZYAN_NO_LIBC
|
||||
|
||||
ZyanStatus ZyanVectorDuplicate(ZyanVector* destination, const ZyanVector* source,
|
||||
ZyanUSize capacity)
|
||||
{
|
||||
return ZyanVectorDuplicateEx(destination, source, capacity, ZyanAllocatorDefault(),
|
||||
ZYAN_VECTOR_DEFAULT_GROWTH_FACTOR, ZYAN_VECTOR_DEFAULT_SHRINK_THRESHOLD);
|
||||
}
|
||||
|
||||
#endif // ZYAN_NO_LIBC
|
||||
|
||||
ZyanStatus ZyanVectorDuplicateEx(ZyanVector* destination, const ZyanVector* source,
|
||||
ZyanUSize capacity, ZyanAllocator* allocator, ZyanU8 growth_factor, ZyanU8 shrink_threshold)
|
||||
{
|
||||
if (!source)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
const ZyanUSize len = source->size;
|
||||
|
||||
capacity = ZYAN_MAX(capacity, len);
|
||||
ZYAN_CHECK(ZyanVectorInitEx(destination, source->element_size, capacity, source->destructor,
|
||||
allocator, growth_factor, shrink_threshold));
|
||||
ZYAN_ASSERT(destination->capacity >= len);
|
||||
|
||||
ZYAN_MEMCPY(destination->data, source->data, len * source->element_size);
|
||||
destination->size = len;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorDuplicateCustomBuffer(ZyanVector* destination, const ZyanVector* source,
|
||||
void* buffer, ZyanUSize capacity)
|
||||
{
|
||||
if (!source)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
const ZyanUSize len = source->size;
|
||||
|
||||
if (capacity < len)
|
||||
{
|
||||
return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
ZYAN_CHECK(ZyanVectorInitCustomBuffer(destination, source->element_size, buffer, capacity,
|
||||
source->destructor));
|
||||
ZYAN_ASSERT(destination->capacity >= len);
|
||||
|
||||
ZYAN_MEMCPY(destination->data, source->data, len * source->element_size);
|
||||
destination->size = len;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Element access */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
const void* ZyanVectorGet(const ZyanVector* vector, ZyanUSize index)
|
||||
{
|
||||
if (!vector || (index >= vector->size))
|
||||
{
|
||||
return ZYAN_NULL;
|
||||
}
|
||||
|
||||
ZYAN_ASSERT(vector->element_size);
|
||||
ZYAN_ASSERT(vector->data);
|
||||
|
||||
return ZYCORE_VECTOR_OFFSET(vector, index);
|
||||
}
|
||||
|
||||
void* ZyanVectorGetMutable(const ZyanVector* vector, ZyanUSize index)
|
||||
{
|
||||
if (!vector || (index >= vector->size))
|
||||
{
|
||||
return ZYAN_NULL;
|
||||
}
|
||||
|
||||
ZYAN_ASSERT(vector->element_size);
|
||||
ZYAN_ASSERT(vector->data);
|
||||
|
||||
return ZYCORE_VECTOR_OFFSET(vector, index);
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorGetPointer(const ZyanVector* vector, ZyanUSize index, const void** value)
|
||||
{
|
||||
if (!vector || !value)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if (index >= vector->size)
|
||||
{
|
||||
return ZYAN_STATUS_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
ZYAN_ASSERT(vector->element_size);
|
||||
ZYAN_ASSERT(vector->data);
|
||||
|
||||
*value = (const void*)ZYCORE_VECTOR_OFFSET(vector, index);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorGetPointerMutable(const ZyanVector* vector, ZyanUSize index, void** value)
|
||||
{
|
||||
if (!vector || !value)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if (index >= vector->size)
|
||||
{
|
||||
return ZYAN_STATUS_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
ZYAN_ASSERT(vector->element_size);
|
||||
ZYAN_ASSERT(vector->data);
|
||||
|
||||
*value = ZYCORE_VECTOR_OFFSET(vector, index);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorSet(ZyanVector* vector, ZyanUSize index, const void* value)
|
||||
{
|
||||
if (!vector || !value)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if (index >= vector->size)
|
||||
{
|
||||
return ZYAN_STATUS_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
ZYAN_ASSERT(vector->element_size);
|
||||
ZYAN_ASSERT(vector->data);
|
||||
|
||||
void* const offset = ZYCORE_VECTOR_OFFSET(vector, index);
|
||||
if (vector->destructor)
|
||||
{
|
||||
vector->destructor(offset);
|
||||
}
|
||||
ZYAN_MEMCPY(offset, value, vector->element_size);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Insertion */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanVectorPushBack(ZyanVector* vector, const void* element)
|
||||
{
|
||||
if (!vector || !element)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
ZYAN_ASSERT(vector->element_size);
|
||||
ZYAN_ASSERT(vector->data);
|
||||
|
||||
if (ZYCORE_VECTOR_SHOULD_GROW(vector->size + 1, vector->capacity))
|
||||
{
|
||||
ZYAN_CHECK(ZyanVectorReallocate(vector,
|
||||
ZYAN_MAX(1, (ZyanUSize)((vector->size + 1) * vector->growth_factor))));
|
||||
}
|
||||
|
||||
void* const offset = ZYCORE_VECTOR_OFFSET(vector, vector->size);
|
||||
ZYAN_MEMCPY(offset, element, vector->element_size);
|
||||
|
||||
++vector->size;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorInsert(ZyanVector* vector, ZyanUSize index, const void* element)
|
||||
{
|
||||
return ZyanVectorInsertRange(vector, index, element, 1);
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorInsertRange(ZyanVector* vector, ZyanUSize index, const void* elements,
|
||||
ZyanUSize count)
|
||||
{
|
||||
if (!vector || !elements || !count)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if (index > vector->size)
|
||||
{
|
||||
return ZYAN_STATUS_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
ZYAN_ASSERT(vector->element_size);
|
||||
ZYAN_ASSERT(vector->data);
|
||||
|
||||
if (ZYCORE_VECTOR_SHOULD_GROW(vector->size + count, vector->capacity))
|
||||
{
|
||||
ZYAN_CHECK(ZyanVectorReallocate(vector,
|
||||
ZYAN_MAX(1, (ZyanUSize)((vector->size + count) * vector->growth_factor))));
|
||||
}
|
||||
|
||||
if (index < vector->size)
|
||||
{
|
||||
ZYAN_CHECK(ZyanVectorShiftRight(vector, index, count));
|
||||
}
|
||||
|
||||
void* const offset = ZYCORE_VECTOR_OFFSET(vector, index);
|
||||
ZYAN_MEMCPY(offset, elements, count * vector->element_size);
|
||||
vector->size += count;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorEmplace(ZyanVector* vector, void** element, ZyanMemberFunction constructor)
|
||||
{
|
||||
if (!vector)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return ZyanVectorEmplaceEx(vector, vector->size, element, constructor);
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorEmplaceEx(ZyanVector* vector, ZyanUSize index, void** element,
|
||||
ZyanMemberFunction constructor)
|
||||
{
|
||||
if (!vector)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if (index > vector->size)
|
||||
{
|
||||
return ZYAN_STATUS_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
ZYAN_ASSERT(vector->element_size);
|
||||
ZYAN_ASSERT(vector->data);
|
||||
|
||||
if (ZYCORE_VECTOR_SHOULD_GROW(vector->size + 1, vector->capacity))
|
||||
{
|
||||
ZYAN_CHECK(ZyanVectorReallocate(vector,
|
||||
ZYAN_MAX(1, (ZyanUSize)((vector->size + 1) * vector->growth_factor))));
|
||||
}
|
||||
|
||||
if (index < vector->size)
|
||||
{
|
||||
ZYAN_CHECK(ZyanVectorShiftRight(vector, index, 1));
|
||||
}
|
||||
|
||||
*element = ZYCORE_VECTOR_OFFSET(vector, index);
|
||||
if (constructor)
|
||||
{
|
||||
ZYAN_CHECK(constructor(*element));
|
||||
}
|
||||
|
||||
++vector->size;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Utils */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanVectorSwapElements(ZyanVector* vector, ZyanUSize index_first, ZyanUSize index_second)
|
||||
{
|
||||
if (!vector)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if ((index_first >= vector->size) || (index_second >= vector->size))
|
||||
{
|
||||
return ZYAN_STATUS_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
if (vector->size == vector->capacity)
|
||||
{
|
||||
return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
ZYAN_ASSERT(vector->element_size);
|
||||
ZYAN_ASSERT(vector->data);
|
||||
|
||||
ZyanU64* const t = ZYCORE_VECTOR_OFFSET(vector, vector->size);
|
||||
ZyanU64* const a = ZYCORE_VECTOR_OFFSET(vector, index_first);
|
||||
ZyanU64* const b = ZYCORE_VECTOR_OFFSET(vector, index_second);
|
||||
ZYAN_MEMCPY(t, a, vector->element_size);
|
||||
ZYAN_MEMCPY(a, b, vector->element_size);
|
||||
ZYAN_MEMCPY(b, t, vector->element_size);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Deletion */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanVectorDelete(ZyanVector* vector, ZyanUSize index)
|
||||
{
|
||||
return ZyanVectorDeleteRange(vector, index, 1);
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorDeleteRange(ZyanVector* vector, ZyanUSize index, ZyanUSize count)
|
||||
{
|
||||
if (!vector || !count)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if (index + count > vector->size)
|
||||
{
|
||||
return ZYAN_STATUS_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
if (vector->destructor)
|
||||
{
|
||||
for (ZyanUSize i = index; i < index + count; ++i)
|
||||
{
|
||||
vector->destructor(ZYCORE_VECTOR_OFFSET(vector, i));
|
||||
}
|
||||
}
|
||||
|
||||
if (index + count < vector->size)
|
||||
{
|
||||
ZYAN_CHECK(ZyanVectorShiftLeft(vector, index, count));
|
||||
}
|
||||
|
||||
vector->size -= count;
|
||||
if (ZYCORE_VECTOR_SHOULD_SHRINK(vector->size, vector->capacity, vector->shrink_threshold))
|
||||
{
|
||||
return ZyanVectorReallocate(vector,
|
||||
ZYAN_MAX(1, (ZyanUSize)(vector->size * vector->growth_factor)));
|
||||
}
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorPopBack(ZyanVector* vector)
|
||||
{
|
||||
if (!vector)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if (vector->size == 0)
|
||||
{
|
||||
return ZYAN_STATUS_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
if (vector->destructor)
|
||||
{
|
||||
vector->destructor(ZYCORE_VECTOR_OFFSET(vector, vector->size - 1));
|
||||
}
|
||||
|
||||
--vector->size;
|
||||
if (ZYCORE_VECTOR_SHOULD_SHRINK(vector->size, vector->capacity, vector->shrink_threshold))
|
||||
{
|
||||
return ZyanVectorReallocate(vector,
|
||||
ZYAN_MAX(1, (ZyanUSize)(vector->size * vector->growth_factor)));
|
||||
}
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorClear(ZyanVector* vector)
|
||||
{
|
||||
return ZyanVectorResizeEx(vector, 0, ZYAN_NULL);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Searching */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanVectorFind(const ZyanVector* vector, const void* element, ZyanISize* found_index,
|
||||
ZyanEqualityComparison comparison)
|
||||
{
|
||||
if (!vector)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return ZyanVectorFindEx(vector, element, found_index, comparison, 0, vector->size);
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorFindEx(const ZyanVector* vector, const void* element, ZyanISize* found_index,
|
||||
ZyanEqualityComparison comparison, ZyanUSize index, ZyanUSize count)
|
||||
{
|
||||
if (!vector)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if ((index + count > vector->size) || (index == vector->size))
|
||||
{
|
||||
return ZYAN_STATUS_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
if (!count)
|
||||
{
|
||||
*found_index = -1;
|
||||
return ZYAN_STATUS_FALSE;
|
||||
}
|
||||
|
||||
ZYAN_ASSERT(vector->element_size);
|
||||
ZYAN_ASSERT(vector->data);
|
||||
|
||||
for (ZyanUSize i = index; i < index + count; ++i)
|
||||
{
|
||||
if (comparison(ZYCORE_VECTOR_OFFSET(vector, i), element))
|
||||
{
|
||||
*found_index = i;
|
||||
return ZYAN_STATUS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
*found_index = -1;
|
||||
return ZYAN_STATUS_FALSE;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorBinarySearch(const ZyanVector* vector, const void* element,
|
||||
ZyanUSize* found_index, ZyanComparison comparison)
|
||||
{
|
||||
if (!vector)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return ZyanVectorBinarySearchEx(vector, element, found_index, comparison, 0, vector->size);
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorBinarySearchEx(const ZyanVector* vector, const void* element,
|
||||
ZyanUSize* found_index, ZyanComparison comparison, ZyanUSize index, ZyanUSize count)
|
||||
{
|
||||
if (!vector)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if (((index >= vector->size) && (count > 0)) || (index + count > vector->size))
|
||||
{
|
||||
return ZYAN_STATUS_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
if (!count)
|
||||
{
|
||||
*found_index = index;
|
||||
return ZYAN_STATUS_FALSE;
|
||||
}
|
||||
|
||||
ZYAN_ASSERT(vector->element_size);
|
||||
ZYAN_ASSERT(vector->data);
|
||||
|
||||
ZyanStatus status = ZYAN_STATUS_FALSE;
|
||||
ZyanISize l = index;
|
||||
ZyanISize h = index + count - 1;
|
||||
while (l <= h)
|
||||
{
|
||||
const ZyanUSize mid = l + ((h - l) >> 1);
|
||||
const ZyanI32 cmp = comparison(ZYCORE_VECTOR_OFFSET(vector, mid), element);
|
||||
if (cmp < 0)
|
||||
{
|
||||
l = mid + 1;
|
||||
} else
|
||||
{
|
||||
h = mid - 1;
|
||||
if (cmp == 0)
|
||||
{
|
||||
status = ZYAN_STATUS_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*found_index = l;
|
||||
return status;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Memory management */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanVectorResize(ZyanVector* vector, ZyanUSize size)
|
||||
{
|
||||
return ZyanVectorResizeEx(vector, size, ZYAN_NULL);
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorResizeEx(ZyanVector* vector, ZyanUSize size, const void* initializer)
|
||||
{
|
||||
if (!vector)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if (size == vector->size)
|
||||
{
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (vector->destructor && (size < vector->size))
|
||||
{
|
||||
for (ZyanUSize i = size; i < vector->size; ++i)
|
||||
{
|
||||
vector->destructor(ZYCORE_VECTOR_OFFSET(vector, i));
|
||||
}
|
||||
}
|
||||
|
||||
if (ZYCORE_VECTOR_SHOULD_GROW(size, vector->capacity) ||
|
||||
ZYCORE_VECTOR_SHOULD_SHRINK(size, vector->capacity, vector->shrink_threshold))
|
||||
{
|
||||
ZYAN_ASSERT(vector->growth_factor >= 1);
|
||||
ZYAN_CHECK(ZyanVectorReallocate(vector, (ZyanUSize)(size * vector->growth_factor)));
|
||||
}
|
||||
|
||||
if (initializer && (size > vector->size))
|
||||
{
|
||||
for (ZyanUSize i = vector->size; i < size; ++i)
|
||||
{
|
||||
ZYAN_MEMCPY(ZYCORE_VECTOR_OFFSET(vector, i), initializer, vector->element_size);
|
||||
}
|
||||
}
|
||||
|
||||
vector->size = size;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorReserve(ZyanVector* vector, ZyanUSize capacity)
|
||||
{
|
||||
if (!vector)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (capacity > vector->capacity)
|
||||
{
|
||||
ZYAN_CHECK(ZyanVectorReallocate(vector, capacity));
|
||||
}
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorShrinkToFit(ZyanVector* vector)
|
||||
{
|
||||
if (!vector)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return ZyanVectorReallocate(vector, vector->size);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Information */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZyanVectorGetCapacity(const ZyanVector* vector, ZyanUSize* capacity)
|
||||
{
|
||||
if (!vector)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
*capacity = vector->capacity;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ZyanStatus ZyanVectorGetSize(const ZyanVector* vector, ZyanUSize* size)
|
||||
{
|
||||
if (!vector)
|
||||
{
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
*size = vector->size;
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
@@ -0,0 +1,38 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Core Library (Zycore-C)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
#include <Zycore/Zycore.h>
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
ZyanU64 ZycoreGetVersion(void)
|
||||
{
|
||||
return ZYCORE_VERSION;
|
||||
}
|
||||
|
||||
/* ============================================================================================== */
|
||||
+320
@@ -0,0 +1,320 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Disassembler Library (Zydis)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Functions for decoding instructions.
|
||||
*/
|
||||
|
||||
#ifndef ZYDIS_DECODER_H
|
||||
#define ZYDIS_DECODER_H
|
||||
|
||||
#include <Zycore/Types.h>
|
||||
#include <Zycore/Defines.h>
|
||||
#include <Zydis/DecoderTypes.h>
|
||||
#include <Zydis/Status.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Enums and types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Decoder mode */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisDecoderMode` enum.
|
||||
*/
|
||||
typedef enum ZydisDecoderMode_
|
||||
{
|
||||
/**
|
||||
* Enables minimal instruction decoding without semantic analysis.
|
||||
*
|
||||
* This mode provides access to the mnemonic, the instruction-length, the effective
|
||||
* operand-size, the effective address-width, some attributes (e.g. `ZYDIS_ATTRIB_IS_RELATIVE`)
|
||||
* and all of the information in the `raw` field of the `ZydisDecodedInstruction` struct.
|
||||
*
|
||||
* Operands, most attributes and other specific information (like `AVX` info) are not
|
||||
* accessible in this mode.
|
||||
*
|
||||
* This mode is NOT enabled by default.
|
||||
*/
|
||||
ZYDIS_DECODER_MODE_MINIMAL,
|
||||
/**
|
||||
* Enables the `AMD`-branch mode.
|
||||
*
|
||||
* Intel ignores the operand-size override-prefix (`0x66`) for all branches with 32-bit
|
||||
* immediates and forces the operand-size of the instruction to 64-bit in 64-bit mode.
|
||||
* In `AMD`-branch mode `0x66` is not ignored and changes the operand-size and the size of the
|
||||
* immediate to 16-bit.
|
||||
*
|
||||
* This mode is NOT enabled by default.
|
||||
*/
|
||||
ZYDIS_DECODER_MODE_AMD_BRANCHES,
|
||||
/**
|
||||
* Enables `KNC` compatibility-mode.
|
||||
*
|
||||
* `KNC` and `KNL+` chips are sharing opcodes and encodings for some mask-related instructions.
|
||||
* Enable this mode to use the old `KNC` specifications (different mnemonics, operands, ..).
|
||||
*
|
||||
* This mode is NOT enabled by default.
|
||||
*/
|
||||
ZYDIS_DECODER_MODE_KNC,
|
||||
/**
|
||||
* Enables the `MPX` mode.
|
||||
*
|
||||
* The `MPX` isa-extension reuses (overrides) some of the widenop instruction opcodes.
|
||||
*
|
||||
* This mode is enabled by default.
|
||||
*/
|
||||
ZYDIS_DECODER_MODE_MPX,
|
||||
/**
|
||||
* Enables the `CET` mode.
|
||||
*
|
||||
* The `CET` isa-extension reuses (overrides) some of the widenop instruction opcodes.
|
||||
*
|
||||
* This mode is enabled by default.
|
||||
*/
|
||||
ZYDIS_DECODER_MODE_CET,
|
||||
/**
|
||||
* Enables the `LZCNT` mode.
|
||||
*
|
||||
* The `LZCNT` isa-extension reuses (overrides) some of the widenop instruction opcodes.
|
||||
*
|
||||
* This mode is enabled by default.
|
||||
*/
|
||||
ZYDIS_DECODER_MODE_LZCNT,
|
||||
/**
|
||||
* Enables the `TZCNT` mode.
|
||||
*
|
||||
* The `TZCNT` isa-extension reuses (overrides) some of the widenop instruction opcodes.
|
||||
*
|
||||
* This mode is enabled by default.
|
||||
*/
|
||||
ZYDIS_DECODER_MODE_TZCNT,
|
||||
/**
|
||||
* Enables the `WBNOINVD` mode.
|
||||
*
|
||||
* The `WBINVD` instruction is interpreted as `WBNOINVD` on ICL chips, if a `F3` prefix is
|
||||
* used.
|
||||
*
|
||||
* This mode is disabled by default.
|
||||
*/
|
||||
ZYDIS_DECODER_MODE_WBNOINVD,
|
||||
/**
|
||||
* Enables the `CLDEMOTE` mode.
|
||||
*
|
||||
* The `CLDEMOTE` isa-extension reuses (overrides) some of the widenop instruction opcodes.
|
||||
*
|
||||
* This mode is enabled by default.
|
||||
*/
|
||||
ZYDIS_DECODER_MODE_CLDEMOTE,
|
||||
/**
|
||||
* Enables the `IPREFETCH` mode.
|
||||
*
|
||||
* The `IPREFETCH` isa-extension reuses (overrides) some of the widenop instruction opcodes.
|
||||
*
|
||||
* This mode is enabled by default.
|
||||
*/
|
||||
ZYDIS_DECODER_MODE_IPREFETCH,
|
||||
/**
|
||||
* Enables the `UD0` compatibility mode.
|
||||
*
|
||||
* Some processors decode the `UD0` instruction without a ModR/M byte. Enable this decoder mode
|
||||
* to mimic this behavior.
|
||||
*
|
||||
* This mode is disabled by default.
|
||||
*/
|
||||
ZYDIS_DECODER_MODE_UD0_COMPAT,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_DECODER_MODE_MAX_VALUE = ZYDIS_DECODER_MODE_UD0_COMPAT,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_DECODER_MODE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_DECODER_MODE_MAX_VALUE)
|
||||
} ZydisDecoderMode;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Decoder struct */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisDecoder` struct.
|
||||
*
|
||||
* All fields in this struct should be considered as "private". Any changes may lead to unexpected
|
||||
* behavior.
|
||||
*/
|
||||
typedef struct ZydisDecoder_
|
||||
{
|
||||
/**
|
||||
* The machine mode.
|
||||
*/
|
||||
ZydisMachineMode machine_mode;
|
||||
/**
|
||||
* The stack width.
|
||||
*/
|
||||
ZydisStackWidth stack_width;
|
||||
/**
|
||||
* The decoder mode bitmap.
|
||||
*/
|
||||
ZyanU32 decoder_mode;
|
||||
} ZydisDecoder;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* @addtogroup decoder Decoder
|
||||
* Functions allowing decoding of instruction bytes to a machine interpretable struct.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Initializes the given `ZydisDecoder` instance.
|
||||
*
|
||||
* @param decoder A pointer to the `ZydisDecoder` instance.
|
||||
* @param machine_mode The machine mode.
|
||||
* @param stack_width The stack width.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYDIS_EXPORT ZyanStatus ZydisDecoderInit(ZydisDecoder* decoder, ZydisMachineMode machine_mode,
|
||||
ZydisStackWidth stack_width);
|
||||
|
||||
/**
|
||||
* Enables or disables the specified decoder-mode.
|
||||
*
|
||||
* @param decoder A pointer to the `ZydisDecoder` instance.
|
||||
* @param mode The decoder mode.
|
||||
* @param enabled `ZYAN_TRUE` to enable, or `ZYAN_FALSE` to disable the specified decoder-mode.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYDIS_EXPORT ZyanStatus ZydisDecoderEnableMode(ZydisDecoder* decoder, ZydisDecoderMode mode,
|
||||
ZyanBool enabled);
|
||||
|
||||
/**
|
||||
* Decodes the instruction in the given input `buffer` and returns all details (e.g. operands).
|
||||
*
|
||||
* @param decoder A pointer to the `ZydisDecoder` instance.
|
||||
* @param buffer A pointer to the input buffer.
|
||||
* @param length The length of the input buffer. Note that this can be bigger than the
|
||||
* actual size of the instruction -- you don't have to know the size up
|
||||
* front. This length is merely used to prevent Zydis from doing
|
||||
* out-of-bounds reads on your buffer.
|
||||
* @param instruction A pointer to the `ZydisDecodedInstruction` struct receiving the details
|
||||
* about the decoded instruction.
|
||||
* @param operands A pointer to an array with `ZYDIS_MAX_OPERAND_COUNT` entries that
|
||||
* receives the decoded operands. The number of operands decoded is
|
||||
* determined by the `instruction.operand_count` field. Excess entries are
|
||||
* zeroed.
|
||||
*
|
||||
* This is a convenience function that combines the following functions into one call:
|
||||
*
|
||||
* - `ZydisDecoderDecodeInstruction`
|
||||
* - `ZydisDecoderDecodeOperands`
|
||||
*
|
||||
* Please refer to `ZydisDecoderDecodeInstruction` if operand decoding is not required or should
|
||||
* be done separately (`ZydisDecoderDecodeOperands`).
|
||||
*
|
||||
* This function is not available in MINIMAL_MODE.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYDIS_EXPORT ZyanStatus ZydisDecoderDecodeFull(const ZydisDecoder* decoder,
|
||||
const void* buffer, ZyanUSize length, ZydisDecodedInstruction* instruction,
|
||||
ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT]);
|
||||
|
||||
/**
|
||||
* Decodes the instruction in the given input `buffer`.
|
||||
*
|
||||
* @param decoder A pointer to the `ZydisDecoder` instance.
|
||||
* @param context A pointer to a decoder context struct which is required for further
|
||||
* decoding (e.g. operand decoding using `ZydisDecoderDecodeOperands`) or
|
||||
* `ZYAN_NULL` if not needed.
|
||||
* @param buffer A pointer to the input buffer.
|
||||
* @param length The length of the input buffer. Note that this can be bigger than the
|
||||
* actual size of the instruction -- you don't have to know the size up
|
||||
* front. This length is merely used to prevent Zydis from doing
|
||||
* out-of-bounds reads on your buffer.
|
||||
* @param instruction A pointer to the `ZydisDecodedInstruction` struct, that receives the
|
||||
* details about the decoded instruction.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYDIS_EXPORT ZyanStatus ZydisDecoderDecodeInstruction(const ZydisDecoder* decoder,
|
||||
ZydisDecoderContext* context, const void* buffer, ZyanUSize length,
|
||||
ZydisDecodedInstruction* instruction);
|
||||
|
||||
/**
|
||||
* Decodes the instruction operands.
|
||||
*
|
||||
* @param decoder A pointer to the `ZydisDecoder` instance.
|
||||
* @param context A pointer to the `ZydisDecoderContext` struct.
|
||||
* @param instruction A pointer to the `ZydisDecodedInstruction` struct.
|
||||
* @param operands The array that receives the decoded operands.
|
||||
* Refer to `ZYDIS_MAX_OPERAND_COUNT` or `ZYDIS_MAX_OPERAND_COUNT_VISIBLE`
|
||||
* when allocating space for the array to ensure that the buffer size is
|
||||
* sufficient to always fit all instruction operands.
|
||||
* Refer to `instruction.operand_count` or
|
||||
* `instruction.operand_count_visible' when allocating space for the array
|
||||
* to ensure that the buffer size is sufficient to fit all operands of
|
||||
* the given instruction.
|
||||
* @param operand_count The length of the `operands` array.
|
||||
* This argument as well limits the maximum amount of operands to decode.
|
||||
* If this value is `0`, no operands will be decoded and `ZYAN_NULL` will
|
||||
* be accepted for the `operands` argument.
|
||||
*
|
||||
* This function fails, if `operand_count` is larger than the total number of operands for the
|
||||
* given instruction (`instruction.operand_count`).
|
||||
*
|
||||
* This function is not available in MINIMAL_MODE.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYDIS_EXPORT ZyanStatus ZydisDecoderDecodeOperands(const ZydisDecoder* decoder,
|
||||
const ZydisDecoderContext* context, const ZydisDecodedInstruction* instruction,
|
||||
ZydisDecodedOperand* operands, ZyanU8 operand_count);
|
||||
|
||||
/** @} */
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZYDIS_DECODER_H */
|
||||
+1447
File diff suppressed because it is too large
Load Diff
+76
@@ -0,0 +1,76 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Disassembler Library (Zydis)
|
||||
|
||||
Original Author : Joel Hoener
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Import/export defines for MSVC builds.
|
||||
*/
|
||||
|
||||
#ifndef ZYDIS_DEFINES_H
|
||||
#define ZYDIS_DEFINES_H
|
||||
|
||||
#include <Zycore/Defines.h>
|
||||
|
||||
// This is a cut-down version of what CMake's `GenerateExportHeader` would usually generate. To
|
||||
// simplify builds without CMake, we define these things manually instead of relying on CMake
|
||||
// to generate the header.
|
||||
//
|
||||
// For static builds, our CMakeList will define `ZYDIS_STATIC_BUILD`. For shared library builds,
|
||||
// our CMake will define `ZYDIS_SHOULD_EXPORT` depending on whether the target is being imported or
|
||||
// exported. If CMake isn't used, users can manually define these to fit their use-case.
|
||||
|
||||
// Backward compatibility: CMake would previously generate these variables names. However, because
|
||||
// they have pretty cryptic names, we renamed them when we got rid of `GenerateExportHeader`. For
|
||||
// backward compatibility for users that don't use CMake and previously manually defined these, we
|
||||
// translate the old defines here and print a warning.
|
||||
#if defined(ZYDIS_STATIC_DEFINE)
|
||||
# pragma message("ZYDIS_STATIC_DEFINE was renamed to ZYDIS_STATIC_BUILD.")
|
||||
# define ZYDIS_STATIC_BUILD
|
||||
#endif
|
||||
#if defined(Zydis_EXPORTS)
|
||||
# pragma message("Zydis_EXPORTS was renamed to ZYDIS_SHOULD_EXPORT.")
|
||||
# define ZYDIS_SHOULD_EXPORT
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Symbol is exported in shared library builds.
|
||||
*/
|
||||
#if defined(ZYDIS_STATIC_BUILD)
|
||||
# define ZYDIS_EXPORT
|
||||
#else
|
||||
# if defined(ZYDIS_SHOULD_EXPORT)
|
||||
# define ZYDIS_EXPORT ZYAN_DLLEXPORT
|
||||
# else
|
||||
# define ZYDIS_EXPORT ZYAN_DLLIMPORT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Symbol is not exported and for internal use only.
|
||||
*/
|
||||
#define ZYDIS_NO_EXPORT
|
||||
|
||||
#endif // ZYDIS_DEFINES_H
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Disassembler Library (Zydis)
|
||||
|
||||
Original Author : Joel Hoener
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* All-in-one convenience function providing the simplest possible way to use Zydis.
|
||||
*/
|
||||
|
||||
#ifndef ZYDIS_DISASSEMBLER_H
|
||||
#define ZYDIS_DISASSEMBLER_H
|
||||
|
||||
#include <Zydis/Decoder.h>
|
||||
#include <Zydis/Formatter.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* All commonly used information about a decoded instruction that Zydis can provide.
|
||||
*
|
||||
* This structure is filled in by calling `ZydisDisassembleIntel` or `ZydisDisassembleATT`.
|
||||
*/
|
||||
typedef struct ZydisDisassembledInstruction_
|
||||
{
|
||||
/**
|
||||
* The runtime address that was passed when disassembling the instruction.
|
||||
*/
|
||||
ZyanU64 runtime_address;
|
||||
/**
|
||||
* General information about the decoded instruction in machine-readable format.
|
||||
*/
|
||||
ZydisDecodedInstruction info;
|
||||
/**
|
||||
* The operands of the decoded instruction in a machine-readable format.
|
||||
*
|
||||
* The amount of actual operands can be determined by inspecting the corresponding fields
|
||||
* in the `info` member of this struct. Inspect `operand_count_visible` if you care about
|
||||
* visible operands (those that are printed by the formatter) or `operand_count` if you're
|
||||
* also interested in implicit operands (for example the registers implicitly accessed by
|
||||
* `pushad`). Unused entries are zeroed.
|
||||
*/
|
||||
ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT];
|
||||
/**
|
||||
* The textual, human-readable representation of the instruction.
|
||||
*
|
||||
* Guaranteed to be zero-terminated.
|
||||
*/
|
||||
char text[96];
|
||||
} ZydisDisassembledInstruction;
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* Disassemble an instruction and format it to human-readable text in a single step (Intel syntax).
|
||||
*
|
||||
* @param machine_mode The machine mode to assume when disassembling. When in doubt, pass
|
||||
* `ZYDIS_MACHINE_MODE_LONG_64` for what is typically referred to as
|
||||
* "64-bit mode" or `ZYDIS_MACHINE_MODE_LEGACY_32` for "32-bit mode".
|
||||
* @param runtime_address The program counter (`eip` / `rip`) to assume when formatting the
|
||||
* instruction. Many instructions behave differently depending on the
|
||||
* address they are located at.
|
||||
* @param buffer A pointer to the raw instruction bytes that you wish to decode.
|
||||
* @param length The length of the input buffer. Note that this can be bigger than the
|
||||
* actual size of the instruction -- you don't have to know the size up
|
||||
* front. This length is merely used to prevent Zydis from doing
|
||||
* out-of-bounds reads on your buffer.
|
||||
* @param instruction A pointer to receive the decoded instruction information. Can be
|
||||
* uninitialized and reused on later calls.
|
||||
*
|
||||
* This is a convenience function intended as a quick path for getting started with using Zydis.
|
||||
* It internally calls a range of other more advanced functions to obtain all commonly needed
|
||||
* information about the instruction. It is likely that you won't need most of this information in
|
||||
* practice, so it is advisable to instead call these more advanced functions directly if you're
|
||||
* concerned about performance.
|
||||
*
|
||||
* This function essentially combines the following more advanced functions into a single call:
|
||||
*
|
||||
* - `ZydisDecoderInit`
|
||||
* - `ZydisDecoderDecodeInstruction`
|
||||
* - `ZydisDecoderDecodeOperands`
|
||||
* - `ZydisFormatterInit`
|
||||
* - `ZydisFormatterFormatInstruction`
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYDIS_EXPORT ZyanStatus ZydisDisassembleIntel(ZydisMachineMode machine_mode,
|
||||
ZyanU64 runtime_address, const void* buffer, ZyanUSize length,
|
||||
ZydisDisassembledInstruction *instruction);
|
||||
|
||||
/**
|
||||
* Disassemble an instruction and format it to human-readable text in a single step (AT&T syntax).
|
||||
*
|
||||
* @copydetails ZydisDisassembleIntel
|
||||
*/
|
||||
ZYDIS_EXPORT ZyanStatus ZydisDisassembleATT(ZydisMachineMode machine_mode,
|
||||
ZyanU64 runtime_address, const void* buffer, ZyanUSize length,
|
||||
ZydisDisassembledInstruction *instruction);
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZYDIS_DISASSEMBLER_H */
|
||||
+471
@@ -0,0 +1,471 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Disassembler Library (Zydis)
|
||||
|
||||
Original Author : Mappa
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Functions for encoding instructions.
|
||||
*/
|
||||
|
||||
#ifndef ZYDIS_ENCODER_H
|
||||
#define ZYDIS_ENCODER_H
|
||||
|
||||
#include <Zycore/Types.h>
|
||||
#include <Zydis/MetaInfo.h>
|
||||
#include <Zydis/Register.h>
|
||||
#include <Zydis/DecoderTypes.h>
|
||||
#include <Zydis/Mnemonic.h>
|
||||
#include <Zydis/Status.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Macros */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Constants */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Maximum number of encodable (explicit and implicit) operands
|
||||
*/
|
||||
#define ZYDIS_ENCODER_MAX_OPERANDS 5
|
||||
|
||||
// If asserts are failing here remember to update encoder table generator before fixing asserts
|
||||
ZYAN_STATIC_ASSERT(ZYAN_BITS_TO_REPRESENT(ZYDIS_ENCODER_MAX_OPERANDS) == 3);
|
||||
|
||||
/**
|
||||
* Combination of all user-encodable prefixes
|
||||
*/
|
||||
#define ZYDIS_ENCODABLE_PREFIXES (ZYDIS_ATTRIB_HAS_LOCK | \
|
||||
ZYDIS_ATTRIB_HAS_REP | \
|
||||
ZYDIS_ATTRIB_HAS_REPE | \
|
||||
ZYDIS_ATTRIB_HAS_REPNE | \
|
||||
ZYDIS_ATTRIB_HAS_BND | \
|
||||
ZYDIS_ATTRIB_HAS_XACQUIRE | \
|
||||
ZYDIS_ATTRIB_HAS_XRELEASE | \
|
||||
ZYDIS_ATTRIB_HAS_BRANCH_NOT_TAKEN | \
|
||||
ZYDIS_ATTRIB_HAS_BRANCH_TAKEN | \
|
||||
ZYDIS_ATTRIB_HAS_NOTRACK | \
|
||||
ZYDIS_ATTRIB_HAS_SEGMENT_CS | \
|
||||
ZYDIS_ATTRIB_HAS_SEGMENT_SS | \
|
||||
ZYDIS_ATTRIB_HAS_SEGMENT_DS | \
|
||||
ZYDIS_ATTRIB_HAS_SEGMENT_ES | \
|
||||
ZYDIS_ATTRIB_HAS_SEGMENT_FS | \
|
||||
ZYDIS_ATTRIB_HAS_SEGMENT_GS)
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Enums and types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* Defines possible physical instruction encodings as bit flags, so multiple acceptable encodings
|
||||
* can be specified simultaneously.
|
||||
*/
|
||||
typedef enum ZydisEncodableEncoding_
|
||||
{
|
||||
ZYDIS_ENCODABLE_ENCODING_DEFAULT = 0x00000000,
|
||||
ZYDIS_ENCODABLE_ENCODING_LEGACY = 0x00000001,
|
||||
ZYDIS_ENCODABLE_ENCODING_3DNOW = 0x00000002,
|
||||
ZYDIS_ENCODABLE_ENCODING_XOP = 0x00000004,
|
||||
ZYDIS_ENCODABLE_ENCODING_VEX = 0x00000008,
|
||||
ZYDIS_ENCODABLE_ENCODING_EVEX = 0x00000010,
|
||||
ZYDIS_ENCODABLE_ENCODING_MVEX = 0x00000020,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_ENCODABLE_ENCODING_MAX_VALUE = (ZYDIS_ENCODABLE_ENCODING_MVEX |
|
||||
(ZYDIS_ENCODABLE_ENCODING_MVEX - 1)),
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_ENCODABLE_ENCODING_REQUIRED_BITS =
|
||||
ZYAN_BITS_TO_REPRESENT(ZYDIS_ENCODABLE_ENCODING_MAX_VALUE)
|
||||
} ZydisEncodableEncoding;
|
||||
|
||||
/**
|
||||
* Defines encodable physical/effective sizes of relative immediate operands. See
|
||||
* `ZydisEncoderRequest.branch_width` for more details.
|
||||
*/
|
||||
typedef enum ZydisBranchWidth_
|
||||
{
|
||||
ZYDIS_BRANCH_WIDTH_NONE,
|
||||
ZYDIS_BRANCH_WIDTH_8,
|
||||
ZYDIS_BRANCH_WIDTH_16,
|
||||
ZYDIS_BRANCH_WIDTH_32,
|
||||
ZYDIS_BRANCH_WIDTH_64,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_BRANCH_WIDTH_MAX_VALUE = ZYDIS_BRANCH_WIDTH_64,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_BRANCH_WIDTH_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_BRANCH_WIDTH_MAX_VALUE)
|
||||
} ZydisBranchWidth;
|
||||
|
||||
/**
|
||||
* Defines possible values for address size hints. See `ZydisEncoderRequest` for more information
|
||||
* about address size hints.
|
||||
*/
|
||||
typedef enum ZydisAddressSizeHint_
|
||||
{
|
||||
ZYDIS_ADDRESS_SIZE_HINT_NONE,
|
||||
ZYDIS_ADDRESS_SIZE_HINT_16,
|
||||
ZYDIS_ADDRESS_SIZE_HINT_32,
|
||||
ZYDIS_ADDRESS_SIZE_HINT_64,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_ADDRESS_SIZE_HINT_MAX_VALUE = ZYDIS_ADDRESS_SIZE_HINT_64,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_ADDRESS_SIZE_HINT_REQUIRED_BITS =
|
||||
ZYAN_BITS_TO_REPRESENT(ZYDIS_ADDRESS_SIZE_HINT_MAX_VALUE)
|
||||
} ZydisAddressSizeHint;
|
||||
|
||||
/**
|
||||
* Defines possible values for operand size hints. See `ZydisEncoderRequest` for more information
|
||||
* about operand size hints.
|
||||
*/
|
||||
typedef enum ZydisOperandSizeHint_
|
||||
{
|
||||
ZYDIS_OPERAND_SIZE_HINT_NONE,
|
||||
ZYDIS_OPERAND_SIZE_HINT_8,
|
||||
ZYDIS_OPERAND_SIZE_HINT_16,
|
||||
ZYDIS_OPERAND_SIZE_HINT_32,
|
||||
ZYDIS_OPERAND_SIZE_HINT_64,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_OPERAND_SIZE_HINT_MAX_VALUE = ZYDIS_OPERAND_SIZE_HINT_64,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_OPERAND_SIZE_HINT_REQUIRED_BITS =
|
||||
ZYAN_BITS_TO_REPRESENT(ZYDIS_OPERAND_SIZE_HINT_MAX_VALUE)
|
||||
} ZydisOperandSizeHint;
|
||||
|
||||
/**
|
||||
* Describes explicit or implicit instruction operand.
|
||||
*/
|
||||
typedef struct ZydisEncoderOperand_
|
||||
{
|
||||
/**
|
||||
* The type of the operand.
|
||||
*/
|
||||
ZydisOperandType type;
|
||||
/**
|
||||
* Extended info for register-operands.
|
||||
*/
|
||||
struct ZydisEncoderOperandReg_
|
||||
{
|
||||
/**
|
||||
* The register value.
|
||||
*/
|
||||
ZydisRegister value;
|
||||
/**
|
||||
* Is this 4th operand (`VEX`/`XOP`). Despite its name, `is4` encoding can sometimes be
|
||||
* applied to 3rd operand instead of 4th. This field is used to resolve such ambiguities.
|
||||
* For all other operands it should be set to `ZYAN_FALSE`.
|
||||
*/
|
||||
ZyanBool is4;
|
||||
} reg;
|
||||
/**
|
||||
* Extended info for memory-operands.
|
||||
*/
|
||||
struct ZydisEncoderOperandMem_
|
||||
{
|
||||
/**
|
||||
* The base register.
|
||||
*/
|
||||
ZydisRegister base;
|
||||
/**
|
||||
* The index register.
|
||||
*/
|
||||
ZydisRegister index;
|
||||
/**
|
||||
* The scale factor.
|
||||
*/
|
||||
ZyanU8 scale;
|
||||
/**
|
||||
* The displacement value. This value is always treated as 64-bit signed integer, so it's
|
||||
* important to take this into account when specifying absolute addresses. For example
|
||||
* to specify a 16-bit address 0x8000 in 16-bit mode it should be sign extended to
|
||||
* `0xFFFFFFFFFFFF8000`. See `address_size_hint` for more information about absolute
|
||||
* addresses.
|
||||
*/
|
||||
ZyanI64 displacement;
|
||||
/**
|
||||
* Size of this operand in bytes.
|
||||
*/
|
||||
ZyanU16 size;
|
||||
} mem;
|
||||
/**
|
||||
* Extended info for pointer-operands.
|
||||
*/
|
||||
struct ZydisEncoderOperandPtr_
|
||||
{
|
||||
/**
|
||||
* The segment value.
|
||||
*/
|
||||
ZyanU16 segment;
|
||||
/**
|
||||
* The offset value.
|
||||
*/
|
||||
ZyanU32 offset;
|
||||
} ptr;
|
||||
/**
|
||||
* Extended info for immediate-operands.
|
||||
*/
|
||||
union ZydisEncoderOperandImm_
|
||||
{
|
||||
/**
|
||||
* The unsigned immediate value.
|
||||
*/
|
||||
ZyanU64 u;
|
||||
/**
|
||||
* The signed immediate value.
|
||||
*/
|
||||
ZyanI64 s;
|
||||
} imm;
|
||||
} ZydisEncoderOperand;
|
||||
|
||||
/**
|
||||
* Main structure consumed by the encoder. It represents full semantics of an instruction.
|
||||
*/
|
||||
typedef struct ZydisEncoderRequest_
|
||||
{
|
||||
/**
|
||||
* The machine mode used to encode this instruction.
|
||||
*/
|
||||
ZydisMachineMode machine_mode;
|
||||
/**
|
||||
* This optional field can be used to restrict allowed physical encodings for desired
|
||||
* instruction. Some mnemonics can be supported by more than one encoding, so this field can
|
||||
* resolve ambiguities e.g. you can disable `AVX-512` extensions by prohibiting usage of `EVEX`
|
||||
* prefix and allow only `VEX` variants.
|
||||
*/
|
||||
ZydisEncodableEncoding allowed_encodings;
|
||||
/**
|
||||
* The instruction-mnemonic.
|
||||
*/
|
||||
ZydisMnemonic mnemonic;
|
||||
/**
|
||||
* A combination of requested encodable prefixes (`ZYDIS_ATTRIB_HAS_*` flags) for desired
|
||||
* instruction. See `ZYDIS_ENCODABLE_PREFIXES` for list of available prefixes.
|
||||
*/
|
||||
ZydisInstructionAttributes prefixes;
|
||||
/**
|
||||
* Branch type (required for branching instructions only). Use `ZYDIS_BRANCH_TYPE_NONE` to let
|
||||
* encoder pick size-optimal branch type automatically (`short` and `near` are prioritized over
|
||||
* `far`).
|
||||
*/
|
||||
ZydisBranchType branch_type;
|
||||
/**
|
||||
* Specifies physical size for relative immediate operands. Use `ZYDIS_BRANCH_WIDTH_NONE` to
|
||||
* let encoder pick size-optimal branch width automatically. For segment:offset `far` branches
|
||||
* this field applies to physical size of the offset part. For branching instructions without
|
||||
* relative operands this field affects effective operand size attribute.
|
||||
*/
|
||||
ZydisBranchWidth branch_width;
|
||||
/**
|
||||
* Optional address size hint used to resolve ambiguities for some instructions. Generally
|
||||
* encoder deduces address size from `ZydisEncoderOperand` structures that represent
|
||||
* explicit and implicit operands. This hint resolves conflicts when instruction's hidden
|
||||
* operands scale with address size attribute.
|
||||
*
|
||||
* This hint is also used for instructions with absolute memory addresses (memory operands with
|
||||
* displacement and no registers). Since displacement field is a 64-bit signed integer it's not
|
||||
* possible to determine actual size of the address value in all situations. This hint
|
||||
* specifies size of the address value provided inside encoder request rather than desired
|
||||
* address size attribute of encoded instruction. Use `ZYDIS_ADDRESS_SIZE_HINT_NONE` to assume
|
||||
* address size default for specified machine mode.
|
||||
*/
|
||||
ZydisAddressSizeHint address_size_hint;
|
||||
/**
|
||||
* Optional operand size hint used to resolve ambiguities for some instructions. Generally
|
||||
* encoder deduces operand size from `ZydisEncoderOperand` structures that represent
|
||||
* explicit and implicit operands. This hint resolves conflicts when instruction's hidden
|
||||
* operands scale with operand size attribute.
|
||||
*/
|
||||
ZydisOperandSizeHint operand_size_hint;
|
||||
/**
|
||||
* The number of instruction-operands.
|
||||
*/
|
||||
ZyanU8 operand_count;
|
||||
/**
|
||||
* Detailed info for all explicit and implicit instruction operands.
|
||||
*/
|
||||
ZydisEncoderOperand operands[ZYDIS_ENCODER_MAX_OPERANDS];
|
||||
/**
|
||||
* Extended info for `EVEX` instructions.
|
||||
*/
|
||||
struct ZydisEncoderRequestEvexFeatures_
|
||||
{
|
||||
/**
|
||||
* The broadcast-mode. Specify `ZYDIS_BROADCAST_MODE_INVALID` for instructions with
|
||||
* static broadcast functionality.
|
||||
*/
|
||||
ZydisBroadcastMode broadcast;
|
||||
/**
|
||||
* The rounding-mode.
|
||||
*/
|
||||
ZydisRoundingMode rounding;
|
||||
/**
|
||||
* Signals, if the `SAE` (suppress-all-exceptions) functionality should be enabled for
|
||||
* the instruction.
|
||||
*/
|
||||
ZyanBool sae;
|
||||
/**
|
||||
* Signals, if the zeroing-mask functionality should be enabled for the instruction.
|
||||
* Specify `ZYAN_TRUE` for instructions with forced zeroing mask.
|
||||
*/
|
||||
ZyanBool zeroing_mask;
|
||||
} evex;
|
||||
/**
|
||||
* Extended info for `MVEX` instructions.
|
||||
*/
|
||||
struct ZydisEncoderRequestMvexFeatures_
|
||||
{
|
||||
/**
|
||||
* The broadcast-mode.
|
||||
*/
|
||||
ZydisBroadcastMode broadcast;
|
||||
/**
|
||||
* The data-conversion mode.
|
||||
*/
|
||||
ZydisConversionMode conversion;
|
||||
/**
|
||||
* The rounding-mode.
|
||||
*/
|
||||
ZydisRoundingMode rounding;
|
||||
/**
|
||||
* The `AVX` register-swizzle mode.
|
||||
*/
|
||||
ZydisSwizzleMode swizzle;
|
||||
/**
|
||||
* Signals, if the `SAE` (suppress-all-exceptions) functionality is enabled for
|
||||
* the instruction.
|
||||
*/
|
||||
ZyanBool sae;
|
||||
/**
|
||||
* Signals, if the instruction has a memory-eviction-hint (`KNC` only).
|
||||
*/
|
||||
ZyanBool eviction_hint;
|
||||
} mvex;
|
||||
} ZydisEncoderRequest;
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* @addtogroup encoder Encoder
|
||||
* Functions allowing encoding of instruction bytes from a machine interpretable struct.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Encodes instruction with semantics specified in encoder request structure.
|
||||
*
|
||||
* @param request A pointer to the `ZydisEncoderRequest` struct.
|
||||
* @param buffer A pointer to the output buffer receiving encoded instruction.
|
||||
* @param length A pointer to the variable containing length of the output buffer. Upon
|
||||
* successful return this variable receives length of the encoded instruction.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYDIS_EXPORT ZyanStatus ZydisEncoderEncodeInstruction(const ZydisEncoderRequest *request,
|
||||
void *buffer, ZyanUSize *length);
|
||||
|
||||
/**
|
||||
* Encodes instruction with semantics specified in encoder request structure. This function expects
|
||||
* absolute addresses inside encoder request instead of `EIP`/`RIP`-relative values. Function
|
||||
* predicts final instruction length prior to encoding and writes back calculated relative operands
|
||||
* to provided encoder request.
|
||||
*
|
||||
* @param request A pointer to the `ZydisEncoderRequest` struct.
|
||||
* @param buffer A pointer to the output buffer receiving encoded instruction.
|
||||
* @param length A pointer to the variable containing length of the output buffer. Upon
|
||||
* successful return this variable receives length of the encoded
|
||||
* instruction.
|
||||
* @param runtime_address The runtime address of the instruction.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYDIS_EXPORT ZyanStatus ZydisEncoderEncodeInstructionAbsolute(ZydisEncoderRequest *request,
|
||||
void *buffer, ZyanUSize *length, ZyanU64 runtime_address);
|
||||
|
||||
/**
|
||||
* Converts decoded instruction to encoder request that can be passed to
|
||||
* `ZydisEncoderEncodeInstruction`.
|
||||
*
|
||||
* @param instruction A pointer to the `ZydisDecodedInstruction` struct.
|
||||
* @param operands A pointer to the decoded operands.
|
||||
* @param operand_count The operand count.
|
||||
* @param request A pointer to the `ZydisEncoderRequest` struct, that receives
|
||||
* information necessary for encoder to re-encode the instruction.
|
||||
*
|
||||
* This function performs simple structure conversion and does minimal sanity checks on the
|
||||
* input. There's no guarantee that produced request will be accepted by
|
||||
* `ZydisEncoderEncodeInstruction` if malformed `ZydisDecodedInstruction` or malformed
|
||||
* `ZydisDecodedOperands` is passed to this function.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYDIS_EXPORT ZyanStatus ZydisEncoderDecodedInstructionToEncoderRequest(
|
||||
const ZydisDecodedInstruction* instruction, const ZydisDecodedOperand* operands,
|
||||
ZyanU8 operand_count, ZydisEncoderRequest* request);
|
||||
|
||||
/**
|
||||
* Fills provided buffer with `NOP` instructions using longest possible multi-byte instructions.
|
||||
*
|
||||
* @param buffer A pointer to the output buffer receiving encoded instructions.
|
||||
* @param length Size of the output buffer.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYDIS_EXPORT ZyanStatus ZydisEncoderNopFill(void *buffer, ZyanUSize length);
|
||||
|
||||
/** @} */
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZYDIS_ENCODER_H */
|
||||
+1148
File diff suppressed because it is too large
Load Diff
+306
@@ -0,0 +1,306 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Disassembler Library (Zydis)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Implements the `ZydisFormatterToken` type and provides functions to use it.
|
||||
*/
|
||||
|
||||
#ifndef ZYDIS_FORMATTER_TOKEN_H
|
||||
#define ZYDIS_FORMATTER_TOKEN_H
|
||||
|
||||
#include <Zycore/String.h>
|
||||
#include <Zycore/Types.h>
|
||||
#include <Zydis/Defines.h>
|
||||
#include <Zydis/Status.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Constants */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Token types */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisTokenType` data-type.
|
||||
*/
|
||||
typedef ZyanU8 ZydisTokenType;
|
||||
|
||||
#define ZYDIS_TOKEN_INVALID 0x00
|
||||
/**
|
||||
* A whitespace character.
|
||||
*/
|
||||
#define ZYDIS_TOKEN_WHITESPACE 0x01
|
||||
/**
|
||||
* A delimiter character (like `','`, `':'`, `'+'`, `'-'`, `'*'`).
|
||||
*/
|
||||
#define ZYDIS_TOKEN_DELIMITER 0x02
|
||||
/**
|
||||
* An opening parenthesis character (like `'('`, `'['`, `'{'`).
|
||||
*/
|
||||
#define ZYDIS_TOKEN_PARENTHESIS_OPEN 0x03
|
||||
/**
|
||||
* A closing parenthesis character (like `')'`, `']'`, `'}'`).
|
||||
*/
|
||||
#define ZYDIS_TOKEN_PARENTHESIS_CLOSE 0x04
|
||||
/**
|
||||
* A prefix literal (like `"LOCK"`, `"REP"`).
|
||||
*/
|
||||
#define ZYDIS_TOKEN_PREFIX 0x05
|
||||
/**
|
||||
* A mnemonic literal (like `"MOV"`, `"VCMPPSD"`, `"LCALL"`).
|
||||
*/
|
||||
#define ZYDIS_TOKEN_MNEMONIC 0x06
|
||||
/**
|
||||
* A register literal (like `"RAX"`, `"DS"`, `"%ECX"`).
|
||||
*/
|
||||
#define ZYDIS_TOKEN_REGISTER 0x07
|
||||
/**
|
||||
* An absolute address literal (like `0x00400000`).
|
||||
*/
|
||||
#define ZYDIS_TOKEN_ADDRESS_ABS 0x08
|
||||
/**
|
||||
* A relative address literal (like `-0x100`).
|
||||
*/
|
||||
#define ZYDIS_TOKEN_ADDRESS_REL 0x09
|
||||
/**
|
||||
* A displacement literal (like `0xFFFFFFFF`, `-0x100`, `+0x1234`).
|
||||
*/
|
||||
#define ZYDIS_TOKEN_DISPLACEMENT 0x0A
|
||||
/**
|
||||
* An immediate literal (like `0xC0`, `-0x1234`, `$0x0000`).
|
||||
*/
|
||||
#define ZYDIS_TOKEN_IMMEDIATE 0x0B
|
||||
/**
|
||||
* A typecast literal (like `DWORD PTR`).
|
||||
*/
|
||||
#define ZYDIS_TOKEN_TYPECAST 0x0C
|
||||
/**
|
||||
* A decorator literal (like `"Z"`, `"1TO4"`).
|
||||
*/
|
||||
#define ZYDIS_TOKEN_DECORATOR 0x0D
|
||||
/**
|
||||
* A symbol literal.
|
||||
*/
|
||||
#define ZYDIS_TOKEN_SYMBOL 0x0E
|
||||
|
||||
/**
|
||||
* The base for user-defined token types.
|
||||
*/
|
||||
#define ZYDIS_TOKEN_USER 0x80
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Enums and types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Token */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
/**
|
||||
* Defines the `ZydisFormatterToken` struct.
|
||||
*
|
||||
* All fields in this struct should be considered as "private". Any changes may lead to unexpected
|
||||
* behavior.
|
||||
*/
|
||||
typedef struct ZydisFormatterToken_
|
||||
{
|
||||
/**
|
||||
* The token type.
|
||||
*/
|
||||
ZydisTokenType type;
|
||||
/**
|
||||
* An offset to the next token, or `0`.
|
||||
*/
|
||||
ZyanU8 next;
|
||||
} ZydisFormatterToken;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
/**
|
||||
* Defines the `ZydisFormatterTokenConst` data-type.
|
||||
*/
|
||||
typedef const ZydisFormatterToken ZydisFormatterTokenConst;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Buffer */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisFormatterBuffer` struct.
|
||||
*
|
||||
* All fields in this struct should be considered as "private". Any changes may
|
||||
* lead to unexpected behavior.
|
||||
*/
|
||||
typedef struct ZydisFormatterBuffer_
|
||||
{
|
||||
/**
|
||||
* `ZYAN_TRUE`, if the buffer contains a token stream or `ZYAN_FALSE, if it
|
||||
* contains a simple string.
|
||||
*/
|
||||
ZyanBool is_token_list;
|
||||
/**
|
||||
* The remaining capacity of the buffer.
|
||||
*/
|
||||
ZyanUSize capacity;
|
||||
/**
|
||||
* The `ZyanString` instance that refers to the literal value of the most
|
||||
* recently added token.
|
||||
*/
|
||||
ZyanString string;
|
||||
} ZydisFormatterBuffer;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Token */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Returns the `type` and the string `value` of the given `token`.
|
||||
*
|
||||
* @param token A pointer to the `ZydisFormatterToken` struct.
|
||||
* @param type Receives the token type.
|
||||
* @param value Receives a pointer to the string value of the token.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYDIS_EXPORT ZyanStatus ZydisFormatterTokenGetValue(const ZydisFormatterToken* token,
|
||||
ZydisTokenType* type, ZyanConstCharPointer* value);
|
||||
|
||||
/**
|
||||
* Obtains the next `token` linked to the passed one.
|
||||
*
|
||||
* @param token Receives a pointer to the next `ZydisFormatterToken` struct
|
||||
* linked to the passed one.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYDIS_EXPORT ZyanStatus ZydisFormatterTokenNext(ZydisFormatterTokenConst** token);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Buffer */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Returns the current (most recently added) token.
|
||||
*
|
||||
* @param buffer A pointer to the `ZydisFormatterBuffer` struct.
|
||||
* @param token Receives a pointer to the current token.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* This function returns `ZYAN_STATUS_INVALID_OPERATION`, if the buffer does not contain at least
|
||||
* one token.
|
||||
*/
|
||||
ZYDIS_EXPORT ZyanStatus ZydisFormatterBufferGetToken(const ZydisFormatterBuffer* buffer,
|
||||
ZydisFormatterTokenConst** token);
|
||||
|
||||
/**
|
||||
* Returns the `ZyanString` instance associated with the given buffer.
|
||||
*
|
||||
* @param buffer A pointer to the `ZydisFormatterBuffer` struct.
|
||||
* @param string Receives a pointer to the `ZyanString` instance associated with the given
|
||||
* buffer.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* This function returns `ZYAN_STATUS_INVALID_OPERATION`, if the buffer does not contain at least
|
||||
* one token.
|
||||
*
|
||||
* The returned string always refers to the literal value of the current (most recently added)
|
||||
* token and will remain valid until the buffer is destroyed.
|
||||
*/
|
||||
ZYDIS_EXPORT ZyanStatus ZydisFormatterBufferGetString(ZydisFormatterBuffer* buffer,
|
||||
ZyanString** string);
|
||||
|
||||
/**
|
||||
* Appends a new token to the `buffer`.
|
||||
*
|
||||
* @param buffer A pointer to the `ZydisFormatterBuffer` struct.
|
||||
* @param type The type of the new token.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* Note that the `ZyanString` instance returned by `ZydisFormatterBufferGetString` will
|
||||
* automatically be updated by calling this function.
|
||||
*/
|
||||
ZYDIS_EXPORT ZyanStatus ZydisFormatterBufferAppend(ZydisFormatterBuffer* buffer,
|
||||
ZydisTokenType type);
|
||||
|
||||
/**
|
||||
* Returns a snapshot of the buffer-state.
|
||||
*
|
||||
* @param buffer A pointer to the `ZydisFormatterBuffer` struct.
|
||||
* @param state Receives a snapshot of the buffer-state.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* Note that the buffer-state is saved inside the buffer itself and thus becomes invalid as soon
|
||||
* as the buffer gets overwritten or destroyed.
|
||||
*/
|
||||
ZYDIS_EXPORT ZyanStatus ZydisFormatterBufferRemember(const ZydisFormatterBuffer* buffer,
|
||||
ZyanUPointer* state);
|
||||
|
||||
/**
|
||||
* Restores a previously saved buffer-state.
|
||||
*
|
||||
* @param buffer A pointer to the `ZydisFormatterBuffer` struct.
|
||||
* @param state The buffer-state to restore.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* All tokens added after obtaining the given `state` snapshot will be removed. This function
|
||||
* does NOT restore any string content.
|
||||
*
|
||||
* Note that the `ZyanString` instance returned by `ZydisFormatterBufferGetString` will
|
||||
* automatically be updated by calling this function.
|
||||
*/
|
||||
ZYDIS_EXPORT ZyanStatus ZydisFormatterBufferRestore(ZydisFormatterBuffer* buffer,
|
||||
ZyanUPointer state);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZYDIS_FORMATTER_TOKEN_H */
|
||||
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* Defines the `ZydisISAExt` enum.
|
||||
*/
|
||||
typedef enum ZydisISAExt_
|
||||
{
|
||||
ZYDIS_ISA_EXT_INVALID,
|
||||
ZYDIS_ISA_EXT_ADOX_ADCX,
|
||||
ZYDIS_ISA_EXT_AES,
|
||||
ZYDIS_ISA_EXT_AMD3DNOW,
|
||||
ZYDIS_ISA_EXT_AMD3DNOW_PREFETCH,
|
||||
ZYDIS_ISA_EXT_AMD_INVLPGB,
|
||||
ZYDIS_ISA_EXT_AMX_BF16,
|
||||
ZYDIS_ISA_EXT_AMX_FP16,
|
||||
ZYDIS_ISA_EXT_AMX_INT8,
|
||||
ZYDIS_ISA_EXT_AMX_TILE,
|
||||
ZYDIS_ISA_EXT_AVX,
|
||||
ZYDIS_ISA_EXT_AVX2,
|
||||
ZYDIS_ISA_EXT_AVX2GATHER,
|
||||
ZYDIS_ISA_EXT_AVX512EVEX,
|
||||
ZYDIS_ISA_EXT_AVX512VEX,
|
||||
ZYDIS_ISA_EXT_AVXAES,
|
||||
ZYDIS_ISA_EXT_AVX_IFMA,
|
||||
ZYDIS_ISA_EXT_AVX_NE_CONVERT,
|
||||
ZYDIS_ISA_EXT_AVX_VNNI,
|
||||
ZYDIS_ISA_EXT_AVX_VNNI_INT16,
|
||||
ZYDIS_ISA_EXT_AVX_VNNI_INT8,
|
||||
ZYDIS_ISA_EXT_BASE,
|
||||
ZYDIS_ISA_EXT_BMI1,
|
||||
ZYDIS_ISA_EXT_BMI2,
|
||||
ZYDIS_ISA_EXT_CET,
|
||||
ZYDIS_ISA_EXT_CLDEMOTE,
|
||||
ZYDIS_ISA_EXT_CLFLUSHOPT,
|
||||
ZYDIS_ISA_EXT_CLFSH,
|
||||
ZYDIS_ISA_EXT_CLWB,
|
||||
ZYDIS_ISA_EXT_CLZERO,
|
||||
ZYDIS_ISA_EXT_ENQCMD,
|
||||
ZYDIS_ISA_EXT_F16C,
|
||||
ZYDIS_ISA_EXT_FMA,
|
||||
ZYDIS_ISA_EXT_FMA4,
|
||||
ZYDIS_ISA_EXT_GFNI,
|
||||
ZYDIS_ISA_EXT_HRESET,
|
||||
ZYDIS_ISA_EXT_ICACHE_PREFETCH,
|
||||
ZYDIS_ISA_EXT_INVPCID,
|
||||
ZYDIS_ISA_EXT_KEYLOCKER,
|
||||
ZYDIS_ISA_EXT_KEYLOCKER_WIDE,
|
||||
ZYDIS_ISA_EXT_KNC,
|
||||
ZYDIS_ISA_EXT_KNCE,
|
||||
ZYDIS_ISA_EXT_KNCV,
|
||||
ZYDIS_ISA_EXT_LONGMODE,
|
||||
ZYDIS_ISA_EXT_LZCNT,
|
||||
ZYDIS_ISA_EXT_MCOMMIT,
|
||||
ZYDIS_ISA_EXT_MMX,
|
||||
ZYDIS_ISA_EXT_MONITOR,
|
||||
ZYDIS_ISA_EXT_MONITORX,
|
||||
ZYDIS_ISA_EXT_MOVBE,
|
||||
ZYDIS_ISA_EXT_MOVDIR,
|
||||
ZYDIS_ISA_EXT_MPX,
|
||||
ZYDIS_ISA_EXT_MSRLIST,
|
||||
ZYDIS_ISA_EXT_PADLOCK,
|
||||
ZYDIS_ISA_EXT_PAUSE,
|
||||
ZYDIS_ISA_EXT_PBNDKB,
|
||||
ZYDIS_ISA_EXT_PCLMULQDQ,
|
||||
ZYDIS_ISA_EXT_PCOMMIT,
|
||||
ZYDIS_ISA_EXT_PCONFIG,
|
||||
ZYDIS_ISA_EXT_PKU,
|
||||
ZYDIS_ISA_EXT_PREFETCHWT1,
|
||||
ZYDIS_ISA_EXT_PT,
|
||||
ZYDIS_ISA_EXT_RAO_INT,
|
||||
ZYDIS_ISA_EXT_RDPID,
|
||||
ZYDIS_ISA_EXT_RDPRU,
|
||||
ZYDIS_ISA_EXT_RDRAND,
|
||||
ZYDIS_ISA_EXT_RDSEED,
|
||||
ZYDIS_ISA_EXT_RDTSCP,
|
||||
ZYDIS_ISA_EXT_RDWRFSGS,
|
||||
ZYDIS_ISA_EXT_RTM,
|
||||
ZYDIS_ISA_EXT_SERIALIZE,
|
||||
ZYDIS_ISA_EXT_SGX,
|
||||
ZYDIS_ISA_EXT_SGX_ENCLV,
|
||||
ZYDIS_ISA_EXT_SHA,
|
||||
ZYDIS_ISA_EXT_SHA512,
|
||||
ZYDIS_ISA_EXT_SM3,
|
||||
ZYDIS_ISA_EXT_SM4,
|
||||
ZYDIS_ISA_EXT_SMAP,
|
||||
ZYDIS_ISA_EXT_SMX,
|
||||
ZYDIS_ISA_EXT_SNP,
|
||||
ZYDIS_ISA_EXT_SSE,
|
||||
ZYDIS_ISA_EXT_SSE2,
|
||||
ZYDIS_ISA_EXT_SSE3,
|
||||
ZYDIS_ISA_EXT_SSE4,
|
||||
ZYDIS_ISA_EXT_SSE4A,
|
||||
ZYDIS_ISA_EXT_SSSE3,
|
||||
ZYDIS_ISA_EXT_SVM,
|
||||
ZYDIS_ISA_EXT_TBM,
|
||||
ZYDIS_ISA_EXT_TDX,
|
||||
ZYDIS_ISA_EXT_TSX_LDTRK,
|
||||
ZYDIS_ISA_EXT_UINTR,
|
||||
ZYDIS_ISA_EXT_VAES,
|
||||
ZYDIS_ISA_EXT_VMFUNC,
|
||||
ZYDIS_ISA_EXT_VPCLMULQDQ,
|
||||
ZYDIS_ISA_EXT_VTX,
|
||||
ZYDIS_ISA_EXT_WAITPKG,
|
||||
ZYDIS_ISA_EXT_WRMSRNS,
|
||||
ZYDIS_ISA_EXT_X87,
|
||||
ZYDIS_ISA_EXT_XOP,
|
||||
ZYDIS_ISA_EXT_XSAVE,
|
||||
ZYDIS_ISA_EXT_XSAVEC,
|
||||
ZYDIS_ISA_EXT_XSAVEOPT,
|
||||
ZYDIS_ISA_EXT_XSAVES,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_ISA_EXT_MAX_VALUE = ZYDIS_ISA_EXT_XSAVES,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_ISA_EXT_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_ISA_EXT_MAX_VALUE)
|
||||
} ZydisISAExt;
|
||||
@@ -0,0 +1,213 @@
|
||||
/**
|
||||
* Defines the `ZydisISASet` enum.
|
||||
*/
|
||||
typedef enum ZydisISASet_
|
||||
{
|
||||
ZYDIS_ISA_SET_INVALID,
|
||||
ZYDIS_ISA_SET_ADOX_ADCX,
|
||||
ZYDIS_ISA_SET_AES,
|
||||
ZYDIS_ISA_SET_AMD,
|
||||
ZYDIS_ISA_SET_AMD3DNOW,
|
||||
ZYDIS_ISA_SET_AMD_INVLPGB,
|
||||
ZYDIS_ISA_SET_AMX_BF16,
|
||||
ZYDIS_ISA_SET_AMX_FP16,
|
||||
ZYDIS_ISA_SET_AMX_INT8,
|
||||
ZYDIS_ISA_SET_AMX_TILE,
|
||||
ZYDIS_ISA_SET_AVX,
|
||||
ZYDIS_ISA_SET_AVX2,
|
||||
ZYDIS_ISA_SET_AVX2GATHER,
|
||||
ZYDIS_ISA_SET_AVX512BW_128,
|
||||
ZYDIS_ISA_SET_AVX512BW_128N,
|
||||
ZYDIS_ISA_SET_AVX512BW_256,
|
||||
ZYDIS_ISA_SET_AVX512BW_512,
|
||||
ZYDIS_ISA_SET_AVX512BW_KOP,
|
||||
ZYDIS_ISA_SET_AVX512CD_128,
|
||||
ZYDIS_ISA_SET_AVX512CD_256,
|
||||
ZYDIS_ISA_SET_AVX512CD_512,
|
||||
ZYDIS_ISA_SET_AVX512DQ_128,
|
||||
ZYDIS_ISA_SET_AVX512DQ_128N,
|
||||
ZYDIS_ISA_SET_AVX512DQ_256,
|
||||
ZYDIS_ISA_SET_AVX512DQ_512,
|
||||
ZYDIS_ISA_SET_AVX512DQ_KOP,
|
||||
ZYDIS_ISA_SET_AVX512DQ_SCALAR,
|
||||
ZYDIS_ISA_SET_AVX512ER_512,
|
||||
ZYDIS_ISA_SET_AVX512ER_SCALAR,
|
||||
ZYDIS_ISA_SET_AVX512F_128,
|
||||
ZYDIS_ISA_SET_AVX512F_128N,
|
||||
ZYDIS_ISA_SET_AVX512F_256,
|
||||
ZYDIS_ISA_SET_AVX512F_512,
|
||||
ZYDIS_ISA_SET_AVX512F_KOP,
|
||||
ZYDIS_ISA_SET_AVX512F_SCALAR,
|
||||
ZYDIS_ISA_SET_AVX512PF_512,
|
||||
ZYDIS_ISA_SET_AVX512_4FMAPS_512,
|
||||
ZYDIS_ISA_SET_AVX512_4FMAPS_SCALAR,
|
||||
ZYDIS_ISA_SET_AVX512_4VNNIW_512,
|
||||
ZYDIS_ISA_SET_AVX512_BF16_128,
|
||||
ZYDIS_ISA_SET_AVX512_BF16_256,
|
||||
ZYDIS_ISA_SET_AVX512_BF16_512,
|
||||
ZYDIS_ISA_SET_AVX512_BITALG_128,
|
||||
ZYDIS_ISA_SET_AVX512_BITALG_256,
|
||||
ZYDIS_ISA_SET_AVX512_BITALG_512,
|
||||
ZYDIS_ISA_SET_AVX512_FP16_128,
|
||||
ZYDIS_ISA_SET_AVX512_FP16_128N,
|
||||
ZYDIS_ISA_SET_AVX512_FP16_256,
|
||||
ZYDIS_ISA_SET_AVX512_FP16_512,
|
||||
ZYDIS_ISA_SET_AVX512_FP16_SCALAR,
|
||||
ZYDIS_ISA_SET_AVX512_GFNI_128,
|
||||
ZYDIS_ISA_SET_AVX512_GFNI_256,
|
||||
ZYDIS_ISA_SET_AVX512_GFNI_512,
|
||||
ZYDIS_ISA_SET_AVX512_IFMA_128,
|
||||
ZYDIS_ISA_SET_AVX512_IFMA_256,
|
||||
ZYDIS_ISA_SET_AVX512_IFMA_512,
|
||||
ZYDIS_ISA_SET_AVX512_VAES_128,
|
||||
ZYDIS_ISA_SET_AVX512_VAES_256,
|
||||
ZYDIS_ISA_SET_AVX512_VAES_512,
|
||||
ZYDIS_ISA_SET_AVX512_VBMI2_128,
|
||||
ZYDIS_ISA_SET_AVX512_VBMI2_256,
|
||||
ZYDIS_ISA_SET_AVX512_VBMI2_512,
|
||||
ZYDIS_ISA_SET_AVX512_VBMI_128,
|
||||
ZYDIS_ISA_SET_AVX512_VBMI_256,
|
||||
ZYDIS_ISA_SET_AVX512_VBMI_512,
|
||||
ZYDIS_ISA_SET_AVX512_VNNI_128,
|
||||
ZYDIS_ISA_SET_AVX512_VNNI_256,
|
||||
ZYDIS_ISA_SET_AVX512_VNNI_512,
|
||||
ZYDIS_ISA_SET_AVX512_VP2INTERSECT_128,
|
||||
ZYDIS_ISA_SET_AVX512_VP2INTERSECT_256,
|
||||
ZYDIS_ISA_SET_AVX512_VP2INTERSECT_512,
|
||||
ZYDIS_ISA_SET_AVX512_VPCLMULQDQ_128,
|
||||
ZYDIS_ISA_SET_AVX512_VPCLMULQDQ_256,
|
||||
ZYDIS_ISA_SET_AVX512_VPCLMULQDQ_512,
|
||||
ZYDIS_ISA_SET_AVX512_VPOPCNTDQ_128,
|
||||
ZYDIS_ISA_SET_AVX512_VPOPCNTDQ_256,
|
||||
ZYDIS_ISA_SET_AVX512_VPOPCNTDQ_512,
|
||||
ZYDIS_ISA_SET_AVXAES,
|
||||
ZYDIS_ISA_SET_AVX_GFNI,
|
||||
ZYDIS_ISA_SET_AVX_IFMA,
|
||||
ZYDIS_ISA_SET_AVX_NE_CONVERT,
|
||||
ZYDIS_ISA_SET_AVX_VNNI,
|
||||
ZYDIS_ISA_SET_AVX_VNNI_INT16,
|
||||
ZYDIS_ISA_SET_AVX_VNNI_INT8,
|
||||
ZYDIS_ISA_SET_BMI1,
|
||||
ZYDIS_ISA_SET_BMI2,
|
||||
ZYDIS_ISA_SET_CET,
|
||||
ZYDIS_ISA_SET_CLDEMOTE,
|
||||
ZYDIS_ISA_SET_CLFLUSHOPT,
|
||||
ZYDIS_ISA_SET_CLFSH,
|
||||
ZYDIS_ISA_SET_CLWB,
|
||||
ZYDIS_ISA_SET_CLZERO,
|
||||
ZYDIS_ISA_SET_CMOV,
|
||||
ZYDIS_ISA_SET_CMPXCHG16B,
|
||||
ZYDIS_ISA_SET_ENQCMD,
|
||||
ZYDIS_ISA_SET_F16C,
|
||||
ZYDIS_ISA_SET_FAT_NOP,
|
||||
ZYDIS_ISA_SET_FCMOV,
|
||||
ZYDIS_ISA_SET_FCOMI,
|
||||
ZYDIS_ISA_SET_FMA,
|
||||
ZYDIS_ISA_SET_FMA4,
|
||||
ZYDIS_ISA_SET_FXSAVE,
|
||||
ZYDIS_ISA_SET_FXSAVE64,
|
||||
ZYDIS_ISA_SET_GFNI,
|
||||
ZYDIS_ISA_SET_HRESET,
|
||||
ZYDIS_ISA_SET_I186,
|
||||
ZYDIS_ISA_SET_I286PROTECTED,
|
||||
ZYDIS_ISA_SET_I286REAL,
|
||||
ZYDIS_ISA_SET_I386,
|
||||
ZYDIS_ISA_SET_I486,
|
||||
ZYDIS_ISA_SET_I486REAL,
|
||||
ZYDIS_ISA_SET_I86,
|
||||
ZYDIS_ISA_SET_ICACHE_PREFETCH,
|
||||
ZYDIS_ISA_SET_INVPCID,
|
||||
ZYDIS_ISA_SET_KEYLOCKER,
|
||||
ZYDIS_ISA_SET_KEYLOCKER_WIDE,
|
||||
ZYDIS_ISA_SET_KNCE,
|
||||
ZYDIS_ISA_SET_KNCJKBR,
|
||||
ZYDIS_ISA_SET_KNCSTREAM,
|
||||
ZYDIS_ISA_SET_KNCV,
|
||||
ZYDIS_ISA_SET_KNC_MISC,
|
||||
ZYDIS_ISA_SET_KNC_PF_HINT,
|
||||
ZYDIS_ISA_SET_LAHF,
|
||||
ZYDIS_ISA_SET_LONGMODE,
|
||||
ZYDIS_ISA_SET_LWP,
|
||||
ZYDIS_ISA_SET_LZCNT,
|
||||
ZYDIS_ISA_SET_MCOMMIT,
|
||||
ZYDIS_ISA_SET_MONITOR,
|
||||
ZYDIS_ISA_SET_MONITORX,
|
||||
ZYDIS_ISA_SET_MOVBE,
|
||||
ZYDIS_ISA_SET_MOVDIR,
|
||||
ZYDIS_ISA_SET_MPX,
|
||||
ZYDIS_ISA_SET_MSRLIST,
|
||||
ZYDIS_ISA_SET_PADLOCK_ACE,
|
||||
ZYDIS_ISA_SET_PADLOCK_PHE,
|
||||
ZYDIS_ISA_SET_PADLOCK_PMM,
|
||||
ZYDIS_ISA_SET_PADLOCK_RNG,
|
||||
ZYDIS_ISA_SET_PAUSE,
|
||||
ZYDIS_ISA_SET_PBNDKB,
|
||||
ZYDIS_ISA_SET_PCLMULQDQ,
|
||||
ZYDIS_ISA_SET_PCOMMIT,
|
||||
ZYDIS_ISA_SET_PCONFIG,
|
||||
ZYDIS_ISA_SET_PENTIUMMMX,
|
||||
ZYDIS_ISA_SET_PENTIUMREAL,
|
||||
ZYDIS_ISA_SET_PKU,
|
||||
ZYDIS_ISA_SET_POPCNT,
|
||||
ZYDIS_ISA_SET_PPRO,
|
||||
ZYDIS_ISA_SET_PREFETCHWT1,
|
||||
ZYDIS_ISA_SET_PREFETCH_NOP,
|
||||
ZYDIS_ISA_SET_PT,
|
||||
ZYDIS_ISA_SET_RAO_INT,
|
||||
ZYDIS_ISA_SET_RDPID,
|
||||
ZYDIS_ISA_SET_RDPMC,
|
||||
ZYDIS_ISA_SET_RDPRU,
|
||||
ZYDIS_ISA_SET_RDRAND,
|
||||
ZYDIS_ISA_SET_RDSEED,
|
||||
ZYDIS_ISA_SET_RDTSCP,
|
||||
ZYDIS_ISA_SET_RDWRFSGS,
|
||||
ZYDIS_ISA_SET_RTM,
|
||||
ZYDIS_ISA_SET_SERIALIZE,
|
||||
ZYDIS_ISA_SET_SGX,
|
||||
ZYDIS_ISA_SET_SGX_ENCLV,
|
||||
ZYDIS_ISA_SET_SHA,
|
||||
ZYDIS_ISA_SET_SHA512,
|
||||
ZYDIS_ISA_SET_SM3,
|
||||
ZYDIS_ISA_SET_SM4,
|
||||
ZYDIS_ISA_SET_SMAP,
|
||||
ZYDIS_ISA_SET_SMX,
|
||||
ZYDIS_ISA_SET_SNP,
|
||||
ZYDIS_ISA_SET_SSE,
|
||||
ZYDIS_ISA_SET_SSE2,
|
||||
ZYDIS_ISA_SET_SSE2MMX,
|
||||
ZYDIS_ISA_SET_SSE3,
|
||||
ZYDIS_ISA_SET_SSE3X87,
|
||||
ZYDIS_ISA_SET_SSE4,
|
||||
ZYDIS_ISA_SET_SSE42,
|
||||
ZYDIS_ISA_SET_SSE4A,
|
||||
ZYDIS_ISA_SET_SSEMXCSR,
|
||||
ZYDIS_ISA_SET_SSE_PREFETCH,
|
||||
ZYDIS_ISA_SET_SSSE3,
|
||||
ZYDIS_ISA_SET_SSSE3MMX,
|
||||
ZYDIS_ISA_SET_SVM,
|
||||
ZYDIS_ISA_SET_TBM,
|
||||
ZYDIS_ISA_SET_TDX,
|
||||
ZYDIS_ISA_SET_TSX_LDTRK,
|
||||
ZYDIS_ISA_SET_UINTR,
|
||||
ZYDIS_ISA_SET_VAES,
|
||||
ZYDIS_ISA_SET_VMFUNC,
|
||||
ZYDIS_ISA_SET_VPCLMULQDQ,
|
||||
ZYDIS_ISA_SET_VTX,
|
||||
ZYDIS_ISA_SET_WAITPKG,
|
||||
ZYDIS_ISA_SET_WRMSRNS,
|
||||
ZYDIS_ISA_SET_X87,
|
||||
ZYDIS_ISA_SET_XOP,
|
||||
ZYDIS_ISA_SET_XSAVE,
|
||||
ZYDIS_ISA_SET_XSAVEC,
|
||||
ZYDIS_ISA_SET_XSAVEOPT,
|
||||
ZYDIS_ISA_SET_XSAVES,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_ISA_SET_MAX_VALUE = ZYDIS_ISA_SET_XSAVES,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_ISA_SET_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_ISA_SET_MAX_VALUE)
|
||||
} ZydisISASet;
|
||||
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* Defines the `ZydisInstructionCategory` enum.
|
||||
*/
|
||||
typedef enum ZydisInstructionCategory_
|
||||
{
|
||||
ZYDIS_CATEGORY_INVALID,
|
||||
ZYDIS_CATEGORY_ADOX_ADCX,
|
||||
ZYDIS_CATEGORY_AES,
|
||||
ZYDIS_CATEGORY_AMD3DNOW,
|
||||
ZYDIS_CATEGORY_AMX_TILE,
|
||||
ZYDIS_CATEGORY_AVX,
|
||||
ZYDIS_CATEGORY_AVX2,
|
||||
ZYDIS_CATEGORY_AVX2GATHER,
|
||||
ZYDIS_CATEGORY_AVX512,
|
||||
ZYDIS_CATEGORY_AVX512_4FMAPS,
|
||||
ZYDIS_CATEGORY_AVX512_4VNNIW,
|
||||
ZYDIS_CATEGORY_AVX512_BITALG,
|
||||
ZYDIS_CATEGORY_AVX512_VBMI,
|
||||
ZYDIS_CATEGORY_AVX512_VP2INTERSECT,
|
||||
ZYDIS_CATEGORY_AVX_IFMA,
|
||||
ZYDIS_CATEGORY_BINARY,
|
||||
ZYDIS_CATEGORY_BITBYTE,
|
||||
ZYDIS_CATEGORY_BLEND,
|
||||
ZYDIS_CATEGORY_BMI1,
|
||||
ZYDIS_CATEGORY_BMI2,
|
||||
ZYDIS_CATEGORY_BROADCAST,
|
||||
ZYDIS_CATEGORY_CALL,
|
||||
ZYDIS_CATEGORY_CET,
|
||||
ZYDIS_CATEGORY_CLDEMOTE,
|
||||
ZYDIS_CATEGORY_CLFLUSHOPT,
|
||||
ZYDIS_CATEGORY_CLWB,
|
||||
ZYDIS_CATEGORY_CLZERO,
|
||||
ZYDIS_CATEGORY_CMOV,
|
||||
ZYDIS_CATEGORY_COMPRESS,
|
||||
ZYDIS_CATEGORY_COND_BR,
|
||||
ZYDIS_CATEGORY_CONFLICT,
|
||||
ZYDIS_CATEGORY_CONVERT,
|
||||
ZYDIS_CATEGORY_DATAXFER,
|
||||
ZYDIS_CATEGORY_DECIMAL,
|
||||
ZYDIS_CATEGORY_ENQCMD,
|
||||
ZYDIS_CATEGORY_EXPAND,
|
||||
ZYDIS_CATEGORY_FCMOV,
|
||||
ZYDIS_CATEGORY_FLAGOP,
|
||||
ZYDIS_CATEGORY_FMA4,
|
||||
ZYDIS_CATEGORY_FP16,
|
||||
ZYDIS_CATEGORY_GATHER,
|
||||
ZYDIS_CATEGORY_GFNI,
|
||||
ZYDIS_CATEGORY_HRESET,
|
||||
ZYDIS_CATEGORY_IFMA,
|
||||
ZYDIS_CATEGORY_INTERRUPT,
|
||||
ZYDIS_CATEGORY_IO,
|
||||
ZYDIS_CATEGORY_IOSTRINGOP,
|
||||
ZYDIS_CATEGORY_KEYLOCKER,
|
||||
ZYDIS_CATEGORY_KEYLOCKER_WIDE,
|
||||
ZYDIS_CATEGORY_KMASK,
|
||||
ZYDIS_CATEGORY_KNC,
|
||||
ZYDIS_CATEGORY_KNCMASK,
|
||||
ZYDIS_CATEGORY_KNCSCALAR,
|
||||
ZYDIS_CATEGORY_LEGACY,
|
||||
ZYDIS_CATEGORY_LOGICAL,
|
||||
ZYDIS_CATEGORY_LOGICAL_FP,
|
||||
ZYDIS_CATEGORY_LZCNT,
|
||||
ZYDIS_CATEGORY_MISC,
|
||||
ZYDIS_CATEGORY_MMX,
|
||||
ZYDIS_CATEGORY_MOVDIR,
|
||||
ZYDIS_CATEGORY_MPX,
|
||||
ZYDIS_CATEGORY_MSRLIST,
|
||||
ZYDIS_CATEGORY_NOP,
|
||||
ZYDIS_CATEGORY_PADLOCK,
|
||||
ZYDIS_CATEGORY_PBNDKB,
|
||||
ZYDIS_CATEGORY_PCLMULQDQ,
|
||||
ZYDIS_CATEGORY_PCOMMIT,
|
||||
ZYDIS_CATEGORY_PCONFIG,
|
||||
ZYDIS_CATEGORY_PKU,
|
||||
ZYDIS_CATEGORY_POP,
|
||||
ZYDIS_CATEGORY_PREFETCH,
|
||||
ZYDIS_CATEGORY_PREFETCHWT1,
|
||||
ZYDIS_CATEGORY_PT,
|
||||
ZYDIS_CATEGORY_PUSH,
|
||||
ZYDIS_CATEGORY_RDPID,
|
||||
ZYDIS_CATEGORY_RDPRU,
|
||||
ZYDIS_CATEGORY_RDRAND,
|
||||
ZYDIS_CATEGORY_RDSEED,
|
||||
ZYDIS_CATEGORY_RDWRFSGS,
|
||||
ZYDIS_CATEGORY_RET,
|
||||
ZYDIS_CATEGORY_ROTATE,
|
||||
ZYDIS_CATEGORY_SCATTER,
|
||||
ZYDIS_CATEGORY_SEGOP,
|
||||
ZYDIS_CATEGORY_SEMAPHORE,
|
||||
ZYDIS_CATEGORY_SERIALIZE,
|
||||
ZYDIS_CATEGORY_SETCC,
|
||||
ZYDIS_CATEGORY_SGX,
|
||||
ZYDIS_CATEGORY_SHA,
|
||||
ZYDIS_CATEGORY_SHA512,
|
||||
ZYDIS_CATEGORY_SHIFT,
|
||||
ZYDIS_CATEGORY_SMAP,
|
||||
ZYDIS_CATEGORY_SSE,
|
||||
ZYDIS_CATEGORY_STRINGOP,
|
||||
ZYDIS_CATEGORY_STTNI,
|
||||
ZYDIS_CATEGORY_SYSCALL,
|
||||
ZYDIS_CATEGORY_SYSRET,
|
||||
ZYDIS_CATEGORY_SYSTEM,
|
||||
ZYDIS_CATEGORY_TBM,
|
||||
ZYDIS_CATEGORY_TSX_LDTRK,
|
||||
ZYDIS_CATEGORY_UFMA,
|
||||
ZYDIS_CATEGORY_UINTR,
|
||||
ZYDIS_CATEGORY_UNCOND_BR,
|
||||
ZYDIS_CATEGORY_VAES,
|
||||
ZYDIS_CATEGORY_VBMI2,
|
||||
ZYDIS_CATEGORY_VEX,
|
||||
ZYDIS_CATEGORY_VFMA,
|
||||
ZYDIS_CATEGORY_VPCLMULQDQ,
|
||||
ZYDIS_CATEGORY_VTX,
|
||||
ZYDIS_CATEGORY_WAITPKG,
|
||||
ZYDIS_CATEGORY_WIDENOP,
|
||||
ZYDIS_CATEGORY_WRMSRNS,
|
||||
ZYDIS_CATEGORY_X87_ALU,
|
||||
ZYDIS_CATEGORY_XOP,
|
||||
ZYDIS_CATEGORY_XSAVE,
|
||||
ZYDIS_CATEGORY_XSAVEOPT,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_CATEGORY_MAX_VALUE = ZYDIS_CATEGORY_XSAVEOPT,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_CATEGORY_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_CATEGORY_MAX_VALUE)
|
||||
} ZydisInstructionCategory;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,321 @@
|
||||
/**
|
||||
* Defines the `ZydisRegister` enum.
|
||||
*/
|
||||
typedef enum ZydisRegister_
|
||||
{
|
||||
ZYDIS_REGISTER_NONE,
|
||||
|
||||
// General purpose registers 8-bit
|
||||
ZYDIS_REGISTER_AL,
|
||||
ZYDIS_REGISTER_CL,
|
||||
ZYDIS_REGISTER_DL,
|
||||
ZYDIS_REGISTER_BL,
|
||||
ZYDIS_REGISTER_AH,
|
||||
ZYDIS_REGISTER_CH,
|
||||
ZYDIS_REGISTER_DH,
|
||||
ZYDIS_REGISTER_BH,
|
||||
ZYDIS_REGISTER_SPL,
|
||||
ZYDIS_REGISTER_BPL,
|
||||
ZYDIS_REGISTER_SIL,
|
||||
ZYDIS_REGISTER_DIL,
|
||||
ZYDIS_REGISTER_R8B,
|
||||
ZYDIS_REGISTER_R9B,
|
||||
ZYDIS_REGISTER_R10B,
|
||||
ZYDIS_REGISTER_R11B,
|
||||
ZYDIS_REGISTER_R12B,
|
||||
ZYDIS_REGISTER_R13B,
|
||||
ZYDIS_REGISTER_R14B,
|
||||
ZYDIS_REGISTER_R15B,
|
||||
|
||||
// General purpose registers 16-bit
|
||||
ZYDIS_REGISTER_AX,
|
||||
ZYDIS_REGISTER_CX,
|
||||
ZYDIS_REGISTER_DX,
|
||||
ZYDIS_REGISTER_BX,
|
||||
ZYDIS_REGISTER_SP,
|
||||
ZYDIS_REGISTER_BP,
|
||||
ZYDIS_REGISTER_SI,
|
||||
ZYDIS_REGISTER_DI,
|
||||
ZYDIS_REGISTER_R8W,
|
||||
ZYDIS_REGISTER_R9W,
|
||||
ZYDIS_REGISTER_R10W,
|
||||
ZYDIS_REGISTER_R11W,
|
||||
ZYDIS_REGISTER_R12W,
|
||||
ZYDIS_REGISTER_R13W,
|
||||
ZYDIS_REGISTER_R14W,
|
||||
ZYDIS_REGISTER_R15W,
|
||||
|
||||
// General purpose registers 32-bit
|
||||
ZYDIS_REGISTER_EAX,
|
||||
ZYDIS_REGISTER_ECX,
|
||||
ZYDIS_REGISTER_EDX,
|
||||
ZYDIS_REGISTER_EBX,
|
||||
ZYDIS_REGISTER_ESP,
|
||||
ZYDIS_REGISTER_EBP,
|
||||
ZYDIS_REGISTER_ESI,
|
||||
ZYDIS_REGISTER_EDI,
|
||||
ZYDIS_REGISTER_R8D,
|
||||
ZYDIS_REGISTER_R9D,
|
||||
ZYDIS_REGISTER_R10D,
|
||||
ZYDIS_REGISTER_R11D,
|
||||
ZYDIS_REGISTER_R12D,
|
||||
ZYDIS_REGISTER_R13D,
|
||||
ZYDIS_REGISTER_R14D,
|
||||
ZYDIS_REGISTER_R15D,
|
||||
|
||||
// General purpose registers 64-bit
|
||||
ZYDIS_REGISTER_RAX,
|
||||
ZYDIS_REGISTER_RCX,
|
||||
ZYDIS_REGISTER_RDX,
|
||||
ZYDIS_REGISTER_RBX,
|
||||
ZYDIS_REGISTER_RSP,
|
||||
ZYDIS_REGISTER_RBP,
|
||||
ZYDIS_REGISTER_RSI,
|
||||
ZYDIS_REGISTER_RDI,
|
||||
ZYDIS_REGISTER_R8,
|
||||
ZYDIS_REGISTER_R9,
|
||||
ZYDIS_REGISTER_R10,
|
||||
ZYDIS_REGISTER_R11,
|
||||
ZYDIS_REGISTER_R12,
|
||||
ZYDIS_REGISTER_R13,
|
||||
ZYDIS_REGISTER_R14,
|
||||
ZYDIS_REGISTER_R15,
|
||||
|
||||
// Floating point legacy registers
|
||||
ZYDIS_REGISTER_ST0,
|
||||
ZYDIS_REGISTER_ST1,
|
||||
ZYDIS_REGISTER_ST2,
|
||||
ZYDIS_REGISTER_ST3,
|
||||
ZYDIS_REGISTER_ST4,
|
||||
ZYDIS_REGISTER_ST5,
|
||||
ZYDIS_REGISTER_ST6,
|
||||
ZYDIS_REGISTER_ST7,
|
||||
ZYDIS_REGISTER_X87CONTROL,
|
||||
ZYDIS_REGISTER_X87STATUS,
|
||||
ZYDIS_REGISTER_X87TAG,
|
||||
|
||||
// Floating point multimedia registers
|
||||
ZYDIS_REGISTER_MM0,
|
||||
ZYDIS_REGISTER_MM1,
|
||||
ZYDIS_REGISTER_MM2,
|
||||
ZYDIS_REGISTER_MM3,
|
||||
ZYDIS_REGISTER_MM4,
|
||||
ZYDIS_REGISTER_MM5,
|
||||
ZYDIS_REGISTER_MM6,
|
||||
ZYDIS_REGISTER_MM7,
|
||||
|
||||
// Floating point vector registers 128-bit
|
||||
ZYDIS_REGISTER_XMM0,
|
||||
ZYDIS_REGISTER_XMM1,
|
||||
ZYDIS_REGISTER_XMM2,
|
||||
ZYDIS_REGISTER_XMM3,
|
||||
ZYDIS_REGISTER_XMM4,
|
||||
ZYDIS_REGISTER_XMM5,
|
||||
ZYDIS_REGISTER_XMM6,
|
||||
ZYDIS_REGISTER_XMM7,
|
||||
ZYDIS_REGISTER_XMM8,
|
||||
ZYDIS_REGISTER_XMM9,
|
||||
ZYDIS_REGISTER_XMM10,
|
||||
ZYDIS_REGISTER_XMM11,
|
||||
ZYDIS_REGISTER_XMM12,
|
||||
ZYDIS_REGISTER_XMM13,
|
||||
ZYDIS_REGISTER_XMM14,
|
||||
ZYDIS_REGISTER_XMM15,
|
||||
ZYDIS_REGISTER_XMM16,
|
||||
ZYDIS_REGISTER_XMM17,
|
||||
ZYDIS_REGISTER_XMM18,
|
||||
ZYDIS_REGISTER_XMM19,
|
||||
ZYDIS_REGISTER_XMM20,
|
||||
ZYDIS_REGISTER_XMM21,
|
||||
ZYDIS_REGISTER_XMM22,
|
||||
ZYDIS_REGISTER_XMM23,
|
||||
ZYDIS_REGISTER_XMM24,
|
||||
ZYDIS_REGISTER_XMM25,
|
||||
ZYDIS_REGISTER_XMM26,
|
||||
ZYDIS_REGISTER_XMM27,
|
||||
ZYDIS_REGISTER_XMM28,
|
||||
ZYDIS_REGISTER_XMM29,
|
||||
ZYDIS_REGISTER_XMM30,
|
||||
ZYDIS_REGISTER_XMM31,
|
||||
|
||||
// Floating point vector registers 256-bit
|
||||
ZYDIS_REGISTER_YMM0,
|
||||
ZYDIS_REGISTER_YMM1,
|
||||
ZYDIS_REGISTER_YMM2,
|
||||
ZYDIS_REGISTER_YMM3,
|
||||
ZYDIS_REGISTER_YMM4,
|
||||
ZYDIS_REGISTER_YMM5,
|
||||
ZYDIS_REGISTER_YMM6,
|
||||
ZYDIS_REGISTER_YMM7,
|
||||
ZYDIS_REGISTER_YMM8,
|
||||
ZYDIS_REGISTER_YMM9,
|
||||
ZYDIS_REGISTER_YMM10,
|
||||
ZYDIS_REGISTER_YMM11,
|
||||
ZYDIS_REGISTER_YMM12,
|
||||
ZYDIS_REGISTER_YMM13,
|
||||
ZYDIS_REGISTER_YMM14,
|
||||
ZYDIS_REGISTER_YMM15,
|
||||
ZYDIS_REGISTER_YMM16,
|
||||
ZYDIS_REGISTER_YMM17,
|
||||
ZYDIS_REGISTER_YMM18,
|
||||
ZYDIS_REGISTER_YMM19,
|
||||
ZYDIS_REGISTER_YMM20,
|
||||
ZYDIS_REGISTER_YMM21,
|
||||
ZYDIS_REGISTER_YMM22,
|
||||
ZYDIS_REGISTER_YMM23,
|
||||
ZYDIS_REGISTER_YMM24,
|
||||
ZYDIS_REGISTER_YMM25,
|
||||
ZYDIS_REGISTER_YMM26,
|
||||
ZYDIS_REGISTER_YMM27,
|
||||
ZYDIS_REGISTER_YMM28,
|
||||
ZYDIS_REGISTER_YMM29,
|
||||
ZYDIS_REGISTER_YMM30,
|
||||
ZYDIS_REGISTER_YMM31,
|
||||
|
||||
// Floating point vector registers 512-bit
|
||||
ZYDIS_REGISTER_ZMM0,
|
||||
ZYDIS_REGISTER_ZMM1,
|
||||
ZYDIS_REGISTER_ZMM2,
|
||||
ZYDIS_REGISTER_ZMM3,
|
||||
ZYDIS_REGISTER_ZMM4,
|
||||
ZYDIS_REGISTER_ZMM5,
|
||||
ZYDIS_REGISTER_ZMM6,
|
||||
ZYDIS_REGISTER_ZMM7,
|
||||
ZYDIS_REGISTER_ZMM8,
|
||||
ZYDIS_REGISTER_ZMM9,
|
||||
ZYDIS_REGISTER_ZMM10,
|
||||
ZYDIS_REGISTER_ZMM11,
|
||||
ZYDIS_REGISTER_ZMM12,
|
||||
ZYDIS_REGISTER_ZMM13,
|
||||
ZYDIS_REGISTER_ZMM14,
|
||||
ZYDIS_REGISTER_ZMM15,
|
||||
ZYDIS_REGISTER_ZMM16,
|
||||
ZYDIS_REGISTER_ZMM17,
|
||||
ZYDIS_REGISTER_ZMM18,
|
||||
ZYDIS_REGISTER_ZMM19,
|
||||
ZYDIS_REGISTER_ZMM20,
|
||||
ZYDIS_REGISTER_ZMM21,
|
||||
ZYDIS_REGISTER_ZMM22,
|
||||
ZYDIS_REGISTER_ZMM23,
|
||||
ZYDIS_REGISTER_ZMM24,
|
||||
ZYDIS_REGISTER_ZMM25,
|
||||
ZYDIS_REGISTER_ZMM26,
|
||||
ZYDIS_REGISTER_ZMM27,
|
||||
ZYDIS_REGISTER_ZMM28,
|
||||
ZYDIS_REGISTER_ZMM29,
|
||||
ZYDIS_REGISTER_ZMM30,
|
||||
ZYDIS_REGISTER_ZMM31,
|
||||
|
||||
// Matrix registers
|
||||
ZYDIS_REGISTER_TMM0,
|
||||
ZYDIS_REGISTER_TMM1,
|
||||
ZYDIS_REGISTER_TMM2,
|
||||
ZYDIS_REGISTER_TMM3,
|
||||
ZYDIS_REGISTER_TMM4,
|
||||
ZYDIS_REGISTER_TMM5,
|
||||
ZYDIS_REGISTER_TMM6,
|
||||
ZYDIS_REGISTER_TMM7,
|
||||
|
||||
// Flags registers
|
||||
ZYDIS_REGISTER_FLAGS,
|
||||
ZYDIS_REGISTER_EFLAGS,
|
||||
ZYDIS_REGISTER_RFLAGS,
|
||||
|
||||
// Instruction-pointer registers
|
||||
ZYDIS_REGISTER_IP,
|
||||
ZYDIS_REGISTER_EIP,
|
||||
ZYDIS_REGISTER_RIP,
|
||||
|
||||
// Segment registers
|
||||
ZYDIS_REGISTER_ES,
|
||||
ZYDIS_REGISTER_CS,
|
||||
ZYDIS_REGISTER_SS,
|
||||
ZYDIS_REGISTER_DS,
|
||||
ZYDIS_REGISTER_FS,
|
||||
ZYDIS_REGISTER_GS,
|
||||
|
||||
// Table registers
|
||||
ZYDIS_REGISTER_GDTR,
|
||||
ZYDIS_REGISTER_LDTR,
|
||||
ZYDIS_REGISTER_IDTR,
|
||||
ZYDIS_REGISTER_TR,
|
||||
|
||||
// Test registers
|
||||
ZYDIS_REGISTER_TR0,
|
||||
ZYDIS_REGISTER_TR1,
|
||||
ZYDIS_REGISTER_TR2,
|
||||
ZYDIS_REGISTER_TR3,
|
||||
ZYDIS_REGISTER_TR4,
|
||||
ZYDIS_REGISTER_TR5,
|
||||
ZYDIS_REGISTER_TR6,
|
||||
ZYDIS_REGISTER_TR7,
|
||||
|
||||
// Control registers
|
||||
ZYDIS_REGISTER_CR0,
|
||||
ZYDIS_REGISTER_CR1,
|
||||
ZYDIS_REGISTER_CR2,
|
||||
ZYDIS_REGISTER_CR3,
|
||||
ZYDIS_REGISTER_CR4,
|
||||
ZYDIS_REGISTER_CR5,
|
||||
ZYDIS_REGISTER_CR6,
|
||||
ZYDIS_REGISTER_CR7,
|
||||
ZYDIS_REGISTER_CR8,
|
||||
ZYDIS_REGISTER_CR9,
|
||||
ZYDIS_REGISTER_CR10,
|
||||
ZYDIS_REGISTER_CR11,
|
||||
ZYDIS_REGISTER_CR12,
|
||||
ZYDIS_REGISTER_CR13,
|
||||
ZYDIS_REGISTER_CR14,
|
||||
ZYDIS_REGISTER_CR15,
|
||||
|
||||
// Debug registers
|
||||
ZYDIS_REGISTER_DR0,
|
||||
ZYDIS_REGISTER_DR1,
|
||||
ZYDIS_REGISTER_DR2,
|
||||
ZYDIS_REGISTER_DR3,
|
||||
ZYDIS_REGISTER_DR4,
|
||||
ZYDIS_REGISTER_DR5,
|
||||
ZYDIS_REGISTER_DR6,
|
||||
ZYDIS_REGISTER_DR7,
|
||||
ZYDIS_REGISTER_DR8,
|
||||
ZYDIS_REGISTER_DR9,
|
||||
ZYDIS_REGISTER_DR10,
|
||||
ZYDIS_REGISTER_DR11,
|
||||
ZYDIS_REGISTER_DR12,
|
||||
ZYDIS_REGISTER_DR13,
|
||||
ZYDIS_REGISTER_DR14,
|
||||
ZYDIS_REGISTER_DR15,
|
||||
|
||||
// Mask registers
|
||||
ZYDIS_REGISTER_K0,
|
||||
ZYDIS_REGISTER_K1,
|
||||
ZYDIS_REGISTER_K2,
|
||||
ZYDIS_REGISTER_K3,
|
||||
ZYDIS_REGISTER_K4,
|
||||
ZYDIS_REGISTER_K5,
|
||||
ZYDIS_REGISTER_K6,
|
||||
ZYDIS_REGISTER_K7,
|
||||
|
||||
// Bound registers
|
||||
ZYDIS_REGISTER_BND0,
|
||||
ZYDIS_REGISTER_BND1,
|
||||
ZYDIS_REGISTER_BND2,
|
||||
ZYDIS_REGISTER_BND3,
|
||||
ZYDIS_REGISTER_BNDCFG,
|
||||
ZYDIS_REGISTER_BNDSTATUS,
|
||||
|
||||
// Uncategorized
|
||||
ZYDIS_REGISTER_MXCSR,
|
||||
ZYDIS_REGISTER_PKRU,
|
||||
ZYDIS_REGISTER_XCR0,
|
||||
ZYDIS_REGISTER_UIF,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_REGISTER_MAX_VALUE = ZYDIS_REGISTER_UIF,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_REGISTER_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_REGISTER_MAX_VALUE)
|
||||
} ZydisRegister;
|
||||
@@ -0,0 +1,340 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Disassembler Library (Zydis)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
#ifndef ZYDIS_INTERNAL_DECODERDATA_H
|
||||
#define ZYDIS_INTERNAL_DECODERDATA_H
|
||||
|
||||
#include <Zycore/Defines.h>
|
||||
#include <Zycore/Types.h>
|
||||
#include <Zydis/Defines.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Enums and types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
// MSVC does not like types other than (un-)signed int for bit-fields
|
||||
#ifdef ZYAN_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable:4214)
|
||||
#endif
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Decoder tree */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisDecoderTreeNodeType` data-type.
|
||||
*/
|
||||
typedef ZyanU8 ZydisDecoderTreeNodeType;
|
||||
|
||||
/**
|
||||
* Values that represent zydis decoder tree node types.
|
||||
*/
|
||||
enum ZydisDecoderTreeNodeTypes
|
||||
{
|
||||
ZYDIS_NODETYPE_INVALID = 0x00,
|
||||
/**
|
||||
* Reference to an instruction-definition.
|
||||
*/
|
||||
ZYDIS_NODETYPE_DEFINITION_MASK = 0x80,
|
||||
/**
|
||||
* Reference to an XOP-map filter.
|
||||
*/
|
||||
ZYDIS_NODETYPE_FILTER_XOP = 0x01,
|
||||
/**
|
||||
* Reference to an VEX-map filter.
|
||||
*/
|
||||
ZYDIS_NODETYPE_FILTER_VEX = 0x02,
|
||||
/**
|
||||
* Reference to an EVEX/MVEX-map filter.
|
||||
*/
|
||||
ZYDIS_NODETYPE_FILTER_EMVEX = 0x03,
|
||||
/**
|
||||
* Reference to an opcode filter.
|
||||
*/
|
||||
ZYDIS_NODETYPE_FILTER_OPCODE = 0x04,
|
||||
/**
|
||||
* Reference to an instruction-mode filter.
|
||||
*/
|
||||
ZYDIS_NODETYPE_FILTER_MODE = 0x05,
|
||||
/**
|
||||
* Reference to an compacted instruction-mode filter.
|
||||
*/
|
||||
ZYDIS_NODETYPE_FILTER_MODE_COMPACT = 0x06,
|
||||
/**
|
||||
* Reference to a ModRM.mod filter.
|
||||
*/
|
||||
ZYDIS_NODETYPE_FILTER_MODRM_MOD = 0x07,
|
||||
/**
|
||||
* Reference to a compacted ModRM.mod filter.
|
||||
*/
|
||||
ZYDIS_NODETYPE_FILTER_MODRM_MOD_COMPACT = 0x08,
|
||||
/**
|
||||
* Reference to a ModRM.reg filter.
|
||||
*/
|
||||
ZYDIS_NODETYPE_FILTER_MODRM_REG = 0x09,
|
||||
/**
|
||||
* Reference to a ModRM.rm filter.
|
||||
*/
|
||||
ZYDIS_NODETYPE_FILTER_MODRM_RM = 0x0A,
|
||||
/**
|
||||
* Reference to a PrefixGroup1 filter.
|
||||
*/
|
||||
ZYDIS_NODETYPE_FILTER_PREFIX_GROUP1 = 0x0B,
|
||||
/**
|
||||
* Reference to a mandatory-prefix filter.
|
||||
*/
|
||||
ZYDIS_NODETYPE_FILTER_MANDATORY_PREFIX = 0x0C,
|
||||
/**
|
||||
* Reference to an operand-size filter.
|
||||
*/
|
||||
ZYDIS_NODETYPE_FILTER_OPERAND_SIZE = 0x0D,
|
||||
/**
|
||||
* Reference to an address-size filter.
|
||||
*/
|
||||
ZYDIS_NODETYPE_FILTER_ADDRESS_SIZE = 0x0E,
|
||||
/**
|
||||
* Reference to a vector-length filter.
|
||||
*/
|
||||
ZYDIS_NODETYPE_FILTER_VECTOR_LENGTH = 0x0F,
|
||||
/**
|
||||
* Reference to an REX/VEX/EVEX.W filter.
|
||||
*/
|
||||
ZYDIS_NODETYPE_FILTER_REX_W = 0x10,
|
||||
/**
|
||||
* Reference to an REX/VEX/EVEX.B filter.
|
||||
*/
|
||||
ZYDIS_NODETYPE_FILTER_REX_B = 0x11,
|
||||
/**
|
||||
* Reference to an EVEX.b filter.
|
||||
*/
|
||||
ZYDIS_NODETYPE_FILTER_EVEX_B = 0x12,
|
||||
/**
|
||||
* Reference to an MVEX.E filter.
|
||||
*/
|
||||
ZYDIS_NODETYPE_FILTER_MVEX_E = 0x13,
|
||||
/**
|
||||
* Reference to a AMD-mode filter.
|
||||
*/
|
||||
ZYDIS_NODETYPE_FILTER_MODE_AMD = 0x14,
|
||||
/**
|
||||
* Reference to a KNC-mode filter.
|
||||
*/
|
||||
ZYDIS_NODETYPE_FILTER_MODE_KNC = 0x15,
|
||||
/**
|
||||
* Reference to a MPX-mode filter.
|
||||
*/
|
||||
ZYDIS_NODETYPE_FILTER_MODE_MPX = 0x16,
|
||||
/**
|
||||
* Reference to a CET-mode filter.
|
||||
*/
|
||||
ZYDIS_NODETYPE_FILTER_MODE_CET = 0x17,
|
||||
/**
|
||||
* Reference to a LZCNT-mode filter.
|
||||
*/
|
||||
ZYDIS_NODETYPE_FILTER_MODE_LZCNT = 0x18,
|
||||
/**
|
||||
* Reference to a TZCNT-mode filter.
|
||||
*/
|
||||
ZYDIS_NODETYPE_FILTER_MODE_TZCNT = 0x19,
|
||||
/**
|
||||
* Reference to a WBNOINVD-mode filter.
|
||||
*/
|
||||
ZYDIS_NODETYPE_FILTER_MODE_WBNOINVD = 0x1A,
|
||||
/**
|
||||
* Reference to a CLDEMOTE-mode filter.
|
||||
*/
|
||||
ZYDIS_NODETYPE_FILTER_MODE_CLDEMOTE = 0x1B,
|
||||
/**
|
||||
* Reference to a IPREFETCH-mode filter.
|
||||
*/
|
||||
ZYDIS_NODETYPE_FILTER_MODE_IPREFETCH = 0x1C,
|
||||
/**
|
||||
* Reference to a UD0_COMPAT-mode filter.
|
||||
*/
|
||||
ZYDIS_NODETYPE_FILTER_MODE_UD0_COMPAT = 0x1D
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisDecoderTreeNodeValue` data-type.
|
||||
*/
|
||||
typedef ZyanU16 ZydisDecoderTreeNodeValue;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisDecoderTreeNode` struct.
|
||||
*/
|
||||
typedef struct ZydisDecoderTreeNode_
|
||||
{
|
||||
ZydisDecoderTreeNodeType type;
|
||||
ZydisDecoderTreeNodeValue value;
|
||||
} ZydisDecoderTreeNode;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#ifdef ZYAN_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Physical instruction encoding info */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisInstructionEncodingFlags` data-type.
|
||||
*/
|
||||
typedef ZyanU8 ZydisInstructionEncodingFlags;
|
||||
|
||||
/**
|
||||
* The instruction has an optional modrm byte.
|
||||
*/
|
||||
#define ZYDIS_INSTR_ENC_FLAG_HAS_MODRM 0x01
|
||||
|
||||
/**
|
||||
* The instruction has an optional displacement value.
|
||||
*/
|
||||
#define ZYDIS_INSTR_ENC_FLAG_HAS_DISP 0x02
|
||||
|
||||
/**
|
||||
* The instruction has an optional immediate value.
|
||||
*/
|
||||
#define ZYDIS_INSTR_ENC_FLAG_HAS_IMM0 0x04
|
||||
|
||||
/**
|
||||
* The instruction has a second optional immediate value.
|
||||
*/
|
||||
#define ZYDIS_INSTR_ENC_FLAG_HAS_IMM1 0x08
|
||||
|
||||
/**
|
||||
* The instruction ignores the value of `modrm.mod` and always assumes `modrm.mod == 3`
|
||||
* ("reg, reg" - form).
|
||||
*
|
||||
* Instructions with this flag can't have a SIB byte or a displacement value.
|
||||
*/
|
||||
#define ZYDIS_INSTR_ENC_FLAG_FORCE_REG_FORM 0x10
|
||||
|
||||
/**
|
||||
* Defines the `ZydisInstructionEncodingInfo` struct.
|
||||
*/
|
||||
typedef struct ZydisInstructionEncodingInfo_
|
||||
{
|
||||
/**
|
||||
* Contains flags with information about the physical instruction-encoding.
|
||||
*/
|
||||
ZydisInstructionEncodingFlags flags;
|
||||
/**
|
||||
* Displacement info.
|
||||
*/
|
||||
struct
|
||||
{
|
||||
/**
|
||||
* The size of the displacement value.
|
||||
*/
|
||||
ZyanU8 size[3];
|
||||
} disp;
|
||||
/**
|
||||
* Immediate info.
|
||||
*/
|
||||
struct
|
||||
{
|
||||
/**
|
||||
* The size of the immediate value.
|
||||
*/
|
||||
ZyanU8 size[3];
|
||||
/**
|
||||
* Signals, if the value is signed.
|
||||
*/
|
||||
ZyanBool is_signed;
|
||||
/**
|
||||
* Signals, if the value is a relative offset.
|
||||
*/
|
||||
ZyanBool is_relative;
|
||||
} imm[2];
|
||||
} ZydisInstructionEncodingInfo;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Decoder tree */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
extern const ZydisDecoderTreeNode zydis_decoder_tree_root;
|
||||
|
||||
/**
|
||||
* Returns the root node of the instruction tree.
|
||||
*
|
||||
* @return The root node of the instruction tree.
|
||||
*/
|
||||
ZYAN_INLINE const ZydisDecoderTreeNode* ZydisDecoderTreeGetRootNode(void)
|
||||
{
|
||||
return &zydis_decoder_tree_root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the child node of `parent` specified by `index`.
|
||||
*
|
||||
* @param parent The parent node.
|
||||
* @param index The index of the child node to retrieve.
|
||||
*
|
||||
* @return The specified child node.
|
||||
*/
|
||||
ZYDIS_NO_EXPORT const ZydisDecoderTreeNode* ZydisDecoderTreeGetChildNode(
|
||||
const ZydisDecoderTreeNode* parent, ZyanU16 index);
|
||||
|
||||
/**
|
||||
* Returns information about optional instruction parts (like modrm, displacement or
|
||||
* immediates) for the instruction that is linked to the given `node`.
|
||||
*
|
||||
* @param node The instruction definition node.
|
||||
* @param info A pointer to the `ZydisInstructionParts` struct.
|
||||
*/
|
||||
ZYDIS_NO_EXPORT void ZydisGetInstructionEncodingInfo(const ZydisDecoderTreeNode* node,
|
||||
const ZydisInstructionEncodingInfo** info);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZYDIS_INTERNAL_DECODERDATA_H */
|
||||
@@ -0,0 +1,253 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Disassembler Library (Zydis)
|
||||
|
||||
Original Author : Mappa
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
#ifndef ZYDIS_INTERNAL_ENCODERDATA_H
|
||||
#define ZYDIS_INTERNAL_ENCODERDATA_H
|
||||
|
||||
#include <Zycore/Defines.h>
|
||||
#include <Zydis/Mnemonic.h>
|
||||
#include <Zydis/SharedTypes.h>
|
||||
|
||||
/**
|
||||
* Used in encoder's table to represent standard ISA sizes in form of bit flags.
|
||||
*/
|
||||
typedef enum ZydisWidthFlag_
|
||||
{
|
||||
ZYDIS_WIDTH_INVALID = 0x00,
|
||||
ZYDIS_WIDTH_16 = 0x01,
|
||||
ZYDIS_WIDTH_32 = 0x02,
|
||||
ZYDIS_WIDTH_64 = 0x04,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_WIDTH_MAX_VALUE = (ZYDIS_WIDTH_64 | (ZYDIS_WIDTH_64 - 1)),
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_WIDTH_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_WIDTH_MAX_VALUE)
|
||||
} ZydisWidthFlag;
|
||||
|
||||
/**
|
||||
* Used in encoder's table to represent mandatory instruction prefix. Using this enum instead of
|
||||
* actual prefix value saves space.
|
||||
*/
|
||||
typedef enum ZydisMandatoryPrefix_
|
||||
{
|
||||
ZYDIS_MANDATORY_PREFIX_NONE,
|
||||
ZYDIS_MANDATORY_PREFIX_66,
|
||||
ZYDIS_MANDATORY_PREFIX_F2,
|
||||
ZYDIS_MANDATORY_PREFIX_F3,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_MANDATORY_PREFIX_MAX_VALUE = ZYDIS_MANDATORY_PREFIX_F3,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_MANDATORY_PREFIX_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_MANDATORY_PREFIX_MAX_VALUE)
|
||||
} ZydisMandatoryPrefix;
|
||||
|
||||
/**
|
||||
* Used in encoder's table to represent vector size supported by instruction definition.
|
||||
*/
|
||||
typedef enum ZydisVectorLength_
|
||||
{
|
||||
ZYDIS_VECTOR_LENGTH_INVALID,
|
||||
ZYDIS_VECTOR_LENGTH_128,
|
||||
ZYDIS_VECTOR_LENGTH_256,
|
||||
ZYDIS_VECTOR_LENGTH_512,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_VECTOR_LENGTH_MAX_VALUE = ZYDIS_VECTOR_LENGTH_512,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_VECTOR_LENGTH_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_VECTOR_LENGTH_MAX_VALUE)
|
||||
} ZydisVectorLength;
|
||||
|
||||
/**
|
||||
* Used in encoder's table to represent hint type supported by instruction definition.
|
||||
*/
|
||||
typedef enum ZydisSizeHint_
|
||||
{
|
||||
ZYDIS_SIZE_HINT_NONE,
|
||||
ZYDIS_SIZE_HINT_ASZ,
|
||||
ZYDIS_SIZE_HINT_OSZ,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_SIZE_HINT_MAX_VALUE = ZYDIS_SIZE_HINT_OSZ,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_SIZE_HINT_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_SIZE_HINT_MAX_VALUE)
|
||||
} ZydisSizeHint;
|
||||
|
||||
/**
|
||||
* Used in encoder's primary lookup table which allows to access a set of instruction definitions
|
||||
* for specified mnemonic in constant time.
|
||||
*/
|
||||
typedef struct ZydisEncoderLookupEntry_
|
||||
{
|
||||
/**
|
||||
* Index to main array of `ZydisEncodableInstruction`.
|
||||
*/
|
||||
ZyanU16 encoder_reference;
|
||||
/**
|
||||
* The number of entries.
|
||||
*/
|
||||
ZyanU8 instruction_count;
|
||||
} ZydisEncoderLookupEntry;
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
/**
|
||||
* This structure is encoder's internal representation of encodable instruction definition.
|
||||
*/
|
||||
typedef struct ZydisEncodableInstruction_
|
||||
{
|
||||
/**
|
||||
* Index to one of decoder's instruction definition arrays.
|
||||
*/
|
||||
ZyanU16 instruction_reference;
|
||||
/**
|
||||
* Compressed information about operand count and types. Operand count is stored in lowest bits.
|
||||
* Types of subsequent operands are stored in higher bits.
|
||||
*/
|
||||
ZyanU16 operand_mask;
|
||||
/**
|
||||
* The instruction-opcode.
|
||||
*/
|
||||
ZyanU8 opcode;
|
||||
/**
|
||||
* The mandatory ModR/M value.
|
||||
*/
|
||||
ZyanU8 modrm;
|
||||
/**
|
||||
* The instruction-encoding.
|
||||
*/
|
||||
ZyanU8 encoding ZYAN_BITFIELD(ZYDIS_INSTRUCTION_ENCODING_REQUIRED_BITS);
|
||||
/**
|
||||
* The opcode map.
|
||||
*/
|
||||
ZyanU8 opcode_map ZYAN_BITFIELD(ZYDIS_OPCODE_MAP_REQUIRED_BITS);
|
||||
/**
|
||||
* The combination of allowed processor modes.
|
||||
*/
|
||||
ZyanU8 modes ZYAN_BITFIELD(ZYDIS_WIDTH_REQUIRED_BITS);
|
||||
/**
|
||||
* The combination of allowed address sizes.
|
||||
*/
|
||||
ZyanU8 address_sizes ZYAN_BITFIELD(ZYDIS_WIDTH_REQUIRED_BITS);
|
||||
/**
|
||||
* The combination of allowed operand sizes.
|
||||
*/
|
||||
ZyanU8 operand_sizes ZYAN_BITFIELD(ZYDIS_WIDTH_REQUIRED_BITS);
|
||||
/**
|
||||
* The mandatory prefix.
|
||||
*/
|
||||
ZyanU8 mandatory_prefix ZYAN_BITFIELD(ZYDIS_MANDATORY_PREFIX_REQUIRED_BITS);
|
||||
/**
|
||||
* True if `REX.W` is required for this definition.
|
||||
*/
|
||||
ZyanU8 rex_w ZYAN_BITFIELD(1);
|
||||
/**
|
||||
* The vector length.
|
||||
*/
|
||||
ZyanU8 vector_length ZYAN_BITFIELD(ZYDIS_MANDATORY_PREFIX_REQUIRED_BITS);
|
||||
/**
|
||||
* The accepted sizing hint.
|
||||
*/
|
||||
ZyanU8 accepts_hint ZYAN_BITFIELD(ZYDIS_SIZE_HINT_REQUIRED_BITS);
|
||||
/**
|
||||
* Indicates that next instruction definition can be safely used instead of current one. This
|
||||
* is used with some `VEX` instructions to take advantage of 2-byte `VEX` prefix when possible.
|
||||
* 2-byte `VEX` allows to use high registers only when operand is encoded in `modrm_reg`
|
||||
* (high bit in `REX.R`). Encoder uses swappable definitions to take advantage of this
|
||||
* optimization opportunity.
|
||||
*
|
||||
* Second use of this field is to handle special case for `mov` instruction. This particular
|
||||
* conflict is described in detail inside `ZydisHandleSwappableDefinition`.
|
||||
*/
|
||||
ZyanU8 swappable ZYAN_BITFIELD(1);
|
||||
} ZydisEncodableInstruction;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
/**
|
||||
* Contains information used by instruction size prediction algorithm inside
|
||||
* `ZydisEncoderEncodeInstructionAbsolute`.
|
||||
*/
|
||||
typedef struct ZydisEncoderRelInfo_
|
||||
{
|
||||
/**
|
||||
* Sizes of instruction variants. First index is effective address size. Second index is
|
||||
* desired immediate size (8, 16 and 32 bits respectively).
|
||||
*/
|
||||
ZyanU8 size[3][3];
|
||||
/**
|
||||
* See `ZydisSizeHint`.
|
||||
*/
|
||||
ZyanU8 accepts_scaling_hints;
|
||||
/**
|
||||
* True if instruction accepts branch hint prefixes.
|
||||
*/
|
||||
ZyanBool accepts_branch_hints;
|
||||
/**
|
||||
* True if instruction accepts bound (`BND`) prefix.
|
||||
*/
|
||||
ZyanBool accepts_bound;
|
||||
} ZydisEncoderRelInfo;
|
||||
|
||||
/**
|
||||
* Fetches array of `ZydisEncodableInstruction` structures and its size for given instruction
|
||||
* mnemonic.
|
||||
*
|
||||
* @param mnemonic Instruction mnemonic.
|
||||
* @param instruction This variable will receive a pointer to the array of
|
||||
* `ZydisEncodableInstruction` structures.
|
||||
*
|
||||
* @return Entry count (0 if function failed).
|
||||
*/
|
||||
ZyanU8 ZydisGetEncodableInstructions(ZydisMnemonic mnemonic,
|
||||
const ZydisEncodableInstruction **instruction);
|
||||
|
||||
/**
|
||||
* Fetches `ZydisEncoderRelInfo` record for given instruction mnemonic.
|
||||
*
|
||||
* @param mnemonic Instruction mnemonic.
|
||||
*
|
||||
* @return Pointer to `ZydisEncoderRelInfo` structure or `ZYAN_NULL` if instruction doesn't have
|
||||
* relative operands.
|
||||
*/
|
||||
const ZydisEncoderRelInfo *ZydisGetRelInfo(ZydisMnemonic mnemonic);
|
||||
|
||||
#endif /* ZYDIS_INTERNAL_ENCODERDATA_H */
|
||||
@@ -0,0 +1,183 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Disassembler Library (Zydis)
|
||||
|
||||
Original Author : Florian Bernd, Joel Hoener
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Implements the `AT&T` style instruction-formatter.
|
||||
*/
|
||||
|
||||
#ifndef ZYDIS_FORMATTER_ATT_H
|
||||
#define ZYDIS_FORMATTER_ATT_H
|
||||
|
||||
#include <Zydis/Formatter.h>
|
||||
#include <Zydis/Internal/FormatterBase.h>
|
||||
#include <Zydis/Internal/String.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Formatter functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Instruction */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZydisFormatterATTFormatInstruction(const ZydisFormatter* formatter,
|
||||
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Operands */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZydisFormatterATTFormatOperandMEM(const ZydisFormatter* formatter,
|
||||
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Elemental tokens */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZydisFormatterATTPrintMnemonic(const ZydisFormatter* formatter,
|
||||
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
|
||||
|
||||
ZyanStatus ZydisFormatterATTPrintRegister(const ZydisFormatter* formatter,
|
||||
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context, ZydisRegister reg);
|
||||
|
||||
ZyanStatus ZydisFormatterATTPrintAddressABS(const ZydisFormatter* formatter,
|
||||
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
|
||||
|
||||
ZyanStatus ZydisFormatterATTPrintDISP(const ZydisFormatter* formatter,
|
||||
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
|
||||
|
||||
ZyanStatus ZydisFormatterATTPrintIMM(const ZydisFormatter* formatter,
|
||||
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Fomatter presets */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* AT&T */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* The default formatter configuration for `AT&T` style disassembly.
|
||||
*/
|
||||
static const ZydisFormatter FORMATTER_ATT =
|
||||
{
|
||||
/* style */ ZYDIS_FORMATTER_STYLE_ATT,
|
||||
/* force_memory_size */ ZYAN_FALSE,
|
||||
/* force_memory_seg */ ZYAN_FALSE,
|
||||
/* force_memory_scale */ ZYAN_TRUE,
|
||||
/* force_relative_branches */ ZYAN_FALSE,
|
||||
/* force_relative_riprel */ ZYAN_FALSE,
|
||||
/* print_branch_size */ ZYAN_FALSE,
|
||||
/* detailed_prefixes */ ZYAN_FALSE,
|
||||
/* addr_base */ ZYDIS_NUMERIC_BASE_HEX,
|
||||
/* addr_signedness */ ZYDIS_SIGNEDNESS_SIGNED,
|
||||
/* addr_padding_absolute */ ZYDIS_PADDING_AUTO,
|
||||
/* addr_padding_relative */ 2,
|
||||
/* disp_base */ ZYDIS_NUMERIC_BASE_HEX,
|
||||
/* disp_signedness */ ZYDIS_SIGNEDNESS_SIGNED,
|
||||
/* disp_padding */ 2,
|
||||
/* imm_base */ ZYDIS_NUMERIC_BASE_HEX,
|
||||
/* imm_signedness */ ZYDIS_SIGNEDNESS_AUTO,
|
||||
/* imm_padding */ 2,
|
||||
/* case_prefixes */ ZYDIS_LETTER_CASE_DEFAULT,
|
||||
/* case_mnemonic */ ZYDIS_LETTER_CASE_DEFAULT,
|
||||
/* case_registers */ ZYDIS_LETTER_CASE_DEFAULT,
|
||||
/* case_typecasts */ ZYDIS_LETTER_CASE_DEFAULT,
|
||||
/* case_decorators */ ZYDIS_LETTER_CASE_DEFAULT,
|
||||
/* hex_uppercase */ ZYAN_TRUE,
|
||||
/* hex_force_leading_number */ ZYAN_FALSE,
|
||||
/* number_format */
|
||||
{
|
||||
// ZYDIS_NUMERIC_BASE_DEC
|
||||
{
|
||||
// Prefix
|
||||
{
|
||||
/* string */ ZYAN_NULL,
|
||||
/* string_data */ ZYAN_DEFINE_STRING_VIEW(""),
|
||||
/* buffer */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
},
|
||||
// Suffix
|
||||
{
|
||||
/* string */ ZYAN_NULL,
|
||||
/* string_data */ ZYAN_DEFINE_STRING_VIEW(""),
|
||||
/* buffer */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
}
|
||||
},
|
||||
// ZYDIS_NUMERIC_BASE_HEX
|
||||
{
|
||||
// Prefix
|
||||
{
|
||||
/* string */ &FORMATTER_ATT.number_format[
|
||||
ZYDIS_NUMERIC_BASE_HEX][0].string_data,
|
||||
/* string_data */ ZYAN_DEFINE_STRING_VIEW("0x"),
|
||||
/* buffer */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
},
|
||||
// Suffix
|
||||
{
|
||||
/* string */ ZYAN_NULL,
|
||||
/* string_data */ ZYAN_DEFINE_STRING_VIEW(""),
|
||||
/* buffer */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
}
|
||||
}
|
||||
},
|
||||
/* func_pre_instruction */ ZYAN_NULL,
|
||||
/* func_post_instruction */ ZYAN_NULL,
|
||||
/* func_format_instruction */ &ZydisFormatterATTFormatInstruction,
|
||||
/* func_pre_operand */ ZYAN_NULL,
|
||||
/* func_post_operand */ ZYAN_NULL,
|
||||
/* func_format_operand_reg */ &ZydisFormatterBaseFormatOperandREG,
|
||||
/* func_format_operand_mem */ &ZydisFormatterATTFormatOperandMEM,
|
||||
/* func_format_operand_ptr */ &ZydisFormatterBaseFormatOperandPTR,
|
||||
/* func_format_operand_imm */ &ZydisFormatterBaseFormatOperandIMM,
|
||||
/* func_print_mnemonic */ &ZydisFormatterATTPrintMnemonic,
|
||||
/* func_print_register */ &ZydisFormatterATTPrintRegister,
|
||||
/* func_print_address_abs */ &ZydisFormatterATTPrintAddressABS,
|
||||
/* func_print_address_rel */ &ZydisFormatterBasePrintAddressREL,
|
||||
/* func_print_disp */ &ZydisFormatterATTPrintDISP,
|
||||
/* func_print_imm */ &ZydisFormatterATTPrintIMM,
|
||||
/* func_print_typecast */ ZYAN_NULL,
|
||||
/* func_print_segment */ &ZydisFormatterBasePrintSegment,
|
||||
/* func_print_prefixes */ &ZydisFormatterBasePrintPrefixes,
|
||||
/* func_print_decorator */ &ZydisFormatterBasePrintDecorator
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // ZYDIS_FORMATTER_ATT_H
|
||||
@@ -0,0 +1,324 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Disassembler Library (Zydis)
|
||||
|
||||
Original Author : Florian Bernd, Joel Hoener
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Provides formatter functions that are shared between the different formatters.
|
||||
*/
|
||||
|
||||
#ifndef ZYDIS_FORMATTER_BASE_H
|
||||
#define ZYDIS_FORMATTER_BASE_H
|
||||
|
||||
#include <Zydis/Formatter.h>
|
||||
#include <Zydis/Internal/String.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Macros */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* String */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Appends an unsigned numeric value to the given string.
|
||||
*
|
||||
* @param formatter A pointer to the `ZydisFormatter` instance.
|
||||
* @param base The numeric base.
|
||||
* @param str The destination string.
|
||||
* @param value The value to append.
|
||||
* @param padding_length The padding length.
|
||||
* @param force_leading_number Enable this option to prepend a leading `0` if the first
|
||||
* character is non-numeric.
|
||||
*/
|
||||
#define ZYDIS_STRING_APPEND_NUM_U(formatter, base, str, value, padding_length, \
|
||||
force_leading_number) \
|
||||
switch (base) \
|
||||
{ \
|
||||
case ZYDIS_NUMERIC_BASE_DEC: \
|
||||
ZYAN_CHECK(ZydisStringAppendDecU(str, value, padding_length, \
|
||||
(formatter)->number_format[base][0].string, \
|
||||
(formatter)->number_format[base][1].string)); \
|
||||
break; \
|
||||
case ZYDIS_NUMERIC_BASE_HEX: \
|
||||
ZYAN_CHECK(ZydisStringAppendHexU(str, value, padding_length, force_leading_number, \
|
||||
(formatter)->hex_uppercase, \
|
||||
(formatter)->number_format[base][0].string, \
|
||||
(formatter)->number_format[base][1].string)); \
|
||||
break; \
|
||||
default: \
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT; \
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a signed numeric value to the given string.
|
||||
*
|
||||
* @param formatter A pointer to the `ZydisFormatter` instance.
|
||||
* @param base The numeric base.
|
||||
* @param str The destination string.
|
||||
* @param value The value to append.
|
||||
* @param padding_length The padding length.
|
||||
* @param force_leading_number Enable this option to prepend a leading `0`, if the first
|
||||
* character is non-numeric.
|
||||
* @param force_sign Enable to print the '+' sign for positive numbers.
|
||||
*/
|
||||
#define ZYDIS_STRING_APPEND_NUM_S(formatter, base, str, value, padding_length, \
|
||||
force_leading_number, force_sign) \
|
||||
switch (base) \
|
||||
{ \
|
||||
case ZYDIS_NUMERIC_BASE_DEC: \
|
||||
ZYAN_CHECK(ZydisStringAppendDecS(str, value, padding_length, force_sign, \
|
||||
(formatter)->number_format[base][0].string, \
|
||||
(formatter)->number_format[base][1].string)); \
|
||||
break; \
|
||||
case ZYDIS_NUMERIC_BASE_HEX: \
|
||||
ZYAN_CHECK(ZydisStringAppendHexS(str, value, padding_length, force_leading_number, \
|
||||
(formatter)->hex_uppercase, force_sign, \
|
||||
(formatter)->number_format[base][0].string, \
|
||||
(formatter)->number_format[base][1].string)); \
|
||||
break; \
|
||||
default: \
|
||||
return ZYAN_STATUS_INVALID_ARGUMENT; \
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Buffer */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Invokes the `ZydisFormatterBufferAppend` routine, if tokenization is enabled for the
|
||||
* current pass.
|
||||
*
|
||||
* @param buffer A pointer to the `ZydisFormatterBuffer` struct.
|
||||
* @param type The token type.
|
||||
*
|
||||
* Using this macro instead of direct calls to `ZydisFormatterBufferAppend` greatly improves the
|
||||
* performance for non-tokenizing passes.
|
||||
*/
|
||||
#define ZYDIS_BUFFER_APPEND_TOKEN(buffer, type) \
|
||||
if ((buffer)->is_token_list) \
|
||||
{ \
|
||||
ZYAN_CHECK(ZydisFormatterBufferAppend(buffer, type)); \
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a snapshot of the buffer-state.
|
||||
*
|
||||
* @param buffer A pointer to the `ZydisFormatterBuffer` struct.
|
||||
* @param state Receives a snapshot of the buffer-state.
|
||||
*
|
||||
* Using this macro instead of direct calls to `ZydisFormatterBufferRemember` improves the
|
||||
* performance for non-tokenizing passes.
|
||||
*/
|
||||
#define ZYDIS_BUFFER_REMEMBER(buffer, state) \
|
||||
if ((buffer)->is_token_list) \
|
||||
{ \
|
||||
(state) = (ZyanUPointer)(buffer)->string.vector.data; \
|
||||
} else \
|
||||
{ \
|
||||
(state) = (ZyanUPointer)(buffer)->string.vector.size; \
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a string (`STR_`-prefix) or a predefined token-list (`TOK_`-prefix).
|
||||
*
|
||||
* @param buffer A pointer to the `ZydisFormatterBuffer` struct.
|
||||
* @param name The base name (without prefix) of the string- or token.
|
||||
*/
|
||||
#define ZYDIS_BUFFER_APPEND(buffer, name) \
|
||||
if ((buffer)->is_token_list) \
|
||||
{ \
|
||||
ZYAN_CHECK(ZydisFormatterBufferAppendPredefined(buffer, TOK_ ## name)); \
|
||||
} else \
|
||||
{ \
|
||||
ZYAN_CHECK(ZydisStringAppendShort(&buffer->string, &STR_ ## name)); \
|
||||
}
|
||||
|
||||
// TODO: Implement `letter_case` for predefined tokens
|
||||
|
||||
/**
|
||||
* Appends a string (`STR_`-prefix) or a predefined token-list (`TOK_`-prefix).
|
||||
*
|
||||
* @param buffer A pointer to the `ZydisFormatterBuffer` struct.
|
||||
* @param name The base name (without prefix) of the string- or token.
|
||||
* @param letter_case The desired letter-case.
|
||||
*/
|
||||
#define ZYDIS_BUFFER_APPEND_CASE(buffer, name, letter_case) \
|
||||
if ((buffer)->is_token_list) \
|
||||
{ \
|
||||
ZYAN_CHECK(ZydisFormatterBufferAppendPredefined(buffer, TOK_ ## name)); \
|
||||
} else \
|
||||
{ \
|
||||
ZYAN_CHECK(ZydisStringAppendShortCase(&buffer->string, &STR_ ## name, letter_case)); \
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Helper functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Buffer */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
// MSVC does not like the C99 flexible-array extension
|
||||
#ifdef ZYAN_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable:4200)
|
||||
#endif
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
typedef struct ZydisPredefinedToken_
|
||||
{
|
||||
ZyanU8 size;
|
||||
ZyanU8 next;
|
||||
ZyanU8 data[];
|
||||
} ZydisPredefinedToken;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#ifdef ZYAN_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Appends a predefined token-list to the `buffer`.
|
||||
*
|
||||
* @param buffer A pointer to the `ZydisFormatterBuffer` struct.
|
||||
* @param data A pointer to the `ZydisPredefinedToken` struct.
|
||||
*
|
||||
* @return A zycore status code.
|
||||
*
|
||||
* This function is internally used to improve performance while adding static strings or multiple
|
||||
* tokens at once.
|
||||
*/
|
||||
ZYAN_INLINE ZyanStatus ZydisFormatterBufferAppendPredefined(ZydisFormatterBuffer* buffer,
|
||||
const ZydisPredefinedToken* data)
|
||||
{
|
||||
ZYAN_ASSERT(buffer);
|
||||
ZYAN_ASSERT(data);
|
||||
|
||||
const ZyanUSize len = buffer->string.vector.size;
|
||||
ZYAN_ASSERT((len > 0) && (len < 256));
|
||||
if (buffer->capacity <= len + data->size)
|
||||
{
|
||||
return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
ZydisFormatterToken* const last = (ZydisFormatterToken*)buffer->string.vector.data - 1;
|
||||
last->next = (ZyanU8)len;
|
||||
|
||||
ZYAN_MEMCPY((ZyanU8*)buffer->string.vector.data + len, &data->data[0], data->size);
|
||||
|
||||
const ZyanUSize delta = len + data->next;
|
||||
buffer->capacity -= delta;
|
||||
buffer->string.vector.data = (ZyanU8*)buffer->string.vector.data + delta;
|
||||
buffer->string.vector.size = data->size - data->next;
|
||||
buffer->string.vector.capacity = ZYAN_MIN(buffer->capacity, 255);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* General */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Returns the size to be used as explicit size suffix (`AT&T`) or explicit typecast
|
||||
* (`INTEL`), if required.
|
||||
*
|
||||
* @param formatter A pointer to the `ZydisFormatter` instance.
|
||||
* @param context A pointer to the `ZydisFormatterContext` struct.
|
||||
* @param operand The instructions first memory operand.
|
||||
*
|
||||
* @return Returns the explicit size, if required, or `0`, if not needed.
|
||||
*
|
||||
* This function always returns a size different to `0`, if the `ZYDIS_FORMATTER_PROP_FORCE_SIZE`
|
||||
* is set to `ZYAN_TRUE`.
|
||||
*/
|
||||
ZyanU32 ZydisFormatterHelperGetExplicitSize(const ZydisFormatter* formatter,
|
||||
ZydisFormatterContext* context, const ZydisDecodedOperand* operand);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Formatter functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Operands */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZydisFormatterBaseFormatOperandREG(const ZydisFormatter* formatter,
|
||||
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
|
||||
|
||||
ZyanStatus ZydisFormatterBaseFormatOperandPTR(const ZydisFormatter* formatter,
|
||||
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
|
||||
|
||||
ZyanStatus ZydisFormatterBaseFormatOperandIMM(const ZydisFormatter* formatter,
|
||||
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Elemental tokens */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZydisFormatterBasePrintAddressABS(const ZydisFormatter* formatter,
|
||||
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
|
||||
|
||||
ZyanStatus ZydisFormatterBasePrintAddressREL(const ZydisFormatter* formatter,
|
||||
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
|
||||
|
||||
ZyanStatus ZydisFormatterBasePrintIMM(const ZydisFormatter* formatter,
|
||||
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Optional tokens */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZydisFormatterBasePrintSegment(const ZydisFormatter* formatter,
|
||||
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
|
||||
|
||||
ZyanStatus ZydisFormatterBasePrintPrefixes(const ZydisFormatter* formatter,
|
||||
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
|
||||
|
||||
ZyanStatus ZydisFormatterBasePrintDecorator(const ZydisFormatter* formatter,
|
||||
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context, ZydisDecorator decorator);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // ZYDIS_FORMATTER_BASE_H
|
||||
@@ -0,0 +1,271 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Disassembler Library (Zydis)
|
||||
|
||||
Original Author : Florian Bernd, Joel Hoener
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Implements the `INTEL` style instruction-formatter.
|
||||
*/
|
||||
|
||||
#ifndef ZYDIS_FORMATTER_INTEL_H
|
||||
#define ZYDIS_FORMATTER_INTEL_H
|
||||
|
||||
#include <Zydis/Formatter.h>
|
||||
#include <Zydis/Internal/FormatterBase.h>
|
||||
#include <Zydis/Internal/String.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Formatter functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Intel */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZydisFormatterIntelFormatInstruction(const ZydisFormatter* formatter,
|
||||
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
|
||||
|
||||
ZyanStatus ZydisFormatterIntelFormatOperandMEM(const ZydisFormatter* formatter,
|
||||
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
|
||||
|
||||
ZyanStatus ZydisFormatterIntelPrintMnemonic(const ZydisFormatter* formatter,
|
||||
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
|
||||
|
||||
ZyanStatus ZydisFormatterIntelPrintRegister(const ZydisFormatter* formatter,
|
||||
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context, ZydisRegister reg);
|
||||
|
||||
ZyanStatus ZydisFormatterIntelPrintDISP(const ZydisFormatter* formatter,
|
||||
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
|
||||
|
||||
ZyanStatus ZydisFormatterIntelPrintTypecast(const ZydisFormatter* formatter,
|
||||
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* MASM */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
ZyanStatus ZydisFormatterIntelFormatInstructionMASM(const ZydisFormatter* formatter,
|
||||
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
|
||||
|
||||
ZyanStatus ZydisFormatterIntelPrintAddressMASM(const ZydisFormatter* formatter,
|
||||
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Fomatter presets */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* INTEL */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* The default formatter configuration for `INTEL` style disassembly.
|
||||
*/
|
||||
static const ZydisFormatter FORMATTER_INTEL =
|
||||
{
|
||||
/* style */ ZYDIS_FORMATTER_STYLE_INTEL,
|
||||
/* force_memory_size */ ZYAN_FALSE,
|
||||
/* force_memory_seg */ ZYAN_FALSE,
|
||||
/* force_memory_scale */ ZYAN_TRUE,
|
||||
/* force_relative_branches */ ZYAN_FALSE,
|
||||
/* force_relative_riprel */ ZYAN_FALSE,
|
||||
/* print_branch_size */ ZYAN_FALSE,
|
||||
/* detailed_prefixes */ ZYAN_FALSE,
|
||||
/* addr_base */ ZYDIS_NUMERIC_BASE_HEX,
|
||||
/* addr_signedness */ ZYDIS_SIGNEDNESS_SIGNED,
|
||||
/* addr_padding_absolute */ ZYDIS_PADDING_AUTO,
|
||||
/* addr_padding_relative */ 2,
|
||||
/* disp_base */ ZYDIS_NUMERIC_BASE_HEX,
|
||||
/* disp_signedness */ ZYDIS_SIGNEDNESS_SIGNED,
|
||||
/* disp_padding */ 2,
|
||||
/* imm_base */ ZYDIS_NUMERIC_BASE_HEX,
|
||||
/* imm_signedness */ ZYDIS_SIGNEDNESS_UNSIGNED,
|
||||
/* imm_padding */ 2,
|
||||
/* case_prefixes */ ZYDIS_LETTER_CASE_DEFAULT,
|
||||
/* case_mnemonic */ ZYDIS_LETTER_CASE_DEFAULT,
|
||||
/* case_registers */ ZYDIS_LETTER_CASE_DEFAULT,
|
||||
/* case_typecasts */ ZYDIS_LETTER_CASE_DEFAULT,
|
||||
/* case_decorators */ ZYDIS_LETTER_CASE_DEFAULT,
|
||||
/* hex_uppercase */ ZYAN_TRUE,
|
||||
/* hex_force_leading_number */ ZYAN_FALSE,
|
||||
/* number_format */
|
||||
{
|
||||
// ZYDIS_NUMERIC_BASE_DEC
|
||||
{
|
||||
// Prefix
|
||||
{
|
||||
/* string */ ZYAN_NULL,
|
||||
/* string_data */ ZYAN_DEFINE_STRING_VIEW(""),
|
||||
/* buffer */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
},
|
||||
// Suffix
|
||||
{
|
||||
/* string */ ZYAN_NULL,
|
||||
/* string_data */ ZYAN_DEFINE_STRING_VIEW(""),
|
||||
/* buffer */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
}
|
||||
},
|
||||
// ZYDIS_NUMERIC_BASE_HEX
|
||||
{
|
||||
// Prefix
|
||||
{
|
||||
/* string */ &FORMATTER_INTEL.number_format[
|
||||
ZYDIS_NUMERIC_BASE_HEX][0].string_data,
|
||||
/* string_data */ ZYAN_DEFINE_STRING_VIEW("0x"),
|
||||
/* buffer */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
},
|
||||
// Suffix
|
||||
{
|
||||
/* string */ ZYAN_NULL,
|
||||
/* string_data */ ZYAN_DEFINE_STRING_VIEW(""),
|
||||
/* buffer */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
}
|
||||
}
|
||||
},
|
||||
/* func_pre_instruction */ ZYAN_NULL,
|
||||
/* func_post_instruction */ ZYAN_NULL,
|
||||
/* func_format_instruction */ &ZydisFormatterIntelFormatInstruction,
|
||||
/* func_pre_operand */ ZYAN_NULL,
|
||||
/* func_post_operand */ ZYAN_NULL,
|
||||
/* func_format_operand_reg */ &ZydisFormatterBaseFormatOperandREG,
|
||||
/* func_format_operand_mem */ &ZydisFormatterIntelFormatOperandMEM,
|
||||
/* func_format_operand_ptr */ &ZydisFormatterBaseFormatOperandPTR,
|
||||
/* func_format_operand_imm */ &ZydisFormatterBaseFormatOperandIMM,
|
||||
/* func_print_mnemonic */ &ZydisFormatterIntelPrintMnemonic,
|
||||
/* func_print_register */ &ZydisFormatterIntelPrintRegister,
|
||||
/* func_print_address_abs */ &ZydisFormatterBasePrintAddressABS,
|
||||
/* func_print_address_rel */ &ZydisFormatterBasePrintAddressREL,
|
||||
/* func_print_disp */ &ZydisFormatterIntelPrintDISP,
|
||||
/* func_print_imm */ &ZydisFormatterBasePrintIMM,
|
||||
/* func_print_typecast */ &ZydisFormatterIntelPrintTypecast,
|
||||
/* func_print_segment */ &ZydisFormatterBasePrintSegment,
|
||||
/* func_print_prefixes */ &ZydisFormatterBasePrintPrefixes,
|
||||
/* func_print_decorator */ &ZydisFormatterBasePrintDecorator
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* MASM */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* The default formatter configuration for `MASM` style disassembly.
|
||||
*/
|
||||
static const ZydisFormatter FORMATTER_INTEL_MASM =
|
||||
{
|
||||
/* style */ ZYDIS_FORMATTER_STYLE_INTEL_MASM,
|
||||
/* force_memory_size */ ZYAN_TRUE,
|
||||
/* force_memory_seg */ ZYAN_FALSE,
|
||||
/* force_memory_scale */ ZYAN_TRUE,
|
||||
/* force_relative_branches */ ZYAN_FALSE,
|
||||
/* force_relative_riprel */ ZYAN_FALSE,
|
||||
/* print_branch_size */ ZYAN_FALSE,
|
||||
/* detailed_prefixes */ ZYAN_FALSE,
|
||||
/* addr_base */ ZYDIS_NUMERIC_BASE_HEX,
|
||||
/* addr_signedness */ ZYDIS_SIGNEDNESS_SIGNED,
|
||||
/* addr_padding_absolute */ ZYDIS_PADDING_DISABLED,
|
||||
/* addr_padding_relative */ ZYDIS_PADDING_DISABLED,
|
||||
/* disp_base */ ZYDIS_NUMERIC_BASE_HEX,
|
||||
/* disp_signedness */ ZYDIS_SIGNEDNESS_SIGNED,
|
||||
/* disp_padding */ ZYDIS_PADDING_DISABLED,
|
||||
/* imm_base */ ZYDIS_NUMERIC_BASE_HEX,
|
||||
/* imm_signedness */ ZYDIS_SIGNEDNESS_AUTO,
|
||||
/* imm_padding */ ZYDIS_PADDING_DISABLED,
|
||||
/* case_prefixes */ ZYDIS_LETTER_CASE_DEFAULT,
|
||||
/* case_mnemonic */ ZYDIS_LETTER_CASE_DEFAULT,
|
||||
/* case_registers */ ZYDIS_LETTER_CASE_DEFAULT,
|
||||
/* case_typecasts */ ZYDIS_LETTER_CASE_DEFAULT,
|
||||
/* case_decorators */ ZYDIS_LETTER_CASE_DEFAULT,
|
||||
/* hex_uppercase */ ZYAN_TRUE,
|
||||
/* hex_force_leading_number */ ZYAN_TRUE,
|
||||
/* number_format */
|
||||
{
|
||||
// ZYDIS_NUMERIC_BASE_DEC
|
||||
{
|
||||
// Prefix
|
||||
{
|
||||
/* string */ ZYAN_NULL,
|
||||
/* string_data */ ZYAN_DEFINE_STRING_VIEW(""),
|
||||
/* buffer */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
},
|
||||
// Suffix
|
||||
{
|
||||
/* string */ ZYAN_NULL,
|
||||
/* string_data */ ZYAN_DEFINE_STRING_VIEW(""),
|
||||
/* buffer */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
}
|
||||
},
|
||||
// ZYDIS_NUMERIC_BASE_HEX
|
||||
{
|
||||
// Prefix
|
||||
{
|
||||
/* string */ ZYAN_NULL,
|
||||
/* string_data */ ZYAN_DEFINE_STRING_VIEW(""),
|
||||
/* buffer */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
},
|
||||
// Suffix
|
||||
{
|
||||
/* string */ &FORMATTER_INTEL_MASM.number_format[
|
||||
ZYDIS_NUMERIC_BASE_HEX][1].string_data,
|
||||
/* string_data */ ZYAN_DEFINE_STRING_VIEW("h"),
|
||||
/* buffer */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
}
|
||||
}
|
||||
},
|
||||
/* func_pre_instruction */ ZYAN_NULL,
|
||||
/* func_post_instruction */ ZYAN_NULL,
|
||||
/* func_format_instruction */ &ZydisFormatterIntelFormatInstructionMASM,
|
||||
/* func_pre_operand */ ZYAN_NULL,
|
||||
/* func_post_operand */ ZYAN_NULL,
|
||||
/* func_format_operand_reg */ &ZydisFormatterBaseFormatOperandREG,
|
||||
/* func_format_operand_mem */ &ZydisFormatterIntelFormatOperandMEM,
|
||||
/* func_format_operand_ptr */ &ZydisFormatterBaseFormatOperandPTR,
|
||||
/* func_format_operand_imm */ &ZydisFormatterBaseFormatOperandIMM,
|
||||
/* func_print_mnemonic */ &ZydisFormatterIntelPrintMnemonic,
|
||||
/* func_print_register */ &ZydisFormatterIntelPrintRegister,
|
||||
/* func_print_address_abs */ &ZydisFormatterIntelPrintAddressMASM,
|
||||
/* func_print_address_rel */ &ZydisFormatterIntelPrintAddressMASM,
|
||||
/* func_print_disp */ &ZydisFormatterIntelPrintDISP,
|
||||
/* func_print_imm */ &ZydisFormatterBasePrintIMM,
|
||||
/* func_print_typecast */ &ZydisFormatterIntelPrintTypecast,
|
||||
/* func_print_segment */ &ZydisFormatterBasePrintSegment,
|
||||
/* func_print_prefixes */ &ZydisFormatterBasePrintPrefixes,
|
||||
/* func_print_decorator */ &ZydisFormatterBasePrintDecorator
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // ZYDIS_FORMATTER_INTEL_H
|
||||
@@ -0,0 +1,984 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Disassembler Library (Zydis)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
#ifndef ZYDIS_INTERNAL_SHAREDDATA_H
|
||||
#define ZYDIS_INTERNAL_SHAREDDATA_H
|
||||
|
||||
#include <Zycore/Defines.h>
|
||||
#include <Zydis/Mnemonic.h>
|
||||
#include <Zydis/Register.h>
|
||||
#include <Zydis/SharedTypes.h>
|
||||
#include <Zydis/DecoderTypes.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Enums and types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
// MSVC does not like types other than (un-)signed int for bit-fields
|
||||
#ifdef ZYAN_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable:4214)
|
||||
#endif
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Operand definition */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisSemanticOperandType` enum.
|
||||
*/
|
||||
typedef enum ZydisSemanticOperandType_
|
||||
{
|
||||
ZYDIS_SEMANTIC_OPTYPE_UNUSED,
|
||||
ZYDIS_SEMANTIC_OPTYPE_IMPLICIT_REG,
|
||||
ZYDIS_SEMANTIC_OPTYPE_IMPLICIT_MEM,
|
||||
ZYDIS_SEMANTIC_OPTYPE_IMPLICIT_IMM1,
|
||||
ZYDIS_SEMANTIC_OPTYPE_GPR8,
|
||||
ZYDIS_SEMANTIC_OPTYPE_GPR16,
|
||||
ZYDIS_SEMANTIC_OPTYPE_GPR32,
|
||||
ZYDIS_SEMANTIC_OPTYPE_GPR64,
|
||||
ZYDIS_SEMANTIC_OPTYPE_GPR16_32_64,
|
||||
ZYDIS_SEMANTIC_OPTYPE_GPR32_32_64,
|
||||
ZYDIS_SEMANTIC_OPTYPE_GPR16_32_32,
|
||||
ZYDIS_SEMANTIC_OPTYPE_GPR_ASZ,
|
||||
ZYDIS_SEMANTIC_OPTYPE_FPR,
|
||||
ZYDIS_SEMANTIC_OPTYPE_MMX,
|
||||
ZYDIS_SEMANTIC_OPTYPE_XMM,
|
||||
ZYDIS_SEMANTIC_OPTYPE_YMM,
|
||||
ZYDIS_SEMANTIC_OPTYPE_ZMM,
|
||||
ZYDIS_SEMANTIC_OPTYPE_TMM,
|
||||
ZYDIS_SEMANTIC_OPTYPE_BND,
|
||||
ZYDIS_SEMANTIC_OPTYPE_SREG,
|
||||
ZYDIS_SEMANTIC_OPTYPE_CR,
|
||||
ZYDIS_SEMANTIC_OPTYPE_DR,
|
||||
ZYDIS_SEMANTIC_OPTYPE_MASK,
|
||||
ZYDIS_SEMANTIC_OPTYPE_MEM,
|
||||
ZYDIS_SEMANTIC_OPTYPE_MEM_VSIBX,
|
||||
ZYDIS_SEMANTIC_OPTYPE_MEM_VSIBY,
|
||||
ZYDIS_SEMANTIC_OPTYPE_MEM_VSIBZ,
|
||||
ZYDIS_SEMANTIC_OPTYPE_IMM,
|
||||
ZYDIS_SEMANTIC_OPTYPE_REL,
|
||||
ZYDIS_SEMANTIC_OPTYPE_PTR,
|
||||
ZYDIS_SEMANTIC_OPTYPE_AGEN,
|
||||
ZYDIS_SEMANTIC_OPTYPE_MOFFS,
|
||||
ZYDIS_SEMANTIC_OPTYPE_MIB,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_SEMANTIC_OPTYPE_MAX_VALUE = ZYDIS_SEMANTIC_OPTYPE_MIB,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_SEMANTIC_OPTYPE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_SEMANTIC_OPTYPE_MAX_VALUE)
|
||||
} ZydisSemanticOperandType;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisInternalElementType` enum.
|
||||
*/
|
||||
typedef enum ZydisInternalElementType_
|
||||
{
|
||||
ZYDIS_IELEMENT_TYPE_INVALID,
|
||||
ZYDIS_IELEMENT_TYPE_VARIABLE,
|
||||
ZYDIS_IELEMENT_TYPE_STRUCT,
|
||||
ZYDIS_IELEMENT_TYPE_INT,
|
||||
ZYDIS_IELEMENT_TYPE_UINT,
|
||||
ZYDIS_IELEMENT_TYPE_INT1,
|
||||
ZYDIS_IELEMENT_TYPE_INT8,
|
||||
ZYDIS_IELEMENT_TYPE_INT8X4,
|
||||
ZYDIS_IELEMENT_TYPE_INT16,
|
||||
ZYDIS_IELEMENT_TYPE_INT16X2,
|
||||
ZYDIS_IELEMENT_TYPE_INT32,
|
||||
ZYDIS_IELEMENT_TYPE_INT64,
|
||||
ZYDIS_IELEMENT_TYPE_UINT8,
|
||||
ZYDIS_IELEMENT_TYPE_UINT8X4,
|
||||
ZYDIS_IELEMENT_TYPE_UINT16,
|
||||
ZYDIS_IELEMENT_TYPE_UINT16X2,
|
||||
ZYDIS_IELEMENT_TYPE_UINT32,
|
||||
ZYDIS_IELEMENT_TYPE_UINT64,
|
||||
ZYDIS_IELEMENT_TYPE_UINT128,
|
||||
ZYDIS_IELEMENT_TYPE_UINT256,
|
||||
ZYDIS_IELEMENT_TYPE_FLOAT16,
|
||||
ZYDIS_IELEMENT_TYPE_FLOAT16X2,
|
||||
ZYDIS_IELEMENT_TYPE_FLOAT32,
|
||||
ZYDIS_IELEMENT_TYPE_FLOAT64,
|
||||
ZYDIS_IELEMENT_TYPE_FLOAT80,
|
||||
ZYDIS_IELEMENT_TYPE_BFLOAT16X2,
|
||||
ZYDIS_IELEMENT_TYPE_BCD80,
|
||||
ZYDIS_IELEMENT_TYPE_CC3,
|
||||
ZYDIS_IELEMENT_TYPE_CC5,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_IELEMENT_TYPE_MAX_VALUE = ZYDIS_IELEMENT_TYPE_CC5,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_IELEMENT_TYPE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_IELEMENT_TYPE_MAX_VALUE)
|
||||
} ZydisInternalElementType;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisImplicitRegisterType` enum.
|
||||
*/
|
||||
typedef enum ZydisImplicitRegisterType_
|
||||
{
|
||||
// TODO: Rename OSZ|ASZ|SSZ_
|
||||
ZYDIS_IMPLREG_TYPE_STATIC,
|
||||
ZYDIS_IMPLREG_TYPE_GPR_OSZ,
|
||||
ZYDIS_IMPLREG_TYPE_GPR_ASZ,
|
||||
ZYDIS_IMPLREG_TYPE_IP_ASZ,
|
||||
ZYDIS_IMPLREG_TYPE_IP_SSZ,
|
||||
ZYDIS_IMPLREG_TYPE_GPR_SSZ,
|
||||
ZYDIS_IMPLREG_TYPE_FLAGS_SSZ,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_IMPLREG_TYPE_MAX_VALUE = ZYDIS_IMPLREG_TYPE_FLAGS_SSZ,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_IMPLREG_TYPE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_IMPLREG_TYPE_MAX_VALUE)
|
||||
} ZydisImplicitRegisterType;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisImplicitMemBase` enum.
|
||||
*/
|
||||
typedef enum ZydisImplicitMemBase_
|
||||
{
|
||||
// TODO: Rename OSZ|ASZ|SSZ_
|
||||
ZYDIS_IMPLMEM_BASE_AGPR_REG,
|
||||
ZYDIS_IMPLMEM_BASE_AGPR_RM,
|
||||
ZYDIS_IMPLMEM_BASE_AAX,
|
||||
ZYDIS_IMPLMEM_BASE_ADX,
|
||||
ZYDIS_IMPLMEM_BASE_ABX,
|
||||
ZYDIS_IMPLMEM_BASE_ASI,
|
||||
ZYDIS_IMPLMEM_BASE_ADI,
|
||||
ZYDIS_IMPLMEM_BASE_SSP,
|
||||
ZYDIS_IMPLMEM_BASE_SBP,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_IMPLMEM_BASE_MAX_VALUE = ZYDIS_IMPLMEM_BASE_SBP,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_IMPLMEM_BASE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_IMPLMEM_BASE_MAX_VALUE)
|
||||
} ZydisImplicitMemBase;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
// MSVC does not correctly execute the `pragma pack(1)` compiler-directive, if we use the correct
|
||||
// enum types
|
||||
ZYAN_STATIC_ASSERT(ZYDIS_SEMANTIC_OPTYPE_REQUIRED_BITS <= 8);
|
||||
ZYAN_STATIC_ASSERT(ZYDIS_OPERAND_VISIBILITY_REQUIRED_BITS <= 8);
|
||||
ZYAN_STATIC_ASSERT(ZYDIS_OPERAND_ACTION_REQUIRED_BITS <= 8);
|
||||
ZYAN_STATIC_ASSERT(ZYDIS_IELEMENT_TYPE_REQUIRED_BITS <= 8);
|
||||
ZYAN_STATIC_ASSERT(ZYDIS_OPERAND_ENCODING_REQUIRED_BITS <= 8);
|
||||
ZYAN_STATIC_ASSERT(ZYDIS_IMPLREG_TYPE_REQUIRED_BITS <= 8);
|
||||
ZYAN_STATIC_ASSERT(ZYDIS_REGISTER_REQUIRED_BITS <= 16);
|
||||
ZYAN_STATIC_ASSERT(ZYDIS_IMPLMEM_BASE_REQUIRED_BITS <= 8);
|
||||
|
||||
/**
|
||||
* Defines the `ZydisOperandDefinition` struct.
|
||||
*/
|
||||
typedef struct ZydisOperandDefinition_
|
||||
{
|
||||
ZyanU8 type ZYAN_BITFIELD(ZYDIS_SEMANTIC_OPTYPE_REQUIRED_BITS);
|
||||
ZyanU8 visibility ZYAN_BITFIELD(ZYDIS_OPERAND_VISIBILITY_REQUIRED_BITS);
|
||||
ZyanU8 actions ZYAN_BITFIELD(ZYDIS_OPERAND_ACTION_REQUIRED_BITS);
|
||||
ZyanU16 size[3];
|
||||
ZyanU8 element_type ZYAN_BITFIELD(ZYDIS_IELEMENT_TYPE_REQUIRED_BITS);
|
||||
union
|
||||
{
|
||||
ZyanU8 encoding ZYAN_BITFIELD(ZYDIS_OPERAND_ENCODING_REQUIRED_BITS);
|
||||
struct
|
||||
{
|
||||
ZyanU8 type ZYAN_BITFIELD(ZYDIS_IMPLREG_TYPE_REQUIRED_BITS);
|
||||
union
|
||||
{
|
||||
ZyanU16 reg ZYAN_BITFIELD(ZYDIS_REGISTER_REQUIRED_BITS);
|
||||
ZyanU8 id ZYAN_BITFIELD(6);
|
||||
} reg;
|
||||
} reg;
|
||||
struct
|
||||
{
|
||||
ZyanU8 seg ZYAN_BITFIELD(3);
|
||||
ZyanU8 base ZYAN_BITFIELD(ZYDIS_IMPLMEM_BASE_REQUIRED_BITS);
|
||||
} mem;
|
||||
} op;
|
||||
ZyanBool is_multisource4 ZYAN_BITFIELD(1);
|
||||
ZyanBool ignore_seg_override ZYAN_BITFIELD(1);
|
||||
} ZydisOperandDefinition;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Instruction definition */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisReadWriteAction` enum.
|
||||
*/
|
||||
typedef enum ZydisReadWriteAction_
|
||||
{
|
||||
ZYDIS_RW_ACTION_NONE,
|
||||
ZYDIS_RW_ACTION_READ,
|
||||
ZYDIS_RW_ACTION_WRITE,
|
||||
ZYDIS_RW_ACTION_READWRITE,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_RW_ACTION_MAX_VALUE = ZYDIS_RW_ACTION_READWRITE,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_RW_ACTION_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_RW_ACTION_MAX_VALUE)
|
||||
} ZydisReadWriteAction;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisInternalVectorLength` enum.
|
||||
*/
|
||||
typedef enum ZydisInternalVectorLength_
|
||||
{
|
||||
ZYDIS_IVECTOR_LENGTH_DEFAULT,
|
||||
ZYDIS_IVECTOR_LENGTH_FIXED_128,
|
||||
ZYDIS_IVECTOR_LENGTH_FIXED_256,
|
||||
ZYDIS_IVECTOR_LENGTH_FIXED_512,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_IVECTOR_LENGTH_MAX_VALUE = ZYDIS_IVECTOR_LENGTH_FIXED_512,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_IVECTOR_LENGTH_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_IVECTOR_LENGTH_MAX_VALUE)
|
||||
} ZydisInternalVectorLength;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisInternalElementSize` enum.
|
||||
*/
|
||||
typedef enum ZydisInternalElementSize_
|
||||
{
|
||||
ZYDIS_IELEMENT_SIZE_INVALID,
|
||||
ZYDIS_IELEMENT_SIZE_8,
|
||||
ZYDIS_IELEMENT_SIZE_16,
|
||||
ZYDIS_IELEMENT_SIZE_32,
|
||||
ZYDIS_IELEMENT_SIZE_64,
|
||||
ZYDIS_IELEMENT_SIZE_128,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_IELEMENT_SIZE_MAX_VALUE = ZYDIS_IELEMENT_SIZE_128,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_IELEMENT_SIZE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_IELEMENT_SIZE_MAX_VALUE)
|
||||
} ZydisInternalElementSize;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisEVEXFunctionality` enum.
|
||||
*/
|
||||
typedef enum ZydisEVEXFunctionality_
|
||||
{
|
||||
ZYDIS_EVEX_FUNC_INVALID,
|
||||
/**
|
||||
* `EVEX.b` enables broadcast functionality.
|
||||
*/
|
||||
ZYDIS_EVEX_FUNC_BC,
|
||||
/**
|
||||
* `EVEX.b` enables embedded-rounding functionality.
|
||||
*/
|
||||
ZYDIS_EVEX_FUNC_RC,
|
||||
/**
|
||||
* `EVEX.b` enables sae functionality.
|
||||
*/
|
||||
ZYDIS_EVEX_FUNC_SAE,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_EVEX_FUNC_MAX_VALUE = ZYDIS_EVEX_FUNC_SAE,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_EVEX_FUNC_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_EVEX_FUNC_MAX_VALUE)
|
||||
} ZydisEVEXFunctionality;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisEVEXTupleType` enum.
|
||||
*/
|
||||
typedef enum ZydisEVEXTupleType_
|
||||
{
|
||||
ZYDIS_TUPLETYPE_INVALID,
|
||||
/**
|
||||
* Full Vector
|
||||
*/
|
||||
ZYDIS_TUPLETYPE_FV,
|
||||
/**
|
||||
* Half Vector
|
||||
*/
|
||||
ZYDIS_TUPLETYPE_HV,
|
||||
/**
|
||||
* Full Vector Mem
|
||||
*/
|
||||
ZYDIS_TUPLETYPE_FVM,
|
||||
/**
|
||||
* Tuple1 Scalar
|
||||
*/
|
||||
ZYDIS_TUPLETYPE_T1S,
|
||||
/**
|
||||
* Tuple1 Fixed
|
||||
*/
|
||||
ZYDIS_TUPLETYPE_T1F,
|
||||
/**
|
||||
* Tuple1 4x32
|
||||
*/
|
||||
ZYDIS_TUPLETYPE_T1_4X,
|
||||
/**
|
||||
* Gather / Scatter
|
||||
*/
|
||||
ZYDIS_TUPLETYPE_GSCAT,
|
||||
/**
|
||||
* Tuple2
|
||||
*/
|
||||
ZYDIS_TUPLETYPE_T2,
|
||||
/**
|
||||
* Tuple4
|
||||
*/
|
||||
ZYDIS_TUPLETYPE_T4,
|
||||
/**
|
||||
* Tuple8
|
||||
*/
|
||||
ZYDIS_TUPLETYPE_T8,
|
||||
/**
|
||||
* Half Mem
|
||||
*/
|
||||
ZYDIS_TUPLETYPE_HVM,
|
||||
/**
|
||||
* QuarterMem
|
||||
*/
|
||||
ZYDIS_TUPLETYPE_QVM,
|
||||
/**
|
||||
* OctMem
|
||||
*/
|
||||
ZYDIS_TUPLETYPE_OVM,
|
||||
/**
|
||||
* Mem128
|
||||
*/
|
||||
ZYDIS_TUPLETYPE_M128,
|
||||
/**
|
||||
* MOVDDUP
|
||||
*/
|
||||
ZYDIS_TUPLETYPE_DUP,
|
||||
/**
|
||||
* Quarter of the vector-length.
|
||||
*/
|
||||
ZYDIS_TUPLETYPE_QUARTER,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_TUPLETYPE_MAX_VALUE = ZYDIS_TUPLETYPE_QUARTER,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_TUPLETYPE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_TUPLETYPE_MAX_VALUE)
|
||||
} ZydisEVEXTupleType;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisMVEXFunctionality` enum.
|
||||
*/
|
||||
typedef enum ZydisMVEXFunctionality_
|
||||
{
|
||||
/**
|
||||
* The `MVEX.SSS` value is ignored.
|
||||
*/
|
||||
ZYDIS_MVEX_FUNC_IGNORED,
|
||||
/**
|
||||
* `MVEX.SSS` must be `000b`.
|
||||
*/
|
||||
ZYDIS_MVEX_FUNC_INVALID,
|
||||
/**
|
||||
* `MVEX.SSS` controls embedded-rounding functionality.
|
||||
*/
|
||||
ZYDIS_MVEX_FUNC_RC,
|
||||
/**
|
||||
* `MVEX.SSS` controls sae functionality.
|
||||
*/
|
||||
ZYDIS_MVEX_FUNC_SAE,
|
||||
/**
|
||||
* No special operation (32bit float elements).
|
||||
*/
|
||||
ZYDIS_MVEX_FUNC_F_32,
|
||||
/**
|
||||
* No special operation (32bit uint elements).
|
||||
*/
|
||||
ZYDIS_MVEX_FUNC_I_32,
|
||||
/**
|
||||
* No special operation (64bit float elements).
|
||||
*/
|
||||
ZYDIS_MVEX_FUNC_F_64,
|
||||
/**
|
||||
* No special operation (64bit uint elements).
|
||||
*/
|
||||
ZYDIS_MVEX_FUNC_I_64,
|
||||
/**
|
||||
* Sf32(reg) or Si32(reg).
|
||||
*/
|
||||
ZYDIS_MVEX_FUNC_SWIZZLE_32,
|
||||
/**
|
||||
* Sf64(reg) or Si64(reg).
|
||||
*/
|
||||
ZYDIS_MVEX_FUNC_SWIZZLE_64,
|
||||
/**
|
||||
* Sf32(mem).
|
||||
*/
|
||||
ZYDIS_MVEX_FUNC_SF_32,
|
||||
/**
|
||||
* Sf32(mem) broadcast only.
|
||||
*/
|
||||
ZYDIS_MVEX_FUNC_SF_32_BCST,
|
||||
/**
|
||||
* Sf32(mem) broadcast 4to16 only.
|
||||
*/
|
||||
ZYDIS_MVEX_FUNC_SF_32_BCST_4TO16,
|
||||
/**
|
||||
* Sf64(mem).
|
||||
*/
|
||||
ZYDIS_MVEX_FUNC_SF_64,
|
||||
/**
|
||||
* Si32(mem).
|
||||
*/
|
||||
ZYDIS_MVEX_FUNC_SI_32,
|
||||
/**
|
||||
* Si32(mem) broadcast only.
|
||||
*/
|
||||
ZYDIS_MVEX_FUNC_SI_32_BCST,
|
||||
/**
|
||||
* Si32(mem) broadcast 4to16 only.
|
||||
*/
|
||||
ZYDIS_MVEX_FUNC_SI_32_BCST_4TO16,
|
||||
/**
|
||||
* Si64(mem).
|
||||
*/
|
||||
ZYDIS_MVEX_FUNC_SI_64,
|
||||
/**
|
||||
* Uf32.
|
||||
*/
|
||||
ZYDIS_MVEX_FUNC_UF_32,
|
||||
/**
|
||||
* Uf64.
|
||||
*/
|
||||
ZYDIS_MVEX_FUNC_UF_64,
|
||||
/**
|
||||
* Ui32.
|
||||
*/
|
||||
ZYDIS_MVEX_FUNC_UI_32,
|
||||
/**
|
||||
* Ui64.
|
||||
*/
|
||||
ZYDIS_MVEX_FUNC_UI_64,
|
||||
/**
|
||||
* Df32.
|
||||
*/
|
||||
ZYDIS_MVEX_FUNC_DF_32,
|
||||
/**
|
||||
* Df64.
|
||||
*/
|
||||
ZYDIS_MVEX_FUNC_DF_64,
|
||||
/**
|
||||
* Di32.
|
||||
*/
|
||||
ZYDIS_MVEX_FUNC_DI_32,
|
||||
/**
|
||||
* Di64.
|
||||
*/
|
||||
ZYDIS_MVEX_FUNC_DI_64,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_MVEX_FUNC_MAX_VALUE = ZYDIS_MVEX_FUNC_DI_64,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_MVEX_FUNC_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_MVEX_FUNC_MAX_VALUE)
|
||||
} ZydisMVEXFunctionality;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisVEXStaticBroadcast` enum.
|
||||
*/
|
||||
typedef enum ZydisVEXStaticBroadcast
|
||||
{
|
||||
ZYDIS_VEX_STATIC_BROADCAST_NONE,
|
||||
ZYDIS_VEX_STATIC_BROADCAST_1_TO_2,
|
||||
ZYDIS_VEX_STATIC_BROADCAST_1_TO_4,
|
||||
ZYDIS_VEX_STATIC_BROADCAST_1_TO_8,
|
||||
ZYDIS_VEX_STATIC_BROADCAST_1_TO_16,
|
||||
ZYDIS_VEX_STATIC_BROADCAST_1_TO_32,
|
||||
ZYDIS_VEX_STATIC_BROADCAST_2_TO_4,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_VEX_STATIC_BROADCAST_MAX_VALUE = ZYDIS_VEX_STATIC_BROADCAST_2_TO_4,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_VEX_STATIC_BROADCAST_REQUIRED_BITS =
|
||||
ZYAN_BITS_TO_REPRESENT(ZYDIS_VEX_STATIC_BROADCAST_MAX_VALUE)
|
||||
} ZydisVEXStaticBroadcast;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisEVEXStaticBroadcast` enum.
|
||||
*/
|
||||
typedef enum ZydisEVEXStaticBroadcast_
|
||||
{
|
||||
ZYDIS_EVEX_STATIC_BROADCAST_NONE,
|
||||
ZYDIS_EVEX_STATIC_BROADCAST_1_TO_2,
|
||||
ZYDIS_EVEX_STATIC_BROADCAST_1_TO_4,
|
||||
ZYDIS_EVEX_STATIC_BROADCAST_1_TO_8,
|
||||
ZYDIS_EVEX_STATIC_BROADCAST_1_TO_16,
|
||||
ZYDIS_EVEX_STATIC_BROADCAST_1_TO_32,
|
||||
ZYDIS_EVEX_STATIC_BROADCAST_1_TO_64,
|
||||
ZYDIS_EVEX_STATIC_BROADCAST_2_TO_4,
|
||||
ZYDIS_EVEX_STATIC_BROADCAST_2_TO_8,
|
||||
ZYDIS_EVEX_STATIC_BROADCAST_2_TO_16,
|
||||
ZYDIS_EVEX_STATIC_BROADCAST_4_TO_8,
|
||||
ZYDIS_EVEX_STATIC_BROADCAST_4_TO_16,
|
||||
ZYDIS_EVEX_STATIC_BROADCAST_8_TO_16,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_EVEX_STATIC_BROADCAST_MAX_VALUE = ZYDIS_EVEX_STATIC_BROADCAST_8_TO_16,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_EVEX_STATIC_BROADCAST_REQUIRED_BITS =
|
||||
ZYAN_BITS_TO_REPRESENT(ZYDIS_EVEX_STATIC_BROADCAST_MAX_VALUE)
|
||||
} ZydisEVEXStaticBroadcast;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisMVEXStaticBroadcast` enum.
|
||||
*/
|
||||
typedef enum ZydisMVEXStaticBroadcast_
|
||||
{
|
||||
ZYDIS_MVEX_STATIC_BROADCAST_NONE,
|
||||
ZYDIS_MVEX_STATIC_BROADCAST_1_TO_8,
|
||||
ZYDIS_MVEX_STATIC_BROADCAST_1_TO_16,
|
||||
ZYDIS_MVEX_STATIC_BROADCAST_4_TO_8,
|
||||
ZYDIS_MVEX_STATIC_BROADCAST_4_TO_16,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_MVEX_STATIC_BROADCAST_MAX_VALUE = ZYDIS_MVEX_STATIC_BROADCAST_4_TO_16,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_MVEX_STATIC_BROADCAST_REQUIRED_BITS =
|
||||
ZYAN_BITS_TO_REPRESENT(ZYDIS_MVEX_STATIC_BROADCAST_MAX_VALUE)
|
||||
} ZydisMVEXStaticBroadcast;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisMaskPolicy` enum.
|
||||
*/
|
||||
typedef enum ZydisMaskPolicy_
|
||||
{
|
||||
ZYDIS_MASK_POLICY_INVALID,
|
||||
/**
|
||||
* The instruction accepts mask-registers other than the default-mask (K0), but
|
||||
* does not require them.
|
||||
*/
|
||||
ZYDIS_MASK_POLICY_ALLOWED,
|
||||
/**
|
||||
* The instruction requires a mask-register other than the default-mask (K0).
|
||||
*/
|
||||
ZYDIS_MASK_POLICY_REQUIRED,
|
||||
/**
|
||||
* The instruction does not allow a mask-register other than the default-mask (K0).
|
||||
*/
|
||||
ZYDIS_MASK_POLICY_FORBIDDEN,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_MASK_POLICY_MAX_VALUE = ZYDIS_MASK_POLICY_FORBIDDEN,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_MASK_POLICY_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_MASK_POLICY_MAX_VALUE)
|
||||
} ZydisMaskPolicy;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisMaskOverride` enum.
|
||||
*/
|
||||
typedef enum ZydisMaskOverride_
|
||||
{
|
||||
ZYDIS_MASK_OVERRIDE_DEFAULT,
|
||||
ZYDIS_MASK_OVERRIDE_ZEROING,
|
||||
ZYDIS_MASK_OVERRIDE_CONTROL,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_MASK_OVERRIDE_MAX_VALUE = ZYDIS_MASK_OVERRIDE_CONTROL,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_MASK_OVERRIDE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_MASK_OVERRIDE_MAX_VALUE)
|
||||
} ZydisMaskOverride;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#define ZYDIS_OPDEF_REQUIRED_BITS \
|
||||
ZYAN_MAX(ZYDIS_REGKIND_REQUIRED_BITS, ZYDIS_MEMOP_TYPE_REQUIRED_BITS + 1) + 1
|
||||
|
||||
#define ZYDIS_OPDEF_GET_REG(operand_definition) \
|
||||
((operand_definition) & ((1 << ZYDIS_REGKIND_REQUIRED_BITS ) - 1))
|
||||
|
||||
#define ZYDIS_OPDEF_GET_MEM(operand_definition) \
|
||||
((operand_definition) & ((1 << ZYDIS_MEMOP_TYPE_REQUIRED_BITS) - 1))
|
||||
|
||||
#define ZYDIS_OPDEF_GET_REG_HIGH_BIT(operand_definition) \
|
||||
(((operand_definition) >> ZYDIS_REGKIND_REQUIRED_BITS ) & 0x01)
|
||||
|
||||
#define ZYDIS_OPDEF_GET_MEM_HIGH_BIT(operand_definition) \
|
||||
(((operand_definition) >> ZYDIS_MEMOP_TYPE_REQUIRED_BITS) & 0x01)
|
||||
|
||||
// MSVC does not correctly execute the `pragma pack(1)` compiler-directive, if we use the correct
|
||||
// enum types
|
||||
ZYAN_STATIC_ASSERT(ZYDIS_MNEMONIC_REQUIRED_BITS <= 16);
|
||||
ZYAN_STATIC_ASSERT(ZYDIS_CATEGORY_REQUIRED_BITS <= 8);
|
||||
ZYAN_STATIC_ASSERT(ZYDIS_ISA_SET_REQUIRED_BITS <= 8);
|
||||
ZYAN_STATIC_ASSERT(ZYDIS_ISA_EXT_REQUIRED_BITS <= 8);
|
||||
ZYAN_STATIC_ASSERT(ZYDIS_BRANCH_TYPE_REQUIRED_BITS <= 8);
|
||||
ZYAN_STATIC_ASSERT(ZYDIS_EXCEPTION_CLASS_REQUIRED_BITS <= 8);
|
||||
ZYAN_STATIC_ASSERT(ZYDIS_OPDEF_REQUIRED_BITS <= 8);
|
||||
ZYAN_STATIC_ASSERT(ZYDIS_RW_ACTION_REQUIRED_BITS <= 8);
|
||||
|
||||
#ifndef ZYDIS_MINIMAL_MODE
|
||||
# define ZYDIS_INSTRUCTION_DEFINITION_BASE \
|
||||
ZyanU16 mnemonic ZYAN_BITFIELD(ZYDIS_MNEMONIC_REQUIRED_BITS); \
|
||||
ZyanU8 operand_count ZYAN_BITFIELD( 4); \
|
||||
ZyanU8 operand_count_visible ZYAN_BITFIELD( 3); \
|
||||
ZyanU16 operand_reference ZYAN_BITFIELD(15); \
|
||||
ZyanU8 operand_size_map ZYAN_BITFIELD( 3); \
|
||||
ZyanU8 address_size_map ZYAN_BITFIELD( 2); \
|
||||
ZyanU8 flags_reference ZYAN_BITFIELD( 7); \
|
||||
ZyanBool requires_protected_mode ZYAN_BITFIELD( 1); \
|
||||
ZyanBool no_compat_mode ZYAN_BITFIELD( 1); \
|
||||
ZyanU8 category ZYAN_BITFIELD(ZYDIS_CATEGORY_REQUIRED_BITS); \
|
||||
ZyanU8 isa_set ZYAN_BITFIELD(ZYDIS_ISA_SET_REQUIRED_BITS); \
|
||||
ZyanU8 isa_ext ZYAN_BITFIELD(ZYDIS_ISA_EXT_REQUIRED_BITS); \
|
||||
ZyanU8 branch_type ZYAN_BITFIELD(ZYDIS_BRANCH_TYPE_REQUIRED_BITS); \
|
||||
ZyanU8 exception_class ZYAN_BITFIELD(ZYDIS_EXCEPTION_CLASS_REQUIRED_BITS); \
|
||||
ZyanU8 op_reg ZYAN_BITFIELD(ZYDIS_OPDEF_REQUIRED_BITS); \
|
||||
ZyanU8 op_rm ZYAN_BITFIELD(ZYDIS_OPDEF_REQUIRED_BITS); \
|
||||
ZyanU8 cpu_state ZYAN_BITFIELD(ZYDIS_RW_ACTION_REQUIRED_BITS); \
|
||||
ZyanU8 fpu_state ZYAN_BITFIELD(ZYDIS_RW_ACTION_REQUIRED_BITS); \
|
||||
ZyanU8 xmm_state ZYAN_BITFIELD(ZYDIS_RW_ACTION_REQUIRED_BITS); \
|
||||
ZyanBool accepts_segment ZYAN_BITFIELD( 1)
|
||||
#else
|
||||
# define ZYDIS_INSTRUCTION_DEFINITION_BASE \
|
||||
ZyanU16 mnemonic ZYAN_BITFIELD(ZYDIS_MNEMONIC_REQUIRED_BITS); \
|
||||
ZyanU8 operand_size_map ZYAN_BITFIELD( 3); \
|
||||
ZyanU8 address_size_map ZYAN_BITFIELD( 2); \
|
||||
ZyanBool requires_protected_mode ZYAN_BITFIELD( 1); \
|
||||
ZyanBool no_compat_mode ZYAN_BITFIELD( 1); \
|
||||
ZyanU8 op_reg ZYAN_BITFIELD(ZYDIS_OPDEF_REQUIRED_BITS); \
|
||||
ZyanU8 op_rm ZYAN_BITFIELD(ZYDIS_OPDEF_REQUIRED_BITS)
|
||||
#endif
|
||||
|
||||
#define ZYDIS_INSTRUCTION_DEFINITION_BASE_VECTOR \
|
||||
ZYDIS_INSTRUCTION_DEFINITION_BASE; \
|
||||
ZyanU8 op_ndsndd ZYAN_BITFIELD(ZYDIS_OPDEF_REQUIRED_BITS)
|
||||
|
||||
#define ZYDIS_INSTRUCTION_DEFINITION_BASE_VECTOR_INTEL \
|
||||
ZYDIS_INSTRUCTION_DEFINITION_BASE_VECTOR; \
|
||||
ZyanBool is_gather ZYAN_BITFIELD( 1); \
|
||||
ZyanBool no_source_dest_match ZYAN_BITFIELD( 1); \
|
||||
ZyanBool no_source_source_match ZYAN_BITFIELD( 1) // TODO: Could be moved to VEX
|
||||
|
||||
/**
|
||||
* Defines the `ZydisInstructionDefinition` struct.
|
||||
*/
|
||||
typedef struct ZydisInstructionDefinition_
|
||||
{
|
||||
ZYDIS_INSTRUCTION_DEFINITION_BASE;
|
||||
} ZydisInstructionDefinition;
|
||||
|
||||
/**
|
||||
* Defines the `ZydisInstructionDefinitionLEGACY` struct.
|
||||
*/
|
||||
typedef struct ZydisInstructionDefinitionLEGACY_
|
||||
{
|
||||
ZYDIS_INSTRUCTION_DEFINITION_BASE;
|
||||
#ifndef ZYDIS_MINIMAL_MODE
|
||||
ZyanBool is_privileged ZYAN_BITFIELD( 1);
|
||||
#endif
|
||||
ZyanBool accepts_LOCK ZYAN_BITFIELD( 1);
|
||||
#ifndef ZYDIS_MINIMAL_MODE
|
||||
ZyanBool accepts_REP ZYAN_BITFIELD( 1);
|
||||
ZyanBool accepts_REPEREPZ ZYAN_BITFIELD( 1);
|
||||
ZyanBool accepts_REPNEREPNZ ZYAN_BITFIELD( 1);
|
||||
ZyanBool accepts_BOUND ZYAN_BITFIELD( 1);
|
||||
ZyanBool accepts_XACQUIRE ZYAN_BITFIELD( 1);
|
||||
ZyanBool accepts_XRELEASE ZYAN_BITFIELD( 1);
|
||||
ZyanBool accepts_NOTRACK ZYAN_BITFIELD( 1);
|
||||
ZyanBool accepts_hle_without_lock ZYAN_BITFIELD( 1);
|
||||
ZyanBool accepts_branch_hints ZYAN_BITFIELD( 1);
|
||||
#endif
|
||||
} ZydisInstructionDefinitionLEGACY;
|
||||
|
||||
/**
|
||||
* Defines the `ZydisInstructionDefinition3DNOW` struct.
|
||||
*/
|
||||
typedef struct ZydisInstructionDefinition3DNOW_
|
||||
{
|
||||
ZYDIS_INSTRUCTION_DEFINITION_BASE;
|
||||
} ZydisInstructionDefinition3DNOW;
|
||||
|
||||
/**
|
||||
* Defines the `ZydisInstructionDefinitionXOP` struct.
|
||||
*/
|
||||
typedef struct ZydisInstructionDefinitionXOP_
|
||||
{
|
||||
ZYDIS_INSTRUCTION_DEFINITION_BASE_VECTOR;
|
||||
} ZydisInstructionDefinitionXOP;
|
||||
|
||||
// MSVC does not correctly execute the `pragma pack(1)` compiler-directive, if we use the correct
|
||||
// enum types
|
||||
ZYAN_STATIC_ASSERT(ZYDIS_VEX_STATIC_BROADCAST_REQUIRED_BITS <= 8);
|
||||
|
||||
/**
|
||||
* Defines the `ZydisInstructionDefinitionVEX` struct.
|
||||
*/
|
||||
typedef struct ZydisInstructionDefinitionVEX_
|
||||
{
|
||||
ZYDIS_INSTRUCTION_DEFINITION_BASE_VECTOR_INTEL;
|
||||
#ifndef ZYDIS_MINIMAL_MODE
|
||||
ZyanU8 broadcast ZYAN_BITFIELD(ZYDIS_VEX_STATIC_BROADCAST_REQUIRED_BITS);
|
||||
#endif
|
||||
} ZydisInstructionDefinitionVEX;
|
||||
|
||||
#ifndef ZYDIS_DISABLE_AVX512
|
||||
|
||||
// MSVC does not correctly execute the `pragma pack(1)` compiler-directive, if we use the correct
|
||||
// enum types
|
||||
ZYAN_STATIC_ASSERT(ZYDIS_IVECTOR_LENGTH_REQUIRED_BITS <= 8);
|
||||
ZYAN_STATIC_ASSERT(ZYDIS_TUPLETYPE_REQUIRED_BITS <= 8);
|
||||
ZYAN_STATIC_ASSERT(ZYDIS_IELEMENT_SIZE_REQUIRED_BITS <= 8);
|
||||
ZYAN_STATIC_ASSERT(ZYDIS_EVEX_FUNC_REQUIRED_BITS <= 8);
|
||||
ZYAN_STATIC_ASSERT(ZYDIS_MASK_POLICY_REQUIRED_BITS <= 8);
|
||||
ZYAN_STATIC_ASSERT(ZYDIS_MASK_OVERRIDE_REQUIRED_BITS <= 8);
|
||||
ZYAN_STATIC_ASSERT(ZYDIS_EVEX_STATIC_BROADCAST_REQUIRED_BITS <= 8);
|
||||
|
||||
/**
|
||||
* Defines the `ZydisInstructionDefinitionEVEX` struct.
|
||||
*/
|
||||
typedef struct ZydisInstructionDefinitionEVEX_
|
||||
{
|
||||
ZYDIS_INSTRUCTION_DEFINITION_BASE_VECTOR_INTEL;
|
||||
#ifndef ZYDIS_MINIMAL_MODE
|
||||
ZyanU8 vector_length ZYAN_BITFIELD(ZYDIS_IVECTOR_LENGTH_REQUIRED_BITS);
|
||||
ZyanU8 tuple_type ZYAN_BITFIELD(ZYDIS_TUPLETYPE_REQUIRED_BITS);
|
||||
ZyanU8 element_size ZYAN_BITFIELD(ZYDIS_IELEMENT_SIZE_REQUIRED_BITS);
|
||||
ZyanU8 functionality ZYAN_BITFIELD(ZYDIS_EVEX_FUNC_REQUIRED_BITS);
|
||||
#endif
|
||||
ZyanU8 mask_policy ZYAN_BITFIELD(ZYDIS_MASK_POLICY_REQUIRED_BITS);
|
||||
ZyanBool accepts_zero_mask ZYAN_BITFIELD( 1);
|
||||
#ifndef ZYDIS_MINIMAL_MODE
|
||||
ZyanU8 mask_override ZYAN_BITFIELD(ZYDIS_MASK_OVERRIDE_REQUIRED_BITS);
|
||||
ZyanU8 broadcast ZYAN_BITFIELD(ZYDIS_EVEX_STATIC_BROADCAST_REQUIRED_BITS);
|
||||
#endif
|
||||
} ZydisInstructionDefinitionEVEX;
|
||||
#endif
|
||||
|
||||
#ifndef ZYDIS_DISABLE_KNC
|
||||
|
||||
// MSVC does not correctly execute the `pragma pack(1)` compiler-directive, if we use the correct
|
||||
// enum types
|
||||
ZYAN_STATIC_ASSERT(ZYDIS_MVEX_FUNC_REQUIRED_BITS <= 8);
|
||||
ZYAN_STATIC_ASSERT(ZYDIS_MASK_POLICY_REQUIRED_BITS <= 8);
|
||||
ZYAN_STATIC_ASSERT(ZYDIS_MVEX_STATIC_BROADCAST_REQUIRED_BITS <= 8);
|
||||
|
||||
/**
|
||||
* Defines the `ZydisInstructionDefinitionMVEX` struct.
|
||||
*/
|
||||
typedef struct ZydisInstructionDefinitionMVEX_
|
||||
{
|
||||
ZYDIS_INSTRUCTION_DEFINITION_BASE_VECTOR_INTEL;
|
||||
ZyanU8 functionality ZYAN_BITFIELD(ZYDIS_MVEX_FUNC_REQUIRED_BITS);
|
||||
ZyanU8 mask_policy ZYAN_BITFIELD(ZYDIS_MASK_POLICY_REQUIRED_BITS);
|
||||
#ifndef ZYDIS_MINIMAL_MODE
|
||||
ZyanBool has_element_granularity ZYAN_BITFIELD( 1);
|
||||
ZyanU8 broadcast ZYAN_BITFIELD(ZYDIS_MVEX_STATIC_BROADCAST_REQUIRED_BITS);
|
||||
#endif
|
||||
} ZydisInstructionDefinitionMVEX;
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#ifdef ZYAN_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Accessed CPU/FPU flags */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Contains information about the CPU/FPU flags accessed by an instruction.
|
||||
*
|
||||
* We don't want this struct to be packed! A pointer to the individual members will be used by the
|
||||
* `ZydisDecodedInstruction` struct.
|
||||
*/
|
||||
typedef struct ZydisDefinitionAccessedFlags_
|
||||
{
|
||||
ZydisAccessedFlags cpu_flags;
|
||||
ZydisAccessedFlags fpu_flags;
|
||||
} ZydisDefinitionAccessedFlags;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Instruction definition */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Returns the instruction-definition with the given `encoding` and `id`.
|
||||
*
|
||||
* @param encoding The instruction-encoding.
|
||||
* @param id The definition-id.
|
||||
* @param definition A pointer to the variable that receives a pointer to the instruction-
|
||||
* definition.
|
||||
*/
|
||||
ZYDIS_NO_EXPORT void ZydisGetInstructionDefinition(ZydisInstructionEncoding encoding,
|
||||
ZyanU16 id, const ZydisInstructionDefinition** definition);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Operand definition */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef ZYDIS_MINIMAL_MODE
|
||||
/**
|
||||
* Returns the the operand-definitions for the given instruction-`definition`.
|
||||
*
|
||||
* @param definition A pointer to the instruction-definition.
|
||||
*
|
||||
* @return A pointer to the first operand definition of the instruction, or `ZYAN_NULL`.
|
||||
*/
|
||||
ZYDIS_NO_EXPORT const ZydisOperandDefinition* ZydisGetOperandDefinitions(
|
||||
const ZydisInstructionDefinition* definition);
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Element info */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef ZYDIS_MINIMAL_MODE
|
||||
/**
|
||||
* Returns the actual type and size of an internal element-type.
|
||||
*
|
||||
* @param element The internal element type.
|
||||
* @param type The actual element type.
|
||||
* @param size The element size.
|
||||
*/
|
||||
ZYDIS_NO_EXPORT void ZydisGetElementInfo(ZydisInternalElementType element, ZydisElementType* type,
|
||||
ZydisElementSize* size);
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Accessed CPU flags */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef ZYDIS_MINIMAL_MODE
|
||||
/**
|
||||
* Returns the the operand-definitions for the given instruction-`definition`.
|
||||
*
|
||||
* @param definition A pointer to the instruction-definition.
|
||||
* @param flags A pointer to the variable that receives the `ZydisDefinitionAccessedFlags`
|
||||
* struct.
|
||||
*
|
||||
* @return `ZYAN_TRUE`, if the instruction accesses any flags, or `ZYAN_FALSE`, if not.
|
||||
*/
|
||||
ZYDIS_NO_EXPORT ZyanBool ZydisGetAccessedFlags(const ZydisInstructionDefinition* definition,
|
||||
const ZydisDefinitionAccessedFlags** flags);
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZYDIS_INTERNAL_SHAREDDATA_H */
|
||||
+470
@@ -0,0 +1,470 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Disassembler Library (Zydis)
|
||||
|
||||
Original Author : Florian Bernd, Joel Hoener
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Provides some internal, more performant, but unsafe helper functions for the `ZyanString`
|
||||
* data-type.
|
||||
*
|
||||
* Most of these functions are very similar to the ones in `Zycore/String.h`, but inlined and
|
||||
* without optional overhead like parameter-validation checks, etc ...
|
||||
*
|
||||
* The `ZyanString` data-type is able to dynamically allocate memory on the heap, but as `Zydis` is
|
||||
* designed to be a non-'malloc'ing library, all functions in this file assume that the instances
|
||||
* they are operating on are created with a user-defined static-buffer.
|
||||
*/
|
||||
|
||||
#ifndef ZYDIS_INTERNAL_STRING_H
|
||||
#define ZYDIS_INTERNAL_STRING_H
|
||||
|
||||
#include <Zycore/LibC.h>
|
||||
#include <Zycore/String.h>
|
||||
#include <Zycore/Types.h>
|
||||
#include <Zycore/Format.h>
|
||||
#include <Zydis/ShortString.h>
|
||||
#include <Zycore/Defines.h>
|
||||
#include <Zycore/Status.h>
|
||||
#include <Zycore/Vector.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Enums and types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Letter Case */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisLetterCase` enum.
|
||||
*/
|
||||
typedef enum ZydisLetterCase_
|
||||
{
|
||||
/**
|
||||
* Uses the given text "as is".
|
||||
*/
|
||||
ZYDIS_LETTER_CASE_DEFAULT,
|
||||
/**
|
||||
* Converts the given text to lowercase letters.
|
||||
*/
|
||||
ZYDIS_LETTER_CASE_LOWER,
|
||||
/**
|
||||
* Converts the given text to uppercase letters.
|
||||
*/
|
||||
ZYDIS_LETTER_CASE_UPPER,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_LETTER_CASE_MAX_VALUE = ZYDIS_LETTER_CASE_UPPER,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_LETTER_CASE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_LETTER_CASE_MAX_VALUE)
|
||||
} ZydisLetterCase;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Macros */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Internal macros */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Checks for a terminating '\0' character at the end of the string data.
|
||||
*/
|
||||
#define ZYDIS_STRING_ASSERT_NULLTERMINATION(string) \
|
||||
ZYAN_ASSERT(*(char*)((ZyanU8*)(string)->vector.data + (string)->vector.size - 1) == '\0');
|
||||
|
||||
/**
|
||||
* Writes a terminating '\0' character at the end of the string data.
|
||||
*/
|
||||
#define ZYDIS_STRING_NULLTERMINATE(string) \
|
||||
*(char*)((ZyanU8*)(string)->vector.data + (string)->vector.size - 1) = '\0';
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Internal Functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Appending */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Appends the content of the source string to the end of the destination string.
|
||||
*
|
||||
* @param destination The destination string.
|
||||
* @param source The source string.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYAN_INLINE ZyanStatus ZydisStringAppend(ZyanString* destination, const ZyanStringView* source)
|
||||
{
|
||||
ZYAN_ASSERT(destination && source);
|
||||
ZYAN_ASSERT(!destination->vector.allocator);
|
||||
ZYAN_ASSERT(destination->vector.size && source->string.vector.size);
|
||||
|
||||
if (destination->vector.size + source->string.vector.size - 1 > destination->vector.capacity)
|
||||
{
|
||||
return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
ZYAN_MEMCPY((char*)destination->vector.data + destination->vector.size - 1,
|
||||
source->string.vector.data, source->string.vector.size - 1);
|
||||
|
||||
destination->vector.size += source->string.vector.size - 1;
|
||||
ZYDIS_STRING_NULLTERMINATE(destination);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the content of the source string to the end of the destination
|
||||
* string, converting the characters to the specified letter-case.
|
||||
*
|
||||
* @param destination The destination string.
|
||||
* @param source The source string.
|
||||
* @param letter_case The desired letter-case.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYAN_INLINE ZyanStatus ZydisStringAppendCase(ZyanString* destination, const ZyanStringView* source,
|
||||
ZydisLetterCase letter_case)
|
||||
{
|
||||
ZYAN_ASSERT(destination && source);
|
||||
ZYAN_ASSERT(!destination->vector.allocator);
|
||||
ZYAN_ASSERT(destination->vector.size && source->string.vector.size);
|
||||
|
||||
if (destination->vector.size + source->string.vector.size - 1 > destination->vector.capacity)
|
||||
{
|
||||
return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
ZYAN_MEMCPY((char*)destination->vector.data + destination->vector.size - 1,
|
||||
source->string.vector.data, source->string.vector.size - 1);
|
||||
|
||||
switch (letter_case)
|
||||
{
|
||||
case ZYDIS_LETTER_CASE_DEFAULT:
|
||||
break;
|
||||
case ZYDIS_LETTER_CASE_LOWER:
|
||||
{
|
||||
const ZyanUSize index = destination->vector.size - 1;
|
||||
const ZyanUSize count = source->string.vector.size - 1;
|
||||
char* s = (char*)destination->vector.data + index;
|
||||
for (ZyanUSize i = index; i < index + count; ++i)
|
||||
{
|
||||
const char c = *s;
|
||||
if ((c >= 'A') && (c <= 'Z'))
|
||||
{
|
||||
*s = c | 32;
|
||||
}
|
||||
++s;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ZYDIS_LETTER_CASE_UPPER:
|
||||
{
|
||||
const ZyanUSize index = destination->vector.size - 1;
|
||||
const ZyanUSize count = source->string.vector.size - 1;
|
||||
char* s = (char*)destination->vector.data + index;
|
||||
for (ZyanUSize i = index; i < index + count; ++i)
|
||||
{
|
||||
const char c = *s;
|
||||
if ((c >= 'a') && (c <= 'z'))
|
||||
{
|
||||
*s = c & ~32;
|
||||
}
|
||||
++s;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ZYAN_UNREACHABLE;
|
||||
}
|
||||
|
||||
destination->vector.size += source->string.vector.size - 1;
|
||||
ZYDIS_STRING_NULLTERMINATE(destination);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the content of the source short-string to the end of the destination string.
|
||||
*
|
||||
* @param destination The destination string.
|
||||
* @param source The source string.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYAN_INLINE ZyanStatus ZydisStringAppendShort(ZyanString* destination,
|
||||
const ZydisShortString* source)
|
||||
{
|
||||
ZYAN_ASSERT(destination && source);
|
||||
ZYAN_ASSERT(!destination->vector.allocator);
|
||||
ZYAN_ASSERT(destination->vector.size && source->size);
|
||||
|
||||
if (destination->vector.size + source->size > destination->vector.capacity)
|
||||
{
|
||||
return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
ZYAN_MEMCPY((char*)destination->vector.data + destination->vector.size - 1, source->data,
|
||||
(ZyanUSize)source->size + 1);
|
||||
|
||||
destination->vector.size += source->size;
|
||||
ZYDIS_STRING_ASSERT_NULLTERMINATION(destination);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the content of the source short-string to the end of the destination string,
|
||||
* converting the characters to the specified letter-case.
|
||||
*
|
||||
* @param destination The destination string.
|
||||
* @param source The source string.
|
||||
* @param letter_case The desired letter-case.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYAN_INLINE ZyanStatus ZydisStringAppendShortCase(ZyanString* destination,
|
||||
const ZydisShortString* source, ZydisLetterCase letter_case)
|
||||
{
|
||||
ZYAN_ASSERT(destination && source);
|
||||
ZYAN_ASSERT(!destination->vector.allocator);
|
||||
ZYAN_ASSERT(destination->vector.size && source->size);
|
||||
|
||||
if (destination->vector.size + source->size > destination->vector.capacity)
|
||||
{
|
||||
return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
ZYAN_MEMCPY((char*)destination->vector.data + destination->vector.size - 1, source->data,
|
||||
(ZyanUSize)source->size + 1);
|
||||
|
||||
switch (letter_case)
|
||||
{
|
||||
case ZYDIS_LETTER_CASE_DEFAULT:
|
||||
break;
|
||||
case ZYDIS_LETTER_CASE_LOWER:
|
||||
{
|
||||
const ZyanUSize index = destination->vector.size - 1;
|
||||
const ZyanUSize count = source->size;
|
||||
char* s = (char*)destination->vector.data + index;
|
||||
for (ZyanUSize i = index; i < index + count; ++i)
|
||||
{
|
||||
const char c = *s;
|
||||
if ((c >= 'A') && (c <= 'Z'))
|
||||
{
|
||||
*s = c | 32;
|
||||
}
|
||||
++s;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ZYDIS_LETTER_CASE_UPPER:
|
||||
{
|
||||
const ZyanUSize index = destination->vector.size - 1;
|
||||
const ZyanUSize count = source->size;
|
||||
char* s = (char*)destination->vector.data + index;
|
||||
for (ZyanUSize i = index; i < index + count; ++i)
|
||||
{
|
||||
const char c = *s;
|
||||
if ((c >= 'a') && (c <= 'z'))
|
||||
{
|
||||
*s = c & ~32;
|
||||
}
|
||||
++s;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ZYAN_UNREACHABLE;
|
||||
}
|
||||
|
||||
destination->vector.size += source->size;
|
||||
ZYDIS_STRING_ASSERT_NULLTERMINATION(destination);
|
||||
|
||||
return ZYAN_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Formatting */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Formats the given unsigned ordinal `value` to its decimal text-representation and
|
||||
* appends it to the `string`.
|
||||
*
|
||||
* @param string A pointer to the `ZyanString` instance.
|
||||
* @param value The value to append.
|
||||
* @param padding_length Padds the converted value with leading zeros, if the number of chars is
|
||||
* less than the `padding_length`.
|
||||
* @param prefix The string to use as prefix or `ZYAN_NULL`, if not needed.
|
||||
* @param suffix The string to use as suffix or `ZYAN_NULL`, if not needed.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified
|
||||
* `ZyanString` instance.
|
||||
*/
|
||||
ZyanStatus ZydisStringAppendDecU(ZyanString* string, ZyanU64 value, ZyanU8 padding_length,
|
||||
const ZyanStringView* prefix, const ZyanStringView* suffix);
|
||||
|
||||
/**
|
||||
* Formats the given signed ordinal `value` to its decimal text-representation and
|
||||
* appends it to the `string`.
|
||||
*
|
||||
* @param string A pointer to the `ZyanString` instance.
|
||||
* @param value The value to append.
|
||||
* @param padding_length Padds the converted value with leading zeros, if the number of chars is
|
||||
* less than the `padding_length`.
|
||||
* @param force_sign Enable this option to print the `+` sign for positive numbers.
|
||||
* @param prefix The string to use as prefix or `ZYAN_NULL`, if not needed.
|
||||
* @param suffix The string to use as suffix or `ZYAN_NULL`, if not needed.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified
|
||||
* `ZyanString` instance.
|
||||
*/
|
||||
ZYAN_INLINE ZyanStatus ZydisStringAppendDecS(ZyanString* string, ZyanI64 value,
|
||||
ZyanU8 padding_length, ZyanBool force_sign, const ZyanStringView* prefix,
|
||||
const ZyanStringView* suffix)
|
||||
{
|
||||
static const ZydisShortString str_add = ZYDIS_MAKE_SHORTSTRING("+");
|
||||
static const ZydisShortString str_sub = ZYDIS_MAKE_SHORTSTRING("-");
|
||||
|
||||
if (value < 0)
|
||||
{
|
||||
ZYAN_CHECK(ZydisStringAppendShort(string, &str_sub));
|
||||
if (prefix)
|
||||
{
|
||||
ZYAN_CHECK(ZydisStringAppend(string, prefix));
|
||||
}
|
||||
return ZydisStringAppendDecU(string, ZyanAbsI64(value), padding_length,
|
||||
(const ZyanStringView*)ZYAN_NULL, suffix);
|
||||
}
|
||||
|
||||
if (force_sign)
|
||||
{
|
||||
ZYAN_ASSERT(value >= 0);
|
||||
ZYAN_CHECK(ZydisStringAppendShort(string, &str_add));
|
||||
}
|
||||
return ZydisStringAppendDecU(string, value, padding_length, prefix, suffix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the given unsigned ordinal `value` to its hexadecimal text-representation and
|
||||
* appends it to the `string`.
|
||||
*
|
||||
* @param string A pointer to the `ZyanString` instance.
|
||||
* @param value The value to append.
|
||||
* @param padding_length Pads the converted value with leading zeros if the number of
|
||||
* chars is less than the `padding_length`.
|
||||
* @param force_leading_number Enable this option to prepend a leading `0` if the first
|
||||
* character is non-numeric.
|
||||
* @param uppercase Enable this option to use uppercase letters ('A'-'F') instead
|
||||
* of lowercase ones ('a'-'f').
|
||||
* @param prefix The string to use as prefix or `ZYAN_NULL`, if not needed.
|
||||
* @param suffix The string to use as suffix or `ZYAN_NULL`, if not needed.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* This function will fail, if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified
|
||||
* `ZyanString` instance.
|
||||
*/
|
||||
ZyanStatus ZydisStringAppendHexU(ZyanString* string, ZyanU64 value, ZyanU8 padding_length,
|
||||
ZyanBool force_leading_number, ZyanBool uppercase, const ZyanStringView* prefix,
|
||||
const ZyanStringView* suffix);
|
||||
|
||||
/**
|
||||
* Formats the given signed ordinal `value` to its hexadecimal text-representation and
|
||||
* appends it to the `string`.
|
||||
*
|
||||
* @param string A pointer to the `ZyanString` instance.
|
||||
* @param value The value to append.
|
||||
* @param padding_length Padds the converted value with leading zeros, if the number of
|
||||
* chars is less than the `padding_length` (the sign char does not
|
||||
* count).
|
||||
* @param force_leading_number Enable this option to prepend a leading `0`, if the first
|
||||
* character is non-numeric.
|
||||
* @param uppercase Enable this option to use uppercase letters ('A'-'F') instead
|
||||
* of lowercase ones ('a'-'f').
|
||||
* @param force_sign Enable this option to print the `+` sign for positive numbers.
|
||||
* @param prefix The string to use as prefix or `ZYAN_NULL`, if not needed.
|
||||
* @param suffix The string to use as suffix or `ZYAN_NULL`, if not needed.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*
|
||||
* This function will fail if the `ZYAN_STRING_IS_IMMUTABLE` flag is set for the specified
|
||||
* `ZyanString` instance.
|
||||
*/
|
||||
ZYAN_INLINE ZyanStatus ZydisStringAppendHexS(ZyanString* string, ZyanI64 value,
|
||||
ZyanU8 padding_length, ZyanBool force_leading_number, ZyanBool uppercase, ZyanBool force_sign,
|
||||
const ZyanStringView* prefix, const ZyanStringView* suffix)
|
||||
{
|
||||
static const ZydisShortString str_add = ZYDIS_MAKE_SHORTSTRING("+");
|
||||
static const ZydisShortString str_sub = ZYDIS_MAKE_SHORTSTRING("-");
|
||||
|
||||
if (value < 0)
|
||||
{
|
||||
ZYAN_CHECK(ZydisStringAppendShort(string, &str_sub));
|
||||
if (prefix)
|
||||
{
|
||||
ZYAN_CHECK(ZydisStringAppend(string, prefix));
|
||||
}
|
||||
return ZydisStringAppendHexU(string, ZyanAbsI64(value), padding_length,
|
||||
force_leading_number, uppercase, (const ZyanStringView*)ZYAN_NULL, suffix);
|
||||
}
|
||||
|
||||
if (force_sign)
|
||||
{
|
||||
ZYAN_ASSERT(value >= 0);
|
||||
ZYAN_CHECK(ZydisStringAppendShort(string, &str_add));
|
||||
}
|
||||
return ZydisStringAppendHexU(string, value, padding_length, force_leading_number, uppercase,
|
||||
prefix, suffix);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // ZYDIS_INTERNAL_STRING_H
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Disassembler Library (Zydis)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#ifndef ZYDIS_METAINFO_H
|
||||
#define ZYDIS_METAINFO_H
|
||||
|
||||
#include <Zydis/Defines.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Enums and types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
#include <Zydis/Generated/EnumInstructionCategory.h>
|
||||
#include <Zydis/Generated/EnumISASet.h>
|
||||
#include <Zydis/Generated/EnumISAExt.h>
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* Returns the specified instruction category string.
|
||||
*
|
||||
* @param category The instruction category.
|
||||
*
|
||||
* @return The instruction category string or `ZYAN_NULL`, if an invalid category was passed.
|
||||
*/
|
||||
ZYDIS_EXPORT const char* ZydisCategoryGetString(ZydisInstructionCategory category);
|
||||
|
||||
/**
|
||||
* Returns the specified isa-set string.
|
||||
*
|
||||
* @param isa_set The isa-set.
|
||||
*
|
||||
* @return The isa-set string or `ZYAN_NULL`, if an invalid isa-set was passed.
|
||||
*/
|
||||
ZYDIS_EXPORT const char* ZydisISASetGetString(ZydisISASet isa_set);
|
||||
|
||||
/**
|
||||
* Returns the specified isa-extension string.
|
||||
*
|
||||
* @param isa_ext The isa-extension.
|
||||
*
|
||||
* @return The isa-extension string or `ZYAN_NULL`, if an invalid isa-extension was passed.
|
||||
*/
|
||||
ZYDIS_EXPORT const char* ZydisISAExtGetString(ZydisISAExt isa_ext);
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZYDIS_METAINFO_H */
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Disassembler Library (Zydis)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Mnemonic constant definitions and helper functions.
|
||||
*/
|
||||
|
||||
#ifndef ZYDIS_MNEMONIC_H
|
||||
#define ZYDIS_MNEMONIC_H
|
||||
|
||||
#include <Zydis/Defines.h>
|
||||
#include <Zydis/ShortString.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Enums and types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
#include <Zydis/Generated/EnumMnemonic.h>
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* @addtogroup mnemonic Mnemonic
|
||||
* Functions for retrieving mnemonic names.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the specified instruction mnemonic string.
|
||||
*
|
||||
* @param mnemonic The mnemonic.
|
||||
*
|
||||
* @return The instruction mnemonic string or `ZYAN_NULL`, if an invalid mnemonic was passed.
|
||||
*/
|
||||
ZYDIS_EXPORT const char* ZydisMnemonicGetString(ZydisMnemonic mnemonic);
|
||||
|
||||
/**
|
||||
* Returns the specified instruction mnemonic as `ZydisShortString`.
|
||||
*
|
||||
* @param mnemonic The mnemonic.
|
||||
*
|
||||
* @return The instruction mnemonic string or `ZYAN_NULL`, if an invalid mnemonic was passed.
|
||||
*
|
||||
* The `buffer` of the returned struct is guaranteed to be zero-terminated in this special case.
|
||||
*/
|
||||
ZYDIS_EXPORT const ZydisShortString* ZydisMnemonicGetStringWrapped(ZydisMnemonic mnemonic);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZYDIS_MNEMONIC_H */
|
||||
+337
@@ -0,0 +1,337 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Disassembler Library (Zydis)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Utility functions and constants for registers.
|
||||
*/
|
||||
|
||||
#ifndef ZYDIS_REGISTER_H
|
||||
#define ZYDIS_REGISTER_H
|
||||
|
||||
#include <Zycore/Defines.h>
|
||||
#include <Zycore/Types.h>
|
||||
#include <Zydis/Defines.h>
|
||||
#include <Zydis/SharedTypes.h>
|
||||
#include <Zydis/ShortString.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Enums and types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Registers */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#include <Zydis/Generated/EnumRegister.h>
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Register kinds */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisRegisterKind` enum.
|
||||
*
|
||||
* Please note that this enum does not contain a matching entry for all values of the
|
||||
* `ZydisRegister` enum, but only for those registers where it makes sense to logically group them
|
||||
* for decoding/encoding purposes.
|
||||
*
|
||||
* These are mainly the registers that can be identified by an id within their corresponding
|
||||
* register-class.
|
||||
*/
|
||||
typedef enum ZydisRegisterKind_
|
||||
{
|
||||
ZYDIS_REGKIND_INVALID,
|
||||
ZYDIS_REGKIND_GPR,
|
||||
ZYDIS_REGKIND_X87,
|
||||
ZYDIS_REGKIND_MMX,
|
||||
ZYDIS_REGKIND_VR,
|
||||
ZYDIS_REGKIND_TMM,
|
||||
ZYDIS_REGKIND_SEGMENT,
|
||||
ZYDIS_REGKIND_TEST,
|
||||
ZYDIS_REGKIND_CONTROL,
|
||||
ZYDIS_REGKIND_DEBUG,
|
||||
ZYDIS_REGKIND_MASK,
|
||||
ZYDIS_REGKIND_BOUND,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_REGKIND_MAX_VALUE = ZYDIS_REGKIND_BOUND,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_REGKIND_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_REGKIND_MAX_VALUE)
|
||||
} ZydisRegisterKind;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Register classes */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisRegisterClass` enum.
|
||||
*
|
||||
* Please note that this enum does not contain a matching entry for all values of the
|
||||
* `ZydisRegister` enum, but only for those registers where it makes sense to logically group them
|
||||
* for decoding/encoding purposes.
|
||||
*
|
||||
* These are mainly the registers that can be identified by an id within their corresponding
|
||||
* register-class. The `IP` and `FLAGS` values are exceptions to this rule.
|
||||
*/
|
||||
typedef enum ZydisRegisterClass_
|
||||
{
|
||||
ZYDIS_REGCLASS_INVALID,
|
||||
/**
|
||||
* 8-bit general-purpose registers.
|
||||
*/
|
||||
ZYDIS_REGCLASS_GPR8,
|
||||
/**
|
||||
* 16-bit general-purpose registers.
|
||||
*/
|
||||
ZYDIS_REGCLASS_GPR16,
|
||||
/**
|
||||
* 32-bit general-purpose registers.
|
||||
*/
|
||||
ZYDIS_REGCLASS_GPR32,
|
||||
/**
|
||||
* 64-bit general-purpose registers.
|
||||
*/
|
||||
ZYDIS_REGCLASS_GPR64,
|
||||
/**
|
||||
* Floating point legacy registers.
|
||||
*/
|
||||
ZYDIS_REGCLASS_X87,
|
||||
/**
|
||||
* Floating point multimedia registers.
|
||||
*/
|
||||
ZYDIS_REGCLASS_MMX,
|
||||
/**
|
||||
* 128-bit vector registers.
|
||||
*/
|
||||
ZYDIS_REGCLASS_XMM,
|
||||
/**
|
||||
* 256-bit vector registers.
|
||||
*/
|
||||
ZYDIS_REGCLASS_YMM,
|
||||
/**
|
||||
* 512-bit vector registers.
|
||||
*/
|
||||
ZYDIS_REGCLASS_ZMM,
|
||||
/**
|
||||
* Matrix registers.
|
||||
*/
|
||||
ZYDIS_REGCLASS_TMM,
|
||||
/*
|
||||
* Flags registers.
|
||||
*/
|
||||
ZYDIS_REGCLASS_FLAGS,
|
||||
/**
|
||||
* Instruction-pointer registers.
|
||||
*/
|
||||
ZYDIS_REGCLASS_IP,
|
||||
/**
|
||||
* Segment registers.
|
||||
*/
|
||||
ZYDIS_REGCLASS_SEGMENT,
|
||||
/**
|
||||
* Table registers.
|
||||
*/
|
||||
ZYDIS_REGCLASS_TABLE,
|
||||
/**
|
||||
* Test registers.
|
||||
*/
|
||||
ZYDIS_REGCLASS_TEST,
|
||||
/**
|
||||
* Control registers.
|
||||
*/
|
||||
ZYDIS_REGCLASS_CONTROL,
|
||||
/**
|
||||
* Debug registers.
|
||||
*/
|
||||
ZYDIS_REGCLASS_DEBUG,
|
||||
/**
|
||||
* Mask registers.
|
||||
*/
|
||||
ZYDIS_REGCLASS_MASK,
|
||||
/**
|
||||
* Bound registers.
|
||||
*/
|
||||
ZYDIS_REGCLASS_BOUND,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_REGCLASS_MAX_VALUE = ZYDIS_REGCLASS_BOUND,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_REGCLASS_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_REGCLASS_MAX_VALUE)
|
||||
} ZydisRegisterClass;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Register width */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisRegisterWidth` data-type.
|
||||
*/
|
||||
typedef ZyanU16 ZydisRegisterWidth;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Register context */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisRegisterContext` struct.
|
||||
*/
|
||||
typedef struct ZydisRegisterContext_
|
||||
{
|
||||
/**
|
||||
* The values stored in the register context.
|
||||
*/
|
||||
ZyanU64 values[ZYDIS_REGISTER_MAX_VALUE + 1];
|
||||
} ZydisRegisterContext;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* @addtogroup register Register
|
||||
* Functions allowing retrieval of information about registers.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Register */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Returns the register specified by the `register_class` and `id` tuple.
|
||||
*
|
||||
* @param register_class The register class.
|
||||
* @param id The register id.
|
||||
*
|
||||
* @return The register specified by the `register_class` and `id` tuple or `ZYDIS_REGISTER_NONE`,
|
||||
* if an invalid parameter was passed.
|
||||
*/
|
||||
ZYDIS_EXPORT ZydisRegister ZydisRegisterEncode(ZydisRegisterClass register_class, ZyanU8 id);
|
||||
|
||||
/**
|
||||
* Returns the id of the specified register.
|
||||
*
|
||||
* @param reg The register.
|
||||
*
|
||||
* @return The id of the specified register, or -1 if an invalid parameter was passed.
|
||||
*/
|
||||
ZYDIS_EXPORT ZyanI8 ZydisRegisterGetId(ZydisRegister reg);
|
||||
|
||||
/**
|
||||
* Returns the register-class of the specified register.
|
||||
*
|
||||
* @param reg The register.
|
||||
*
|
||||
* @return The register-class of the specified register.
|
||||
*/
|
||||
ZYDIS_EXPORT ZydisRegisterClass ZydisRegisterGetClass(ZydisRegister reg);
|
||||
|
||||
/**
|
||||
* Returns the width of the specified register.
|
||||
*
|
||||
* @param mode The active machine mode.
|
||||
* @param reg The register.
|
||||
*
|
||||
* @return The width of the specified register, or `ZYDIS_REGISTER_NONE` if the register is
|
||||
* invalid for the active machine-mode.
|
||||
*/
|
||||
ZYDIS_EXPORT ZydisRegisterWidth ZydisRegisterGetWidth(ZydisMachineMode mode, ZydisRegister reg);
|
||||
|
||||
/**
|
||||
* Returns the largest enclosing register of the given register.
|
||||
*
|
||||
* @param mode The active machine mode.
|
||||
* @param reg The register.
|
||||
*
|
||||
* @return The largest enclosing register of the given register, or `ZYDIS_REGISTER_NONE` if the
|
||||
* register is invalid for the active machine-mode.
|
||||
*/
|
||||
ZYDIS_EXPORT ZydisRegister ZydisRegisterGetLargestEnclosing(ZydisMachineMode mode,
|
||||
ZydisRegister reg);
|
||||
|
||||
/**
|
||||
* Returns the specified register string.
|
||||
*
|
||||
* @param reg The register.
|
||||
*
|
||||
* @return The register string or `ZYAN_NULL`, if an invalid register was passed.
|
||||
*/
|
||||
ZYDIS_EXPORT const char* ZydisRegisterGetString(ZydisRegister reg);
|
||||
|
||||
/**
|
||||
* Returns the specified register string as `ZydisShortString`.
|
||||
*
|
||||
* @param reg The register.
|
||||
*
|
||||
* @return The register string or `ZYAN_NULL`, if an invalid register was passed.
|
||||
*
|
||||
* The `buffer` of the returned struct is guaranteed to be zero-terminated in this special case.
|
||||
*/
|
||||
ZYDIS_EXPORT const ZydisShortString* ZydisRegisterGetStringWrapped(ZydisRegister reg);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Register class */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Returns the width of the specified register-class.
|
||||
*
|
||||
* @param mode The active machine mode.
|
||||
* @param register_class The register class.
|
||||
*
|
||||
* @return The width of the specified register.
|
||||
*/
|
||||
ZYDIS_EXPORT ZydisRegisterWidth ZydisRegisterClassGetWidth(ZydisMachineMode mode,
|
||||
ZydisRegisterClass register_class);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZYDIS_REGISTER_H */
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Disassembler Library (Zydis)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Functions and types providing encoding information about individual instruction bytes.
|
||||
*/
|
||||
|
||||
#ifndef ZYDIS_SEGMENT_H
|
||||
#define ZYDIS_SEGMENT_H
|
||||
|
||||
#include <Zycore/Defines.h>
|
||||
#include <Zydis/DecoderTypes.h>
|
||||
#include <Zydis/Status.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @addtogroup segment Segment
|
||||
* Functions and types providing encoding information about individual instruction bytes.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Macros */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Constants */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#define ZYDIS_MAX_INSTRUCTION_SEGMENT_COUNT 9
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Enums and types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisInstructionSegment` struct.
|
||||
*/
|
||||
typedef enum ZydisInstructionSegment_
|
||||
{
|
||||
ZYDIS_INSTR_SEGMENT_NONE,
|
||||
/**
|
||||
* The legacy prefixes (including ignored `REX` prefixes).
|
||||
*/
|
||||
ZYDIS_INSTR_SEGMENT_PREFIXES,
|
||||
/**
|
||||
* The effective `REX` prefix byte.
|
||||
*/
|
||||
ZYDIS_INSTR_SEGMENT_REX,
|
||||
/**
|
||||
* The `XOP` prefix bytes.
|
||||
*/
|
||||
ZYDIS_INSTR_SEGMENT_XOP,
|
||||
/**
|
||||
* The `VEX` prefix bytes.
|
||||
*/
|
||||
ZYDIS_INSTR_SEGMENT_VEX,
|
||||
/**
|
||||
* The `EVEX` prefix bytes.
|
||||
*/
|
||||
ZYDIS_INSTR_SEGMENT_EVEX,
|
||||
/**
|
||||
* The `MVEX` prefix bytes.
|
||||
*/
|
||||
ZYDIS_INSTR_SEGMENT_MVEX,
|
||||
/**
|
||||
* The opcode bytes.
|
||||
*/
|
||||
ZYDIS_INSTR_SEGMENT_OPCODE,
|
||||
/**
|
||||
* The `ModRM` byte.
|
||||
*/
|
||||
ZYDIS_INSTR_SEGMENT_MODRM,
|
||||
/**
|
||||
* The `SIB` byte.
|
||||
*/
|
||||
ZYDIS_INSTR_SEGMENT_SIB,
|
||||
/**
|
||||
* The displacement bytes.
|
||||
*/
|
||||
ZYDIS_INSTR_SEGMENT_DISPLACEMENT,
|
||||
/**
|
||||
* The immediate bytes.
|
||||
*/
|
||||
ZYDIS_INSTR_SEGMENT_IMMEDIATE,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_INSTR_SEGMENT_MAX_VALUE = ZYDIS_INSTR_SEGMENT_IMMEDIATE,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_INSTR_SEGMENT_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_INSTR_SEGMENT_MAX_VALUE)
|
||||
} ZydisInstructionSegment;
|
||||
|
||||
/**
|
||||
* Defines the `ZydisInstructionSegments` struct.
|
||||
*/
|
||||
typedef struct ZydisInstructionSegments_
|
||||
{
|
||||
/**
|
||||
* The number of logical instruction segments.
|
||||
*/
|
||||
ZyanU8 count;
|
||||
struct
|
||||
{
|
||||
/**
|
||||
* The type of the segment.
|
||||
*/
|
||||
ZydisInstructionSegment type;
|
||||
/**
|
||||
* The offset of the segment relative to the start of the instruction (in bytes).
|
||||
*/
|
||||
ZyanU8 offset;
|
||||
/**
|
||||
* The size of the segment, in bytes.
|
||||
*/
|
||||
ZyanU8 size;
|
||||
} segments[ZYDIS_MAX_INSTRUCTION_SEGMENT_COUNT];
|
||||
} ZydisInstructionSegments;
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Exported functions */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* Returns offsets and sizes of all logical instruction segments (e.g. `OPCODE`,
|
||||
* `MODRM`, ...).
|
||||
*
|
||||
* @param instruction A pointer to the `ZydisDecodedInstruction` struct.
|
||||
* @param segments Receives the instruction segments information.
|
||||
*
|
||||
* @return A zyan status code.
|
||||
*/
|
||||
ZYDIS_EXPORT ZyanStatus ZydisGetInstructionSegments(const ZydisDecodedInstruction* instruction,
|
||||
ZydisInstructionSegments* segments);
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZYDIS_SEGMENT_H */
|
||||
+731
@@ -0,0 +1,731 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Disassembler Library (Zydis)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Defines decoder/encoder-shared macros and types.
|
||||
*/
|
||||
|
||||
#ifndef ZYDIS_SHAREDTYPES_H
|
||||
#define ZYDIS_SHAREDTYPES_H
|
||||
|
||||
#include <Zycore/Types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Macros */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Constants */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
#define ZYDIS_MAX_INSTRUCTION_LENGTH 15
|
||||
#define ZYDIS_MAX_OPERAND_COUNT 10 // TODO: Auto generate
|
||||
#define ZYDIS_MAX_OPERAND_COUNT_VISIBLE 5 // TODO: Auto generate
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Enums and types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Machine mode */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisMachineMode` enum.
|
||||
*/
|
||||
typedef enum ZydisMachineMode_
|
||||
{
|
||||
/**
|
||||
* 64 bit mode.
|
||||
*/
|
||||
ZYDIS_MACHINE_MODE_LONG_64,
|
||||
/**
|
||||
* 32 bit protected mode.
|
||||
*/
|
||||
ZYDIS_MACHINE_MODE_LONG_COMPAT_32,
|
||||
/**
|
||||
* 16 bit protected mode.
|
||||
*/
|
||||
ZYDIS_MACHINE_MODE_LONG_COMPAT_16,
|
||||
/**
|
||||
* 32 bit protected mode.
|
||||
*/
|
||||
ZYDIS_MACHINE_MODE_LEGACY_32,
|
||||
/**
|
||||
* 16 bit protected mode.
|
||||
*/
|
||||
ZYDIS_MACHINE_MODE_LEGACY_16,
|
||||
/**
|
||||
* 16 bit real mode.
|
||||
*/
|
||||
ZYDIS_MACHINE_MODE_REAL_16,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_MACHINE_MODE_MAX_VALUE = ZYDIS_MACHINE_MODE_REAL_16,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_MACHINE_MODE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_MACHINE_MODE_MAX_VALUE)
|
||||
} ZydisMachineMode;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Stack width */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisStackWidth` enum.
|
||||
*/
|
||||
typedef enum ZydisStackWidth_
|
||||
{
|
||||
ZYDIS_STACK_WIDTH_16,
|
||||
ZYDIS_STACK_WIDTH_32,
|
||||
ZYDIS_STACK_WIDTH_64,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_STACK_WIDTH_MAX_VALUE = ZYDIS_STACK_WIDTH_64,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_STACK_WIDTH_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_STACK_WIDTH_MAX_VALUE)
|
||||
} ZydisStackWidth;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Element type */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisElementType` enum.
|
||||
*/
|
||||
typedef enum ZydisElementType_
|
||||
{
|
||||
ZYDIS_ELEMENT_TYPE_INVALID,
|
||||
/**
|
||||
* A struct type.
|
||||
*/
|
||||
ZYDIS_ELEMENT_TYPE_STRUCT,
|
||||
/**
|
||||
* Unsigned integer value.
|
||||
*/
|
||||
ZYDIS_ELEMENT_TYPE_UINT,
|
||||
/**
|
||||
* Signed integer value.
|
||||
*/
|
||||
ZYDIS_ELEMENT_TYPE_INT,
|
||||
/**
|
||||
* 16-bit floating point value (`half`).
|
||||
*/
|
||||
ZYDIS_ELEMENT_TYPE_FLOAT16,
|
||||
/**
|
||||
* 32-bit floating point value (`single`).
|
||||
*/
|
||||
ZYDIS_ELEMENT_TYPE_FLOAT32,
|
||||
/**
|
||||
* 64-bit floating point value (`double`).
|
||||
*/
|
||||
ZYDIS_ELEMENT_TYPE_FLOAT64,
|
||||
/**
|
||||
* 80-bit floating point value (`extended`).
|
||||
*/
|
||||
ZYDIS_ELEMENT_TYPE_FLOAT80,
|
||||
/**
|
||||
* 16-bit brain floating point value.
|
||||
*/
|
||||
ZYDIS_ELEMENT_TYPE_BFLOAT16,
|
||||
/**
|
||||
* Binary coded decimal value.
|
||||
*/
|
||||
ZYDIS_ELEMENT_TYPE_LONGBCD,
|
||||
/**
|
||||
* A condition code (e.g. used by `CMPPD`, `VCMPPD`, ...).
|
||||
*/
|
||||
ZYDIS_ELEMENT_TYPE_CC,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_ELEMENT_TYPE_MAX_VALUE = ZYDIS_ELEMENT_TYPE_CC,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_ELEMENT_TYPE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_ELEMENT_TYPE_MAX_VALUE)
|
||||
} ZydisElementType;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Element size */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisElementSize` datatype.
|
||||
*/
|
||||
typedef ZyanU16 ZydisElementSize;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Operand type */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisOperandType` enum.
|
||||
*/
|
||||
typedef enum ZydisOperandType_
|
||||
{
|
||||
/**
|
||||
* The operand is not used.
|
||||
*/
|
||||
ZYDIS_OPERAND_TYPE_UNUSED,
|
||||
/**
|
||||
* The operand is a register operand.
|
||||
*/
|
||||
ZYDIS_OPERAND_TYPE_REGISTER,
|
||||
/**
|
||||
* The operand is a memory operand.
|
||||
*/
|
||||
ZYDIS_OPERAND_TYPE_MEMORY,
|
||||
/**
|
||||
* The operand is a pointer operand with a segment:offset lvalue.
|
||||
*/
|
||||
ZYDIS_OPERAND_TYPE_POINTER,
|
||||
/**
|
||||
* The operand is an immediate operand.
|
||||
*/
|
||||
ZYDIS_OPERAND_TYPE_IMMEDIATE,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_OPERAND_TYPE_MAX_VALUE = ZYDIS_OPERAND_TYPE_IMMEDIATE,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_OPERAND_TYPE_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_OPERAND_TYPE_MAX_VALUE)
|
||||
} ZydisOperandType;
|
||||
|
||||
// If asserts are failing here remember to update encoder table generator before fixing asserts
|
||||
ZYAN_STATIC_ASSERT(ZYAN_BITS_TO_REPRESENT(
|
||||
ZYDIS_OPERAND_TYPE_MAX_VALUE - ZYDIS_OPERAND_TYPE_REGISTER) == 2);
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Operand encoding */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisOperandEncoding` enum.
|
||||
*/
|
||||
typedef enum ZydisOperandEncoding_
|
||||
{
|
||||
ZYDIS_OPERAND_ENCODING_NONE,
|
||||
ZYDIS_OPERAND_ENCODING_MODRM_REG,
|
||||
ZYDIS_OPERAND_ENCODING_MODRM_RM,
|
||||
ZYDIS_OPERAND_ENCODING_OPCODE,
|
||||
ZYDIS_OPERAND_ENCODING_NDSNDD,
|
||||
ZYDIS_OPERAND_ENCODING_IS4,
|
||||
ZYDIS_OPERAND_ENCODING_MASK,
|
||||
ZYDIS_OPERAND_ENCODING_DISP8,
|
||||
ZYDIS_OPERAND_ENCODING_DISP16,
|
||||
ZYDIS_OPERAND_ENCODING_DISP32,
|
||||
ZYDIS_OPERAND_ENCODING_DISP64,
|
||||
ZYDIS_OPERAND_ENCODING_DISP16_32_64,
|
||||
ZYDIS_OPERAND_ENCODING_DISP32_32_64,
|
||||
ZYDIS_OPERAND_ENCODING_DISP16_32_32,
|
||||
ZYDIS_OPERAND_ENCODING_UIMM8,
|
||||
ZYDIS_OPERAND_ENCODING_UIMM16,
|
||||
ZYDIS_OPERAND_ENCODING_UIMM32,
|
||||
ZYDIS_OPERAND_ENCODING_UIMM64,
|
||||
ZYDIS_OPERAND_ENCODING_UIMM16_32_64,
|
||||
ZYDIS_OPERAND_ENCODING_UIMM32_32_64,
|
||||
ZYDIS_OPERAND_ENCODING_UIMM16_32_32,
|
||||
ZYDIS_OPERAND_ENCODING_SIMM8,
|
||||
ZYDIS_OPERAND_ENCODING_SIMM16,
|
||||
ZYDIS_OPERAND_ENCODING_SIMM32,
|
||||
ZYDIS_OPERAND_ENCODING_SIMM64,
|
||||
ZYDIS_OPERAND_ENCODING_SIMM16_32_64,
|
||||
ZYDIS_OPERAND_ENCODING_SIMM32_32_64,
|
||||
ZYDIS_OPERAND_ENCODING_SIMM16_32_32,
|
||||
ZYDIS_OPERAND_ENCODING_JIMM8,
|
||||
ZYDIS_OPERAND_ENCODING_JIMM16,
|
||||
ZYDIS_OPERAND_ENCODING_JIMM32,
|
||||
ZYDIS_OPERAND_ENCODING_JIMM64,
|
||||
ZYDIS_OPERAND_ENCODING_JIMM16_32_64,
|
||||
ZYDIS_OPERAND_ENCODING_JIMM32_32_64,
|
||||
ZYDIS_OPERAND_ENCODING_JIMM16_32_32,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_OPERAND_ENCODING_MAX_VALUE = ZYDIS_OPERAND_ENCODING_JIMM16_32_32,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_OPERAND_ENCODING_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_OPERAND_ENCODING_MAX_VALUE)
|
||||
} ZydisOperandEncoding;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Operand visibility */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisOperandVisibility` enum.
|
||||
*/
|
||||
typedef enum ZydisOperandVisibility_
|
||||
{
|
||||
ZYDIS_OPERAND_VISIBILITY_INVALID,
|
||||
/**
|
||||
* The operand is explicitly encoded in the instruction.
|
||||
*/
|
||||
ZYDIS_OPERAND_VISIBILITY_EXPLICIT,
|
||||
/**
|
||||
* The operand is part of the opcode, but listed as an operand.
|
||||
*/
|
||||
ZYDIS_OPERAND_VISIBILITY_IMPLICIT,
|
||||
/**
|
||||
* The operand is part of the opcode, and not typically listed as an operand.
|
||||
*/
|
||||
ZYDIS_OPERAND_VISIBILITY_HIDDEN,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_OPERAND_VISIBILITY_MAX_VALUE = ZYDIS_OPERAND_VISIBILITY_HIDDEN,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_OPERAND_VISIBILITY_REQUIRED_BITS =
|
||||
ZYAN_BITS_TO_REPRESENT(ZYDIS_OPERAND_VISIBILITY_MAX_VALUE)
|
||||
} ZydisOperandVisibility;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Operand action */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisOperandAction` enum.
|
||||
*/
|
||||
typedef enum ZydisOperandAction_
|
||||
{
|
||||
/* ------------------------------------------------------------------------------------------ */
|
||||
/* Elemental actions */
|
||||
/* ------------------------------------------------------------------------------------------ */
|
||||
|
||||
/**
|
||||
* The operand is read by the instruction.
|
||||
*/
|
||||
ZYDIS_OPERAND_ACTION_READ = 0x01,
|
||||
/**
|
||||
* The operand is written by the instruction (must write).
|
||||
*/
|
||||
ZYDIS_OPERAND_ACTION_WRITE = 0x02,
|
||||
/**
|
||||
* The operand is conditionally read by the instruction.
|
||||
*/
|
||||
ZYDIS_OPERAND_ACTION_CONDREAD = 0x04,
|
||||
/**
|
||||
* The operand is conditionally written by the instruction (may write).
|
||||
*/
|
||||
ZYDIS_OPERAND_ACTION_CONDWRITE = 0x08,
|
||||
|
||||
/* ------------------------------------------------------------------------------------------ */
|
||||
/* Combined actions */
|
||||
/* ------------------------------------------------------------------------------------------ */
|
||||
|
||||
/**
|
||||
* The operand is read (must read) and written by the instruction (must write).
|
||||
*/
|
||||
ZYDIS_OPERAND_ACTION_READWRITE = ZYDIS_OPERAND_ACTION_READ | ZYDIS_OPERAND_ACTION_WRITE,
|
||||
/**
|
||||
* The operand is conditionally read (may read) and conditionally written by
|
||||
* the instruction (may write).
|
||||
*/
|
||||
ZYDIS_OPERAND_ACTION_CONDREAD_CONDWRITE =
|
||||
ZYDIS_OPERAND_ACTION_CONDREAD | ZYDIS_OPERAND_ACTION_CONDWRITE,
|
||||
/**
|
||||
* The operand is read (must read) and conditionally written by the
|
||||
* instruction (may write).
|
||||
*/
|
||||
ZYDIS_OPERAND_ACTION_READ_CONDWRITE =
|
||||
ZYDIS_OPERAND_ACTION_READ | ZYDIS_OPERAND_ACTION_CONDWRITE,
|
||||
/**
|
||||
* The operand is written (must write) and conditionally read by the
|
||||
* instruction (may read).
|
||||
*/
|
||||
ZYDIS_OPERAND_ACTION_CONDREAD_WRITE =
|
||||
ZYDIS_OPERAND_ACTION_CONDREAD | ZYDIS_OPERAND_ACTION_WRITE,
|
||||
|
||||
/**
|
||||
* Mask combining all reading access flags.
|
||||
*/
|
||||
ZYDIS_OPERAND_ACTION_MASK_READ = ZYDIS_OPERAND_ACTION_READ | ZYDIS_OPERAND_ACTION_CONDREAD,
|
||||
/**
|
||||
* Mask combining all writing access flags.
|
||||
*/
|
||||
ZYDIS_OPERAND_ACTION_MASK_WRITE = ZYDIS_OPERAND_ACTION_WRITE | ZYDIS_OPERAND_ACTION_CONDWRITE,
|
||||
|
||||
/* ------------------------------------------------------------------------------------------ */
|
||||
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this bitset.
|
||||
*/
|
||||
ZYDIS_OPERAND_ACTION_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_OPERAND_ACTION_CONDWRITE)
|
||||
} ZydisOperandAction;
|
||||
|
||||
/**
|
||||
* Defines the `ZydisOperandActions` data-type.
|
||||
*/
|
||||
typedef ZyanU8 ZydisOperandActions;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Instruction encoding */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisInstructionEncoding` enum.
|
||||
*/
|
||||
typedef enum ZydisInstructionEncoding_
|
||||
{
|
||||
/**
|
||||
* The instruction uses the legacy encoding.
|
||||
*/
|
||||
ZYDIS_INSTRUCTION_ENCODING_LEGACY,
|
||||
/**
|
||||
* The instruction uses the AMD 3DNow-encoding.
|
||||
*/
|
||||
ZYDIS_INSTRUCTION_ENCODING_3DNOW,
|
||||
/**
|
||||
* The instruction uses the AMD XOP-encoding.
|
||||
*/
|
||||
ZYDIS_INSTRUCTION_ENCODING_XOP,
|
||||
/**
|
||||
* The instruction uses the VEX-encoding.
|
||||
*/
|
||||
ZYDIS_INSTRUCTION_ENCODING_VEX,
|
||||
/**
|
||||
* The instruction uses the EVEX-encoding.
|
||||
*/
|
||||
ZYDIS_INSTRUCTION_ENCODING_EVEX,
|
||||
/**
|
||||
* The instruction uses the MVEX-encoding.
|
||||
*/
|
||||
ZYDIS_INSTRUCTION_ENCODING_MVEX,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_INSTRUCTION_ENCODING_MAX_VALUE = ZYDIS_INSTRUCTION_ENCODING_MVEX,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_INSTRUCTION_ENCODING_REQUIRED_BITS =
|
||||
ZYAN_BITS_TO_REPRESENT(ZYDIS_INSTRUCTION_ENCODING_MAX_VALUE)
|
||||
} ZydisInstructionEncoding;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Opcode map */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Defines the `ZydisOpcodeMap` enum.
|
||||
*/
|
||||
typedef enum ZydisOpcodeMap_
|
||||
{
|
||||
ZYDIS_OPCODE_MAP_DEFAULT,
|
||||
ZYDIS_OPCODE_MAP_0F,
|
||||
ZYDIS_OPCODE_MAP_0F38,
|
||||
ZYDIS_OPCODE_MAP_0F3A,
|
||||
ZYDIS_OPCODE_MAP_MAP4, // not used
|
||||
ZYDIS_OPCODE_MAP_MAP5,
|
||||
ZYDIS_OPCODE_MAP_MAP6,
|
||||
ZYDIS_OPCODE_MAP_MAP7, // not used
|
||||
ZYDIS_OPCODE_MAP_0F0F,
|
||||
ZYDIS_OPCODE_MAP_XOP8,
|
||||
ZYDIS_OPCODE_MAP_XOP9,
|
||||
ZYDIS_OPCODE_MAP_XOPA,
|
||||
|
||||
/**
|
||||
* Maximum value of this enum.
|
||||
*/
|
||||
ZYDIS_OPCODE_MAP_MAX_VALUE = ZYDIS_OPCODE_MAP_XOPA,
|
||||
/**
|
||||
* The minimum number of bits required to represent all values of this enum.
|
||||
*/
|
||||
ZYDIS_OPCODE_MAP_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_OPCODE_MAP_MAX_VALUE)
|
||||
} ZydisOpcodeMap;
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
/* Instruction attributes */
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @defgroup instruction_attributes Instruction attributes
|
||||
*
|
||||
* Constants describing various properties of an instruction. Used in the
|
||||
* @ref ZydisDecodedInstruction.attributes and @ref ZydisEncoderRequest.prefixes fields.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Defines the `ZydisInstructionAttributes` data-type.
|
||||
*/
|
||||
typedef ZyanU64 ZydisInstructionAttributes;
|
||||
|
||||
/**
|
||||
* The instruction has the `ModRM` byte.
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_HAS_MODRM (1ULL << 0)
|
||||
/**
|
||||
* The instruction has the `SIB` byte.
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_HAS_SIB (1ULL << 1)
|
||||
/**
|
||||
* The instruction has the `REX` prefix.
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_HAS_REX (1ULL << 2)
|
||||
/**
|
||||
* The instruction has the `XOP` prefix.
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_HAS_XOP (1ULL << 3)
|
||||
/**
|
||||
* The instruction has the `VEX` prefix.
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_HAS_VEX (1ULL << 4)
|
||||
/**
|
||||
* The instruction has the `EVEX` prefix.
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_HAS_EVEX (1ULL << 5)
|
||||
/**
|
||||
* The instruction has the `MVEX` prefix.
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_HAS_MVEX (1ULL << 6)
|
||||
/**
|
||||
* The instruction has one or more operands with position-relative offsets.
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_IS_RELATIVE (1ULL << 7)
|
||||
/**
|
||||
* The instruction is privileged.
|
||||
*
|
||||
* Privileged instructions are any instructions that require a current ring level below 3.
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_IS_PRIVILEGED (1ULL << 8)
|
||||
/**
|
||||
* The instruction accesses one or more CPU-flags.
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_CPUFLAG_ACCESS (1ULL << 9)
|
||||
/**
|
||||
* The instruction may conditionally read the general CPU state.
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_CPU_STATE_CR (1ULL << 10)
|
||||
/**
|
||||
* The instruction may conditionally write the general CPU state.
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_CPU_STATE_CW (1ULL << 11)
|
||||
/**
|
||||
* The instruction may conditionally read the FPU state (X87, MMX).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_FPU_STATE_CR (1ULL << 12)
|
||||
/**
|
||||
* The instruction may conditionally write the FPU state (X87, MMX).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_FPU_STATE_CW (1ULL << 13)
|
||||
/**
|
||||
* The instruction may conditionally read the XMM state (AVX, AVX2, AVX-512).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_XMM_STATE_CR (1ULL << 14)
|
||||
/**
|
||||
* The instruction may conditionally write the XMM state (AVX, AVX2, AVX-512).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_XMM_STATE_CW (1ULL << 15)
|
||||
/**
|
||||
* The instruction accepts the `LOCK` prefix (`0xF0`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_ACCEPTS_LOCK (1ULL << 16)
|
||||
/**
|
||||
* The instruction accepts the `REP` prefix (`0xF3`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_ACCEPTS_REP (1ULL << 17)
|
||||
/**
|
||||
* The instruction accepts the `REPE`/`REPZ` prefix (`0xF3`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_ACCEPTS_REPE (1ULL << 18)
|
||||
/**
|
||||
* The instruction accepts the `REPE`/`REPZ` prefix (`0xF3`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_ACCEPTS_REPZ ZYDIS_ATTRIB_ACCEPTS_REPE
|
||||
/**
|
||||
* The instruction accepts the `REPNE`/`REPNZ` prefix (`0xF2`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_ACCEPTS_REPNE (1ULL << 19)
|
||||
/**
|
||||
* The instruction accepts the `REPNE`/`REPNZ` prefix (`0xF2`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_ACCEPTS_REPNZ ZYDIS_ATTRIB_ACCEPTS_REPNE
|
||||
/**
|
||||
* The instruction accepts the `BND` prefix (`0xF2`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_ACCEPTS_BND (1ULL << 20)
|
||||
/**
|
||||
* The instruction accepts the `XACQUIRE` prefix (`0xF2`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_ACCEPTS_XACQUIRE (1ULL << 21)
|
||||
/**
|
||||
* The instruction accepts the `XRELEASE` prefix (`0xF3`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_ACCEPTS_XRELEASE (1ULL << 22)
|
||||
/**
|
||||
* The instruction accepts the `XACQUIRE`/`XRELEASE` prefixes (`0xF2`, `0xF3`)
|
||||
* without the `LOCK` prefix (`0x0F`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_ACCEPTS_HLE_WITHOUT_LOCK (1ULL << 23)
|
||||
/**
|
||||
* The instruction accepts branch hints (0x2E, 0x3E).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_ACCEPTS_BRANCH_HINTS (1ULL << 24)
|
||||
/**
|
||||
* The instruction accepts the `CET` `no-track` prefix (`0x3E`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_ACCEPTS_NOTRACK (1ULL << 25)
|
||||
/**
|
||||
* The instruction accepts segment prefixes (`0x2E`, `0x36`, `0x3E`, `0x26`,
|
||||
* `0x64`, `0x65`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_ACCEPTS_SEGMENT (1ULL << 26)
|
||||
/**
|
||||
* The instruction has the `LOCK` prefix (`0xF0`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_HAS_LOCK (1ULL << 27)
|
||||
/**
|
||||
* The instruction has the `REP` prefix (`0xF3`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_HAS_REP (1ULL << 28)
|
||||
/**
|
||||
* The instruction has the `REPE`/`REPZ` prefix (`0xF3`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_HAS_REPE (1ULL << 29)
|
||||
/**
|
||||
* The instruction has the `REPE`/`REPZ` prefix (`0xF3`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_HAS_REPZ ZYDIS_ATTRIB_HAS_REPE
|
||||
/**
|
||||
* The instruction has the `REPNE`/`REPNZ` prefix (`0xF2`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_HAS_REPNE (1ULL << 30)
|
||||
/**
|
||||
* The instruction has the `REPNE`/`REPNZ` prefix (`0xF2`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_HAS_REPNZ ZYDIS_ATTRIB_HAS_REPNE
|
||||
/**
|
||||
* The instruction has the `BND` prefix (`0xF2`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_HAS_BND (1ULL << 31)
|
||||
/**
|
||||
* The instruction has the `XACQUIRE` prefix (`0xF2`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_HAS_XACQUIRE (1ULL << 32)
|
||||
/**
|
||||
* The instruction has the `XRELEASE` prefix (`0xF3`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_HAS_XRELEASE (1ULL << 33)
|
||||
/**
|
||||
* The instruction has the branch-not-taken hint (`0x2E`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_HAS_BRANCH_NOT_TAKEN (1ULL << 34)
|
||||
/**
|
||||
* The instruction has the branch-taken hint (`0x3E`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_HAS_BRANCH_TAKEN (1ULL << 35)
|
||||
/**
|
||||
* The instruction has the `CET` `no-track` prefix (`0x3E`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_HAS_NOTRACK (1ULL << 36)
|
||||
/**
|
||||
* The instruction has the `CS` segment modifier (`0x2E`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_HAS_SEGMENT_CS (1ULL << 37)
|
||||
/**
|
||||
* The instruction has the `SS` segment modifier (`0x36`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_HAS_SEGMENT_SS (1ULL << 38)
|
||||
/**
|
||||
* The instruction has the `DS` segment modifier (`0x3E`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_HAS_SEGMENT_DS (1ULL << 39)
|
||||
/**
|
||||
* The instruction has the `ES` segment modifier (`0x26`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_HAS_SEGMENT_ES (1ULL << 40)
|
||||
/**
|
||||
* The instruction has the `FS` segment modifier (`0x64`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_HAS_SEGMENT_FS (1ULL << 41)
|
||||
/**
|
||||
* The instruction has the `GS` segment modifier (`0x65`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_HAS_SEGMENT_GS (1ULL << 42)
|
||||
/**
|
||||
* The instruction has a segment modifier.
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_HAS_SEGMENT (ZYDIS_ATTRIB_HAS_SEGMENT_CS | \
|
||||
ZYDIS_ATTRIB_HAS_SEGMENT_SS | \
|
||||
ZYDIS_ATTRIB_HAS_SEGMENT_DS | \
|
||||
ZYDIS_ATTRIB_HAS_SEGMENT_ES | \
|
||||
ZYDIS_ATTRIB_HAS_SEGMENT_FS | \
|
||||
ZYDIS_ATTRIB_HAS_SEGMENT_GS)
|
||||
/**
|
||||
* The instruction has the operand-size override prefix (`0x66`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_HAS_OPERANDSIZE (1ULL << 43) // TODO: rename
|
||||
/**
|
||||
* The instruction has the address-size override prefix (`0x67`).
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_HAS_ADDRESSSIZE (1ULL << 44) // TODO: rename
|
||||
/**
|
||||
* The instruction has the `EVEX.b` bit set.
|
||||
*
|
||||
* This attribute is mainly used by the encoder.
|
||||
*/
|
||||
#define ZYDIS_ATTRIB_HAS_EVEX_B (1ULL << 45) // TODO: rename
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------- */
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZYDIS_SHAREDTYPES_H */
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
/***************************************************************************************************
|
||||
|
||||
Zyan Disassembler Library (Zydis)
|
||||
|
||||
Original Author : Florian Bernd
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
|
||||
***************************************************************************************************/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Defines the immutable and storage-efficient `ZydisShortString` struct, which
|
||||
* is used to store strings in the generated tables.
|
||||
*/
|
||||
|
||||
#ifndef ZYDIS_SHORTSTRING_H
|
||||
#define ZYDIS_SHORTSTRING_H
|
||||
|
||||
#include <Zycore/Defines.h>
|
||||
#include <Zycore/Types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Enums and types */
|
||||
/* ============================================================================================== */
|
||||
|
||||
#if !defined(ZYAN_APPLE)
|
||||
# pragma pack(push, 1)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Defines the `ZydisShortString` struct.
|
||||
*
|
||||
* This compact struct is mainly used for internal string-tables to save up some bytes.
|
||||
*
|
||||
* All fields in this struct should be considered as "private". Any changes may lead to unexpected
|
||||
* behavior.
|
||||
*/
|
||||
typedef struct ZydisShortString_
|
||||
{
|
||||
/**
|
||||
* The buffer that contains the actual (null-terminated) string.
|
||||
*/
|
||||
const char* data;
|
||||
/**
|
||||
* The length (number of characters) of the string (without 0-termination).
|
||||
*/
|
||||
ZyanU8 size;
|
||||
} ZydisShortString;
|
||||
|
||||
#if !defined(ZYAN_APPLE)
|
||||
# pragma pack(pop)
|
||||
#endif
|
||||
|
||||
/* ============================================================================================== */
|
||||
/* Macros */
|
||||
/* ============================================================================================== */
|
||||
|
||||
/**
|
||||
* Declares a `ZydisShortString` from a static C-style string.
|
||||
*
|
||||
* @param string The C-string constant.
|
||||
*/
|
||||
#define ZYDIS_MAKE_SHORTSTRING(string) \
|
||||
{ string, sizeof(string) - 1 }
|
||||
|
||||
/* ============================================================================================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZYDIS_SHORTSTRING_H */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user