Search code examples
iosobjective-clldb

Change value of const variables in LLDB


Const variables are good. However, sometimes I want to dynamically change their values when debugging to trace some specific behavior.

When I po flag = NO I receive this error:

error: <user expression 0>:1:34: cannot assign to variable 'flag' with const-qualified type 'const BOOL &' (aka 'const bool &')

Is there any workaround?


Solution

  • You can make the expression succeed by using const_cast, but it is likely to not do what you want. For instance:

    (lldb) run
    Process 32640 launched: '/tmp/foo' (x86_64)
    Process 32640 stopped
    * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
        frame #0: 0x0000000100003f66 foo`main at foo.c:7
       4    main()
       5    {
       6      const int foo = 10;
    -> 7      printf("%d\n", foo);
              ^
       8      return 0;
       9    }
    Target 0: (foo) stopped.
    (lldb) expr foo = 20
    error: <user expression 0>:1:5: cannot assign to variable 'foo' with const-qualified type 'const int &'
    foo = 20
    ~~~ ^
    note: variable 'foo' declared const here
    

    const_cast to the rescue:

    (lldb) expr *(const_cast<int*>(&foo)) = 20
    (int) $1 = 20
    

    We really did change the value in the foo slot, as you can see by:

    (lldb) expr foo
    (const int) $2 = 20
    

    and:

    (lldb) frame var foo
    (const int) foo = 20
    

    But the compiler is free to inline the value of const variables, which it does pretty freely even at -O0 (*). For instance, the call to printf compiled on x86_64 at -O0 to:

    ->  0x100003f66 <+22>: leaq   0x39(%rip), %rdi          ; "%d\n"
        0x100003f6d <+29>: movl   $0xa, %esi
        0x100003f72 <+34>: movb   $0x0, %al
        0x100003f74 <+36>: callq  0x100003f86               ; symbol stub for: printf
    

    Note that it doesn't reference any variables, it just puts 0xa into the second argument passing register directly. So unsurprisingly:

    (lldb) c
    Process 33433 resuming
    10
    

    (*) At higher optimization levels there probably wouldn't even be a variable allocated on the frame for const variables. The value would just get inserted immediately as above, and the debug information would also record it for the debugger's display, but there wouldn't be anything in memory to change from the old to the new value.