c++ valgrind在Raspberry Pi上返回未处理的指令

mqxuamgl  于 2023-05-20  发布在  其他
关注(0)|答案(5)|浏览(210)

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

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

hec6srdp

hec6srdp1#

从你的代码(一个简单的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
一种可能性是您的程序有一个bug,并错误地跳转到一个非代码地址,在这种情况下,您将得到一个SIGILL信号。Memcheck可能会在发生这种情况之前发出警告,但如果跳转恰好落在可寻址内存中,则可能不会。

**另一种可能性是Valgrind不处理指令。如果您使用的是较旧的Valgrind,则较新的版本可能会处理该指令。**然而,所有指令集都有一些模糊的,很少使用的指令。此外,在amd 64上有几乎无限数量的冗余指令前缀组合,其中许多没有记录,但被CPU接受。所以Valgrind仍然会时不时地出现解码失败的情况。如果发生这种情况,请提交bug报告。
EDIT2:

Raspberry Pi CPU:

  • 700 MHz ARM 1176 JZF-S内核(ARM 11系列,ARMv 6指令集)[3]
  • 2.11.限制 *

在ARM上,基本上支持整个ARMv7-A指令集,包括ARM和Thumb模式。不支持ThumbEE和Jazelle。 neon 、VFPv 3和ARMv 6介质支持相当完整
您的程序/库只是碰巧有一些指令还不支持。

ykejflvf

ykejflvf2#

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

  1. cd /etc
  2. sudo nano ld.so.preload
    1.删除包含“www.example.com“的行libarmmem.so(/usr/lib/arm-linux-gnueabihf/libarmmem.so)
    1.保存并退出ld.so.preload
    1.运行valgrind
  3. valgrind测试完成后,将管路放回ld.so.预载
    预加载的“libarmmem.so”包含“memcmp”函数中的指令“setend”,其导致未处理的指令错误。标准库(在未加载预加载的“libarmmem.so”库时使用)不包括“memcmp”中的“setend”指令。
wpx232ag

wpx232ag3#

TL;DR:如果你使用的是Raspbian,请删除raspi-copies-and-fills包。它也可以在其他一些Linux变体中工作,如NOOBS。
正如Phong已经指出的,Valgrind不支持此指令。有一个bug报告解释了这个问题:
这不断出现,例如最近的bug 366464。也许我应该解释一下为什么不支持。这是因为我们没有一个可行的方法来做到这一点。Valgrind的JIT在代码块第一次被访问时对其进行检测,并且当前块的字节序被“烘焙”到检测中。所以有两个选择:
(1)当执行SETEND指令时,丢弃Valgrind创建的所有JIT代码,并使用新的字节序JIT新代码块。
(2)JIT代码以一种与端序无关的方式进行块处理,并对每次内存访问进行运行时测试,以决定是调用big还是little
端序检测辅助函数。
(1)对于不使用SETEND的代码,它的性能开销为零,但是对于使用SETEND的代码,它的性能开销非常大(完全不可行)。
(2)使endian更改自由,但惩罚所有内存流量,无论是否实际使用SETEND。
所以我觉得这两个都不能接受。我想不出任何其他方法来实现它。
换句话说,在valgrind中很难实现这条指令。总结线程:这个指令最常见的原因是Raspberry Pi提供的一些更快的内存管理函数(memcmp,memset等)。
我通过(暂时)从我的Raspbian安装中删除raspi-copies-and-fills来解决它。

v440hwme

v440hwme4#

Valgrind在Raspberry Pi上显然存在问题:
https://web.archive.org/web/20131003042418/http://www.raspberrypisoft.com/tag/valgrind/
我建议使用其他工具来找到seg故障。

7uzetpgm

7uzetpgm5#

libarmmem.so的memcmp()使用多字节加载指令,同时使用称为SWAR的技术来搜索缓冲区中的差异。然而,它使用“setend be”指令将处理器置于big-endian模式,以便在寄存器不匹配时更容易找到差异,然后在找到差异后,“setend le”在返回之前恢复endianness模式。这在ARM 11上很好用,但...
Valgrind doesn't implement setend emulation for Arm processors(可能是因为它会使正常情况下的native-endian访问变慢),因此它触发了“unrecognized instruction”。
SWAR向量化的memcmp()可以在没有SETEND,and I did so, and it's merged upstream的情况下实现。在相关内核上进行足够大的比较时,性能影响大致可以忽略不计。
@ayke也是正确的,禁用libarmmem也可以工作,但这将改变所有的libarmmem,而不仅仅是memcmp()。

相关问题