]> git.saurik.com Git - apple/xnu.git/blame - libsa/c++rem3.c
xnu-517.7.21.tar.gz
[apple/xnu.git] / libsa / c++rem3.c
CommitLineData
9bccf70c
A
1// 45678901234567890123456789012345678901234567890123456789012345678901234567890
2/*
3
4Rules specification by
5Stan Shebs of Apple Computer, Inc 2002
6
7Parse and remangle implemented by
8Godfrey van der Linden of Apple Computer, Inc 2002
9
10Rules for demangling IOKit symbols
11
12In Darwin versions 1.0 through at least 5.2, IOKit is compiled using
13GCC version 2. GCC 2's C++ symbol mangling algorithm ultimately
14derives from the basic scheme described in the Annotated C++ Reference
15Manual (ARM), section 7.2.1c, with a number of changes, mostly due to
16the expansion of the language since the ARM was published in 1990.
17
18This description is not complete. It omits RTTI, thunks, and
19templates, since they are not allowed in IOKit. The description also
20mentions mangled name constructs that are not disallowed in IOKit, but
21that as of Jan 2002, did actually appear in any symbol in the base
22system.
23
24A mangled name basically consists of a function name followed
25by two underscores, optionally followed by a signature computed
26from the function's argument types. (Note that in Darwin, the
27compiler adds an additional underscore to all C and C++ symbols.
28The description assumes this has been removed.)
29
30<special_or_name> ::= <gnu_special>
31 | <mangled_name>
32
33<mangled_name> ::= <prefix> [ <signature> ]
34
35<prefix> ::= [ "_GLOBAL_" [ID] "__" ] <function_name> "__" [ <opinfo> ]
36
37<function_name> ::= <char> <char>*
38 | NULL
39
40Questions for Stan (@@@Stan@@@)
411> A valid <opinfo> implies a null function name.
422> I wonder if an <opinfo> is mutually exclusive with a <function_name> perhaps something like :-
43<prefix> ::= [ "_GLOBAL_" ("I"|"D") "__" ] ((<function_name> "__") | <opinfo>)
443> Do constructors turn up as an opinfo or a NULL function name?
45
46The optional "_GLOBAL_"("I"|"D")"__" sequence indicates global constructors
47and destructors, but in practice these do not appear with the mach-o Apple 2.95
48
49A Null <function_name> indicates a constructor or an operator.
50
51Since <function_name> may include trailing underscores, the demangler
52should scan forward until a non-underscore is seen, and then take the
53last two as the separator between name and signature.
54
55<function_name> may also include any number of leading underscores, so
56the demangler needs to add those to <function_name> and look for the
57"__" following the name.
58
59<gnu_special> ::= ("_._"|"_$_" ) <class_name> ; destructor
60 | "__vt_" <class_name> ; virtual table
61 | "_" <class_name> ("."|"$") <varname> ; Variable
62
63<class_name> ::= <counted_class_name>
64 | "Q" <qualified_name>
65 | "K" <qualified_name> ; ignored and illegal
66
67<counted_class_name> ::= <count> <name>
68
69<qualified_name> ::= <q_count> <counted_class_name> <counted_class_name>*
70
71<opinfo> ::= "type" <type>
72 | "__op" <type>
73 | <opname> "__"
74 | "a"
75
76<opname> ::= "aa" # &&
77 | "aad" # &=
78 | "ad" # &
79 | "adv" # /=
80 | "aer" # ^=
81 | "als" # <<=
82 | "amd" # %=
83 | "ami" # -=
84 | "aml" # *=
85 | "aor" # |=
86 | "apl" # +=
87 | "ars" # >>=
88 | "as" # =
89 | "cl" # ()
90 | "cm" # ,
91 | "cn" # ?:
92 | "co" # ~
93 | "dl" # delete
94 | "dv" # /
95 | "eq" # ==
96 | "er" # ^
97 | "ge" # >=
98 | "gt" # >
99 | "le" # <=
100 | "ls" # <<
101 | "lt" # <
102 | "md" # %
103 | "mi" # -
104 | "ml" # *
105 | "mm" # --
106 | "mn" # <?
107 | "mx" # >?
108 | "ne" # !=
109 | "nt" # !
110 | "nw" # new
111 | "oo" # ||
112 | "or" # |
113 | "pl" # +
114 | "pp" # ++
115 | "rf" # ->
116 | "rm" # ->*
117 | "rs" # >>
118 | "sz" # sizeof
119 | "vc" # []
120 | "vd" # delete[]
121 | "vn" # new[]
122
123Questions for Stan (@@@Stan@@@)
1241> What the hell is The "type" & "__op" stuff?
125
126IOKit has so far only been observed to use operations new ("nw") and
127delete ("dl").
128
129The signature is a concatenated list of elements, which are usually
130argument types, but may include other sorts of things.
131
132<signature> ::= <qualifier>* <s_element> <argument_types>
133
134<s_element> ::= <class_name>
135 | "S"
136 | "F" <argument_types> [ "_" <return_type> ]
137
138Questions for Stan (@@@Stan@@@)
1391> I think the 'B' phrase should probably read '| "B" <index>'?
1402> Ambiguous productions for signature
141 OSObject::func(struct timeval fred) => _func__8OSObject7timeval
142 signature could be parsed as
143 <s_element> <s_element> or <s_element> <argument_types>
144 I believe the second one must be the valid production.
145
146<count> ::= <digit> <digit>*
147
148<varname> :: <name>
149
150<name> ::= <char> <char>*
151
152The <count> is the number of characters in <name>.
153
154Argument types are a concatenated sequence of types.
155
156<argument_types> ::= # Empty
157 | <arg_type>+
158<arg_type> ::= <type> [ "n" <index> ]
159 | "N" <count> <pos>
160 | "T" <index>
161
162The "N" repeats and "T" references to already-seen typescan only
163appear if -fno-squangle (no squashed mangling), and in practice aren't
164seen in IOKit symbols.
165
166<index> ::= <digit> | <digit> <digit> <digit>* "_"
167
168Return types are just like any other sort of type.
169
170<return_type> ::= <type>
171
172Types consist of a variable number of declarators in front of a basic
173type.
174
175<type> ::= <declarator>* <base_type>
176
177<declarator> ::= "P" ; pointer
178 | "p" ; pointer (but never occurs?)
179 | "R" ; reference (&)
180 | "A" <count> ; array
181 | "T" <index>
182 | "O" <count>
183 | <qualifier>
184
185The "A" <count> production can produce an ambigous output if it is followed by a counted class name or structure name.
186
187The "T" reference to a type does not appear in IOKit symbols, nor do
188the "M" and "O" declarators.
189
190<base_type> ::= <function_type> ; function
191 | <method_type> ; method
192 | <type_qualifier>* <fund_type_id>
193
194<function_type> ::= "F" <argument_types> "_" <type>
195
196<method_type> ::= "M" <class_name> <function_type>
197
198A qualified name consists of a count of types, followed by all the
199types concatenated together. For instance, Namespace::Class is
200Q29Namespace5Class. For more than 9 types (which has not yet occurred
201in IOKit), the multi-digit count is surrounded by underscores.
202
203Questions for Stan (@@@Stan@@@)
2041> Can the types in a qualified name really be generic types or can the set be restricted to just counted class names?
205
206<q_count> ::= <digit> | "_" <digit> <digit>* "_"
207
208Fundamental types are single letters representing standard built-in
209types, optionally preceded by type qualifiers for properties like
210signedness and constness. For instance, CUi is a const unsigned int.
211
212<type_qualifier> ::= "S" ; signed (chars only)
213 | "U" ; unsigned (any integral type)
214 | "J" ; __complex
215 | <qualifier>
216
217<fund_type_id> ::= <class_name>
218 | "b" ; bool
219 | "c" ; char
220 | "d" ; double
221 | "f" ; float
222 | "i" ; int
223 | "l" ; long
224 | "r" ; long double
225 | "s" ; short
226 | "v" ; void
227 | "w" ; wchar_t
228 | "x" ; long long
229 | "G" <count> ; ?????
230 | "e" ; ellipsis
231
232"G" does not appear in IOKit symbols in this context.
233
234<qualifier> ::= "C" ; const
235 | "V" ; volatile
236 | "u" ; restrict (C99)
237 | "G" ; struct/union/enum unused by gcc3
238
239The restrict qualifier has not appeared in IOKit symbols.
240
241*/
242#if KERNEL
243
244#include <stdarg.h>
245#include <string.h>
246
247#include <sys/systm.h>
248
249#include <libkern/OSTypes.h>
250
251#include <libsa/stdlib.h>
252
253enum { false = 0, true = 1 };
254
255#else /* !KERNEL */
256
257#include <unistd.h>
258
259#include <stdio.h>
260#include <stdlib.h>
261#include <string.h>
262
263#include <CoreFoundation/CoreFoundation.h>
264
265#endif /* KERNEL */
266
267#include "c++rem3.h"
268
269#define STRLEN(s) (sizeof(s)-1)
270#define APPENDSTR(c, str) do { appendNStr(c, str, STRLEN(str)); } while (0)
271
272#define MAX_COMPOUND_TYPES 128
273#define MAX_ENTRIES 256
274#define MAX_SDICT_ENTRIES 256
275#define MAX_BDICT_ENTRIES 64
276#define MAX_RETURN_BUFFER 256
277
278// Can't be bigger that 16 entries
279typedef enum NameTypes {
280 kNTUndefined, kNTClass, kNTFunction, kNTFuncEnd,
281 kNTMethod, kNTBuiltIn, kNTDeclarator, kNTArray,
282 kNTKName, kNTSubstitute, kNTSubQualClass
283} NameTypes;
284
285typedef struct TypeData {
286 short fStartEntry, fNumEntries;
287} TypeData;
288
289typedef struct BaseTypeData {
290 const char *fFundTypeID; // May contain the type itself for kNTBuiltIt
291 unsigned int fLen:16;
292 unsigned int fType:4; // Must fit a NameType
293 unsigned int fVolatile:1;
294 unsigned int fConst:1;
295 unsigned int fSigned:1;
296 unsigned int fUnsigned:1;
297 unsigned int fPseudo:1;
298 unsigned int fQualified:1;
299} BaseTypeData;
300
301typedef struct CheckPoint {
302 const char *fInChar;
303 unsigned char fNumI, fNumO, fNumT, fNumB, fNumS;
304} CheckPoint;
305
306typedef struct ParseContext {
307 CheckPoint fP;
308 BaseTypeData fInEntries[MAX_ENTRIES]; // Input parsed elements
309 BaseTypeData fOutEntries[MAX_ENTRIES]; // Output parsed elements
310 TypeData fTypeList[MAX_COMPOUND_TYPES]; // Table of types
311 TypeData fSubDict[MAX_SDICT_ENTRIES];
312 TypeData fBDict[MAX_BDICT_ENTRIES]; // B dictionary types
313 BaseTypeData *fCurBaseP;
314 const char *fInStr;
315 char *fOutStrEnd;
316 char *fOutChar;
317 int fInSize;
318 Rem3Return fRetCode;
319} ParseContext;
320
321//
322// The only forward declaration necessary
323//
324static Boolean parse_type(ParseContext *c);
325
326// Helper functions for walking through the string
327static __inline__ char getNext(ParseContext *c)
328{
329 return *c->fP.fInChar++;
330}
331
332static __inline__ CheckPoint *checkPoint(ParseContext *c)
333{
334 return &c->fP;
335}
336
337static __inline__ void resetTo(ParseContext *c, CheckPoint *chk)
338{
339 c->fP = *chk;
340}
341
342static __inline__ const char *inCharFromCheck(ParseContext *c, CheckPoint *chk)
343{
344 return chk->fInChar;
345}
346
347static __inline__ void advance(ParseContext *c, int len)
348{
349 c->fP.fInChar += len;
350}
351
352static __inline__ Boolean retard(ParseContext *c, int len)
353{
354 const char *cp = c->fP.fInChar - len;
355 if (cp < c->fInStr)
356 return false;
357
358 c->fP.fInChar = cp;
359 return true;
360}
361
362static __inline__ char peekAt(ParseContext *c, int index)
363{
364 return c->fP.fInChar[index];
365}
366
367static __inline__ char peekNext(ParseContext *c)
368{
369 return peekAt(c, 0);
370}
371
372static __inline__ Boolean atEnd(ParseContext *c)
373{
374 return '\0' == peekNext(c);
375}
376
377static __inline__ Boolean hasRemain(ParseContext *c, int len)
378{
379 return (c->fP.fInChar - c->fInStr + len <= c->fInSize);
380}
381
382//
383// Routines for allocating entries in the various
384//
385static __inline__ BaseTypeData *newIn(ParseContext *c)
386{
387 BaseTypeData *iP;
388
389 if (c->fP.fNumI < MAX_ENTRIES) {
390 iP = &c->fInEntries[c->fP.fNumI++];
391 bzero(iP, sizeof(*iP));
392 c->fCurBaseP = iP;
393 return iP;
394 }
395 else {
396 c->fRetCode = kR3InternalNotRemangled;
397 return NULL;
398 }
399}
400
401static __inline__ BaseTypeData *newOut(ParseContext *c)
402{
403 BaseTypeData *oP;
404
405 if (c->fP.fNumO < MAX_ENTRIES) {
406 oP = &c->fOutEntries[c->fP.fNumO++];
407 return oP;
408 }
409 else {
410 c->fRetCode = kR3InternalNotRemangled;
411 return NULL;
412 }
413}
414
415static __inline__ TypeData *
416newSub(ParseContext *c, int start, int num)
417{
418 TypeData *sP;
419
420 if (c->fP.fNumS < MAX_SDICT_ENTRIES) {
421 sP = &c->fSubDict[c->fP.fNumS++];
422 sP->fStartEntry = start;
423 sP->fNumEntries = num;
424 return sP;
425 }
426 else {
427 c->fRetCode = kR3InternalNotRemangled;
428 return NULL;
429 }
430}
431
432static __inline__ TypeData *
433newBDict(ParseContext *c, int start, int num)
434{
435 TypeData *bP;
436
437 if (c->fP.fNumB < MAX_BDICT_ENTRIES) {
438 bP = &c->fBDict[c->fP.fNumB++];
439 bP->fStartEntry = start;
440 bP->fNumEntries = num;
441 return bP;
442 }
443 else {
444 c->fRetCode = kR3InternalNotRemangled;
445 return NULL;
446 }
447}
448
449static __inline__ TypeData *
450newType(ParseContext *c, int start)
451{
452 TypeData *tP;
453
454 if (c->fP.fNumT < MAX_COMPOUND_TYPES) {
455 tP = &c->fTypeList[c->fP.fNumT++];
456 tP->fStartEntry = start;
457 return tP;
458 }
459 else
460 return NULL;
461}
462
463static __inline__ TypeData *
464dupType(ParseContext *c, TypeData *iTP, int offset)
465{
466 TypeData *tP = newType(c, iTP->fStartEntry + offset);
467 if (tP)
468 tP->fNumEntries = iTP->fNumEntries;
469
470 return tP;
471}
472
473//
474// Identifier character recognition helpers, can be optimised
475//
476static __inline__ Boolean isValidFirstAlphabetic(char c)
477{
478 if ('a' <= c && c <= 'z')
479 return true;
480 else if ('A' <= c && c <= 'Z')
481 return true;
482 else
483 return false;
484}
485
486static __inline__ Boolean isValidFirstChar(char c)
487{
488 if (isValidFirstAlphabetic(c))
489 return true;
490 else if (c == '_')
491 return true;
492 else
493 return false;
494}
495
496static __inline__ Boolean isValidChar(char c)
497{
498 if (isValidFirstChar(c))
499 return true;
500 else if ('0' <= c && c <= '9')
501 return true;
502 else
503 return false;
504}
505
506//
507// Helper function for recognising characters and strings
508//
509
510// Check the current input is the given character
511static __inline__ Boolean isNext(ParseContext *c, char ch)
512{
513 if (peekNext(c) == ch) {
514 advance(c, 1);
515 return true;
516 }
517 else
518 return false;
519}
520
521// Check the current input is ONE of the characters in str
522static Boolean charNext(ParseContext *c, char *str)
523{
524 if (hasRemain(c, 1)) {
525 char ch = peekNext(c);
526 char next;
527
528 while ( (next = *str++) )
529 if (next == ch) {
530 advance(c, 1);
531 return true;
532 }
533 }
534
535 return false;
536}
537
538// Check the current input for 'str'
539static Boolean strNext(ParseContext *c, const char *str)
540{
541 const char *cp = c->fP.fInChar;
542
543 do {
544 if (!*str) {
545 c->fP.fInChar = (char *) cp;
546 return true;
547 }
548 else if (!*cp)
549 return false;
550
551 } while (*cp++ == *str++);
552
553 return false;
554}
555
556//
557// Qualifier re-encoding
558//
559static void
560decodeQual(BaseTypeData *typeP, int *qualLenP, const char **qualP)
561{
562 const char *qual;
563 int qualLen;
564
565 if (typeP->fConst && typeP->fVolatile)
566 { qual = "VK"; qualLen = 2; }
567 else if (typeP->fConst)
568 { qual = "K"; qualLen = 1; }
569 else if (typeP->fVolatile)
570 { qual = "V"; qualLen = 1; }
571 else
572 { qual = NULL; qualLen = 0; }
573
574 *qualLenP = qualLen;
575 *qualP = qual;
576}
577
578
579//
580// Output functions
581//
582
583static void appendChar(ParseContext *c, char ch)
584{
585 char *outAddr = c->fOutChar++;
586 if (outAddr < c->fOutStrEnd)
587 *outAddr = ch;
588}
589
590static void appendNStr(ParseContext *c, const char *str, int len)
591{
592 char *outAddr = c->fOutChar;
593
594 c->fOutChar += len;
595 if (c->fOutChar < c->fOutStrEnd)
596 bcopy(str, outAddr, len);
597}
598
599static __inline__ void appendStr(ParseContext *c, const char *str)
600{
601 appendNStr(c, str, strlen(str));
602}
603
604static void appendSub(ParseContext *c, int ls)
605{
606 appendChar(c, 'S');
607 if (ls) {
608 if (--ls >= 36) {
609 int ms;
610
611 ms = ls / 36;
612 appendChar(c, (ms < 10)? '0' + ms : 'A' + ms - 10);
613 ls -= (ms * 36);
614 }
615 appendChar(c, (ls < 10)? '0' + ls : 'A' + ls - 10);
616 }
617 appendChar(c, '_');
618}
619
620static Boolean compareTypes(ParseContext *c, int sub, int entry, int numEntries)
621{
622 TypeData *subP = &c->fSubDict[sub];
623 BaseTypeData *bSP, *bIP;
624 int i;
625
626 if (subP->fNumEntries != numEntries)
627 return false;
628
629 bSP = &c->fInEntries[subP->fStartEntry];
630 bIP = &c->fInEntries[entry];
631
632 for (i = 0; i < numEntries; i++, bSP++, bIP++) {
633 if (bSP->fType != bIP->fType)
634 return false;
635
636 switch (bSP->fType) {
637 case kNTClass:
638 if (bSP->fLen != bIP->fLen)
639 return false;
640 else if (strncmp(bSP->fFundTypeID, bIP->fFundTypeID, bSP->fLen))
641 return false;
642 break;
643
644 case kNTArray:
645 case kNTBuiltIn:
646 case kNTDeclarator:
647 if (bSP->fFundTypeID != bIP->fFundTypeID)
648 return false;
649 break;
650
651 case kNTMethod:
652 case kNTFunction:
653 case kNTUndefined:
654 case kNTKName:
655 break; // OK so far
656
657 default:
658 return false; // Fatal errors
659 }
660 }
661
662 return true;
663}
664
665static int searchDict(ParseContext *c, int entry, int numE)
666{
667 int sub, numSubs = c->fP.fNumS;
668
669 // don't try to substitute the last builtin
670 if (numE == 1 && kNTBuiltIn == c->fInEntries[entry].fType)
671 return -1;
672
673 for (sub = 0; sub < numSubs; sub++)
674 if (compareTypes(c, sub, entry, numE))
675 return sub;
676
677 return -1;
678}
679
680static int searchDictClass(ParseContext *c, const char *qname, int len)
681{
682 TypeData *subP;
683 int sub, numSubs = c->fP.fNumS;
684
685 for (sub = 0, subP = c->fSubDict; sub < numSubs; sub++, subP++) {
686 BaseTypeData *iP = &c->fInEntries[subP->fStartEntry];
687
688 if (kNTClass != iP->fType || iP->fLen != len)
689 continue;
690 if (!strncmp(iP->fFundTypeID, qname, len))
691 return sub;
692 }
693
694 return -1;
695}
696
697static Boolean
698appendQualifiedClass(ParseContext *c, int entry)
699{
700 BaseTypeData *iP, *oP, *sP, *endSP;
701 const char *cp, *typeID;
702 int sub, subEntry, prefixLen;
703 int q_count;
704
705 int decodeStart = c->fP.fNumI;
706
707 // Scan through the incom
708 iP = &c->fInEntries[entry];
709 endSP = &c->fInEntries[MAX_ENTRIES];
710 sP = &c->fInEntries[decodeStart];
711
712 prefixLen = iP->fLen;
713 typeID = cp = iP->fFundTypeID;
714 for (q_count = 0; sP < endSP && (cp-typeID) < prefixLen; q_count++, sP++) {
715 int count;
716
717 count = strtoul(cp, (char **) &cp, 10);
718 cp += count;
719
720 sP->fType = kNTClass;
721 sP->fFundTypeID = typeID;
722 sP->fLen = cp - typeID;
723 }
724 if (sP >= endSP)
725 return false;
726
727 // Search backwards until I find the first substitution
728 sub = -1;
729 for (subEntry = q_count, sP--; subEntry > 0; subEntry--, sP--) {
730 sub = searchDictClass(c, sP->fFundTypeID, sP->fLen);
731 if (-1 != sub)
732 break;
733 }
734
735 // Now drop the symbol into the output buffer
736 oP = newOut(c);
737 if (!oP)
738 return false;
739
740 if (sub < 0)
741 *oP = *iP; // No sub copy original
742 else {
743 // Substitution found
744 prefixLen = sP->fLen; // Length of substitution
745
746 oP->fType = kNTSubstitute; // Assume complete substitution
747 oP->fLen = sub;
748 oP->fFundTypeID = 0;
749
750 // We have a partial substitution so tag on the unmatched bit
751 if (prefixLen != iP->fLen) {
752 oP->fType = kNTSubQualClass; // Re-characterise as 2 part sub
753
754 oP = newOut(c);
755 if (!oP)
756 return false;
757
758 *oP = *iP; // Duplicate the original
759 oP->fType = kNTSubQualClass;
760 oP->fFundTypeID += prefixLen; // Skip leading substituted text
761 oP->fLen -= prefixLen;
762 }
763 }
764
765 // Finally insert the qualified class names into the dictionary
766 for (subEntry++, sP++; subEntry < q_count; subEntry++, decodeStart++) {
767 c->fInEntries[decodeStart] = *sP++;
768 if (!newSub(c, decodeStart, 1))
769 return false;
770 }
771 c->fP.fNumI = decodeStart;
772
773 if (!newSub(c, entry, 1))
774 return false;
775
776 return true;
777}
778
779static int
780appendType(ParseContext *c, int type)
781{
782 BaseTypeData *iP, *oP;
783 TypeData *tP;
784 int i, sub;
785 int entry, numE, lastEntry;
786 Boolean found;
787
788 if (type >= c->fP.fNumT)
789 return -1;
790
791 tP = &c->fTypeList[type++];
792 entry = tP->fStartEntry;
793 numE = tP->fNumEntries;
794 lastEntry = entry + numE;
795 iP = 0;
796 for (i = 0, found = false, sub = -1; i < numE; i++) {
797 iP = &c->fInEntries[entry + i];
798 switch (iP->fType) {
799
800 // Function & Builtin can't be compressed alone
801 case kNTFunction:
802 case kNTBuiltIn:
803 i++; // Copy the current entry
804 found = true;
805 break;
806
807 case kNTClass:
808 case kNTMethod:
809 sub = searchDict(c, entry + i, numE - i);
810 if (sub < 0 && !iP->fQualified)
811 i++;
812 found = true;
813 break;
814
815 case kNTDeclarator:
816 case kNTArray:
817 sub = searchDict(c, entry + i, numE - i);
818 found = (sub >= 0);
819 break;
820
821 // Internal error's should never occur
822 case kNTKName:
823 case kNTSubstitute:
824 case kNTSubQualClass:
825 case kNTUndefined:
826 default:
827 return -1;
828 }
829 if (found)
830 break;
831 }
832
833 if (!found)
834 return -1; // Internal error: no terminal symbol?
835
836 // Copy the already input buffer to the output
837 oP = &c->fOutEntries[c->fP.fNumO];
838 if (i) {
839 if (c->fP.fNumO + i >= MAX_ENTRIES)
840 return -1;
841
842 bcopy(&c->fInEntries[entry], oP, i * sizeof(*oP));
843 c->fP.fNumO += i;
844 oP += i;
845 }
846
847 if (sub >= 0) {
848 // We found a substitution
849 oP->fType = kNTSubstitute;
850 oP->fLen = sub;
851 c->fP.fNumO++; // Increment output for the substitution
852
853 // Walk over types that have been substituted
854 while (type < c->fP.fNumT
855 && c->fTypeList[type].fStartEntry < lastEntry)
856 type++;
857 }
858 else switch (iP->fType)
859 {
860 case kNTMethod:
861 type = appendType(c, type); // Class Name
862 if (type < 0)
863 return type;
864 type = appendType(c, type); // Pointer to function
865 if (type < 0)
866 return type;
867 break;
868
869 case kNTFunction:
870 type = appendType(c, type); // Return type
871 if (type < 0)
872 return type;
873
874 // process the argument list
875 do {
876 tP = &c->fTypeList[type];
877 if (tP->fStartEntry < lastEntry) {
878 type = appendType(c, type);
879 if (type < 0)
880 return type;
881 }
882 else
883 break;
884 } while (type < c->fP.fNumT);
885 oP = newOut(c);
886 if (!oP)
887 return -1;
888 oP->fType = kNTFuncEnd;
889 break;
890
891 case kNTBuiltIn:
892 i--; // Do not store the buildit in the dictionary
893 break;
894
895 case kNTClass: // Nothing more to do
896 if (!iP->fQualified)
897 break;
898 else if (appendQualifiedClass(c, entry + i))
899 break;
900 else
901 return -1;
902 }
903
904 // No further substititions to be had update the dictionary
905 for (i += entry; --i >= entry; ) {
906 if (!newSub(c, i, lastEntry - i))
907 return -1;
908 }
909
910 return type;
911}
912
913static Boolean appendArgumentList(ParseContext *c)
914{
915 int i, num;
916
917 c->fRetCode = kR3InternalNotRemangled;
918 // Setup the output entry array
919 num = c->fP.fNumT;
920 for (i = 0; i < num; ) {
921 i = appendType(c, i);
922 if (i < 0)
923 return false;
924 }
925
926 // First pass output uncompressed types
927 for (i = 0, num = c->fP.fNumO; i < num; i++) {
928 BaseTypeData *bP;
929
930 bP = &c->fOutEntries[i];
931
932 if (bP->fPseudo)
933 continue; // Pseudo entry do not output;
934
935 switch (bP->fType) {
936
937 case kNTSubstitute: appendSub(c, bP->fLen); break;
938
939 case kNTSubQualClass:
940 appendChar(c, 'N');
941 appendSub(c, bP->fLen);
942 i++; bP = &c->fOutEntries[i];
943 appendNStr(c, bP->fFundTypeID, bP->fLen);
944 appendChar(c, 'E');
945 break;
946
947 case kNTClass:
948 if (bP->fQualified) {
949 appendChar(c, 'N');
950 appendNStr(c, bP->fFundTypeID, bP->fLen);
951 appendChar(c, 'E');
952 }
953 else
954 appendNStr(c, bP->fFundTypeID, bP->fLen);
955 break;
956
957 case kNTArray: {
958 char numbuf[16]; // Bigger than MAX_LONG + 3
959 int len;
960 len = snprintf(numbuf, sizeof(numbuf),
961 "A%lu_", (unsigned long) bP->fFundTypeID);
962 appendNStr(c, numbuf, len);
963 break;
964 }
965
966 case kNTBuiltIn:
967 case kNTDeclarator: appendChar(c, (int) bP->fFundTypeID); break;
968 case kNTMethod: appendChar(c, 'M'); break;
969 case kNTFunction: appendChar(c, 'F'); break;
970 case kNTFuncEnd: appendChar(c, 'E'); break;
971
972 case kNTUndefined:
973 case kNTKName:
974 default:
975 return false; // Fatal errors
976 }
977 }
978
979 // Successful remangle
980 c->fRetCode = kR3Remangled;
981 return true;
982}
983
984//
985// Parse routines
986//
987
988// <count> ::= <digit> <digit>*
989static Boolean parse_count(ParseContext *c, int *countP)
990{
991 int count = 0;
992 char ch;
993
994 ch = peekNext(c);
995 if (ch < '1' || ch > '9')
996 return false;
997
998 count = strtol(c->fP.fInChar, (char **) &c->fP.fInChar, 10);
999 if (countP)
1000 *countP = count;
1001
1002 return true;
1003}
1004
1005
1006// "n" <index> can cause the following type to be ambiguous as
1007// n23_Pc... can be
1008// "n" <digit> <counted_class_name> ...
1009// | "n" <digit> <digit> '_' <declarator> <fund_type_id> ...
1010// However as the class '_Pc' is probably going to be unlikely a quick
1011// check to see if the next field is a valid type would probably clear
1012// up the abiguity for the majority of cases.
1013//
1014// <index> ::= <digit> | <digit> <digit> <digit>* "_"
1015static Boolean parse_index(ParseContext *c, int *indexP)
1016{
1017 CheckPoint chk = *checkPoint(c);
1018 char ch0, ch1;
1019 int index;
1020
1021 ch0 = peekAt(c, 0);
1022 ch1 = peekAt(c, 1);
1023
1024 if ( !('0' <= ch0 && ch0 <= '9') )
1025 goto abandonParse;
1026 if ('0' <= ch1 && ch1 <= '9') {
1027 if (!parse_count(c, &index))
1028 goto abandonParse;
1029 if (isNext(c, '_')) {
1030 // @@@ gvdl: Ambiguity check one day
1031 if (indexP)
1032 *indexP = index;
1033 return true;
1034 }
1035 else
1036 resetTo(c, &chk); // Must be the one digit case
1037 }
1038
1039 // One digit case
1040 advance(c, 1);
1041 index = ch0 - '0';
1042
1043 if (indexP)
1044 *indexP = index;
1045 return true;
1046
1047abandonParse:
1048 return false;
1049}
1050
1051
1052// <qualifier> ::= "C" ; const
1053// | "V" ; volatile
1054// | "u" ; restrict (C99) unsupported
1055// | "G" ; struct/union/enum ; unused in gcc3
1056static Boolean parse_qualifiers(ParseContext *c)
1057{
1058 BaseTypeData *bP = c->fCurBaseP;
1059
1060 for (;;) {
1061 if (isNext(c, 'C'))
1062 bP->fConst = true; // "C" ; const
1063 else if (isNext(c, 'V'))
1064 bP->fVolatile = true; // "V" ; volatile
1065 else if (isNext(c, 'u'))
1066 return false; // "u" ; restrict (C99)
1067 else if (isNext(c, 'G'))
1068 continue; // "G" ; struct/union/enum ; unused
1069 else
1070 break;
1071 }
1072
1073 return true;
1074}
1075
1076// Assumes we have an open fInEntry in fCurBaseP
1077static Boolean duplicateEntries(ParseContext *c, int start, int numE)
1078{
1079 BaseTypeData *bIP = &c->fInEntries[start]; // First duplicate entry
1080 BaseTypeData *bP = c->fCurBaseP;
1081 int i;
1082
1083 // Duplicating a method
1084 if (kNTMethod == bIP->fType) {
1085 bP--; // Strip leading 'P' declarator
1086 c->fP.fNumI--;
1087 }
1088
1089 numE--;
1090
1091 // do we have room available for duplication
1092 if (c->fP.fNumI + numE >= MAX_ENTRIES)
1093 return false;
1094
1095 // Copy the parse entries over
1096 bcopy(bIP, bP, (numE + 1) * sizeof(*bP));
1097
1098 // Now we have to duplicate the types for the new entry
1099 for (i = 0; i < c->fP.fNumT; i++) {
1100 TypeData *tP = &c->fTypeList[i];
1101 if (tP->fStartEntry < start)
1102 continue;
1103 else if (tP->fStartEntry <= start + numE)
1104 dupType(c, tP, bP - bIP);
1105 else
1106 break;
1107 }
1108
1109 c->fP.fNumI += numE;
1110 bP += numE;
1111 c->fCurBaseP = bP;
1112
1113 return true;
1114}
1115
1116// Must have a valid c->fCurBaseP pointer on entry
1117// <class_name> ::= <counted_class_name> ; plain class name
1118// | "Q" <qualified_name> ; qualified name
1119// | "B" <index> ; compressed name
1120// | "K" <qualified_name> ; ignored and illegal
1121// <qualified_name> ::= <q_count> <counted_class_name>+
1122// <q_count> ::= <digit> | "_" <digit> <digit>* "_"
1123// <counted_class_name> ::= <count> <name>
1124// <name> ::= <char> <char>*
1125static Boolean
1126parse_class_name(ParseContext *c)
1127{
1128 BaseTypeData *bP = c->fCurBaseP;
1129 const char *typeId = c->fP.fInChar;
1130 char ch;
1131 int count;
1132
1133 if (parse_count(c, &count)) {
1134
1135 // <counted_class_name> ::= <count> <name>
1136 if (!hasRemain(c, count))
1137 goto abandonParse;
1138
1139 bP->fType = kNTClass;
1140 advance(c, count);
1141
1142 bP->fFundTypeID = typeId;
1143 bP->fLen = c->fP.fInChar - typeId;
1144 }
1145 else {
1146 switch (peekNext(c)) {
1147
1148 case 'Q': {
1149 int i, q_count;
1150
1151 advance(c, 1);
1152
1153 // | "Q" <qualified_name> ; qualified name
1154 // <qualified_name> ::= <q_count> <counted_class_name>+
1155 // <q_count> ::= <digit> | "_" <digit> <digit>* "_"
1156 if ('_' == (ch = getNext(c))) {
1157 advance(c, 1);
1158 if (!parse_count(c, &q_count) || !isNext(c, '_'))
1159 goto abandonParse;
1160 }
1161 else if ('1' <= ch && ch <= '9')
1162 q_count = ch - '0';
1163
1164 if (!q_count)
1165 goto abandonParse;
1166
1167 typeId = c->fP.fInChar;
1168 bP->fType = kNTClass;
1169 bP->fQualified = true;
1170 i = 0;
1171 for (i = 0; i < q_count; i++) {
1172 if (parse_count(c, &count))
1173 advance(c, count);
1174 else
1175 goto abandonParse;
1176 }
1177 bP->fLen = c->fP.fInChar - typeId;
1178 bP->fFundTypeID = typeId;
1179 break;
1180 }
1181
1182 case 'B':
1183 // | "B" <index>
1184 advance(c, 1);
1185
1186 if (!parse_index(c, &count) || count >= c->fP.fNumB)
1187 goto abandonParse;
1188
1189 if (!duplicateEntries(c, c->fBDict[count].fStartEntry,
1190 c->fBDict[count].fNumEntries))
1191 goto abandonParse;
1192 return true;
1193
1194 case 'K': default:
1195 goto abandonParse;
1196 }
1197 }
1198
1199 if (newBDict(c, bP - c->fInEntries, 1))
1200 return true;
1201
1202abandonParse:
1203 return false;
1204}
1205
1206// <fund_type_id> ::= <class_name>
1207// | "b" ; bool
1208// | "c" ; char
1209// | "d" ; double
1210// | "e" ; ellipsis
1211// | "f" ; float
1212// | "i" ; int
1213// | "l" ; long
1214// | "r" ; long double
1215// | "s" ; short
1216// | "v" ; void
1217// | "w" ; wchar_t
1218// | "x" ; long long
1219// | "G" <count> ; ???
1220static Boolean parse_fund_type_id(ParseContext *c)
1221{
1222 BaseTypeData *bP = c->fCurBaseP;
1223
1224 if (!parse_class_name(c)) {
1225 // Use the TypeID pointer as a 4 character buffer
1226 char ch = peekNext(c);
1227
1228 if (bP->fSigned && 'c' != ch)
1229 goto abandonParse; // illegal only chars can be signed
1230
1231 switch (ch) {
1232
1233 case 'b': case 'd': case 'f': case 'v': case 'w': // No map types
1234 break;
1235
1236 case 'c': // character
1237 if (bP->fSigned) ch = 'a';
1238 else if (bP->fUnsigned) ch = 'h';
1239 break;
1240 case 'e': // ellipsis
1241 ch = 'z';
1242 break;
1243 case 'i': // int
1244 if (bP->fUnsigned) ch = 'j';
1245 break;
1246 case 'l': // long
1247 if (bP->fUnsigned) ch = 'm';
1248 break;
1249 case 'r': // long double
1250 ch = 'e';
1251 break;
1252 case 's': // short
1253 if (bP->fUnsigned) ch = 't';
1254 break;
1255 case 'x': // long long
1256 if (bP->fUnsigned) ch = 'y';
1257 break;
1258
1259 case 'G': // Don't understand "G"
1260 default:
1261 goto abandonParse;
1262 }
1263
1264 advance(c, 1); // Consume the input character
1265 bP->fFundTypeID = (void *) (int) ch;
1266 bP->fLen = 0;
1267 bP->fType = kNTBuiltIn;
1268 }
1269
1270 return true;
1271
1272abandonParse:
1273 return false;
1274}
1275
1276// <arg_type> ::= <type> [ "n" <index> ]
1277// | "N" <count> <pos> ; Not implemented
1278// | "T" <index> ; Not implemented
1279static Boolean parse_arg_type(ParseContext *c)
1280{
1281 // Don't bother to check point as parse_argument_types does it for us
1282
1283 TypeData *typeP;
1284 int repeat = 0;
1285
1286 typeP = &c->fTypeList[c->fP.fNumT]; // Cache type for later repeat
1287 if (!parse_type(c))
1288 return false;
1289
1290 // Now check for a repeat count on this type
1291 if (isNext(c, 'n')) {
1292 if (!parse_index(c, &repeat))
1293 return false;
1294
1295 do {
1296 c->fCurBaseP = newIn(c); // Duplicate requires a fresh type
1297 if (!c->fCurBaseP)
1298 return false;
1299 if (!duplicateEntries(c, typeP->fStartEntry, typeP->fNumEntries))
1300 return false;
1301 } while (--repeat);
1302 }
1303
1304 return true;
1305}
1306
1307// <argument_types> ::= # Empty
1308// | <arg_type>+
1309static Boolean parse_argument_types(ParseContext *c)
1310{
1311 if (atEnd(c))
1312 return true;
1313
1314 if (!parse_arg_type(c))
1315 goto abandonParse;
1316
1317 while (!atEnd(c) && parse_arg_type(c))
1318 ;
1319
1320 return true;
1321
1322 // Not a counted class name so reset to checkPoint
1323abandonParse:
1324 return false;
1325}
1326
1327// leaf function so the copy aside buffer isn't on the primary
1328// recursion stack.
1329static Boolean
1330rotateFunction(ParseContext *c, int argStart, int retStart)
1331{
1332 char returnTypeBuffer[MAX_RETURN_BUFFER];
1333 int numArg, numRet;
1334 int lenArg, lenRet;
1335 char *sArgP, *sRetP;
1336 int i;
1337
1338 TypeData *argTP = &c->fTypeList[argStart];
1339 TypeData *retTP = &c->fTypeList[retStart];
1340
1341 // Rotate around the entries first
1342 numArg = retTP->fStartEntry - argTP->fStartEntry;
1343 numRet = retTP->fNumEntries;
1344 lenArg = numArg * sizeof(BaseTypeData);
1345 lenRet = numRet * sizeof(BaseTypeData);
1346
1347 // Copy the return type into a buffer
1348 if (lenRet > sizeof(returnTypeBuffer))
1349 return false;
1350
1351 sArgP = (char *) (&c->fInEntries[argTP->fStartEntry]);
1352 sRetP = (char *) (&c->fInEntries[retTP->fStartEntry]);
1353
1354 bcopy(sRetP, returnTypeBuffer, lenRet);
1355 bcopy(sArgP, sArgP + lenRet, lenArg);
1356 bcopy(returnTypeBuffer, sArgP, lenRet);
1357
1358 // Retarget the argument and return types for the new entry positions
1359 lenArg = numArg;
1360 lenRet = numRet;
1361 numArg = retStart - argStart;
1362 numRet = c->fP.fNumT - retStart;
1363 for (i = 0; i < numArg; i++)
1364 c->fTypeList[argStart+i].fStartEntry += lenRet;
1365 for (i = 0; i < numRet; i++)
1366 c->fTypeList[retStart+i].fStartEntry -= lenArg;
1367
1368 // Rotate the BDictionary
1369 for (i = 0; i < c->fP.fNumB; i++) {
1370 TypeData *bDP = &c->fBDict[i];
1371 int start = bDP->fStartEntry;
1372
1373 if (start >= argTP->fStartEntry)
1374 bDP->fStartEntry = start + lenRet;
1375 else if (start >= retTP->fStartEntry)
1376 bDP->fStartEntry = start - lenArg;
1377 }
1378
1379 // Finally rotate the retargeted type structures.
1380 lenArg = numArg * sizeof(TypeData);
1381 lenRet = numRet * sizeof(TypeData);
1382
1383 sArgP = (char *) (&c->fTypeList[argStart]);
1384 sRetP = (char *) (&c->fTypeList[retStart]);
1385
1386 bcopy(sRetP, returnTypeBuffer, lenRet);
1387 bcopy(sArgP, sArgP + lenRet, lenArg);
1388 bcopy(returnTypeBuffer, sArgP, lenRet);
1389
1390 return true;
1391}
1392
1393// <function_type> ::= "F" <argument_types> "_" <type>
1394static Boolean parse_function_type(ParseContext *c, Boolean forMethod)
1395{
1396 TypeData *bDictP = 0;
1397 BaseTypeData *bP = c->fCurBaseP;
1398
1399 int argTypeStart, retTypeStart;
1400
1401 if (!forMethod) {
1402 bDictP = newBDict(c, c->fP.fNumI-1, 0);
1403 if (!bDictP)
1404 goto abandonParse;
1405 }
1406
1407 if (!isNext(c, 'F'))
1408 goto abandonParse;
1409
1410 bP->fType = kNTFunction;
1411
1412 // Note that the argument types will advance the Entry list
1413 argTypeStart = c->fP.fNumT;
1414 if (!parse_argument_types(c))
1415 goto abandonParse;
1416
1417 if (!isNext(c, '_'))
1418 goto abandonParse;
1419
1420 // Parse the return type
1421 retTypeStart = c->fP.fNumT;
1422 if (!parse_type(c))
1423 goto abandonParse;
1424
1425 // gcc3 puts the return code just after the 'F' declaration
1426 // as this impacts the order of the compression I need to rotate
1427 // the return type and the argument types.
1428 if (!rotateFunction(c, argTypeStart, retTypeStart))
1429 goto abandonParse;
1430
1431 if (!forMethod)
1432 bDictP->fNumEntries = c->fP.fNumI - bDictP->fStartEntry;
1433
1434 return true;
1435
1436abandonParse:
1437 return false;
1438}
1439
1440// To convert 2.95 method to a 3.0 method I need to prune the
1441// first argument of the function type out of the parse tree.
1442static Boolean cleanMethodFunction(ParseContext *c, int type)
1443{
1444 TypeData *typeP, *startTP, *endTP;
1445 BaseTypeData *bP;
1446 int i, thisStart, thisEnd, thisLen, funcRemain;
1447
1448 // Get pointer for the return value's type.
1449 startTP = &c->fTypeList[type+1];
1450 endTP = &c->fTypeList[c->fP.fNumT];
1451
1452 // Now look for the first type that starts after the return type
1453 thisEnd = startTP->fStartEntry + startTP->fNumEntries;
1454 for (startTP++; startTP < endTP; startTP++)
1455 if (startTP->fStartEntry >= thisEnd)
1456 break;
1457
1458 if (startTP >= endTP) {
1459 c->fRetCode = kR3InternalNotRemangled;
1460 return false; // Internal error: should never happen
1461 }
1462
1463 // We now have a pointer to the 1st argument in the input list
1464 // we will need to excise the entries from the input list and don't forget
1465 // to remove the associated types from the type list.
1466
1467 thisLen = startTP->fNumEntries;
1468 thisStart = startTP->fStartEntry;
1469 thisEnd = thisStart + thisLen;
1470 funcRemain = c->fP.fNumI - thisEnd;
1471 bP = &c->fInEntries[thisStart];
1472
1473 // If we have no arguments then replace the pointer with a void
1474 if (!funcRemain) {
1475 c->fP.fNumI -= (thisLen - 1);
1476
1477 bP->fFundTypeID = (void *) (int) 'v'; // Void arg list
1478 bP->fLen = 0;
1479 bP->fType = kNTBuiltIn;
1480
1481 // Update the type entry for the void argument list
1482 startTP->fNumEntries = 1;
1483 return true;
1484 }
1485
1486 // Move the argument list down to replace the 'this' pointer
1487 bcopy(bP + thisLen, bP, funcRemain * sizeof(*bP));
1488 c->fP.fNumI -= thisLen;
1489
1490 // And remove the 'this' pointers type
1491
1492 // First walk over all of the types that have to be removed
1493 for (typeP = startTP + 1; typeP < endTP; typeP++)
1494 if (typeP->fStartEntry >= thisEnd)
1495 break;
1496
1497 if (typeP >= endTP) {
1498 c->fRetCode = kR3InternalNotRemangled;
1499 return false; // Internal error Can't be a void argument list.
1500 }
1501
1502 bcopy(typeP, startTP, (char *) endTP - (char *) typeP);
1503
1504 c->fP.fNumT -= typeP - startTP;
1505 endTP = &c->fTypeList[c->fP.fNumT];
1506 for (typeP = startTP ; typeP < endTP; typeP++)
1507 typeP->fStartEntry -= thisLen;
1508
1509 // Finally we can retarget the BDictionary lists
1510 for (i = 0; i < c->fP.fNumB; i++) {
1511 TypeData *bDP = &c->fBDict[i];
1512 int start = bDP->fStartEntry;
1513
1514 if (start < thisStart)
1515 continue;
1516 if (start >= thisEnd)
1517 break;
1518
1519 bDP->fStartEntry = start - thisLen;
1520 }
1521
1522 return true;
1523}
1524
1525// <method_type> ::= "M" <class_name> <function_type>
1526//
1527// Note this is a very bad function. Gcc3 doesn't doesn't use pointer that
1528// is immediately before this entry. We will have to delete the 'P' declarator
1529// that is before the method declaration.
1530// We will also have to prune the first type in the argument list as Gcc3
1531// doesn't register the 'this' pointer within the function list.
1532static Boolean parse_method_type(ParseContext *c)
1533{
1534 TypeData *bDictP;
1535 TypeData *typeP;
1536 BaseTypeData *bP;
1537
1538 bDictP = newBDict(c, c->fP.fNumI-2, 0);
1539 if (!bDictP)
1540 goto abandonParse;
1541
1542 // Replace 'P' declarator
1543 c->fP.fNumI--;
1544 bP = c->fCurBaseP - 1;
1545
1546 if (!isNext(c, 'M'))
1547 goto abandonParse;
1548
1549 if (bP->fFundTypeID != (void *) (int) 'P')
1550 goto abandonParse;
1551
1552 // Replace the previous 'Pointer' declarator
1553 bP->fType = kNTMethod;
1554 bP->fFundTypeID = NULL;
1555 bP->fLen = 0;
1556
1557 // Grab the method's 'this' type specification
1558 typeP = newType(c, c->fP.fNumI);
1559 if (!newIn(c) || !typeP)
1560 goto abandonParse;
1561
1562 if (!parse_class_name(c))
1563 goto abandonParse;
1564 typeP->fNumEntries = c->fP.fNumI - typeP->fStartEntry;
1565
1566 // Grab the <function_type> specifier
1567 typeP = newType(c, c->fP.fNumI);
1568 if (!newIn(c) || !typeP)
1569 goto abandonParse;
1570
1571 if (!parse_function_type(c, /* forMethod */ true))
1572 goto abandonParse;
1573
1574 if (!cleanMethodFunction(c, typeP - c->fTypeList))
1575 goto abandonParse;
1576 typeP->fNumEntries = c->fP.fNumI - typeP->fStartEntry;
1577
1578 // Finally update the dictionary with the M & 'this'
1579 bDictP->fNumEntries = c->fP.fNumI - bDictP->fStartEntry;
1580
1581 return true;
1582
1583abandonParse:
1584 return false;
1585}
1586
1587static Boolean emitQualifiers(ParseContext *c)
1588{
1589 BaseTypeData *bP = c->fCurBaseP;
1590
1591 if (bP->fVolatile || bP->fConst) {
1592 Boolean isConst, isVolatile, isSigned, isUnsigned;
1593
1594 isVolatile = bP->fVolatile;
1595 isConst = bP->fConst;
1596 isSigned = bP->fSigned;
1597 isUnsigned = bP->fUnsigned;
1598 bP->fConst = bP->fVolatile = bP->fSigned = bP->fUnsigned = 0;
1599
1600 if (isVolatile) {
1601 bP->fType = kNTDeclarator;
1602 bP->fFundTypeID = (void *) (int) 'V';
1603 bP->fLen = 0;
1604 bP = newIn(c);
1605 if (!bP)
1606 return false;
1607 }
1608 if (isConst) {
1609 bP->fType = kNTDeclarator;
1610 bP->fFundTypeID = (void *) (int) 'K';
1611 bP->fLen = 0;
1612 bP = newIn(c);
1613 if (!bP)
1614 return false;
1615 }
1616 bP->fSigned = isSigned;
1617 bP->fUnsigned = isUnsigned;
1618 }
1619
1620 return true;
1621}
1622
1623
1624// <base_type> ::= <function_type> ; function
1625// | <method_type> ; method
1626// | <type_qualifier>* <fund_type_id>
1627// <type_qualifier> ::= "S" ; signed (chars only)
1628// | "U" ; unsigned (any integral type)
1629// | "J" ; __complex
1630// | <qualifier>
1631static Boolean parse_base_type(ParseContext *c)
1632{
1633 if ('F' == peekNext(c)) {
1634 if (!parse_function_type(c, /* forMethod */ false))
1635 goto abandonParse;
1636 }
1637 else if ('M' == peekNext(c)) {
1638 if (!parse_method_type(c))
1639 goto abandonParse;
1640 }
1641 else {
1642 // | <type_qualifier>* <fund_type_id>
1643 BaseTypeData *bP = c->fCurBaseP;
1644 for (;;) {
1645 if (isNext(c, 'S'))
1646 // <type_qualifier> ::= "S" ; signed (chars only)
1647 { bP->fSigned = true; continue; }
1648 else if (isNext(c, 'U'))
1649 // | "U" ; unsigned (any integral type)
1650 { bP->fUnsigned = true; continue; }
1651 else if (isNext(c, 'C'))
1652 // | <qualifier>
1653 // <qualifier> ::= "C" ; const
1654 { bP->fConst = true; continue; }
1655 else if (isNext(c, 'V'))
1656 // | "V" ; volatile
1657 { bP->fVolatile = true; continue; }
1658 else if (charNext(c, "Ju"))
1659 goto abandonParse; // Don't support these qualifiers
1660 // | "J" ; __complex
1661 // | "u" ; restrict (C99)
1662 else
1663 break;
1664 }
1665
1666 if (!emitQualifiers(c))
1667 goto abandonParse;
1668
1669 if (!parse_fund_type_id(c))
1670 goto abandonParse;
1671 }
1672 return true;
1673
1674abandonParse:
1675 return false;
1676}
1677
1678// Use the top SDict as a stack of declarators.
1679// parses <declarator>*
1680// <declarator> ::= "P" ; pointer
1681// | "p" ; pointer (but never occurs?)
1682// | "R" ; reference (&)
1683// | "A" <count> ; array
1684// | "T" <index>
1685// | "O" <count>
1686// | <qualifier>
1687//
1688// As a side-effect the fCurBaseP is setup with any qualifiers on exit
1689static Boolean parse_declarators(ParseContext *c)
1690{
1691 int count;
1692 BaseTypeData *dP;
1693
1694 // Note we MUST go through the for loop at least once
1695 for (count = 0; ; count++) {
1696 const char *curDecl;
1697 char ch;
1698
1699 if (!newIn(c))
1700 goto abandonParse;
1701
1702 // <declarator> ::= <qualifier> production
1703 if (!parse_qualifiers(c) || !emitQualifiers(c))
1704 goto abandonParse;
1705
1706 dP = c->fCurBaseP; // Find the current base type pointer
1707
1708 curDecl = c->fP.fInChar;
1709
1710 switch (peekNext(c)) {
1711
1712 case 'P': case 'p': case 'R':
1713 // <declarator> ::= "P" ; pointer
1714 // | "p" ; pointer (but never occurs?)
1715 // | "R" ; reference (&)
1716
1717 dP->fType = kNTDeclarator;
1718 advance(c, 1);
1719
1720 ch = *curDecl;
1721 if ('p' == ch) ch = 'P';
1722 dP->fFundTypeID = (void *) (int) ch;
1723 dP->fLen = 0;
1724 continue; // Go around again
1725
1726 case 'A':
1727 // | "A" <count> ; array
1728 dP->fType = kNTArray;
1729
1730 advance(c, 1); curDecl++;
1731 curDecl = (void *)
1732 strtoul(curDecl, (char **) &c->fP.fInChar, 10);
1733 if (!curDecl)
1734 goto abandonParse;
1735 dP->fFundTypeID = curDecl;
1736 dP->fLen = 0;
1737 continue; // Go around again
1738
1739 case 'T': case 'O':
1740 // | "T" <index> Unsupported
1741 // | "O" <count> Unsupported
1742 goto abandonParse;
1743
1744 default:
1745 break;
1746 }
1747
1748 break;
1749 }
1750
1751 dP->fLen = 0;
1752 return true;
1753
1754abandonParse:
1755 return false;
1756}
1757
1758// <type> ::= <declarator>* <base_type>
1759static Boolean parse_type(ParseContext *c)
1760{
1761 CheckPoint chk = *checkPoint(c);
1762 TypeData *typeP = newType(c, c->fP.fNumI);
1763 if (!typeP)
1764 goto abandonParse;
1765
1766 // As a side-effect the fCurBaseP is setup with any qualifiers on exit
1767 if (!parse_declarators(c))
1768 goto abandonParse;
1769
1770 // Merge the last qualifiers into the base type
1771 if (!parse_base_type(c) || kNTUndefined == c->fCurBaseP->fType)
1772 goto abandonParse;
1773
1774 typeP->fNumEntries = c->fP.fNumI - typeP->fStartEntry;
1775 return true;
1776
1777abandonParse:
1778 resetTo(c, &chk);
1779 return false;
1780}
1781
1782// <function_name> ::= <char> <char>*
1783// No need to check point as an invalid function name is fatal
1784// Consumes trailing "__".
1785static Boolean
1786parse_function_name(ParseContext *c)
1787{
1788 char ch;
1789
1790 while ( (ch = peekNext(c)) )
1791 {
1792 advance(c, 1);
1793 if ('_' == ch && '_' == peekNext(c)) {
1794 do {
1795 advance(c, 1);
1796 } while ('_' == peekNext(c));
1797 return true;
1798 }
1799 }
1800
1801 return false;
1802}
1803
1804// <opinfo> ::= "type" <type>
1805// | "__op" <type>
1806// | <opname> "__" ; Implies null function name
1807// | "a"
1808// <opname> ::= "aa" # && ==> "aa"
1809// | "aad" # &= ==> "aN"
1810// | "ad" # & ==> "ad"
1811// | "adv" # /= ==> "dV"
1812// | "aer" # ^= ==> "eO"
1813// | "als" # <<= ==> "lS"
1814// | "amd" # %= ==> "rM"
1815// | "ami" # -= ==> "mI"
1816// | "aml" # *= ==> "mL
1817// | "aor" # |= ==> "oR
1818// | "apl" # += ==> "pL
1819// | "ars" # >>= ==> "rS
1820// | "as" # = ==> "aS
1821// | "cl" # () ==> "cl
1822// | "cm" # , ==> "cm
1823// | "cn" # ?: ==> "qu
1824// | "co" # ~ ==> "co
1825// | "dl" # delete ==> "dl
1826// | "dv" # / ==> "dv
1827// | "eq" # == ==> "eq
1828// | "er" # ^ ==> "eo
1829// | "ge" # >= ==> "ge
1830// | "gt" # > ==> "gt
1831// | "le" # <= ==> "le
1832// | "ls" # << ==> "ls
1833// | "lt" # < ==> "lt
1834// | "md" # % ==> "rm
1835// | "mi" # - ==> "mi
1836// | "ml" # * ==> "ml
1837// | "mm" # -- ==> "mm
1838// | "mn" # <? ==> "????????????????
1839// | "mx" # >? ==> "????????????????
1840// | "ne" # != ==> "ne
1841// | "nt" # ! ==> "nt
1842// | "nw" # new ==> "nw
1843// | "oo" # || ==> "oo"
1844// | "or" # | ==> "or
1845// | "pl" # + ==> "pl
1846// | "pp" # ++ ==> "pp
1847// | "rf" # -> ==> "pt
1848// | "rm" # ->* ==> "pm
1849// | "rs" # >> ==> "rs
1850// | "sz" # sizeof ==> "sz
1851// | "vc" # [] ==> "ix
1852// | "vd" # delete[] ==> "da
1853// | "vn" # new[] ==> "na
1854static struct opMap {
1855 const char *op295, *op3;
1856} opMapTable[] = {
1857 {"aad", "aN" }, {"adv", "dV" }, {"aer", "eO" }, {"als", "lS" },
1858 {"amd", "rM" }, {"ami", "mI" }, {"aml", "mL" }, {"aor", "oR" },
1859 {"apl", "pL" }, {"ars", "rS" }, {"aa", "aa" }, {"ad", "ad" },
1860 {"as", "aS" }, {"cl", "cl" }, {"cm", "cm" }, {"cn", "qu" },
1861 {"co", "co" }, {"dl", "dl" }, {"dv", "dv" }, {"eq", "eq" },
1862 {"er", "eo" }, {"ge", "ge" }, {"gt", "gt" }, {"le", "le" },
1863 {"ls", "ls" }, {"lt", "lt" }, {"md", "rm" }, {"mi", "mi" },
1864 {"ml", "ml" }, {"mm", "mm" }, {"mn", NULL }, {"mx", NULL },
1865 {"ne", "ne" }, {"nt", "nt" }, {"nw", "nw" }, {"oo", "oo" },
1866 {"or", "or" }, {"pl", "pl" }, {"pp", "pp" }, {"rf", "pt" },
1867 {"rm", "pm" }, {"rs", "rs" }, {"sz", "sz" }, {"vc", "ix" },
1868 {"vd", "da" }, {"vn", "na" },
1869};
1870
1871static Boolean parse_opinfo(ParseContext *c, const char **opInfoP)
1872{
1873 CheckPoint chk = *checkPoint(c);
1874 const char *op;
1875 char ch;
1876 int i;
1877
1878 if ('a' == (ch = peekNext(c))) {
1879 goto abandonParse;
1880 }
1881 else if (strNext(c, "type")) {
1882 goto abandonParse;
1883 }
1884 else if (retard(c, 4) && strNext(c, "____op")) {
1885 // @@@ gvdl: check this out it may change
1886 // <opinfo> ::= "__op" <type>
1887 goto abandonParse;
1888 }
1889
1890 // Failed till now so reset and see if we have an operator
1891 resetTo(c, &chk);
1892
1893 // quick check to see if we may have an operator
1894 if (!strrchr("acdeglmnoprsv", peekNext(c)))
1895 goto abandonParse;
1896
1897 op = NULL;
1898 for (i = 0; i < sizeof(opMapTable)/sizeof(opMapTable[0]); i++) {
1899 if (strNext(c, opMapTable[i].op295)) {
1900 op = opMapTable[i].op3;
1901 break;
1902 }
1903 }
1904 if (!op)
1905 goto abandonParse;
1906
1907 if (!strNext(c, "__")) // Trailing underbars
1908 goto abandonParse;
1909
1910 if (opInfoP)
1911 *opInfoP = op;
1912 return true;
1913
1914abandonParse:
1915 return false;
1916}
1917
1918// <signature> ::= <qualifier>* <s_element> <argument_types>
1919// <s_element> ::= <class_name>
1920// | "K" <qualified_name>
1921// | "S"
1922// | "F" <argument_types> [ "_" <return_type> ]
1923// <return_type> ::= <type>
1924// Treat the prefix's s_element as a full type
1925static Boolean
1926parse_signature(ParseContext *c,
1927 const char *func, int funcLen, const char *op)
1928{
1929 BaseTypeData *bP;
1930 TypeData *tP;
1931
1932 Boolean isFunction = false;
1933
1934 if (isNext(c, 'F')) {
1935 // | "F" <argument_types> [ "_" <return_type> ]
1936
1937 char numbuf[16]; // Bigger than MAX_INT + 4
1938 int len;
1939 isFunction = true;
1940 if (!funcLen)
1941 goto abandonParse;
1942
1943 len = snprintf(numbuf, sizeof(numbuf), "__Z%d", funcLen);
1944
1945 appendNStr(c, numbuf, len);
1946 appendNStr(c, func, funcLen);
1947 }
1948 else if (isNext(c, 'S')) {
1949 // | "S" ; Ignored
1950 goto abandonParse;
1951 }
1952 else {
1953 const char *qual;
1954 int qualLen;
1955
1956 // See if we can find a qualified class reference
1957 tP = newType(c, c->fP.fNumI);
1958 if (!tP)
1959 goto abandonParse;
1960
1961 bP = newIn(c);
1962 if (!bP)
1963 goto abandonParse;
1964
1965 // Parse any qualifiers, store results in *fCurBaseP
1966 bP->fPseudo = true;
1967 if (!parse_qualifiers(c))
1968 goto abandonParse;
1969
1970 if (!parse_class_name(c))
1971 goto abandonParse;
1972
1973 bP = c->fCurBaseP; // class name may have redifined current
1974 tP->fNumEntries = c->fP.fNumI - tP->fStartEntry;
1975
1976 APPENDSTR(c, "__ZN");
1977 decodeQual(bP, &qualLen, &qual);
1978 if (qualLen)
1979 appendNStr(c, qual, qualLen);
1980 appendNStr(c, bP->fFundTypeID, bP->fLen);
1981
1982 if (funcLen) {
1983 char numbuf[16]; // Bigger than MAX_INT + 1
1984 int len;
1985
1986 len = snprintf(numbuf, sizeof(numbuf), "%d", funcLen);
1987 appendNStr(c, numbuf, len);
1988 appendNStr(c, func, funcLen);
1989 }
1990 else if (op)
1991 appendStr(c, op);
1992 else {
1993 // No function & no op means constructor choose one of C1 & C2
1994 APPENDSTR(c, "C2");
1995 }
1996 appendChar(c, 'E');
1997 }
1998
1999 if (atEnd(c)) {
2000 appendChar(c, 'v'); // void argument list
2001 c->fRetCode = kR3Remangled;
2002 return true;
2003 }
2004
2005 c->fCurBaseP = NULL;
2006 if (!parse_argument_types(c))
2007 goto abandonParse;
2008
2009 if (isFunction) {
2010 if (isNext(c, '_')) {
2011 // && !parse_type(c) @@@ gvdl: Unsupported return
2012 c->fRetCode = kR3InternalNotRemangled;
2013 goto abandonParse;
2014 }
2015 }
2016
2017 if (!atEnd(c))
2018 goto abandonParse;
2019
2020 // OK we have a complete and successful parse now output the
2021 // argument list
2022 return appendArgumentList(c);
2023
2024abandonParse:
2025 return false;
2026}
2027
2028// <mangled_name> ::= <prefix> [ <signature> ]
2029// <prefix> ::= [ "_GLOBAL_" [ID] "__" ] <function_name> "__" [ <opinfo> ]
2030static Boolean parse_mangled_name(ParseContext *c)
2031{
2032 CheckPoint chk;
2033 CheckPoint dubBarChk;
2034 const char *func;
2035
2036 // <prefix> parse
2037 if (strNext(c, "_GLOBAL_")) { // Is this GLOBAL static constructor?
2038 // gvdl: can't deal with _GLOBAL_
2039 c->fRetCode = kR3InternalNotRemangled;
2040 return false; // Can't deal with these
2041 }
2042
2043 func = c->fP.fInChar;
2044 for (chk = *checkPoint(c); ; resetTo(c, &dubBarChk)) {
2045 int funcLen;
2046 const char *op = NULL;
2047
2048 if (!parse_function_name(c))
2049 goto abandonParse;
2050 dubBarChk = *checkPoint(c);
2051
2052 // Note that the opInfo may be earlier than the curDoubleBar
2053 // in which case the function name may need to be shrunk later on.
2054 (void) parse_opinfo(c, &op);
2055
2056 if (atEnd(c))
2057 goto abandonParse; // No Signature?
2058
2059 funcLen = inCharFromCheck(c, &dubBarChk) - func - 2;
2060 if (parse_signature(c, func, funcLen, op))
2061 return true;
2062
2063 if (kR3NotRemangled != c->fRetCode)
2064 goto abandonParse;
2065
2066 // If no error then try again maybe another '__' exists
2067 }
2068
2069abandonParse:
2070 resetTo(c, &chk);
2071 return false;
2072}
2073
2074// <gnu_special> ::= ("_._" | "_$_" ) <class_name> ; destructor
2075// | "__vt_" <class_name> ; virtual table
2076// | "_" <class_name> ("."|"$") <varname>
2077static Boolean parse_gnu_special(ParseContext *c)
2078{
2079 CheckPoint chk = *checkPoint(c);
2080 BaseTypeData *bP = newIn(c);
2081
2082 if (!bP)
2083 return false;
2084
2085 // What do the intel desctructors look like
2086 if (strNext(c, "_._") || strNext(c, "_$_") ) // Is this a destructor
2087 {
2088 if (!parse_class_name(c) || !atEnd(c))
2089 goto abandonParse;
2090 APPENDSTR(c, "__ZN");
2091 appendNStr(c, bP->fFundTypeID, bP->fLen);
2092 APPENDSTR(c, "D2Ev");
2093 c->fRetCode = kR3Remangled;
2094 return true;
2095 }
2096 else if (strNext(c, "__vt_")) // Is it's a vtable?
2097 {
2098 if (!parse_class_name(c) || !atEnd(c))
2099 goto abandonParse;
2100
2101 APPENDSTR(c, "__ZTV");
2102 if (kNTClass != bP->fType)
2103 goto abandonParse;
2104 else if (bP->fQualified) {
2105 appendChar(c, 'N');
2106 appendNStr(c, bP->fFundTypeID, bP->fLen);
2107 appendChar(c, 'E');
2108 }
2109 else
2110 appendNStr(c, bP->fFundTypeID, bP->fLen);
2111
2112 c->fRetCode = kR3Remangled;
2113 return true;
2114 }
2115 else if (isNext(c, '_')) // Maybe it's a variable
2116 {
2117 const char *varname;
2118 int varlen, len;
2119 char numbuf[16]; // Bigger than MAX_INT + 1
2120
2121 if (!parse_class_name(c)) // Loads up the bP structure
2122 goto abandonParse;
2123
2124 if (!isNext(c, '.') && !isNext(c, '$'))
2125 goto abandonParse;
2126
2127 // Parse the variable name now.
2128 varname = c->fP.fInChar;
2129 if (atEnd(c) || !isValidFirstChar(getNext(c)))
2130 goto abandonParse;
2131
2132 while ( !atEnd(c) )
2133 if (!isValidChar(getNext(c)))
2134 goto abandonParse;
2135
2136 varlen = c->fP.fInChar - varname;
2137 len = snprintf(numbuf, sizeof(numbuf), "%d", varlen);
2138
2139 APPENDSTR(c, "__ZN");
2140 appendNStr(c, bP->fFundTypeID, bP->fLen);
2141
2142 appendNStr(c, numbuf, len);
2143 appendNStr(c, varname, varlen);
2144 appendChar(c, 'E');
2145
2146 c->fRetCode = kR3Remangled;
2147 return true;
2148 }
2149
2150 // Oh well it is none of those so give up but reset scan
2151abandonParse:
2152 resetTo(c, &chk);
2153 return false;
2154}
2155
2156// <special_or_name> ::= <gnu_special>
2157// | <mangled_name>
2158static Boolean parse_special_or_name(ParseContext *c)
2159{
2160 Boolean res;
2161
2162
2163 res = (parse_gnu_special(c) || parse_mangled_name(c));
2164 appendChar(c, '\0');
2165
2166 return res;
2167}
2168
2169Rem3Return rem3_remangle_name(char *gcc3, int *gcc3size, const char *gcc295)
2170{
2171 ParseContext *c;
2172 Rem3Return result;
2173 int size;
2174
2175 if (!gcc295 || !gcc3 || !gcc3size)
2176 return kR3BadArgument;
2177
2178 size = strlen(gcc295);
2179 if (size < 2)
2180 return kR3NotRemangled; // Not a valid C++ symbol
2181 else if (*gcc295 != '_')
2182 return kR3NotRemangled; // no leading '_', not valid
2183
2184 c = (ParseContext *) malloc(sizeof(*c));
2185 if (!c)
2186 return kR3InternalNotRemangled;
2187 bzero(c, sizeof(*c));
2188
2189 c->fInSize = size;
2190 c->fInStr = gcc295 + 1; // Strip leading '_'
2191 c->fP.fInChar = c->fInStr;
2192
2193 c->fOutStrEnd = gcc3 + *gcc3size;
2194 c->fOutChar = gcc3;
2195
2196 c->fRetCode = kR3NotRemangled;
2197 (void) parse_special_or_name(c);
2198
2199 result = c->fRetCode;
2200 if (kR3Remangled == result) {
2201 if (c->fOutChar > c->fOutStrEnd)
2202 result = kR3BufferTooSmallRemangled;
2203 *gcc3size = c->fOutChar - gcc3 - 1; // Remove nul from len
2204 }
2205
2206 free(c);
2207
2208 return result;
2209}