#include "zeek/ScriptCoverageManager.h" #include #include #include #include #include #include #include #include "zeek/Stmt.h" #include "zeek/Desc.h" #include "zeek/Reporter.h" #include "zeek/util.h" using namespace std; namespace zeek::detail { ScriptCoverageManager::ScriptCoverageManager() : ignoring(0), delim('\t') { } ScriptCoverageManager::~ScriptCoverageManager() { for ( auto& s : stmts ) Unref(s); } void ScriptCoverageManager::AddStmt(Stmt* s) { if ( ignoring != 0 ) return; Ref(s); stmts.push_back(s); } bool ScriptCoverageManager::ReadStats() { char* bf = util::zeekenv("ZEEK_PROFILER_FILE"); if ( ! bf ) return false; std::ifstream ifs; ifs.open(bf, std::ifstream::in); if ( ! ifs ) return false; std::stringstream ss; ss << ifs.rdbuf(); std::string file_contents = ss.str(); ss.clear(); std::vector lines; util::tokenize_string(file_contents, "\n", &lines); string delimiter; delimiter = delim; for ( const auto& line : lines ) { if ( line.empty() ) continue; std::vector line_components; util::tokenize_string(line, delimiter, &line_components); if ( line_components.size() != 3 ) { fprintf(stderr, "invalid ZEEK_PROFILER_FILE line: %s\n", line.data()); continue; } std::string& cnt = line_components[0]; std::string& location = line_components[1]; std::string& desc = line_components[2]; pair location_desc(std::move(location), std::move(desc)); uint64_t count; util::atoi_n(cnt.size(), cnt.c_str(), nullptr, 10, count); usage_map.emplace(std::move(location_desc), count); } return true; } bool ScriptCoverageManager::WriteStats() { char* bf = util::zeekenv("ZEEK_PROFILER_FILE"); if ( ! bf ) return false; util::SafeDirname dirname{bf}; if ( ! util::detail::ensure_intermediate_dirs(dirname.result.data()) ) { reporter->Error("Failed to open ZEEK_PROFILER_FILE destination '%s' for writing", bf); return false; } FILE* f; const char* p = strstr(bf, "XXXXXX"); if ( p && ! p[6] ) { mode_t old_umask = umask(S_IXUSR | S_IRWXO | S_IRWXG); int fd = mkstemp(bf); umask(old_umask); if ( fd == -1 ) { reporter->Error("Failed to generate unique file name from ZEEK_PROFILER_FILE: %s", bf); return false; } f = fdopen(fd, "w"); } else { f = fopen(bf, "w"); } if ( ! f ) { reporter->Error("Failed to open ZEEK_PROFILER_FILE destination '%s' for writing", bf); return false; } for ( list::const_iterator it = stmts.begin(); it != stmts.end(); ++it ) { ODesc location_info; (*it)->GetLocationInfo()->Describe(&location_info); ODesc desc_info; (*it)->Describe(&desc_info); string desc(desc_info.Description()); canonicalize_desc cd{delim}; for_each(desc.begin(), desc.end(), cd); pair location_desc(location_info.Description(), desc); if ( usage_map.find(location_desc) != usage_map.end() ) usage_map[location_desc] += (*it)->GetAccessCount(); else usage_map[location_desc] = (*it)->GetAccessCount(); } map, uint64_t >::const_iterator it; for ( it = usage_map.begin(); it != usage_map.end(); ++it ) { fprintf(f, "%" PRIu64"%c%s%c%s\n", it->second, delim, it->first.first.c_str(), delim, it->first.second.c_str()); } fclose(f); return true; } } // namespace zeek::detail