xref: /illumos-gate/usr/src/lib/libumem/common/misc.c (revision 65bac82b14db6446c8bfb4ddb4c2faee8feddc58)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <unistd.h>
28 #include <dlfcn.h>
29 #include <signal.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <string.h>
33 
34 #include <sys/machelf.h>
35 
36 #include <umem_impl.h>
37 #include "misc.h"
38 
39 #define	UMEM_ERRFD	2	/* goes to standard error */
40 #define	UMEM_MAX_ERROR_SIZE 4096 /* error messages are truncated to this */
41 
42 /*
43  * This is a circular buffer for holding error messages.
44  * umem_error_enter appends to the buffer, adding "..." to the beginning
45  * if data has been lost.
46  */
47 
48 #define	ERR_SIZE 8192		/* must be a power of 2 */
49 
50 static mutex_t umem_error_lock = DEFAULTMUTEX;
51 
52 char umem_error_buffer[ERR_SIZE] = "";
53 uint_t umem_error_begin = 0;
54 uint_t umem_error_end = 0;
55 
56 #define	WRITE_AND_INC(var, value) { \
57 	umem_error_buffer[(var)++] = (value); \
58 	var = P2PHASE((var), ERR_SIZE); \
59 }
60 
61 static void
62 umem_log_enter(const char *error_str)
63 {
64 	int looped;
65 	char c;
66 
67 	looped = 0;
68 
69 	(void) mutex_lock(&umem_error_lock);
70 
71 	while ((c = *error_str++) != '\0') {
72 		WRITE_AND_INC(umem_error_end, c);
73 		if (umem_error_end == umem_error_begin)
74 			looped = 1;
75 	}
76 
77 	umem_error_buffer[umem_error_end] = 0;
78 
79 	if (looped) {
80 		uint_t idx;
81 		umem_error_begin = P2PHASE(umem_error_end + 1, ERR_SIZE);
82 
83 		idx = umem_error_begin;
84 		WRITE_AND_INC(idx, '.');
85 		WRITE_AND_INC(idx, '.');
86 		WRITE_AND_INC(idx, '.');
87 	}
88 
89 	(void) mutex_unlock(&umem_error_lock);
90 }
91 
92 void
93 umem_error_enter(const char *error_str)
94 {
95 #ifndef UMEM_STANDALONE
96 	if (umem_output && !issetugid())
97 		(void) write(UMEM_ERRFD, error_str, strlen(error_str));
98 #endif
99 
100 	umem_log_enter(error_str);
101 }
102 
103 int
104 highbit(ulong_t i)
105 {
106 	register int h = 1;
107 
108 	if (i == 0)
109 		return (0);
110 #ifdef _LP64
111 	if (i & 0xffffffff00000000ul) {
112 		h += 32; i >>= 32;
113 	}
114 #endif
115 	if (i & 0xffff0000) {
116 		h += 16; i >>= 16;
117 	}
118 	if (i & 0xff00) {
119 		h += 8; i >>= 8;
120 	}
121 	if (i & 0xf0) {
122 		h += 4; i >>= 4;
123 	}
124 	if (i & 0xc) {
125 		h += 2; i >>= 2;
126 	}
127 	if (i & 0x2) {
128 		h += 1;
129 	}
130 	return (h);
131 }
132 
133 int
134 lowbit(ulong_t i)
135 {
136 	register int h = 1;
137 
138 	if (i == 0)
139 		return (0);
140 #ifdef _LP64
141 	if (!(i & 0xffffffff)) {
142 		h += 32; i >>= 32;
143 	}
144 #endif
145 	if (!(i & 0xffff)) {
146 		h += 16; i >>= 16;
147 	}
148 	if (!(i & 0xff)) {
149 		h += 8; i >>= 8;
150 	}
151 	if (!(i & 0xf)) {
152 		h += 4; i >>= 4;
153 	}
154 	if (!(i & 0x3)) {
155 		h += 2; i >>= 2;
156 	}
157 	if (!(i & 0x1)) {
158 		h += 1;
159 	}
160 	return (h);
161 }
162 
163 void
164 hrt2ts(hrtime_t hrt, timestruc_t *tsp)
165 {
166 	tsp->tv_sec = hrt / NANOSEC;
167 	tsp->tv_nsec = hrt % NANOSEC;
168 }
169 
170 void
171 log_message(const char *format, ...)
172 {
173 	char buf[UMEM_MAX_ERROR_SIZE] = "";
174 
175 	va_list va;
176 
177 	va_start(va, format);
178 	(void) vsnprintf(buf, UMEM_MAX_ERROR_SIZE-1, format, va);
179 	va_end(va);
180 
181 #ifndef UMEM_STANDALONE
182 	if (umem_output > 1)
183 		(void) write(UMEM_ERRFD, buf, strlen(buf));
184 #endif
185 
186 	umem_log_enter(buf);
187 }
188 
189 #ifndef UMEM_STANDALONE
190 void
191 debug_printf(const char *format, ...)
192 {
193 	char buf[UMEM_MAX_ERROR_SIZE] = "";
194 
195 	va_list va;
196 
197 	va_start(va, format);
198 	(void) vsnprintf(buf, UMEM_MAX_ERROR_SIZE-1, format, va);
199 	va_end(va);
200 
201 	(void) write(UMEM_ERRFD, buf, strlen(buf));
202 }
203 #endif
204 
205 void
206 umem_vprintf(const char *format, va_list va)
207 {
208 	char buf[UMEM_MAX_ERROR_SIZE] = "";
209 
210 	(void) vsnprintf(buf, UMEM_MAX_ERROR_SIZE-1, format, va);
211 
212 	umem_error_enter(buf);
213 }
214 
215 void
216 umem_printf(const char *format, ...)
217 {
218 	va_list va;
219 
220 	va_start(va, format);
221 	umem_vprintf(format, va);
222 	va_end(va);
223 }
224 
225 /*ARGSUSED*/
226 void
227 umem_printf_warn(void *ignored, const char *format, ...)
228 {
229 	va_list va;
230 
231 	va_start(va, format);
232 	umem_vprintf(format, va);
233 	va_end(va);
234 }
235 
236 /*
237  * print_sym tries to print out the symbol and offset of a pointer
238  */
239 int
240 print_sym(void *pointer)
241 {
242 	int result;
243 	Dl_info sym_info;
244 
245 	uintptr_t end = (uintptr_t)NULL;
246 
247 	Sym *ext_info = NULL;
248 
249 	result = dladdr1(pointer, &sym_info, (void **)&ext_info,
250 	    RTLD_DL_SYMENT);
251 
252 	if (result != 0) {
253 		const char *endpath;
254 
255 		end = (uintptr_t)sym_info.dli_saddr + ext_info->st_size;
256 
257 		endpath = strrchr(sym_info.dli_fname, '/');
258 		if (endpath)
259 			endpath++;
260 		else
261 			endpath = sym_info.dli_fname;
262 		umem_printf("%s'", endpath);
263 	}
264 
265 	if (result == 0 || (uintptr_t)pointer > end) {
266 		umem_printf("?? (0x%p)", pointer);
267 		return (0);
268 	} else {
269 		umem_printf("%s+0x%p", sym_info.dli_sname,
270 		    (char *)pointer - (char *)sym_info.dli_saddr);
271 		return (1);
272 	}
273 }
274