Zen and the Art of Debugging C/C++ in Linux with GDB P: 19 jwwicks C/C++ Programs and Debugging in Linux



This tutorial will give you a basic idea how to debug a program in Linux using GDB. As you are aware Visual Studio doesnt run on Linux so you have to use some of the tools provided on the command-line. If you hate the command line tools, get over it since youre bound to be using them at some point in your career. All commands in Linux ARE case sensitive so capital letters are different from lowercase letters. If you need basic information about a command type command --help at the shell prompt, where command is any Linux command and youll get a help screen. Heres a basic list of commands youll get to know in Linux:



ls  Usage: ls [OPTION]... [FILE]...

List information about the FILEs (the current directory by default).

Example: ls -l *.c



man  Usage: man [OPTION]... [COMMAND]...

Displays a manual page(s) about a command



clear  Clears the shell screen.



grep  Usage: grep [OPTION]... PATTERN [FILE] ...

Search for PATTERN in each FILE or standard input.

Example: grep -i 'hello world' menu.h main.c



apropos  Usage: apropos KEYWORD...

Search for KEYWORD in commands. Great for finding a command when you arent sure what it is.



Note: I had to change the makefile sections somewhat just so I could post so anytime you see GNU_COMPILER replace it with the appropriate command.



Creating a Project



In Linux youll use a shell of some sort, CShell or Bash etc to create projects. For Windows based computers on a college campus youll probably use





Your instructor/administrator will give you logon information. Once logged in, do a directory listing with the ls command. For most college accounts there is only one directory initially and that is public_html. In general it is a good practice to arrange your files on disk in some sort of directory scheme.

Note: When creating directories in Linux uppercase letters ARE significant; Projects is NOT the same as projects.

Create a directory called projects using the mkdir command like the following:





Change to the projects directory using the cd command. Create a directory for this application using the mkdir command again and call it MyProjectName1 where MyProjectName1 is some descriptive name for the program you are working on. For instance, if you are writing a program that computes income taxes type in MyTaxProgram or something similar.





Now change to this directory with the same cd command used previously. At this point your screen should look like the following:





Now that we have a project directory well need to create a makefile to handle the building of our project once we get some source files created. The makefile is just a text file like any other but it has some special commands inside it to build our executable. To create a text file do the following:

1. Start youre favorite Unix editor, there are several, vi and emacs are the most widely used editors but pico/nano is a good basic editor available on most machines in college labs. All the following examples use pico so the commands will be different if you are using a different editor. Type pico at the command prompt and youll see the following screen:





2. Press ctrl-O and save the file as makefile.





3. Then add the following text to the makefile:

Expand | Select | Wrap | Line Numbers main.exe: Source1.cpp GNU_COMPILER -Wall Source1.cpp -o main.exe Note: The name Source1.cpp MUST match the name you'll use for the source code file in the next section.

4. Press ctrl-O again to save the changes to your makefile.





Creating a New Source Code File



If you are working on a new program, a new source code file must be created after the project directory has been created. The steps below describe how to create the new source code file:

1. Start youre favorite Unix editor.

2. Press ctrl-O and save the file as Source1.cpp where Source1.cpp is some descriptive name for the program you are working on. For instance, if you are writing a program that computes income taxes type in MyTaxProgram.cpp or something similar.





3. Add the following text to your Source1.cpp file:

Expand | Select | Wrap | Line Numbers ////////////////////////// /// source1.cpp - /// Purpose: Some source code file /// /// Author: My Name /// Date: January 1st, 2xxx /// //////////////////////// /// History /// INI 2xxx-01-01 v1.00.00 Initial release // Includes #include <iostream> #include <iomanip> using namespace std; int main(int argc, char** argv) { int ret_val = 0; // holds return value for main program cout << "Hello World..." << endl; return ret_val; }





Compiling my first Program



Now that we have our makefile and Source1.cpp files created all thats needed is to run the make utility to create our executable for testing.

1. Get a directory listing of the current files in our project directory by using the ls command.

2. Run the make command by typing make at the command prompt.

3. Messages from the compiler (error messages, warning messages and a successful compile/build message) will be displayed on screen.

4. Get a directory listing of the current files in our project directory by using the ls command again.



Note: Notice the new file created by make called main.exe. This is our executable.





Running a Program



Once the compile/build is successful, type the name of our executable at the command prompt to run it. In this case our executable is main.exe so type the following at the command prompt ./main.exe. The following output should be displayed:





Lets add the following text to our code to make this program a little more interesting.

1. Add the following text before main:

