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 52static mutex_t umem_error_lock = DEFAULTMUTEX; 53 54static char umem_error_buffer[ERR_SIZE] = ""; 55static uint_t umem_error_begin = 0; 56static 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 63static void 64umem_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 94void 95umem_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 105int 106highbit(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 135int 136lowbit(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 165void 166hrt2ts(hrtime_t hrt, timestruc_t *tsp) 167{ 168 tsp->tv_sec = hrt / NANOSEC; 169 tsp->tv_nsec = hrt % NANOSEC; 170} 171 172void 173log_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 192void 193debug_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 207void 208umem_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 217void 218umem_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*/ 228void 229umem_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 */ 241int 242print_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