Debugging an iterator/fold with rust-lldb

I want to view the accumulator of a fold operation as it iterates, but I'm a total n00b when it comes to lldb or gdb. For reference, I'm using rust-lldb. Here's an example program to illustrate my question:

fn main() {
    let nums = [0, 1, 2, 3, 4, 5];
    let sum = nums.iter()
        .fold(0, |acc, num| {
            acc + num
        });
    println!("{}", sum);
}

I'm able to set a breakpoint at the let sum = ... line, but I haven't figured out what combination of stepping into/over/out of/etc will let me look at the accumulator. Can someone offer me some guidance?

Alright, I found the solution in another thread: here. I'll describe the solution to my particular problem just in case someone else comes along in the future.

The OP in the thread I linked wanted to know how to debug a statement of the form

let foo = something().iter()
    .something_else()
    .another_thing()
    .method_that_takes_a_closure(|x| {
        x > 0 // want to debug this statement
    });

OP's issue was confusion over where to put the breakpoint, and which combination of step into and step over would let them debug that particular statement. The key is to put the breakpoint on the first line of the closure body.

I just needed to check the value of the fold accumulator on every iteration. That meant that I didn't need to see every step of the closure body. In other words, I didn't need to step into/over anything. What I do is set my breakpoint inside the closure body, then just continue and fr v every time I hit the breakpoint. Here's what that looks like:

First I reformat my example program so that the closure body is on its own line:

fn main() {
    let nums = [0, 1, 2, 3, 4, 5];
    let sum = nums.iter()
        .fold(0, |acc, num| {
            acc + num  // <- set the breakpoint here
        });
    println!("{}", sum);
}

Then I set the breakpoint:

(lldb) b 5
Breakpoint 1: where = debugme`debugme::main::_$u7b$$u7b$closure$u7d$$u7d$::h0b8b03109d968c3a + 19 at main.rs:5, address = 0x00000001000018f3

Run the program and let it hit the breakpoint:

(lldb) r
Process 3647 launched: 'path/to/program' (x86_64)
Process 3647 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x00000001000018f3 debugme`debugme::main::_$u7b$$u7b$closure$u7d$$u7d$::h0b8b03109d968c3a((null)=&0x7ffeefbff228, acc=0, num=&0x7ffeefbff2bc) at main.rs:5
   2   	    let nums = [0, 1, 2, 3, 4, 5];
   3   	    let sum = nums.iter()
   4   	        .fold(0, |acc, num| {
-> 5   	            acc + num
   6   	        });
   7   	    println!("{}", sum);
   8   	}
Target 0: (debugme) stopped.

Check the variables in the stack frame before the body is evaluated:

(lldb) fr v
(closure *)  = &0x7ffeefbff228
(int) acc = 0
(int *) num = &0x7ffeefbff2bc

Continue and let it run until it hits the breakpoint again:

(lldb) c
Process 3647 resuming
Process 3647 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x00000001000018f3 debugme`debugme::main::_$u7b$$u7b$closure$u7d$$u7d$::h0b8b03109d968c3a((null)=&0x7ffeefbff228, acc=0, num=&0x7ffeefbff2c0) at main.rs:5
   2   	    let nums = [0, 1, 2, 3, 4, 5];
   3   	    let sum = nums.iter()
   4   	        .fold(0, |acc, num| {
-> 5   	            acc + num
   6   	        });
   7   	    println!("{}", sum);
   8   	}
Target 0: (debugme) stopped.

Check the variables again. This won't be very interesting because the first number we added to the accumulator was 0.

(lldb) fr v
(closure *)  = &0x7ffeefbff228
(int) acc = 0
(int *) num = &0x7ffeefbff2c0

Now if we c and fr v again, we'll see that the accumulator has changed:

(lldb) c
Process 3647 resuming
Process 3647 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x00000001000018f3 debugme`debugme::main::_$u7b$$u7b$closure$u7d$$u7d$::h0b8b03109d968c3a((null)=&0x7ffeefbff228, acc=1, num=&0x7ffeefbff2c4) at main.rs:5
   2   	    let nums = [0, 1, 2, 3, 4, 5];
   3   	    let sum = nums.iter()
   4   	        .fold(0, |acc, num| {
-> 5   	            acc + num
   6   	        });
   7   	    println!("{}", sum);
   8   	}
Target 0: (debugme) stopped.
(lldb) fr v
(closure *)  = &0x7ffeefbff228
(int) acc = 1
(int *) num = &0x7ffeefbff2c4

Notice the (int) acc = 1 at the bottom there (that's the accumulator).

Hopefully someone else will find this helpful in the future and I didn't just type this out for nothing :slight_smile:

4 Likes