1
0
Fork 0

Add some cross platform example projects

This commit is contained in:
Duncan Ogilvie 2023-09-22 18:51:13 +02:00
parent 2223a7f10b
commit b89af0c51e
58 changed files with 39125 additions and 56 deletions

3
src/cross/.gitattributes vendored Normal file
View File

@ -0,0 +1,3 @@
# cmkr
/**/CMakeLists.txt linguist-generated
/**/cmkr.cmake linguist-vendored

133
src/cross/CMakeLists.txt generated Normal file
View File

@ -0,0 +1,133 @@
# This file is automatically generated from cmake.toml - DO NOT EDIT
# See https://github.com/build-cpp/cmkr for more information
cmake_minimum_required(VERSION 3.15)
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
message(FATAL_ERROR "In-tree builds are not supported. Run CMake from a separate directory: cmake -B build")
endif()
set(CMKR_ROOT_PROJECT OFF)
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
set(CMKR_ROOT_PROJECT ON)
# Bootstrap cmkr and automatically regenerate CMakeLists.txt
include(cmkr.cmake OPTIONAL RESULT_VARIABLE CMKR_INCLUDE_RESULT)
if(CMKR_INCLUDE_RESULT)
cmkr()
endif()
# Enable folder support
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
# Create a configure-time dependency on cmake.toml to improve IDE support
configure_file(cmake.toml cmake.toml COPYONLY)
endif()
project(cross)
include("gui/Qt.cmake")
# Subdirectory: gui
set(CMKR_CMAKE_FOLDER ${CMAKE_FOLDER})
if(CMAKE_FOLDER)
set(CMAKE_FOLDER "${CMAKE_FOLDER}/gui")
else()
set(CMAKE_FOLDER gui)
endif()
add_subdirectory(gui)
set(CMAKE_FOLDER ${CMKR_CMAKE_FOLDER})
# Subdirectory: vendor
set(CMKR_CMAKE_FOLDER ${CMAKE_FOLDER})
if(CMAKE_FOLDER)
set(CMAKE_FOLDER "${CMAKE_FOLDER}/vendor")
else()
set(CMAKE_FOLDER vendor)
endif()
add_subdirectory(vendor)
set(CMAKE_FOLDER ${CMKR_CMAKE_FOLDER})
# Target: minidump
set(minidump_SOURCES
"minidump/GotoDialog.cpp"
"minidump/MainWindow.cpp"
"minidump/MiniDisassembly.cpp"
"minidump/MiniDump.cpp"
"minidump/MiniHexDump.cpp"
"minidump/MiniMemoryMap.cpp"
"minidump/Navigation.cpp"
"minidump/REToolSync.cpp"
"minidump/main.cpp"
"minidump/GotoDialog.h"
"minidump/MainWindow.h"
"minidump/MiniDisassembly.h"
"minidump/MiniDump.h"
"minidump/MiniHexDump.h"
"minidump/MiniMemoryMap.h"
"minidump/Navigation.h"
"minidump/REToolSync.h"
"minidump/udmp-parser.h"
"minidump/udmp-utils.h"
"minidump/MainWindow.ui"
cmake.toml
)
qt_executable(minidump ${minidump_SOURCES})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${minidump_SOURCES})
target_compile_features(minidump PRIVATE
cxx_std_17
)
target_link_libraries(minidump PRIVATE
${QT_LIBRARIES}
widgets
cpp-httplib
)
get_directory_property(CMKR_VS_STARTUP_PROJECT DIRECTORY ${PROJECT_SOURCE_DIR} DEFINITION VS_STARTUP_PROJECT)
if(NOT CMKR_VS_STARTUP_PROJECT)
set_property(DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT minidump)
endif()
set(CMKR_TARGET minidump)
qt_finalize_executable(${CMKR_TARGET})
# Target: remote_table
set(remote_table_SOURCES
"remote_table/JsonRpcClient.cpp"
"remote_table/MainWindow.cpp"
"remote_table/RemoteTable.cpp"
"remote_table/TableServer.cpp"
"remote_table/main.cpp"
"remote_table/JsonRpcClient.h"
"remote_table/MainWindow.h"
"remote_table/RemoteTable.h"
"remote_table/TableRpcData.h"
"remote_table/TableServer.h"
"remote_table/MainWindow.ui"
"remote_table/json.hpp"
cmake.toml
)
qt_executable(remote_table ${remote_table_SOURCES})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${remote_table_SOURCES})
target_compile_features(remote_table PRIVATE
cxx_std_17
)
target_link_libraries(remote_table PRIVATE
${QT_LIBRARIES}
widgets
)
get_directory_property(CMKR_VS_STARTUP_PROJECT DIRECTORY ${PROJECT_SOURCE_DIR} DEFINITION VS_STARTUP_PROJECT)
if(NOT CMKR_VS_STARTUP_PROJECT)
set_property(DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT remote_table)
endif()
set(CMKR_TARGET remote_table)
qt_finalize_executable(${CMKR_TARGET})

49
src/cross/cmake.toml Normal file
View File

@ -0,0 +1,49 @@
# Reference: https://build-cpp.github.io/cmkr/cmake-toml
[project]
name = "cross"
include-after = ["gui/Qt.cmake"]
[subdir.gui]
[subdir.vendor]
[template.qt_executable]
type = "executable"
add-function = "qt_executable"
pass-sources = true
[target.minidump]
type = "qt_executable"
sources = [
"minidump/*.cpp",
"minidump/*.h",
"minidump/*.ui",
"minidump/*.qrc",
]
link-libraries = [
"${QT_LIBRARIES}",
"widgets",
"cpp-httplib",
]
compile-features = ["cxx_std_17"]
cmake-after = """
qt_finalize_executable(${CMKR_TARGET})
"""
[target.remote_table]
type = "qt_executable"
sources = [
"remote_table/*.cpp",
"remote_table/*.h",
"remote_table/*.ui",
"remote_table/*.qrc",
"remote_table/json.hpp",
]
link-libraries = [
"${QT_LIBRARIES}",
"widgets",
]
compile-features = ["cxx_std_17"]
cmake-after = """
qt_finalize_executable(${CMKR_TARGET})
"""

253
src/cross/cmkr.cmake vendored Normal file
View File

