>> DOUG LLOYD: All right GDB.
What is it exactly?
So GDB, which stands for the GNU Debugger,
is a really awesome tool that we can use to help us debug our programs,
or find out where things are going wrong in our programs.
GDB is amazingly powerful, but the output and interaction with it
can be a little bit cryptic.
It's usually a command line tool, and it can throw a lot of messages at you.
And it can kind of hard to parse exactly what's going on.
Fortunately, we've taken steps to fix this problem for you
as you work through CS50.
If you aren't using the graphical debugger, which my colleague Dan
Armandarse has spoken quite a bit about in a video that
should be over here right now, you might need
to use these command line tools to work with GDB.
If you're working in the CS50 IDE, you don't need to do this.
But if you're not working in the CS50 IDE,
perhaps using a version of CS50 Appliance,
or another Linux operating system with GDB installed on it,
you may need to use these command line tools.
>> And since you might have to do that, it's
useful just to understand how GDB works from the command line.
But again, if you're using the CS50 IDE, you
can use the graphical debugger that is built into the IDE.
So to get things going with GDB, to start the debugging
process of a particular program, all you need do
is type GDB followed by the program name.
So for example, if your program is hello, you would type GDB hello.
>> When you do that, you're going to pull up the GDB environment.
Your prompt will change, and instead of being what it usually
is when you type things at the command line-- ls,
cd-- all of your typical Linux commands, your prompt
will change to, probably, something like parentheses GDB parentheses.
That's your new GDB prompt, because you're inside the GDB environment.
Once inside of that environment, there's two major commands
that you'll probably use in the following order.
>> The first is b, which is short for break.
And after you type b, you typically type the name of a function,
or if you happen to know around what line number
your program is starting to behave a little weird,
you can type a line number there as well.
What b, or break, does is it allows your program
to run up until a certain point, namely, the name of the function
that you specify or the line number that you specify.
>> And at that point, it will freeze execution.
This is a really good thing, because once execution has been frozen,
you can begin to very slowly step through your program.
Typically, if you've been running your programs, they're pretty short.
Usually, you type dot slash whatever the name of your program is, hit Enter,
and before you can blink, your program is already finished.
It's not really a lot of time to try and figure out what's going wrong.
So it really to be able to slow things down by setting a break point with b,
and then stepping in.
>> Then once you've set your break point, you can run the program.
And if you have any command line arguments,
you specify them here, not when you type GDB your program name.
You specify all the command line arguments by taking r, or run,
and then whatever command line arguments you need inside of your program.
There are a number of other really important and useful commands
inside of the GDP environment.
So let me just quickly go over some of them.
>> The first is n, which is short for next, and you can type next instead of n,
both would work.
And it's just the shorthand.
And as you've probably already gotten used to, being able to type things
shorter is generally better.
And what it will do is it'll step forward one block of code.
So it'll move forward until a function call.
And then instead of diving into that function
and going through all of that functions code, it will just have the function.
>> The function will be called.
It will do whatever its work is.
It will return a value to the function that called it.
And then you'll move on to the next line of that calling function.
If you want to step inside of the function,
instead of just having it execute, especially
if you think that the problem might lie inside of that function,
you could, of course, set a break point inside of that function.
Or if you're already running, you can use s to step forward one line of code.
>> So this will step in and dive into functions,
instead of just have the execute and continuing on in the function
that you're in for debugging.
If you ever want to know the value of a variable,
you can type p, or Print, and then the variable name.
And that will print out to you, inside of the GDB environment,
the name of the variable, that you-- excuse me-- the value of the variable
that you've named.
If you want to know the values of every local variable accessible from where
you currently are in your program, you can type info locals.
It's a lot faster than typing p and then whatever,
listing out all of the variables that you know exist.
You can type info locals, and it will print out everything for you.
Next up is bt, which is short for Back Trace.
Now, generally, particularly early in CS50,
you won't really have occasion to use bt, or Back Trace,
because you're not having functions that call other functions.
>> You might have main call a function, but that's probably it.
You don't have that other function calling another function, which
calls another function, and so on.
But as your programs get more complex, and particularly
when you begin working with recursion, back trace
can be a really useful way to let you kind of get some context for where
I am in my program.
So say you've written your code, and you know that main calls a function
f, which calls a function g, which calls a function h.
So we have several layers of nesting going on here.
>> If you're inside of your GDB environment,
and you know your inside of h, but you forget
about what got you to where you are-- you can type bt, or back trace,
and it will print out h, g, f main, alongside some other information, which
gives you a clue that, OK main called f, f called g, g called h,
and that's where I currently am in my program.
So it can be really useful, especially as the cryptic-ness of GDB
becomes a little overwhelming, to find out exactly where things are.
Finally, when your program is done, or when you're done debugging it
and you want to step away from the GDB environment,
it helps to know how to get out of it.
You can type q, or Quit, to get out.
Now, before today's video I prepared a buggy program
called buggy1, which I compiled from a file known as buggy1.c.
As you might expect, this program is in fact buggy.
Something goes wrong when I try and run it.
Now, unfortunately, I inadvertently deleted my buggy1.c file,
so in order for me to figure out what's going wrong with this program,
I'm going to have to use GDB kind of blindly, trying
to navigate through this program to figure out exactly what's going wrong.
But using just the tools we've already learned about,
we can pretty much figure out exactly what it is.
So let's head over to CS50 IDE and have a look.
OK, so we're here in my CS50 IDE environment,
and I'll zoom in a little bit so you can see a little more.
In my terminal window, if I list the contents of my current director
with ls, we'll see that I have a couple of source files
here, including the previously discussed buggy1.
What exactly goes on when I try and run buggy1.
Well let's find out.
I type dot slash, buggy, and I hit Enter.
>> Segmentation faults.
That's not good.
If you recall, a segmentation fault typically
occurs when we access memory that we're not allowed to touch.
We've somehow reached outside of the bounds
of what the program, the compiler, has given us.
And so already that's a clue to keep in the toolbox
as we begin the debugging process.
Something has gone a little wrong here.
>> All right, so let's start up the GDB environment
and see if we can figure out what exactly the problem is.
I'm going to clear my screen, and I'm going to type GDB
again, to enter the GDB environment, and the name of the program
that I want to debug, buggy1.
We get a little message, reading symbols from buggy1, done.
All that means is it pulled together all of the code,
and now it's been loaded into GDB, and it's ready to go.
>> Now, what do I want to do?
Do you recall what the first step typically is
after I'm inside of this environment?
Hopefully, you said set a break point, because
in fact that is what I want to do.
Now, I don't have the source code for this
in front of me, which is probably not the typical use case, by the way.
You probably will.
So that's good.
But assuming you don't, what's the one function that you know
exists in every single C program?
No matter how big or how complicated it is, this function definitely exists.
Main, right?
>> So failing all else, we can set a break point at main.
And again, I could just type break main, instead of b.
And if you're curious, if you ever type out a long command
and then realize that you typed the wrong thing,
and you want to get rid of all as I just did,
you can take Control U, which will delete everything and bring you back
to the beginning of the cursor lines.
A lot faster than just hold down the delete, or hitting it a bunch times
over.
>> So we'll set a break point at main.
And as you can see, it says we've set a break point at file buggy1.c,
and apparently the first line of code of main is line seven.
Again, we don't have the source file here,
but I'll assume that it's telling me the truth.
And then, I'm just trying and run the program, r.
Starting program.
All right, so this message is a little cryptic.
But basically what's happening here is it's just
telling me I've hit my break point, break point number 1.
>> And then, that line of code, no such file or directory.
The only reason that I'm seeing that message
is because I inadvertently deleted my buggy.c file.
If my buggy1.c file existed in the current directory,
that line right there would actually tell me what the line of code
literally reads.
Unfortunately, I deleted it.
We're going to have to kind of navigate through this a little more blindly.
>> OK, so let's see, what do I want to do here?
Well, I would like to know what local variables maybe are available to me.
I've started my program.
Let's see what might be already initialized for us.
I type Info locals, no locals.
All right, so that doesn't give me a ton of information.
I could try and print out a variable, but I don't know any variable names.
I could try a back trace, but I'm inside of main,
so I know I haven't made another function call right now.
>> So looks like my only options are to use n or so and start to dive in.
I'm going to use n.
So I type n.
Oh my gosh, what is going on here.
Program received signals, SIGSEGV segmentation fault,
and then a whole bunch of stuff.
I'm already overwhelmed.
Well, there's actually a lot to be learned here.
So what does this tell us?
What it tells us is, this program is about to, but hasn't yet, seg fault.
And in particular, I'm going to zoom in even further here,
it's about to seg fault about something called strcmp.
>> Now, we may not have discussed this function extensively.
But it is-- because we're not going to talk about every function that
exists in the C standard library-- but they're all available to you,
particularly if you take a look at reference.cs50.net.
And strcmp is a really powerful function that exists inside
of the string.h header file, which is a header
file that is dedicated to functions that work with and manipulate strings.
>> And in particular, what strcmp does is it compares the values of two strings.
So I'm about to segmentation fault on a call to strcmp it seems.
I hit n, and in fact I get the message, program terminated with signal SIGSEGV
segmentation fault. So now I actually have seg faulted,
and my program has pretty much effectively given up.
This is the end of the program.
It broke down, it crashed.
So wasn't a lot, but I actually did learn quite a bit
from this little experience.
What have I learned?
Well, my program crashes pretty much immediately.
My program crashes on a call to strcmp, but I
don't have any local variables in my program at the time that it crashes.
So what string, or strings, could I possibly be comparing.
If I don't have any local variables, you might
surmise that I have-- there maybe is a global variable, which could be true.
>> But generally, it seems like I'm comparing
to something that doesn't exist.
So let's investigate that a little further.
So I'm going to clear my screen.
I'm going to quit out of the GDB environment for a second.
And I'm thinking, OK, so there's no local variables in my program.
I wonder if maybe I'm supposed to pass in a string as a command line argument.
So let's just test this out.
I haven't done this before.
>> Let's see if maybe if I run this program with a command line argument it works.
Huh, no segmentation fault there.
It just told me that I figured it out.
So maybe that's the fix here.
And indeed, if I go back and look at the actual source code for buggy1.c,
it seems as though what I'm doing is I'm making a call to strcmp without
checking whether in fact argv[1] exists.
This is actually the source code for buggy1.c.
So what I really need to do here to fix my program,
assuming I have the file in front of me, is
to just add a check to make sure that argc is equal to 2.
So this example, again, like I said, is a little bit contrived, right?
You're generally not going to accidentally delete your source code
and then have to try and debug the program.
But hopefully, it gave you an illustration
of the kinds of things that you could be thinking about
as you're debugging your program.
>> What's the state of affairs here?
What variables do I have accessible to me?
Where exactly is my program crashing, on what line,
on what call to what function?
What kind of clues does that give me?
And that's exactly the kind of mindset that you
should be getting into when you're thinking about debugging your programs.
>> I'm Doug Lloyd.
This is CS50.