Skip to content
This repository was archived by the owner on Apr 10, 2021. It is now read-only.

Commit 81a616d

Browse files
Huge update, disassembler, inlinizer, granular profiler, other stuff
1 parent a844fa6 commit 81a616d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1874
-15
lines changed

byond-extools/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ source_group(TREE ${SRC_DIR} FILES ${SRC_FILES})
2525
#source_group("tffi" FILES ${TFFI})
2626
if (WIN32)
2727
set_property(TARGET byond-extools PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
28+
target_compile_options(byond-extools PRIVATE "/MP")
2829
target_include_directories(byond-extools PUBLIC src/polyhook)
2930
target_link_directories(byond-extools PUBLIC src/polyhook)
3031
target_link_libraries(byond-extools asmjit)

byond-extools/src/core/byond_structures.h

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#pragma once
22

3+
#define FLAG_PROFILE 0x10000
4+
35
struct String
46
{
57
char* stringData;
@@ -8,6 +10,16 @@ struct String
810
unsigned int refcount;
911
};
1012

13+
struct trvh //temporary return value holder, used for sidestepping the fact that structs with constructors are passed in memory and not in eax/ecx when returning them
14+
{
15+
char type;
16+
union
17+
{
18+
int value;
19+
float valuef;
20+
};
21+
};
22+
1123
struct Value
1224
{
1325
char type;
@@ -16,6 +28,20 @@ struct Value
1628
int value;
1729
float valuef;
1830
};
31+
32+
Value(char type, int value) : type(type), value(value) {};
33+
Value(char type, float valuef) : type(type), valuef(valuef) {};
34+
Value(trvh trvh)
35+
{
36+
type = trvh.type;
37+
if (type == 0x2A)
38+
value = trvh.value;
39+
else
40+
valuef = trvh.valuef;
41+
}
42+
inline static Value Null() {
43+
return { 0 ,0 };
44+
}
1945
};
2046

2147
struct IDArrayEntry
@@ -120,4 +146,29 @@ struct ProcSetupEntry
120146
};
121147
int* bytecode;
122148
int unknown;
149+
};
150+
151+
struct ProfileEntry
152+
{
153+
unsigned int seconds;
154+
unsigned int microseconds;
155+
156+
unsigned long long as_microseconds()
157+
{
158+
return 1000000 * (unsigned long long)seconds + microseconds;
159+
}
160+
double as_seconds()
161+
{
162+
return (double)seconds + microseconds / 1000000;
163+
}
164+
};
165+
166+
struct ProfileInfo
167+
{
168+
unsigned int call_count;
169+
ProfileEntry real;
170+
ProfileEntry total;
171+
ProfileEntry self;
172+
ProfileEntry overtime;
173+
unsigned int proc_id;
123174
};

byond-extools/src/core/core.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "find_functions.h"
33
#include "../tffi/tffi.h"
44
#include "../proxy/proxy_object.h"
5+
#include "../optimizer/optimizer.h"
56

67
CrashProcPtr CrashProc;
78
SuspendPtr Suspend;
@@ -11,10 +12,15 @@ GetVariablePtr GetVariable;
1112
GetStringTableIndexPtr GetStringTableIndex;
1213
GetProcArrayEntryPtr GetProcArrayEntry;
1314
GetStringTableEntryPtr GetStringTableEntry;
15+
CallGlobalProcPtr CallGlobalProc;
16+
GetProfileInfoPtr GetProfileInfo;
1417

1518
ExecutionContext** Core::current_execution_context_ptr;
19+
ExecutionContext** Core::parent_context_ptr_hack;
1620
ProcSetupEntry** Core::proc_setup_table;
1721

22+
unsigned int* Core::some_flags_including_profile;
23+
1824
std::map<unsigned int, opcode_handler> Core::opcode_handlers;
1925
std::map<std::string, unsigned int> Core::name_to_opcode;
2026
unsigned int next_opcode_id = 0x1337;
@@ -46,16 +52,66 @@ unsigned int Core::register_opcode(std::string name, opcode_handler handler)
4652
return next_opcode;
4753
}
4854

