Cari di RHE Linux 
    RHE Linux User Manual
Daftar Isi
(Sebelumnya) 30 : Chapter 4. Compiling and ...30 : Chapter 6. Profiling - De ... (Berikutnya)

Developer Guide

Chapter 5. Debugging

Useful, well-written software generally goes through several different phases of application development, allowing ample opportunity for mistakes to be made. Some phases come with their own set of mechanisms to detect errors. For example, during compilation an elementary semantic analysis is often performed to make sure objects, such as variables and functions, are adequately described.
The error-checking mechanisms performed during each application development phase aims to catch simple and obvious mistakes in code. The debugging phase helps to bring more subtle errors to light that fell through the cracks during routine code inspection.

5.1. ELF Executable Binaries

Red Hat Enterprise Linux uses ELF for executable binaries, shared libraries, or debuginfo files. Within these debuginfo ELF files, the DWARF format is used. Version 3 of DWARF is used in ELF files (that is, gcc -g is equivalent to gcc -gdwarf-3). DWARF debuginfo includes:
  • names of all the compiled functions and variables, including their target addresses in binaries
  • source files used for compilation, including their source line numbers
  • local variables location

Important

STABS is occasionally used with UNIX. STABS is an older, less capable format. Its use is discouraged by Red Hat. GCC and GDB support STABS production and consumption on a best effort basis only.
Within these ELF files, the GCC debuginfo level is also used. The default is level 2, where macro information is not present; level 3 has C/C++ macro definitions included, but the debuginfo can be very large with this setting. The command for the default gcc -g is the same as gcc -g2. To change the macro information to level three, use gcc -g3.
There are multiple levels of debuginfo available. Use the command readelf -WS file to see which sections are used in a file.

Table 5.1. debuginfo levels

Binary State
Command
Notes
Stripped
strip file
or
gcc -s -o file
Only the symbols required for runtime linkage with shared libraries are present.
ELF section in use: .dynsym
ELF symbols
gcc -o file
Only the names of functions and variables are present, no binding to the source files and no types.
ELF section in use: .symtab
DWARF debuginfo with macros
gcc -g -o file
The source file names and line numbers are known, including types.
ELF section in use: .debug_*
DWARF debuginfo with macros
gcc -g3 -o file
Similar to gcc -g but the macros are known to GDB.
ELF section in use: .debug_macro

Note

GDB never interprets the source files, it only displays them as text. Use gcc -g and its variants to store the information into DWARF.
Compiling a program or library with gcc -rdynamic is discouraged. For specific symbols, use gcc -Wl, --dynamic-list=... instead. If gcc -rdynamic is used, the strip command or -s gcc option have no effect. This is because all ELF symbols are kept in the binary for possible runtime linkage with shared libraries.
ELF symbols can be read by the readelf -s file command.
DWARF symbols are read by the readelf -w file command.
The command readelf -wi file is a good verification of debuginfo, compiled within your program. The commands strip file or gcc -s are commonly accidentally executed on the output during various compilation stages of the program.
The readelf -w file command can also be used to show a special section called .eh_frame with a format and purpose is similar to the DWARF section .debug_frame. The .eh_frame section is used for runtime C++ exception resolution and is present even if -g gcc option was not used. It is kept in the primary RPM and is never present in the debuginfo RPMs.
Debuginfo RPMs contain the sections .symtab and .debug_*. Neither .eh_frame, .eh_frame_hdr, nor .dynsym are moved or present in debuginfo RPMs as those sections are needed during program runtime.

5.2. Installing Debuginfo Packages

Red Hat Enterprise Linux also provides -debuginfo packages for all architecture-dependent RPMs included in the operating system. A packagename-debuginfo-version-release.architecture.rpm package contains detailed information about the relationship of the package source files and the final installed binary. The debuginfo packages contain both .debug files, which in turn contain DWARF debuginfo and the source files used for compiling the binary packages.

Note

