From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 24008 invoked by alias); 25 Oct 2019 12:44:43 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 24000 invoked by uid 89); 25 Oct 2019 12:44:43 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-22.2 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,KAM_SHORT,RCVD_IN_DNSWL_LOW,SPF_HELO_PASS,SPF_PASS autolearn=ham version=3.3.1 spammy=$C$, $c$, H*r:sk:compute, 2016-2019 X-HELO: out2-smtp.messagingengine.com Received: from out2-smtp.messagingengine.com (HELO out2-smtp.messagingengine.com) (66.111.4.26) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 25 Oct 2019 12:44:39 +0000 Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailout.nyi.internal (Postfix) with ESMTP id D99CC22237; Fri, 25 Oct 2019 08:44:37 -0400 (EDT) Received: from imap1 ([10.202.2.51]) by compute4.internal (MEProxy); Fri, 25 Oct 2019 08:44:37 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=lyken.rs; h= mime-version:message-id:in-reply-to:references:date:from:to:cc :subject:content-type; s=fm1; bh=1gCkLsCKZhzMA/QRVwBVHjV9LnUd1XE HMsbtZsH0mII=; b=gHk8RjFvAmj85Ths2CkBChdXt9ACQMcWOE+0UR9PZuT2T8m Hi3qwbQOG1fZ0cWll5L2QVK+axz2Ew7YDNWmzilcXKzN/4C+bZvYKpXoq6Kazd3i DHx42JXV8rxc+PztTSzx+F+JaX8WatmalGftI/GSYvbkyfQe3G53MlPt4QJRnpuV M+T5pVMWSjW2Er7UsO4br/f0Ozq8xyLbJ4+pf8lKBC5MSuLnKMNWtAnGh6yieeeA glvi8rWZ6PSNL+a/L24Ii5NuuapkLBfxru6p944AR/Ha6reSwqKYSIXpetaZceBq nJ17kl3tV8BW4UafdRdVosNy9NObFJ2BimJ7joQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm1; bh=1gCkLs CKZhzMA/QRVwBVHjV9LnUd1XEHMsbtZsH0mII=; b=jDpuYdfu9xYsNp01EAQ/Qn k4YPK7m1FDvrEcg3oxJw/PAXf5RaheKrydVsF/3Wrfz2ZPzh05zMHC9YvmczE0NG pbRHZYiZ0Zr47N867WYLN4WZzHF+ODWhJ3KYLUdI9CHmIMEVqRQ5tmUgy6SYJgpu udXyCiJe2n7P0uhiIfzw9brbz8HoGXJJl+IQyj4Xzopr1KdrHcEG5Kgs96X/y8Cw p4wYMZdNAjGjSA0mVujcM/P2pFLGeML4BDKOK9OgsxouqLVuoGrBYv0U4kMLVpY5 HnXLUM9und5ns1PepY2ALPHfMdDH9ErFZq9/VxNGM6PjdVeRFRyNzmj0Jw5KtrzQ == X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedufedrleefgdehiecutefuodetggdotefrodftvf curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu uegrihhlohhuthemuceftddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenuc fjughrpefofgggkfgjfhffhffvufgtsehttdertderreejnecuhfhrohhmpedfgfguuhgr rhguqdfoihhhrghiuceuuhhrthgvshgtuhdfuceovgguugihsgeslhihkhgvnhdrrhhsqe enucffohhmrghinhepghhnuhdrohhrghenucfrrghrrghmpehmrghilhhfrhhomhepvggu ugihsgeslhihkhgvnhdrrhhsnecuvehluhhsthgvrhfuihiivgeptd Received: by mailuser.nyi.internal (Postfix, from userid 501) id D3CE4C200A4; Fri, 25 Oct 2019 08:44:36 -0400 (EDT) User-Agent: Cyrus-JMAP/3.1.7-470-gedfae93-fmstable-20191021v4 Mime-Version: 1.0 Message-Id: <67e9719b-fbf8-49f5-929d-724d90197927@www.fastmail.com> In-Reply-To: References: Date: Fri, 25 Oct 2019 12:46:00 -0000 From: "Eduard-Mihai Burtescu" To: "Ian Lance Taylor" Cc: "Alexander Monakov" , gcc-patches , "Ian Lance Taylor" Subject: =?UTF-8?Q?Re:_[PATCH]_Refactor_rust-demangle_to_be_independent_of_C++_de?= =?UTF-8?Q?mangling.?= Content-Type: text/plain X-SW-Source: 2019-10/txt/msg01831.txt.bz2 > This can be further optimized by using memcmp in place of strncmp, since from > the length check you know that you won't see the null terminator among the three > chars you're checking. Fair enough, here's the combined changelog/diff, with memcmp: 2019-10-22 Eduard-Mihai Burtescu include/ChangeLog: * demangle.h (rust_demangle_callback): Add. libiberty/ChangeLog: * cplus-dem.c (cplus_demangle): Use rust_demangle directly. (rust_demangle): Remove. * rust-demangle.c (is_prefixed_hash): Rename to is_legacy_prefixed_hash. (parse_lower_hex_nibble): Rename to decode_lower_hex_nibble. (parse_legacy_escape): Rename to decode_legacy_escape. (rust_is_mangled): Remove. (struct rust_demangler): Add. (ERROR_AND): Add. (CHECK_OR): Add. (peek): Add. (next): Add. (struct rust_mangled_ident): Add. (parse_ident): Add. (rust_demangle_sym): Remove. (print_str): Add. (PRINT): Add. (print_ident): Add. (rust_demangle_callback): Add. (struct str_buf): Add. (str_buf_reserve): Add. (str_buf_append): Add. (str_buf_demangle_callback): Add. (rust_demangle): Add. * rust-demangle.h: Remove. diff --git a/include/demangle.h b/include/demangle.h index 06c32571d5c..ce7235d13f3 100644 --- a/include/demangle.h +++ b/include/demangle.h @@ -159,6 +159,11 @@ ada_demangle (const char *mangled, int options); extern char * dlang_demangle (const char *mangled, int options); +extern int +rust_demangle_callback (const char *mangled, int options, + demangle_callbackref callback, void *opaque); + + extern char * rust_demangle (const char *mangled, int options); diff --git a/libiberty/cplus-dem.c b/libiberty/cplus-dem.c index a39e2bf2ed4..735a61d7a82 100644 --- a/libiberty/cplus-dem.c +++ b/libiberty/cplus-dem.c @@ -52,7 +52,6 @@ void * realloc (); #define CURRENT_DEMANGLING_STYLE options #include "libiberty.h" -#include "rust-demangle.h" enum demangling_styles current_demangling_style = auto_demangling; @@ -160,27 +159,20 @@ cplus_demangle (const char *mangled, int options) if ((options & DMGL_STYLE_MASK) == 0) options |= (int) current_demangling_style & DMGL_STYLE_MASK; + /* The Rust demangling is implemented elsewhere. + Legacy Rust symbols overlap with GNU_V3, so try Rust first. */ + if (RUST_DEMANGLING || AUTO_DEMANGLING) + { + ret = rust_demangle (mangled, options); + if (ret || RUST_DEMANGLING) + return ret; + } + /* The V3 ABI demangling is implemented elsewhere. */ - if (GNU_V3_DEMANGLING || RUST_DEMANGLING || AUTO_DEMANGLING) + if (GNU_V3_DEMANGLING || AUTO_DEMANGLING) { ret = cplus_demangle_v3 (mangled, options); - if (GNU_V3_DEMANGLING) - return ret; - - if (ret) - { - /* Rust symbols are GNU_V3 mangled plus some extra subtitutions. - The subtitutions are always smaller, so do in place changes. */ - if (rust_is_mangled (ret)) - rust_demangle_sym (ret); - else if (RUST_DEMANGLING) - { - free (ret); - ret = NULL; - } - } - - if (ret || RUST_DEMANGLING) + if (ret || GNU_V3_DEMANGLING) return ret; } @@ -204,27 +196,6 @@ cplus_demangle (const char *mangled, int options) return (ret); } -char * -rust_demangle (const char *mangled, int options) -{ - /* Rust symbols are GNU_V3 mangled plus some extra subtitutions. */ - char *ret = cplus_demangle_v3 (mangled, options); - - /* The Rust subtitutions are always smaller, so do in place changes. */ - if (ret != NULL) - { - if (rust_is_mangled (ret)) - rust_demangle_sym (ret); - else - { - free (ret); - ret = NULL; - } - } - - return ret; -} - /* Demangle ada names. The encoding is documented in gcc/ada/exp_dbug.ads. */ char * diff --git a/libiberty/rust-demangle.c b/libiberty/rust-demangle.c index 6b62e6dbd80..95255d0b601 100644 --- a/libiberty/rust-demangle.c +++ b/libiberty/rust-demangle.c @@ -33,9 +33,11 @@ If not, see . */ #include "safe-ctype.h" +#include #include #include #include +#include #ifdef HAVE_STRING_H #include @@ -47,207 +49,115 @@ extern void *memset(void *s, int c, size_t n); #include #include "libiberty.h" -#include "rust-demangle.h" - -/* Mangled (legacy) Rust symbols look like this: - _$LT$std..sys..fd..FileDesc$u20$as$u20$core..ops..Drop$GT$::drop::hc68340e1baa4987a - - The original symbol is: - ::drop - - The last component of the path is a 64-bit hash in lowercase hex, - prefixed with "h". Rust does not have a global namespace between - crates, an illusion which Rust maintains by using the hash to - distinguish things that would otherwise have the same symbol. - - Any path component not starting with a XID_Start character is - prefixed with "_". - - The following escape sequences are used: - - "," => $C$ - "@" => $SP$ - "*" => $BP$ - "&" => $RF$ - "<" => $LT$ - ">" => $GT$ - "(" => $LP$ - ")" => $RP$ - "\u{XY}" => $uXY$ - - A double ".." means "::" and a single "." means "-". - - The only characters allowed in the mangled symbol are a-zA-Z0-9 and _.:$ */ - -static const char *hash_prefix = "::h"; -static const size_t hash_prefix_len = 3; -static const size_t hash_len = 16; - -static int is_prefixed_hash (const char *start); -static int parse_lower_hex_nibble (char nibble); -static char parse_legacy_escape (const char **in); - -/* INPUT: sym: symbol that has been through C++ (gnu v3) demangling - - This function looks for the following indicators: - - 1. The hash must consist of "h" followed by 16 lowercase hex digits. - - 2. As a sanity check, the hash must use between 5 and 15 of the 16 - possible hex digits. This is true of 99.9998% of hashes so once - in your life you may see a false negative. The point is to - notice path components that could be Rust hashes but are - probably not, like "haaaaaaaaaaaaaaaa". In this case a false - positive (non-Rust symbol has an important path component - removed because it looks like a Rust hash) is worse than a false - negative (the rare Rust symbol is not demangled) so this sets - the balance in favor of false negatives. - - 3. There must be no characters other than a-zA-Z0-9 and _.:$ */ - -int -rust_is_mangled (const char *sym) +struct rust_demangler { - size_t len, len_without_hash; - const char *end; - - if (!sym) - return 0; - - len = strlen (sym); - if (len <= hash_prefix_len + hash_len) - /* Not long enough to contain "::h" + hash + something else */ - return 0; - - len_without_hash = len - (hash_prefix_len + hash_len); - if (!is_prefixed_hash (sym + len_without_hash)) - return 0; - - end = sym + len_without_hash; - - while (sym < end) - { - if (*sym == '$' || *sym == '.' || *sym == '_' || *sym == ':' - || ISALNUM (*sym)) - sym++; - else - return 0; - } + const char *sym; + size_t sym_len; + + void *callback_opaque; + demangle_callbackref callback; + + /* Position of the next character to read from the symbol. */ + size_t next; + + /* Non-zero if any error occurred. */ + int errored; + + /* Non-zero if printing should be verbose (e.g. include hashes). */ + int verbose; + + /* Rust mangling version, with legacy mangling being -1. */ + int version; +}; + +#define ERROR_AND(x) \ + do \ + { \ + rdm->errored = 1; \ + x; \ + } \ + while (0) +#define CHECK_OR(cond, x) \ + do \ + { \ + if (!(cond)) \ + ERROR_AND (x); \ + } \ + while (0) + +/* Parsing functions. */ - return 1; +static char +peek (const struct rust_demangler *rdm) +{ + if (rdm->next < rdm->sym_len) + return rdm->sym[rdm->next]; + return 0; } -/* A hash is the prefix "::h" followed by 16 lowercase hex digits. The - hex digits must contain at least 5 distinct digits. */ +static char +next (struct rust_demangler *rdm) +{ + char c = peek (rdm); + CHECK_OR (c, return 0); + rdm->next++; + return c; +} -static int -is_prefixed_hash (const char *str) +struct rust_mangled_ident { - const char *end; - char seen[16]; - size_t i; - int count, nibble; + /* ASCII part of the identifier. */ + const char *ascii; + size_t ascii_len; +}; - if (strncmp (str, hash_prefix, hash_prefix_len)) - return 0; - str += hash_prefix_len; +static struct rust_mangled_ident +parse_ident (struct rust_demangler *rdm) +{ + char c; + size_t start, len; + struct rust_mangled_ident ident; - memset (seen, 0, sizeof(seen)); - for (end = str + hash_len; str < end; str++) - { - nibble = parse_lower_hex_nibble (*str); - if (nibble < 0) - return 0; - seen[nibble] = 1; - } + ident.ascii = NULL; + ident.ascii_len = 0; - /* Count how many distinct digits seen */ - count = 0; - for (i = 0; i < 16; i++) - if (seen[i]) - count++; + c = next (rdm); + CHECK_OR (ISDIGIT (c), return ident); + len = c - '0'; - return count >= 5; -} + if (c != '0') + while (ISDIGIT (peek (rdm))) + len = len * 10 + (next (rdm) - '0'); -/* - INPUT: sym: symbol for which rust_is_mangled(sym) returned 1. + start = rdm->next; + rdm->next += len; + /* Check for overflows. */ + CHECK_OR ((start <= rdm->next) && (rdm->next <= rdm->sym_len), return ident); - The input is demangled in-place because the mangled name is always - longer than the demangled one. */ + ident.ascii = rdm->sym + start; + ident.ascii_len = len; -void -rust_demangle_sym (char *sym) -{ - const char *in; - char *out; - const char *end; - char unescaped; + if (ident.ascii_len == 0) + ident.ascii = NULL; - if (!sym) - return; + return ident; +} - in = sym; - out = sym; - end = sym + strlen (sym) - (hash_prefix_len + hash_len); +/* Printing functions. */ - while (in < end) - { - if (*in == '$') - { - unescaped = parse_legacy_escape (&in); - if (unescaped) - *out++ = unescaped; - else - /* unexpected escape sequence, skip the rest of this segment. */ - while (in < end && *in != ':') - *out++ = *in++; - } - else if (*in == '_') - { - /* If this is the start of a path component and the next - character is an escape sequence, ignore the underscore. The - mangler inserts an underscore to make sure the path - component begins with a XID_Start character. */ - if ((in == sym || in[-1] == ':') && in[1] == '$') - in++; - else - *out++ = *in++; - } - else if (*in == '.') - { - if (in[1] == '.') - { - /* ".." becomes "::" */ - *out++ = ':'; - *out++ = ':'; - in += 2; - } - else - { - /* "." becomes "-" */ - *out++ = '-'; - in++; - } - } - else if (*in == ':' || ISALNUM (*in)) - *out++ = *in++; - else - { - /* unexpected character in symbol, not rust_is_mangled. */ - *out++ = '?'; /* This is pretty lame, but it's hard to do better. */ - *out = '\0'; - return; - } - } - - *out = '\0'; +static void +print_str (struct rust_demangler *rdm, const char *data, size_t len) +{ + if (!rdm->errored) + rdm->callback (data, len, rdm->callback_opaque); } +#define PRINT(s) print_str (rdm, s, strlen (s)) + /* Return a 0x0-0xf value if the char is 0-9a-f, and -1 otherwise. */ static int -parse_lower_hex_nibble (char nibble) +decode_lower_hex_nibble (char nibble) { if ('0' <= nibble && nibble <= '9') return nibble - '0'; @@ -258,17 +168,17 @@ parse_lower_hex_nibble (char nibble) /* Return the unescaped character for a "$...$" escape, or 0 if invalid. */ static char -parse_legacy_escape (const char **in) +decode_legacy_escape (const char *e, size_t len, size_t *out_len) { char c = 0; - const char *e; size_t escape_len = 0; int lo_nibble = -1, hi_nibble = -1; - if ((*in)[0] != '$') + if (len < 3 || e[0] != '$') return 0; - e = *in + 1; + e++; + len--; if (e[0] == 'C') { @@ -276,7 +186,7 @@ parse_legacy_escape (const char **in) c = ','; } - else + else if (len > 2) { escape_len = 2; @@ -294,14 +204,14 @@ parse_legacy_escape (const char **in) c = '('; else if (e[0] == 'R' && e[1] == 'P') c = ')'; - else if (e[0] == 'u') + else if (e[0] == 'u' && len > 3) { escape_len = 3; - hi_nibble = parse_lower_hex_nibble (e[1]); + hi_nibble = decode_lower_hex_nibble (e[1]); if (hi_nibble < 0) return 0; - lo_nibble = parse_lower_hex_nibble (e[2]); + lo_nibble = decode_lower_hex_nibble (e[2]); if (lo_nibble < 0) return 0; @@ -314,9 +224,314 @@ parse_legacy_escape (const char **in) } } - if (!c || e[escape_len] != '$') + if (!c || len <= escape_len || e[escape_len] != '$') return 0; - *in += 2 + escape_len; + *out_len = 2 + escape_len; return c; } + +static void +print_ident (struct rust_demangler *rdm, struct rust_mangled_ident ident) +{ + char unescaped; + size_t len; + + if (rdm->errored) + return; + + if (rdm->version == -1) + { + /* Ignore leading underscores preceding escape sequences. + The mangler inserts an underscore to make sure the + identifier begins with a XID_Start character. */ + if (ident.ascii_len >= 2 && ident.ascii[0] == '_' + && ident.ascii[1] == '$') + { + ident.ascii++; + ident.ascii_len--; + } + + while (ident.ascii_len > 0) + { + /* Handle legacy escape sequences ("$...$", ".." or "."). */ + if (ident.ascii[0] == '$') + { + unescaped + = decode_legacy_escape (ident.ascii, ident.ascii_len, &len); + if (unescaped) + print_str (rdm, &unescaped, 1); + else + { + /* Unexpected escape sequence, print the rest verbatim. */ + print_str (rdm, ident.ascii, ident.ascii_len); + return; + } + } + else if (ident.ascii[0] == '.') + { + if (ident.ascii_len >= 2 && ident.ascii[1] == '.') + { + /* ".." becomes "::" */ + PRINT ("::"); + len = 2; + } + else + { + /* "." becomes "-" */ + PRINT ("-"); + len = 1; + } + } + else + { + /* Print everything before the next escape sequence, at once. */ + for (len = 0; len < ident.ascii_len; len++) + if (ident.ascii[len] == '$' || ident.ascii[len] == '.') + break; + + print_str (rdm, ident.ascii, len); + } + + ident.ascii += len; + ident.ascii_len -= len; + } + + return; + } +} + +/* A legacy hash is the prefix "h" followed by 16 lowercase hex digits. + The hex digits must contain at least 5 distinct digits. */ +static int +is_legacy_prefixed_hash (struct rust_mangled_ident ident) +{ + uint16_t seen; + int nibble; + size_t i, count; + + if (ident.ascii_len != 17 || ident.ascii[0] != 'h') + return 0; + + seen = 0; + for (i = 0; i < 16; i++) + { + nibble = decode_lower_hex_nibble (ident.ascii[1 + i]); + if (nibble < 0) + return 0; + seen |= (uint16_t)1 << nibble; + } + + /* Count how many distinct digits were seen. */ + count = 0; + while (seen) + { + if (seen & 1) + count++; + seen >>= 1; + } + + return count >= 5; +} + +int +rust_demangle_callback (const char *mangled, int options, + demangle_callbackref callback, void *opaque) +{ + const char *p; + struct rust_demangler rdm; + struct rust_mangled_ident ident; + + rdm.sym = mangled; + rdm.sym_len = 0; + + rdm.callback_opaque = opaque; + rdm.callback = callback; + + rdm.next = 0; + rdm.errored = 0; + rdm.verbose = (options & DMGL_VERBOSE) != 0; + rdm.version = 0; + + /* Rust symbols always start with _ZN (legacy). */ + if (rdm.sym[0] == '_' && rdm.sym[1] == 'Z' && rdm.sym[2] == 'N') + { + rdm.sym += 3; + rdm.version = -1; + } + else + return 0; + + /* Legacy Rust symbols use only [_0-9a-zA-Z.:$] characters. */ + for (p = rdm.sym; *p; p++) + { + rdm.sym_len++; + + if (*p == '_' || ISALNUM (*p)) + continue; + + if (rdm.version == -1 && (*p == '$' || *p == '.' || *p == ':')) + continue; + + return 0; + } + + /* Legacy Rust symbols need to be handled separately. */ + if (rdm.version == -1) + { + /* Legacy Rust symbols always end with E. */ + if (!(rdm.sym_len > 0 && rdm.sym[rdm.sym_len - 1] == 'E')) + return 0; + rdm.sym_len--; + + /* Legacy Rust symbols also always end with a path segment + that encodes a 16 hex digit hash, i.e. '17h[a-f0-9]{16}'. + This early check, before any parse_ident calls, should + quickly filter out most C++ symbols unrelated to Rust. */ + if (!(rdm.sym_len > 19 + && !memcmp (&rdm.sym[rdm.sym_len - 19], "17h", 3))) + return 0; + + do + { + ident = parse_ident (&rdm); + if (rdm.errored || !ident.ascii) + return 0; + } + while (rdm.next < rdm.sym_len); + + /* The last path segment should be the hash. */ + if (!is_legacy_prefixed_hash (ident)) + return 0; + + /* Reset the state for a second pass, to print the symbol. */ + rdm.next = 0; + if (!rdm.verbose && rdm.sym_len > 19) + { + /* Hide the last segment, containing the hash, if not verbose. */ + rdm.sym_len -= 19; + } + + do + { + if (rdm.next > 0) + print_str (&rdm, "::", 2); + + ident = parse_ident (&rdm); + print_ident (&rdm, ident); + } + while (rdm.next < rdm.sym_len); + } + else + return 0; + + return !rdm.errored; +} + +/* Growable string buffers. */ +struct str_buf +{ + char *ptr; + size_t len; + size_t cap; + int errored; +}; + +static void +str_buf_reserve (struct str_buf *buf, size_t extra) +{ + size_t available, min_new_cap, new_cap; + char *new_ptr; + + /* Allocation failed before. */ + if (buf->errored) + return; + + available = buf->cap - buf->len; + + if (extra <= available) + return; + + min_new_cap = buf->cap + (extra - available); + + /* Check for overflows. */ + if (min_new_cap < buf->cap) + { + buf->errored = 1; + return; + } + + new_cap = buf->cap; + + if (new_cap == 0) + new_cap = 4; + + /* Double capacity until sufficiently large. */ + while (new_cap < min_new_cap) + { + new_cap *= 2; + + /* Check for overflows. */ + if (new_cap < buf->cap) + { + buf->errored = 1; + return; + } + } + + new_ptr = (char *)realloc (buf->ptr, new_cap); + if (new_ptr == NULL) + { + free (buf->ptr); + buf->ptr = NULL; + buf->len = 0; + buf->cap = 0; + buf->errored = 1; + } + else + { + buf->ptr = new_ptr; + buf->cap = new_cap; + } +} + +static void +str_buf_append (struct str_buf *buf, const char *data, size_t len) +{ + str_buf_reserve (buf, len); + if (buf->errored) + return; + + memcpy (buf->ptr + buf->len, data, len); + buf->len += len; +} + +static void +str_buf_demangle_callback (const char *data, size_t len, void *opaque) +{ + str_buf_append ((struct str_buf *)opaque, data, len); +} + +char * +rust_demangle (const char *mangled, int options) +{ + struct str_buf out; + int success; + + out.ptr = NULL; + out.len = 0; + out.cap = 0; + out.errored = 0; + + success = rust_demangle_callback (mangled, options, + str_buf_demangle_callback, &out); + + if (!success) + { + free (out.ptr); + return NULL; + } + + str_buf_append (&out, "\0", 1); + return out.ptr; +} diff --git a/libiberty/rust-demangle.h b/libiberty/rust-demangle.h deleted file mode 100644 index abf4c6cde55..00000000000 --- a/libiberty/rust-demangle.h +++ /dev/null @@ -1,45 +0,0 @@ -/* Internal demangler interface for the Rust programming language. - Copyright (C) 2016-2019 Free Software Foundation, Inc. - Written by David Tolnay (dtolnay@gmail.com). - -This file is part of the libiberty library. -Libiberty is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public -License as published by the Free Software Foundation; either -version 2 of the License, or (at your option) any later version. - -In addition to the permissions in the GNU Library General Public -License, the Free Software Foundation gives you unlimited permission -to link the compiled version of this file into combinations with other -programs, and to distribute those combinations without any restriction -coming from the use of this file. (The Library Public License -restrictions do apply in other respects; for example, they cover -modification of the file, and distribution when not linked into a -combined executable.) - -Libiberty is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with libiberty; see the file COPYING.LIB. -If not, see . */ - -/* This file provides some definitions shared by cplus-dem.c and - rust-demangle.c. It should not be included by any other files. */ - -/* Returns non-zero iff MANGLED is a rust mangled symbol. MANGLED must - already have been demangled through cplus_demangle_v3. If this function - returns non-zero then MANGLED can be demangled (in-place) using - RUST_DEMANGLE_SYM. */ -extern int -rust_is_mangled (const char *mangled); - -/* Demangles SYM (in-place) if RUST_IS_MANGLED returned non-zero for SYM. - If RUST_IS_MANGLED returned zero for SYM then RUST_DEMANGLE_SYM might - replace characters that cannot be demangled with '?' and might truncate - SYM. After calling RUST_DEMANGLE_SYM SYM might be shorter, but never - larger. */ -extern void -rust_demangle_sym (char *sym);