使用gdb计算机器指令

Lee*_*eor 14 x86 trace gdb

我需要根据x86机器指令数来估计程序中某些热点的确切起始位置(以便稍后可以在某个仿真器/模拟器中运行).有没有办法使用gdb来计算执行到断点的机器指令的数量?

当然还有其他选择,我可以使用仿真/二进制检测工具(如Pin),并在计算指令时跟踪运行,但这需要在我工作的每个平台上安装此工具 - 并非总是可行.我需要一些可以在任何Linux机器上使用的工具.

用GDB,我想它也可以运行stepi X,直到我们遇到断点过大的进步是某种粗粒搜索,然后降低分辨率重复,但是这将是极为缓慢.还有另一种方法吗?

Mar*_*ick 17

试试这个:

set pagination off
set $count=0
while ($pc != 0xyourstoppingaddress)
stepi
set $count++
end
print $count
Run Code Online (Sandbox Code Playgroud)

然后去喝杯咖啡.或者是一顿长长的午餐

  • @12431234123412341234123 尝试将 `while $pc != 0xyourstoppingaddress` 更改为 `while $pc != 0xyourstoppingaddress && $_siginfo.si_signo != 11` 以运行循环,直到收到 SIGSEGV。`stepi` 命令将导致程序获取 SIGTRAP 信号 (5),因此如果您想在 SIGTRAP 之外的任何信号上停止,请尝试 `while $pc != 0xyourstoppingaddress && $_siginfo.si_signo == 5` (3认同)
  • 工作正常,除了我需要在那里添加`start`.我要去吃午饭了,谢谢!:) (2认同)

ead*_*ead 6

这实际上只是对 Mark 解决方案可用性的一点点改进。

我们可以定义一个函数do_count

define do_count
set $count=0
while ($pc != $arg0)
stepi
set $count=$count+1
end
print $count
end
Run Code Online (Sandbox Code Playgroud)

然后可以重复使用此函数来一遍又一遍地计算步数:

set pagination off
do_count 0xaddress1
do_count 0xaddress2
Run Code Online (Sandbox Code Playgroud)

甚至可以将此定义放入.gdbinit(在 Linux 上,在 Windows 上应调用gdb.ini)的主文件夹中,因此在 gdb 启动后它会自动变为可用(用于show user查看函数是否已加载)。


Lek*_*eyn 5

如果您确实想要一个周期计数(可能是已知 IPC 的指令计数的近似值),并且您在裸机 ARM 上运行,您可能能够读取周期计数器,例如参见ARM Cortex M4 上的周期计数器(或M3)?


在您的场景中,我会尝试Process Record 和 Replay来获取已用指令计数(自 GDB 7.0 起可用,之后改进):

  1. 开始测量:(record btrace或者record full如果前者不可用)。
  2. continue执行(直到出现断点,或使用next或其他命令单步执行)。
  3. 获得测量: info record
  4. 清除记录结果:(record stop推荐使用,因为缓冲区大小有限)。

例子:

(gdb)记录 btrace
(gdb) 框架
#0 __sanitizer::InitTlsSize () 在 .../lib/sanitizer_common/sanitizer_linux_libcdep.cc:220
第 220 章
(gdb)信息记录
活动记录目标:record-btrace
录音格式:Branch Trace Store。
缓冲区大小:64kB。在线程 1(线程 0xf7c92300 (LWP 20579))的 0 个函数(0 个间隙)中
记录了0 条指令。
(gdb) 下一个
226 ...
(gdb)信息记录
活动记录目标:record-btrace
录音格式:Branch Trace Store。
缓冲区大小:64kB。在线程 1(线程 0xf7c92300 (LWP 20579))的 145 个函数(0 个间隙)中
记录了2859 条指令

限制:

  • 记录缓冲区的大小有限(set record btrace pt buffer-size <size>对于上面的 BTS 格式,可以增加,请参阅其他类型的文档)。
  • 使用record full,并非所有指令都可以捕获。值得注意的是,SSE 和 AVX 指令不受支持,会导致 gdb 暂停执行。
  • 记录每条指令(尤其是完整格式)时会产生一些开销。虽然它不应该像其他答案中描述的 gdb step 方法那么糟糕(每次都必须通过 ptrace )。