Expand | Select | Wrap | Line Numbers // Global constants and variables #define PRG_NAME "MyProjectName1 - v 1.0.00" #define CPY_RGHT "Copyright © 2xxx - " #define AUTHOR "My Name" // function prototypes void show_copyright( void );

Expand | Select | Wrap | Line Numbers show_copyright();

Expand | Select | Wrap | Line Numbers ///////////////////////// /// show_copyright /// Purpose: Show program name and copyright notice /// /// Parameters : None /// Output : couts PRG_NAME, CPY_RGHT and AUTHOR defines /// /// Returns : None /// SideEffects : None //////////////////////// void show_copyright ( void ) { cout << AUTHOR << "'s " << PRG_NAME << endl; cout << CPY_RGHT << AUTHOR << endl << endl; return; }





4. Now Compile/build and run the solution as you did before. You should see the following screen:







Debugging a Program



It can sometimes be difficult to determine why a program does not run successfully. A debugger allows a programmer to step through a program line-by-line to watch it execute and fail. The values of variables can be watched as execution takes place as well. GNU C++ has a debugger which can be used to step through a program. It is important to note that the program must compile first. Lets add some more code to our Source1.cpp file (Note: this code has a logic problem in it to help you get used to debugging):



1. Add the following code before main after the show_copyright function prototype:

Expand | Select | Wrap | Line Numbers char get_choice( void ); bool is_valid_choice( char );

Expand | Select | Wrap | Line Numbers char choice;

Expand | Select | Wrap | Line Numbers do{ cout << "Hello World..." << endl; choice = get_choice(); }while(!is_valid_choice( choice));

Expand | Select | Wrap | Line Numbers ///////////////////////// /// get_choice /// Purpose: Check to see if user wants to continue /// /// Parameters: None /// Output: Prompts user to continue program /// /// Returns: char ch - Choice entered by user /// SideEffects: None ///////////////////////// char get_choice( void ) { char ret_val; char ch; cout << "Do you want to continue (1 = Yes) (0 = No) ?: "; cin >> ch; ret_val = ch; return ret_val; } ///////////////////////// /// is_valid_choice /// Purpose: Checks for valid yes or no entry to continue /// /// Parameters : char val - Current choice to continue /// Output : Displays an error message if an invalid choice is passed /// /// Returns : true if choice is valid and false otherwise /// SideEffects : None //////////////////////// bool is_valid_choice( char val ) { bool ret_val = true; switch (val){ case 0: case 1: break; default: ret_val = false; cout << "Invalid choice : " << val << endl; cout << "Please enter one of the following(0 or 1) : " << endl; break; } return ret_val; }





6. Press 0 and instead of stopping the program like we asked, our program continues. We have a bug here Watson. Press Ctrl+C to stop executing the program. Now well work on finding the bug in our code using the GNU debugger command gdb, but first we have to compile our program with some special code to enable debugging. To do that well first need to create a directory named Debug and then modify our makefile to build our application with debugging information. At the command prompt use the mkdir command to create a new directory named Debug. Use the ls command to confirm that the directory was created and you should see a screen similar to the following:





Next open the makefile in your editor of choice, well use pico again. Change the makefile so it has the following text in it:

Expand | Select | Wrap | Line Numbers main.exe: Source1.cpp GNU_COMPILER -Wall Source1.cpp -o main.exe dbg_main: Source1.cpp GNU_COMPILER -g Wall Source1.cpp o ./Debug/main.exe make dbg_main and get a directory listing of the Debug directory using ls and you should have the following on your screen:





Now well run the GNU debugger gdb with the newly compiled application with debugging information in it. Type gdb Debug/main.exe at the command prompt. You should see a screen similar to the following:





At this point you are in the debugger and there are a number of command that can be used from here to help you figure out whats going on inside your program. Heres a basic list of commands youll get to know in the GNU debugger:



help  Usage: help [COMMAND]

List information about the COMMAND

Example: help running or help breakpoints



list  Usage: list [LINE or FUNCTION][,][LINE]...

Lists the lines in a file, 10 lines at a time

Example: list 1,100



break  Usage: break [LINE or FUNCTION]

Creates a breakpoint at a specified LINE or FUNCTION location

Example: break 100



run  Usage: run [ARGUMENTS] ...

Runs the currently loaded program with the specified ARGUMENTS.

Example: run -I hello world



next  Usage: next

Steps through the next statement in the program.

step  Usage: step

Steps through one instruction only.



quit  Usage: quit

Quits the GNU debugger.





Breakpoints



