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