xref: /illumos-gate/usr/src/cmd/sgs/libelf/misc/args.c (revision 7c478bd9)
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  */
45 typedef struct {
46 	char *list[10];
47 	int pos;
48 } Place;
49 
50 static 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  */
56 typedef struct {
57 	String *ptr;
58 	int Sign,Uns,Cons,Vol;
59 } Arg_Remem;
60 
61 /* initialize Arg_Remem */
62 static void
mkar(r)63 mkar(r)
64 Arg_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 */
71 static void
delar(r)72 delar(r)
73 Arg_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  */
82 static void
nsetarg(String ** sptr,Arg_Remem * r,const char * c,int n)83 nsetarg(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  */
102 static void
setarg(String ** sptr,Arg_Remem * r,const char * c)103 setarg(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  */
112 int
demangle_doarg(sptr,c)113 demangle_doarg(sptr,c)
114 String **sptr;
115 char *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  */
342 int
demangle_doargs(sptr,c)343 demangle_doargs(sptr,c)
344 String **sptr;
345 char *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