aboutsummaryrefslogtreecommitdiff
path: root/src/libmach/manglegcc2.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libmach/manglegcc2.c')
-rw-r--r--src/libmach/manglegcc2.c337
1 files changed, 337 insertions, 0 deletions
diff --git a/src/libmach/manglegcc2.c b/src/libmach/manglegcc2.c
new file mode 100644
index 00000000..035ffd35
--- /dev/null
+++ b/src/libmach/manglegcc2.c
@@ -0,0 +1,337 @@
+/*
+ * gcc2 name demangler.
+ */
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+
+#define debug 0
+
+typedef struct Chartab Chartab;
+struct Chartab
+{
+ char c;
+ char *s;
+};
+
+static char*
+chartabsearch(Chartab *ct, int c)
+{
+ for(; ct->c; ct++)
+ if(ct->c == c)
+ return ct->s;
+ return nil;
+}
+
+typedef struct Gccstate Gccstate;
+struct Gccstate
+{
+ char *name[128];
+ int nname;
+};
+static int gccname(char**, char**, Gccstate*);
+char*
+demanglegcc2(char *s, char *buf)
+{
+ char *p, *os, *name, *t;
+ int namelen;
+ Gccstate state;
+
+ state.nname = 0;
+ os = s;
+ p = buf;
+
+ if(memcmp(os, "_._", 3) == 0){
+ name = "destructor";
+ namelen = strlen(name);
+ s = os+3;
+ }else{
+ /* the mangled part begins with the final __ */
+ if((s = strstr(os, "__")) == nil)
+ return os;
+ do{
+ t = s;
+ if(strchr("123456789FHQt", s[2]))
+ break;
+ }while((s = strstr(t+1, "__")) != nil);
+
+ s = t;
+ name = os;
+ namelen = t - os;
+ if(namelen == 0){
+ name = "constructor";
+ namelen = strlen(name);
+ }
+ s += 2;
+ }
+
+ switch(*s){
+ default:
+ return os;
+
+ case 'F': /* plain function */
+ s++;
+ break;
+
+ case 'Q':
+ case 'H':
+ case 't':
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ if(!gccname(&s, &p, &state)){
+ if(debug) fprint(2, "bad name: %s\n", os);
+ return os;
+ }
+ strcpy(p, "::");
+ p += 2;
+ break;
+ }
+
+ memmove(p, name, namelen);
+ p += namelen;
+
+ if(*s && *s != '_'){
+ /* the rest of the name is the argument types */
+ *p++ = '(';
+ while(*s != 0 && *s != '_' && gccname(&s, &p, &state))
+ *p++ = ',';
+ if(*(p-1) == ',')
+ p--;
+ *p++ = ')';
+ }
+
+ if(*s == '_'){
+ /* the remainder is the type of the return value */
+ }
+
+ *p = 0;
+ return buf;
+}
+
+static Chartab typetab[] =
+{
+ 'b', "bool",
+ 'c', "char",
+ 'd', "double",
+ 'i', "int",
+ 'l', "long",
+ 'v', "void",
+ 0, 0
+};
+
+static int
+gccnumber(char **ps, int *pn)
+{
+ char *s;
+ int n;
+
+ s = *ps;
+ if(!isdigit((uchar)*s))
+ return 0;
+ n = strtol(s, &s, 10);
+ if(*s == '_')
+ s++;
+ *ps = s;
+ *pn = n;
+ return 1;
+}
+
+/*
+ * Pick apart the next mangled name section.
+ * Names and types are treated as the same.
+ * Let's see how far we can go before that becomes a problem.
+ */
+static int
+gccname(char **ps, char **pp, Gccstate *state)
+{
+ int i, n, m, val;
+ char c, *os, *s, *t, *p;
+
+ s = *ps;
+ os = s;
+ p = *pp;
+
+/* print("\tgccname: %s\n", s); */
+
+#if 0
+ /* overloaded operators */
+ for(i=0; operators[i].shrt; i++){
+ if(memcmp(operators[i].shrt, s, 2) == 0){
+ strcpy(p, "operator$");
+ strcat(p, operators[i].lng);
+ p += strlen(p);
+ s += 2;
+ goto suffix;
+ }
+ }
+#endif
+ /* basic types */
+ if((t = chartabsearch(typetab, *s)) != nil){
+ s++;
+ strcpy(p, t);
+ p += strlen(t);
+ goto suffix;
+ }
+
+ switch(*s){
+ default:
+ bad:
+ if(debug) fprint(2, "gccname: %s (%s)\n", os, s);
+ return 0;
+
+ case '1': case '2': case '3': case '4': /* name length */
+ case '5': case '6': case '7': case '8': case '9':
+ n = strtol(s, &s, 10);
+ memmove(p, s, n);
+ p += n;
+ s += n;
+ break;
+
+ case 'C': /* const */
+ s++;
+ strcpy(p, "const ");
+ p += strlen(p);
+ if(!gccname(&s, &p, state))
+ return 0;
+ break;
+
+ case 'U': /* unsigned */
+ s++;
+ strcpy(p, "unsigned ");
+ p += strlen(p);
+ if(!gccname(&s, &p, state))
+ return 0;
+ break;
+
+#if 0
+ case 'L': /* default value */
+ t = s;
+ s++;
+ if(!gccname(&s, &p, state))
+ return 0;
+ if(!isdigit((uchar)*s)){
+ fprint(2, "bad value: %s\n", t);
+ return 0;
+ }
+ n = strtol(s, &s, 10);
+ if(*s != 'E'){
+ fprint(2, "bad value2: %s\n", t);
+ return 0;
+ }
+ sprint(p, "=%d", n);
+ p += strlen(p);
+ s++;
+ break;
+#endif
+
+ case 'N': /* repeated name/type */
+ case 'X':
+ c = *s++;
+ if(!isdigit((uchar)*s) || !isdigit((uchar)*(s+1)))
+ goto bad;
+ n = *s++ - '0';
+ m = *s++ - '0';
+ sprint(p, "%c%d/%d", c, n, m);
+ p += strlen(p);
+ break;
+
+ case 'Q': /* hierarchical name */
+ s++;
+ if(!isdigit((uchar)*s))
+ goto bad;
+ n = *s++ - '0';
+ for(i=0; i<n; i++){
+ if(!gccname(&s, &p, state)){
+ if(debug) fprint(2, "bad name in hierarchy: %s in %s\n", s, os);
+ return 0;
+ }
+ if(i+1 < n){
+ strcpy(p, "::");
+ p += 2;
+ }
+ }
+ break;
+
+ case 'P': /* pointer to */
+ s++;
+ if(!gccname(&s, &p, state))
+ return 0;
+ *p++ = '*';
+ break;
+
+ case 'R': /* reference to */
+ s++;
+ if(!gccname(&s, &p, state))
+ return 0;
+ *p++ = '&';
+ break;
+
+ case 'S': /* standard or previously-seen name */
+ s++;
+ if('0' <= *s && *s <= '9'){
+ /* previously seen */
+ t = s-1;
+ n = strtol(s, &s, 10);
+ if(*s != '_'){
+ fprint(2, "bad S: %s\n", t);
+ return 0;
+ }
+ s++;
+ sprint(p, "S%d_", n);
+ p += strlen(p);
+ break;
+ }
+ goto bad;
+
+ case 't': /* named template */
+ c = *s++;
+ if(!gccname(&s, &p, state))
+ return 0;
+ goto template;
+ case 'H': /* nameless template */
+ c = *s++;
+ template:
+ if(!gccnumber(&s, &n))
+ goto bad;
+ *p++ = '<';
+ for(i=0; i<n; i++){
+ val = 1;
+ if(*s == 'Z'){
+ val = 0;
+ s++;
+ }
+ if(!gccname(&s, &p, state))
+ goto bad;
+ if(val){
+ if(!gccnumber(&s, &m))
+ goto bad;
+ sprint(p, "=%d", m);
+ p += strlen(p);
+ }
+ if(i+1 < n)
+ *p++ = ',';
+ }
+ *p++ = '>';
+ if(c == 'H'){
+ if(*s != '_')
+ goto bad;
+ s++;
+ }
+ break;
+
+ case 'T': /* previously-seen type??? e.g., T2 */
+ t = s;
+ for(s++; isdigit((uchar)*s); s++)
+ ;
+ memmove(p, t, s-t);
+ p += s-t;
+ break;
+ }
+
+suffix:
+ *ps = s;
+ *pp = p;
+ return 1;
+}
+