Skip to content

Commit

Permalink
v1.2.3
Browse files Browse the repository at this point in the history
  • Loading branch information
nico committed Aug 7, 2023
2 parents eaf1699 + 3ade67e commit c874601
Show file tree
Hide file tree
Showing 24 changed files with 5,524 additions and 2,874 deletions.
31 changes: 31 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Build and test

on: [push, pull_request]

jobs:
build:
runs-on: ${{ matrix.os }}

strategy:
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]

steps:
- uses: actions/checkout@v3

- name: Set up Ninja
uses: ashutoshvarma/[email protected]

- uses: ilammy/[email protected]

- name: CMake
run: |
cmake -GNinja .
- name: Build
run: |
ninja
- name: Test
run: |
python3 demumble_test.py
18 changes: 18 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.*.sw?

# dist.py outputs:
buildlinux/
buildmac/
buildwin/
demumble-linux.zip
demumble-mac.zip
demumble-win.zip

# build outputs when building as described in README.md:
.ninja_deps
.ninja_log
CMakeCache.txt
CMakeFiles/
build.ninja
cmake_install.cmake
demumble
15 changes: 13 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.2.0 FATAL_ERROR)
cmake_minimum_required(VERSION 3.5.0 FATAL_ERROR)
project(demumble CXX)

if (UNIX)
Expand All @@ -19,9 +19,17 @@ if (UNIX)
endif()

