Home | History | Annotate | Download | only in dis
      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 2006 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 <dlfcn.h>
     30 #include <stdarg.h>
     31 #include <stdio.h>
     32 #include <stdlib.h>
     33 #include <demangle.h>
     34 
     35 #include "dis_util.h"
     36 
     37 int g_error;	/* global process exit status, set when warn() is called */
     38 
     39 /*
     40  * Fatal error.  Print out the error with a leading "dis: ", and then exit the
     41  * program.
     42  */
     43 void
     44 die(const char *fmt, ...)
     45 {
     46 	va_list ap;
     47 
     48 	(void) fprintf(stderr, "dis: fatal: ");
     49 
     50 	va_start(ap, fmt);
     51 	(void) vfprintf(stderr, fmt, ap);
     52 	va_end(ap);
     53 
     54 	(void) fprintf(stderr, "\n");
     55 
     56 	exit(1);
     57 }
     58 
     59 /*
     60  * Non-fatal error.  Print out the error with a leading "dis: ", set the global
     61  * error flag, and return.
     62  */
     63 void
     64 warn(const char *fmt, ...)
     65 {
     66 	va_list ap;
     67 
     68 	(void) fprintf(stderr, "dis: warning: ");
     69 
     70 	va_start(ap, fmt);
     71 	(void) vfprintf(stderr, fmt, ap);
     72 	va_end(ap);
     73 
     74 	(void) fprintf(stderr, "\n");
     75 
     76 	g_error = 1;
     77 }
     78 
     79 /*
     80  * Convenience wrapper around malloc() to cleanly exit if any allocation fails.
     81  */
     82 void *
     83 safe_malloc(size_t size)
     84 {
     85 	void *ret;
     86 
     87 	if ((ret = calloc(1, size)) == NULL)
     88 		die("Out of memory");
     89 
     90 	return (ret);
     91 }
     92 
     93 
     94 /*
     95  * Generic interface to demangle C++ names.  Calls cplus_demangle to do the
     96  * necessary translation.  If the translation fails, the argument is returned
     97  * unchanged.  The memory returned is only valid until the next call to
     98  * demangle().
     99  *
    100  * We dlopen() libdemangle.so rather than linking directly against it in case it
    101  * is not installed on the system.
    102  */
    103 const char *
    104 dis_demangle(const char *name)
    105 {
    106 	static char *demangled_name;
    107 	static int (*demangle_func)() = NULL;
    108 	static int size = BUFSIZE;
    109 	static int first_flag = 0;
    110 	int ret;
    111 
    112 	/*
    113 	 * If this is the first call, allocate storage
    114 	 * for the buffer.
    115 	 */
    116 	if (first_flag == 0) {
    117 		void *demangle_hand;
    118 
    119 		demangle_hand = dlopen("libdemangle.so.1", RTLD_LAZY);
    120 		if (demangle_hand != NULL)
    121 			demangle_func = (int (*)(int))dlsym(
    122 				demangle_hand, "cplus_demangle");
    123 
    124 		demangled_name = safe_malloc(size);
    125 		first_flag = 1;
    126 	}
    127 
    128 	/*
    129 	 * If libdemangle is not present, pass through unchanged.
    130 	 */
    131 	if (demangle_func == NULL)
    132 		return (name);
    133 
    134 	/*
    135 	 * The function returns -1 when the buffer size is not sufficient.
    136 	 */
    137 	while ((ret = (*demangle_func)(name, demangled_name, size)) == -1) {
    138 		free(demangled_name);
    139 		size = size + BUFSIZE;
    140 		demangled_name = safe_malloc(size);
    141 	}
    142 
    143 	if (ret != 0)
    144 		return (name);
    145 
    146 	return (demangled_name);
    147 }
    148