代码之家  ›  专栏  ›  技术社区  ›  Takatoshi Kondo

如何使用gdb查看boost::multi_index散列索引的数据

  •  7
  • Takatoshi Kondo  · 技术社区  · 7 年前

    我想看看使用gdb的boost::multi_index(版本1.67.0)所包含的数据。 首先我试过 https://github.com/ruediger/Boost-Pretty-Printer . 似乎哈希索引如 hashed_unique 不支持。

    我注意到如果第一个索引是支持的类型,比如 sequenced ,Boost Pretty Printer工作正常。 但是,我现在无法编辑代码。我需要调试一个核心文件和一个二进制可执行文件。

    我尝试用散列索引来理解多个索引的内部结构。

    我编写了以下测试代码:

    #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

    当我打印es时, (gdb) p es 我得到了以下输出:

    $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
    }
    

    我发现 node_count = 2 . 似乎元素的数量。我试着挖掘成员变量。例如) member , buckets 等等。但我找不到数据 0x12 0x34 ,到目前为止。

    我怎么才能拿到?


    编辑:2018/07/28 11:51 JST

    谢谢你的评论,我找到了解决办法。我根据评论总结了两种方法。

    基于@sehe方法的运行时共享库加载,

    1. 编写调试打印函数( debug_print() )作为共享库( dp.so ).
    2. 运行gdb。 gdb target_executable_file
    3. set environment LD_PRELOAD ./dp.so .
    4. 设置断点。
    5. r
    6. 当断点命中时,执行 call debug_print(data) . data 是你想看到的目标。

    这种方法不需要重新编译目标。但是,当我加载核心文件时, 调试打印() 已经不在记忆里了。所以这种方法不适用于核心文件。 我在找强制装载 副总裁 在核心文件加载后,但到目前为止我找不到路。

    用gdb跟踪多个索引的内部结构

    这种方法是使用核心文件的。 这种方法基于@joaqÃn M LÃ3 pez MuÃ?oz的评论。

    1. 用核心文件运行gdb。 gdb target_executable_file core_file .
    2. 执行以下命令访问数据。 T 是多个索引的元素类型。 数据 是多索引容器变量。 N 是索引数。

    第一个数据

    p *(T*)((char*)(*data.member).prior_ - sizeof(T) - 0x10 * (N - 1))

    第二数据

    p *(T*)((char*)(*(*data.member).prior_).prior_ - sizeof(T) - 0x10 * (N - 1))

    ……遵循同样的模式。

    非常感谢您@sele和@joaqÃn M LÃ3 pez MuÃ?oz!!


    编辑:2018/07/28 15:22 JST

    我实现了对Boost Pretty打印机的散列索引支持。它基于上述方法。

    我发送了请求:

    https://github.com/ruediger/Boost-Pretty-Printer/pull/36


    编辑:2018/07/28 15:42 JST

    我明白了0x10的意思。它是指针大小乘以2。所以在64位环境中,64位=8字节,8*2=16=0x10。 在32位环境中,32位=4字节,4*2=8=0x08。

    我还更新了拉取请求。


    编辑:2018/08/02 09:30 JST

    最后,我发送了两个请求,两个请求都被合并。现在,我们可以简单地使用Boost Pretty Printer,并打印将哈希索引作为第一个索引的多索引容器。

    https://github.com/ruediger/Boost-Pretty-Printer/pull/36

    https://github.com/ruediger/Boost-Pretty-Printer/pull/37

    下面是内部结构和迭代算法:

    https://speakerdeck.com/redboltz/boost-multi-index-version-equals-1-dot-56-dot-0-internal-structure-and-iteration-algorithm-for-gdb-boost-prerry-printer

    3 回复  |  直到 7 年前
        1
  •  3
  •   sehe    7 年前

    我已经看过那些Python漂亮打印机的实现,我同意这并不容易。

    也许您可以在另一个地方定义一些调试打印功能,比如 可以 修改,甚至在另一个库中进行预加载。如果您使用后者,请确保您使用的库/编译器版本和标志完全相同,否则您只会得到未定义的结果。在这两种情况下,请确保在链接时未对函数进行优化。

    你可以用 gdb call 用于计算该函数的命令,如下所示:

    enter image description here

        2
  •  2
  •   Joaquín M López Muñoz    7 年前

    Boost.MultiIndex的哈希表结构如 this article . 虽然看起来很复杂,但是您可以按照相反的顺序遍历所有节点,从虚拟头节点开始(用于表示容器的结束),然后按照 prior_ 指针。此头节点由指向 member 在里面 boost::multi_index::detail::header_holder<...> . 希望这有帮助。

        3
  •  1
  •   Takatoshi Kondo    7 年前

    新Boost版本的解决方案

    如果使用Boost 1.56.0或更高版本,可以使用Boost Pretty打印机打印容器。

    安装Boost漂亮打印机

    github站点是 https://github.com/ruediger/Boost-Pretty-Printer

    安装手册是 https://github.com/ruediger/Boost-Pretty-Printer#installation

    在gdb上执行打印命令。

    然后,你就可以得到结果了。

    如果您已经安装了Boost Pretty Printer,但无法获得Pretty print结果,则需要更新它。

    https://github.com/ruediger/Boost-Pretty-Printer/commit/d8557f664e0dd3d11bb0464d8f670e99946e88b9

    旧Boost版本的解决方案

    如果您使用的是低于1.56.0的Boost版本,那么您有一些选择。

    1。正在更新boost。

    只需更新boost库并重新编译程序。

    赞成的意见

    • 如果你能做到,这是最简单的方法。

    欺骗

    • 它需要重新编译目标。
    • 这可能会给您的应用程序带来舒适性问题。
    • 它不适用于现有的二进制可执行文件和核心文件。

    2。动态加载共享库

    正在写入调试打印功能。下面是代码示例:

    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;
        }
    }
    

    使用与目标相同的编译器选项编译它。加上 -fPIC 对于共享库。

    clang++ -g -c dp.cpp -fPIC

    然后你得到 dp.o

    将其链接为共享库

    clang++ -shared -o dp.so dp.o

    然后你得到 dp.so

    运行gdb。 gdb target_executable_file

    set environment LD_PRELOAD ./dp.so .

    设置断点。

    r

    当断点命中时,执行 call dp(data) . 数据是你想看到的目标

    赞成的意见

    • 不需要重新编译目标。

    欺骗

    • 无法处理核心文件。

    三。为旧版本开发Boost漂亮打印支持

    不幸的是,当前的Boost Pretty Print散列索引只支持Boost 1.56.0或更高版本。但是你可以自己实现旧的支持。

    以下是针对>=1.56版本的迭代和迭代算法的数据结构描述。我认为实现旧版本的迭代算法是一个很好的提示。

    https://speakerdeck.com/redboltz/boost-multi-index-version-equals-1-dot-56-dot-0-internal-structure-and-iteration-algorithm-for-gdb-boost-prerry-printer

    以及我的请求(合并)。 https://github.com/ruediger/Boost-Pretty-Printer/pull/36

    https://github.com/ruediger/Boost-Pretty-Printer/pull/37

    对于<1.56版本,我编写了程序来检查内部结构。

    #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
    }
    

    我得到了下面的gdb输出:

    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
    ...
    

    此信息和@joaqÃn M LÃ3 pez MuÃ?oz's comment 也可能是实现<1.56 Boost Pretty Printer的一个好提示。

    赞成的意见

    • 不需要重新编译目标。
    • 处理好核心文件。

    欺骗

    • 您需要实现Boost Pretty打印机支持。