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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * String conversion routines for symbol attributes. 30 */ 31 #include <stdio.h> 32 #include <demangle.h> 33 #include "_conv.h" 34 #include "symbols_msg.h" 35 #include <sys/elf_SPARC.h> 36 37 static const char vis_types[4] = { 38 'D', /* STV_DEFAULT */ 39 'I', /* STV_INTERNAL */ 40 'H', /* STV_HIDDEN */ 41 'P' /* STV_PROTECTED */ 42 }; 43 44 const char * 45 conv_sym_stother(uchar_t stother) 46 { 47 uint_t vis = ELF_ST_VISIBILITY(stother); 48 static char string[STRSIZE]; 49 uint_t ndx = 0; 50 51 string[ndx++] = vis_types[vis]; 52 /* 53 * If unkown bits are present in stother - throw out a '?' 54 */ 55 if (stother & ~MSK_SYM_VISIBILITY) 56 string[ndx++] = '?'; 57 58 string[ndx++] = '\0'; 59 60 return (string); 61 } 62 63 static const Msg types[] = { 64 MSG_STT_NOTYPE, MSG_STT_OBJECT, MSG_STT_FUNC, 65 MSG_STT_SECTION, MSG_STT_FILE, MSG_STT_COMMON, 66 MSG_STT_TLS 67 }; 68 69 const char * 70 conv_info_type_str(ushort_t mach, uchar_t type) 71 { 72 static char string[STRSIZE] = { '\0' }; 73 74 75 if (type < STT_NUM) 76 return (MSG_ORIG(types[type])); 77 else if (((mach == EM_SPARC) || (mach == EM_SPARC32PLUS) || 78 (mach == EM_SPARCV9)) && (type == STT_SPARC_REGISTER)) 79 return (MSG_ORIG(MSG_STT_REGISTER)); 80 else 81 return (conv_invalid_str(string, STRSIZE, type, 0)); 82 } 83 84 static const Msg binds[] = { 85 MSG_STB_LOCAL, MSG_STB_GLOBAL, MSG_STB_WEAK 86 }; 87 88 const char * 89 conv_info_bind_str(uchar_t bind) 90 { 91 static char string[STRSIZE] = { '\0' }; 92 93 if (bind >= STB_NUM) 94 return (conv_invalid_str(string, STRSIZE, bind, 0)); 95 else 96 return (MSG_ORIG(binds[bind])); 97 } 98 99 const char * 100 conv_shndx_str(ushort_t shndx) 101 { 102 static char string[STRSIZE] = { '\0' }; 103 104 if (shndx == SHN_UNDEF) 105 return (MSG_ORIG(MSG_SHN_UNDEF)); 106 else if (shndx == SHN_SUNW_IGNORE) 107 return (MSG_ORIG(MSG_SHN_SUNW_IGNORE)); 108 else if (shndx == SHN_ABS) 109 return (MSG_ORIG(MSG_SHN_ABS)); 110 else if (shndx == SHN_COMMON) 111 return (MSG_ORIG(MSG_SHN_COMMON)); 112 else if (shndx == SHN_AFTER) 113 return (MSG_ORIG(MSG_SHN_AFTER)); 114 else if (shndx == SHN_BEFORE) 115 return (MSG_ORIG(MSG_SHN_BEFORE)); 116 else if (shndx == SHN_XINDEX) 117 return (MSG_ORIG(MSG_SHN_XINDEX)); 118 else 119 return (conv_invalid_str(string, STRSIZE, shndx, 1)); 120 } 121 122 const char * 123 conv_sym_value_str(ushort_t mach, uint_t type, uint64_t value) 124 { 125 static char string[STRSIZE64] = { '\0' }; 126 const char *fmt; 127 128 if (((mach == EM_SPARC) || (mach == EM_SPARC32PLUS) || 129 (mach == EM_SPARCV9)) && (type == STT_SPARC_REGISTER)) 130 return (conv_sym_SPARC_value_str(value)); 131 132 /* 133 * Should obtain the elf class rather than relying on e_machine here... 134 */ 135 if (mach == EM_SPARCV9) 136 fmt = MSG_ORIG(MSG_FMT_VAL_64); 137 else 138 fmt = MSG_ORIG(MSG_FMT_VAL); 139 140 (void) sprintf(string, fmt, EC_XWORD(value)); 141 return (string); 142 } 143 144 /* 145 * Demangle C++ symbols. 146 * 147 * This routine acts as a generic routine for use by liblddbg (and hence tools 148 * like elfdump(1) and pvs(1)), ld(1) and ld.so.1(1). 149 * 150 * The C++ ABI-2 places no limits on symbol names, thus when demangling a name 151 * it's possible the buffer won't be big enough (DEMANGLE_ESPACE) so here we 152 * try to allocate bigger buffers. However, we place a limit on this buffer 153 * size for fear of a C++ error sending us into an infinit loop. 154 * 155 * NOTE. we create and use a common buffer for use by cplus_demangle(), thus 156 * each call to this routine will override the contents of any existing call. 157 * Normally this is sufficient for typical error diagnostics referencing one 158 * symbol. For those diagnostics using more than one symbol name, all but the 159 * last name must be copied to a temporary buffer (regardless of whether 160 * demangling occurred, as the process of attempting to demangle may damage the 161 * buffer). One model is: 162 * 163 * if ((_name1 = demangle(name1)) != name1) { 164 * char * __name1 = alloca(strlen(_name1) + 1); 165 * (void) strcpy(__name1, _name1); 166 * name1 = (const char *)__name1; 167 * } 168 * name2 = demangle(name2); 169 * eprintf(format, name1, name2); 170 */ 171 #define SYM_MAX 1000 172 173 const char * 174 conv_sym_dem(const char *name) 175 { 176 static char _str[SYM_MAX], *str = _str; 177 static size_t size = SYM_MAX; 178 static int again = 1; 179 static int (*fptr)() = 0; 180 int error; 181 182 if (str == 0) 183 return (name); 184 185 /* 186 * If we haven't located the demangler yet try now (we do this rather 187 * than maintain a static dependency on libdemangle as it's part of an 188 * optional package). Null the str element out to reject any other 189 * callers until this operation is complete - under ld.so.1 we can get 190 * into serious recursion without this. 191 */ 192 if (fptr == 0) { 193 void *hdl; 194 195 str = 0; 196 if (!(hdl = dlopen(MSG_ORIG(MSG_DEM_LIB), RTLD_LAZY)) || 197 !(fptr = (int (*)())dlsym(hdl, MSG_ORIG(MSG_DEM_SYM)))) 198 return (name); 199 str = _str; 200 } 201 202 if ((error = (*fptr)(name, str, size)) == 0) 203 return ((const char *)str); 204 205 while ((error == DEMANGLE_ESPACE) && again) { 206 char *_str; 207 size_t _size = size; 208 209 /* 210 * If we haven't allocated our maximum try incrementing the 211 * present buffer size. Use malloc() rather than realloc() so 212 * that we at least have the old buffer on failure. 213 */ 214 if (((_size += SYM_MAX) > (SYM_MAX * 4)) || 215 ((_str = malloc(_size)) == 0)) { 216 again = 0; 217 break; 218 } 219 if (size != SYM_MAX) { 220 free(str); 221 } 222 str = _str; 223 size = _size; 224 225 if ((error = (*fptr)(name, str, size)) == 0) 226 return ((const char *)str); 227 } 228 return (name); 229 } 230