diff --git a/src/tests/add-ons/kernel/debugger/Jamfile b/src/tests/add-ons/kernel/debugger/Jamfile index 55fb43dd9c..203b02773e 100644 --- a/src/tests/add-ons/kernel/debugger/Jamfile +++ b/src/tests/add-ons/kernel/debugger/Jamfile @@ -11,3 +11,8 @@ UnitTestLib libkerneldebuggertest.so : be [ TargetLibstdc++ ] [ TargetLibsupc++ ] ; +SimpleTest haikuc++filt : + c++filt.cpp + : Debugger_demangler.o + be [ TargetLibstdc++ ] [ TargetLibsupc++ ] + ; diff --git a/src/tests/add-ons/kernel/debugger/c++filt.cpp b/src/tests/add-ons/kernel/debugger/c++filt.cpp new file mode 100644 index 0000000000..fd5671f461 --- /dev/null +++ b/src/tests/add-ons/kernel/debugger/c++filt.cpp @@ -0,0 +1,197 @@ +/* + * 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 +#include +#include +#include +#include + +#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; + + // Itanium symbols start with 1-4 underscores followed by Z. + // strnstr() is BSD, so use a small local buffer and strstr(). + const int N = 5; // == strlen("____Z") + 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) +{ + // search '__' starting from the end, don't accept them at the start + 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--; + } + + // if we've found a symbol, go backwards to its beginning + 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; + // Read stdin instead. + // By default, don't demangle types. Mangled function names are unlikely + // to appear in text for since they start with _Z (or ___Z) or ?? / ?$ / ?@. + // But type manglings can be regular words ("Pi" is "int*"). + // (For command-line args, do try to demangle types though.) + 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; + + // Check if we have a symbol, and then for how long it is. + 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))) { + // Print all the stuff before the symbol. + if (print_mode == kPrintAll) + printf("%.*s", static_cast(real_cur - cur), cur); + cur = real_cur; + while (cur + n_sym != end && is_mangle_char_posix(cur[n_sym])) + ++n_sym; + } else { + // No symbols found in this block; skip it. + 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; + } + } +} diff --git a/src/tests/add-ons/kernel/debugger/gcc2_demangle_test.cpp b/src/tests/add-ons/kernel/debugger/gcc2_demangle_test.cpp deleted file mode 100644 index fc6c5f36bd..0000000000 --- a/src/tests/add-ons/kernel/debugger/gcc2_demangle_test.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. - * This file may be used under the terms of the MIT License. - */ - - -#define kprintf printf - -#include "gcc2.cpp" - - -int -main(int argc, char** argv) -{ - for (int i = 1; i < argc; i++) { - bool isObjectMethod; - char name[64]; - const char* symbol = demangle_symbol_gcc2(argv[i], name, sizeof(name), - &isObjectMethod); - if (symbol == NULL) { - printf("%s: cannot be parsed\n", argv[i]); - continue; - } - - printf("%s (%s method)\n", symbol, isObjectMethod ? "object" : "class"); - - uint32 cookie = 0; - int32 type; - size_t length; - while (get_next_argument_gcc2(&cookie, argv[i], name, sizeof(name), - &type, &length) == B_OK) { - printf("name \"%s\", type %.4s, length %lu\n", name, (char*)&type, - length); - } - } - - return 0; -}