55+
ExecutionContext* Core::get_context()
56+
{
57+
return *current_execution_context_ptr;
58+
}
59+
60+
ExecutionContext* Core::_get_parent_context()
61+
{
62+
return *parent_context_ptr_hack;
63+
}
64+
65+
Value Core::get_stack_value(unsigned int which)
66+
{
67+
return (*Core::current_execution_context_ptr)->stack[(*Core::current_execution_context_ptr)->stack_size - which - 1];
68+
}
69+
70+
void Core::stack_pop(unsigned int how_many)
71+
{
72+
(*Core::current_execution_context_ptr)->stack_size -= how_many;
73+
}
74+
75+
void Core::stack_push(Value val)
76+
{
77+
(*Core::current_execution_context_ptr)->stack_size++;
78+
(*Core::current_execution_context_ptr)->stack[(*Core::current_execution_context_ptr)->stack_size-1] = val;
79+
}
80+
81+
void Core::enable_profiling()
82+
{
83+
*some_flags_including_profile |= FLAG_PROFILE;
84+
}
85+
86+
void Core::disable_profiling()
87+
{
88+
*some_flags_including_profile &= ~FLAG_PROFILE;
89+
}
90+
91+
4992
const char* good = "gucci";
5093
const char* bad = "pain";
5194

95+
extern "C" EXPORT const char* enable_profiling(int n_args, const char* args)
96+
{
97+
Core::enable_profiling();
98+
return good;
99+
}
100+
101+
extern "C" EXPORT const char* disable_profiling(int n_args, const char* args)
102+
{
103+
Core::disable_profiling();
104+
return good;
105+
}
106+
52107
extern "C" EXPORT const char* core_initialize(int n_args, const char* args)
53108
{
54109
if (!Core::initialize())
55110
{
56111
Core::Alert("Core init failed!");
57112
return bad;
58113
}
114+
optimizer_initialize();
59115
return good;
60116
}
61117

@@ -71,4 +127,13 @@ extern "C" EXPORT const char* proxy_initialize(int n_args, const char* args)
71127
if (!(Core::initialize() && Proxy::initialize()))
72128
return bad;
73129
return good;
130+
}
131+
132+
void init_testing();
133+
void run_tests();
134+
extern "C" EXPORT const char* run_tests(int n_args, const char* args)
135+
{
136+
init_testing();
137+
run_tests();
138+
return good;
74139
}

byond-extools/src/core/core.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,18 @@ namespace Core
2121
extern std::map<unsigned int, opcode_handler> opcode_handlers;
2222
extern std::map<std::string, unsigned int> name_to_opcode;
2323
extern ExecutionContext** current_execution_context_ptr;
24+
extern ExecutionContext** parent_context_ptr_hack;
2425
extern ProcSetupEntry** proc_setup_table;
26+
extern unsigned int* some_flags_including_profile;
27+
ExecutionContext* get_context();
28+
ExecutionContext* _get_parent_context();
2529
unsigned int register_opcode(std::string name, opcode_handler handler);
2630
void Alert(const char* what);
2731
bool initialize();
2832
extern bool initialized;
33+
Value get_stack_value(unsigned int which);
34+
void stack_pop(unsigned int how_many);
35+
void stack_push(Value val);
36+
void enable_profiling();
37+
void disable_profiling();
2938
}

