1 /* Write formatted list with names for addresses in backtrace to a file.
2    Copyright (C) 1998, 2000, 2003, 2005 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
5 
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10 
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15 
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; see the file COPYING.LIB.  If
18    not, see <http://www.gnu.org/licenses/>.
19 
20    Based on glibc/sysdeps/generic/elf/backtracesymsfd.c
21 
22    Copyright (C) 2010 STMicroelectronics Ltd
23    Author(s): Carmelo Amoroso <carmelo.amoroso@st.com>
24    * Modified to work with uClibc
25      - updated headers inclusion
26      - updated formatting and style
27      - updated to use dladdr from libdl
28      - updated to use snprintf instead of _itoa_word */
29 
30 #include <execinfo.h>
31 #include <string.h>
32 #include <sys/uio.h>
33 #include <dlfcn.h>
34 #include <stdio.h>
35 #include <link.h>	/* required for __ELF_NATIVE_CLASS */
36 
37 #if __ELF_NATIVE_CLASS == 32
38 # define WORD_WIDTH 8
39 #else
40 /* We assyme 64bits.  */
41 # define WORD_WIDTH 16
42 #endif
43 
44 #define BUF_SIZE (WORD_WIDTH + 1)
45 
backtrace_symbols_fd(void * const * array,int size,int fd)46 void backtrace_symbols_fd (void *const *array, int size, int fd)
47 {
48 	struct iovec iov[9];
49 	int cnt;
50 
51 	for (cnt = 0; cnt < size; ++cnt) {
52 		char buf[BUF_SIZE];
53 		Dl_info info;
54 		size_t last = 0;
55 		size_t len = 0;
56 
57 		memset(buf, 0, sizeof(buf));
58 		if (dladdr (array[cnt], &info)
59 			&& info.dli_fname && info.dli_fname[0] != '\0')	{
60 			/* Name of the file.  */
61 			iov[0].iov_base = (void *) info.dli_fname;
62 			iov[0].iov_len = strlen (info.dli_fname);
63 			last = 1;
64 
65 			/* Symbol name.  */
66 			if (info.dli_sname != NULL) {
67 				char buf2[BUF_SIZE];
68 				memset(buf2, 0, sizeof(buf2));
69 				size_t diff;
70 
71 				iov[1].iov_base = (void *) "(";
72 				iov[1].iov_len = 1;
73 				iov[2].iov_base = (void *) info.dli_sname;
74 				iov[2].iov_len = strlen (info.dli_sname);
75 
76 				if (array[cnt] >= (void *) info.dli_saddr) {
77 					iov[3].iov_base = (void *) "+0x";
78 					diff = array[cnt] - info.dli_saddr;
79 				} else {
80 					iov[3].iov_base = (void *) "-0x";
81 					diff = info.dli_saddr - array[cnt];
82 				}
83 
84 				iov[3].iov_len = 3;
85 
86 				/* convert diff to a string in hex format */
87 				len = snprintf(buf2, sizeof(buf2), "%lx", (unsigned long) diff);
88 				iov[4].iov_base = buf2;
89 				iov[4].iov_len = len;
90 
91 				iov[5].iov_base = (void *) ")";
92 				iov[5].iov_len = 1;
93 
94 				last = 6;
95 			}
96 		}
97 
98 		iov[last].iov_base = (void *) "[0x";
99 		iov[last].iov_len = 3;
100 		++last;
101 
102 		/* convert array[cnt] to a string in hex format */
103 		len = snprintf(buf, sizeof(buf), "%lx", (unsigned long) array[cnt]);
104 		iov[last].iov_base = buf;
105 		iov[last].iov_len = len;
106 
107 		++last;
108 
109 		iov[last].iov_base = (void *) "]\n";
110 		iov[last].iov_len = 2;
111 		++last;
112 
113 		writev (fd, iov, last);
114 	}
115 }
116