diff --git a/.gitignore b/.gitignore index 6fc74aa5e..f2e0a4d18 100644 --- a/.gitignore +++ b/.gitignore @@ -890,6 +890,7 @@ configure~ /memcheck/tests/deep_templates /memcheck/tests/demangle /memcheck/tests/demangle-rust +/memcheck/tests/demangle-swift /memcheck/tests/describe-block /memcheck/tests/descr_belowsp /memcheck/tests/dir diff --git a/auxprogs/update-demangler b/auxprogs/update-demangler index 9b62fffca..f19b02d9d 100755 --- a/auxprogs/update-demangler +++ b/auxprogs/update-demangler @@ -5,7 +5,7 @@ set -e #--------------------------------------------------------------------- # This quick and dirty script assists in updating the C++ demangler # machinery in coregrind/m_demangle. -# The script will check out +# The script will check out # - old and new revisions of the C++ demangler related files from GCC's trunk # - m_demangle from valgrind's trunk. # It will assemble @@ -63,6 +63,7 @@ cp ../gcc/libiberty/cplus-dem.c . cp ../gcc/libiberty/dyn-string.c . cp ../gcc/libiberty/d-demangle.c . cp ../gcc/libiberty/rust-demangle.c . +cp ../gcc/libiberty/swift-demangle.c . cp ../gcc/libiberty/safe-ctype.c . cd .. @@ -85,6 +86,7 @@ cp ../gcc/libiberty/cplus-dem.c . cp ../gcc/libiberty/dyn-string.c . cp ../gcc/libiberty/d-demangle.c . cp ../gcc/libiberty/rust-demangle.c . +cp ../gcc/libiberty/swift-demangle.c . cp ../gcc/libiberty/safe-ctype.c . cd .. diff --git a/coregrind/Makefile.am b/coregrind/Makefile.am index 14698153c..8494adcd9 100644 --- a/coregrind/Makefile.am +++ b/coregrind/Makefile.am @@ -398,6 +398,7 @@ COREGRIND_SOURCES_COMMON = \ m_demangle/dyn-string.c \ m_demangle/d-demangle.c \ m_demangle/rust-demangle.c \ + m_demangle/swift-demangle.c \ m_demangle/safe-ctype.c \ m_dispatch/dispatch-x86-linux.S \ m_dispatch/dispatch-amd64-linux.S \ diff --git a/coregrind/m_demangle/cplus-dem.c b/coregrind/m_demangle/cplus-dem.c index cbe697361..741394d83 100644 --- a/coregrind/m_demangle/cplus-dem.c +++ b/coregrind/m_demangle/cplus-dem.c @@ -128,7 +128,7 @@ const struct demangler_engine libiberty_demanglers[] = enum demangling_styles cplus_demangle_set_style (enum demangling_styles style) { - const struct demangler_engine *demangler = libiberty_demanglers; + const struct demangler_engine *demangler = libiberty_demanglers; for (; demangler->demangling_style != unknown_demangling; ++demangler) if (style == demangler->demangling_style) @@ -145,7 +145,7 @@ cplus_demangle_set_style (enum demangling_styles style) enum demangling_styles cplus_demangle_name_to_style (const char *name) { - const struct demangler_engine *demangler = libiberty_demanglers; + const struct demangler_engine *demangler = libiberty_demanglers; for (; demangler->demangling_style != unknown_demangling; ++demangler) if (strcmp (name, demangler->demangling_style_name) == 0) @@ -211,6 +211,13 @@ ML_(cplus_demangle) (const char *mangled, int options) return ret; } + if (SWIFT_DEMANGLING || AUTO_DEMANGLING) + { + ret = swift_demangle (mangled, options); + if (ret || SWIFT_DEMANGLING) + return ret; + } + return (ret); } @@ -223,7 +230,7 @@ ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED) const char* p; char *d; char *demangled = NULL; - + /* Discard leading _ada_, which is used for library level subprograms. */ if (strncmp (mangled, "_ada_", 5) == 0) mangled += 5; @@ -239,7 +246,7 @@ ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED) they occur only once. */ len0 = strlen (mangled) + 7 + 1; demangled = XNEWVEC (char, len0); - + d = demangled; p = mangled; while (1) diff --git a/coregrind/m_demangle/demangle.c b/coregrind/m_demangle/demangle.c index 25669598a..e86fe47bd 100644 --- a/coregrind/m_demangle/demangle.c +++ b/coregrind/m_demangle/demangle.c @@ -7,7 +7,7 @@ This file is part of Valgrind, a dynamic binary instrumentation framework. - Copyright (C) 2000-2017 Julian Seward + Copyright (C) 2000-2017 Julian Seward jseward@acm.org Rust demangler components are @@ -107,7 +107,7 @@ void VG_(demangle) ( Bool do_cxx_demangling, Bool do_z_demangling, /* OUT */ const HChar **result ) { /* Possibly undo (2) */ - /* Z-Demangling was requested. + /* Z-Demangling was requested. The fastest way to see if it's a Z-mangled name is just to attempt to Z-demangle it (with NULL for the soname buffer, since we're not interested in that). */ @@ -125,11 +125,25 @@ void VG_(demangle) ( Bool do_cxx_demangling, Bool do_z_demangling, // - Rust "legacy" mangled symbols start with "_Z". // - Rust "v0" mangled symbols start with "_R". // - D programming language mangled symbols start with "_D". + // - Swift starts with many symbols: + // "_T": legacy + // "_T0": Swift v4 + // "$S"/"_$S": Swift v4.x + // "$s"/"_$s": Swift v5 // XXX: the Java/Rust/Ada demangling here probably doesn't work. See // https://bugs.kde.org/show_bug.cgi?id=445235 for details. if (do_cxx_demangling && VG_(clo_demangle) - && orig != NULL && orig[0] == '_' - && (orig[1] == 'Z' || orig[1] == 'R' || orig[1] == 'D')) { + && orig != NULL + && ( + VG_(strstr)(orig, "_Z") == orig + || VG_(strstr)(orig, "_R") == orig + || VG_(strstr)(orig, "_D") == orig + || VG_(strstr)(orig, "_T") == orig + || VG_(strstr)(orig, "$S") == orig + || VG_(strstr)(orig, "$s") == orig + || VG_(strstr)(orig, "_$S") == orig + || VG_(strstr)(orig, "_$s") == orig + )) { /* !!! vvv STATIC vvv !!! */ static HChar* demangled = NULL; /* !!! ^^^ STATIC ^^^ !!! */ @@ -199,8 +213,8 @@ void VG_(demangle) ( Bool do_cxx_demangling, Bool do_z_demangling, /*--- DEMANGLE Z-ENCODED NAMES ---*/ /*------------------------------------------------------------*/ -/* Demangle a Z-encoded name as described in pub_tool_redir.h. - Z-encoded names are used by Valgrind for doing function +/* Demangle a Z-encoded name as described in pub_tool_redir.h. + Z-encoded names are used by Valgrind for doing function interception/wrapping. Demangle 'sym' into its soname and fnname parts, putting them in @@ -211,7 +225,7 @@ void VG_(demangle) ( Bool do_cxx_demangling, Bool do_z_demangling, 'so' as NULL is acceptable if the caller is only interested in the function name part. */ -Bool VG_(maybe_Z_demangle) ( const HChar* sym, +Bool VG_(maybe_Z_demangle) ( const HChar* sym, /*OUT*/const HChar** so, /*OUT*/const HChar** fn, /*OUT*/Bool* isWrap, @@ -235,7 +249,7 @@ Bool VG_(maybe_Z_demangle) ( const HChar* sym, } sobuf[0] = fnbuf[0] = '\0'; - if (so) + if (so) *so = sobuf; *fn = fnbuf; diff --git a/coregrind/m_demangle/demangle.h b/coregrind/m_demangle/demangle.h index a51815347..54d7cd991 100644 --- a/coregrind/m_demangle/demangle.h +++ b/coregrind/m_demangle/demangle.h @@ -59,21 +59,22 @@ extern "C" { #define DMGL_GNAT (1 << 15) #define DMGL_DLANG (1 << 16) #define DMGL_RUST (1 << 17) /* Rust wraps GNU_V3 style mangling. */ +#define DMGL_SWIFT (1 << 18) /* If none of these are set, use 'current_demangling_style' as the default. */ -#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU_V3|DMGL_JAVA|DMGL_GNAT|DMGL_DLANG|DMGL_RUST) +#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU_V3|DMGL_JAVA|DMGL_GNAT|DMGL_DLANG|DMGL_RUST|SWIFT_RUST) /* Disable a limit on the depth of recursion in mangled strings. Note if this limit is disabled then stack exhaustion is possible when demangling pathologically complicated strings. Bug reports about stack - exhaustion when the option is enabled will be rejected. */ -#define DMGL_NO_RECURSE_LIMIT (1 << 18) + exhaustion when the option is enabled will be rejected. */ +#define DMGL_NO_RECURSE_LIMIT (1 << 18) /* If DMGL_NO_RECURSE_LIMIT is not enabled, then this is the value used as the maximum depth of recursion allowed. It should be enough for any real-world mangled name. */ #define DEMANGLE_RECURSION_LIMIT 2048 - + /* Enumeration of possible demangling styles. Lucid and ARM styles are still kept logically distinct, even though @@ -91,7 +92,8 @@ extern enum demangling_styles java_demangling = DMGL_JAVA, gnat_demangling = DMGL_GNAT, dlang_demangling = DMGL_DLANG, - rust_demangling = DMGL_RUST + rust_demangling = DMGL_RUST, + swift_demangling = DMGL_SWIFT } current_demangling_style; /* Define string names for the various demangling styles. */ @@ -103,6 +105,7 @@ extern enum demangling_styles #define GNAT_DEMANGLING_STYLE_STRING "gnat" #define DLANG_DEMANGLING_STYLE_STRING "dlang" #define RUST_DEMANGLING_STYLE_STRING "rust" +#define SWIFT_DEMANGLING_STYLE_STRING "swift" /* Some macros to test what demangling style is active. */ @@ -113,6 +116,7 @@ extern enum demangling_styles #define GNAT_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNAT) #define DLANG_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_DLANG) #define RUST_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_RUST) +#define SWIFT_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_SWIFT) /* Provide information about the available demangle styles. This code is pulled from gdb into libiberty because it is useful to binutils also. */ @@ -169,6 +173,9 @@ rust_demangle_callback (const char *mangled, int options, extern char * rust_demangle (const char *mangled, int options); +extern char * +swift_demangle (const char *mangled, int options); + enum gnu_v3_ctor_kinds { gnu_v3_complete_object_ctor = 1, gnu_v3_base_object_ctor, diff --git a/coregrind/m_demangle/swift-demangle.c b/coregrind/m_demangle/swift-demangle.c new file mode 100644 index 000000000..ffb96e447 --- /dev/null +++ b/coregrind/m_demangle/swift-demangle.c @@ -0,0 +1,56 @@ +/*--------------------------------------------------------------------*/ +/*--- Swift demangler ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (c) 2024-2024 Louis Brunner + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . + + The GNU General Public License is contained in the file COPYING. +*/ + +#include "vg_libciface.h" + +#include "ansidecl.h" +#include "demangle.h" +#include "safe-ctype.h" + +char* swift_demangle (const char *mangled, int options) +{ + UInt prefix_length = 0; + Bool legacy = False; + + if (VG_(strstr)(mangled, "_T0") == mangled || VG_(strstr)(mangled, "_$S") == mangled || VG_(strstr)(mangled, "_$s") == mangled) { + prefix_length = 3; + } + if (VG_(strstr)(mangled, "_T") == mangled) { + prefix_length = 2; + legacy = True; + } + if (VG_(strstr)(mangled, "$S") == mangled || VG_(strstr)(mangled, "$s") == mangled) { + prefix_length = 2; + } + + if (prefix_length == 0) { + return NULL; + } + + mangled += prefix_length; + + return NULL; +} diff --git a/memcheck/tests/Makefile.am b/memcheck/tests/Makefile.am index 2998c99c7..8cb5d5c77 100644 --- a/memcheck/tests/Makefile.am +++ b/memcheck/tests/Makefile.am @@ -372,6 +372,7 @@ EXTRA_DIST = \ recursive-merge.stderr.exp recursive-merge.vgtest \ resvn_stack.stderr.exp resvn_stack.vgtest \ demangle-rust.vgtest demangle-rust.stderr.exp \ + demangle-swift.vgtest demangle-swift.stderr.exp \ sbfragment.stdout.exp sbfragment.stderr.exp sbfragment.vgtest \ sem.stderr.exp sem.vgtest \ sendmsg.stderr.exp sendmsg.stderr.exp-solaris sendmsg.vgtest \ @@ -489,6 +490,7 @@ check_PROGRAMS = \ custom-overlap \ demangle \ demangle-rust \ + demangle-swift \ big_debuginfo_symbol \ deep-backtrace \ describe-block \ @@ -698,6 +700,8 @@ endif demangle_SOURCES = demangle.cpp demangle_rust_SOURCES = demangle-rust.c demangle_rust_CFLAGS = $(AM_CFLAGS) @FLAG_W_NO_USE_AFTER_FREE@ +demangle_swift_SOURCES = demangle-swift.c +demangle_swift_CFLAGS = $(AM_CFLAGS) @FLAG_W_NO_USE_AFTER_FREE@ dw4_CFLAGS = $(AM_CFLAGS) -gdwarf-4 -fdebug-types-section descr_belowsp_LDADD = -lpthread diff --git a/memcheck/tests/demangle-swift.c b/memcheck/tests/demangle-swift.c new file mode 100644 index 000000000..9c0c8d4ed --- /dev/null +++ b/memcheck/tests/demangle-swift.c @@ -0,0 +1,40 @@ +// Same principle as demangle-rust.c, but for Swift symbols. + +#include + +int $sSo13NSFileManagerC10FoundationE28withFileSystemRepresentation3for_xSS_xSPys4Int8VGSgKXEtKlFSDySo0A12AttributeKeyaypG_Tg5(int *p) +{ + free(p); + free(p); + return 1; +} + +int $ss26_SwiftDeferredNSDictionaryC12bridgeValuess20__BridgingHashBufferCSgyF(int* p) +{ + return $sSo13NSFileManagerC10FoundationE28withFileSystemRepresentation3for_xSS_xSPys4Int8VGSgKXEtKlFSDySo0A12AttributeKeyaypG_Tg5(p); +} + +int $sSS7cStringSSSPys4Int8VG_tcfC(int* p) +{ + return $ss26_SwiftDeferredNSDictionaryC12bridgeValuess20__BridgingHashBufferCSgyF(p); +} + +int $s10Foundation16_FileManagerImplV16attributesOfItem6atPathSDySo18NSFileAttributeKeyaypGSS_tKFAHSPys4Int8VGSgKXEfU_TA(size_t s) +{ + return $sSS7cStringSSSPys4Int8VG_tcfC(malloc(s)); +} + +int _TtBv4Bf16_(void) +{ + return $s10Foundation16_FileManagerImplV16attributesOfItem6atPathSDySo18NSFileAttributeKeyaypGSS_tKFAHSPys4Int8VGSgKXEfU_TA(sizeof(int)); +} + +int $ss6SimpleHr(void) +{ + return _TtBv4Bf16_(); +} + +int main(void) +{ + return $ss6SimpleHr(); +} diff --git a/memcheck/tests/demangle-swift.stderr.exp b/memcheck/tests/demangle-swift.stderr.exp new file mode 100644 index 000000000..6579f0842 --- /dev/null +++ b/memcheck/tests/demangle-swift.stderr.exp @@ -0,0 +1,16 @@ +Invalid free() / delete / delete[] / realloc() + at 0x........: free (vg_replace_malloc.c:...) + by 0x........: ::fold_with:: (demangle-rust.c:13) + by 0x........: rustc_expand::mbe::macro_parser::parse_tt (demangle-rust.c:20) + by 0x........: core::str::lossy::Utf8Lossy::from_bytes (demangle-rust.c:26) + by 0x........: main (demangle-rust.c:31) + Address 0x........ is 0 bytes inside a block of size 4 free'd + at 0x........: free (vg_replace_malloc.c:...) + by 0x........: ::fold_with:: (demangle-rust.c:12) + by 0x........: rustc_expand::mbe::macro_parser::parse_tt (demangle-rust.c:20) + by 0x........: core::str::lossy::Utf8Lossy::from_bytes (demangle-rust.c:26) + by 0x........: main (demangle-rust.c:31) + Block was alloc'd at + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (demangle-rust.c:31) + diff --git a/memcheck/tests/demangle-swift.vgtest b/memcheck/tests/demangle-swift.vgtest new file mode 100644 index 000000000..c62c44116 --- /dev/null +++ b/memcheck/tests/demangle-swift.vgtest @@ -0,0 +1,2 @@ +prog: demangle-swift +vgopts: -q