You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Use Ctrl-c/backtrace to interrupt/understand stuck program in gdb
commit 6001271c6ff93156816e6bc08a708b6bbcfa19a1
Author: Julie Zelenski <[email protected]>
Date: Wed Jan 30 11:31:18 2019 -0800
Use Ctrl-c/backtrace to interrupt/understand stuck program in gdb
Copy file name to clipboardexpand all lines: labs/lab3/README.md
+76-20
Original file line number
Diff line number
Diff line change
@@ -92,7 +92,7 @@ Start address 0x8000
92
92
Transfer rate: 3136 bits in <1 sec.
93
93
```
94
94
95
-
The commands below set a *breakpoint*at the start of `main`and then start executing the program:
95
+
Use the commands below to set a *breakpoint*on the `main`function and start executing the program:
96
96
97
97
```
98
98
(gdb) break main
@@ -131,7 +131,7 @@ you're in, while `step` executes the next line of code,
131
131
which may be in a different function.
132
132
133
133
Use `run` to restart the program
134
-
and then use `step`to when you hit the breakpoint.
134
+
and then use `step` you hit the breakpoint.
135
135
136
136
```
137
137
(gdb) run
@@ -147,14 +147,28 @@ diff (a=a@entry=33, b=b@entry=107) at simple.c:27
147
147
27 return abs(a - b);
148
148
```
149
149
150
-
You are now stopped at the first line of `diff`. If you `step` from here, you will enter in the call to the `abs` function.
150
+
The program is now stopped at the first line of `diff`. When you `step`, you enter the call to the `abs` function.
151
151
152
152
```
153
153
(gdb) step
154
154
abs (v=v@entry=-74) at simple.c:5
155
155
5 }
156
156
```
157
157
158
+
Use `continue` to resume executing the program from here. Wait a moment, and then type `Ctrl-c` to interrupt the running program and return control to gdb. Use the `backtrace` command to see where the program was executing when it was interrupted (ignore the warnings about frame issues):
159
+
160
+
```^C
161
+
Program received signal SIGINT, Interrupt.
162
+
0x0000800c in hang ()
163
+
(gdb) backtrace
164
+
Python Exception <type 'exceptions.ImportError'> No module named frames:
165
+
#0 0x0000800c in hang ()
166
+
#1 0x0000800c in _start ()
167
+
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
168
+
```
169
+
170
+
The above information tells you that the program is stopped in `hang` which is called from `_start`. Review the code in `start.s` and `cstart.c` to remind yourself of what happens in a C program before and after `main()`. If currently in `hang`, the program has finished and is in the final "holding pattern". This is the normal behavior for a C program that has successfully run to completion. Learn to recognize how this situation is presented in the debugger, you hope to be seeing a lot of successful program completion!
171
+
158
172
When debugging a function, a common workflow is to
159
173
160
174
1.`break` on the function.
@@ -461,14 +475,14 @@ at the baud rate of 115200.
461
475
The screen should be cleared and the cursor positioned
462
476
in the upper left hand corner.
463
477
Type in some characters. What happens?
464
-
What happens if you push return on your keyboard?
478
+
What happens if you type return on your keyboard?
465
479
466
-
To exit screen, type `Ctrl-A` followed by `k`.
480
+
To exit screen, type `Ctrl-a` followed by `k`.
467
481
You should see the following message.
468
482
469
483
Really kill this window? [y/n]
470
484
471
-
Typing `y`should return you to the shell.
485
+
Typing `y`returns to the shell.
472
486
473
487
[screen is terminating]
474
488
@@ -482,9 +496,9 @@ Send the program to the Pi with the command `rpi-install.py -s echo.bin`. (Invo
482
496
sending the program.) Any characters you now type should be echoed back to your
483
497
terminal.
484
498
485
-
Unplug the jumper from the RX pin on the USB-serial. What changes?
499
+
As you continue typing, have your partner gently unplug the jumper from the RX pin on your USB-serial and then re-connect it. What changes? Why does that happen?
486
500
487
-
Use `Ctrl-A``k` to exit `screen`.
501
+
Use `Ctrl-a``k` to exit `screen`.
488
502
489
503
#### 2c) UART test
490
504
@@ -516,7 +530,7 @@ in one go.
516
530
hello, laptop
517
531
hello, laptop
518
532
519
-
This will print forever until you reset the Pi. Use `Ctrl-A``k` to exit `screen`.
533
+
This will print forever until you reset the Pi. Use `Ctrl-a``k` to exit `screen`.
520
534
521
535
#### 2d) printf
522
536
@@ -526,7 +540,7 @@ directory.
526
540
This program repeatedly prints "hello, laptop" using `printf`.
527
541
In Assignment 3, you will implement your own version of `printf`.
528
542
529
-
Once you have a working `printf` (or the solution version we provide in `libpi.a`), you can use it to report your program state and super-charge your debugging. What a big improvement over trying to communicate everything via blinking LEDs!
543
+
Once you have a working `printf`, you can use it to report your program state and super-charge your debugging. What a big improvement over trying to communicate everything via blinking LEDs!
530
544
531
545
For example, you can call `printf("value: %d\n", 10);`
532
546
to print the number 10 or `printf("value: %c\n", 'a');`
@@ -585,17 +599,60 @@ of your program executing correctly.
585
599
#### 4a) Debug strlen
586
600
587
601
588
-
Now edit `strlen` to intentionally
589
-
plant a bug, such as changing it to return `i + 1` instead of `i`. This will cause the asserts in `test_strlen` to fail. Rebuild the program and run
590
-
under the debugger. The first thing to observe is that there is no flashing red light (remember the simulator is not talking to your Pi nor its peripherals). The program appears to be stuck. Use control-C to interrupt the program and return control to the debugger. Use `backtrace` to see where the program is stopped. What was the program doing before you stopped it? Learn from this information how to recognize a failed assert in the debugger.
602
+
Edit `strlen` to intentionally
603
+
plant a bug, such as changing it to return `i + 1` instead of `i`. This buggy program is expected to fail the tests in `test_strlen`. Use `make install` to build the program and run on the Pi. You should see the flashing red LED that indicates a failed assert.
591
604
592
-
Restore `strlen` to its correct implementation, rebuild and run under the debugger. All tests should pass. As expected, there is no green light from the simulator, and once again the program appears stuck. Use control-C and `backtrace`to see what's going on. Learn from this information how to recognize successful program completion in the debugger.
605
+
Let's learn how a failed assert is presented under the debugger. Get the buggy program under gdb and `run` it. First note that there is no flashing red light. The simulator is not talking to your Pi nor its peripherals. Your Pi doesn't even need to be connected!
593
606
594
-
Both `strlen` and `strcpy` have been shown to work correctly for valid calls. We are now going to do a little exploration into what happens
595
-
for calls that are not so kosher.
607
+
What do you see in gdb? Not much; the program appears to be stuck. Type `Ctrl-c` to interrupt the program and use `backtrace` to see where the program is stopped.
608
+
609
+
```^C
610
+
Program received signal SIGINT, Interrupt.
611
+
timer_get_ticks () at timer.c:10
612
+
10 timer.c: No such file or directory.
613
+
(gdb) backtrace
614
+
Python Exception <type 'exceptions.ImportError'> No module named frames:
615
+
#0 timer_get_ticks () at timer.c:10
616
+
#1 0x000084b0 in timer_delay_us (usecs=usecs@entry=200000) at timer.c:17
617
+
#2 0x000084f8 in timer_delay_ms (msecs=msecs@entry=200) at timer.c:22
618
+
#3 0x0000841c in pi_abort () at pi.c:40
619
+
#4 0x00008078 in test_strlen () at cstrings.c:28
620
+
#5 0x0000822c in main () at cstrings.c:78
621
+
```
622
+
623
+
A-ha! When an assert fails, it calls `pi_abort` to flash the red light. The above backtrace tells you that the program is waiting in the delay loop within `pi_abort`. Given the simulator does not emulate the timer or GPIO peripherals, `pi_abort` behaves as a no-action infinite loop. By looking further into the backtrace, we learn that the failed assertion occurred on line 28 of the `cstrings.c` file. Use `list` to see that code now:
This allows us to pinpoint exactly which assert failed (rather than have to comment-in-and-out tests one by one to find it). Hooray for gdb!
640
+
641
+
Restore `strlen` to its correct implementation, rebuild and run again under the debugger. All tests should pass. As expected, there is no green light from the simulator, but once again the program appears stuck. Type `Ctrl-c` to interrupt the program and use `backtrace` to see what's going on. What evidence confirms that the program successfully ran to completion?
642
+
643
+
{% include callout.html type="warning" %}
644
+
__Tip__: Any time your program is executing, typing `Ctrl-c` will interrupt the program and return control to the debugger. `backtrace` will show where the program was executing when it was interrupted.
645
+
646
+
Learn to recognize these two common situations:
647
+
+ a successful run to completion that is waiting in `hang`
648
+
+ a failed assert in `pi_abort` valiantly flashing a non-existent red LED
649
+
</div>
596
650
597
651
#### 4b) Debug bogus_strlen_calls
598
652
653
+
Both `strlen` and `strcpy` have been shown to work correctly for valid calls. We are now going to do a little exploration into what happens
654
+
for calls that are not so kosher.
655
+
599
656
Review the code in the aptly-named `bogus_strlen_calls` function.
600
657
Get together with your tablemates and look at the three "bogus" calls.
601
658
For each consider __why__ it is invalid: what is improper about the C-string that is being passed as the argument?
@@ -608,7 +665,7 @@ to a single character. Furthermore the address might not have a char pointee at
608
665
609
666
Uncomment the call to `stress_test_strlen` in `main()`. Rebuild the program and run it under gdb. Single step through the call to
610
667
`bogus_strlen_calls` and print the value returned from each of the
611
-
bad calls. Is the result what you anticipated? What have you learned about the
668
+
bad calls. Is the result what you anticipated? What did you learn from this about the
612
669
observed consequences of reading uninitialized or invalid memory?
613
670
614
671
#### 4c) Debug sketchy_strcpy_call
@@ -629,7 +686,7 @@ been destroyed here? At what point in the execution does the
629
686
overwritten data result in a bad consequence?
630
687
631
688
#### 4d) Differences under simulation
632
-
It is important to be aware of the possible discrepancies you may observe when comparing the behavior of a program running on the Pi versus running under the gdb simulator. Read the section titled [Differences due to simulation](/guides/gdb/#differences-due-to-simulation) in our gdb guide to be introduced to some issues you may run into.
689
+
It is important to be aware of the discrepancies you may observe when comparing the behavior of a program running on the Pi versus running under the gdb simulator. Read the section titled [Differences due to simulation](/guides/gdb/#differences-due-to-simulation) in our gdb guide to be introduced to some of the issues you may run into.
633
690
634
691
Change to the directory `lab3/code/simulator` directory and review the program in the `buggy.c` file Trace through the operation of the program. What do you predict will be printed as output?
635
692
@@ -639,8 +696,7 @@ Use `make install` to run the program on the Raspberry Pi. Does the output print
639
696
640
697
Now use gdb on the `buggy.elf` program. This directory has a `.gdbinit` configuration file that will automatically issue the `target` and `load` commands once gdb is started so you don't have to do so manually. Run the program under gdb. When running under the simulator, the program does have the same output that you observed when running on the Pi. Why is it different?
641
698
642
-
Use control-C to stop the program (remember that after main() finishes, our programs at `hang`). Without exiting gdb, use `run` to run the program for a second time. How does this output compare to the previous run? Run a few more times in gdb until you understand the pattern.
643
-
699
+
Type `Ctrl-c` to stop the program. Without exiting gdb, use `run` to run the program for a second time. How does this output compare to the previous run? Run a few more times in gdb until you understand the pattern. What have you learned about how the simulator handles the state of memory between runs? How does this compare to what happens to the state of memory when you reset the actual Pi and re-run the program?
0 commit comments