blob: 1a262878c9618e97653e4b6740b0b1a8d2268af9 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
#include "fetcher.h"
WarpFetcher::WarpFetcher()
{
m_logger = new BinaryNinja::Logger("WARP Fetcher");
}
void WarpFetcher::AddPendingFunction(const FunctionRef& func)
{
std::lock_guard<std::mutex> lock(m_requestMutex);
const auto guid = Warp::GetAnalysisFunctionGUID(*func);
if (!guid.has_value() || m_processedGuids.contains(*guid))
return;
m_pendingRequests.push_back(func);
}
std::vector<FunctionRef> WarpFetcher::FlushPendingFunctions()
{
std::lock_guard<std::mutex> lock(m_requestMutex);
std::vector<FunctionRef> requests = std::move(m_pendingRequests);
m_pendingRequests.clear();
return requests;
}
void WarpFetcher::ExecuteCompletionCallback()
{
BinaryNinja::ExecuteOnMainThread([this]() {
// TODO: Holding the mutex here is dangerous!
std::lock_guard<std::mutex> lock(m_requestMutex);
m_completionCallbacks.erase(
std::ranges::remove_if(m_completionCallbacks, [](const auto& cb) { return cb() == RemoveCallback; })
.begin(),
m_completionCallbacks.end());
});
}
std::shared_ptr<WarpFetcher> WarpFetcher::Global()
{
static auto global = std::make_shared<WarpFetcher>();
return global;
}
void WarpFetcher::FetchPendingFunctions(const std::vector<Warp::SourceTag>& allowedTags)
{
m_requestInProgress = true;
const auto requests = FlushPendingFunctions();
if (requests.empty())
{
m_logger->LogDebug("No pending requests to fetch... skipping");
m_requestInProgress = false;
return;
}
const auto start_time = std::chrono::high_resolution_clock::now();
// Because we must fetch for a single target we map the function guids to the associated platform to perform fetches
// for each.
std::map<PlatformRef, std::vector<Warp::FunctionGUID>> platformMappedGuids;
for (const auto& func : requests)
{
const auto guid = Warp::GetAnalysisFunctionGUID(*func);
if (!guid.has_value())
continue;
auto platform = func->GetPlatform();
platformMappedGuids[platform].push_back(guid.value());
}
for (const auto& [platform, guids] : platformMappedGuids)
{
m_logger->LogDebugF("Fetching {} functions for platform {}", guids.size(), platform->GetName());
auto target = Warp::Target::FromPlatform(*platform);
for (const auto& container : Warp::Container::All())
container->FetchFunctions(*target, guids, allowedTags);
std::lock_guard<std::mutex> lock(m_requestMutex);
for (const auto& guid : guids)
m_processedGuids.insert(guid);
}
m_requestInProgress = false;
ExecuteCompletionCallback();
const auto end_time = std::chrono::high_resolution_clock::now();
const std::chrono::duration<double> elapsed_time = end_time - start_time;
m_logger->LogDebug("Fetch batch took %f seconds", elapsed_time.count());
}
void WarpFetcher::ClearProcessed()
{
m_logger->LogInfoF("Clearing {} processed functions from cache...", m_processedGuids.size());
m_processedGuids.clear();
}
|