xref: /freebsd/contrib/wpa/src/utils/trace.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
1e28a4053SRui Paulo /*
2e28a4053SRui Paulo  * Backtrace debugging
3e28a4053SRui Paulo  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
4e28a4053SRui Paulo  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
7e28a4053SRui Paulo  */
8e28a4053SRui Paulo 
985732ac8SCy Schubert #ifdef WPA_TRACE_BFD
1085732ac8SCy Schubert #define _GNU_SOURCE
1185732ac8SCy Schubert #include <link.h>
1285732ac8SCy Schubert #endif /* WPA_TRACE_BCD */
13e28a4053SRui Paulo #include "includes.h"
14e28a4053SRui Paulo 
15e28a4053SRui Paulo #include "common.h"
16e28a4053SRui Paulo #include "trace.h"
17e28a4053SRui Paulo 
18e28a4053SRui Paulo #ifdef WPA_TRACE
19e28a4053SRui Paulo 
20e28a4053SRui Paulo static struct dl_list active_references =
21e28a4053SRui Paulo { &active_references, &active_references };
22e28a4053SRui Paulo 
23e28a4053SRui Paulo #ifdef WPA_TRACE_BFD
24e28a4053SRui Paulo #include <bfd.h>
255b9c547cSRui Paulo 
265b9c547cSRui Paulo #define DMGL_PARAMS      (1 << 0)
275b9c547cSRui Paulo #define DMGL_ANSI        (1 << 1)
28e28a4053SRui Paulo 
29e28a4053SRui Paulo static char *prg_fname = NULL;
30e28a4053SRui Paulo static bfd *cached_abfd = NULL;
31e28a4053SRui Paulo static asymbol **syms = NULL;
3285732ac8SCy Schubert static unsigned long start_offset;
3385732ac8SCy Schubert static int start_offset_looked_up;
3485732ac8SCy Schubert 
3585732ac8SCy Schubert 
callback(struct dl_phdr_info * info,size_t size,void * data)3685732ac8SCy Schubert static int callback(struct dl_phdr_info *info, size_t size, void *data)
3785732ac8SCy Schubert {
3885732ac8SCy Schubert 	/*
3985732ac8SCy Schubert 	 * dl_iterate_phdr(3):
4085732ac8SCy Schubert 	 * "The first object visited by callback is the main program."
4185732ac8SCy Schubert 	 */
4285732ac8SCy Schubert 	start_offset = info->dlpi_addr;
4385732ac8SCy Schubert 
4485732ac8SCy Schubert 	/*
4585732ac8SCy Schubert 	 * dl_iterate_phdr(3):
4685732ac8SCy Schubert 	 * "The dl_iterate_phdr() function walks through the list of an
4785732ac8SCy Schubert 	 *  application's shared objects and calls the function callback
4885732ac8SCy Schubert 	 *  once for each object, until either all shared objects have
4985732ac8SCy Schubert 	 *  been processed or callback returns a nonzero value."
5085732ac8SCy Schubert 	 */
5185732ac8SCy Schubert 	return 1;
5285732ac8SCy Schubert }
5385732ac8SCy Schubert 
54e28a4053SRui Paulo 
get_prg_fname(void)55e28a4053SRui Paulo static void get_prg_fname(void)
56e28a4053SRui Paulo {
57e28a4053SRui Paulo 	char exe[50], fname[512];
58e28a4053SRui Paulo 	int len;
59e28a4053SRui Paulo 	os_snprintf(exe, sizeof(exe) - 1, "/proc/%u/exe", getpid());
60e28a4053SRui Paulo 	len = readlink(exe, fname, sizeof(fname) - 1);
61e28a4053SRui Paulo 	if (len < 0 || len >= (int) sizeof(fname)) {
625b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "readlink: %s", strerror(errno));
63e28a4053SRui Paulo 		return;
64e28a4053SRui Paulo 	}
65e28a4053SRui Paulo 	fname[len] = '\0';
66e28a4053SRui Paulo 	prg_fname = strdup(fname);
67e28a4053SRui Paulo }
68e28a4053SRui Paulo 
69e28a4053SRui Paulo 
open_bfd(const char * fname)70e28a4053SRui Paulo static bfd * open_bfd(const char *fname)
71e28a4053SRui Paulo {
72e28a4053SRui Paulo 	bfd *abfd;
73e28a4053SRui Paulo 	char **matching;
74e28a4053SRui Paulo 
75e28a4053SRui Paulo 	abfd = bfd_openr(prg_fname, NULL);
76e28a4053SRui Paulo 	if (abfd == NULL) {
77e28a4053SRui Paulo 		wpa_printf(MSG_INFO, "bfd_openr failed");
78e28a4053SRui Paulo 		return NULL;
79e28a4053SRui Paulo 	}
80e28a4053SRui Paulo 
81e28a4053SRui Paulo 	if (bfd_check_format(abfd, bfd_archive)) {
82e28a4053SRui Paulo 		wpa_printf(MSG_INFO, "bfd_check_format failed");
83e28a4053SRui Paulo 		bfd_close(abfd);
84e28a4053SRui Paulo 		return NULL;
85e28a4053SRui Paulo 	}
86e28a4053SRui Paulo 
87e28a4053SRui Paulo 	if (!bfd_check_format_matches(abfd, bfd_object, &matching)) {
88e28a4053SRui Paulo 		wpa_printf(MSG_INFO, "bfd_check_format_matches failed");
89e28a4053SRui Paulo 		free(matching);
90e28a4053SRui Paulo 		bfd_close(abfd);
91e28a4053SRui Paulo 		return NULL;
92e28a4053SRui Paulo 	}
93e28a4053SRui Paulo 
94e28a4053SRui Paulo 	return abfd;
95e28a4053SRui Paulo }
96e28a4053SRui Paulo 
97e28a4053SRui Paulo 
read_syms(bfd * abfd)98e28a4053SRui Paulo static void read_syms(bfd *abfd)
99e28a4053SRui Paulo {
100e28a4053SRui Paulo 	long storage, symcount;
101e28a4053SRui Paulo 	bfd_boolean dynamic = FALSE;
102e28a4053SRui Paulo 
103e28a4053SRui Paulo 	if (syms)
104e28a4053SRui Paulo 		return;
105e28a4053SRui Paulo 
106e28a4053SRui Paulo 	if (!(bfd_get_file_flags(abfd) & HAS_SYMS)) {
107e28a4053SRui Paulo 		wpa_printf(MSG_INFO, "No symbols");
108e28a4053SRui Paulo 		return;
109e28a4053SRui Paulo 	}
110e28a4053SRui Paulo 
111e28a4053SRui Paulo 	storage = bfd_get_symtab_upper_bound(abfd);
112e28a4053SRui Paulo 	if (storage == 0) {
113e28a4053SRui Paulo 		storage = bfd_get_dynamic_symtab_upper_bound(abfd);
114e28a4053SRui Paulo 		dynamic = TRUE;
115e28a4053SRui Paulo 	}
116e28a4053SRui Paulo 	if (storage < 0) {
117e28a4053SRui Paulo 		wpa_printf(MSG_INFO, "Unknown symtab upper bound");
118e28a4053SRui Paulo 		return;
119e28a4053SRui Paulo 	}
120e28a4053SRui Paulo 
121e28a4053SRui Paulo 	syms = malloc(storage);
122e28a4053SRui Paulo 	if (syms == NULL) {
123e28a4053SRui Paulo 		wpa_printf(MSG_INFO, "Failed to allocate memory for symtab "
124e28a4053SRui Paulo 			   "(%ld bytes)", storage);
125e28a4053SRui Paulo 		return;
126e28a4053SRui Paulo 	}
127e28a4053SRui Paulo 	if (dynamic)
128e28a4053SRui Paulo 		symcount = bfd_canonicalize_dynamic_symtab(abfd, syms);
129e28a4053SRui Paulo 	else
130e28a4053SRui Paulo 		symcount = bfd_canonicalize_symtab(abfd, syms);
131e28a4053SRui Paulo 	if (symcount < 0) {
132e28a4053SRui Paulo 		wpa_printf(MSG_INFO, "Failed to canonicalize %ssymtab",
133e28a4053SRui Paulo 			   dynamic ? "dynamic " : "");
134e28a4053SRui Paulo 		free(syms);
135e28a4053SRui Paulo 		syms = NULL;
136e28a4053SRui Paulo 		return;
137e28a4053SRui Paulo 	}
138e28a4053SRui Paulo }
139e28a4053SRui Paulo 
140e28a4053SRui Paulo 
141e28a4053SRui Paulo struct bfd_data {
142e28a4053SRui Paulo 	bfd_vma pc;
143e28a4053SRui Paulo 	bfd_boolean found;
144e28a4053SRui Paulo 	const char *filename;
145e28a4053SRui Paulo 	const char *function;
146e28a4053SRui Paulo 	unsigned int line;
147e28a4053SRui Paulo };
148e28a4053SRui Paulo 
149c1d255d3SCy Schubert /*
150c1d255d3SCy Schubert  * binutils removed the bfd parameter and renamed things but
151c1d255d3SCy Schubert  * those were macros so we can detect their absence.
152c1d255d3SCy Schubert  * Cf. https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=commitdiff;h=fd3619828e94a24a92cddec42cbc0ab33352eeb4;hp=5dfda3562a69686c43aad4fb0269cc9d5ec010d5
153c1d255d3SCy Schubert  */
154c1d255d3SCy Schubert #ifndef bfd_get_section_vma
155c1d255d3SCy Schubert #define bfd_get_section_vma(bfd, section) bfd_section_vma(section)
156c1d255d3SCy Schubert #endif
157c1d255d3SCy Schubert #ifndef bfd_get_section_size
158c1d255d3SCy Schubert #define bfd_get_section_size bfd_section_size
159c1d255d3SCy Schubert #endif
160e28a4053SRui Paulo 
find_addr_sect(bfd * abfd,asection * section,void * obj)161e28a4053SRui Paulo static void find_addr_sect(bfd *abfd, asection *section, void *obj)
162e28a4053SRui Paulo {
163e28a4053SRui Paulo 	struct bfd_data *data = obj;
164e28a4053SRui Paulo 	bfd_vma vma;
165e28a4053SRui Paulo 	bfd_size_type size;
166e28a4053SRui Paulo 
167e28a4053SRui Paulo 	if (data->found)
168e28a4053SRui Paulo 		return;
169e28a4053SRui Paulo 
170e28a4053SRui Paulo 	if (!(bfd_get_section_vma(abfd, section)))
171e28a4053SRui Paulo 		return;
172e28a4053SRui Paulo 
173e28a4053SRui Paulo 	vma = bfd_get_section_vma(abfd, section);
174e28a4053SRui Paulo 	if (data->pc < vma)
175e28a4053SRui Paulo 		return;
176e28a4053SRui Paulo 
177e28a4053SRui Paulo 	size = bfd_get_section_size(section);
178e28a4053SRui Paulo 	if (data->pc >= vma + size)
179e28a4053SRui Paulo 		return;
180e28a4053SRui Paulo 
181e28a4053SRui Paulo 	data->found = bfd_find_nearest_line(abfd, section, syms,
182e28a4053SRui Paulo 					    data->pc - vma,
183e28a4053SRui Paulo 					    &data->filename,
184e28a4053SRui Paulo 					    &data->function,
185e28a4053SRui Paulo 					    &data->line);
186e28a4053SRui Paulo }
187e28a4053SRui Paulo 
188e28a4053SRui Paulo 
wpa_trace_bfd_addr(void * pc)189e28a4053SRui Paulo static void wpa_trace_bfd_addr(void *pc)
190e28a4053SRui Paulo {
191e28a4053SRui Paulo 	bfd *abfd = cached_abfd;
192e28a4053SRui Paulo 	struct bfd_data data;
193e28a4053SRui Paulo 	const char *name;
194e28a4053SRui Paulo 	char *aname = NULL;
195e28a4053SRui Paulo 	const char *filename;
196e28a4053SRui Paulo 
197e28a4053SRui Paulo 	if (abfd == NULL)
198e28a4053SRui Paulo 		return;
199e28a4053SRui Paulo 
200*a90b9d01SCy Schubert 	data.pc = (uintptr_t) ((u8 *) pc - start_offset);
201e28a4053SRui Paulo 	data.found = FALSE;
202e28a4053SRui Paulo 	bfd_map_over_sections(abfd, find_addr_sect, &data);
203e28a4053SRui Paulo 
204e28a4053SRui Paulo 	if (!data.found)
205e28a4053SRui Paulo 		return;
206e28a4053SRui Paulo 
207e28a4053SRui Paulo 	do {
208e28a4053SRui Paulo 		if (data.function)
209e28a4053SRui Paulo 			aname = bfd_demangle(abfd, data.function,
210e28a4053SRui Paulo 					     DMGL_ANSI | DMGL_PARAMS);
211e28a4053SRui Paulo 		name = aname ? aname : data.function;
212e28a4053SRui Paulo 		filename = data.filename;
213e28a4053SRui Paulo 		if (filename) {
214e28a4053SRui Paulo 			char *end = os_strrchr(filename, '/');
215e28a4053SRui Paulo 			int i = 0;
216e28a4053SRui Paulo 			while (*filename && *filename == prg_fname[i] &&
217e28a4053SRui Paulo 			       filename <= end) {
218e28a4053SRui Paulo 				filename++;
219e28a4053SRui Paulo 				i++;
220e28a4053SRui Paulo 			}
221e28a4053SRui Paulo 		}
222e28a4053SRui Paulo 		wpa_printf(MSG_INFO, "     %s() %s:%u",
223e28a4053SRui Paulo 			   name, filename, data.line);
224e28a4053SRui Paulo 		free(aname);
2255b9c547cSRui Paulo 		aname = NULL;
226e28a4053SRui Paulo 
227e28a4053SRui Paulo 		data.found = bfd_find_inliner_info(abfd, &data.filename,
228e28a4053SRui Paulo 						   &data.function, &data.line);
229e28a4053SRui Paulo 	} while (data.found);
230e28a4053SRui Paulo }
231e28a4053SRui Paulo 
232e28a4053SRui Paulo 
wpa_trace_bfd_addr2func(void * pc)233e28a4053SRui Paulo static const char * wpa_trace_bfd_addr2func(void *pc)
234e28a4053SRui Paulo {
235e28a4053SRui Paulo 	bfd *abfd = cached_abfd;
236e28a4053SRui Paulo 	struct bfd_data data;
237e28a4053SRui Paulo 
238e28a4053SRui Paulo 	if (abfd == NULL)
239e28a4053SRui Paulo 		return NULL;
240e28a4053SRui Paulo 
241*a90b9d01SCy Schubert 	data.pc = (uintptr_t) ((u8 *) pc - start_offset);
242e28a4053SRui Paulo 	data.found = FALSE;
243e28a4053SRui Paulo 	bfd_map_over_sections(abfd, find_addr_sect, &data);
244e28a4053SRui Paulo 
245e28a4053SRui Paulo 	if (!data.found)
246e28a4053SRui Paulo 		return NULL;
247e28a4053SRui Paulo 
248e28a4053SRui Paulo 	return data.function;
249e28a4053SRui Paulo }
250e28a4053SRui Paulo 
251e28a4053SRui Paulo 
wpa_trace_bfd_init(void)252e28a4053SRui Paulo static void wpa_trace_bfd_init(void)
253e28a4053SRui Paulo {
254e28a4053SRui Paulo 	if (!prg_fname) {
255e28a4053SRui Paulo 		get_prg_fname();
256e28a4053SRui Paulo 		if (!prg_fname)
257e28a4053SRui Paulo 			return;
258e28a4053SRui Paulo 	}
259e28a4053SRui Paulo 
260e28a4053SRui Paulo 	if (!cached_abfd) {
261e28a4053SRui Paulo 		cached_abfd = open_bfd(prg_fname);
262e28a4053SRui Paulo 		if (!cached_abfd) {
263e28a4053SRui Paulo 			wpa_printf(MSG_INFO, "Failed to open bfd");
264e28a4053SRui Paulo 			return;
265e28a4053SRui Paulo 		}
266e28a4053SRui Paulo 	}
267e28a4053SRui Paulo 
268e28a4053SRui Paulo 	read_syms(cached_abfd);
269e28a4053SRui Paulo 	if (!syms) {
270e28a4053SRui Paulo 		wpa_printf(MSG_INFO, "Failed to read symbols");
271e28a4053SRui Paulo 		return;
272e28a4053SRui Paulo 	}
27385732ac8SCy Schubert 
27485732ac8SCy Schubert 	if (!start_offset_looked_up) {
27585732ac8SCy Schubert 		dl_iterate_phdr(callback, NULL);
27685732ac8SCy Schubert 		start_offset_looked_up = 1;
27785732ac8SCy Schubert 	}
278e28a4053SRui Paulo }
279e28a4053SRui Paulo 
280e28a4053SRui Paulo 
wpa_trace_dump_funcname(const char * title,void * pc)281e28a4053SRui Paulo void wpa_trace_dump_funcname(const char *title, void *pc)
282e28a4053SRui Paulo {
283e28a4053SRui Paulo 	wpa_printf(MSG_INFO, "WPA_TRACE: %s: %p", title, pc);
284e28a4053SRui Paulo 	wpa_trace_bfd_init();
285e28a4053SRui Paulo 	wpa_trace_bfd_addr(pc);
286e28a4053SRui Paulo }
287e28a4053SRui Paulo 
2885b9c547cSRui Paulo 
wpa_trace_calling_func(const char * buf[],size_t len)2895b9c547cSRui Paulo size_t wpa_trace_calling_func(const char *buf[], size_t len)
2905b9c547cSRui Paulo {
2915b9c547cSRui Paulo 	bfd *abfd;
2925b9c547cSRui Paulo 	void *btrace_res[WPA_TRACE_LEN];
2935b9c547cSRui Paulo 	int i, btrace_num;
2945b9c547cSRui Paulo 	size_t pos = 0;
2955b9c547cSRui Paulo 
2965b9c547cSRui Paulo 	if (len == 0)
2975b9c547cSRui Paulo 		return 0;
2985b9c547cSRui Paulo 	if (len > WPA_TRACE_LEN)
2995b9c547cSRui Paulo 		len = WPA_TRACE_LEN;
3005b9c547cSRui Paulo 
3015b9c547cSRui Paulo 	wpa_trace_bfd_init();
3025b9c547cSRui Paulo 	abfd = cached_abfd;
3035b9c547cSRui Paulo 	if (!abfd)
3045b9c547cSRui Paulo 		return 0;
3055b9c547cSRui Paulo 
3065b9c547cSRui Paulo 	btrace_num = backtrace(btrace_res, len);
3075b9c547cSRui Paulo 	if (btrace_num < 1)
3085b9c547cSRui Paulo 		return 0;
3095b9c547cSRui Paulo 
3105b9c547cSRui Paulo 	for (i = 0; i < btrace_num; i++) {
3115b9c547cSRui Paulo 		struct bfd_data data;
3125b9c547cSRui Paulo 
313*a90b9d01SCy Schubert 		data.pc = (uintptr_t) ((u8 *) btrace_res[i] - start_offset);
3145b9c547cSRui Paulo 		data.found = FALSE;
3155b9c547cSRui Paulo 		bfd_map_over_sections(abfd, find_addr_sect, &data);
3165b9c547cSRui Paulo 
3175b9c547cSRui Paulo 		while (data.found) {
3185b9c547cSRui Paulo 			if (data.function &&
3195b9c547cSRui Paulo 			    (pos > 0 ||
3205b9c547cSRui Paulo 			     os_strcmp(data.function, __func__) != 0)) {
3215b9c547cSRui Paulo 				buf[pos++] = data.function;
3225b9c547cSRui Paulo 				if (pos == len)
3235b9c547cSRui Paulo 					return pos;
3245b9c547cSRui Paulo 			}
3255b9c547cSRui Paulo 
3265b9c547cSRui Paulo 			data.found = bfd_find_inliner_info(abfd, &data.filename,
3275b9c547cSRui Paulo 							   &data.function,
3285b9c547cSRui Paulo 							   &data.line);
3295b9c547cSRui Paulo 		}
3305b9c547cSRui Paulo 	}
3315b9c547cSRui Paulo 
3325b9c547cSRui Paulo 	return pos;
3335b9c547cSRui Paulo }
3345b9c547cSRui Paulo 
335e28a4053SRui Paulo #else /* WPA_TRACE_BFD */
336e28a4053SRui Paulo 
337e28a4053SRui Paulo #define wpa_trace_bfd_init() do { } while (0)
338e28a4053SRui Paulo #define wpa_trace_bfd_addr(pc) do { } while (0)
339e28a4053SRui Paulo #define wpa_trace_bfd_addr2func(pc) NULL
340e28a4053SRui Paulo 
341e28a4053SRui Paulo #endif /* WPA_TRACE_BFD */
342e28a4053SRui Paulo 
wpa_trace_dump_func(const char * title,void ** btrace,int btrace_num)343e28a4053SRui Paulo void wpa_trace_dump_func(const char *title, void **btrace, int btrace_num)
344e28a4053SRui Paulo {
345e28a4053SRui Paulo 	char **sym;
346e28a4053SRui Paulo 	int i;
347e28a4053SRui Paulo 	enum { TRACE_HEAD, TRACE_RELEVANT, TRACE_TAIL } state;
348e28a4053SRui Paulo 
349e28a4053SRui Paulo 	wpa_trace_bfd_init();
350e28a4053SRui Paulo 	wpa_printf(MSG_INFO, "WPA_TRACE: %s - START", title);
351e28a4053SRui Paulo 	sym = backtrace_symbols(btrace, btrace_num);
352e28a4053SRui Paulo 	state = TRACE_HEAD;
353e28a4053SRui Paulo 	for (i = 0; i < btrace_num; i++) {
354e28a4053SRui Paulo 		const char *func = wpa_trace_bfd_addr2func(btrace[i]);
355e28a4053SRui Paulo 		if (state == TRACE_HEAD && func &&
356e28a4053SRui Paulo 		    (os_strcmp(func, "wpa_trace_add_ref_func") == 0 ||
357e28a4053SRui Paulo 		     os_strcmp(func, "wpa_trace_check_ref") == 0 ||
358e28a4053SRui Paulo 		     os_strcmp(func, "wpa_trace_show") == 0))
359e28a4053SRui Paulo 			continue;
360e28a4053SRui Paulo 		if (state == TRACE_TAIL && sym && sym[i] &&
361e28a4053SRui Paulo 		    os_strstr(sym[i], "__libc_start_main"))
362e28a4053SRui Paulo 			break;
363e28a4053SRui Paulo 		if (state == TRACE_HEAD)
364e28a4053SRui Paulo 			state = TRACE_RELEVANT;
365e28a4053SRui Paulo 		if (sym)
366e28a4053SRui Paulo 			wpa_printf(MSG_INFO, "[%d]: %s", i, sym[i]);
367e28a4053SRui Paulo 		else
368e28a4053SRui Paulo 			wpa_printf(MSG_INFO, "[%d]: ?? [%p]", i, btrace[i]);
369e28a4053SRui Paulo 		wpa_trace_bfd_addr(btrace[i]);
370e28a4053SRui Paulo 		if (state == TRACE_RELEVANT && func &&
371e28a4053SRui Paulo 		    os_strcmp(func, "main") == 0)
372e28a4053SRui Paulo 			state = TRACE_TAIL;
373e28a4053SRui Paulo 	}
374e28a4053SRui Paulo 	free(sym);
375e28a4053SRui Paulo 	wpa_printf(MSG_INFO, "WPA_TRACE: %s - END", title);
376e28a4053SRui Paulo }
377e28a4053SRui Paulo 
378e28a4053SRui Paulo 
wpa_trace_show(const char * title)379e28a4053SRui Paulo void wpa_trace_show(const char *title)
380e28a4053SRui Paulo {
381e28a4053SRui Paulo 	struct info {
382e28a4053SRui Paulo 		WPA_TRACE_INFO
383e28a4053SRui Paulo 	} info;
384e28a4053SRui Paulo 	wpa_trace_record(&info);
385e28a4053SRui Paulo 	wpa_trace_dump(title, &info);
386e28a4053SRui Paulo }
387e28a4053SRui Paulo 
388e28a4053SRui Paulo 
wpa_trace_add_ref_func(struct wpa_trace_ref * ref,const void * addr)389e28a4053SRui Paulo void wpa_trace_add_ref_func(struct wpa_trace_ref *ref, const void *addr)
390e28a4053SRui Paulo {
391e28a4053SRui Paulo 	if (addr == NULL)
392e28a4053SRui Paulo 		return;
393e28a4053SRui Paulo 	ref->addr = addr;
394e28a4053SRui Paulo 	wpa_trace_record(ref);
395e28a4053SRui Paulo 	dl_list_add(&active_references, &ref->list);
396e28a4053SRui Paulo }
397e28a4053SRui Paulo 
398e28a4053SRui Paulo 
wpa_trace_check_ref(const void * addr)399e28a4053SRui Paulo void wpa_trace_check_ref(const void *addr)
400e28a4053SRui Paulo {
401e28a4053SRui Paulo 	struct wpa_trace_ref *ref;
402e28a4053SRui Paulo 	dl_list_for_each(ref, &active_references, struct wpa_trace_ref, list) {
403e28a4053SRui Paulo 		if (addr != ref->addr)
404e28a4053SRui Paulo 			continue;
405e28a4053SRui Paulo 		wpa_trace_show("Freeing referenced memory");
406e28a4053SRui Paulo 		wpa_trace_dump("Reference registration", ref);
407e28a4053SRui Paulo 		abort();
408e28a4053SRui Paulo 	}
409e28a4053SRui Paulo }
410e28a4053SRui Paulo 
411780fb4a2SCy Schubert 
wpa_trace_deinit(void)412780fb4a2SCy Schubert void wpa_trace_deinit(void)
413780fb4a2SCy Schubert {
414780fb4a2SCy Schubert #ifdef WPA_TRACE_BFD
415780fb4a2SCy Schubert 	free(syms);
416780fb4a2SCy Schubert 	syms = NULL;
417780fb4a2SCy Schubert #endif /* WPA_TRACE_BFD */
418780fb4a2SCy Schubert }
419780fb4a2SCy Schubert 
420e28a4053SRui Paulo #endif /* WPA_TRACE */
421