X-Git-Url: https://repo.jachan.dev/binutils.git/blobdiff_plain/e1c145993ec59ed01a1bbc88c294ac3167fa5c66..07882245940db77eb343864330f652d3ec6a0d8a:/binutils/stabs.c diff --git a/binutils/stabs.c b/binutils/stabs.c index 3d34301bb4..f931ff2820 100644 --- a/binutils/stabs.c +++ b/binutils/stabs.c @@ -1,5 +1,5 @@ /* stabs.c -- Parse stabs debugging information - Copyright (C) 1995 Free Software Foundation, Inc. + Copyright (C) 1995, 1996 Free Software Foundation, Inc. Written by Ian Lance Taylor . This file is part of GNU Binutils. @@ -30,6 +30,7 @@ #include "bfd.h" #include "bucomm.h" #include "libiberty.h" +#include "demangle.h" #include "debug.h" #include "budbg.h" @@ -48,11 +49,23 @@ struct stab_handle { - /* The type of the last stab symbol, so that we can detect N_SO - pairs. */ - int last_type; + /* The BFD. */ + bfd *abfd; + /* True if this is stabs in sections. */ + boolean sections; + /* The symbol table. */ + asymbol **syms; + /* The number of symbols. */ + long symcount; + /* The accumulated file name string. */ + char *so_string; + /* The value of the last N_SO symbol. */ + bfd_vma so_value; + /* The value of the start of the file, so that we can handle file + relative N_LBRAC and N_RBRAC symbols. */ + bfd_vma file_start_offset; /* The offset of the start of the function, so that we can handle - function relative N_RBRAC symbols. */ + function relative N_LBRAC and N_RBRAC symbols. */ bfd_vma function_start_offset; /* The version number of gcc which compiled the current compilation unit, 0 if not compiled by gcc. */ @@ -66,6 +79,10 @@ struct stab_handle struct bincl_file *bincl_stack; /* Whether we are inside a function or not. */ boolean within_function; + /* The address of the end of the function, used if we have seen an + N_FUN symbol while in a function. This is -1 if we have not seen + an N_FUN (the normal case). */ + bfd_vma function_end; /* The depth of block nesting. */ int block_depth; /* List of pending variable definitions. */ @@ -134,17 +151,20 @@ static void warn_stab PARAMS ((const char *, const char *)); static boolean parse_stab_string PARAMS ((PTR, struct stab_handle *, int, int, bfd_vma, const char *)); static debug_type parse_stab_type - PARAMS ((PTR, struct stab_handle *, const char **, debug_type **)); + PARAMS ((PTR, struct stab_handle *, const char *, const char **, + debug_type **)); static boolean parse_stab_type_number PARAMS ((const char **, int *)); static debug_type parse_stab_range_type - PARAMS ((PTR, struct stab_handle *, const char **, const int *)); + PARAMS ((PTR, struct stab_handle *, const char *, const char **, + const int *)); static debug_type parse_stab_sun_builtin_type PARAMS ((PTR, const char **)); static debug_type parse_stab_sun_floating_type PARAMS ((PTR, const char **)); static debug_type parse_stab_enum_type PARAMS ((PTR, const char **)); static debug_type parse_stab_struct_type - PARAMS ((PTR, struct stab_handle *, const char **, boolean, const int *)); + PARAMS ((PTR, struct stab_handle *, const char *, const char **, boolean, + const int *)); static boolean parse_stab_baseclasses PARAMS ((PTR, struct stab_handle *, const char **, debug_baseclass **)); static boolean parse_stab_struct_fields @@ -156,7 +176,11 @@ static boolean parse_stab_one_struct_field PARAMS ((PTR, struct stab_handle *, const char **, const char *, debug_field *, boolean *)); static boolean parse_stab_members - PARAMS ((PTR, struct stab_handle *, const char **, debug_method **)); + PARAMS ((PTR, struct stab_handle *, const char *, const char **, + const int *, debug_method **)); +static debug_type parse_stab_argtypes + PARAMS ((PTR, struct stab_handle *, debug_type, const char *, const char *, + debug_type, const char *, boolean, boolean, const char **)); static boolean parse_stab_tilde_field PARAMS ((PTR, struct stab_handle *, const char **, const int *, debug_type *, boolean *)); @@ -176,6 +200,11 @@ static boolean stab_record_type PARAMS ((PTR, struct stab_handle *, const int *, debug_type)); static debug_type stab_xcoff_builtin_type PARAMS ((PTR, struct stab_handle *, int)); +static debug_type stab_find_tagged_type + PARAMS ((PTR, struct stab_handle *, const char *, int, + enum debug_type_kind)); +static debug_type *stab_demangle_argtypes + PARAMS ((PTR, struct stab_handle *, const char *, boolean *)); /* Save a string in memory. */ @@ -323,16 +352,25 @@ warn_stab (p, err) /*ARGSUSED*/ PTR -start_stab (dhandle) +start_stab (dhandle, abfd, sections, syms, symcount) PTR dhandle; + bfd *abfd; + boolean sections; + asymbol **syms; + long symcount; { struct stab_handle *ret; ret = (struct stab_handle *) xmalloc (sizeof *ret); memset (ret, 0, sizeof *ret); + ret->abfd = abfd; + ret->sections = sections; + ret->syms = syms; + ret->symcount = symcount; ret->files = 1; ret->file_types = (struct stab_types **) xmalloc (sizeof *ret->file_types); ret->file_types[0] = NULL; + ret->function_end = (bfd_vma) -1; return (PTR) ret; } @@ -349,15 +387,21 @@ finish_stab (dhandle, handle) if (info->within_function) { - if (! debug_end_function (dhandle, (bfd_vma) -1)) + if (! stab_emit_pending_vars (dhandle, info) + || ! debug_end_function (dhandle, info->function_end)) return false; info->within_function = false; + info->function_end = (bfd_vma) -1; } for (st = info->tags; st != NULL; st = st->next) { - st->slot = debug_make_undefined_tagged_type (dhandle, st->name, - st->kind); + enum debug_type_kind kind; + + kind = st->kind; + if (kind == DEBUG_KIND_ILLEGAL) + kind = DEBUG_KIND_STRUCT; + st->slot = debug_make_undefined_tagged_type (dhandle, st->name, kind); if (st->slot == DEBUG_TYPE_NULL) return false; } @@ -378,6 +422,38 @@ parse_stab (dhandle, handle, type, desc, value, string) { struct stab_handle *info = (struct stab_handle *) handle; + /* gcc will emit two N_SO strings per compilation unit, one for the + directory name and one for the file name. We just collect N_SO + strings as we see them, and start the new compilation unit when + we see a non N_SO symbol. */ + if (info->so_string != NULL + && (type != N_SO || *string == '\0' || value != info->so_value)) + { + if (! debug_set_filename (dhandle, info->so_string)) + return false; + info->main_filename = info->so_string; + + info->gcc_compiled = 0; + info->n_opt_found = false; + + /* Generally, for stabs in the symbol table, the N_LBRAC and + N_RBRAC symbols are relative to the N_SO symbol value. */ + if (! info->sections) + info->file_start_offset = info->so_value; + + /* We need to reset the mapping from type numbers to types. We + can't free the old mapping, because of the use of + debug_make_indirect_type. */ + info->files = 1; + info->file_types = ((struct stab_types **) + xmalloc (sizeof *info->file_types)); + info->file_types[0] = NULL; + + info->so_string = NULL; + + /* Now process whatever type we just got. */ + } + switch (type) { case N_FN: @@ -396,7 +472,10 @@ parse_stab (dhandle, handle, type, desc, value, string) } /* Start an inner lexical block. */ - if (! debug_start_block (dhandle, value + info->function_start_offset)) + if (! debug_start_block (dhandle, + (value + + info->file_start_offset + + info->function_start_offset))) return false; /* Emit any pending variable definitions. */ @@ -418,61 +497,63 @@ parse_stab (dhandle, handle, type, desc, value, string) return false; /* End an inner lexical block. */ - if (! debug_end_block (dhandle, value + info->function_start_offset)) + if (! debug_end_block (dhandle, + (value + + info->file_start_offset + + info->function_start_offset))) return false; --info->block_depth; - if (info->block_depth == 0) + if (info->block_depth < 0) { - info->within_function = false; - if (! debug_end_function (dhandle, - value + info->function_start_offset)) - return false; + fprintf (stderr, "Too many N_RBRACs\n"); + return false; } break; case N_SO: - /* Start a file. If we get two in a row, the first is the - directory name. An empty string is emitted by gcc at the end - of a compilation unit. */ - if (*string == '\0') - { - if (info->within_function) - { - if (! debug_end_function (dhandle, (bfd_vma) -1)) - return false; - info->within_function = false; - } - return true; - } - info->gcc_compiled = 0; - info->n_opt_found = false; - if (info->last_type == N_SO) + /* This always ends a function. */ + if (info->within_function) { - char *o; - - if (! debug_append_filename (dhandle, string)) + bfd_vma endval; + + endval = value; + if (*string != '\0' + && info->function_end != (bfd_vma) -1 + && info->function_end < endval) + endval = info->function_end; + if (! stab_emit_pending_vars (dhandle, info) + || ! debug_end_function (dhandle, endval)) return false; - o = info->main_filename; - info->main_filename = concat (o, string, (const char *) NULL); - free (o); + info->within_function = false; + info->function_end = (bfd_vma) -1; } + + /* An empty string is emitted by gcc at the end of a compilation + unit. */ + if (*string == '\0') + return true; + + /* Just accumulate strings until we see a non N_SO symbol. If + the string starts with '/', we discard the previously + accumulated strings. */ + if (info->so_string == NULL) + info->so_string = xstrdup (string); else { - if (! debug_set_filename (dhandle, string)) - return false; - if (info->main_filename != NULL) - free (info->main_filename); - info->main_filename = xstrdup (string); + char *f; - /* We need to reset the mapping from type numbers to types. - We can't free the old mapping, because of the use of - debug_make_indirect_type. */ - info->files = 1; - info->file_types = ((struct stab_types **) - xmalloc (sizeof *info->file_types)); - info->file_types[0] = NULL; + f = info->so_string; + if (*string == '/') + info->so_string = xstrdup (string); + else + info->so_string = concat (info->so_string, string, + (const char *) NULL); + free (f); } + + info->so_value = value; + break; case N_SOL: @@ -521,10 +602,40 @@ parse_stab (dhandle, handle, type, desc, value, string) return false; break; + case N_FUN: + if (*string == '\0') + { + if (info->within_function) + { + /* This always marks the end of a function; we don't + need to worry about info->function_end. */ + if (info->sections) + value += info->function_start_offset; + if (! stab_emit_pending_vars (dhandle, info) + || ! debug_end_function (dhandle, value)) + return false; + info->within_function = false; + info->function_end = (bfd_vma) -1; + } + break; + } + + /* A const static symbol in the .text section will have an N_FUN + entry. We need to use these to mark the end of the function, + in case we are looking at gcc output before it was changed to + always emit an empty N_FUN. We can't call debug_end_function + here, because it might be a local static symbol. */ + if (info->within_function + && (info->function_end == (bfd_vma) -1 + || value < info->function_end)) + info->function_end = value; + + /* Fall through. */ /* FIXME: gdb checks the string for N_STSYM, N_LCSYM or N_ROSYM symbols, and if it does not start with :S, gdb relocates the value to the start of the section. gcc always seems to use :S, so we don't worry about this. */ + /* Fall through. */ default: { const char *colon; @@ -535,10 +646,21 @@ parse_stab (dhandle, handle, type, desc, value, string) { if (info->within_function) { - if (! debug_end_function (dhandle, (bfd_vma) -1)) + bfd_vma endval; + + endval = value; + if (info->function_end != (bfd_vma) -1 + && info->function_end < endval) + endval = info->function_end; + if (! stab_emit_pending_vars (dhandle, info) + || ! debug_end_function (dhandle, endval)) return false; + info->function_end = (bfd_vma) -1; } - info->function_start_offset = value; + /* For stabs in sections, line numbers and block addresses + are offsets from the start of the function. */ + if (info->sections) + info->function_start_offset = value; info->within_function = true; } @@ -562,8 +684,6 @@ parse_stab (dhandle, handle, type, desc, value, string) break; } - info->last_type = type; - return true; } @@ -688,7 +808,8 @@ parse_stab_string (dhandle, info, stabtype, desc, value, string) can be represented as integral. e.g. "b:c=e6,0" for "const b = blob1" (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;"). */ - dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL); + dtype = parse_stab_type (dhandle, info, (const char *) NULL, + &p, (debug_type **) NULL); if (dtype == DEBUG_TYPE_NULL) return false; if (*p != ',') @@ -708,7 +829,8 @@ parse_stab_string (dhandle, info, stabtype, desc, value, string) case 'C': /* The name of a caught exception. */ - dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL); + dtype = parse_stab_type (dhandle, info, (const char *) NULL, + &p, (debug_type **) NULL); if (dtype == DEBUG_TYPE_NULL) return false; if (! debug_record_label (dhandle, name, dtype, value)) @@ -718,7 +840,8 @@ parse_stab_string (dhandle, info, stabtype, desc, value, string) case 'f': case 'F': /* A function definition. */ - dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL); + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); if (dtype == DEBUG_TYPE_NULL) return false; if (! debug_record_function (dhandle, name, dtype, type == 'F', value)) @@ -731,7 +854,8 @@ parse_stab_string (dhandle, info, stabtype, desc, value, string) while (*p == ';') { ++p; - if (parse_stab_type (dhandle, info, &p, (debug_type **) NULL) + if (parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL) == DEBUG_TYPE_NULL) return false; } @@ -739,14 +863,34 @@ parse_stab_string (dhandle, info, stabtype, desc, value, string) break; case 'G': - /* A global symbol. The value must be extracted from the symbol - table. */ - dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL); - if (dtype == DEBUG_TYPE_NULL) - return false; - if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_GLOBAL, - (bfd_vma) -1)) - return false; + { + char leading; + long c; + asymbol **ps; + + /* A global symbol. The value must be extracted from the + symbol table. */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); + if (dtype == DEBUG_TYPE_NULL) + return false; + leading = bfd_get_symbol_leading_char (info->abfd); + for (c = info->symcount, ps = info->syms; c > 0; --c, ++ps) + { + const char *n; + + n = bfd_asymbol_name (*ps); + if (leading != '\0' && *n == leading) + ++n; + if (*n == *name && strcmp (n, name) == 0) + break; + } + if (c > 0) + value = bfd_asymbol_value (*ps); + if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_GLOBAL, + value)) + return false; + } break; /* This case is faked by a conditional above, when there is no @@ -754,7 +898,8 @@ parse_stab_string (dhandle, info, stabtype, desc, value, string) contains 'l'. */ case 'l': case 's': - dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL); + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); if (dtype == DEBUG_TYPE_NULL) return false; if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_LOCAL, @@ -765,18 +910,24 @@ parse_stab_string (dhandle, info, stabtype, desc, value, string) case 'p': /* A function parameter. */ if (*p != 'F') - dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL); + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); else { /* pF is a two-letter code that means a function parameter in Fortran. The type-number specifies the type of the return value. Translate it into a pointer-to-function type. */ ++p; - dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL); + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); if (dtype != DEBUG_TYPE_NULL) - dtype = debug_make_pointer_type (dhandle, - debug_make_function_type (dhandle, - dtype)); + { + debug_type ftype; + + ftype = debug_make_function_type (dhandle, dtype, + (debug_type *) NULL, false); + dtype = debug_make_pointer_type (dhandle, ftype); + } } if (dtype == DEBUG_TYPE_NULL) return false; @@ -798,7 +949,8 @@ parse_stab_string (dhandle, info, stabtype, desc, value, string) while (*p == ';') { ++p; - if (parse_stab_type (dhandle, info, &p, (debug_type **) NULL) + if (parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL) == DEBUG_TYPE_NULL) return false; } @@ -807,7 +959,8 @@ parse_stab_string (dhandle, info, stabtype, desc, value, string) /* Fall through. */ case 'R': /* Parameter which is in a register. */ - dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL); + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); if (dtype == DEBUG_TYPE_NULL) return false; if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REG, @@ -817,7 +970,8 @@ parse_stab_string (dhandle, info, stabtype, desc, value, string) case 'r': /* Register variable (either global or local). */ - dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL); + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); if (dtype == DEBUG_TYPE_NULL) return false; if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_REGISTER, @@ -831,7 +985,8 @@ parse_stab_string (dhandle, info, stabtype, desc, value, string) case 'S': /* Static symbol at top level of file */ - dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL); + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); if (dtype == DEBUG_TYPE_NULL) return false; if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_STATIC, @@ -841,7 +996,7 @@ parse_stab_string (dhandle, info, stabtype, desc, value, string) case 't': /* A typedef. */ - dtype = parse_stab_type (dhandle, info, &p, &slot); + dtype = parse_stab_type (dhandle, info, name, &p, &slot); if (dtype == DEBUG_TYPE_NULL) return false; if (name == NULL) @@ -874,7 +1029,7 @@ parse_stab_string (dhandle, info, stabtype, desc, value, string) ++p; } - dtype = parse_stab_type (dhandle, info, &p, &slot); + dtype = parse_stab_type (dhandle, info, name, &p, &slot); if (dtype == DEBUG_TYPE_NULL) return false; if (name == NULL) @@ -917,7 +1072,8 @@ parse_stab_string (dhandle, info, stabtype, desc, value, string) case 'V': /* Static symbol of local scope */ - dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL); + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); if (dtype == DEBUG_TYPE_NULL) return false; /* FIXME: gdb checks os9k_stabs here. */ @@ -928,7 +1084,8 @@ parse_stab_string (dhandle, info, stabtype, desc, value, string) case 'v': /* Reference parameter. */ - dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL); + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); if (dtype == DEBUG_TYPE_NULL) return false; if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REFERENCE, @@ -938,7 +1095,8 @@ parse_stab_string (dhandle, info, stabtype, desc, value, string) case 'a': /* Reference parameter which is in a register. */ - dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL); + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); if (dtype == DEBUG_TYPE_NULL) return false; if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REF_REG, @@ -951,7 +1109,8 @@ parse_stab_string (dhandle, info, stabtype, desc, value, string) Sun claims ("dbx and dbxtool interfaces", 2nd ed) that Pascal uses it too, but when I tried it Pascal used "x:3" (local symbol) instead. */ - dtype = parse_stab_type (dhandle, info, &p, (debug_type **) NULL); + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); if (dtype == DEBUG_TYPE_NULL) return false; if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_LOCAL, @@ -970,12 +1129,16 @@ parse_stab_string (dhandle, info, stabtype, desc, value, string) return true; } -/* Parse a stabs type. */ +/* Parse a stabs type. The typename argument is non-NULL if this is a + typedef or a tag definition. The pp argument points to the stab + string, and is updated. The slotp argument points to a place to + store the slot used if the type is being defined. */ static debug_type -parse_stab_type (dhandle, info, pp, slotp) +parse_stab_type (dhandle, info, typename, pp, slotp) PTR dhandle; struct stab_handle *info; + const char *typename; const char **pp; debug_type **slotp; { @@ -1088,8 +1251,6 @@ parse_stab_type (dhandle, info, pp, slotp) { enum debug_type_kind code; const char *q1, *q2, *p; - char *name; - struct stab_tag *st; /* A cross reference to another type. */ @@ -1134,52 +1295,9 @@ parse_stab_type (dhandle, info, pp, slotp) } } - name = savestring (*pp, p - *pp); + dtype = stab_find_tagged_type (dhandle, info, *pp, p - *pp, code); *pp = p + 1; - - /* We pass DEBUG_KIND_VOID because we want all tags in the - same namespace. This is right for C, and I don't know how - to handle other languages. FIXME. */ - dtype = debug_find_tagged_type (dhandle, name, DEBUG_KIND_VOID); - if (dtype != DEBUG_TYPE_NULL) - { - free (name); - if (typenums[0] != -1) - { - if (! stab_record_type (dhandle, info, typenums, dtype)) - return DEBUG_TYPE_NULL; - } - return dtype; - } - - /* We need to allocate an entry on the undefined tag list. */ - for (st = info->tags; st != NULL; st = st->next) - { - if (st->name[0] == name[0] - && strcmp (st->name, name) == 0) - break; - } - if (st == NULL) - { - st = (struct stab_tag *) xmalloc (sizeof *st); - memset (st, 0, sizeof *st); - - st->next = info->tags; - st->name = name; - st->kind = code; - st->slot = DEBUG_TYPE_NULL; - st->type = debug_make_indirect_type (dhandle, &st->slot, name); - info->tags = st; - } - - dtype = st->type; - if (typenums[0] != -1) - { - if (! stab_record_type (dhandle, info, typenums, dtype)) - return DEBUG_TYPE_NULL; - } - return dtype; } break; @@ -1221,7 +1339,8 @@ parse_stab_type (dhandle, info, pp, slotp) /* Go back to the number and have parse_stab_type get it. This means that we can deal with something like t(1,2)=(3,4)=... which the Lucid compiler uses. */ - dtype = parse_stab_type (dhandle, info, pp, (debug_type **) NULL); + dtype = parse_stab_type (dhandle, info, (const char *) NULL, + pp, (debug_type **) NULL); if (dtype == DEBUG_TYPE_NULL) return DEBUG_TYPE_NULL; } @@ -1237,7 +1356,9 @@ parse_stab_type (dhandle, info, pp, slotp) case '*': dtype = debug_make_pointer_type (dhandle, - parse_stab_type (dhandle, info, pp, + parse_stab_type (dhandle, info, + (const char *) NULL, + pp, (debug_type **) NULL)); break; @@ -1245,7 +1366,8 @@ parse_stab_type (dhandle, info, pp, slotp) /* Reference to another type. */ dtype = (debug_make_reference_type (dhandle, - parse_stab_type (dhandle, info, pp, (debug_type **) NULL))); + parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL))); break; case 'f': @@ -1253,14 +1375,18 @@ parse_stab_type (dhandle, info, pp, slotp) /* FIXME: gdb checks os9k_stabs here. */ dtype = (debug_make_function_type (dhandle, - parse_stab_type (dhandle, info, pp, (debug_type **) NULL))); + parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL), + (debug_type *) NULL, false)); break; case 'k': /* Const qualifier on some type (Sun). */ /* FIXME: gdb accepts 'c' here if os9k_stabs. */ dtype = debug_make_const_type (dhandle, - parse_stab_type (dhandle, info, pp, + parse_stab_type (dhandle, info, + (const char *) NULL, + pp, (debug_type **) NULL)); break; @@ -1269,7 +1395,8 @@ parse_stab_type (dhandle, info, pp, slotp) /* FIXME: gdb accepts 'i' here if os9k_stabs. */ dtype = (debug_make_volatile_type (dhandle, - parse_stab_type (dhandle, info, pp, (debug_type **) NULL))); + parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL))); break; case '@': @@ -1281,7 +1408,8 @@ parse_stab_type (dhandle, info, pp, slotp) /* Member type. */ - domain = parse_stab_type (dhandle, info, pp, (debug_type **) NULL); + domain = parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL); if (domain == DEBUG_TYPE_NULL) return DEBUG_TYPE_NULL; @@ -1292,7 +1420,8 @@ parse_stab_type (dhandle, info, pp, slotp) } ++*pp; - memtype = parse_stab_type (dhandle, info, pp, (debug_type **) NULL); + memtype = parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL); if (memtype == DEBUG_TYPE_NULL) return DEBUG_TYPE_NULL; @@ -1307,8 +1436,8 @@ parse_stab_type (dhandle, info, pp, slotp) debug_type return_type; ++*pp; - return_type = parse_stab_type (dhandle, info, pp, - (debug_type **) NULL); + return_type = parse_stab_type (dhandle, info, (const char *) NULL, + pp, (debug_type **) NULL); if (return_type == DEBUG_TYPE_NULL) return DEBUG_TYPE_NULL; if (**pp != ';') @@ -1318,7 +1447,8 @@ parse_stab_type (dhandle, info, pp, slotp) } ++*pp; dtype = debug_make_method_type (dhandle, return_type, - DEBUG_TYPE_NULL, NULL); + DEBUG_TYPE_NULL, + (debug_type *) NULL, false); } else { @@ -1327,8 +1457,10 @@ parse_stab_type (dhandle, info, pp, slotp) debug_type *args; unsigned int n; unsigned int alloc; + boolean varargs; - domain = parse_stab_type (dhandle, info, pp, (debug_type **) NULL); + domain = parse_stab_type (dhandle, info, (const char *) NULL, + pp, (debug_type **) NULL); if (domain == DEBUG_TYPE_NULL) return DEBUG_TYPE_NULL; @@ -1339,8 +1471,8 @@ parse_stab_type (dhandle, info, pp, slotp) } ++*pp; - return_type = parse_stab_type (dhandle, info, pp, - (debug_type **) NULL); + return_type = parse_stab_type (dhandle, info, (const char *) NULL, + pp, (debug_type **) NULL); if (return_type == DEBUG_TYPE_NULL) return DEBUG_TYPE_NULL; @@ -1363,23 +1495,36 @@ parse_stab_type (dhandle, info, pp, slotp) xrealloc ((PTR) args, alloc * sizeof *args)); } - args[n] = parse_stab_type (dhandle, info, pp, - (debug_type **) NULL); + args[n] = parse_stab_type (dhandle, info, (const char *) NULL, + pp, (debug_type **) NULL); if (args[n] == DEBUG_TYPE_NULL) return DEBUG_TYPE_NULL; ++n; } ++*pp; + /* If the last type is not void, then this function takes a + variable number of arguments. Otherwise, we must strip + the void type. */ + if (n == 0 + || debug_get_type_kind (dhandle, args[n - 1]) != DEBUG_KIND_VOID) + varargs = true; + else + { + --n; + varargs = false; + } + args[n] = DEBUG_TYPE_NULL; - dtype = debug_make_method_type (dhandle, return_type, domain, args); + dtype = debug_make_method_type (dhandle, return_type, domain, args, + varargs); } break; case 'r': /* Range type. */ - dtype = parse_stab_range_type (dhandle, info, pp, typenums); + dtype = parse_stab_range_type (dhandle, info, typename, pp, typenums); break; case 'b': @@ -1401,7 +1546,7 @@ parse_stab_type (dhandle, info, pp, slotp) case 's': case 'u': /* Struct or union type. */ - dtype = parse_stab_struct_type (dhandle, info, pp, + dtype = parse_stab_struct_type (dhandle, info, typename, pp, descriptor == 's', typenums); break; @@ -1419,7 +1564,9 @@ parse_stab_type (dhandle, info, pp, slotp) case 'S': dtype = debug_make_set_type (dhandle, - parse_stab_type (dhandle, info, pp, + parse_stab_type (dhandle, info, + (const char *) NULL, + pp, (debug_type **) NULL), stringp); break; @@ -1491,9 +1638,10 @@ parse_stab_type_number (pp, typenums) /* Parse a range type. */ static debug_type -parse_stab_range_type (dhandle, info, pp, typenums) +parse_stab_range_type (dhandle, info, typename, pp, typenums) PTR dhandle; struct stab_handle *info; + const char *typename; const char **pp; const int *typenums; { @@ -1520,7 +1668,8 @@ parse_stab_range_type (dhandle, info, pp, typenums) if (**pp == '=') { *pp = orig; - index_type = parse_stab_type (dhandle, info, pp, (debug_type **) NULL); + index_type = parse_stab_type (dhandle, info, (const char *) NULL, + pp, (debug_type **) NULL); if (index_type == DEBUG_TYPE_NULL) return DEBUG_TYPE_NULL; } @@ -1576,6 +1725,11 @@ parse_stab_range_type (dhandle, info, pp, typenums) if (self_subrange && n2 == 0 && n3 == 0) return debug_make_void_type (dhandle); + /* A type defined as a subrange of itself, with n2 positive and + n3 zero, is a complex type, and n2 is the number of bytes. */ + if (self_subrange && n3 == 0 && n2 > 0) + return debug_make_complex_type (dhandle, n2); + /* If n3 is zero and n2 is positive, this is a floating point type, and n2 is the number of bytes. */ if (n3 == 0 && n2 > 0) @@ -1584,6 +1738,17 @@ parse_stab_range_type (dhandle, info, pp, typenums) /* If the upper bound is -1, this is an unsigned int. */ if (n2 == 0 && n3 == -1) { + /* When gcc is used with -gstabs, but not -gstabs+, it will emit + long long int:t6=r1;0;-1; + long long unsigned int:t7=r1;0;-1; + We hack here to handle this reasonably. */ + if (typename != NULL) + { + if (strcmp (typename, "long long int") == 0) + return debug_make_int_type (dhandle, 8, false); + else if (strcmp (typename, "long long unsigned int") == 0) + return debug_make_int_type (dhandle, 8, true); + } /* FIXME: The size here really depends upon the target. */ return debug_make_int_type (dhandle, 4, true); } @@ -1848,9 +2013,10 @@ parse_stab_enum_type (dhandle, pp) *PP will point to "4a:1,0,32;;". */ static debug_type -parse_stab_struct_type (dhandle, info, pp, structp, typenums) +parse_stab_struct_type (dhandle, info, tagname, pp, structp, typenums) PTR dhandle; struct stab_handle *info; + const char *tagname; const char **pp; boolean structp; const int *typenums; @@ -1872,7 +2038,7 @@ parse_stab_struct_type (dhandle, info, pp, structp, typenums) /* Get the other information. */ if (! parse_stab_baseclasses (dhandle, info, pp, &baseclasses) || ! parse_stab_struct_fields (dhandle, info, pp, &fields, &statics) - || ! parse_stab_members (dhandle, info, pp, &methods) + || ! parse_stab_members (dhandle, info, tagname, pp, typenums, &methods) || ! parse_stab_tilde_field (dhandle, info, pp, typenums, &vptrbase, &ownvptr)) return DEBUG_TYPE_NULL; @@ -1996,7 +2162,8 @@ parse_stab_baseclasses (dhandle, info, pp, retp) } ++*pp; - type = parse_stab_type (dhandle, info, pp, (debug_type **) NULL); + type = parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL); if (type == DEBUG_TYPE_NULL) return false; @@ -2154,7 +2321,8 @@ parse_stab_cpp_abbrev (dhandle, info, pp, retp) after is a regular type definition. Lookup the type, find it's name, and construct the field name. */ - context = parse_stab_type (dhandle, info, pp, (debug_type **) NULL); + context = parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL); if (context == DEBUG_TYPE_NULL) return false; @@ -2187,7 +2355,8 @@ parse_stab_cpp_abbrev (dhandle, info, pp, retp) } ++*pp; - type = parse_stab_type (dhandle, info, pp, (debug_type **) NULL); + type = parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL); if (**pp != ',') { bad_stab (orig); @@ -2261,7 +2430,8 @@ parse_stab_one_struct_field (dhandle, info, pp, p, retp, staticsp) ++*pp; } - type = parse_stab_type (dhandle, info, pp, (debug_type **) NULL); + type = parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL); if (type == DEBUG_TYPE_NULL) return false; @@ -2351,10 +2521,12 @@ parse_stab_one_struct_field (dhandle, info, pp, p, retp, staticsp) name (such as `+=') and `.' marks the end of the operator name. */ static boolean -parse_stab_members (dhandle, info, pp, retp) +parse_stab_members (dhandle, info, tagname, pp, typenums, retp) PTR dhandle; struct stab_handle *info; + const char *tagname; const char **pp; + const int *typenums; debug_method **retp; { const char *orig; @@ -2419,11 +2591,14 @@ parse_stab_members (dhandle, info, pp, retp) do { debug_type type; + boolean stub; char *argtypes; enum debug_visibility visibility; boolean constp, volatilep, staticp; bfd_vma voffset; debug_type context; + const char *physname; + boolean varargs; if (look_ahead_type != DEBUG_TYPE_NULL) { @@ -2433,7 +2608,8 @@ parse_stab_members (dhandle, info, pp, retp) } else { - type = parse_stab_type (dhandle, info, pp, (debug_type **) NULL); + type = parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL); if (type == DEBUG_TYPE_NULL) return false; if (**pp != ':') @@ -2451,7 +2627,10 @@ parse_stab_members (dhandle, info, pp, retp) return false; } - /* FIXME: gdb sets is_stub here. */ + stub = false; + if (debug_get_type_kind (dhandle, type) == DEBUG_KIND_METHOD + && debug_get_parameter_types (dhandle, type, &varargs) == NULL) + stub = true; argtypes = savestring (*pp, p - *pp); *pp = p + 1; @@ -2509,12 +2688,8 @@ parse_stab_members (dhandle, info, pp, retp) { case '*': /* virtual member function, followed by index. The sign - bit is set to distinguish pointers-to-methods from - virtual function indicies. Since the array is in - words, the quantity must be shifted left by 1 on 16 - bit machine, and by 2 on 32 bit machine, forcing the - sign bit out, and usable as a valid index into the - array. Remove the sign bit here. */ + bit is supposedly set to distinguish + pointers-to-methods from virtual function indicies. */ ++*pp; voffset = parse_number (pp, (boolean *) NULL); if (**pp != ';') @@ -2524,7 +2699,6 @@ parse_stab_members (dhandle, info, pp, retp) } ++*pp; voffset &= 0x7fffffff; - voffset += 2; if (**pp == ';' || *pp == '\0') { @@ -2536,11 +2710,14 @@ parse_stab_members (dhandle, info, pp, retp) /* Figure out from whence this virtual function came. It may belong to virtual function table of one of its baseclasses. */ - look_ahead_type = parse_stab_type (dhandle, info, pp, + look_ahead_type = parse_stab_type (dhandle, info, + (const char *) NULL, + pp, (debug_type **) NULL); if (**pp == ':') { /* g++ version 1 overloaded methods. */ + context = DEBUG_TYPE_NULL; } else { @@ -2561,8 +2738,9 @@ parse_stab_members (dhandle, info, pp, retp) ++*pp; staticp = true; voffset = 0; - /* FIXME: gdb sets is_stub here. */ context = DEBUG_TYPE_NULL; + if (strncmp (argtypes, name, strlen (name)) != 0) + stub = true; break; default: @@ -2578,6 +2756,33 @@ parse_stab_members (dhandle, info, pp, retp) break; } + /* If the type is not a stub, then the argtypes string is + the physical name of the function. Otherwise the + argtypes string is the mangled form of the argument + types, and the full type and the physical name must be + extracted from them. */ + if (! stub) + physname = argtypes; + else + { + debug_type class_type, return_type; + + class_type = stab_find_type (dhandle, info, typenums); + if (class_type == DEBUG_TYPE_NULL) + return false; + return_type = debug_get_return_type (dhandle, type); + if (return_type == DEBUG_TYPE_NULL) + { + bad_stab (orig); + return false; + } + type = parse_stab_argtypes (dhandle, info, class_type, name, + tagname, return_type, argtypes, + constp, volatilep, &physname); + if (type == DEBUG_TYPE_NULL) + return false; + } + if (cvars + 1 >= allocvars) { allocvars += 10; @@ -2587,13 +2792,13 @@ parse_stab_members (dhandle, info, pp, retp) } if (! staticp) - variants[cvars] = debug_make_method_variant (dhandle, argtypes, + variants[cvars] = debug_make_method_variant (dhandle, physname, type, visibility, constp, volatilep, voffset, context); else variants[cvars] = debug_make_static_method_variant (dhandle, - argtypes, + physname, type, visibility, constp, @@ -2630,6 +2835,131 @@ parse_stab_members (dhandle, info, pp, retp) return true; } +/* Parse a string representing argument types for a method. Stabs + tries to save space by packing argument types into a mangled + string. This string should give us enough information to extract + both argument types and the physical name of the function, given + the tag name. */ + +static debug_type +parse_stab_argtypes (dhandle, info, class_type, fieldname, tagname, + return_type, argtypes, constp, volatilep, pphysname) + PTR dhandle; + struct stab_handle *info; + debug_type class_type; + const char *fieldname; + const char *tagname; + debug_type return_type; + const char *argtypes; + boolean constp; + boolean volatilep; + const char **pphysname; +{ + boolean is_full_physname_constructor; + boolean is_constructor; + boolean is_destructor; + debug_type *args; + boolean varargs; + + /* Constructors are sometimes handled specially. */ + is_full_physname_constructor = ((argtypes[0] == '_' + && argtypes[1] == '_' + && (isdigit ((unsigned char) argtypes[2]) + || argtypes[2] == 'Q' + || argtypes[2] == 't')) + || strncmp (argtypes, "__ct", 4) == 0); + + is_constructor = (is_full_physname_constructor + || (tagname != NULL + && strcmp (fieldname, tagname) == 0)); + is_destructor = ((argtypes[0] == '_' + && (argtypes[1] == '$' || argtypes[1] == '.') + && argtypes[2] == '_') + || strncmp (argtypes, "__dt", 4) == 0); + + if (is_destructor || is_full_physname_constructor) + *pphysname = argtypes; + else + { + unsigned int len; + const char *const_prefix; + const char *volatile_prefix; + char buf[20]; + unsigned int mangled_name_len; + char *physname; + + len = tagname == NULL ? 0 : strlen (tagname); + const_prefix = constp ? "C" : ""; + volatile_prefix = volatilep ? "V" : ""; + + if (len == 0) + sprintf (buf, "__%s%s", const_prefix, volatile_prefix); + else if (tagname != NULL && strchr (tagname, '<') != NULL) + { + /* Template methods are fully mangled. */ + sprintf (buf, "__%s%s", const_prefix, volatile_prefix); + tagname = NULL; + len = 0; + } + else + sprintf (buf, "__%s%s%d", const_prefix, volatile_prefix, len); + + mangled_name_len = ((is_constructor ? 0 : strlen (fieldname)) + + strlen (buf) + + len + + strlen (argtypes) + + 1); + + if (fieldname[0] == 'o' + && fieldname[1] == 'p' + && (fieldname[2] == '$' || fieldname[2] == '.')) + { + const char *opname; + + opname = cplus_mangle_opname (fieldname + 3, 0); + if (opname == NULL) + { + fprintf (stderr, "No mangling for \"%s\"\n", fieldname); + return DEBUG_TYPE_NULL; + } + mangled_name_len += strlen (opname); + physname = (char *) xmalloc (mangled_name_len); + strncpy (physname, fieldname, 3); + strcpy (physname + 3, opname); + } + else + { + physname = (char *) xmalloc (mangled_name_len); + if (is_constructor) + physname[0] = '\0'; + else + strcpy (physname, fieldname); + } + + strcat (physname, buf); + if (tagname != NULL) + strcat (physname, tagname); + strcat (physname, argtypes); + + *pphysname = physname; + } + + if (*argtypes == '\0') + { + args = (debug_type *) xmalloc (sizeof *args); + *args = NULL; + return debug_make_method_type (dhandle, return_type, class_type, args, + false); + } + + args = stab_demangle_argtypes (dhandle, info, *pphysname, &varargs); + if (args == NULL) + return DEBUG_TYPE_NULL; + + return debug_make_method_type (dhandle, return_type, class_type, args, + varargs); +} + /* The tail end of stabs for C++ classes that contain a virtual function pointer contains a tilde, a %, and a type number. The type number refers to the base class (possibly this class itself) which @@ -2694,7 +3024,8 @@ parse_stab_tilde_field (dhandle, info, pp, typenums, retvptrbase, retownvptr) *pp = hold; - vtype = parse_stab_type (dhandle, info, pp, (debug_type **) NULL); + vtype = parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL); for (p = *pp; *p != ';' && *p != '\0'; p++) ; if (*p != ';') @@ -2721,6 +3052,8 @@ parse_stab_array_type (dhandle, info, pp, stringp) boolean stringp; { const char *orig; + const char *p; + int typenums[2]; debug_type index_type; boolean adjustable; bfd_signed_vma lower, upper; @@ -2737,7 +3070,27 @@ parse_stab_array_type (dhandle, info, pp, stringp) /* FIXME: gdb checks os9k_stabs here. */ - index_type = parse_stab_type (dhandle, info, pp, (debug_type **) NULL); + /* If the index type is type 0, we take it as int. */ + p = *pp; + if (! parse_stab_type_number (&p, typenums)) + return false; + if (typenums[0] == 0 && typenums[1] == 0 && **pp != '=') + { + index_type = debug_find_named_type (dhandle, "int"); + if (index_type == DEBUG_TYPE_NULL) + { + index_type = debug_make_int_type (dhandle, 4, false); + if (index_type == DEBUG_TYPE_NULL) + return false; + } + *pp = p; + } + else + { + index_type = parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL); + } + if (**pp != ';') { bad_stab (orig); @@ -2775,7 +3128,8 @@ parse_stab_array_type (dhandle, info, pp, stringp) } ++*pp; - element_type = parse_stab_type (dhandle, info, pp, (debug_type **) NULL); + element_type = parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL); if (element_type == DEBUG_TYPE_NULL) return false; @@ -2854,7 +3208,8 @@ stab_record_variable (dhandle, info, name, type, kind, val) { struct stab_pending_var *v; - if (! info->within_function + if ((kind == DEBUG_GLOBAL || kind == DEBUG_STATIC) + || ! info->within_function || (info->gcc_compiled == 0 && info->n_opt_found)) return debug_record_variable (dhandle, name, type, kind, val); @@ -3172,3 +3527,1506 @@ stab_xcoff_builtin_type (dhandle, info, typenum) return rettype; } + +/* Find or create a tagged type. */ + +static debug_type +stab_find_tagged_type (dhandle, info, p, len, kind) + PTR dhandle; + struct stab_handle *info; + const char *p; + int len; + enum debug_type_kind kind; +{ + char *name; + debug_type dtype; + struct stab_tag *st; + + name = savestring (p, len); + + /* We pass DEBUG_KIND_ILLEGAL because we want all tags in the same + namespace. This is right for C, and I don't know how to handle + other languages. FIXME. */ + dtype = debug_find_tagged_type (dhandle, name, DEBUG_KIND_ILLEGAL); + if (dtype != DEBUG_TYPE_NULL) + { + free (name); + return dtype; + } + + /* We need to allocate an entry on the undefined tag list. */ + for (st = info->tags; st != NULL; st = st->next) + { + if (st->name[0] == name[0] + && strcmp (st->name, name) == 0) + { + if (st->kind == DEBUG_KIND_ILLEGAL) + st->kind = kind; + free (name); + break; + } + } + if (st == NULL) + { + st = (struct stab_tag *) xmalloc (sizeof *st); + memset (st, 0, sizeof *st); + + st->next = info->tags; + st->name = name; + st->kind = kind; + st->slot = DEBUG_TYPE_NULL; + st->type = debug_make_indirect_type (dhandle, &st->slot, name); + info->tags = st; + } + + return st->type; +} + +/* In order to get the correct argument types for a stubbed method, we + need to extract the argument types from a C++ mangled string. + Since the argument types can refer back to the return type, this + means that we must demangle the entire physical name. In gdb this + is done by calling cplus_demangle and running the results back + through the C++ expression parser. Since we have no expression + parser, we must duplicate much of the work of cplus_demangle here. + + We assume that GNU style demangling is used, since this is only + done for method stubs, and only g++ should output that form of + debugging information. */ + +/* This structure is used to hold a pointer to type information which + demangling a string. */ + +struct stab_demangle_typestring +{ + /* The start of the type. This is not null terminated. */ + const char *typestring; + /* The length of the type. */ + unsigned int len; +}; + +/* This structure is used to hold information while demangling a + string. */ + +struct stab_demangle_info +{ + /* The debugging information handle. */ + PTR dhandle; + /* The stab information handle. */ + struct stab_handle *info; + /* The array of arguments we are building. */ + debug_type *args; + /* Whether the method takes a variable number of arguments. */ + boolean varargs; + /* The array of types we have remembered. */ + struct stab_demangle_typestring *typestrings; + /* The number of typestrings. */ + unsigned int typestring_count; + /* The number of typestring slots we have allocated. */ + unsigned int typestring_alloc; +}; + +static void stab_bad_demangle PARAMS ((const char *)); +static unsigned int stab_demangle_count PARAMS ((const char **)); +static boolean stab_demangle_get_count + PARAMS ((const char **, unsigned int *)); +static boolean stab_demangle_prefix + PARAMS ((struct stab_demangle_info *, const char **)); +static boolean stab_demangle_function_name + PARAMS ((struct stab_demangle_info *, const char **, const char *)); +static boolean stab_demangle_signature + PARAMS ((struct stab_demangle_info *, const char **)); +static boolean stab_demangle_qualified + PARAMS ((struct stab_demangle_info *, const char **, debug_type *)); +static boolean stab_demangle_template + PARAMS ((struct stab_demangle_info *, const char **)); +static boolean stab_demangle_class + PARAMS ((struct stab_demangle_info *, const char **, const char **)); +static boolean stab_demangle_args + PARAMS ((struct stab_demangle_info *, const char **, debug_type **, + boolean *)); +static boolean stab_demangle_arg + PARAMS ((struct stab_demangle_info *, const char **, debug_type **, + unsigned int *, unsigned int *)); +static boolean stab_demangle_type + PARAMS ((struct stab_demangle_info *, const char **, debug_type *)); +static boolean stab_demangle_fund_type + PARAMS ((struct stab_demangle_info *, const char **, debug_type *)); +static boolean stab_demangle_remember_type + PARAMS ((struct stab_demangle_info *, const char *, int)); + +/* Warn about a bad demangling. */ + +static void +stab_bad_demangle (s) + const char *s; +{ + fprintf (stderr, "bad mangled name `%s'\n", s); +} + +/* Get a count from a stab string. */ + +static unsigned int +stab_demangle_count (pp) + const char **pp; +{ + unsigned int count; + + count = 0; + while (isdigit ((unsigned char) **pp)) + { + count *= 10; + count += **pp - '0'; + ++*pp; + } + return count; +} + +/* Require a count in a string. The count may be multiple digits, in + which case it must end in an underscore. */ + +static boolean +stab_demangle_get_count (pp, pi) + const char **pp; + unsigned int *pi; +{ + if (! isdigit ((unsigned char) **pp)) + return false; + + *pi = **pp - '0'; + ++*pp; + if (isdigit ((unsigned char) **pp)) + { + unsigned int count; + const char *p; + + count = *pi; + p = *pp; + do + { + count *= 10; + count += *p - '0'; + ++p; + } + while (isdigit ((unsigned char) *p)); + if (*p == '_') + { + *pp = p + 1; + *pi = count; + } + } + + return true; +} + +/* This function demangles a physical name, returning a NULL + terminated array of argument types. */ + +static debug_type * +stab_demangle_argtypes (dhandle, info, physname, pvarargs) + PTR dhandle; + struct stab_handle *info; + const char *physname; + boolean *pvarargs; +{ + struct stab_demangle_info minfo; + + minfo.dhandle = dhandle; + minfo.info = info; + minfo.args = NULL; + minfo.varargs = false; + minfo.typestring_alloc = 10; + minfo.typestrings = ((struct stab_demangle_typestring *) + xmalloc (minfo.typestring_alloc + * sizeof *minfo.typestrings)); + minfo.typestring_count = 0; + + /* cplus_demangle checks for special GNU mangled forms, but we can't + see any of them in mangled method argument types. */ + + if (! stab_demangle_prefix (&minfo, &physname)) + goto error_return; + + if (*physname != '\0') + { + if (! stab_demangle_signature (&minfo, &physname)) + goto error_return; + } + + free (minfo.typestrings); + minfo.typestrings = NULL; + + if (minfo.args == NULL) + fprintf (stderr, "no argument types in mangled string\n"); + + *pvarargs = minfo.varargs; + return minfo.args; + + error_return: + if (minfo.typestrings != NULL) + free (minfo.typestrings); + return NULL; +} + +/* Demangle the prefix of the mangled name. */ + +static boolean +stab_demangle_prefix (minfo, pp) + struct stab_demangle_info *minfo; + const char **pp; +{ + const char *scan; + unsigned int i; + + /* cplus_demangle checks for global constructors and destructors, + but we can't see them in mangled argument types. */ + + /* Look for `__'. */ + scan = *pp; + do + { + scan = strchr (scan, '_'); + } + while (scan != NULL && *++scan != '_'); + + if (scan == NULL) + { + stab_bad_demangle (*pp); + return false; + } + + --scan; + + /* We found `__'; move ahead to the last contiguous `__' pair. */ + i = strspn (scan, "_"); + if (i > 2) + scan += i - 2; + + if (scan == *pp + && (isdigit ((unsigned char) scan[2]) + || scan[2] == 'Q' + || scan[2] == 't')) + { + /* This is a GNU style constructor name. */ + *pp = scan + 2; + return true; + } + else if (scan == *pp + && ! isdigit ((unsigned char) scan[2]) + && scan[2] != 't') + { + /* Look for the `__' that separates the prefix from the + signature. */ + while (*scan == '_') + ++scan; + scan = strstr (scan, "__"); + if (scan == NULL || scan[2] == '\0') + { + stab_bad_demangle (*pp); + return false; + } + + return stab_demangle_function_name (minfo, pp, scan); + } + else if (scan[2] != '\0') + { + /* The name doesn't start with `__', but it does contain `__'. */ + return stab_demangle_function_name (minfo, pp, scan); + } + else + { + stab_bad_demangle (*pp); + return false; + } + /*NOTREACHED*/ +} + +/* Demangle a function name prefix. The scan argument points to the + double underscore which separates the function name from the + signature. */ + +static boolean +stab_demangle_function_name (minfo, pp, scan) + struct stab_demangle_info *minfo; + const char **pp; + const char *scan; +{ + const char *name; + + /* The string from *pp to scan is the name of the function. We + don't care about the name, since we just looking for argument + types. However, for conversion operators, the name may include a + type which we must remember in order to handle backreferences. */ + + name = *pp; + *pp = scan + 2; + + if (*pp - name >= 5 + && strncmp (name, "type", 4) == 0 + && (name[4] == '$' || name[4] == '.')) + { + const char *tem; + + /* This is a type conversion operator. */ + tem = name + 5; + if (! stab_demangle_type (minfo, &tem, (debug_type *) NULL)) + return false; + } + else if (name[0] == '_' + && name[1] == '_' + && name[2] == 'o' + && name[3] == 'p') + { + const char *tem; + + /* This is a type conversion operator. */ + tem = name + 4; + if (! stab_demangle_type (minfo, &tem, (debug_type *) NULL)) + return false; + } + + return true; +} + +/* Demangle the signature. This is where the argument types are + found. */ + +static boolean +stab_demangle_signature (minfo, pp) + struct stab_demangle_info *minfo; + const char **pp; +{ + const char *orig; + boolean expect_func, func_done; + const char *hold; + + orig = *pp; + + expect_func = false; + func_done = false; + hold = NULL; + + while (**pp != '\0') + { + switch (**pp) + { + case 'Q': + hold = *pp; + if (! stab_demangle_qualified (minfo, pp, (debug_type *) NULL) + || ! stab_demangle_remember_type (minfo, hold, *pp - hold)) + return false; + expect_func = true; + hold = NULL; + break; + + case 'S': + /* Static member function. FIXME: Can this happen? */ + if (hold == NULL) + hold = *pp; + ++*pp; + break; + + case 'C': + /* Const member function. */ + if (hold == NULL) + hold = *pp; + ++*pp; + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (hold == NULL) + hold = *pp; + if (! stab_demangle_class (minfo, pp, (const char **) NULL) + || ! stab_demangle_remember_type (minfo, hold, *pp - hold)) + return false; + expect_func = true; + hold = NULL; + break; + + case 'F': + /* Function. I don't know if this actually happens with g++ + output. */ + hold = NULL; + func_done = true; + ++*pp; + if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs)) + return false; + break; + + case 't': + /* Template. */ + if (hold == NULL) + hold = *pp; + if (! stab_demangle_template (minfo, pp) + || ! stab_demangle_remember_type (minfo, hold, *pp - hold)) + return false; + hold = NULL; + expect_func = true; + break; + + case '_': + /* At the outermost level, we cannot have a return type + specified, so if we run into another '_' at this point we + are dealing with a mangled name that is either bogus, or + has been mangled by some algorithm we don't know how to + deal with. So just reject the entire demangling. */ + stab_bad_demangle (orig); + return false; + + default: + /* Assume we have stumbled onto the first outermost function + argument token, and start processing args. */ + func_done = true; + if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs)) + return false; + break; + } + + if (expect_func) + { + func_done = true; + if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs)) + return false; + } + } + + if (! func_done) + { + /* With GNU style demangling, bar__3foo is 'foo::bar(void)', and + bar__3fooi is 'foo::bar(int)'. We get here when we find the + first case, and need to ensure that the '(void)' gets added + to the current declp. */ + if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs)) + return false; + } + + return true; +} + +/* Demangle a qualified name, such as "Q25Outer5Inner" which is the + mangled form of "Outer::Inner". */ + +static boolean +stab_demangle_qualified (minfo, pp, ptype) + struct stab_demangle_info *minfo; + const char **pp; + debug_type *ptype; +{ + const char *orig; + const char *p; + unsigned int qualifiers; + debug_type context; + + orig = *pp; + + switch ((*pp)[1]) + { + case '_': + /* GNU mangled name with more than 9 classes. The count is + preceded by an underscore (to distinguish it from the <= 9 + case) and followed by an underscore. */ + p = *pp + 2; + if (! isdigit ((unsigned char) *p) || *p == '0') + { + stab_bad_demangle (orig); + return false; + } + qualifiers = atoi (p); + while (isdigit ((unsigned char) *p)) + ++p; + if (*p != '_') + { + stab_bad_demangle (orig); + return false; + } + *pp = p + 1; + break; + + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + qualifiers = (*pp)[1] - '0'; + /* Skip an optional underscore after the count. */ + if ((*pp)[2] == '_') + ++*pp; + *pp += 2; + break; + + case '0': + default: + stab_bad_demangle (orig); + return false; + } + + context = DEBUG_TYPE_NULL; + + /* Pick off the names. */ + while (qualifiers-- > 0) + { + if (**pp == '_') + ++*pp; + if (**pp == 't') + { + /* FIXME: I don't know how to handle the ptype != NULL case + here. */ + if (! stab_demangle_template (minfo, pp)) + return false; + } + else + { + unsigned int len; + + len = stab_demangle_count (pp); + if (strlen (*pp) < len) + { + stab_bad_demangle (orig); + return false; + } + + if (ptype != NULL) + { + const debug_field *fields; + + fields = NULL; + if (context != DEBUG_TYPE_NULL) + fields = debug_get_fields (minfo->dhandle, context); + + context = DEBUG_TYPE_NULL; + + if (fields != NULL) + { + char *name; + + /* Try to find the type by looking through the + fields of context until we find a field with the + same type. This ought to work for a class + defined within a class, but it won't work for, + e.g., an enum defined within a class. stabs does + not give us enough information to figure out the + latter case. */ + + name = savestring (*pp, len); + + for (; *fields != DEBUG_FIELD_NULL; fields++) + { + debug_type ft; + const char *dn; + + ft = debug_get_field_type (minfo->dhandle, *fields); + if (ft == NULL) + return false; + dn = debug_get_type_name (minfo->dhandle, ft); + if (dn != NULL && strcmp (dn, name) == 0) + { + context = ft; + break; + } + } + + free (name); + } + + if (context == DEBUG_TYPE_NULL) + { + /* We have to fall back on finding the type by name. + If there are more types to come, then this must + be a class. Otherwise, it could be anything. */ + + if (qualifiers == 0) + { + char *name; + + name = savestring (*pp, len); + context = debug_find_named_type (minfo->dhandle, + name); + free (name); + } + + if (context == DEBUG_TYPE_NULL) + { + context = stab_find_tagged_type (minfo->dhandle, + minfo->info, + *pp, len, + (qualifiers == 0 + ? DEBUG_KIND_ILLEGAL + : DEBUG_KIND_CLASS)); + if (context == DEBUG_TYPE_NULL) + return false; + } + } + } + + *pp += len; + } + } + + if (ptype != NULL) + *ptype = context; + + return true; +} + +/* Demangle a template. */ + +static boolean +stab_demangle_template (minfo, pp) + struct stab_demangle_info *minfo; + const char **pp; +{ + const char *orig; + unsigned int r, i; + + orig = *pp; + + ++*pp; + + /* Skip the template name. */ + r = stab_demangle_count (pp); + if (r == 0 || strlen (*pp) < r) + { + stab_bad_demangle (orig); + return false; + } + *pp += r; + + /* Get the size of the parameter list. */ + if (stab_demangle_get_count (pp, &r) == 0) + { + stab_bad_demangle (orig); + return false; + } + + for (i = 0; i < r; i++) + { + if (**pp == 'Z') + { + /* This is a type parameter. */ + ++*pp; + if (! stab_demangle_type (minfo, pp, (debug_type *) NULL)) + return false; + } + else + { + const char *old_p; + boolean pointerp, realp, integralp, charp, boolp; + boolean done; + + old_p = *pp; + pointerp = false; + realp = false; + integralp = false; + charp = false; + boolp = false; + done = false; + + /* This is a value parameter. */ + + if (! stab_demangle_type (minfo, pp, (debug_type *) NULL)) + return false; + + while (*old_p != '\0' && ! done) + { + switch (*old_p) + { + case 'P': + case 'p': + case 'R': + pointerp = true; + done = true; + break; + case 'C': /* Const. */ + case 'S': /* Signed. */ + case 'U': /* Unsigned. */ + case 'V': /* Volatile. */ + case 'F': /* Function. */ + case 'M': /* Member function. */ + case 'O': /* ??? */ + ++old_p; + break; + case 'Q': /* Qualified name. */ + integralp = true; + done = true; + break; + case 'T': /* Remembered type. */ + abort (); + case 'v': /* Void. */ + abort (); + case 'x': /* Long long. */ + case 'l': /* Long. */ + case 'i': /* Int. */ + case 's': /* Short. */ + case 'w': /* Wchar_t. */ + integralp = true; + done = true; + break; + case 'b': /* Bool. */ + boolp = true; + done = true; + break; + case 'c': /* Char. */ + charp = true; + done = true; + break; + case 'r': /* Long double. */ + case 'd': /* Double. */ + case 'f': /* Float. */ + realp = true; + done = true; + break; + default: + /* Assume it's a user defined integral type. */ + integralp = true; + done = true; + break; + } + } + + if (integralp) + { + if (**pp == 'm') + ++*pp; + while (isdigit ((unsigned char) **pp)) + ++*pp; + } + else if (charp) + { + unsigned int val; + + if (**pp == 'm') + ++*pp; + val = stab_demangle_count (pp); + if (val == 0) + { + stab_bad_demangle (orig); + return false; + } + } + else if (boolp) + { + unsigned int val; + + val = stab_demangle_count (pp); + if (val != 0 && val != 1) + { + stab_bad_demangle (orig); + return false; + } + } + else if (realp) + { + if (**pp == 'm') + ++*pp; + while (isdigit ((unsigned char) **pp)) + ++*pp; + if (**pp == '.') + { + ++*pp; + while (isdigit ((unsigned char) **pp)) + ++*pp; + } + if (**pp == 'e') + { + ++*pp; + while (isdigit ((unsigned char) **pp)) + ++*pp; + } + } + else if (pointerp) + { + unsigned int len; + + if (! stab_demangle_get_count (pp, &len)) + { + stab_bad_demangle (orig); + return false; + } + *pp += len; + } + } + } + + return true; +} + +/* Demangle a class name. */ + +static boolean +stab_demangle_class (minfo, pp, pstart) + struct stab_demangle_info *minfo; + const char **pp; + const char **pstart; +{ + const char *orig; + unsigned int n; + + orig = *pp; + + n = stab_demangle_count (pp); + if (strlen (*pp) < n) + { + stab_bad_demangle (orig); + return false; + } + + if (pstart != NULL) + *pstart = *pp; + + *pp += n; + + return true; +} + +/* Demangle function arguments. If the pargs argument is not NULL, it + is set to a NULL terminated array holding the arguments. */ + +static boolean +stab_demangle_args (minfo, pp, pargs, pvarargs) + struct stab_demangle_info *minfo; + const char **pp; + debug_type **pargs; + boolean *pvarargs; +{ + const char *orig; + unsigned int alloc, count; + + orig = *pp; + + alloc = 10; + if (pargs != NULL) + { + *pargs = (debug_type *) xmalloc (alloc * sizeof **pargs); + *pvarargs = false; + } + count = 0; + + while (**pp != '_' && **pp != '\0' && **pp != 'e') + { + if (**pp == 'N' || **pp == 'T') + { + char temptype; + unsigned int r, t; + + temptype = **pp; + ++*pp; + + if (temptype == 'T') + r = 1; + else + { + if (! stab_demangle_get_count (pp, &r)) + { + stab_bad_demangle (orig); + return false; + } + } + + if (! stab_demangle_get_count (pp, &t)) + { + stab_bad_demangle (orig); + return false; + } + + if (t >= minfo->typestring_count) + { + stab_bad_demangle (orig); + return false; + } + while (r-- > 0) + { + const char *tem; + + tem = minfo->typestrings[t].typestring; + if (! stab_demangle_arg (minfo, &tem, pargs, &count, &alloc)) + return false; + } + } + else + { + if (! stab_demangle_arg (minfo, pp, pargs, &count, &alloc)) + return false; + } + } + + if (pargs != NULL) + (*pargs)[count] = DEBUG_TYPE_NULL; + + if (**pp == 'e') + { + if (pargs != NULL) + *pvarargs = true; + ++*pp; + } + + return true; +} + +/* Demangle a single argument. */ + +static boolean +stab_demangle_arg (minfo, pp, pargs, pcount, palloc) + struct stab_demangle_info *minfo; + const char **pp; + debug_type **pargs; + unsigned int *pcount; + unsigned int *palloc; +{ + const char *start; + debug_type type; + + start = *pp; + if (! stab_demangle_type (minfo, pp, + pargs == NULL ? (debug_type *) NULL : &type) + || ! stab_demangle_remember_type (minfo, start, *pp - start)) + return false; + + if (pargs != NULL) + { + if (type == DEBUG_TYPE_NULL) + return false; + + if (*pcount + 1 >= *palloc) + { + *palloc += 10; + *pargs = ((debug_type *) + xrealloc (*pargs, *palloc * sizeof **pargs)); + } + (*pargs)[*pcount] = type; + ++*pcount; + } + + return true; +} + +/* Demangle a type. If the ptype argument is not NULL, *ptype is set + to the newly allocated type. */ + +static boolean +stab_demangle_type (minfo, pp, ptype) + struct stab_demangle_info *minfo; + const char **pp; + debug_type *ptype; +{ + const char *orig; + + orig = *pp; + + switch (**pp) + { + case 'P': + case 'p': + /* A pointer type. */ + ++*pp; + if (! stab_demangle_type (minfo, pp, ptype)) + return false; + if (ptype != NULL) + *ptype = debug_make_pointer_type (minfo->dhandle, *ptype); + break; + + case 'R': + /* A reference type. */ + ++*pp; + if (! stab_demangle_type (minfo, pp, ptype)) + return false; + if (ptype != NULL) + *ptype = debug_make_reference_type (minfo->dhandle, *ptype); + break; + + case 'A': + /* An array. */ + { + unsigned long high; + + ++*pp; + high = 0; + while (**pp != '\0' && **pp != '_') + { + if (! isdigit ((unsigned char) **pp)) + { + stab_bad_demangle (orig); + return false; + } + high *= 10; + high += **pp - '0'; + ++*pp; + } + if (**pp != '_') + { + stab_bad_demangle (orig); + return false; + } + ++*pp; + + if (! stab_demangle_type (minfo, pp, ptype)) + return false; + if (ptype != NULL) + { + debug_type int_type; + + int_type = debug_find_named_type (minfo->dhandle, "int"); + if (int_type == NULL) + int_type = debug_make_int_type (minfo->dhandle, 4, false); + *ptype = debug_make_array_type (minfo->dhandle, *ptype, int_type, + 0, high, false); + } + } + break; + + case 'T': + /* A back reference to a remembered type. */ + { + unsigned int i; + const char *p; + + ++*pp; + if (! stab_demangle_get_count (pp, &i)) + { + stab_bad_demangle (orig); + return false; + } + if (i >= minfo->typestring_count) + { + stab_bad_demangle (orig); + return false; + } + p = minfo->typestrings[i].typestring; + if (! stab_demangle_type (minfo, &p, ptype)) + return false; + } + break; + + case 'F': + /* A function. */ + { + debug_type *args; + boolean varargs; + + ++*pp; + if (! stab_demangle_args (minfo, pp, + (ptype == NULL + ? (debug_type **) NULL + : &args), + (ptype == NULL + ? (boolean *) NULL + : &varargs))) + return false; + if (**pp != '_') + { + /* cplus_demangle will accept a function without a return + type, but I don't know when that will happen, or what + to do if it does. */ + stab_bad_demangle (orig); + return false; + } + ++*pp; + if (! stab_demangle_type (minfo, pp, ptype)) + return false; + if (ptype != NULL) + *ptype = debug_make_function_type (minfo->dhandle, *ptype, args, + varargs); + + } + break; + + case 'M': + case 'O': + { + boolean memberp, constp, volatilep; + debug_type *args; + boolean varargs; + unsigned int n; + const char *name; + + memberp = **pp == 'M'; + constp = false; + volatilep = false; + args = NULL; + varargs = false; + + ++*pp; + if (! isdigit ((unsigned char) **pp)) + { + stab_bad_demangle (orig); + return false; + } + n = stab_demangle_count (pp); + if (strlen (*pp) < n) + { + stab_bad_demangle (orig); + return false; + } + name = *pp; + *pp += n; + + if (memberp) + { + if (**pp == 'C') + { + constp = true; + ++*pp; + } + else if (**pp == 'V') + { + volatilep = true; + ++*pp; + } + if (**pp != 'F') + { + stab_bad_demangle (orig); + return false; + } + ++*pp; + if (! stab_demangle_args (minfo, pp, + (ptype == NULL + ? (debug_type **) NULL + : &args), + (ptype == NULL + ? (boolean *) NULL + : &varargs))) + return false; + } + + if (**pp != '_') + { + stab_bad_demangle (orig); + return false; + } + ++*pp; + + if (! stab_demangle_type (minfo, pp, ptype)) + return false; + + if (ptype != NULL) + { + debug_type class_type; + + class_type = stab_find_tagged_type (minfo->dhandle, minfo->info, + name, (int) n, + DEBUG_KIND_CLASS); + if (class_type == DEBUG_TYPE_NULL) + return false; + + if (! memberp) + *ptype = debug_make_offset_type (minfo->dhandle, class_type, + *ptype); + else + { + /* FIXME: We have no way to record constp or + volatilep. */ + *ptype = debug_make_method_type (minfo->dhandle, *ptype, + class_type, args, varargs); + } + } + } + break; + + case 'G': + ++*pp; + if (! stab_demangle_type (minfo, pp, ptype)) + return false; + break; + + case 'C': + ++*pp; + if (! stab_demangle_type (minfo, pp, ptype)) + return false; + if (ptype != NULL) + *ptype = debug_make_const_type (minfo->dhandle, *ptype); + break; + + case 'Q': + { + const char *hold; + + hold = *pp; + if (! stab_demangle_qualified (minfo, pp, ptype)) + return false; + } + break; + + default: + if (! stab_demangle_fund_type (minfo, pp, ptype)) + return false; + break; + } + + return true; +} + +/* Demangle a fundamental type. If the ptype argument is not NULL, + *ptype is set to the newly allocated type. */ + +static boolean +stab_demangle_fund_type (minfo, pp, ptype) + struct stab_demangle_info *minfo; + const char **pp; + debug_type *ptype; +{ + const char *orig; + boolean constp, volatilep, unsignedp, signedp; + boolean done; + + orig = *pp; + + constp = false; + volatilep = false; + unsignedp = false; + signedp = false; + + done = false; + while (! done) + { + switch (**pp) + { + case 'C': + constp = true; + ++*pp; + break; + + case 'U': + unsignedp = true; + ++*pp; + break; + + case 'S': + signedp = true; + ++*pp; + break; + + case 'V': + volatilep = true; + ++*pp; + break; + + default: + done = true; + break; + } + } + + switch (**pp) + { + case '\0': + case '_': + /* cplus_demangle permits this, but I don't know what it means. */ + stab_bad_demangle (orig); + break; + + case 'v': /* void */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, "void"); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_void_type (minfo->dhandle); + } + ++*pp; + break; + + case 'x': /* long long */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, + (unsignedp + ? "long long unsigned int" + : "long long int")); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_int_type (minfo->dhandle, 8, unsignedp); + } + ++*pp; + break; + + case 'l': /* long */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, + (unsignedp + ? "long unsigned int" + : "long int")); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_int_type (minfo->dhandle, 4, unsignedp); + } + ++*pp; + break; + + case 'i': /* int */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, + (unsignedp + ? "unsigned int" + : "int")); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_int_type (minfo->dhandle, 4, unsignedp); + } + ++*pp; + break; + + case 's': /* short */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, + (unsignedp + ? "short unsigned int" + : "short int")); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_int_type (minfo->dhandle, 2, unsignedp); + } + ++*pp; + break; + + case 'b': /* bool */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, "bool"); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_bool_type (minfo->dhandle, 4); + } + ++*pp; + break; + + case 'c': /* char */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, + (unsignedp + ? "unsigned char" + : (signedp + ? "signed char" + : "char"))); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_int_type (minfo->dhandle, 1, unsignedp); + } + ++*pp; + break; + + case 'w': /* wchar_t */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, "__wchar_t"); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_int_type (minfo->dhandle, 2, true); + } + ++*pp; + break; + + case 'r': /* long double */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, "long double"); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_float_type (minfo->dhandle, 8); + } + ++*pp; + break; + + case 'd': /* double */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, "double"); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_float_type (minfo->dhandle, 8); + } + ++*pp; + break; + + case 'f': /* float */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, "float"); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_float_type (minfo->dhandle, 4); + } + ++*pp; + break; + + case 'G': + ++*pp; + if (! isdigit ((unsigned char) **pp)) + { + stab_bad_demangle (orig); + return false; + } + /* Fall through. */ + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + const char *hold; + + if (! stab_demangle_class (minfo, pp, &hold)) + return false; + if (ptype != NULL) + { + char *name; + + name = savestring (hold, *pp - hold); + *ptype = debug_find_named_type (minfo->dhandle, name); + if (*ptype == DEBUG_TYPE_NULL) + { + /* FIXME: It is probably incorrect to assume that + undefined types are tagged types. */ + *ptype = stab_find_tagged_type (minfo->dhandle, minfo->info, + hold, *pp - hold, + DEBUG_KIND_ILLEGAL); + } + free (name); + } + } + break; + + case 't': + if (! stab_demangle_template (minfo, pp)) + return false; + if (ptype != NULL) + { + debug_type t; + + /* FIXME: I really don't know how a template should be + represented in the current type system. Perhaps the + template should be demangled into a string, and the type + should be represented as a named type. However, I don't + know what the base type of the named type should be. */ + t = debug_make_void_type (minfo->dhandle); + t = debug_make_pointer_type (minfo->dhandle, t); + t = debug_name_type (minfo->dhandle, "TEMPLATE", t); + *ptype = t; + } + break; + + default: + stab_bad_demangle (orig); + return false; + } + + if (ptype != NULL) + { + if (constp) + *ptype = debug_make_const_type (minfo->dhandle, *ptype); + if (volatilep) + *ptype = debug_make_volatile_type (minfo->dhandle, *ptype); + } + + return true; +} + +/* Remember a type string in a demangled string. */ + +static boolean +stab_demangle_remember_type (minfo, p, len) + struct stab_demangle_info *minfo; + const char *p; + int len; +{ + if (minfo->typestring_count >= minfo->typestring_alloc) + { + minfo->typestring_alloc += 10; + minfo->typestrings = ((struct stab_demangle_typestring *) + xrealloc (minfo->typestrings, + (minfo->typestring_alloc + * sizeof *minfo->typestrings))); + } + + minfo->typestrings[minfo->typestring_count].typestring = p; + minfo->typestrings[minfo->typestring_count].len = (unsigned int) len; + ++minfo->typestring_count; + + return true; +}