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 (c) 1988 AT&T
24 *	  All Rights Reserved
25 *
26 *
27 *	Copyright (c) 1998 by Sun Microsystems, Inc.
28 *	All rights reserved.
29 */
30#pragma ident	"%Z%%M%	%I%	%E% SMI" 	/* SVr4.0 1.2	*/
31
32#include	<ctype.h>
33#include	<stdlib.h>
34#include	<string.h>
35#include	"elf_dem.h"
36#include	"String.h"
37#include	"msg.h"
38
39/* This structure is used to keep
40 * track of pointers to argument
41 * descriptions in the mangled string.
42 * This is needed for N and T encodings
43 * to work.
44 */
45typedef struct {
46	char *list[10];
47	int pos;
48} Place;
49
50static Place here;
51
52/* Strings and flags needed by the argument demangles.  The declarator
53 * is built up in ptr.  Type modifiers are held in the flag fields.
54 * The type itself is passed in separately.
55 */
56typedef struct {
57	String *ptr;
58	int Sign,Uns,Cons,Vol;
59} Arg_Remem;
60
61/* initialize Arg_Remem */
62static void
63mkar(r)
64Arg_Remem *r;
65{
66	r->ptr = mk_String((String *)0);
67	r->Sign = r->Uns = r->Cons = r->Vol = 0;
68}
69
70/* free data for Arg_Remem */
71static void
72delar(r)
73Arg_Remem *r;
74{
75	free_String(r->ptr);
76}
77
78/* This routine formats a single argument
79 * on the buffer sptr.
80 * c is the type or class name, n is its length.
81 */
82static void
83nsetarg(String ** sptr, Arg_Remem * r, const char * c, int n)
84{
85	r->ptr = nprep_String(c, r->ptr, n);
86	if(r->Cons)
87		r->ptr = prep_String(MSG_ORIG(MSG_STR_CONST_1), r->ptr);
88	if(r->Vol)
89		r->ptr = prep_String(MSG_ORIG(MSG_STR_VOLATILE_1), r->ptr);
90	if(r->Uns)
91		r->ptr = prep_String(MSG_ORIG(MSG_STR_UNSIGNED), r->ptr);
92	else if(r->Sign)
93		r->ptr = prep_String(MSG_ORIG(MSG_STR_SIGNED), r->ptr);
94	*sptr = app_String(*sptr,PTR(r->ptr));
95	delar(r);
96}
97
98/* This routine formats a single argument
99 * on the buffer sptr.
100 * c is the null terminated type or class name.
101 */
102static void
103setarg(String ** sptr, Arg_Remem * r, const char * c)
104{
105	nsetarg(sptr, r, c, ID_NAME_MAX);
106}
107
108
109/* Demangle a single function argument.
110 * Returns the number of characters processed from c.
111 */
112int
113demangle_doarg(sptr,c)
114String **sptr;
115char *c;
116{
117	register int i;
118	Arg_Remem ar;
119	mkar(&ar);
120
121	if(here.pos < 10 && here.pos >= 0)
122		here.list[here.pos++] = c;
123
124	for(i=0;c[i];i++) {
125		/* Loop until you find a type.
126		   Then call setarg and return.
127		*/
128		switch(c[i]) {
129
130		case 'T':
131			{
132				Place tmp;
133				tmp = here;
134				here.pos = c[1] - '1';
135				if(here.pos < 0 || here.pos >= tmp.pos-1) {
136					delar(&ar);
137					return -1;
138				}
139				(void) demangle_doarg(sptr,here.list[here.pos]);
140				here = tmp;
141				delar(&ar);
142				return 2;
143			}
144		case 'N':
145			{
146				Place tmp;
147				int cycles,pos;
148				cycles = c[1] - '0'; pos = c[2] - '1';
149				here.pos += cycles - 1;
150				tmp = here;
151				if(cycles <= 1 || cycles > 9 || pos < 0 || pos >= tmp.pos-1) {
152					delar(&ar);
153					return -1;
154				}
155				while(cycles--) {
156					here = tmp;
157					here.pos = pos;
158					(void) demangle_doarg(sptr,here.list[here.pos]);
159					(*sptr) = app_String(*sptr,
160					    MSG_ORIG(MSG_STR_COMMA));
161				}
162				*sptr = trunc_String(*sptr, 1);
163				here = tmp;
164				delar(&ar);
165				return 3;
166			}
167
168		/* Qualifiers to type names */
169		case 'S':
170			ar.Sign = 1;
171			break;
172		case 'U':
173			ar.Uns = 1;
174			break;
175		case 'C':
176			ar.Cons = 1;
177			break;
178		case 'V':
179			ar.Vol = 1;
180			break;
181
182		/* Pointers, references, and Member Pointers */
183		case 'P':
184		case 'R':
185		case 'M':
186			if(ar.Cons) {
187				ar.ptr = prep_String(MSG_ORIG(MSG_STR_CONST_2),
188				    ar.ptr);
189				ar.Cons = 0;
190			}
191			if(ar.Vol) {
192				ar.ptr =
193				    prep_String(MSG_ORIG(MSG_STR_VOLATILE_2),
194				    ar.ptr);
195				ar.Vol = 0;
196			}
197			if(c[i] == 'P')
198				ar.ptr = prep_String(MSG_ORIG(MSG_STR_STAR),
199				    ar.ptr);
200			else if(c[i] == 'R')
201				ar.ptr = prep_String(MSG_ORIG(MSG_STR_AMP),
202				    ar.ptr);
203			else {
204				int cnt = 0;
205				char *s;
206				ar.ptr =
207				    prep_String(MSG_ORIG(MSG_STR_DBLCOLSTAR),
208				    ar.ptr);
209				/* Skip over the 'M' */
210				i++;
211				cnt = strtol(c+i, &s, 10);
212				i = s - c;
213				ar.ptr = nprep_String(c+i,ar.ptr,cnt);
214				ar.ptr = prep_String(MSG_ORIG(MSG_STR_SPACE),
215				    ar.ptr);
216				i += cnt;
217				/* The loop increments i */
218				i--;
219			}
220			break;
221
222		/* Demangle for basic built-in types */
223		case 'i':
224			setarg(sptr, &ar, MSG_ORIG(MSG_STR_INT));
225			return i + 1;
226		case 'c':
227			setarg(sptr, &ar, MSG_ORIG(MSG_STR_CHAR));
228			return i + 1;
229		case 's':
230			setarg(sptr, &ar, MSG_ORIG(MSG_STR_SHORT));
231			return i + 1;
232		case 'l':
233			setarg(sptr, &ar, MSG_ORIG(MSG_STR_LONG));
234			return i + 1;
235		case 'f':
236			setarg(sptr, &ar, MSG_ORIG(MSG_STR_FLOAT));
237			return i + 1;
238		case 'd':
239			setarg(sptr, &ar, MSG_ORIG(MSG_STR_DOUBLE));
240			return i + 1;
241		case 'r':
242			setarg(sptr, &ar, MSG_ORIG(MSG_STR_LONGDOUBLE));
243			return i + 1;
244
245		/* Class encodings */
246		case '1': case '2': case '3':
247		case '4': case '5': case '6':
248		case '7': case '8': case '9':
249			{
250				int cnt = 0;
251				char *s;
252				cnt = strtol(c+i, &s, 10);
253				i = s - c;
254				if ((int) strlen(c+i) < cnt) {
255					delar(&ar);
256					return -1;
257				}
258				nsetarg(sptr,&ar,c+i,cnt);
259				return i+cnt;
260			}
261
262		/* Ellipsis and void */
263		case 'e':
264			setarg(sptr, &ar, MSG_ORIG(MSG_STR_ELIPSE));
265			return i + 1;
266		case 'v':
267			setarg(sptr, &ar, MSG_ORIG(MSG_STR_VOID));
268			return i + 1;
269
270		/* Arrays */
271		case 'A':
272			if(*PTR(ar.ptr)) {
273				ar.ptr = prep_String(MSG_ORIG(MSG_STR_OPENPAR),
274				   ar.ptr);
275				ar.ptr = app_String(ar.ptr,
276				   MSG_ORIG(MSG_STR_CLOSEPAR));
277			}
278			ar.ptr = app_String(ar.ptr, MSG_ORIG(MSG_STR_OPENBRAK));
279			{
280				int cnt = 0;
281				i++;
282				while(isdigit(c[i+cnt]))
283					cnt++;
284				ar.ptr = napp_String(ar.ptr,c+i,cnt);
285				i += cnt;
286				if(c[i] != '_') {
287					delar(&ar);
288					return -1;
289				}
290			}
291			ar.ptr = app_String(ar.ptr,
292			    MSG_ORIG(MSG_STR_CLOSEBRAK));
293			break;
294
295		/* Functions
296		 * This will always be called as a pointer
297		 * to a function.
298		 */
299		case 'F':
300			ar.ptr = prep_String(MSG_ORIG(MSG_STR_OPENPAR), ar.ptr);
301			ar.ptr = app_String(ar.ptr, MSG_ORIG(MSG_STR_CLOSEPAR));
302			{
303				Place tmp;
304				tmp = here;
305				i++;
306				i += demangle_doargs(&ar.ptr,c+i);
307				if(c[i] != '_') {
308					delar(&ar);
309					return -1;
310				}
311				here = tmp;
312			}
313			break;
314
315		/* Needed when this is called to demangle
316		 * an argument of a pointer to a function.
317		 */
318		case '_':
319			delar(&ar);
320			return 0;
321
322		default:
323			delar(&ar);
324			return -1;
325		}
326	}
327
328	/* Did the argument list terminate properly? */
329	{
330		int rc = 0;
331		if(*PTR(ar.ptr) || ar.Uns || ar.Sign || ar.Cons || ar.Vol)
332			rc = -1;
333		delar(&ar);
334		return rc;
335	}
336}
337
338/* This function is called to demangle
339 * an argument list.
340 * Returns the number of characters processed from c.
341 */
342int
343demangle_doargs(sptr,c)
344String **sptr;
345char *c;
346{
347	int i,n = 0;
348	here.pos = 0;
349
350	*sptr = app_String(*sptr,MSG_ORIG(MSG_STR_OPENPAR));
351	while(*c && (i = demangle_doarg(sptr,c)) > 0) {
352		c += i;
353		n += i;
354		(*sptr) = app_String(*sptr,(*c && *c == 'e') ?
355		    MSG_ORIG(MSG_STR_SPACE) : MSG_ORIG(MSG_STR_COMMA));
356	}
357
358	if(i < 0)
359		return -1;
360
361	*sptr = app_String(trunc_String(*sptr, 1), MSG_ORIG(MSG_STR_CLOSEPAR));
362
363	return n;
364}
365