我需要根据x86机器指令数来估计程序中某些热点的确切起始位置(以便稍后可以在某些模拟器/模拟器中运行)。有没有办法使用gdb来计算执行到断点的机器指令的数量?
当然还有其他选择,我可以使用仿真/二进制检测工具(如Pin),并在计算指令时跟踪运行,但这需要在我工作的每个平台上安装此工具 - 并非总是可行。我需要一些可以在任何linux机器上使用的工具。
使用gdb,我猜也可以在大步幅上运行stepi X
作为某种粗粒度搜索,直到我们到达断点,然后以降低分辨率重复,但这将是极其缓慢的。还有另一种方法吗?
答案 0 :(得分:15)
试试这个:
set pagination off
set $count=0
while ($pc != 0xyourstoppingaddress)
stepi
set $count++
end
print $count
然后去喝杯咖啡。或者是一顿长长的午餐。
答案 1 :(得分:3)
这实际上只是对Mark解决方案可用性的略微改进。
我们可以定义一个函数do_count
:
define do_count
set $count=0
while ($pc != $arg0)
stepi
set $count=$count+1
end
print $count
end
然后可以重复使用此函数来反复计算步数:
set pagination off
do_count 0xaddress1
do_count 0xaddress2
甚至可以将此定义放入主文件夹中的.gdbinit
(在Linux上,在Windows上,它应该被称为gdb.ini
),因此它在gdb启动后自动变为可用(使用show user
查看函数是否已加载)。
答案 2 :(得分:1)
如果你真的想要一个循环计数(可能是已知IPC的指令计数的近似值),并且你在裸机ARM上运行,你可能能够读取循环计数器,参见例如{{ 3}}
在您的场景中,我会尝试Cycle counter on ARM Cortex M4 (or M3)?来获取已用完的指令数(自GDB 7.0起可用,之后进行了改进):
record btrace
(如果前者不可用,则为record full
。)continue
执行(直到断点,或使用next
或其他命令逐步完成)。info record
record stop
(建议缓冲区的大小有限)。示例:
(gdb) record btrace (gdb) frame #0 __sanitizer::InitTlsSize () at .../lib/sanitizer_common/sanitizer_linux_libcdep.cc:220 220 void *get_tls_static_info_ptr = dlsym(RTLD_NEXT, "_dl_get_tls_static_info"); (gdb) info record Active record target: record-btrace Recording format: Branch Trace Store. Buffer size: 64kB. Recorded 0 instructions in 0 functions (0 gaps) for thread 1 (Thread 0xf7c92300 (LWP 20579)). (gdb) next 226 ... (gdb) info record Active record target: record-btrace Recording format: Branch Trace Store. Buffer size: 64kB. Recorded 2859 instructions in 145 functions (0 gaps) for thread 1 (Thread 0xf7c92300 (LWP 20579)).
限制:
set record btrace pt buffer-size <size>
增加,有关其他类型,请参阅Process Record and Replay。)record full
,并非所有指令都可以捕获。值得注意的是,SSE和AVX指令不受支持,将导致gdb暂停执行。