Depending on the options you use when compiling and linking your program, the debugging information available in your program's executable file may range from full to nonexistent. Programs that include shared libraries or other code modules may contain limited debugging information regardless of the compile options you use. Ladebug supports the debugging of programs that do not contain complete debugging information.
This chapter describes how to use Ladebug to debug a program containing limited debugging information. It provides examples and discusses some of the limitations you may experience. There are many scenarios under which a program can be compiled and linked- discussing each is beyond the scope of this chapter.
Some compilers provide variants of the debug flag that provide different levels of debugging information and optimization. Depending on the options you use when compiling and linking your program, the debugging information available in the program's executable file may range from full to nonexistent. Programs that include shared libraries or other code modules may contain limited debugging information regardless of the compile options you use. Ladebug uses whatever information is available during a debugging session.
For example, with full debugging information, Ladebug can set breakpoints on procedures and functions; it recognizes routine names and knows parameters and values; it can display source code, knows the source file name, and can provide line numbers.
When encountering limited debugging information, Ladebug attempts to set breakpoints by making assumptions from the available information. See Section 17.2 for sample sessions in which you debug programs with limited information.
If no debugging information is available in the program's executable file, Ladebug allows for machine-level debugging. (See Chapter 18 for information on machine-level debugging.)
The following are some examples of compile and link options that are likely to produce limited debugging information:
-g
flag
-g0, -g1,
or -g
-x
flag. (The -r
linker flag is usually used with the -x
flag, except
in the final link.)
-s
flag
ostrip
command
strip
command
The following sections compare Ladebug's ability to debug programs containing full or limited debugging information in the program's symbol table. Each example is provided in two forms:
-g2
(full debugging
information)
As a sample program is analyzed, you will first see the output based on full debugging information, which is then compared to the output where some of the debugging information is missing.
The examples provided are for illustration only and do not cover all of the conditions you may encounter. Use these example to help understand what may be happening when you debug your own programs and modules that contain less than full debugging information.
-g2
flag.
Sample sessions are presented as follows:
-x
. The operating system is
Digital UNIX 4.0.
-x
. The operating system is
Digital UNIX 3.2.
-x -r
. The operating system is Digital UNIX 3.2.
-
x
and -r
flags over both files.
This section presents a sample debugging session on a C++ program
containing full symbolic debugging information, then the same
program compiled with -g2
and linked with -
x
. In the second form of the example program, -
x
strips all symbolic debugging information except for
procedure and file information. The operating system is Digital
UNIX 4.0.
If your executable file contains full symbolic debugging information, Ladebug can set a breakpoint at various levels, as shown in Example 17-1.
(ladebug) stop in Thing::Thing Select an overloaded function1 ---------------------------------------------------- 1 Thing::Thing(char* const) 2 Thing::Thing(const int) 3 Thing::Thing(void) 4 None of the above ---------------------------------------------------- 3 [#1: stop in Thing::Thing(void) ] (ladebug) stop in Thing::Thing(const int) [#2: stop in Thing::Thing(const int) ] (ladebug) stop in dump Symbol dump not visible in current scope. dump has no valid breakpoint address Warning: Breakpoint not set (ladebug) stop in Thing::dump [#3: stop in void Thing::dump(const char* const) ]2
Thing::
scope qualification;
Thing::
is part of the name of the routine.
Thing::
is part of the name for the function
dump
.
If your executable file contains limited symbolic debugging information, Ladebug lacks information to set breakpoints as shown in Example 17-2.
(ladebug) stop in Thing::Thing Thing is not a valid breakpoint address Warning: Breakpoint not set1 (ladebug) stop in Thing2 Thing is not a valid breakpoint address Warning: Breakpoint not set (ladebug) stop in Thing::~Thing stop in Thing::~Thing Unable to parse input as legal command or C++ expression. (ladebug) stop in ~Thing stop in ~Thing Unable to parse input as legal command or C++ expression. (ladebug) stop in dump [#1: stop in dump ]3
dump
is unique and not dependent upon the
classname Thing::
to distinguish it.
Example 17-3 shows how Ladebug can list the source code corresponding to the position of the program counter if your executable file contains full debugging information.
(ladebug) run [1] stopped at [Thing::Thing(void):58 0x120002170] (Cannot find source file classdefinition.C) (ladebug) use ./src Directory search path for source files: . ./bin /usr/users/debug/ladebug ./src (ladebug) list 59 dump ("Thing constructor, no arguments"); 60 } 61 62 63 Thing::Thing (const Thing1 t1) 64 : thisThing1 (t1), 65 thisThing2 (bogusThing2), 66 thisSideEffect (1) 67 { 68 sideEffect++; 69 dump ("Thing constructor, Thing1 argument"); 70 } 71 72 #ifndef CHANGE_ORDER 73 Thing::Thing (const Thing2 t2) 74 : thisThing1 (bogusThing1), 75 thisThing2 (t2), 76 thisSideEffect (1) 77 { 78 sideEffect++; 79 dump ("Thing constructor, Thing2 argument");
Without full symbolic debugging information, Ladebug does not know
name of the source file. It can display some information for the
routine dump
because it is unique and not dependent
upon the Thing::
class.
If your executable file contains full debugging information, Ladebug can display the stack trace of currently active functions. In Example 17-4, note the detailed call stack with class types and values in them.
(ladebug) where >0 0x120002170 in ((Thing*)0x11ffff7c8)->Thing() classdefinition.C:58 #1 0x120002574 in main() classdefinition.C:106 (ladebug) cont [3] stopped at [void Thing::dump(const char* const):93 0x1200023f0] 93 sideEffect++; (ladebug) where >0 0x1200023f0 in ((Thing*)0x11ffff7c8)->dump(header=0x120001b80="Thing constructor, no arguments") classdefinition.C:93 #1 0x120002198 in ((Thing*)0x11ffff7c8)->Thing() classdefinition.C:59 #2 0x120002574 in main() classdefinition.C:106 (ladebug) quit
If your executable file contains limited symbolic debugging
information, Ladebug can show that you are in a routine called
Thing
but can't differentiate which one. Example 17-5 illustrates this.
(ladebug) where >0 0x1200023e8 in dump(0x3ff80894608, 0x12000294f, 0x11ffff7c8, 0xc70, 0x3ff808941cc, 0x120002950) DebugInformationStrippedFromFile0:??? #1 0x120002198 in Thing(0x11ffff7c8, 0xc70, 0x3ff808941cc, 0x120002950, 0xd10, 0x3ffc0819100) DebugInformationStrippedFromFile0:??? #2 0x120002574 in main(0x3ffc0002078, 0xffffffff, 0x120001b70, 0x1, 0x140000060, 0x0) DebugInformationStrippedFromFile0:??? (ladebug) quit
This section presents a sample debugging session on a C program,
first containing full symbolic debugging information, then compiled
in the same way but linked with the -x
flag. The
operating system is Digital UNIX 3.2.
In the second form of the program, -x
strips all
symbolic debugging information except for procedure and file
information.
Example 17-6 invokes the user
program with full debugging information and sets breakpoints on
three routines: main,
buildLocalList,
and createNewElement
.
csh> $LADEBUG ../bin/c_gflags001-g Welcome to the Ladebug Debugger Version 4.0-9 ------------------ object file name: ../bin/c_gflags001-g Reading symbolic information ...done (ladebug) stop in main [#1: stop in main ] (ladebug) stop in buildLocalList [#2: stop in buildLocalList ] (ladebug) stop in createNewElement [#3: stop in createNewElement ] (ladebug) run [1] stopped at [void main(void):157 0x1200014b8]1 157 mainList = buildLocalList (5); (ladebug)
Example 17-7 shows a program
compiled with -g2
and linked with -x
. In
this case, the user program has all symbolic debugging information
stripped, except for procedure and file information. The local
(nonglobal) symbols are not preserved in the debugging information
and Ladebug has no information to work with.
csh> $LADEBUG ../bin/c_gflags001-x Welcome to the Ladebug Debugger Version 4.0-9 ------------------ object file name: ../bin/c_gflags001-x Reading symbolic information ...done (ladebug) stop in main [#1: stop in main ] (ladebug) stop in buildLocalList [#2: stop in buildLocalList ] (ladebug) stop in createNewElement [#3: stop in createNewElement ] (ladebug) run [1] stopped at [main:??? 0x1200014b0]1
Ladebug normally starts on the first line of the source code. It skips over initialization and other bookkeeping information in the prologue when you enter a routine, so that the stack and parameters are in the expected state. In this example, the information about the prologue is not available, so Ladebug does its best to stop in the routine.
Example 17-8 shows how Ladebug can list the source code corresponding to the position of the program counter if your executable contains full debugging information,
Ladebug knows about the current program counter and displays lines from line 157.
(ladebug) use ../src Directory search path for source files: . ../bin ../src (ladebug) list 158 dumpLocalList ("Local list"); 159 160 buildDuplicateList (); 161 dumpDuplicateList ("Duplicate list"); 162 163 return; 164 } /* main */ 165
In Example 17-9, the name of the source file has been stripped out completely from the symbol table. Ladebug makes up a name for this file: DebugInformationStrippedFromFile0.
(ladebug) use ../src Directory search path for source files: . ../bin ../src (ladebug) list (Can't find file DebugInformationStrippedFromFile0)
The name Ladebug creates is of some value. In some cases, this may
be the only way of discriminating between two different instances of
an overloaded function name. For example, there may be two different
functions named buildList
that can only be resolved by
using one of these generated source file names.
The file name "DebugInformationStrippedFromFile0" has the symbol
table file number in it. For more complex programs, you could use
odump(1)
and stdump(1)
to identify where
you are in your code.
If your executable file contains full debugging information, Ladebug can display the stack trace of currently active functions with detailed information as shown in Example 17-10.
(ladebug) cont [2] stopped at [buildLocalList:65 0x1200013ac] 65 firstElement = NULL_LIST;1 (ladebug) where2 >0 0x1200013ac in buildLocalList(lengthOfList=5) gflags001a.c:65 #1 0x1200014c4 in main() gflags001a.c:157 (ladebug) c [3] stopped at [createNewElement:44 0x120001348] 44 newElement = (ListElementHandle) malloc (sizeof (ListElement)); (ladebug) where3 >0 0x120001348 in createNewElement(dataValue=0, useValue=0)gflags001a.c:44 #1 0x1200013d8 in buildLocalList(lengthOfList=5) gflags001a.c:71 #2 0x1200014c4 in main() gflags001a.c:157 (ladebug) quit
lengthOfList
), and its type and
value. It also knows that there is only one parameter for
buildLocalList
and none for main
.
With limited debugging information, Ladebug must approximate the call stack information, as in Example 17-11.
(ladebug) c [2] stopped at [buildLocalList: ??? 0x120001398]1 (ladebug) where >0 0x120001398 in buildLocalList(0x1200012b4, 0x0, 0x0, 0x0, 0x1, 0x11ffffbf8) DebugInformationStrippedFromFile0:???2 #1 0x1200014c4 in main(0x1, 0x20000000, 0x120001278, 0x120001200, 0x1200012b4, DebugInformationStrippedFromFile0:??? (ladebug) c [3] stopped at [createNewElement: ??? 0x120001328] (ladebug) where3 >0 0x120001328 in createNewElement(0x3ff80016b18, 0x0, 0x1200014c4, 0x0, 0x1, DebugInformationStrippedFromFile0:??? #1 0x1200013d8 in buildLocalList(0x1200014c4, 0x0, 0x1, 0x0, 0x100000000,0x10 DebugInformationStrippedFromFile0:??? #2 0x1200014c4 in main(0x1, 0x0, 0x100000000, 0x100000005, 0x1200012b4, 0x0) DebugInformationStrippedFromFile0:??? (ladebug) quit
This example program contains two program files, calldriver.C and callstack_intermediates.C, that contain various static and global routines. The static routines are known only within the file while the global (external) routines are known to both files.
In the first form of this program, both calldriver.C and
callstack_intermediates.C have full symbolic debugging information.
The second form of the program contains limited debugging
information; calldriver.C is compiled with -g2
and
linked with the -x -r
options, stripping out much
of the symbol table, so only part of this program has reasonable
symbols.
Figure 17-1 shows the structure of the example program.
Example 17-12 invokes the user program with full debugging information and sets breakpoints on four routines.
csh> $LADEBUG ../bin/x_callstack01-g Welcome to the Ladebug Debugger Version 4.0-9 ------------------ object file name: ../bin/x_callstack01-g Reading symbolic information ...done Directory search path for source files: . ../bin /usr/users/debug/ladebug (ladebug) stop in full_local [#1: stop in int full_local(const unsigned) ]1 (ladebug) stop in full_global [#2: stop in int full_global(const unsigned) ] (ladebug) stop in intermediate_global [#3: stop in int intermediate_global(const unsigned) ] (ladebug) stop in intermediate_local [#4: stop in int intermediate_local(const unsigned) ] (ladebug) run2 [3] stopped at [int intermediate_global(const unsigned):41 0x12000206c] 41 intermediate_global_count++;3
run
command, ladebug can
determine the routine name, the line number, and address for the
routine.
When calldriver.C is compiled with -g2
but linked
with -x -r
, you get the result shown in Example 17-13 when you run the
debugger:
csh> $LADEBUG ../bin/x_callstack01-xr Welcome to the Ladebug Debugger Version 4.0-9 ------------------ object file name: ../bin/x_callstack01-xr Reading symbolic information ...done Directory search path for source files: . ../bin /usr/users/debug/ladebug (ladebug) stop in full_local Symbol full_local undefined.1 full_local has no valid breakpoint address Warning: Breakpoint not set (ladebug) stop in full_global [#1: stop in full_global ]2 (ladebug) stop in intermediate_local [#2: stop in int intermediate_local(const unsigned) ]3 (ladebug) stop in intermediate_global [#3: stop in int intermediate_global(const unsigned) ] (ladebug) run4 [3] stopped at [int intermediate_global(const unsigned):41 0x12000206c] (Cannot find source file callstack_intermediates.C)
odump()-Fv ../bin/x_
callstack01-xr
and look for more information about this
file.
Example 17-14 shows how Ladebug can list the source code for the file callstack_intermediates.C if your executable file contains full debugging information. For this part of the program, Ladebug knows source lines, routine types, and routine parameters.
(ladebug) use ../src Directory search path for source files: . ../bin /usr/users/debug/ladebug ../src (ladebug) list 42 43 #ifdef DO_IO 44 cout << "intermediate_global: called with (" << i 45 << "), count now (" << intermediate_global_count << ")"<<endl; 46 #endif // DO_IO 47 48 const int result = intermediate_local (i); 49 return result; 50 } // intermediate_global 51
When the program is compiled the same way but linked with -x
-r
, the results are the same for callstack_intermediates.C.
However, you can't see or list the source for callstack_driver.C.
Example 17-15 shows how Ladebug displays the stack trace of currently active functions if your executable file contains full debugging information.
(ladebug) where1 >0 0x12000206c in intermediate_global(i=0) callstack_intermediates.C:41 #1 0x120001f6c in main() callstack_driver.C:69 (ladebug) cont2 [4] stopped at [int intermediate_local(const unsigned):27 0x120001fec] 27 intermediate_local_count++; (ladebug) cont [2] stopped at [int full_global(const unsigned):41 0x120001edc] 41 full_global_count++; (ladebug) cont [1] stopped at [int full_local(const unsigned):27 0x120001e70] 27 full_local_count++; (ladebug) where3 >0 0x120001e70 in full_local(i=0) callstack_driver.C:27 #1 0x120001efc in full_global(i=0) callstack_driver.C:48 #2 0x12000200c in intermediate_local(i=0) callstack_intermediates.C:34 #3 0x12000208c in intermediate_global(i=0) callstack_intermediates.C:48 #4 0x120001f6c in main() callstack_driver.C:69
cont
command, Ladebug
provides full information on the next breakpoint. In this case,
it shows the static routine intermediate_local
and
the number of arguments and its type (const unsigned
).
When callstack_driver.C is compiled with -g2 and linked with
-x -r
, the results are different, as shown in Example 17-16.
(ladebug) where >0 0x12000206c in intermediate_global(i=0) callstack_intermediates.C:41 #1 0x120001f6c in ../bin/x_callstack01-xr1 (ladebug) cont [2] stopped at [int intermediate_local(const unsigned):27 0x120001fec] 27 intermediate_local_count++; (ladebug) cont [1] stopped at [full_global: ??? 0x120001ec8]2 (ladebug) where >0 0x120001ec8 in full_global(0x0, 0x870, 0x3ff808941cc, 0x1200022d0, 0x8e0, 0x3ffc0819100) DebugInformationStrippedFromFile2:???3 #1 0x12000200c in intermediate_local(i=0) callstack_intermediates.C:34 #2 0x12000208c in intermediate_global(i=0) callstack_intermediates.C:48 #3 0x120001f6c in ../bin/x_callstack01-xr4
full_global
but cannot tell in which file or on
what line number.
full_global
:
DebugInformationStrippedFromFile2. Since it does not know the
names or values of the parameters associated with full_
global
, it lists the first six register parameters,
according to the compiler calling convention
The results are different when you print static and local variables with full or limited debugging information. Full information produces the results shown in Example 17-17.
(ladebug) print full_local_count1 0 (ladebug) print full_global_count2 1 (ladebug) print intermediate_local_count Symbol intermediate_local_count not visible in current scope. Error: no value for intermediate_local_count3 (ladebug) print intermediate_global_count 1
Example 17-18 shows the results with limited debugging information for callstack_driver.C.
(ladebug) print full_local_count Symbol full_local_count undefined.1 Error: no value for full_local_count (ladebug) print full_global_count2 0
-g2
.
The sample program in this section is the same as the program used
in Section 17.2.3, except that it was
linked with a different series of -x
and -
r
flags. As a result, different parts of the program have
symbolic debugging information removed. Both files, calldriver.C and
callstack_intermediates.C, contain limited debugging information.
As you go through this example debugging session, compare the
results with output of the programs compiled with -g2
in Section 17.2.3.
When you try to set a breakpoint, Ladebug cannot recognize the names of static or global routines. The information about the routines in both calldriver.C and callstack_intermediates.C has been stripped out, as shown in Example 17-19.
csh> $LADEBUG ../bin/x_callstack03-xr Welcome to the Ladebug Debugger Version 4.0-9 ------------------ object file name: ../bin/x_callstack03-xr Reading symbolic information ...done Directory search path for source files: . ../bin /usr/users/debug/ladebug (ladebug) stop in full_local Symbol full_local undefined. full_local has no valid breakpoint address1 Warning: Breakpoint not set (ladebug) stop in full_global [#1: stop in full_global ]2 (ladebug) stop in intermediate_local Symbol intermediate_local undefined. intermediate_local has no valid breakpoint address3 Warning: Breakpoint not set (ladebug) stop in intermediate_global [#2: stop in intermediate_global ]4 (ladebug) run [2] stopped at [intermediate_global: ??? 0x1200015a8]
With limited debugging information on both files, Ladebug cannot list the source since it does not have the name of the file. It does provide a name for the file (DebugInformationStrippedFromFile7), as shown in Example 17-20, which allows you to distinguish from other information later on.
(ladebug) use ../src Directory search path for source files: . ../bin /usr/users/debug/ladebug ../src (ladebug) list (Can't find file DebugInformationStrippedFromFile7)
With limited debugging information, Ladebug displays the stack trace as shown in Example 17-21.
(ladebug) where >0 0x1200015a8 in intermediate_global(0x1, 0x0, 0x0, 0x0, 0x1, 0x11ffff9a0) DebugInformationStrippedFromFile7:???1 #1 0x1200014bc in ../bin/x_callstack03-xr2 (ladebug) cont [1] stopped at [full_global: ??? 0x120001418]3 (ladebug) where >0 0x120001418 in full_global(0x0, 0x1400000d8, 0x3ff808941cc, 0x120001810, 0x6d0, 0x3ffc0819100)DebugInformationStrippedFromFile6:???4 #1 0x12000155c in UnknownProcedure0FromFile7(0x0, 0x1400000d8, 0x3ff808941cc, 0x120001810, 0x6d0, 0x3ffc0819100) DebugInformationStrippedFromFile7:???5 . . .
full_global
but cannot tell which file or line
number.
-x -
r
strips out the names of static routines but retains
some routine information). Ladebug creates a routine name
(UnknownProcedure0FromFile7). Because Ladebug recognizes the
routine name "UnknownProcedure0FromFile7", you can figure out
the name of the static routine Ladebug would use by running
odump -Pv
.
Ladebug lets you set a breakpoint on the routine name it created in Example 17-10, even though information is lacking for static routines. It can display information on global variables. Information about static variables local to this file is lost, as shown in Example 17-22.
(ladebug) stop in UnknownProcedure0FromFile7 [#3: stop in UnknownProcedure0FromFile7 ] (ladebug) print full_local_count Symbol full_local_count undefined. Error: no value for full_local_count (ladebug) print full_global_count 0 (ladebug) print intermediate_local_count Symbol intermediate_local_count undefined. Error: no value for intermediate_local_count (ladebug) print intermediate_global_count 1 (ladebug) quit