/*
* 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 (c) 1988 AT&T
* All Rights Reserved
*
*
* Copyright (c) 1998 by Sun Microsystems, Inc.
* All rights reserved.
*/
#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
#include <ctype.h>
#include <setjmp.h>
#include <stdlib.h>
#include <string.h>
#include <thread.h>
#include <note.h>
#include "elf_dem.h"
#include "String.h"
#include "msg.h"
/* The variable "hold" contains the pointer to the array initially
* handed to demangle. It is returned if it is not possible to
* demangle the string. NULL is returned if a memory allocation
* problem is encountered. Thus one can do the following:
*
* char *mn = "Some mangled name";
* char *dm = mangle(mn);
* if (dm == NULL)
* printf("allocation error\n");
* else if (dm == mn)
* printf("name could not be demangled\n");
* else
* printf("demangled name is: %s\n",dm);
*/
static char *hold;
/* this String is the working buffer for the demangle
* routine. A pointer into this String is returned
* from demangle when it is possible to demangle the
* String. For this reason, the pointer should not
* be saved between calls of demangle(), nor freed.
*/
static String *s = 0;
static int
getint(c)
char **c;
{
return strtol(*c, c, 10);
}
/* If a mangled name has a __
* that is not at the very beginning
* of the string, then this routine
* is called to demangle that part
* of the name. All overloaded functions,
* and class members fall into this category.
*
* c should start with two underscores followed by a non-zero digit or an F.
*/
static char *
second(c)
char *c;
{
int n;
if(strncmp(c, MSG_ORIG(MSG_STR_DBLUNDBAR), 2))
return hold;
c += 2;
if (!(isdigit(*c) || *c == 'F'))
return hold;
if (isdigit(*c)) {
/* a member */
n = getint(&c);
if (n == 0 || (int) strlen(c) < n)
return hold;
s = prep_String(MSG_ORIG(MSG_STR_DBLCOL), s);
s = nprep_String(c,s,n);
c += n;
}
if(*c == 'F') {
/* an overloaded function */
switch (*++c) {
case '\0':
return hold;
case 'v':
s = app_String(s, MSG_ORIG(MSG_STR_OPENCLOSEPAR));
break;
default:
if(demangle_doargs(&s,c) < 0)
return hold;
}
}
return PTR(s);
}
char *
demangle(c)
char *c;
{
register int i = 0;
extern jmp_buf jbuf;
static mutex_t mlock = DEFAULTMUTEX;
NOTE(MUTEX_PROTECTS_DATA(mlock, String))
(void) mutex_lock(&mlock);
if (setjmp(jbuf)) {
(void) mutex_unlock(&mlock);
return 0;
}
hold = c;
s = mk_String(s);
s = set_String(s, MSG_ORIG(MSG_STR_EMPTY));
if(c == 0 || *c == 0) {
c = hold;
(void) mutex_unlock(&mlock);
return c;
}
if(strncmp(c, MSG_ORIG(MSG_STR_DBLUNDBAR), 2) != 0) {
/* If a name does not begin with a __
* but it does contain one, it is either
* a member or an overloaded function.
*/
while(c[i] && strncmp(c+i, MSG_ORIG(MSG_STR_DBLUNDBAR), 2))
i++;
if (c[i]) {
/* Advance to first non-underscore */
while (c[i+2] == '_')
i++;
}
if(strncmp(c+i, MSG_ORIG(MSG_STR_DBLUNDBAR), 2) == 0) {
/* Copy the simple name */
s = napp_String(s,c,i);
/* Process the signature */
c = second(c+i);
(void) mutex_unlock(&mlock);
return c;
} else {
c = hold;
(void) mutex_unlock(&mlock);
return c;
}
} else {
const char * x;
int oplen;
c += 2;
/* For automatic variables, or internal static
* variables, a __(number) is prepended to the
* name. If this is encountered, strip this off
* and return.
*/
if(isdigit(*c)) {
while(isdigit(*c))
c++;
(void) mutex_unlock(&mlock);
return c;
}
/* Handle operator functions -- this
* automatically calls second, since
* all operator functions are overloaded.
*/
if(x = findop(c, &oplen)) {
s = app_String(s, MSG_ORIG(MSG_STR_OPERATOR_1));
s = app_String(s,x);
c += oplen;
c = second(c);
(void) mutex_unlock(&mlock);
return c;
}
/* Operator cast does not fit the mould
* of the other operators. Its type name
* is encoded. The cast function must
* take a void as an argument.
*/
if(strncmp(c, MSG_ORIG(MSG_STR_OP), 2) == 0) {
int r;
s = app_String(s, MSG_ORIG(MSG_STR_OPERATOR_2));
c += 2;
r = demangle_doarg(&s,c);
if(r < 0) {
c = hold;
(void) mutex_unlock(&mlock);
return c;
}
c += r;
c = second(c);
(void) mutex_unlock(&mlock);
return c;
}
/* Constructors and Destructors are also
* a special case of operator name. Note
* that the destructor, while overloaded,
* must always take the same arguments --
* none.
*/
if ((*c == 'c' || *c == 'd') && strncmp(c+1,
MSG_ORIG(MSG_STR_TDBLUNDBAR), 3) == 0) {
int n;
char *c2 = c+2;
char cx = c[0];
c += 4;
n = getint(&c);
if(n == 0) {
c = hold;
(void) mutex_unlock(&mlock);
return c;
}
s = napp_String(s,c,n);
if(cx == 'd')
s = prep_String(MSG_ORIG(MSG_STR_TILDE), s);
c = second(c2);
(void) mutex_unlock(&mlock);
return c;
}
c = hold;
(void) mutex_unlock(&mlock);
return c;
}
}