
Learning C with gdb - happy4crazy
https://www.hackerschool.com/blog/5-learning-c-with-gdb
======
breckinloggins
Also cool to play around with are the various options that let GCC (and
presumably LLVM) show you the various compilation stages of your C code. You
can even spit out the C and resulting assembly side-by-side.

I haven't had the time to play with this, but Part 4 of the excellent "Unix as
IDE" series [1] goes into it and I'm sure there's more around the web.

Another _really_ fun way to get into the underlying assembler that the C
compiler generates is Vidar Hokstad's "Writing a compiler in Ruby, bottom up"
[2]. This series involves writing little C functions, compiling them to the
simplest assembly you can get, then writing a ruby compiler (in Ruby!) that
emits that assembly. Some people have objections to the approach, but it's
really quite nifty. I especially like it because it's really refreshing to see
a compiler tutorial that _doesn't_ start with the lexer and parser.

[1] <http://blog.sanctum.geek.nz/unix-as-ide-compiling/> [2]
<http://www.hokstad.com/compiler>

------
dkhenry
GDB skills are one of those super useful abilities that you just can't find in
most CS graduates. I often spend a few days with new C developers just
teaching them how to use GDB to find problems. They are amazed when they find
out you can examine variables and set conditional breakpoints.

~~~
jobu
This is an area where many college professors fall short. In my intro to CS
class we learned C, and the professor explicitly told us to debug our code
with printf statements. It wasn't until my first job that I even found out
about gdb. I can't believe how much time I wasted trying to debug C and C++
code in college with nothing more than printf and cout.

~~~
dkhenry
What makes it even worse is the lack of a REPL means that between each change
you need to recompile. In any large program this is going to take minutes and
they add up. A simple GDB invocation is not only a better way of tracking it
down, but can potently save hours.

~~~
rll
Well, ccache helps a lot with that. And sometimes it becomes easier to throw
an __asm__("int3"); into your code than try to massage gdb into breaking at
the exact right spot in your code and only under certain conditions.

~~~
apaprocki
Use of __builtin_trap() (GCC) or raise(SIGTRAP) would be a lot more portable.

