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