byond-extools/src/core/find_functions.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,12 @@ bool Core::find_functions()
1919
FIND_OR_DIE(GetStringTableIndex, "55 8B EC 8B 45 08 83 EC 18 53 8B 1D ?? ?? ?? ?? 56 57 85 C0 75 ?? 68 ?? ?? ?? ?? FF D3 83 C4 04 C6 45 10 00 80 7D 0C 00 89 45 E8 74 ?? 8D 45 10 50 8D 45 E8 50");
2020
FIND_OR_DIE(GetProcArrayEntry, "55 8B EC 8B 45 08 3B 05 ?? ?? ?? ?? 72 04 33 C0 5D C3 8D 0C C0 A1 ?? ?? ?? ?? 8D 04 88 5D C3");
2121
FIND_OR_DIE(GetStringTableEntry, "55 8B EC 8B 4D 08 3B 0D ?? ?? ?? ?? 73 10 A1");
22+
FIND_OR_DIE(CallGlobalProc, "55 8B EC 81 EC 98 00 00 00 A1 ?? ?? ?? ?? 33 C5 89 45 FC 8B 55 14 8B 45 30 89 85 6C FF FF FF 53 8B 5D 24 56 8B 75 2C 57 8B 7D 28 81 FA FF FF 00 00 75 ?? 0F 57 C0 66 0F 13 85 68 FF FF FF 8B BD 6C FF FF FF 8B 9D 68 FF FF FF 85 F6");
23+
FIND_OR_DIE(GetProfileInfo, "55 8B EC A1 ?? ?? ?? ?? 56 8B 75 08 3B F0 73 30 8B ?? ?? ?? ?? ?? 85 C9 75 36 8D 04 80 C1 E0 03 50 FF 15 ?? ?? ?? ?? 83 C4 04 A3 ?? ?? ?? ?? 85 C0 75 12 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 83 C4 04 33 C0 5E 5D C3 E8 ?? ?? ?? ?? 8B ?? ?? ?? ?? ?? 8D 04 B6 8D 04 C1 5E 5D C3");
2224
current_execution_context_ptr = *(ExecutionContext * **)Pocket::Sigscan::FindPattern(BYONDCORE, "A1 ?? ?? ?? ?? 8D ?? ?? ?? ?? ?? 83 C4 08 89 48 28 8D ?? ?? ?? ?? ?? 89 48 2C 83 3D ?? ?? ?? ?? ?? 74 25 8B 00 FF 30 E8 ?? ?? ?? ?? 83 C4 04 FF 30 E8 ?? ?? ?? ?? 83 C4 04 FF 30 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 83 C4 08 66 ?? ?? ?? ?? ?? ?? A1 ?? ?? ?? ?? 75 28 A8 02 75 24 E8 ?? ?? ?? ?? 85 C0 75 09 50", 1);
2325
proc_setup_table = **(ProcSetupEntry * ***)Pocket::Sigscan::FindPattern(BYONDCORE, "A1 ?? ?? ?? ?? FF 34 B8 FF D6 47 83 C4 04 3B ?? ?? ?? ?? ?? 72 EA FF 35 ?? ?? ?? ?? FF D6 33 FF 83 C4 04 39 ?? ?? ?? ?? ?? 76 1E", 1);
26+
some_flags_including_profile = *(unsigned int**)Pocket::Sigscan::FindPattern(BYONDCORE, "F7 05 ?? ?? ?? ?? ?? ?? ?? ?? 74 34 8B 01 FF 30 E8 ?? ?? ?? ?? 83 C4 04 8B D8 E8 ?? ?? ?? ?? 8B F0 8B FA E8 ?? ?? ?? ?? 85 DB 74 02 FF 03 8B ?? ?? ?? ?? ?? 89 71 70 89 79 74 89 41 78 89 51 7C 83 3D ?? ?? ?? ?? ?? 5B 74 37", 2);
27+
parent_context_ptr_hack = *(ExecutionContext***)Pocket::Sigscan::FindPattern(BYONDCORE, "A1 ?? ?? ?? ?? 89 46 04 8B 45 E0 89 77 18 89 3E 89 ?? ?? ?? ?? ?? FF 70 18 E8 ?? ?? ?? ?? 8B ?? ?? ?? ?? ?? 83 C4 10 8B 40 04 89 41 10 C7 41 ?? ?? ?? ?? ?? F6 47 04 08 8B 77 2C 89 75 F8 0F 84 ?? ?? ?? ?? 8B 06", 1);
2428
#else
2529
FIND_OR_DIE(CrashProc, "55 89 E5 53 83 EC ?? 80 3D ?? ?? ?? ?? ?? 75 ?? C7 04 24 ?? ?? ?? ?? E8 ?? ?? ?? ?? 85 C0 75 ?? C7 04 24 ?? ?? ?? ?? 8D 5D ?? E8 ?? ?? ?? ?? 8B 45 ?? 89 5C 24 ?? C7 04 24 ?? ?? ?? ?? 89 44 24 ?? E8 ?? ?? ?? ?? C7 04 24 ?? ?? ?? ??");
2630
FIND_OR_DIE(Suspend, "55 89 E5 57 31 FF 56 89 C6 53 83 EC ?? 89 F0"); //regparm3