Most of the debugger functionality is missed if attempting to debug a package without having its debuginfo equivalent installed. For example, the names of exported shared library functions will still be available, but the matching source file lines will not be without the debuginfo package installed.
Use gcc compilation option -g for your own programs. The debugging experience is better if no optimizations (gcc option -O, such as -O2) is applied with -g.
For Red Hat Enterprise Linux 6, the debuginfo packages are now available on a new channel on the Red Hat Network. To install the -debuginfo package of a package (that is, typically packagename-debuginfo), first the machine has to be subscribed to the corresponding Debuginfo channel. For example, for Red Hat Enterprise Server 6, the corresponding channel would be Red Hat Enterprise Linux Server Debuginfo (v. 6).
Red Hat Enterprise Linux system packages are compiled with optimizations (gcc option -O2). This means that some variables will be displayed as <optimized out>. Stepping through code will 'jump' a little but a crash can still be analyzed. If some debugging information is missing because of the optimizations, the right variable information can be found by disassembling the code and matching it to the source manually. This is applicable only in exceptional cases and is not suitable for regular debugging.
For system packages, GDB informs the user if it is missing some debuginfo packages that limit its functionality.
gdb ls[...]Reading symbols from /bin/ls...(no debugging symbols found)...done.Missing separate debuginfos, use: debuginfo-install coreutils-8.4-16.el6.x86_64(gdb) q
If the system package to be debugged is known, use the command suggested by GDB above. It will also automatically install all the debug packages packagename depends on.
# debuginfo-install packagename

5.2.1. Installing Debuginfo Packages for Core Files Analysis

A core file is a representation of the memory image at the time of a process crash. For bug reporting of system program crashes, Red Hat recommends the use of the ABRT tool, explained in the Automatic Bug Reporting Tool chapter in the Red Hat Deployment Guide. If ABRT is not suitable for your purposes, the steps it automates are explained here.
If the ulimit -c unlimited setting is in use when a process crashes, the core file is dumped into the current directory. The core file contains only the memory areas modified by the process from the original state of disk files. In order to perform a full analysis of a crash, a core file is required to have:
  • the core file itself
  • the executable binary which has crashed, such as /usr/sbin/sendmail
  • all the shared libraries loaded in the binary when it crashed
  • .debug files and source files (both stored in debuginfo RPMs) for the executable and all of its loaded libraries
For a proper analysis, either the exact version-release.architecture for all the RPMs involved or the same build of your own compiled binaries is needed. At the time of the crash, the application may have already recompiled or been updated by yum on the disk, rendering the files inappropriate for the core file analysis.
The core file contains build-ids of all the binaries involved. For more information on build-id, see Section 4.6, "build-id Unique Identification of Binaries". The contents of the core file can be displayed by:
$ eu-unstrip -n --core=./core.98140x400000+0x207000 2818b2009547f780a5639c904cded443e564973e@0x400284 /bin/sleep /usr/lib/debug/bin/sleep.debug [exe]0x7fff26fff000+0x1000 1e2a683b7d877576970e4275d41a6aaec280795e@0x7fff26fff340 . - linux-vdso.so.10x35e7e00000+0x3b6000 374add1ead31ccb449779bc7ee7877de3377e5ad@0x35e7e00280 /lib64/libc-2.14.90.so /usr/lib/debug/lib64/libc-2.14.90.so.debug libc.so.60x35e7a00000+0x224000 3ed9e61c2b7e707ce244816335776afa2ad0307d@0x35e7a001d8 /lib64/ld-2.14.90.so /usr/lib/debug/lib64/ld-2.14.90.so.debug ld-linux-x86-64.so.2
The meaning of the columns in each line are:
  • The in-memory address where the specific binary was mapped to (for example, 0x400000 in the first line).
  • The size of the binary (for example, +0x207000 in the first line).
  • The 160-bit SHA-1 build-id of the binary (for example, 2818b2009547f780a5639c904cded443e564973e in the first line).
  • The in-memory address where the build-id bytes were stored (for example, @0x400284 in the first line).
  • The on-disk binary file, if available (for example, /bin/sleep in the first line). This was found by eu-unstrip for this module.
  • The on-disk debuginfo file, if available (for example, /usr/lib/debug/bin/sleep.debug). However, best practice is to use the binary file reference instead.
  • The shared library name as stored in the shared library list in the core file (for example, libc.so.6 in the third line).
