| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Asterisk -- An open source telephony toolkit. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 1999 - 2013, Digium, Inc. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Matt Jordan <mjordan@digium.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * See http://www.asterisk.org for more information about
 | 
					
						
							|  |  |  |  * the Asterisk project. Please do not directly contact | 
					
						
							|  |  |  |  * any of the maintainers of this project for assistance; | 
					
						
							|  |  |  |  * the project provides a web site, mailing lists and IRC | 
					
						
							|  |  |  |  * channels for your use. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software, distributed under the terms of | 
					
						
							|  |  |  |  * the GNU General Public License Version 2. See the LICENSE file | 
					
						
							|  |  |  |  * at the top of the source tree. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*! \file
 | 
					
						
							|  |  |  |  * \brief Asterisk backtrace generation | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This file provides backtrace generation utilities | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*** MODULEINFO
 | 
					
						
							|  |  |  | 	<support_level>core</support_level> | 
					
						
							|  |  |  |  ***/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Block automatic include of asterisk/lock.h to allow use of pthread_mutex | 
					
						
							|  |  |  |  * functions directly.  We don't need or want the lock.h overhead. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #define _ASTERISK_LOCK_H
 | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * The astmm ast_ memory management functions can cause ast_bt_get_symbols | 
					
						
							|  |  |  |  * to be invoked so we must not use them. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #define ASTMM_LIBC ASTMM_IGNORE
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "asterisk.h"
 | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | #include "asterisk/backtrace.h"
 | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * As stated above, the vector macros call the ast_ functions so | 
					
						
							|  |  |  |  * we need to remap those back to the libc ones. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #undef ast_free
 | 
					
						
							|  |  |  | #undef ast_calloc
 | 
					
						
							|  |  |  | #undef ast_malloc
 | 
					
						
							|  |  |  | #define ast_free(x) free(x)
 | 
					
						
							|  |  |  | #define ast_calloc(n, x) calloc(n, x)
 | 
					
						
							|  |  |  | #define ast_malloc(x) malloc(x)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "asterisk/vector.h"
 | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifdef HAVE_BKTR
 | 
					
						
							|  |  |  | #include <execinfo.h>
 | 
					
						
							|  |  |  | #if defined(HAVE_DLADDR) && defined(HAVE_BFD) && defined(BETTER_BACKTRACES)
 | 
					
						
							|  |  |  | #include <dlfcn.h>
 | 
					
						
							|  |  |  | #include <bfd.h>
 | 
					
						
							| 
									
										
										
										
											2020-03-16 12:11:11 +02:00
										 |  |  | #ifndef bfd_get_section_size
 | 
					
						
							|  |  |  | #define bfd_get_section_size(x) bfd_section_size(x)
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | #ifndef bfd_get_section_vma
 | 
					
						
							|  |  |  | #define bfd_get_section_vma(x, y)	bfd_section_vma(y)
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2020-04-01 11:00:14 +02:00
										 |  |  | #ifndef bfd_get_section_flags
 | 
					
						
							|  |  |  | #define bfd_get_section_flags(x, y) bfd_section_flags(y)
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | #include <pthread.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* simple definition of S_OR so we don't have include strings.h */ | 
					
						
							|  |  |  | #define S_OR(a, b) (a && a[0] != '\0') ? a : b
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | struct ast_bt *__ast_bt_create(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | 	struct ast_bt *bt = calloc(1, sizeof(*bt)); | 
					
						
							| 
									
										
										
										
											2013-08-23 18:07:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 	if (!bt) { | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	bt->alloced = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_bt_get_addresses(bt); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return bt; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int __ast_bt_get_addresses(struct ast_bt *bt) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	bt->num_frames = backtrace(bt->addresses, AST_MAX_BT_FRAMES); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void *__ast_bt_destroy(struct ast_bt *bt) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-08-23 18:07:40 +00:00
										 |  |  | 	if (bt && bt->alloced) { | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | 		free(bt); | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | #ifdef BETTER_BACKTRACES
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct bfd_data { | 
					
						
							|  |  |  | 	struct ast_vector_string *return_strings; | 
					
						
							|  |  |  | 	bfd_vma pc;            /* bfd.h */ | 
					
						
							|  |  |  | 	asymbol **syms;        /* bfd.h */ | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 	Dl_info dli;           /* dlfcn.h */ | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | 	const char *libname; | 
					
						
							|  |  |  | 	int dynamic; | 
					
						
							|  |  |  | 	int has_syms; | 
					
						
							|  |  |  | 	char *msg; | 
					
						
							|  |  |  | 	int found; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define MSG_BUFF_LEN 1024
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void process_section(bfd *bfdobj, asection *section, void *obj) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct bfd_data *data = obj; | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 	const char *file, *func; | 
					
						
							|  |  |  | 	unsigned int line; | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | 	bfd_vma offset; | 
					
						
							|  |  |  | 	bfd_vma vma; | 
					
						
							|  |  |  | 	bfd_size_type size; | 
					
						
							|  |  |  | 	bfd_boolean line_found = 0; | 
					
						
							|  |  |  | 	char *fn; | 
					
						
							|  |  |  | 	int inlined = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-19 12:39:08 -06:00
										 |  |  | 	offset = data->pc - (data->dynamic ? (bfd_vma)(uintptr_t) data->dli.dli_fbase : 0); | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (!(bfd_get_section_flags(bfdobj, section) & SEC_ALLOC)) { | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | 	vma = bfd_get_section_vma(bfdobj, section); | 
					
						
							|  |  |  | 	size = bfd_get_section_size(section); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (offset < vma || offset >= vma + size) { | 
					
						
							|  |  |  | 		/* Not in this section */ | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	line_found = bfd_find_nearest_line(bfdobj, section, data->syms, offset - vma, &file, | 
					
						
							|  |  |  | 		&func, &line); | 
					
						
							|  |  |  | 	if (!line_found) { | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * If we find a line, we will want to continue calling bfd_find_inliner_info | 
					
						
							|  |  |  | 	 * to capture any inlined functions that don't have their own stack frames. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	do { | 
					
						
							|  |  |  | 		data->found++; | 
					
						
							|  |  |  | 		/* file can possibly be null even with a success result from bfd_find_nearest_line */ | 
					
						
							|  |  |  | 		file = file ? file : ""; | 
					
						
							|  |  |  | 		fn = strrchr(file, '/'); | 
					
						
							| 
									
										
										
										
											2018-12-19 12:39:08 -06:00
										 |  |  | #define FMT_INLINED     "[%s] %s %s:%u %s()"
 | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | #define FMT_NOT_INLINED "[%p] %s %s:%u %s()"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		snprintf(data->msg, MSG_BUFF_LEN, inlined ? FMT_INLINED : FMT_NOT_INLINED, | 
					
						
							| 
									
										
										
										
											2018-12-19 12:39:08 -06:00
										 |  |  | 			inlined ? "inlined" : (char *)(uintptr_t) data->pc, | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | 			data->libname, | 
					
						
							|  |  |  | 			fn ? fn + 1 : file, | 
					
						
							|  |  |  | 			line, S_OR(func, "???")); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (AST_VECTOR_APPEND(data->return_strings, strdup(data->msg))) { | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		inlined++; | 
					
						
							|  |  |  | 		/* Let's see if there are any inlined functions */ | 
					
						
							|  |  |  | 	} while (bfd_find_inliner_info(bfdobj, &file, &func, &line)); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | struct ast_vector_string *__ast_bt_get_symbols(void **addresses, size_t num_frames) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_vector_string *return_strings; | 
					
						
							|  |  |  | 	int stackfr; | 
					
						
							|  |  |  | 	bfd *bfdobj; | 
					
						
							|  |  |  | 	long allocsize; | 
					
						
							|  |  |  | 	char msg[MSG_BUFF_LEN]; | 
					
						
							|  |  |  | 	static pthread_mutex_t bfd_mutex = PTHREAD_MUTEX_INITIALIZER; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return_strings = malloc(sizeof(struct ast_vector_string)); | 
					
						
							|  |  |  | 	if (!return_strings) { | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (AST_VECTOR_INIT(return_strings, num_frames)) { | 
					
						
							|  |  |  | 		free(return_strings); | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (stackfr = 0; stackfr < num_frames; stackfr++) { | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | 		int symbolcount; | 
					
						
							|  |  |  | 		struct bfd_data data = { | 
					
						
							|  |  |  | 			.return_strings = return_strings, | 
					
						
							|  |  |  | 			.msg = msg, | 
					
						
							| 
									
										
										
										
											2018-12-19 12:39:08 -06:00
										 |  |  | 			.pc = (bfd_vma)(uintptr_t) addresses[stackfr], | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | 			.found = 0, | 
					
						
							|  |  |  | 			.dynamic = 0, | 
					
						
							|  |  |  | 		}; | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		msg[0] = '\0'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-19 12:39:08 -06:00
										 |  |  | 		if (!dladdr((void *)(uintptr_t) data.pc, &data.dli)) { | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | 		data.libname = strrchr(data.dli.dli_fname, '/'); | 
					
						
							|  |  |  | 		if (!data.libname) { | 
					
						
							|  |  |  | 			data.libname = data.dli.dli_fname; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			data.libname++; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		pthread_mutex_lock(&bfd_mutex); | 
					
						
							|  |  |  | 		/* Using do while(0) here makes it easier to escape and clean up */ | 
					
						
							|  |  |  | 		do { | 
					
						
							|  |  |  | 			bfdobj = bfd_openr(data.dli.dli_fname, NULL); | 
					
						
							|  |  |  | 			if (!bfdobj) { | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/* bfd_check_format does more than check.  It HAS to be called */ | 
					
						
							|  |  |  | 			if (!bfd_check_format(bfdobj, bfd_object)) { | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | 			data.has_syms = !!(bfd_get_file_flags(bfdobj) & HAS_SYMS); | 
					
						
							|  |  |  | 			data.dynamic = !!(bfd_get_file_flags(bfdobj) & DYNAMIC); | 
					
						
							| 
									
										
										
										
											2013-08-23 18:07:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | 			if (!data.has_syms) { | 
					
						
							|  |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | 			allocsize = data.dynamic ? | 
					
						
							|  |  |  | 				bfd_get_dynamic_symtab_upper_bound(bfdobj) : bfd_get_symtab_upper_bound(bfdobj); | 
					
						
							|  |  |  | 			if (allocsize < 0) { | 
					
						
							|  |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | 			data.syms = malloc(allocsize); | 
					
						
							|  |  |  | 			if (!data.syms) { | 
					
						
							|  |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			symbolcount = data.dynamic ? | 
					
						
							|  |  |  | 				bfd_canonicalize_dynamic_symtab(bfdobj, data.syms) : bfd_canonicalize_symtab(bfdobj, data.syms); | 
					
						
							|  |  |  | 			if (symbolcount < 0) { | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			bfd_map_over_sections(bfdobj, process_section, &data); | 
					
						
							|  |  |  | 		} while(0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 		if (bfdobj) { | 
					
						
							|  |  |  | 			bfd_close(bfdobj); | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | 			free(data.syms); | 
					
						
							|  |  |  | 			data.syms = NULL; | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | 		pthread_mutex_unlock(&bfd_mutex); | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/* Default output, if we cannot find the information within BFD */ | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | 		if (!data.found) { | 
					
						
							|  |  |  | 			snprintf(msg, sizeof(msg), "%s %s()", | 
					
						
							|  |  |  | 				data.libname, | 
					
						
							|  |  |  | 				S_OR(data.dli.dli_sname, "<unknown>")); | 
					
						
							|  |  |  | 			AST_VECTOR_APPEND(return_strings, strdup(msg)); | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | 	return return_strings; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2013-08-23 18:07:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | #else
 | 
					
						
							|  |  |  | struct ast_vector_string *__ast_bt_get_symbols(void **addresses, size_t num_frames) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char **strings; | 
					
						
							|  |  |  | 	struct ast_vector_string *return_strings; | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return_strings = malloc(sizeof(struct ast_vector_string)); | 
					
						
							|  |  |  | 	if (!return_strings) { | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (AST_VECTOR_INIT(return_strings, num_frames)) { | 
					
						
							|  |  |  | 		free(return_strings); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | 	strings = backtrace_symbols(addresses, num_frames); | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 	if (strings) { | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | 		for (i = 0; i < num_frames; i++) { | 
					
						
							|  |  |  | 			AST_VECTOR_APPEND(return_strings, strdup(strings[i])); | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | 		free(strings); | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-08-23 18:07:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | 	return return_strings; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif /* BETTER_BACKTRACES */
 | 
					
						
							| 
									
										
										
										
											2013-08-23 18:07:40 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-08 08:53:44 -07:00
										 |  |  | void __ast_bt_free_symbols(struct ast_vector_string *symbols) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	AST_VECTOR_CALLBACK_VOID(symbols, free); | 
					
						
							|  |  |  | 	AST_VECTOR_PTR_FREE(symbols); | 
					
						
							| 
									
										
										
										
											2013-06-08 22:09:07 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif /* HAVE_BKTR */
 |