|
|
1.1 root 1: /* Demangler for GNU C++
2: Copyright 1989, 1991 Free Software Foundation, Inc.
3: Written by James Clark ([email protected])
4: Rewritten by Fred Fish ([email protected]) for ARM and Lucid demangling
5:
6: This file is part of the libiberty library.
7: Libiberty is free software; you can redistribute it and/or
8: modify it under the terms of the GNU Library General Public
9: License as published by the Free Software Foundation; either
10: version 2 of the License, or (at your option) any later version.
11:
12: Libiberty is distributed in the hope that it will be useful,
13: but WITHOUT ANY WARRANTY; without even the implied warranty of
14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15: Library General Public License for more details.
16:
17: You should have received a copy of the GNU Library General Public
18: License along with libiberty; see the file COPYING.LIB. If
19: not, write to the Free Software Foundation, Inc., 675 Mass Ave,
20: Cambridge, MA 02139, USA. */
21:
22: /* This file exports two functions; cplus_mangle_opname and cplus_demangle.
23:
24: This file imports xmalloc and xrealloc, which are like malloc and
25: realloc except that they generate a fatal error if there is no
26: available memory. */
27:
28: #include "demangle.h"
29: #undef CURRENT_DEMANGLING_STYLE
30: #define CURRENT_DEMANGLING_STYLE work->options
31: #include <ctype.h>
32: #include <string.h>
33: #include <stdio.h>
34:
35: extern char *xmalloc PARAMS((long));
36: extern char *xrealloc PARAMS((PTR, long));
37: extern char *strstr PARAMS ((const char *, const char *));
38: extern void free PARAMS((PTR));
39:
40: /* In order to allow a single demangler executable to demangle strings
41: using various common values of CPLUS_MARKER, as well as any specific
42: one set at compile time, we maintain a string containing all the
43: commonly used ones, and check to see if the marker we are looking for
44: is in that string. CPLUS_MARKER is usually '$' on systems where the
45: assembler can deal with that. Where the assembler can't, it's usually
46: '.' (but on many systems '.' is used for other things). We put the
47: current defined CPLUS_MARKER first (which defaults to '$'), followed
48: by the next most common value, followed by an explicit '$' in case
49: the value of CPLUS_MARKER is not '$'.
50:
51: We could avoid this if we could just get g++ to tell us what the actual
52: cplus marker character is as part of the debug information, perhaps by
53: ensuring that it is the character that terminates the gcc<n>_compiled
54: marker symbol (FIXME). */
55:
56: #if !defined (CPLUS_MARKER)
57: #define CPLUS_MARKER '$'
58: #endif
59:
60: enum demangling_styles current_demangling_style = gnu_demangling;
61:
62: static char cplus_markers[] = { CPLUS_MARKER, '.', '$', '\0' };
63:
64: void
65: set_cplus_marker_for_demangling (ch)
66: int ch;
67: {
68: cplus_markers[0] = ch;
69: }
70:
71: /* Stuff that is shared between sub-routines.
72: * Using a shared structure allows cplus_demangle to be reentrant. */
73:
74: struct work_stuff
75: {
76: int options;
77: char **typevec;
78: int ntypes;
79: int typevec_size;
80: int constructor;
81: int destructor;
82: int static_type; /* A static member function */
83: int const_type; /* A const member function */
84: };
85:
86: #define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI)
87: #define PRINT_ARG_TYPES (work -> options & DMGL_PARAMS)
88:
89: static CONST struct optable
90: {
91: CONST char *in;
92: CONST char *out;
93: int flags;
94: } optable[] = {
95: {"nw", " new", DMGL_ANSI}, /* new (1.92, ansi) */
96: {"dl", " delete", DMGL_ANSI}, /* new (1.92, ansi) */
97: {"new", " new", 0}, /* old (1.91, and 1.x) */
98: {"delete", " delete", 0}, /* old (1.91, and 1.x) */
99: {"as", "=", DMGL_ANSI}, /* ansi */
100: {"ne", "!=", DMGL_ANSI}, /* old, ansi */
101: {"eq", "==", DMGL_ANSI}, /* old, ansi */
102: {"ge", ">=", DMGL_ANSI}, /* old, ansi */
103: {"gt", ">", DMGL_ANSI}, /* old, ansi */
104: {"le", "<=", DMGL_ANSI}, /* old, ansi */
105: {"lt", "<", DMGL_ANSI}, /* old, ansi */
106: {"plus", "+", 0}, /* old */
107: {"pl", "+", DMGL_ANSI}, /* ansi */
108: {"apl", "+=", DMGL_ANSI}, /* ansi */
109: {"minus", "-", 0}, /* old */
110: {"mi", "-", DMGL_ANSI}, /* ansi */
111: {"ami", "-=", DMGL_ANSI}, /* ansi */
112: {"mult", "*", 0}, /* old */
113: {"ml", "*", DMGL_ANSI}, /* ansi */
114: {"amu", "*=", DMGL_ANSI}, /* ansi (ARM/Lucid) */
115: {"aml", "*=", DMGL_ANSI}, /* ansi (GNU/g++) */
116: {"convert", "+", 0}, /* old (unary +) */
117: {"negate", "-", 0}, /* old (unary -) */
118: {"trunc_mod", "%", 0}, /* old */
119: {"md", "%", DMGL_ANSI}, /* ansi */
120: {"amd", "%=", DMGL_ANSI}, /* ansi */
121: {"trunc_div", "/", 0}, /* old */
122: {"dv", "/", DMGL_ANSI}, /* ansi */
123: {"adv", "/=", DMGL_ANSI}, /* ansi */
124: {"truth_andif", "&&", 0}, /* old */
125: {"aa", "&&", DMGL_ANSI}, /* ansi */
126: {"truth_orif", "||", 0}, /* old */
127: {"oo", "||", DMGL_ANSI}, /* ansi */
128: {"truth_not", "!", 0}, /* old */
129: {"nt", "!", DMGL_ANSI}, /* ansi */
130: {"postincrement","++", 0}, /* old */
131: {"pp", "++", DMGL_ANSI}, /* ansi */
132: {"postdecrement","--", 0}, /* old */
133: {"mm", "--", DMGL_ANSI}, /* ansi */
134: {"bit_ior", "|", 0}, /* old */
135: {"or", "|", DMGL_ANSI}, /* ansi */
136: {"aor", "|=", DMGL_ANSI}, /* ansi */
137: {"bit_xor", "^", 0}, /* old */
138: {"er", "^", DMGL_ANSI}, /* ansi */
139: {"aer", "^=", DMGL_ANSI}, /* ansi */
140: {"bit_and", "&", 0}, /* old */
141: {"ad", "&", DMGL_ANSI}, /* ansi */
142: {"aad", "&=", DMGL_ANSI}, /* ansi */
143: {"bit_not", "~", 0}, /* old */
144: {"co", "~", DMGL_ANSI}, /* ansi */
145: {"call", "()", 0}, /* old */
146: {"cl", "()", DMGL_ANSI}, /* ansi */
147: {"alshift", "<<", 0}, /* old */
148: {"ls", "<<", DMGL_ANSI}, /* ansi */
149: {"als", "<<=", DMGL_ANSI}, /* ansi */
150: {"arshift", ">>", 0}, /* old */
151: {"rs", ">>", DMGL_ANSI}, /* ansi */
152: {"ars", ">>=", DMGL_ANSI}, /* ansi */
153: {"component", "->", 0}, /* old */
154: {"pt", "->", DMGL_ANSI}, /* ansi; Lucid C++ form */
155: {"rf", "->", DMGL_ANSI}, /* ansi; ARM/GNU form */
156: {"indirect", "*", 0}, /* old */
157: {"method_call", "->()", 0}, /* old */
158: {"addr", "&", 0}, /* old (unary &) */
159: {"array", "[]", 0}, /* old */
160: {"vc", "[]", DMGL_ANSI}, /* ansi */
161: {"compound", ", ", 0}, /* old */
162: {"cm", ", ", DMGL_ANSI}, /* ansi */
163: {"cond", "?:", 0}, /* old */
164: {"cn", "?:", DMGL_ANSI}, /* psuedo-ansi */
165: {"max", ">?", 0}, /* old */
166: {"mx", ">?", DMGL_ANSI}, /* psuedo-ansi */
167: {"min", "<?", 0}, /* old */
168: {"mn", "<?", DMGL_ANSI}, /* psuedo-ansi */
169: {"nop", "", 0}, /* old (for operator=) */
170: {"rm", "->*", DMGL_ANSI} /* ansi */
171: };
172:
173:
174: typedef struct string /* Beware: these aren't required to be */
175: { /* '\0' terminated. */
176: char *b; /* pointer to start of string */
177: char *p; /* pointer after last character */
178: char *e; /* pointer after end of allocated space */
179: } string;
180:
181: #define STRING_EMPTY(str) ((str) -> b == (str) -> p)
182: #define PREPEND_BLANK(str) {if (!STRING_EMPTY(str)) \
183: string_prepend(str, " ");}
184: #define APPEND_BLANK(str) {if (!STRING_EMPTY(str)) \
185: string_append(str, " ");}
186:
187: #define ARM_VTABLE_STRING "__vtbl__" /* Lucid/ARM virtual table prefix */
188: #define ARM_VTABLE_STRLEN 8 /* strlen (ARM_VTABLE_STRING) */
189:
190: /* Prototypes for local functions */
191:
192: static char *
193: mop_up PARAMS ((struct work_stuff *, string *, int));
194:
195: #if 0
196: static int
197: demangle_method_args PARAMS ((struct work_stuff *work, CONST char **, string *));
198: #endif
199:
200: static int
201: demangle_template PARAMS ((struct work_stuff *work, CONST char **, string *,
202: string *));
203:
204: static int
205: demangle_qualified PARAMS ((struct work_stuff *, CONST char **, string *,
206: int, int));
207:
208: static int
209: demangle_class PARAMS ((struct work_stuff *, CONST char **, string *));
210:
211: static int
212: demangle_fund_type PARAMS ((struct work_stuff *, CONST char **, string *));
213:
214: static int
215: demangle_signature PARAMS ((struct work_stuff *, CONST char **, string *));
216:
217: static int
218: demangle_prefix PARAMS ((struct work_stuff *, CONST char **, string *));
219:
220: static int
221: gnu_special PARAMS ((struct work_stuff *, CONST char **, string *));
222:
223: static int
224: arm_special PARAMS ((struct work_stuff *, CONST char **, string *));
225:
226: static void
227: string_need PARAMS ((string *, int));
228:
229: static void
230: string_delete PARAMS ((string *));
231:
232: static void
233: string_init PARAMS ((string *));
234:
235: static void
236: string_clear PARAMS ((string *));
237:
238: #if 0
239: static int
240: string_empty PARAMS ((string *));
241: #endif
242:
243: static void
244: string_append PARAMS ((string *, CONST char *));
245:
246: static void
247: string_appends PARAMS ((string *, string *));
248:
249: static void
250: string_appendn PARAMS ((string *, CONST char *, int));
251:
252: static void
253: string_prepend PARAMS ((string *, CONST char *));
254:
255: static void
256: string_prependn PARAMS ((string *, CONST char *, int));
257:
258: static int
259: get_count PARAMS ((CONST char **, int *));
260:
261: static int
262: consume_count PARAMS ((CONST char **));
263:
264: static int
265: demangle_args PARAMS ((struct work_stuff *, CONST char **, string *));
266:
267: static int
268: do_type PARAMS ((struct work_stuff *, CONST char **, string *));
269:
270: static int
271: do_arg PARAMS ((struct work_stuff *, CONST char **, string *));
272:
273: static void
274: demangle_function_name PARAMS ((struct work_stuff *, CONST char **, string *,
275: CONST char *));
276:
277: static void
278: remember_type PARAMS ((struct work_stuff *, CONST char *, int));
279:
280: static void
281: forget_types PARAMS ((struct work_stuff *));
282:
283: static void
284: string_prepends PARAMS ((string *, string *));
285:
286: /* Translate count to integer, consuming tokens in the process.
287: Conversion terminates on the first non-digit character.
288: Trying to consume something that isn't a count results in
289: no consumption of input and a return of 0. */
290:
291: static int
292: consume_count (type)
293: CONST char **type;
294: {
295: int count = 0;
296:
297: while (isdigit (**type))
298: {
299: count *= 10;
300: count += **type - '0';
301: (*type)++;
302: }
303: return (count);
304: }
305:
306: /* Takes operator name as e.g. "++" and returns mangled
307: operator name (e.g. "postincrement_expr"), or NULL if not found.
308:
309: If OPTIONS & DMGL_ANSI == 1, return the ANSI name;
310: if OPTIONS & DMGL_ANSI == 0, return the old GNU name. */
311:
312: char *
313: cplus_mangle_opname (opname, options)
314: char *opname;
315: int options;
316: {
317: int i;
318: int len;
319:
320: len = strlen (opname);
321: for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
322: {
323: if (strlen (optable[i].out) == len
324: && (options & DMGL_ANSI) == (optable[i].flags & DMGL_ANSI)
325: && memcmp (optable[i].out, opname, len) == 0)
326: return ((char *)optable[i].in);
327: }
328: return (0);
329: }
330:
331: /* check to see whether MANGLED can match TEXT in the first TEXT_LEN
332: characters. */
333:
334: int cplus_match (mangled, text, text_len)
335: CONST char *mangled;
336: char *text;
337: int text_len;
338: {
339: if (strncmp (mangled, text, text_len) != 0) {
340: return(0); /* cannot match either */
341: } else {
342: return(1); /* matches mangled, may match demangled */
343: }
344: }
345:
346: /* char *cplus_demangle (const char *mangled, int options)
347:
348: If MANGLED is a mangled function name produced by GNU C++, then
349: a pointer to a malloced string giving a C++ representation
350: of the name will be returned; otherwise NULL will be returned.
351: It is the caller's responsibility to free the string which
352: is returned.
353:
354: The OPTIONS arg may contain one or more of the following bits:
355:
356: DMGL_ANSI ANSI qualifiers such as `const' and `void' are
357: included.
358: DMGL_PARAMS Function parameters are included.
359:
360: For example,
361:
362: cplus_demangle ("foo__1Ai", DMGL_PARAMS) => "A::foo(int)"
363: cplus_demangle ("foo__1Ai", DMGL_PARAMS | DMGL_ANSI) => "A::foo(int)"
364: cplus_demangle ("foo__1Ai", 0) => "A::foo"
365:
366: cplus_demangle ("foo__1Afe", DMGL_PARAMS) => "A::foo(float,...)"
367: cplus_demangle ("foo__1Afe", DMGL_PARAMS | DMGL_ANSI)=> "A::foo(float,...)"
368: cplus_demangle ("foo__1Afe", 0) => "A::foo"
369:
370: Note that any leading underscores, or other such characters prepended by
371: the compilation system, are presumed to have already been stripped from
372: MANGLED. */
373:
374: char *
375: cplus_demangle (mangled, options)
376: CONST char *mangled;
377: int options;
378: {
379: string decl;
380: int success = 0;
381: struct work_stuff work[1];
382: char *demangled = NULL;
383:
384: if ((mangled != NULL) && (*mangled != '\0'))
385: {
386: memset ((char *) work, 0, sizeof (work));
387: work -> options = options;
388: if ((work->options & DMGL_STYLE_MASK) == 0)
389: work->options |= (int)current_demangling_style & DMGL_STYLE_MASK;
390:
391: string_init (&decl);
392:
393: /* First check to see if gnu style demangling is active and if the
394: string to be demangled contains a CPLUS_MARKER. If so, attempt to
395: recognize one of the gnu special forms rather than looking for a
396: standard prefix. In particular, don't worry about whether there
397: is a "__" string in the mangled string. Consider "_$_5__foo" for
398: example. */
399:
400: if ((AUTO_DEMANGLING || GNU_DEMANGLING))
401: {
402: success = gnu_special (work, &mangled, &decl);
403: }
404: if (!success)
405: {
406: success = demangle_prefix (work, &mangled, &decl);
407: }
408: if (success && (*mangled != '\0'))
409: {
410: success = demangle_signature (work, &mangled, &decl);
411: }
412: if (work->constructor == 2)
413: {
414: string_prepend(&decl, "global constructors keyed to ");
415: work->constructor = 0;
416: }
417: else if (work->destructor == 2)
418: {
419: string_prepend(&decl, "global destructors keyed to ");
420: work->destructor = 0;
421: }
422: demangled = mop_up (work, &decl, success);
423: }
424: return (demangled);
425: }
426:
427: static char *
428: mop_up (work, declp, success)
429: struct work_stuff *work;
430: string *declp;
431: int success;
432: {
433: char *demangled = NULL;
434:
435: /* Discard the remembered types, if any. */
436:
437: forget_types (work);
438: if (work -> typevec != NULL)
439: {
440: free ((char *) work -> typevec);
441: }
442:
443: /* If demangling was successful, ensure that the demangled string is null
444: terminated and return it. Otherwise, free the demangling decl. */
445:
446: if (!success)
447: {
448: string_delete (declp);
449: }
450: else
451: {
452: string_appendn (declp, "", 1);
453: demangled = declp -> b;
454: }
455: return (demangled);
456: }
457:
458: /*
459:
460: LOCAL FUNCTION
461:
462: demangle_signature -- demangle the signature part of a mangled name
463:
464: SYNOPSIS
465:
466: static int
467: demangle_signature (struct work_stuff *work, const char **mangled,
468: string *declp);
469:
470: DESCRIPTION
471:
472: Consume and demangle the signature portion of the mangled name.
473:
474: DECLP is the string where demangled output is being built. At
475: entry it contains the demangled root name from the mangled name
476: prefix. I.E. either a demangled operator name or the root function
477: name. In some special cases, it may contain nothing.
478:
479: *MANGLED points to the current unconsumed location in the mangled
480: name. As tokens are consumed and demangling is performed, the
481: pointer is updated to continuously point at the next token to
482: be consumed.
483:
484: Demangling GNU style mangled names is nasty because there is no
485: explicit token that marks the start of the outermost function
486: argument list.
487: */
488:
489: static int
490: demangle_signature (work, mangled, declp)
491: struct work_stuff *work;
492: CONST char **mangled;
493: string *declp;
494: {
495: int success = 1;
496: int func_done = 0;
497: int expect_func = 0;
498: CONST char *oldmangled = NULL;
499: string trawname;
500: string tname;
501:
502: while (success && (**mangled != '\0'))
503: {
504: switch (**mangled)
505: {
506: case 'Q':
507: oldmangled = *mangled;
508: success = demangle_qualified (work, mangled, declp, 1, 0);
509: if (success)
510: {
511: remember_type (work, oldmangled, *mangled - oldmangled);
512: }
513: if (AUTO_DEMANGLING || GNU_DEMANGLING)
514: {
515: expect_func = 1;
516: }
517: oldmangled = NULL;
518: break;
519:
520: case 'S':
521: /* Static member function */
522: if (oldmangled == NULL)
523: {
524: oldmangled = *mangled;
525: }
526: (*mangled)++;
527: work -> static_type = 1;
528: break;
529:
530: case 'C':
531: /* a const member function */
532: if (oldmangled == NULL)
533: {
534: oldmangled = *mangled;
535: }
536: (*mangled)++;
537: work -> const_type = 1;
538: break;
539:
540: case '0': case '1': case '2': case '3': case '4':
541: case '5': case '6': case '7': case '8': case '9':
542: if (oldmangled == NULL)
543: {
544: oldmangled = *mangled;
545: }
546: success = demangle_class (work, mangled, declp);
547: if (success)
548: {
549: remember_type (work, oldmangled, *mangled - oldmangled);
550: }
551: if (AUTO_DEMANGLING || GNU_DEMANGLING)
552: {
553: expect_func = 1;
554: }
555: oldmangled = NULL;
556: break;
557:
558: case 'F':
559: /* Function */
560: /* ARM style demangling includes a specific 'F' character after
561: the class name. For GNU style, it is just implied. So we can
562: safely just consume any 'F' at this point and be compatible
563: with either style. */
564:
565: oldmangled = NULL;
566: func_done = 1;
567: (*mangled)++;
568:
569: /* For lucid/ARM style we have to forget any types we might
570: have remembered up to this point, since they were not argument
571: types. GNU style considers all types seen as available for
572: back references. See comment in demangle_args() */
573:
574: if (LUCID_DEMANGLING || ARM_DEMANGLING)
575: {
576: forget_types (work);
577: }
578: success = demangle_args (work, mangled, declp);
579: break;
580:
581: case 't':
582: /* G++ Template */
583: string_init(&trawname);
584: string_init(&tname);
585: success = demangle_template (work, mangled, &tname, &trawname);
586: string_append(&tname, "::");
587: string_prepends(declp, &tname);
588: if (work -> destructor & 1)
589: {
590: string_prepend (&trawname, "~");
591: string_appends (declp, &trawname);
592: work->destructor -= 1;
593: }
594: if ((work->constructor & 1) || (work->destructor & 1))
595: {
596: string_appends (declp, &trawname);
597: work->constructor -= 1;
598: }
599: string_delete(&trawname);
600: string_delete(&tname);
601: expect_func = 1;
602: break;
603:
604: case '_':
605: /* At the outermost level, we cannot have a return type specified,
606: so if we run into another '_' at this point we are dealing with
607: a mangled name that is either bogus, or has been mangled by
608: some algorithm we don't know how to deal with. So just
609: reject the entire demangling. */
610: success = 0;
611: break;
612:
613: default:
614: if (AUTO_DEMANGLING || GNU_DEMANGLING)
615: {
616: /* Assume we have stumbled onto the first outermost function
617: argument token, and start processing args. */
618: func_done = 1;
619: success = demangle_args (work, mangled, declp);
620: }
621: else
622: {
623: /* Non-GNU demanglers use a specific token to mark the start
624: of the outermost function argument tokens. Typically 'F',
625: for ARM-demangling, for example. So if we find something
626: we are not prepared for, it must be an error. */
627: success = 0;
628: }
629: break;
630: }
631: if (AUTO_DEMANGLING || GNU_DEMANGLING)
632: {
633: if (success && expect_func)
634: {
635: func_done = 1;
636: success = demangle_args (work, mangled, declp);
637: }
638: }
639: }
640: if (success && !func_done)
641: {
642: if (AUTO_DEMANGLING || GNU_DEMANGLING)
643: {
644: /* With GNU style demangling, bar__3foo is 'foo::bar(void)', and
645: bar__3fooi is 'foo::bar(int)'. We get here when we find the
646: first case, and need to ensure that the '(void)' gets added to
647: the current declp. Note that with ARM, the first case
648: represents the name of a static data member 'foo::bar',
649: which is in the current declp, so we leave it alone. */
650: success = demangle_args (work, mangled, declp);
651: }
652: }
653: if (success && work -> static_type && PRINT_ARG_TYPES)
654: {
655: string_append (declp, " static");
656: }
657: if (success && work -> const_type && PRINT_ARG_TYPES)
658: {
659: string_append (declp, " const");
660: }
661: return (success);
662: }
663:
664: #if 0
665:
666: static int
667: demangle_method_args (work, mangled, declp)
668: struct work_stuff *work;
669: CONST char **mangled;
670: string *declp;
671: {
672: int success = 0;
673:
674: if (work -> static_type)
675: {
676: string_append (declp, *mangled + 1);
677: *mangled += strlen (*mangled);
678: success = 1;
679: }
680: else
681: {
682: success = demangle_args (work, mangled, declp);
683: }
684: return (success);
685: }
686:
687: #endif
688:
689: static int
690: demangle_template (work, mangled, tname, trawname)
691: struct work_stuff *work;
692: CONST char **mangled;
693: string *tname;
694: string *trawname;
695: {
696: int i;
697: int is_pointer;
698: int is_real;
699: int is_integral;
700: int r;
701: int need_comma = 0;
702: int success = 0;
703: int done;
704: CONST char *old_p;
705: CONST char *start;
706: int symbol_len;
707: string temp;
708:
709: (*mangled)++;
710: start = *mangled;
711: /* get template name */
712: if ((r = consume_count (mangled)) == 0)
713: {
714: return (0);
715: }
716: if (trawname)
717: string_appendn (trawname, *mangled, r);
718: string_appendn (tname, *mangled, r);
719: *mangled += r;
720: string_append (tname, "<");
721: /* get size of template parameter list */
722: if (!get_count (mangled, &r))
723: {
724: return (0);
725: }
726: for (i = 0; i < r; i++)
727: {
728: if (need_comma)
729: {
730: string_append (tname, ", ");
731: }
732: /* Z for type parameters */
733: if (**mangled == 'Z')
734: {
735: (*mangled)++;
736: /* temp is initialized in do_type */
737: success = do_type (work, mangled, &temp);
738: if (success)
739: {
740: string_appends (tname, &temp);
741: }
742: string_delete(&temp);
743: if (!success)
744: {
745: break;
746: }
747: }
748: else
749: {
750: /* otherwise, value parameter */
751: old_p = *mangled;
752: is_pointer = 0;
753: is_real = 0;
754: is_integral = 0;
755: done = 0;
756: /* temp is initialized in do_type */
757: success = do_type (work, mangled, &temp);
758: if (success)
759: {
760: string_appends (tname, &temp);
761: }
762: string_delete(&temp);
763: if (!success)
764: {
765: break;
766: }
767: string_append (tname, "=");
768: while (*old_p && !done)
769: {
770: switch (*old_p)
771: {
772: case 'P':
773: case 'R':
774: done = is_pointer = 1;
775: break;
776: case 'C': /* const */
777: case 'S': /* explicitly signed [char] */
778: case 'U': /* unsigned */
779: case 'V': /* volatile */
780: case 'F': /* function */
781: case 'M': /* member function */
782: case 'O': /* ??? */
783: old_p++;
784: continue;
785: case 'Q': /* repetition of following */
786: case 'T': /* remembered type */
787: abort ();
788: break;
789: case 'v': /* void */
790: abort ();
791: break;
792: case 'x': /* long long */
793: case 'l': /* long */
794: case 'i': /* int */
795: case 's': /* short */
796: case 'c': /* char */
797: case 'w': /* wchar_t */
798: done = is_integral = 1;
799: break;
800: case 'r': /* long double */
801: case 'd': /* double */
802: case 'f': /* float */
803: done = is_real = 1;
804: break;
805: default:
806: abort ();
807: }
808: }
809: if (is_integral)
810: {
811: if (**mangled == 'm')
812: {
813: string_appendn (tname, "-", 1);
814: (*mangled)++;
815: }
816: while (isdigit (**mangled))
817: {
818: string_appendn (tname, *mangled, 1);
819: (*mangled)++;
820: }
821: }
822: else if (is_real)
823: {
824: if (**mangled == 'm')
825: {
826: string_appendn (tname, "-", 1);
827: (*mangled)++;
828: }
829: while (isdigit (**mangled))
830: {
831: string_appendn (tname, *mangled, 1);
832: (*mangled)++;
833: }
834: if (**mangled == '.') /* fraction */
835: {
836: string_appendn (tname, ".", 1);
837: (*mangled)++;
838: while (isdigit (**mangled))
839: {
840: string_appendn (tname, *mangled, 1);
841: (*mangled)++;
842: }
843: }
844: if (**mangled == 'e') /* exponent */
845: {
846: string_appendn (tname, "e", 1);
847: (*mangled)++;
848: while (isdigit (**mangled))
849: {
850: string_appendn (tname, *mangled, 1);
851: (*mangled)++;
852: }
853: }
854: }
855: else if (is_pointer)
856: {
857: if (!get_count (mangled, &symbol_len))
858: {
859: success = 0;
860: break;
861: }
862: string_appendn (tname, *mangled, symbol_len);
863: *mangled += symbol_len;
864: }
865: }
866: need_comma = 1;
867: }
868: string_append (tname, ">");
869:
870: /*
871: if (work -> static_type)
872: {
873: string_append (declp, *mangled + 1);
874: *mangled += strlen (*mangled);
875: success = 1;
876: }
877: else
878: {
879: success = demangle_args (work, mangled, declp);
880: }
881: }
882: */
883: return (success);
884: }
885:
886: static int
887: arm_pt (work, mangled, n, anchor, args)
888: struct work_stuff *work;
889: CONST char *mangled;
890: int n;
891: CONST char **anchor, **args;
892: {
893: /* ARM template? */
894: if (ARM_DEMANGLING && (*anchor = strstr(mangled, "__pt__")))
895: {
896: int len;
897: *args = *anchor + 6;
898: len = consume_count (args);
899: if (*args + len == mangled + n && **args == '_')
900: {
901: ++*args;
902: return 1;
903: }
904: }
905: return 0;
906: }
907:
908: static int
909: demangle_class_name (work, mangled, declp)
910: struct work_stuff *work;
911: CONST char **mangled;
912: string *declp;
913: {
914: int n;
915: int success = 0;
916:
917: n = consume_count (mangled);
918: if (strlen (*mangled) >= n)
919: {
920: CONST char *p;
921: CONST char *args;
922: CONST char *e = *mangled + n;
923: /* ARM template? */
924: if (arm_pt (work, *mangled, n, &p, &args))
925: {
926: string arg;
927: string_init (&arg);
928: string_appendn (declp, *mangled, p - *mangled);
929: string_append (declp, "<");
930: /* should do error checking here */
931: while (args < e) {
932: string_clear (&arg);
933: do_type (work, &args, &arg);
934: string_appends (declp, &arg);
935: string_append (declp, ",");
936: }
937: string_delete (&arg);
938: --declp->p;
939: string_append (declp, ">");
940: }
941: else
942: {
943: string_appendn (declp, *mangled, n);
944: }
945: *mangled += n;
946: success = 1;
947: }
948: return (success);
949: }
950:
951: /*
952:
953: LOCAL FUNCTION
954:
955: demangle_class -- demangle a mangled class sequence
956:
957: SYNOPSIS
958:
959: static int
960: demangle_class (struct work_stuff *work, const char **mangled,
961: strint *declp)
962:
963: DESCRIPTION
964:
965: DECLP points to the buffer into which demangling is being done.
966:
967: *MANGLED points to the current token to be demangled. On input,
968: it points to a mangled class (I.E. "3foo", "13verylongclass", etc.)
969: On exit, it points to the next token after the mangled class on
970: success, or the first unconsumed token on failure.
971:
972: If the CONSTRUCTOR or DESTRUCTOR flags are set in WORK, then
973: we are demangling a constructor or destructor. In this case
974: we prepend "class::class" or "class::~class" to DECLP.
975:
976: Otherwise, we prepend "class::" to the current DECLP.
977:
978: Reset the constructor/destructor flags once they have been
979: "consumed". This allows demangle_class to be called later during
980: the same demangling, to do normal class demangling.
981:
982: Returns 1 if demangling is successful, 0 otherwise.
983:
984: */
985:
986: static int
987: demangle_class (work, mangled, declp)
988: struct work_stuff *work;
989: CONST char **mangled;
990: string *declp;
991: {
992: int success = 0;
993: string class_name;
994:
995: string_init (&class_name);
996: if (demangle_class_name (work, mangled, &class_name))
997: {
998: if ((work->constructor & 1) || (work->destructor & 1))
999: {
1000: string_prepends (declp, &class_name);
1001: if (work -> destructor & 1)
1002: {
1003: string_prepend (declp, "~");
1004: work -> destructor -= 1;
1005: }
1006: else
1007: {
1008: work -> constructor -= 1;
1009: }
1010: }
1011: string_prepend (declp, "::");
1012: string_prepends (declp, &class_name);
1013: success = 1;
1014: }
1015: string_delete (&class_name);
1016: return (success);
1017: }
1018:
1019: /*
1020:
1021: LOCAL FUNCTION
1022:
1023: demangle_prefix -- consume the mangled name prefix and find signature
1024:
1025: SYNOPSIS
1026:
1027: static int
1028: demangle_prefix (struct work_stuff *work, const char **mangled,
1029: string *declp);
1030:
1031: DESCRIPTION
1032:
1033: Consume and demangle the prefix of the mangled name.
1034:
1035: DECLP points to the string buffer into which demangled output is
1036: placed. On entry, the buffer is empty. On exit it contains
1037: the root function name, the demangled operator name, or in some
1038: special cases either nothing or the completely demangled result.
1039:
1040: MANGLED points to the current pointer into the mangled name. As each
1041: token of the mangled name is consumed, it is updated. Upon entry
1042: the current mangled name pointer points to the first character of
1043: the mangled name. Upon exit, it should point to the first character
1044: of the signature if demangling was successful, or to the first
1045: unconsumed character if demangling of the prefix was unsuccessful.
1046:
1047: Returns 1 on success, 0 otherwise.
1048: */
1049:
1050: static int
1051: demangle_prefix (work, mangled, declp)
1052: struct work_stuff *work;
1053: CONST char **mangled;
1054: string *declp;
1055: {
1056: int success = 1;
1057: CONST char *scan;
1058: int i;
1059:
1060: if (strncmp(*mangled, "_GLOBAL_$D$", 11) == 0)
1061: {
1062: /* it's a GNU global destructor to be executed at program exit */
1063: (*mangled) += 11;
1064: work->destructor = 2;
1065: }
1066: else if (strncmp(*mangled, "_GLOBAL_$I$", 11) == 0)
1067: {
1068: /* it's a GNU global constructor to be executed at program initial */
1069: (*mangled) += 11;
1070: work->constructor = 2;
1071: }
1072: else if (ARM_DEMANGLING && strncmp(*mangled, "__std__", 7) == 0)
1073: {
1074: /* it's a ARM global destructor to be executed at program exit */
1075: (*mangled) += 7;
1076: work->destructor = 2;
1077: }
1078: else if (ARM_DEMANGLING && strncmp(*mangled, "__sti__", 7) == 0)
1079: {
1080: /* it's a ARM global constructor to be executed at program initial */
1081: (*mangled) += 7;
1082: work->constructor = 2;
1083: }
1084:
1085: /* This block of code is a reduction in strength time optimization
1086: of:
1087: scan = strstr (*mangled, "__"); */
1088:
1089: {
1090: scan = *mangled;
1091:
1092: do {
1093: scan = strchr (scan, '_');
1094: } while (scan != NULL && *++scan != '_');
1095:
1096: if (scan != NULL) --scan;
1097: }
1098:
1099: if (scan != NULL)
1100: {
1101: /* We found a sequence of two or more '_', ensure that we start at
1102: the last pair in the sequence. */
1103: i = strspn (scan, "_");
1104: if (i > 2)
1105: {
1106: scan += (i - 2);
1107: }
1108: }
1109:
1110: if (scan == NULL)
1111: {
1112: success = 0;
1113: }
1114: else if (work -> static_type)
1115: {
1116: if (!isdigit (scan[0]) && (scan[0] != 't'))
1117: {
1118: success = 0;
1119: }
1120: }
1121: else if ((scan == *mangled) &&
1122: (isdigit (scan[2]) || (scan[2] == 'Q') || (scan[2] == 't')))
1123: {
1124: /* The ARM says nothing about the mangling of local variables.
1125: But cfront mangles local variables by prepending __<nesting_level>
1126: to them. As an extension to ARM demangling we handle this case. */
1127: if ((LUCID_DEMANGLING || ARM_DEMANGLING) && isdigit (scan[2]))
1128: {
1129: *mangled = scan + 2;
1130: consume_count (mangled);
1131: string_append (declp, *mangled);
1132: *mangled += strlen (*mangled);
1133: success = 1;
1134: }
1135: else
1136: {
1137: /* A GNU style constructor starts with "__[0-9Qt]. */
1138: work -> constructor += 1;
1139: *mangled = scan + 2;
1140: }
1141: }
1142: else if ((scan == *mangled) && !isdigit (scan[2]) && (scan[2] != 't'))
1143: {
1144: /* Mangled name starts with "__". Skip over any leading '_' characters,
1145: then find the next "__" that separates the prefix from the signature.
1146: */
1147: if (!(ARM_DEMANGLING || LUCID_DEMANGLING)
1148: || (arm_special (work, mangled, declp) == 0))
1149: {
1150: while (*scan == '_')
1151: {
1152: scan++;
1153: }
1154: if ((scan = strstr (scan, "__")) == NULL || (*(scan + 2) == '\0'))
1155: {
1156: /* No separator (I.E. "__not_mangled"), or empty signature
1157: (I.E. "__not_mangled_either__") */
1158: success = 0;
1159: }
1160: else
1161: {
1162: demangle_function_name (work, mangled, declp, scan);
1163: }
1164: }
1165: }
1166: else if (*(scan + 2) != '\0')
1167: {
1168: /* Mangled name does not start with "__" but does have one somewhere
1169: in there with non empty stuff after it. Looks like a global
1170: function name. */
1171: demangle_function_name (work, mangled, declp, scan);
1172: }
1173: else
1174: {
1175: /* Doesn't look like a mangled name */
1176: success = 0;
1177: }
1178:
1179: if (!success && (work->constructor == 2 || work->destructor == 2))
1180: {
1181: string_append (declp, *mangled);
1182: *mangled += strlen (*mangled);
1183: success = 1;
1184: }
1185: return (success);
1186: }
1187:
1188: /*
1189:
1190: LOCAL FUNCTION
1191:
1192: gnu_special -- special handling of gnu mangled strings
1193:
1194: SYNOPSIS
1195:
1196: static int
1197: gnu_special (struct work_stuff *work, const char **mangled,
1198: string *declp);
1199:
1200:
1201: DESCRIPTION
1202:
1203: Process some special GNU style mangling forms that don't fit
1204: the normal pattern. For example:
1205:
1206: _$_3foo (destructor for class foo)
1207: _vt$foo (foo virtual table)
1208: _vt$foo$bar (foo::bar virtual table)
1209: _3foo$varname (static data member)
1210: _Q22rs2tu$vw (static data member)
1211: __t6vector1Zii (constructor with template)
1212: */
1213:
1214: static int
1215: gnu_special (work, mangled, declp)
1216: struct work_stuff *work;
1217: CONST char **mangled;
1218: string *declp;
1219: {
1220: int n;
1221: int success = 1;
1222: CONST char *p;
1223:
1224: if ((*mangled)[0] == '_'
1225: && strchr (cplus_markers, (*mangled)[1]) != NULL
1226: && (*mangled)[2] == '_')
1227: {
1228: /* Found a GNU style destructor, get past "_<CPLUS_MARKER>_" */
1229: (*mangled) += 3;
1230: work -> destructor += 1;
1231: }
1232: else if ((*mangled)[0] == '_'
1233: && (*mangled)[1] == 'v'
1234: && (*mangled)[2] == 't'
1235: && strchr (cplus_markers, (*mangled)[3]) != NULL)
1236: {
1237: /* Found a GNU style virtual table, get past "_vt<CPLUS_MARKER>"
1238: and create the decl. Note that we consume the entire mangled
1239: input string, which means that demangle_signature has no work
1240: to do. */
1241: (*mangled) += 4;
1242: while (**mangled != '\0')
1243: {
1244: if (isdigit(*mangled[0]))
1245: {
1246: n = consume_count(mangled);
1247: }
1248: else
1249: {
1250: n = strcspn (*mangled, cplus_markers);
1251: }
1252: string_appendn (declp, *mangled, n);
1253: (*mangled) += n;
1254:
1255: if (**mangled != '\0')
1256: {
1257: string_append (declp, "::");
1258: (*mangled)++;
1259: }
1260: }
1261: string_append (declp, " virtual table");
1262: }
1263: else if ((*mangled)[0] == '_'
1264: && (strchr("0123456789Qt", (*mangled)[1]) != NULL)
1265: && (p = strpbrk (*mangled, cplus_markers)) != NULL)
1266: {
1267: /* static data member, "_3foo$varname" for example */
1268: (*mangled)++;
1269: switch (**mangled)
1270: {
1271: case 'Q':
1272: success = demangle_qualified (work, mangled, declp, 0, 1);
1273: break;
1274: case 't':
1275: success = demangle_template (work, mangled, declp, 0);
1276: break;
1277: default:
1278: n = consume_count (mangled);
1279: string_appendn (declp, *mangled, n);
1280: (*mangled) += n;
1281: }
1282: if (success && (p == *mangled))
1283: {
1284: /* Consumed everything up to the cplus_marker, append the
1285: variable name. */
1286: (*mangled)++;
1287: string_append (declp, "::");
1288: n = strlen (*mangled);
1289: string_appendn (declp, *mangled, n);
1290: (*mangled) += n;
1291: }
1292: else
1293: {
1294: success = 0;
1295: }
1296: }
1297: else
1298: {
1299: success = 0;
1300: }
1301: return (success);
1302: }
1303:
1304: /*
1305:
1306: LOCAL FUNCTION
1307:
1308: arm_special -- special handling of ARM/lucid mangled strings
1309:
1310: SYNOPSIS
1311:
1312: static int
1313: arm_special (struct work_stuff *work, const char **mangled,
1314: string *declp);
1315:
1316:
1317: DESCRIPTION
1318:
1319: Process some special ARM style mangling forms that don't fit
1320: the normal pattern. For example:
1321:
1322: __vtbl__3foo (foo virtual table)
1323: __vtbl__3foo__3bar (bar::foo virtual table)
1324:
1325: */
1326:
1327: static int
1328: arm_special (work, mangled, declp)
1329: struct work_stuff *work;
1330: CONST char **mangled;
1331: string *declp;
1332: {
1333: int n;
1334: int success = 1;
1335: CONST char *scan;
1336:
1337: if (strncmp (*mangled, ARM_VTABLE_STRING, ARM_VTABLE_STRLEN) == 0)
1338: {
1339: /* Found a ARM style virtual table, get past ARM_VTABLE_STRING
1340: and create the decl. Note that we consume the entire mangled
1341: input string, which means that demangle_signature has no work
1342: to do. */
1343: scan = *mangled + ARM_VTABLE_STRLEN;
1344: while (*scan != '\0') /* first check it can be demangled */
1345: {
1346: n = consume_count (&scan);
1347: if (n==0)
1348: {
1349: return (0); /* no good */
1350: }
1351: scan += n;
1352: if (scan[0] == '_' && scan[1] == '_')
1353: {
1354: scan += 2;
1355: }
1356: }
1357: (*mangled) += ARM_VTABLE_STRLEN;
1358: while (**mangled != '\0')
1359: {
1360: n = consume_count (mangled);
1361: string_prependn (declp, *mangled, n);
1362: (*mangled) += n;
1363: if ((*mangled)[0] == '_' && (*mangled)[1] == '_')
1364: {
1365: string_prepend (declp, "::");
1366: (*mangled) += 2;
1367: }
1368: }
1369: string_append (declp, " virtual table");
1370: }
1371: else
1372: {
1373: success = 0;
1374: }
1375: return (success);
1376: }
1377:
1378: /*
1379:
1380: LOCAL FUNCTION
1381:
1382: demangle_qualified -- demangle 'Q' qualified name strings
1383:
1384: SYNOPSIS
1385:
1386: static int
1387: demangle_qualified (struct work_stuff *, const char *mangled,
1388: string *result, int isfuncname, int append);
1389:
1390: DESCRIPTION
1391:
1392: Demangle a qualified name, such as "Q25Outer5Inner" which is
1393: the mangled form of "Outer::Inner". The demangled output is
1394: prepended or appended to the result string according to the
1395: state of the append flag.
1396:
1397: If isfuncname is nonzero, then the qualified name we are building
1398: is going to be used as a member function name, so if it is a
1399: constructor or destructor function, append an appropriate
1400: constructor or destructor name. I.E. for the above example,
1401: the result for use as a constructor is "Outer::Inner::Inner"
1402: and the result for use as a destructor is "Outer::Inner::~Inner".
1403:
1404: BUGS
1405:
1406: Numeric conversion is ASCII dependent (FIXME).
1407:
1408: */
1409:
1410: static int
1411: demangle_qualified (work, mangled, result, isfuncname, append)
1412: struct work_stuff *work;
1413: CONST char **mangled;
1414: string *result;
1415: int isfuncname;
1416: int append;
1417: {
1418: int qualifiers;
1419: int namelength;
1420: int success = 1;
1421: CONST char *p;
1422: char num[2];
1423: string temp;
1424:
1425: string_init (&temp);
1426: switch ((*mangled)[1])
1427: {
1428: case '_':
1429: /* GNU mangled name with more than 9 classes. The count is preceded
1430: by an underscore (to distinguish it from the <= 9 case) and followed
1431: by an underscore. */
1432: p = *mangled + 2;
1433: qualifiers = atoi (p);
1434: if (!isdigit (*p) || *p == '0')
1435: success = 0;
1436:
1437: /* Skip the digits. */
1438: while (isdigit (*p))
1439: ++p;
1440:
1441: if (*p != '_')
1442: success = 0;
1443:
1444: *mangled = p + 1;
1445: break;
1446:
1447: case '1':
1448: case '2':
1449: case '3':
1450: case '4':
1451: case '5':
1452: case '6':
1453: case '7':
1454: case '8':
1455: case '9':
1456: /* The count is in a single digit. */
1457: num[0] = (*mangled)[1];
1458: num[1] = '\0';
1459: qualifiers = atoi (num);
1460:
1461: /* If there is an underscore after the digit, skip it. This is
1462: said to be for ARM-qualified names, but the ARM makes no
1463: mention of such an underscore. Perhaps cfront uses one. */
1464: if ((*mangled)[2] == '_')
1465: {
1466: (*mangled)++;
1467: }
1468: (*mangled) += 2;
1469: break;
1470:
1471: case '0':
1472: default:
1473: success = 0;
1474: }
1475:
1476: if (!success)
1477: return success;
1478:
1479: /* Pick off the names and collect them in the temp buffer in the order
1480: in which they are found, separated by '::'. */
1481:
1482: while (qualifiers-- > 0)
1483: {
1484: if (*mangled[0] == 't')
1485: {
1486: success = demangle_template(work, mangled, &temp, 0);
1487: if (!success) break;
1488: }
1489: else
1490: {
1491: namelength = consume_count (mangled);
1492: if (strlen (*mangled) < namelength)
1493: {
1494: /* Simple sanity check failed */
1495: success = 0;
1496: break;
1497: }
1498: string_appendn (&temp, *mangled, namelength);
1499: *mangled += namelength;
1500: }
1501: if (qualifiers > 0)
1502: {
1503: string_appendn (&temp, "::", 2);
1504: }
1505: }
1506:
1507: /* If we are using the result as a function name, we need to append
1508: the appropriate '::' separated constructor or destructor name.
1509: We do this here because this is the most convenient place, where
1510: we already have a pointer to the name and the length of the name. */
1511:
1512: if (isfuncname && (work->constructor & 1 || work->destructor & 1))
1513: {
1514: string_appendn (&temp, "::", 2);
1515: if (work -> destructor & 1)
1516: {
1517: string_append (&temp, "~");
1518: }
1519: string_appendn (&temp, (*mangled) - namelength, namelength);
1520: }
1521:
1522: /* Now either prepend the temp buffer to the result, or append it,
1523: depending upon the state of the append flag. */
1524:
1525: if (append)
1526: {
1527: string_appends (result, &temp);
1528: }
1529: else
1530: {
1531: if (!STRING_EMPTY (result))
1532: {
1533: string_appendn (&temp, "::", 2);
1534: }
1535: string_prepends (result, &temp);
1536: }
1537:
1538: string_delete (&temp);
1539: return (success);
1540: }
1541:
1542: /*
1543:
1544: LOCAL FUNCTION
1545:
1546: get_count -- convert an ascii count to integer, consuming tokens
1547:
1548: SYNOPSIS
1549:
1550: static int
1551: get_count (const char **type, int *count)
1552:
1553: DESCRIPTION
1554:
1555: Return 0 if no conversion is performed, 1 if a string is converted.
1556: */
1557:
1558: static int
1559: get_count (type, count)
1560: CONST char **type;
1561: int *count;
1562: {
1563: CONST char *p;
1564: int n;
1565:
1566: if (!isdigit (**type))
1567: {
1568: return (0);
1569: }
1570: else
1571: {
1572: *count = **type - '0';
1573: (*type)++;
1574: if (isdigit (**type))
1575: {
1576: p = *type;
1577: n = *count;
1578: do
1579: {
1580: n *= 10;
1581: n += *p - '0';
1582: p++;
1583: }
1584: while (isdigit (*p));
1585: if (*p == '_')
1586: {
1587: *type = p + 1;
1588: *count = n;
1589: }
1590: }
1591: }
1592: return (1);
1593: }
1594:
1595: /* result will be initialised here; it will be freed on failure */
1596:
1597: static int
1598: do_type (work, mangled, result)
1599: struct work_stuff *work;
1600: CONST char **mangled;
1601: string *result;
1602: {
1603: int n;
1604: int done;
1605: int success;
1606: string decl;
1607: CONST char *remembered_type;
1608: int constp;
1609: int volatilep;
1610:
1611: string_init (&decl);
1612: string_init (result);
1613:
1614: done = 0;
1615: success = 1;
1616: while (success && !done)
1617: {
1618: int member;
1619: switch (**mangled)
1620: {
1621:
1622: /* A pointer type */
1623: case 'P':
1624: (*mangled)++;
1625: string_prepend (&decl, "*");
1626: break;
1627:
1628: /* A reference type */
1629: case 'R':
1630: (*mangled)++;
1631: string_prepend (&decl, "&");
1632: break;
1633:
1634: /* An array */
1635: case 'A':
1636: {
1637: CONST char *p = ++(*mangled);
1638:
1639: string_prepend (&decl, "(");
1640: string_append (&decl, ")[");
1641: /* Copy anything up until the next underscore (the size of the
1642: array). */
1643: while (**mangled && **mangled != '_')
1644: ++(*mangled);
1645: if (**mangled == '_')
1646: {
1647: string_appendn (&decl, p, *mangled - p);
1648: string_append (&decl, "]");
1649: *mangled += 1;
1650: }
1651: else
1652: success = 0;
1653: break;
1654: }
1655:
1656: /* A back reference to a previously seen type */
1657: case 'T':
1658: (*mangled)++;
1659: if (!get_count (mangled, &n) || n >= work -> ntypes)
1660: {
1661: success = 0;
1662: }
1663: else
1664: {
1665: remembered_type = work -> typevec[n];
1666: mangled = &remembered_type;
1667: }
1668: break;
1669:
1670: /* A function */
1671: case 'F':
1672: (*mangled)++;
1673: if (!STRING_EMPTY (&decl) && decl.b[0] == '*')
1674: {
1675: string_prepend (&decl, "(");
1676: string_append (&decl, ")");
1677: }
1678: /* After picking off the function args, we expect to either find the
1679: function return type (preceded by an '_') or the end of the
1680: string. */
1681: if (!demangle_args (work, mangled, &decl)
1682: || (**mangled != '_' && **mangled != '\0'))
1683: {
1684: success = 0;
1685: }
1686: if (success && (**mangled == '_'))
1687: {
1688: (*mangled)++;
1689: }
1690: break;
1691:
1692: case 'M':
1693: case 'O':
1694: {
1695: constp = 0;
1696: volatilep = 0;
1697:
1698: member = **mangled == 'M';
1699: (*mangled)++;
1700: if (!isdigit (**mangled))
1701: {
1702: success = 0;
1703: break;
1704: }
1705: n = consume_count (mangled);
1706: if (strlen (*mangled) < n)
1707: {
1708: success = 0;
1709: break;
1710: }
1711: string_append (&decl, ")");
1712: string_prepend (&decl, "::");
1713: string_prependn (&decl, *mangled, n);
1714: string_prepend (&decl, "(");
1715: *mangled += n;
1716: if (member)
1717: {
1718: if (**mangled == 'C')
1719: {
1720: (*mangled)++;
1721: constp = 1;
1722: }
1723: if (**mangled == 'V')
1724: {
1725: (*mangled)++;
1726: volatilep = 1;
1727: }
1728: if (*(*mangled)++ != 'F')
1729: {
1730: success = 0;
1731: break;
1732: }
1733: }
1734: if ((member && !demangle_args (work, mangled, &decl))
1735: || **mangled != '_')
1736: {
1737: success = 0;
1738: break;
1739: }
1740: (*mangled)++;
1741: if (! PRINT_ANSI_QUALIFIERS)
1742: {
1743: break;
1744: }
1745: if (constp)
1746: {
1747: APPEND_BLANK (&decl);
1748: string_append (&decl, "const");
1749: }
1750: if (volatilep)
1751: {
1752: APPEND_BLANK (&decl);
1753: string_append (&decl, "volatile");
1754: }
1755: break;
1756: }
1757: case 'G':
1758: (*mangled)++;
1759: break;
1760:
1761: case 'C':
1762: (*mangled)++;
1763: /*
1764: if ((*mangled)[1] == 'P')
1765: {
1766: */
1767: if (PRINT_ANSI_QUALIFIERS)
1768: {
1769: if (!STRING_EMPTY (&decl))
1770: {
1771: string_prepend (&decl, " ");
1772: }
1773: string_prepend (&decl, "const");
1774: }
1775: break;
1776: /*
1777: }
1778: */
1779:
1780: /* fall through */
1781: default:
1782: done = 1;
1783: break;
1784: }
1785: }
1786:
1787: switch (**mangled)
1788: {
1789: /* A qualified name, such as "Outer::Inner". */
1790: case 'Q':
1791: success = demangle_qualified (work, mangled, result, 0, 1);
1792: break;
1793:
1794: default:
1795: success = demangle_fund_type (work, mangled, result);
1796: break;
1797: }
1798:
1799: if (success)
1800: {
1801: if (!STRING_EMPTY (&decl))
1802: {
1803: string_append (result, " ");
1804: string_appends (result, &decl);
1805: }
1806: }
1807: else
1808: {
1809: string_delete (result);
1810: }
1811: string_delete (&decl);
1812: return (success);
1813: }
1814:
1815: /* Given a pointer to a type string that represents a fundamental type
1816: argument (int, long, unsigned int, etc) in TYPE, a pointer to the
1817: string in which the demangled output is being built in RESULT, and
1818: the WORK structure, decode the types and add them to the result.
1819:
1820: For example:
1821:
1822: "Ci" => "const int"
1823: "Sl" => "signed long"
1824: "CUs" => "const unsigned short"
1825:
1826: */
1827:
1828: static int
1829: demangle_fund_type (work, mangled, result)
1830: struct work_stuff *work;
1831: CONST char **mangled;
1832: string *result;
1833: {
1834: int done = 0;
1835: int success = 1;
1836:
1837: /* First pick off any type qualifiers. There can be more than one. */
1838:
1839: while (!done)
1840: {
1841: switch (**mangled)
1842: {
1843: case 'C':
1844: (*mangled)++;
1845: if (PRINT_ANSI_QUALIFIERS)
1846: {
1847: APPEND_BLANK (result);
1848: string_append (result, "const");
1849: }
1850: break;
1851: case 'U':
1852: (*mangled)++;
1853: APPEND_BLANK (result);
1854: string_append (result, "unsigned");
1855: break;
1856: case 'S': /* signed char only */
1857: (*mangled)++;
1858: APPEND_BLANK (result);
1859: string_append (result, "signed");
1860: break;
1861: case 'V':
1862: (*mangled)++;
1863: if (PRINT_ANSI_QUALIFIERS)
1864: {
1865: APPEND_BLANK (result);
1866: string_append (result, "volatile");
1867: }
1868: break;
1869: default:
1870: done = 1;
1871: break;
1872: }
1873: }
1874:
1875: /* Now pick off the fundamental type. There can be only one. */
1876:
1877: switch (**mangled)
1878: {
1879: case '\0':
1880: case '_':
1881: break;
1882: case 'v':
1883: (*mangled)++;
1884: APPEND_BLANK (result);
1885: string_append (result, "void");
1886: break;
1887: case 'x':
1888: (*mangled)++;
1889: APPEND_BLANK (result);
1890: string_append (result, "long long");
1891: break;
1892: case 'l':
1893: (*mangled)++;
1894: APPEND_BLANK (result);
1895: string_append (result, "long");
1896: break;
1897: case 'i':
1898: (*mangled)++;
1899: APPEND_BLANK (result);
1900: string_append (result, "int");
1901: break;
1902: case 's':
1903: (*mangled)++;
1904: APPEND_BLANK (result);
1905: string_append (result, "short");
1906: break;
1907: case 'c':
1908: (*mangled)++;
1909: APPEND_BLANK (result);
1910: string_append (result, "char");
1911: break;
1912: case 'w':
1913: (*mangled)++;
1914: APPEND_BLANK (result);
1915: string_append (result, "wchar_t");
1916: break;
1917: case 'r':
1918: (*mangled)++;
1919: APPEND_BLANK (result);
1920: string_append (result, "long double");
1921: break;
1922: case 'd':
1923: (*mangled)++;
1924: APPEND_BLANK (result);
1925: string_append (result, "double");
1926: break;
1927: case 'f':
1928: (*mangled)++;
1929: APPEND_BLANK (result);
1930: string_append (result, "float");
1931: break;
1932: case 'G':
1933: (*mangled)++;
1934: if (!isdigit (**mangled))
1935: {
1936: success = 0;
1937: break;
1938: }
1939: /* fall through */
1940: /* An explicit type, such as "6mytype" or "7integer" */
1941: case '0':
1942: case '1':
1943: case '2':
1944: case '3':
1945: case '4':
1946: case '5':
1947: case '6':
1948: case '7':
1949: case '8':
1950: case '9':
1951: APPEND_BLANK (result);
1952: if (!demangle_class_name (work, mangled, result)) {
1953: --result->p;
1954: success = 0;
1955: }
1956: break;
1957: case 't':
1958: success = demangle_template(work,mangled, result, 0);
1959: break;
1960: default:
1961: success = 0;
1962: break;
1963: }
1964:
1965: return (success);
1966: }
1967:
1968: /* `result' will be initialized in do_type; it will be freed on failure */
1969:
1970: static int
1971: do_arg (work, mangled, result)
1972: struct work_stuff *work;
1973: CONST char **mangled;
1974: string *result;
1975: {
1976: CONST char *start = *mangled;
1977:
1978: if (!do_type (work, mangled, result))
1979: {
1980: return (0);
1981: }
1982: else
1983: {
1984: remember_type (work, start, *mangled - start);
1985: return (1);
1986: }
1987: }
1988:
1989: static void
1990: remember_type (work, start, len)
1991: struct work_stuff *work;
1992: CONST char *start;
1993: int len;
1994: {
1995: char *tem;
1996:
1997: if (work -> ntypes >= work -> typevec_size)
1998: {
1999: if (work -> typevec_size == 0)
2000: {
2001: work -> typevec_size = 3;
2002: work -> typevec =
2003: (char **) xmalloc (sizeof (char *) * work -> typevec_size);
2004: }
2005: else
2006: {
2007: work -> typevec_size *= 2;
2008: work -> typevec =
2009: (char **) xrealloc ((char *)work -> typevec,
2010: sizeof (char *) * work -> typevec_size);
2011: }
2012: }
2013: tem = xmalloc (len + 1);
2014: memcpy (tem, start, len);
2015: tem[len] = '\0';
2016: work -> typevec[work -> ntypes++] = tem;
2017: }
2018:
2019: /* Forget the remembered types, but not the type vector itself. */
2020:
2021: static void
2022: forget_types (work)
2023: struct work_stuff *work;
2024: {
2025: int i;
2026:
2027: while (work -> ntypes > 0)
2028: {
2029: i = --(work -> ntypes);
2030: if (work -> typevec[i] != NULL)
2031: {
2032: free (work -> typevec[i]);
2033: work -> typevec[i] = NULL;
2034: }
2035: }
2036: }
2037:
2038: /* Process the argument list part of the signature, after any class spec
2039: has been consumed, as well as the first 'F' character (if any). For
2040: example:
2041:
2042: "__als__3fooRT0" => process "RT0"
2043: "complexfunc5__FPFPc_PFl_i" => process "PFPc_PFl_i"
2044:
2045: DECLP must be already initialised, usually non-empty. It won't be freed
2046: on failure.
2047:
2048: Note that g++ differs significantly from ARM and lucid style mangling
2049: with regards to references to previously seen types. For example, given
2050: the source fragment:
2051:
2052: class foo {
2053: public:
2054: foo::foo (int, foo &ia, int, foo &ib, int, foo &ic);
2055: };
2056:
2057: foo::foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; }
2058: void foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; }
2059:
2060: g++ produces the names:
2061:
2062: __3fooiRT0iT2iT2
2063: foo__FiR3fooiT1iT1
2064:
2065: while lcc (and presumably other ARM style compilers as well) produces:
2066:
2067: foo__FiR3fooT1T2T1T2
2068: __ct__3fooFiR3fooT1T2T1T2
2069:
2070: Note that g++ bases it's type numbers starting at zero and counts all
2071: previously seen types, while lucid/ARM bases it's type numbers starting
2072: at one and only considers types after it has seen the 'F' character
2073: indicating the start of the function args. For lucid/ARM style, we
2074: account for this difference by discarding any previously seen types when
2075: we see the 'F' character, and subtracting one from the type number
2076: reference.
2077:
2078: */
2079:
2080: static int
2081: demangle_args (work, mangled, declp)
2082: struct work_stuff *work;
2083: CONST char **mangled;
2084: string *declp;
2085: {
2086: string arg;
2087: int need_comma = 0;
2088: int r;
2089: int t;
2090: CONST char *tem;
2091: char temptype;
2092:
2093: if (PRINT_ARG_TYPES)
2094: {
2095: string_append (declp, "(");
2096: if (**mangled == '\0')
2097: {
2098: string_append (declp, "void");
2099: }
2100: }
2101:
2102: while (**mangled != '_' && **mangled != '\0' && **mangled != 'e')
2103: {
2104: if ((**mangled == 'N') || (**mangled == 'T'))
2105: {
2106: temptype = *(*mangled)++;
2107:
2108: if (temptype == 'N')
2109: {
2110: if (!get_count (mangled, &r))
2111: {
2112: return (0);
2113: }
2114: }
2115: else
2116: {
2117: r = 1;
2118: }
2119: if (!get_count (mangled, &t))
2120: {
2121: return (0);
2122: }
2123: if (LUCID_DEMANGLING || ARM_DEMANGLING)
2124: {
2125: t--;
2126: }
2127: /* Validate the type index. Protect against illegal indices from
2128: malformed type strings. */
2129: if ((t < 0) || (t >= work -> ntypes))
2130: {
2131: return (0);
2132: }
2133: while (--r >= 0)
2134: {
2135: tem = work -> typevec[t];
2136: if (need_comma && PRINT_ARG_TYPES)
2137: {
2138: string_append (declp, ", ");
2139: }
2140: if (!do_arg (work, &tem, &arg))
2141: {
2142: return (0);
2143: }
2144: if (PRINT_ARG_TYPES)
2145: {
2146: string_appends (declp, &arg);
2147: }
2148: string_delete (&arg);
2149: need_comma = 1;
2150: }
2151: }
2152: else
2153: {
2154: if (need_comma & PRINT_ARG_TYPES)
2155: {
2156: string_append (declp, ", ");
2157: }
2158: if (!do_arg (work, mangled, &arg))
2159: {
2160: return (0);
2161: }
2162: if (PRINT_ARG_TYPES)
2163: {
2164: string_appends (declp, &arg);
2165: }
2166: string_delete (&arg);
2167: need_comma = 1;
2168: }
2169: }
2170:
2171: if (**mangled == 'e')
2172: {
2173: (*mangled)++;
2174: if (PRINT_ARG_TYPES)
2175: {
2176: if (need_comma)
2177: {
2178: string_append (declp, ",");
2179: }
2180: string_append (declp, "...");
2181: }
2182: }
2183:
2184: if (PRINT_ARG_TYPES)
2185: {
2186: string_append (declp, ")");
2187: }
2188: return (1);
2189: }
2190:
2191: static void
2192: demangle_function_name (work, mangled, declp, scan)
2193: struct work_stuff *work;
2194: CONST char **mangled;
2195: string *declp;
2196: CONST char *scan;
2197: {
2198: int i;
2199: int len;
2200: string type;
2201: CONST char *tem;
2202:
2203: string_appendn (declp, (*mangled), scan - (*mangled));
2204: string_need (declp, 1);
2205: *(declp -> p) = '\0';
2206:
2207: /* Consume the function name, including the "__" separating the name
2208: from the signature. We are guaranteed that SCAN points to the
2209: separator. */
2210:
2211: (*mangled) = scan + 2;
2212:
2213: if (LUCID_DEMANGLING || ARM_DEMANGLING)
2214: {
2215:
2216: /* See if we have an ARM style constructor or destructor operator.
2217: If so, then just record it, clear the decl, and return.
2218: We can't build the actual constructor/destructor decl until later,
2219: when we recover the class name from the signature. */
2220:
2221: if (strcmp (declp -> b, "__ct") == 0)
2222: {
2223: work -> constructor += 1;
2224: string_clear (declp);
2225: return;
2226: }
2227: else if (strcmp (declp -> b, "__dt") == 0)
2228: {
2229: work -> destructor += 1;
2230: string_clear (declp);
2231: return;
2232: }
2233: }
2234:
2235: if (declp->p - declp->b >= 3
2236: && declp->b[0] == 'o'
2237: && declp->b[1] == 'p'
2238: && strchr (cplus_markers, declp->b[2]) != NULL)
2239: {
2240: /* see if it's an assignment expression */
2241: if (declp->p - declp->b >= 10 /* op$assign_ */
2242: && memcmp (declp->b + 3, "assign_", 7) == 0)
2243: {
2244: for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
2245: {
2246: len = declp->p - declp->b - 10;
2247: if (strlen (optable[i].in) == len
2248: && memcmp (optable[i].in, declp->b + 10, len) == 0)
2249: {
2250: string_clear (declp);
2251: string_append (declp, "operator");
2252: string_append (declp, optable[i].out);
2253: string_append (declp, "=");
2254: break;
2255: }
2256: }
2257: }
2258: else
2259: {
2260: for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
2261: {
2262: int len = declp->p - declp->b - 3;
2263: if (strlen (optable[i].in) == len
2264: && memcmp (optable[i].in, declp->b + 3, len) == 0)
2265: {
2266: string_clear (declp);
2267: string_append (declp, "operator");
2268: string_append (declp, optable[i].out);
2269: break;
2270: }
2271: }
2272: }
2273: }
2274: else if (declp->p - declp->b >= 5 && memcmp (declp->b, "type$", 5) == 0)
2275: {
2276: /* type conversion operator */
2277: tem = declp->b + 5;
2278: if (do_type (work, &tem, &type))
2279: {
2280: string_clear (declp);
2281: string_append (declp, "operator ");
2282: string_appends (declp, &type);
2283: string_delete (&type);
2284: }
2285: }
2286: else if (declp->b[0] == '_' && declp->b[1] == '_'
2287: && declp->b[2] == 'o' && declp->b[3] == 'p')
2288: {
2289: /* ANSI. */
2290: /* type conversion operator. */
2291: tem = declp->b + 4;
2292: if (do_type (work, &tem, &type))
2293: {
2294: string_clear (declp);
2295: string_append (declp, "operator ");
2296: string_appends (declp, &type);
2297: string_delete (&type);
2298: }
2299: }
2300: else if (declp->b[0] == '_' && declp->b[1] == '_'
2301: && declp->b[2] >= 'a' && declp->b[2] <= 'z'
2302: && declp->b[3] >= 'a' && declp->b[3] <= 'z')
2303: {
2304: if (declp->b[4] == '\0')
2305: {
2306: /* Operator. */
2307: for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
2308: {
2309: if (strlen (optable[i].in) == 2
2310: && memcmp (optable[i].in, declp->b + 2, 2) == 0)
2311: {
2312: string_clear (declp);
2313: string_append (declp, "operator");
2314: string_append (declp, optable[i].out);
2315: break;
2316: }
2317: }
2318: }
2319: else
2320: {
2321: if (declp->b[2] == 'a' && declp->b[5] == '\0')
2322: {
2323: /* Assignment. */
2324: for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
2325: {
2326: if (strlen (optable[i].in) == 3
2327: && memcmp (optable[i].in, declp->b + 2, 3) == 0)
2328: {
2329: string_clear (declp);
2330: string_append (declp, "operator");
2331: string_append (declp, optable[i].out);
2332: break;
2333: }
2334: }
2335: }
2336: }
2337: }
2338: }
2339:
2340: /* a mini string-handling package */
2341:
2342: static void
2343: string_need (s, n)
2344: string *s;
2345: int n;
2346: {
2347: int tem;
2348:
2349: if (s->b == NULL)
2350: {
2351: if (n < 32)
2352: {
2353: n = 32;
2354: }
2355: s->p = s->b = xmalloc (n);
2356: s->e = s->b + n;
2357: }
2358: else if (s->e - s->p < n)
2359: {
2360: tem = s->p - s->b;
2361: n += tem;
2362: n *= 2;
2363: s->b = xrealloc (s->b, n);
2364: s->p = s->b + tem;
2365: s->e = s->b + n;
2366: }
2367: }
2368:
2369: static void
2370: string_delete (s)
2371: string *s;
2372: {
2373: if (s->b != NULL)
2374: {
2375: free (s->b);
2376: s->b = s->e = s->p = NULL;
2377: }
2378: }
2379:
2380: static void
2381: string_init (s)
2382: string *s;
2383: {
2384: s->b = s->p = s->e = NULL;
2385: }
2386:
2387: static void
2388: string_clear (s)
2389: string *s;
2390: {
2391: s->p = s->b;
2392: }
2393:
2394: #if 0
2395:
2396: static int
2397: string_empty (s)
2398: string *s;
2399: {
2400: return (s->b == s->p);
2401: }
2402:
2403: #endif
2404:
2405: static void
2406: string_append (p, s)
2407: string *p;
2408: CONST char *s;
2409: {
2410: int n;
2411: if (s == NULL || *s == '\0')
2412: return;
2413: n = strlen (s);
2414: string_need (p, n);
2415: memcpy (p->p, s, n);
2416: p->p += n;
2417: }
2418:
2419: static void
2420: string_appends (p, s)
2421: string *p, *s;
2422: {
2423: int n;
2424:
2425: if (s->b != s->p)
2426: {
2427: n = s->p - s->b;
2428: string_need (p, n);
2429: memcpy (p->p, s->b, n);
2430: p->p += n;
2431: }
2432: }
2433:
2434: static void
2435: string_appendn (p, s, n)
2436: string *p;
2437: CONST char *s;
2438: int n;
2439: {
2440: if (n != 0)
2441: {
2442: string_need (p, n);
2443: memcpy (p->p, s, n);
2444: p->p += n;
2445: }
2446: }
2447:
2448: static void
2449: string_prepend (p, s)
2450: string *p;
2451: CONST char *s;
2452: {
2453: if (s != NULL && *s != '\0')
2454: {
2455: string_prependn (p, s, strlen (s));
2456: }
2457: }
2458:
2459: static void
2460: string_prepends (p, s)
2461: string *p, *s;
2462: {
2463: if (s->b != s->p)
2464: {
2465: string_prependn (p, s->b, s->p - s->b);
2466: }
2467: }
2468:
2469: static void
2470: string_prependn (p, s, n)
2471: string *p;
2472: CONST char *s;
2473: int n;
2474: {
2475: char *q;
2476:
2477: if (n != 0)
2478: {
2479: string_need (p, n);
2480: for (q = p->p - 1; q >= p->b; q--)
2481: {
2482: q[n] = q[0];
2483: }
2484: memcpy (p->b, s, n);
2485: p->p += n;
2486: }
2487: }
2488:
2489: /* To generate a standalone demangler program for testing purposes, just
2490: compile and link this file with -DMAIN. When run, it demangles each
2491: command line arg, or each stdin string, and prints the result on stdout. */
2492:
2493: #ifdef MAIN
2494:
2495: static void
2496: demangle_it (mangled_name)
2497: char *mangled_name;
2498: {
2499: char *result;
2500:
2501: result = cplus_demangle (mangled_name, DMGL_PARAMS | DMGL_ANSI);
2502: if (result == NULL)
2503: {
2504: printf ("%s\n", mangled_name);
2505: }
2506: else
2507: {
2508: printf ("%s\n", result);
2509: free (result);
2510: }
2511: }
2512:
2513: char *
2514: xmalloc (size)
2515: long size;
2516: {
2517: char * newmem;
2518:
2519: if ((newmem = (char *) malloc ((int) size)) == NULL)
2520: {
2521: fprintf (stderr, "\nCan't allocate %u bytes\n", size);
2522: exit (1);
2523: }
2524: return (newmem);
2525: }
2526:
2527: char *
2528: xrealloc (oldmem, size)
2529: PTR oldmem;
2530: long size;
2531: {
2532: char * newmem;
2533:
2534: if ((newmem = (char *) realloc ((char *) oldmem, (int) size)) == NULL)
2535: {
2536: fprintf (stderr, "\nCan't reallocate %u bytes\n", size);
2537: exit (1);
2538: }
2539: return (newmem);
2540: }
2541:
2542: #include "getopt.h"
2543:
2544: static char *program_name;
2545: extern char *program_version;
2546:
2547: static void
2548: usage (stream, status)
2549: FILE *stream;
2550: int status;
2551: {
2552: fprintf (stream, "\
2553: Usage: %s [-_] [-s {gnu,lucid,arm}] [--strip-underscores]\n\
2554: [--format={gnu,lucid,arm}] [--help] [--version] [arg...]\n",
2555: program_name);
2556: exit (status);
2557: }
2558:
2559: #define MBUF_SIZE 512
2560: char mbuffer[MBUF_SIZE];
2561:
2562: /* Defined in the automatically-generated ../binutils/underscore.c. */
2563: extern int prepends_underscore;
2564:
2565: int strip_underscore = 0;
2566:
2567: static struct option long_options[] = {
2568: {"strip-underscores", no_argument, 0, '_'},
2569: {"format", required_argument, 0, 's'},
2570: {"help", no_argument, 0, 'h'},
2571: {"version", no_argument, 0, 'v'},
2572: {0, no_argument, 0, 0}
2573: };
2574:
2575: int
2576: main (argc, argv)
2577: int argc;
2578: char **argv;
2579: {
2580: char *result;
2581: int c;
2582:
2583: program_name = argv[0];
2584: strip_underscore = prepends_underscore;
2585:
2586: while ((c = getopt_long (argc, argv, "_s:", long_options, (int *) 0)) != EOF)
2587: {
2588: switch (c)
2589: {
2590: case '?':
2591: usage (stderr, 1);
2592: break;
2593: case 'h':
2594: usage (stdout, 0);
2595: case 'v':
2596: printf ("GNU %s version %s\n", program_name, program_version);
2597: exit (0);
2598: case '_':
2599: strip_underscore = 1;
2600: break;
2601: case 's':
2602: if (strcmp (optarg, "gnu") == 0)
2603: {
2604: current_demangling_style = gnu_demangling;
2605: }
2606: else if (strcmp (optarg, "lucid") == 0)
2607: {
2608: current_demangling_style = lucid_demangling;
2609: }
2610: else if (strcmp (optarg, "arm") == 0)
2611: {
2612: current_demangling_style = arm_demangling;
2613: }
2614: else
2615: {
2616: fprintf (stderr, "%s: unknown demangling style `%s'\n",
2617: program_name, optarg);
2618: exit (1);
2619: }
2620: break;
2621: }
2622: }
2623:
2624: if (optind < argc)
2625: {
2626: for ( ; optind < argc; optind++)
2627: {
2628: demangle_it (argv[optind]);
2629: }
2630: }
2631: else
2632: {
2633: for (;;)
2634: {
2635: int i = 0;
2636: c = getchar ();
2637: /* Try to read a label. */
2638: while (c != EOF && (isalnum(c) || c == '_' || c == '$' || c == '.'))
2639: {
2640: if (i >= MBUF_SIZE-1)
2641: break;
2642: mbuffer[i++] = c;
2643: c = getchar ();
2644: }
2645: if (i > 0)
2646: {
2647: int skip_first = strip_underscore && i > 1 && mbuffer[0] == '_';
2648: mbuffer[i] = 0;
2649:
2650: result = cplus_demangle (mbuffer+skip_first,
2651: DMGL_PARAMS | DMGL_ANSI);
2652: if (result)
2653: {
2654: fputs (result, stdout);
2655: free (result);
2656: }
2657: else
2658: fputs (mbuffer + skip_first, stdout);
2659: }
2660: if (c == EOF)
2661: break;
2662: putchar (c);
2663: }
2664: }
2665:
2666: exit (0);
2667: }
2668:
2669: #endif /* main */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.