$ c++ -g -c product.cpp
15 May 2024
A reminder and exploration of low-level software basics: building and debugging (in "easy mode", i.e., with debugging symbols).
1. Preparation
Complete the following steps before coming to the lab. For this week, you do not need to submit your pre-lab work, but you are very welcome to ask questions if anything doesn’t make sense to you.
-
[optional] Identify a lab partner[1].
-
Ensure that you are able to log into a LabNet Linux image.
-
Explore some of the available text editors on our LabNet machines. You’re probably quite used to a full-featured IDE such as Visual Studio Code, but it’s good to also be familiar with command-line tools that tend to be available in more restricted environments than their graphical counterparts.
- Vim / gVim
-
This is the classic modal editor that I use in class (actually, I use Neovim, a modern take on the classic… probably a good place to start if you’re new to the Vim ecosystem, either via the command line
nvim
or a GUI like Neovide).If you haven’t used Vim before, you might like to learn a bit about it by running
vimtutor
at the command line (a great place to start!), via the OpenVim interactive tutorial or perhaps by a less interactive tutorial.Vim is very configurable via commands and startup scripts. Once you get into it, you’ll be able to customize things very much to your liking. For example, here’s my Vim config: my .vimrc file for all Vim instances and my .gvimrc file for graphical instances)
- Emacs
-
This is another classic, popular editor among programmers. You can run
emacs
at the command line or use a graphical version. Options include: - Visual Studio Code
-
A cross-platform editor from Microsoft. It should be installed and ready for use with at least Python, as we use it in ENGI 1020. You may need to install additional extensions for C, LLDB, etc.
- gedit
-
This is a general-purpose text editor for open-source platforms. It’s included with the GNOME desktop environment (the default graphical environment for Ubuntu) and runs on FreeBSD, Linux and other Unix-like platforms.
- Others
-
There may be other editors installed on our LabNet image, too… perhaps Kate or Atom or others?
2. Procedure
Complete the following procedure, recording all commands that you execute and their outputs.
Save all output files for next week’s lab.
2.1. Compilation
-
Download product.cpp and compile it using the following command:
What file is generated?
-
Inspect this file by passing it to the
nm
program. Find the symbol for theproduct
function within thenm
output (hint: you may find thegrep
utility to be helpful… runman grep
for more information about this utility). What is this symbol called? -
Read the
DESCRIPTION
section of the manual page for thec++filt
program (runman c++filt
). Usec++filt
to demangle this C++ name into a function signature. What is this signature? -
What is the symbol name for the
main
function? Even within a C++ file,main
is named according to C symbol name rules. How does this differ from the C++ symbol for theproduct
function? -
Download Makefile to the same directory, ensuring that its name is
Makefile
after it is saved (notMakefile.txt
, just plainMakefile
). Runmake product
to build an executable binary calledproduct
from yourproduct.o
object file. What commands doesmake
execute for you? -
Use the command
objdump -S
to disassemble the object fileproduct.o
. Pipe the result throughc++filt
and save it to a fileproduct.o.dump
(hint: the>
character can be used to redirect output from a command into a file). Within this file, find the disassembly of theproduct
function. What is its numeric offset within the object file? What else do you observe about the function? -
Re-generate the dump file above, this time using the option
--disassemble=SYMBOL
, whereSYMBOL
is the C++-mangled symbol name for theproduct
function. How does this dump file differ from the previous dump file? -
Use
objdump
to disassemble theproduct
function within theproduct
binary and save the (C++-demangled) output to a fileproduct.dump
. What is different about the dumps of the object file and the full binary?Details
There are a few ways that you can compare these two dump files:
-
Visual inspection in side-by-side text editors (sounds like a lot of work!)
-
The
diff
command, i.e.,diff product.o.dump product.dump
. Personally I like to use the "unified diff" format (-u
option), but YMMV. -
Fancy word-granual coloured diffs at the command line:
$ wdiff -n product.o.dump product.dump | colordiff
-
A GUI tool like Meld (which is available in our LabNet Ubuntu image)
-
-
Run the
product
program with no command-line arguments. What do you observe?
2.2. Debugging with symbols
-
Use the
product
program to compute the product of the numbers 1, 2 and 3. What do you observe? -
Run
product
under the LLDB debugger by executinglldb ./product
, then executing therun
command within LLDB. What do you observe? Exit usingexit
. -
Run
product
under the debugger with command-line arguments:$ lldb -- ./product 1 2 3
What do you observe when you
run
the program? -
Run
help break set
to explore the syntax of setting a breakpoint. How can you set a breakpoint at the beginning of theproduct
function? -
Set a breakpoint at the beginning of the
product
function and re-run the program from the start (withrun
). Use thebt
command to get a backtrace of the current call stack. What is the next instruction to execute? Verify this using theregister read
command. -
Use the
frame variable
command to print all local variables. Where does thenumbers
pointer point to? -
Use the command
expr &numbers
to get the address of thenumbers
pointer (i.e., the address of the variable containing the pointer to the array). What is this address (of thenumbers
pointer)? -
Use the
memory read
command to output the pointer value held in thenumbers
variable, and then the contents of the array pointed at bynumbers
. For example, if you wanted to output 64 B of memory starting at address 0x00007ff7bfeff000, you would run:(lldb) mem read 0x00007ff7bfeff000 0x00007ff7bfeff000+64
-
Using these addresses and memory contents, draw a diagram showing how
numbers
points to location in memory, and how that memory contains the integer values derived from the program’s command line arguments. Include all relevant memory addresses in your diagram. -
Run the
continue
command three times to pause the program at the fourth invocation ofproduct
. What is the address of each instruction in the call stack? Find these instructions inproduct.dump
and include them in your report. -
What address does
numbers
point to now? What is the address of thenumbers
pointer? -
Use the
memory read
command to print the contents of 384 B (0x180 B) of stack memory, starting at the address ofnumbers
.-
What value is contained at the address of
numbers
? -
Identify all parameters and return address within the portion of stack memory that you printed.
-