Print this page
12310 Add demangle(1) command
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libdemangle/common/demangle.c
+++ new/usr/src/lib/libdemangle/common/demangle.c
1 1 /*
2 2 * This file and its contents are supplied under the terms of the
3 3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 4 * You may only use this file in accordance with the terms of version
5 5 * 1.0 of the CDDL.
6 6 *
7 7 * A full copy of the text of the CDDL should have accompanied this
8 8 * source. A copy of the CDDL is also available via the Internet at
9 9 * http://www.illumos.org/license/CDDL.
10 10 */
11 11
12 12 /*
13 13 * Copyright 2018 Jason King
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
14 14 * Copyright 2019, Joyent, Inc.
15 15 */
16 16
17 17 #include <stdlib.h>
18 18 #include <stdio.h>
19 19 #include <string.h>
20 20 #include <errno.h>
21 21 #include <pthread.h>
22 22 #include <sys/ctype.h>
23 23 #include <sys/debug.h>
24 +#include <sys/sysmacros.h>
24 25 #include <stdarg.h>
25 26 #include "demangle-sys.h"
26 27 #include "demangle_int.h"
27 28
28 29 #define DEMANGLE_DEBUG "DEMANGLE_DEBUG"
29 30
30 31 static pthread_once_t debug_once = PTHREAD_ONCE_INIT;
31 32 volatile boolean_t demangle_debug;
32 33 FILE *debugf = stderr;
33 34
35 +static struct {
36 + const char *str;
37 + sysdem_lang_t lang;
38 +} lang_tbl[] = {
39 + { "auto", SYSDEM_LANG_AUTO },
40 + { "c++", SYSDEM_LANG_CPP },
41 + { "rust", SYSDEM_LANG_RUST },
42 +};
43 +
34 44 static const char *
35 45 langstr(sysdem_lang_t lang)
36 46 {
37 - switch (lang) {
38 - case SYSDEM_LANG_AUTO:
39 - return ("auto");
40 - case SYSDEM_LANG_CPP:
41 - return ("c++");
42 - case SYSDEM_LANG_RUST:
43 - return ("rust");
44 - default:
45 - return ("invalid");
47 + size_t i;
48 +
49 + for (i = 0; i < ARRAY_SIZE(lang_tbl); i++) {
50 + if (lang == lang_tbl[i].lang)
51 + return (lang_tbl[i].str);
46 52 }
53 + return ("invalid");
47 54 }
48 55
56 +boolean_t
57 +sysdem_parse_lang(const char *str, sysdem_lang_t *langp)
58 +{
59 + size_t i;
60 +
61 + for (i = 0; i < ARRAY_SIZE(lang_tbl); i++) {
62 + if (strcmp(str, lang_tbl[i].str) == 0) {
63 + *langp = lang_tbl[i].lang;
64 + return (B_TRUE);
65 + }
66 + }
67 +
68 + return (B_FALSE);
69 +}
70 +
49 71 static sysdem_lang_t
50 72 detect_lang(const char *str, size_t n)
51 73 {
52 74 const char *p = str;
53 75 size_t len;
54 76
55 77 if (n < 3 || str[0] != '_')
56 78 return (SYSDEM_LANG_AUTO);
57 79
58 80 /*
59 81 * Check for ^_Z or ^__Z
60 82 */
61 83 p = str + 1;
62 84 if (*p == '_') {
63 85 p++;
64 86 }
65 87
66 88 if (*p != 'Z')
67 89 return (SYSDEM_LANG_AUTO);
68 90
69 91 /*
70 92 * Sadly, rust currently uses the same prefix as C++, however
71 93 * demangling rust as a C++ mangled name yields less than desirable
72 94 * results. However rust names end with a hash. We use that to
73 95 * attempt to disambiguate
74 96 */
75 97
76 98 /* Find 'h'<hexdigit>+E$ */
77 99 if ((p = strrchr(p, 'h')) == NULL)
78 100 return (SYSDEM_LANG_CPP);
79 101
80 102 if ((len = strspn(p + 1, "0123456789abcdef")) == 0)
81 103 return (SYSDEM_LANG_CPP);
82 104
83 105 p += len + 1;
84 106
85 107 if (p[0] != 'E' || p[1] != '\0')
86 108 return (SYSDEM_LANG_CPP);
87 109
88 110 return (SYSDEM_LANG_RUST);
89 111 }
90 112
91 113 static void
92 114 check_debug(void)
93 115 {
94 116 if (getenv(DEMANGLE_DEBUG))
95 117 demangle_debug = B_TRUE;
96 118 }
97 119
98 120 char *
99 121 sysdemangle(const char *str, sysdem_lang_t lang, sysdem_ops_t *ops)
100 122 {
101 123 /*
102 124 * While the language specific demangler code can handle non-NUL
103 125 * terminated strings, we currently don't expose this to consumers.
104 126 * Consumers should still pass in a NUL-terminated string.
105 127 */
106 128 size_t slen;
107 129
108 130 VERIFY0(pthread_once(&debug_once, check_debug));
109 131
110 132 DEMDEBUG("name = '%s'", (str == NULL) ? "(NULL)" : str);
111 133 DEMDEBUG("lang = %s (%d)", langstr(lang), lang);
112 134
113 135 if (str == NULL) {
114 136 errno = EINVAL;
115 137 return (NULL);
116 138 }
117 139
118 140 slen = strlen(str);
119 141
120 142 switch (lang) {
121 143 case SYSDEM_LANG_AUTO:
122 144 case SYSDEM_LANG_CPP:
123 145 case SYSDEM_LANG_RUST:
124 146 break;
125 147 default:
126 148 errno = EINVAL;
127 149 return (NULL);
128 150 }
129 151
130 152 if (ops == NULL)
131 153 ops = sysdem_ops_default;
132 154
133 155 if (lang == SYSDEM_LANG_AUTO) {
134 156 lang = detect_lang(str, slen);
135 157 if (lang != SYSDEM_LANG_AUTO)
136 158 DEMDEBUG("detected language is %s", langstr(lang));
137 159 }
138 160
139 161 switch (lang) {
140 162 case SYSDEM_LANG_CPP:
141 163 return (cpp_demangle(str, slen, ops));
142 164 case SYSDEM_LANG_RUST:
143 165 return (rust_demangle(str, slen, ops));
144 166 case SYSDEM_LANG_AUTO:
145 167 DEMDEBUG("could not detect language");
146 168 errno = ENOTSUP;
147 169 return (NULL);
148 170 default:
149 171 /*
150 172 * This can't happen unless there's a bug with detect_lang,
151 173 * but gcc doesn't know that.
152 174 */
153 175 errno = EINVAL;
154 176 return (NULL);
155 177 }
156 178 }
157 179
158 180 int
159 181 demdebug(const char *fmt, ...)
160 182 {
161 183 va_list ap;
162 184
163 185 flockfile(debugf);
164 186 (void) fprintf(debugf, "LIBDEMANGLE: ");
165 187 va_start(ap, fmt);
166 188 (void) vfprintf(debugf, fmt, ap);
167 189 (void) fputc('\n', debugf);
168 190 (void) fflush(debugf);
169 191 va_end(ap);
170 192 funlockfile(debugf);
171 193
172 194 return (0);
173 195 }
↓ open down ↓ |
115 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX