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 static char umem_error_buffer[ERR_SIZE] = ""; 53 static uint_t umem_error_begin = 0; 54 static 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