<<

Debugging Techniques

Mike Johanson (modified by Stef Nychka)

Department of Computing Science University of Alberta

CMPUT 201, Fall 2005

M. Johanson Techniques Introduction

Part I

Introduction

M. Johanson Debugging Techniques Introduction ; core dumped.

As you have probably found through your work on Assignment 1.. ...debugging programs can be frustrating. It is very easy to write outside of arrays bounds, use uninitialized values, use inappropriate data types, etc. gcc errors and warnings are not always helpful to beginners (or, sometimes, to experienced programmers!)

M. Johanson Debugging Techniques Introduction Segmentation fault; core dumped.

As you have probably found through your work on Assignment 1.. ...debugging C programs can be frustrating. It is very easy to write outside of arrays bounds, use uninitialized values, use inappropriate data types, etc. gcc errors and warnings are not always helpful to beginners (or, sometimes, to experienced programmers!)

M. Johanson Debugging Techniques Introduction Segmentation fault; core dumped.

As you have probably found through your work on Assignment 1.. ...debugging C programs can be frustrating. It is very easy to write outside of arrays bounds, use uninitialized values, use inappropriate data types, etc. gcc errors and warnings are not always helpful to beginners (or, sometimes, to experienced programmers!)

M. Johanson Debugging Techniques Introduction Segmentation fault; core dumped.

As you have probably found through your work on Assignment 1.. ...debugging C programs can be frustrating. It is very easy to write outside of arrays bounds, use uninitialized values, use inappropriate data types, etc. gcc errors and warnings are not always helpful to beginners (or, sometimes, to experienced programmers!)

M. Johanson Debugging Techniques Introduction

If your program has a runtime bug: If you are lucky, your program will crash and you will realize you have a problem If you are unlucky, it will run, and you may not realize for a long time that you have a problem - if at all

M. Johanson Debugging Techniques Introduction

If your program has a runtime bug: If you are lucky, your program will crash and you will realize you have a problem If you are unlucky, it will run, and you may not realize for a long time that you have a problem - if at all

M. Johanson Debugging Techniques Introduction

If your program has a runtime bug: If you are lucky, your program will crash and you will realize you have a problem If you are unlucky, it will run, and you may not realize for a long time that you have a problem - if at all

M. Johanson Debugging Techniques Introduction Motivations for this talk

In the first half of this talk, we will cover some simple tips: Macros to make your debugging printouts more useful #ifdef - to display debugging output only when you need it assert() - to find errors before they happen In the second half, we will explain how to use the gdb and ddd debugger programs

M. Johanson Debugging Techniques Introduction Motivations for this talk

In the first half of this talk, we will cover some simple tips: Macros to make your debugging printouts more useful #ifdef - to display debugging output only when you need it assert() - to find errors before they happen In the second half, we will explain how to use the gdb and ddd debugger programs

M. Johanson Debugging Techniques Introduction Motivations for this talk

In the first half of this talk, we will cover some simple tips: Macros to make your debugging printouts more useful #ifdef - to display debugging output only when you need it assert() - to find errors before they happen In the second half, we will explain how to use the gdb and ddd debugger programs

M. Johanson Debugging Techniques Introduction Motivations for this talk

In the first half of this talk, we will cover some simple tips: Macros to make your debugging printouts more useful #ifdef - to display debugging output only when you need it assert() - to find errors before they happen In the second half, we will explain how to use the gdb and ddd debugger programs

M. Johanson Debugging Techniques Introduction Motivations for this talk

In the first half of this talk, we will cover some simple tips: Macros to make your debugging printouts more useful #ifdef - to display debugging output only when you need it assert() - to find errors before they happen In the second half, we will explain how to use the gdb and ddd debugger programs

M. Johanson Debugging Techniques Simple debugging tips

Part II

Simple debugging tips

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly Using macros like LINE

If you do use printf() to debug, you can make your output more useful:

printf(‘‘Error on line %d in file %s\n’’, __LINE__, __FILE__);

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly LINE

printf(‘‘Error on line %d in file %s\n’’, __LINE__, __FILE__); printf(‘‘Program compiled at %s on %s\n’’, __TIME__, __DATE__);

During compilation, the replaces LINE and FILE with the line number and file name. This is called a macro (King, pg 287) Now, your printf() statement tells you where in the code it is By printing out the time and date that the program was compiled, you can be sure that you are working with the most recent copy of your program

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly LINE

printf(‘‘Error on line %d in file %s\n’’, __LINE__, __FILE__); printf(‘‘Program compiled at %s on %s\n’’, __TIME__, __DATE__);

During compilation, the compiler replaces LINE and FILE with the line number and file name. This is called a macro (King, pg 287) Now, your printf() statement tells you where in the code it is By printing out the time and date that the program was compiled, you can be sure that you are working with the most recent copy of your program

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly LINE

printf(‘‘Error on line %d in file %s\n’’, __LINE__, __FILE__); printf(‘‘Program compiled at %s on %s\n’’, __TIME__, __DATE__);

