Probe GPS async route worker

This commit is contained in:
2026-06-20 14:43:13 -05:00
parent cfedbeddf9
commit 0891a6265a
+386
View File
@@ -150,6 +150,12 @@ constexpr uintptr_t kGpsQuerySubmitRva = 0x070A42C;
constexpr uintptr_t kGpsQueryDispatchRva = 0x070A570; constexpr uintptr_t kGpsQueryDispatchRva = 0x070A570;
constexpr uintptr_t kGpsQueryResultFetchRva = 0x07094B8; constexpr uintptr_t kGpsQueryResultFetchRva = 0x07094B8;
constexpr uintptr_t kGpsQueryStatusRva = 0x0AA5704; constexpr uintptr_t kGpsQueryStatusRva = 0x0AA5704;
constexpr uintptr_t kGpsDispatchAdvanceRva = 0x08D17D8;
constexpr uintptr_t kGpsAsyncWorkerTickRva = 0x0126B28;
constexpr uintptr_t kGpsRouteJobStartRva = 0x0818928;
constexpr uintptr_t kGpsRouteJobPollRva = 0x0883CD8;
constexpr uintptr_t kGpsRouteFinishRva = 0x11F5F60;
constexpr uintptr_t kGpsRouteJobBuildRva = 0x0818BA8;
constexpr uintptr_t kGpsRouteProducerRva = 0x044CC7C; constexpr uintptr_t kGpsRouteProducerRva = 0x044CC7C;
constexpr uintptr_t kGpsSearchRva = 0x044F054; constexpr uintptr_t kGpsSearchRva = 0x044F054;
constexpr uintptr_t kGpsEdgeCostRva = 0x044F838; constexpr uintptr_t kGpsEdgeCostRva = 0x044F838;
@@ -213,11 +219,18 @@ uint32_t gGpsQuerySubmitLogCount = 0;
uint32_t gGpsQueryDispatchLogCount = 0; uint32_t gGpsQueryDispatchLogCount = 0;
uint32_t gGpsQueryResultFetchLogCount = 0; uint32_t gGpsQueryResultFetchLogCount = 0;
uint32_t gGpsQueryStatusLogCount = 0; uint32_t gGpsQueryStatusLogCount = 0;
uint32_t gGpsDispatchAdvanceLogCount = 0;
uint32_t gGpsAsyncWorkerTickLogCount = 0;
uint32_t gGpsRouteJobStartLogCount = 0;
uint32_t gGpsRouteJobPollLogCount = 0;
uint32_t gGpsRouteFinishLogCount = 0;
uint32_t gGpsRouteJobBuildLogCount = 0;
uint32_t gGpsRouteProducerLogCount = 0; uint32_t gGpsRouteProducerLogCount = 0;
uint32_t gGpsSearchLogCount = 0; uint32_t gGpsSearchLogCount = 0;
uint32_t gGpsEdgeCostLogCount = 0; uint32_t gGpsEdgeCostLogCount = 0;
std::array<uint32_t, 64> gGpsEdgeCostClassLogCounts{}; std::array<uint32_t, 64> gGpsEdgeCostClassLogCounts{};
std::mutex gGpsCostLogMutex; std::mutex gGpsCostLogMutex;
std::mutex gGpsAsyncLogMutex;
uint64_t gLogStartTick = 0; uint64_t gLogStartTick = 0;
uint64_t gLogFrequency = 0; uint64_t gLogFrequency = 0;
void* gMappinSetTrackedTarget = nullptr; void* gMappinSetTrackedTarget = nullptr;
@@ -312,6 +325,13 @@ using GpsQuerySubmitFunc = int32_t (*)(void* aManager, void* aQuery);
using GpsQueryDispatchFunc = void (*)(void* aRuntimeQuery, void* aTargetPosition, void* aArg3, void* aArg4); using GpsQueryDispatchFunc = void (*)(void* aRuntimeQuery, void* aTargetPosition, void* aArg3, void* aArg4);
using GpsQueryResultFetchFunc = bool (*)(void* aManager, uint32_t aQueryId, void* aOutPath); using GpsQueryResultFetchFunc = bool (*)(void* aManager, uint32_t aQueryId, void* aOutPath);
using GpsQueryStatusFunc = int32_t (*)(void* aManager, uint32_t aQueryId); using GpsQueryStatusFunc = int32_t (*)(void* aManager, uint32_t aQueryId);
using GpsDispatchAdvanceFunc = void (*)(void* aRouteSystem, void* aRuntimeQuery, void* aOutTicket,
void* aTargetPosition, void* aSourcePosition);
using GpsAsyncWorkerTickFunc = void (*)(void* aRouteSystem);
using GpsRouteJobStartFunc = bool (*)(void* aRouteSystem, void* aActiveEntry, float aDelta, void* aOutLocal);
using GpsRouteJobPollFunc = bool (*)(void* aRouteSystem, void* aActiveEntry);
using GpsRouteFinishFunc = void* (*)(void* aResultQueue, void* aOutEntry, void* aActiveEntry, void* aLocalResult);
using GpsRouteJobBuildFunc = void* (*)(void* aJob, void* aOut, void* aRequest);
using GpsRouteProducerFunc = int32_t (*)(void* aGraph, void* aQuery, void* aOutResult); using GpsRouteProducerFunc = int32_t (*)(void* aGraph, void* aQuery, void* aOutResult);
using GpsSearchFunc = int32_t (*)(void* aGraph, uint64_t aStartHandle, uint64_t aTargetHandle, void* aStartPoint, using GpsSearchFunc = int32_t (*)(void* aGraph, uint64_t aStartHandle, uint64_t aTargetHandle, void* aStartPoint,
void* aTargetPoint, void* aCostProvider, void* aOutPath, uint32_t* aOutCount); void* aTargetPoint, void* aCostProvider, void* aOutPath, uint32_t* aOutCount);
@@ -370,6 +390,12 @@ GpsQuerySubmitFunc gOriginalGpsQuerySubmit = nullptr;
GpsQueryDispatchFunc gOriginalGpsQueryDispatch = nullptr; GpsQueryDispatchFunc gOriginalGpsQueryDispatch = nullptr;
GpsQueryResultFetchFunc gOriginalGpsQueryResultFetch = nullptr; GpsQueryResultFetchFunc gOriginalGpsQueryResultFetch = nullptr;
GpsQueryStatusFunc gOriginalGpsQueryStatus = nullptr; GpsQueryStatusFunc gOriginalGpsQueryStatus = nullptr;
GpsDispatchAdvanceFunc gOriginalGpsDispatchAdvance = nullptr;
GpsAsyncWorkerTickFunc gOriginalGpsAsyncWorkerTick = nullptr;
GpsRouteJobStartFunc gOriginalGpsRouteJobStart = nullptr;
GpsRouteJobPollFunc gOriginalGpsRouteJobPoll = nullptr;
GpsRouteFinishFunc gOriginalGpsRouteFinish = nullptr;
GpsRouteJobBuildFunc gOriginalGpsRouteJobBuild = nullptr;
GpsRouteProducerFunc gOriginalGpsRouteProducer = nullptr; GpsRouteProducerFunc gOriginalGpsRouteProducer = nullptr;
GpsSearchFunc gOriginalGpsSearch = nullptr; GpsSearchFunc gOriginalGpsSearch = nullptr;
GpsEdgeCostFunc gOriginalGpsEdgeCost = nullptr; GpsEdgeCostFunc gOriginalGpsEdgeCost = nullptr;
@@ -1414,6 +1440,138 @@ void AppendGpsResultObjectSummary(std::ostringstream& aLine, const char* aPrefix
AppendUint64Field(aLine, (std::string(aPrefix) + "_u50").c_str(), aResultObject, 0x50); AppendUint64Field(aLine, (std::string(aPrefix) + "_u50").c_str(), aResultObject, 0x50);
} }
uint32_t NextGpsAsyncLogCall(uint32_t& aCounter)
{
std::lock_guard lock(gGpsAsyncLogMutex);
return aCounter++;
}
bool TryReadUint32FieldValue(void* aObject, uintptr_t aOffset, uint32_t& aValue)
{
return aObject && TryReadMemory(reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(aObject) + aOffset),
aValue);
}
void AppendRouteJobSummary(std::ostringstream& aLine, const char* aPrefix, void* aJob)
{
const auto prefix = std::string(aPrefix);
AppendPointerWithRva(aLine, prefix.c_str(), aJob);
if (!aJob)
{
return;
}
AppendUint32Field(aLine, (prefix + "_type10").c_str(), aJob, 0x10);
AppendPointerField(aLine, (prefix + "_result18").c_str(), aJob, 0x18);
AppendPointerField(aLine, (prefix + "_result30").c_str(), aJob, 0x30);
AppendUint32Field(aLine, (prefix + "_u4c").c_str(), aJob, 0x4C);
AppendUint32Field(aLine, (prefix + "_count50").c_str(), aJob, 0x50);
AppendUint32Field(aLine, (prefix + "_retry54").c_str(), aJob, 0x54);
AppendUint32Field(aLine, (prefix + "_flagsc0").c_str(), aJob, 0xC0);
AppendUint32Field(aLine, (prefix + "_statec4").c_str(), aJob, 0xC4);
AppendPointerField(aLine, (prefix + "_chunkse0").c_str(), aJob, 0xE0);
AppendUint32Field(aLine, (prefix + "_chunks_cap_e8").c_str(), aJob, 0xE8);
AppendUint32Field(aLine, (prefix + "_chunks_count_ec").c_str(), aJob, 0xEC);
AppendPointerField(aLine, (prefix + "_nodesf8").c_str(), aJob, 0xF8);
}
void AppendRouteSystemSummary(std::ostringstream& aLine, const char* aPrefix, void* aRouteSystem)
{
const auto prefix = std::string(aPrefix);
AppendPointerWithRva(aLine, prefix.c_str(), aRouteSystem);
if (!aRouteSystem)
{
return;
}
AppendUint32Field(aLine, (prefix + "_queued8fc0").c_str(), aRouteSystem, 0x8FC0);
AppendUint32Field(aLine, (prefix + "_active8fd0").c_str(), aRouteSystem, 0x8FD0);
AppendPointerField(aLine, (prefix + "_job90d0").c_str(), aRouteSystem, 0x90D0);
auto* job = ReadPointerField(aRouteSystem, 0x90D0);
if (!job)
{
return;
}
AppendRouteJobSummary(aLine, (prefix + "_job").c_str(), job);
}
bool HasPendingRouteWork(void* aRouteSystem)
{
uint32_t queued = 0;
uint32_t active = 0;
TryReadUint32FieldValue(aRouteSystem, 0x8FC0, queued);
TryReadUint32FieldValue(aRouteSystem, 0x8FD0, active);
return queued != 0 || active != 0 || ReadPointerField(aRouteSystem, 0x90D0) != nullptr;
}
void AppendRouteRequestFields(std::ostringstream& aLine, const char* aPrefix, void* aObject, uintptr_t aOffset)
{
const auto prefix = std::string(aPrefix);
auto* base = aObject ? reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(aObject) + aOffset) : nullptr;
AppendPointerWithRva(aLine, prefix.c_str(), base);
if (!base)
{
return;
}
AppendBytesPointer(aLine, (prefix + "_raw40").c_str(), base, 0x40);
AppendVector4Field(aLine, (prefix + "_vec00").c_str(), base, 0x00);
AppendVector4Field(aLine, (prefix + "_vec10").c_str(), base, 0x10);
AppendUint32Field(aLine, (prefix + "_u00").c_str(), base, 0x00);
AppendUint32Field(aLine, (prefix + "_u08").c_str(), base, 0x08);
AppendUint32Field(aLine, (prefix + "_u1c").c_str(), base, 0x1C);
AppendUint16Field(aLine, (prefix + "_u1e").c_str(), base, 0x1E);
AppendUint32Field(aLine, (prefix + "_u20").c_str(), base, 0x20);
AppendUint16Field(aLine, (prefix + "_u20w").c_str(), base, 0x20);
AppendUint16Field(aLine, (prefix + "_u24").c_str(), base, 0x24);
AppendUint16Field(aLine, (prefix + "_u26").c_str(), base, 0x26);
AppendUint16Field(aLine, (prefix + "_u28").c_str(), base, 0x28);
AppendUint32Field(aLine, (prefix + "_u70").c_str(), base, 0x70);
AppendByteField(aLine, (prefix + "_b74").c_str(), base, 0x74);
AppendByteField(aLine, (prefix + "_b75").c_str(), base, 0x75);
AppendByteField(aLine, (prefix + "_b76").c_str(), base, 0x76);
AppendByteField(aLine, (prefix + "_b77").c_str(), base, 0x77);
}
void AppendRouteQueueEntrySummary(std::ostringstream& aLine, const char* aPrefix, void* aEntry)
{
const auto prefix = std::string(aPrefix);
AppendPointerWithRva(aLine, prefix.c_str(), aEntry);
if (!aEntry)
{
return;
}
AppendUint32Field(aLine, (prefix + "_id00").c_str(), aEntry, 0x00);
AppendRouteRequestFields(aLine, (prefix + "_payload10").c_str(), aEntry, 0x10);
AppendPointerField(aLine, (prefix + "_vtable40").c_str(), aEntry, 0x40);
AppendPointerField(aLine, (prefix + "_self78").c_str(), aEntry, 0x78);
AppendUint32Field(aLine, (prefix + "_u80").c_str(), aEntry, 0x80);
AppendByteField(aLine, (prefix + "_b84").c_str(), aEntry, 0x84);
AppendByteField(aLine, (prefix + "_b85").c_str(), aEntry, 0x85);
AppendByteField(aLine, (prefix + "_b86").c_str(), aEntry, 0x86);
AppendByteField(aLine, (prefix + "_b87").c_str(), aEntry, 0x87);
}
void AppendRouteOutputPointerSummary(std::ostringstream& aLine, const char* aPrefix, void* aOut)
{
const auto prefix = std::string(aPrefix);
AppendPointerWithRva(aLine, prefix.c_str(), aOut);
if (!aOut)
{
return;
}
auto* value = ReadPointerField(aOut, 0x00);
AppendPointerWithRva(aLine, (prefix + "_value").c_str(), value);
if (value && IsReadableMemory(value, 0x58))
{
AppendGpsResultObjectSummary(aLine, (prefix + "_result").c_str(), value);
}
}
void TrackGpsQuery(uint32_t aQueryId, void* aManager, uintptr_t aSubmitReturnRva, uint32_t aSubmitCall) void TrackGpsQuery(uint32_t aQueryId, void* aManager, uintptr_t aSubmitReturnRva, uint32_t aSubmitCall)
{ {
if (aQueryId == UINT32_MAX) if (aQueryId == UINT32_MAX)
@@ -2841,6 +2999,216 @@ int32_t DetourGpsQueryStatus(void* aManager, uint32_t aQueryId)
return result; return result;
} }
void DetourGpsDispatchAdvance(void* aRouteSystem, void* aRuntimeQuery, void* aOutTicket, void* aTargetPosition,
void* aSourcePosition)
{
constexpr uint32_t kMaxCalls = 128;
const auto callCount = NextGpsAsyncLogCall(gGpsDispatchAdvanceLogCount);
const auto shouldLog = callCount < kMaxCalls;
if (shouldLog)
{
std::ostringstream line;
line << "hook GPSDispatchAdvance 0x8d17d8 call=" << callCount;
AppendRouteSystemSummary(line, "routeSystem", aRouteSystem);
AppendPointerWithRva(line, "runtimeQuery", aRuntimeQuery);
AppendPointerWithRva(line, "outTicket", aOutTicket);
AppendUint32Field(line, "runtimeQuery_state138", aRuntimeQuery, 0x138);
AppendUint32Field(line, "runtimeQuery_bank13c", aRuntimeQuery, 0x13C);
AppendVector4Pointer(line, "target", aTargetPosition);
AppendVector4Pointer(line, "source", aSourcePosition);
AppendReturnRva(line, __builtin_return_address(0));
LogRed4ext(line.str());
}
if (gOriginalGpsDispatchAdvance)
{
gOriginalGpsDispatchAdvance(aRouteSystem, aRuntimeQuery, aOutTicket, aTargetPosition, aSourcePosition);
}
if (shouldLog)
{
std::ostringstream line;
line << "hook GPSDispatchAdvance result call=" << callCount;
AppendUint32Field(line, "outTicket_value", aOutTicket, 0x00);
AppendRouteSystemSummary(line, "routeSystem", aRouteSystem);
LogRed4ext(line.str());
}
}
void DetourGpsAsyncWorkerTick(void* aRouteSystem)
{
constexpr uint32_t kMaxCalls = 192;
const auto callCount = NextGpsAsyncLogCall(gGpsAsyncWorkerTickLogCount);
const auto shouldLogBefore = callCount < 16 || (callCount < kMaxCalls && HasPendingRouteWork(aRouteSystem));
if (shouldLogBefore)
{
std::ostringstream line;
line << "hook GPSAsyncWorkerTick 0x126b28 call=" << callCount;
AppendRouteSystemSummary(line, "routeSystem", aRouteSystem);
AppendReturnRva(line, __builtin_return_address(0));
LogRed4ext(line.str());
}
if (gOriginalGpsAsyncWorkerTick)
{
gOriginalGpsAsyncWorkerTick(aRouteSystem);
}
const auto shouldLogAfter = shouldLogBefore || (callCount < kMaxCalls && HasPendingRouteWork(aRouteSystem));
if (shouldLogAfter)
{
std::ostringstream line;
line << "hook GPSAsyncWorkerTick result call=" << callCount;
AppendRouteSystemSummary(line, "routeSystem", aRouteSystem);
LogRed4ext(line.str());
}
}
bool DetourGpsRouteJobStart(void* aRouteSystem, void* aActiveEntry, float aDelta, void* aOutLocal)
{
constexpr uint32_t kMaxCalls = 128;
const auto callCount = NextGpsAsyncLogCall(gGpsRouteJobStartLogCount);
const auto shouldLog = callCount < kMaxCalls;
if (shouldLog)
{
std::ostringstream line;
line << "hook GPSRouteJobStart 0x818928 call=" << callCount << " dt=" << aDelta;
AppendRouteSystemSummary(line, "routeSystem", aRouteSystem);
AppendRouteQueueEntrySummary(line, "activeEntry", aActiveEntry);
AppendRouteOutputPointerSummary(line, "outLocal", aOutLocal);
AppendReturnRva(line, __builtin_return_address(0));
LogRed4ext(line.str());
}
bool result = false;
if (gOriginalGpsRouteJobStart)
{
result = gOriginalGpsRouteJobStart(aRouteSystem, aActiveEntry, aDelta, aOutLocal);
}
if (shouldLog)
{
std::ostringstream line;
line << "hook GPSRouteJobStart result call=" << callCount << " value=" << static_cast<uint32_t>(result);
AppendRouteSystemSummary(line, "routeSystem", aRouteSystem);
AppendRouteQueueEntrySummary(line, "activeEntry", aActiveEntry);
AppendRouteOutputPointerSummary(line, "outLocal", aOutLocal);
LogRed4ext(line.str());
}
return result;
}
bool DetourGpsRouteJobPoll(void* aRouteSystem, void* aActiveEntry)
{
constexpr uint32_t kMaxCalls = 128;
const auto callCount = NextGpsAsyncLogCall(gGpsRouteJobPollLogCount);
const auto shouldLog = callCount < kMaxCalls;
if (shouldLog)
{
std::ostringstream line;
line << "hook GPSRouteJobPoll 0x883cd8 call=" << callCount;
AppendRouteSystemSummary(line, "routeSystem", aRouteSystem);
AppendRouteQueueEntrySummary(line, "activeEntry", aActiveEntry);
AppendReturnRva(line, __builtin_return_address(0));
LogRed4ext(line.str());
}
bool result = false;
if (gOriginalGpsRouteJobPoll)
{
result = gOriginalGpsRouteJobPoll(aRouteSystem, aActiveEntry);
}
if (shouldLog || result)
{
std::ostringstream line;
line << "hook GPSRouteJobPoll result call=" << callCount << " value=" << static_cast<uint32_t>(result);
AppendRouteSystemSummary(line, "routeSystem", aRouteSystem);
AppendRouteQueueEntrySummary(line, "activeEntry", aActiveEntry);
LogRed4ext(line.str());
}
return result;
}
void* DetourGpsRouteFinish(void* aResultQueue, void* aOutEntry, void* aActiveEntry, void* aLocalResult)
{
constexpr uint32_t kMaxCalls = 128;
const auto callCount = NextGpsAsyncLogCall(gGpsRouteFinishLogCount);
const auto shouldLog = callCount < kMaxCalls;
if (shouldLog)
{
std::ostringstream line;
line << "hook GPSRouteFinish 0x11f5f60 call=" << callCount;
AppendPointerWithRva(line, "resultQueue", aResultQueue);
AppendRouteQueueEntrySummary(line, "activeEntry", aActiveEntry);
AppendRouteOutputPointerSummary(line, "localResult", aLocalResult);
AppendPointerWithRva(line, "outEntry", aOutEntry);
AppendReturnRva(line, __builtin_return_address(0));
LogRed4ext(line.str());
}
void* result = nullptr;
if (gOriginalGpsRouteFinish)
{
result = gOriginalGpsRouteFinish(aResultQueue, aOutEntry, aActiveEntry, aLocalResult);
}
if (shouldLog)
{
std::ostringstream line;
line << "hook GPSRouteFinish result call=" << callCount;
AppendPointerWithRva(line, "value", result);
AppendRouteOutputPointerSummary(line, "localResult", aLocalResult);
AppendPointerWithRva(line, "outEntry", aOutEntry);
LogRed4ext(line.str());
}
return result;
}
void* DetourGpsRouteJobBuild(void* aJob, void* aOut, void* aRequest)
{
constexpr uint32_t kMaxCalls = 128;
const auto callCount = NextGpsAsyncLogCall(gGpsRouteJobBuildLogCount);
const auto shouldLog = callCount < kMaxCalls;
if (shouldLog)
{
std::ostringstream line;
line << "hook GPSRouteJobBuild 0x818ba8 call=" << callCount;
AppendRouteJobSummary(line, "job", aJob);
AppendRouteOutputPointerSummary(line, "out", aOut);
AppendRouteRequestFields(line, "request", aRequest, 0x00);
AppendReturnRva(line, __builtin_return_address(0));
LogRed4ext(line.str());
}
void* result = nullptr;
if (gOriginalGpsRouteJobBuild)
{
result = gOriginalGpsRouteJobBuild(aJob, aOut, aRequest);
}
if (shouldLog)
{
std::ostringstream line;
line << "hook GPSRouteJobBuild result call=" << callCount;
AppendPointerWithRva(line, "value", result);
AppendRouteOutputPointerSummary(line, "out", aOut);
AppendRouteJobSummary(line, "job", aJob);
LogRed4ext(line.str());
}
return result;
}
int32_t DetourGpsRouteProducer(void* aGraph, void* aQuery, void* aOutResult) int32_t DetourGpsRouteProducer(void* aGraph, void* aQuery, void* aOutResult)
{ {
constexpr uint32_t kMaxCalls = 512; constexpr uint32_t kMaxCalls = 512;
@@ -3361,6 +3729,24 @@ RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::v1::PluginHandle aHandle, RED4e
AttachProbeHook("GPSQueryStatus 0xaa5704", kGpsQueryStatusRva, AttachProbeHook("GPSQueryStatus 0xaa5704", kGpsQueryStatusRva,
reinterpret_cast<void*>(&DetourGpsQueryStatus), reinterpret_cast<void*>(&DetourGpsQueryStatus),
reinterpret_cast<void**>(&gOriginalGpsQueryStatus)); reinterpret_cast<void**>(&gOriginalGpsQueryStatus));
AttachProbeHook("GPSDispatchAdvance 0x8d17d8", kGpsDispatchAdvanceRva,
reinterpret_cast<void*>(&DetourGpsDispatchAdvance),
reinterpret_cast<void**>(&gOriginalGpsDispatchAdvance));
AttachProbeHook("GPSAsyncWorkerTick 0x126b28", kGpsAsyncWorkerTickRva,
reinterpret_cast<void*>(&DetourGpsAsyncWorkerTick),
reinterpret_cast<void**>(&gOriginalGpsAsyncWorkerTick));
AttachProbeHook("GPSRouteJobStart 0x818928", kGpsRouteJobStartRva,
reinterpret_cast<void*>(&DetourGpsRouteJobStart),
reinterpret_cast<void**>(&gOriginalGpsRouteJobStart));
AttachProbeHook("GPSRouteJobPoll 0x883cd8", kGpsRouteJobPollRva,
reinterpret_cast<void*>(&DetourGpsRouteJobPoll),
reinterpret_cast<void**>(&gOriginalGpsRouteJobPoll));
AttachProbeHook("GPSRouteFinish 0x11f5f60", kGpsRouteFinishRva,
reinterpret_cast<void*>(&DetourGpsRouteFinish),
reinterpret_cast<void**>(&gOriginalGpsRouteFinish));
AttachProbeHook("GPSRouteJobBuild 0x818ba8", kGpsRouteJobBuildRva,
reinterpret_cast<void*>(&DetourGpsRouteJobBuild),
reinterpret_cast<void**>(&gOriginalGpsRouteJobBuild));
AttachProbeHook("GPSRouteProducer 0x44cc7c", kGpsRouteProducerRva, AttachProbeHook("GPSRouteProducer 0x44cc7c", kGpsRouteProducerRva,
reinterpret_cast<void*>(&DetourGpsRouteProducer), reinterpret_cast<void*>(&DetourGpsRouteProducer),
reinterpret_cast<void**>(&gOriginalGpsRouteProducer)); reinterpret_cast<void**>(&gOriginalGpsRouteProducer));