For each build-id (for example, ab/cdef0123456789012345678901234567890123) a symbolic link is included in its debuginfo RPM. Using the /bin/sleep executable above as an example, the coreutils-debuginfo RPM contains, among other files:
lrwxrwxrwx 1 root root 24 Nov 29 17:07 /usr/lib/debug/.build-id/28/18b2009547f780a5639c904cded443e564973e -> ../../../../../bin/sleep*lrwxrwxrwx 1 root root 21 Nov 29 17:07 /usr/lib/debug/.build-id/28/18b2009547f780a5639c904cded443e564973e.debug -> ../../bin/sleep.debug
In some cases (such as loading a core file), GDB does not know the name, version, or release of a name-debuginfo-version-release.rpm package; it only knows the build-id. In such cases, GDB suggests a different command:
gdb -c ./core[...]Missing separate debuginfo for the main executable filenameTry: yum --disablerepo='*' --enablerepo='*debug*' install /usr/lib/debug/.build-id/ef/dd0b5e69b0742fa5e5bad0771df4d1df2459d1
The version-release.architecture of the binary package packagename-debuginfo-version-release.architecture.rpm must be an exact match. If it differs then GDB cannot use the debuginfo package. Even the same version-release.architecture from a different build leads to an incompatible debuginfo package. If GDB reports a missing debuginfo, ensure to recheck:
rpm -q packagename packagename-debuginfo
The version-release.architecture definitions should match.
rpm -V packagename packagename-debuginfo
This command should produce no output, except possibly modified configuration files of packagename, for example.
rpm -qi packagename packagename-debuginfo
The version-release.architecture should display matching information for Vendor, Build Date, and Build Host. For example, using a CentOS debuginfo RPM for a Red Hat Enterprise Linux RPM package will not work.
If the required build-id is known, the following command can query which RPM contains it:
$ repoquery --disablerepo='*' --enablerepo='*-debug*' -qf /usr/lib/debug/.build-id/ef/dd0b5e69b0742fa5e5bad0771df4d1df2459d1
For example, a version of an executable which matches the core file can be installed by:
# yum --enablerepo='*-debug*' install $(eu-unstrip -n --core=./core.9814 | sed -e 's#^[^ ]* \(..\)\([^@ ]*\).*$#/usr/lib/debug/.build-id/\1/\2#p' -e 's/$/.debug/')
Similar methods are available if the binaries are not packaged into RPMs and stored in yum repositories. It is possible to create local repositories with custom application builds by using /usr/bin/createrepo.

5.3. GDB

Fundamentally, like most debuggers, GDB manages the execution of compiled code in a very closely controlled environment. This environment makes possible the following fundamental mechanisms necessary to the operation of GDB:
  • Inspect and modify memory within the code being debugged (for example, reading and setting variables).
  • Control the execution state of the code being debugged, principally whether it's running or stopped.
  • Detect the execution of particular sections of code (for example, stop running code when it reaches a specified area of interest to the programmer).
  • Detect access to particular areas of memory (for example, stop running code when it accesses a specified variable).
  • Execute portions of code (from an otherwise stopped program) in a controlled manner.
  • Detect various programmatic asynchronous events such as signals.
The operation of these mechanisms rely mostly on information produced by a compiler. For example, to view the value of a variable, GDB has to know:
  • The location of the variable in memory
  • The nature of the variable
This means that displaying a double-precision floating point value requires a very different process from displaying a string of characters. For something complex like a structure, GDB has to know not only the characteristics of each individual elements in the structure, but the morphology of the structure as well.
GDB requires the following items in order to fully function:
Debug Information
Much of GDB's operations rely on a program's debug information. While this information generally comes from compilers, much of it is necessary only while debugging a program, that is, it is not used during the program's normal execution. For this reason, compilers do not always make that information available by default - GCC, for instance, must be explicitly instructed to provide this debugging information with the -g flag.
To make full use of GDB's capabilities, it is highly advisable to make the debug information available first to GDB. GDB can only be of very limited use when run against code with no available debug information.
Source Code
One of the most useful features of GDB (or any other debugger) is the ability to associate events and circumstances in program execution with their corresponding location in source code. This location normally refers to a specific line or series of lines in a source file. This, of course, would require that a program's source code be available to GDB at debug time.

5.3.1. Simple GDB

