uftrace是一个跟踪程序的函数调用记录的一个工具,代码见
https://github.com/namhyung/uftrace
参数解析使用的argp,我把glibc里的argp模块单独提取出来了,见
argp模块
参数解析完会执行各种命令
switch (opts.mode) {
case UFTRACE_MODE_RECORD:
ret = command_record(argc, argv, &opts);
break;
case UFTRACE_MODE_REPLAY:
ret = command_replay(argc, argv, &opts);
break;
......
打印语句如下:
pr_dbg(“live-record finished… \n”);
默认是关闭的,需要加–debug打开
这是一个宏定义:
#ifndef PR_DOMAIN
# define PR_DOMAIN DBG_UFTRACE
#endif
#define pr_dbg(fmt, ...) \
({ \
if (dbg_domain[PR_DOMAIN]) \
__pr_dbg(PR_FMT ": " fmt, ## __VA_ARGS__); \
})
展开如下:
({ \
if (dbg_domain[DBG_UFTRACE]) \
__pr_dbg("uftrace" ": " "live-record finished.. \n"); \
})
__pr_dbg可以理解和printf一样。
输入–debug选项后,argp解析后会在parse_option函数里把debug变量设为1,然后通过下面代码把打印调试信息使能
if (debug) {
int d;
/* set default debug level */
for (d = 0; d < DBG_DOMAIN_MAX; d++) {
if (dbg_domain[d] == -1 || !dbg_domain_set)
dbg_domain[d] = debug;
}
}
由下面这2个函数获得
//symname就是函数名
sym = task_find_sym(sessions, task, rstack);
symname = symbol_getname(sym, rstack->addr);
信息放在session里,所以还要先创建session
//创建sessions
create_session(sess, &smsg, dirname, exename, sym_rel_addr);
load_symtabs(&s->symtabs, dirname, s->exename);
load_symbol_file
rb_link_node(&s->node, parent, p);
程序运行后会fork一个子进程,再execv执行要调试的程序,
pid = fork();
if (pid < 0)
pr_err("cannot start child process");
if (pid == 0) {
if (opts->keep_pid)
ret = do_main_loop(pfd, efd, opts, getppid());
else
do_child_exec(pfd, efd, opts, argv);
return ret;
}
if (opts->keep_pid)
do_child_exec(pfd, efd, opts, argv);
else
ret = do_main_loop(pfd, efd, opts, pid);
子进程的代码编译前要加-finstrument-functions,编译后会插入mcount和
void __cyg_profile_func_enter (void *this_fn, void *call_site);
等等,然后fork后的子进程调用setup_child_environ设置环境变量,加载动态库,execv调试进程后会在mcount和__cyg_profile_func_enter里把地址打印到sid-XXX.map文件里
子进程和父进程通过pipe和poll来通信,do_main_loop接收通信消息,并根据map文件进一步处理,相关代码:
save_session_symbols
maps = scandir(opts->dirname, &map_list, filter_map, alphasort);
/* find "sid-XXX.map" file */
static int filter_map(const struct dirent *de)
{
size_t len = strlen(de->d_name);
return !strncmp("sid-", de->d_name, 4) &&
!strncmp(".map", de->d_name + len - 4, 4);
}
write_symbol_files
load_symtabs
load_symtab
save_symbol_file
gcc -finstrument-functions 追踪函数调用,获取程序的执行流程