@ -0,0 +1,253 @@
include_guard()
# Change these defaults to point to your infrastructure if desired
set(CMKR_REPO "https://github.com/build-cpp/cmkr" CACHE STRING "cmkr git repository" FORCE)
set(CMKR_TAG "v0.2.23" CACHE STRING "cmkr git tag (this needs to be available forever)" FORCE)
set(CMKR_COMMIT_HASH "" CACHE STRING "cmkr git commit hash (optional)" FORCE)
# To bootstrap/generate a cmkr project: cmake -P cmkr.cmake
if(CMAKE_SCRIPT_MODE_FILE)
set(CMAKE_BINARY_DIR "${CMAKE_BINARY_DIR}/build")
set(CMAKE_CURRENT_BINARY_DIR "${CMAKE_BINARY_DIR}")
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}")
endif()
# Set these from the command line to customize for development/debugging purposes
set(CMKR_EXECUTABLE "" CACHE FILEPATH "cmkr executable")
set(CMKR_SKIP_GENERATION OFF CACHE BOOL "skip automatic cmkr generation")
set(CMKR_BUILD_TYPE "Debug" CACHE STRING "cmkr build configuration")
mark_as_advanced(CMKR_REPO CMKR_TAG CMKR_COMMIT_HASH CMKR_EXECUTABLE CMKR_SKIP_GENERATION CMKR_BUILD_TYPE)
# Disable cmkr if generation is disabled
if(DEFINED ENV{CI} OR CMKR_SKIP_GENERATION OR CMKR_BUILD_SKIP_GENERATION)
message(STATUS "[cmkr] Skipping automatic cmkr generation")
unset(CMKR_BUILD_SKIP_GENERATION CACHE)
macro(cmkr)
endmacro()
return()
endif()
# Disable cmkr if no cmake.toml file is found
if(NOT CMAKE_SCRIPT_MODE_FILE AND NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake.toml")
message(AUTHOR_WARNING "[cmkr] Not found: ${CMAKE_CURRENT_SOURCE_DIR}/cmake.toml")
macro(cmkr)
endmacro()
return()
endif()
# Convert a Windows native path to CMake path
if(CMKR_EXECUTABLE MATCHES "\\\\")
string(REPLACE "\\" "/" CMKR_EXECUTABLE_CMAKE "${CMKR_EXECUTABLE}")
set(CMKR_EXECUTABLE "${CMKR_EXECUTABLE_CMAKE}" CACHE FILEPATH "" FORCE)
unset(CMKR_EXECUTABLE_CMAKE)
endif()
# Helper macro to execute a process (COMMAND_ERROR_IS_FATAL ANY is 3.19 and higher)
function(cmkr_exec)
execute_process(COMMAND ${ARGV} RESULT_VARIABLE CMKR_EXEC_RESULT)
if(NOT CMKR_EXEC_RESULT EQUAL 0)
message(FATAL_ERROR "cmkr_exec(${ARGV}) failed (exit code ${CMKR_EXEC_RESULT})")
endif()
endfunction()
# Windows-specific hack (CMAKE_EXECUTABLE_PREFIX is not set at the moment)
if(WIN32)
set(CMKR_EXECUTABLE_NAME "cmkr.exe")
else()
set(CMKR_EXECUTABLE_NAME "cmkr")
endif()
# Use cached cmkr if found
if(DEFINED ENV{CMKR_CACHE})
set(CMKR_DIRECTORY_PREFIX "$ENV{CMKR_CACHE}")
string(REPLACE "\\" "/" CMKR_DIRECTORY_PREFIX "${CMKR_DIRECTORY_PREFIX}")
if(NOT CMKR_DIRECTORY_PREFIX MATCHES "\\/$")
set(CMKR_DIRECTORY_PREFIX "${CMKR_DIRECTORY_PREFIX}/")
endif()
# Build in release mode for the cache
set(CMKR_BUILD_TYPE "Release")
else()
set(CMKR_DIRECTORY_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/_cmkr_")
endif()
set(CMKR_DIRECTORY "${CMKR_DIRECTORY_PREFIX}${CMKR_TAG}")
set(CMKR_CACHED_EXECUTABLE "${CMKR_DIRECTORY}/bin/${CMKR_EXECUTABLE_NAME}")
# Helper function to check if a string starts with a prefix
# Cannot use MATCHES, see: https://github.com/build-cpp/cmkr/issues/61
function(cmkr_startswith str prefix result)
string(LENGTH "${prefix}" prefix_length)
string(LENGTH "${str}" str_length)
if(prefix_length LESS_EQUAL str_length)
string(SUBSTRING "${str}" 0 ${prefix_length} str_prefix)
if(prefix STREQUAL str_prefix)
set("${result}" ON PARENT_SCOPE)
return()
endif()
endif()
set("${result}" OFF PARENT_SCOPE)
endfunction()
# Handle upgrading logic
if(CMKR_EXECUTABLE AND NOT CMKR_CACHED_EXECUTABLE STREQUAL CMKR_EXECUTABLE)
cmkr_startswith("${CMKR_EXECUTABLE}" "${CMAKE_CURRENT_BINARY_DIR}/_cmkr" CMKR_STARTSWITH_BUILD)
cmkr_startswith("${CMKR_EXECUTABLE}" "${CMKR_DIRECTORY_PREFIX}" CMKR_STARTSWITH_CACHE)
if(CMKR_STARTSWITH_BUILD)
if(DEFINED ENV{CMKR_CACHE})
message(AUTHOR_WARNING "[cmkr] Switching to cached cmkr: '${CMKR_CACHED_EXECUTABLE}'")
if(EXISTS "${CMKR_CACHED_EXECUTABLE}")
set(CMKR_EXECUTABLE "${CMKR_CACHED_EXECUTABLE}" CACHE FILEPATH "Full path to cmkr executable" FORCE)
else()
unset(CMKR_EXECUTABLE CACHE)
endif()
else()
message(AUTHOR_WARNING "[cmkr] Upgrading '${CMKR_EXECUTABLE}' to '${CMKR_CACHED_EXECUTABLE}'")
unset(CMKR_EXECUTABLE CACHE)
endif()
elseif(DEFINED ENV{CMKR_CACHE} AND CMKR_STARTSWITH_CACHE)
message(AUTHOR_WARNING "[cmkr] Upgrading cached '${CMKR_EXECUTABLE}' to '${CMKR_CACHED_EXECUTABLE}'")
unset(CMKR_EXECUTABLE CACHE)
endif()
endif()
if(CMKR_EXECUTABLE AND EXISTS "${CMKR_EXECUTABLE}")
message(VERBOSE "[cmkr] Found cmkr: '${CMKR_EXECUTABLE}'")
elseif(CMKR_EXECUTABLE AND NOT CMKR_EXECUTABLE STREQUAL CMKR_CACHED_EXECUTABLE)
message(FATAL_ERROR "[cmkr] '${CMKR_EXECUTABLE}' not found")
elseif(NOT CMKR_EXECUTABLE AND EXISTS "${CMKR_CACHED_EXECUTABLE}")
set(CMKR_EXECUTABLE "${CMKR_CACHED_EXECUTABLE}" CACHE FILEPATH "Full path to cmkr executable" FORCE)
message(STATUS "[cmkr] Found cached cmkr: '${CMKR_EXECUTABLE}'")
else()
set(CMKR_EXECUTABLE "${CMKR_CACHED_EXECUTABLE}" CACHE FILEPATH "Full path to cmkr executable" FORCE)
message(VERBOSE "[cmkr] Bootstrapping '${CMKR_EXECUTABLE}'")
message(STATUS "[cmkr] Fetching cmkr...")
if(EXISTS "${CMKR_DIRECTORY}")
cmkr_exec("${CMAKE_COMMAND}" -E rm -rf "${CMKR_DIRECTORY}")
endif()
find_package(Git QUIET REQUIRED)
cmkr_exec("${GIT_EXECUTABLE}"
clone
--config advice.detachedHead=false
--branch ${CMKR_TAG}
--depth 1
${CMKR_REPO}
"${CMKR_DIRECTORY}"
)
if(CMKR_COMMIT_HASH)
execute_process(
COMMAND "${GIT_EXECUTABLE}" checkout -q "${CMKR_COMMIT_HASH}"
RESULT_VARIABLE CMKR_EXEC_RESULT
WORKING_DIRECTORY "${CMKR_DIRECTORY}"
)
if(NOT CMKR_EXEC_RESULT EQUAL 0)
message(FATAL_ERROR "Tag '${CMKR_TAG}' hash is not '${CMKR_COMMIT_HASH}'")
endif()
endif()
message(STATUS "[cmkr] Building cmkr (using system compiler)...")
cmkr_exec("${CMAKE_COMMAND}"
--no-warn-unused-cli
"${CMKR_DIRECTORY}"
"-B${CMKR_DIRECTORY}/build"
"-DCMAKE_BUILD_TYPE=${CMKR_BUILD_TYPE}"
"-DCMAKE_UNITY_BUILD=ON"
"-DCMAKE_INSTALL_PREFIX=${CMKR_DIRECTORY}"
"-DCMKR_GENERATE_DOCUMENTATION=OFF"
)
cmkr_exec("${CMAKE_COMMAND}"
--build "${CMKR_DIRECTORY}/build"
--config "${CMKR_BUILD_TYPE}"
--parallel
)
cmkr_exec("${CMAKE_COMMAND}"
--install "${CMKR_DIRECTORY}/build"
--config "${CMKR_BUILD_TYPE}"
--prefix "${CMKR_DIRECTORY}"
--component cmkr
)
if(NOT EXISTS ${CMKR_EXECUTABLE})
message(FATAL_ERROR "[cmkr] Failed to bootstrap '${CMKR_EXECUTABLE}'")
endif()
cmkr_exec("${CMKR_EXECUTABLE}" version)
message(STATUS "[cmkr] Bootstrapped ${CMKR_EXECUTABLE}")
endif()
execute_process(COMMAND "${CMKR_EXECUTABLE}" version
RESULT_VARIABLE CMKR_EXEC_RESULT
)
if(NOT CMKR_EXEC_RESULT EQUAL 0)
message(FATAL_ERROR "[cmkr] Failed to get version, try clearing the cache and rebuilding")
endif()
# Use cmkr.cmake as a script
if(CMAKE_SCRIPT_MODE_FILE)
if(NOT EXISTS "${CMAKE_SOURCE_DIR}/cmake.toml")
execute_process(COMMAND "${CMKR_EXECUTABLE}" init
RESULT_VARIABLE CMKR_EXEC_RESULT
)
if(NOT CMKR_EXEC_RESULT EQUAL 0)
message(FATAL_ERROR "[cmkr] Failed to bootstrap cmkr project. Please report an issue: https://github.com/build-cpp/cmkr/issues/new")
else()
message(STATUS "[cmkr] Modify cmake.toml and then configure using: cmake -B build")
endif()
else()
execute_process(COMMAND "${CMKR_EXECUTABLE}" gen
RESULT_VARIABLE CMKR_EXEC_RESULT
)
if(NOT CMKR_EXEC_RESULT EQUAL 0)
message(FATAL_ERROR "[cmkr] Failed to generate project.")
else()
message(STATUS "[cmkr] Configure using: cmake -B build")
endif()
endif()
endif()
# This is the macro that contains black magic
macro(cmkr)
# When this macro is called from the generated file, fake some internal CMake variables
get_source_file_property(CMKR_CURRENT_LIST_FILE "${CMAKE_CURRENT_LIST_FILE}" CMKR_CURRENT_LIST_FILE)
if(CMKR_CURRENT_LIST_FILE)
set(CMAKE_CURRENT_LIST_FILE "${CMKR_CURRENT_LIST_FILE}")
get_filename_component(CMAKE_CURRENT_LIST_DIR "${CMAKE_CURRENT_LIST_FILE}" DIRECTORY)
endif()
# File-based include guard (include_guard is not documented to work)
get_source_file_property(CMKR_INCLUDE_GUARD "${CMAKE_CURRENT_LIST_FILE}" CMKR_INCLUDE_GUARD)
if(NOT CMKR_INCLUDE_GUARD)
set_source_files_properties("${CMAKE_CURRENT_LIST_FILE}" PROPERTIES CMKR_INCLUDE_GUARD TRUE)
file(SHA256 "${CMAKE_CURRENT_LIST_FILE}" CMKR_LIST_FILE_SHA256_PRE)
# Generate CMakeLists.txt
cmkr_exec("${CMKR_EXECUTABLE}" gen
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
)
file(SHA256 "${CMAKE_CURRENT_LIST_FILE}" CMKR_LIST_FILE_SHA256_POST)
# Delete the temporary file if it was left for some reason
set(CMKR_TEMP_FILE "${CMAKE_CURRENT_SOURCE_DIR}/CMakerLists.txt")
if(EXISTS "${CMKR_TEMP_FILE}")
file(REMOVE "${CMKR_TEMP_FILE}")
endif()
if(NOT CMKR_LIST_FILE_SHA256_PRE STREQUAL CMKR_LIST_FILE_SHA256_POST)
# Copy the now-generated CMakeLists.txt to CMakerLists.txt
# This is done because you cannot include() a file you are currently in
configure_file(CMakeLists.txt "${CMKR_TEMP_FILE}" COPYONLY)
# Add the macro required for the hack at the start of the cmkr macro
set_source_files_properties("${CMKR_TEMP_FILE}" PROPERTIES
CMKR_CURRENT_LIST_FILE "${CMAKE_CURRENT_LIST_FILE}"
)
# 'Execute' the newly-generated CMakeLists.txt
include("${CMKR_TEMP_FILE}")
# Delete the generated file
file(REMOVE "${CMKR_TEMP_FILE}")
# Do not execute the rest of the original CMakeLists.txt
return()
endif()
# Resume executing the unmodified CMakeLists.txt
endif()
endmacro()

334
src/cross/gui/Bridge.cpp Normal file
View File

@ -0,0 +1,334 @@
#include <cstdio>
#include <QGuiApplication>
#include <QClipboard>
#include "Bridge.h"
#include "Types.h"
#include "Bridge.h"
#include <zydis_wrapper.h>
struct InvalidMemoryProvider : MemoryProvider
{
bool read(duint addr, void* dest, duint size) override
{
return false;
}
bool getRange(duint addr, duint & base, duint & size) override
{
return false;
}
bool isCodePtr(duint addr) override
{
return false;
}
bool isValidPtr(duint addr) override
{
return false;
}
} gInvalidMemoryProvider;
static MemoryProvider* gMemory = &gInvalidMemoryProvider;
void DbgSetMemoryProvider(MemoryProvider* provider)
{
gMemory = provider ? provider : &gInvalidMemoryProvider;
}
// BRIDGE
bool BridgeSettingGet(const char* section, const char* key, char* value)
{
return false;
}
bool BridgeSettingSet(const char* section, const char* key, const char* value)
{
return false;
}
bool BridgeSettingGetUint(const char* section, const char* key, duint* value)
{
return false;
}
bool BridgeSettingSetUint(const char* section, const char* key, duint value)
{
return false;
}
const wchar_t* BridgeUserDirectory()
{
return L".";
}
void* BridgeAlloc(size_t size)
{
return malloc(size);
}
void BridgeFree(void* ptr)
{
free(ptr);
}
// DBG
bool DbgIsDebugging()
{
return true;
}
DBGFUNCTIONS* DbgFunctions()
{
static DBGFUNCTIONS* cache = []
{
static DBGFUNCTIONS f;
f.GetTraceRecordHitCount = [](duint addr) -> duint
{
return 0;
};
f.ModBaseFromAddr = [](duint addr) -> duint
{
return 0;
};
f.ModNameFromAddr = [](duint addr, char* name, bool extension)
{
return false;
};
f.StringFormatInline = [](char* dest, duint size, const char* format)
{
return false;
};
f.MemIsCodePage = [](duint addr, bool refresh)
{
return gMemory->isCodePtr(addr);
};
f.GetMnemonicBrief = [](const char* mnem, size_t resultSize, char* result)
{
*result = '\0';
};
f.ModRelocationAtAddr = [](duint addr, DBGRELOCATIONINFO * relocation)
{
return false;
};
f.PatchGetEx = [](duint addr, DBGPATCHINFO * info)
{
return false;
};
f.ValFromString = [](const char* expr, duint * value)
{
bool success = false;
*value = DbgEval(expr, &success);
return success;
};
f.ModGetParty = [](duint addr)
{
return 0;
};
f.PatchInRange = [](duint start, duint end)
{
return false;
};
f.MemPatch = [](duint start, const unsigned char* data, duint size)
{
return false;
};
return &f;
}();
return cache;
}
bool DbgGetLabelAt(duint addr, SEGTYPE seg, char* label)
{
return false;
}
bool DbgGetModuleAt(duint addr, char* module)
{
return false;
}
bool DbgGetCommentAt(duint addr, char* comment)
{
return false;
}
bool DbgGetBookmarkAt(duint addr)
{
return false;
}
BPXTYPE DbgGetBpxTypeAt(duint addr)
{
return bp_none;
}
bool DbgMemIsValidReadPtr(duint addr)
{
return gMemory->isValidPtr(addr);
}
bool DbgGetStringAt(duint addr, char* str)
{
return false;
}
bool DbgEval(const char* expr, bool* success)
{
return false;
}
duint DbgValFromString(const char* expr)
{
duint result = 0;
if(!DbgEval(expr))
result = 0;
return result;
}
bool DbgCmdExec(const char* cmd)
{
printf("DbgCmdExec(\"%s\")\n", cmd);
return false;
}
bool DbgCmdExecDirect(const char* cmd)
{
printf("DbgCmdExecDirect(\"%s\")\n", cmd);
return false;
}
bool DbgCmdExec(const QString & cmd)
{
return DbgCmdExec(cmd.toUtf8().constData());
}
bool DbgCmdExecDirect(const QString & cmd)
{
return DbgCmdExecDirect(cmd.toUtf8().constData());
}
duint DbgMemFindBaseAddr(duint addr, duint* size)
{
duint rangeBase = 0;
duint rangeSize = 0;
if(!gMemory->getRange(addr, rangeBase, rangeSize))
return 0;
if(size != nullptr)
*size = rangeSize;
return rangeBase;
}
bool DbgMemRead(duint addr, void* dest, size_t size)
{
return gMemory->read(addr, dest, size);
}
FUNCTYPE DbgGetFunctionTypeAt(duint addr)
{
return FUNC_NONE;
}
XREFTYPE DbgGetXrefTypeAt(duint addr)
{
return XREF_NONE;
}
ARGTYPE DbgGetArgTypeAt(duint addr)
{
return ARG_NONE;
}
LOOPTYPE DbgGetLoopTypeAt(duint addr, int depth)
{
return LOOP_NONE;
}
duint DbgGetBranchDestination(duint addr)
{
uint8_t data[MAX_DISASM_BUFFER];
if(!DbgMemRead(addr, data, sizeof(data)))
return 0;
Zydis zydis(true); // TODO: architecture
if(!zydis.Disassemble(addr, data))
return 0;
return zydis.BranchDestination();
}
bool DbgIsJumpGoingToExecute(duint addr)
{
return false; // TODO
}
bool DbgXrefGet(duint addr, XREF_INFO* info)
{
return false;
}
void DbgReleaseEncodeTypeBuffer(void* buffer)
{
BridgeFree(buffer);
}
void* DbgGetEncodeTypeBuffer(duint addr, duint* size)
{
return nullptr;
}
bool DbgSetEncodeType(duint addr, duint size, ENCODETYPE type)
{
return false;
}
void DbgDelEncodeTypeRange(duint start, duint end)
{
}
void DbgDelEncodeTypeSegment(duint start)
{
}
// GUI
void GuiExecuteOnGuiThreadEx(GuiCallback callback, void* data)
{
// TODO: force schedule on the GUI thread
callback(data);
}
void GuiAddLogMessage(const char* msg)
{
Bridge::getBridge()->addMsgToLog(msg);
}
void GuiUpdateAllViews()
{
Bridge::getBridge()->repaintTableView();
}
void GuiUpdatePatches()
{
}
Bridge* Bridge::getBridge()
{
static Bridge i;
return &i;
}
void Bridge::CopyToClipboard(const QString & str)
{
QGuiApplication::clipboard()->setText(str);
}
void Bridge::addMsgToLog(const QByteArray & bytes)
{
printf("addMsgToLog: %s\n", bytes.data());
}

172
src/cross/gui/Bridge.h Normal file
View File

@ -0,0 +1,172 @@
#pragma once
#include <QObject>
#include <QString>
#include <QDebug>
#include "Types.h"
#define MAX_SETTING_SIZE 4096
bool BridgeSettingGet(const char* section, const char* key, char* value);
bool BridgeSettingSet(const char* section, const char* key, const char* value);
bool BridgeSettingGetUint(const char* section, const char* key, duint* value);
bool BridgeSettingSetUint(const char* section, const char* key, duint value);
const wchar_t* BridgeUserDirectory();
void* BridgeAlloc(size_t size);
void BridgeFree(void* ptr);
#define MAX_LABEL_SIZE 256
#define MAX_MODULE_SIZE 256
#define MAX_COMMENT_SIZE 256
#define MAX_STRING_SIZE 2048
enum SEGTYPE
{
SEG_DEFAULT,
SEG_ES,
SEG_DS,
SEG_FS,
SEG_GS,
SEG_CS,
SEG_SS,
};
enum BPXTYPE
{
bp_none,
bp_normal,
bp_hardware,
bp_memory,
};
typedef enum
{
FUNC_NONE,
FUNC_BEGIN,
FUNC_MIDDLE,
FUNC_END,
FUNC_SINGLE
} FUNCTYPE;
typedef enum
{
LOOP_NONE,
LOOP_BEGIN,
LOOP_MIDDLE,
LOOP_ENTRY,
LOOP_END,
LOOP_SINGLE
} LOOPTYPE;
typedef enum
{
ARG_NONE,
ARG_BEGIN,
ARG_MIDDLE,
ARG_END,
ARG_SINGLE
} ARGTYPE;
typedef struct
{
uint32_t rva;
uint8_t type;
uint16_t size;
} DBGRELOCATIONINFO;
typedef struct
{
char mod[MAX_MODULE_SIZE];
duint addr;
unsigned char oldbyte;
unsigned char newbyte;
} DBGPATCHINFO;
struct DBGFUNCTIONS
{
duint(*GetTraceRecordHitCount)(duint addr);
duint(*ModBaseFromAddr)(duint addr);
bool (*ModNameFromAddr)(duint base, char* name, bool extension);
bool (*StringFormatInline)(char* dest, duint size, const char* format);
bool (*MemIsCodePage)(duint addr, bool refresh);
void (*GetMnemonicBrief)(const char* mnem, size_t resultSize, char* result);
bool (*ModRelocationAtAddr)(duint addr, DBGRELOCATIONINFO* relocation);
bool (*PatchGetEx)(duint addr, DBGPATCHINFO* info);
bool (*ValFromString)(const char* expr, duint* value);
int (*ModGetParty)(duint addr);
bool (*PatchInRange)(duint start, duint end);
bool (*MemPatch)(duint start, const unsigned char* data, duint size);
};
struct MemoryProvider
{
virtual ~MemoryProvider() = default;
virtual bool read(duint addr, void* dest, duint size) = 0;
virtual bool getRange(duint addr, duint & base, duint & size) = 0;
virtual bool isCodePtr(duint addr) = 0;
virtual bool isValidPtr(duint addr) = 0;
};
void DbgSetMemoryProvider(MemoryProvider* provider);
bool DbgIsDebugging();
DBGFUNCTIONS* DbgFunctions();
bool DbgGetLabelAt(duint addr, SEGTYPE seg, char* label);
bool DbgGetModuleAt(duint addr, char* module);
bool DbgGetCommentAt(duint addr, char* comment);
bool DbgGetBookmarkAt(duint addr);
BPXTYPE DbgGetBpxTypeAt(duint addr);
bool DbgMemIsValidReadPtr(duint addr);
bool DbgGetStringAt(duint addr, char* str);
bool DbgEval(const char* expr, bool* success = nullptr);
duint DbgValFromString(const char* expr);
bool DbgCmdExec(const char* cmd);
bool DbgCmdExecDirect(const char* cmd);
duint DbgMemFindBaseAddr(duint addr, duint* size);
bool DbgMemRead(duint addr, void* dest, size_t size);
FUNCTYPE DbgGetFunctionTypeAt(duint addr);
XREFTYPE DbgGetXrefTypeAt(duint addr);
ARGTYPE DbgGetArgTypeAt(duint addr);
LOOPTYPE DbgGetLoopTypeAt(duint addr, int depth);
duint DbgGetBranchDestination(duint addr);
bool DbgIsJumpGoingToExecute(duint addr);
bool DbgXrefGet(duint addr, XREF_INFO* info);
void DbgReleaseEncodeTypeBuffer(void* buffer);
void* DbgGetEncodeTypeBuffer(duint addr, duint* size);
bool DbgSetEncodeType(duint addr, duint size, ENCODETYPE type);
void DbgDelEncodeTypeRange(duint start, duint end);
void DbgDelEncodeTypeSegment(duint start);
using GuiCallback = void(*)(void*);
void GuiExecuteOnGuiThreadEx(GuiCallback callback, void* data);
void GuiAddLogMessage(const char* msg);
void GuiUpdateAllViews();
void GuiUpdatePatches();
// QString helpers
bool DbgCmdExec(const QString & cmd);
bool DbgCmdExecDirect(const QString & cmd);
class Bridge : public QObject
{
Q_OBJECT
Bridge() = default;
signals:
void close();
void repaintTableView();
void updateDump();
void updateDisassembly();
void dbgStateChanged(DBGSTATE state);
public:
static Bridge* getBridge();
static void CopyToClipboard(const QString & str);
void addMsgToLog(const QByteArray & bytes);
duint mLastCip = 0;
bool mIsRunning = true;
};

100
src/cross/gui/CMakeLists.txt generated Normal file
View File

@ -0,0 +1,100 @@
set(widgets_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../gui/Src")
add_subdirectory(
${CMAKE_CURRENT_SOURCE_DIR}/../../zydis_wrapper
${CMAKE_CURRENT_BINARY_DIR}/zydis_wrapper
)
include(Qt.cmake)
set(hook_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/Bridge.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Bridge.h
${CMAKE_CURRENT_SOURCE_DIR}/Configuration.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Configuration.h
${CMAKE_CURRENT_SOURCE_DIR}/MagicMenu.h
${CMAKE_CURRENT_SOURCE_DIR}/MiscUtil.cpp
${CMAKE_CURRENT_SOURCE_DIR}/MiscUtil.h
${CMAKE_CURRENT_SOURCE_DIR}/StringUtil.cpp
${CMAKE_CURRENT_SOURCE_DIR}/StringUtil.h
${CMAKE_CURRENT_SOURCE_DIR}/Types.h
${CMAKE_CURRENT_SOURCE_DIR}/Imports.h
)
set(widgets_SOURCES
${widgets_SOURCE_DIR}/BasicView/AbstractStdTable.cpp
${widgets_SOURCE_DIR}/BasicView/AbstractStdTable.h
${widgets_SOURCE_DIR}/BasicView/AbstractTableView.cpp
${widgets_SOURCE_DIR}/BasicView/AbstractTableView.h
${widgets_SOURCE_DIR}/BasicView/Disassembly.cpp
${widgets_SOURCE_DIR}/BasicView/Disassembly.h
${widgets_SOURCE_DIR}/BasicView/HexDump.cpp
${widgets_SOURCE_DIR}/BasicView/HexDump.h
${widgets_SOURCE_DIR}/BasicView/HistoryLineEdit.cpp
${widgets_SOURCE_DIR}/BasicView/HistoryLineEdit.h
${widgets_SOURCE_DIR}/BasicView/StdTable.cpp
${widgets_SOURCE_DIR}/BasicView/StdTable.h
${widgets_SOURCE_DIR}/Disassembler/Architecture.cpp
${widgets_SOURCE_DIR}/Disassembler/Architecture.h
${widgets_SOURCE_DIR}/Disassembler/QZydis.cpp
${widgets_SOURCE_DIR}/Disassembler/QZydis.h
${widgets_SOURCE_DIR}/Disassembler/ZydisTokenizer.cpp
${widgets_SOURCE_DIR}/Disassembler/ZydisTokenizer.h
${widgets_SOURCE_DIR}/Gui/BrowseDialog.cpp
${widgets_SOURCE_DIR}/Gui/BrowseDialog.h
${widgets_SOURCE_DIR}/Gui/BrowseDialog.ui
${widgets_SOURCE_DIR}/Gui/ColumnReorderDialog.cpp
${widgets_SOURCE_DIR}/Gui/ColumnReorderDialog.h
${widgets_SOURCE_DIR}/Gui/ColumnReorderDialog.ui
${widgets_SOURCE_DIR}/Gui/ComboBoxDialog.cpp
${widgets_SOURCE_DIR}/Gui/ComboBoxDialog.h
${widgets_SOURCE_DIR}/Gui/ComboBoxDialog.ui
${widgets_SOURCE_DIR}/Gui/DisassemblyPopup.cpp
${widgets_SOURCE_DIR}/Gui/DisassemblyPopup.h
${widgets_SOURCE_DIR}/Gui/LineEditDialog.cpp
${widgets_SOURCE_DIR}/Gui/LineEditDialog.h
${widgets_SOURCE_DIR}/Gui/LineEditDialog.ui
${widgets_SOURCE_DIR}/Memory/MemoryPage.cpp
${widgets_SOURCE_DIR}/Memory/MemoryPage.h
${widgets_SOURCE_DIR}/Utils/ActionHelpers.h
${widgets_SOURCE_DIR}/Utils/CachedFontMetrics.h
${widgets_SOURCE_DIR}/Utils/CodeFolding.cpp
${widgets_SOURCE_DIR}/Utils/CodeFolding.h
${widgets_SOURCE_DIR}/Utils/EncodeMap.cpp
${widgets_SOURCE_DIR}/Utils/EncodeMap.h
${widgets_SOURCE_DIR}/Utils/MenuBuilder.cpp
${widgets_SOURCE_DIR}/Utils/MenuBuilder.h
${widgets_SOURCE_DIR}/Utils/MethodInvoker.h
${widgets_SOURCE_DIR}/Utils/RichTextPainter.cpp
${widgets_SOURCE_DIR}/Utils/RichTextPainter.h
${widgets_SOURCE_DIR}/Utils/VaHistory.h
)
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR})
add_library(widgets STATIC
${hook_SOURCES}
${widgets_SOURCES}
)
target_include_directories(widgets PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
${widgets_SOURCE_DIR}
)
source_group(TREE ${widgets_SOURCE_DIR} FILES ${widgets_SOURCES})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX hook FILES ${hook_SOURCES})
target_compile_definitions(widgets PRIVATE
QT_NO_DEPRECATED_WARNINGS
)
target_link_libraries(widgets PUBLIC
${QT_LIBRARIES}
zydis_wrapper
)
# https://doc.qt.io/qt-6/wasm.html#asyncify
if(EMSCRIPTEN)
#target_link_options(${CMKR_TARGET} PUBLIC -sASYNCIFY -Os)
endif()

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,132 @@
#pragma once
#include <QObject>
#include <QKeySequence>
#include <QMap>
#include <QColor>
#include <QFont>
#include "Types.h"
// TODO: declare AppearanceDialog and SettingsDialog entries here, so that you only have to do it in once place
#define Config() (Configuration::instance())
#define ConfigColor(x) (Config()->getColor(x))
#define ConfigBool(x,y) (Config()->getBool(x,y))
#define ConfigUint(x,y) (Config()->getUint(x,y))
#define ConfigFont(x) (Config()->getFont(x))
#define ConfigShortcut(x) (Config()->getShortcut(x).Hotkey)
#define ConfigHScrollBarStyle() "QScrollBar:horizontal{border:1px solid grey;background:#f1f1f1;height:10px}QScrollBar::handle:horizontal{background:#aaaaaa;min-width:20px;margin:1px}QScrollBar::add-line:horizontal,QScrollBar::sub-line:horizontal{width:0;height:0}"
#define ConfigVScrollBarStyle() "QScrollBar:vertical{border:1px solid grey;background:#f1f1f1;width:10px}QScrollBar::handle:vertical{background:#aaaaaa;min-height:20px;margin:1px}QScrollBar::add-line:vertical,QScrollBar::sub-line:vertical{width:0;height:0}"
class MenuBuilder;
class QAction;
class QWheelEvent;
class Configuration : public QObject
{
Q_OBJECT
public:
//Structures
struct Shortcut
{
QString Name;
QKeySequence Hotkey;
bool GlobalShortcut;
Shortcut(QString name = QString(), QString hotkey = QString(), bool global = false)
: Name(name), Hotkey(hotkey, QKeySequence::PortableText), GlobalShortcut(global) { }
Shortcut(std::initializer_list<QString> names, QString hotkey = QString(), bool global = false)
: Shortcut(QStringList(names).join(" -> "), hotkey, global) { }
};
//Functions
Configuration();
static Configuration* instance();
void load();
void save();
void readColors();
void writeColors();
void readBools();
void writeBools();
void readUints();
void writeUints();
void readFonts();
void writeFonts();
void readShortcuts();
void writeShortcuts();
void registerMenuBuilder(MenuBuilder* menu, size_t count);
void registerMainMenuStringList(QList<QAction*>* menu);
const QColor getColor(const QString & id) const;
const bool getBool(const QString & category, const QString & id) const;
void setBool(const QString & category, const QString & id, const bool b);
const duint getUint(const QString & category, const QString & id) const;
void setUint(const QString & category, const QString & id, const duint i);
const QFont getFont(const QString & id) const;
const Shortcut getShortcut(const QString & key_id) const;
void setShortcut(const QString & key_id, const QKeySequence key_sequence);
void setPluginShortcut(const QString & key_id, QString description, QString defaultShortcut, bool global);
void loadWindowGeometry(QWidget* window);
void saveWindowGeometry(QWidget* window);
void zoomFont(const QString & fontName, QWheelEvent* event);
//default setting maps
QMap<QString, QColor> defaultColors;
QMap<QString, QMap<QString, bool>> defaultBools;
QMap<QString, QMap<QString, duint>> defaultUints;
QMap<QString, QFont> defaultFonts;
QMap<QString, Shortcut> defaultShortcuts;
//public variables
QMap<QString, QColor> Colors;
QMap<QString, QMap<QString, bool>> Bools;
QMap<QString, QMap<QString, duint>> Uints;
QMap<QString, QFont> Fonts;
QMap<QString, Shortcut> Shortcuts;
//custom menu maps
struct MenuMap
{
union
{
QList<QAction*>* mainMenuList;
MenuBuilder* builder;
};
int type;
size_t count;
MenuMap() { }
MenuMap(QList<QAction*>* mainMenuList, size_t count)
: mainMenuList(mainMenuList), type(1), count(count) { }
MenuMap(MenuBuilder* builder, size_t count)
: builder(builder), type(0), count(count) { }
};
QList<MenuMap> NamedMenuBuilders;
static Configuration* mPtr;
signals:
void colorsUpdated();
void fontsUpdated();
void guiOptionsUpdated();
void shortcutsUpdated();
void tokenizerConfigUpdated();
void disableAutoCompleteUpdated();
private:
QColor colorFromConfig(const QString & id);
bool colorToConfig(const QString & id, const QColor color);
bool boolFromConfig(const QString & category, const QString & id);
bool boolToConfig(const QString & category, const QString & id, bool bBool);
duint uintFromConfig(const QString & category, const QString & id);
bool uintToConfig(const QString & category, const QString & id, duint i);
QFont fontFromConfig(const QString & id);
bool fontToConfig(const QString & id, const QFont font);
QString shortcutFromConfig(const QString & id);
bool shortcutToConfig(const QString & id, const QKeySequence shortcut);
mutable bool noMoreMsgbox;
QMap<QString, int> mZoomFontDelta;
};

