This is a framework used for the final project of NCSU CSC412/512.
- Please see the doc for detail requirement.
Use the following commands to get source code and build:
$ git clone --recurse https://github.ncsu.edu/qzhao24/csc_412_512_final_project.git$ ./build.shYou need to finish the function of bool IntegerOverflow(Instruction *instr, uint64_t flagsValue) in src/profiler.cpp. The function has two arguments: instr is a pointer to the current instruction, and flagsValue is the value of FLAGS register (https://en.wikipedia.org/wiki/FLAGS_register) after the instruction is executed.
To work on this framework, you must understand its implementation. We provide the introduction as follows.
In an application, every instrucntion can be represented as below (similar to the 3-address IR):
operator [source_operand_0, ... ] => [destination_operand_0 ]
In this framework, we abstract each executed instruction to an object of class Instruction. We abstract all operands to objects of struct Operand.
Each instruction object maintains its operator (type is OperatorType), its source operands, and its destination operands. When you obtain an instruction object, you can call its member functions to get the operator and all operands:
- get the operator type
OperatorType Instruction::getOperatorType()- get all source operands in a vector
std::vector<Operand> Instruction::getSrcOperandList()- get the source operand at index idx
Operand Instruction::ggetSrcOperand(int idx)- get all destination operands in a vector
std::vector<Operand> Instruction::getDstOperandList()- get the destination operand at index idx
Operand Instruction::getDstOperand(int idx)Each operand object maintains its type (type is OperandType), size(the Byte Size of Value), value, and options. Operand object is a structure, and you can directly access its fileds.
Because operands may have different sizes and types, their values may be of different sizes. To obtain a operand's value, we provide the following function:
- Util Function for Getting an Operand Value (This function returns an int64_t value. )
inline int64_t GetOpndIntValue(Operand opnd)The profile.cpp contains the main logic of the tool. It supports two callback functions during the application execution. The framework will automatically invoke these callbacks and pass arguments to them.
- Function Invoked After Every Instrunction Execution
void OnAfterInsExec(Instruction *instr, context_handle_t contxt, uint64_t flagsValue, CtxtContainer *ctxtContainer)IntegerOverflow() will be called by this function, and if it returns true the framework will record the instruction as an overflow instance. In this function, we provide some example code for you to use Instruction and Operand.
- Function Invoked Before Application Exit
void OnBeforeAppExit(CtxtContainer *ctxtContainer)This function will output all the recorded instructions to a txt file and a .drcctprof file.
The following figure shows the execution logic of the above two functions.
After you finish the implementation, run the following commands to rebuild your source code and run the tool to profile the test application:
$ ./run.shThe process will generate two profiles, one is a text file, and one is a .drcctprof file. You can directly open the .drcctprof file in VSCode if you have installed our Viewer extension.
We provide a test program. When you run the tool, it will build the application and profile it. The program's source code is available at test_apps/src/test1.c. It has 16 locations that trigger integer overflows. Your output needs to include all of them.
Your submission need contains 4 files:
-
the modified profiler.cpp
-
integer-overflow-profile.txt
-
integer-overflow-profile.drcctprof
-
screenshot of flamegraph view by open integer-overflow-profile.drcctprof through Viewer extension. This is for extra credit.
Not that the following screenshot is just part of the entire flame graph view. You need to submit the entire flame graph as the screenshot to obtain the extra credit.

