13

I want to be able to get the address and print a single pair from an STL container using GDB.

E.g., given the following toy program:

#include <map>

int main() 
{
  std::map<int,int> amap;
  amap.insert(std::make_pair(1,2));

}

which I compile as:

g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp

Then, when I try to examine a single element of map, for example:

p amap.begin()

I get:

"Cannot evaluate function -- may be in-lined" 

Why is this happening and how do I work around it?

Tested in Ubuntu 20.04, GCC 9.3.0, 2.34.

user202729
  • 3,358
  • 3
  • 25
  • 36
SFD
  • 565
  • 7
  • 18
  • See also: [c++ - Possible to call inline functions in gdb and/or emit them using GCC? - Stack Overflow](https://stackoverflow.com/questions/22029834/possible-to-call-inline-functions-in-gdb-and-or-emit-them-using-gcc) – user202729 Dec 07 '21 at 05:54

2 Answers2

21

This is because amap.begin() does not exist in resulting binary. This is how C++ templates work: if you don't use or explicitly instantiate some template method it is not generated in resulting binary.

If you do want to call amap.begin() from gdb you have to instantiate it. One way to do it is to instantiate all methods of std::map:

#include <map>

template class std::map<int,int>;

int main()
{
  std::map<int,int> amap;
  amap.insert(std::make_pair(1,2));
}

gdb session:

(gdb) p amap.begin()
$1 = {first = 1, second = 2}
ks1322
  • 33,961
  • 14
  • 109
  • 164
  • This is great thanks! Could your provide more insight what happens when the compiler sees 'template class std::map' i.e what makes it instantiate all the members of the class? Furthermore, while this works if source is available, how do you handle cases where you have debuging symbols but not source? I.e what is the recommended why of inspecting and debugging stl containers in such cases? – SFD Nov 16 '16 at 15:02
  • `template class std::map` - this statement forces class template explicit instantiation, see http://en.cppreference.com/w/cpp/language/class_template. If you have no source you can use Python pretty printers (https://sourceware.org/gdb/wiki/STLSupport), they may be already installed on your distribution. – ks1322 Nov 16 '16 at 15:26
  • This method **can't** be used when one of the data types in the template is local. Instead, it's also possible to just call a function to make that particular function implicitly instantiated: [c++ - gdb stl functions still show as inlined after disabling optimizations - Stack Overflow](https://stackoverflow.com/questions/40173061/gdb-stl-functions-still-show-as-inlined-after-disabling-optimizations) – user202729 Dec 07 '21 at 05:51
6

@ks1322 has the correct answer. Here are some additional information that may be useful in the future.

Only the constructor, destructor and insert methods on std::map are in the debuginfo:

(gdb) info functions std::map
All functions matching regular expression "std::map":

File /usr/include/c++/6/bits/stl_map.h:
std::pair<std::_Rb_tree_iterator<std::pair<int const, int> >, bool> std::map<int, int, std::less<int>, std::allocator<std::pair<int const, int> > >::insert<std::pair<int, int>, void>(std::pair<int, int>&&);
void std::map<int, int, std::less<int>, std::allocator<std::pair<int const, int> > >::map();
void std::map<int, int, std::less<int>, std::allocator<std::pair<int const, int> > >::~map();

Still, we can call both the size and empty methods:

(gdb) p amap.size()
$1 = 1
(gdb) p amap.empty()
$2 = false

That's because gdb has something called xmethods, a python API for calling mockup functions meant to work identically to the functions that have not been instantiated. The libstdc++ xmethods can be found here. If we disable them, then the same error message appears:

(gdb) disable xmethod
(gdb) p amap.size()
Cannot evaluate function -- may be inlined
(gdb) p amap.empty()
Cannot evaluate function -- may be inlined
(gdb) 
Daniel Näslund
  • 2,300
  • 3
  • 22
  • 27
  • Depends what version of gdb since when i type enable xmethod, I still can't print the size. – Mark Mar 16 '20 at 23:03