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