1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2025-12-10 09:32:29 +01:00

Fix testpaint

This commit is contained in:
Ted John
2017-12-03 22:07:24 +00:00
parent 99d7aaa2d6
commit ebf43c2529
14 changed files with 522 additions and 18 deletions

View File

@@ -132,6 +132,9 @@ add_custom_target(g2 DEPENDS ${PROJECT} g2.dat)
# Include tests
if (WITH_TESTS)
enable_testing()
if (UNIX AND (NOT USE_MMAP) AND FORCE32)
include("${ROOT_DIR}/test/testpaint/CMakeLists.txt" NO_POLICY_SCOPE)
endif ()
include("${ROOT_DIR}/test/tests/CMakeLists.txt" NO_POLICY_SCOPE)
endif ()

View File

@@ -39,8 +39,6 @@ uint32 gPickupPeepImage;
sint32 gPickupPeepX;
sint32 gPickupPeepY;
rct_drawpixelinfo *unk_140E9A8;
/**
* 12 elements from 0xF3 are the peep top colour, 12 elements from 0xCA are peep trouser colour
*

View File

@@ -269,8 +269,6 @@ extern bool gTinyFontAntiAliased;
extern rct_drawpixelinfo gScreenDPI;
extern rct_drawpixelinfo gWindowDPI;
extern rct_drawpixelinfo *unk_140E9A8;
//
bool clip_drawpixelinfo(rct_drawpixelinfo *dst, rct_drawpixelinfo *src, sint32 x, sint32 y, sint32 width, sint32 height);
void gfx_set_dirty_blocks(sint16 left, sint16 top, sint16 right, sint16 bottom);

View File

@@ -20,6 +20,7 @@
#include "../common.h"
#include "../world/map.h"
#pragma pack(push, 1)
typedef struct rct_vehicle_colour {
uint8 body_colour;
uint8 trim_colour;
@@ -75,6 +76,7 @@ typedef struct rct_ride_entry_vehicle {
sint8* peep_loading_positions; // 0x61 , 0x7B
uint16 peep_loading_positions_count;
} rct_ride_entry_vehicle;
#pragma pack(pop)
typedef struct rct_vehicle {
uint8 sprite_identifier; // 0x00

View File

@@ -4,6 +4,54 @@ if (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)
message(FATAL_ERROR "Building in-source is not supported! Create a build dir and remove ${CMAKE_SOURCE_DIR}/CMakeCache.txt")
endif ()
set(OPENRCT2_EXE "${ROOT_DIR}/openrct2.exe")
add_custom_command(
OUTPUT openrct2_text
COMMAND dd if="${OPENRCT2_EXE}" of="${CMAKE_BINARY_DIR}/openrct2_text" bs=4096 skip=1 count=1187
DEPENDS ${OPENRCT2_EXE}
)
add_custom_command(
OUTPUT openrct2_data
COMMAND dd if="${OPENRCT2_EXE}" of="${CMAKE_BINARY_DIR}/openrct2_data" bs=4096 skip=1188 count=318
COMMAND dd if=/dev/zero of="${CMAKE_BINARY_DIR}/openrct2_data" bs=4096 seek=318 count=2630 conv=notrunc
COMMAND dd if="${OPENRCT2_EXE}" of="${CMAKE_BINARY_DIR}/openrct2_data" bs=4096 skip=1506 seek=2948 count=1 conv=notrunc
DEPENDS ${OPENRCT2_EXE}
)
add_custom_target(segfiles DEPENDS openrct2_text openrct2_data)
if (NOT USE_MMAP)
set(OBJ_FORMAT "elf32-i386")
set(LINKER_SCRIPT "ld_script_i386.xc")
if (APPLE)
set(RCT2_SEGMENT_LINKER_FLAGS "-sectcreate rct2_text __text ${CMAKE_BINARY_DIR}/openrct2_text -sectcreate rct2_data __data ${CMAKE_BINARY_DIR}/openrct2_data -segaddr rct2_data 0x8a4000 -segprot rct2_data rwx rwx -segaddr rct2_text 0x401000 -segprot rct2_text rwx rwx -segaddr __TEXT 0x2000000 -read_only_relocs suppress")
else ()
# For Linux we have to use objcopy to wrap regular binaries into a linkable
# format. We use specific section names which are then referenced in a
# bespoke linker script so they can be placed at predefined VMAs.
add_custom_command(
OUTPUT openrct2_text_section.o
COMMAND objcopy --input binary --output ${OBJ_FORMAT} --binary-architecture i386 openrct2_text openrct2_text_section.o --rename-section .data=.rct2_text,contents,alloc,load,readonly,code
DEPENDS segfiles
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
add_custom_command(
OUTPUT openrct2_data_section.o
COMMAND objcopy --input binary --output ${OBJ_FORMAT} --binary-architecture i386 openrct2_data openrct2_data_section.o --rename-section .data=.rct2_data,contents,alloc,load,readonly,data
DEPENDS segfiles
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
add_custom_target(linkable_sections DEPENDS openrct2_text_section.o openrct2_data_section.o)
set_source_files_properties(
openrct2_text_section.o openrct2_data_section.o
PROPERTIES
EXTERNAL_OBJECT true
GENERATED true
)
# can't use GLOB here, as the files don't exist yet at cmake-time
set(RCT2_SECTIONS "${CMAKE_BINARY_DIR}/openrct2_data_section.o" "${CMAKE_BINARY_DIR}/openrct2_text_section.o")
set(RCT2_SEGMENT_LINKER_FLAGS "-Wl,-T,\"${ROOT_DIR}/distribution/linux/${LINKER_SCRIPT}\"")
endif ()
endif ()
set(OPENRCT2_SRCPATH "${ROOT_DIR}/src/openrct2")
file(GLOB_RECURSE ORCT2_RIDE_SOURCES "${OPENRCT2_SRCPATH}/ride/*/*.cpp")
file(GLOB_RECURSE ORCT2_RIDE_DEP_SOURCES "${OPENRCT2_SRCPATH}/ride/ride_data.c"
@@ -19,8 +67,13 @@ file(GLOB_RECURSE ORCT2_TESTPAINT_SOURCES "${CMAKE_CURRENT_LIST_DIR}/*.c"
"${CMAKE_CURRENT_LIST_DIR}/*.cpp"
"${CMAKE_CURRENT_LIST_DIR}/*.h")
# Disable optimizations for addresses.c for all compilers, to allow optimized
# builds without need for -fno-omit-frame-pointer
set_source_files_properties(${CMAKE_CURRENT_LIST_DIR}/addresses.c PROPERTIES COMPILE_FLAGS -O0)
add_executable(testpaint EXCLUDE_FROM_ALL ${ORCT2_RIDE_SOURCES} ${ORCT2_RIDE_DEP_SOURCES} ${ORCT2_TESTPAINT_SOURCES} ${RCT2_SECTIONS})
target_include_directories(testpaint PRIVATE "${ROOT_DIR}/src/")
set_target_properties(testpaint PROPERTIES COMPILE_FLAGS "-DNO_VEHICLES -D__TESTPAINT__ -Wno-unused")
set_target_properties(testpaint PROPERTIES LINK_FLAGS ${RCT2_SEGMENT_LINKER_FLAGS})
add_dependencies(testpaint segfiles)

View File

@@ -15,11 +15,11 @@
#pragma endregion
#include "hook.h"
#include "PaintIntercept.hpp"
#include "FunctionCall.hpp"
#include <openrct2/common.h>
#include <openrct2/rct2/hook.h>
#include <openrct2/interface/viewport.h>
#include <openrct2/paint/supports.h>
#include <openrct2/sprites.h>
@@ -233,7 +233,7 @@ namespace PaintIntercept {
static uint8 InterceptPaint6C(registers *regs)
{
if ((regs->ebp & 0x03) != get_current_rotation())
if ((regs->ebp & 0x03) != RCT2_CurrentRotation)
{
// Log error
log_error("Ebp is different from current rotation");
@@ -273,7 +273,7 @@ namespace PaintIntercept {
}
static uint8 InterceptPaintFull(uint8 function, registers *regs) {
if ((regs->ebp & 0x03) != get_current_rotation()) {
if ((regs->ebp & 0x03) != RCT2_CurrentRotation) {
// Log error
log_error("Ebp is different from current rotation");
}

View File

@@ -17,6 +17,7 @@
#include <algorithm>
#include <vector>
#include "hook.h"
#include "GeneralSupportHeightCall.hpp"
#include "Printer.hpp"
#include "SegmentSupportHeightCall.hpp"
@@ -27,7 +28,6 @@
#include <openrct2/paint/supports.h>
#include <openrct2/ride/TrackData.h>
#include <openrct2/interface/viewport.h>
#include <openrct2/rct2/hook.h>
namespace TestPaint
{
@@ -47,7 +47,7 @@ namespace TestPaint
rct_drawpixelinfo dpi = { 0 };
dpi.zoom_level = 1;
unk_140E9A8 = &dpi;
RCT2_GLOBAL(0x0140E9A8, rct_drawpixelinfo *) = &dpi;
gPaintSession.Unk140E9A8 = &dpi;
Ride ride = {0};
@@ -59,10 +59,18 @@ namespace TestPaint
rideEntry.vehicles[0] = vehicleEntry;
gRideList[0] = ride;
RCT2_ADDRESS(0x013628F8, Ride)[0] = ride;
gRideEntries[0] = &rideEntry;
g141E9DB = G141E9DB_FLAG_1 | G141E9DB_FLAG_2;
gPaintSession.Unk141E9DB = G141E9DB_FLAG_1 | G141E9DB_FLAG_2;
gCurrentViewportFlags = 0;
RCT2_GLOBAL(0x0141E9E4, uint32) = 0;
gScenarioTicks = 0;
RCT2_GLOBAL(0x00F663AC, uint32) = 0;
}
void ResetTunnels() {

View File

@@ -28,8 +28,32 @@ extern "C"
#include <openrct2/paint/tile_element/tile_element.h>
}
#define gRideEntries RCT2_ADDRESS(RCT2_ADDRESS_RIDE_ENTRIES, rct_ride_entry*)
#define gCurrentRotation RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8)
#include "addresses.h"
#define gRideEntries RCT2_ADDRESS(0x009ACFA4, rct_ride_entry*)
#define gSupportSegments RCT2_ADDRESS(0x0141E9B4, support_height)
#define gWoodenSupportsPrependTo RCT2_GLOBAL(0x009DEA58, paint_struct *)
#define gPaintStructs RCT2_ADDRESS(0x00EE788C, paint_entry)
#define g_currently_drawn_item RCT2_GLOBAL(0x009DE578, void*)
#define gEndOfPaintStructArray RCT2_GLOBAL(0x00EE7880, paint_entry *)
#define gPaintSpritePosition RCT2_GLOBAL(0x009DE568, LocationXY16)
#define gPaintInteractionType RCT2_GLOBAL(0x009DE570, uint8)
#define gSupportSegments RCT2_ADDRESS(0x0141E9B4, support_height)
#define gSupport RCT2_GLOBAL(0x0141E9D8, support_height)
#define gWoodenSupportsPrependTo RCT2_GLOBAL(0x009DEA58, paint_struct *)
#define gPaintMapPosition RCT2_GLOBAL(0x009DE574, LocationXY16)
#define gLeftTunnels RCT2_ADDRESS(0x009E3138, tunnel_entry)
#define gLeftTunnelCount RCT2_GLOBAL(0x0141F56A, uint8)
#define gRightTunnels RCT2_ADDRESS(0x009E30B6, tunnel_entry)
#define gRightTunnelCount RCT2_GLOBAL(0x0141F56B, uint8)
#define gVerticalTunnelHeight RCT2_GLOBAL(0x009E323C, uint8)
#define gSurfaceElement RCT2_GLOBAL(0x009E3250, rct_tile_element *)
#define gDidPassSurface RCT2_GLOBAL(0x009DE57C, bool)
#define g141E9DB RCT2_GLOBAL(0x0141E9DB, uint8)
#define gUnk141E9DC RCT2_GLOBAL(0x0141E9DC, uint16)
#define gTrackColours RCT2_ADDRESS(0x00F44198, uint32)
#define RCT2_CurrentRotation RCT2_GLOBAL(0x0141E9E0, uint8)
enum {
TEST_SUCCESS,

View File

@@ -166,6 +166,9 @@ public:
Ride *ride, rct_ride_entry *rideEntry
) override {
ride->entrance_style = variant;
Ride * rct2ride = RCT2_ADDRESS(0x013628F8, Ride);
rct2ride->entrance_style = variant;
}
};
@@ -345,6 +348,7 @@ static uint8 TestTrackElementPaintCalls(uint8 rideType, uint8 trackType, uint8 t
for (int currentRotation = 0; currentRotation < 4; currentRotation++) {
gCurrentRotation = currentRotation;
RCT2_CurrentRotation = currentRotation;
for (int direction = 0; direction < 4; direction++) {
RCT2_GLOBAL(0x009DE56A, sint16) = 64; // x
RCT2_GLOBAL(0x009DE56E, sint16) = 64; // y

View File

@@ -0,0 +1,85 @@
#pragma region Copyright (c) 2014-2017 OpenRCT2 Developers
/*****************************************************************************
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
*
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* A full copy of the GNU General Public License can be found in licence.txt
*****************************************************************************/
#pragma endregion
#include "addresses.h"
#if defined(__GNUC__)
#ifdef __clang__
#define DISABLE_OPT __attribute__((noinline,optnone))
#else
#define DISABLE_OPT __attribute__((noinline,optimize("O0")))
#endif // __clang__
#else
#define DISABLE_OPT
#endif // defined(__GNUC__)
// This variable serves a purpose of identifying a crash if it has happened inside original code.
// When switching to original code, stack frame pointer is modified and prevents breakpad from providing stack trace.
volatile sint32 _originalAddress = 0;
sint32 DISABLE_OPT RCT2_CALLPROC_X(sint32 address, sint32 _eax, sint32 _ebx, sint32 _ecx, sint32 _edx, sint32 _esi, sint32 _edi, sint32 _ebp)
{
sint32 result = 0;
_originalAddress = address;
#if defined(PLATFORM_X86) && !defined(NO_RCT2)
#ifdef _MSC_VER
__asm {
push ebp
push address
mov eax, _eax
mov ebx, _ebx
mov ecx, _ecx
mov edx, _edx
mov esi, _esi
mov edi, _edi
mov ebp, _ebp
call [esp]
lahf
pop ebp
pop ebp
/* Load result with flags */
mov result, eax
}
#else
__asm__ volatile ( "\
\n\
push %%ebx \n\
push %%ebp \n\
push %[address] \n\
mov %[eax], %%eax \n\
mov %[ebx], %%ebx \n\
mov %[ecx], %%ecx \n\
mov %[edx], %%edx \n\
mov %[esi], %%esi \n\
mov %[edi], %%edi \n\
mov %[ebp], %%ebp \n\
call *(%%esp) \n\
lahf \n\
add $4, %%esp \n\
pop %%ebp \n\
pop %%ebx \n\
/* Load result with flags */ \n\
mov %%eax, %[result] \n\
" : [address] "+m" (address), [eax] "+m" (_eax), [ebx] "+m" (_ebx), [ecx] "+m" (_ecx), [edx] "+m" (_edx), [esi] "+m" (_esi), [edi] "+m" (_edi), [ebp] "+m" (_ebp), [result] "+m" (result)
:
: "eax","ecx","edx","esi","edi","memory"
);
#endif
#endif // PLATFORM_X86
_originalAddress = 0;
// lahf only modifies ah, zero out the rest
return result & 0xFF00;
}

View File

@@ -0,0 +1,69 @@
#pragma region Copyright (c) 2014-2017 OpenRCT2 Developers
/*****************************************************************************
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
*
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* A full copy of the GNU General Public License can be found in licence.txt
*****************************************************************************/
#pragma endregion
#ifndef _ADDRESSES_H_
#define _ADDRESSES_H_
#include <openrct2/common.h>
#ifdef USE_MMAP
#if defined(PLATFORM_64BIT)
#define GOOD_PLACE_FOR_DATA_SEGMENT ((uintptr_t)0x200000000)
#elif defined(PLATFORM_32BIT)
#define GOOD_PLACE_FOR_DATA_SEGMENT ((uintptr_t)0x09000000)
#else
#error "Unknown platform"
#endif
#else
#define GOOD_PLACE_FOR_DATA_SEGMENT ((uintptr_t)0x8a4000)
#endif
#define RCT2_ADDRESS(address, type) ((type*)(GOOD_PLACE_FOR_DATA_SEGMENT - 0x8a4000 + (address)))
#define RCT2_GLOBAL(address, type) (*((type*)(GOOD_PLACE_FOR_DATA_SEGMENT - 0x8a4000 + (address))))
#define RCT2_ADDRESS_RIDE_ENTRIES 0x009ACFA4
#define RCT2_ADDRESS_CURRENT_ROTATION 0x0141E9E0
#define RCT2_ADDRESS_SPRITE_LIST 0x010E63BC
#define RCT2_ADDRESS_CURRENT_SUPPORT_SEGMENTS 0x0141E9B4
#define RCT2_ADDRESS_PAINT_BOUNDBOX_OFFSET_X 0x009DEA52
#define RCT2_ADDRESS_PAINT_BOUNDBOX_OFFSET_Y 0x009DEA54
#define RCT2_ADDRESS_PAINT_BOUNDBOX_OFFSET_Z 0x009DEA56
#ifdef __cplusplus
extern "C"
{
#endif
/**
* Returns the flags register
*
* Flags register is as follows:
* 0bSZ0A_0P0C_0000_0000
* S = Signed flag
* Z = Zero flag
* C = Carry flag
* A = Adjust flag
* P = Parity flag
* All other bits are undefined.
*/
sint32 RCT2_CALLPROC_X(sint32 address, sint32 _eax, sint32 _ebx, sint32 _ecx, sint32 _edx, sint32 _esi, sint32 _edi, sint32 _ebp);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -23,21 +23,20 @@
#include <openrct2/world/sprite.h>
#include <openrct2/paint/tile_element/tile_element.h>
#include <openrct2/ride/ride.h>
#define RCT2_ADDRESS_SPRITE_LIST 0x010E63BC
#include "addresses.h"
#define gRideEntries RCT2_ADDRESS(RCT2_ADDRESS_RIDE_ENTRIES, rct_ride_entry*)
#define gCurrentRotation RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8)
rct_tile_element *gTileElements = (rct_tile_element *) RCT2_ADDRESS_TILE_ELEMENTS;
rct_tile_element **gTileElementTilePointers = (rct_tile_element **) RCT2_ADDRESS_TILE_TILE_ELEMENT_POINTERS;
Ride *gRideList = RCT2_ADDRESS(RCT2_ADDRESS_RIDE_LIST, Ride);
#define gTileElementTilePointers RCT2_ADDRESS(0x013CE9A4, rct_tile_element*)
Ride gRideList[MAX_RIDES];
rct_sprite *sprite_list = RCT2_ADDRESS(RCT2_ADDRESS_SPRITE_LIST, rct_sprite);
sint16 gMapSizeUnits;
sint16 gMapBaseZ;
bool gTrackDesignSaveMode = false;
uint8 gTrackDesignSaveRideIndex = 255;
uint8 gClipHeight = 255;
uint32 gCurrentViewportFlags;
uint32 gScenarioTicks;
uint8 gCurrentRotation;
const LocationXY16 TileDirectionDelta[] = {
{-32, 0},

213
test/testpaint/hook.c Normal file
View File

@@ -0,0 +1,213 @@
#pragma region Copyright (c) 2014-2017 OpenRCT2 Developers
/*****************************************************************************
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
*
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* A full copy of the GNU General Public License can be found in licence.txt
*****************************************************************************/
#pragma endregion
#include <openrct2/common.h>
#ifndef NO_RCT2
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/mman.h>
#endif // _WIN32
#include "hook.h"
void* _hookTableAddress = 0;
sint32 _hookTableOffset = 0;
sint32 _maxHooks = 1000;
#define HOOK_BYTE_COUNT (140)
registers gHookRegisters = {0};
// This macro writes a little-endian 4-byte long value into *data
// It is used to avoid type punning.
#define write_address_strictalias(data, addr) \
*(data + 0) = ((addr) & 0x000000ff) >> 0; \
*(data + 1) = ((addr) & 0x0000ff00) >> 8; \
*(data + 2) = ((addr) & 0x00ff0000) >> 16; \
*(data + 3) = ((addr) & 0xff000000) >> 24;
static void hookfunc(uintptr_t address, uintptr_t hookAddress, sint32 stacksize)
{
sint32 i = 0;
uint8 data[HOOK_BYTE_COUNT] = {0};
uintptr_t registerAddress = (uintptr_t) &gHookRegisters;
data[i++] = 0x89; // mov [gHookRegisters], eax
data[i++] = (0b000 << 3) | 0b101;
write_address_strictalias(&data[i], registerAddress);
i += 4;
data[i++] = 0x89; // mov [gHookRegisters + 4], ebx
data[i++] = (0b011 << 3) | 0b101;
write_address_strictalias(&data[i], registerAddress + 4);
i += 4;
data[i++] = 0x89; // mov [gHookRegisters + 8], ecx
data[i++] = (0b001 << 3) | 0b101;
write_address_strictalias(&data[i], registerAddress + 8);
i += 4;
data[i++] = 0x89; // mov [gHookRegisters + 12], edx
data[i++] = (0b010 << 3) | 0b101;
write_address_strictalias(&data[i], registerAddress + 12);
i += 4;
data[i++] = 0x89; // mov [gHookRegisters + 16], esi
data[i++] = (0b110 << 3) | 0b101;
write_address_strictalias(&data[i], registerAddress + 16);
i += 4;
data[i++] = 0x89; // mov [gHookRegisters + 20], edi
data[i++] = (0b111 << 3) | 0b101;
write_address_strictalias(&data[i], registerAddress + 20);
i += 4;
data[i++] = 0x89; // mov [gHookRegisters + 24], ebp
data[i++] = (0b101 << 3) | 0b101;
write_address_strictalias(&data[i], registerAddress + 24);
i += 4;
// work out distance to nearest 0xC
// (esp - numargs * 4) & 0xC
// move to align - 4
// save that amount
// push the registers to be on the stack to access as arguments
data[i++] = 0x68; // push gHookRegisters
write_address_strictalias(&data[i], registerAddress);
i += 4;
data[i++] = 0xE8; // call
write_address_strictalias(&data[i], hookAddress - address - i - 4);
i += 4;
data[i++] = 0x83; // add esp, 4
data[i++] = 0xC4;
data[i++] = 0x04;
data[i++] = 0x25; // and eax,0xff
data[i++] = 0xff;
data[i++] = 0x00;
data[i++] = 0x00;
data[i++] = 0x00;
data[i++] = 0xc1; // shl eax, 8
data[i++] = 0xe0;
data[i++] = 0x08;
data[i++] = 0x9e; // sahf
data[i++] = 0x9c; // pushf
data[i++] = 0x8B; // mov eax, [gHookRegisters]
data[i++] = (0b000 << 3) | 0b101;
write_address_strictalias(&data[i], registerAddress);
i += 4;
data[i++] = 0x8B; // mov ebx, [gHookRegisters + 4]
data[i++] = (0b011 << 3) | 0b101;
write_address_strictalias(&data[i], registerAddress + 4);
i += 4;
data[i++] = 0x8B; // mov ecx, [gHookRegisters + 8]
data[i++] = (0b001 << 3) | 0b101;
write_address_strictalias(&data[i], registerAddress + 8);
i += 4;
data[i++] = 0x8B; // mov edx, [gHookRegisters + 12]
data[i++] = (0b010 << 3) | 0b101;
write_address_strictalias(&data[i], registerAddress + 12);
i += 4;
data[i++] = 0x8B; // mov esi, [gHookRegisters + 16]
data[i++] = (0b110 << 3) | 0b101;
write_address_strictalias(&data[i], registerAddress + 16);
i += 4;
data[i++] = 0x8B; // mov edi, [gHookRegisters + 20]
data[i++] = (0b111 << 3) | 0b101;
write_address_strictalias(&data[i], registerAddress + 20);
i += 4;
data[i++] = 0x8B; // mov ebp, [gHookRegisters + 24]
data[i++] = (0b101 << 3) | 0b101;
write_address_strictalias(&data[i], registerAddress + 24);
i += 4;
data[i++] = 0x9d; // popf
data[i++] = 0xC3; // retn
#ifdef _WIN32
WriteProcessMemory(GetCurrentProcess(), (LPVOID)address, data, i, 0);
#else
// We own the pages with PROT_WRITE | PROT_EXEC, we can simply just memcpy the data
memcpy((void *)address, data, i);
#endif // _WIN32
}
void addhook(uintptr_t address, hook_function *function)
{
if (!_hookTableAddress) {
size_t size = _maxHooks * HOOK_BYTE_COUNT;
#ifdef _WIN32
_hookTableAddress = VirtualAllocEx(GetCurrentProcess(), NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
#else
_hookTableAddress = mmap(NULL, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (_hookTableAddress == MAP_FAILED)
{
perror("mmap");
exit(1);
}
#endif // _WIN32
}
if (_hookTableOffset > _maxHooks) {
return;
}
uint32 hookaddress = (uint32)_hookTableAddress + (_hookTableOffset * HOOK_BYTE_COUNT);
uint8 data[9];
sint32 i = 0;
data[i++] = 0xE9; // jmp
write_address_strictalias(&data[i], hookaddress - address - i - 4);
i += 4;
data[i++] = 0xC3; // retn
#ifdef _WIN32
WriteProcessMemory(GetCurrentProcess(), (LPVOID)address, data, i, 0);
#else
// We own the pages with PROT_WRITE | PROT_EXEC, we can simply just memcpy the data
sint32 err = mprotect((void *)0x401000, 0x8a4000 - 0x401000, PROT_READ | PROT_WRITE);
if (err != 0)
{
perror("mprotect");
}
memcpy((void *)address, data, i);
err = mprotect((void *)0x401000, 0x8a4000 - 0x401000, PROT_READ | PROT_EXEC);
if (err != 0)
{
perror("mprotect");
}
#endif // _WIN32
hookfunc(hookaddress, (uintptr_t)function, 0);
_hookTableOffset++;
}
#endif

48
test/testpaint/hook.h Normal file
View File

@@ -0,0 +1,48 @@
#pragma region Copyright (c) 2014-2017 OpenRCT2 Developers
/*****************************************************************************
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
*
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* A full copy of the GNU General Public License can be found in licence.txt
*****************************************************************************/
#pragma endregion
#ifndef _HOOK_H_
#define _HOOK_H_
#ifndef NO_RCT2
#include <openrct2/common.h>
enum {
X86_FLAG_CARRY = 1 << 0,
X86_FLAG_PARITY = 1 << 2,
X86_FLAG_ADJUST = 1 << 4,
X86_FLAG_ZERO = 1 << 6,
X86_FLAG_SIGN = 1 << 7,
};
typedef uint8 (hook_function)(registers *regs);
#ifdef __cplusplus
extern "C" {
#endif
void addhook(uintptr_t address, hook_function *function);
#ifdef __cplusplus
}
#endif
#endif
#endif