A breakpoint tells the debugger to pause execution of a program until you tell it to continue. In order to step through a program (i.e. watch a program execute), a breakpoint should be set on the executable statement at which you want execution to pause. To set a breakpoint on a statement, use the break command at the (gdb) prompt. You specify either a function name or the line number of the executable to break on if you know it.

Determining where you want the breakpoint is a critical part of debugging. Put your breakpoint too soon in the execution of the program and you waste time stepping through code that doesnt need to be debugged. Put the breakpoint too late and you might just miss the bug altogether. In our sample program above we have two possible places in our code that could be causing the problem. Either the get_choice function isnt returning the proper value or the is_valid_choice function isnt correctly checking the value. Lets set a breakpoint to check the return value of the get_choice function. There are two possible places to check the value, one being inside the function itself or in the assignment statement in main. Well set our breakpoint in main so we can check the return value. First well use the list command to find the line we want in the executable. In our example main starts at line 26 and ends at line 39 so the command list 26,39 will show those lines in the debugger:



Note: Your line numbers may vary depending on how you create the source file. Experiment.



In our example the line to set the breakpoint on is line number 35. So type in the command break 35 at the (gdb) prompt. You should see a screen similar to the following:







Watching a Program Execute



Once a breakpoint is set, start the debugger by using the run command. The program will begin to run but pause at the statement with the breakpoint prior to its execution. For our sample you should see something like the screen below:





At this point you have a number of choices (detailed below)

1) It is often helpful to know the value of a variable at a certain point in an executing program. The debugger allows you to look at the contents of variables as a program executes. Use the print command to display the value of an expression or variable.

2) If the current statement is a function call, Use the step command to go into the function to watch it execute.

3) Go to the next statement in the program by using the next command.



Lets use the print command to inspect the value of choice in our application. Notice the value for choice in the window below is the char 0 or NULL. Well be double-checking it in the next section once the get_choice function returns a value.





Since were not interested in stepping into the get_choice function well use the next command at the gdb prompt to execute the next statement in our program





Input and Output



As you may have notice output from our application appears in the gdb console window. You should get a prompt asking Do you want to continue (1 = Yes) (0 = No), type in a 0 and hit [Enter]. Now lets use the print command again on choice. You should see a screen similar to the following:





Notice the change from before, 48 and 0 instead of 0 and \0. The 48 is the ASCII value for the character 0, so the get_choice function is correctly returning a character value and choice is correctly storing that value. By stepping through the program weve discovered our bug isnt in the get_choice function. Since our next statement in the program is the other function we need to check, is_valid_choice, and we know that a valid character is stored in choice and the is_valid_choice function should just keep looping with no error message. Use the step command to execute the is_valid_choice function. Notice what happens to our console window.





This isnt correct since we know that the character 0 was passed in the variable choice to the function is_valid_choice by the following statement in main: }while(!is_valid_choice( choice));. So the problem has to be in the way in which is_valid_choice is checking the value. So well use the step command to execute each statement in that function to find out where things are going wrong. But first you have to step past a couple of the statements to get to the is_valid_choice function again. Notice that the line number on the left hand side of the console window above is 34. That indicates the current statement. In our example its the cout statement that displays the Hello World  message. Type next to execute this statement. Type next to once again execute the get_choice function statement on line 35. In the console window type in 1 at the Do you want to continue prompt and then press [Enter] to continue the program. Now type step to debug the is_valid_choice function.





Notice that the line number on the left side of the screen is at line 90 inside the is_valid_choice function and that the variable called val has the value passed in the actual parameter choice, ASCII 49 and 1, from main.



Lets list the next 10 lines by typing list 90,100 at the (gdb) prompt. Notice that line number 93 is the case statement for 1. Our program should execute line 93 since val has a 1 in it. Type step twice more and notice that the line number jumps all the way to the first statement inside the default: section of the switch, line number 96. It should have hit the break statement in line 94 after seeing

Expand | Select | Wrap | Line Numbers case 1: break;





What You are Looking for



There are two ways in which a debugger is most helpful: 1) to verify statements are executed as expected, and 2) to verify that variables have their expected values. Look at the case statement very carefully we seem to be comparing an integer 1 with the character 1, which is 49 in ASCII, so our program is functioning correctly but our logic test isnt right. Change the case statement in the is_valid_choice function to look for character data:



