我需要根据x86机器指令数来估计程序中某些热点的确切起始位置(以便稍后可以在某个仿真器/模拟器中运行)。有没有办法使用gdb来计算执行到断点的机器指令的数量?
当然还有其他选择,我可以使用仿真/二进制检测工具(如Pin),并在计算指令时跟踪运行,但这需要在我工作的每个平台上安装此工具 - 并非总是可行。我需要一些可以在任何Linux机器上使用的工具。
使用gdb,我想也可以将stepi X
作为某种粗粒度搜索运行set pagination off
set $count=0
while ($pc != 0xyourstoppingaddress)
stepi
set $count++
end
print $count
,直到我们达到断点,然后以降低分辨率重复,但这将是极其缓慢的。还有另一种方法吗?
试试这个:
do_count
然后去喝杯咖啡。或者是一顿长长的午餐
这实际上只是对Mark解决方案可用性的略微改进。
我们可以定义一个函数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
甚至可以将这个定义放入gdb.ini
(在Linux上,在Windows上,它应该被称为show user
)在home文件夹中,因此它在gdb启动后自动变为可用(使用Cycle counter on ARM Cortex M4 (or M3)?查看,是否加载了该函数)。
如果你真的想要一个循环计数(可能是已知IPC的指令计数的近似值),并且你在裸机ARM上运行,你可能能够读取循环计数器,例如参见Process Record and Replay
在您的场景中,我会尝试使用record btrace
来获取已用完的指令数(自GDB 7.0起可用,之后进行了改进):
record full
(如果前者不可用,则为continue
)。next
(直到断点,或使用info record
或其他命令逐步执行)。record stop
set record btrace pt buffer-size <size>
(建议缓冲区的大小有限)。例:
(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)).
限制:
record full
)。