* Copyright 2018, Haiku, Inc. All rights reserved.
* Based on Demumble; Copyright 2016-2018, Nico Weber.
* https://github.com/nico/demumble/
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include "Demangler.h"
static void print_help(FILE* out)
{
fprintf(out,
"usage: haikuc++filt [options] [symbols...]\n"
"\n"
"if symbols are unspecified, reads from stdin.\n"
"\n"
"options:\n"
" -m only print mangled names that were demangled,"
"omit other output\n"
" -u use unbuffered output\n"
" --no-gcc2 ignore GCC 2-style symbols\n");
}
static bool starts_with(const char* s, const char* prefix)
{
return strncmp(s, prefix, strlen(prefix)) == 0;
}
static void print_demangled(const char* s)
{
const char* cxa_in = s;
if (starts_with(s, "__Z") || starts_with(s, "____Z"))
cxa_in += 1;
printf("%s", Demangler::Demangle(cxa_in).String());
}
static bool is_mangle_char_posix(char c)
{
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9') || c == '_';
}
static bool look_for_itanium_prefix(char** str, char* end)
{
char* s = *str;
s += strcspn(s, "_?");
if (s == end)
return false;
const int N = 5;
char prefix[N + 1];
strncpy(prefix, s, N);
prefix[N] = '\0';
if (strstr(prefix, "_Z")) {
*str = s;
return true;
}
return false;
}
static bool look_for_gcc2_symbol(char** str, char* end)
{
char* s = *str;
size_t pos = (end - s) - 1;
char* mangled = NULL;
while (pos > 1) {
if (s[pos] == '_') {
if (s[pos - 1] == '_') {
mangled = s + pos + 1;
break;
} else
pos--;
}
pos--;
}
while (mangled != NULL && mangled > (s + 1)
&& is_mangle_char_posix(mangled[-1])) {
mangled--;
}
if (mangled != NULL)
*str = mangled;
return mangled != NULL;
}
static char buf[8192];
int main(int argc, char* argv[])
{
enum { kPrintAll, kPrintMatching } print_mode = kPrintAll;
bool noGCC2 = false;
while (argc > 1 && argv[1][0] == '-') {
if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) {
print_help(stdout);
return 0;
} else if (strcmp(argv[1], "-m") == 0) {
print_mode = kPrintMatching;
} else if (strcmp(argv[1], "--no-gcc2") == 0) {
noGCC2 = true;
} else if (strcmp(argv[1], "-u") == 0) {
setbuf(stdout, NULL);
} else if (strcmp(argv[1], "--") == 0) {
--argc;
++argv;
break;
} else {
fprintf(stderr, "c++filt: unrecognized option `%s'\n", argv[1]);
print_help(stderr);
return 1;
}
--argc;
++argv;
}
for (int i = 1; i < argc; ++i) {
print_demangled(argv[i]);
printf("\n");
}
if (argc != 1)
return 0;
while (fgets(buf, sizeof(buf), stdin)) {
bool need_separator = false;
char* cur = buf;
char* end = cur + strlen(cur);
while (cur != end) {
if (print_mode == kPrintMatching && need_separator)
printf("\n");
need_separator = false;
size_t n_sym = 0;
char* real_cur = cur;
if (look_for_itanium_prefix(&real_cur, end) ||
(!noGCC2 && look_for_gcc2_symbol(&real_cur, end))) {
if (print_mode == kPrintAll)
printf("%.*s", static_cast<int>(real_cur - cur), cur);
cur = real_cur;
while (cur + n_sym != end && is_mangle_char_posix(cur[n_sym]))
++n_sym;
} else {
printf("%s", cur);
cur = end;
continue;
}
if (n_sym == 0) {
++cur;
continue;
}
char tmp = cur[n_sym];
cur[n_sym] = '\0';
print_demangled(cur);
need_separator = true;
cur[n_sym] = tmp;
cur += n_sym;
}
}
}