1 /*
   2  * Copyright (c) 2014 Alex Crichton
   3  *
   4  * Permission is hereby granted, free of charge, to any
   5  * person obtaining a copy of this software and associated
   6  * documentation files (the "Software"), to deal in the
   7  * Software without restriction, including without
   8  * limitation the rights to use, copy, modify, merge,
   9  * publish, distribute, sublicense, and/or sell copies of
  10  * the Software, and to permit persons to whom the Software
  11  * is furnished to do so, subject to the following
  12  * conditions:
  13  *
  14  * The above copyright notice and this permission notice
  15  * shall be included in all copies or substantial portions
  16  * of the Software.
  17  *
  18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
  19  * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  20  * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  21  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
  22  * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  23  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  24  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
  25  * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  26  * DEALINGS IN THE SOFTWARE.
  27  */
  28 /*
  29  * Copyright 2019, Joyent, Inc.
  30  */
  31 
  32 /*
  33  * Test cases taken from rustc-demangle 0.1.9
  34  */
  35 #include <errno.h>
  36 #include <stdio.h>
  37 #include <stdlib.h>
  38 #include <string.h>
  39 #include <sys/sysmacros.h>
  40 #include <demangle-sys.h>
  41 
  42 typedef struct rust_test_case {
  43         const char *mangled;
  44         const char *demangled;
  45 } rust_test_case_t;
  46 #define T(_m, _d) { .mangled = _m, .demangled = _d }
  47 #define T_ERR(_m) { .mangled = _m }
  48 
  49 typedef struct rust_test_grp {
  50         const char              *name;
  51         rust_test_case_t        tests[];
  52 } rust_test_grp_t;
  53 #define GROUP(_n, ...)                  \
  54         static rust_test_grp_t _n = {   \
  55                 .name = #_n,            \
  56                 .tests = {              \
  57                         __VA_ARGS__,    \
  58                         { NULL, NULL }  \
  59                 }                       \
  60         }
  61 
  62 GROUP(demangle,
  63     T_ERR("test"),
  64     T("_ZN4testE", "test"),
  65     T_ERR("_ZN4test"),
  66     T("_ZN4test1a2bcE", "test::a::bc"));
  67 
  68 GROUP(demangle_dollars,
  69     T("_ZN4$RP$E", ")"),
  70     T("_ZN8$RF$testE", "&test"),
  71     T("_ZN8$BP$test4foobE", "*test::foob"),
  72     T("_ZN9$u20$test4foobE", " test::foob"),
  73     T("_ZN35Bar$LT$$u5b$u32$u3b$$u20$4$u5d$$GT$E", "Bar<[u32; 4]>"));
  74 
  75 GROUP(demangle_many_dollars,
  76     T("_ZN13test$u20$test4foobE", "test test::foob"),
  77     T("_ZN12test$BP$test4foobE", "test*test::foob"));
  78 
  79 /* BEGIN CSTYLED */
  80 GROUP(demangle_osx,
  81     T("__ZN5alloc9allocator6Layout9for_value17h02a996811f781011E",
  82     "alloc::allocator::Layout::for_value::h02a996811f781011"),
  83     T("__ZN38_$LT$core..option..Option$LT$T$GT$$GT$6unwrap18_MSG_FILE_LINE_COL17haf7cb8d5824ee659E",
  84     "<core::option::Option<T>>::unwrap::_MSG_FILE_LINE_COL::haf7cb8d5824ee659"),
  85     T("__ZN4core5slice89_$LT$impl$u20$core..iter..traits..IntoIterator$u20$for$u20$$RF$$u27$a$u20$$u5b$T$u5d$$GT$9into_iter17h450e234d27262170E",
  86     "core::slice::<impl core::iter::traits::IntoIterator for &'a [T]>::into_iter::h450e234d27262170"));
  87 /* END CSTYLED */
  88 
  89 GROUP(demangle_elements_beginning_with_underscore,
  90     T("_ZN13_$LT$test$GT$E", "<test>"),
  91     T("_ZN28_$u7b$$u7b$closure$u7d$$u7d$E", "{{closure}}"),
  92     T("_ZN15__STATIC_FMTSTRE", "__STATIC_FMTSTR"));
  93 
  94 /* BEGIN CSTYLED */
  95 GROUP(demangle_trait_impls,
  96     T("_ZN71_$LT$Test$u20$$u2b$$u20$$u27$static$u20$as$u20$foo..Bar$LT$Test$GT$$GT$3barE",
  97     "<Test + 'static as foo::Bar<Test>>::bar"));
  98 /* END CSTYLED */
  99 
 100 GROUP(invalid_no_chop, T_ERR("_ZNfooE"));
 101 
 102 /* BEGIN CSTYLED */
 103 GROUP(handle_assoc_types,
 104     T("_ZN151_$LT$alloc..boxed..Box$LT$alloc..boxed..FnBox$LT$A$C$$u20$Output$u3d$R$GT$$u20$$u2b$$u20$$u27$a$GT$$u20$as$u20$core..ops..function..FnOnce$LT$A$GT$$GT$9call_once17h69e8f44b3723e1caE",
 105     "<alloc::boxed::Box<alloc::boxed::FnBox<A, Output=R> + 'a> as core::ops::function::FnOnce<A>>::call_once::h69e8f44b3723e1ca"));
 106 /* END CSTYLED */
 107 
 108 static rust_test_grp_t *rust_tests[] = {
 109         &demangle,
 110         &demangle_dollars,
 111         &demangle_many_dollars,
 112         &demangle_osx,
 113         &demangle_elements_beginning_with_underscore,
 114         &demangle_trait_impls,
 115         &invalid_no_chop,
 116         &handle_assoc_types
 117 };
 118 
 119 static const size_t n_rust_tests = ARRAY_SIZE(rust_tests);
 120 
 121 static boolean_t
 122 check_failure(size_t i, rust_test_case_t *tc, const char *dem, boolean_t res)
 123 {
 124         int savederr = errno;
 125 
 126         if (dem == NULL && savederr == EINVAL)
 127                 return (B_TRUE);
 128 
 129         if (res)
 130                 (void) printf("FAILURE\n");
 131 
 132         if (dem != NULL) {
 133                 (void) printf("  [%zu] Successfully demanged an invalid "
 134                     "name\n", i);
 135                 (void) printf("         Name: '%s'\n", tc->mangled);
 136                 (void) printf("    Demangled: '%s'\n", dem);
 137                 return (B_FALSE);
 138         }
 139 
 140         (void) printf("  [%zu] demangle() returned an unexpected error\n", i);
 141         (void) printf("    Errno: %d\n", savederr);
 142         return (B_FALSE);
 143 }
 144 
 145 static boolean_t
 146 check_success(size_t i, rust_test_case_t *tc, const char *dem, boolean_t res)
 147 {
 148         if (dem != NULL && strcmp(tc->demangled, dem) == 0)
 149                 return (B_TRUE);
 150 
 151         if (res)
 152                 (void) printf("FAILURE\n");
 153 
 154         if (dem == NULL) {
 155                 (void) printf("  [%zu] Failed to demangle '%s'\n", i,
 156                     tc->mangled);
 157                 return (B_FALSE);
 158         }
 159 
 160         (void) printf("  [%zu] Demangled results do not match.\n", i);
 161         (void) printf("       Mangled: %s\n", tc->mangled);
 162         (void) printf("      Expected: %s\n", tc->demangled);
 163         (void) printf("        Actual: %s\n", dem);
 164         return (B_FALSE);
 165 }
 166 
 167 static boolean_t
 168 run_test(rust_test_grp_t *test)
 169 {
 170         boolean_t res = B_TRUE;
 171 
 172         (void) printf("Test %s: ", test->name);
 173 
 174         for (size_t i = 0; test->tests[i].mangled != NULL; i++) {
 175                 char *dem;
 176 
 177                 dem = sysdemangle(test->tests[i].mangled, SYSDEM_LANG_RUST,
 178                     NULL);
 179                 if (test->tests[i].demangled == NULL)
 180                         res &= check_failure(i, &test->tests[i], dem, res);
 181                 else
 182                         res &= check_success(i, &test->tests[i], dem, res);
 183 
 184                 free(dem);
 185         }
 186 
 187         if (res)
 188                 (void) printf("SUCCESS\n");
 189 
 190         return (res);
 191 }
 192 
 193 int
 194 main(int argc, char **argv)
 195 {
 196         boolean_t ok = B_TRUE;
 197 
 198         for (size_t i = 0; i < n_rust_tests; i++)
 199                 ok &= run_test(rust_tests[i]);
 200 
 201         return (ok ? 0 : 1);
 202 }
 203 
 204 const char *
 205 _umem_debug_init(void)
 206 {
 207         return ("default,verbose");
 208 }
 209 
 210 const char *
 211 _umem_logging_init(void)
 212 {
 213         return ("fail,contents");
 214 }