vectorscan/src/util/report_manager.cpp
Justin Viiret 5dfae12a62 ng: split NGWrapper into NGHolder, ExpressionInfo
We now use NGHolder for all graph information, while other expression
properties (report, flag information, etc) go in new class
ExpressionInfo.
2017-04-26 15:18:09 +10:00

267 lines
8.0 KiB
C++

/*
* Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Intel Corporation nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/** \file
* \brief ReportManager: tracks Report structures, exhaustion and dedupe keys.
*/
#include "report_manager.h"
#include "grey.h"
#include "ue2common.h"
#include "compiler/compiler.h"
#include "nfagraph/ng.h"
#include "rose/rose_build.h"
#include "util/compile_error.h"
#include "util/container.h"
#include <deque>
#include <map>
#include <sstream>
#include <vector>
using namespace std;
namespace ue2 {
ReportManager::ReportManager(const Grey &g)
: grey(g), freeEIndex(0), global_exhaust(true) {}
u32 ReportManager::getInternalId(const Report &ir) {
auto it = reportIdToInternalMap.find(ir);
if (it != reportIdToInternalMap.end()) {
DEBUG_PRINTF("existing report %zu\n", it->second);
return it->second;
}
// Construct a new internal report and assign it a ReportID.
if (numReports() >= grey.limitReportCount) {
throw ResourceLimitError();
}
u32 size = reportIds.size();
reportIds.push_back(ir);
reportIdToInternalMap[ir] = size;
DEBUG_PRINTF("new report %u\n", size);
return size;
}
const Report &ReportManager::getReport(u32 id) const {
assert(id < reportIds.size());
return reportIds.at(id);
}
size_t ReportManager::numReports() const {
return reportIds.size();
}
u32 ReportManager::getExhaustibleKey(u32 a) {
auto it = toExhaustibleKeyMap.find(a);
if (it == toExhaustibleKeyMap.end()) {
// get size before assigning to avoid wacky LHS shenanigans
u32 size = toExhaustibleKeyMap.size();
bool inserted;
tie(it, inserted) = toExhaustibleKeyMap.emplace(s64a{a}, size);
assert(inserted);
}
DEBUG_PRINTF("%lld -> ekey %u\n", it->first, it->second);
return it->second;
}
u32 ReportManager::getUnassociatedExhaustibleKey(void) {
u32 rv = toExhaustibleKeyMap.size();
bool inserted;
map<s64a, u32>::const_iterator it;
tie(it, inserted) = toExhaustibleKeyMap.emplace(--freeEIndex, rv);
assert(inserted);
assert(it->second == rv);
return rv;
}
u32 ReportManager::numDkeys() const {
DEBUG_PRINTF("%zu dkeys\n", reportIdToDedupeKey.size());
return reportIdToDedupeKey.size();
}
u32 ReportManager::numEkeys() const {
return (u32) toExhaustibleKeyMap.size();
}
bool ReportManager::patternSetCanExhaust() const {
return global_exhaust && !toExhaustibleKeyMap.empty();
}
vector<ReportID> ReportManager::getDkeyToReportTable() const {
vector<ReportID> rv(reportIdToDedupeKey.size());
for (const auto &m : reportIdToDedupeKey) {
assert(m.second < rv.size());
rv[m.second] = m.first;
}
return rv;
}
void ReportManager::assignDkeys(const RoseBuild *rose) {
DEBUG_PRINTF("assigning...\n");
map<u32, ue2::flat_set<ReportID>> ext_to_int;
for (u32 i = 0; i < reportIds.size(); i++) {
const Report &ir = reportIds[i];
/* need to populate dkey */
if (isExternalReport(ir)) {
ext_to_int[ir.onmatch].insert(i);
}
}
auto dedupe = rose->generateDedupeAux();
for (const auto &m : ext_to_int) {
u32 ext = m.first;
if (!dedupe->requiresDedupeSupport(m.second)) {
DEBUG_PRINTF("%u does not require dedupe\n", ext);
continue; /* no dedupe required for this set */
}
u32 dkey = reportIdToDedupeKey.size();
reportIdToDedupeKey[ext] = dkey;
DEBUG_PRINTF("ext=%u -> dkey=%u\n", ext, dkey);
}
}
u32 ReportManager::getDkey(const Report &r) const {
if (!isExternalReport(r)) {
return ~u32{0};
}
auto it = reportIdToDedupeKey.find(r.onmatch);
if (it == reportIdToDedupeKey.end()) {
return ~u32{0};
}
return it->second;
}
void ReportManager::registerExtReport(ReportID id,
const external_report_info &ext) {
if (contains(externalIdMap, id)) {
const external_report_info &eri = externalIdMap.at(id);
if (eri.highlander != ext.highlander) {
/* we have a problem */
ostringstream out;
out << "Expression (index " << ext.first_pattern_index
<< ") with match ID " << id << " ";
if (!ext.highlander) {
out << "did not specify ";
} else {
out << "specified ";
}
out << "HS_FLAG_SINGLEMATCH whereas previous expression (index "
<< eri.first_pattern_index << ") with the same match ID did";
if (ext.highlander) {
out << " not";
}
out << ".";
throw CompileError(ext.first_pattern_index, out.str());
}
} else {
externalIdMap.emplace(id, ext);
}
// Any non-highlander pattern will render us not globally exhaustible.
if (!ext.highlander) {
global_exhaust = false;
}
}
Report ReportManager::getBasicInternalReport(const ExpressionInfo &expr,
s32 adj) {
/* validate that we are not violating highlander constraints, this will
* throw a CompileError if so. */
registerExtReport(expr.report,
external_report_info(expr.highlander, expr.index));
/* create the internal report */
u32 ekey = INVALID_EKEY;
if (expr.highlander) {
/* all patterns with the same report id share an ekey */
ekey = getExhaustibleKey(expr.report);
}
return makeECallback(expr.report, adj, ekey);
}
void ReportManager::setProgramOffset(ReportID id, u32 programOffset) {
assert(id < reportIds.size());
assert(!contains(reportIdToProgramOffset, id));
reportIdToProgramOffset.emplace(id, programOffset);
}
u32 ReportManager::getProgramOffset(ReportID id) const {
assert(id < reportIds.size());
assert(contains(reportIdToProgramOffset, id));
return reportIdToProgramOffset.at(id);
}
static
void ekeysUnion(std::set<u32> *ekeys, u32 more) {
if (!ekeys->empty()) {
if (more == INVALID_EKEY) {
ekeys->clear();
} else {
ekeys->insert(more);
}
}
}
set<u32> reportsToEkeys(const set<ReportID> &reports, const ReportManager &rm) {
assert(!reports.empty());
set<u32> ekeys;
for (auto it = reports.begin(), ite = reports.end(); it != ite; ++it) {
u32 e = rm.getReport(*it).ekey;
if (it == reports.begin()) {
if (e != INVALID_EKEY) {
ekeys.insert(e);
}
} else {
ekeysUnion(&ekeys, e);
}
}
return ekeys;
}
} // namespace ue2