From bce178e3a55674f7bff68ab7325de0a09fa0ecce Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Fri, 6 Dec 2024 22:24:27 +0200 Subject: [PATCH 1/3] add demangling of V0 Rust symbols (#1070) --- src/demangle.cpp | 115 +- src/demangle.h | 7 +- src/flightRecorder.cpp | 2 +- src/frameName.cpp | 3 +- src/rustDemangle.cpp | 2039 ++++++++++++++++++++++++++++++++++ src/rustDemangle.h | 77 ++ src/vmEntry.h | 7 + test/native/demangleTest.cpp | 161 +++ 8 files changed, 2334 insertions(+), 77 deletions(-) create mode 100644 src/rustDemangle.cpp create mode 100644 src/rustDemangle.h create mode 100644 test/native/demangleTest.cpp diff --git a/src/demangle.cpp b/src/demangle.cpp index 23ac34a87..603c548bd 100644 --- a/src/demangle.cpp +++ b/src/demangle.cpp @@ -7,7 +7,7 @@ #include #include #include "demangle.h" - +#include "rustDemangle.h" char* Demangle::demangleCpp(const char* s) { int status; @@ -25,80 +25,49 @@ char* Demangle::demangleCpp(const char* s) { return result; } -char* Demangle::demangleRust(const char* s, const char* e) { - // Demangled symbol can be 1.5x longer than original, e.g. 1A1B1C -> A::B::C - char* result = (char*)malloc((e - s) * 3 / 2 + 1); - if (result == NULL) { - return NULL; +bool Demangle::isRustSymbol(const char *s) { + // "_R" symbols (Rust "mangling V0") symbols can always be easily distinguished from C++ symbols. + if (s[0] == '_' && s[1] == 'R') { + return true; } - char* r = result; - char* tmp; - - while (s < e) { - unsigned long len = strtoul(s, &tmp, 10); - const char* next = tmp + len; - if (len == 0 || next > e) { - break; + // Rust symbols with the legacy demangling (`_ZN3foo3bar17h0123456789abcdefE`) look very much like valid + // C++ demangling symbols, but we only want to use the Rust demangling for Rust symbols since + // the Rust demangling does not support C++ anonymous namespaces (e.g. `_ZN12_GLOBAL__N_113single_threadE` + // is supposed to demangle to `(anonymous namespace)::single_thread`, but Rust will demangle it to + // `_GLOBAL__N_1::single_thread`). + // + // So try to have a heuristic to avoid sending C++ symbols to Rust demangling - if a symbol's last "E" + // refers to a Rust hash, expect it to be a Rust symbol. We don't require the `E` to be at the end + // of the string since there can be `.lto.1` suffixes. + // + // FIXME: there might be a better heuristic if there are problems with this one + const char* e = strrchr(s, 'E'); + if (e != NULL && e - s > 22 && e[-19] == '1' && e[-18] == '7' && e[-17] == 'h') { + const char* h = e - 16; + while ((*h >= '0' && *h <= '9') || (*h >= 'a' && *h <= 'f')) h++; + if (h == e) { + return true; } + } - s = tmp; - if (s[0] == '_' && s[1] == '$') s++; - - if (r > result) { - *r++ = ':'; - *r++ = ':'; - } + return false; +} - while (s < next) { - if (s[0] == '$') { - if (s[1] == 'L' && s[2] == 'T' && s[3] == '$') { - *r++ = '<'; - s += 4; - } else if (s[1] == 'G' && s[2] == 'T' && s[3] == '$') { - *r++ = '>'; - s += 4; - } else if (s[1] == 'L' && s[2] == 'P' && s[3] == '$') { - *r++ = '('; - s += 4; - } else if (s[1] == 'R' && s[2] == 'P' && s[3] == '$') { - *r++ = ')'; - s += 4; - } else if (s[1] == 'S' && s[2] == 'P' && s[3] == '$') { - *r++ = '@'; - s += 4; - } else if (s[1] == 'B' && s[2] == 'P' && s[3] == '$') { - *r++ = '*'; - s += 4; - } else if (s[1] == 'R' && s[2] == 'F' && s[3] == '$') { - *r++ = '&'; - s += 4; - } else if (s[1] == 'C' && s[2] == '$') { - *r++ = ','; - s += 3; - } else if (s[1] == 'u') { - *r++ = (char)strtoul(s + 2, &tmp, 16); - s = tmp + 1; - } else { - *r++ = '$'; - s++; - } - } else if (s[0] == '.' && s[1] == '.') { - *r++ = ':'; - *r++ = ':'; - s += 2; - } else { - *r++ = *s++; - } +char* Demangle::demangleRust(struct demangle const *demangle, bool full_signature) { + char* result; + for (size_t demangled_size = 64; demangled_size < 1000000; demangled_size *= 2) { + result = (char *)malloc(demangled_size); + if (result == NULL) { + return NULL; } - - if (s > next) { - break; + if (rust_demangle_display_demangle(demangle, result, demangled_size, !full_signature /* alternate */) == OverflowOk) { + return result; } + free(result); } - - *r = 0; - return result; + // demangling Rust failed, return NULL + return NULL; } void Demangle::cutArguments(char* s) { @@ -117,13 +86,11 @@ void Demangle::cutArguments(char* s) { } char* Demangle::demangle(const char* s, bool full_signature) { - // Check if the mangled symbol ends with a Rust hash "17hE" - const char* e = strrchr(s, 'E'); - if (e != NULL && e - s > 22 && e[-19] == '1' && e[-18] == '7' && e[-17] == 'h') { - const char* h = e - 16; - while ((*h >= '0' && *h <= '9') || (*h >= 'a' && *h <= 'f')) h++; - if (h == e) { - return demangleRust(s + 3, e - 19); + if (isRustSymbol(s)) { + struct demangle demangle; + rust_demangle_demangle(s, &demangle); + if (rust_demangle_is_known(&demangle)) { + return demangleRust(&demangle, full_signature); } } diff --git a/src/demangle.h b/src/demangle.h index 509feadd8..aa7e48c82 100644 --- a/src/demangle.h +++ b/src/demangle.h @@ -6,15 +6,20 @@ #ifndef _DEMANGLE_H #define _DEMANGLE_H +struct demangle; class Demangle { private: static char* demangleCpp(const char* s); - static char* demangleRust(const char* s, const char* e); + static char* demangleRust(struct demangle const *demangle, bool full_signature); + static bool isRustSymbol(const char *s); static void cutArguments(char* s); public: static char* demangle(const char* s, bool full_signature); + static bool needsDemangling(const char *s) { + return s[0] == '_' && (s[1] == 'R' || s[1] == 'Z'); + } }; #endif // _DEMANGLE_H diff --git a/src/flightRecorder.cpp b/src/flightRecorder.cpp index c357f960c..69ed3a39b 100644 --- a/src/flightRecorder.cpp +++ b/src/flightRecorder.cpp @@ -148,7 +148,7 @@ class Lookup { mi->_line_number_table_size = 0; mi->_line_number_table = NULL; - if (name[0] == '_' && name[1] == 'Z') { + if (Demangle::needsDemangling(name)) { char* demangled = Demangle::demangle(name, false); if (demangled != NULL) { mi->_name = _symbols.lookup(demangled); diff --git a/src/frameName.cpp b/src/frameName.cpp index 63a32686a..710a92de4 100644 --- a/src/frameName.cpp +++ b/src/frameName.cpp @@ -119,7 +119,7 @@ void FrameName::buildFilter(std::vector& vector, const char* base, int const char* FrameName::decodeNativeSymbol(const char* name) { const char* lib_name = (_style & STYLE_LIB_NAMES) ? Profiler::instance()->getLibraryName(name) : NULL; - if (name[0] == '_' && name[1] == 'Z') { + if (Demangle::needsDemangling(name)) { char* demangled = Demangle::demangle(name, _style & STYLE_SIGNATURES); if (demangled != NULL) { if (lib_name != NULL) { @@ -333,6 +333,7 @@ FrameTypeId FrameName::type(ASGCT_CallFrame& frame) { case BCI_NATIVE_FRAME: { const char* name = (const char*)frame.method_id; if ((name[0] == '_' && name[1] == 'Z') || + (name[0] == '_' && name[1] == 'R') || (name[0] == '+' && name[1] == '[') || (name[0] == '-' && name[1] == '[')) { return FRAME_CPP; diff --git a/src/rustDemangle.cpp b/src/rustDemangle.cpp new file mode 100644 index 000000000..4e3571b03 --- /dev/null +++ b/src/rustDemangle.cpp @@ -0,0 +1,2039 @@ +/* + * Copyright The async-profiler authors + * SPDX-License-Identifier: Apache-2.0 + */ + +// Code for demangling Rust symbols. This code is mostly +// a line-by-line translation of the Rust code in `rustc-demangle`. + +// you can find the latest version of this code in https://github.com/rust-lang/rustc-demangle + +#include +#include +#include +#include +#include +#include + +#include "rustDemangle.h" + +#if defined(__GNUC__) || defined(__clang__) +#define NODISCARD __attribute__((warn_unused_result)) +#else +#define NODISCARD +#endif + +#define MAX_DEPTH 500 + +typedef enum { + DemangleOk, + DemangleInvalid, + DemangleRecursed, + DemangleBug, +} demangle_status; + +struct demangle_v0 { + const char *mangled; + size_t mangled_len; +}; + +struct demangle_legacy { + const char *mangled; + size_t mangled_len; + size_t elements; +}; + +// private version of memrchr to avoid _GNU_SOURCE +static void *demangle_memrchr(const void *s, int c, size_t n) { + const uint8_t *s_ = (uint8_t *)s; + for (; n != 0; n--) { + if (s_[n-1] == c) { + return (void*)&s_[n-1]; + } + } + return NULL; +} + + +static bool unicode_iscontrol(uint32_t ch) { + // this is *technically* a unicode table, but + // some unicode properties are simpler than you might think + return ch < 0x20 || (ch >= 0x7f && ch < 0xa0); +} + +// "good enough" tables, the only consequence is that when printing +// *constant strings*, some characters are printed as `\u{abcd}` rather than themselves. +// +// I'm leaving these here to allow easily replacing them with actual +// tables if desired. +static bool unicode_isprint(uint32_t ch) { + if (ch < 0x20) { + return false; + } + if (ch < 0x7f) { + return true; + } + return false; +} + +static bool unicode_isgraphemextend(uint32_t ch) { + (void)ch; + return false; +} + +static bool str_isascii(const char *s, size_t s_len) { + for (size_t i = 0; i < s_len; i++) { + if (s[i] & 0x80) { + return false; + } + } + + return true; +} + +typedef enum { + PunycodeOk, + PunycodeError +} punycode_status; + +struct parser { + // the parser assumes that `sym` has a safe "terminating byte". It might be NUL, + // but it might also be something else if a symbol is "truncated". + const char *sym; + size_t sym_len; + size_t next; + uint32_t depth; +}; + +struct printer { + demangle_status status; // if status == 0 parser is valid + struct parser parser; + char *out; // NULL for no output [in which case out_len is not decremented] + size_t out_len; + uint32_t bound_lifetime_depth; + bool alternate; +}; + +static NODISCARD overflow_status printer_print_path(struct printer *printer, bool in_value); +static NODISCARD overflow_status printer_print_type(struct printer *printer); +static NODISCARD overflow_status printer_print_const(struct printer *printer, bool in_value); + +static NODISCARD demangle_status try_parse_path(struct parser *parser) { + struct printer printer = { + DemangleOk, + *parser, + NULL, + SIZE_MAX, + 0, + false + }; + overflow_status ignore = printer_print_path(&printer, false); // can't fail since no output + (void)ignore; + *parser = printer.parser; + return printer.status; +} + +NODISCARD static demangle_status rust_demangle_v0_demangle(const char *s, size_t s_len, struct demangle_v0 *res, const char **rest) { + if (s_len > strlen(s)) { + // s_len only exists to shorten the string, this is not a buffer API + return DemangleInvalid; + } + + const char *inner; + size_t inner_len; + if (s_len >= 2 && !strncmp(s, "_R", strlen("_R"))) { + inner = s+2; + inner_len = s_len - 2; + } else if (s_len >= 1 && !strncmp(s, "R", strlen("R"))) { + // On Windows, dbghelp strips leading underscores, so we accept "R..." + // form too. + inner = s+1; + inner_len = s_len - 1; + } else if (s_len >= 3 && !strncmp(s, "__R", strlen("__R"))) { + // On OSX, symbols are prefixed with an extra _ + inner = s+3; + inner_len = s_len - 3; + } else { + return DemangleInvalid; + } + + // Paths always start with uppercase characters. + if (*inner < 'A' || *inner > 'Z') { + return DemangleInvalid; + } + + if (!str_isascii(inner, inner_len)) { + return DemangleInvalid; + } + + struct parser parser = { inner, inner_len, 0, 0 }; + + demangle_status status = try_parse_path(&parser); + if (status != DemangleOk) return status; + char next = parser.sym[parser.next]; + + // Instantiating crate (paths always start with uppercase characters). + if (parser.next < parser.sym_len && next >= 'A' && next <= 'Z') { + status = try_parse_path(&parser); + if (status != DemangleOk) return status; + } + + res->mangled = inner; + res->mangled_len = inner_len; + if (rest) { + *rest = parser.sym + parser.next; + } + + return DemangleOk; +} + +// This might require `len` to be up to 3 characters bigger than the real output len in case of utf-8 +NODISCARD static overflow_status rust_demangle_v0_display_demangle(struct demangle_v0 res, char *out, size_t len, bool alternate) { + struct printer printer = { + DemangleOk, + { + res.mangled, + res.mangled_len, + 0, + 0 + }, + out, + len, + 0, + alternate + }; + if (printer_print_path(&printer, true) == OverflowOverflow) { + return OverflowOverflow; + } + if (printer.out_len < OVERFLOW_MARGIN) { + return OverflowOverflow; + } + *printer.out = '\0'; + return OverflowOk; +} + +static size_t code_to_utf8(unsigned char *buffer, uint32_t code) +{ + if (code <= 0x7F) { + buffer[0] = code; + return 1; + } + if (code <= 0x7FF) { + buffer[0] = 0xC0 | (code >> 6); /* 110xxxxx */ + buffer[1] = 0x80 | (code & 0x3F); /* 10xxxxxx */ + return 2; + } + if (code <= 0xFFFF) { + buffer[0] = 0xE0 | (code >> 12); /* 1110xxxx */ + buffer[1] = 0x80 | ((code >> 6) & 0x3F); /* 10xxxxxx */ + buffer[2] = 0x80 | (code & 0x3F); /* 10xxxxxx */ + return 3; + } + if (code <= 0x10FFFF) { + buffer[0] = 0xF0 | (code >> 18); /* 11110xxx */ + buffer[1] = 0x80 | ((code >> 12) & 0x3F); /* 10xxxxxx */ + buffer[2] = 0x80 | ((code >> 6) & 0x3F); /* 10xxxxxx */ + buffer[3] = 0x80 | (code & 0x3F); /* 10xxxxxx */ + return 4; + } + return 0; +} + + +// return length of char at byte, or SIZE_MAX if invalid. buf should have 4 valid characters +static NODISCARD size_t utf8_next_char(uint8_t *s, uint32_t *ch) { + uint8_t byte = *s; + // UTF8-1 = %x00-7F + // UTF8-2 = %xC2-DF UTF8-tail + // UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) / + // %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail ) + // UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) / + // %xF4 %x80-8F 2( UTF8-tail ) + if (byte < 0x80) { + *ch = byte; + return 1; + } else if (byte < 0xc2) { + return SIZE_MAX; + } else if (byte < 0xe0) { + if (s[1] >= 0x80 && s[1] < 0xc0) { + *ch = ((byte&0x1f)<<6) + (s[1] & 0x3f); + return 2; + } + return SIZE_MAX; + } if (byte < 0xf0) { + if (!(s[1] >= 0x80 && s[1] < 0xc0) || !(s[2] >= 0x80 && s[2] < 0xc0)) { + return SIZE_MAX; // basic validation + } + if (byte == 0xe0 && s[1] < 0xa0) { + return SIZE_MAX; // overshort + } + if (byte == 0xed && s[1] >= 0xa0) { + return SIZE_MAX; // surrogate + } + *ch = ((byte&0x0f)<<12) + ((s[1] & 0x3f)<<6) + (s[2] & 0x3f); + return 3; + } else if (byte < 0xf5) { + if (!(s[1] >= 0x80 && s[1] < 0xc0) || !(s[2] >= 0x80 && s[2] < 0xc0) || !(s[3] >= 0x80 && s[3] < 0xc0)) { + return SIZE_MAX; // basic validation + } + if (byte == 0xf0 && s[1] < 0x90) { + return SIZE_MAX; // overshort + } + if (byte == 0xf4 && s[1] >= 0x90) { + return SIZE_MAX; // over max + } + *ch = ((byte&0x07)<<18) + ((s[1] & 0x3f)<<12) + ((s[2] & 0x3f)<<6) + (s[3]&0x3f); + return 4; + } else { + return SIZE_MAX; + } +} + +static NODISCARD bool validate_char(uint32_t n) { + return ((n ^ 0xd800) - 0x800) < 0x110000 - 0x800; +} + +#define SMALL_PUNYCODE_LEN 128 + +static NODISCARD punycode_status punycode_decode(const char *start, size_t ascii_len, const char *punycode_start, size_t punycode_len, uint32_t (*out_)[SMALL_PUNYCODE_LEN], size_t *out_len) { + uint32_t *out = *out_; + + if (punycode_len == 0) { + return PunycodeError; + } + + if (ascii_len > SMALL_PUNYCODE_LEN) { + return PunycodeError; + } + for (size_t i = 0; i < ascii_len; i++) { + out[i] = start[i]; + } + size_t len = ascii_len; + + size_t base = 36, t_min = 1, t_max = 26, skew = 38, damp = 700, bias = 72, i = 0, n = 0x80; + for (;;) { + size_t delta = 0, w = 1, k = 0; + for (;;) { + k += base; + size_t biased = k < bias ? 0 : k - bias; + size_t t = MIN(MAX(biased, t_min), t_max); + size_t d; + if (punycode_len == 0) { + return PunycodeError; + } + char nx = *punycode_start++; + punycode_len--; + if ('a' <= nx && nx <= 'z') { + d = nx - 'a'; + } else if ('0' <= nx && nx <= '9') { + d = 26 + (nx - '0'); + } else { + return PunycodeError; + } + if (w == 0 || d > SIZE_MAX / w || d*w > SIZE_MAX - delta) { + return PunycodeError; + } + delta += d * w; + if (d < t) { + break; + } + if (base < t || w == 0 || (base - t) > SIZE_MAX / w) { + return PunycodeError; + } + w *= (base - t); + } + + len += 1; + if (i > SIZE_MAX - delta) { + return PunycodeError; + } + i += delta; + if (n > SIZE_MAX - i / len) { + return PunycodeError; + } + n += i / len; + i %= len; + + // char validation + if (n > UINT32_MAX || !validate_char((uint32_t)n)) { + return PunycodeError; + } + + // insert new character + if (len > SMALL_PUNYCODE_LEN) { + return PunycodeError; + } + memmove(out + i + 1, out + i, (len - i - 1) * sizeof(uint32_t)); + out[i] = (uint32_t)n; + + // start i index at incremented position + i++; + + // If there are no more deltas, decoding is complete. + if (punycode_len == 0) { + *out_len = len; + return PunycodeOk; + } + + // Perform bias adaptation. + delta /= damp; + damp = 2; + + delta += delta / len; + k = 0; + while (delta > ((base - t_min) * t_max) / 2) { + delta /= base - t_min; + k += base; + } + bias = k + ((base - t_min + 1) * delta) / (delta + skew); + } +} + +struct ident { + const char *ascii_start; + size_t ascii_len; + const char *punycode_start; + size_t punycode_len; +}; + +static NODISCARD overflow_status display_ident(const char *ascii_start, size_t ascii_len, const char *punycode_start, size_t punycode_len, uint8_t *out, size_t *out_len) { + uint32_t outbuf[SMALL_PUNYCODE_LEN]; + + size_t wide_len; + size_t out_buflen = *out_len; + + if (punycode_len == 0) { + if (ascii_len > out_buflen) { + return OverflowOverflow; + } + memcpy(out, ascii_start, ascii_len); + *out_len = ascii_len; + } else if (punycode_decode(ascii_start, ascii_len, punycode_start, punycode_len, &outbuf, &wide_len) == PunycodeOk) { + size_t narrow_len = 0; + for (size_t i = 0; i < wide_len; i++) { + if (out_buflen - narrow_len < 4) { + return OverflowOverflow; + } + unsigned char *pos = &out[narrow_len]; + narrow_len += code_to_utf8(pos, outbuf[i]); + } + *out_len = narrow_len; + } else { + size_t narrow_len = 0; + if (out_buflen < strlen("punycode{")) { + return OverflowOverflow; + } + memcpy(out, "punycode{", strlen("punycode{")); + narrow_len = strlen("punycode{"); + if (ascii_len > 0) { + if (out_buflen - narrow_len < ascii_len || out_buflen - narrow_len - ascii_len < 1) { + return OverflowOverflow; + } + memcpy(out + narrow_len, ascii_start, ascii_len); + narrow_len += ascii_len; + out[narrow_len] = '-'; + narrow_len++; + } + if (out_buflen - narrow_len < punycode_len || out_buflen - narrow_len - punycode_len < 1) { + return OverflowOverflow; + } + memcpy(out + narrow_len, punycode_start, punycode_len); + narrow_len += punycode_len; + out[narrow_len] = '}'; + narrow_len++; + *out_len = narrow_len; + } + + return OverflowOk; +} + +static NODISCARD bool try_parse_uint(const char *buf, size_t len, uint64_t *result) { + size_t cur = 0; + for(;cur < len && buf[cur] == '0';cur++); + uint64_t result_val = 0; + if (len - cur > 16) return false; + for(;cur < len;cur++) { + char c = buf[cur]; + result_val <<= 4; + if ('0' <= c && c <= '9') { + result_val += c - '0'; + } else if ('a' <= c && c <= 'f') { + result_val += 10 + (c - 'a'); + } else { + return false; + } + } + *result = result_val; + return true; +} + +static NODISCARD bool dinibble2int(const char *buf, uint8_t *result) { + uint8_t result_val = 0; + for (int i = 0; i < 2; i++) { + char c = buf[i]; + result_val <<= 4; + if ('0' <= c && c <= '9') { + result_val += c - '0'; + } else if ('a' <= c && c <= 'f') { + result_val += 10 + (c - 'a'); + } else { + return false; + } + } + *result = result_val; + return true; +} + + +typedef enum { + NtsOk = 0, + NtsOverflow = 1, + NtsInvalid = 2 +} nibbles_to_string_status; + +// '\u{10ffff}', +margin +#define ESCAPED_SIZE 12 + +static NODISCARD size_t char_to_string(uint32_t ch, uint8_t quote, bool first, char (*buf)[ESCAPED_SIZE]) { + // encode the character + char *escaped_buf = *buf; + escaped_buf[0] = '\\'; + size_t escaped_len = 2; + switch (ch) { + case '\0': + escaped_buf[1] = '0'; + break; + case '\t': + escaped_buf[1] = 't'; + break; + case '\r': + escaped_buf[1] = 'r'; + break; + case '\n': + escaped_buf[1] = 'n'; + break; + case '\\': + escaped_buf[1] = '\\'; + break; + default: + if (ch == quote) { + escaped_buf[1] = ch; + } else if (!unicode_isprint(ch) || (first && unicode_isgraphemextend(ch))) { + int hexlen = snprintf(escaped_buf, ESCAPED_SIZE, "\\u{%x}", (unsigned int)ch); + if (hexlen < 0) { + return 0; // (snprintf shouldn't fail!) + } + escaped_len = hexlen; + } else { + // printable character + escaped_buf[0] = ch; + escaped_len = 1; + } + break; + } + + return escaped_len; +} + +// convert nibbles to a single/double-quoted string +static NODISCARD nibbles_to_string_status nibbles_to_string(const char *buf, size_t len, uint8_t *out, size_t *out_len) { + uint8_t quote = '"'; + bool first = true; + + if ((len % 2) != 0) { + return NtsInvalid; // odd number of nibbles + } + + size_t cur_out_len = 0; + + // write starting quote + if (out != NULL) { + cur_out_len = *out_len; + if (cur_out_len == 0) { + return NtsOverflow; + } + *out++ = quote; + cur_out_len--; + } + + uint8_t conv_buf[4] = {0}; + size_t conv_buf_len = 0; + while (len > 1 || conv_buf_len > 0) { + while (len > 1 && conv_buf_len < sizeof(conv_buf)) { + if (!dinibble2int(buf, &conv_buf[conv_buf_len])) { + return NtsInvalid; + } + conv_buf_len++; + buf += 2; + len -= 2; + } + + // conv_buf is full here if possible, process 1 UTF-8 character + uint32_t ch = 0; + size_t consumed = utf8_next_char(conv_buf, &ch); + if (consumed > conv_buf_len) { + // either SIZE_MAX (invalid UTF-8) or finished input buffer and + // there are still bytes remaining, in both cases invalid + return NtsInvalid; + } + + // "consume" the character + memmove(conv_buf, conv_buf+consumed, conv_buf_len-consumed); + conv_buf_len -= consumed; + + char escaped_buf[ESCAPED_SIZE]; + size_t escaped_len = char_to_string(ch, '"', first, &escaped_buf); + if (out != NULL) { + if (cur_out_len < escaped_len) { + return NtsOverflow; + } + memcpy(out, escaped_buf, escaped_len); + out += escaped_len; + cur_out_len -= escaped_len; + } + first = false; + } + + // write ending quote + if (out != NULL) { + if (cur_out_len == 0) { + return NtsOverflow; + } + *out++ = quote; + cur_out_len--; + *out_len -= cur_out_len; // subtract remaining space to get used space + } + + return NtsOk; +} + +static const char* basic_type(uint8_t tag) { + switch(tag) { + case 'b': + return "bool"; + case 'c': + return "char"; + case 'e': + return "str"; + case 'u': + return "()"; + case 'a': + return "i8"; + case 's': + return "i16"; + case 'l': + return "i32"; + case 'x': + return "i64"; + case 'n': + return "i128"; + case 'i': + return "isize"; + case 'h': + return "u8"; + case 't': + return "u16"; + case 'm': + return "u32"; + case 'y': + return "u64"; + case 'o': + return "u128"; + case 'j': + return "usize"; + case 'f': + return "f32"; + case 'd': + return "f64"; + case 'z': + return "!"; + case 'p': + return "_"; + case 'v': + return "..."; + default: + return NULL; + } +} + +static NODISCARD demangle_status parser_push_depth(struct parser *parser) { + parser->depth++; + if (parser->depth > MAX_DEPTH) { + return DemangleRecursed; + } else { + return DemangleOk; + } +} + +static demangle_status parser_pop_depth(struct parser *parser) { + parser->depth--; + return DemangleOk; +} + +static uint8_t parser_peek(struct parser const *parser) { + if (parser->next == parser->sym_len) { + return 0; // add a "pseudo nul terminator" to avoid peeking past the end of a symbol + } else { + return parser->sym[parser->next]; + } +} + +static bool parser_eat(struct parser *parser, uint8_t ch) { + if (parser_peek(parser) == ch) { + if (ch != 0) { // safety: make sure we don't skip past the NUL terminator + parser->next++; + } + return true; + } else { + return false; + } +} + +static uint8_t parser_next(struct parser *parser) { + // don't advance after end of input, and return an imaginary NUL terminator + if (parser->next == parser->sym_len) { + return 0; + } else { + return parser->sym[parser->next++]; + } +} + +static NODISCARD demangle_status parser_ch(struct parser *parser, uint8_t *next) { + // don't advance after end of input + if (parser->next == parser->sym_len) { + return DemangleInvalid; + } else { + *next = parser->sym[parser->next++]; + return DemangleOk; + } +} + +struct buf { + const char *start; + size_t len; +}; + +static NODISCARD demangle_status parser_hex_nibbles(struct parser *parser, struct buf *buf) { + size_t start = parser->next; + for (;;) { + uint8_t ch = parser_next(parser); + if (ch == '_') { + break; + } + if (!(('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'f'))) { + return DemangleInvalid; + } + } + buf->start = parser->sym + start; + buf->len = parser->next - start - 1; // skip final _ + return DemangleOk; +} + +static NODISCARD demangle_status parser_digit_10(struct parser *parser, uint8_t *out) { + uint8_t ch = parser_peek(parser); + if ('0' <= ch && ch <= '9') { + *out = ch - '0'; + parser->next++; + return DemangleOk; + } else { + return DemangleInvalid; + } +} + +static NODISCARD demangle_status parser_digit_62(struct parser *parser, uint64_t *out) { + uint8_t ch = parser_peek(parser); + if ('0' <= ch && ch <= '9') { + *out = ch - '0'; + parser->next++; + return DemangleOk; + } else if ('a' <= ch && ch <= 'z') { + *out = 10 + (ch - 'a'); + parser->next++; + return DemangleOk; + } else if ('A' <= ch && ch <= 'Z') { + *out = 10 + 26 + (ch - 'A'); + parser->next++; + return DemangleOk; + } else { + return DemangleInvalid; + } +} + +static NODISCARD demangle_status parser_integer_62(struct parser *parser, uint64_t *out) { + if (parser_eat(parser, '_')) { + *out = 0; + return DemangleOk; + } + + uint64_t x = 0; + demangle_status status; + while (!parser_eat(parser, '_')) { + uint64_t d; + if ((status = parser_digit_62(parser, &d)) != DemangleOk) { + return status; + } + if (x > UINT64_MAX / 62) { + return DemangleInvalid; + } + x *= 62; + if (x > UINT64_MAX - d) { + return DemangleInvalid; + } + x += d; + } + if (x == UINT64_MAX) { + return DemangleInvalid; + } + *out = x + 1; + return DemangleOk; +} + +static NODISCARD demangle_status parser_opt_integer_62(struct parser *parser, uint8_t tag, uint64_t *out) { + if (!parser_eat(parser, tag)) { + *out = 0; + return DemangleOk; + } + + demangle_status status; + if ((status = parser_integer_62(parser, out)) != DemangleOk) { + return status; + } + if (*out == UINT64_MAX) { + return DemangleInvalid; + } + *out = *out + 1; + return DemangleOk; +} + +static NODISCARD demangle_status parser_disambiguator(struct parser *parser, uint64_t *out) { + return parser_opt_integer_62(parser, 's', out); +} + +typedef uint8_t parser_namespace_type; + +static NODISCARD demangle_status parser_namespace(struct parser *parser, parser_namespace_type *out) { + uint8_t next = parser_next(parser); + if ('A' <= next && next <= 'Z') { + *out = next; + return DemangleOk; + } else if ('a' <= next && next <= 'z') { + *out = 0; + return DemangleOk; + } else { + return DemangleInvalid; + } +} + +static NODISCARD demangle_status parser_backref(struct parser *parser, struct parser *out) { + size_t start = parser->next; + if (start == 0) { + return DemangleBug; + } + size_t s_start = start - 1; + uint64_t i; + demangle_status status = parser_integer_62(parser, &i); + if (status != DemangleOk) { + return status; + } + if (i >= s_start) { + return DemangleInvalid; + } + struct parser res = { + .sym = parser->sym, + .sym_len = parser->sym_len, + .next = (size_t)i, + .depth = parser->depth + }; + status = parser_push_depth(&res); + if (status != DemangleOk) { + return status; + } + *out = res; + return DemangleOk; +} + +static NODISCARD demangle_status parser_ident(struct parser *parser, struct ident *out) { + bool is_punycode = parser_eat(parser, 'u'); + size_t len; + uint8_t d; + demangle_status status = parser_digit_10(parser, &d); + len = d; + if (status != DemangleOk) { + return status; + } + if (len) { + for (;;) { + status = parser_digit_10(parser, &d); + if (status != DemangleOk) { + break; + } + if (len > SIZE_MAX / 10) { + return DemangleInvalid; + } + len *= 10; + if (len > SIZE_MAX - d) { + return DemangleInvalid; + } + len += d; + } + } + + // Skip past the optional `_` separator. + parser_eat(parser, '_'); + + size_t start = parser->next; + if (parser->sym_len - parser->next < len) { + return DemangleInvalid; + } + parser->next += len; + + const char *ident = &parser->sym[start]; + + if (is_punycode) { + const char *underscore = (const char *)demangle_memrchr(ident, '_', (size_t)len); + if (underscore == NULL) { + *out = (struct ident){ + .ascii_start="", + .ascii_len=0, + .punycode_start=ident, + .punycode_len=len + }; + } else { + size_t ascii_len = underscore - ident; + // ascii_len <= len - 1 since `_` is in the first len bytes + size_t punycode_len = len - 1 - ascii_len; + *out = (struct ident){ + .ascii_start=ident, + .ascii_len=ascii_len, + .punycode_start=underscore + 1, + .punycode_len=punycode_len + }; + } + if (out->punycode_len == 0) { + return DemangleInvalid; + } + return DemangleOk; + } else { + *out = (struct ident) { + .ascii_start=ident, + .ascii_len=(size_t)len, + .punycode_start="", + .punycode_len=0, + }; + return DemangleOk; + } +} + +#define INVALID_SYNTAX "{invalid syntax}" + +static const char *demangle_error_message(demangle_status status) { + switch (status) { + case DemangleInvalid: + return INVALID_SYNTAX; + case DemangleBug: + return "{bug}"; + case DemangleRecursed: + return "{recursion limit reached}"; + default: + return "{unknown error}"; + } +} + +#define PRINT(print_fn) \ + do { \ + if ((print_fn) == OverflowOverflow) { \ + return OverflowOverflow; \ + } \ + } while(0) + +#define PRINT_CH(printer, s) PRINT(printer_print_ch((printer), (s))) +#define PRINT_STR(printer, s) PRINT(printer_print_str((printer), (s))) +#define PRINT_U64(printer, s) PRINT(printer_print_u64((printer), (s))) +#define PRINT_IDENT(printer, s) PRINT(printer_print_ident((printer), (s))) + +#define INVALID(printer) \ + do { \ + PRINT_STR((printer), INVALID_SYNTAX); \ + (printer)->status = DemangleInvalid; \ + return OverflowOk; \ + } while(0) + +#define PARSE(printer, method, ...) \ + do { \ + if ((printer)->status != DemangleOk) { \ + PRINT_STR((printer), "?"); \ + return OverflowOk; \ + } else { \ + demangle_status _parse_status = method(&(printer)->parser, ## __VA_ARGS__); \ + if (_parse_status != DemangleOk) { \ + PRINT_STR((printer), demangle_error_message(_parse_status)); \ + (printer)->status = _parse_status; \ + return OverflowOk; \ + } \ + } \ + } while(0) + +#define PRINT_SEP_LIST(printer, body, sep) \ + do { \ + size_t _sep_list_i; \ + PRINT_SEP_LIST_COUNT(printer, _sep_list_i, body, sep); \ + } while(0) + +#define PRINT_SEP_LIST_COUNT(printer, count, body, sep) \ + do { \ + count = 0; \ + while ((printer)->status == DemangleOk && !printer_eat((printer), 'E')) { \ + if (count > 0) { PRINT_STR(printer, sep); } \ + body; \ + count++; \ + } \ + } while(0) + +static bool printer_eat(struct printer *printer, uint8_t b) { + if (printer->status != DemangleOk) { + return false; + } + + return parser_eat(&printer->parser, b); +} + +static void printer_pop_depth(struct printer *printer) { + if (printer->status == DemangleOk) { + parser_pop_depth(&printer->parser); + } +} + +static NODISCARD overflow_status printer_print_buf(struct printer *printer, const char *start, size_t len) { + if (printer->out == NULL) { + return OverflowOk; + } + if (printer->out_len < len) { + return OverflowOverflow; + } + + memcpy(printer->out, start, len); + printer->out += len; + printer->out_len -= len; + return OverflowOk; +} + +static NODISCARD overflow_status printer_print_str(struct printer *printer, const char *buf) { + return printer_print_buf(printer, buf, strlen(buf)); +} + +static NODISCARD overflow_status printer_print_ch(struct printer *printer, char ch) { + return printer_print_buf(printer, &ch, 1); +} + +static NODISCARD overflow_status printer_print_u64(struct printer *printer, uint64_t n) { + char buf[32] = {0}; + sprintf(buf, "%llu", (unsigned long long)n); // printing uint64 uses 21 < 32 chars + return printer_print_str(printer, buf); +} + +static NODISCARD overflow_status printer_print_ident(struct printer *printer, struct ident *ident) { + if (printer->out == NULL) { + return OverflowOk; + } + + size_t out_len = printer->out_len; + overflow_status status; + if ((status = display_ident(ident->ascii_start, ident->ascii_len, ident->punycode_start, ident->punycode_len, (uint8_t*)printer->out, &out_len)) != OverflowOk) { + return status; + } + printer->out += out_len; + printer->out_len -= out_len; + return OverflowOk; +} + +typedef overflow_status (*printer_fn)(struct printer *printer); +typedef overflow_status (*backref_fn)(struct printer *printer, bool *arg); + +static NODISCARD overflow_status printer_print_backref(struct printer *printer, backref_fn func, bool *arg) { + struct parser backref; + PARSE(printer, parser_backref, &backref); + + if (printer->out == NULL) { + return OverflowOk; + } + + struct parser orig_parser = printer->parser; + demangle_status orig_status = printer->status; // fixme not sure this is needed match for Ok on the Rust side + printer->parser = backref; + printer->status = DemangleOk; + overflow_status status = func(printer, arg); + printer->parser = orig_parser; + printer->status = orig_status; + + return status; +} + +static NODISCARD overflow_status printer_print_lifetime_from_index(struct printer *printer, uint64_t lt) { + // Bound lifetimes aren't tracked when skipping printing. + if (printer->out == NULL) { + return OverflowOk; + } + + PRINT_STR(printer, "'"); + if (lt == 0) { + PRINT_STR(printer, "_"); + return OverflowOk; + } + + if (printer->bound_lifetime_depth < lt) { + INVALID(printer); + } else { + uint64_t depth = printer->bound_lifetime_depth - lt; + if (depth < 26) { + PRINT_CH(printer, 'a' + depth); + } else { + PRINT_STR(printer, "_"); + PRINT_U64(printer, depth); + } + + return OverflowOk; + } +} + +static NODISCARD overflow_status printer_in_binder(struct printer *printer, printer_fn func) { + uint64_t bound_lifetimes; + PARSE(printer, parser_opt_integer_62, 'G', &bound_lifetimes); + + // Don't track bound lifetimes when skipping printing. + if (printer->out == NULL) { + return func(printer); + } + + if (bound_lifetimes > 0) { + PRINT_STR(printer, "for<"); + for (uint64_t i = 0; i < bound_lifetimes; i++) { + if (i > 0) { + PRINT_STR(printer, ", "); + } + printer->bound_lifetime_depth++; + PRINT(printer_print_lifetime_from_index(printer, 1)); + } + PRINT_STR(printer, "> "); + } + + overflow_status r = func(printer); + printer->bound_lifetime_depth -= bound_lifetimes; + + return r; +} + +static NODISCARD overflow_status printer_print_generic_arg(struct printer *printer) { + if (printer_eat(printer, 'L')) { + uint64_t lt; + PARSE(printer, parser_integer_62, <); + return printer_print_lifetime_from_index(printer, lt); + } else if (printer_eat(printer, 'K')) { + return printer_print_const(printer, false); + } else { + return printer_print_type(printer); + } +} + +static NODISCARD overflow_status printer_print_generic_args(struct printer *printer) { + PRINT_STR(printer, "<"); + PRINT_SEP_LIST(printer, PRINT(printer_print_generic_arg(printer)), ", "); + PRINT_STR(printer, ">"); + return OverflowOk; +} + +static NODISCARD overflow_status printer_print_path_out_of_value(struct printer *printer, bool *_arg) { + (void)_arg; + return printer_print_path(printer, false); +} + +static NODISCARD overflow_status printer_print_path_in_value(struct printer *printer, bool *_arg) { + (void)_arg; + return printer_print_path(printer, true); +} + +static NODISCARD overflow_status printer_print_path(struct printer *printer, bool in_value) { + PARSE(printer, parser_push_depth); + uint8_t tag; + PARSE(printer, parser_ch, &tag); + + overflow_status st; + uint64_t dis; + struct ident name; + parser_namespace_type ns; + char *orig_out; + + switch(tag) { + case 'C': + PARSE(printer, parser_disambiguator, &dis); + PARSE(printer, parser_ident, &name); + + PRINT_IDENT(printer, &name); + + if (printer->out != NULL && !printer->alternate && dis != 0) { + PRINT_STR(printer, "["); + char buf[24] = {0}; + sprintf(buf, "%llx", (unsigned long long)dis); + PRINT_STR(printer, buf); + PRINT_STR(printer, "]"); + } + break; + case 'N': + PARSE(printer, parser_namespace, &ns); + if ((st = printer_print_path(printer, in_value)) != OverflowOk) { + return st; + } + + // HACK(eddyb) if the parser is already marked as having errored, + // `parse!` below will print a `?` without its preceding `::` + // (because printing the `::` is skipped in certain conditions, + // i.e. a lowercase namespace with an empty identifier), + // so in order to get `::?`, the `::` has to be printed here. + if (printer->status != DemangleOk) { + PRINT_STR(printer, "::"); + } + + PARSE(printer, parser_disambiguator, &dis); + PARSE(printer, parser_ident, &name); + // Special namespace, like closures and shims + if (ns) { + PRINT_STR(printer, "::{"); + if (ns == 'C') { + PRINT_STR(printer, "closure"); + } else if (ns == 'S') { + PRINT_STR(printer, "shim"); + } else { + PRINT_CH(printer, ns); + } + if (name.ascii_len != 0 || name.punycode_len != 0) { + PRINT_STR(printer, ":"); + PRINT_IDENT(printer, &name); + } + PRINT_STR(printer, "#"); + PRINT_U64(printer, dis); + PRINT_STR(printer, "}"); + } else { + // Implementation-specific/unspecified namespaces + if (name.ascii_len != 0 || name.punycode_len != 0) { + PRINT_STR(printer, "::"); + PRINT_IDENT(printer, &name); + } + } + break; + case 'M': + case 'X': + // for impls, ignore the impls own path + PARSE(printer, parser_disambiguator, &dis); + orig_out = printer->out; + printer->out = NULL; + PRINT(printer_print_path(printer, false)); + printer->out = orig_out; + + // fallthru + case 'Y': + PRINT_STR(printer, "<"); + PRINT(printer_print_type(printer)); + if (tag != 'M') { + PRINT_STR(printer, " as "); + PRINT(printer_print_path(printer, false)); + } + PRINT_STR(printer, ">"); + break; + case 'I': + PRINT(printer_print_path(printer, in_value)); + if (in_value) { + PRINT_STR(printer, "::"); + } + PRINT(printer_print_generic_args(printer)); + break; + case 'B': + PRINT(printer_print_backref(printer, in_value ? printer_print_path_in_value : printer_print_path_out_of_value, NULL)); + break; + default: + INVALID(printer); + break; + } + + printer_pop_depth(printer); + return OverflowOk; +} + +static NODISCARD overflow_status printer_print_const_uint(struct printer *printer, uint8_t tag) { + struct buf hex; + PARSE(printer, parser_hex_nibbles, &hex); + + uint64_t val; + if (try_parse_uint(hex.start, hex.len, &val)) { + PRINT_U64(printer, val); + } else { + PRINT_STR(printer, "0x"); + PRINT(printer_print_buf(printer, hex.start, hex.len)); + } + + if (printer->out != NULL && !printer->alternate) { + const char *ty = basic_type(tag); + if (/* safety */ ty != NULL) { + PRINT_STR(printer, ty); + } + } + + return OverflowOk; +} + +static NODISCARD overflow_status printer_print_const_str_literal(struct printer *printer) { + struct buf hex; + PARSE(printer, parser_hex_nibbles, &hex); + + size_t out_len = SIZE_MAX; + nibbles_to_string_status nts_status = nibbles_to_string(hex.start, hex.len, NULL, &out_len); + switch (nts_status) { + case NtsOk: + if (printer->out != NULL) { + out_len = printer->out_len; + nts_status = nibbles_to_string(hex.start, hex.len, (uint8_t*)printer->out, &out_len); + if (nts_status != NtsOk) { + return OverflowOverflow; + } + printer->out += out_len; + printer->out_len -= out_len; + } + return OverflowOk; + case NtsOverflow: + // technically if there is a string of size `SIZE_MAX/6` whose escaped version overflows + // SIZE_MAX but has an invalid char, this will be a "fake" overflow. In practice, + // that is not going to happen and a fuzzer will not generate strings of this length. + return OverflowOverflow; + case NtsInvalid: + default: + INVALID(printer); + } +} + +static NODISCARD overflow_status printer_print_const_struct(struct printer *printer) { + uint64_t dis; + struct ident name; + PARSE(printer, parser_disambiguator, &dis); + PARSE(printer, parser_ident, &name); + PRINT_IDENT(printer, &name); + PRINT_STR(printer, ": "); + return printer_print_const(printer, true); +} + +static NODISCARD overflow_status printer_print_const_out_of_value(struct printer *printer, bool *_arg) { + (void)_arg; + return printer_print_const(printer, false); +} + +static NODISCARD overflow_status printer_print_const_in_value(struct printer *printer, bool *_arg) { + (void)_arg; + return printer_print_const(printer, true); +} + +static NODISCARD overflow_status printer_print_const(struct printer *printer, bool in_value) { + uint8_t tag; + + PARSE(printer, parser_ch, &tag); + PARSE(printer, parser_push_depth); + + struct buf hex; + uint64_t val; + size_t count; + + bool opened_brace = false; +#define OPEN_BRACE_IF_OUTSIDE_EXPR \ + do { if (!in_value) { \ + opened_brace = true; \ + PRINT_STR(printer, "{"); \ + } } while(0) + + switch(tag) { + case 'p': + PRINT_STR(printer, "_"); + break; + // Primitive leaves with hex-encoded values (see `basic_type`). + case 'a': + case 's': + case 'l': + case 'x': + case 'n': + case 'i': + if (printer_eat(printer, 'n')) { + PRINT_STR(printer, "-"); + } + /* fallthrough */ + case 'h': + case 't': + case 'm': + case 'y': + case 'o': + case 'j': + PRINT(printer_print_const_uint(printer, tag)); + break; + case 'b': + PARSE(printer, parser_hex_nibbles, &hex); + if (try_parse_uint(hex.start, hex.len, &val)) { + if (val == 0) { + PRINT_STR(printer, "false"); + } else if (val == 1) { + PRINT_STR(printer, "true"); + } else { + INVALID(printer); + } + } else { + INVALID(printer); + } + break; + case 'c': + PARSE(printer, parser_hex_nibbles, &hex); + if (try_parse_uint(hex.start, hex.len, &val) + && val < UINT32_MAX + && validate_char((uint32_t)val)) + { + char escaped_buf[ESCAPED_SIZE]; + size_t escaped_size = char_to_string((uint32_t)val, '\'', true, &escaped_buf); + + PRINT_STR(printer, "'"); + PRINT(printer_print_buf(printer, escaped_buf, escaped_size)); + PRINT_STR(printer, "'"); + } else { + INVALID(printer); + } + break; + case 'e': + OPEN_BRACE_IF_OUTSIDE_EXPR; + PRINT_STR(printer, "*"); + PRINT(printer_print_const_str_literal(printer)); + break; + case 'R': + case 'Q': + if (tag == 'R' && printer_eat(printer, 'e')) { + PRINT(printer_print_const_str_literal(printer)); + } else { + OPEN_BRACE_IF_OUTSIDE_EXPR; + PRINT_STR(printer, "&"); + if (tag != 'R') { + PRINT_STR(printer, "mut "); + } + PRINT(printer_print_const(printer, true)); + } + break; + case 'A': + OPEN_BRACE_IF_OUTSIDE_EXPR; + PRINT_STR(printer, "["); + PRINT_SEP_LIST(printer, PRINT(printer_print_const(printer, true)), ", "); + PRINT_STR(printer, "]"); + break; + case 'T': + OPEN_BRACE_IF_OUTSIDE_EXPR; + PRINT_STR(printer, "("); + PRINT_SEP_LIST_COUNT(printer, count, PRINT(printer_print_const(printer, true)), ", "); + if (count == 1) { + PRINT_STR(printer, ","); + } + PRINT_STR(printer, ")"); + break; + case 'V': + OPEN_BRACE_IF_OUTSIDE_EXPR; + PRINT(printer_print_path(printer, true)); + PARSE(printer, parser_ch, &tag); + switch(tag) { + case 'U': + break; + case 'T': + PRINT_STR(printer, "("); + PRINT_SEP_LIST(printer, PRINT(printer_print_const(printer, true)), ", "); + PRINT_STR(printer, ")"); + break; + case 'S': + PRINT_STR(printer, " { "); + PRINT_SEP_LIST(printer, PRINT(printer_print_const_struct(printer)), ", "); + PRINT_STR(printer, " }"); + break; + default: + INVALID(printer); + } + break; + case 'B': + PRINT(printer_print_backref(printer, in_value ? printer_print_const_in_value : printer_print_const_out_of_value, NULL)); + break; + default: + INVALID(printer); + } +#undef OPEN_BRACE_IF_OUTSIDE_EXPR + + if (opened_brace) { + PRINT_STR(printer, "}"); + } + printer_pop_depth(printer); + + return OverflowOk; +} + +/// A trait in a trait object may have some "existential projections" +/// (i.e. associated type bindings) after it, which should be printed +/// in the `<...>` of the trait, e.g. `dyn Trait`. +/// To this end, this method will keep the `<...>` of an 'I' path +/// open, by omitting the `>`, and return `Ok(true)` in that case. +static NODISCARD overflow_status printer_print_maybe_open_generics(struct printer *printer, bool *open) { + if (printer_eat(printer, 'B')) { + // NOTE(eddyb) the closure may not run if printing is being skipped, + // but in that case the returned boolean doesn't matter. + *open = false; + return printer_print_backref(printer, printer_print_maybe_open_generics, open); + } else if(printer_eat(printer, 'I')) { + PRINT(printer_print_path(printer, false)); + PRINT_STR(printer, "<"); + PRINT_SEP_LIST(printer, PRINT(printer_print_generic_arg(printer)), ", "); + *open = true; + return OverflowOk; + } else { + PRINT(printer_print_path(printer, false)); + *open = false; + return OverflowOk; + } +} + +static NODISCARD overflow_status printer_print_dyn_trait(struct printer *printer) { + bool open; + PRINT(printer_print_maybe_open_generics(printer, &open)); + + while (printer_eat(printer, 'p')) { + if (!open) { + PRINT_STR(printer, "<"); + open = true; + } else { + PRINT_STR(printer, ", "); + } + + struct ident name; + PARSE(printer, parser_ident, &name); + + PRINT_IDENT(printer, &name); + PRINT_STR(printer, " = "); + PRINT(printer_print_type(printer)); + } + + if (open) { + PRINT_STR(printer, ">"); + } + + return OverflowOk; +} + +static NODISCARD overflow_status printer_print_object_bounds(struct printer *printer) { + PRINT_SEP_LIST(printer, PRINT(printer_print_dyn_trait(printer)), " + "); + return OverflowOk; +} + +static NODISCARD overflow_status printer_print_function_type(struct printer *printer) { + bool is_unsafe = printer_eat(printer, 'U'); + const char *abi; + size_t abi_len; + if (printer_eat(printer, 'K')) { + if (printer_eat(printer, 'C')) { + abi = "C"; + abi_len = 1; + } else { + struct ident abi_ident; + PARSE(printer, parser_ident, &abi_ident); + if (abi_ident.ascii_len == 0 || abi_ident.punycode_len != 0) { + INVALID(printer); + } + abi = abi_ident.ascii_start; + abi_len = abi_ident.ascii_len; + } + } else { + abi = NULL; + abi_len = 0; + } + + if (is_unsafe) { + PRINT_STR(printer, "unsafe "); + } + + if (abi != NULL) { + PRINT_STR(printer, "extern \""); + + // replace _ with - + while (abi_len > 0) { + const char *minus = (const char *)memchr(abi, '_', abi_len); + if (minus == NULL) { + PRINT(printer_print_buf(printer, (const char*)abi, abi_len)); + break; + } else { + size_t space_to_minus = minus - abi; + PRINT(printer_print_buf(printer, (const char*)abi, space_to_minus)); + PRINT_STR(printer, "-"); + abi = minus + 1; + abi_len -= (space_to_minus + 1); + } + } + + PRINT_STR(printer, "\" "); + } + + PRINT_STR(printer, "fn("); + PRINT_SEP_LIST(printer, PRINT(printer_print_type(printer)), ", "); + PRINT_STR(printer, ")"); + + if (printer_eat(printer, 'u')) { + // Skip printing the return type if it's 'u', i.e. `()`. + } else { + PRINT_STR(printer, " -> "); + PRINT(printer_print_type(printer)); + } + + return OverflowOk; +} + +static NODISCARD overflow_status printer_print_type_backref(struct printer *printer, bool *_arg) { + (void)_arg; + return printer_print_type(printer); +} + +static NODISCARD overflow_status printer_print_type(struct printer *printer) { + uint8_t tag; + PARSE(printer, parser_ch, &tag); + + const char *basic_ty = basic_type(tag); + if (basic_ty) { + return printer_print_str(printer, basic_ty); + } + + uint64_t count; + uint64_t lt; + + PARSE(printer, parser_push_depth); + switch (tag) { + case 'R': + case 'Q': + PRINT_STR(printer, "&"); + if (printer_eat(printer, 'L')) { + PARSE(printer, parser_integer_62, <); + if (lt != 0) { + PRINT(printer_print_lifetime_from_index(printer, lt)); + PRINT_STR(printer, " "); + } + } + if (tag != 'R') { + PRINT_STR(printer, "mut "); + } + PRINT(printer_print_type(printer)); + break; + case 'P': + case 'O': + PRINT_STR(printer, "*"); + if (tag != 'P') { + PRINT_STR(printer, "mut "); + } else { + PRINT_STR(printer, "const "); + } + PRINT(printer_print_type(printer)); + break; + case 'A': + case 'S': + PRINT_STR(printer, "["); + PRINT(printer_print_type(printer)); + if (tag == 'A') { + PRINT_STR(printer, "; "); + PRINT(printer_print_const(printer, true)); + } + PRINT_STR(printer, "]"); + break; + case 'T': + PRINT_STR(printer, "("); + PRINT_SEP_LIST_COUNT(printer, count, PRINT(printer_print_type(printer)), ", "); + if (count == 1) { + PRINT_STR(printer, ","); + } + PRINT_STR(printer, ")"); + break; + case 'F': + PRINT(printer_in_binder(printer, printer_print_function_type)); + break; + case 'D': + PRINT_STR(printer, "dyn "); + PRINT(printer_in_binder(printer, printer_print_object_bounds)); + + if (!printer_eat(printer, 'L')) { + INVALID(printer); + } + PARSE(printer, parser_integer_62, <); + + if (lt != 0) { + PRINT_STR(printer, " + "); + PRINT(printer_print_lifetime_from_index(printer, lt)); + } + break; + case 'B': + PRINT(printer_print_backref(printer, printer_print_type_backref, NULL)); + break; + default: + // Go back to the tag, so `print_path` also sees it. + if (printer->status == DemangleOk && /* safety */ printer->parser.next > 0) { + printer->parser.next--; + } + PRINT(printer_print_path(printer, false)); + } + + printer_pop_depth(printer); + return OverflowOk; +} + +NODISCARD static demangle_status rust_demangle_legacy_demangle(const char *s, size_t s_len, struct demangle_legacy *res, const char **rest) +{ + if (s_len > strlen(s)) { + // s_len only exists to shorten the string, this is not a buffer API + return DemangleInvalid; + } + + const char *inner; + size_t inner_len; + if (s_len >= 3 && !strncmp(s, "_ZN", 3)) { + inner = s + 3; + inner_len = s_len - 3; + } else if (s_len >= 2 && !strncmp(s, "ZN", 2)) { + // On Windows, dbghelp strips leading underscores, so we accept "ZN...E" + // form too. + inner = s + 2; + inner_len = s_len - 2; + } else if (s_len >= 4 && !strncmp(s, "__ZN", 4)) { + // On OSX, symbols are prefixed with an extra _ + inner = s + 4; + inner_len = s_len - 4; + } else { + return DemangleInvalid; + } + + if (!str_isascii(inner, inner_len)) { + return DemangleInvalid; + } + + size_t elements = 0; + const char *chars = inner; + size_t chars_len = inner_len; + if (chars_len == 0) { + return DemangleInvalid; + } + char c; + while ((c = *chars) != 'E') { + // Decode an identifier element's length + if (c < '0' || c > '9') { + return DemangleInvalid; + } + size_t len = 0; + while (c >= '0' && c <= '9') { + size_t d = c - '0'; + if (len > SIZE_MAX / 10) { + return DemangleInvalid; + } + len *= 10; + if (len > SIZE_MAX - d) { + return DemangleInvalid; + } + len += d; + + chars++; + chars_len--; + if (chars_len == 0) { + return DemangleInvalid; + } + c = *chars; + } + + // Advance by the length + if (chars_len <= len) { + return DemangleInvalid; + } + chars += len; + chars_len -= len; + elements++; + } + *res = (struct demangle_legacy) { inner, inner_len, elements }; + *rest = chars + 1; + return DemangleOk; +} + +static bool is_rust_hash(const char *s, size_t len) { + if (len == 0 || s[0] != 'h') { + return false; + } + + for (size_t i = 1; i < len; i++) { + if (!((s[i] >= '0' && s[i] <= '9') || (s[i] >= 'a' && s[i] <= 'f') || (s[i] >= 'A' && s[i] <= 'F'))) { + return false; + } + } + + return true; +} + +NODISCARD static overflow_status rust_demangle_legacy_display_demangle(struct demangle_legacy res, char *out, size_t len, bool alternate) +{ + struct printer printer = { + // not actually using the parser part of the printer, just keeping it to share the format functions + DemangleOk, + { NULL }, + out, + len, + 0, + alternate + }; + const char *inner = res.mangled; + for (size_t element = 0; element < res.elements; element++) { + size_t i = 0; + const char *rest; + for (rest = inner; rest < res.mangled + res.mangled_len && *rest >= '0' && *rest <= '9'; rest++) { + i *= 10; + i += *rest - '0'; + } + if ((size_t)(res.mangled + res.mangled_len - rest) < i) { + // safety: shouldn't reach this place if the input string is validated. bail out. + // safety: we knwo rest <= res.mangled + res.mangled_len from the for-loop above + break; + } + + size_t len = i; + inner = rest + len; + + // From here on, inner contains a pointer to the next element, rest[:len] to the current one + if (alternate && element + 1 == res.elements && is_rust_hash(rest, i)) { + break; + } + if (element != 0) { + PRINT_STR(&printer, "::"); + } + + if (len >= 2 && !strncmp(rest, "_$", 2)) { + rest++; + len--; + } + + while (len > 0) { + if (rest[0] == '.') { + if (len >= 2 && rest[1] == '.') { + PRINT_STR(&printer, "::"); + rest += 2; + len -= 2; + } else { + PRINT_STR(&printer, "."); + rest += 1; + len -= 1; + } + } else if (rest[0] == '$') { + const char *escape = (const char *)memchr(rest + 1, '$', len - 1); + if (escape == NULL) { + break; + } + const char *escape_start = rest + 1; + size_t escape_len = escape - (rest + 1); + + size_t next_len = len - (escape + 1 - rest); + const char *next_rest = escape + 1; + + char ch; + if ((escape_len == 2 && escape_start[0] == 'S' && escape_start[1] == 'P')) { + ch = '@'; + } else if ((escape_len == 2 && escape_start[0] == 'B' && escape_start[1] == 'P')) { + ch = '*'; + } else if ((escape_len == 2 && escape_start[0] == 'R' && escape_start[1] == 'F')) { + ch = '&'; + } else if ((escape_len == 2 && escape_start[0] == 'L' && escape_start[1] == 'T')) { + ch = '<'; + } else if ((escape_len == 2 && escape_start[0] == 'G' && escape_start[1] == 'T')) { + ch = '>'; + } else if ((escape_len == 2 && escape_start[0] == 'L' && escape_start[1] == 'P')) { + ch = '('; + } else if ((escape_len == 2 && escape_start[0] == 'R' && escape_start[1] == 'P')) { + ch = ')'; + } else if ((escape_len == 1 && escape_start[0] == 'C')) { + ch = ','; + } else { + if (escape_len > 1 && escape_start[0] == 'u') { + escape_start++; + escape_len--; + uint64_t val; + if (try_parse_uint(escape_start, escape_len, &val) + && val < UINT32_MAX + && validate_char((uint32_t)val)) + { + if (!unicode_iscontrol(val)) { + uint8_t wchr[4]; + size_t wchr_len = code_to_utf8(wchr, (uint32_t)val); + PRINT(printer_print_buf(&printer, (const char*)wchr, wchr_len)); + len = next_len; + rest = next_rest; + continue; + } + } + } + break; // print the rest of this element raw + } + PRINT_CH(&printer, ch); + len = next_len; + rest = next_rest; + } else { + size_t j = 0; + for (;j < len && rest[j] != '$' && rest[j] != '.';j++); + if (j == len) { + break; + } + PRINT(printer_print_buf(&printer, rest, j)); + rest += j; + len -= j; + } + } + PRINT(printer_print_buf(&printer, rest, len)); + } + + if (printer.out_len < OVERFLOW_MARGIN) { + return OverflowOverflow; + } + *printer.out = '\0'; + return OverflowOk; +} + +static bool is_symbol_like(const char *s, size_t len) { + // rust-demangle definition of symbol like: control characters and space are not symbol-like, all else is + for (size_t i = 0; i < len; i++) { + char ch = s[i]; + if (!(ch >= 0x21 && ch <= 0x7e)) { + return false; + } + } + return true; +} + +void rust_demangle_demangle(const char *s, struct demangle *res) +{ + // During ThinLTO LLVM may import and rename internal symbols, so strip out + // those endings first as they're one of the last manglings applied to symbol + // names. + const char *llvm = ".llvm."; + const char *found_llvm = strstr(s, llvm); + size_t s_len = strlen(s); + if (found_llvm) { + const char *all_hex_ptr = found_llvm + strlen(".llvm."); + bool all_hex = true; + for (;*all_hex_ptr;all_hex_ptr++) { + if (!(('0' <= *all_hex_ptr && *all_hex_ptr <= '9') || + ('A' <= *all_hex_ptr && *all_hex_ptr <= 'F') || + *all_hex_ptr == '@')) { + all_hex = false; + break; + } + } + + if (all_hex) { + s_len = found_llvm - s; + } + } + + const char *suffix; + struct demangle_legacy legacy; + demangle_status st = rust_demangle_legacy_demangle(s, s_len, &legacy, &suffix); + if (st == DemangleOk) { + *res = (struct demangle) { + .style=DemangleStyleLegacy, + .mangled=legacy.mangled, + .mangled_len=legacy.mangled_len, + .elements=legacy.elements, + .original=s, + .original_len=s_len, + .suffix=suffix, + .suffix_len=s_len - (suffix - s), + }; + } else { + struct demangle_v0 v0; + st = rust_demangle_v0_demangle(s, s_len, &v0, &suffix); + if (st == DemangleOk) { + *res = (struct demangle) { + .style=DemangleStyleV0, + .mangled=v0.mangled, + .mangled_len=v0.mangled_len, + .elements=0, + .original=s, + .original_len=s_len, + .suffix=suffix, + .suffix_len=s_len - (suffix - s), + }; + } else { + *res = (struct demangle) { + .style=DemangleStyleUnknown, + .mangled=NULL, + .mangled_len=0, + .elements=0, + .original=s, + .original_len=s_len, + .suffix=s, + .suffix_len=0, + }; + } + } + + // Output like LLVM IR adds extra period-delimited words. See if + // we are in that case and save the trailing words if so. + if (res->suffix_len) { + if (res->suffix[0] == '.' && is_symbol_like(res->suffix, res->suffix_len)) { + // Keep the suffix + } else { + // Reset the suffix and invalidate the demangling + res->style = DemangleStyleUnknown; + res->suffix_len = 0; + } + } +} + +bool rust_demangle_is_known(struct demangle *res) { + return res->style != DemangleStyleUnknown; +} + +overflow_status rust_demangle_display_demangle(struct demangle const *res, char *out, size_t len, bool alternate) { + size_t original_len = res->original_len; + size_t out_len; + switch (res->style) { + case DemangleStyleUnknown: + if (len < original_len) { + return OverflowOverflow; + } else { + memcpy(out, res->original, original_len); + out += original_len; + len -= original_len; + break; + } + break; + case DemangleStyleLegacy: { + struct demangle_legacy legacy = { + res->mangled, + res->mangled_len, + res->elements + }; + if (rust_demangle_legacy_display_demangle(legacy, out, len, alternate) == OverflowOverflow) { + return OverflowOverflow; + } + out_len = strlen(out); + out += out_len; + len -= out_len; + break; + } + case DemangleStyleV0: { + struct demangle_v0 v0 = { + res->mangled, + res->mangled_len + }; + if (rust_demangle_v0_display_demangle(v0, out, len, alternate) == OverflowOverflow) { + return OverflowOverflow; + } + out_len = strlen(out); + out += out_len; + len -= out_len; + break; + } + } + size_t suffix_len = res->suffix_len; + if (len < suffix_len || len - suffix_len < OVERFLOW_MARGIN) { + return OverflowOverflow; + } + memcpy(out, res->suffix, suffix_len); + out[suffix_len] = 0; + return OverflowOk; +} diff --git a/src/rustDemangle.h b/src/rustDemangle.h new file mode 100644 index 000000000..92c73869a --- /dev/null +++ b/src/rustDemangle.h @@ -0,0 +1,77 @@ +/* + * Copyright The async-profiler authors + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _H_DEMANGLE_V0_H +#define _H_DEMANGLE_V0_H + +#include + +#if defined(__GNUC__) || defined(__clang__) +#define DEMANGLE_NODISCARD __attribute__((warn_unused_result)) +#else +#define DEMANGLE_NODISCARD +#endif + +typedef enum { + OverflowOk, + OverflowOverflow +} overflow_status; + +enum demangle_style { + DemangleStyleUnknown = 0, + DemangleStyleLegacy, + DemangleStyleV0, +}; + +// Not using a union here to make the struct easier to copy-paste if needed. +struct demangle { + enum demangle_style style; + // points to the "mangled" part of the name, + // not including `ZN` or `R` prefixes. + const char *mangled; + size_t mangled_len; + // In DemangleStyleLegacy, is the number of path elements + size_t elements; + // while it's called "original", it will not contain `.llvm.9D1C9369@@16` suffixes + // that are to be ignored. + const char *original; + size_t original_len; + // Contains the part after the mangled name that is to be outputted, + // which can be `.exit.i.i` suffixes LLVM sometimes adds. + const char *suffix; + size_t suffix_len; +}; + +// if the length of the output buffer is less than `output_len-OVERFLOW_MARGIN`, +// the demangler will return `OverflowOverflow` even if there is no overflow. +#define OVERFLOW_MARGIN 4 + +/// Demangle a C string that refers to a Rust symbol and put the demangle intermediate result in `res`. +/// Beware that `res` contains references into `s`. If `s` is modified (or free'd) before calling +/// `rust_demangle_display_demangle` behavior is undefined. +/// +/// Use `rust_demangle_display_demangle` to convert it to an actual string. +void rust_demangle_demangle(const char *s, struct demangle *res); + +/// Write the string in a `struct demangle` into a buffer. +/// +/// Return `OverflowOk` if the output buffer was sufficiently big, `OverflowOverflow` if it wasn't. +/// This function is `O(n)` in the length of the input + *output* [$], but the demangled output of demangling a symbol can +/// be exponentially[$$] large, therefore it is recommended to have a sane bound (`rust-demangle` +/// uses 1,000,000 bytes) on `len`. +/// +/// `alternate`, if true, uses the less verbose alternate formatting (Rust `{:#}`) is used, which does not show +/// symbol hashes and types of constant ints. +/// +/// [$] It's `O(n * MAX_DEPTH)`, but `MAX_DEPTH` is a constant 300 and therefore it's `O(n)` +/// [$$] Technically, bounded by `O(n^MAX_DEPTH)`, but this is practically exponential. +DEMANGLE_NODISCARD overflow_status rust_demangle_display_demangle(struct demangle const *res, char *out, size_t len, bool alternate); + +/// Returns true if `res` refers to a known valid Rust demangling style, false if it's an unknown style. +bool rust_demangle_is_known(struct demangle *res); + +#undef DEMANGLE_NODISCARD + +#endif diff --git a/src/vmEntry.h b/src/vmEntry.h index bc6e7a22a..7a08ec006 100644 --- a/src/vmEntry.h +++ b/src/vmEntry.h @@ -13,6 +13,13 @@ enum FrameTypeId { FRAME_INTERPRETED = 0, FRAME_JIT_COMPILED = 1, FRAME_INLINED = 2, + // The distinction between FRAME_NATIVE and FRAME_CPP is for visual purposes + // to make differentiating between libc and application code easier, which + // means that C and asm code is FRAME_NATIVE and Rust/Objective-C code is of + // type FRAME_CPP. + // + // There probably should be a better way of doing this distinction, but it + // works well enough in practice. FRAME_NATIVE = 3, FRAME_CPP = 4, FRAME_KERNEL = 5, diff --git a/test/native/demangleTest.cpp b/test/native/demangleTest.cpp new file mode 100644 index 000000000..2e5d09846 --- /dev/null +++ b/test/native/demangleTest.cpp @@ -0,0 +1,161 @@ +/* + * Copyright The async-profiler authors + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "arch.h" +#include "testRunner.hpp" +#include "demangle.h" +#include + +TEST_CASE(Demangle_test_needs_demangling) { + // Rust legacy-mangled symbol + CHECK_EQ(Demangle::needsDemangling("_ZN12panic_unwind3imp5panic17exception_cleanup17he4cf772173d90f46E"), true); + // Rust v0-mangled symbol + CHECK_EQ(Demangle::needsDemangling("_RNvCs6KtT2fMGqXk_8infiloop4main"), true); + // C++ symbol + CHECK_EQ(Demangle::needsDemangling("_ZNKSbIwSt11char_traitsIwESaIwEE4_Rep12_M_is_sharedEv"), true); + // C symbols + CHECK_EQ(Demangle::needsDemangling("malloc"), false); + CHECK_EQ(Demangle::needsDemangling("_malloc"), false); +} + +TEST_CASE(Demangle_test_demangle_cpp) { + char *s = Demangle::demangle("_ZNSt15basic_streambufIwSt11char_traitsIwEE9pbackfailEj", false); + // 2 different demangling formats between libc++ (Mac) and libstdc++ (most Linux) + if (strcmp(s, "std::basic_streambuf >::pbackfail") == 0) { + CHECK_EQ(s, "std::basic_streambuf >::pbackfail"); + } else { + CHECK_EQ(s, "std::basic_streambuf>::pbackfail"); + } + free(s); +} + +TEST_CASE(Demangle_test_demangle_cpp_rust_like) { + char *s = Demangle::demangle("_ZN5MyMapESt6vectorIRKSsE", true); + CHECK_EQ(s, "MyMap(std::vector)"); + free(s); +} + +TEST_CASE(Demangle_test_demangle_cpp_rust_like_2) { + char *s = Demangle::demangle("_ZN12_GLOBAL__N_113single_threadE", true); + CHECK_EQ(s, "(anonymous namespace)::single_thread"); + free(s); +} + +TEST_CASE(Demangle_test_demangle_cpp_full_signature) { + char *s = Demangle::demangle("_ZNSt15basic_streambufIwSt11char_traitsIwEE9pbackfailEj", true); + // 2 different demangling formats between libc++ (Mac) and libstdc++ (most Linux) + if (strcmp(s, "std::basic_streambuf >::pbackfail(unsigned int)") == 0) { + CHECK_EQ(s, "std::basic_streambuf >::pbackfail(unsigned int)"); + } else { + CHECK_EQ(s, "std::basic_streambuf>::pbackfail(unsigned int)"); + } + free(s); +} + +TEST_CASE(Demangle_test_demangle_rust_legacy) { + char *s = Demangle::demangle("_ZN12panic_unwind3imp5panic17exception_cleanup17he4cf772173d90f46E", false); + CHECK_EQ(s, "panic_unwind::imp::panic::exception_cleanup"); + free(s); +} + +TEST_CASE(Demangle_test_demangle_rust_legacy_dot_lto) { + char *s = Demangle::demangle("_ZN12panic_unwind3imp5panic17exception_cleanup17he4cf772173d90f46E.lto.1", false); + CHECK_EQ(s, "panic_unwind::imp::panic::exception_cleanup.lto.1"); + free(s); +} + +TEST_CASE(Demangle_test_demangle_rust_legacy_full_signature) { + char *s = Demangle::demangle("_ZN12panic_unwind3imp5panic17exception_cleanup17he4cf772173d90f46E", true); + CHECK_EQ(s, "panic_unwind::imp::panic::exception_cleanup::he4cf772173d90f46"); + free(s); +} + +TEST_CASE(Demangle_test_demangle_rust_legacy_full_signature_dot_lto) { + char *s = Demangle::demangle("_ZN12panic_unwind3imp5panic17exception_cleanup17he4cf772173d90f46E.lto.1", true); + CHECK_EQ(s, "panic_unwind::imp::panic::exception_cleanup::he4cf772173d90f46.lto.1"); + free(s); +} + +TEST_CASE(Demangle_test_demangle_rust_v0) { + char *s = Demangle::demangle("_RNvCs6KtT2fMGqXk_8infiloop4main", false); + CHECK_EQ(s, "infiloop::main"); + free(s); +} + +TEST_CASE(Demangle_test_demangle_rust_v0_full_signature) { + char *s = Demangle::demangle("_RNvCs6KtT2fMGqXk_8infiloop4main", true); + CHECK_EQ(s, "infiloop[4e9e38d21762ec98]::main"); + free(s); +} + +TEST_CASE(Demangle_test_demangle_rust_v0_dot_lto) { + char *s = Demangle::demangle("_RNvCs6KtT2fMGqXk_8infiloop4main.lto.1", false); + CHECK_EQ(s, "infiloop::main.lto.1"); + free(s); +} + +TEST_CASE(Demangle_test_demangle_rust_v0_full_signature_dot_lto) { + char *s = Demangle::demangle("_RNvCs6KtT2fMGqXk_8infiloop4main.lto.1", true); + CHECK_EQ(s, "infiloop[4e9e38d21762ec98]::main.lto.1"); + free(s); +} + +TEST_CASE(Demangle_test_demangle_rust_v0_punycode) { + char *s = Demangle::demangle("_RNqCs4fqI2P2rA04_11utf8_identsu30____7hkackfecea1cbdathfdh9hlq6y", false); + CHECK_EQ(strcmp(s, + "utf8_idents::\xe1\x83\xa1\xe1\x83\x90\xe1\x83\xad\xe1\x83\x9b\xe1\x83\x94\xe1\x83\x9a" + "\xe1\x83\x90\xe1\x83\x93_\xe1\x83\x92\xe1\x83\x94\xe1\x83\x9b\xe1\x83\xa0\xe1\x83\x98" + "\xe1\x83\x94\xe1\x83\x9a\xe1\x83\x98_\xe1\x83\xa1\xe1\x83\x90\xe1\x83\x93\xe1\x83\x98" + "\xe1\x83\x9a\xe1\x83\x98"), 0); + free(s); +} + +TEST_CASE(Demangle_test_demangle_rust_v0_consts) { + char *s = Demangle::demangle("_RIC0KVNtC3foo3BarS1sRe616263_2chc78_5sliceRAh1_h2_h3_EEE", false); + CHECK_EQ(strcmp(s, + "::<{foo::Bar { s: \"abc\", ch: 'x', slice: &[1, 2, 3] }}>"), 0); + free(s); +} + +TEST_CASE(Demangle_test_demangle_rust_v0_consts_full_signature) { + char *s = Demangle::demangle("_RIC0KVNtC3foo3BarS1sRe616263_2chc78_5sliceRAh1_h2_h3_EEE", true); + CHECK_EQ(strcmp(s, + "::<{foo::Bar { s: \"abc\", ch: 'x', slice: &[1u8, 2u8, 3u8] }}>"), 0); + free(s); +} + +TEST_CASE(Demangle_test_demangle_rust_v0_const_string) { + char *s = Demangle::demangle("_RIC0Kef09f908af09fa688f09fa686f09f90ae20c2a720f09f90b6f09f9192e29895f09f94a520c2a720f09fa7a1f09f929bf09f929af09f9299f09f929c_E", false); + CHECK_EQ(strcmp(s, + "::<{*\"\\u{1f40a}\\u{1f988}\\u{1f986}\\u{1f42e} \\u{a7} \\u{1f436}\\u{1f452}\\u{2615}\\u{1f525}" + " \\u{a7} \\u{1f9e1}\\u{1f49b}\\u{1f49a}\\u{1f499}\\u{1f49c}\"}>"), 0); + free(s); +} + +TEST_CASE(Demangle_test_demangle_rust_v0_invalid_backref) { + char *s = Demangle::demangle("_RNvNvB0_1x1y", false); + CHECK_EQ(s, "{invalid syntax}::x::y"); + free(s); +} + +TEST_CASE(Demangle_test_demangle_rust_v0_expanding) { + // Test that demangling of a symbol that is big is handled correctly + char *s = Demangle::demangle("_RNvMC0" "TTTTTT" "p" "Ba_E" "B9_E" "B8_E" "B7_E" "B6_E" "B5_E" "3run", false); + const char *expected = + "<" + "((((((_, _), (_, _)), ((_, _), (_, _))), (((_, _), (_, _)), ((_, _), (_, _)))), " + "((((_, _), (_, _)), ((_, _), (_, _))), (((_, _), (_, _)), ((_, _), (_, _))))), " + "(((((_, _), (_, _)), ((_, _), (_, _))), (((_, _), (_, _)), ((_, _), (_, _)))), " + "((((_, _), (_, _)), ((_, _), (_, _))), (((_, _), (_, _)), ((_, _), (_, _))))))" + ">::run"; + CHECK_EQ(s, expected); + free(s); +} + +TEST_CASE(Demangle_test_demangle_rust_v0_infinite) { + // Test that demangling of a symbol that is stupidly big is handled correctly + char *s = Demangle::demangle("_RNvMC0" "TTTTTTTTTTTTTTTT" "p" "Bk_Bk_Bk_Bk_Bk_Bk_Bk_Bk_E" "Bj_E" "Bi_E" "Bh_E" "Bg_E" "Bf_E" "Be_E" "Bd_E" "Bc_E" "Bb_E" "Ba_E" "B9_E" "B8_E" "B7_E" "B6_E" "B5_E" "3run", false); + CHECK_EQ(s, NULL); +} From 04cc4759d45e7202b91aa93128f48aadd76af40b Mon Sep 17 00:00:00 2001 From: Andrei Pangin Date: Fri, 6 Dec 2024 22:58:14 +0000 Subject: [PATCH 2/3] Minor formatting; removed whitespace at EOL --- src/demangle.cpp | 6 +++--- src/demangle.h | 7 ++++--- src/rustDemangle.cpp | 18 +++++++++--------- src/vmEntry.h | 2 +- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/demangle.cpp b/src/demangle.cpp index 603c548bd..c2535ef88 100644 --- a/src/demangle.cpp +++ b/src/demangle.cpp @@ -9,6 +9,7 @@ #include "demangle.h" #include "rustDemangle.h" + char* Demangle::demangleCpp(const char* s) { int status; char* result = abi::__cxa_demangle(s, NULL, NULL, &status); @@ -25,7 +26,7 @@ char* Demangle::demangleCpp(const char* s) { return result; } -bool Demangle::isRustSymbol(const char *s) { +bool Demangle::isRustSymbol(const char* s) { // "_R" symbols (Rust "mangling V0") symbols can always be easily distinguished from C++ symbols. if (s[0] == '_' && s[1] == 'R') { return true; @@ -55,9 +56,8 @@ bool Demangle::isRustSymbol(const char *s) { } char* Demangle::demangleRust(struct demangle const *demangle, bool full_signature) { - char* result; for (size_t demangled_size = 64; demangled_size < 1000000; demangled_size *= 2) { - result = (char *)malloc(demangled_size); + char* result = (char*)malloc(demangled_size); if (result == NULL) { return NULL; } diff --git a/src/demangle.h b/src/demangle.h index aa7e48c82..d7e01f61e 100644 --- a/src/demangle.h +++ b/src/demangle.h @@ -12,13 +12,14 @@ class Demangle { private: static char* demangleCpp(const char* s); static char* demangleRust(struct demangle const *demangle, bool full_signature); - static bool isRustSymbol(const char *s); + static bool isRustSymbol(const char* s); static void cutArguments(char* s); public: static char* demangle(const char* s, bool full_signature); - static bool needsDemangling(const char *s) { - return s[0] == '_' && (s[1] == 'R' || s[1] == 'Z'); + + static bool needsDemangling(const char* s) { + return s[0] == '_' && (s[1] == 'R' || s[1] == 'Z'); } }; diff --git a/src/rustDemangle.cpp b/src/rustDemangle.cpp index 4e3571b03..217fe475b 100644 --- a/src/rustDemangle.cpp +++ b/src/rustDemangle.cpp @@ -1079,7 +1079,7 @@ static NODISCARD overflow_status printer_print_lifetime_from_index(struct printe PRINT_STR(printer, "_"); return OverflowOk; } - + if (printer->bound_lifetime_depth < lt) { INVALID(printer); } else { @@ -1344,7 +1344,7 @@ static NODISCARD overflow_status printer_print_const(struct printer *printer, bo opened_brace = true; \ PRINT_STR(printer, "{"); \ } } while(0) - + switch(tag) { case 'p': PRINT_STR(printer, "_"); @@ -1455,7 +1455,7 @@ static NODISCARD overflow_status printer_print_const(struct printer *printer, bo case 'B': PRINT(printer_print_backref(printer, in_value ? printer_print_const_in_value : printer_print_const_out_of_value, NULL)); break; - default: + default: INVALID(printer); } #undef OPEN_BRACE_IF_OUTSIDE_EXPR @@ -1772,7 +1772,7 @@ NODISCARD static overflow_status rust_demangle_legacy_display_demangle(struct de struct printer printer = { // not actually using the parser part of the printer, just keeping it to share the format functions DemangleOk, - { NULL }, + { NULL }, out, len, 0, @@ -1795,7 +1795,7 @@ NODISCARD static overflow_status rust_demangle_legacy_display_demangle(struct de size_t len = i; inner = rest + len; - // From here on, inner contains a pointer to the next element, rest[:len] to the current one + // From here on, inner contains a pointer to the next element, rest[:len] to the current one if (alternate && element + 1 == res.elements && is_rust_hash(rest, i)) { break; } @@ -1807,7 +1807,7 @@ NODISCARD static overflow_status rust_demangle_legacy_display_demangle(struct de rest++; len--; } - + while (len > 0) { if (rest[0] == '.') { if (len >= 2 && rest[1] == '.') { @@ -1826,7 +1826,7 @@ NODISCARD static overflow_status rust_demangle_legacy_display_demangle(struct de } const char *escape_start = rest + 1; size_t escape_len = escape - (rest + 1); - + size_t next_len = len - (escape + 1 - rest); const char *next_rest = escape + 1; @@ -1966,7 +1966,7 @@ void rust_demangle_demangle(const char *s, struct demangle *res) .original_len=s_len, .suffix=s, .suffix_len=0, - }; + }; } } @@ -1987,7 +1987,7 @@ bool rust_demangle_is_known(struct demangle *res) { return res->style != DemangleStyleUnknown; } -overflow_status rust_demangle_display_demangle(struct demangle const *res, char *out, size_t len, bool alternate) { +overflow_status rust_demangle_display_demangle(struct demangle const *res, char *out, size_t len, bool alternate) { size_t original_len = res->original_len; size_t out_len; switch (res->style) { diff --git a/src/vmEntry.h b/src/vmEntry.h index 7a08ec006..bb2dba3d1 100644 --- a/src/vmEntry.h +++ b/src/vmEntry.h @@ -16,7 +16,7 @@ enum FrameTypeId { // The distinction between FRAME_NATIVE and FRAME_CPP is for visual purposes // to make differentiating between libc and application code easier, which // means that C and asm code is FRAME_NATIVE and Rust/Objective-C code is of - // type FRAME_CPP. + // type FRAME_CPP. // // There probably should be a better way of doing this distinction, but it // works well enough in practice. From 9c37bb0f62fee5ffbdc3217fdeb8eda56a521598 Mon Sep 17 00:00:00 2001 From: Andrei Pangin Date: Fri, 6 Dec 2024 23:06:32 +0000 Subject: [PATCH 3/3] Doc formatting --- .assets/images/flamegraph_colors.png | Bin 13530 -> 118632 bytes docs/ProfilerOptions.md | 71 +++++++++++++-------------- docs/Troubleshooting.md | 4 +- 3 files changed, 37 insertions(+), 38 deletions(-) diff --git a/.assets/images/flamegraph_colors.png b/.assets/images/flamegraph_colors.png index 02e50e24fed11915c4a4b147412f9e1acaa83661..a55b97d95f84a0e04c574f2255cdb5a65314a189 100644 GIT binary patch literal 118632 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 N+Q44iL&vk0Hq5y4rNHR~BzZLsZ6pNUokDk7G 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 VCzlAw7qQ+{^7T(hxrEHO~CHRP7X2iN8dOP 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: `asprof -d 30 `` | -| `--timeout N` | `timeout=N` | The profiling duration, in seconds. The profiler will run for the specified period of time and then automatically stop.
Example: `java -agentpath:/path/to/libasyncProfiler.so=start,event=cpu,timeout=30,file=profile.html ` | -| `-e --event EVENT` | `event=EVENT` | The profiling event: `cpu`, `alloc`, `lock`, `cache-misses` etc. Use `list` to see the complete list of available events.
Please refer to [Special Event Types](https://github.com/async-profiler/async-profiler/blob/master/docs/ProfilingModes.md#special-event-types-supported-on-linux) for additional information. | -| `-i --interval N` | `interval=N` | Interval has different meaning depending on the event. For CPU profiling, it's CPU time. In wall clock mode, it's wall clock time. For Java method profiling or native function profiling, it's number of calls. For PMU profiling, it's number of events.
Example: `asprof -e cpu -i 500us 8983` | -| `--alloc N` | `alloc=N` | Allocation profiling interval in bytes or in other units, if N is followed by `k` (kilobytes), `m` (megabytes), or `g` (gigabytes). | -| `--live` | `live` | Retain allocation samples with live objects only (object that have not been collected by the end of profiling session). Useful for finding Java heap memory leaks. | -| `--lock DURATION` | `lock=DURATION` | In lock profiling mode, sample contended locks when total lock duration overflows the threshold | -| `-j N` | `jstackdepth=N` | Sets the maximum stack depth. The default is 2048.
Example: `asprof -j 30 8983` | -| `-I PATTERN` | `include=PATTERN` | Filter stack traces by the given pattern(s). `-I` defines the name pattern that *must* be present in the stack traces. `-I` can be specified multiple times. A pattern may begin or end with a star `*` that denotes any (possibly empty) sequence of characters.
Example: `asprof -I 'Primes.*' -I 'java/*' 8983` | -| `-X PATTERN` | `exclude=PATTERN` | Filter stack traces by the given pattern(s). `-X` defines the name pattern that *must not* occur in any of stack traces in the output. `-X` can be specified multiple times. A pattern may begin or end with a star `*` that denotes any (possibly empty) sequence of characters.
Example: `asprof -X '*Unsafe.park*' 8983` | -| `-L level` | `loglevel=level` | Log level: `debug`, `info`, `warn`, `error` or `none`. | +| asprof | Launch as agent | Description | +|--------------------|-------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `-o fmt` | `fmt` | Specifies what information to dump when profiling ends. For various dump option details, please refer to [Dump Option Appendix](#dump-option). | +| `-d N` | N/A | asprof-only option designed for interactive use. It is a shortcut for running 3 actions: start, sleep for N seconds, stop. If no `start`, `resume`, `stop` or `status` option is given, the profiler will run for the specified period of time and then automatically stop.
Example: `asprof -d 30 `` | +| `--timeout N` | `timeout=N` | The profiling duration, in seconds. The profiler will run for the specified period of time and then automatically stop.
Example: `java -agentpath:/path/to/libasyncProfiler.so=start,event=cpu,timeout=30,file=profile.html ` | +| `-e --event EVENT` | `event=EVENT` | The profiling event: `cpu`, `alloc`, `lock`, `cache-misses` etc. Use `list` to see the complete list of available events.
Please refer to [Special Event Types](https://github.com/async-profiler/async-profiler/blob/master/docs/ProfilingModes.md#special-event-types-supported-on-linux) for additional information. | +| `-i --interval N` | `interval=N` | Interval has different meaning depending on the event. For CPU profiling, it's CPU time. In wall clock mode, it's wall clock time. For Java method profiling or native function profiling, it's number of calls. For PMU profiling, it's number of events.
Example: `asprof -e cpu -i 500us 8983` | +| `--alloc N` | `alloc=N` | Allocation profiling interval in bytes or in other units, if N is followed by `k` (kilobytes), `m` (megabytes), or `g` (gigabytes). | +| `--live` | `live` | Retain allocation samples with live objects only (object that have not been collected by the end of profiling session). Useful for finding Java heap memory leaks. | +| `--lock DURATION` | `lock=DURATION` | In lock profiling mode, sample contended locks when total lock duration overflows the threshold | +| `-j N` | `jstackdepth=N` | Sets the maximum stack depth. The default is 2048.
Example: `asprof -j 30 8983` | +| `-I PATTERN` | `include=PATTERN` | Filter stack traces by the given pattern(s). `-I` defines the name pattern that *must* be present in the stack traces. `-I` can be specified multiple times. A pattern may begin or end with a star `*` that denotes any (possibly empty) sequence of characters.
Example: `asprof -I 'Primes.*' -I 'java/*' 8983` | +| `-X PATTERN` | `exclude=PATTERN` | Filter stack traces by the given pattern(s). `-X` defines the name pattern that *must not* occur in any of stack traces in the output. `-X` can be specified multiple times. A pattern may begin or end with a star `*` that denotes any (possibly empty) sequence of characters.
Example: `asprof -X '*Unsafe.park*' 8983` | +| `-L level` | `loglevel=level` | Log level: `debug`, `info`, `warn`, `error` or `none`. | | `-F features` | `features=LIST` | Comma separated (or `+` separated when launching as an agent) list of stack walking features. Supported features are:
  • `stats` - log stack walking performance stats.
  • `vtable` - display targets of megamorphic virtual calls as an extra frame on top of `vtable stub` or `itable stub`.
  • `comptask` - display current compilation task (a Java method being compiled) in a JIT compiler stack trace.
  • `pcaddr` - display instruction addresses .
More details [here](https://github.com/async-profiler/async-profiler/blob/master/docs/AdvancedStacktraceFeatures.md). | -| `-f FILENAME` | `file` | The file name to dump the profile information to.
`%p` in the file name is expanded to the PID of the target JVM;
`%t` - to the timestamp;
`%n{MAX}` - to the sequence number;
`%{ENV}` - to the value of the given environment variable.
Example: `asprof -o collapsed -f /tmp/traces-%t.txt 8983` | -| `--loop TIME` | `loop=TIME` | Run profiler in a loop (continuous profiling). The argument is either a clock time (`hh:mm:ss`) or a loop duration in `s`econds, `m`inutes, `h`ours, or `d`ays. Make sure the filename includes a timestamp pattern, or the output will be overwritten on each iteration.
Example: `asprof --loop 1h -f /var/log/profile-%t.jfr 8983` | -| `--all-user` | `alluser` | Include only user-mode events. This option is helpful when kernel profiling is restricted by `perf_event_paranoid` settings. | -| `--sched` | `sched` | Group threads by Linux-specific scheduling policy: BATCH/IDLE/OTHER. | -| `--cstack MODE` | `cstack=MODE` | How to walk native frames (C stack). Possible modes are `fp` (Frame Pointer), `dwarf` (DWARF unwind info), `lbr` (Last Branch Record, available on Haswell since Linux 4.1), `vm`, `vmx` (HotSpot VM Structs) and `no` (do not collect C stack).

By default, C stack is shown in cpu, ctimer, wall-clock and perf-events profiles. Java-level events like `alloc` and `lock` collect only Java stack. | -| `--signal NUM` | `signal=NUM` | Use alternative signal for cpu or wall clock profiling. To change both signals, specify two numbers separated by a slash: `--signal SIGCPU/SIGWALL`. | -| `--clock SOURCE` | `clock=SOURCE` | Clock source for JFR timestamps: `tsc` (default) or `monotonic` (equivalent for `CLOCK_MONOTONIC`). | -| `--begin function` | `begin=FUNCTION` | Automatically start profiling when the specified native function is executed. | -| `--end function` | `end=FUNCTION` | Automatically stop profiling when the specified native function is executed. | -| `--ttsp` | `ttsp` | time-to-safepoint profiling. An alias for `--begin SafepointSynchronize::begin --end RuntimeService::record_safepoint_synchronized`.
It is not a separate event type, but rather a constraint. Whatever event type you choose (e.g. `cpu` or `wall`), the profiler will work as usual, except that only events between the safepoint request and the start of the VM operation will be recorded. | -| `--ttsp` | `ttsp` | time-to-safepoint profiling. An alias for `--begin SafepointSynchronize::begin --end RuntimeService::record_safepoint_synchronized`.
It is not a separate event type, but rather a constraint. Whatever event type you choose (e.g. `cpu` or `wall`), the profiler will work as usual, except that only events between the safepoint request and the start of the VM operation will be recorded. | -| `--libpath PATH` | `libpath=PATH` | Full path to libasyncProfiler.so in the container | -| `--filter FILTER` | `filter=FILTER` | Filter threads with thread ids during wall-clock profiling mode | -| `--fdtransfer` | `fdtransfer` | Runs a background process that provides access to perf_events to an unprivileged process. `--fdtransfer` is useful for profiling a process in a container (which lacks access to perf_events) from the host.
See [Profiling Java in a container](#https://github.com/async-profiler/async-profiler/blob/master/docs/ProfilingInContainer.md). | -| `-v --version` | `version` | Prints the version of profiler library. If PID is specified, gets the version of the library loaded into the given process. | +| `-f FILENAME` | `file` | The file name to dump the profile information to.
`%p` in the file name is expanded to the PID of the target JVM;
`%t` - to the timestamp;
`%n{MAX}` - to the sequence number;
`%{ENV}` - to the value of the given environment variable.
Example: `asprof -o collapsed -f /tmp/traces-%t.txt 8983` | +| `--loop TIME` | `loop=TIME` | Run profiler in a loop (continuous profiling). The argument is either a clock time (`hh:mm:ss`) or a loop duration in `s`econds, `m`inutes, `h`ours, or `d`ays. Make sure the filename includes a timestamp pattern, or the output will be overwritten on each iteration.
Example: `asprof --loop 1h -f /var/log/profile-%t.jfr 8983` | +| `--all-user` | `alluser` | Include only user-mode events. This option is helpful when kernel profiling is restricted by `perf_event_paranoid` settings. | +| `--sched` | `sched` | Group threads by Linux-specific scheduling policy: BATCH/IDLE/OTHER. | +| `--cstack MODE` | `cstack=MODE` | How to walk native frames (C stack). Possible modes are `fp` (Frame Pointer), `dwarf` (DWARF unwind info), `lbr` (Last Branch Record, available on Haswell since Linux 4.1), `vm`, `vmx` (HotSpot VM Structs) and `no` (do not collect C stack).

By default, C stack is shown in cpu, ctimer, wall-clock and perf-events profiles. Java-level events like `alloc` and `lock` collect only Java stack. | +| `--signal NUM` | `signal=NUM` | Use alternative signal for cpu or wall clock profiling. To change both signals, specify two numbers separated by a slash: `--signal SIGCPU/SIGWALL`. | +| `--clock SOURCE` | `clock=SOURCE` | Clock source for JFR timestamps: `tsc` (default) or `monotonic` (equivalent for `CLOCK_MONOTONIC`). | +| `--begin function` | `begin=FUNCTION` | Automatically start profiling when the specified native function is executed. | +| `--end function` | `end=FUNCTION` | Automatically stop profiling when the specified native function is executed. | +| `--ttsp` | `ttsp` | time-to-safepoint profiling. An alias for `--begin SafepointSynchronize::begin --end RuntimeService::record_safepoint_synchronized`.
It is not a separate event type, but rather a constraint. Whatever event type you choose (e.g. `cpu` or `wall`), the profiler will work as usual, except that only events between the safepoint request and the start of the VM operation will be recorded. | +| `--libpath PATH` | `libpath=PATH` | Full path to libasyncProfiler.so in the container | +| `--filter FILTER` | `filter=FILTER` | Filter threads with thread ids during wall-clock profiling mode | +| `--fdtransfer` | `fdtransfer` | Runs a background process that provides access to perf_events to an unprivileged process. `--fdtransfer` is useful for profiling a process in a container (which lacks access to perf_events) from the host.
See [Profiling Java in a container](#https://github.com/async-profiler/async-profiler/blob/master/docs/ProfilingInContainer.md). | +| `-v --version` | `version` | Prints the version of profiler library. If PID is specified, gets the version of the library loaded into the given process. | ## Options applicable to JFR output only | asprof | Launch as agent | Description | |----------------------|--------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `--chunksize N` | `chunksize=N` | Approximate size for a single JFR chunk. A new chunk will be started whenever specified size is reached. The default `chunksize` is 100MB.
Example: `asprof -f profile.jfr --chunksize 100m 8983` | -| `--chunktime N` | `chunktime=N` | Approximate time limit for a single JFR chunk. A new chunk will be started whenever specified time limit is reached. The default `chunktime` is 1 hour.
Example: `asprof -f profile.jfr --chunktime 1h 8983` | +| `--chunksize N` | `chunksize=N` | Approximate size for a single JFR chunk. A new chunk will be started whenever specified size is reached. The default `chunksize` is 100MB.
Example: `asprof -f profile.jfr --chunksize 100m 8983` | +| `--chunktime N` | `chunktime=N` | Approximate time limit for a single JFR chunk. A new chunk will be started whenever specified time limit is reached. The default `chunktime` is 1 hour.
Example: `asprof -f profile.jfr --chunktime 1h 8983` | | `--jfropts OPTIONS` | `jfropts=OPTIONS` | Comma separated list of JFR recording options. Currently, the only available option is `mem` supported on Linux 3.17+. `mem` enables accumulating events in memory instead of flushing synchronously to a file. | -| `--jfrsync CONFIG` | `jfrsync[=CONFIG]` | Start Java Flight Recording with the given configuration synchronously with the profiler. The output .jfr file will include all regular JFR events, except that execution samples will be obtained from async-profiler. This option implies `-o jfr`.
`CONFIG` is a predefined JFR profile or a JFR configuration file (.jfc) or a list of JFR events started with `+`.

Example: `asprof -e cpu --jfrsync profile -f combined.jfr 8983` | +| `--jfrsync CONFIG` | `jfrsync[=CONFIG]` | Start Java Flight Recording with the given configuration synchronously with the profiler. The output .jfr file will include all regular JFR events, except that execution samples will be obtained from async-profiler. This option implies `-o jfr`.
`CONFIG` is a predefined JFR profile or a JFR configuration file (.jfc) or a list of JFR events started with `+`.

Example: `asprof -e cpu --jfrsync profile -f combined.jfr 8983` | ## Options applicable to FlameGraph and Tree view outputs only | asprof | Launch as agent | Description | |----------------------|--------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `--title TITLE` | `title=TITLE` | Custom title of a FlameGraph.
Example: `asprof -f profile.html --title "Sample CPU profile" 8983` | -| `--minwidth PERCENT` | `minwidth=PERCENT` | Minimum frame width as a percentage. Smaller frames will not be visible.
Example: `asprof -f profile.html --minwidth 0.5 8983` | -| `--reverse` | `reverse` | Reverse stack traces.
Example: `asprof -f profile.html --reverse 8983` | +| `--title TITLE` | `title=TITLE` | Custom title of a FlameGraph.
Example: `asprof -f profile.html --title "Sample CPU profile" 8983` | +| `--minwidth PERCENT` | `minwidth=PERCENT` | Minimum frame width as a percentage. Smaller frames will not be visible.
Example: `asprof -f profile.html --minwidth 0.5 8983` | +| `--reverse` | `reverse` | Reverse stack traces.
Example: `asprof -f profile.html --reverse 8983` | ## Options applicable to any output format except JFR | asprof | Launch as agent | Description | |----------------|-----------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `-t --threads` | `threads` | Profile threads separately. Each stack trace will end with a frame that denotes a single thread.
Example: `asprof -t 8983` | +| `-t --threads` | `threads` | Profile threads separately. Each stack trace will end with a frame that denotes a single thread.
Example: `asprof -t 8983` | | `-s --simple` | `simple` | Print simple class names instead of fully qualified names. | | `-n --norm` | `norm` | Normalize names of hidden classes / lambdas. | | `-g --sig` | `sig` | Print method signatures. | diff --git a/docs/Troubleshooting.md b/docs/Troubleshooting.md index 93a264c21..21468fd80 100644 --- a/docs/Troubleshooting.md +++ b/docs/Troubleshooting.md @@ -55,9 +55,9 @@ 1. `/proc/sys/kernel/perf_event_paranoid` is set to restricted mode (>=2). 2. seccomp disables `perf_event_open` API in a container. 3. OS runs under a hypervisor that does not virtualize performance counters. - 4. perf_event_open API is not supported on this system, e.g. WSL.
+ 4. perf_event_open API is not supported on this system, e.g. WSL. -
For permissions-related reasons (such as 1 and 2), using `--fdtransfer` while running the profiler +
For permissions-related reasons (such as 1 and 2), using `--fdtransfer` while running the profiler as a privileged user may solve the issue. If changing the configuration is not possible, you may fall back to