Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I debug a failing cargo test in GDB?

I have a failing Cargo test:

$ cargo test [snip]     Running target/gunzip-c62d8688496249d8  running 2 tests test test_extract_failure ... FAILED test test_extract_success ... ok  failures:  ---- test_extract_failure stdout ----         task 'test_extract_failure' panicked at 'assertion failed: result.is_err()', /home/dhardy/other/flate2-rs/tests/gunzip.rs:19    failures:     test_extract_failure  test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured  task '<main>' panicked at 'Some tests failed', /home/rustbuild/src/rust-buildbot/slave/nightly-linux/build/src/libtest/lib.rs:250 

How do I launch the failing test in a debugger like GDB?

This should be a general question, but for those wanting to retrace my steps, install a recent nightly Rust build and:

git clone https://github.com/dhardy/flate2-rs.git git checkout 24979640a880 cd flate2-rs cargo test 
like image 310
dhardy Avatar asked Dec 03 '14 10:12

dhardy


People also ask

How do I debug rust?

Use breakpoints in VSCode Add "Rust" or "rust-analyzer" extension in your VSCode. Add "CodeLLDB" extension in your VSCode. Click on the debug icon in your VSCode, then click on "add launch.

What does cargo test do?

Documentation tests It extracts code samples from documentation comments of the library target, and then executes them. Different from normal test targets, each code block compiles to a doctest executable on the fly with rustc . These executables run in parallel in separate processes.

What is rust GDB?

rust-gdb is a prebuilt binary that comes with the Rust installation (using Rustup, for example) and is installed automatically.

Does rust have a debugger?

With Rust, you can use print statements [ println() ], logging at the debug level, or the standard built-in dbg tool to exterminate bugs in your code.


1 Answers

You can get a test binary to filter the tests it runs by passing additional arguments to it; Cargo exposes this directly, too. Thus, cargo test test_extract_failure will just run that specific case. (This is convenient if you have other tests that panic and are expected to fail, so that they won’t call the rust_panic function I am about to mention, leaving only the offending call there.)

In order to use gdb, you’ll need to run the test binary directly (if you use Cargo it runs in a subprocess and thus gdb won’t catch panics inside it). Cargo helpfully tells you the file name, target/gunzip-c62d8688496249d8. You can run this directly with --test to make it a test run:

$ target/gunzip-c62d8688496249d8 --test test_extract_failure running 1 test test test_extract_failure ... FAILED  failures:  ---- test_extract_failure stdout ----         task 'test_extract_failure' panicked at 'assertion failed: result.is_err()', /home/dhardy/other/flate2-rs/tests/gunzip.rs:19    failures:     test_extract_failure  test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured  task '<main>' panicked at 'Some tests failed', /home/rustbuild/src/rust-buildbot/slave/nightly-linux/build/src/libtest/lib.rs:250 

Now to hook it up with gdb. There is a convenient function for which you can insert a breakpoint, rust_panic. Once in gdb, break rust_panic means it will pause whenever something triggers a panic, before actually doing the unwinding.

Here’s what a session might end up looking like:

$ gdb target/demo-92d91e26f6ebc557 … Reading symbols from target/demo-92d91e26f6ebc557...done. (gdb) break rust_panic Breakpoint 1 at 0xccb60 (gdb) run --test test_extract_failure Starting program: /tmp/demo/target/demo-92d91e26f6ebc557 --test test_extract_failure warning: Could not load shared library symbols for linux-vdso.so.1. Do you need "set solib-search-path" or "set sysroot"? [Thread debugging using libthread_db enabled] Using host libthread_db library "/usr/lib/libthread_db.so.1".  running 1 test [New Thread 0x7ffff6ef4700 (LWP 14254)] [New Thread 0x7ffff5fff700 (LWP 14255)] [Switching to Thread 0x7ffff5fff700 (LWP 14255)]  Breakpoint 1, 0x0000555555620b60 in rust_panic () (gdb) bt #0  0x0000555555620b60 in rust_panic () #1  0x0000555555621274 in unwind::begin_unwind_inner::hb821324209c8ed246Qc () #2  0x000055555556bb6d in unwind::begin_unwind::h7834652822578025936 () #3  0x000055555556b9fd in demo::do_something () at <std macros>:8 #4  0x000055555556b98e in demo::test_extract_failure () at src/lib.rs:3 #5  0x000055555559aa4b in task::TaskBuilder::try_future::closure.8077 () #6  0x000055555560fd03 in task::TaskBuilder::spawn_internal::closure.30919 () #7  0x000055555561f672 in task::Task::spawn::closure.5759 () #8  0x0000555555621cac in rust_try_inner () #9  0x0000555555621c96 in rust_try () #10 0x000055555561f713 in unwind::try::ha8078a6ae9b50ccepFc () #11 0x000055555561f51c in task::Task::run::hdb5fabf381084abafOb () #12 0x000055555561f168 in task::Task::spawn::closure.5735 () #13 0x0000555555620595 in thread::thread_start::h4d73784c295273b3i6b () #14 0x00007ffff79c2314 in start_thread () from /usr/lib/libpthread.so.0 #15 0x00007ffff72e25bd in clone () from /usr/lib/libc.so.6 (gdb)  

In that particular case, #0–#2 and #5–#15 are noise, #3 and #4 are the signal we want.

like image 145
Chris Morgan Avatar answered Oct 04 '22 06:10

Chris Morgan