3
src/cross/gui/Imports.h Normal file
View File

@ -0,0 +1,3 @@
#pragma once
#include "Types.h"

120
src/cross/gui/MagicMenu.h Normal file
View File

@ -0,0 +1,120 @@
#pragma once
#include <type_traits>
#include "Utils/MenuBuilder.h"
#include <QCoreApplication>
#include <QDebug>
// TODO: support QT_TR_NOOP in linguist
#define TR(str) TranslatedText(str)
template<class Base>
class MagicMenu
{
MenuBuilder* mMenuBuilder = nullptr;
Base* base()
{
return static_cast<Base*>(this);
}
public:
struct TranslatedText
{
const char* text = nullptr;
explicit TranslatedText(const char* text)
: text(text)
{
}
TranslatedText(const TranslatedText &) = delete;
TranslatedText(TranslatedText &&) = delete;
};
// TODO: see if it's possible to support ActionDescription("Goto", "G") directly in linguist
struct TableAction
{
const char* name = nullptr;
const char* defaultShortcut = nullptr;
TableAction(const TranslatedText & name, const char* defaultShortcut = nullptr)
: name(name.text), defaultShortcut(defaultShortcut)
{
}
TableAction(const TableAction &) = delete;
TableAction(TableAction &&) = delete;
QAction* buildAction(QWidget* widget) const
{
auto className = widget->metaObject()->className();
qDebug() << "Register shortcut action:" << className << ":" << name;
auto qAction = new QAction(QCoreApplication::translate(className, name));
// TODO: set shortcut based on configuration
qAction->setShortcut(QKeySequence(defaultShortcut));
qAction->setShortcutContext(Qt::WidgetShortcut);
// TODO: allow shortcut to update dynamically
widget->addAction(qAction);
return qAction;
}
};
MagicMenu()
{
mMenuBuilder = new MenuBuilder(base());
base()->setContextMenuPolicy(Qt::CustomContextMenu);
QObject::connect(base(), &QWidget::customContextMenuRequested, [this](const QPoint & pos)
{
if(pos.y() < base()->getHeaderHeight())
return;
auto wMenu = new QMenu(base());
mMenuBuilder->build(wMenu);
if(wMenu->actions().length())
{
wMenu->popup(base()->mapToGlobal(pos));
}
});
}
MenuBuilder* menuBuilder()
{
return mMenuBuilder;
}
// TODO: support conditional actions
template<typename SlotFn>
void addMenuAction(const TableAction & action, SlotFn && slot)
{
auto qAction = action.buildAction(base());
QObject::connect(qAction, &QAction::triggered, base(), slot);
mMenuBuilder->addAction(qAction);
}
template<typename SlotFn>
void addMenuAction(const TableAction & action, SlotFn && slot, const std::function<bool()> & condition)
{
auto qAction = action.buildAction(base());
QObject::connect(qAction, &QAction::triggered, base(), slot);
mMenuBuilder->addAction(qAction, [condition](QMenu*)
{
return condition();
});
}
/*void addMenuAction(const TableAction& action, const char* slot)
{
auto qAction = action.buildAction(base());
QObject::connect(qAction, SIGNAL(triggered(bool)), base(), SLOT(slot));
mMenuBuilder->addAction(qAction);
}*/
void addMenuBuilder(const TranslatedText & title, MenuBuilder::BuildCallback && callback)
{
auto trTitle = QCoreApplication::translate(base()->metaObject()->className(), title.text);
auto qMenu = new QMenu(trTitle, base());
mMenuBuilder->addMenu(qMenu, std::move(callback));
}
};

