2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A#pragma ident "%Z%%M% %I% %E% SMI"
2N/A
2N/A#include <unistd.h>
2N/A#include <dlfcn.h>
2N/A#include <signal.h>
2N/A#include <stdarg.h>
2N/A#include <stdio.h>
2N/A#include <string.h>
2N/A
2N/A#include <sys/machelf.h>
2N/A
2N/A#include <umem_impl.h>
2N/A#include "misc.h"
2N/A
2N/A#define UMEM_ERRFD 2 /* goes to standard error */
2N/A#define UMEM_MAX_ERROR_SIZE 4096 /* error messages are truncated to this */
2N/A
2N/A/*
2N/A * This is a circular buffer for holding error messages.
2N/A * umem_error_enter appends to the buffer, adding "..." to the beginning
2N/A * if data has been lost.
2N/A */
2N/A
2N/A#define ERR_SIZE 8192 /* must be a power of 2 */
2N/A
2N/Astatic mutex_t umem_error_lock = DEFAULTMUTEX;
2N/A
2N/Astatic char umem_error_buffer[ERR_SIZE] = "";
2N/Astatic uint_t umem_error_begin = 0;
2N/Astatic uint_t umem_error_end = 0;
2N/A
2N/A#define WRITE_AND_INC(var, value) { \
2N/A umem_error_buffer[(var)++] = (value); \
2N/A var = P2PHASE((var), ERR_SIZE); \
2N/A}
2N/A
2N/Astatic void
2N/Aumem_log_enter(const char *error_str)
2N/A{
2N/A int looped;
2N/A char c;
2N/A
2N/A looped = 0;
2N/A
2N/A (void) mutex_lock(&umem_error_lock);
2N/A
2N/A while ((c = *error_str++) != '\0') {
2N/A WRITE_AND_INC(umem_error_end, c);
2N/A if (umem_error_end == umem_error_begin)
2N/A looped = 1;
2N/A }
2N/A
2N/A umem_error_buffer[umem_error_end] = 0;
2N/A
2N/A if (looped) {
2N/A uint_t idx;
2N/A umem_error_begin = P2PHASE(umem_error_end + 1, ERR_SIZE);
2N/A
2N/A idx = umem_error_begin;
2N/A WRITE_AND_INC(idx, '.');
2N/A WRITE_AND_INC(idx, '.');
2N/A WRITE_AND_INC(idx, '.');
2N/A }
2N/A
2N/A (void) mutex_unlock(&umem_error_lock);
2N/A}
2N/A
2N/Avoid
2N/Aumem_error_enter(const char *error_str)
2N/A{
2N/A#ifndef UMEM_STANDALONE
2N/A if (umem_output && !issetugid())
2N/A (void) write(UMEM_ERRFD, error_str, strlen(error_str));
2N/A#endif
2N/A
2N/A umem_log_enter(error_str);
2N/A}
2N/A
2N/Aint
2N/Ahighbit(ulong_t i)
2N/A{
2N/A register int h = 1;
2N/A
2N/A if (i == 0)
2N/A return (0);
2N/A#ifdef _LP64
2N/A if (i & 0xffffffff00000000ul) {
2N/A h += 32; i >>= 32;
2N/A }
2N/A#endif
2N/A if (i & 0xffff0000) {
2N/A h += 16; i >>= 16;
2N/A }
2N/A if (i & 0xff00) {
2N/A h += 8; i >>= 8;
2N/A }
2N/A if (i & 0xf0) {
2N/A h += 4; i >>= 4;
2N/A }
2N/A if (i & 0xc) {
2N/A h += 2; i >>= 2;
2N/A }
2N/A if (i & 0x2) {
2N/A h += 1;
2N/A }
2N/A return (h);
2N/A}
2N/A
2N/Aint
2N/Alowbit(ulong_t i)
2N/A{
2N/A register int h = 1;
2N/A
2N/A if (i == 0)
2N/A return (0);
2N/A#ifdef _LP64
2N/A if (!(i & 0xffffffff)) {
2N/A h += 32; i >>= 32;
2N/A }
2N/A#endif
2N/A if (!(i & 0xffff)) {
2N/A h += 16; i >>= 16;
2N/A }
2N/A if (!(i & 0xff)) {
2N/A h += 8; i >>= 8;
2N/A }
2N/A if (!(i & 0xf)) {
2N/A h += 4; i >>= 4;
2N/A }
2N/A if (!(i & 0x3)) {
2N/A h += 2; i >>= 2;
2N/A }
2N/A if (!(i & 0x1)) {
2N/A h += 1;
2N/A }
2N/A return (h);
2N/A}
2N/A
2N/Avoid
2N/Ahrt2ts(hrtime_t hrt, timestruc_t *tsp)
2N/A{
2N/A tsp->tv_sec = hrt / NANOSEC;
2N/A tsp->tv_nsec = hrt % NANOSEC;
2N/A}
2N/A
2N/Avoid
2N/Alog_message(const char *format, ...)
2N/A{
2N/A char buf[UMEM_MAX_ERROR_SIZE] = "";
2N/A
2N/A va_list va;
2N/A
2N/A va_start(va, format);
2N/A (void) vsnprintf(buf, UMEM_MAX_ERROR_SIZE-1, format, va);
2N/A va_end(va);
2N/A
2N/A#ifndef UMEM_STANDALONE
2N/A if (umem_output > 1)
2N/A (void) write(UMEM_ERRFD, buf, strlen(buf));
2N/A#endif
2N/A
2N/A umem_log_enter(buf);
2N/A}
2N/A
2N/A#ifndef UMEM_STANDALONE
2N/Avoid
2N/Adebug_printf(const char *format, ...)
2N/A{
2N/A char buf[UMEM_MAX_ERROR_SIZE] = "";
2N/A
2N/A va_list va;
2N/A
2N/A va_start(va, format);
2N/A (void) vsnprintf(buf, UMEM_MAX_ERROR_SIZE-1, format, va);
2N/A va_end(va);
2N/A
2N/A (void) write(UMEM_ERRFD, buf, strlen(buf));
2N/A}
2N/A#endif
2N/A
2N/Avoid
2N/Aumem_vprintf(const char *format, va_list va)
2N/A{
2N/A char buf[UMEM_MAX_ERROR_SIZE] = "";
2N/A
2N/A (void) vsnprintf(buf, UMEM_MAX_ERROR_SIZE-1, format, va);
2N/A
2N/A umem_error_enter(buf);
2N/A}
2N/A
2N/Avoid
2N/Aumem_printf(const char *format, ...)
2N/A{
2N/A va_list va;
2N/A
2N/A va_start(va, format);
2N/A umem_vprintf(format, va);
2N/A va_end(va);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Avoid
2N/Aumem_printf_warn(void *ignored, const char *format, ...)
2N/A{
2N/A va_list va;
2N/A
2N/A va_start(va, format);
2N/A umem_vprintf(format, va);
2N/A va_end(va);
2N/A}
2N/A
2N/A/*
2N/A * print_sym tries to print out the symbol and offset of a pointer
2N/A */
2N/Aint
2N/Aprint_sym(void *pointer)
2N/A{
2N/A int result;
2N/A Dl_info sym_info;
2N/A
2N/A uintptr_t end = NULL;
2N/A
2N/A Sym *ext_info = NULL;
2N/A
2N/A result = dladdr1(pointer, &sym_info, (void **)&ext_info,
2N/A RTLD_DL_SYMENT);
2N/A
2N/A if (result != 0) {
2N/A const char *endpath;
2N/A
2N/A end = (uintptr_t)sym_info.dli_saddr + ext_info->st_size;
2N/A
2N/A endpath = strrchr(sym_info.dli_fname, '/');
2N/A if (endpath)
2N/A endpath++;
2N/A else
2N/A endpath = sym_info.dli_fname;
2N/A umem_printf("%s'", endpath);
2N/A }
2N/A
2N/A if (result == 0 || (uintptr_t)pointer > end) {
2N/A umem_printf("?? (0x%p)", pointer);
2N/A return (0);
2N/A } else {
2N/A umem_printf("%s+0x%p", sym_info.dli_sname,
2N/A (char *)pointer - (char *)sym_info.dli_saddr);
2N/A return (1);
2N/A }
2N/A}