if (WIN32)
# https://gitlab.kitware.com/cmake/cmake/-/issues/20610
string(REGEX REPLACE "/GR" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
string(REGEX REPLACE "/EHsc" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
add_definitions(-D_HAS_EXCEPTIONS=0)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zc:inline /EHs-c- /GR-")
add_definitions(-D_CRT_SECURE_NO_WARNINGS) # The LLVM build sets this.

# Disable cl.exe warnings that LLVM disables as well.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4244 /wd4267")

# This is apparently the simplest way to statically link the CRT in CMake:
string(TOUPPER "${CMAKE_BUILD_TYPE}" build)
set(flag_var "CMAKE_CXX_FLAGS_${build}")
Expand All @@ -33,9 +41,12 @@ endif()
include_directories(third_party/llvm/include)
add_executable(demumble
demumble.cc
third_party/llvm/lib/Demangle/Demangle.cpp
third_party/llvm/lib/Demangle/ItaniumDemangle.cpp
third_party/llvm/lib/Demangle/DLangDemangle.cpp
third_party/llvm/lib/Demangle/MicrosoftDemangle.cpp
third_party/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp
third_party/llvm/lib/Demangle/RustDemangle.cpp
)
set_target_properties(demumble PROPERTIES CXX_STANDARD 11
set_target_properties(demumble PROPERTIES CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON)
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
# demumble

`demumble` demangles both Itanium and Visual Studio symbols. It runs on both
POSIX and Windows.
`demumble` demangles both Itanium and Visual Studio symbols. It runs on
both POSIX and Windows.

$ demumble _Z4funcPci
func(char*, int)
$ demumble '?Fx_i@@YAHP6AHH@Z@Z'
int __cdecl Fx_i(int (__cdecl *)(int))


It can also demangle Rust and D symbols.

## Download

There are prebuilt x64 binaries for Linux, Mac (10.9+), and Windows on the
Expand All @@ -19,9 +21,9 @@ It has several nice features that c++filt lacks (and lacks many of c++filt's
features I never use).

Smart about underscores: C++ symbols have an additional leading underscore on
OS X. `operator new` is mangled as `_Znw` on Linux but `__Znw` on Mac. OS X's
macOS. `operator new` is mangled as `_Znw` on Linux but `__Znw` on Mac. macOS's
c++filt automatically strips one leading underscore, but Linux's c++filt
doesn't. So if you want to demangle a Linux symbol on OS X, you need to pass
doesn't. So if you want to demangle a Linux symbol on macOS, you need to pass
`-n` to tell it to not strip the underscore, and if you want to demangle an OS
X symbol on Linux you likewise need to pass `-_`. demumble just does the right
thing:
Expand Down Expand Up @@ -75,7 +77,7 @@ Optionally print both mangled and demangled names:

## Build instructions

Use cmake to build: `cmake -G Ninja && ninja`
Use cmake to build: `cmake -G Ninja . && ninja`

Run tests after building: `python demumble_test.py`

Expand Down
18 changes: 9 additions & 9 deletions RELEASING
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
Push new release branch:
1. make sure branches 'master' and 'release' are synced up locally
2. update demumble.cc with new version (with ".git"), then
1. make sure branches 'main' and 'release' are synced up locally
2. update kDemumbleVersion in demumble.cc with new version (with ".git"), then
git commit -am 'mark this 1.0.0.git'
3. git checkout release; git merge master
4. fix version number in src/version.cc (it will likely conflict in the above)
5. commit, tag, push (don't forget to push --tags)
3. git checkout release; git merge main
4. fix version number in src/version.cc (it will conflict in the above)
5. commit, tag, push (don't forget to push --tags), build binaries
git commit -am v1.0.0; git push origin release
git tag v1.0.0; git push --tags
# Push the 1.0.0.git change on master too:
git checkout master; git push origin master
6. add binaries to https://github.com/nico/demumble/releases
build them with `./dist.py` (on the release branch)
./dist.py # on the 'release' branch
# Push the 1.0.0.git change on main too:
git checkout main; git push origin main
6. add demumble-{linux,mac,win}.zip to https://github.com/nico/demumble/releases
49 changes: 34 additions & 15 deletions demumble.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

#include "llvm/Demangle/Demangle.h"

const char kDemumbleVersion[] = "1.2.2";
const char kDemumbleVersion[] = "1.2.3";

static int print_help(FILE* out) {
fprintf(out,
Expand All @@ -22,15 +22,19 @@ static int print_help(FILE* out) {
return out == stdout ? 0 : 1;
}

static void print_demangled(const char* format, const char* s) {
if (char* itanium = llvm::itaniumDemangle(s, NULL, NULL, NULL)) {
printf(format, itanium, s);
static void print_demangled(const char* format, std::string_view s,
size_t* n_used) {
if (char* itanium = llvm::itaniumDemangle(s)) {
printf(format, itanium, (int)s.size(), s.data());
free(itanium);
} else if (char* ms = llvm::microsoftDemangle(s, NULL, NULL, NULL)) {
printf(format, ms, s);
} else if (char* rust = llvm::rustDemangle(s)) {
printf(format, rust, (int)s.size(), s.data());
free(rust);
} else if (char* ms = llvm::microsoftDemangle(s, n_used, NULL)) {
printf(format, ms, (int)s.size(), s.data());
free(ms);
} else {
printf("%s", s);
printf("%.*s", (int)s.size(), s.data());
}
}

Expand All @@ -39,6 +43,12 @@ static bool is_mangle_char_itanium(char c) {
(c >= '0' && c <= '9') || c == '_' || c == '$';
}

static bool is_mangle_char_rust(char c) {
// See https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html.
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9') || c == '_';
}

static bool is_mangle_char_win(char c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9') || strchr("?_@$", c);
Expand All @@ -53,6 +63,11 @@ static bool is_plausible_itanium_prefix(char* s) {
return strstr(prefix, "_Z");
}

static bool is_plausible_rust_prefix(char* s) {
// Rust symbols start with "_R".
return s[0] == '_' && s[1] == 'R';
}

static char buf[8192];
int main(int argc, char* argv[]) {
enum { kPrintAll, kPrintMatching } print_mode = kPrintAll;
Expand All @@ -68,9 +83,9 @@ int main(int argc, char* argv[]) {
++argv;
break;
} else if (argv[1][0] == '-' && argv[1][1] != '-') {
for (int i = 1; i < strlen(argv[1]); ++i)
for (size_t i = 1; i < strlen(argv[1]); ++i)
switch (argv[1][i]) {
case 'b': print_format = "\"%s\" (%s)"; break;
case 'b': print_format = "\"%s\" (%.*s)"; break;
case 'h': return print_help(stdout);
case 'm': print_mode = kPrintMatching; break;
case 'u': setbuf(stdout, NULL); break;
Expand All @@ -87,8 +102,11 @@ int main(int argc, char* argv[]) {
++argv;
}
for (int i = 1; i < argc; ++i) {
print_demangled(print_format, argv[i]);
size_t used = strlen(argv[i]);
print_demangled(print_format, { argv[i], used }, &used);
printf("\n");
if (used < strlen(argv[i]))
printf(" unused suffix: %s\n", argv[i] + used);
}
if (argc == 1) { // Read stdin instead.
// By default, don't demangle types. Mangled function names are unlikely
Expand Down Expand Up @@ -118,20 +136,21 @@ int main(int argc, char* argv[]) {
else if (is_plausible_itanium_prefix(cur))
while (cur + n_sym != end && is_mangle_char_itanium(cur[n_sym]))
++n_sym;
else if (is_plausible_rust_prefix(cur))
while (cur + n_sym != end && is_mangle_char_rust(cur[n_sym]))
++n_sym;
else {
if (print_mode == kPrintAll)
printf("_");
++cur;
continue;
}

char tmp = cur[n_sym];
cur[n_sym] = '\0';
print_demangled(print_format, cur);
size_t n_used = n_sym;
print_demangled(print_format, { cur, n_sym }, &n_used);
need_separator = true;
cur[n_sym] = tmp;

cur += n_sym;
cur += n_used;
}
}
}
Expand Down
20 changes: 13 additions & 7 deletions demumble_test.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
#!/usr/bin/env python
from __future__ import print_function
#!/usr/bin/env python3
import os, re, subprocess, sys

tests = [
('demumble hello', 'hello\n'),
('demumble _Z4funcPci _Z1fv', 'func(char*, int)\nf()\n'),
('demumble < _Z4funcPci _Z1fv', 'func(char*, int)\nf()\n'),
('demumble _RINvNtC3std3mem8align_ofdE _RNvNvC5mylib3foo3bar',
'std::mem::align_of::<f64>\nmylib::foo::bar\n'),
('demumble < _RINvNtC3std3mem8align_ofdE _RNvNvC5mylib3foo3bar',
'std::mem::align_of::<f64>\nmylib::foo::bar\n'),
('demumble ?Fxi@@YAHP6AHH@Z@Z', 'int __cdecl Fxi(int (__cdecl *)(int))\n'),
('demumble ??0S@@QEAA@$$QEAU0@@Z', 'public: __cdecl S::S(struct S &&)\n'),
('demumble ??_C@_02PCEFGMJL@hi?$AA@', '"hi"\n'),
('demumble __Znwi', 'operator new(int)\n'), # Strip extra _ (for OS X)
('demumble __Znwi', 'operator new(int)\n'), # Strip extra _ (for macOS)
('demumble < __Znwi', 'operator new(int)\n'), # Also from stdin
('demumble -m hi _Z1fv ho _Z1gv', 'hi\nf()\nho\ng()\n'),
('demumble -m < hi_ho _Z1fv ho _Z1gv ?hm', 'f()\ng()\n?hm\n'),
Expand Down Expand Up @@ -40,6 +43,9 @@
('demumble < _ZZ3fooiENK3$_0clEi',
'foo(int)::$_0::operator()(int) const\n'),
('demumble .?AVNet@@', "class Net `RTTI Type Descriptor Name'\n"),
('demumble < asdf?x@@3HAjkl', 'asdfint xjkl\n'),
('demumble < asdf?x@@3Hjkl', 'asdf?x@@3Hjkl\n'),
('demumble ?x@@3HAjkl', 'int x\n unused suffix: jkl\n'),
]

status = 0
Expand All @@ -50,12 +56,12 @@
if '<' in cmd:
p = subprocess.Popen(cmd[:cmd.index('<')], stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
universal_newlines=True)
encoding='utf-8')
out = p.communicate(input='\n'.join(cmd[cmd.index('<') + 1:]) + '\n')[0]
else:
out = subprocess.check_output(cmd, universal_newlines=True)
out = subprocess.check_output(cmd, encoding='utf-8')
if (out != t[1] if isinstance(t[1], str) else not t[1].match(out)):
print("`%s`: Expected '%s', got '%s'" % (t[0], t[1], out))
print(f"`{t[0]}`: Expected '{t[1]}', got '{out}'")
status = 1
print("passed" if status == 0 else "failed")
print('passed' if status == 0 else 'failed')
sys.exit(status)
Loading

0 comments on commit c874601

Please sign in to comment.