19

I'm debugging a C++ program in Xcode 5 using lldb, and I would like to evaluate arbitrary expressions in the debugger, particularly those that use overloaded operators.

For example, I created a very simple Xcode 5 C++ project with the following main.cpp and all compiler/linker/etc options set to the default:

#include <iostream>
#include <vector>

int main(int argc, const char * argv[])
{
  std::vector<int> vec;
  vec.push_back(42);
  std::cout << "vec[0] = " << vec[0] << std::endl;
  return 0;
}

I set a breakpoint on the return 0; line and ran the program.

Then, at the lldb prompt, printing the vector as a whole works fine:

(lldb) expr vec
(std::__1::vector<int, std::__1::allocator<int> >) $0 = size=1 {
  [0] = 42
}

However, I can't access its members using the overloaded operator[]:

(lldb) expr vec[0]
error: call to a function 'std::__1::vector<int, std::__1::allocator<int> >::operator[](unsigned long)' ('_ZNSt3__16vectorIiNS_9allocatorIiEEEixEm') that is not present in the target
error: The expression could not be prepared to run in the target

Similarly, I can't get the iterator (though I have less experience here, so my syntax may be wrong):

(lldb) expr vector<int>::iterator it = vec.begin()
error: use of undeclared identifier 'vector'
error: expected '(' for function-style cast or type construction
error: expected '(' for function-style cast or type construction
error: 3 errors parsing expression

and

(lldb) expr (vector<int>::iterator) vec.begin()
error: use of undeclared identifier 'vector'
error: expected '(' for function-style cast or type construction
error: expected '(' for function-style cast or type construction
error: 3 errors parsing expression

Analogously, printing a simple string works fine:

(lldb) expr string("a")
(std::__1::string) $0 = "a"

However, a simple string concatenation fails:

(lldb) expr string("a") + string("b")
error: invalid operands to binary expression ('string' (aka 'std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >') and 'string')
error: 1 errors parsing expression

What am I doing wrong? Does lldb support evaluation with overloaded operators?

Thank you in advance!

Daniel Golden
  • 3,752
  • 2
  • 27
  • 32
  • frame variable vec[0] should work to print the element in the vector – Enrico Granata Dec 05 '13 at 20:58
  • Ah, that does work, thank you, @EnricoGranata. However, it doesn't work for getting the vector iterator or concatenating strings. So I'm 1/3 of the way there. – Daniel Golden Dec 05 '13 at 23:03
  • I am not sure why vec[0] does not work in an expression, but if you use vec.begin() in your source code, then you should be able to say expr vec.begin(); just try to call begin() in your main() – Enrico Granata Dec 06 '13 at 00:50

2 Answers2

26

I just ran into the same issue and apparently found a simple work-around. You can access i-th element of a vector vec like this:

(lldb) p vec.__begin_[i]
(int) $1 = 100
Dimaleks
  • 466
  • 4
  • 10
  • Thanks so much for this tip, it was helpful to me. If there are updates on ways to get lldb to evaluate C++ expressions and do things like execute vec.size(), I would like to know. Can gdb? – kdog May 18 '14 at 12:34
  • 2
    Note for readers: there is a SINGLE underscore after "begin"! Thanks, it works! – laszlo.endre Dec 18 '14 at 11:29
22

Note that the C++ standard libraries are set up so that they inline all the templated functions that they can sensibly inline, and no real function copies exist. So for instance, when you go to call std::vector<int>::begin(), there is no such function. All its uses have been inlined.

That is why you are getting errors about "call to function... not present in target." There may be inlined copies of the function, but none we can actually call. As an example, if I build a little C++ program that makes a std::vector, and pushes some elements onto it and then iterates over them, and then do:

    (lldb) image lookup -r -n begin
    2 matches found in /private/tmp/vector:
        Address: vector[0x0000000100000eaf] (vector.__TEXT.__text + 1071)
        Summary: vector`main + 1071 [inlined] std::__1::vector<int, std::__1::allocator<int> >::begin() at vector.cpp:12
                 vector`main + 1071 at vector.cpp:12        Address: vector[0x0000000100000eaf] (vector.__TEXT.__text + 1071)
        Summary: vector`main + 1071 [inlined] std::__1::vector<int, std::__1::allocator<int> >::begin() at vector.cpp:12
                 vector`main + 1071 at vector.cpp:12

So all the instances of the begin & end accessors for std::vector<int> are inlined. And further down in the part that comes from the std c library itself:

12 matches found in /usr/lib/libc++.1.dylib:
    Address: libc++.1.dylib[0x000000000003e4ec] (libc++.1.dylib.__TEXT.__text + 252188)
    Summary: libc++.1.dylib`std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::begin()        Address: libc++.1.dylib[0x000000000003e51c] (libc++.1.dylib.__TEXT.__text + 252236)
    Summary: libc++.1.dylib`std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::begin() const        Address: libc++.1.dylib[0x000000000003e574] (libc++.1.dylib.__TEXT.__text + 252324)

and a few more for basic_string, and that's all. So there aren't any real implementations that we can call. Then once we've only got a little bit of the real world of these std objects available to us, the world falls apart in other odd ways as you start to push on it.

lldb isn't currently smart enough to figure out how to reconstitute a templated function/method from the C++ standard library's header files. We don't have enough of the environment in which your code was originally compiled to do that task.

Note that this isn't really a problem with overloaded operators, it is more a problem with the way the std libraries are used by the compiler. Things should work better for your own classes, where at -O0 there isn't so much inlining.

Jim Ingham
  • 25,260
  • 2
  • 55
  • 63
  • Thanks, this is a great explanation of why I'm unable to call certain expressions through lldb. But if I **really want** to call those expressions, is the best workaround to write my own wrapper function that calls the inlined function, and then call that wrapper function from lldb? – Daniel Golden Dec 11 '13 at 15:56
  • 3
    Isn't the whole point of Apple managing their own compiler supposed to be that they can offer end-to-end integration like this? – Rag Feb 04 '14 at 23:46