GDB literally contains dozens of commands. This section describes the most fundamental ones.
br (breakpoint)
The breakpoint command instructs GDB to halt execution upon reaching a specified point in the execution. That point can be specified a number of ways, but the most common are just as the line number in the source file, or the name of a function. Any number of breakpoints can be in effect simultaneously. This is frequently the first command issued after starting GDB.
r (run)
The run command starts the execution of the program. If run is executed with any arguments, those arguments are passed on to the executable as if the program has been started normally. Users normally issue this command after setting breakpoints.
Before an executable is started, or once the executable stops at, for example, a breakpoint, the state of many aspects of the program can be inspected. The following commands are a few of the more common ways things can be examined.
p (print)
The print command displays the value of the argument given, and that argument can be almost anything relevant to the program. Usually, the argument is the name of a variable of any complexity, from a simple single value to a structure. An argument can also be an expression valid in the current language, including the use of program variables and library functions, or functions defined in the program being tested.
bt (backtrace)
The backtrace displays the chain of function calls used up until the execution was terminated. This is useful for investigating serious bugs (such as segmentation faults) with elusive causes.
l (list)
When execution is stopped, the list command shows the line in the source code corresponding to where the program stopped.
The execution of a stopped program can be resumed in a number of ways. The following are the most common.
c (continue)
The continue command restarts the execution of the program, which will continue to execute until it encounters a breakpoint, runs into a specified or emergent condition (for example, an error), or terminates.
n (next)
Like continue, the next command also restarts execution; however, in addition to the stopping conditions implicit in the continue command, next will also halt execution at the next sequential line of code in the current source file.
s (step)
Like next, the step command also halts execution at each sequential line of code in the current source file. However, if execution is currently stopped at a source line containing a function call, GDB stops execution after entering the function call (rather than executing it).
fini (finish)
Like the aforementioned commands, the finish command resumes executions, but halts when execution returns from a function.
Finally, two essential commands:
q (quit)
This terminates the execution.
h (help)
The help command provides access to its extensive internal documentation. The command takes arguments: help breakpoint (or h br), for example, shows a detailed description of the breakpoint command. Refer to the help output of each command for more detailed information.

5.3.2. Running GDB

This section will describe a basic execution of GDB, using the following simple program:
hello.c
#include <stdio.h>char hello[] = { "Hello, World!" };intmain(){  fprintf (stdout, "%s\n", hello);  return (0);}
The following procedure illustrates the debugging process in its most basic form.

Procedure 5.1. Debugging a 'Hello World' Program

  1. Compile hello.c into an executable with the debug flag set, as in:
    gcc -g -o hello hello.c
    Ensure that the resulting binary hello is in the same directory as hello.c.
  2. Run gdb on the hello binary, that is, gdb hello.
  3. After several introductory comments, gdb will display the default GDB prompt:
    (gdb)
  4. The variable hello is global, so it can be seen even before the main procedure starts:
    gdb) p hello$1 = "Hello, World!"(gdb) p hello[0]$2 = 72 'H'(gdb) p *hello$3 = 72 'H'(gdb)
    Note that the print targets hello[0] and *hello require the evaluation of an expression, as does, for example, *(hello + 1):
    (gdb) p *(hello + 1)$4 = 101 'e'
  5. Next, list the source:
    (gdb) l1   #include <stdio.h>23   char hello[] = { "Hello, World!" };45   int6   main()7   {8 fprintf (stdout, "%s\n", hello);9 return (0);10  }
    The list reveals that the fprintf call is on line 8. Apply a breakpoint on that line and resume the code:
    (gdb) br 8Breakpoint 1 at 0x80483ed: file hello.c, line 8.(gdb) rStarting program: /home/moller/tinkering/gdb-manual/helloBreakpoint 1, main () at hello.c:88 fprintf (stdout, "%s\n", hello);
  6. Finally, use the next command to step past the fprintf call, executing it:
    (gdb) nHello, World!9 return (0);
The following sections describe more complex applications of GDB.

5.3.3. Conditional Breakpoints

In many real-world cases, a program may perform its task well during the first few thousand times; it may then start crashing or encountering errors during its eight thousandth iteration of the task. Debugging programs like this can be difficult, as it is hard to imagine a programmer with the patience to issue a continue command thousands of times just to get to the iteration that crashed.
Situations like this are common in real life, which is why GDB allows programmers to attach conditions to a breakpoint. For example, consider the following program:
simple.c
#include <stdio.h>main(){  int i;  for (i = 0; i++) {fprintf (stdout, "i = %d\n", i);  }}
To set a conditional breakpoint at the GDB prompt:
(gdb) br 8 if i == 8936Breakpoint 1 at 0x80483f5: file iterations.c, line 8.(gdb) r
With this condition, the program execution will eventually stop with the following output:
i = 8931i = 8932i = 8933i = 8934i = 8935Breakpoint 1, main () at iterations.c:88   fprintf (stdout, "i = %d\n", i);
Inspect the breakpoint information (using info br) to review the breakpoint status:
(gdb) info brNum Type   Disp Enb Address What1   breakpoint keep y   0x080483f5 in main at iterations.c:8 stop only if i == 8936 breakpoint already hit 1 time

5.3.4. Forked Execution

