88#include " llvm/Support/FileSystem.h"
99#include " llvm/Support/JSON.h"
1010#include " llvm/Support/raw_ostream.h"
11- #include < string>
12- #include < unordered_map>
1311
1412using namespace llvm ;
1513
@@ -18,8 +16,7 @@ AnalysisKey MitigationAnalysis::Key;
1816// Add a command line flag for the module name
1917static cl::opt<std::string>
2018 ClOutputModuleName (" mitigation-analysis-dso-name" , cl::Optional,
21- cl::desc (" DSO name for the module" ),
22- cl::init(" unknown" ));
19+ cl::desc (" DSO name for the module" ), cl::init(" " ));
2320
2421enum class MitigationState { Ineligible, EligibleDisabled, EligibleEnabled };
2522
@@ -30,6 +27,37 @@ static const std::unordered_map<MitigationState, std::string> mapStateToString =
3027 {MitigationState::EligibleEnabled, " Enabled" },
3128};
3229
30+ struct ModuleMitigationInfo {
31+ std::size_t eligable_auto_var_init = 0 ;
32+ std::size_t enabled_auto_var_init = 0 ;
33+
34+ std::size_t eligable_cfi_icall = 0 ;
35+ std::size_t enabled_cfi_icall = 0 ;
36+
37+ std::size_t eligable_cfi_vcall = 0 ;
38+ std::size_t enabled_cfi_vcall = 0 ;
39+
40+ std::size_t eligable_cfi_nvcall = 0 ;
41+ std::size_t enabled_cfi_nvcall = 0 ;
42+
43+ std::size_t eligable_stack_clash_protection = 0 ;
44+ std::size_t enabled_stack_clash_protection = 0 ;
45+
46+ std::size_t eligable_stack_protector = 0 ;
47+ std::size_t enabled_stack_protector = 0 ;
48+
49+ std::size_t eligable_stack_protector_strong = 0 ;
50+ std::size_t enabled_stack_protector_strong = 0 ;
51+
52+ std::size_t eligable_stack_protector_all = 0 ;
53+ std::size_t enabled_stack_protector_all = 0 ;
54+
55+ std::size_t eligable_libcpp_hardening_mode = 0 ;
56+ std::size_t enabled_libcpp_hardening_mode = 0 ;
57+
58+ std::size_t total_functions = 0 ;
59+ };
60+
3361struct MitigationInfo {
3462 MitigationState auto_var_init = MitigationState::Ineligible;
3563 MitigationState cfi_icall = MitigationState::Ineligible;
@@ -59,6 +87,56 @@ static inline MitigationState valToState(int value) {
5987 }
6088}
6189
90+ static void updateModuleInfo (ModuleMitigationInfo &moduleInfo,
91+ const MitigationInfo &info) {
92+ moduleInfo.total_functions ++;
93+
94+ moduleInfo.eligable_auto_var_init +=
95+ (info.auto_var_init != MitigationState::Ineligible);
96+ moduleInfo.enabled_auto_var_init +=
97+ (info.auto_var_init == MitigationState::EligibleEnabled);
98+
99+ moduleInfo.eligable_cfi_icall +=
100+ (info.cfi_icall != MitigationState::Ineligible);
101+ moduleInfo.enabled_cfi_icall +=
102+ (info.cfi_icall == MitigationState::EligibleEnabled);
103+
104+ moduleInfo.eligable_cfi_vcall +=
105+ (info.cfi_vcall != MitigationState::Ineligible);
106+ moduleInfo.enabled_cfi_vcall +=
107+ (info.cfi_vcall == MitigationState::EligibleEnabled);
108+
109+ moduleInfo.eligable_cfi_nvcall +=
110+ (info.cfi_nvcall != MitigationState::Ineligible);
111+ moduleInfo.enabled_cfi_nvcall +=
112+ (info.cfi_nvcall == MitigationState::EligibleEnabled);
113+
114+ moduleInfo.eligable_stack_clash_protection +=
115+ (info.stack_clash_protection != MitigationState::Ineligible);
116+ moduleInfo.enabled_stack_clash_protection +=
117+ (info.stack_clash_protection == MitigationState::EligibleEnabled);
118+
119+ moduleInfo.eligable_stack_protector +=
120+ (info.stack_protector != MitigationState::Ineligible);
121+ moduleInfo.enabled_stack_protector +=
122+ (info.stack_protector == MitigationState::EligibleEnabled);
123+
124+ moduleInfo.eligable_stack_protector_strong +=
125+ (info.stack_protector_strong != MitigationState::Ineligible);
126+ moduleInfo.enabled_stack_protector_strong +=
127+ (info.stack_protector_strong == MitigationState::EligibleEnabled);
128+
129+ moduleInfo.eligable_stack_protector_all +=
130+ (info.stack_protector_all != MitigationState::Ineligible);
131+ moduleInfo.enabled_stack_protector_all +=
132+ (info.stack_protector_all == MitigationState::EligibleEnabled);
133+
134+ moduleInfo.eligable_libcpp_hardening_mode +=
135+ (info.libcpp_hardening_mode != MitigationState::Ineligible);
136+ moduleInfo.enabled_libcpp_hardening_mode +=
137+ (info.libcpp_hardening_mode == MitigationState::EligibleEnabled);
138+ }
139+
62140// / Print out fields in MitigationInfo for debugging/verification purposes.
63141#ifndef NDEBUG
64142static void printInfo (const MitigationInfo &info) {
@@ -131,9 +209,10 @@ static void writeJsonToFile(const std::string &jsonString,
131209 const std::string &fileName,
132210 const std::string &errorMsg) {
133211 std::error_code errCode;
134- raw_fd_ostream OutputStream (fileName, errCode, sys::fs::CD_CreateAlways ,
212+ raw_fd_ostream OutputStream (fileName, errCode, sys::fs::CD_OpenAlways ,
135213 sys::fs::FA_Read | sys::fs::FA_Write,
136- sys::fs::OF_Text | sys::fs::OF_UpdateAtime);
214+ sys::fs::OF_Text | sys::fs::OF_UpdateAtime |
215+ sys::fs::OF_Append);
137216 if (errCode) {
138217 errs () << errorMsg << " \n " ;
139218 errs () << errCode.message () << " \n " ;
@@ -175,6 +254,42 @@ static json::Object infoToJson(const MitigationInfo &info) {
175254 return object;
176255}
177256
257+ // / Convert a ModuleMitigationInfo struct to a JSON object.
258+ static json::Object moduleInfoToJson (const ModuleMitigationInfo &moduleInfo) {
259+ json::Object object;
260+
261+ object[" enabled_auto_var_init" ] = moduleInfo.enabled_auto_var_init ;
262+ object[" eligable_cfi_icall" ] = moduleInfo.eligable_cfi_icall ;
263+ object[" enabled_cfi_icall" ] = moduleInfo.enabled_cfi_icall ;
264+ object[" eligable_cfi_vcall" ] = moduleInfo.eligable_cfi_vcall ;
265+ object[" enabled_cfi_vcall" ] = moduleInfo.enabled_cfi_vcall ;
266+ object[" eligable_cfi_nvcall" ] = moduleInfo.eligable_cfi_nvcall ;
267+ object[" enabled_cfi_nvcall" ] = moduleInfo.enabled_cfi_nvcall ;
268+ object[" eligable_stack_clash_protection" ] =
269+ moduleInfo.eligable_stack_clash_protection ;
270+ object[" enabled_stack_clash_protection" ] =
271+ moduleInfo.enabled_stack_clash_protection ;
272+ object[" eligable_stack_protector" ] = moduleInfo.eligable_stack_protector ;
273+ object[" enabled_stack_protector" ] = moduleInfo.enabled_stack_protector ;
274+ object[" eligable_stack_protector_strong" ] =
275+ moduleInfo.eligable_stack_protector_strong ;
276+ object[" enabled_stack_protector_strong" ] =
277+ moduleInfo.enabled_stack_protector_strong ;
278+ object[" eligable_stack_protector_all" ] =
279+ moduleInfo.eligable_stack_protector_all ;
280+ object[" enabled_stack_protector_all" ] =
281+ moduleInfo.enabled_stack_protector_all ;
282+ object[" eligable_libcpp_hardening_mode" ] =
283+ moduleInfo.eligable_libcpp_hardening_mode ;
284+ object[" enabled_libcpp_hardening_mode" ] =
285+ moduleInfo.enabled_libcpp_hardening_mode ;
286+
287+ object[" total_functions" ] = moduleInfo.total_functions ;
288+ object[" module" ] =
289+ ClOutputModuleName.empty () ? std::string (" unknown" ) : ClOutputModuleName;
290+ return object;
291+ }
292+
178293// / Return true if function F calls a function whose name contains
179294// / targetFunctionName.
180295static bool functionCallsFunctionWithName (Function &F,
@@ -250,9 +365,13 @@ static MitigationState detectLibcppHardeningMode(Function &F) {
250365 return MitigationState::Ineligible;
251366}
252367
368+ MitigationAnalysis::MitigationAnalysis (MitigationAnalysisSummary Summary)
369+ : summary_(std::move(Summary)) {}
370+
253371PreservedAnalyses MitigationAnalysis::run (Module &M,
254372 ModuleAnalysisManager &AM) {
255373 json::Array jsonArray;
374+ ModuleMitigationInfo moduleInfo;
256375
257376 for (Function &F : M) {
258377 LLVMContext &Context = F.getContext ();
@@ -262,7 +381,8 @@ PreservedAnalyses MitigationAnalysis::run(Module &M,
262381 continue ;
263382
264383 MitigationInfo info;
265- info.gmodule = ClOutputModuleName;
384+ info.gmodule = ClOutputModuleName.empty () ? std::string (" unknown" )
385+ : ClOutputModuleName;
266386 info.function = F.getName ();
267387
268388 for (unsigned i = 0 ; i < ExistingMD->getNumOperands (); ++i) {
@@ -283,20 +403,36 @@ PreservedAnalyses MitigationAnalysis::run(Module &M,
283403
284404 info.libcpp_hardening_mode = detectLibcppHardeningMode (F);
285405
286- info.source_mapping = getFunctionSourcePath (F);
287- info.type_signature = getFirstFunctionTypeSignature (F);
288- info.type_id = getFunctionTypeId (F);
406+ if (summary_ == MitigationAnalysisSummary::FUNCTION) {
407+ info.source_mapping = getFunctionSourcePath (F);
408+ info.type_signature = getFirstFunctionTypeSignature (F);
409+ info.type_id = getFunctionTypeId (F);
289410
290- DEBUG_WITH_TYPE (kMitigationAnalysisDebugType , printInfo (info));
291- jsonArray.push_back (infoToJson (info));
411+ DEBUG_WITH_TYPE (kMitigationAnalysisDebugType , printInfo (info));
412+ jsonArray.push_back (infoToJson (info));
413+ } else {
414+ // Start aggregating mitigations for entire module
415+ updateModuleInfo (moduleInfo, info);
416+ }
292417 }
293418
419+ std::string fileName =
420+ ClOutputModuleName.empty ()
421+ ? std::string (" mitigation_info.json" )
422+ : formatv (" mitigation_info-{0}.json" , ClOutputModuleName);
294423 if (!jsonArray.empty ()) {
295424 std::string jsonString =
296425 formatv (" {0}" , json::Value (std::move (jsonArray))).str ();
297426 if (!jsonString.empty ()) {
298- writeJsonToFile (jsonString, " mitigation_info.json" ,
299- " Couldn't write to mitigation_info.json!" );
427+ writeJsonToFile (jsonString, fileName,
428+ formatv (" Couldn't write to {0}!" , fileName));
429+ }
430+ } else if (moduleInfo.total_functions > 0 ) {
431+ std::string jsonString =
432+ formatv (" {0}" , json::Value (moduleInfoToJson (moduleInfo))).str ();
433+ if (!jsonString.empty ()) {
434+ writeJsonToFile (jsonString, fileName,
435+ formatv (" Couldn't write to {0}!" , fileName));
300436 }
301437 }
302438
0 commit comments