diff options
Diffstat (limited to 'zfs/lib/libumem/misc.c')
-rw-r--r-- | zfs/lib/libumem/misc.c | 298 |
1 files changed, 298 insertions, 0 deletions
diff --git a/zfs/lib/libumem/misc.c b/zfs/lib/libumem/misc.c new file mode 100644 index 000000000..aa4d63ff0 --- /dev/null +++ b/zfs/lib/libumem/misc.c @@ -0,0 +1,298 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +/* + * Portions Copyright 2006 OmniTI, Inc. + */ + +/* #pragma ident "@(#)misc.c 1.6 05/06/08 SMI" */ + +#define _BUILDING_UMEM_MISC_C +#include "config.h" +/* #include "mtlib.h" */ +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#if HAVE_DLFCN_H +#include <dlfcn.h> +#endif +#include <signal.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + +#if HAVE_SYS_MACHELF_H +#include <sys/machelf.h> +#endif + +#include <umem_impl.h> +#include "misc.h" + +#ifdef ECELERITY +#include "util.h" +#endif + +#define UMEM_ERRFD 2 /* goes to standard error */ +#define UMEM_MAX_ERROR_SIZE 4096 /* error messages are truncated to this */ + +/* + * This is a circular buffer for holding error messages. + * umem_error_enter appends to the buffer, adding "..." to the beginning + * if data has been lost. + */ + +#define ERR_SIZE 8192 /* must be a power of 2 */ + +static mutex_t umem_error_lock = DEFAULTMUTEX; + +static char umem_error_buffer[ERR_SIZE] = ""; +static uint_t umem_error_begin = 0; +static uint_t umem_error_end = 0; + +#define WRITE_AND_INC(var, value) { \ + umem_error_buffer[(var)++] = (value); \ + var = P2PHASE((var), ERR_SIZE); \ +} + +static void +umem_log_enter(const char *error_str, int serious) +{ + int looped; + char c; + + looped = 0; +#ifdef ECELERITY + mem_printf(serious ? DCRITICAL : DINFO, "umem: %s", error_str); +#endif + + (void) mutex_lock(&umem_error_lock); + + while ((c = *error_str++) != '\0') { + WRITE_AND_INC(umem_error_end, c); + if (umem_error_end == umem_error_begin) + looped = 1; + } + + umem_error_buffer[umem_error_end] = 0; + + if (looped) { + uint_t idx; + umem_error_begin = P2PHASE(umem_error_end + 1, ERR_SIZE); + + idx = umem_error_begin; + WRITE_AND_INC(idx, '.'); + WRITE_AND_INC(idx, '.'); + WRITE_AND_INC(idx, '.'); + } + + (void) mutex_unlock(&umem_error_lock); +} + +void +umem_error_enter(const char *error_str) +{ +#ifndef UMEM_STANDALONE + if (umem_output && !issetugid()) + (void) write(UMEM_ERRFD, error_str, strlen(error_str)); +#endif + + umem_log_enter(error_str, 1); +} + +int +highbit(ulong_t i) +{ + register int h = 1; + + if (i == 0) + return (0); +#ifdef _LP64 + if (i & 0xffffffff00000000ul) { + h += 32; i >>= 32; + } +#endif + if (i & 0xffff0000) { + h += 16; i >>= 16; + } + if (i & 0xff00) { + h += 8; i >>= 8; + } + if (i & 0xf0) { + h += 4; i >>= 4; + } + if (i & 0xc) { + h += 2; i >>= 2; + } + if (i & 0x2) { + h += 1; + } + return (h); +} + +int +lowbit(ulong_t i) +{ + register int h = 1; + + if (i == 0) + return (0); +#ifdef _LP64 + if (!(i & 0xffffffff)) { + h += 32; i >>= 32; + } +#endif + if (!(i & 0xffff)) { + h += 16; i >>= 16; + } + if (!(i & 0xff)) { + h += 8; i >>= 8; + } + if (!(i & 0xf)) { + h += 4; i >>= 4; + } + if (!(i & 0x3)) { + h += 2; i >>= 2; + } + if (!(i & 0x1)) { + h += 1; + } + return (h); +} + +void +hrt2ts(hrtime_t hrt, timestruc_t *tsp) +{ + tsp->tv_sec = hrt / NANOSEC; + tsp->tv_nsec = hrt % NANOSEC; +} + +void +log_message(const char *format, ...) +{ + char buf[UMEM_MAX_ERROR_SIZE] = ""; + + va_list va; + + va_start(va, format); + (void) vsnprintf(buf, UMEM_MAX_ERROR_SIZE-1, format, va); + va_end(va); + +#ifndef UMEM_STANDALONE + if (umem_output > 1) + (void) write(UMEM_ERRFD, buf, strlen(buf)); +#endif + + umem_log_enter(buf, 0); +} + +#ifndef UMEM_STANDALONE +void +debug_printf(const char *format, ...) +{ + char buf[UMEM_MAX_ERROR_SIZE] = ""; + + va_list va; + + va_start(va, format); + (void) vsnprintf(buf, UMEM_MAX_ERROR_SIZE-1, format, va); + va_end(va); + + (void) write(UMEM_ERRFD, buf, strlen(buf)); +} +#endif + +void +umem_vprintf(const char *format, va_list va) +{ + char buf[UMEM_MAX_ERROR_SIZE] = ""; + + (void) vsnprintf(buf, UMEM_MAX_ERROR_SIZE-1, format, va); + + umem_error_enter(buf); +} + +void +umem_printf(const char *format, ...) +{ + va_list va; + + va_start(va, format); + umem_vprintf(format, va); + va_end(va); +} + +/*ARGSUSED*/ +void +umem_printf_warn(void *ignored, const char *format, ...) +{ + va_list va; + + va_start(va, format); + umem_vprintf(format, va); + va_end(va); +} + +/* + * print_sym tries to print out the symbol and offset of a pointer + */ +int +print_sym(void *pointer) +{ +#if HAVE_SYS_MACHELF_H + int result; + Dl_info sym_info; + + uintptr_t end = NULL; + + Sym *ext_info = NULL; + + result = dladdr1(pointer, &sym_info, (void **)&ext_info, + RTLD_DL_SYMENT); + + if (result != 0) { + const char *endpath; + + end = (uintptr_t)sym_info.dli_saddr + ext_info->st_size; + + endpath = strrchr(sym_info.dli_fname, '/'); + if (endpath) + endpath++; + else + endpath = sym_info.dli_fname; + umem_printf("%s'", endpath); + } + + if (result == 0 || (uintptr_t)pointer > end) { + umem_printf("?? (0x%p)", pointer); + return (0); + } else { + umem_printf("%s+0x%p", sym_info.dli_sname, + (char *)pointer - (char *)sym_info.dli_saddr); + return (1); + } +#else + return 0; +#endif +} |