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:
https://speakerdeck.com/redboltz/boost-multi-index-version-equals-1-dot-56-dot-0-internal-structure-and-iteration-algorithm-for-gdb-boost-prerry-printer
I've looked at the implementation of those Python pretty printers and I agree that it's not going to be easy.
Maybe you can define some debug-printing functions in another place, like another translation unit that you can modify, or even in another library that you then PRELOAD. If you do the latter, make absolutely sure you are using the same library/compiler versions and flags or you'll simply get undefined results. In both scenarios, ensure that the function isn't optimized out at link time.
You could then use the gdb
call
command to evaluate that function, like so:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With