10

我最近一直在尝试在我的树莓派(模型 b)上使用 valgrind 调试分段错误,运行 Debian GNU/Linux7.0(wheezy)。每次我在已编译的 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.

4

4 回答 4

7

从您的代码(一个简单的 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 还是会时不时出现解码失败的情况。如果发生这种情况,请提交错误报告。

编辑2:

来自维基百科,Raspberry Pi CPU:

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

2.11。限制

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

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

于 2013-07-16T07:31:03.420 回答
5

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

  1. 光盘/等
  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”指令。

于 2017-02-06T18:32:03.613 回答
4

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


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

这不断出现,例如最近在错误 366464 中。也许我应该更多地解释为什么不支持它。这是因为我们没有可行的方法来做到这一点。Valgrind 的 JIT 在首次访问时检测代码块,并且当前块的字节序被“嵌入”到检测中。所以有两种选择:

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

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

(1) 为不使用 SETEND 的代码提供零性能开销,但对使用 SETEND 的代码造成巨大(完全不可行)的影响。

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

所以我觉得这两个都不可接受。而且我想不出任何其他方式来实现它。

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

我通过(暂时)raspi-copies-and-fills从我的 Raspbian 安装中删除它来解决它。

于 2016-09-25T15:37:28.403 回答
3

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

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

我建议使用其他工具来查找段错误。

于 2013-07-16T14:31:57.433 回答