Debugging Rust programs
Depending on your language background, the debugging situation in Rust may be very familiar and comfortable, or it might strike you as a touch bare bones. Rust relies on the commonly used debugging tools that other programming languages have to hand—gdb or lldb. Both will work, though historically, lldb has had some issues, and it's only since about mid-2016 that either tool has supported unmangled Rust. Let's try gdb on hello_world from the previous section:
hello_world > gdb target/x86_64-unknown-linux-gnu/debug/hello_world GNU gdb (Debian 7.12-6) 7.12.0.20161007-git Copyright (C) 2016 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from target/x86_64-unknown-linux-gnu/debug/hello_world...done. warning: Missing auto-load script at offset 0 in section .debug_gdb_scripts of file /home/blt/projects/hello_world/target/x86_64-unknown-linux-gnu/debug/hello_world. Use `info auto-load python-scripts [REGEXP]' to list them. (gdb) run Starting program: /home/blt/projects/hello_world/target/x86_64-unknown-linux-gnu/debug/hello_world [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Hello, world! [Inferior 1 (process 15973) exited normally]
Let's also try lldb:
hello_world > lldb --version lldb version 3.9.1 ( revision ) hello_world > lldb target/x86_64-unknown-linux-gnu/debug/hello_world (lldb) target create "target/x86_64-unknown-linux-gnu/debug/hello_world" Current executable set to 'target/x86_64-unknown-linux-gnu/debug/hello_world' (x86_64). (lldb) process launch Process 16000 launched: '/home/blt/projects/hello_world/target/x86_64-unknown-linux-gnu/debug/hello_world' (x86_64) Hello, world! Process 16000 exited with status = 0 (0x00000000)
Either debugger is viable, and you're warmly encouraged to choose the one that suits your debugging style. This book will lean toward the use of lldb because of vague authorial preference.
The other suite of tooling you'll commonly see in Rust development—and elsewhere in this book—is valgrind. Rust being memory safe, you might wonder when valgrind would find use. Well, whenever you use unsafe. The unsafe keyword in Rust is fairly uncommon in day-to-day code, but does appear when squeezing out extra percentage points from hot code paths now and again. Note that unsafe blocks will absolutely appear in this book. If we run valgrind on hello_world, we'll get no leaks, as expected:
hello_world > valgrind --tool=memcheck target/x86_64-unknown-linux-gnu/debug/hello_world ==16462== Memcheck, a memory error detector ==16462== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. ==16462== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info ==16462== Command: target/x86_64-unknown-linux-gnu/debug/hello_world ==16462== Hello, world! ==16462== ==16462== HEAP SUMMARY: ==16462== in use at exit: 0 bytes in 0 blocks ==16462== total heap usage: 7 allocs, 7 frees, 2,032 bytes allocated ==16462== ==16462== All heap blocks were freed -- no leaks are possible ==16462== ==16462== For counts of detected and suppressed errors, rerun with: -v ==16462== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Profiling memory use in Rust programs is an important day-to-day task when writing performance-critical projects. For this, we use Massif, the heap profiler:
hello_world > valgrind --tool=massif target/x86_64-unknown-linux-gnu/debug/hello_world ==16471== Massif, a heap profiler ==16471== Copyright (C) 2003-2015, and GNU GPL'd, by Nicholas Nethercote ==16471== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info ==16471== Command: target/x86_64-unknown-linux-gnu/debug/hello_world ==16471== Hello, world! ==16471==
Profiling the cache is also an important routine task. For this, we use cachegrind, the cache and branch-prediction profiler:
hello_world > valgrind --tool=cachegrind target/x86_64-unknown-linux-gnu/debug/hello_world ==16495== Cachegrind, a cache and branch-prediction profiler ==16495== Copyright (C) 2002-2015, and GNU GPL'd, by Nicholas Nethercote et al. ==16495== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info ==16495== Command: target/x86_64-unknown-linux-gnu/debug/hello_world ==16495== --16495-- warning: L3 cache found, using its data for the LL simulation. Hello, world! ==16495== ==16495== I refs: 533,954 ==16495== I1 misses: 2,064 ==16495== LLi misses: 1,907 ==16495== I1 miss rate: 0.39% ==16495== LLi miss rate: 0.36% ==16495== ==16495== D refs: 190,313 (131,906 rd + 58,407 wr) ==16495== D1 misses: 4,665 ( 3,209 rd + 1,456 wr) ==16495== LLd misses: 3,480 ( 2,104 rd + 1,376 wr) ==16495== D1 miss rate: 2.5% ( 2.4% + 2.5% ) ==16495== LLd miss rate: 1.8% ( 1.6% + 2.4% ) ==16495== ==16495== LL refs: 6,729 ( 5,273 rd + 1,456 wr) ==16495== LL misses: 5,387 ( 4,011 rd + 1,376 wr) ==16495== LL miss rate: 0.7% ( 0.6% + 2.4% )
Each of these will be used throughout the book and on much more interesting projects than hello_world. But hello_world is the first cross-compilation achieved in this text, and that's no small thing.