1 | //===-- llvm-undname.cpp - Microsoft ABI name undecorator |
2 | //------------------===// |
3 | // |
4 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
5 | // See https://llvm.org/LICENSE.txt for license information. |
6 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
7 | // |
8 | //===----------------------------------------------------------------------===// |
9 | // |
10 | // This utility works like the windows undname utility. It converts mangled |
11 | // Microsoft symbol names into pretty C/C++ human-readable names. |
12 | // |
13 | //===----------------------------------------------------------------------===// |
14 | |
15 | #include "llvm/ADT/StringRef.h" |
16 | #include "llvm/Demangle/Demangle.h" |
17 | #include "llvm/Support/CommandLine.h" |
18 | #include "llvm/Support/ErrorOr.h" |
19 | #include "llvm/Support/InitLLVM.h" |
20 | #include "llvm/Support/MemoryBuffer.h" |
21 | #include "llvm/Support/Process.h" |
22 | #include "llvm/Support/WithColor.h" |
23 | #include "llvm/Support/raw_ostream.h" |
24 | #include <cstdio> |
25 | #include <cstring> |
26 | #include <iostream> |
27 | #include <string> |
28 | |
29 | using namespace llvm; |
30 | |
31 | cl::OptionCategory UndNameCategory("UndName Options" ); |
32 | |
33 | cl::opt<bool> DumpBackReferences("backrefs" , cl::Optional, |
34 | cl::desc("dump backreferences" ), cl::Hidden, |
35 | cl::init(Val: false), cl::cat(UndNameCategory)); |
36 | cl::opt<bool> NoAccessSpecifier("no-access-specifier" , cl::Optional, |
37 | cl::desc("skip access specifiers" ), cl::Hidden, |
38 | cl::init(Val: false), cl::cat(UndNameCategory)); |
39 | cl::opt<bool> NoCallingConvention("no-calling-convention" , cl::Optional, |
40 | cl::desc("skip calling convention" ), |
41 | cl::Hidden, cl::init(Val: false), |
42 | cl::cat(UndNameCategory)); |
43 | cl::opt<bool> NoReturnType("no-return-type" , cl::Optional, |
44 | cl::desc("skip return types" ), cl::Hidden, |
45 | cl::init(Val: false), cl::cat(UndNameCategory)); |
46 | cl::opt<bool> NoMemberType("no-member-type" , cl::Optional, |
47 | cl::desc("skip member types" ), cl::Hidden, |
48 | cl::init(Val: false), cl::cat(UndNameCategory)); |
49 | cl::opt<bool> NoVariableType("no-variable-type" , cl::Optional, |
50 | cl::desc("skip variable types" ), cl::Hidden, |
51 | cl::init(Val: false), cl::cat(UndNameCategory)); |
52 | cl::opt<std::string> RawFile("raw-file" , cl::Optional, |
53 | cl::desc("for fuzzer data" ), cl::Hidden, |
54 | cl::cat(UndNameCategory)); |
55 | cl::opt<bool> WarnTrailing("warn-trailing" , cl::Optional, |
56 | cl::desc("warn on trailing characters" ), cl::Hidden, |
57 | cl::init(Val: false), cl::cat(UndNameCategory)); |
58 | cl::list<std::string> Symbols(cl::Positional, cl::desc("<input symbols>" ), |
59 | cl::cat(UndNameCategory)); |
60 | |
61 | static bool msDemangle(const std::string &S) { |
62 | int Status; |
63 | MSDemangleFlags Flags = MSDF_None; |
64 | if (DumpBackReferences) |
65 | Flags = MSDemangleFlags(Flags | MSDF_DumpBackrefs); |
66 | if (NoAccessSpecifier) |
67 | Flags = MSDemangleFlags(Flags | MSDF_NoAccessSpecifier); |
68 | if (NoCallingConvention) |
69 | Flags = MSDemangleFlags(Flags | MSDF_NoCallingConvention); |
70 | if (NoReturnType) |
71 | Flags = MSDemangleFlags(Flags | MSDF_NoReturnType); |
72 | if (NoMemberType) |
73 | Flags = MSDemangleFlags(Flags | MSDF_NoMemberType); |
74 | if (NoVariableType) |
75 | Flags = MSDemangleFlags(Flags | MSDF_NoVariableType); |
76 | |
77 | size_t NRead; |
78 | char *ResultBuf = microsoftDemangle(mangled_name: S, n_read: &NRead, status: &Status, Flags); |
79 | if (Status == llvm::demangle_success) { |
80 | outs() << ResultBuf << "\n" ; |
81 | outs().flush(); |
82 | if (WarnTrailing && NRead < S.size()) |
83 | WithColor::warning() << "trailing characters: " << S.c_str() + NRead |
84 | << "\n" ; |
85 | } else { |
86 | WithColor::error() << "Invalid mangled name\n" ; |
87 | } |
88 | std::free(ptr: ResultBuf); |
89 | return Status == llvm::demangle_success; |
90 | } |
91 | |
92 | int main(int argc, char **argv) { |
93 | InitLLVM X(argc, argv); |
94 | |
95 | cl::HideUnrelatedOptions(Categories: {&UndNameCategory, &getColorCategory()}); |
96 | cl::ParseCommandLineOptions(argc, argv, Overview: "llvm-undname\n" ); |
97 | |
98 | if (!RawFile.empty()) { |
99 | ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr = |
100 | MemoryBuffer::getFileOrSTDIN(Filename: RawFile); |
101 | if (std::error_code EC = FileOrErr.getError()) { |
102 | WithColor::error() << "Could not open input file \'" << RawFile |
103 | << "\': " << EC.message() << '\n'; |
104 | return 1; |
105 | } |
106 | return msDemangle(S: std::string(FileOrErr->get()->getBuffer())) ? 0 : 1; |
107 | } |
108 | |
109 | bool Success = true; |
110 | if (Symbols.empty()) { |
111 | while (true) { |
112 | std::string LineStr; |
113 | std::getline(is&: std::cin, str&: LineStr); |
114 | if (std::cin.eof()) |
115 | break; |
116 | |
117 | StringRef Line(LineStr); |
118 | Line = Line.trim(); |
119 | if (Line.empty() || Line.starts_with(Prefix: "#" ) || Line.starts_with(Prefix: ";" )) |
120 | continue; |
121 | |
122 | // If the user is manually typing in these decorated names, don't echo |
123 | // them to the terminal a second time. If they're coming from redirected |
124 | // input, however, then we should display the input line so that the |
125 | // mangled and demangled name can be easily correlated in the output. |
126 | if (!sys::Process::StandardInIsUserInput()) { |
127 | outs() << Line << "\n" ; |
128 | outs().flush(); |
129 | } |
130 | if (!msDemangle(S: std::string(Line))) |
131 | Success = false; |
132 | outs() << "\n" ; |
133 | } |
134 | } else { |
135 | for (StringRef S : Symbols) { |
136 | outs() << S << "\n" ; |
137 | outs().flush(); |
138 | if (!msDemangle(S: std::string(S))) |
139 | Success = false; |
140 | outs() << "\n" ; |
141 | } |
142 | } |
143 | |
144 | return Success ? 0 : 1; |
145 | } |
146 | |