Among the more challenging bugs confronting programmers is where one program (the parent) makes an independent copy of itself (a fork). That fork then creates a child process which, in turn, fails. Debugging the parent process may or may not be useful. Often the only way to get to the bug may be by debugging the child process, but this is not always possible.
The set follow-fork-mode feature is used to overcome this barrier allowing programmers to follow a a child process instead of the parent process.
set follow-fork-mode parent
The original process is debugged after a fork. The child process runs unimpeded. This is the default.
set follow-fork-mode child
The new process is debugged after a fork. The parent process runs unimpeded.
show follow-fork-mode
Display the current debugger response to a fork call.
Use the set detach-on-fork command to debug both the parent and the child processes after a fork, or retain debugger control over them both.
set detach-on-fork on
The child process (or parent process, depending on the value of follow-fork-mode) will be detached and allowed to run independently. This is the default.
set detach-on-fork off
Both processes will be held under the control of GDB. One process (child or parent, depending on the value of follow-fork-mode) is debugged as usual, while the other is suspended.
show detach-on-fork
Show whether detach-on-fork mode is on or off.
Consider the following program:
fork.c
#include <unistd.h>int main(){  pid_t  pid;  const char *name;  pid = fork();  if (pid == 0) {  name = "I am the child"; }  else {  name = "I am the parent"; }  return 0;}
This program, compiled with the command gcc -g fork.c -o fork -lpthread and examined under GDB will show:
gdb ./fork[...](gdb) break mainBreakpoint 1 at 0x4005dc: file fork.c, line 8.(gdb) run[...]Breakpoint 1, main () at fork.c:88   pid = fork();(gdb) nextDetaching after fork from child process 3840.9   if (pid == 0)(gdb) next15   name = "I am the parent";(gdb) next17   return 0;(gdb) print name$1 = 0x400717 "I am the parent"
GDB followed the parent process and allowed the child process (process 3840) to continue execution.
The following is the same test using set follow-fork-mode child.
(gdb) set follow-fork-mode child(gdb) break mainBreakpoint 1 at 0x4005dc: file fork.c, line 8.(gdb) run[...]Breakpoint 1, main () at fork.c:88  pid = fork();(gdb) next[New process 3875][Thread debugging using libthread_db enabled][Switching to Thread 0x7ffff7fd5720 (LWP 3875)]9  if (pid == 0)(gdb) next11  name = "I am the child";(gdb) next17  return 0;(gdb) print name$2 = 0x400708 "I am the child"(gdb) 
GDB switched to the child process here.
This can be permanent by adding the setting to the appropriate .gdbinit.
For example, if set follow-fork-mode ask is added to ~/.gdbinit, then ask mode becomes the default mode.

5.3.5. Debugging Individual Threads

