【问题标题】:valgrind returning an unhandled instruction on Raspberry Pivalgrind 在 Raspberry Pi 上返回未处理的指令
【发布时间】:2013-06-30 02:58:56
【问题描述】:

我最近一直在尝试在运行 Debian GNU/Linux7.0 (wheezy) 的树莓派(模型 b)上使用 valgrind 来调试分段错误。每次我在已编译的 C++ 程序上运行 valgrind 时,都会得到如下信息:

disInstr(arm): unhandled instruction: 0xF1010200
    cond=15(0xF) 27:20=16(0x10) 4:4=0 3:0=0(0x0)
valgrind: Unrecognized instruction at address 0x4843638.
at 0x4843638: ??? (in /usr/lib/arm-linux-gnueabihf/libconfi_rpi.so)

然后是正常的 valgrind 东西,导致 SIGILL 并终止我的程序。起初我认为我的程序中存在一些内存泄漏,导致它执行一段非指令内存作为指令,但后来我运行了以下 hello world 代码,得到了相同的结果。

#include <iostream>
using namespace std;

int main() {
cout<<"Hello World"<<endl;

return 0;
}

其中不可能存在内存泄漏/段错误,那么为什么会给我这个错误? 我对 valgrind 很陌生,但我用最基本的 valgrind ./a.out 运行它。

【问题讨论】:

  • 试试这个:valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes ./a 并发布发生了什么。
  • 为什么不使用 gcc 调试器 gdb ?用它很容易知道段错误的原因!
  • @Phong:这不是段错误。 Valgrind 不确定如何处理指令。
  • @cornstalks:我知道问题出在 valgrind 上。但他说他首先尝试调试一个段错误。

标签: c++ valgrind raspberry-pi


【解决方案1】:

从您的代码(一个简单的 hello world)中,它抱怨 Unrecognized instruction at address 0x4843638。我的猜测是:

  • 由于valgrind需要拦截你的malloc系统调用函数(c标准库)。这允许 valgrind 检查您分配/释放了多少用于内存泄漏检测的资源(例如)。如果 valgrind 无法识别您的标准库环境(或处理器的指令语言),它可能不会像预期的那样运行,这将是您崩溃的原因。您应该检查 valgrind 版本并下载适合您平台的版本。

编辑:

http://valgrind.org/docs/manual/faq.html

3.3.我的程序死了,一路打印这样的消息:

vex x86->IR:未处理的指令字节:0x66 0xF 0x2E 0x5

一种可能是您的程序有错误并错误地跳转 到一个非代码地址,在这种情况下你会得到一个 SIGILL 信号。 Memcheck 可能会在这发生之前发出警告,但它可能 如果跳转恰好落在可寻址内存中,则不会。

另一种可能是 Valgrind 不处理指令。 如果您使用的是较旧的 Valgrind,则较新的版本可能会处理 指令。 然而,所有指令集都有一些晦涩难懂的,很少 使用说明。此外,在 amd64 上有几乎无限的数量 冗余指令前缀的组合,其中许多 未记录但被 CPU 接受。所以 Valgrind 仍然有 不时解码失败。如果发生这种情况,请提交一份 错误报告。

EDIT2:

来自维基百科,Raspberry Pi CPU:

  • 700 MHz ARM1176JZF-S 内核(ARM11 系列,ARMv6 指令集)[3]

2.11.限制

在 ARM 上,基本上支持整个 ARMv7-A 指令集, 在 ARM 和 Thumb 模式下。不支持 ThumbEE 和 Jazelle。 NEON、VFPv3 和 ARMv6 媒体支持相当完善

您的程序/库恰好有一些指令尚不支持。

【讨论】:

  • 实际上您要做的是检查最新版本。如果没有,那么这是一个 valgrind 错误。填写问题并希望尽快解决。 (Valgrind 项目很大,如果他们能复现,应该不会花很长时间)
  • “下载适合你平台的那个”:我用apt-get安装了我的,所以它特别适合Raspbian。我会尝试最新版本。
  • 我只是检查了 Raspberry(ARMv6) 和 valgrind 之间的指令集兼容性。从常见问题中可以看出,valgrind 并不完全支持 ARMv6。 (我根据它更新了答案)。很抱歉这么晚才注意到。我担心你不能在你的覆盆子上使用实际的 valgrind...
【解决方案2】:

在安装了 Raspian 的 NOOBS 的 Raspberry Pi 3 上,通过在终端窗口中执行以下操作来实现 ayke 的答案:

  1. cd /etc
  2. sudo nano ld.so.preload
  3. 删除包含“libarmmem.so”的行 (/usr/lib/arm-linux-gnueabihf/libarmmem.so)
  4. 保存并退出 ld.so.preload
  5. 运行 valgrind
  6. 在 valgrind 测试完成后将线路放回 ld.so.preload

预加载的“libarmmem.so”包含“memcmp”函数中的“setend”指令,导致未处理的指令错误。标准库(未加载预加载的“libarmmem.so”库时使用)在“memcmp”中不包含“setend”指令。

【讨论】:

  • 一种对我有用且更容易逆转的解决方案:“sudo mv /etc/ld.so.preload /etc/ld.so.preload.disabled”
【解决方案3】:

TL;DR:如果您使用的是 Raspbian,请删除包 raspi-copies-and-fills。它也可能适用于其他一些 Linux 变体,例如 NOOBS。


正如 Phong 已经指出的那样,Valgrind 不支持此指令。 有一个bug report 解释了这个问题:

这种情况不断出现,例如最近出现在错误 366464 中。 也许我应该更多地解释为什么不支持它。这是因为我们 没有可行的方法来做到这一点。 Valgrind 的 JIT 仪器代码 第一次访问的块,以及当前的字节序 块被“烘焙”到仪器中。所以有两个 选项:

(1) 执行 SETEND 指令时,丢弃所有 JITted 代码 Valgrind 创建的,并以新的字节顺序 JIT 新的代码块。

(2) 以与字节序无关的方式 JIT 代码块并进行运行时测试 对于每次内存访问,决定是调用大内存还是小内存
字节序检测辅助函数。

(1) 为不使用 SETEND 的代码提供零性能开销 但是对于这样做的代码来说是一个巨大的(完全不可行的)命中。

(2) 使字节序更改免费,但惩罚所有内存流量 不管是否实际使用了 SETEND。

所以我认为其中任何一个都不可接受。我想不出任何 其他实现方式。

换句话说,很难在 valgrind 中实现这条指令。 总结线程:该指令最常见的原因是Raspberry Pi附带的一些更快的内存管理功能(memcmp,memset等)。

我通过(暂时)从我的 Raspbian 安装中删除 raspi-copies-and-fills 解决了这个问题。

【讨论】:

    【解决方案4】:

    Valgrind 在 Raspberry Pi 上显然存在问题:

    https://web.archive.org/web/20131003042418/http://www.raspberrypisoft.com/tag/valgrind/

    我建议使用其他工具来查找 seg 故障。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-14
      相关资源
      最近更新 更多