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