Skip to content

Commit cdbaf90

Browse files
committed
[demangle] Add a new tool called swift-demangle-yamldump.
This is a separate tool so we can use all of LLVM without worrying about creating a dependency from the demangler on LLVM's libsupport. I am going to use it to fix cmpcodesize for the new mangling by eliminating cmpcodesize's usage of regex to classify symbols. Instead, we can just read in the yaml version of the symbol trees for each demangled node and process that instead. rdar://41146023
1 parent ec732b0 commit cdbaf90

File tree

5 files changed

+244
-1
lines changed

5 files changed

+244
-1
lines changed

test/Demangle/yaml-dump.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: %swift-demangle-yamldump '_$S4main5inneryys5Int32Vz_yADctF25closure_with_box_argumentxz_Bi32__lXXTf1nc_n' | %FileCheck %s
2+
3+
// CHECK: ---
4+
// CHECK: name: '_$S4main5inneryys5Int32Vz_yADctF25closure_with_box_argumentxz_Bi32__lXXTf1nc_n'
5+
// CHECK: kind: Global
6+
// CHECK: children:
7+
// CHECK: - name: ''
8+
// CHECK: kind: FunctionSignatureSpecialization
9+
// CHECK: children:
10+
// CHECK: - name: ''
11+
// CHECK: kind: Function
12+
// CHECK: children:
13+
// CHECK: ...
14+

test/lit.cfg

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ config.sourcekitd_test = inferSwiftBinary('sourcekitd-test')
271271
config.complete_test = inferSwiftBinary('complete-test')
272272
config.swift_api_digester = inferSwiftBinary('swift-api-digester')
273273
config.swift_refactor = inferSwiftBinary('swift-refactor')
274+
config.swift_demangle_yamldump = inferSwiftBinary('swift-demangle-yamldump')
274275

275276
config.swift_utils = make_path(config.swift_src_root, 'utils')
276277
config.line_directive = make_path(config.swift_utils, 'line-directive')
@@ -364,6 +365,7 @@ config.substitutions.append( ('%llvm-link', config.llvm_link) )
364365
config.substitutions.append( ('%swift-llvm-opt', config.swift_llvm_opt) )
365366
config.substitutions.append( ('%llvm-dwarfdump', config.llvm_dwarfdump) )
366367
config.substitutions.append( ('%llvm-dis', config.llvm_dis) )
368+
config.substitutions.append( ('%swift-demangle-yamldump', config.swift_demangle_yamldump) )
367369

