1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
|
/*
* This file and its contents are supplied under the terms of the
* Common Development and Distribution License ("CDDL"), version 1.0.
* You may only use this file in accordance with the terms of version
* 1.0 of the CDDL.
*
* A full copy of the text of the CDDL should have accompanied this
* source. A copy of the CDDL is also available via the Internet at
* http://www.illumos.org/license/CDDL.
*/
/*
* Copyright 2020 Joyent, Inc.
*/
#include <ctype.h>
#include <demangle-sys.h>
#include <err.h>
#include <errno.h>
#include <libcustr.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#define _(x) gettext(x)
locale_t c_locale;
static int do_symbols(sysdem_lang_t, int, char * const *);
static int do_input(sysdem_lang_t, FILE *restrict, FILE *restrict);
static int do_demangle(const char *, sysdem_lang_t, FILE *);
static void appendc(custr_t *, char);
static void xputc(int, FILE *);
static void
usage(void)
{
(void) fprintf(stderr, _("Usage: %s [-l lang] [sym...]\n"),
getprogname());
exit(2);
}
int
main(int argc, char * const *argv)
{
sysdem_lang_t lang = SYSDEM_LANG_AUTO;
int c;
int ret;
(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
/*
* For detecting symbol boundaries, we want to use the C locale
* definitions for use in isalnum_l().
*/
if ((c_locale = newlocale(LC_CTYPE_MASK, "C", NULL)) == NULL)
err(EXIT_FAILURE, _("failed to construct C locale"));
while ((c = getopt(argc, argv, "hl:")) != -1) {
switch (c) {
case 'l':
if (sysdem_parse_lang(optarg, &lang))
break;
errx(EXIT_FAILURE, _("Unsupported language '%s'\n"),
optarg);
case 'h':
case '?':
usage();
}
}
argc -= optind;
argv += optind;
if (argc > 0)
ret = do_symbols(lang, argc, argv);
else
ret = do_input(lang, stdin, stdout);
return ((ret < 0) ? EXIT_FAILURE : EXIT_SUCCESS);
}
static int
do_symbols(sysdem_lang_t lang, int argc, char * const *argv)
{
int ret = 0;
for (int i = 0; i < argc; i++) {
if (do_demangle(argv[i], lang, stdout) < 0)
ret = -1;
else
xputc('\n', stdout);
}
return (ret);
}
static int
do_input(sysdem_lang_t lang, FILE *restrict in, FILE *restrict out)
{
custr_t *word = NULL;
int c;
int ret = 0;
boolean_t in_symbol = B_FALSE;
if (custr_alloc(&word) != 0)
err(EXIT_FAILURE, _("failed to allocate memory"));
while ((c = fgetc(in)) != EOF) {
if (in_symbol) {
/*
* All currently supported mangling formats only use
* alphanumeric characters, '.', '_', or '$' in
* mangled names. Once we've seen the potential start
* of a symbol ('_'), we accumulate subsequent
* charaters into 'word'. If we encounter a character
* that is not a part of that set ([A-Za-z0-9._$]), we
* treat it as a delimiter, we stop accumulating
* characters into word, and we attempt to demangle the
* accumulated string in 'word' by calling
* demangle_custr().
*
* Similar utilities like c++filt behave in a similar
* fashion when reading from stdin to allow for
* demangling of symbols embedded in surrounding text.
*/
if (isalnum_l(c, c_locale) || c == '.' || c == '_' ||
c == '$') {
appendc(word, c);
continue;
}
/*
* Hit a symbol boundary, attempt to demangle what
* we've accumulated in word and reset word.
*/
if (do_demangle(custr_cstr(word), lang, out) < 0)
ret = -1;
custr_reset(word);
in_symbol = B_FALSE;
}
if (c != '_') {
xputc(c, out);
} else {
in_symbol = B_TRUE;
appendc(word, c);
}
}
if (ferror(in))
err(EXIT_FAILURE, _("error reading input"));
/*
* If we were accumulating characters for a symbol and hit EOF,
* attempt to demangle what we accumulated.
*/
if (custr_len(word) > 0 && do_demangle(custr_cstr(word), lang, out) < 0)
ret = -1;
custr_free(word);
return (ret);
}
/*
* Attempt to demangle 'sym' as a symbol for 'lang' and write the result
* to 'out'. If 'sym' could not be demangled as 'lang' symbol, the original
* string is output instead.
*
* If an error other than 'not a mangled symbol' is encountered (e.g. ENOMEM),
* a warning is sent to stderr and -1 is returned. Otherwise, 0 is returned
* (including when 'sym' is merely not a mangled symbol of 'lang').
*/
static int
do_demangle(const char *sym, sysdem_lang_t lang, FILE *out)
{
char *demangled = sysdemangle(sym, lang, NULL);
if (demangled == NULL && errno != EINVAL && errno != ENOTSUP) {
warn(_("error while demangling '%s'"), sym);
return (-1);
}
if (fprintf(out, "%s", (demangled != NULL) ? demangled : sym) < 0)
err(EXIT_FAILURE, _("failed to write to output"));
free(demangled);
return (0);
}
static void
appendc(custr_t *cus, char c)
{
if (custr_appendc(cus, c) == 0)
return;
err(EXIT_FAILURE, _("failed to save character from input"));
}
static void
xputc(int c, FILE *out)
{
if (fputc(c, out) < 0)
err(EXIT_FAILURE, _("failed to write output"));
}
|