uftrace关键代码记录

uftrace是一个跟踪程序的函数调用记录的一个工具,代码见
https://github.com/namhyung/uftrace

1.参数解析

参数解析使用的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;
	......

2. 调试信息

打印语句如下:
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;
		}
	}

3.函数符号

由下面这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执行要调试的程序,

扫描二维码关注公众号,回复: 12497489 查看本文章
	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

4.参考

gcc -finstrument-functions 追踪函数调用,获取程序的执行流程

利用 gcc/g++ 的 -finstrument-functions 的注入选项

https://github.com/finaldie/ftracer

猜你喜欢

转载自blog.csdn.net/pfysw/article/details/108976966