Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to see boost::multi_index hashed index's data using gdb

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?


Edit: 2018/07/28 11:51 JST

Thanks for the comments, I found the solution. I summarize two approaches based on the comments.

Runtime shared library loading based on @sehe 's approach,

  1. Write a debug print function (debug_print()) as a shared library (dp.so).
  2. run gdb. gdb target_executable_file
  3. Do set environment LD_PRELOAD ./dp.so.
  4. Set breakpoints.
  5. Do r
  6. When the breakpoint hits, do 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.

Trace multi_index's internal structure using gdb

This approach is work with core-file. This approach is based on @Joaquín M López Muñoz 's comment.

  1. Run gdb with core file. gdb target_executable_file core_file.
  2. Do the following command to access the data. 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 !!


Edit: 2018/07/28 15:22 JST

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


Edit: 2018/07/28 15:42 JST

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.


Edit: 2018/08/02 09:30 JST

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

like image 845
Takatoshi Kondo Avatar asked Jul 27 '18 02:07

Takatoshi Kondo


Video Answer


1 Answers

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:

enter image description here

like image 160
sehe Avatar answered Oct 13 '22 20:10

sehe