【问题标题】:How to see boost::multi_index hashed index's data using gdb如何使用 gdb 查看 boost::multi_index 散列索引的数据
【发布时间】:2018-07-27 02:16:13
【问题描述】:

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

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

我试图用散列索引了解multi_index的内部结构。

我写了以下测试代码:

#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。似乎元素的数量。我尝试挖掘成员变量。例如)memberbuckets 等。但是目前我找不到0x120x34的数据。

我如何获得它们?


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

感谢 cmets,我找到了解决方案。我根据 cmets 总结了两种方法。

基于@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 是您要查看的目标。

这种方法不需要重新编译目标。但是,当我加载核心文件时,debug_print() 不再在内存中。所以这种方法不适用于核心文件。 我正在寻找加载核心文件后强制加载dp.so,但到目前为止我找不到路。

使用 gdb 跟踪 multi_index 的内部结构

这种方法适用于核心文件。 这种方法基于@Joaquín M López Muñoz 的评论。

  1. 使用核心文件运行 gdb。 gdb target_executable_file core_file.
  2. 执行以下命令来访问数据。 T 是 multi_index 的元素类型。 data 是 multi_index 容器变量。 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 和@Joaquín M López Muñoz !!


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

我为 Boost-Pretty-Printer 实现了散列索引支持。它基于上述方法。

我为此发送了拉取请求:

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


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

我知道 0x10 是什么意思。它是指针大小乘以 2。所以在 64 位环境中,64 位 = 8 字节,8 * 2 = 16 = 0x10。 32bit环境下32bit = 4byte, 4 * 2 = 8 = 0x08。

我还更新了拉取请求。


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

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

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

【问题讨论】:

  • 也许您可以将您的更新推广为答案。我很乐意将我的赏金奖励给您为获得这些拉取请求所做的努力。当然,您可以保持接受的答案没有问题,希望额外的关注也能从中受益。
  • @sehe,感谢您的评论。我可以看到上面的消息This question has an open bounty worth +250 reputation from sehe ending in 4 days.。我已经阅读了赏金的帮助页面。但我不明白我能做什么。如何推广我的更新以回答?我需要自己发布新答案吗?或者有什么方法可以设置我的编辑回答?
  • 确实,我的意思是您可以根据您在问题中编辑的信息手动创建答案,抱歉我的措辞令人困惑。
  • 好的,我会尽快发布我的答案。

标签: c++ boost gdb multi-index


【解决方案1】:

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

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

然后您可以使用gdb call 命令来评估该函数,如下所示:

【讨论】:

  • @HenriMenke 我正在使用 i3wm(这是一个平铺 wm)。编辑器是vim,调试器集成是Pyclewn
  • @sehe,感谢您的评论。我无法编辑可执行文件的任何部分。因此,正如您所提到的,我认为制作包含调试打印功能的共享库并预加载它。我会尝试这种方法。
  • 我制作了包含调试打印功能的共享对象。然后在 gdb 上执行set environment LD_PRELOAD ./debug_print.so。然后设置断点并运行目标。最后,call debug_print(es) 在 gdb 上,得到了价值。非常感谢!
  • 加载核心文件不会创建进程。因此不涉及运行时链接器并且预加载不适用
  • 是的。到目前为止,我找不到将核心文件和共享库一起工作的方式。对了,github.com/ruediger/Boost-Pretty-Printer/pull/36刚刚被合并了。
【解决方案2】:

Boost.MultiIndex 的哈希表结构在this article 的第二个图上描述。看起来很复杂,事实证明您可以从虚拟头节点(用于指示容器结束)开始并遵循prior_ 指针,以相反的顺序遍历所有节点。此头节点由boost::multi_index::detail::header_holder&lt;...&gt; 中的member 指向。希望这会有所帮助。

【讨论】:

  • 感谢您的评论。我可以在我的示例中获得 0x12 和 0x34。我使用以下命令。 p/x *(int*)((char*)(*es.member).prior_ - 0x08) 然后我得到了$28 = 0x34。然后p/x *(int*)((char*)(*(*es.member).prior_).prior_ - 0x08) 得到$29 = 0x12。我只是想获取值,我不确定 -8 字节是否正确,但我会将相同的方式应用于我的目标可执行文件和核心文件。谢谢。
  • 当我将数据类型从 int 更改为其他类型(例如 std::string)时,这种方法不起作用。也许我需要以某种方式调整指针位置。
  • 你必须减去sizeof(value_type)加上填充。
  • 感谢您的评论。我写了wandbox.org/permlink/PuPiQDppwhPO3NvJ 并打印了预期的结果。见评论结尾。如果索引为 1,它会起作用。但是,如果我再添加一个索引,结果就会改变。 wandbox.org/permlink/FYld0vpaT1SGMaqQ 是吗。我想我需要更多的指针调整。
  • p/x *(elem*)((char*)(*es.member).prior_ - sizeof(elem) - 0x10) 返回 $4 = { x = 0x56, y = "DEF", z = 0x78p/x *(elem*)((char*)(*(*es.member).prior_).prior_ - sizeof(elem) - 0x10) 返回 $4 = { x = 0x12, y = "ABC", z = 0x34 。我还在分析。
【解决方案3】:

新 Boost 版本的解决方案

如果您使用的是 Boost 1.56.0 或更高版本,则可以使用 Boost-Pretty-Printer 打印容器。

安装 Boost-Pretty-Printer

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

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

在 gdb 上执行打印命令。

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

如果您已经安装了Boost-Pretty-Printer,但无法获得漂亮的打印结果,则需要更新它。

hashed_index 支持自引入以来 https://github.com/ruediger/Boost-Pretty-Printer/commit/d8557f664e0dd3d11bb0464d8f670e99946e88b9

旧 Boost 版本的解决方案

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

1。更新提升。

只需更新您的 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)。 data 是你想看到的目标

优点

  • 不需要重新编译目标。

缺点

  • 不适用于核心文件。

3。为旧版本开发 Boost-Pretty-Print 支持

不幸的是,当前的 Boost-Pretty-Print hashed_indexes 仅支持 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

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

此信息和@Joaquín M López Muñoz 的 comment 也可能是实施

优点

  • 不需要重新编译目标。
  • 与核心文件配合得很好。

缺点

  • 您需要实现 Boost-Pretty-Printer 支持。

【讨论】:

  • 关于 1.56 之前的散列索引实现的摘要中有一个错误。碰巧的是,您链接的文章中的图片 1 和 3 指的是从未正式发布的设计。在 Boost 1.56 之前,散列索引被实现为一个单链表,其中桶数组条目链接在元素之间——可以通过与桶的地址范围进行比较来判断特定节点是实际节点还是桶数组条目数组。
  • 感谢您指出我的错误。我稍后会更新我的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-01-23
  • 1970-01-01
  • 1970-01-01
  • 2016-02-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多