byond-extools/src/core/hooking.cpp

Lines changed: 136 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,145 @@
11
#include "hooking.h"
2+
#include "../tffi/tffi.h"
3+
#include <chrono>
4+
#include <fstream>
5+
#include "json.hpp"
6+
#include <stack>
27

38
#ifdef _WIN32
49
static PLH::CapstoneDisassembler* disassembler;
510
#else
611
urmem::hook CrashProcDetour;
712
#endif
813
CrashProcPtr oCrashProc;
14+
CallGlobalProcPtr oCallGlobalProc;
15+
16+
#define TOMICROS(x) std::chrono::duration_cast<std::chrono::microseconds>(x).count()
17+
18+
struct ExtendedProfile
19+
{
20+
unsigned int proc_id;
21+
int* bytecode; //facilitate faster searches up the call stack
22+
std::vector<ExtendedProfile*> subcalls;
23+
std::chrono::time_point<std::chrono::steady_clock> start_time;
24+
std::chrono::time_point<std::chrono::steady_clock> end_time;
25+
unsigned long long total_time = 0;
26+
int call_id = 0;
27+
};
28+
29+
ExtendedProfile* proc_being_profiled;
30+
ExtendedProfile* profile_result;
31+
std::stack<ExtendedProfile*> call_stack;
32+
33+
void output_subcalls(std::string base, std::ofstream& output, ExtendedProfile* profile, int depth)
34+
{
35+
base += Core::get_proc(profile->proc_id).name+";";
36+
//Core::Alert(base.c_str());
37+
if (!(profile->subcalls.empty()))
38+
{
39+
output << base << "self " << TOMICROS(profile->subcalls.back()->start_time - profile->start_time) << "\n";
40+
for (ExtendedProfile* sub : profile->subcalls)
41+
{
42+
output_subcalls(base, output, sub, ++depth);
43+
}
44+
ExtendedProfile* last_sub = profile->subcalls.back();
45+
output << base << "self " << TOMICROS(profile_result->end_time - last_sub->end_time) << "\n";
46+
}
47+
else
48+
{
49+
base.pop_back();
50+
output << base << " "<< TOMICROS(profile->end_time - profile->start_time) << "\n";
51+
}
52+
}
53+
54+
void dump_extended_profile()
55+
{
56+
/*nlohmann::json result;
57+
result["version"] = "0.0.1";
58+
result["$schema"] = "https://www.speedscope.app/file-format-schema.json";
59+
result["name"] = Core::get_proc(profile_result->proc_id).name;
60+
result["activeProfileIndex"] = 1;
61+
62+
nlohmann::json shared;
63+
std::vector<std::pair<std::string, std::string>> frames;
64+
frames.push_back({ "name", "self" });
65+
frames.push_back({"name", Core::get_proc(profile_result->proc_id).name });
66+
for (ExtendedProfile* sub : profile_result->subcalls)
67+
{
68+
frames.push_back({ "name", Core::get_proc(sub->proc_id).name });
69+
}
70+
shared["frames"] = frames;
71+
result["shared"] = shared;
72+
73+
nlohmann::json profile;
74+
profile["type"] = "sampled";
75+
profile["name"] = Core::get_proc(profile_result->proc_id).name;
76+
profile["unit"] = "microseconds";
77+
profile["startValue"] = 0;
78+
profile["endValue"] = profile_result->total_time;
79+
80+
81+
std::ofstream output("extended_profile.txt");
82+
output << result.dump();*/
83+
std::ofstream output("extended_profile.txt");
84+
output_subcalls("", output, profile_result, 0);
85+
output.flush();
86+
}
87+
88+
trvh __cdecl hCallGlobalProc(char unk1, int unk2, int proc_type, unsigned int proc_id, int const_0, char unk3, int unk4, Value* argList, unsigned int argListLen, int const_0_2, int const_0_3)
89+
{
90+
int call_id = 0;
91+
if (extended_profiling_procs.find(proc_id) != extended_profiling_procs.end())
92+
{
93+
proc_being_profiled = new ExtendedProfile();
94+
proc_being_profiled->proc_id = proc_id;
95+
proc_being_profiled->bytecode = Core::get_context()->bytecode;
96+
proc_being_profiled->start_time = std::chrono::high_resolution_clock::now();
97+
call_stack.push(proc_being_profiled);
98+
}
99+
if (proc_being_profiled && proc_being_profiled->proc_id != proc_id)
100+
{
101+
call_id = rand();
102+
ExecutionContext* parent_ctx = Core::_get_parent_context();
103+
if (call_stack.top()->proc_id == Core::get_proc(parent_ctx->bytecode).id)
104+
{
105+
ExtendedProfile* subcall = new ExtendedProfile();
106+
subcall->proc_id = proc_id;
107+
subcall->bytecode = Core::get_proc(proc_id).get_bytecode();
108+
subcall->start_time = std::chrono::high_resolution_clock::now();
109+
subcall->call_id = call_id;
110+
call_stack.top()->subcalls.push_back(subcall);
111+
call_stack.push(subcall);
112+
}
113+
}
114+
if (proc_hooks.find(proc_id) != proc_hooks.end())
115+
{
116+
trvh result = proc_hooks[proc_id](argList, argListLen);
117+
Core::Alert("hook");
118+
return result;
119+
}
120+
trvh result = oCallGlobalProc(unk1, unk2, proc_type, proc_id, const_0, unk3, unk4, argList, argListLen, const_0_2, const_0_3);
121+
if (proc_being_profiled)
122+
{
123+
ExtendedProfile* top = call_stack.top();
124+
if (top->proc_id == proc_id)
125+
{
126+
ExtendedProfile* sub = call_stack.top();
127+
sub->end_time = std::chrono::high_resolution_clock::now();
128+
call_stack.pop();
129+
sub->total_time = std::chrono::duration_cast<std::chrono::microseconds>(sub->end_time - sub->start_time).count();
130+
}
131+
if (proc_being_profiled->proc_id == proc_id)
132+
{
133+
proc_being_profiled->end_time = std::chrono::high_resolution_clock::now();
134+
proc_being_profiled->total_time = std::chrono::duration_cast<std::chrono::microseconds>(proc_being_profiled->end_time - proc_being_profiled->start_time).count();
135+
profile_result = proc_being_profiled;
136+
proc_being_profiled = nullptr;
137+
dump_extended_profile();
138+
//Core::Alert("Extended profile results written to file");
139+
}
140+
}
141+
return result;
142+
}
9143

10144
void hCrashProc(char* error, int argument)
11145
{
@@ -59,7 +193,8 @@ bool Core::hook_custom_opcodes()
59193
{
60194
#ifdef _WIN32
61195
oCrashProc = (CrashProcPtr)install_hook(CrashProc, hCrashProc);
62-
return oCrashProc;
196+
oCallGlobalProc = (CallGlobalProcPtr)install_hook(CallGlobalProc, hCallGlobalProc);
197+
return oCrashProc && oCallGlobalProc;
63198
#else
64199
CrashProcDetour = (CrashProcDetour)install_hook(CrashProc, hCrashProc);
65200
return CrashProcDetour;

byond-extools/src/core/hooking.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include "internal_functions.h"
44
#include "core.h"
5+
#include "proc_management.h"
56
#ifdef _WIN32
67
#include <headers/CapstoneDisassembler.hpp>
78
#include <headers/Detour/x86Detour.hpp>

0 commit comments

Comments
 (0)