perf probe: Introduce debuginfo to encapsulate dwarf information
Introduce debuginfo to encapsulate dwarf information. This new object allows us to reuse and expand debuginfo easily. Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Ingo Molnar <mingo@elte.hu> Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net> Link: http://lkml.kernel.org/r/20110627072739.6528.12438.stgit@fedora15 Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
This commit is contained in:
		
							parent
							
								
									e0d153c690
								
							
						
					
					
						commit
						ff74178350
					
				| @ -170,16 +170,17 @@ const char *kernel_get_module_path(const char *module) | ||||
| } | ||||
| 
 | ||||
| #ifdef DWARF_SUPPORT | ||||
| static int open_vmlinux(const char *module) | ||||
| /* Open new debuginfo of given module */ | ||||
| static struct debuginfo *open_debuginfo(const char *module) | ||||
| { | ||||
| 	const char *path = kernel_get_module_path(module); | ||||
| 
 | ||||
| 	if (!path) { | ||||
| 		pr_err("Failed to find path of %s module.\n", | ||||
| 		       module ?: "kernel"); | ||||
| 		return -ENOENT; | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	pr_debug("Try to open %s\n", path); | ||||
| 	return open(path, O_RDONLY); | ||||
| 	return debuginfo__new(path); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| @ -193,13 +194,24 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, | ||||
| 	struct map *map; | ||||
| 	u64 addr; | ||||
| 	int ret = -ENOENT; | ||||
| 	struct debuginfo *dinfo; | ||||
| 
 | ||||
| 	sym = __find_kernel_function_by_name(tp->symbol, &map); | ||||
| 	if (sym) { | ||||
| 		addr = map->unmap_ip(map, sym->start + tp->offset); | ||||
| 		pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol, | ||||
| 			 tp->offset, addr); | ||||
| 		ret = find_perf_probe_point((unsigned long)addr, pp); | ||||
| 
 | ||||
| 		dinfo = debuginfo__new_online_kernel(addr); | ||||
| 		if (dinfo) { | ||||
| 			ret = debuginfo__find_probe_point(dinfo, | ||||
| 						 (unsigned long)addr, pp); | ||||
| 			debuginfo__delete(dinfo); | ||||
| 		} else { | ||||
| 			pr_debug("Failed to open debuginfo at 0x%" PRIx64 "\n", | ||||
| 				 addr); | ||||
| 			ret = -ENOENT; | ||||
| 		} | ||||
| 	} | ||||
| 	if (ret <= 0) { | ||||
| 		pr_debug("Failed to find corresponding probes from " | ||||
| @ -220,20 +232,22 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | ||||
| 					   int max_tevs, const char *module) | ||||
| { | ||||
| 	bool need_dwarf = perf_probe_event_need_dwarf(pev); | ||||
| 	int fd, ntevs; | ||||
| 	struct debuginfo *dinfo = open_debuginfo(module); | ||||
| 	int ntevs; | ||||
| 
 | ||||
| 	fd = open_vmlinux(module); | ||||
| 	if (fd < 0) { | ||||
| 	if (!dinfo) { | ||||
| 		if (need_dwarf) { | ||||
| 			pr_warning("Failed to open debuginfo file.\n"); | ||||
| 			return fd; | ||||
| 			return -ENOENT; | ||||
| 		} | ||||
| 		pr_debug("Could not open vmlinux. Try to use symbols.\n"); | ||||
| 		pr_debug("Could not open debuginfo. Try to use symbols.\n"); | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Searching trace events corresponding to probe event */ | ||||
| 	ntevs = find_probe_trace_events(fd, pev, tevs, max_tevs); | ||||
| 	/* Searching trace events corresponding to a probe event */ | ||||
| 	ntevs = debuginfo__find_trace_events(dinfo, pev, tevs, max_tevs); | ||||
| 
 | ||||
| 	debuginfo__delete(dinfo); | ||||
| 
 | ||||
| 	if (ntevs > 0) {	/* Succeeded to find trace events */ | ||||
| 		pr_debug("find %d probe_trace_events.\n", ntevs); | ||||
| @ -371,8 +385,9 @@ int show_line_range(struct line_range *lr, const char *module) | ||||
| { | ||||
| 	int l = 1; | ||||
| 	struct line_node *ln; | ||||
| 	struct debuginfo *dinfo; | ||||
| 	FILE *fp; | ||||
| 	int fd, ret; | ||||
| 	int ret; | ||||
| 	char *tmp; | ||||
| 
 | ||||
| 	/* Search a line range */ | ||||
| @ -380,13 +395,14 @@ int show_line_range(struct line_range *lr, const char *module) | ||||
| 	if (ret < 0) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	fd = open_vmlinux(module); | ||||
| 	if (fd < 0) { | ||||
| 	dinfo = open_debuginfo(module); | ||||
| 	if (!dinfo) { | ||||
| 		pr_warning("Failed to open debuginfo file.\n"); | ||||
| 		return fd; | ||||
| 		return -ENOENT; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = find_line_range(fd, lr); | ||||
| 	ret = debuginfo__find_line_range(dinfo, lr); | ||||
| 	debuginfo__delete(dinfo); | ||||
| 	if (ret == 0) { | ||||
| 		pr_warning("Specified source line is not found.\n"); | ||||
| 		return -ENOENT; | ||||
| @ -448,7 +464,8 @@ end: | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int show_available_vars_at(int fd, struct perf_probe_event *pev, | ||||
| static int show_available_vars_at(struct debuginfo *dinfo, | ||||
| 				  struct perf_probe_event *pev, | ||||
| 				  int max_vls, struct strfilter *_filter, | ||||
| 				  bool externs) | ||||
| { | ||||
| @ -463,7 +480,8 @@ static int show_available_vars_at(int fd, struct perf_probe_event *pev, | ||||
| 		return -EINVAL; | ||||
| 	pr_debug("Searching variables at %s\n", buf); | ||||
| 
 | ||||
| 	ret = find_available_vars_at(fd, pev, &vls, max_vls, externs); | ||||
| 	ret = debuginfo__find_available_vars_at(dinfo, pev, &vls, | ||||
| 						max_vls, externs); | ||||
| 	if (ret <= 0) { | ||||
| 		pr_err("Failed to find variables at %s (%d)\n", buf, ret); | ||||
| 		goto end; | ||||
| @ -504,24 +522,26 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs, | ||||
| 			int max_vls, const char *module, | ||||
| 			struct strfilter *_filter, bool externs) | ||||
| { | ||||
| 	int i, fd, ret = 0; | ||||
| 	int i, ret = 0; | ||||
| 	struct debuginfo *dinfo; | ||||
| 
 | ||||
| 	ret = init_vmlinux(); | ||||
| 	if (ret < 0) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	dinfo = open_debuginfo(module); | ||||
| 	if (!dinfo) { | ||||
| 		pr_warning("Failed to open debuginfo file.\n"); | ||||
| 		return -ENOENT; | ||||
| 	} | ||||
| 
 | ||||
| 	setup_pager(); | ||||
| 
 | ||||
| 	for (i = 0; i < npevs && ret >= 0; i++) { | ||||
| 		fd = open_vmlinux(module); | ||||
| 		if (fd < 0) { | ||||
| 			pr_warning("Failed to open debug information file.\n"); | ||||
| 			ret = fd; | ||||
| 			break; | ||||
| 		} | ||||
| 		ret = show_available_vars_at(fd, &pevs[i], max_vls, _filter, | ||||
| 	for (i = 0; i < npevs && ret >= 0; i++) | ||||
| 		ret = show_available_vars_at(dinfo, &pevs[i], max_vls, _filter, | ||||
| 					     externs); | ||||
| 	} | ||||
| 
 | ||||
| 	debuginfo__delete(dinfo); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -116,29 +116,37 @@ static const Dwfl_Callbacks offline_callbacks = { | ||||
| }; | ||||
| 
 | ||||
| /* Get a Dwarf from offline image */ | ||||
| static Dwarf *dwfl_init_offline_dwarf(int fd, Dwfl **dwflp, Dwarf_Addr *bias) | ||||
| static int debuginfo__init_offline_dwarf(struct debuginfo *self, | ||||
| 					 const char *path) | ||||
| { | ||||
| 	Dwfl_Module *mod; | ||||
| 	Dwarf *dbg = NULL; | ||||
| 	int fd; | ||||
| 
 | ||||
| 	if (!dwflp) | ||||
| 		return NULL; | ||||
| 	fd = open(path, O_RDONLY); | ||||
| 	if (fd < 0) | ||||
| 		return fd; | ||||
| 
 | ||||
| 	*dwflp = dwfl_begin(&offline_callbacks); | ||||
| 	if (!*dwflp) | ||||
| 		return NULL; | ||||
| 	self->dwfl = dwfl_begin(&offline_callbacks); | ||||
| 	if (!self->dwfl) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	mod = dwfl_report_offline(*dwflp, "", "", fd); | ||||
| 	mod = dwfl_report_offline(self->dwfl, "", "", fd); | ||||
| 	if (!mod) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	dbg = dwfl_module_getdwarf(mod, bias); | ||||
| 	if (!dbg) { | ||||
| 	self->dbg = dwfl_module_getdwarf(mod, &self->bias); | ||||
| 	if (!self->dbg) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	return 0; | ||||
| error: | ||||
| 		dwfl_end(*dwflp); | ||||
| 		*dwflp = NULL; | ||||
| 	} | ||||
| 	return dbg; | ||||
| 	if (self->dwfl) | ||||
| 		dwfl_end(self->dwfl); | ||||
| 	else | ||||
| 		close(fd); | ||||
| 	memset(self, 0, sizeof(*self)); | ||||
| 
 | ||||
| 	return -ENOENT; | ||||
| } | ||||
| 
 | ||||
| #if _ELFUTILS_PREREQ(0, 148) | ||||
| @ -174,54 +182,83 @@ static const Dwfl_Callbacks kernel_callbacks = { | ||||
| }; | ||||
| 
 | ||||
| /* Get a Dwarf from live kernel image */ | ||||
| static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr, Dwfl **dwflp, | ||||
| 					  Dwarf_Addr *bias) | ||||
| static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self, | ||||
| 					       Dwarf_Addr addr) | ||||
| { | ||||
| 	Dwarf *dbg; | ||||
| 
 | ||||
| 	if (!dwflp) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	*dwflp = dwfl_begin(&kernel_callbacks); | ||||
| 	if (!*dwflp) | ||||
| 		return NULL; | ||||
| 	self->dwfl = dwfl_begin(&kernel_callbacks); | ||||
| 	if (!self->dwfl) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	/* Load the kernel dwarves: Don't care the result here */ | ||||
| 	dwfl_linux_kernel_report_kernel(*dwflp); | ||||
| 	dwfl_linux_kernel_report_modules(*dwflp); | ||||
| 	dwfl_linux_kernel_report_kernel(self->dwfl); | ||||
| 	dwfl_linux_kernel_report_modules(self->dwfl); | ||||
| 
 | ||||
| 	dbg = dwfl_addrdwarf(*dwflp, addr, bias); | ||||
| 	self->dbg = dwfl_addrdwarf(self->dwfl, addr, &self->bias); | ||||
| 	/* Here, check whether we could get a real dwarf */ | ||||
| 	if (!dbg) { | ||||
| 	if (!self->dbg) { | ||||
| 		pr_debug("Failed to find kernel dwarf at %lx\n", | ||||
| 			 (unsigned long)addr); | ||||
| 		dwfl_end(*dwflp); | ||||
| 		*dwflp = NULL; | ||||
| 		dwfl_end(self->dwfl); | ||||
| 		memset(self, 0, sizeof(*self)); | ||||
| 		return -ENOENT; | ||||
| 	} | ||||
| 	return dbg; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| #else | ||||
| /* With older elfutils, this just support kernel module... */ | ||||
| static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr __used, Dwfl **dwflp, | ||||
| 					  Dwarf_Addr *bias) | ||||
| static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self, | ||||
| 					       Dwarf_Addr addr __used) | ||||
| { | ||||
| 	int fd; | ||||
| 	const char *path = kernel_get_module_path("kernel"); | ||||
| 
 | ||||
| 	if (!path) { | ||||
| 		pr_err("Failed to find vmlinux path\n"); | ||||
| 		return NULL; | ||||
| 		return -ENOENT; | ||||
| 	} | ||||
| 
 | ||||
| 	pr_debug2("Use file %s for debuginfo\n", path); | ||||
| 	fd = open(path, O_RDONLY); | ||||
| 	if (fd < 0) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	return dwfl_init_offline_dwarf(fd, dwflp, bias); | ||||
| 	return debuginfo__init_offline_dwarf(self, path); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| struct debuginfo *debuginfo__new(const char *path) | ||||
| { | ||||
| 	struct debuginfo *self = zalloc(sizeof(struct debuginfo)); | ||||
| 	if (!self) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	if (debuginfo__init_offline_dwarf(self, path) < 0) { | ||||
| 		free(self); | ||||
| 		self = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	return self; | ||||
| } | ||||
| 
 | ||||
| struct debuginfo *debuginfo__new_online_kernel(unsigned long addr) | ||||
| { | ||||
| 	struct debuginfo *self = zalloc(sizeof(struct debuginfo)); | ||||
| 	if (!self) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	if (debuginfo__init_online_kernel_dwarf(self, (Dwarf_Addr)addr) < 0) { | ||||
| 		free(self); | ||||
| 		self = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	return self; | ||||
| } | ||||
| 
 | ||||
| void debuginfo__delete(struct debuginfo *self) | ||||
| { | ||||
| 	if (self) { | ||||
| 		if (self->dwfl) | ||||
| 			dwfl_end(self->dwfl); | ||||
| 		free(self); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Probe finder related functions | ||||
|  */ | ||||
| @ -949,28 +986,18 @@ static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data) | ||||
| } | ||||
| 
 | ||||
| /* Find probe points from debuginfo */ | ||||
| static int find_probes(int fd, struct probe_finder *pf) | ||||
| static int debuginfo__find_probes(struct debuginfo *self, | ||||
| 				  struct probe_finder *pf) | ||||
| { | ||||
| 	struct perf_probe_point *pp = &pf->pev->point; | ||||
| 	Dwarf_Off off, noff; | ||||
| 	size_t cuhl; | ||||
| 	Dwarf_Die *diep; | ||||
| 	Dwarf *dbg = NULL; | ||||
| 	Dwfl *dwfl; | ||||
| 	Dwarf_Addr bias;	/* Currently ignored */ | ||||
| 	int ret = 0; | ||||
| 
 | ||||
| 	dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias); | ||||
| 	if (!dbg) { | ||||
| 		pr_warning("No debug information found in the vmlinux - " | ||||
| 			"please rebuild with CONFIG_DEBUG_INFO=y.\n"); | ||||
| 		close(fd);	/* Without dwfl_end(), fd isn't closed. */ | ||||
| 		return -EBADF; | ||||
| 	} | ||||
| 
 | ||||
| #if _ELFUTILS_PREREQ(0, 142) | ||||
| 	/* Get the call frame information from this dwarf */ | ||||
| 	pf->cfi = dwarf_getcfi(dbg); | ||||
| 	pf->cfi = dwarf_getcfi(self->dbg); | ||||
| #endif | ||||
| 
 | ||||
| 	off = 0; | ||||
| @ -989,7 +1016,8 @@ static int find_probes(int fd, struct probe_finder *pf) | ||||
| 			.data = pf, | ||||
| 		}; | ||||
| 
 | ||||
| 		dwarf_getpubnames(dbg, pubname_search_cb, &pubname_param, 0); | ||||
| 		dwarf_getpubnames(self->dbg, pubname_search_cb, | ||||
| 				  &pubname_param, 0); | ||||
| 		if (pubname_param.found) { | ||||
| 			ret = probe_point_search_cb(&pf->sp_die, &probe_param); | ||||
| 			if (ret) | ||||
| @ -998,9 +1026,9 @@ static int find_probes(int fd, struct probe_finder *pf) | ||||
| 	} | ||||
| 
 | ||||
| 	/* Loop on CUs (Compilation Unit) */ | ||||
| 	while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { | ||||
| 	while (!dwarf_nextcu(self->dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { | ||||
| 		/* Get the DIE(Debugging Information Entry) of this CU */ | ||||
| 		diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die); | ||||
| 		diep = dwarf_offdie(self->dbg, off + cuhl, &pf->cu_die); | ||||
| 		if (!diep) | ||||
| 			continue; | ||||
| 
 | ||||
| @ -1027,8 +1055,6 @@ static int find_probes(int fd, struct probe_finder *pf) | ||||
| 
 | ||||
| found: | ||||
| 	line_list__free(&pf->lcache); | ||||
| 	if (dwfl) | ||||
| 		dwfl_end(dwfl); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| @ -1074,8 +1100,9 @@ static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf) | ||||
| } | ||||
| 
 | ||||
| /* Find probe_trace_events specified by perf_probe_event from debuginfo */ | ||||
| int find_probe_trace_events(int fd, struct perf_probe_event *pev, | ||||
| 			    struct probe_trace_event **tevs, int max_tevs) | ||||
| int debuginfo__find_trace_events(struct debuginfo *self, | ||||
| 				 struct perf_probe_event *pev, | ||||
| 				 struct probe_trace_event **tevs, int max_tevs) | ||||
| { | ||||
| 	struct trace_event_finder tf = { | ||||
| 			.pf = {.pev = pev, .callback = add_probe_trace_event}, | ||||
| @ -1090,7 +1117,7 @@ int find_probe_trace_events(int fd, struct perf_probe_event *pev, | ||||
| 	tf.tevs = *tevs; | ||||
| 	tf.ntevs = 0; | ||||
| 
 | ||||
| 	ret = find_probes(fd, &tf.pf); | ||||
| 	ret = debuginfo__find_probes(self, &tf.pf); | ||||
| 	if (ret < 0) { | ||||
| 		free(*tevs); | ||||
| 		*tevs = NULL; | ||||
| @ -1184,9 +1211,10 @@ out: | ||||
| } | ||||
| 
 | ||||
| /* Find available variables at given probe point */ | ||||
| int find_available_vars_at(int fd, struct perf_probe_event *pev, | ||||
| 			   struct variable_list **vls, int max_vls, | ||||
| 			   bool externs) | ||||
| int debuginfo__find_available_vars_at(struct debuginfo *self, | ||||
| 				      struct perf_probe_event *pev, | ||||
| 				      struct variable_list **vls, | ||||
| 				      int max_vls, bool externs) | ||||
| { | ||||
| 	struct available_var_finder af = { | ||||
| 			.pf = {.pev = pev, .callback = add_available_vars}, | ||||
| @ -1201,7 +1229,7 @@ int find_available_vars_at(int fd, struct perf_probe_event *pev, | ||||
| 	af.vls = *vls; | ||||
| 	af.nvls = 0; | ||||
| 
 | ||||
| 	ret = find_probes(fd, &af.pf); | ||||
| 	ret = debuginfo__find_probes(self, &af.pf); | ||||
| 	if (ret < 0) { | ||||
| 		/* Free vlist for error */ | ||||
| 		while (af.nvls--) { | ||||
| @ -1219,28 +1247,19 @@ int find_available_vars_at(int fd, struct perf_probe_event *pev, | ||||
| } | ||||
| 
 | ||||
| /* Reverse search */ | ||||
| int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt) | ||||
| int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr, | ||||
| 				struct perf_probe_point *ppt) | ||||
| { | ||||
| 	Dwarf_Die cudie, spdie, indie; | ||||
| 	Dwarf *dbg = NULL; | ||||
| 	Dwfl *dwfl = NULL; | ||||
| 	Dwarf_Addr _addr, baseaddr, bias = 0; | ||||
| 	Dwarf_Addr _addr, baseaddr; | ||||
| 	const char *fname = NULL, *func = NULL, *tmp; | ||||
| 	int baseline = 0, lineno = 0, ret = 0; | ||||
| 
 | ||||
| 	/* Open the live linux kernel */ | ||||
| 	dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias); | ||||
| 	if (!dbg) { | ||||
| 		pr_warning("No debug information found in the vmlinux - " | ||||
| 			"please rebuild with CONFIG_DEBUG_INFO=y.\n"); | ||||
| 		ret = -EINVAL; | ||||
| 		goto end; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Adjust address with bias */ | ||||
| 	addr += bias; | ||||
| 	addr += self->bias; | ||||
| 
 | ||||
| 	/* Find cu die */ | ||||
| 	if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr - bias, &cudie)) { | ||||
| 	if (!dwarf_addrdie(self->dbg, (Dwarf_Addr)addr - self->bias, &cudie)) { | ||||
| 		pr_warning("Failed to find debug information for address %lx\n", | ||||
| 			   addr); | ||||
| 		ret = -EINVAL; | ||||
| @ -1316,8 +1335,6 @@ post: | ||||
| 		} | ||||
| 	} | ||||
| end: | ||||
| 	if (dwfl) | ||||
| 		dwfl_end(dwfl); | ||||
| 	if (ret == 0 && (fname || func)) | ||||
| 		ret = 1;	/* Found a point */ | ||||
| 	return ret; | ||||
| @ -1427,26 +1444,15 @@ static int find_line_range_by_func(struct line_finder *lf) | ||||
| 	return param.retval; | ||||
| } | ||||
| 
 | ||||
| int find_line_range(int fd, struct line_range *lr) | ||||
| int debuginfo__find_line_range(struct debuginfo *self, struct line_range *lr) | ||||
| { | ||||
| 	struct line_finder lf = {.lr = lr, .found = 0}; | ||||
| 	int ret = 0; | ||||
| 	Dwarf_Off off = 0, noff; | ||||
| 	size_t cuhl; | ||||
| 	Dwarf_Die *diep; | ||||
| 	Dwarf *dbg = NULL; | ||||
| 	Dwfl *dwfl; | ||||
| 	Dwarf_Addr bias;	/* Currently ignored */ | ||||
| 	const char *comp_dir; | ||||
| 
 | ||||
| 	dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias); | ||||
| 	if (!dbg) { | ||||
| 		pr_warning("No debug information found in the vmlinux - " | ||||
| 			"please rebuild with CONFIG_DEBUG_INFO=y.\n"); | ||||
| 		close(fd);	/* Without dwfl_end(), fd isn't closed. */ | ||||
| 		return -EBADF; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Fastpath: lookup by function name from .debug_pubnames section */ | ||||
| 	if (lr->function) { | ||||
| 		struct pubname_callback_param pubname_param = { | ||||
| @ -1455,7 +1461,8 @@ int find_line_range(int fd, struct line_range *lr) | ||||
| 		struct dwarf_callback_param line_range_param = { | ||||
| 			.data = (void *)&lf, .retval = 0}; | ||||
| 
 | ||||
| 		dwarf_getpubnames(dbg, pubname_search_cb, &pubname_param, 0); | ||||
| 		dwarf_getpubnames(self->dbg, pubname_search_cb, | ||||
| 				  &pubname_param, 0); | ||||
| 		if (pubname_param.found) { | ||||
| 			line_range_search_cb(&lf.sp_die, &line_range_param); | ||||
| 			if (lf.found) | ||||
| @ -1465,11 +1472,12 @@ int find_line_range(int fd, struct line_range *lr) | ||||
| 
 | ||||
| 	/* Loop on CUs (Compilation Unit) */ | ||||
| 	while (!lf.found && ret >= 0) { | ||||
| 		if (dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) != 0) | ||||
| 		if (dwarf_nextcu(self->dbg, off, &noff, &cuhl, | ||||
| 				 NULL, NULL, NULL) != 0) | ||||
| 			break; | ||||
| 
 | ||||
| 		/* Get the DIE(Debugging Information Entry) of this CU */ | ||||
| 		diep = dwarf_offdie(dbg, off + cuhl, &lf.cu_die); | ||||
| 		diep = dwarf_offdie(self->dbg, off + cuhl, &lf.cu_die); | ||||
| 		if (!diep) | ||||
| 			continue; | ||||
| 
 | ||||
| @ -1503,7 +1511,6 @@ found: | ||||
| 	} | ||||
| 
 | ||||
| 	pr_debug("path: %s\n", lr->path); | ||||
| 	dwfl_end(dwfl); | ||||
| 	return (ret < 0) ? ret : lf.found; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -16,23 +16,42 @@ static inline int is_c_varname(const char *name) | ||||
| } | ||||
| 
 | ||||
| #ifdef DWARF_SUPPORT | ||||
| 
 | ||||
| #include "dwarf-aux.h" | ||||
| 
 | ||||
| /* TODO: export debuginfo data structure even if no dwarf support */ | ||||
| 
 | ||||
| /* debug information structure */ | ||||
| struct debuginfo { | ||||
| 	Dwarf		*dbg; | ||||
| 	Dwfl		*dwfl; | ||||
| 	Dwarf_Addr	bias; | ||||
| }; | ||||
| 
 | ||||
| extern struct debuginfo *debuginfo__new(const char *path); | ||||
| extern struct debuginfo *debuginfo__new_online_kernel(unsigned long addr); | ||||
| extern void debuginfo__delete(struct debuginfo *self); | ||||
| 
 | ||||
| /* Find probe_trace_events specified by perf_probe_event from debuginfo */ | ||||
| extern int find_probe_trace_events(int fd, struct perf_probe_event *pev, | ||||
| 				    struct probe_trace_event **tevs, | ||||
| 				    int max_tevs); | ||||
| extern int debuginfo__find_trace_events(struct debuginfo *self, | ||||
| 					struct perf_probe_event *pev, | ||||
| 					struct probe_trace_event **tevs, | ||||
| 					int max_tevs); | ||||
| 
 | ||||
| /* Find a perf_probe_point from debuginfo */ | ||||
| extern int find_perf_probe_point(unsigned long addr, | ||||
| 				 struct perf_probe_point *ppt); | ||||
| extern int debuginfo__find_probe_point(struct debuginfo *self, | ||||
| 				       unsigned long addr, | ||||
| 				       struct perf_probe_point *ppt); | ||||
| 
 | ||||
| /* Find a line range */ | ||||
| extern int find_line_range(int fd, struct line_range *lr); | ||||
| extern int debuginfo__find_line_range(struct debuginfo *self, | ||||
| 				      struct line_range *lr); | ||||
| 
 | ||||
| /* Find available variables */ | ||||
| extern int find_available_vars_at(int fd, struct perf_probe_event *pev, | ||||
| 				  struct variable_list **vls, int max_points, | ||||
| 				  bool externs); | ||||
| #include "dwarf-aux.h" | ||||
| extern int debuginfo__find_available_vars_at(struct debuginfo *self, | ||||
| 					     struct perf_probe_event *pev, | ||||
| 					     struct variable_list **vls, | ||||
| 					     int max_points, bool externs); | ||||
| 
 | ||||
| struct probe_finder { | ||||
| 	struct perf_probe_event	*pev;		/* Target probe event */ | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user