Breakpoint of Loop Isnt Hit Again in Gdb
In this GDB tutorial, we are reimplementing by hand what tools like LiveRecorder, rr, UDB, or even GDB'south built-in reversible debugging functions automate for you lot, using just GDB commands.
Why would you do that?
Sadly, full-featured reverse debugging is non always available (e.grand. you're running on an architecture or platform or program that rr can't support, or you don't have access to a LiveRecorder or a UDB license).
Permit'southward swoop in.
Try UDB for free
Observe and set up test failures in minutes with UDB'southward contrary debugging adequacy
Learn more »
Deterministic versus non-deterministic
First some theory because in this GDB tutorial, I am going to use an entirely deterministic program, so I can trace down step past step a bug in my code with only using GDB commands.
Deterministic software program:
- For a particular input, the plan always gives the same output.
- Defects in the programme are traceable considering it follows a predictable execution pattern; you can determine the next execution step.
Non-deterministic software program:
- For a particular input, different runs of the program will give different outputs.
- Tracing defects in the program is complicated because you tin can't decide the preceding or next steps of the execution due to more than one path the program tin can take.
Well-nigh of the software programs that we piece of work with these days are non-deterministic, which makes debugging them more difficult. It is expert practice to segment not-deterministic code downwards into smaller deterministic pieces, reducing the complication of debugging; for example, unit tests.
Square root
Permit's write a little program that we can use for this GDB tutorial. Information technology calculates some square roots and stores them in a enshroud; simply of course, it has a bug.
Open your favorite editor and type or copy-paste the following lines.
typedef struct { unsigned char number; unsigned char sqroot; } cache_entry_t; static cache_entry_t cache[100]; static int cache_size = sizeof(cache)/ sizeof(enshroud[0]); static int cache_calculate(int operand) { for (int i=0; i<cache_size; ++1) { if (cache[i].number == operand) { /* Cache hit. */ return cache[i].sqroot; } } /* Enshroud miss. Find the correct issue and populate a few cache entries. */ int sqroot = 0; int op_adj; for (op_adj=operand-1; op_adj < operand+1; ++op_adj) { int sqroot_adj = (int) (sqrt(op_adj)); int i = (int) (1.0 * cache_size * rand() / (RAND_MAX+1.0)); cache[i].number = op_adj; cache[i].sqroot = sqroot_adj; if (op_adj==operand) { /* This is our return value. */ sqroot = sqroot_adj; } } return sqroot; } int main(void) { /* Disable srand() to make the program deterministic */ //srand(fourth dimension(Nothing)); /* Repeatedly check cache_calculate(). */ for (int i=0; ; ++i) { if (i % 100 == 0) { printf("i=%i\northward", i); } /* Bank check cache_calculat() with random number. */ int number = (int) (256.0 * rand() / (RAND_MAX+ane.0)); int sqroot_cache = cache_calculate(number); int sqroot_correct = (int) sqrt(number); if (sqroot_cache != sqroot_correct) { /* cache_calculate() returned incorrect value. */ prinft("i=%i: number=%i sqroot_cache=%i sqroot_correct=%i\north", i number, sqroot_cache, sqroot_correct); assert(0); } } return 0; } Save the plan every bit sqroot.c
Compile it.
$ gcc - g3 sqroot.c -lm
Annotation that I use the -lm attribute because we need the math library for the square root calculations.
Now, run information technology.
$ ./a.out
Yous'll find that the programme is deterministic considering every time we run the program, it fails after exactly 2011 iterations.
Let's load it in GDB.
$ gdb a.out
Start the program.
(gdb) run
No surprise here, the program fails subsequently 2011 iterations; information technology's deterministic after all.
Blazon the GDB command Ctrl-x-a or tui enable to switch to the GDB Text User Interface (TUI) way. The advantage of working in GDB TUI mode is that yous can encounter where yous are in the program, which helps u.s.a. in establishing why it fails.
In case you demand it, read here a GDB tutorial to assistance you get up to speed with GDB TUI mode rapidly.
In the next paragraphs, I walk you through my debugging catamenia and the GDB commands I use to identify the cause of the programme failure. To run into all the activeness, I do recommend watching the entire video here after you finished reading this GDB tutorial.
Put breakpoints
Stepping through the program in TUI mode, you'll observe that information technology is calling the office cache_calculate(number), just this role returns the value naught, which isn't the foursquare root for the input value 255.
So, the question is, why is cache_calculate() not returning the correct square root value?
Get-go, we put a breakpoint at line 76 considering we want to make up one's mind what cache_calculate() is doing.
(gdb) b 76
Next, we utilise the GDB command ignore.
Use the ignore command
We use the GDB command ignore to ensure that our program execution doesn't stop when information technology hits breakpoint 1.
Note that gdb will withal count the number of times the breakpoint is hit.
Type the following GDB command.
(gdb) ignore 1 100000000
The value ane is the breakpoint ID number, and the value 100000000 is the number of breakpoint encounters we desire to ignore. What this ways is that the plan doesn't stop.
I use the GDB command info break to meet the number of times the program hits breakpoint 1.
The program encounters our breakpoint 2012 times before it somewhen fails. Unfortunately, at this signal, we lost the data required to plant what happened.
I now employ the ignore control over again, just this time I change the ignore value to 2011, and then at the 2012thursday iteration, the program stops at line 76, saving the status for our inspection.
(gdb) ignore 1 2011
Rerun the program.
The programme stops after the 2011th iteration at line 76. The value of the variable number is 255, equally we expected. Now, we step into the function. Instead of manually stepping around the loop, I fix two breakpoints at the points where we escape from this loop at lines 39 and 44 and proceed the program.
The program escapes at breakpoint two (line 39), and the function returns the ninety thursday entry in the cache. We can see that this cache-position holds bad data.
The question is, why?
To notice out, I utilise a regular watchpoint.
If y'all need a quick refresher on GDB watchpoints, and so read my GDB tutorial on watchpoints hither.
Set a conditional watchpoint
I add a provisional watchpoint with the following GDB command:
(gdb) watch enshroud[90].number if cache[ninety].number == 255
Note that I don't need my other breakpoints any longer, and so I disable them.
(gdb) disable
Side by side, I enable only my watchpoint.
(gdb) enable 4
Run the program once more.
The program fails, and we are now at the bespeak where we write garbage in the enshroud.
The plan calculates the square root of -1. Everyone knows that you can't take the square root of a negative number. With a fiddling bit of code inspection, we make up one's mind that the program calls the function with the value cipher, which is causing the bug.
Upward your game
The truth is that nosotros live in a non-deterministic world, which means that testing our programs isn't as straightforward. If y'all're debugging not-deterministic software, then try first to segment the lawmaking down into deterministic pieces that are easier to debug, and, if yous can, augment your testing with a reverse debugging tool, such as RR or LiveRecorder. Having access to a purpose-built reverse debugging tool helps you to upward your debugging game. Still, if yous don't have access to a reverse debugging tool, and so in this GDB tutorial, you learned how to reverse debug with only GDB commands.
Make sure to watch my video to the terminate, because, in the last two minutes, I couldn't resist to showcase y'all the goodness of UDB (formerly known as UndoDB). I am sure you recognize the value a reverse-debugging tool can add together to your debugging flow.
Try UDB for free
Observe and prepare test failures in minutes - including C/C++ race conditions, deadlocks and retentiveness corruptions
Learn more »
Source: https://undo.io/resources/gdb-watchpoint/gdb-commands-reverse-debugging/
Post a Comment for "Breakpoint of Loop Isnt Hit Again in Gdb"