Expand | Select | Wrap | Line Numbers switch (val){ case '0': case '1': break; make dbg_main and then restart the debugger with gdb Debug/main.exe. Type break 35 to add the breakpoint again for the get_choice statement, then type run to begin the debugging session like before. Type next and then type a 1 again when prompted and press [Enter] as you did before in the console window. Type next again and notice that this time through, the application jumps to the end of the program, line number 38, like it should.





Type kill at the (gdb) prompt to stop debugging the application.

There is still one more logic problem in this program and you should use the same techniques to find it. (Hint: the program should continue printing Hello World and asking the user to continue if the user enters a 1 at the prompt.)





Solutions



Here's a strictly Standard C solution...

Expand | Select | Wrap | Line Numbers /////////////////////////////////////// /// \file main.c /// \brief Some source code file Project Main Module /// /// \author My Name /// \version 00.99.00 /// \date January 1st, 2xxx /// //////////////////////// // History // INI 2xxx-01-01 v1.00.00 Initial release // Includes #include <stdio.h> #include <stdlib.h> // Global constants and variables #define PRG_NAME "MyProjectName1 - v 1.0.00" #define CPY_RGHT "Copyright © 2xxx - " #define AUTHOR "My Name" // function prototypes void show_copyright( void ); char get_choice( void ); unsigned int is_valid_choice( char ); // Uncomment to run just the testing main //#define TEST 1 ///////////////////////// /// \fn main(int argc, char** argv) /// \brief Main module for Hello World program. /// /// \param argc - integer number of arguments passed from system to program /// \param argv - pointer to array of characters of arguments passed to program from system /// /// \return integer value for success or failure ///////////////////////// #ifndef TEST int main(int argc, char** argv) { int ret_val = 0; // holds return value for main program char choice = '0'; show_copyright(); do{ do{ printf("Hello World...

"); choice = get_choice(); }while(!is_valid_choice( choice)); }while(choice == '1'); return ret_val; } #else // Testing Main int main( int argc, char** argv) { int ret_val = 0; return ret_val; } #endif ///////////////////////// /// \fn show_copyright(void) /// \brief Show program name and copyright notice /// /// \b SideEffects : None

/// \b Output : couts PRG_NAME, CPY_RGHT and AUTHOR defines

/// /// \return None //////////////////////// void show_copyright ( void ) { printf("%s 's %s

", AUTHOR, PRG_NAME); printf("%s %s

", CPY_RGHT, AUTHOR); return; } ///////////////////////// /// \fn get_choice( void ) /// \brief Check to see if user wants to continue /// /// \b SideEffects: None

/// \b Output: Prompts user to continue program

/// /// \param None /// /// \return char ch - Choice entered by user ///////////////////////// char get_choice( void ) { char ret_val; char ch; printf("Do you want to continue (1 = Yes) (0 = No) ?: "); fflush(stdin); scanf("%c^%*",&ch); ret_val = ch; return ret_val; } ///////////////////////// /// \fn is_valid_choice( char val ) /// \brief Checks for valid yes or no entry to continue /// /// \b SideEffects : None

/// \b Output : Displays an error message if an invalid choice is passed

/// /// \param val - Current choice to continue /// /// \return boolean true if choice is valid and false otherwise //////////////////////// unsigned int is_valid_choice( char val ) { unsigned int ret_val = 1; switch (val){ case '0': case '1': break; default: ret_val = 0; printf("Invalid choice : %c

", val); printf("Please enter one of the following(0 or 1) :

"); break; } return ret_val; }

Expand | Select | Wrap | Line Numbers /////////////////////////////////////// /// \file main.cpp /// \brief Some source code file Project Main Module /// /// \author My Name /// \version 00.99.00 /// \date January 1st, 2xxx /// //////////////////////// // History // INI 2xxx-01-01 v1.00.00 Initial release // Includes #include <iostream> #include <iomanip> using namespace std; // Global constants and variables const char PRG_NAME[] = {"MyProjectName1 - v 1.0.00"}; const char CPY_RGHT[] = {"Copyright © 2xxx - "}; const char AUTHOR[] = {"My Name"}; // function prototypes void show_copyright( void ); char get_choice( void ); bool is_valid_choice( char ); // Uncomment to run just the testing main //#define TEST 1 ///////////////////////// /// \fn main(int argc, char** argv) /// \brief Main module for Hello World program. /// /// \param argc - integer number of arguments passed from system to program /// \param argv - pointer to array of characters of arguments passed to program from system /// /// \return integer value for success or failure ///////////////////////// #ifndef TEST int main(int argc, char** argv) { int ret_val = 0; // holds return value for main program char choice; show_copyright(); do{ do{ cout << "Hello World..." << endl; choice = get_choice(); }while(!is_valid_choice( choice)); }while(choice == '1'); return ret_val; } #else // Testing Main int main( int argc, char** argv) { int ret_val = 0; return ret_val; } #endif ///////////////////////// /// \fn show_copyright(void) /// \brief Show program name and copyright notice /// /// \b SideEffects : None

/// \b Output : couts PRG_NAME, CPY_RGHT and AUTHOR defines

/// /// \return None //////////////////////// void show_copyright ( void ) { cout << AUTHOR << "'s " << PRG_NAME << endl; cout << CPY_RGHT << AUTHOR << endl << endl; return; } ///////////////////////// /// \fn get_choice( void ) /// \brief Check to see if user wants to continue /// /// \b SideEffects: None

/// \b Output: Prompts user to continue program

/// /// \param None /// /// \return char ch - Choice entered by user ///////////////////////// char get_choice( void ) { char ret_val; char ch; cout << "Do you want to continue (1 = Yes) (0 = No) ?: "; cin >> ch; ret_val = ch; return ret_val; } ///////////////////////// /// \fn is_valid_choice( char val ) /// \brief Checks for valid yes or no entry to continue /// /// \b SideEffects : None

/// \b Output : Displays an error message if an invalid choice is passed

/// /// \param val - Current choice to continue /// /// \return boolean true if choice is valid and false otherwise //////////////////////// bool is_valid_choice( char val ) { bool ret_val = true; switch (val){ case '0': case '1': break; default: ret_val = false; cout << "Invalid choice : " << val << endl; cout << "Please enter one of the following(0 or 1) : " << endl; break; } return ret_val; }



main.cpp

Expand | Select | Wrap | Line Numbers /////////////////////////////////////// /// \file main.cpp /// \brief Some source code file Project Main Module /// /// \author My Name /// \version 00.99.00 /// \date January 1st, 2xxx /// //////////////////////// // History // INI 2xxx-01-01 v1.00.00 Initial release // Includes #include <iostream> #include <iomanip> #include "oApp.h" using namespace std; // Uncomment to run just the testing main //#define TEST 1 ///////////////////////// /// \fn main(int argc, char** argv) /// \brief Main module for Hello World program. /// /// \param argc - integer number of arguments passed from system to program /// \param argv - pointer to array of characters of arguments passed to program from system /// /// \return integer value for success or failure ///////////////////////// #ifndef TEST int main(int argc, char** argv) { int ret_val = 0; // holds return value for main program oApp* myApp = new oApp; myApp->init("Your Message Here...

"); myApp->set_copyright("Copyright© 2006-2008 - "); myApp->set_author("Your Name"); myApp->set_program_name("YourProgramName v00.99.00"); myApp->run(); myApp->done(); delete myApp; return ret_val; } #else // Testing Main int main( int argc, char** argv) { int ret_val = 0; return ret_val; } #endif

Expand | Select | Wrap | Line Numbers #include <iostream> #include <iomanip> #include <string> using namespace std; class oApp{ public: oApp(){ m_choice = '0'; m_author = "My Name"; m_copyright = "Copyright © 2xxx - "; m_program = "MyProjectName1 v1.0.00"; m_message = "Hello World..."; } ~oApp() {}; void init( const string s ); void run( void ); void done( void ); string get_copyright( void ); bool set_copyright( const string copyright ); string get_author( void ); bool set_author( const string author ); string get_program_name( void ); bool set_program_name( const string name ); void show_copyright( void ); private: string m_author; string m_program; string m_copyright; string m_message; char m_choice; char get_choice( void ); bool is_valid_choice( char val ); };

Expand | Select | Wrap | Line Numbers #include "oApp.h" void oApp::init( const string s ) { this->m_message = s; } void oApp::run( void ) { show_copyright(); do{ do{ cout << this->m_message << endl; this->m_choice = get_choice(); }while(!is_valid_choice( this->m_choice )); }while(this->m_choice == '1'); } void oApp::done( void ){} string oApp::get_copyright( void ) { string ret_val = this->m_copyright; return ret_val; } bool oApp::set_copyright( const string copyright ) { bool ret_val = false; m_copyright = copyright; ret_val = this->m_copyright == copyright; return ret_val; } string oApp::get_author( void ) { string ret_val = this->m_author; return ret_val; } bool oApp::set_author( const string author ) { bool ret_val = false; m_author = author; ret_val = this->m_author == author; return ret_val; } string oApp::get_program_name( void ) { string ret_val = this->m_program; return ret_val; } bool oApp::set_program_name( const string name ) { bool ret_val = false; m_program = name; ret_val = this->m_program == name; return ret_val; } ///////////////////////// /// \fn get_choice( void ) /// \brief Check to see if user wants to continue /// /// \b SideEffects: None

/// \b Output: Prompts user to continue program

/// /// \param None /// /// \return char ch - Choice entered by user ///////////////////////// char oApp::get_choice( void ) { char ret_val; char ch; cout << "Do you want to continue (1 = Yes) (0 = No) ?: "; cin >> ch; ret_val = ch; return ret_val; } ///////////////////////// /// \fn is_valid_choice( char val ) /// \brief Checks for valid yes or no entry to continue /// /// \b SideEffects : None

/// \b Output : Displays an error message if an invalid choice is passed

/// /// \param val - Current choice to continue /// /// \return boolean true if choice is valid and false otherwise //////////////////////// bool oApp::is_valid_choice( char val ) { bool ret_val = true; switch (val){ case '0': case '1': break; default: ret_val = false; cout << "Invalid choice : " << val << endl; cout << "Please enter one of the following(0 or 1) : " << endl; break; } return ret_val; } ///////////////////////// /// \fn show_copyright(void) /// \brief Show program name and copyright notice /// /// \b SideEffects : None

/// \b Output : couts m_ProgramName, m_Copyright and m_Author

/// /// \return None //////////////////////// void oApp::show_copyright ( void ) { cout << this->m_author << "'s " << this->m_program << endl; cout << this->m_copyright << this->m_author << endl << endl; return; } This tutorial will give you a basic idea how to debug a program in Linux using GDB. As you are aware Visual Studio doesnt run on Linux so you have to use some of the tools provided on the command-line. If you hate the command line tools, get over it since youre bound to be using them at some point in your career. All commands in Linux ARE case sensitive so capital letters are different from lowercase letters. If you need basic information about a command typeat the shell prompt, whereis any Linux command and youll get a help screen. Heres a basic list of commands youll get to know in Linux: Usage: ls [OPTION]... [FILE]...List information about the FILEs (the current directory by default).Example: ls -l *.c Usage: man [OPTION]... [COMMAND]...Displays a manual page(s) about a command Clears the shell screen. Usage: grep [OPTION]... PATTERN [FILE] ...Search for PATTERN in each FILE or standard input.Example: grep -i 'hello world' menu.h main.c Usage: apropos KEYWORD...Search for KEYWORD in commands. Great for finding a command when you arent sure what it is.Note: I had to change the makefile sections somewhat just so I could post so anytime you see GNU_COMPILER replace it with the appropriate command.In Linux youll use a shell of some sort, CShell or Bash etc to create projects. For Windows based computers on a college campus youll probably use PuTTY . If you're already using Linux or some other variant of Unix then you'll have your own favorite Telnet/SSH Client. Once you start the PuTTY session youll get a screen similar to the following:Your instructor/administrator will give you logon information. Once logged in, do a directory listing with thecommand. For most college accounts there is only one directory initially and that is public_html. In general it is a good practice to arrange your files on disk in some sort of directory scheme.: When creating directories in Linux uppercase letterssignificant;isthe same asCreate a directory calledusing thecommand like the following:Change to thedirectory using thecommand. Create a directory for this application using the mkdir command again and call itwhere MyProjectName1 is some descriptive name for the program you are working on. For instance, if you are writing a program that computes income taxes type in MyTaxProgram or something similar.Now change to this directory with the same cd command used previously. At this point your screen should look like the following:Now that we have a project directory well need to create a makefile to handle the building of our project once we get some source files created. The makefile is just a text file like any other but it has some special commands inside it to build our executable. To create a text file do the following:1. Start youre favorite Unix editor, there are several, vi and emacs are the most widely used editors but pico/nano is a good basic editor available on most machines in college labs. All the following examples use pico so the commands will be different if you are using a different editor. Typeat the command prompt and youll see the following screen:2. Press ctrl-O and save the file as3. Then add the following text to the makefile:: The name Source1.cpp MUST match the name you'll use for the source code file in the next section.4. Press ctrl-O again to save the changes to your makefile.If you are working on a new program, a new source code file must be created after the project directory has been created. The steps below describe how to create the new source code file:1. Start youre favorite Unix editor.2. Press ctrl-O and save the file aswhere Source1.cpp is some descriptive name for the program you are working on. For instance, if you are writing a program that computes income taxes type in MyTaxProgram.cpp or something similar.3. Add the following text to your Source1.cpp file:4. Press ctrl-O again to save the changes to your Source1.cpp file.Now that we have our makefile and Source1.cpp files created all thats needed is to run the make utility to create our executable for testing.1. Get a directory listing of the current files in our project directory by using thecommand.2. Run the make command by typingat the command prompt.3. Messages from the compiler (error messages, warning messages and a successful compile/build message) will be displayed on screen.4. Get a directory listing of the current files in our project directory by using thecommand again.: Notice the new file created by make called. This is our executable.Once the compile/build is successful, type the name of our executable at the command prompt to run it. In this case our executable is main.exe so type the following at the command prompt. The following output should be displayed:Lets add the following text to our code to make this program a little more interesting.1. Add the following text before main:2. Add this call to the copyright function before the Hello World  statement in main:3. After main add the following function:Your Source1.cpp file should look like the following when you are done with all these changes:4. Now Compile/build and run the solution as you did before. You should see the following screen:It can sometimes be difficult to determine why a program does not run successfully. A debugger allows a programmer to step through a program line-by-line to watch it execute and fail. The values of variables can be watched as execution takes place as well. GNU C++ has a debugger which can be used to step through a program. It is important to note that the program must compile first. Lets add some more code to our Source1.cpp file (Note: this code has a logic problem in it to help you get used to debugging):1. Add the following code before main after the show_copyright function prototype:2. Add the following in main:3. Change the cout statement with Hello World  to the following:4. Add the following functions after the show_copyright function:5. Build and run the solution as before and you should see the following screen:6. Pressand instead of stopping the program like we asked, our program continues. We have a bug here Watson. Press Ctrl+C to stop executing the program. Now well work on finding the bug in our code using the GNU debugger command gdb, but first we have to compile our program with some special code to enable debugging. To do that well first need to create a directory named Debug and then modify our makefile to build our application with debugging information. At the command prompt use thecommand to create a new directory named. Use thecommand to confirm that the directory was created and you should see a screen similar to the following:Next open the makefile in your editor of choice, well use pico again. Change the makefile so it has the following text in it:Now run make using the following targetand get a directory listing of the Debug directory usingand you should have the following on your screen:Now well run the GNU debugger gdb with the newly compiled application with debugging information in it. Typeat the command prompt. You should see a screen similar to the following:At this point you are in the debugger and there are a number of command that can be used from here to help you figure out whats going on inside your program. Heres a basic list of commands youll get to know in the GNU debugger: Usage: help [COMMAND]List information about the COMMANDExample: help running or help breakpoints Usage: list [LINE or FUNCTION][,][LINE]...Lists the lines in a file, 10 lines at a timeExample: list 1,100 Usage: break [LINE or FUNCTION]Creates a breakpoint at a specified LINE or FUNCTION locationExample: break 100 Usage: run [ARGUMENTS] ...Runs the currently loaded program with the specified ARGUMENTS.Example: run -I hello world Usage: nextSteps through the next statement in the program.step  Usage: stepSteps through one instruction only. Usage: quitQuits the GNU debugger.A breakpoint tells the debugger to pause execution of a program until you tell it to continue. In order to step through a program (i.e. watch a program execute), a breakpoint should be set on the executable statement at which you want execution to pause. To set a breakpoint on a statement, use thecommand at the (gdb) prompt. You specify either a function name or the line number of the executable to break on if you know it.Determining where you want the breakpoint is a critical part of debugging. Put your breakpoint too soon in the execution of the program and you waste time stepping through code that doesnt need to be debugged. Put the breakpoint too late and you might just miss the bug altogether. In our sample program above we have two possible places in our code that could be causing the problem. Either the get_choice function isnt returning the proper value or the is_valid_choice function isnt correctly checking the value. Lets set a breakpoint to check the return value of the get_choice function. There are two possible places to check the value, one being inside the function itself or in the assignment statement in main. Well set our breakpoint in main so we can check the return value. First well use the list command to find the line we want in the executable. In our example main starts at line 26 and ends at line 39 so the commandwill show those lines in the debugger:: Your line numbers may vary depending on how you create the source file. Experiment.In our example the line to set the breakpoint on is line number 35. So type in the commandat the (gdb) prompt. You should see a screen similar to the following:Once a breakpoint is set, start the debugger by using thecommand. The program will begin to run but pause at the statement with the breakpoint prior to its execution. For our sample you should see something like the screen below:At this point you have a number of choices (detailed below)1) It is often helpful to know the value of a variable at a certain point in an executing program. The debugger allows you to look at the contents of variables as a program executes. Use thecommand to display the value of an expression or variable.2) If the current statement is a function call, Use thecommand to go into the function to watch it execute.3) Go to the next statement in the program by using thecommand.Lets use the print command to inspect the value of choice in our application. Notice the value for choice in the window below is the char 0 or NULL. Well be double-checking it in the next section once the get_choice function returns a value.Since were not interested in stepping into the get_choice function well use thecommand at the gdb prompt to execute the next statement in our programAs you may have notice output from our application appears in the gdb console window. You should get a prompt asking, type in aand hit [Enter]. Now lets use the print command again on choice. You should see a screen similar to the following:Notice the change from before, 48 and 0 instead of 0 and \0. The 48 is the ASCII value for the character 0, so the get_choice function is correctly returning a character value and choice is correctly storing that value. By stepping through the program weve discovered our bug isnt in the get_choice function. Since our next statement in the program is the other function we need to check, is_valid_choice, and we know that a valid character is stored in choice and the is_valid_choice function should just keep looping with no error message. Use the step command to execute the is_valid_choice function. Notice what happens to our console window.This isnt correct since we know that the character 0 was passed in the variable choice to the function is_valid_choice by the following statement in main: }while(!is_valid_choice( choice));. So the problem has to be in the way in which is_valid_choice is checking the value. So well use the step command to execute each statement in that function to find out where things are going wrong. But first you have to step past a couple of the statements to get to the is_valid_choice function again. Notice that the line number on the left hand side of the console window above is 34. That indicates the current statement. In our example its the cout statement that displays the Hello World  message. Type next to execute this statement. Type next to once again execute the get_choice function statement on line 35. In the console window type in 1 at the Do you want to continue prompt and then press [Enter] to continue the program. Now type step to debug the is_valid_choice function.Notice that the line number on the left side of the screen is at line 90 inside the is_valid_choice function and that the variable called val has the value passed in the actual parameter choice, ASCII 49 and 1, from main.Lets list the next 10 lines by typingat the (gdb) prompt. Notice that line number 93 is the case statement for 1. Our program should execute line 93 since val has a 1 in it. Type step twice more and notice that the line number jumps all the way to the first statement inside the default: section of the switch, line number 96. It should have hit the break statement in line 94 after seeingBut it didnt for some reason.There are two ways in which a debugger is most helpful: 1) to verify statements are executed as expected, and 2) to verify that variables have their expected values. Look at the case statement very carefully we seem to be comparing an integer 1 with the character 1, which is 49 in ASCII, so our program is functioning correctly but our logic test isnt right. Change the case statement in the is_valid_choice function to look for character data:After editing the code to correct the problem, save your changes, rebuild the program with the commandand then restart the debugger with. Type break 35 to add the breakpoint again for the get_choice statement, then type run to begin the debugging session like before. Type next and then type a 1 again when prompted and press [Enter] as you did before in the console window. Type next again and notice that this time through, the application jumps to the end of the program, line number 38, like it should.Typeat the (gdb) prompt to stop debugging the application.There is still one more logic problem in this program and you should use the same techniques to find it. (Hint: the program should continue printing Hello World and asking the user to continue if the user enters a 1 at the prompt.)Here's a strictly Standard C solution...A C++ with Streams solutionAnd finally a C++ with classes solutionmain.cppoApp.hoApp.cpp Aug 7 '08 # 1 Share this Article 2 Comments P: 1 asm0x217 Excellent! Love the multiple solution approach you took! Superb. Aug 30 '08 # 2 P: 1 WinGDB



"[...] As you are aware Visual Studio doesn’t run on Linux [...]"



but you can connect from Visual Studio to Linux host (for example through ssh) ;) so if you are interested in debugging Linux applications under Visual Studio then please visit our site:



Kind Regards,

WinGDB team Hello,"[...] As you are aware Visual Studio doesn’t run on Linux [...]"but you can connect from Visual Studio to Linux host (for example through ssh) ;) so if you are interested in debugging Linux applications under Visual Studio then please visit our site: http://www.wingdb.com :)Kind Regards,WinGDB team Jul 1 '09 # 3 Message Post your comment Join Now » Sign in to post your comment or Sign up for a free account. Similar topics Debugging memory leaks

debugging core dumps on other computer

Debugging core file?

debugging php mail

Debugging standard C library routines

Debugging a server-client app

Python Debugger / IDE ??

long post about PHPEclipse session debugging

Debugging C++ program in GDB on linux Browse more C / C++ Articles on Bytes Article Stats viewed: 19432

comments: 2

date written:Aug 7 '08 Follow this article