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