Linux上可以使用perf快速定位耗时的函数,其实gdb利用采样也能做到:程序运行一阵子,我CTRL+C一次获得此时的调用栈,次数多了最耗时的函数自然就暴露出来了。下面是bash脚本,需要运行一阵子后自己统计次数最多的函数。
#!/bin/bash
if test $# -ne 1; then
echo "Usage: `basename $0 .sh` " 1>&2
exit 1
fi
if test ! -r /proc/$1; then
echo "Process $1 not found." 1>&2
exit 1
fi
PROCESS_LINE=`ps -p $1|wc -l`
while [ "$PROCESS_LINE" == "2" ]; do
PROCESS_PS=`ps -p $1|wc -l`
if [ "$PROCESS_LINE" != "2" ]
then
break
fi
gdb -p $1 \
-ex "set pagination off" \
-ex "set logging on" \
-ex "where" \
-ex "detach" \
-ex "quit"| grep '^#0'
sleep 5;
done
有时拿到客户core dump,如果通过自己算结构的偏移去找某个字段的值很麻烦,有没有办法引入这些符号的定义哪?还真有,下面是个例子
// sample.c
#include "sample.h"
struct sample foo; //把所有有用的struct都放进来!
gcc -g -c sample.c
(gdb) add-symbol-file sample.o 0
add symbol table from file "sample.o" at .text_addr = 0x0
(gdb) p (struct sample *)0x7fffffffd6b0
$1 = (struct sample *) 0x7fffffffd6b0
(gdb) p *$1
$2 = {i = 42, less = 0x7fffffffd6b0, more = 0x7fffffffd6b0}
In GDB, the value of $ is the value returned from the previous command.
(gdb) p mgmt_thread_data.next_thread
$67 = (struct k_thread *) 0x2000188c
(gdb) p $.next_thread
$68 = (struct k_thread *) 0x200022ac
(gdb)
$69 = (struct k_thread *) 0x2000a120
(gdb)info proc mappings
有一个shell command功能与之类似:pmap -d pid
(gdb)info source
CTRL+x and a
winheight src+N 调整src窗口大小
(gdb)shell [shell-command]
eg. (gdb) shell ls
直接管道连接gdb命令和shell命令并不支持,如下会报错:
(gdb) where|grep libc
A syntax error in expression, near `|grep libc'.
(gdb) pipe where|grep libc
Undefined command: "pipe". Try "help".
办法是基于gdb对Python的接口写一个Python脚本:
from __future__ import print_function
import gdb
import string
import subprocess
import sys
#please refer to doc https://sourceware.org/gdb/onlinedocs/gdb/Python-API.html#Python-API
class ShellPipe (gdb.Command):
"Command to pipe gdb internal command output to external commands."
def __init__(self):
super (ShellPipe, self).__init__("shell-pipe",
gdb.COMMAND_DATA,
gdb.COMPLETE_NONE, True)
gdb.execute("alias -a sp = shell-pipe", True)
def invoke(self, arg, from_tty):
arg = arg.strip()
if arg == "":
print("Argument required (gdb_command_and_args | externalcommand..).")
return
gdb_command, shell_commands = None, None
if '|' in arg:
gdb_command, shell_commands = arg.split("|") #, maxsplit=1)
gdb_command, shell_commands = gdb_command.strip(), shell_commands.strip()
else:
gdb_command = arg
# Collect the output and feed it through the pipe
output = gdb.execute(gdb_command, True, True)
if shell_commands:
shell_process = subprocess.Popen(shell_commands, stdin=subprocess.PIPE, shell=True)
shell_process.communicate(output.encode('utf-8'))
else:
sys.stdout.write(output)
ShellPipe()
使用举例:
(gdb) source 上面的文件
(gdb) shell-pipe where|grep libc
#0 0x00007f30626175f3 in __msgrcv_nocancel () from /usr/lib64/libc.so.6
(gdb) 数组@个数
比如:arr@5
(gdb) p /x "HELLO"
$5 = {0x48, 0x45, 0x4c, 0x4c, 0x4f, 0x0}
(gdb) find /b start_addr, end_addr, 0x48, 0x45, 0x4c, 0x4c, 0x4f 查找"HELLO"
(gdb) find /w 0x1be4d80a, +10, 842121264 在[0x1be4d80a,0x1be4d80a+10)中查找int 842121264
需求:回到刚刚运行的代码再执行一遍
This is yet another use case for Reverse Debugging.
1. You should start process record and replay at some point:
(gdb) record
2. When you want to see last executed lines you can go backwards like this:
(gdb) reverse-step 3
(gdb) disass 函数
(gdb) layout asm
有时想知道当前怎么处理信号的,又不想从代码里找,有个gdb脚本可以用
http://palves.net/list-active-signal-handlers-with-gdb/
(gdb) info signal-dispositions 2 5
Number Name Description Disposition
2 SIGINT Interrupt rl_signal_handler in section .text of build/gdb/gdb
5 SIGTRAP Trace/breakpoint trap SIG_DFL
(gdb) macro define offsetof(t, f) &((t *) 0)->f