404
src/cross/gui/MiscUtil.cpp Normal file
View File

@ -0,0 +1,404 @@
#include "MiscUtil.h"
//#include <QtWin>
#include <QApplication>
#include <QMessageBox>
#include <QDir>
#include <Gui/LineEditDialog.h>
#include <Gui/ComboBoxDialog.h>
#include "StringUtil.h"
#include <Gui/BrowseDialog.h>
#include "Bridge.h"
#include <thread>
#if 0
void SetApplicationIcon(WId winId)
{
std::thread([winId]
{
HICON hIcon = LoadIcon(GetModuleHandleW(0), MAKEINTRESOURCE(100));
SendMessageW((HWND)winId, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
DestroyIcon(hIcon);
}).detach();
}
#endif // 0
QByteArray & ByteReverse(QByteArray & array)
{
int length = array.length();
for(int i = 0; i < length / 2; i++)
{
char temp = array[i];
array[i] = array[length - i - 1];
array[length - i - 1] = temp;
}
return array;
}
QByteArray ByteReverse(QByteArray && array)
{
int length = array.length();
for(int i = 0; i < length / 2; i++)
{
char temp = array[i];
array[i] = array[length - i - 1];
array[length - i - 1] = temp;
}
return array;
}
bool SimpleInputBox(QWidget* parent, const QString & title, QString defaultValue, QString & output, const QString & placeholderText, const QIcon* icon)
{
LineEditDialog mEdit(parent);
mEdit.setWindowIcon(icon ? *icon : parent->windowIcon());
mEdit.setText(defaultValue);
mEdit.setPlaceholderText(placeholderText);
mEdit.setWindowTitle(title);
mEdit.setCheckBox(false);
// TODO: WebAssembly support
if(mEdit.exec() == QDialog::Accepted)
{
output = mEdit.editText;
return true;
}
else
return false;
}
bool SimpleChoiceBox(QWidget* parent, const QString & title, QString defaultValue, const QStringList & choices, QString & output, bool editable, const QString & placeholderText, const QIcon* icon, int minimumContentsLength)
{
ComboBoxDialog mChoice(parent);
mChoice.setWindowIcon(icon ? *icon : parent->windowIcon());
mChoice.setEditable(editable);
mChoice.setItems(choices);
mChoice.setText(defaultValue);
mChoice.setPlaceholderText(placeholderText);
mChoice.setWindowTitle(title);
mChoice.setCheckBox(false);
if(minimumContentsLength >= 0)
mChoice.setMinimumContentsLength(minimumContentsLength);
// TODO: WebAssembly support
if(mChoice.exec() == QDialog::Accepted)
{
output = mChoice.currentText();
return true;
}
else
return false;
}
void SimpleErrorBox(QWidget* parent, const QString & title, const QString & text)
{
QMessageBox msg(QMessageBox::Critical, title, text, QMessageBox::NoButton, parent);
msg.setWindowIcon(DIcon("fatal-error"));
msg.setParent(parent, Qt::Dialog);
msg.setWindowFlags(msg.windowFlags() & (~Qt::WindowContextHelpButtonHint));
// TODO: WebAssembly support
msg.exec();
}
void SimpleWarningBox(QWidget* parent, const QString & title, const QString & text)
{
QMessageBox msg(QMessageBox::Warning, title, text, QMessageBox::NoButton, parent);
msg.setWindowIcon(DIcon("exclamation"));
msg.setParent(parent, Qt::Dialog);
msg.setWindowFlags(msg.windowFlags() & (~Qt::WindowContextHelpButtonHint));
// TODO: WebAssembly support
msg.exec();
}
void SimpleInfoBox(QWidget* parent, const QString & title, const QString & text)
{
QMessageBox msg(QMessageBox::Information, title, text, QMessageBox::NoButton, parent);
msg.setWindowIcon(DIcon("information"));
msg.setParent(parent, Qt::Dialog);
msg.setWindowFlags(msg.windowFlags() & (~Qt::WindowContextHelpButtonHint));
msg.exec();
}
QString getSymbolicName(duint addr)
{
char labelText[MAX_LABEL_SIZE] = "";
char moduleText[MAX_MODULE_SIZE] = "";
bool bHasLabel = DbgGetLabelAt(addr, SEG_DEFAULT, labelText);
bool bHasModule = (DbgGetModuleAt(addr, moduleText) && !QString(labelText).startsWith("JMP.&"));
QString addrText = ToPtrString(addr);
if(bHasLabel && bHasModule) // <module.label>
return QString("%1 <%2.%3>").arg(addrText).arg(moduleText).arg(labelText);
else if(bHasModule) // module.addr
return QString("%1.%2").arg(moduleText).arg(addrText);
else if(bHasLabel) // <label>
return QString("<%1>").arg(labelText);
else
return addrText;
}
QString getSymbolicNameStr(duint addr)
{
char labelText[MAX_LABEL_SIZE] = "";
char moduleText[MAX_MODULE_SIZE] = "";
char string[MAX_STRING_SIZE] = "";
bool bHasString = DbgGetStringAt(addr, string);
bool bHasLabel = DbgGetLabelAt(addr, SEG_DEFAULT, labelText);
bool bHasModule = (DbgGetModuleAt(addr, moduleText) && !QString(labelText).startsWith("JMP.&"));
QString addrText = DbgMemIsValidReadPtr(addr) ? ToPtrString(addr) : ToHexString(addr);
QString finalText;
if(bHasString)
finalText = addrText + " " + QString(string);
else if(bHasLabel && bHasModule) //<module.label>
finalText = QString("<%1.%2>").arg(moduleText).arg(labelText);
else if(bHasModule) //module.addr
finalText = QString("%1.%2").arg(moduleText).arg(addrText);
else if(bHasLabel) //<label>
finalText = QString("<%1>").arg(labelText);
else
{
finalText = addrText;
if(addr == (addr & 0xFF))
{
QChar c = QChar((char)addr);
if(c.isPrint() || c.isSpace())
finalText += QString(" '%1'").arg(EscapeCh(c));
}
else if(addr == (addr & 0xFFF)) //UNICODE?
{
QChar c = QChar((ushort)addr);
if(c.isPrint() || c.isSpace())
finalText += QString(" L'%1'").arg(EscapeCh(c));
}
}
return finalText;
}
QIcon getFileIcon(QString file)
{
#if 0
SHFILEINFO info;
if(SHGetFileInfoW((const wchar_t*)file.utf16(), 0, &info, sizeof(info), SHGFI_ICON) == 0)
return QIcon(); //API error
QIcon result = QIcon(QtWin::fromHICON(info.hIcon));
DestroyIcon(info.hIcon);
return result;
#endif // 0
return QIcon();
}
//Export table in CSV. TODO: Display a dialog where the user choose what column to export and in which encoding
bool ExportCSV(dsint rows, dsint columns, std::vector<QString> headers, std::function<QString(dsint, dsint)> getCellContent)
{
BrowseDialog browse(
nullptr,
QApplication::translate("ExportCSV", "Export data in CSV format"),
QApplication::translate("ExportCSV", "Enter the CSV file name to export"),
QApplication::translate("ExportCSV", "CSV files (*.csv);;All files (*.*)"),
getDbPath("export.csv", true),
true
);
browse.setWindowIcon(DIcon("database-export"));
// TODO: WebAssembly support
if(browse.exec() == QDialog::Accepted)
{
FILE* csv;
bool utf16;
csv = fopen(browse.path.toUtf8().data(), "wb");
if(csv == NULL)
{
GuiAddLogMessage(QApplication::translate("ExportCSV", "CSV export error\n").toUtf8().constData());
return false;
}
else
{
duint setting;
if(BridgeSettingGetUint("Misc", "Utf16LogRedirect", &setting))
utf16 = !!setting;
else
utf16 = false;
if(utf16 && ftell(csv) == 0)
{
unsigned short BOM = 0xfeff;
fwrite(&BOM, 2, 1, csv);
}
dsint row, column;
QString text;
QString cell;
if(headers.size() > 0)
{
for(column = 0; column < columns; column++)
{
cell = headers.at(column);
if(cell.contains('"') || cell.contains(',') || cell.contains('\r') || cell.contains('\n'))
{
if(cell.contains('"'))
cell = cell.replace("\"", "\"\"");
cell = "\"" + cell + "\"";
}
if(column != columns - 1)
cell = cell + ",";
text = text + cell;
}
if(utf16)
{
text = text + "\r\n";
if(!fwrite(text.utf16(), text.length(), 2, csv))
{
fclose(csv);
GuiAddLogMessage(QApplication::translate("ExportCSV", "CSV export error\n").toUtf8().constData());
return false;
}
}
else
{
text = text + "\n";
QByteArray utf8;
utf8 = text.toUtf8();
if(!fwrite(utf8.constData(), utf8.size(), 1, csv))
{
fclose(csv);
GuiAddLogMessage(QApplication::translate("ExportCSV", "CSV export error\n").toUtf8().constData());
return false;
}
}
}
for(row = 0; row < rows; row++)
{
text.clear();
for(column = 0; column < columns; column++)
{
cell = getCellContent(row, column);
if(cell.contains('"') || cell.contains(',') || cell.contains('\r') || cell.contains('\n'))
{
if(cell.contains('"'))
cell = cell.replace("\"", "\"\"");
cell = "\"" + cell + "\"";
}
if(column != columns - 1)
cell = cell + ",";
text = text + cell;
}
if(utf16)
{
text = text + "\r\n";
if(!fwrite(text.utf16(), text.length(), 2, csv))
{
fclose(csv);
GuiAddLogMessage(QApplication::translate("ExportCSV", "CSV export error\n").toUtf8().constData());
return false;
}
}
else
{
text = text + "\n";
QByteArray utf8;
utf8 = text.toUtf8();
if(!fwrite(utf8.constData(), utf8.size(), 1, csv))
{
fclose(csv);
GuiAddLogMessage(QApplication::translate("ExportCSV", "CSV export error\n").toUtf8().constData());
return false;
}
}
}
fclose(csv);
GuiAddLogMessage(QApplication::translate("ExportCSV", "Saved CSV data at %1\n").arg(browse.path).toUtf8().constData());
return true;
}
}
else
return false;
}
static bool allowSeasons()
{
//srand(time());
duint setting = 0;
return !BridgeSettingGetUint("Gui", "NoSeasons", &setting) || !setting;
}
static bool isChristmas()
{
auto date = QDateTime::currentDateTime().date();
return date.month() == 12 && date.day() >= 23 && date.day() <= 26;
}
//https://www.daniweb.com/programming/software-development/threads/463261/c-easter-day-calculation
bool isEaster()
{
auto date = QDateTime::currentDateTime().date();
int K, M, S, A, D, R, OG, SZ, OE, X = date.year();
K = X / 100; // Secular number
M = 15 + (3 * K + 3) / 4 - (8 * K + 13) / 25; // Secular Moon shift
S = 2 - (3 * K + 3) / 4; // Secular sun shift
A = X % 19; // Moon parameter
D = (19 * A + M) % 30; // Seed for 1st full Moon in spring
R = D / 29 + (D / 28 - D / 29) * (A / 11); // Calendarian correction quantity
OG = 21 + D - R; // Easter limit
SZ = 7 - (X + X / 4 + S) % 7; // 1st sunday in March
OE = 7 - (OG - SZ) % 7; // Distance Easter sunday from Easter limit in days
int MM = ((OG + OE) > 31) ? 4 : 3;
int DD = (((OG + OE) % 31) == 0) ? 31 : ((OG + OE) % 31);
return date.month() == MM && date.day() >= DD - 2 && date.day() <= DD + 1;
}
bool isSeasonal()
{
return (isChristmas() || isEaster());
}
QIcon DIconHelper(QString name)
{
if(name.endsWith(".png"))
name = name.left(name.length() - 4);
static bool seasons = allowSeasons();
static bool christmas = isChristmas();
static bool easter = isEaster();
if(seasons)
{
if(christmas)
name = QString("christmas%1").arg(rand() % 8 + 1);
else if(easter)
name = QString("easter%1").arg(rand() % 8 + 1);
}
return QIcon::fromTheme(name);
}
QString getDbPath(const QString & filename, bool addDateTimeSuffix)
{
auto path = QString("%1/db").arg(QString::fromWCharArray(BridgeUserDirectory()));
if(!filename.isEmpty())
{
path += '/';
path += filename;
// Add a date suffix before the extension
if(addDateTimeSuffix)
{
auto extensionIdx = path.lastIndexOf('.');
if(extensionIdx == -1)
{
extensionIdx = path.length();
}
auto now = QDateTime::currentDateTime();
char suffix[64];
sprintf_s(suffix, "-%04d%02d%02d-%02d%02d%02d",
now.date().year(),
now.date().month(),
now.date().day(),
now.time().hour(),
now.time().minute(),
now.time().second()
);
path.insert(extensionIdx, suffix);
}
}
return QDir::toNativeSeparators(path);
}
QString mainModuleName(bool extension)
{
auto base = DbgEval("mod.main()");
char name[MAX_MODULE_SIZE] = "";
if(base && DbgFunctions()->ModNameFromAddr(base, name, extension))
{
return name;
}
return QString();
}

28
src/cross/gui/MiscUtil.h Normal file
View File

@ -0,0 +1,28 @@
#pragma once
#include <QIcon>
#include <functional>
#include "Types.h"
class QWidget;
class QByteArray;
//void SetApplicationIcon(WId winId);
QByteArray & ByteReverse(QByteArray & array);
QByteArray ByteReverse(QByteArray && array);
bool SimpleInputBox(QWidget* parent, const QString & title, QString defaultValue, QString & output, const QString & placeholderText, const QIcon* icon = nullptr);
bool SimpleChoiceBox(QWidget* parent, const QString & title, QString defaultValue, const QStringList & choices, QString & output, bool editable, const QString & placeholderText, const QIcon* icon = nullptr, int minimumContentsLength = -1);
void SimpleErrorBox(QWidget* parent, const QString & title, const QString & text);
void SimpleWarningBox(QWidget* parent, const QString & title, const QString & text);
void SimpleInfoBox(QWidget* parent, const QString & title, const QString & text);
QString getSymbolicName(duint addr);
QString getSymbolicNameStr(duint addr);
bool ExportCSV(dsint rows, dsint columns, std::vector<QString> headers, std::function<QString(dsint, dsint)> getCellContent);
bool isEaster();
bool isSeasonal();
QIcon getFileIcon(QString file);
QIcon DIconHelper(QString name);
QString getDbPath(const QString & filename = QString(), bool addDateTimeSuffix = false);
QString mainModuleName(bool extension = false);
#define DIcon(name) [](QString arg) { static QIcon icon(DIconHelper(std::move(arg))); return icon; }(name)

63
src/cross/gui/Qt.cmake Normal file
View File

@ -0,0 +1,63 @@
include_guard(DIRECTORY)
# https://www.kdab.com/wp-content/uploads/stories/QTVTC20-Using-Modern-CMake-Kevin-Funk.pdf
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
#set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_GLOBAL_AUTOGEN_TARGET ON)
set_property(GLOBAL PROPERTY AUTOGEN_SOURCE_GROUP "Qt")
set_property(GLOBAL PROPERTY AUTOGEN_TARGETS_FOLDER "Qt")
set_property(GLOBAL PROPERTY AUTOMOC_SOURCE_GROUP "Qt")
set_property(GLOBAL PROPERTY AUTOMOC_TARGETS_FOLDER "Qt")
set_property(GLOBAL PROPERTY AUTORCC_SOURCE_GROUP "Qt")
set_property(GLOBAL PROPERTY AUTOUIC_SOURCE_GROUP "Qt")
# Find whether we are using Qt5 or Qt6
# NOTE: do not add components here, it doesn't work
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
set(QT_PACKAGE "Qt${QT_VERSION_MAJOR}")
# Find the exact Qt version
set(QT_LIBRARIES
${QT_PACKAGE}::Widgets
${QT_PACKAGE}::Svg
${QT_PACKAGE}::WebSockets
)
if("${QT_PACKAGE}" STREQUAL "Qt6")
set(ADDITIONAL_COMPONENTS OpenGLWidgets)
list(APPEND QT_LIBRARIES Qt6::OpenGLWidgets)
else()
set(ADDITIONAL_COMPONENTS "")
endif()
find_package(${QT_PACKAGE} COMPONENTS Widgets Svg PrintSupport WebSockets ${ADDITIONAL_COMPONENTS} REQUIRED)
message(STATUS "Found ${QT_PACKAGE}: ${${QT_PACKAGE}_DIR}")
# https://stackoverflow.com/a/41199492/1806760
# TODO: set VCINSTALLDIR environment variable
# TODO: move to a custom target you can trigger manually
# TODO: support macdeployqt
if(${QT_PACKAGE}_FOUND AND WIN32 AND TARGET ${QT_PACKAGE}::qmake AND NOT TARGET ${QT_PACKAGE}::windeployqt)
get_target_property(_qt_qmake_location ${QT_PACKAGE}::qmake IMPORTED_LOCATION)
execute_process(
COMMAND "${_qt_qmake_location}" -query QT_INSTALL_PREFIX
RESULT_VARIABLE return_code
OUTPUT_VARIABLE qt_install_prefix
OUTPUT_STRIP_TRAILING_WHITESPACE
)
set(imported_location "${qt_install_prefix}/bin/windeployqt.exe")
if(EXISTS ${imported_location})
add_executable(${QT_PACKAGE}::windeployqt IMPORTED)
set_target_properties(${QT_PACKAGE}::windeployqt PROPERTIES
IMPORTED_LOCATION ${imported_location}
)
endif()
endif()
function(qt_executable tgt)
qt_add_executable(${tgt} MANUAL_FINALIZATION ${ARGN})
endfunction()

View File

@ -0,0 +1,284 @@
#include <stdint.h>
//#include "main.h"
#include "StringUtil.h"
#include "MiscUtil.h"
//#include "ldconvert.h"
#include "Configuration.h"
#include "Bridge.h"
QString ToLongDoubleString(const void* buffer)
{
char str[32];
//ld2str(buffer, str);
return str;
}
QString EscapeCh(QChar ch)
{
switch(ch.unicode())
{
case '\0':
return "\\0";
case '\t':
return "\\t";
case '\f':
return "\\f";
case '\v':
return "\\v";
case '\n':
return "\\n";
case '\r':
return "\\r";
case '\\':
return "\\\\";
case '\"':
return "\\\"";
case '\a':
return "\\a";
case '\b':
return "\\b";
default:
return QString(1, QChar(ch));
}
}
QString fillValue(const char* value, int valsize, bool bFpuRegistersLittleEndian)
{
if(bFpuRegistersLittleEndian)
return QString(QByteArray(value, valsize).toHex()).toUpper();
else // Big Endian
return QString(ByteReverse(QByteArray(value, valsize)).toHex()).toUpper();
}
QString composeRegTextXMM(const char* value, int mode)
{
bool bFpuRegistersLittleEndian = ConfigBool("Gui", "FpuRegistersLittleEndian");
QString valueText;
switch(mode)
{
default:
case 0:
{
valueText = fillValue(value, 16, bFpuRegistersLittleEndian);
}
break;
case 2:
{
const double* dbl_values = reinterpret_cast<const double*>(value);
if(bFpuRegistersLittleEndian)
valueText = ToDoubleString(&dbl_values[0]) + ' ' + ToDoubleString(&dbl_values[1]);
else // Big Endian
valueText = ToDoubleString(&dbl_values[1]) + ' ' + ToDoubleString(&dbl_values[0]);
}
break;
case 1:
{
const float* flt_values = reinterpret_cast<const float*>(value);
if(bFpuRegistersLittleEndian)
valueText = ToFloatString(&flt_values[0]) + ' ' + ToFloatString(&flt_values[1]) + ' '
+ ToFloatString(&flt_values[2]) + ' ' + ToFloatString(&flt_values[3]);
else // Big Endian
valueText = ToFloatString(&flt_values[3]) + ' ' + ToFloatString(&flt_values[2]) + ' '
+ ToFloatString(&flt_values[1]) + ' ' + ToFloatString(&flt_values[0]);
}
break;
case 9:
{
if(bFpuRegistersLittleEndian)
valueText = fillValue(value) + ' ' + fillValue(value + 1 * 2) + ' ' + fillValue(value + 2 * 2) + ' ' + fillValue(value + 3 * 2)
+ ' ' + fillValue(value + 4 * 2) + ' ' + fillValue(value + 5 * 2) + ' ' + fillValue(value + 6 * 2) + ' ' + fillValue(value + 7 * 2);
else // Big Endian
valueText = fillValue(value + 7 * 2) + ' ' + fillValue(value + 6 * 2) + ' ' + fillValue(value + 5 * 2) + ' ' + fillValue(value + 4 * 2)
+ ' ' + fillValue(value + 3 * 2) + ' ' + fillValue(value + 2 * 2) + ' ' + fillValue(value + 1 * 2) + ' ' + fillValue(value);
}
break;
case 3:
{
const short* sword_values = reinterpret_cast<const short*>(value);
if(bFpuRegistersLittleEndian)
valueText = QString::number(sword_values[0]) + ' ' + QString::number(sword_values[1]) + ' ' + QString::number(sword_values[2]) + ' ' + QString::number(sword_values[3])
+ ' ' + QString::number(sword_values[4]) + ' ' + QString::number(sword_values[5]) + ' ' + QString::number(sword_values[6]) + ' ' + QString::number(sword_values[7]);
else // Big Endian
valueText = QString::number(sword_values[7]) + ' ' + QString::number(sword_values[6]) + ' ' + QString::number(sword_values[5]) + ' ' + QString::number(sword_values[4])
+ ' ' + QString::number(sword_values[3]) + ' ' + QString::number(sword_values[2]) + ' ' + QString::number(sword_values[1]) + ' ' + QString::number(sword_values[0]);
}
break;
case 6:
{
const unsigned short* uword_values = reinterpret_cast<const unsigned short*>(value);
if(bFpuRegistersLittleEndian)
valueText = QString::number(uword_values[0]) + ' ' + QString::number(uword_values[1]) + ' ' + QString::number(uword_values[2]) + ' ' + QString::number(uword_values[3])
+ ' ' + QString::number(uword_values[4]) + ' ' + QString::number(uword_values[5]) + ' ' + QString::number(uword_values[6]) + ' ' + QString::number(uword_values[7]);
else // Big Endian
valueText = QString::number(uword_values[7]) + ' ' + QString::number(uword_values[6]) + ' ' + QString::number(uword_values[5]) + ' ' + QString::number(uword_values[4])
+ ' ' + QString::number(uword_values[3]) + ' ' + QString::number(uword_values[2]) + ' ' + QString::number(uword_values[1]) + ' ' + QString::number(uword_values[0]);
}
break;
case 10:
{
if(bFpuRegistersLittleEndian)
valueText = fillValue(value, 4) + ' ' + fillValue(value + 1 * 4, 4) + ' ' + fillValue(value + 2 * 4, 4) + ' ' + fillValue(value + 3 * 4, 4);
else // Big Endian
valueText = fillValue(value + 3 * 4, 4) + ' ' + fillValue(value + 2 * 4, 4) + ' ' + fillValue(value + 1 * 4, 4) + ' ' + fillValue(value, 4);
}
break;
case 4:
{
const int* sdword_values = reinterpret_cast<const int*>(value);
if(bFpuRegistersLittleEndian)
valueText = QString::number(sdword_values[0]) + ' ' + QString::number(sdword_values[1]) + ' ' + QString::number(sdword_values[2]) + ' ' + QString::number(sdword_values[3]);
else // Big Endian
valueText = QString::number(sdword_values[3]) + ' ' + QString::number(sdword_values[2]) + ' ' + QString::number(sdword_values[1]) + ' ' + QString::number(sdword_values[0]);
}
break;
case 7:
{
const unsigned int* udword_values = reinterpret_cast<const unsigned int*>(value);
if(bFpuRegistersLittleEndian)
valueText = QString::number(udword_values[0]) + ' ' + QString::number(udword_values[1]) + ' ' + QString::number(udword_values[2]) + ' ' + QString::number(udword_values[3]);
else // Big Endian
valueText = QString::number(udword_values[3]) + ' ' + QString::number(udword_values[2]) + ' ' + QString::number(udword_values[1]) + ' ' + QString::number(udword_values[0]);
}
break;
case 11:
{
if(bFpuRegistersLittleEndian)
valueText = fillValue(value, 8) + ' ' + fillValue(value + 8, 8);
else // Big Endian
valueText = fillValue(value + 8, 8) + ' ' + fillValue(value, 8);
}
break;
case 5:
{
const long long* sqword_values = reinterpret_cast<const long long*>(value);
if(bFpuRegistersLittleEndian)
valueText = QString::number(sqword_values[0]) + ' ' + QString::number(sqword_values[1]);
else // Big Endian
valueText = QString::number(sqword_values[1]) + ' ' + QString::number(sqword_values[0]);
}
break;
case 8:
{
const unsigned long long* uqword_values = reinterpret_cast<const unsigned long long*>(value);
if(bFpuRegistersLittleEndian)
valueText = QString::number(uqword_values[0]) + ' ' + QString::number(uqword_values[1]);
else // Big Endian
valueText = QString::number(uqword_values[1]) + ' ' + QString::number(uqword_values[0]);
}
break;
}
return valueText;
}
QString composeRegTextYMM(const char* value, int mode)
{
bool bFpuRegistersLittleEndian = ConfigBool("Gui", "FpuRegistersLittleEndian");
if(mode == 0)
return fillValue(value, 32, bFpuRegistersLittleEndian);
else if(bFpuRegistersLittleEndian)
return composeRegTextXMM(value, mode) + ' ' + composeRegTextXMM(value + 16, mode);
else
return composeRegTextXMM(value + 16, mode) + ' ' + composeRegTextXMM(value, mode);
}
QString GetDataTypeString(const void* buffer, duint size, ENCODETYPE type)
{
switch(type)
{
case enc_byte:
return ToIntegralString<unsigned char>(buffer);
case enc_word:
return ToIntegralString<unsigned short>(buffer);
case enc_dword:
return ToIntegralString<unsigned int>(buffer);
case enc_fword:
return QString(ByteReverse(QByteArray((const char*)buffer, 6)).toHex());
case enc_qword:
return ToIntegralString<unsigned long long int>(buffer);
case enc_tbyte:
return QString(ByteReverse(QByteArray((const char*)buffer, 10)).toHex());
case enc_oword:
return QString(ByteReverse(QByteArray((const char*)buffer, 16)).toHex());
case enc_mmword:
return QString(QByteArray((const char*)buffer, size).toHex());
case enc_xmmword:
return composeRegTextXMM((const char*)buffer, ConfigUint("Gui", "SIMDRegistersDisplayMode"));
case enc_ymmword:
return composeRegTextYMM((const char*)buffer, ConfigUint("Gui", "SIMDRegistersDisplayMode"));
case enc_real4:
return ToFloatString(buffer);
case enc_real8:
return ToDoubleString(buffer);
case enc_real10:
return ToLongDoubleString(buffer);
case enc_ascii:
return EscapeCh(*(const char*)buffer);
case enc_unicode:
return EscapeCh(QChar((uchar) * (const wchar_t*)buffer));
default:
return ToIntegralString<unsigned char>(buffer);
}
}
QString ToDateString(const QDate & date)
{
static const char* months[] =
{
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
};
char result[32];
sprintf_s(result, "%s %d %d", months[date.month() - 1], date.day(), date.year());
return result;
}
#if 0
QString FILETIMEToDate(const FILETIME & date)
{
FILETIME localdate;
FileTimeToLocalFileTime(&date, &localdate);
SYSTEMTIME systime;
FileTimeToSystemTime(&localdate, &systime);
QDate qdate = QDate(systime.wYear, systime.wMonth, systime.wDay);
quint64 time100ns = (quint64)localdate.dwHighDateTime << 32 | (quint64)localdate.dwLowDateTime;
time100ns %= (1000ull * 60ull * 60ull * 24ull * 10000ull);
localdate.dwHighDateTime = time100ns >> 32;
localdate.dwLowDateTime = time100ns & 0xFFFFFFFF;
if(qdate != QDate::currentDate())
return QLocale(QString(currentLocale)).toString(qdate) + FILETIMEToTime(localdate);
else // today
return FILETIMEToTime(localdate);
}
#endif // 0
bool GetCommentFormat(duint addr, QString & comment, bool* autoComment)
{
comment.clear();
char commentData[MAX_COMMENT_SIZE] = "";
if(!DbgGetCommentAt(addr, commentData))
return false;
auto a = *commentData == '\1';
if(autoComment)
*autoComment = a;
if(!strstr(commentData, "{"))
{
comment = commentData + a;
return true;
}
char commentFormat[MAX_SETTING_SIZE] = "";
if(DbgFunctions()->StringFormatInline(commentData + a, MAX_SETTING_SIZE, commentFormat))
comment = commentFormat;
else
comment = commentData + a;
return true;
}

137
src/cross/gui/StringUtil.h Normal file
View File

@ -0,0 +1,137 @@
#pragma once
#include <sstream>
#include <iomanip>
#include <QString>
#include <QDateTime>
#include <QLocale>
#include "Types.h"
// Hack for compatibility: https://stackoverflow.com/a/75748797/1806760
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
namespace Qt
{
constexpr auto KeepEmptyParts = QString::KeepEmptyParts;
constexpr auto SkipEmptyParts = QString::SkipEmptyParts;
}
#endif // QT_VERSION
inline QString ToPtrString(duint Address)
{
//
// This function exists because of how QT handles
// variables in strings.
//
// QString::arg():
// ((int32)0xFFFF0000) == 0xFFFFFFFFFFFF0000 with sign extension
//
char temp[32];
sprintf_s(temp, "%016llX", Address);
return QString(temp);
}
inline QString ToLongLongHexString(unsigned long long Value)
{
char temp[32];
sprintf_s(temp, "%llX", Value);
return QString(temp);
}
inline QString ToHexString(duint Value)
{
char temp[32];
sprintf_s(temp, "%llX", Value);
return QString(temp);
}
inline QString ToDecString(dsint Value)
{
char temp[32];
sprintf_s(temp, "%lld", Value);
return QString(temp);
}
inline QString ToByteString(unsigned char Value)
{
char temp[4];
sprintf_s(temp, "%02X", Value);
return QString(temp);
}
inline QString ToWordString(unsigned short Value)
{
char temp[8];
sprintf_s(temp, "%04X", Value);
return QString(temp);
}
inline QString ToDwordString(unsigned int Value)
{
char temp[16];
sprintf_s(temp, "%08X", Value);
return QString(temp);
}
template<typename T>
inline QString ToFloatingString(const void* buffer, int precision)
{
auto value = *(const T*)buffer;
std::stringstream wFloatingStr;
wFloatingStr << std::setprecision(precision) << value;
return QString::fromStdString(wFloatingStr.str());
}
template<typename T>
inline QString ToIntegralString(const void* buffer)
{
auto value = *(const T*)buffer;
return ToLongLongHexString(value);
}
inline QString ToFloatString(const void* buffer, int precision = std::numeric_limits<float>::digits10)
{
return ToFloatingString<float>(buffer, precision);
}
inline QString ToDoubleString(const void* buffer, int precision = std::numeric_limits<double>::digits10)
{
return ToFloatingString<double>(buffer, precision);
}
QString ToLongDoubleString(const void* buffer);
QString ToDateString(const QDate & date);
QString fillValue(const char* value, int valsize = 2, bool bFpuRegistersLittleEndian = false);
QString composeRegTextXMM(const char* value, int mode);
QString composeRegTextYMM(const char* value, int mode);
QString GetDataTypeString(const void* buffer, duint size, ENCODETYPE type);
inline QDate GetCompileDate()
{
return QLocale("en_US").toDate(QString(__DATE__).simplified(), "MMM d yyyy");
}
#if 0
// Format : d:hh:mm:ss.1234567
inline QString FILETIMEToTime(const FILETIME & time)
{
// FILETIME is in 100ns
quint64 time100ns = (quint64)time.dwHighDateTime << 32 | (quint64)time.dwLowDateTime;
quint64 milliseconds = time100ns / 10000;
quint64 days = milliseconds / (1000 * 60 * 60 * 24);
QTime qtime = QTime::fromMSecsSinceStartOfDay(milliseconds % (1000 * 60 * 60 * 24));
if(days == 0) // 0 days
return QString().sprintf("%02d:%02d:%02d.%07lld", qtime.hour(), qtime.minute(), qtime.second(), time100ns % 10000000);
else
return QString().sprintf("%lld:%02d:%02d:%02d.%07lld", days, qtime.hour(), qtime.minute(), qtime.second(), time100ns % 10000000);
}
QString FILETIMEToDate(const FILETIME & date);
#endif // 0
bool GetCommentFormat(duint addr, QString & comment, bool* autoComment = nullptr);
QString EscapeCh(QChar ch);

76
src/cross/gui/Types.h Normal file
View File

@ -0,0 +1,76 @@
#pragma once
#include <cstdint>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
// TODO: do something cross platform
using duint = uint64_t;
using dsint = int64_t;
#ifndef _WIN32
template<size_t Count, class... Args>
int sprintf_s(char (&Dest)[Count], const char* fmt, Args... args)
{
return snprintf(Dest, Count, fmt, args...);
}
inline size_t strcpy_s(char* dst, size_t size, const char* src)
{
return strlcpy(dst, src, size);
}
#endif // _WIN32
// These types are needed in very deep UI components
typedef enum
{
enc_unknown, //must be 0
enc_byte, //1 byte
enc_word, //2 bytes
enc_dword, //4 bytes
enc_fword, //6 bytes
enc_qword, //8 bytes
enc_tbyte, //10 bytes
enc_oword, //16 bytes
enc_mmword, //8 bytes
enc_xmmword, //16 bytes
enc_ymmword, //32 bytes
enc_zmmword, //64 bytes avx512 not supported
enc_real4, //4 byte float
enc_real8, //8 byte double
enc_real10, //10 byte decimal
enc_ascii, //ascii sequence
enc_unicode, //unicode sequence
enc_code, //start of code
enc_junk, //junk code
enc_middle //middle of data
} ENCODETYPE;
typedef enum
{
initialized,
paused,
running,
stopped
} DBGSTATE;
typedef enum
{
XREF_NONE,
XREF_DATA,
XREF_JMP,
XREF_CALL
} XREFTYPE;
typedef struct
{
duint addr;
XREFTYPE type;
} XREF_RECORD;
typedef struct
{
duint refcount;
XREF_RECORD* references;
} XREF_INFO;

View File

@ -0,0 +1,62 @@
#include "JsonRpcClient.h"
JsonRpcClient::JsonRpcClient(QObject* parent)
: QObject(parent)
{
connect(&mSocket, &QWebSocket::connected, this, &JsonRpcClient::connected);
connect(&mSocket, &QWebSocket::disconnected, this, &JsonRpcClient::disconnected);
connect(&mSocket, &QWebSocket::textMessageReceived, this, &JsonRpcClient::textMessageReceivedSlot);
}
void JsonRpcClient::open(const QUrl & url)
{
mSocket.open(url);
}
bool JsonRpcClient::isConnected()
{
return mSocket.state() == QAbstractSocket::ConnectedState;
}
void JsonRpcClient::call(const QString & method, nlohmann::json params, Callback finished)
{
auto id = mRequestId++;
nlohmann::json request;
request["jsonrpc"] = "2.0";
request["method"] = method.toStdString();
request["params"] = std::move(params);
request["id"] = id;
// TODO: timeout
mCalls.emplace(id, std::move(finished));
mSocket.sendTextMessage(QString::fromStdString(request.dump()));
}
void JsonRpcClient::textMessageReceivedSlot(const QString & message)
{
//qDebug() << "[client] textMessageReceivedSlot" << message;
// This is fine 🔥
auto response = nlohmann::json::parse(message.toStdString());
// TODO: rewrite to not use exceptions for WASM
try
{
auto magic = response.at("jsonrpc").get<std::string>();
if(magic != "2.0")
{
qDebug() << "[client] Invalid magic:" << magic;
return;
}
auto result = response.at("result");
auto id = response.at("id").get<uint64_t>();
auto itr = mCalls.find(id);
if(itr == mCalls.end())
{
qDebug() << "[client] Unknown response id:" << id;
return;
}
itr->second(result);
}
catch(std::exception & x)
{
qDebug() << "[client] JSON exception:" << x.what();
}
}

View File

@ -0,0 +1,49 @@
#pragma once
#include <QObject>
#include <QWebSocket>
#include <unordered_map>
#include <functional>
#include "json.hpp"
// https://www.jsonrpc.org/specification
class JsonRpcClient : public QObject
{
Q_OBJECT
public:
using Callback = std::function<void(const nlohmann::json &)>;
JsonRpcClient(QObject* parent = nullptr);
void open(const QUrl & url);
bool isConnected();
void call(const QString & method, nlohmann::json params, Callback finished);
template<class Response, class Request>
void call(const Request & params, const std::function<void(Response)> & finished)
{
if(strcmp(Request::method, Response::method) != 0)
throw std::runtime_error("Mismatching method name");
nlohmann::json jparams;
nlohmann::to_json(jparams, params);
call(Request::method, std::move(jparams), [finished](const nlohmann::json & response)
{
Response r;
nlohmann::from_json(response, r);
finished(std::move(r));
});
}
signals:
void connected();
void disconnected();
private slots:
void textMessageReceivedSlot(const QString & message);
private:
uint64_t mRequestId = 0;
QWebSocket mSocket;
std::unordered_map<int, Callback> mCalls;
};

View File

@ -0,0 +1,33 @@
#include "MainWindow.h"
#include "./ui_MainWindow.h"
#include <QDebug>
#include <QMessageBox>
#include <QVBoxLayout>
#include <QFileDialog>
#include "StringUtil.h"
#include <fstream>
MainWindow::MainWindow(QWidget* parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
setupWidgets();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::closeEvent(QCloseEvent* event)
{
QMainWindow::closeEvent(event);
}
void MainWindow::setupWidgets()
{
mTable = new RemoteTable(this);
ui->tabWidget->addTab(mTable, "Remote Table");
}

View File

@ -0,0 +1,32 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <memory>
#include <QMainWindow>
#include "RemoteTable.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget* parent = nullptr);
~MainWindow();
protected:
void closeEvent(QCloseEvent* event) override;
private:
void setupWidgets();
private:
Ui::MainWindow* ui = nullptr;
RemoteTable* mTable = nullptr;
};
#endif // MAINWINDOW_H

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1280</width>
<height>800</height>
</rect>
</property>
<property name="windowTitle">
<string>Remote Table</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>-1</number>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1280</width>
<height>22</height>
</rect>
</property>
<widget class="QMenu" name="menu_File">
<property name="title">
<string>&amp;File</string>
</property>
</widget>
<addaction name="menu_File"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,197 @@
#include "RemoteTable.h"
#include "StringUtil.h"
#include "Bridge.h"
#include <QMessageBox>
#include <QTimer>
RemoteTable::RemoteTable(QWidget* parent)
: AbstractStdTable(parent)
{
std::map<ColumnIndex, std::pair<int, QString>> columns;
columns[ColAddress] = { 50, tr("Address") };
columns[ColData] = { 50, tr("Data") };
int col = 0;
for(const auto & itr : columns)
{
if(itr.first != col)
{
qDebug() << "Bad column index" << col << "!=" << itr.first;
QApplication::exit(1);
}
addColumnAt(calculateColumnWidth(itr.second.first), itr.second.second, true);
col++;
}
setupMenu();
mRpc.open(QUrl("ws://127.0.0.1:42069"));
connect(&mRpc, &JsonRpcClient::connected, this, [this]()
{
prepareData();
});
// Test
setRowCount(0x2000ull);
}
QString RemoteTable::getCellContent(duint row, duint col)
{
auto relativeRow = row - getTableOffset();
auto base = QString("row: %1, col: %2").arg(row, 5).arg(col);
if(relativeRow < mRemoteData.size())
{
auto data = QString::fromStdString(mRemoteData[relativeRow][col]);
return base + " " + data;
}
else
{
return "(FETCHING DATA...)";
return QString();
return base + " (FETCHING DATA...)";
}
}
bool RemoteTable::isValidIndex(duint row, duint col)
{
if(row >= getRowCount())
return false;
return col >= ColAddress && col <= ColData;
}
void RemoteTable::sortRows(duint column, bool ascending)
{
}
duint RemoteTable::sliderMovedHook(QScrollBar::SliderAction action, duint value, dsint delta)
{
auto actionName = [action]()
{
switch(action)
{
case QScrollBar::SliderNoAction:
return "SliderNoAction";
case QScrollBar::SliderSingleStepAdd:
return "SliderSingleStepAdd";
case QScrollBar::SliderSingleStepSub:
return "SliderSingleStepSub";
case QScrollBar::SliderPageStepAdd:
return "SliderPageStepAdd";
case QScrollBar::SliderPageStepSub:
return "SliderPageStepSub";
case QScrollBar::SliderToMinimum:
return "SliderToMinimum";
case QScrollBar::SliderToMaximum:
return "SliderToMaximum";
case QScrollBar::SliderMove:
return "SliderMove";
default:
return "<unknown>";
}
}();
//qDebug() << "sliderMovedHook" << actionName << "value" << value << "delta" << delta;
return AbstractStdTable::sliderMovedHook(action, value, delta);
}
void RemoteTable::prepareData()
{
AbstractStdTable::prepareData();
if(!mRpc.isConnected())
{
qDebug() << "socket not ready bro";
return;
}
auto now = std::chrono::system_clock::now();
auto elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(now - mLastPrepare).count();
mLastPrepare = now;
auto linesToPrint = getNbrOfLineToPrint();
auto offset = getTableOffset();
//qDebug() << "offset" << offset << "lines" << linesToPrint << "last" << offset + linesToPrint - 1 << "elapsed" << elapsedMs;
#if 0
const uint32_t totalRefreshMs = 300;
const uint32_t scrollDebounceMs = 300;
if(elapsedMs >= totalRefreshMs)
{
qDebug() << "100% send request";
}
else if(elapsedMs < scrollDebounceMs)
{
qDebug() << "scroll debounce";
}
else
{
qDebug() << "unclear request";
}
#endif
//mRemoteData.clear();
//qDebug() << "prepareData";
// TODO: do some cooldown and don't enqueue unnecessary requests
// TODO: use the average/median/last latency of the connection as a debouncing timer
// TODO: use some basic prediction heuristics (scroll direction etc) to anticipate the scroll
// TODO: measure the ping
TableRequest r;
r.offset = offset;
r.lines = linesToPrint;
r.scroll = 0; // TODO
if(!mCurrentSent)
{
if(mNextRequired) __debugbreak();
mCurrentSent = true;
qDebug() << "send rpc request";
mCurrentRequest = r;
mRpc.call<TableResponse>(r, [this](TableResponse response) { handleTableResponse(response); });
}
else
{
qDebug() << "add rpc to backlog";
mNextRequest = r;
mNextRequired = true;
}
}
void RemoteTable::handleTableResponse(const TableResponse & response)
{
if(mNextRequired)
{
mNextRequired = false;
mCurrentRequest = mNextRequest;
if(!mCurrentSent) __debugbreak();
qDebug() << "send rpc request (backlog)";
mRpc.call<TableResponse>(mCurrentRequest, [this](TableResponse response) { handleTableResponse(response); });
}
else
{
mCurrentSent = false;
qDebug() << "final response";
}
mRemoteData = std::move(response.rows);
updateViewport();
}
void RemoteTable::setupMenu()
{
addMenuAction(TableAction(TR("Goto line"), "G"), [this]()
{
qDebug() << "scroll select";
auto ok = scrollSelect(5000);
if(!ok)
qDebug() << "failz";
reloadData();
});
}

View File

@ -0,0 +1,46 @@
#pragma once
#include <BasicView/AbstractStdTable.h>
#include "MagicMenu.h"
#include "JsonRpcClient.h"
#include "TableRpcData.h"
#include <QWebSocket>
class RemoteTable : public AbstractStdTable, public MagicMenu<RemoteTable>
{
Q_OBJECT
public:
explicit RemoteTable(QWidget* parent = nullptr);
protected:
QString getCellContent(duint row, duint col) override;
bool isValidIndex(duint row, duint col) override;
void sortRows(duint column, bool ascending) override;
duint sliderMovedHook(QScrollBar::SliderAction action, duint value, dsint delta) override;
void prepareData() override;
private:
enum ColumnIndex
{
ColAddress,
ColData,
};
std::vector<std::vector<std::string>> mRemoteData;
std::chrono::time_point<std::chrono::system_clock> mLastPrepare;
QWebSocket mSocket;
JsonRpcClient mRpc;
TableRequest mCurrentRequest;
bool mCurrentSent = false;
TableRequest mNextRequest;
bool mNextRequired = false;
void handleTableResponse(const TableResponse & response);
void setupMenu();
void setupConnection();
};

View File

@ -0,0 +1,28 @@
#pragma once
#include "Types.h"
#include "json.hpp"
#include <vector>
#include <string>
struct TableRequest
{
static constexpr const char* method = "table";
duint offset = 0;
duint lines = 0;
dsint scroll = 0;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(TableRequest, offset, lines, scroll);
struct TableResponse
{
static constexpr const char* method = "table";
std::vector<std::vector<std::string>> rows;
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(TableResponse, rows);
//QString jsonRpcRequest(const QString& method, )

View File

@ -0,0 +1,106 @@
#include "TableServer.h"
#include "TableRpcData.h"
#include <QWebSocketServer>
#include <QWebSocket>
#include <QDebug>
#include <QThread>
#include <QApplication>
#include <chrono>
TableServer::TableServer(QObject* parent)
: QObject(parent)
, mServer(new QWebSocketServer("TableServer", QWebSocketServer::NonSecureMode))
{
if(mServer->listen(QHostAddress::LocalHost, 42069))
{
qDebug() << "[server] Listening on ws://127.0.0.1:42069";
connect(mServer, &QWebSocketServer::newConnection, this, [this]()
{
auto socket = mServer->nextPendingConnection();
connect(socket, &QWebSocket::textMessageReceived, this, [this](QString message)
{
//qDebug() << "[server] textMessageReceived:" << message;
auto client = qobject_cast<QWebSocket*>(sender());
try
{
auto request = nlohmann::json::parse(message.toStdString());
auto magic = request["jsonrpc"].get<std::string>();
if(magic != "2.0")
{
qDebug() << "[server] Invalid magic:" << magic;
return;
}
auto method = request["method"].get<std::string>();
auto id = request["id"].get<uint64_t>();
auto params = request["params"];
nlohmann::json response;
response["jsonrpc"] = "2.0";
response["id"] = id;
nlohmann::json & result = response["result"];
if(method == "table")
{
TableRequest request;
nlohmann::from_json(params, request);
TableResponse response{};
if(!table(request, response))
{
// TODO: write error response
qDebug() << "[server] bad fail";
}
nlohmann::to_json(result, response);
}
else
{
qDebug() << "[server] unknown method:" << method.c_str();
return;
}
client->sendTextMessage(QString::fromStdString(response.dump()));
}
catch(std::exception & x)
{
qDebug() << "[server] JSON error:" << x.what();
}
});
mClients << socket;
});
}
else
{
qDebug() << "[server] Error listening";
}
}
bool TableServer::table(const TableRequest & request, TableResponse & response)
{
response.rows.resize(request.lines);
for(uint64_t line = 0; line < request.lines; line++)
{
auto & row = response.rows[line];
row.resize(2);
row[0] = "address: " + std::to_string(line + request.offset);
row[1] = "data: " + std::to_string(line + request.offset);
}
// Sleep without hanging event loop
auto start = std::chrono::system_clock::now();
while(true)
{
auto now = std::chrono::system_clock::now();
auto elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(now - start).count();
if(elapsedMs >= 500)
break;
QApplication::processEvents();
}
return true;
}

View File

@ -0,0 +1,22 @@
#pragma once
#include <QObject>
#include "TableRpcData.h"
QT_FORWARD_DECLARE_CLASS(QWebSocketServer)
QT_FORWARD_DECLARE_CLASS(QWebSocket)
class TableServer : public QObject
{
Q_OBJECT
public:
TableServer(QObject* parent = nullptr);
private:
bool table(const TableRequest & request, TableResponse & response);
private:
QWebSocketServer* mServer = nullptr;
QList<QWebSocket*> mClients;
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,20 @@
#include <QApplication>
#include <QThread>
#include "MainWindow.h"
#include "Configuration.h"
#include "TableServer.h"
#if QT_VERSION < QT_VERSION_CHECK(5, 12, 0)
#error Your Qt version is likely too old, upgrade to 5.12 or higher
#endif // QT_VERSION
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
Configuration config;
TableServer server;
MainWindow w;
w.show();
return a.exec();
}

15
src/cross/vendor/CMakeLists.txt generated vendored Normal file
View File

@ -0,0 +1,15 @@
# This file is automatically generated from cmake.toml - DO NOT EDIT
# See https://github.com/build-cpp/cmkr for more information
# Create a configure-time dependency on cmake.toml to improve IDE support
if(CMKR_ROOT_PROJECT)
configure_file(cmake.toml cmake.toml COPYONLY)
endif()
# Target: cpp-httplib
add_library(cpp-httplib INTERFACE)
target_include_directories(cpp-httplib INTERFACE
cpp-httplib
)

3
src/cross/vendor/cmake.toml vendored Normal file
View File

@ -0,0 +1,3 @@
[target.cpp-httplib]
type = "interface"
include-directories = ["cpp-httplib"]

10263
src/cross/vendor/cpp-httplib/httplib.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
#include "AbstractStdTable.h"
#include "Bridge.h"
#include "RichTextPainter.h"
#include <Utils/RichTextPainter.h>
AbstractStdTable::AbstractStdTable(QWidget* parent) : AbstractTableView(parent)
{

View File

@ -1,10 +1,10 @@
#include "AbstractTableView.h"
#include <QStyleOptionButton>
#include "Configuration.h"
#include "ColumnReorderDialog.h"
#include "CachedFontMetrics.h"
#include <Gui/ColumnReorderDialog.h>
#include <Utils/CachedFontMetrics.h>
#include "Bridge.h"
#include "MethodInvoker.h"
#include <Utils/MethodInvoker.h>
AbstractTableScrollBar::AbstractTableScrollBar(QScrollBar* scrollbar)
{

View File

@ -9,9 +9,9 @@
#include <QMenu>
#include "StringUtil.h"
#include "Configuration.h"
#include "MenuBuilder.h"
#include <Utils/MenuBuilder.h>
#include "MiscUtil.h"
#include "ActionHelpers.h"
#include <Utils/ActionHelpers.h>
class CachedFontMetrics;
class ColumnReorderDialog;

View File

@ -1,12 +1,12 @@
#include "Disassembly.h"
#include "Configuration.h"
#include "CodeFolding.h"
#include "EncodeMap.h"
#include <Utils/CodeFolding.h>
#include <Utils/EncodeMap.h>
#include "Bridge.h"
#include "CachedFontMetrics.h"
#include "QZydis.h"
#include "MemoryPage.h"
#include "DisassemblyPopup.h"
#include <Utils/CachedFontMetrics.h>
#include <Disassembler/QZydis.h>
#include <Memory/MemoryPage.h>
#include <Gui/DisassemblyPopup.h>
Disassembly::Disassembly(Architecture* architecture, bool isMain, QWidget* parent)
: AbstractTableView(parent),

View File

@ -1,9 +1,9 @@
#pragma once
#include "AbstractTableView.h"
#include "QZydis.h"
#include <Disassembler/QZydis.h>
#include <QTextLayout>
#include "Architecture.h"
#include <Disassembler/Architecture.h>
class CodeFoldingHelper;
class MemoryPage;

View File

@ -1,9 +1,10 @@
#pragma once
#include "AbstractTableView.h"
#include "RichTextPainter.h"
#include "MemoryPage.h"
#include "VaHistory.h"
#include <Utils/RichTextPainter.h>
#include <Memory/MemoryPage.h>
#include <Utils/VaHistory.h>
#include <Disassembler/Architecture.h>
class HexDump : public AbstractTableView
{

View File

@ -1,8 +1,8 @@
#include "QZydis.h"
#include "StringUtil.h"
#include "EncodeMap.h"
#include "CodeFolding.h"
#include "Bridge.h"
#include <Utils/EncodeMap.h>
#include <Utils/CodeFolding.h>
#include <Bridge.h>
#ifndef _countof
#define _countof(array) (sizeof(array) / sizeof(array[0]))

View File

@ -1,8 +1,8 @@
#include "ZydisTokenizer.h"
#include "Configuration.h"
#include "StringUtil.h"
#include "CachedFontMetrics.h"
#include "Bridge.h"
#include <Utils/CachedFontMetrics.h>
#include <Bridge.h>
ZydisTokenizer::ZydisTokenizer(int maxModuleLength, Architecture* architecture)
: mMaxModuleLength(maxModuleLength),

View File

@ -1,8 +1,8 @@
#pragma once
#include <zydis_wrapper.h>
#include "RichTextPainter.h"
#include "Configuration.h"
#include <Utils/RichTextPainter.h>
#include <Configuration.h>
#include <map>
#include <QHash>
#include <QtCore>

View File

@ -1,7 +1,7 @@
#include "BrowseDialog.h"
#include "ui_BrowseDialog.h"
#include "MiscUtil.h"
#include <QDirModel>
#include <QFileSystemModel>
#include <QCompleter>
#include <QFileDialog>
#include <Configuration.h>
@ -26,7 +26,7 @@ BrowseDialog::BrowseDialog(QWidget* parent, const QString & title, const QString
ui->lineEdit->setSelection(lastSlashIdx + 1, periodIdx - lastSlashIdx - 1);
}
QCompleter* completer = new QCompleter(ui->lineEdit);
completer->setModel(new QDirModel(completer));
completer->setModel(new QFileSystemModel(completer));
ui->lineEdit->setCompleter(completer);
Config()->loadWindowGeometry(this);
}

View File

@ -1,6 +1,6 @@
#include "ColumnReorderDialog.h"
#include "ui_ColumnReorderDialog.h"
#include "AbstractTableView.h"
#include <BasicView/AbstractTableView.h>
#include <QMessageBox>
ColumnReorderDialog::ColumnReorderDialog(AbstractTableView* parent) :

View File

@ -1,11 +1,11 @@
#include "DisassemblyPopup.h"
#include "CachedFontMetrics.h"
#include "Configuration.h"
#include "StringUtil.h"
#include "MiscUtil.h"
#include <Utils/CachedFontMetrics.h>
#include <Configuration.h>
#include <StringUtil.h>
#include <MiscUtil.h>
#include <QPainter>
#include <QStyleOptionFrame>
#include "Bridge.h"
#include <Bridge.h>
DisassemblyPopup::DisassemblyPopup(AbstractTableView* parent, Architecture* architecture) :
QFrame(parent, Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::WindowDoesNotAcceptFocus),

View File

@ -1,10 +1,9 @@
#pragma once
#include <QFrame>
#include "Imports.h"
#include "QZydis.h"
#include "AbstractTableView.h"
#include "StdSearchListView.h"
#include <Imports.h>
#include <Disassembler/QZydis.h>
#include <BasicView/AbstractTableView.h>
class CachedFontMetrics;

View File

@ -1,4 +1,5 @@
#include "MemoryPage.h"
#include <Bridge.h>
MemoryPage::MemoryPage(duint parBase, duint parSize, QObject* parent) : QObject(parent), mBase(0), mSize(0)
{

View File

@ -1,7 +1,7 @@
#pragma once
#include <QObject>
#include "Imports.h"
#include <Imports.h>
class MemoryPage : public QObject
{

View File

@ -3,7 +3,7 @@
#include <QAction>
#include <functional>
#include <utility>
#include "Configuration.h"
#include <Configuration.h>
using SlotFunc = std::function<void()>;
using MakeMenuFunc1 = std::function<QMenu*(const QString &)>;

View File

@ -1,5 +1,5 @@
#include "BackgroundFlickerThread.h"
#include "Configuration.h"
#include <Configuration.h>
#include <Windows.h>
BackgroundFlickerThread::BackgroundFlickerThread(QWidget* widget, QColor & background, QObject* parent) : QThread(parent), background(background)

View File

@ -1,6 +1,6 @@
#pragma once
#include "Imports.h"
#include <Imports.h>
#include <map>
class CodeFoldingHelper

View File

@ -1,4 +1,4 @@
#include "Configuration.h"
#include <Configuration.h>
#include <QApplication>
#include <QFontInfo>
#include <QMessageBox>

View File

@ -1,4 +1,5 @@
#include "EncodeMap.h"
#include "Bridge.h"
EncodeMap::EncodeMap(QObject* parent)
: QObject(parent),
@ -23,7 +24,7 @@ void EncodeMap::setMemoryRegion(duint addr)
if(mBuffer)
DbgReleaseEncodeTypeBuffer(mBuffer);
mBuffer = (byte*)DbgGetEncodeTypeBuffer(addr, &mBufferSize);
mBuffer = (uint8_t*)DbgGetEncodeTypeBuffer(addr, &mBufferSize);
}
void EncodeMap::setDataType(duint va, ENCODETYPE type)

View File

@ -1,7 +1,9 @@
#pragma once
#include <cstdint>
#include <QObject>
#include "Imports.h"
#include <Imports.h>
class EncodeMap : public QObject
{
@ -81,6 +83,6 @@ public:
protected:
duint mBase;
duint mSize;
byte* mBuffer;
uint8_t* mBuffer;
duint mBufferSize;
};

View File

@ -74,7 +74,7 @@ bool MenuBuilder::build(QMenu* menu) const
if(_callback && !_callback(menu))
return false;
QMenu* submenu;
if(id != 0)
if(!id.isEmpty())
submenu = new QMenu(tr("More commands"), menu);
else
submenu = nullptr;
@ -82,7 +82,7 @@ bool MenuBuilder::build(QMenu* menu) const
{
const Container & container = _containers.at(i);
QMenu* _menu;
if(id != 0 && container.type != Container::Separator && Config()->getBool("Gui", QString("Menu%1Hidden%2").arg(id).arg(i)))
if(!id.isEmpty() && container.type != Container::Separator && Config()->getBool("Gui", QString("Menu%1Hidden%2").arg(id).arg(i)))
_menu = submenu;
else
_menu = menu;
@ -104,7 +104,7 @@ bool MenuBuilder::build(QMenu* menu) const
break;
}
}
if(id != 0 && !submenu->actions().isEmpty())
if(!id.isEmpty() && !submenu->actions().isEmpty())
{
menu->addSeparator();
menu->addMenu(submenu);

View File

@ -13,7 +13,7 @@ class MenuBuilder : public QObject
public:
typedef std::function<bool(QMenu*)> BuildCallback;
inline MenuBuilder(QObject* parent, BuildCallback callback = nullptr)
explicit MenuBuilder(QObject* parent, BuildCallback callback = nullptr)
: QObject(parent),
_callback(callback)
{
@ -21,24 +21,24 @@ public:
void loadFromConfig();
inline void addSeparator()
void addSeparator()
{
_containers.push_back(Container());
}
inline QAction* addAction(QAction* action)
QAction* addAction(QAction* action)
{
_containers.push_back(Container(action));
return action;
}
inline QAction* addAction(QAction* action, BuildCallback callback)
QAction* addAction(QAction* action, BuildCallback callback)
{
addBuilder(new MenuBuilder(action->parent(), callback))->addAction(action);
return action;
}
inline QMenu* addMenu(QMenu* menu)
QMenu* addMenu(QMenu* menu)
{
_containers.push_back(Container(menu));
return menu;
@ -48,7 +48,7 @@ public:
QMenu* addMenu(QMenu* submenu, MenuBuilder* builder);
inline MenuBuilder* addBuilder(MenuBuilder* builder)
MenuBuilder* addBuilder(MenuBuilder* builder)
{
_containers.push_back(Container(builder));
return builder;
@ -63,7 +63,7 @@ public:
bool build(QMenu* menu) const;
inline bool empty() const
bool empty() const
{
return _containers.empty();
}

View File

@ -3,7 +3,7 @@
#include "StringUtil.h"
#include "MiscUtil.h"
#include "ldconvert.h"
#include "Configuration.h"
#include <Configuration.h>
QString ToLongDoubleString(const void* buffer)
{

View File

@ -1,6 +1,6 @@
#include "SymbolAutoCompleteModel.h"
#include "MiscUtil.h"
#include "Configuration.h"
#include <Configuration.h>
SymbolAutoCompleteModel::SymbolAutoCompleteModel(std::function<QString()> getTextProc, QObject* parent)
: QAbstractItemModel(parent),

29
src/zydis_wrapper/CMakeLists.txt generated Normal file
View File

@ -0,0 +1,29 @@
set(zydis_wrapper_SOURCES
Zydis/Zydis.c
Zydis/Zydis.h
zydis_wrapper.cpp
zydis_wrapper.h
)
add_library(zydis_wrapper STATIC)
target_sources(zydis_wrapper PRIVATE ${zydis_wrapper_SOURCES})
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${zydis_wrapper_SOURCES})
target_compile_definitions(zydis_wrapper PUBLIC
ZYCORE_STATIC_BUILD
ZYDIS_STATIC_BUILD
)
target_compile_features(zydis_wrapper PUBLIC
cxx_std_11
)
target_include_directories(zydis_wrapper PUBLIC
.
)
target_include_directories(zydis_wrapper PRIVATE
Zydis
)