]> git.saurik.com Git - apple/xnu.git/blame - libsa/c++rem3.c
xnu-1228.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
2d21ac55 342static __inline__ const char *inCharFromCheck(CheckPoint *chk)
9bccf70c
A
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
2d21ac55 522static Boolean charNext(ParseContext *c, const char *str)
9bccf70c
A
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) {
2d21ac55 545 c->fP.fInChar = (const char *) cp;
9bccf70c
A
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;
2d21ac55 702 char *cp_new;
9bccf70c
A
703 int sub, subEntry, prefixLen;
704 int q_count;
705
706 int decodeStart = c->fP.fNumI;
707
708 // Scan through the incom
709 iP = &c->fInEntries[entry];
710 endSP = &c->fInEntries[MAX_ENTRIES];
711 sP = &c->fInEntries[decodeStart];
712
713 prefixLen = iP->fLen;
714 typeID = cp = iP->fFundTypeID;
715 for (q_count = 0; sP < endSP && (cp-typeID) < prefixLen; q_count++, sP++) {
716 int count;
717
2d21ac55
A
718 count = strtoul(cp, &cp_new, 10);
719 cp = cp_new + count;
9bccf70c
A
720
721 sP->fType = kNTClass;
722 sP->fFundTypeID = typeID;
723 sP->fLen = cp - typeID;
724 }
725 if (sP >= endSP)
726 return false;
727
728 // Search backwards until I find the first substitution
729 sub = -1;
730 for (subEntry = q_count, sP--; subEntry > 0; subEntry--, sP--) {
731 sub = searchDictClass(c, sP->fFundTypeID, sP->fLen);
732 if (-1 != sub)
733 break;
734 }
735
736 // Now drop the symbol into the output buffer
737 oP = newOut(c);
738 if (!oP)
739 return false;
740
741 if (sub < 0)
742 *oP = *iP; // No sub copy original
743 else {
744 // Substitution found
745 prefixLen = sP->fLen; // Length of substitution
746
747 oP->fType = kNTSubstitute; // Assume complete substitution
748 oP->fLen = sub;
2d21ac55 749 oP->fFundTypeID = NULL;
9bccf70c
A
750
751 // We have a partial substitution so tag on the unmatched bit
752 if (prefixLen != iP->fLen) {
753 oP->fType = kNTSubQualClass; // Re-characterise as 2 part sub
754
755 oP = newOut(c);
756 if (!oP)
757 return false;
758
759 *oP = *iP; // Duplicate the original
760 oP->fType = kNTSubQualClass;
761 oP->fFundTypeID += prefixLen; // Skip leading substituted text
762 oP->fLen -= prefixLen;
763 }
764 }
765
766 // Finally insert the qualified class names into the dictionary
767 for (subEntry++, sP++; subEntry < q_count; subEntry++, decodeStart++) {
768 c->fInEntries[decodeStart] = *sP++;
769 if (!newSub(c, decodeStart, 1))
770 return false;
771 }
772 c->fP.fNumI = decodeStart;
773
774 if (!newSub(c, entry, 1))
775 return false;
776
777 return true;
778}
779
780static int
781appendType(ParseContext *c, int type)
782{
783 BaseTypeData *iP, *oP;
784 TypeData *tP;
785 int i, sub;
786 int entry, numE, lastEntry;
787 Boolean found;
788
789 if (type >= c->fP.fNumT)
790 return -1;
791
792 tP = &c->fTypeList[type++];
793 entry = tP->fStartEntry;
794 numE = tP->fNumEntries;
795 lastEntry = entry + numE;
2d21ac55 796 iP = NULL;
9bccf70c
A
797 for (i = 0, found = false, sub = -1; i < numE; i++) {
798 iP = &c->fInEntries[entry + i];
799 switch (iP->fType) {
800
801 // Function & Builtin can't be compressed alone
802 case kNTFunction:
803 case kNTBuiltIn:
804 i++; // Copy the current entry
805 found = true;
806 break;
807
808 case kNTClass:
809 case kNTMethod:
810 sub = searchDict(c, entry + i, numE - i);
811 if (sub < 0 && !iP->fQualified)
812 i++;
813 found = true;
814 break;
815
816 case kNTDeclarator:
817 case kNTArray:
818 sub = searchDict(c, entry + i, numE - i);
819 found = (sub >= 0);
820 break;
821
822 // Internal error's should never occur
823 case kNTKName:
824 case kNTSubstitute:
825 case kNTSubQualClass:
826 case kNTUndefined:
827 default:
828 return -1;
829 }
830 if (found)
831 break;
832 }
833
834 if (!found)
835 return -1; // Internal error: no terminal symbol?
836
837 // Copy the already input buffer to the output
838 oP = &c->fOutEntries[c->fP.fNumO];
839 if (i) {
840 if (c->fP.fNumO + i >= MAX_ENTRIES)
841 return -1;
842
843 bcopy(&c->fInEntries[entry], oP, i * sizeof(*oP));
844 c->fP.fNumO += i;
845 oP += i;
846 }
847
848 if (sub >= 0) {
849 // We found a substitution
850 oP->fType = kNTSubstitute;
851 oP->fLen = sub;
852 c->fP.fNumO++; // Increment output for the substitution
853
854 // Walk over types that have been substituted
855 while (type < c->fP.fNumT
856 && c->fTypeList[type].fStartEntry < lastEntry)
857 type++;
858 }
859 else switch (iP->fType)
860 {
861 case kNTMethod:
862 type = appendType(c, type); // Class Name
863 if (type < 0)
864 return type;
865 type = appendType(c, type); // Pointer to function
866 if (type < 0)
867 return type;
868 break;
869
870 case kNTFunction:
871 type = appendType(c, type); // Return type
872 if (type < 0)
873 return type;
874
875 // process the argument list
876 do {
877 tP = &c->fTypeList[type];
878 if (tP->fStartEntry < lastEntry) {
879 type = appendType(c, type);
880 if (type < 0)
881 return type;
882 }
883 else
884 break;
885 } while (type < c->fP.fNumT);
886 oP = newOut(c);
887 if (!oP)
888 return -1;
889 oP->fType = kNTFuncEnd;
890 break;
891
892 case kNTBuiltIn:
893 i--; // Do not store the buildit in the dictionary
894 break;
895
896 case kNTClass: // Nothing more to do
897 if (!iP->fQualified)
898 break;
899 else if (appendQualifiedClass(c, entry + i))
900 break;
901 else
902 return -1;
903 }
904
905 // No further substititions to be had update the dictionary
906 for (i += entry; --i >= entry; ) {
907 if (!newSub(c, i, lastEntry - i))
908 return -1;
909 }
910
911 return type;
912}
913
914static Boolean appendArgumentList(ParseContext *c)
915{
916 int i, num;
917
918 c->fRetCode = kR3InternalNotRemangled;
919 // Setup the output entry array
920 num = c->fP.fNumT;
921 for (i = 0; i < num; ) {
922 i = appendType(c, i);
923 if (i < 0)
924 return false;
925 }
926
927 // First pass output uncompressed types
928 for (i = 0, num = c->fP.fNumO; i < num; i++) {
929 BaseTypeData *bP;
930
931 bP = &c->fOutEntries[i];
932
933 if (bP->fPseudo)
934 continue; // Pseudo entry do not output;
935
936 switch (bP->fType) {
937
938 case kNTSubstitute: appendSub(c, bP->fLen); break;
939
940 case kNTSubQualClass:
941 appendChar(c, 'N');
942 appendSub(c, bP->fLen);
943 i++; bP = &c->fOutEntries[i];
944 appendNStr(c, bP->fFundTypeID, bP->fLen);
945 appendChar(c, 'E');
946 break;
947
948 case kNTClass:
949 if (bP->fQualified) {
950 appendChar(c, 'N');
951 appendNStr(c, bP->fFundTypeID, bP->fLen);
952 appendChar(c, 'E');
953 }
954 else
955 appendNStr(c, bP->fFundTypeID, bP->fLen);
956 break;
957
958 case kNTArray: {
959 char numbuf[16]; // Bigger than MAX_LONG + 3
960 int len;
961 len = snprintf(numbuf, sizeof(numbuf),
962 "A%lu_", (unsigned long) bP->fFundTypeID);
963 appendNStr(c, numbuf, len);
964 break;
965 }
966
967 case kNTBuiltIn:
968 case kNTDeclarator: appendChar(c, (int) bP->fFundTypeID); break;
969 case kNTMethod: appendChar(c, 'M'); break;
970 case kNTFunction: appendChar(c, 'F'); break;
971 case kNTFuncEnd: appendChar(c, 'E'); break;
972
973 case kNTUndefined:
974 case kNTKName:
975 default:
976 return false; // Fatal errors
977 }
978 }
979
980 // Successful remangle
981 c->fRetCode = kR3Remangled;
982 return true;
983}
984
985//
986// Parse routines
987//
988
989// <count> ::= <digit> <digit>*
990static Boolean parse_count(ParseContext *c, int *countP)
991{
992 int count = 0;
993 char ch;
2d21ac55 994 char *newp;
9bccf70c
A
995
996 ch = peekNext(c);
997 if (ch < '1' || ch > '9')
998 return false;
999
2d21ac55
A
1000 count = strtol(c->fP.fInChar, &newp, 10);
1001 c->fP.fInChar = newp;
9bccf70c
A
1002 if (countP)
1003 *countP = count;
1004
1005 return true;
1006}
1007
1008
1009// "n" <index> can cause the following type to be ambiguous as
1010// n23_Pc... can be
1011// "n" <digit> <counted_class_name> ...
1012// | "n" <digit> <digit> '_' <declarator> <fund_type_id> ...
1013// However as the class '_Pc' is probably going to be unlikely a quick
1014// check to see if the next field is a valid type would probably clear
1015// up the abiguity for the majority of cases.
1016//
1017// <index> ::= <digit> | <digit> <digit> <digit>* "_"
1018static Boolean parse_index(ParseContext *c, int *indexP)
1019{
1020 CheckPoint chk = *checkPoint(c);
1021 char ch0, ch1;
1022 int index;
1023
1024 ch0 = peekAt(c, 0);
1025 ch1 = peekAt(c, 1);
1026
1027 if ( !('0' <= ch0 && ch0 <= '9') )
1028 goto abandonParse;
1029 if ('0' <= ch1 && ch1 <= '9') {
1030 if (!parse_count(c, &index))
1031 goto abandonParse;
1032 if (isNext(c, '_')) {
1033 // @@@ gvdl: Ambiguity check one day
1034 if (indexP)
1035 *indexP = index;
1036 return true;
1037 }
1038 else
1039 resetTo(c, &chk); // Must be the one digit case
1040 }
1041
1042 // One digit case
1043 advance(c, 1);
1044 index = ch0 - '0';
1045
1046 if (indexP)
1047 *indexP = index;
1048 return true;
1049
1050abandonParse:
1051 return false;
1052}
1053
1054
1055// <qualifier> ::= "C" ; const
1056// | "V" ; volatile
1057// | "u" ; restrict (C99) unsupported
1058// | "G" ; struct/union/enum ; unused in gcc3
1059static Boolean parse_qualifiers(ParseContext *c)
1060{
1061 BaseTypeData *bP = c->fCurBaseP;
1062
1063 for (;;) {
1064 if (isNext(c, 'C'))
1065 bP->fConst = true; // "C" ; const
1066 else if (isNext(c, 'V'))
1067 bP->fVolatile = true; // "V" ; volatile
1068 else if (isNext(c, 'u'))
1069 return false; // "u" ; restrict (C99)
1070 else if (isNext(c, 'G'))
1071 continue; // "G" ; struct/union/enum ; unused
1072 else
1073 break;
1074 }
1075
1076 return true;
1077}
1078
1079// Assumes we have an open fInEntry in fCurBaseP
1080static Boolean duplicateEntries(ParseContext *c, int start, int numE)
1081{
1082 BaseTypeData *bIP = &c->fInEntries[start]; // First duplicate entry
1083 BaseTypeData *bP = c->fCurBaseP;
1084 int i;
1085
1086 // Duplicating a method
1087 if (kNTMethod == bIP->fType) {
1088 bP--; // Strip leading 'P' declarator
1089 c->fP.fNumI--;
1090 }
1091
1092 numE--;
1093
1094 // do we have room available for duplication
1095 if (c->fP.fNumI + numE >= MAX_ENTRIES)
1096 return false;
1097
1098 // Copy the parse entries over
1099 bcopy(bIP, bP, (numE + 1) * sizeof(*bP));
1100
1101 // Now we have to duplicate the types for the new entry
1102 for (i = 0; i < c->fP.fNumT; i++) {
1103 TypeData *tP = &c->fTypeList[i];
1104 if (tP->fStartEntry < start)
1105 continue;
1106 else if (tP->fStartEntry <= start + numE)
1107 dupType(c, tP, bP - bIP);
1108 else
1109 break;
1110 }
1111
1112 c->fP.fNumI += numE;
1113 bP += numE;
1114 c->fCurBaseP = bP;
1115
1116 return true;
1117}
1118
1119// Must have a valid c->fCurBaseP pointer on entry
1120// <class_name> ::= <counted_class_name> ; plain class name
1121// | "Q" <qualified_name> ; qualified name
1122// | "B" <index> ; compressed name
1123// | "K" <qualified_name> ; ignored and illegal
1124// <qualified_name> ::= <q_count> <counted_class_name>+
1125// <q_count> ::= <digit> | "_" <digit> <digit>* "_"
1126// <counted_class_name> ::= <count> <name>
1127// <name> ::= <char> <char>*
1128static Boolean
1129parse_class_name(ParseContext *c)
1130{
1131 BaseTypeData *bP = c->fCurBaseP;
1132 const char *typeId = c->fP.fInChar;
1133 char ch;
1134 int count;
1135
1136 if (parse_count(c, &count)) {
1137
1138 // <counted_class_name> ::= <count> <name>
1139 if (!hasRemain(c, count))
1140 goto abandonParse;
1141
1142 bP->fType = kNTClass;
1143 advance(c, count);
1144
1145 bP->fFundTypeID = typeId;
1146 bP->fLen = c->fP.fInChar - typeId;
1147 }
1148 else {
1149 switch (peekNext(c)) {
1150
1151 case 'Q': {
1152 int i, q_count;
1153
1154 advance(c, 1);
1155
1156 // | "Q" <qualified_name> ; qualified name
1157 // <qualified_name> ::= <q_count> <counted_class_name>+
1158 // <q_count> ::= <digit> | "_" <digit> <digit>* "_"
1159 if ('_' == (ch = getNext(c))) {
1160 advance(c, 1);
1161 if (!parse_count(c, &q_count) || !isNext(c, '_'))
1162 goto abandonParse;
1163 }
1164 else if ('1' <= ch && ch <= '9')
1165 q_count = ch - '0';
1166
1167 if (!q_count)
1168 goto abandonParse;
1169
1170 typeId = c->fP.fInChar;
1171 bP->fType = kNTClass;
1172 bP->fQualified = true;
1173 i = 0;
1174 for (i = 0; i < q_count; i++) {
1175 if (parse_count(c, &count))
1176 advance(c, count);
1177 else
1178 goto abandonParse;
1179 }
1180 bP->fLen = c->fP.fInChar - typeId;
1181 bP->fFundTypeID = typeId;
1182 break;
1183 }
1184
1185 case 'B':
1186 // | "B" <index>
1187 advance(c, 1);
1188
1189 if (!parse_index(c, &count) || count >= c->fP.fNumB)
1190 goto abandonParse;
1191
1192 if (!duplicateEntries(c, c->fBDict[count].fStartEntry,
1193 c->fBDict[count].fNumEntries))
1194 goto abandonParse;
1195 return true;
1196
1197 case 'K': default:
1198 goto abandonParse;
1199 }
1200 }
1201
1202 if (newBDict(c, bP - c->fInEntries, 1))
1203 return true;
1204
1205abandonParse:
1206 return false;
1207}
1208
1209// <fund_type_id> ::= <class_name>
1210// | "b" ; bool
1211// | "c" ; char
1212// | "d" ; double
1213// | "e" ; ellipsis
1214// | "f" ; float
1215// | "i" ; int
1216// | "l" ; long
1217// | "r" ; long double
1218// | "s" ; short
1219// | "v" ; void
1220// | "w" ; wchar_t
1221// | "x" ; long long
1222// | "G" <count> ; ???
1223static Boolean parse_fund_type_id(ParseContext *c)
1224{
1225 BaseTypeData *bP = c->fCurBaseP;
1226
1227 if (!parse_class_name(c)) {
1228 // Use the TypeID pointer as a 4 character buffer
1229 char ch = peekNext(c);
1230
1231 if (bP->fSigned && 'c' != ch)
1232 goto abandonParse; // illegal only chars can be signed
1233
1234 switch (ch) {
1235
1236 case 'b': case 'd': case 'f': case 'v': case 'w': // No map types
1237 break;
1238
1239 case 'c': // character
1240 if (bP->fSigned) ch = 'a';
1241 else if (bP->fUnsigned) ch = 'h';
1242 break;
1243 case 'e': // ellipsis
1244 ch = 'z';
1245 break;
1246 case 'i': // int
1247 if (bP->fUnsigned) ch = 'j';
1248 break;
1249 case 'l': // long
1250 if (bP->fUnsigned) ch = 'm';
1251 break;
1252 case 'r': // long double
1253 ch = 'e';
1254 break;
1255 case 's': // short
1256 if (bP->fUnsigned) ch = 't';
1257 break;
1258 case 'x': // long long
1259 if (bP->fUnsigned) ch = 'y';
1260 break;
1261
1262 case 'G': // Don't understand "G"
1263 default:
1264 goto abandonParse;
1265 }
1266
1267 advance(c, 1); // Consume the input character
1268 bP->fFundTypeID = (void *) (int) ch;
1269 bP->fLen = 0;
1270 bP->fType = kNTBuiltIn;
1271 }
1272
1273 return true;
1274
1275abandonParse:
1276 return false;
1277}
1278
1279// <arg_type> ::= <type> [ "n" <index> ]
1280// | "N" <count> <pos> ; Not implemented
1281// | "T" <index> ; Not implemented
1282static Boolean parse_arg_type(ParseContext *c)
1283{
1284 // Don't bother to check point as parse_argument_types does it for us
1285
1286 TypeData *typeP;
1287 int repeat = 0;
1288
1289 typeP = &c->fTypeList[c->fP.fNumT]; // Cache type for later repeat
1290 if (!parse_type(c))
1291 return false;
1292
1293 // Now check for a repeat count on this type
1294 if (isNext(c, 'n')) {
1295 if (!parse_index(c, &repeat))
1296 return false;
1297
1298 do {
1299 c->fCurBaseP = newIn(c); // Duplicate requires a fresh type
1300 if (!c->fCurBaseP)
1301 return false;
1302 if (!duplicateEntries(c, typeP->fStartEntry, typeP->fNumEntries))
1303 return false;
1304 } while (--repeat);
1305 }
1306
1307 return true;
1308}
1309
1310// <argument_types> ::= # Empty
1311// | <arg_type>+
1312static Boolean parse_argument_types(ParseContext *c)
1313{
1314 if (atEnd(c))
1315 return true;
1316
1317 if (!parse_arg_type(c))
1318 goto abandonParse;
1319
1320 while (!atEnd(c) && parse_arg_type(c))
1321 ;
1322
1323 return true;
1324
1325 // Not a counted class name so reset to checkPoint
1326abandonParse:
1327 return false;
1328}
1329
1330// leaf function so the copy aside buffer isn't on the primary
1331// recursion stack.
1332static Boolean
1333rotateFunction(ParseContext *c, int argStart, int retStart)
1334{
1335 char returnTypeBuffer[MAX_RETURN_BUFFER];
2d21ac55
A
1336 unsigned int numArg, numRet;
1337 unsigned int lenArg, lenRet;
9bccf70c 1338 char *sArgP, *sRetP;
2d21ac55 1339 unsigned int i;
9bccf70c
A
1340
1341 TypeData *argTP = &c->fTypeList[argStart];
1342 TypeData *retTP = &c->fTypeList[retStart];
1343
1344 // Rotate around the entries first
1345 numArg = retTP->fStartEntry - argTP->fStartEntry;
1346 numRet = retTP->fNumEntries;
1347 lenArg = numArg * sizeof(BaseTypeData);
1348 lenRet = numRet * sizeof(BaseTypeData);
1349
1350 // Copy the return type into a buffer
1351 if (lenRet > sizeof(returnTypeBuffer))
1352 return false;
1353
1354 sArgP = (char *) (&c->fInEntries[argTP->fStartEntry]);
1355 sRetP = (char *) (&c->fInEntries[retTP->fStartEntry]);
1356
1357 bcopy(sRetP, returnTypeBuffer, lenRet);
1358 bcopy(sArgP, sArgP + lenRet, lenArg);
1359 bcopy(returnTypeBuffer, sArgP, lenRet);
1360
1361 // Retarget the argument and return types for the new entry positions
1362 lenArg = numArg;
1363 lenRet = numRet;
1364 numArg = retStart - argStart;
1365 numRet = c->fP.fNumT - retStart;
1366 for (i = 0; i < numArg; i++)
1367 c->fTypeList[argStart+i].fStartEntry += lenRet;
1368 for (i = 0; i < numRet; i++)
1369 c->fTypeList[retStart+i].fStartEntry -= lenArg;
1370
1371 // Rotate the BDictionary
1372 for (i = 0; i < c->fP.fNumB; i++) {
1373 TypeData *bDP = &c->fBDict[i];
1374 int start = bDP->fStartEntry;
1375
1376 if (start >= argTP->fStartEntry)
1377 bDP->fStartEntry = start + lenRet;
1378 else if (start >= retTP->fStartEntry)
1379 bDP->fStartEntry = start - lenArg;
1380 }
1381
1382 // Finally rotate the retargeted type structures.
1383 lenArg = numArg * sizeof(TypeData);
1384 lenRet = numRet * sizeof(TypeData);
1385
1386 sArgP = (char *) (&c->fTypeList[argStart]);
1387 sRetP = (char *) (&c->fTypeList[retStart]);
1388
1389 bcopy(sRetP, returnTypeBuffer, lenRet);
1390 bcopy(sArgP, sArgP + lenRet, lenArg);
1391 bcopy(returnTypeBuffer, sArgP, lenRet);
1392
1393 return true;
1394}
1395
1396// <function_type> ::= "F" <argument_types> "_" <type>
1397static Boolean parse_function_type(ParseContext *c, Boolean forMethod)
1398{
2d21ac55 1399 TypeData *bDictP = NULL;
9bccf70c
A
1400 BaseTypeData *bP = c->fCurBaseP;
1401
1402 int argTypeStart, retTypeStart;
1403
1404 if (!forMethod) {
1405 bDictP = newBDict(c, c->fP.fNumI-1, 0);
1406 if (!bDictP)
1407 goto abandonParse;
1408 }
1409
1410 if (!isNext(c, 'F'))
1411 goto abandonParse;
1412
1413 bP->fType = kNTFunction;
1414
1415 // Note that the argument types will advance the Entry list
1416 argTypeStart = c->fP.fNumT;
1417 if (!parse_argument_types(c))
1418 goto abandonParse;
1419
1420 if (!isNext(c, '_'))
1421 goto abandonParse;
1422
1423 // Parse the return type
1424 retTypeStart = c->fP.fNumT;
1425 if (!parse_type(c))
1426 goto abandonParse;
1427
1428 // gcc3 puts the return code just after the 'F' declaration
1429 // as this impacts the order of the compression I need to rotate
1430 // the return type and the argument types.
1431 if (!rotateFunction(c, argTypeStart, retTypeStart))
1432 goto abandonParse;
1433
1434 if (!forMethod)
1435 bDictP->fNumEntries = c->fP.fNumI - bDictP->fStartEntry;
1436
1437 return true;
1438
1439abandonParse:
1440 return false;
1441}
1442
1443// To convert 2.95 method to a 3.0 method I need to prune the
1444// first argument of the function type out of the parse tree.
1445static Boolean cleanMethodFunction(ParseContext *c, int type)
1446{
1447 TypeData *typeP, *startTP, *endTP;
1448 BaseTypeData *bP;
1449 int i, thisStart, thisEnd, thisLen, funcRemain;
1450
1451 // Get pointer for the return value's type.
1452 startTP = &c->fTypeList[type+1];
1453 endTP = &c->fTypeList[c->fP.fNumT];
1454
1455 // Now look for the first type that starts after the return type
1456 thisEnd = startTP->fStartEntry + startTP->fNumEntries;
1457 for (startTP++; startTP < endTP; startTP++)
1458 if (startTP->fStartEntry >= thisEnd)
1459 break;
1460
1461 if (startTP >= endTP) {
1462 c->fRetCode = kR3InternalNotRemangled;
1463 return false; // Internal error: should never happen
1464 }
1465
1466 // We now have a pointer to the 1st argument in the input list
1467 // we will need to excise the entries from the input list and don't forget
1468 // to remove the associated types from the type list.
1469
1470 thisLen = startTP->fNumEntries;
1471 thisStart = startTP->fStartEntry;
1472 thisEnd = thisStart + thisLen;
1473 funcRemain = c->fP.fNumI - thisEnd;
1474 bP = &c->fInEntries[thisStart];
1475
1476 // If we have no arguments then replace the pointer with a void
1477 if (!funcRemain) {
1478 c->fP.fNumI -= (thisLen - 1);
1479
1480 bP->fFundTypeID = (void *) (int) 'v'; // Void arg list
1481 bP->fLen = 0;
1482 bP->fType = kNTBuiltIn;
1483
1484 // Update the type entry for the void argument list
1485 startTP->fNumEntries = 1;
1486 return true;
1487 }
1488
1489 // Move the argument list down to replace the 'this' pointer
1490 bcopy(bP + thisLen, bP, funcRemain * sizeof(*bP));
1491 c->fP.fNumI -= thisLen;
1492
1493 // And remove the 'this' pointers type
1494
1495 // First walk over all of the types that have to be removed
1496 for (typeP = startTP + 1; typeP < endTP; typeP++)
1497 if (typeP->fStartEntry >= thisEnd)
1498 break;
1499
1500 if (typeP >= endTP) {
1501 c->fRetCode = kR3InternalNotRemangled;
1502 return false; // Internal error Can't be a void argument list.
1503 }
1504
1505 bcopy(typeP, startTP, (char *) endTP - (char *) typeP);
1506
1507 c->fP.fNumT -= typeP - startTP;
1508 endTP = &c->fTypeList[c->fP.fNumT];
1509 for (typeP = startTP ; typeP < endTP; typeP++)
1510 typeP->fStartEntry -= thisLen;
1511
1512 // Finally we can retarget the BDictionary lists
1513 for (i = 0; i < c->fP.fNumB; i++) {
1514 TypeData *bDP = &c->fBDict[i];
1515 int start = bDP->fStartEntry;
1516
1517 if (start < thisStart)
1518 continue;
1519 if (start >= thisEnd)
1520 break;
1521
1522 bDP->fStartEntry = start - thisLen;
1523 }
1524
1525 return true;
1526}
1527
1528// <method_type> ::= "M" <class_name> <function_type>
1529//
1530// Note this is a very bad function. Gcc3 doesn't doesn't use pointer that
1531// is immediately before this entry. We will have to delete the 'P' declarator
1532// that is before the method declaration.
1533// We will also have to prune the first type in the argument list as Gcc3
1534// doesn't register the 'this' pointer within the function list.
1535static Boolean parse_method_type(ParseContext *c)
1536{
1537 TypeData *bDictP;
1538 TypeData *typeP;
1539 BaseTypeData *bP;
1540
1541 bDictP = newBDict(c, c->fP.fNumI-2, 0);
1542 if (!bDictP)
1543 goto abandonParse;
1544
1545 // Replace 'P' declarator
1546 c->fP.fNumI--;
1547 bP = c->fCurBaseP - 1;
1548
1549 if (!isNext(c, 'M'))
1550 goto abandonParse;
1551
1552 if (bP->fFundTypeID != (void *) (int) 'P')
1553 goto abandonParse;
1554
1555 // Replace the previous 'Pointer' declarator
1556 bP->fType = kNTMethod;
1557 bP->fFundTypeID = NULL;
1558 bP->fLen = 0;
1559
1560 // Grab the method's 'this' type specification
1561 typeP = newType(c, c->fP.fNumI);
1562 if (!newIn(c) || !typeP)
1563 goto abandonParse;
1564
1565 if (!parse_class_name(c))
1566 goto abandonParse;
1567 typeP->fNumEntries = c->fP.fNumI - typeP->fStartEntry;
1568
1569 // Grab the <function_type> specifier
1570 typeP = newType(c, c->fP.fNumI);
1571 if (!newIn(c) || !typeP)
1572 goto abandonParse;
1573
1574 if (!parse_function_type(c, /* forMethod */ true))
1575 goto abandonParse;
1576
1577 if (!cleanMethodFunction(c, typeP - c->fTypeList))
1578 goto abandonParse;
1579 typeP->fNumEntries = c->fP.fNumI - typeP->fStartEntry;
1580
1581 // Finally update the dictionary with the M & 'this'
1582 bDictP->fNumEntries = c->fP.fNumI - bDictP->fStartEntry;
1583
1584 return true;
1585
1586abandonParse:
1587 return false;
1588}
1589
1590static Boolean emitQualifiers(ParseContext *c)
1591{
1592 BaseTypeData *bP = c->fCurBaseP;
1593
1594 if (bP->fVolatile || bP->fConst) {
1595 Boolean isConst, isVolatile, isSigned, isUnsigned;
1596
1597 isVolatile = bP->fVolatile;
1598 isConst = bP->fConst;
1599 isSigned = bP->fSigned;
1600 isUnsigned = bP->fUnsigned;
1601 bP->fConst = bP->fVolatile = bP->fSigned = bP->fUnsigned = 0;
1602
1603 if (isVolatile) {
1604 bP->fType = kNTDeclarator;
1605 bP->fFundTypeID = (void *) (int) 'V';
1606 bP->fLen = 0;
1607 bP = newIn(c);
1608 if (!bP)
1609 return false;
1610 }
1611 if (isConst) {
1612 bP->fType = kNTDeclarator;
1613 bP->fFundTypeID = (void *) (int) 'K';
1614 bP->fLen = 0;
1615 bP = newIn(c);
1616 if (!bP)
1617 return false;
1618 }
1619 bP->fSigned = isSigned;
1620 bP->fUnsigned = isUnsigned;
1621 }
1622
1623 return true;
1624}
1625
1626
1627// <base_type> ::= <function_type> ; function
1628// | <method_type> ; method
1629// | <type_qualifier>* <fund_type_id>
1630// <type_qualifier> ::= "S" ; signed (chars only)
1631// | "U" ; unsigned (any integral type)
1632// | "J" ; __complex
1633// | <qualifier>
1634static Boolean parse_base_type(ParseContext *c)
1635{
1636 if ('F' == peekNext(c)) {
1637 if (!parse_function_type(c, /* forMethod */ false))
1638 goto abandonParse;
1639 }
1640 else if ('M' == peekNext(c)) {
1641 if (!parse_method_type(c))
1642 goto abandonParse;
1643 }
1644 else {
1645 // | <type_qualifier>* <fund_type_id>
1646 BaseTypeData *bP = c->fCurBaseP;
1647 for (;;) {
1648 if (isNext(c, 'S'))
1649 // <type_qualifier> ::= "S" ; signed (chars only)
1650 { bP->fSigned = true; continue; }
1651 else if (isNext(c, 'U'))
1652 // | "U" ; unsigned (any integral type)
1653 { bP->fUnsigned = true; continue; }
1654 else if (isNext(c, 'C'))
1655 // | <qualifier>
1656 // <qualifier> ::= "C" ; const
1657 { bP->fConst = true; continue; }
1658 else if (isNext(c, 'V'))
1659 // | "V" ; volatile
1660 { bP->fVolatile = true; continue; }
1661 else if (charNext(c, "Ju"))
1662 goto abandonParse; // Don't support these qualifiers
1663 // | "J" ; __complex
1664 // | "u" ; restrict (C99)
1665 else
1666 break;
1667 }
1668
1669 if (!emitQualifiers(c))
1670 goto abandonParse;
1671
1672 if (!parse_fund_type_id(c))
1673 goto abandonParse;
1674 }
1675 return true;
1676
1677abandonParse:
1678 return false;
1679}
1680
1681// Use the top SDict as a stack of declarators.
1682// parses <declarator>*
1683// <declarator> ::= "P" ; pointer
1684// | "p" ; pointer (but never occurs?)
1685// | "R" ; reference (&)
1686// | "A" <count> ; array
1687// | "T" <index>
1688// | "O" <count>
1689// | <qualifier>
1690//
1691// As a side-effect the fCurBaseP is setup with any qualifiers on exit
1692static Boolean parse_declarators(ParseContext *c)
1693{
1694 int count;
2d21ac55 1695 unsigned long l;
9bccf70c 1696 BaseTypeData *dP;
2d21ac55 1697 char *newp;
9bccf70c
A
1698
1699 // Note we MUST go through the for loop at least once
1700 for (count = 0; ; count++) {
1701 const char *curDecl;
1702 char ch;
1703
1704 if (!newIn(c))
1705 goto abandonParse;
1706
1707 // <declarator> ::= <qualifier> production
1708 if (!parse_qualifiers(c) || !emitQualifiers(c))
1709 goto abandonParse;
1710
1711 dP = c->fCurBaseP; // Find the current base type pointer
1712
1713 curDecl = c->fP.fInChar;
1714
1715 switch (peekNext(c)) {
1716
1717 case 'P': case 'p': case 'R':
1718 // <declarator> ::= "P" ; pointer
1719 // | "p" ; pointer (but never occurs?)
1720 // | "R" ; reference (&)
1721
1722 dP->fType = kNTDeclarator;
1723 advance(c, 1);
1724
1725 ch = *curDecl;
1726 if ('p' == ch) ch = 'P';
1727 dP->fFundTypeID = (void *) (int) ch;
1728 dP->fLen = 0;
1729 continue; // Go around again
1730
1731 case 'A':
1732 // | "A" <count> ; array
1733 dP->fType = kNTArray;
1734
1735 advance(c, 1); curDecl++;
2d21ac55
A
1736 l = strtoul(curDecl, &newp, 10);
1737 c->fP.fInChar = newp;
1738 curDecl = (const char *)l;
9bccf70c
A
1739 if (!curDecl)
1740 goto abandonParse;
1741 dP->fFundTypeID = curDecl;
1742 dP->fLen = 0;
1743 continue; // Go around again
1744
1745 case 'T': case 'O':
1746 // | "T" <index> Unsupported
1747 // | "O" <count> Unsupported
1748 goto abandonParse;
1749
1750 default:
1751 break;
1752 }
1753
1754 break;
1755 }
1756
1757 dP->fLen = 0;
1758 return true;
1759
1760abandonParse:
1761 return false;
1762}
1763
1764// <type> ::= <declarator>* <base_type>
1765static Boolean parse_type(ParseContext *c)
1766{
1767 CheckPoint chk = *checkPoint(c);
1768 TypeData *typeP = newType(c, c->fP.fNumI);
1769 if (!typeP)
1770 goto abandonParse;
1771
1772 // As a side-effect the fCurBaseP is setup with any qualifiers on exit
1773 if (!parse_declarators(c))
1774 goto abandonParse;
1775
1776 // Merge the last qualifiers into the base type
1777 if (!parse_base_type(c) || kNTUndefined == c->fCurBaseP->fType)
1778 goto abandonParse;
1779
1780 typeP->fNumEntries = c->fP.fNumI - typeP->fStartEntry;
1781 return true;
1782
1783abandonParse:
1784 resetTo(c, &chk);
1785 return false;
1786}
1787
1788// <function_name> ::= <char> <char>*
1789// No need to check point as an invalid function name is fatal
1790// Consumes trailing "__".
1791static Boolean
1792parse_function_name(ParseContext *c)
1793{
1794 char ch;
1795
1796 while ( (ch = peekNext(c)) )
1797 {
1798 advance(c, 1);
1799 if ('_' == ch && '_' == peekNext(c)) {
1800 do {
1801 advance(c, 1);
1802 } while ('_' == peekNext(c));
1803 return true;
1804 }
1805 }
1806
1807 return false;
1808}
1809
1810// <opinfo> ::= "type" <type>
1811// | "__op" <type>
1812// | <opname> "__" ; Implies null function name
1813// | "a"
1814// <opname> ::= "aa" # && ==> "aa"
1815// | "aad" # &= ==> "aN"
1816// | "ad" # & ==> "ad"
1817// | "adv" # /= ==> "dV"
1818// | "aer" # ^= ==> "eO"
1819// | "als" # <<= ==> "lS"
1820// | "amd" # %= ==> "rM"
1821// | "ami" # -= ==> "mI"
1822// | "aml" # *= ==> "mL
1823// | "aor" # |= ==> "oR
1824// | "apl" # += ==> "pL
1825// | "ars" # >>= ==> "rS
1826// | "as" # = ==> "aS
1827// | "cl" # () ==> "cl
1828// | "cm" # , ==> "cm
1829// | "cn" # ?: ==> "qu
1830// | "co" # ~ ==> "co
1831// | "dl" # delete ==> "dl
1832// | "dv" # / ==> "dv
1833// | "eq" # == ==> "eq
1834// | "er" # ^ ==> "eo
1835// | "ge" # >= ==> "ge
1836// | "gt" # > ==> "gt
1837// | "le" # <= ==> "le
1838// | "ls" # << ==> "ls
1839// | "lt" # < ==> "lt
1840// | "md" # % ==> "rm
1841// | "mi" # - ==> "mi
1842// | "ml" # * ==> "ml
1843// | "mm" # -- ==> "mm
1844// | "mn" # <? ==> "????????????????
1845// | "mx" # >? ==> "????????????????
1846// | "ne" # != ==> "ne
1847// | "nt" # ! ==> "nt
1848// | "nw" # new ==> "nw
1849// | "oo" # || ==> "oo"
1850// | "or" # | ==> "or
1851// | "pl" # + ==> "pl
1852// | "pp" # ++ ==> "pp
1853// | "rf" # -> ==> "pt
1854// | "rm" # ->* ==> "pm
1855// | "rs" # >> ==> "rs
1856// | "sz" # sizeof ==> "sz
1857// | "vc" # [] ==> "ix
1858// | "vd" # delete[] ==> "da
1859// | "vn" # new[] ==> "na
1860static struct opMap {
1861 const char *op295, *op3;
1862} opMapTable[] = {
1863 {"aad", "aN" }, {"adv", "dV" }, {"aer", "eO" }, {"als", "lS" },
1864 {"amd", "rM" }, {"ami", "mI" }, {"aml", "mL" }, {"aor", "oR" },
1865 {"apl", "pL" }, {"ars", "rS" }, {"aa", "aa" }, {"ad", "ad" },
1866 {"as", "aS" }, {"cl", "cl" }, {"cm", "cm" }, {"cn", "qu" },
1867 {"co", "co" }, {"dl", "dl" }, {"dv", "dv" }, {"eq", "eq" },
1868 {"er", "eo" }, {"ge", "ge" }, {"gt", "gt" }, {"le", "le" },
1869 {"ls", "ls" }, {"lt", "lt" }, {"md", "rm" }, {"mi", "mi" },
1870 {"ml", "ml" }, {"mm", "mm" }, {"mn", NULL }, {"mx", NULL },
1871 {"ne", "ne" }, {"nt", "nt" }, {"nw", "nw" }, {"oo", "oo" },
1872 {"or", "or" }, {"pl", "pl" }, {"pp", "pp" }, {"rf", "pt" },
1873 {"rm", "pm" }, {"rs", "rs" }, {"sz", "sz" }, {"vc", "ix" },
1874 {"vd", "da" }, {"vn", "na" },
1875};
1876
1877static Boolean parse_opinfo(ParseContext *c, const char **opInfoP)
1878{
1879 CheckPoint chk = *checkPoint(c);
1880 const char *op;
1881 char ch;
2d21ac55 1882 unsigned int i;
9bccf70c
A
1883
1884 if ('a' == (ch = peekNext(c))) {
1885 goto abandonParse;
1886 }
1887 else if (strNext(c, "type")) {
1888 goto abandonParse;
1889 }
1890 else if (retard(c, 4) && strNext(c, "____op")) {
1891 // @@@ gvdl: check this out it may change
1892 // <opinfo> ::= "__op" <type>
1893 goto abandonParse;
1894 }
1895
1896 // Failed till now so reset and see if we have an operator
1897 resetTo(c, &chk);
1898
1899 // quick check to see if we may have an operator
1900 if (!strrchr("acdeglmnoprsv", peekNext(c)))
1901 goto abandonParse;
1902
1903 op = NULL;
1904 for (i = 0; i < sizeof(opMapTable)/sizeof(opMapTable[0]); i++) {
1905 if (strNext(c, opMapTable[i].op295)) {
1906 op = opMapTable[i].op3;
1907 break;
1908 }
1909 }
1910 if (!op)
1911 goto abandonParse;
1912
1913 if (!strNext(c, "__")) // Trailing underbars
1914 goto abandonParse;
1915
1916 if (opInfoP)
1917 *opInfoP = op;
1918 return true;
1919
1920abandonParse:
1921 return false;
1922}
1923
1924// <signature> ::= <qualifier>* <s_element> <argument_types>
1925// <s_element> ::= <class_name>
1926// | "K" <qualified_name>
1927// | "S"
1928// | "F" <argument_types> [ "_" <return_type> ]
1929// <return_type> ::= <type>
1930// Treat the prefix's s_element as a full type
1931static Boolean
1932parse_signature(ParseContext *c,
1933 const char *func, int funcLen, const char *op)
1934{
1935 BaseTypeData *bP;
1936 TypeData *tP;
1937
1938 Boolean isFunction = false;
1939
1940 if (isNext(c, 'F')) {
1941 // | "F" <argument_types> [ "_" <return_type> ]
1942
1943 char numbuf[16]; // Bigger than MAX_INT + 4
1944 int len;
1945 isFunction = true;
1946 if (!funcLen)
1947 goto abandonParse;
1948
1949 len = snprintf(numbuf, sizeof(numbuf), "__Z%d", funcLen);
1950
1951 appendNStr(c, numbuf, len);
1952 appendNStr(c, func, funcLen);
1953 }
1954 else if (isNext(c, 'S')) {
1955 // | "S" ; Ignored
1956 goto abandonParse;
1957 }
1958 else {
1959 const char *qual;
1960 int qualLen;
1961
1962 // See if we can find a qualified class reference
1963 tP = newType(c, c->fP.fNumI);
1964 if (!tP)
1965 goto abandonParse;
1966
1967 bP = newIn(c);
1968 if (!bP)
1969 goto abandonParse;
1970
1971 // Parse any qualifiers, store results in *fCurBaseP
1972 bP->fPseudo = true;
1973 if (!parse_qualifiers(c))
1974 goto abandonParse;
1975
1976 if (!parse_class_name(c))
1977 goto abandonParse;
1978
1979 bP = c->fCurBaseP; // class name may have redifined current
1980 tP->fNumEntries = c->fP.fNumI - tP->fStartEntry;
1981
1982 APPENDSTR(c, "__ZN");
1983 decodeQual(bP, &qualLen, &qual);
1984 if (qualLen)
1985 appendNStr(c, qual, qualLen);
1986 appendNStr(c, bP->fFundTypeID, bP->fLen);
1987
1988 if (funcLen) {
1989 char numbuf[16]; // Bigger than MAX_INT + 1
1990 int len;
1991
1992 len = snprintf(numbuf, sizeof(numbuf), "%d", funcLen);
1993 appendNStr(c, numbuf, len);
1994 appendNStr(c, func, funcLen);
1995 }
1996 else if (op)
1997 appendStr(c, op);
1998 else {
1999 // No function & no op means constructor choose one of C1 & C2
2000 APPENDSTR(c, "C2");
2001 }
2002 appendChar(c, 'E');
2003 }
2004
2005 if (atEnd(c)) {
2006 appendChar(c, 'v'); // void argument list
2007 c->fRetCode = kR3Remangled;
2008 return true;
2009 }
2010
2011 c->fCurBaseP = NULL;
2012 if (!parse_argument_types(c))
2013 goto abandonParse;
2014
2015 if (isFunction) {
2016 if (isNext(c, '_')) {
2017 // && !parse_type(c) @@@ gvdl: Unsupported return
2018 c->fRetCode = kR3InternalNotRemangled;
2019 goto abandonParse;
2020 }
2021 }
2022
2023 if (!atEnd(c))
2024 goto abandonParse;
2025
2026 // OK we have a complete and successful parse now output the
2027 // argument list
2028 return appendArgumentList(c);
2029
2030abandonParse:
2031 return false;
2032}
2033
2034// <mangled_name> ::= <prefix> [ <signature> ]
2035// <prefix> ::= [ "_GLOBAL_" [ID] "__" ] <function_name> "__" [ <opinfo> ]
2036static Boolean parse_mangled_name(ParseContext *c)
2037{
2038 CheckPoint chk;
2039 CheckPoint dubBarChk;
2040 const char *func;
2041
2042 // <prefix> parse
2043 if (strNext(c, "_GLOBAL_")) { // Is this GLOBAL static constructor?
2044 // gvdl: can't deal with _GLOBAL_
2045 c->fRetCode = kR3InternalNotRemangled;
2046 return false; // Can't deal with these
2047 }
2048
2049 func = c->fP.fInChar;
2050 for (chk = *checkPoint(c); ; resetTo(c, &dubBarChk)) {
2051 int funcLen;
2052 const char *op = NULL;
2053
2054 if (!parse_function_name(c))
2055 goto abandonParse;
2056 dubBarChk = *checkPoint(c);
2057
2058 // Note that the opInfo may be earlier than the curDoubleBar
2059 // in which case the function name may need to be shrunk later on.
2060 (void) parse_opinfo(c, &op);
2061
2062 if (atEnd(c))
2063 goto abandonParse; // No Signature?
2064
2d21ac55 2065 funcLen = inCharFromCheck(&dubBarChk) - func - 2;
9bccf70c
A
2066 if (parse_signature(c, func, funcLen, op))
2067 return true;
2068
2069 if (kR3NotRemangled != c->fRetCode)
2070 goto abandonParse;
2071
2072 // If no error then try again maybe another '__' exists
2073 }
2074
2075abandonParse:
2076 resetTo(c, &chk);
2077 return false;
2078}
2079
2080// <gnu_special> ::= ("_._" | "_$_" ) <class_name> ; destructor
2081// | "__vt_" <class_name> ; virtual table
2082// | "_" <class_name> ("."|"$") <varname>
2083static Boolean parse_gnu_special(ParseContext *c)
2084{
2085 CheckPoint chk = *checkPoint(c);
2086 BaseTypeData *bP = newIn(c);
2087
2088 if (!bP)
2089 return false;
2090
2091 // What do the intel desctructors look like
2092 if (strNext(c, "_._") || strNext(c, "_$_") ) // Is this a destructor
2093 {
2094 if (!parse_class_name(c) || !atEnd(c))
2095 goto abandonParse;
2096 APPENDSTR(c, "__ZN");
2097 appendNStr(c, bP->fFundTypeID, bP->fLen);
2098 APPENDSTR(c, "D2Ev");
2099 c->fRetCode = kR3Remangled;
2100 return true;
2101 }
2102 else if (strNext(c, "__vt_")) // Is it's a vtable?
2103 {
2104 if (!parse_class_name(c) || !atEnd(c))
2105 goto abandonParse;
2106
2107 APPENDSTR(c, "__ZTV");
2108 if (kNTClass != bP->fType)
2109 goto abandonParse;
2110 else if (bP->fQualified) {
2111 appendChar(c, 'N');
2112 appendNStr(c, bP->fFundTypeID, bP->fLen);
2113 appendChar(c, 'E');
2114 }
2115 else
2116 appendNStr(c, bP->fFundTypeID, bP->fLen);
2117
2118 c->fRetCode = kR3Remangled;
2119 return true;
2120 }
2121 else if (isNext(c, '_')) // Maybe it's a variable
2122 {
2123 const char *varname;
2124 int varlen, len;
2125 char numbuf[16]; // Bigger than MAX_INT + 1
2126
2127 if (!parse_class_name(c)) // Loads up the bP structure
2128 goto abandonParse;
2129
2130 if (!isNext(c, '.') && !isNext(c, '$'))
2131 goto abandonParse;
2132
2133 // Parse the variable name now.
2134 varname = c->fP.fInChar;
2135 if (atEnd(c) || !isValidFirstChar(getNext(c)))
2136 goto abandonParse;
2137
2138 while ( !atEnd(c) )
2139 if (!isValidChar(getNext(c)))
2140 goto abandonParse;
2141
2142 varlen = c->fP.fInChar - varname;
2143 len = snprintf(numbuf, sizeof(numbuf), "%d", varlen);
2144
2145 APPENDSTR(c, "__ZN");
2146 appendNStr(c, bP->fFundTypeID, bP->fLen);
2147
2148 appendNStr(c, numbuf, len);
2149 appendNStr(c, varname, varlen);
2150 appendChar(c, 'E');
2151
2152 c->fRetCode = kR3Remangled;
2153 return true;
2154 }
2155
2156 // Oh well it is none of those so give up but reset scan
2157abandonParse:
2158 resetTo(c, &chk);
2159 return false;
2160}
2161
2162// <special_or_name> ::= <gnu_special>
2163// | <mangled_name>
2164static Boolean parse_special_or_name(ParseContext *c)
2165{
2166 Boolean res;
2167
2168
2169 res = (parse_gnu_special(c) || parse_mangled_name(c));
2170 appendChar(c, '\0');
2171
2172 return res;
2173}
2174
2175Rem3Return rem3_remangle_name(char *gcc3, int *gcc3size, const char *gcc295)
2176{
2177 ParseContext *c;
2178 Rem3Return result;
2179 int size;
2180
2181 if (!gcc295 || !gcc3 || !gcc3size)
2182 return kR3BadArgument;
2183
2184 size = strlen(gcc295);
2185 if (size < 2)
2186 return kR3NotRemangled; // Not a valid C++ symbol
2187 else if (*gcc295 != '_')
2188 return kR3NotRemangled; // no leading '_', not valid
2189
2190 c = (ParseContext *) malloc(sizeof(*c));
2191 if (!c)
2192 return kR3InternalNotRemangled;
2193 bzero(c, sizeof(*c));
2194
2195 c->fInSize = size;
2196 c->fInStr = gcc295 + 1; // Strip leading '_'
2197 c->fP.fInChar = c->fInStr;
2198
2199 c->fOutStrEnd = gcc3 + *gcc3size;
2200 c->fOutChar = gcc3;
2201
2202 c->fRetCode = kR3NotRemangled;
2203 (void) parse_special_or_name(c);
2204
2205 result = c->fRetCode;
2206 if (kR3Remangled == result) {
2207 if (c->fOutChar > c->fOutStrEnd)
2208 result = kR3BufferTooSmallRemangled;
2209 *gcc3size = c->fOutChar - gcc3 - 1; // Remove nul from len
2210 }
2211
2212 free(c);
2213
2214 return result;
2215}