GDB Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi guys thanks for coming this is a supplementary tutorial we're giving it outside of regular tutorial hours but honestly I think of all the tutorials that we're gonna give in the term this is probably the most most important most valuable definitely recovering one of my favorite tools and I think probably one of the tools it's gonna save you the most time in the long run in this course and in pretty much any other course that you're gonna use C++ in yes if you guys remember from this past Wednesday's to toriel we talked a bit about Val grind which was a super handy tool for debugging it allows you to easily find memory errors in your code so if you have memory leaks if you have bad memory accesses if you don't match your news with your deletes Val grind will let you know but really any error outside of memory leaks and and memory kinds of errors without grind isn't going to catch so we need more tools we need something else to be able to help us find and identify and kind of deal with those other kinds of bugs because as we all know bugs can come in all shapes and forms and a lot of them can be really hard to find so today we're gonna be talking about a tool that we have access to in the student environment called I mean so is there GDB gd0 jecht debugger and what gdb allows us to do is take our programs that we've compiled and kind of take them apart so we can run through them but we can also stop in the middle of execution we can step through our code one line at a time we can look at variables we can look at the stack it's honestly a really really powerful tool that allows us to kind of take apart our programs without having to necessarily kind of parse through the source code sometimes it's hard to read sometimes it's hard to follow we make mistakes but gdb lets us really hone in on those details there are times when gdb is kind of overkill most of you guys are probably familiar with caveman debugging or printf debugging where you throw printf statements throughout all your code and then use that to find when when your code breaks and there are times when honestly that's the easiest solution just throw it printf statement in there and that will help you kind of figure out what's going on but for anything more than kind of the smallest bugs Wow I say that printf debugging is sort of like a spoon and gdb is like a full set of surgical tools and today we're gonna be spending an hour talking about those tools and maybe maybe scratching just the surface and giving you just what you need to be able to kind of go through this course and find your bugs but if you guys do want to kind of delve more into this gdb is an extremely powerful tool and there are tons of resources online to kind of take a look at what it has to offer so to begin when we have a program let's say I have my example program here called basic 1cc super simple program main function were assigning some values to some integers we're adding one to another and then we'll be making k equal to j times 2 and then that we're printing out hello there super simple program and when we compile this code when i say g + + basic one dot c c that's going to produce a dot dot oops a dot outs executable file and what happens during that process when i run that g + + command is g + + takes my source code mixes it all around optimizes it runs a bunch of optimizations that make your code faster it can unravel loops i can pre evaluate some expressions it can eliminate dead code that we can't reach but the issue there is that it jumbles up our code so we can't really look inside of our executable files and kind of piece together what's going on so as some of you might remember from our Val grind tutorial there is a compiler flag that we can use to tell the compiler not only to leave our code intact so don't run any optimizations like leave four line for line exactly what my source code says to do and also to package in with our compiled code a copy of the original source file so that we can actually look inside and go line by line and see what exactly it's doing so this flag is the - G flag I'm also going to tell it to use C++ 14 and compiled basic one dot C C and let's gonna let's put it in our basic one file so we can pile fine it looks the same but now that we have used our - G file our - G flag and incorporated all of that information into our executable file gdb can now extract that information and take a look at it and let us kind of play around with our code and see what's going on so just keep that in mind when you want to use gdb use the - g compiler flag now I've been talking a lot about gdb and praten in principle let's take a look at how it works in practice so to run a program inside of gdb type gdb and then the name of the program so in this case basic one so I run this and then we get a whole bunch of license agreement sort of stuff and then at the bottom we have a small prompt gdb and I can type whatever commands I want in there and gdb will run them so to start out if I want to debug my program let's start out by trying to run our program so gdb has its own set of commands just like bash has a full set of commands that do a bunch of cool stuff gdb has its set of commands that each does a different thing that helps us debug our code so the first command that we're going to be talking about today and I'll actually add them to the board as we go yeah just add them here we have the run command and the run command surprisingly enough runs our program so when I type run into gdb and hit enter it will output right here starting program and then it tells you what the executable file is the path to the file here's our output hello there and then we exit our program normally and then we get our gdb prompt telling us okay what do you want me to do next this is cool we can run a program inside gdb but it's not any different from what we were already able to do we could already run a program let's take advantage of one of the tools that gdb has to offer called breakpoints which some of you might be familiar with if you've programmed in an IDE before let's tell gdb to instead of running through our entire program to stop at a certain point in order to tell it where to stop we can give gdb a breakpoint and all that is is just a specific line of code where when we our program reaches that line we stop executing we stop at that point we wait and then we can give gdb more commands in order to create a breakpoint we use the break command break and we can set a breakpoint at a specific line so I could say break seven and that will set a breakpoint at line seven our program will stop at line seven we can also give gdb a function name so in this case I'm gonna say break main and we have now created a breakpoint that's our main function in our program so our outputs our output from gdb it says breakpoint one at this memory address in file basic one cc at line four so now when we run our program my type run Hey enter we start our program but then instead of running the whole program in getting our output we see this point one main function at this line in this file and then our line four of our program so what's happened here is we've run our code up to that point and then we've stopped and gdb says okay cool let's stop at the beginning of the main function and now tell me what to do so this is super handy because now we've stopped our program before it completes and we can kind of take a look at kind of the state of our program at different points in the code so just one quick side note by the way when we run our program with run this run command works just like the commands name in bash so if I want to give it arguments I can say r1 r2 these are my arguments I can do input redirection I can say here's my in file in so in gdb if you want to run your program just as you would another program with arguments and inputs you do so with the run command like we're doing here now we've stopped at line four of our program I want to tell gdb to instead of keep running my program let's just take one step forward in our program let's just say okay run this one line and then stop again in order to do that we have the next command + e x t next and that tells gdb run the program and stop at the next line so I type next into my prompt hit enter and we're now at our next line of our program line five and it's just an assignment of the number seven to the integer K now there are points when we're stepping through our code where we might get lost all I can see here is just the name of this single line so if you guys are ever stepping through your code and you want to say wait a minute let's just take a look at the context where actually am I the list command here li st list by type list and hit enter it will print out the lines of code around where I currently am so we were at line five here's line five in the program and then we get a few lines before and a few lines after so that can come in handy if you ever want to know where you are in your program so now we're at line five and just just so you know the line that gdb will print out is the next line to execute so right now it's telling us line five in K equals seven this means that neck that when I type next that is the command that is going to be run so at this point RJ has been assigned and our K is about to be assigned now if this were a more complicated program doing more complicated things I might want to make sure that at this point in the program the value of J is what I want it to be it looking at this looking at this source code the value of J at this point should be three now I can tell gdb hey please let me know what the value of this variable is and in order to tell gdb to print out the value stored at some variable we can use the print command pri and T print and what print will do is print out the value of a variable that we give it so if I say print J it will give us three which is good because we've just assigned the value of three to J now let's take a few more steps forward in our program so I'm going to write next again and we now have our line line seven J plus equals K so we're adding K to J and then let's go to the next line and before we continue all of these commands have short hands so I might accidentally use some of the short hands while we're using the tutorial one of them which is just handy to know is you can instead of typing next just type the letter N and that has the same effect so I type and and then we move on to the next line of our program now one more note about the about the print command is that it is pretty smart this is kind of one of the GD B's real strengths the print command not only can access the value of a variable and print it out it actually understands C and C++ style syntax in terms of evaluating expressions so at this points in our program we have we can print out so P is P is also a way of printing P J let's print J so the value of J is 10 I could also say print J plus okay and that will evaluate the expression that we give it and then print out the result and this can be as complicated as you want you can say J times 3 plus K times 2 minus 2 and it'll evaluate the expressions we give it the pointer dereferencing operator also works here so if we have a pointer and we want to see what value is stored at that address I could say print dereference my pointer pointer and that will give me the value there so the print command is really really handy it's one of the ones we'll use most often when we're using gdb just to make sure that either is a sanity check to see what our variables have assigned to them or just to really see kind of what the flow of our program is actually doing to the values that we're storing and that's it for this specific example are there any questions before I move on yes we'll take a look at that later so we will get to that point we're asking about function calls we will get to that later good question so let's move on to another example and it looks like I'm sort of stuck in gdb I can't really sort of say : Q because this isn't vim but luckily we have the quick command Q UI T quit and that allows us to leave our current instance of gdb if we're still running the program it will ask us to confirm we can say yes and we're back where we started we're good to go now let's take a look at a slightly more complicated program called example 1 dot C C so in this program we have three functions that's line three we have our crash function which basically just takes an integer pointer and assigns the value of one to two what it's pointing to we have our function f right here which has a few function calls in it and then our main function which declares integer I and then calls function f on the address of I now let's run this program in gdb example 1 now actually before we run in gdb let's just try running the program on its own example one I hit enter segmentation fault everyone's least favorite thing to see when they're writing C++ programs what's so annoying about this is that this error message is as uninformative as it gets all I know is that there's been a seg fault somewhere in my program and it's up to me to find it this is where gdb comes in real handy we can open gdb with our source our our executable file and let's let's take a look I'll give you a spoiler that the segfault happens in our function crash which is a very descriptive function name as it points us in the right direction let's break so let's set a breakpoint at our function crash so there's our break point and then let's run our program so what's handy about our output here is that when we stop at our break point gdb will tell us not only the line that we're currently on but it will tell us here that's we're in function crash that was called with this value we can see the parameters that were passed to our function and as we can see here the value that was passed to I in this function was no pointers so we know that's the problem with our code happens sometime before crash was called now this is a pretty simple program but in larger programs where a function might be called at various points in our code we might want a way to kind of pinpoint where exactly this function call happened what what led up to this point how can we isolate the specific function call that led to our bug and at this point I mean if I hit next this is gonna get a complaint it's gonna seg fault because I would be trying to dereference a null pointer I have my I is a null pointer and here I'm dereferencing it so let's not do that let's not step forward in our code let's take a look at how we got here and gdb this is another one of its big strengths givea gives us the ability to navigate the call stack not only does it let us kind of take a peek at at the lower levels of the call stack but we can also take an overview glance and mess around with what we have so if I want to say - gdb tell me what what function called my function crash let's move up our stack frame let's move up our call stack and see what function call called our crash and in order to do this we have two new commands up and down and up and down allow us to peek up and down the call stack so for example if I type up here then we move up the call stack to our function f in which the function crash was called so we can move up and see that function crash was called at line 11 of our source code we can see that function f had this I passed to it so we can see that I is not null pointer which means that at some point between when function f was called and when function crash was called inside of F something happened to our pointer I can also continue to move up here on in my main function and we can see that F was called on line 16 of our main function and we can move back down with down to kind of go back down our call stack now we have enough information here to see that something happened inside of our function f so let's set a breakpoint at our function f and let's run our program from the start again so I'm going to type run it's gonna say the program being debugged has been started already let's say no let's start from the beginning yes and now we have arrived at our call of function f we can see that I is some valid pointer and that J is a pointer that is being set to equal whatever I is no let's keep track of what J is let's step through our code and keep track of what the value of our pointer J is before we get to our function crash and this way maybe we might be able to find out exactly where in our function f our pointer became a null pointer now one thing I could do is just print out the value of J but that becomes very tedious if I want to step through a lot of lines of code this will mean typing next then typing print J then typing next then typing print J and that's very tedious I would rather just tell gdb you know what every time I run a command tell me the value of J and this way just saves time for me and it also allows me to easily keep track of what the value of J is throughout my program running in order to do this we have a new command display D is PLA Y display and display tells gdb display the value J at every command we run so I type display J and this is going to print out it seems like it's just printing out the value of J but when I do next and move on to the next line of code we can see that alongside the line of code that we're running next it also prints out the current value of J so we know that after that line of code 8 right here we assign the value of I to J which is why in our when we get to line 9 J is equal to what our initial value of I was so let's take a few more steps through our code we have in our source code let's list it out first li st list so we can see here we assign I to J and then J is set to equal the result of sophisticated J and then complicated of J now these two functions are very sophisticated and very complicated and also we don't have access to their source code they have been compiled elsewhere and brought in for us and we can't really take a look inside of them so let's try stepping through our code so we've just run our function sophisticated and assigned the return value to J and we can see that at line 10 rj is still equal to what we want it to be so let's try stepping forward in our code and now we can see that after running our function complicated and assigning the return value to j that j is now no pointer which means that when we call our function crash it's going to crash using display is very handy because it allows us to kind of keep track of stuff without always continuously printing but if we're going through our code and then we say okay I've had enough of J I don't want you to keep reminding me what the value is I've seen what I need to see there is the corresponding command to display on display which funnily enough tells gdb to stop displaying J so when I say on display J my display number at or near J it will complain to me oh and sorry this is one thing with on display we do not tell it we when we say to display a variable we give the variable name when we say to undisplaced play so display a like display of ID one is keeping track of J I could make more displays I could say display I and you can see that this display has ID too so when I want to stay stop displaying I just say on display and give it the ID number so I say I'll just play one and then we're good to go when I step through my code it's gonna crash there we go broke right our back to our breakpoint crash and notice that now that we've left the scope of our call function we are not getting the display anymore well I think that that's it for that example oh one last point and one last command helps us kind of take a look at our call stack that comes in very handy since up-and-down are kind of limited like let's say I have some big program that has a ton of function calls if I want to kind of trace back what function calls led me to this current line I'm gonna have to type up and then go up and up and up and that's kind of annoying that's kind of tedious so I have a way of telling gdb hey instead of showing me one stack frame at a time print out the entire call stack and the command do this is called back trace BAC K tra see back trace and this will print back trace this will print the entire call stack every single function with all of the parameters passed to that function and the line in the code at which that function is like the different line in the source code where we can find that function so this can come in super handy when we're trying to kind of isolate parts of our code let's take a look at one more example where following the call stack can be kind of useful as some of you might remember from CS 135 there are some programming problems where the code that's required to solve that problem is a lot shorter if we make use of a very special tool called recursion I have fond memories of recursion I assume all of you love recursion as well let's take a look at a program I wrote called recursive and recursive solves a very common example problem when we're talking about recursion it calculates the factorial of some integer so my program has a main function that asks it prompts to input an integer you can give it an integer and if it's a positive integer it will calculate the factorial and then print it out and if it's not then it will complain so I try running my recursive program let's give it a nice small 1/4 and then outputs that 4 factorial is 24 now in the case of recursion we get a lot of function calls and if you remember the - G flag which we need to run gdb tells it not to optimize so a common optimization in which you might know about called tail recursion might kind of flatten out the call stack when we're using recursive functions but that's not the case here because we've told it not to optimize so when I call recursive here let's break at my function factorial factorial let's run the code let's enter a positive integer let's try 4 again because we know that one works and then we get to our function factorial and we know that we passed the value 4 to it now at this point I can step through my function factorial we start with an if statement if n which is sort of the same as saying if n is not 0 so type next again and then we reach our line where it tells it to return n times the factorial of n minus 1 and this is how we recursively can define the factorial function and you'll notice that there is a call to our factorial function a recursive call right here now at this point in the code we have a function call but I don't want to step over that function call I don't want to just kind of run that line of code and move on I actually want to jump into the function call I want to tell gdb don't just skip over this line go into my function factorial and let's walk through the lines of code inside the function we have another gdb command that will do that for us called step ste P and step unlike next will actually go inside any functions that are listed inside of our inside of our line of code there so when I tie up step here we now actually go into our factorial and as you can see here we're now in a call of factorial where n is equal to three so this is our recursive call if you remember a factorial before we called factorial on four and then internally we recursively called factorial of n minus one and here we are factorial of n minus 1 is factorial where N is equal to three so I have my recursive call here but it can get kind of long to do this sort of process with a recursive function especially if my function is quite long I don't want to have to step through every single line of code in order to step in in fact if we look at my line of code here I stepped into it but it told it told me hey just so you know this is a break point this is break point one at this line so let's see if we can make use of break points again to stop us from having to step through every line of code let's just say gdb keep running and instead of going one line at a time just run as many lines as you can until you reach the next breakpoint so at the next call of factorial it will stop at this breakpoint because it's a break point and we can kind of jump through our iterations of a recursive function more quickly that way so in order to tell it to keep running code and not stop one line at a time and to stop at a breakpoint we have the command continue continue cont I and Yui and it's basically like calling run except instead of starting from the beginning of the program we start from wherever we currently are in our running program so when I type continue we can see that we've reached our breakpoint at this in this case we had one breakpoint set to factorial and as we can see we are at the crawl of factorial where n is equal to two so this comes in very handy if we want to set numerous breakpoints throughout our program and kind of jump around we can set breakpoints wherever we need and then just kind of continue to jump to the next breakpoint that we set now let's keep going let's continue and we are at one and let's continue one more time so now we're at our base case now we're at our zero which means that if we were to run through this instead of trying to return n times factorial of n minus one our program just returns one yes I see a question why I type step here so the reason step is different is that okay actually yes fair point in this case because we have a break point the next would have actually stopped at that break point right there but if we had not had a break point inside of our function then we would have just kind of skipped over that function call so yes actually I can make an example of step later on where there isn't a break point inside but that is a fair point because there's a break point inside of a function if we try to use next to step over that function the break point will actually stop inside of our function and stop us from continuing so that's actually a fair point so from this point we're now at our base case we're at zero and instead of doing a recursive call it will return one now at this point if I if I continue to hit next it will just reach the end return and then I'll hop all the way back up to my main function call I don't really want to do that I want gdb to show me what it does as it unravels the stack in this recursive call so I want to tell gdb run this function run this current function call all the way to the end and then when you pop this current stack frame when you finish this current function stop the code this is just one of those other commands that allows you to kind of navigate through your code the command is called finish F I and I Sh finish and what finish allows us to do is tell gdb to finish this current function call and then stop once we've finished the call so once we pop that stack frame for that function stop there and if we take a look finish if I run finish here we will now hop out of our function call it says run till exit from number zero so this is a stack frame zero the top of a stack factorial and here's our function call it then gives us the function call that we've returned into the line that we've returned into and then which is very handy the value that our function returned so let's say we're trying to step through our code and we're inside of a function and we don't really care about what the function is doing we just want to we just want to see what the return value of the current function is we just give it finish and then we jump to the end and see the return value so let's run finish again as we can see it returns zero it returns one again because we did 1 factorial times 0 factorial 1 times 1 is 1 we can run a finish again we get 2 we run it again and as you can see we're unraveling the stack our recursive calls a factorial are returning these values and then we finish on our second-to-last stack frame at our main function where are called 2 factorial Levin has returned 24 and as we know that's the correct value so that's kind of a handy use of our of our stack frame of our ability to kind of navigate stack frames let's actually try this one more time and just to show you one more thing which can be handy when were you doing recursive calls if I want to say continue continue continue I am pretty deep in the stack and let's say I'm having a very big program that has a big recursive function that recurse is a bunch of times and I want to be able to trace down each of the parameters that was passed to my recursive function let's say it's not simple like this where it just goes down by one each time it could be something crazy who knows we can use back trace which can be abbreviated to BT and we can take a look at our stack right here and we can see that our recursive function the first call was passed with the value for the next with three and the next with two and we are currently at a call where we pass the number one so here's just another case where we can use back trace to kind of find out where we are no let's take a look at one more example where we have example - its Apple - it's a super long super complicated file not that long but it's not very obvious what things are doing these file these function names are not very descriptive we have our function small which divides an integer by 68 we have our bar which multiplies it by 3 and then returns the value of some unknown function we have our function roof which does some math and then also subtracts the value of a function call we have our function foo which calls a bunch of things it's all super complicated lots of funky math and at the end we have our main function and all this program does all we want our program to do is to make sure that at the end of our run of the program our variable X that we've declared and defined to be 10 in our main function all that we want is for it to not be equal to zero at the end of the program now as you might be able to predict when we run our program we get our error message x is 0 at the end of running the program this is not what we want so let's take a look at our program through the lens of gdb example 2 and let's set a breakpoint at our main function and let's run our program so we stopped it our main function in it next C n is gonna be sets 10 we get to our function call foo and I can tell you in advance foo is the problem at some point like if we check if we print out the value of x it's 10 so we know that sometime between sending it to 10 and checking the value it gets set to 0 and foo is the only function there so foo must be the problem and as we know foo calls a bunch of functions it does a bunch of complicated stuff it's really hard to follow oh I really care about in my program is when the value of x is changed all I want to know is at what point X is going to become a different value and specifically when it's going to become 0 now gdb offers more than one way to tell our program when to stop the first one which we know about is breakpoints we can tell it here's a line number and in a specific file or here's a function name once you reach this point in the code once you reach this line stop here but there's another way we can tell gdb when to stop and that is with watch points watc H watch and what the watch command does is it's pretty self descriptive we tell GDB GDB watch this variable don't take your eyes off of it and if anything changes let me know so I'm gonna tell gdb to watch my variable X and it says that it said a hardware watch point at variable X so it's gonna be keeping its eye on that variable and now let's run continue so let's continue through our code and then lo and behold our program has stopped at let's see line 11 of our example to example 2 dot C see file in the function bar where we pass the value 30 I don't even know how we got there but we can see here that at this specific line in the program at line 11 that the value of x has just changed it's changed from 10 to 30 now this is super handy as you can probably imagine if we don't necessarily have a specific line and the code we want to stop to but we just want to kind of keep track of a variable and know when it's being changed something we don't want I can keep continuing through my program it's super complicated the value of x changes a few times to a bunch of values until it changes to negative one and then it gets set to zero and then we can continue through here and then we reach the end of our program where we get our output right here error X is set to zero but through using watch points we're able to determine that inside of our function foo just before line 25 our value of X was set to zero we can take a look and lists you can specify a line width list or lis DL for short and should probably their list 25 if we take a look at line 25 here the line before is where it was changed and you can see here we've incrementing the value of Z which happens to be a reference to our value X so that's just kind of one case where watch points are super super handy and one more point on watch points if we are debugging a really big program and I know this has happened to me where I'm going through my code I'm trying to kind of narrow down where my error is occurring and I'm sending a bunch of breakpoints I'm setting a breakpoint at main I'm setting it like the function I think it's that's the problem I'm sitting at specific lines to kind of try and pinpoint where exactly the error is the program is too big to just step through so I'm just setting breakpoints and when I find the error I want to keep debug in my code I want to keep stepping through but I have all these breakpoints that are getting in the way it's slowing me down I'm trying to continue through my code and it just keeps stopping me well gdb understands that it knows that even if you set a breakpoint at the beginning you might not want it all the way through your debugging process so it gives us not only a way to print out what what breakpoints and watch points we currently have set but also a way to remove them when we're done with them so we have the command info which is a very versatile command info is info has a lot of different uses but we can type info breakpoints points and when we type that my watch point was deleted with the previous run but let's just say watch X let's info break points and here we get as output a nice little table that gives us all the information we need the ID number of the break point or watch point but type so we have a break point here we have this one which was already dealt with we have our Hardware watch point that we just set and then a bunch of other details and it tells you what it's following here it's looking for this specific line and our watch point is following variable X now that we know what we are actually following what our watch points and break points are keeping track of we can tell gdb I'm done with them let's get rid of them and aptly-named and very descriptive that's a B not a D we can delete our break points and watch points de le te delete now if I type delete if you remember from before we don't give the name we give the ID number I want to delete the watch point that I just made this specific watch point right here i'm gonna type delete 3 and it seems like nothing's happened but when I check my break points here my break point is gone don't need to worry about it anymore or in this case my watch point is gone and I can keep going through my code without worrying about being stopped if I want to keep going through my code and I say I'm done with him all of my breakpoints in watch points I just want to get I want to clear the slate start over again typing delete on its own without any any variable any any parameters will delete all of my breakpoints in watch points and it will prompt it will say are you sure do you want to delete them all and I can say yes I hate this breakpoint time to die and then we're free of that breakpoint small side note info breakpoints is very long to type I space B also works and if we take a look now info breakpoints tells us that there are no more breakpoints or watch points which is nice because that's what we were trying to do I have one last example and let's just make sure we've gone through everything there's one more actually there's one more command that is handy if we go back to our basic program basic and if you're trying to run a program be sure to leave gdb before you try to run gdb basic one so let's break at the main function and run our program let's step through so we have our variables J and K not only can we print out the value of J but we can say what is J sometimes we have a bunch of complicated programs and we forget the type of what we're working with this often happens we're working on really really big programs and you just see a variable name for like 50 lines of code you forget what exactly is this I can say what is J and it will tell me that the type of J is int shorthand for what is it's just what J and then we also get that J is an integer now those are but this kind of list is pretty much this should this should suffice for the course of the term you should be able to do all of your debugging with these commands this is kind of the gist of what I had off the top of my head when I started working on this tutorial but over the course of doing research for this tutorial I happened upon a couple more really really useful commands that I wish I would have known in CS 246 so I'm going to share them with you in the last couple minutes of this tutorial so that you guys are going to be like super debuggers and we'll have a much easier time than I had when I was writing programs for this course so I have a program here called example three so you see and example three not super complicated we have integer X which is set to 16 we run some mystery function on X and we give it one who knows what it's gonna do and then here all we say is X mod 2 which means what's the remainder when we divide by 2 in other words if X is odd run function fun if X is even in other words X mod 2 is 0 run function funner now these functions who knows what they do we try running our program example 3 we get CS 1 36 CS 1 36 a bunch of times and then I can't wait for CS 2 46 now let's debug let's not really debug this program is pretty cool already but let's take a look at what's going on inside of our program and kind of see what these special commands are so let's set a breakpoint at main and run our program so we are here our main function now there are times that I've happened upon while debugging where I'm stepping through my program I'm just rapidly hitting hitting Enter just kind of stepping through getting to the point I want and I'm like gosh Diggity darn it I passed the line that I want to stop at all my variables are messed up now what am I supposed to do well gdb a few years ago implemented what I think is a very cool feature which I call reverse debugging which basically allows us not only to run our program as we've written it but to start at a certain point in our program and run it in reverse step back one line at a time and undo commands that we've run this comes in super handy and I wish I had known this when I was taking 246 this functionality and probably obviously be finicky sometimes and might not always work there are cases where the compiled code can't really figure out what the previous step was and in the case of the student environment on its own we can't really extrapolate what old values of variables are just from the code itself so in order to make use of this functionality we need to tell gdb before we get started like we've stopped at our break point at this point onwards record everything that happens keep track of every change of every variable every line that we run so let's we have our advanced functions here our advanced commands in order to tell gdb to record what happens in order to kind of replay in reverse we type target ta rget target record space no space target space record - full and this tells it record everything from this point onward so when I say target record full seems like nothing's happened but let's step through our code so we assign 16 to acts we run mystery we get here and I'm like wait a second let's take a look let's print out X right now okay X is 17 right now what was X before I ran mystery let's imagine there's a bunch of lines of code there what was X before I run mystery well I just used the next command to jump to step through my code let's use reverse next and look now we are right before we called our mystery function and if I print out the value of x now it's back to being 16 just like it was before rivers next is long to write so we can just write our and and that takes us back one more step there are also other commands for example reverse step which is RS and reverse continue so if you want and say let's jump back to this point in the code you can set a breakpoint before where you currently are and then just reverse back up at that point now this is super handy but there are where it might not work just because it's it's a finicky feature but let's let's try running our program once more so now that we know that when the program is as it is currently when X is set to 16 at the beginning our program says 136 136 a bunch of times honestly I would rather it say 246 let's change the behavior of our program now normally if I find a bug in my code and I want to change what my program does I have to shut down gdb go to my source code change all my source code recompile reopen gdb set all my breakpoints again run through my code it's a super long process no one wants to do that if you find a small thing in your code you just want to say hey if I change this value will the behavior change then gdb gives us a way while running our program to change the behavior and one way in which it allows us to do that let's say I'm running my program and X here has been set to 16 and here I get to mystery and I say I know what this is gonna do it's gonna set it to 17 which is odd let's change the value of x before we run mystery and see what happens and the way we do this is with the command set and similarly to info set has a lot of uses so we want to specify set var so SVT space var set variable and then we could say x equals 15 actually that's a race now that's not part of the command but let's see where that actually does if I say set bar x equals to 15 and we print out the value of x remember we just set X to 16 and I print out X we get 15 which means when I run my code when I continue my code we get this beautiful output CS 246 I love CS 246 thank you very much for coming to this tutorial I hope you found it useful and good luck with the next assignment [Applause]
Info
Channel: CS 246
Views: 14,482
Rating: 4.9507389 out of 5
Keywords:
Id: svG6OPyKsrw
Channel Id: undefined
Length: 55min 12sec (3312 seconds)
Published: Fri Jun 21 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.