-
Notifications
You must be signed in to change notification settings - Fork 33
High Level Description of the Steps in LLFI
The goal of this document is to list the purpose of the steps in LLFI and their input/output dependencies. This document does not contain low-level information such as paths etc., but rather examines each step at a high level. The HOWTO documents explain how to use LLFI using the GUI and the command line interface respectively.
-
CompileToIR(deprecate): This compiles the source files to .ll form, which is LLVM’s Intermediate representation (IR). This step is essential for analyzing the programs using LLFI.
Input: Source C or C++ files (in the future, other languages will be supported too)
Output: .ll and .bc files for the program - we’ll call this sample.ll
-
Instrument: The purpose of this step is to insert call-back functions in the LLVM's Intermediate representation code (.ll/.bc files) for profiling and fault injection. We only insert the call-backs in the “places of interest” in the IR code files. The places of interest are determined by the faults to inject specified in the input.yaml file.
To generate readable IR (.ll file):
<llfi_build_root>/bin/instrument -l<shared_library> --readable sample.ll
To generate IR in bitcode format (.bc file):<llfi_build_root>/bin/instrument -l<shared_library> sample.bc
Input: The sample.ll file generated in step 1, and the input.yaml file with compileTime options
Output: Two .ll (or .bc) files for profiling and fault injection respectively. The files will be called sample-profiling.ll and sample-faultinjection.ll respectively. The corresponding executables are also generated, sample-profiling.exe and sample-faultInjection.exe.
-
Profiling: The purpose of this step is to obtain a dynamic execution count of the places of interest in the .ll file identified in step 2. This is needed as the fault injection step attempts to randomly choose an instance of the “places to inject” at runtime, based on their total execution count. It also creates a file with the fault-free or golden output, to be used for comparison with the fault injected runs. If the total_cycles is 0 in the file, then your test case is not exercising the “places of interest”, which is a problem as you’ll not be able to inject faults then. This could also be because of a runtime error that’s causing your program to exit prematurely.
<llfi_build_root>/bin/profile ./llfi/sample-profiling.exe <program arguments>
Input: The profiling executable sample-profiling.exe, a representative test case for running the program (e.g., command line arguments)
Output: llfi-stat-profile.txt which is a text file containing the total number of cycles (i.e., execution instances of the places of interest), and an output file containing the golden output of the program
-
Fault Injection: The purpose of this step is to inject faults systematically and in a reproducible manner. The fault injection works as follows. It first chooses an instance of the “places of interest” in the fault-injection ll file, and then injects a single fault into it at runtime. The result is then logged (i.e., where the fault was injected, what type) and the program allowed to continue. The final output of the program is also logged. This requires the profiling step to have completed successfully and the corresponding stat file to have been created. It also compares the output generated with the golden output generated in the profiling step, and in case of a mismatch, labels it an SDC (Silent Data Corruption). Similarly, it logs application crashes/hangs after the fault.
<llfi_build_root>/bin/injectfault ./llfi/sample-faultinjection.exe <program arguments>
Input: The fault-injection executable sample-faultInjection.exe, the input yaml file with the runtime options filled in, especially the number of fault injection runs and the fault injector type. Also, the outputs of the profiling step 3.
Output: Outcome of the fault injected experiments, as well as the log files for the injections and the output files generated. Any error messages written to stderr by the application are also logged.
-
Tracing (optional): The purpose of this step is to trace the propagation of faults in the LLVM IR code and to visualize how the LLVM IR code are mapped to the C/C++ source code. We need to specify that the trace should be collected at compile-time (step 2). This generates an execution trace after the profiling and fault-injection steps, for each fault injected. The traces can be compared to identify how the fault propagated.
A sample input.yaml with tracing enabled, note the tracingPropagation and tracingPropagationOption options:
defaultTimeOut: 500 compileOption: instSelMethod: - insttype: include: - all exclude: - ret regSelMethod: regloc regloc: dstreg tracingPropagation: True tracingPropagationOption: maxTrace: 250 debugTrace: False generateCDFG: True runOption: - run: numOfRuns: 5 fi_type: bitflip
Input: 1) The input.yaml file with the tracingPropagation set to True and the tracing .ll file generated. 2) The outputs of the profiling and fault injection steps with tracing enabled.
Output: A text file showing the differences between a set of fault-injected traces and the golden trace. This can be visualized with At&t’s GraphViz tool as we support the .dot format. Note that the diff files can also be programmatically manipulated.
Dependable Systems Lab - University of British Columbia (UBC)