During compilation, the compiler replaces LINE and FILE with the line number and file name. This is called a macro (King, pg 287) Now, your printf() statement tells you where in the code it is By printing out the time and date that the program was compiled, you can be sure that you are working with the most recent copy of your program

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly LINE

printf(‘‘Error on line %d in file %s\n’’, __LINE__, __FILE__); printf(‘‘Program compiled at %s on %s\n’’, __TIME__, __DATE__);

During compilation, the compiler replaces LINE and FILE with the line number and file name. This is called a macro (King, pg 287) Now, your printf() statement tells you where in the code it is By printing out the time and date that the program was compiled, you can be sure that you are working with the most recent copy of your program

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly Using #ifdef

What if you have some useful debugging printf() statements, but you don’t want to add and remove them all the time?

int foo(int x, int y) { #ifdef DEBUG printf(‘‘x is %d, y is %d\n’’, x, y); #endif }

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly

int foo(int x, int y) { #ifdef DEBUG printf(‘‘x is \%d, y is \%d\n’’, x, y); #endif }

To include this code, compile your program with -DDEBUG (yes, two D’s) gcc -DDEBUG -o myprogram myprogram.c

To turn off the output (especially when handing in the assignment), stop compiling with -DDEBUG When the compiler reaches that line, it ignores everything between #ifdef and #endif

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly

int foo(int x, int y) { #ifdef DEBUG printf(‘‘x is \%d, y is \%d\n’’, x, y); #endif }

To include this code, compile your program with -DDEBUG (yes, two D’s) gcc -DDEBUG -o myprogram myprogram.c

To turn off the output (especially when handing in the assignment), stop compiling with -DDEBUG When the compiler reaches that line, it ignores everything between #ifdef and #endif

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly

int foo(int x, int y) { #ifdef DEBUG printf(‘‘x is \%d, y is \%d\n’’, x, y); #endif }

To include this code, compile your program with -DDEBUG (yes, two D’s) gcc -DDEBUG -o myprogram myprogram.c

To turn off the output (especially when handing in the assignment), stop compiling with -DDEBUG When the compiler reaches that line, it ignores everything between #ifdef and #endif

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly

int foo(int x, int y) { #ifdef DEBUG printf(‘‘x is \%d, y is \%d\n’’, x, y); #endif }

To include this code, compile your program with -DDEBUG (yes, two D’s) gcc -DDEBUG -o myprogram myprogram.c

To turn off the output (especially when handing in the assignment), stop compiling with -DDEBUG When the compiler reaches that line, it ignores everything between #ifdef and #endif

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly assert()

If your program has a bug, would you rather: Have it crash right away, so you can use a debugger Keep running until the bug causes a crash Keep running without crashing, and you may not notice ...probably the first one! There is a useful (but easy to abuse) function called assert() that can help you check for “this-should-never-happen” cases.

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly assert()

If your program has a bug, would you rather: Have it crash right away, so you can use a debugger Keep running until the bug causes a crash Keep running without crashing, and you may not notice ...probably the first one! There is a useful (but easy to abuse) function called assert() that can help you check for “this-should-never-happen” cases.

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly assert()

If your program has a bug, would you rather: Have it crash right away, so you can use a debugger Keep running until the bug causes a crash Keep running without crashing, and you may not notice ...probably the first one! There is a useful (but easy to abuse) function called assert() that can help you check for “this-should-never-happen” cases.

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly assert()

If your program has a bug, would you rather: Have it crash right away, so you can use a debugger Keep running until the bug causes a crash Keep running without crashing, and you may not notice ...probably the first one! There is a useful (but easy to abuse) function called assert() that can help you check for “this-should-never-happen” cases.

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly assert()

If your program has a bug, would you rather: Have it crash right away, so you can use a debugger Keep running until the bug causes a crash Keep running without crashing, and you may not notice ...probably the first one! There is a useful (but easy to abuse) function called assert() that can help you check for “this-should-never-happen” cases.

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly assert()

If your program has a bug, would you rather: Have it crash right away, so you can use a debugger Keep running until the bug causes a crash Keep running without crashing, and you may not notice ...probably the first one! There is a useful (but easy to abuse) function called assert() that can help you check for “this-should-never-happen” cases.

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly

// From assignment 1 char *getMatrixName(int matrixNumber) { return matrixArray[matrixNumber].name; }

Lets say some part of your program calls this function with a bad value of matrixNumber In the above code, what would happen if matrixNumber was... < 0? > 16? Where would the program crash? Probably somewhere unrelated to this function or to the function that called it!

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly

// From assignment 1 char *getMatrixName(int matrixNumber) { return matrixArray[matrixNumber].name; }

Lets say some part of your program calls this function with a bad value of matrixNumber In the above code, what would happen if matrixNumber was... < 0? > 16? Where would the program crash? Probably somewhere unrelated to this function or to the function that called it!

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly

// From assignment 1 char *getMatrixName(int matrixNumber) { return matrixArray[matrixNumber].name; }

Lets say some part of your program calls this function with a bad value of matrixNumber In the above code, what would happen if matrixNumber was... < 0? > 16? Where would the program crash? Probably somewhere unrelated to this function or to the function that called it!

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly

// From assignment 1 char *getMatrixName(int matrixNumber) { return matrixArray[matrixNumber].name; }

Lets say some part of your program calls this function with a bad value of matrixNumber In the above code, what would happen if matrixNumber was... < 0? > 16? Where would the program crash? Probably somewhere unrelated to this function or to the function that called it!

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly

// From assignment 1 char *getMatrixName(int matrixNumber) { return matrixArray[matrixNumber].name; }

Lets say some part of your program calls this function with a bad value of matrixNumber In the above code, what would happen if matrixNumber was... < 0? > 16? Where would the program crash? Probably somewhere unrelated to this function or to the function that called it!

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly

// From assignment 1 char *getMatrixName(int matrixNumber) { return matrixArray[matrixNumber].name; }

Lets say some part of your program calls this function with a bad value of matrixNumber In the above code, what would happen if matrixNumber was... < 0? > 16? Where would the program crash? Probably somewhere unrelated to this function or to the function that called it!

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly

// From assignment 1 char *getMatrixName(int matrixNumber) { assert((matrixNumber >= 0) && (matrixNumber < MAX_NUM_MATRICES)); return matrixArray[matrixNumber].name; }

assert() takes one parameter - an integer This is usually done by writing a true/false expression as the parameter If this is 0 (false), the program exits immediately Otherwise, nothing happens. In this example, if the function is called with an illegal matrix number, assert() causes the program to exit. This is a lot better than trying to read from matrixArray[-1] or matrixArray[42] or something else outside of the array!

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly

// From assignment 1 char *getMatrixName(int matrixNumber) { assert((matrixNumber >= 0) && (matrixNumber < MAX_NUM_MATRICES)); return matrixArray[matrixNumber].name; }

assert() takes one parameter - an integer This is usually done by writing a true/false expression as the parameter If this is 0 (false), the program exits immediately Otherwise, nothing happens. In this example, if the function is called with an illegal matrix number, assert() causes the program to exit. This is a lot better than trying to read from matrixArray[-1] or matrixArray[42] or something else outside of the array!

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly

// From assignment 1 char *getMatrixName(int matrixNumber) { assert((matrixNumber >= 0) && (matrixNumber < MAX_NUM_MATRICES)); return matrixArray[matrixNumber].name; }

assert() takes one parameter - an integer This is usually done by writing a true/false expression as the parameter If this is 0 (false), the program exits immediately Otherwise, nothing happens. In this example, if the function is called with an illegal matrix number, assert() causes the program to exit. This is a lot better than trying to read from matrixArray[-1] or matrixArray[42] or something else outside of the array!

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly

// From assignment 1 char *getMatrixName(int matrixNumber) { assert((matrixNumber >= 0) && (matrixNumber < MAX_NUM_MATRICES)); return matrixArray[matrixNumber].name; }

assert() takes one parameter - an integer This is usually done by writing a true/false expression as the parameter If this is 0 (false), the program exits immediately Otherwise, nothing happens. In this example, if the function is called with an illegal matrix number, assert() causes the program to exit. This is a lot better than trying to read from matrixArray[-1] or matrixArray[42] or something else outside of the array!

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly

// From assignment 1 char *getMatrixName(int matrixNumber) { assert((matrixNumber >= 0) && (matrixNumber < MAX_NUM_MATRICES)); return matrixArray[matrixNumber].name; }

assert() takes one parameter - an integer This is usually done by writing a true/false expression as the parameter If this is 0 (false), the program exits immediately Otherwise, nothing happens. In this example, if the function is called with an illegal matrix number, assert() causes the program to exit. This is a lot better than trying to read from matrixArray[-1] or matrixArray[42] or something else outside of the array!

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly

// From assignment 1 char *getMatrixName(int matrixNumber) { assert((matrixNumber >= 0) && (matrixNumber < MAX_NUM_MATRICES)); return matrixArray[matrixNumber].name; }

assert() takes one parameter - an integer This is usually done by writing a true/false expression as the parameter If this is 0 (false), the program exits immediately Otherwise, nothing happens. In this example, if the function is called with an illegal matrix number, assert() causes the program to exit. This is a lot better than trying to read from matrixArray[-1] or matrixArray[42] or something else outside of the array!

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly

// From assignment 1 char *getMatrixName(int matrixNumber) { assert((matrixNumber >= 0) && (matrixNumber < MAX_NUM_MATRICES)); return matrixArray[matrixNumber].name; }

assert() is useful for making sure that your parameters are within a certain range. Here, the program would crash immediately and we have a better idea of where the problem is However: assert() is NOT useful for checking the user’s input If the user makes a mistake, the program should tell them why their input was bad - it should not crash without explanation. If a situation is ’possible’, assert() shouldn’t be used. Use assert() for cases that should never happen if the program was working properly.

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly

// From assignment 1 char *getMatrixName(int matrixNumber) { assert((matrixNumber >= 0) && (matrixNumber < MAX_NUM_MATRICES)); return matrixArray[matrixNumber].name; }

assert() is useful for making sure that your parameters are within a certain range. Here, the program would crash immediately and we have a better idea of where the problem is However: assert() is NOT useful for checking the user’s input If the user makes a mistake, the program should tell them why their input was bad - it should not crash without explanation. If a situation is ’possible’, assert() shouldn’t be used. Use assert() for cases that should never happen if the program was working properly.

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly

// From assignment 1 char *getMatrixName(int matrixNumber) { assert((matrixNumber >= 0) && (matrixNumber < MAX_NUM_MATRICES)); return matrixArray[matrixNumber].name; }

assert() is useful for making sure that your parameters are within a certain range. Here, the program would crash immediately and we have a better idea of where the problem is However: assert() is NOT useful for checking the user’s input If the user makes a mistake, the program should tell them why their input was bad - it should not crash without explanation. If a situation is ’possible’, assert() shouldn’t be used. Use assert() for cases that should never happen if the program was working properly.

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly

// From assignment 1 char *getMatrixName(int matrixNumber) { assert((matrixNumber >= 0) && (matrixNumber < MAX_NUM_MATRICES)); return matrixArray[matrixNumber].name; }

assert() is useful for making sure that your parameters are within a certain range. Here, the program would crash immediately and we have a better idea of where the problem is However: assert() is NOT useful for checking the user’s input If the user makes a mistake, the program should tell them why their input was bad - it should not crash without explanation. If a situation is ’possible’, assert() shouldn’t be used. Use assert() for cases that should never happen if the program was working properly.

M. Johanson Debugging Techniques Using macros like LINE Simple debugging tips Using #ifdef Using assert() properly

// From assignment 1 char *getMatrixName(int matrixNumber) { assert((matrixNumber >= 0) && (matrixNumber < MAX_NUM_MATRICES)); return matrixArray[matrixNumber].name; }

assert() is useful for making sure that your parameters are within a certain range. Here, the program would crash immediately and we have a better idea of where the problem is However: assert() is NOT useful for checking the user’s input If the user makes a mistake, the program should tell them why their input was bad - it should not crash without explanation. If a situation is ’possible’, assert() shouldn’t be used. Use assert() for cases that should never happen if the program was working properly.

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables GDB and DDD Introduction

In Java, you used the Eclipse debugger Debugging in C, using gdb or ddd, is very similar. gdb is a text-based debugger ddd is a graphical front-end for gdb

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables GDB and DDD Introduction

In Java, you used the Eclipse debugger Debugging in C, using gdb or ddd, is very similar. gdb is a text-based debugger ddd is a graphical front-end for gdb

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables GDB and DDD Introduction

In Java, you used the Eclipse debugger Debugging in C, using gdb or ddd, is very similar. gdb is a text-based debugger ddd is a graphical front-end for gdb

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables GDB and DDD Introduction

In Java, you used the Eclipse debugger Debugging in C, using gdb or ddd, is very similar. gdb is a text-based debugger ddd is a graphical front-end for gdb

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables Ways to start the debugger

There are two ways you can start the debugger: Run your program within it, track its progress, and look into any crashes that happen Use a core file created by a previous crash If your program exits with a segmentation fault, you may notice a file called ’core’ in your working directory. This file contains the memory state of the program at the time of the crash. You can load it in the debugger to find out what went wrong. These files are safe to delete if you don’t use them; they can take up a lot of space.

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables Ways to start the debugger

There are two ways you can start the debugger: Run your program within it, track its progress, and look into any crashes that happen Use a core file created by a previous crash If your program exits with a segmentation fault, you may notice a file called ’core’ in your working directory. This file contains the memory state of the program at the time of the crash. You can load it in the debugger to find out what went wrong. These files are safe to delete if you don’t use them; they can take up a lot of space.

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables Ways to start the debugger

There are two ways you can start the debugger: Run your program within it, track its progress, and look into any crashes that happen Use a core file created by a previous crash If your program exits with a segmentation fault, you may notice a file called ’core’ in your working directory. This file contains the memory state of the program at the time of the crash. You can load it in the debugger to find out what went wrong. These files are safe to delete if you don’t use them; they can take up a lot of space.

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables Ways to start the debugger

There are two ways you can start the debugger: Run your program within it, track its progress, and look into any crashes that happen Use a core file created by a previous crash If your program exits with a segmentation fault, you may notice a file called ’core’ in your working directory. This file contains the memory state of the program at the time of the crash. You can load it in the debugger to find out what went wrong. These files are safe to delete if you don’t use them; they can take up a lot of space.

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables Ways to start the debugger

There are two ways you can start the debugger: Run your program within it, track its progress, and look into any crashes that happen Use a core file created by a previous crash If your program exits with a segmentation fault, you may notice a file called ’core’ in your working directory. This file contains the memory state of the program at the time of the crash. You can load it in the debugger to find out what went wrong. These files are safe to delete if you don’t use them; they can take up a lot of space.

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables Ways to start the debugger

There are two ways you can start the debugger: Run your program within it, track its progress, and look into any crashes that happen Use a core file created by a previous crash If your program exits with a segmentation fault, you may notice a file called ’core’ in your working directory. This file contains the memory state of the program at the time of the crash. You can load it in the debugger to find out what went wrong. These files are safe to delete if you don’t use them; they can take up a lot of space.

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables Ways to start the debugger

There are two ways you can start the debugger: Run your program within it, track its progress, and look into any crashes that happen Use a core file created by a previous crash If your program exits with a segmentation fault, you may notice a file called ’core’ in your working directory. This file contains the memory state of the program at the time of the crash. You can load it in the debugger to find out what went wrong. These files are safe to delete if you don’t use them; they can take up a lot of space.

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables Compiling to use gdb

To use the debugger, you need to compile your program with the ’-g’ flag This makes your program larger and slower (which is why it isn’t turned on by default)

$ gcc -g -o crash crash.c

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables Compiling to use gdb

To use the debugger, you need to compile your program with the ’-g’ flag This makes your program larger and slower (which is why it isn’t turned on by default)

$ gcc -g -o crash crash.c

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables Compiling to use gdb

To use the debugger, you need to compile your program with the ’-g’ flag This makes your program larger and slower (which is why it isn’t turned on by default)

$ gcc -g -o crash crash.c

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables Detecting the cause of segmentation faults using gdb

#include int main() { char *foo = NULL; strncpy(foo, "Copying to an illegal location " "causes a crash!\n", 100); return 0; }

When you run this program, it crashes with a segmentation fault. One technique would be to edit the code and add in printf() statements everywhere For a large program, this can take a long time, and then a long time to remove them ...and then a long time to add and remove them next time it crashes... Using gdb is much easier and faster, at least to get a general idea of what’s going wrong

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables Detecting the cause of segmentation faults using gdb

#include int main() { char *foo = NULL; strncpy(foo, "Copying to an illegal location " "causes a crash!\n", 100); return 0; }

When you run this program, it crashes with a segmentation fault. One technique would be to edit the code and add in printf() statements everywhere For a large program, this can take a long time, and then a long time to remove them ...and then a long time to add and remove them next time it crashes... Using gdb is much easier and faster, at least to get a general idea of what’s going wrong

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables Detecting the cause of segmentation faults using gdb

#include int main() { char *foo = NULL; strncpy(foo, "Copying to an illegal location " "causes a crash!\n", 100); return 0; }

When you run this program, it crashes with a segmentation fault. One technique would be to edit the code and add in printf() statements everywhere For a large program, this can take a long time, and then a long time to remove them ...and then a long time to add and remove them next time it crashes... Using gdb is much easier and faster, at least to get a general idea of what’s going wrong

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables Detecting the cause of segmentation faults using gdb

#include int main() { char *foo = NULL; strncpy(foo, "Copying to an illegal location " "causes a crash!\n", 100); return 0; }

When you run this program, it crashes with a segmentation fault. One technique would be to edit the code and add in printf() statements everywhere For a large program, this can take a long time, and then a long time to remove them ...and then a long time to add and remove them next time it crashes... Using gdb is much easier and faster, at least to get a general idea of what’s going wrong

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables Detecting the cause of segmentation faults using gdb

#include int main() { char *foo = NULL; strncpy(foo, "Copying to an illegal location " "causes a crash!\n", 100); return 0; }

When you run this program, it crashes with a segmentation fault. One technique would be to edit the code and add in printf() statements everywhere For a large program, this can take a long time, and then a long time to remove them ...and then a long time to add and remove them next time it crashes... Using gdb is much easier and faster, at least to get a general idea of what’s going wrong

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables Detecting the cause of segmentation faults using gdb

$ gdb crash ...some startup output from gdb gets displayed...

(gdb) run Starting program: /home/michael/labs/c201_fall2005/lab4/examples/crash Program received SIGSEGV, Segmentation fault. 0x40092d25 in strncpy () from /lib/libc.so.6

(gdb) where #0 0x40092d25 in strncpy () from /lib/libc.so.6 #1 0x080483ee in main () at crash.c:5

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables Detecting the cause of segmentation faults using gdb

$ gdb crash ...some startup output from gdb gets displayed...

(gdb) run Starting program: /home/michael/labs/c201_fall2005/lab4/examples/crash Program received signal SIGSEGV, Segmentation fault. 0x40092d25 in strncpy () from /lib/libc.so.6

(gdb) where #0 0x40092d25 in strncpy () from /lib/libc.so.6 #1 0x080483ee in main () at crash.c:5

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables Detecting the cause of segmentation faults using gdb

$ gdb crash ...some startup output from gdb gets displayed...

(gdb) run Starting program: /home/michael/labs/c201_fall2005/lab4/examples/crash Program received signal SIGSEGV, Segmentation fault. 0x40092d25 in strncpy () from /lib/libc.so.6

(gdb) where #0 0x40092d25 in strncpy () from /lib/libc.so.6 #1 0x080483ee in main () at crash.c:5

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables

The lines starting with #0, #1, show the stack of function calls made The crash actually happens in the function strncpy in /lib/libc.so.6, which was called by our code in crash.c at line 5 We start at the top of the stack (#0), where the crash happened. If we want to see what our variables were at the time of the crash, we need to move up in the stack. Use the ’up’ and ’down’ commands to move within the stack. Typing ’up’ gives us this information:

#1 0x080483b2 in main () at crash.c:5 5 strncpy(foo, "Copying to an illegal location "

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables

The lines starting with #0, #1, show the stack of function calls made The crash actually happens in the function strncpy in /lib/libc.so.6, which was called by our code in crash.c at line 5 We start at the top of the stack (#0), where the crash happened. If we want to see what our variables were at the time of the crash, we need to move up in the stack. Use the ’up’ and ’down’ commands to move within the stack. Typing ’up’ gives us this information:

#1 0x080483b2 in main () at crash.c:5 5 strncpy(foo, "Copying to an illegal location "

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables

The lines starting with #0, #1, show the stack of function calls made The crash actually happens in the function strncpy in /lib/libc.so.6, which was called by our code in crash.c at line 5 We start at the top of the stack (#0), where the crash happened. If we want to see what our variables were at the time of the crash, we need to move up in the stack. Use the ’up’ and ’down’ commands to move within the stack. Typing ’up’ gives us this information:

#1 0x080483b2 in main () at crash.c:5 5 strncpy(foo, "Copying to an illegal location "

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables

The lines starting with #0, #1, show the stack of function calls made The crash actually happens in the function strncpy in /lib/libc.so.6, which was called by our code in crash.c at line 5 We start at the top of the stack (#0), where the crash happened. If we want to see what our variables were at the time of the crash, we need to move up in the stack. Use the ’up’ and ’down’ commands to move within the stack. Typing ’up’ gives us this information:

#1 0x080483b2 in main () at crash.c:5 5 strncpy(foo, "Copying to an illegal location "

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables

#1 0x080483b2 in main () at crash.c:5 5 strncpy(foo, "Copying to an illegal location "

From this, we can see what context we are in - we are ’working in’ function main() in crash.c We can print the value of any of the variables in this context:

(gdb) print *foo Cannot access memory at address 0x0

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables

#1 0x080483b2 in main () at crash.c:5 5 strncpy(foo, "Copying to an illegal location "

From this, we can see what context we are in - we are ’working in’ function main() in crash.c We can print the value of any of the variables in this context:

(gdb) print *foo Cannot access memory at address 0x0

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables

#1 0x080483b2 in main () at crash.c:5 5 strncpy(foo, "Copying to an illegal location "

From this, we can see what context we are in - we are ’working in’ function main() in crash.c We can print the value of any of the variables in this context:

(gdb) print *foo Cannot access memory at address 0x0

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables

With just a few keystrokes (gdb crash, where) we were able to identify the line on which the crash happened It also lets us see the contents of memory while the program runs. This is exactly the information that printf() would have given us - only this is much faster. The debugger will also let us see what parts of the program are being executed, as we will see in the next example.

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables

With just a few keystrokes (gdb crash, where) we were able to identify the line on which the crash happened It also lets us see the contents of memory while the program runs. This is exactly the information that printf() would have given us - only this is much faster. The debugger will also let us see what parts of the program are being executed, as we will see in the next example.

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables

With just a few keystrokes (gdb crash, where) we were able to identify the line on which the crash happened It also lets us see the contents of memory while the program runs. This is exactly the information that printf() would have given us - only this is much faster. The debugger will also let us see what parts of the program are being executed, as we will see in the next example.

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables

With just a few keystrokes (gdb crash, where) we were able to identify the line on which the crash happened It also lets us see the contents of memory while the program runs. This is exactly the information that printf() would have given us - only this is much faster. The debugger will also let us see what parts of the program are being executed, as we will see in the next example.

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables Using DDD to track variables

ddd is a graphical front end for gdb that is more convenient for examining how a program runs and the contents of its memory:

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables A quick explanation of DDD’s interface

Your DDD window is divided into three sections The top section displays any variables that you want to track. You can see the value of these variables at any time. The middle section displays your code, the line being executed (green line), and any breakpoints you have chosen (red stop sign). If you mouseover a variable name, the current value is displayed at the bottom. The bottom section is a gdb interface, where you can manually enter gdb commands. The floating menu allows you to advance commands, move up and down in contexts, edit and recompile the code, and so on. Right-clicking on the code allows you to display variables and set breakpoints.

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables A quick explanation of DDD’s interface

Your DDD window is divided into three sections The top section displays any variables that you want to track. You can see the value of these variables at any time. The middle section displays your code, the line being executed (green line), and any breakpoints you have chosen (red stop sign). If you mouseover a variable name, the current value is displayed at the bottom. The bottom section is a gdb interface, where you can manually enter gdb commands. The floating menu allows you to advance commands, move up and down in contexts, edit and recompile the code, and so on. Right-clicking on the code allows you to display variables and set breakpoints.

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables A quick explanation of DDD’s interface

Your DDD window is divided into three sections The top section displays any variables that you want to track. You can see the value of these variables at any time. The middle section displays your code, the line being executed (green line), and any breakpoints you have chosen (red stop sign). If you mouseover a variable name, the current value is displayed at the bottom. The bottom section is a gdb interface, where you can manually enter gdb commands. The floating menu allows you to advance commands, move up and down in contexts, edit and recompile the code, and so on. Right-clicking on the code allows you to display variables and set breakpoints.

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables A quick explanation of DDD’s interface

Your DDD window is divided into three sections The top section displays any variables that you want to track. You can see the value of these variables at any time. The middle section displays your code, the line being executed (green line), and any breakpoints you have chosen (red stop sign). If you mouseover a variable name, the current value is displayed at the bottom. The bottom section is a gdb interface, where you can manually enter gdb commands. The floating menu allows you to advance commands, move up and down in contexts, edit and recompile the code, and so on. Right-clicking on the code allows you to display variables and set breakpoints.

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables A quick explanation of DDD’s interface

Your DDD window is divided into three sections The top section displays any variables that you want to track. You can see the value of these variables at any time. The middle section displays your code, the line being executed (green line), and any breakpoints you have chosen (red stop sign). If you mouseover a variable name, the current value is displayed at the bottom. The bottom section is a gdb interface, where you can manually enter gdb commands. The floating menu allows you to advance commands, move up and down in contexts, edit and recompile the code, and so on. Right-clicking on the code allows you to display variables and set breakpoints.

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables A quick explanation of DDD’s interface

Your DDD window is divided into three sections The top section displays any variables that you want to track. You can see the value of these variables at any time. The middle section displays your code, the line being executed (green line), and any breakpoints you have chosen (red stop sign). If you mouseover a variable name, the current value is displayed at the bottom. The bottom section is a gdb interface, where you can manually enter gdb commands. The floating menu allows you to advance commands, move up and down in contexts, edit and recompile the code, and so on. Right-clicking on the code allows you to display variables and set breakpoints.

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables Using DDD to track variables

You can use gdb or ddd to track the progress of your program It will show you what line your program is executing at any time Values of variables can be displayed graphically This does everything that you would do with printf() statements, only easier and faster.

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables Using DDD to track variables

You can use gdb or ddd to track the progress of your program It will show you what line your program is executing at any time Values of variables can be displayed graphically This does everything that you would do with printf() statements, only easier and faster.

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables Using DDD to track variables

You can use gdb or ddd to track the progress of your program It will show you what line your program is executing at any time Values of variables can be displayed graphically This does everything that you would do with printf() statements, only easier and faster.

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables Using DDD to track variables

You can use gdb or ddd to track the progress of your program It will show you what line your program is executing at any time Values of variables can be displayed graphically This does everything that you would do with printf() statements, only easier and faster.

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables A simple sample program

ddd can be a great tool for tracking down infinite loops.

#include int main() { int x; for (x=1; x++; x < 10) { printf("x"); } }

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables Tracking down an infinite loop

Start by loading the program in ddd

$ ddd loop

Click the ’run’ button on the floating menu. Since the program seems to be infinite-looping, hit the ’’ button Click ’next’ a few times and watch the green arrow move This shows which line of code is being executed

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables Tracking down an infinite loop

Start by loading the program in ddd

$ ddd loop

Click the ’run’ button on the floating menu. Since the program seems to be infinite-looping, hit the ’Interrupt’ button Click ’next’ a few times and watch the green arrow move This shows which line of code is being executed

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables Tracking down an infinite loop

Start by loading the program in ddd

$ ddd loop

Click the ’run’ button on the floating menu. Since the program seems to be infinite-looping, hit the ’Interrupt’ button Click ’next’ a few times and watch the green arrow move This shows which line of code is being executed

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables Tracking down an infinite loop

Start by loading the program in ddd

$ ddd loop

Click the ’run’ button on the floating menu. Since the program seems to be infinite-looping, hit the ’Interrupt’ button Click ’next’ a few times and watch the green arrow move This shows which line of code is being executed

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables Tracking down an infinite loop

By pressing ’next’, we can watch the arrow to figure out where our program is looping Right click on a variable in the code and choose ’Display’. At the top, a new box will appear showing the value of that variable as the program runs. This is the same kind of information you would get from using printf() statements - but without having to change your code or recompile.

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables Tracking down an infinite loop

By pressing ’next’, we can watch the arrow to figure out where our program is looping Right click on a variable in the code and choose ’Display’. At the top, a new box will appear showing the value of that variable as the program runs. This is the same kind of information you would get from using printf() statements - but without having to change your code or recompile.

M. Johanson Debugging Techniques Introduction Debuggers Using GDB to catch segmentation faults Using DDD to track variables Tracking down an infinite loop

By pressing ’next’, we can watch the arrow to figure out where our program is looping Right click on a variable in the code and choose ’Display’. At the top, a new box will appear showing the value of that variable as the program runs. This is the same kind of information you would get from using printf() statements - but without having to change your code or recompile.

M. Johanson Debugging Techniques Conclusion

In this lab, I’ve tried to give you a few tools for debugging your programs: DATE , LINE , etc to make debugging output more useful #ifdef, #endif to allow you to leave debugging output in your program assert() to let you catch bugs as soon as they happen, and not when they crash your program debuggers like gdb and ddd, to help you find bugs faster and diagnose problems Debuggers can do a lot more than what we’ve explained in this lab The best way to appreciate how much better the debugger is than printf() statements is to use it. Next time you get a segmentation fault or an odd bug, use the debugger first - you’ll be surprised how easy it is to find

M. Johanson Debugging Techniques Conclusion

In this lab, I’ve tried to give you a few tools for debugging your programs: DATE , LINE , etc to make debugging output more useful #ifdef, #endif to allow you to leave debugging output in your program assert() to let you catch bugs as soon as they happen, and not when they crash your program debuggers like gdb and ddd, to help you find bugs faster and diagnose problems Debuggers can do a lot more than what we’ve explained in this lab The best way to appreciate how much better the debugger is than printf() statements is to use it. Next time you get a segmentation fault or an odd bug, use the debugger first - you’ll be surprised how easy it is to find

M. Johanson Debugging Techniques Conclusion

In this lab, I’ve tried to give you a few tools for debugging your programs: DATE , LINE , etc to make debugging output more useful #ifdef, #endif to allow you to leave debugging output in your program assert() to let you catch bugs as soon as they happen, and not when they crash your program debuggers like gdb and ddd, to help you find bugs faster and diagnose problems Debuggers can do a lot more than what we’ve explained in this lab The best way to appreciate how much better the debugger is than printf() statements is to use it. Next time you get a segmentation fault or an odd bug, use the debugger first - you’ll be surprised how easy it is to find

M. Johanson Debugging Techniques Conclusion

In this lab, I’ve tried to give you a few tools for debugging your programs: DATE , LINE , etc to make debugging output more useful #ifdef, #endif to allow you to leave debugging output in your program assert() to let you catch bugs as soon as they happen, and not when they crash your program debuggers like gdb and ddd, to help you find bugs faster and diagnose problems Debuggers can do a lot more than what we’ve explained in this lab The best way to appreciate how much better the debugger is than printf() statements is to use it. Next time you get a segmentation fault or an odd bug, use the debugger first - you’ll be surprised how easy it is to find

M. Johanson Debugging Techniques Conclusion

In this lab, I’ve tried to give you a few tools for debugging your programs: DATE , LINE , etc to make debugging output more useful #ifdef, #endif to allow you to leave debugging output in your program assert() to let you catch bugs as soon as they happen, and not when they crash your program debuggers like gdb and ddd, to help you find bugs faster and diagnose problems Debuggers can do a lot more than what we’ve explained in this lab The best way to appreciate how much better the debugger is than printf() statements is to use it. Next time you get a segmentation fault or an odd bug, use the debugger first - you’ll be surprised how easy it is to find

M. Johanson Debugging Techniques Conclusion

In this lab, I’ve tried to give you a few tools for debugging your programs: DATE , LINE , etc to make debugging output more useful #ifdef, #endif to allow you to leave debugging output in your program assert() to let you catch bugs as soon as they happen, and not when they crash your program debuggers like gdb and ddd, to help you find bugs faster and diagnose problems Debuggers can do a lot more than what we’ve explained in this lab The best way to appreciate how much better the debugger is than printf() statements is to use it. Next time you get a segmentation fault or an odd bug, use the debugger first - you’ll be surprised how easy it is to find

M. Johanson Debugging Techniques Conclusion

In this lab, I’ve tried to give you a few tools for debugging your programs: DATE , LINE , etc to make debugging output more useful #ifdef, #endif to allow you to leave debugging output in your program assert() to let you catch bugs as soon as they happen, and not when they crash your program debuggers like gdb and ddd, to help you find bugs faster and diagnose problems Debuggers can do a lot more than what we’ve explained in this lab The best way to appreciate how much better the debugger is than printf() statements is to use it. Next time you get a segmentation fault or an odd bug, use the debugger first - you’ll be surprised how easy it is to find

M. Johanson Debugging Techniques Conclusion

In this lab, I’ve tried to give you a few tools for debugging your programs: DATE , LINE , etc to make debugging output more useful #ifdef, #endif to allow you to leave debugging output in your program assert() to let you catch bugs as soon as they happen, and not when they crash your program debuggers like gdb and ddd, to help you find bugs faster and diagnose problems Debuggers can do a lot more than what we’ve explained in this lab The best way to appreciate how much better the debugger is than printf() statements is to use it. Next time you get a segmentation fault or an odd bug, use the debugger first - you’ll be surprised how easy it is to find

M. Johanson Debugging Techniques