GDB has the ability to debug individual threads, and to manipulate and examine them independently. This functionality is not enabled by default. To do so use set non-stop on and set target-async on. These can be added to .gdbinit. Once that functionality is turned on, GDB is ready to conduct thread debugging.
For example, the following program creates two threads. These two threads, along with the original thread executing main makes a total of three threads.
three-threads.c
#include <stdio.h>#include <pthread.h>#include <unistd.h>pthread_t thread;void* thread3 (void* d){  int count3 = 0;  while(count3 < 1000){ sleep(10); printf("Thread 3: %d\n", count3++);  }  return NULL;}void* thread2 (void* d){  int count2 = 0;  while(count2 < 1000){ printf("Thread 2: %d\n", count2++);  }  return NULL;}int main (){  pthread_create (&thread, NULL, thread2, NULL);  pthread_create (&thread, NULL, thread3, NULL); //Thread 1  int count1 = 0;  while(count1 < 1000){ printf("Thread 1: %d\n", count1++);  }  pthread_join(thread,NULL);  return 0;}
Compile this program in order to examine it under GDB.
gcc -g three-threads.c -o three-threads  -lpthreadgdb ./three-threads
First set breakpoints on all thread functions; thread1, thread2, and main.
(gdb) break thread3Breakpoint 1 at 0x4006c0: file three-threads.c, line 9.(gdb) break thread2Breakpoint 2 at 0x40070c: file three-threads.c, line 20.(gdb) break mainBreakpoint 3 at 0x40074a: file three-threads.c, line 30.
Then run the program.
(gdb) run[...]Breakpoint 3, main () at three-threads.c:3030  pthread_create (&thread, NULL, thread2, NULL);[...](gdb) info threads* 1 Thread 0x7ffff7fd5720 (LWP 4620)  main () at three-threads.c:30(gdb) 
Note that the command info threads provides a summary of the program's threads and some details about their current state. In this case there is only one thread that has been created so far.
Continue execution some more.
(gdb) next[New Thread 0x7ffff7fd3710 (LWP 4687)]31  pthread_create (&thread, NULL, thread3, NULL);(gdb) Breakpoint 2, thread2 (d=0x0) at three-threads.c:2020  int count2 = 0;next[New Thread 0x7ffff75d2710 (LWP 4688)]34  int count1 = 0;(gdb) Breakpoint 1, thread3 (d=0x0) at three-threads.c:99  int count3 = 0;info threads  3 Thread 0x7ffff75d2710 (LWP 4688)  thread3 (d=0x0) at three-threads.c:9  2 Thread 0x7ffff7fd3710 (LWP 4687)  thread2 (d=0x0) at three-threads.c:20* 1 Thread 0x7ffff7fd5720 (LWP 4620)  main () at three-threads.c:34
Here, two more threads are created. The star indicates the thread currently under focus. Also, the newly created threads have hit the breakpoint set for them in their initialization functions. Namely, thread2() and thread3().
To begin real thread debugging, use the thread <thread number> command to switch the focus to another thread.
(gdb) thread 2[Switching to thread 2 (Thread 0x7ffff7fd3710 (LWP 4687))]#0  thread2 (d=0x0) at three-threads.c:2020  int count2 = 0;(gdb) list15  return NULL;16}1718void* thread2 (void* d)19{20  int count2 = 0;2122  while(count2 < 1000){23 printf("Thread 2: %d\n", count2++);24  }
Thread 2 stopped at line 20 in its function thread2().
(gdb) next22  while(count2 < 1000){(gdb) print count2$1 = 0(gdb) next23 printf("Thread 2: %d\n", count2++);(gdb) nextThread 2: 022  while(count2 < 1000){(gdb) next23 printf("Thread 2: %d\n", count2++);(gdb) print count2$2 = 1(gdb) info threads  3 Thread 0x7ffff75d2710 (LWP 4688)  thread3 (d=0x0) at three-threads.c:9* 2 Thread 0x7ffff7fd3710 (LWP 4687)  thread2 (d=0x0) at three-threads.c:23  1 Thread 0x7ffff7fd5720 (LWP 4620)  main () at three-threads.c:34(gdb) 
Above, a few lines of thread2 printed the counter count2 and left thread 2 at line 23 as is seen by the output of 'info threads'.
Now thread3.
(gdb) thread 3[Switching to thread 3 (Thread 0x7ffff75d2710 (LWP 4688))]#0  thread3 (d=0x0) at three-threads.c:99  int count3 = 0;(gdb) list45pthread_t thread;67void* thread3 (void* d)8{9  int count3 = 0;1011  while(count3 < 1000){12 sleep(10);13 printf("Thread 3: %d\n", count3++);(gdb) 
Thread three is a little different in that it has a sleep statement and executes slowly. Think of it as a representation of an uninteresting IO thread. Because this thread is uninteresting, continue its execution uninterrupted, using the continue.
(gdb) continue &(gdb) Thread 3: 0Thread 3: 1Thread 3: 2Thread 3: 3
Take note of the & at the end of the continue. This allows the GDB prompt to return so other commands can be executed. Using the interrupt, execution can be stopped should thread 3 become interesting again.
(gdb) interrupt[Thread 0x7ffff75d2710 (LWP 4688)] #3 stopped.0x000000343f4a6a6d in nanosleep () at ../sysdeps/unix/syscall-template.S:8282T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS)
It is also possible to go back to the original main thread and examine it some more.
(gdb) thread 1[Switching to thread 1 (Thread 0x7ffff7fd5720 (LWP 4620))]#0  main () at three-threads.c:3434  int count1 = 0;(gdb) next36  while(count1 < 1000){(gdb) next37 printf("Thread 1: %d\n", count1++);(gdb) nextThread 1: 036  while(count1 < 1000){(gdb) next37 printf("Thread 1: %d\n", count1++);(gdb) nextThread 1: 136  while(count1 < 1000){(gdb) next37 printf("Thread 1: %d\n", count1++);(gdb) nextThread 1: 236  while(count1 < 1000){(gdb) print count1 $3 = 3(gdb) info threads   3 Thread 0x7ffff75d2710 (LWP 4688)  0x000000343f4a6a6d in nanosleep () at ../sysdeps/unix/syscall-template.S:82  2 Thread 0x7ffff7fd3710 (LWP 4687)  thread2 (d=0x0) at three-threads.c:23* 1 Thread 0x7ffff7fd5720 (LWP 4620)  main () at three-threads.c:36(gdb) 
As can be seen from the output of info threads, the other threads are where they were left, unaffected by the debugging of thread 1.

5.3.6. Alternative User Interfaces for GDB

GDB uses the command line as its default interface. However, it also has an API called machine interface (MI). MI allows IDE developers to create other user interfaces to GDB.
Some examples of these interfaces are:
Eclipse (CDT)
A graphical debugger interface integrated with the Eclipse development environment. More information can be found at the Eclipse website.
Nemiver
A graphical debugger interface which is well suited to the GNOME Desktop Environment. More information can be found at the Nemiver website
Emacs
A GDB interface which is integrated with the emacs. More information can be found at the Emacs website

5.3.7. GDB Documentation

For more detailed information about GDB, refer to the GDB manual:
Also, the commands info gdb and man gdb will provide more concise information that is up to date with the installed version of gdb.

5.4. Variable Tracking at Assignments

Variable Tracking at Assignments (VTA) is a new infrastructure included in GCC used to improve variable tracking during optimizations. This allows GCC to produce more precise, meaningful, and useful debugging information for GDB, SystemTap, and other debugging tools.
When GCC compiles code with optimizations enabled, variables are renamed, moved around, or even removed altogether. As such, optimized compiling can cause a debugger to report that some variables have been <optimized out>. With VTA enabled, optimized code is internally annotated to ensure that optimization passes to transparently keep track of each variable's value, regardless of whether the variable is moved or removed. The effect of this is more parameter and variable values available, even for the optimized (gcc -O2 -g built) code. It also displays the <optimized out> message less.
VTA's benefits are more pronounced when debugging applications with inlined functions. Without VTA, optimization could completely remove some arguments of an inlined function, preventing the debugger from inspecting its value. With VTA, optimization will still happen, and appropriate debugging information will be generated for any missing arguments.
VTA is enabled by default when compiling code with optimizations and debugging information enabled (that is, gcc -O -g or, more commonly, gcc -O2 -g). To disable VTA during such builds, add the -fno-var-tracking-assignments. In addition, the VTA infrastructure includes the new gcc option -fcompare-debug. This option tests code compiled by GCC with debug information and without debug information: the test passes if the two binaries are identical. This test ensures that executable code is not affected by any debugging options, which further ensures that there are no hidden bugs in the debug code. Note that -fcompare-debug adds significant cost in compilation time. Refer to man gcc for details about this option.
For more information about the infrastructure and development of VTA, refer to A Plan to Fix Local Variable Debug Information in GCC, available at the following link:
A slide deck version of this whitepaper is also available at http://people.redhat.com/aoliva/papers/vta/slides.pdf.

5.5. Python Pretty-Printers

The GDB command print outputs comprehensive debugging information for a target application. GDB aims to provide as much debugging data as it can to users; however, this means that for highly complex programs the amount of data can become very cryptic.
In addition, GDB does not provide any tools that help decipher GDB print output. GDB does not even empower users to easily create tools that can help decipher program data. This makes the practice of reading and understanding debugging data quite arcane, particularly for large, complex projects.
For most developers, the only way to customize GDB print output (and make it more meaningful) is to revise and recompile GDB. However, very few developers can actually do this. Further, this practice will not scale well, particularly if the developer must also debug other programs that are heterogeneous and contain equally complex debugging data.
To address this, the Red Hat Enterprise Linux 6 version of GDB is now compatible with Python pretty-printers. This allows the retrieval of more meaningful debugging data by leaving the introspection, printing, and formatting logic to a third-party Python script.
Compatibility with Python pretty-printers gives you the chance to truly customize GDB output as you see fit. This makes GDB a more viable debugging solution to a wider range of projects, since you now have the flexibility to adapt GDB output as required, and with greater ease. Further, developers with intimate knowledge of a project and a specific programming language are best qualified in deciding what kind of output is meaningful, allowing them to improve the usefulness of that output.
The Python pretty-printers implementation allows users to automatically inspect, format, and print program data according to specification. These specifications are written as rules implemented via Python scripts. This offers the following benefits:
Safe
To pass program data to a set of registered Python pretty-printers, the GDB development team added hooks to the GDB printing code. These hooks were implemented with safety in mind: the built-in GDB printing code is still intact, allowing it to serve as a default fallback printing logic. As such, if no specialized printers are available, GDB will still print debugging data the way it always did. This ensures that GDB is backwards-compatible; users who do not require pretty-printers can still continue using GDB.
Highly Customizable
This new "Python-scripted" approach allows users to distill as much knowledge as required into specific printers. As such, a project can have an entire library of printer scripts that parses program data in a unique manner specific to its user's requirements. There is no limit to the number of printers a user can build for a specific project; what's more, being able to customize debugging data script by script offers users an easier way to re-use and re-purpose printer scripts - or even a whole library of them.
Easy to Learn
The best part about this approach is its lower barrier to entry. Python scripting is comparatively easy to learn and has a large library of free documentation available online. In addition, most programmers already have basic to intermediate experience in Python scripting, or in scripting in general.
Here is a small example of a pretty printer. Consider the following C++ program:
fruit.cc
enum Fruits {Orange, Apple, Banana};class Fruit{  int fruit; public:  Fruit (int f) {  fruit = f; }};int main(){  Fruit myFruit(Apple);  return 0; // line 17   }
This is compiled with the command g++ -g fruit.cc -o fruit. Now, examine this program with GDB.
gdb ./fruit [...](gdb) break 17Breakpoint 1 at 0x40056d: file fruit.cc, line 17.(gdb) runBreakpoint 1, main () at fruit.cc:1717  return 0; // line 17(gdb) print myFruit $1 = {fruit = 1}
The output of {fruit = 1} is correct because that is the internal representation of 'fruit' in the data structure 'Fruit'. However, this is not easily read by humans as it is difficult to tell which fruit the integer 1 represents.
To solve this problem, write the following pretty printer:
fruit.pyclass FruitPrinter: def __init__(self, val): self.val = val def to_string (self): fruit = self.val['fruit'] if (fruit == 0): name = "Orange" elif (fruit == 1): name = "Apple" elif (fruit == 2): name = "Banana" else: name = "unknown" return "Our fruit is " + namedef lookup_type (val): if str(val.type) == 'Fruit': return FruitPrinter(val) return Nonegdb.pretty_printers.append (lookup_type)
Examine this printer from the bottom up.
The line gdb.pretty_printers.append (lookup_type) adds the function lookup_type to GDB's list of printer lookup functions.
The function lookup_type is responsible for examining the type of object to be printed, and returning an appropriate pretty printer. The object is passed by GDB in the parameter val. val.type is an attribute which represents the type of the pretty printer.
FruitPrinter is where the actual work is done. More specifically in the to_string function of that Class. In this function, the integer fruit is retrieved using the python dictionary syntax self.val['fruit']. Then the name is determined using that value. The string returned by this function is the string that will be printed to the user.
After creating fruit.py, it must then be loaded into GDB with the following command:
(gdb) python execfile("fruit.py")
The GDB and Python Pretty-Printers whitepaper provides more details on this feature. This whitepaper also includes details and examples on how to write your own Python pretty-printer as well as how to import it into GDB. Refer to the following link for more information:

5.6. Debugging C/C++ Applications with Eclipse

The Eclipse C/C++ development tools have excellent integration with the GNU Debugger (GDB). These Eclipse plug-ins take advantage of the latest features available in GDB.
Starting a debugging session for an application is similar to launching the application through either the context menu's Debug AsC/C++ Application, or using the Run menu. The context menu can be accessed in one of three ways:
  • Clicking the right mouse button with the cursor in the editor.
  • On the application binary.
  • On the project containing the binary of interest.
If more than one binary can be launched, a dialog will be presented to choose which one.
After the session has started, a prompt will appear to switch to the Debug perspective, which contains the following collection of views related to debugging.
Control View
The Control View is known as the Debug view and has buttons for stepping over and into code selections. It also allows for thread process suspension.
Source Code Editor View
The Source Code Editor View reflects which source code lines correspond to the position of the debugger in the execution. By pressing the Instruction Stepping Mode button in the Debug view toolbar, it is possible to control the execution of the application by assembly instruction instead of by source code line.
Console View
The Console View displays the input and output that is available.
Finally, variable data and other information can been found in the corresponding views in the Debug perspective.
For further details, refer to the ConceptsDebug, Getting StartedDebugging Projects, and TasksRunning and Debugging Projects sections of the C/C++ Development User Guide in the Help Contents.
(Sebelumnya) 30 : Chapter 4. Compiling and ...30 : Chapter 6. Profiling - De ... (Berikutnya)