Update the debugging section to include lldb as well.

Clean up the sections a bit to distinguish the two available debuggers (gdb
and llvm).  This includes giving the existing gdb sections a title that
ends in "with gdb". The existing gdb section were grouped together into a
new "Using gdb" section and moved up one section level (sect3 to sect2).

A new section "Introduction to available debuggers" introduces and
distinguishes gbd and lldb. Insert a new "Using lldb" section after the
introduction, using the same structure and example code as the gdb section
to ease comparison between the two compilers.

An earlier reference to gdb is replaced by a generic debugger reference.
Include the neccessary whitespace changes. On top of that, update copyright
years of the developers-handbook.

Thanks to Pau Amma for his diligent work on the patch and incorporating
our feedback from the review!

Submitted by:	    pauamma_gundo.com
Reviewed by:	    debdrup, woodsb02, emaste, bcr
Approved by:	    bcr
Differential Revision:	https://reviews.freebsd.org/D25139
This commit is contained in:
Benedict Reuschling 2020-06-15 08:13:08 +00:00
parent 6fd6f2470f
commit 7bcd3378e9
Notes: svn2git 2020-12-08 03:00:23 +00:00
svn path=/head/; revision=54255
2 changed files with 407 additions and 91 deletions

View file

@ -36,6 +36,8 @@
<year>2016</year>
<year>2017</year>
<year>2018</year>
<year>2019</year>
<year>2020</year>
<holder>The FreeBSD Documentation Project</holder>
</copyright>

View file

