I'd like to see the data contained by boost::multi_index(version 1.67.0) using gdb.
First I tried https://github.com/ruediger/Boost-Pretty-Printer.
It seems that hashed indexes such as hashed_unique
are not supported.
I noticed that if the first index is a supported type such as sequenced
, Boost-Pretty-Printer works fine.
However, I cannot edit the code now. I need to debug a core file and a binary executable.
I tried to understand the internal structure of multi_index with hashed index.
I worte the following test code:
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/identity.hpp>
namespace mi = boost::multi_index;
struct t_hash{};
using elems = mi::multi_index_container<
int,
mi::indexed_by<
mi::hashed_unique<
mi::tag<t_hash>,
mi::identity<int>
>
>
>;
int main() {
elems es { 0x12, 0x34 };
return 0; // set break point here and (gdb) p es
}
https://wandbox.org/permlink/UtMfVRI4rT5AXUOZ
When I print es, (gdb) p es
I got the following output:
$1 = {
<boost::base_from_member<std::allocator<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<int, std::allocator<int> >, boost::multi_index::detail::hashed_unique_tag> >, 0>> = {
member = {
<__gnu_cxx::new_allocator<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<int, std::allocator<int> >, boost::multi_index::detail::hashed_unique_tag> >> = {<No data fields>}, <No data fields>}
},
<boost::multi_index::detail::header_holder<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<int, std::allocator<int> >, boost::multi_index::detail::hashed_unique_tag>*, boost::multi_index::multi_index_container<int, boost::multi_index::indexed_by<boost::multi_index::hashed_unique<boost::multi_index::tag<t_hash, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>, boost::multi_index::identity<int>, mpl_::na, mpl_::na>, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>, std::allocator<int> > >> = {
<boost::noncopyable_::noncopyable> = {<No data fields>},
members of boost::multi_index::detail::header_holder<boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<int, std::allocator<int> >, boost::multi_index::detail::hashed_unique_tag>*, boost::multi_index::multi_index_container<int, boost::multi_index::indexed_by<boost::multi_index::hashed_unique<boost::multi_index::tag<t_hash, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>, boost::multi_index::identity<int>, mpl_::na, mpl_::na>, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>, std::allocator<int> > >:
member = 0x55555576ee70
},
<boost::multi_index::detail::hashed_index<boost::multi_index::identity<int>, boost::hash<int>, std::equal_to<int>, boost::multi_index::detail::nth_layer<1, int, boost::multi_index::indexed_by<boost::multi_index::hashed_unique<boost::multi_index::tag<t_hash, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>, boost::multi_index::identity<int>, mpl_::na, mpl_::na>, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>, std::allocator<int> >, boost::mpl::v_item<t_hash, boost::mpl::vector0<mpl_::na>, 0>, boost::multi_index::detail::hashed_unique_tag>> = {
<boost::multi_index::detail::index_base<int, boost::multi_index::indexed_by<boost::multi_index::hashed_unique<boost::multi_index::tag<t_hash, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>, boost::multi_index::identity<int>, mpl_::na, mpl_::na>, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>, std::allocator<int> >> = {<No data fields>},
members of boost::multi_index::detail::hashed_index<boost::multi_index::identity<int>, boost::hash<int>, std::equal_to<int>, boost::multi_index::detail::nth_layer<1, int, boost::multi_index::indexed_by<boost::multi_index::hashed_unique<boost::multi_index::tag<t_hash, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>, boost::multi_index::identity<int>, mpl_::na, mpl_::na>, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>, std::allocator<int> >, boost::mpl::v_item<t_hash, boost::mpl::vector0<mpl_::na>, 0>, boost::multi_index::detail::hashed_unique_tag>:
key = {
<boost::multi_index::detail::non_const_identity_base<int>> = {<No data fields>}, <No data fields>},
hash_ = {
<boost::hash_detail::hash_base<int>> = {
<std::unary_function<int, unsigned long>> = {<No data fields>}, <No data fields>}, <No data fields>},
eq_ = {
<std::binary_function<int, int, bool>> = {<No data fields>}, <No data fields>},
buckets = {
<boost::multi_index::detail::bucket_array_base<true>> = {
<boost::noncopyable_::noncopyable> = {<No data fields>},
},
members of boost::multi_index::detail::bucket_array<std::allocator<int> >:
size_index_ = 0,
spc = {
<boost::noncopyable_::noncopyable> = {<No data fields>},
members of boost::multi_index::detail::auto_space<boost::multi_index::detail::hashed_index_base_node_impl<std::allocator<char> >, std::allocator<int> >:
al_ = {
<__gnu_cxx::new_allocator<boost::multi_index::detail::hashed_index_base_node_impl<std::allocator<char> > >> = {<No data fields>}, <No data fields>},
n_ = 54,
data_ = 0x55555576ee90
}
},
mlf = 1,
max_load = 53
},
members of boost::multi_index::multi_index_container<int, boost::multi_index::indexed_by<boost::multi_index::hashed_unique<boost::multi_index::tag<t_hash, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>, boost::multi_index::identity<int>, mpl_::na, mpl_::na>, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na, mpl_::na>, std::allocator<int> >:
node_count = 2
}
I found node_count = 2
. It seems that the number of elements. I tried digging the member variables. e.g.) member
, buckets
, and so on. But I cannot found the data 0x12
and 0x34
, so far.
How do I get them?
Thanks for the comments, I found the solution. I summarize two approaches based on the comments.
debug_print()
) as a shared library (dp.so
).gdb target_executable_file
set environment LD_PRELOAD ./dp.so
.r
call debug_print(data)
. data
is the target you want to see.This approach does't need to re-compile the target. However, when I load core file, debug_print()
is no longer on memory. So this approach doesn't work with core file.
I'm looking for forcibly load dp.so
after core-file loaded, but I couldn't find the way, so far.
This approach is work with core-file. This approach is based on @Joaquín M López Muñoz 's comment.
gdb target_executable_file core_file
.T
is multi_index's element type. data
is multi_index container variable. N
is number of indexes.1st data
p *(T*)((char*)(*data.member).prior_ - sizeof(T) - 0x10 * (N - 1))
2nd data
p *(T*)((char*)(*(*data.member).prior_).prior_ - sizeof(T) - 0x10 * (N - 1))
...follow the same pattern.
Thank you very much @sele and @Joaquín M López Muñoz !!
I implemented hashed indexes support for Boost-Pretty-Printer. It is based on the above approach.
I sent the pull request for that:
https://github.com/ruediger/Boost-Pretty-Printer/pull/36
I figured out what 0x10 mean. It is pointer size multiplies 2. So in 64bit environment, 64bit = 8byte, 8 * 2 = 16 = 0x10. In 32bit environment 32bit = 4byte, 4 * 2 = 8 = 0x08.
I also updated the pull request.
Finally, I sent two pull requests and both are merged. Now, we can simple use Boost-Pretty-Printer and print the multi_index container that has hashed_index as the first index.
https://github.com/ruediger/Boost-Pretty-Printer/pull/36
https://github.com/ruediger/Boost-Pretty-Printer/pull/37
Here is internal structure and iterating algorithm:
If you are using Boost 1.56.0 or later, you can print the container using Boost-Pretty-Printer.
The github site is https://github.com/ruediger/Boost-Pretty-Printer
Installation manual is https://github.com/ruediger/Boost-Pretty-Printer#installation
Then, you can get the result.
If you have already installed Boost-Pretty-Printer and couldn't getpretty print result, you need to update it.
hashed_index support is introduced since https://github.com/ruediger/Boost-Pretty-Printer/commit/d8557f664e0dd3d11bb0464d8f670e99946e88b9
If you are using Boost version less than 1.56.0, you have some choices.
Just update your boost library and re-compile your program.
Writing debug print function. Here is the code example:
dp.cpp
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/identity.hpp>
namespace mi = boost::multi_index;
struct t_hash{};
// define the same structure of the debug target
using elems = mi::multi_index_container<
int,
mi::indexed_by<
mi::hashed_unique<
mi::tag<t_hash>,
mi::identity<int>
>
>
>;
#include <iostream>
// debug print function
void dp(elems const& es) {
for (auto const& e : es) {
std::cout << e << std::endl;
}
}
Compile it using the same compiler option as the target. And add -fPIC
for shared library.
clang++ -g -c dp.cpp -fPIC
Then you get dp.o
Link it as a shared library
clang++ -shared -o dp.so dp.o
Then you get dp.so
Run gdb. gdb target_executable_file
Do set environment LD_PRELOAD ./dp.so
.
Set breakpoints.
Do r
When the breakpoint hits, do call dp(data)
. data is the target you want to see
Unfortunately, current Boost-Pretty-Print hashed_indexes supports only Boost 1.56.0 or later. But you can implement older support by yourself.
Here is the data structure description that is focused on iteration and iteration algorithm for >= 1.56 version. I think that it is a good hint to implement older version iteration algorithm.
And my pull requests (merged). https://github.com/ruediger/Boost-Pretty-Printer/pull/36
https://github.com/ruediger/Boost-Pretty-Printer/pull/37
For < 1.56 version, I wrote the program to check the internal structure.
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <string>
namespace mi = boost::multi_index;
struct t_hash{};
using elems = mi::multi_index_container<
int,
mi::indexed_by<
mi::hashed_non_unique<
mi::tag<t_hash>,
mi::identity<int>
>
>
>;
int main(int argc, char** argv) {
auto size = boost::lexical_cast<int>(argv[1]);
elems es;
for (int i = 0; i != size; ++i) {
es.insert(i);
}
return 0; // break here
}
And I got the following gdb output:
b 30
r 5
p es.member
0x555555770e70
p (*es.member).next_
0x555555771038
p (*(*es.member).next_).next_
0x555555770e78
p (*(*(*es.member).next_).next_).next_
0x555555771038
...
x /200xb 0x555555771030
0x555555771030: 0x30 0x10 0x77 0x55 0x55 0x55 0x00 0x00
0x555555771038: 0x78 0x0e 0x77 0x55 0x55 0x55 0x00 0x00
0x555555771040: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x555555771048: 0x21 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x555555771050: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0x555555771058: 0x90 0x0e 0x77 0x55 0x55 0x55 0x00 0x00
0x555555771060: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x555555771068: 0x21 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x555555771070: 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0x555555771078: 0x98 0x0e 0x77 0x55 0x55 0x55 0x00 0x00
0x555555771080: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x555555771088: 0x21 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x555555771090: 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x00
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0x555555771098: 0xa0 0x0e 0x77 0x55 0x55 0x55 0x00 0x00
0x5555557710a0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x5555557710a8: 0x21 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x5555557710b0: 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0x00
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0x5555557710b8: 0xa8 0x0e 0x77 0x55 0x55 0x55 0x00 0x00
0x5555557710c0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x5555557710c8: 0x21 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x5555557710d0: 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0x5555557710d8: 0xb0 0x0e 0x77 0x55 0x55 0x55 0x00 0x00
0x5555557710e0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x5555557710e8: 0x21 0xef 0x00 0x00 0x00 0x00 0x00 0x00
0x5555557710f0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
...
This information and @Joaquín M López Muñoz's comment also could be a good hint to implement the < 1.56 Boost-Pretty-Printer.