------
codeinthehole
If you enjoyed this, then you'll certainly enjoy the programming chapter of
'Hacking: The Art of Exploitation' by Jon Erickson
([http://en.wikipedia.org/wiki/Hacking:_The_Art_of_Exploitatio...](http://en.wikipedia.org/wiki/Hacking:_The_Art_of_Exploitation)).
The first half of the book is a similar exploration of C programming using GDB
to explain everything. Recommended.

~~~
happy4crazy
Hacker School agrees--we have two copies in our library :)

------
tmurray
I'm surprised nobody's linked the gdb reference card. It's fairly old now, but
it's still handy if you don't use gdb that often:

<http://users.ece.utexas.edu/~adnan/gdb-refcard.pdf>

~~~
reirob
Many thanks for this link. Exactly what I need at the moment.

------
Derbasti
While graphical debuggers are great overall, there are times when I prefer to
get down to the command line and do my debugging there. And quite
surprisingly, I don't lose much efficiency there, either.

But then, this could be the story of most command line utilities: Seems fiddly
at first, but actually it is quite usable and often times more convenient than
all those whiz-bang graphical tools.

~~~
dkhenry
The only thing I like about graphical debuggers is the ease of which you can
set up multi-window dashboards. I can have my stack windows a few watched
variables and the code all on one screen at the same time as I step through
the program

------
winter_blue
The visual debugger in both Eclipse CDT and Visual C++ let you do things like
create breakpoints, step through your program, monitor variable values, even
create conditional breakpoints that are triggered when a particular lineof
code is executed n number of times or when some particular expression
involving variables in the local context of the breakpoint turn true.

My question is, what advantages do you get in using gdb directly through the
CLI rather than through an IDE? (like Eclipse/NetBeans which itself uses gdb
for C/C++ debugging, but has a nice graphical UI for it.)

~~~
ajross
Flip it around: what advantage does a "nice graphical UI" give you for what is
fundamentally a text processing problem. Except for the most basic stuff
(starting, stopping, setting a breakpoint at a line, looking at a variable
value) everything you want to do in gdb involves something approximating a
query language: set a watchpoint on the 32 bit quantity stored at this
address; dump memory from this pointer; call this function (e.g. strstr() on a
memory region) and tell me the result.

Watching your code run and hitting a "next" button repeatedly isn't really a
good use of the tool.

~~~
winter_blue
> Watching your code run and hitting a "next" button repeatedly isn't really a
> good use of the tool.

It's really useful to get yourself familiar with someone else's code.

------
stcredzero
There was a debugger posted here to HN awhile back that actually displayed
structs and pointers graphically. What was the name of that project, and is it
still around? I was trying to find it the other day. I thought that was a
dynamite tool for students.

With LLVM, we should be able to have a REPL for C. as a pedagogical tool.

~~~
SAHChandler
I believe it was Tenacious-C: <http://tenaciousc.com/>

~~~
stcredzero
Yes, that was it! We have a winner! (A wiener?)

~~~
heretohelp
Sadly, Windows-only.

------
X-Istence
lldb would be even better for using instead of gdb because lldb actually uses
clang's parsing for everything.

I was watching an Apple talk on lldb which explained this in more detail, and
it shows a lot of promise for a debugger to have a full C compiler inside of
it.

------
jparishy
This is pretty neat, though I found myself doing similar things in small test
files when I was first learning C and printing the results. C compile times
suck, but with like a 10 line program or so to toy with a language semantic,
it was practically instant (in 2007). But then again I had never used a
dynamic language like Ruby/Python before then so I didn't know better.

More people should be hopping on this bandwagon though because debuggers are
awesome. I typically find myself using `po` the most in LLDB (Xcode, iOS
development) but it's insanely useful especially when Xcode refuses to show me
the values of something I want in the Variables View, ex. NSDictionary
keys/values, objects in an NSArray, etc. I'll also use it sometimes to execute
simple commands like `[myArrayObject count]` when the Variables View refuses
to show me property values. Sometimes Xcode's GUI bits just don't cut it!

There's more info on what you can do with LLDB here:
<http://lldb.llvm.org/tutorial.html>

And if you've used GDB, this might be of use: <http://lldb.llvm.org/lldb-
gdb.html>

~~~
geoka9
> C compile times suck

Can I ask you what you're comparing with? I can compare with C++, Scala and
Go. The first two are horrible in that department when compared with C. Go's
compiles are blazingly fast.

~~~
jparishy
I'm not really comparing it to anything, just speaking from experience of
having waited many hours waiting for C programs to compile in the past.

~~~
ghshephard
Isn't the job of your Makefile to require recompilation of only those source
files that have changed?

I just did a random google of "how long to compile linux kernel" and came
across this: <https://plus.google.com/u/0/+LinusTorvalds/posts/6BxnSisp8fU>

One nice excerpt:

"Total build time after make clean is about 1min, give or take 10secs. `touch
include/linux/version.h` is 6 seconds to rebuild. Just doing a rebuild without
touching anything is 2.7secs.

For a defconfig, it does build a godawful amount of modules :^)

'allnoconfig; make' is 16 seconds...﻿"

~~~
infinite8s
You've probably never tried compiling the linux kernel back in the late 90s
with a top of the line machine (hint - gcc was slow, it would take over 35
minutes or so to compile from scratch) ;)

------
doctorwho
It's great for instant feedback but IMHO interactive programming makes it easy
(or at least easier) to be lazy. If you get used to coding by trial and error
you'll never really understand the language or the problem you're trying to
solve, you'll just keep trying things until it works. I know that's not how
everyone approaches programming but I've seen it far too often to dismiss it

------
geoka9
There's also CINT (a C interpreter), which can be used as a REPL:

<http://root.cern.ch/drupal/content/cint>

------
djcb
for the somewhat-graphically-inclined, gdb mode in emacs has the much under-
advertized 'M-x gdb-many-windows' which shows your stack, local variables,
breakpoints etc. in separate 'windows'.

------
iopuy
I find the basic c tutorials a nice refresher. Here is one from a few weeks
back on memory addresses and pointers in c
<http://news.ycombinator.com/item?id=4399498> .

------
agumonkey
gdb is like acid, works everywhere : <https://stripe.com/blog/exploring-
python-using-gdb>

~~~
happy4crazy
That post was one of the things that inspired me to start tinkering with gdb.
Very cool stuff.

~~~
agumonkey
It broke a mental barrier I had gdb begin for `native only` programs.

------
joeld42
This looks really great, but I'd call it "Learning GDB with C"

------
phao
Very interesting! But I'd say this is too dangerous because of the misleading
conclusions that it'd "make" you realize.

Relying on what is printed out of printing a pointer value (which is not what
the author is doing) is also misleading. Concluding stuff like "the size of an
int is 4" or "size of double is 8" is also misleading. Again, it's not the
conclusions the author is realizing, but for someone doing exploratory
programming, it may be the case since the point of exploratory programming is
learning by seeing how the system responds to the things you're doing.

And maybe I am wrong, but even the author got mislead by it.

"I'm going to ignore why 2147483648 == -2147483648; the point is that even
arithmetic can be tricky in C, and gdb understands C arithmetic."

That's actually the result of undefined behavior, and not so much a result or
"how C integer arithmetic works".

I really liked the idea. I just think it may be misleading if the tool you're
using is GDB.

It'd be interesting a tool which allowed that sort of exploratory programming,
but taking into consideration undefined behavior, unspecified things and
implementation defined behavior.

~~~
AYBABTME
That's not undefined, it's simply the bitwise representation of a 32 bits
integer.

~~~
phao
C allows more than 1 representation for integers. I know at least 3 possible
ones: two's complement, ones' complement and signed magnitude.

The "natural wrap up" is not the same in all of the representations.

When the integer is unsigned, C gives you more guarantees, but for signed
types, you're out of luck, and get to undefined bahvior land.

Check this out: <http://web.torek.net/torek/c/numbers.html>

And as an after note...

The maximum int may be less than 2^31-1. Maybe your C implementation decides
that your int type will be a 16bits object with values ranging from -2^15 to
2^15-1. In that case, that integer literal would not be an int, and is likely
to be a long, and maybe, in this same implementation, a long is a 61bit object
ranging from -2^63 to 2^63-1. In that case, that assertion is just plain
false. That's not the system exposed in the article though. But it could
happen in some other system.

This can be true even on a 32bit system.

------
sswezey
Having programmed a fair amount of C, I regret never learning properly how to
use gdb. This article is quite helpful!

~~~
eru
It's never too late to start.

------
jfaucett
Does anyone else think debuggers are awesome for learning how
programs/languages work? Its pretty much always the first thing I do, even
before reading docs, build and debug.

------
m_eiman
Here's a more full-featured C++ REPL:
<http://root.cern.ch/drupal/content/what-cling>

~~~
Create
...except, that it isn't C++ standard compliant, and you are worse off than
when you started out. "full-featured C++" is misleading.

<http://www.insectnation.org/howto/living-without-root>

<https://linuxfr.org/nodes/18919/comments/632920>

<http://comments.gmane.org/gmane.comp.lang.c%2B%2B.root/5924>

~~~
octopus
You are making a confusion here, CINT != CLING.

~~~
Create
CINT referenced, because CLING hasn't seen deployment and real tests. Maybe in
a few years.

------
narrator
I just got back into C programming after a long absence. Programming with
Eclipse CDT is the way to go, at least for starting out. The debugger is
great.

------
stonefroot
I want to be able to do this with assembly, e.g., see what is in each register
as I step through the program.

~~~
duaneb
GDB can step through instruction by instruction, and you can easily examine
registers.

~~~
stonefroot
Can I do this with a hand-written assembly program, i.e. not necessarily one
that has been compiled with as and subject to GNU default optimisations or
"constraints"?

~~~
cfallin
The commands you want are "stepi" (single-step one instruction), "disass"
(disassemble at the current point in the program), and "info registers" (show
you what's in all of the registers). These work equally well for hand-written
assembly and for any arbitrary compiled program.

~~~
stonefroot
cfallin: many, many thanks.

I guess should read the gdb manual, and, if it's anything like the as manual
(which I've learned is not always the full story), the source too.

------
wildmXranat
In addition to the gdb command, what would be a good GUI front-end for it ?

~~~
mtoddh
Emacs actually integrates pretty nicely with gdb. Just split the source file
being debugged horizontally and fire up gdb in the other window:

Split the windows horizontally: C-x 2 Switch to the other window: C-x o Fire
up gdb: M-x gdb

You can set breakpoints with C-x <SPC>. Emacs will show an arrow next the
source line about to be executed.

~~~
edge17
yea, agree with this. emacs integration is very nice. as a side note, if
you're particularly aggressive with gdb or the project you're working on is
very large it helps to increase the buffer size significantly

------
shocks
You should use debugging not only to learn and fix bugs, but also to check
your code actually does what you think it does.

------
agrona
gdb is one of those tools that I regret never learning because I've always had
an IDE. I was able to follow the examples here well enough, but the array
assignment causes gdb to crash in Cygwin. Does anyone have any suggestions for
how to overcome that (short of installing a vm & a real linux)?

------
16s
gdb is very nice. I use it with C++ too. Watch sizeof on char arrays. Why is
my string's sizeof always 8? That confuses some when starting out.

~~~
lysol
That's because sizeof is for the size of the variable (a char pointer), not
the size of the string up to the null terminator, which is what strlen's for.

------
izx
don't forget about panel mode in gdb!

ctrl-x, a

to toggle it on/off

