 Where do we want to insert the code and what code do we want to insert? These are questions which are related to the problem that you are trying to solve. And the third question is actually how do we actually go about inserting this extra code? There are various approaches like source code instrumentation and static binary instrumentation. We saw the drawbacks of these and the most popular approach for instrumentation is dynamic binary instrumentation. It is similar to just in time combination. Except that in just in time combination we are generating code from byte code to machine code. In dynamic binary instrumentation we are generating code from machine code to machine code. And while generating this code, we can insert some extra code in the application. These and learned about PIN, so PIN is a dynamic binary instrumentation engine. It provides a rich set of API to write in C or C++ your own instrumentation tool. And these instrumentation teams are called PIN tools. So PIN tools actually modify the, they are the kind of thought of as plugins. They modify the code generation path and things. So as I told you the PIN tools are C or C++ application. They consist of two types of routines instrumentation routine and analysis routine. And instrumentation routines are called by PIN whenever PIN is about to generate code for an instruction. So these instrumentation routines investigates the static properties of the application. And it decides whether it wants to add some extra code or it wants to insert a call to analysis routine or not. And if so it asks PIN to actually inject a call to analysis routine. And in analysis routine we actually, analysis routine actually defines what the instrumentation code would be doing. So what code we are instrumenting that is actually the analysis routine. And the important point was that so PIN tool actually registers a callback with PIN at what instrumentation routine we use. So do you understand what a callback means? What does it mean by a callback? So callback is in the normal way of programming we actually call a function. So that function is executed at the same time when we call the function. So that is a synchronous execution. Then callback we actually register with the runtime engine that this is the function that you have to execute. It is up to the runtime engine when it wants to execute that function. So it is like a asynchronous execution of functions. So PIN tools are registering with PIN what is the instrumentation function that we have to call. And PIN will call the instrumentation function whenever it is about to generate the code. So this is how we launch PIN. We give that with the dash T commanding argument specify the PIN tool. And after the double dash we specify the application that we want to instrument. We can attach PIN to an already running process through by supplying the dash TID argument to PIN. Then we saw a PIN tool which was... Yeah it's a dynamic library which is built for the PIN tool. So you have to build a dynamic library. So make files are there in the PIN kit. There is a sample make file provided in the PIN that you can directly use it. Most of the time you guys would be using modifying the PIN tools which are already provided. So all the build make files are already there for it. So then we were trying to see a tool which was counting the number of instructions. Here what we were trying to do is that just before each instruction we were trying to insert this counter plus plus. So whenever... So before each instruction suppose that we have inserted this counter plus plus. So whenever this instruction is about to be executed the counter would be incremented by one. So this counter is actually keeping track of the number of instructions which are executed by the application. So this is how it worked. So when it runs with PIN it displays the number of instructions that are executed. We are here we are instrumenting the LS application. You saw this is the code for the INS count. So the do count is the analysis routine. Instruction was the instrumentation routine. And here INS add instrument function. Here we are registering the callback for instrumentation routine with PIN. So it is saying that whenever PIN is about to generate code for an instruction. For each instruction it should call the analysis routine before it. And in the analysis routine we were saying that insert a call to... Insert a call to this do count function analysis function just before this instruction. Just before the code for this instruction insert a call to the do count analysis function. And the do count we were just including the counter by one. And then this we were registering a callback for an application end event. Whenever the application is about to end the PIN function would be called. And PIN function just prints the I count value. So focus on this instrumentation call INS insert call. So the first argument to INS insert call function is actually through this function call. PIN tool is asking PIN to inject a call to analysis routine. So this function takes the input to the instruction for which instruction it is asking to inject call. The position, this position is instrumentation position relative to the instruction. And then the analysis routine. And this is a place marker for the end of arguments to INS insert call. Analysis routine actually specifies the position relative to an instruction. Where PIN should inject a call to a instrumentation point is a position relative to an instruction. Where PIN should inject a call to the analysis routine. So this JLE instruction is a branch instruction. So it is a conditional branch instruction. Here it is doing the comparison when some flags would be set. And JLE would inspect those flags and based on that it will either traverse this path or it will jump to this. So when the instrumentation point is I point before, the analysis call is injected just before this instruction. And when the instrumentation point is I point after, then the analysis call is injected on the fall through it. By fall through I mean the instruction which is next to that instruction in the source code. So here the move instruction is next to this JLE instruction in the source code. But this definition of fall through it actually, so fall through it may not always exist. Suppose that here it was a conditional branch, so there were two parts. But if this was an unconditional jump instruction, there would only be a single path which will only be a single control flow path. So if suppose that this was a conditional jump, then this path would always be taken. Unconditional jump, then this path would always be taken. So the fall through it won't always exist. And if the instrumentation point was I point taken branch, then it actually injects the call on the branch path, the branch taken path. You care about this. So if this does not exist, then is it legal to pass it as I point after? So if suppose that the fall through it does not exist, then you still pass I point after. It won't actually insert the analysis routine because that path does not exist. You can always use them but the analysis call won't happen. Then we saw the second instrumentation tool which was trying to print the instruction trace. So the instruction trace is just a list of instructions. So these are the instruction addresses which are executed. So we were actually trying to do that just before instruction. We were trying to insert a call to this print IP function which takes as input the instruction address. And it just prints it. So here we are passing arguments to the analysis function. So this code is almost similar to the last print tool. So let's look at the analysis routine. In the analysis routine, here it takes as input the instruction address. And it just prints in the trace file the instruction pointer. In the instrumentation routine, it's almost the same except that the input arguments to this have now changed. We are passing an additional IR instruction pointer argument. This IR instruction pointer argument actually, so it is like a macro. So whenever this is passed, the address of the current instruction which we are trying to instrument, that address would be passed as an input argument to the analysis routine. So whatever is placed after the analysis function in this function, and before the IR again would be passed as an input to the analysis routine. Here IR instruction pointer is passed and put up. Yeah, it will automatically, so here it knows what instruction it is instrumenting. So it can determine on its own what is the instruction address. There are some other examples. So there are a lot of more arguments which you can. So suppose that you want to pass a 32-bit integer value. So in the previous example, you are just passing a single IR instruction pointer. Most of the time, this is not the case. We pass two arguments. The first one specifies the type of the argument that we are trying to pass to the analysis. And the second one is actual value. So suppose that we want to pass a 32-bit integer value to the analysis routine. So in the arguments, you will specify IR32. And then the second argument would be the value that we want to pass. So this is kind of a shorthand which can be provided. So here we don't have to specifically specify the value. We can do something like this. We can say that IR address integer. So this is a type for addresses. So we are trying to pass an address of instruction. And then this is the actual value that we are trying. So this IR instruction pointer is a shorthand for this. And then we can pass register values. So this is the type of register value. And this is the initial name for who values we want to pass. Similarly, there are... So this is also a shorthand directly determined from the current instruction information, which is the... What is the branch target address? And IR memory of EA. So here we are specifying... So an instruction can have some number of memory operands. Memop is the index of the memory operands. And this is the type of the effective address of the memory operands. There are many more input arguments you can... You should read the pin manual first. Now let's come into the... So till now what we have been doing is that we have been integrating each instruction in the application. So we registered... So we have been injecting a call to the analytical function just before each instruction. So most of the time that is not necessary. We would actually want to instrument a specific class of instructions. Suppose that we want to do memory... Suppose that we want to do cache simulation. So here we are only interested in instrumenting instructions which perform a load store, which do a load or a store. So we are actually interested in only instrumenting such as that. So pin provides API functions through which we can examine and classify what type of instruction this is. So we would use the pin API functions to examine whether an instruction is doing a load and a store. Only if it is doing a load and a store we would inject a call to the analytical function. So this is a fine tool for printing out the memory trace. The memory trace looks like this. Each line here is the instruction address which did this load and a store. And then either it was a read or a write and then the memory address on which it was doing the load or so. So the pinart trace.so is the tool that I have been taking from the pin manuals. So we run it like this. Now let's look at the pin tool. So this is a simple C application. So these are the analysis routines. So record a memory. So this would be called whenever there is a memory read. The first argument is taking the instruction pointer which we saw in the last Hindu and then it is taking the address. This is the memory operand address. The address of the memory operand and it is printing the instruction point address, the read and then the memory operand. Similarly it is record mem write. It is just printing the root of it. I am not showing the pin's initialization in the code. So I am only doing instruction instrumentation and the instrumentation function is instruction. So if you look in the instruction function. So this function would be called whenever the pin is trying to generate code for an instruction. So this is a pin API function through which we get the number of memory operands. So an H86 instruction can perform more than one load store. Here I am counting the number of memory operands in the instruction. So H86 instructions have more than one memory operand and then I am iterating over the memory operand and I am finding out whether it is doing a memory read or a memory write. So H86 memory operands can be both used as a source and as a destination. The same operand can be used both as a source and as a destination. So I check for both whether it is, there is no else both are individual. So if it is doing a memory read, then I insert a call. So this is this, what I am talking about this INS predicated call. INS insert predicated. This is almost similar to INS insert call which we saw previously. And we pass INS, the instruction, the position instrumentation point INS before. Then because this is a read, so we call the read analysis routine. And then we pass the instruction address just like in the previous and we have to also pass the memory operand. So the memory operand is passed like this. So we give IR memory operand here and then we give the memo. So we discussed this previously that this was a shorthand and here we are passing to our image. So they both would be used to pass the second argument. Do you get what is happening over here? And similarly for write, so whenever it is a write, we are just changing them and calling the memory write analysis function. So here we are injecting, so suppose that the instruction is doing both read and write, the same instruction. So we are injecting first two analysis, calls to two different analysis routines. And whenever that is about, that the analysis routine is about to be executed, it will pass the instruction pointer and it will pass the memory operand. So now what happens is that the memory operand in most of the X86 instructions is determined at the run time. When the instruction is actually doing to be executed. So when we are doing the instrumentation, at that point we do not know what is the memory operand's address. That would only be known when the instruction is about to be executed. So first question was actually that, why can't we pass here? So when the instruction is about to be executed, at that point spin has to again look up the instructions, environment to find out the memory operand. Like is that converted, get converted into some template? Yeah, it gets, so this memory of ea and memop, this would get converted into some code which will find out the instruction's memory operand's address. And that would be passed to the read record member. So here, I guess I could also then interpret at run time whether it's a read or a write. But here I'm doing it, we know that information before, just like decoding the instruction. Yeah, so I'm just trying to point out that you should try to do as much as you can at instrumentation time. You can use your run time over it. So here also I could move the read write checking that run time. But I'm not doing it. Yeah, I mean you can even move. Yeah, you can. So I'm not displayed that memory operand, so we can also pass the program's context, the execution context as an input argument to an analysis routine. So we can... But the overhead of that is quite large. Instrumentation actually slows down. So we should most of the time do most of the work during the instrumentation time because that is called once and the analysis routine for that do the minimal work. So are you clear about this? So you're going to talk about the predicated call? Yeah, yeah, I forgot. Okay, so here we are doing INS insert predicated call. I mean... So X86 has some instructions which have some predicate before them and only if the predicate is true the instruction is actually executed. So the predicate is itself a part of the instruction. Only if the predicate is true the instruction would actually be executed. So the predicates are like some conditions of... Let's talk about instruction granularity. Till now we have been... So till now we have been registering a callback to an instruction instrumentation routine. So this function actually said whenever PIN was about to generate code for our instruction it should call the instrumentation routine. So we were actually instrumenting at the granularity of each instruction. We were calling the instrumentation routine for each instruction. The overhead of this is quite large. So PIN provides other instruction granularities. You can call the analysis instrumentation routine at basic block. So now let's first see what these are. So a basic block is a sequence of instructions which are terminated by a control flow changing instruction. So whenever you have a... Suppose that this is the... This is some code sequence and so this was a control flow instruction so this is one basic block and it starts... This is second basic block. And then there is trace. Trace is a sequence of basic blocks which are terminated at an unconditional control flow change. So this whole is a single trace. The trace won't be terminated here because the trace is terminated at an unconditional flow. So PIN provides you with these other API calls to register instrumentation routines for doing basic block-level instrumentation and trace-based instrumentation. So when I say trace-based instrumentation that means whenever PIN is about to generate code for a trace it should call the analysis routine. Now we were saying whenever PIN is about to generate code for an instruction it should call the analysis routine. Now we would be saying whenever PIN is about to generate code it should call the analysis routine ok. So, we have seen instruction based instrumentation we would see example of these would see example of these and then the fourth type is routine based instrumentation, routines are function. So, this is almost similar to instruction it says that whenever pin is about to generate code for an instruction for a function it should call the analysis routine I before that. Instruction counting these basic work and trace we have benefit. Yeah, we would see. So, this was the instruction count too. So, we were injecting these counter plus plus just before instruction. So, this is not that efficient mechanism of counting instructions because we have to there are lot of additions that this code would have to do that. So, this is a straight forward mechanism, but it is not that efficient can you guys think of a another type of what how can we optimize this for the lesson. We have to count the still the number of instructions, but can we do somehow I mean reduce this number of analysis calls that we are inserting. So, this is the same course it consists of two basic blocks ok and a basic block has a single entry point and a single exit point it does not. So, what we can do is that just before the start of the basic block we can we can count the number of instructions in the basic block and we can just increment the counter by there. So, this would be a. So, instead of doing three additions we are doing now a single addition similarly for the second basic block. Yeah. So, here of course, the point is that basic blocks are static entities. So, you count the number of instructions in the basic block instrumented. So, that is the whole point right. Yeah. Otherwise I do not see anything. How do you know how to do instruction? Because so we would see how we get the counter. No otherwise if I am counting it means I mean how do I go three for example, here counter plus equal to 3 you are saying if I am counting number of instructions and execute I mean at runtime then of course, there is no gain but I will do the same thing. If only if I can discover that there are three instructions to the instrumentation. Yeah. They only I have a gain. And I think you can do that because basic blocks are static entities. You know number of instructions in the basic block is not going to change. Yeah. The only thing that is going to change is how many times. So, that is because the basic block has a single late three point has a single late three point that is good. Because of that the number of instructions would remain the same. So, let us see how. So, we have to figure out what are the basic blocks and we have to count the number of instructions in the basic block and we. So, let us see the code for this. So, this is our analysis routine has changed. It has a input argument C which it increments the icon by that C and this is our instrumentation routine we will come to this. Let us focus on the callback function. So, instead of doing INS add instrument function we are doing trace add instrumentation instrument function. So, here we are doing a callback for trace instrumentation. So, whenever pin is about to generate code for a trace it will call this trace instrumentation function. Now, let us look at the instrumentation function here what we are doing. So, a trace was just a sequence of basic blocks. So, it can be thought of as a list of basic blocks. So, here in the instrumentation function we are actually iterating over the basic blocks in the trace. So, we get the head basic. So, trace is a list of basic blocks. So, we get the head pointer and we are checking whether the basic block is on which you can then. So, this is the and in each iteration of this for loop we are saying we are asking pin to inject a call at the start of the just before it generates code for the basic block. So, previously we were doing INS insert call that was saying just before it generates code for the instruction it should inject call to the analysis. Here we are saying that just before it generates code for the basic block we should insert a call to the analysis. So, we are iterating over the list of basic block and we have this we inject a call. So, for each basic block we inject a call to this loop call function. The input arguments here are we pass 32 IR 32 and this is the value that we are trying to pass. We can find out the. So, this is a pin A K function which gives us the number of instructions in the and this is what executes an instrumentation type. So, essentially it passes a constant. So, here the instrumentation function is taking as input the trace for which pin is about to generate code and yeah and the second argument is the second argument passed over here. We do not use it. So, we just pass 0. So, here the instrumentation function is taking as input the trace for which pin is about to generate code and yeah and the second argument is the second argument passed over here. We do not use it. So, we just pass 0. So, do you get this here I said that we can do instrumentation at different granularities. We can do instrumentation at basic block. So, we were actually doing. So, in the example we saw we were actually calling the instrumentation function at the granularity of trace and we were injecting analysis routines at the granularity of basic blocks. There is no specific instrumentation routine to register a callback for basic block. So, there are only two instrumentation register two on add instrument function one is INS add instrumentation and there is trace other is trace add it. We can only register instrumentation callback for either instruction level or for the trace level. And in the trace level we can iterate over the basic block. So, there was one more of the routines. Now, we will see an example for how to do this routine based instrumentation. So, this is procedure instruction count. This is also taken from the pin manual. So, this is how. So, this is the tool proc count. So, and this is the instruction that we are instrumenting. We are doing a graph on we are trying to find this thing in the main file. This is the and this is the. So, this actually creates a file proc count data and this is the output of proc count. Then you see this. So, it gives us the name of the function which and it prints the library which is providing this function and it prints the address of the starting of the function and it prints the how many calls were made to this function and how many instructions are there in the function. So, this is a part of the print. So, we define some structure which. So, RTN means routine which is same for a function. The structure tracks the name and this is the name of the image, the library which is the address. This is all the information that was printed over here. This is a pointer to the routine. The RTN, how many times it is called and the number of instructions. So, this will be used to make a link list of the other team. And then we pass a pointer to it and it just increments. This is our analysis routine. We pass a pointer to it to integer and it just increments it by one. This is just to get some path. This is the instrumentation function and we are doing RTN add instrument. So, whenever it is about to generate code for a function it will call this instrumentation routine. So, in the instrumentation routine we get the routine for which it is about to generate code. We create a new object of the RTN count of the structure. RTN count is the structure. We create a new object for this routine. We initialize its name. These are P and API functions to get the name of the routine. So, I will explain this afterwards. This is something to get the name of the library. This is to get the name of the library. We initialize the library's name. We get the address of the routine. We set our routine, our instruction count to zero. We do routine. How many times the routine is called to also zero? So, we are preparing a link list of the routines which are called. So, this is RTN list is the head of the list. So, we are saying routine dash next is the current head of the routine and we set the new head as the newly created routine. So, whenever we are about to instrument routine we should have. I will talk about this afterwards. Now, let's look at this. This is the main instrumentation part. This was just the initializing. Here we are doing RTN insert call. This is similar to IMS or trace insert call. And we are passing routine, the position before the routine the analysis function is do count. And we are passing the IR. So, this is the input type for a pointer that we are trying to pass. And we are passing a pointer to RTN count. So, we are adding a call to do count function just before this routine. And we are passing the do count the RTN count. RTN count is actually trying to maintain how many times that routine is being called. So, whenever the routine is about to be called this do count would also be called. And it will increment this RTN count by one. So, it will count the number of times this function is being called. So, the second thing. So, now, we are iterating over the routine, the instructions in the routine. So, we get the head instruction at the starting of the routine. And we if the instruction is valid we keep on. So, we are iterating over the instruction. So, a routine is just a can be thought of as a linked list of instructions. So, we are iterating over that linked list. And then we are doing a instruction instrumentation. And we are just instrumenting a call to do count before this instruction. And we are passing this icon variable of this structure as a input argument. So, whenever instruction in that routine would be executed it will count the it will increment this icon by one. So, this icon would actually count the total number of instructions which are executed by that routine in all the invoices of that routine. We could have optimized this by doing similarly breaking down it in basic blocks and add it. So, one more thing just before doing the instrumentation we have to do this we have to open this routine RTN open and then close. So, the instruction is just provided by the. Yeah, always information is provided by RTN. These are the API functions to get you can actually maintain it like this routine structure as a list of instructions. So, if you go back now to your that thing when the list is shown. Yeah. Yeah. So, if I add up the last column I will get total number of variable instructions. Yeah, but I do not see any. So, there must be so the main function in the program. So, how do the pen tools are all simple you can debug them. So, debugging them is slightly different. So, we use GDB for debugging. So, whenever you are. So, you have to first combine them with Darjeet argument. How many of you have not used GDB? So, learn that. Unless you are a great coder you will never So, you first do GDB pen in one terminal and you do not run anything here. So, just start this and wait and then second terminal you actually call your pen routine, but you also pass this pause tool a command line argument and this is the number of seconds that. So, what this will do is that after starting the program it will wait for these many seconds. After that it will start the program. So, you can pass anything over here. In this 10 seconds you have to go back to this terminal and you have to execute these. So, it will print this thing. So, you have to print the PID of this process. In this terminal you have to do attach to this PID. So, what it will do it will attach this to this terminal and then you can do all break. So, essentially you are attaching GDB to the process. So, here after you do attach you can create break points and do a continue and when you do this it will also print a line which says the basically display the command which is to. So, to add the symbol information of the PIN tool in with GDB. So, after doing attach you should execute that command that I am not showing that here and it will attach the symbol information and then you can insert any break points and this is the last slide and this is the link to the PIN manual. You can also find it on the home page of PIN. You should go through it. There are not more examples in it and you should read them. Then there is a PIN news group. If you have any questions you can ask them. You can post on this and if you have any other questions you can ask me. This is my email id. Okay. Thanks.