@ -832,7 +832,7 @@ int main() {
</question>
<answer>
<para>Use <command>gdb</command> to analyze the core (see
<para>Use a debugger to analyze the core (see
<xref linkend="debugging"/>).</para>
</answer>
</qandaentry>
@ -967,12 +967,12 @@ free(foo);</programlisting>
<para>Alternatively, you can create a core dump from
inside your program, by calling the
<function>abort()</function> function. See the manual
<function>abort()</function> function. See the manual
page of &man.abort.3; to learn more.</para>
<para>If you want to create a core dump from outside your
program, but do not want the process to terminate, you
can use the <command>gcore</command> program. See the
can use the <command>gcore</command> program. See the
manual page of &man.gcore.1; for more
information.</para>
</answer>
@ -1325,75 +1325,389 @@ DISTFILES= scheme-microcode+dist-7.3-freebsd.tgz
<title>Debugging</title>
<sect2>
<title>The Debugger</title>
<title>Introduction to Available Debuggers</title>
<para>The debugger that comes with FreeBSD is called
<para>Using a debugger allows running the program under more
controlled circumstances. Typically, it is possible to step
through the program a line at a time, inspect the value of
variables, change them, tell the debugger to run up to a
certain point and then stop, and so on. It is also possible
to attach to a program that is already running, or load a core
file to investigate why the program crashed. It is even
possible to debug the kernel, though that is a little trickier
than the user applications we will be discussing in this
section.</para>
<para>This section is intended to be a quick introduction to
using debuggers and does not cover specialized topics such as
debugging the kernel. For more information about that, refer
to <xref linkend="kerneldebug" />.</para>
<para>The standard debugger supplied with
&os;&nbsp;&rel121.current; is called <command>lldb</command>
(<application>LLVM debugger</application>). As it is part of
the standard installation for that release, there is no need
to do anything special to use it. It has good command help,
accessible via the <userinput>help</userinput> command, as
well as <link xlink:href="https://lldb.llvm.org/">a web
tutorial and documentation</link>.</para>
<note>
<para>The <command>lldb</command> command is available for
&os;&nbsp;&rel1.current; <link
xlink:href="&url.books.handbook;/ports-using.html">from
ports or packages</link> as
<package>devel/llvm</package>. This will install the
default version of lldb (currently 9.0).</para>
</note>
<para>The other debugger available with &os; is called
<command>gdb</command> (<application>GNU
debugger</application>). You start it up by typing</para>
debugger</application>). Unlike lldb, it is not installed
by default on &os;&nbsp;&rel121.current;; to use it, <link
xlink:href="&url.books.handbook;/ports-using.html">install</link>
<package>devel/gdb</package> from ports or packages. The
version installed by default on &os;&nbsp;&rel1.current; is
old; instead, install <package>devel/gdb</package> there as
well. It has quite good on-line help, as well as a set of
info pages.</para>
<para>Which one to use is largely a matter of taste. If
familiar with one only, use that one. People familiar
with neither or both but wanting to use one from inside
<application>Emacs</application> will need to use
<command>gdb</command> as <command>lldb</command> is
unsupported by <application>Emacs</application>. Otherwise,
try both and see which one you prefer.</para>
</sect2>
<sect2>
<title>Using lldb</title>
<sect3>
<title>Starting lldb</title>
<para>Start up lldb by typing</para>
<screen>&prompt.user; <userinput>lldb -- <replaceable>progname</replaceable></userinput></screen>
</sect3>
<sect3>
<title>Running a Program with lldb</title>
<para>Compile the program with <option>-g</option> to get the
most out of using <command>lldb</command>. It will work
without, but will only display the name of the function
currently running, instead of the source code. If it
displays a line like:</para>
<screen>Breakpoint 1: where = temp`main, address = &hellip;</screen>
<para>(without an indication of source code filename and line
number) when setting a breakpoint, this means that the
program was not compiled with <option>-g</option>.</para>
<tip>
<para>Most <command>lldb</command> commands have shorter
forms that can be used instead. The longer forms are
used here for clarity.</para>
</tip>
<para>At the <command>lldb</command> prompt, type
<userinput>breakpoint set -n main</userinput>. This will
tell the debugger not to display the preliminary set-up code
in the program being run and to stop execution at the
beginning of the program's code. Now type
<userinput>process launch</userinput> to actually start the
program&mdash; it will start at the beginning of the set-up
code and then get stopped by the debugger when it calls
<function>main()</function>.</para>
<para>To step through the program a line at a time, type
<userinput>thread step-over</userinput>. When the program
gets to a function call, step into it by typing
<userinput>thread step-in</userinput>. Once in a function
call, return from it by typing
<userinput>thread step-out</userinput> or use
<userinput>up</userinput> and <userinput>down</userinput> to
take a quick look at the caller.</para>
<para>Here is a simple example of how to spot a mistake in a
program with <command>lldb</command>. This is our program
(with a deliberate mistake):</para>
<programlisting>#include &lt;stdio.h&gt;
int bazz(int anint);
main() {
int i;
printf("This is my program\n");
bazz(i);
return 0;
}
int bazz(int anint) {
printf("You gave me %d\n", anint);
return anint;
}</programlisting>
<para>This program sets <symbol>i</symbol> to be
<literal>5</literal> and passes it to a function
<function>bazz()</function> which prints out the number we
gave it.</para>
<para>Compiling and running the program displays</para>
<screen>&prompt.user; <userinput>cc -g -o temp temp.c</userinput>
&prompt.user; <userinput>./temp</userinput>
This is my program
anint = -5360</screen>
<para>That is not what was expected! Time to see what is going
on!</para>
<screen>&prompt.user; <userinput>lldb -- temp</userinput>
(lldb) target create "temp"
Current executable set to 'temp' (x86_64).
(lldb) <userinput>breakpoint set -n main</userinput> <lineannotation>Skip the set-up code</lineannotation>
Breakpoint 1: where = temp`main + 15 at temp.c:8:2, address = 0x00000000002012ef <lineannotation>lldb puts breakpoint at main()</lineannotation>
(lldb) <userinput>process launch</userinput> <lineannotation>Run as far as main()</lineannotation>
Process 9992 launching
Process 9992 launched: '/home/pauamma/tmp/temp' (x86_64) <lineannotation>Program starts running</lineannotation>
Process 9992 stopped
* thread #1, name = 'temp', stop reason = breakpoint 1.1 <lineannotation>lldb stops at main()</lineannotation>
frame #0: 0x00000000002012ef temp`main at temp.c:8:2
5 main() {
6 int i;
7
-> 8 printf("This is my program\n"); <lineannotation>Indicates the line where it stopped</lineannotation>
9 bazz(i);
10 return 0;
11 }
(lldb) <userinput>thread step-over</userinput> <lineannotation>Go to next line</lineannotation>
This is my program <lineannotation>Program prints out</lineannotation>
Process 9992 stopped
* thread #1, name = 'temp', stop reason = step over
frame #0: 0x0000000000201300 temp`main at temp.c:9:7
6 int i;
7
8 printf("This is my program\n");
-> 9 bazz(i);
10 return 0;
11 }
12
(lldb) <userinput>thread step-in</userinput> <lineannotation>step into bazz()</lineannotation>
Process 9992 stopped
* thread #1, name = 'temp', stop reason = step in
frame #0: 0x000000000020132b temp`bazz(anint=-5360) at temp.c:14:29 <lineannotation>lldb displays stack frame</lineannotation>
11 }
12
13 int bazz(int anint) {
-> 14 printf("You gave me %d\n", anint);
15 return anint;
16 }
(lldb)</screen>
<para>Hang on a minute! How did <symbol>anint</symbol> get to
be <literal>-5360</literal>? Was it not set to
<literal>5</literal> in <function>main()</function>? Let us
move up to <function>main()</function> and have a
look.</para>
<screen>(lldb) <userinput>up</userinput> <lineannotation>Move up call stack</lineannotation>
frame #1: 0x000000000020130b temp`main at temp.c:9:2 <lineannotation>lldb displays stack frame</lineannotation>
6 int i;
7
8 printf("This is my program\n");
-> 9 bazz(i);
10 return 0;
11 }
12
(lldb) <userinput>frame variable i</userinput> <lineannotation>Show us the value of i</lineannotation>
(int) i = -5360 <lineannotation>lldb displays -5360</lineannotation></screen>
<para>Oh dear! Looking at the code, we forgot to initialize
<symbol>i</symbol>. We meant to put</para>
<programlisting><lineannotation>&hellip;</lineannotation>
main() {
int i;
i = 5;
printf("This is my program\n");
<lineannotation>&hellip;</lineannotation></programlisting>
<para>but we left the <literal>i=5;</literal> line out. As we
did not initialize <symbol>i</symbol>, it had whatever
number happened to be in that area of memory when the
program ran, which in this case happened to be
<literal>-5360</literal>.</para>
<note>
<para>The <command>lldb</command> command displays the stack
frame every time we go into or out of a function, even if
we are using <userinput>up</userinput> and
<userinput>down</userinput> to move around the call stack.
This shows the name of the function and the values of its
arguments, which helps us keep track of where we are and
what is going on. (The stack is a storage area where the
program stores information about the arguments passed to
functions and where to go when it returns from a function
call.)</para>
</note>
</sect3>
<sect3>
<title>Examining a Core File with lldb</title>
<para>A core file is basically a file which contains the
complete state of the process when it crashed. In
<quote>the good old days</quote>, programmers had to print
out hex listings of core files and sweat over machine code
manuals, but now life is a bit easier. Incidentally, under
&os; and other 4.4BSD systems, a core file is called
<filename><replaceable>progname</replaceable>.core</filename>
instead of just <filename>core</filename>, to make it
clearer which program a core file belongs to.</para>
<para>To examine a core file, specify the name of the core
file in addition to the program itself. Instead of starting
up <command>lldb</command> in the usual way, type
<userinput>lldb -c <replaceable>progname</replaceable>.core
-- <replaceable>progname</replaceable></userinput></para>
<para>The debugger will display something like this:</para>
<screen>&prompt.user; <userinput>lldb -c <filename><replaceable>progname</replaceable>.core</filename> -- <filename><replaceable>progname</replaceable></filename></userinput>
(lldb) target create "<filename><replaceable>progname</replaceable></filename>" --core "<filename><replaceable>progname</replaceable></filename>.core"
Core file '/home/pauamma/tmp/<filename><replaceable>progname</replaceable>.core</filename>' (x86_64) was loaded.
(lldb)</screen>
<para>In this case, the program was called
<filename><replaceable>progname</replaceable></filename>, so
the core file is called
<filename><replaceable>progname</replaceable>.core</filename>.
The debugger does not display why the program crashed or
where. For this, use
<userinput>thread backtrace all</userinput>. This will also
show how the function where the program dumped core was
called.</para>
<screen>(lldb) <userinput>thread backtrace all</userinput>
* thread #1, name = '<filename><replaceable>progname</replaceable></filename>', stop reason = signal SIGSEGV
* frame #0: 0x0000000000201347 <filename><replaceable>progname</replaceable></filename>`bazz(anint=5) at temp2.c:17:10
frame #1: 0x0000000000201312 <filename><replaceable>progname</replaceable></filename>`main at temp2.c:10:2
frame #2: 0x000000000020110f <filename><replaceable>progname</replaceable></filename>`_start(ap=&lt;unavailable&gt;, cleanup=&lt;unavailable&gt;) at crt1.c:76:7
(lldb)</screen>
<para><literal>SIGSEGV</literal> indicates that the program
tried to access memory (run code or read/write data usually)
at a location that does not belong to it, but does not give
any specifics. For that, look at the source code at line 10
of file temp2.c, in <function>bazz()</function>. The
backtrace also says that in this case,
<function>bazz()</function> was called from
<function>main()</function>.</para>
</sect3>
<sect3>
<title>Attaching to a Running Program with lldb</title>
<para>One of the neatest features about
<command>lldb</command> is that it can attach to a program
that is already running. Of course, that requires
sufficient permissions to do so. A common problem is
stepping through a program that forks and wanting to trace
the child, but the debugger will only trace the
parent.</para>
<para>To do that, start up another <command>lldb</command>,
use <command>ps</command> to find the process ID for the
child, and do</para>
<screen>(lldb) <userinput>process attach -p <replaceable>pid</replaceable></userinput></screen>
<para>in <command>lldb</command>, and then debug as
usual.</para>
<para>For that to work well, the code that calls
<function>fork</function> to create the child needs to do
something like the following (courtesy of the
<command>gdb</command> info pages):</para>
<programlisting><lineannotation>&hellip;</lineannotation>
if ((pid = fork()) &lt; 0) /* _Always_ check this */
error();
else if (pid == 0) { /* child */
int PauseMode = 1;
while (PauseMode)
sleep(10); /* Wait until someone attaches to us */
<lineannotation>&hellip;</lineannotation>
} else { /* parent */
<lineannotation>&hellip;</lineannotation></programlisting>
<para>Now all that is needed is to attach to the child, set
<symbol>PauseMode</symbol> to <literal>0</literal> with
<userinput>expr PauseMode = 0</userinput> and wait
for the <function>sleep()</function> call to return.</para>
</sect3>
</sect2>
<sect2>
<title>Using gdb</title>
<sect3>
<title>Starting gdb</title>
<para>Start up gdb by typing</para>
<screen>&prompt.user; <userinput>gdb <replaceable>progname</replaceable></userinput></screen>
<para>although many people prefer to run it inside
<application>Emacs</application>. You can do this by:</para>
<application>Emacs</application>. To do this, type:</para>
<screen><userinput>M-x gdb RET <replaceable>progname</replaceable> RET</userinput></screen>
<para>Using a debugger allows you to run the program under more
controlled circumstances. Typically, you can step through the
program a line at a time, inspect the value of variables,
change them, tell the debugger to run up to a certain point
and then stop, and so on. You can even attach to a program
that is already running, or load a core file to investigate
why the program crashed. It is even possible to debug the
kernel, though that is a little trickier than the user
applications we will be discussing in this section.</para>
<para><command>gdb</command> has quite good on-line help, as
well as a set of info pages, so this section will concentrate
on a few of the basic commands.</para>
<para>Finally, if you find its text-based command-prompt style
off-putting, there is a graphical front-end for it
<para>Finally, for those finding its text-based command-prompt
style off-putting, there is a graphical front-end for it
(<package>devel/xxgdb</package>) in the Ports
Collection.</para>
<para>This section is intended to be an introduction to using
<command>gdb</command> and does not cover specialized topics
such as debugging the kernel.</para>
</sect2>
</sect3>
<sect2>
<title>Running a Program in the Debugger</title>
<sect3>
<title>Running a Program with gdb</title>
<para>You will need to have compiled the program with
<para>Compile the program with
<option>-g</option> to get the most out of using
<command>gdb</command>. It will work without, but you will
only see the name of the function you are in, instead of the
source code. If you see a line like:</para>
<command>gdb</command>. It will work without, but will
only display the name of the function currently running,
instead of the source code. A line like:</para>
<screen>&hellip; (no debugging symbols found) &hellip;</screen>
<para>when <command>gdb</command> starts up, you will know that
the program was not compiled with <option>-g</option>.</para>
<para>when <command>gdb</command> starts up means that the
program was not compiled with <option>-g</option>.</para>
<para>At the <command>gdb</command> prompt, type
<userinput>break main</userinput>. This will tell the
debugger that you are not interested in watching the
preliminary set-up code in the program being run, and that it
should stop execution at the beginning of your code. Now type
<userinput>run</userinput> to start the program&mdash;it will
start at the beginning of the set-up code and then get stopped
by the debugger when it calls <function>main()</function>.
(If you have ever wondered where <function>main()</function>
gets called from, now you know!).</para>
debugger to skip the preliminary set-up code in the program
being run and to stop execution at the beginning of the
program's code. Now type <userinput>run</userinput> to start
the program&mdash; it will start at the beginning of the
set-up code and then get stopped by the debugger when it calls
<function>main()</function>.</para>
<para>You can now step through the program, a line at a time, by
pressing <command>n</command>. If you get to a function call,
you can step into it by pressing <command>s</command>. Once
you are in a function call, you can return from stepping into
a function call by pressing <command>f</command>. You can
also use <command>up</command> and <command>down</command> to
take a quick look at the caller.</para>
<para>To step through the program a line at a time, press
<command>n</command>. When at a function call, step into it
by pressing <command>s</command>. Once in a function call,
return from it by pressing <command>f</command>, or use
<command>up</command> and <command>down</command> to take
a quick look at the caller.</para>
<para>Here is a simple example of how to spot a mistake in a
program with <command>gdb</command>. This is our program
@ -1421,7 +1735,7 @@ int bazz(int anint) {
<function>bazz()</function> which prints out the number we
gave it.</para>
<para>When we compile and run the program we get</para>
<para>Compiling and running the program displays</para>
<screen>&prompt.user; <userinput>cc -g -o temp temp.c</userinput>
&prompt.user; <userinput>./temp</userinput>
@ -1449,7 +1763,7 @@ bazz (anint=4231) at temp.c:17 <lineannotation>gdb displays stack frame</linea
(gdb)</screen>
<para>Hang on a minute! How did <symbol>anint</symbol> get to be
<literal>4231</literal>? Did we not we set it to be
<literal>4231</literal>? Was it not set to
<literal>5</literal> in <function>main()</function>? Let us
move up to <function>main()</function> and have a look.</para>
@ -1476,26 +1790,26 @@ main() {
<literal>4231</literal>.</para>
<note>
<para><command>gdb</command> displays the stack frame every
time we go into or out of a function, even if we are using
<command>up</command> and <command>down</command> to move
around the call stack. This shows the name of the function
and the values of its arguments, which helps us keep track
of where we are and what is going on. (The stack is a
storage area where the program stores information about the
arguments passed to functions and where to go when it
returns from a function call).</para>
</note>
</sect2>
<para>The <command>gdb</command> command displays the stack
frame every time we go into or out of a function, even if we
are using <command>up</command> and <command>down</command>
to move around the call stack. This shows the name of the
function and the values of its arguments, which helps us
keep track of where we are and what is going on. (The stack
is a storage area where the program stores information about
the arguments passed to functions and where to go when it
returns from a function call.)</para>
</note>
</sect3>
<sect2>
<title>Examining a Core File</title>
<sect3>
<title>Examining a Core File with gdb</title>
<para>A core file is basically a file which contains the
complete state of the process when it crashed. In <quote>the
good old days</quote>, programmers had to print out hex
listings of core files and sweat over machine code manuals,
but now life is a bit easier. Incidentally, under FreeBSD and
but now life is a bit easier. Incidentally, under &os; and
other 4.4BSD systems, a core file is called
<filename><replaceable>progname</replaceable>.core</filename>
instead of just <filename>core</filename>, to make it clearer
@ -1507,30 +1821,30 @@ main() {
<screen>(gdb) <userinput>core <replaceable>progname</replaceable>.core</userinput></screen>
<para>If you are not in the same directory as the core file, you
will have to do <userinput>dir /path/to/core/file</userinput>
first.</para>
<para>If the core file is not in the current directory, type
<userinput>dir /path/to/core/file</userinput> first.</para>
<para>You should see something like this:</para>
<para>The debugger should display something like this:</para>
<screen>&prompt.user; <userinput>gdb a.out</userinput>
<screen>&prompt.user; <userinput>gdb <filename><replaceable>progname</replaceable></filename></userinput>
GDB is free software and you are welcome to distribute copies of it
under certain conditions; type "show copying" to see the conditions.
There is absolutely no warranty for GDB; type "show warranty" for details.
GDB 4.13 (i386-unknown-freebsd), Copyright 1994 Free Software Foundation, Inc.
(gdb) <userinput>core a.out.core</userinput>
Core was generated by `a.out'.
(gdb) <userinput>core <filename><replaceable>progname</replaceable>.core</filename></userinput>
Core was generated by `<filename><replaceable>progname</replaceable></filename>'.
Program terminated with signal 11, Segmentation fault.
Cannot access memory at address 0x7020796d.
#0 0x164a in bazz (anint=0x5) at temp.c:17
(gdb)</screen>
<para>In this case, the program was called
<filename>a.out</filename>, so the core file is called
<filename>a.out.core</filename>. We can see that the program
crashed due to trying to access an area in memory that was not
available to it in a function called
<function>bazz</function>.</para>
<filename><replaceable>progname</replaceable></filename>, so
the core file is called
<filename><replaceable>progname</replaceable>.core</filename>.
We can see that the program crashed due to trying to access an
area in memory that was not available to it in a function
called <function>bazz</function>.</para>
<para>Sometimes it is useful to be able to see how a function
was called, as the problem could have occurred a long way up
@ -1547,19 +1861,19 @@ Cannot access memory at address 0x7020796d.
<para>The <function>end()</function> function is called when a
program crashes; in this case, the <function>bazz()</function>
function was called from <function>main()</function>.</para>
</sect2>
</sect3>
<sect2>
<title>Attaching to a Running Program</title>
<sect3>
<title>Attaching to a Running Program with gdb</title>
<para>One of the neatest features about <command>gdb</command>
is that it can attach to a program that is already running.
Of course, that assumes you have sufficient permissions to do
so. A common problem is when you are stepping through a
program that forks, and you want to trace the child, but the
debugger will only let you trace the parent.</para>
Of course, that requires sufficient permissions to do
so. A common problem is stepping through a program that forks
and wanting to trace the child, but the debugger will only
trace the parent.</para>
<para>What you do is start up another <command>gdb</command>,
<para>To do that, start up another <command>gdb</command>,
use <command>ps</command> to find the process ID for the
child, and do</para>
@ -1567,10 +1881,9 @@ Cannot access memory at address 0x7020796d.
<para>in <command>gdb</command>, and then debug as usual.</para>
<para><quote>That is all very well,</quote> you are probably
thinking, <quote>but by the time I have done that, the child
process will be over the hill and far away</quote>. Fear
not, gentle reader, here is how to do it (courtesy of the
<para>For that to work well, the code that calls
<function>fork</function> to create the child needs to do
something like the following (courtesy of the
<command>gdb</command> info pages):</para>
<programlisting><lineannotation>&hellip;</lineannotation>
@ -1585,9 +1898,10 @@ else if (pid == 0) { /* child */
} else { /* parent */
<lineannotation>&hellip;</lineannotation></programlisting>
<para>Now all you have to do is attach to the child, set
<para>Now all that is needed is to attach to the child, set
<symbol>PauseMode</symbol> to <literal>0</literal>, and wait
for the <function>sleep()</function> call to return!</para>
</sect3>
</sect2>
</sect1>