Skip to content

Commit f522d0d

Browse files
zelenskiCS107E Bot
authored and
CS107E Bot
committed
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
1 parent 8321c38 commit f522d0d

File tree

1 file changed

+76
-20
lines changed

1 file changed

+76
-20
lines changed

labs/lab3/README.md

+76-20
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ Start address 0x8000
9292
Transfer rate: 3136 bits in <1 sec.
9393
```
9494

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:
9696

9797
```
9898
(gdb) break main
@@ -131,7 +131,7 @@ you're in, while `step` executes the next line of code,
131131
which may be in a different function.
132132

133133
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.
135135

136136
```
137137
(gdb) run
@@ -147,14 +147,28 @@ diff (a=a@entry=33, b=b@entry=107) at simple.c:27
147147
27 return abs(a - b);
148148
```
149149

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.
151151

152152
```
153153
(gdb) step
154154
abs (v=v@entry=-74) at simple.c:5
155155
5 }
156156
```
157157

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+
158172
When debugging a function, a common workflow is to
159173

160174
1. `break` on the function.
@@ -461,14 +475,14 @@ at the baud rate of 115200.
461475
The screen should be cleared and the cursor positioned
462476
in the upper left hand corner.
463477
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?
465479

466-
To exit screen, type `Ctrl-A` followed by `k`.
480+
To exit screen, type `Ctrl-a` followed by `k`.
467481
You should see the following message.
468482

469483
Really kill this window? [y/n]
470484

471-
Typing `y` should return you to the shell.
485+
Typing `y` returns to the shell.
472486

473487
[screen is terminating]
474488

@@ -482,9 +496,9 @@ Send the program to the Pi with the command `rpi-install.py -s echo.bin`. (Invo
482496
sending the program.) Any characters you now type should be echoed back to your
483497
terminal.
484498

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?
486500

487-
Use `Ctrl-A` `k` to exit `screen`.
501+
Use `Ctrl-a` `k` to exit `screen`.
488502

489503
#### 2c) UART test
490504

@@ -516,7 +530,7 @@ in one go.
516530
hello, laptop
517531
hello, laptop
518532

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`.
520534

521535
#### 2d) printf
522536

@@ -526,7 +540,7 @@ directory.
526540
This program repeatedly prints "hello, laptop" using `printf`.
527541
In Assignment 3, you will implement your own version of `printf`.
528542

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!
530544

531545
For example, you can call `printf("value: %d\n", 10);`
532546
to print the number 10 or `printf("value: %c\n", 'a');`
@@ -585,17 +599,60 @@ of your program executing correctly.
585599
#### 4a) Debug strlen
586600

587601

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.
591604

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!
593606

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:
624+
625+
```
626+
(gdb) list cstrings.c:28
627+
23
628+
24 void test_strlen(void)
629+
25 {
630+
26 char *fruit = "watermelon";
631+
27
632+
28 assert(strlen("green") == 5);
633+
29 assert(strlen("") == 0);
634+
30 assert(strlen(fruit) == 2 + strlen(fruit + 2));
635+
31 }
636+
32
637+
```
638+
639+
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>
596650

597651
#### 4b) Debug bogus_strlen_calls
598652

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+
599656
Review the code in the aptly-named `bogus_strlen_calls` function.
600657
Get together with your tablemates and look at the three "bogus" calls.
601658
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
608665

609666
Uncomment the call to `stress_test_strlen` in `main()`. Rebuild the program and run it under gdb. Single step through the call to
610667
`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
612669
observed consequences of reading uninitialized or invalid memory?
613670

614671
#### 4c) Debug sketchy_strcpy_call
@@ -629,7 +686,7 @@ been destroyed here? At what point in the execution does the
629686
overwritten data result in a bad consequence?
630687

631688
#### 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.
633690

634691
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?
635692

@@ -639,8 +696,7 @@ Use `make install` to run the program on the Raspberry Pi. Does the output print
639696

640697
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?
641698

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?
644700

645701
## Check in with TA
646702

0 commit comments

Comments
 (0)