GDB Basics
Now we’re going to use a sample program, map, for some GDB practice. The map program is designed to print out its own executing structure. Before you start, be sure to take a look at map.c
and recurse.c
which form the program. Once you feel familiar with the program, you can compile it by running make map
.
For all of the homework assignments and project the starter repositories have been configured such that you can directly use VSCode to run gdb interactively. For the assignments, this is done by providing a configuration file .vscode/launch.json
. For this assignment, this file looks like:
{
"version": "0.2.0",
"configurations": [
{
"name": "gdb debug executable",
"type": "cppdbg",
"request": "launch",
"program": "/pintos/src/map",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
]
}
For more information about this file format, please see the corresponding documentation.
This configuration file will show a command in the debug pane of VSCode named gdb debug executable
you can use to launch a debugging session. Please have a closer look at this file to see how this is set up so you can create similar configurations yourself in the future.
While you go through the command sequence outlined below, be sure to also record and submit your answers to the six questions in the file results/answers.md
. We highly recommend this site for an easy-to-read GDB refresher. Note, that from inside VSCode you have all of the supported GDB commands available to you by prefixing them with -exec
in the debugger command prompt at the very bottom of the ‘Debug Console’ window.
- Set a breakpoint at the beginning of the program’s execution (the
'{'
at the beginning ofmain
) by clicking on the left margin of that line. A red dot will appear to mark the break point you created. - Now run GDB on the
map
executable by running thegdb debug executable
task from the VSCode debug tab. - The program will run and stop at the breakpoint.
Q1: What memory address does
argv
store? You will see the values of all local variables shown in the ‘Variables’ pane on the left.Q2: Describe what’s located at that memory address. (What does
argv
point to?) This information can be discovered by clicking on the arrow next to theargv
variable.
- Step until you reach the first call to
recur
. Use the step-over function (the keyboard shortcut for this isF10
).
Q3: What is the memory address of the
recur
function (hover with your mouse over therecur
function name)?
- Step-into the first call to
recur
(the keyboard shortcut for this isF11
). - Step-over until you reach the if statement.
- Switch into assembly view (right click into the editor window, select ‘Open Disassembly View’).
- Step-over instructions until you reach the
call
instruction.
Q4: What values are in all the CPU registers? This information can be collected by opening the ‘Registers’ node in the ‘Variables’ pane on the left.
- Step-into the
call
instruction. - Switch back to C code mode (simply close the Disassembly window).
- Now print out the current call stack (type
-exec backtrace
in the debugger command prompt). Hint: what does the backtrace command do? - Now set a breakpoint on the first statement inside the
recur
function which is only triggered when the argument is0
. This can be done by first creating a breakpoint and then right clicking on it. Select ‘Edit Breakpoint’. Now you can enter a C-style expression referring to variables as needed. The breakpoint will be ‘hit’ only if the expression evaluates to true. - Continue until the breakpoint is hit (the keyboard shortcut for this is
F5
). - Print the call stack now.
Q5: Now go up the call stack until you reach main. What is the return address to the main function (
-exec up
will move the debugger’s view of the stack ‘up’ by one function invocation level; the debugger will print the address and the function name of the new level)?
The debugger command up
does not execute any code, i.e. the next instruction to be executed is still the one inside the call to recur(0)
. This command simply shifts the debugger’s ‘attention’ one stack level up.
- Go down the call stack back to where you started off from (the command is
-exec down 3
) - Now step out until you reach
main
(the keyboard shortcut for stepping out one level isShift+F11
). - Step-over until you reach the statement
return 0;
. Switch back into the assembly view.
Q6: Which assembly instructions correspond to the
return 0
in C?
- Now switch back to the source layout.
- Run the program to completion.
Next up: From Source Code to Executable.