368370
# This must come after all substitutions containing "%swift".
369371
config.substitutions.append(
@@ -1055,7 +1057,7 @@ config.target_sil_llvm_gen = (
10551057
'%s -target %s %s'
10561058
% (config.sil_llvm_gen, config.variant_triple, mcp_opt))
10571059

1058-
config.target_sil_nm= (
1060+
config.target_sil_nm = (
10591061
'%s -target %s %s'
10601062
% (config.sil_nm, config.variant_triple, mcp_opt))
10611063

@@ -1129,6 +1131,7 @@ config.substitutions.append(('%target-sil-opt', config.target_sil_opt))
11291131
config.substitutions.append(('%target-sil-func-extractor', config.target_sil_func_extractor))
11301132
config.substitutions.append(('%target-sil-llvm-gen', config.target_sil_llvm_gen))
11311133
config.substitutions.append(('%target-sil-nm', config.target_sil_nm))
1134+
11321135
config.substitutions.append(
11331136
('%target-swift-ide-test\(mock-sdk:([^)]+)\)',
11341137
'%s \\1 %s -swift-version %s' %

tools/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ add_swift_tool_subdirectory(sil-opt)
2020
add_swift_tool_subdirectory(swift-ide-test)
2121
add_swift_tool_subdirectory(swift-remoteast-test)
2222
add_swift_tool_subdirectory(swift-demangle)
23+
add_swift_tool_subdirectory(swift-demangle-yamldump)
2324
add_swift_tool_subdirectory(lldb-moduleimport-test)
2425
add_swift_tool_subdirectory(sil-func-extractor)
2526
add_swift_tool_subdirectory(sil-llvm-gen)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
add_swift_host_tool(swift-demangle-yamldump
2+
swift-demangle-yamldump.cpp
3+
LINK_LIBRARIES swiftDemangling
4+
LLVM_COMPONENT_DEPENDS support
5+
SWIFT_COMPONENT tools
6+
)
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
//===--- swift-demangle-yamldump.cpp --------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
///
13+
/// \file
14+
///
15+
/// This tool is similar to the demangler but is intended to /not/ be installed
16+
/// into the OS. This means that it can link against llvm support and friends
17+
/// and thus provide extra functionality. Today it is only used to dump the
18+
/// demangler tree in YAML form for easy processing.
19+
///
20+
//===----------------------------------------------------------------------===//
21+
22+
#include "swift/Basic/LLVM.h"
23+
#include "swift/Demangling/Demangle.h"
24+
#include "swift/Demangling/ManglingMacros.h"
25+
#include "llvm/ADT/StringRef.h"
26+
#include "llvm/ADT/SmallString.h"
27+
#include "llvm/Support/YAMLTraits.h"
28+
#include "llvm/Support/CommandLine.h"
29+
#include "llvm/Support/MemoryBuffer.h"
30+
#include "llvm/Support/PrettyStackTrace.h"
31+
#include "llvm/Support/Regex.h"
32+
#include "llvm/Support/Signals.h"
33+
#include "llvm/Support/raw_ostream.h"
34+
35+
// For std::rand, to work around a bug if main()'s first function call passes
36+
// argv[0].
37+
#if defined(__CYGWIN__)
38+
#include <cstdlib>
39+
#endif
40+
41+
#include <iostream>
42+
43+
using namespace swift;
44+
using namespace swift::Demangle;
45+
46+
//===----------------------------------------------------------------------===//
47+
// YAML Dump Implementation
48+
//===----------------------------------------------------------------------===//
49+
50+
namespace {
51+
52+
using llvm::yaml::IO;
53+
using llvm::yaml::MappingTraits;
54+
using llvm::yaml::Output;
55+
using llvm::yaml::ScalarEnumerationTraits;
56+
using llvm::yaml::SequenceTraits;
57+
58+
struct YAMLNode {
59+
Node::Kind kind;
60+
std::vector<YAMLNode *> children;
61+
StringRef name = StringRef();
62+
63+
YAMLNode(Node::Kind kind) : kind(kind), children() {}
64+
};
65+
66+
} // end anonymous namespace
67+
68+
namespace llvm {
69+
namespace yaml {
70+
71+
template <> struct ScalarEnumerationTraits<swift::Demangle::Node::Kind> {
72+
static void enumeration(IO &io, swift::Demangle::Node::Kind &value) {
73+
#define NODE(ID) io.enumCase(value, #ID, swift::Demangle::Node::Kind::ID);
74+
#include "swift/Demangling/DemangleNodes.def"
75+
}
76+
};
77+
78+
template <> struct MappingTraits<YAMLNode *> {
79+
static void mapping(IO &io, YAMLNode *&node) {
80+
io.mapOptional("name", node->name);
81+
io.mapRequired("kind", node->kind);
82+
io.mapRequired("children", node->children);
83+
}
84+
};
85+
86+
template <> struct MappingTraits<YAMLNode> {
87+
static void mapping(IO &io, YAMLNode &node) {
88+
io.mapOptional("name", node.name);
89+
io.mapRequired("kind", node.kind);
90+
io.mapRequired("children", node.children);
91+
}
92+
};
93+
94+
} // namespace yaml
95+
} // namespace llvm
96+
97+
LLVM_YAML_IS_SEQUENCE_VECTOR(YAMLNode *)
98+
99+
static std::string getNodeTreeAsYAML(llvm::StringRef name,
100+
NodePointer root) {
101+
std::vector<std::unique_ptr<YAMLNode>> nodes;
102+
103+
std::vector<std::pair<NodePointer, YAMLNode *>> worklist;
104+
nodes.emplace_back(new YAMLNode(root->getKind()));
105+
nodes.back()->name = name;
106+
worklist.emplace_back(root, &*nodes.back());
107+
108+
while (!worklist.empty()) {
109+
NodePointer np;
110+
YAMLNode *node;
111+
std::tie(np, node) = worklist.back();
112+
worklist.pop_back();
113+
114+
for (unsigned i = 0; i < np->getNumChildren(); ++i) {
115+
nodes.emplace_back(new YAMLNode(np->getChild(i)->getKind()));
116+
node->children.emplace_back(&*nodes.back());
117+
}
118+
}
119+
120+
std::string output;
121+
llvm::raw_string_ostream stream(output);
122+
llvm::yaml::Output yout(stream);
123+
yout << *nodes.front();
124+
return stream.str();
125+
}
126+
127+
//===----------------------------------------------------------------------===//
128+
// Top Level Entrypoint
129+
//===----------------------------------------------------------------------===//
130+
131+
static llvm::cl::opt<bool>
132+
DisableSugar("no-sugar",
133+
llvm::cl::desc("No sugar mode (disable common language idioms "
134+
"such as ? and [] from the output)"));
135+
136+
static llvm::cl::opt<bool> Simplified(
137+
"simplified",
138+
llvm::cl::desc("Don't display module names or implicit self types"));
139+
140+
static llvm::cl::list<std::string>
141+
InputNames(llvm::cl::Positional, llvm::cl::desc("[mangled name...]"),
142+
llvm::cl::ZeroOrMore);
143+
144+
static llvm::StringRef substrBefore(llvm::StringRef whole,
145+
llvm::StringRef part) {
146+
return whole.slice(0, part.data() - whole.data());
147+
}
148+
149+
static llvm::StringRef substrAfter(llvm::StringRef whole,
150+
llvm::StringRef part) {
151+
return whole.substr((part.data() - whole.data()) + part.size());
152+
}
153+
154+
static void demangle(llvm::raw_ostream &os, llvm::StringRef name,
155+
swift::Demangle::Context &DCtx,
156+
const swift::Demangle::DemangleOptions &options) {
157+
bool hadLeadingUnderscore = false;
158+
if (name.startswith("__")) {
159+
hadLeadingUnderscore = true;
160+
name = name.substr(1);
161+
}
162+
swift::Demangle::NodePointer pointer = DCtx.demangleSymbolAsNode(name);
163+
// We do not emit a message so that we end up dumping
164+
llvm::outs() << getNodeTreeAsYAML(name, pointer);
165+
DCtx.clear();
166+
}
167+
168+
static int demangleSTDIN(const swift::Demangle::DemangleOptions &options) {
169+
// This doesn't handle Unicode symbols, but maybe that's okay.
170+
// Also accept the future mangling prefix.
171+
llvm::Regex maybeSymbol("(_T|_?\\$[Ss])[_a-zA-Z0-9$.]+");
172+
173+
swift::Demangle::Context DCtx;
174+
for (std::string mangled; std::getline(std::cin, mangled);) {
175+
llvm::StringRef inputContents(mangled);
176+
177+
llvm::SmallVector<llvm::StringRef, 1> matches;
178+
while (maybeSymbol.match(inputContents, &matches)) {
179+
llvm::outs() << substrBefore(inputContents, matches.front());
180+
demangle(llvm::outs(), matches.front(), DCtx, options);
181+
inputContents = substrAfter(inputContents, matches.front());
182+
}
183+
184+
llvm::errs() << "Failed to match: " << inputContents << '\n';
185+
}
186+
187+
return EXIT_SUCCESS;
188+
}
189+
190+
int main(int argc, char **argv) {
191+
#if defined(__CYGWIN__)
192+
// Cygwin clang 3.5.2 with '-O3' generates CRASHING BINARY,
193+
// if main()'s first function call is passing argv[0].
194+
std::rand();
195+
#endif
196+
llvm::cl::ParseCommandLineOptions(argc, argv);
197+
198+
swift::Demangle::DemangleOptions options;
199+
options.SynthesizeSugarOnTypes = !DisableSugar;
200+
if (Simplified)
201+
options = swift::Demangle::DemangleOptions::SimplifiedUIDemangleOptions();
202+
203+
if (InputNames.empty()) {
204+
return demangleSTDIN(options);
205+
} else {
206+
swift::Demangle::Context DCtx;
207+
for (llvm::StringRef name : InputNames) {
208+
if (name.startswith("S")) {
209+
std::string correctedName = std::string("$") + name.str();
210+
demangle(llvm::outs(), correctedName, DCtx, options);
211+
} else {
212+
demangle(llvm::outs(), name, DCtx, options);
213+
}
214+
llvm::outs() << '\n';
215+
}
216+
217+
return EXIT_SUCCESS;
218+
}
219+
}

0 commit comments

Comments
 (0)