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 | static cl::OptionCategory UndNameCategory("UndName Options" ); |
32 | |
33 | static cl::opt<bool> DumpBackReferences("backrefs" , cl::Optional, |
34 | cl::desc("dump backreferences" ), |
35 | cl::Hidden, cl::init(Val: false), |
36 | cl::cat(UndNameCategory)); |
37 | static cl::opt<bool> NoAccessSpecifier("no-access-specifier" , cl::Optional, |
38 | cl::desc("skip access specifiers" ), |
39 | cl::Hidden, cl::init(Val: false), |
40 | cl::cat(UndNameCategory)); |
41 | static cl::opt<bool> NoCallingConvention("no-calling-convention" , cl::Optional, |
42 | cl::desc("skip calling convention" ), |
43 | cl::Hidden, cl::init(Val: false), |
44 | cl::cat(UndNameCategory)); |
45 | static cl::opt<bool> NoReturnType("no-return-type" , cl::Optional, |
46 | cl::desc("skip return types" ), cl::Hidden, |
47 | cl::init(Val: false), cl::cat(UndNameCategory)); |
48 | static cl::opt<bool> NoMemberType("no-member-type" , cl::Optional, |
49 | cl::desc("skip member types" ), cl::Hidden, |
50 | cl::init(Val: false), cl::cat(UndNameCategory)); |
51 | static cl::opt<bool> NoVariableType("no-variable-type" , cl::Optional, |
52 | cl::desc("skip variable types" ), cl::Hidden, |
53 | cl::init(Val: false), cl::cat(UndNameCategory)); |
54 | static cl::opt<std::string> RawFile("raw-file" , cl::Optional, |
55 | cl::desc("for fuzzer data" ), cl::Hidden, |
56 | cl::cat(UndNameCategory)); |
57 | static cl::opt<bool> WarnTrailing("warn-trailing" , cl::Optional, |
58 | cl::desc("warn on trailing characters" ), |
59 | cl::Hidden, cl::init(Val: false), |
60 | cl::cat(UndNameCategory)); |
61 | static cl::list<std::string> Symbols(cl::Positional, |
62 | cl::desc("<input symbols>" ), |
63 | cl::cat(UndNameCategory)); |
64 | |
65 | static bool msDemangle(const std::string &S) { |
66 | int Status; |
67 | MSDemangleFlags Flags = MSDF_None; |
68 | if (DumpBackReferences) |
69 | Flags = MSDemangleFlags(Flags | MSDF_DumpBackrefs); |
70 | if (NoAccessSpecifier) |
71 | Flags = MSDemangleFlags(Flags | MSDF_NoAccessSpecifier); |
72 | if (NoCallingConvention) |
73 | Flags = MSDemangleFlags(Flags | MSDF_NoCallingConvention); |
74 | if (NoReturnType) |
75 | Flags = MSDemangleFlags(Flags | MSDF_NoReturnType); |
76 | if (NoMemberType) |
77 | Flags = MSDemangleFlags(Flags | MSDF_NoMemberType); |
78 | if (NoVariableType) |
79 | Flags = MSDemangleFlags(Flags | MSDF_NoVariableType); |
80 | |
81 | size_t NRead; |
82 | char *ResultBuf = microsoftDemangle(mangled_name: S, n_read: &NRead, status: &Status, Flags); |
83 | if (Status == llvm::demangle_success) { |
84 | outs() << ResultBuf << "\n" ; |
85 | outs().flush(); |
86 | if (WarnTrailing && NRead < S.size()) |
87 | WithColor::warning() << "trailing characters: " << S.c_str() + NRead |
88 | << "\n" ; |
89 | } else { |
90 | WithColor::error() << "Invalid mangled name\n" ; |
91 | } |
92 | std::free(ptr: ResultBuf); |
93 | return Status == llvm::demangle_success; |
94 | } |
95 | |
96 | int main(int argc, char **argv) { |
97 | InitLLVM X(argc, argv); |
98 | |
99 | cl::HideUnrelatedOptions(Categories: {&UndNameCategory, &getColorCategory()}); |
100 | cl::ParseCommandLineOptions(argc, argv, Overview: "llvm-undname\n" ); |
101 | |
102 | if (!RawFile.empty()) { |
103 | ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr = |
104 | MemoryBuffer::getFileOrSTDIN(Filename: RawFile); |
105 | if (std::error_code EC = FileOrErr.getError()) { |
106 | WithColor::error() << "Could not open input file \'" << RawFile |
107 | << "\': " << EC.message() << '\n'; |
108 | return 1; |
109 | } |
110 | return msDemangle(S: std::string(FileOrErr->get()->getBuffer())) ? 0 : 1; |
111 | } |
112 | |
113 | bool Success = true; |
114 | if (Symbols.empty()) { |
115 | while (true) { |
116 | std::string LineStr; |
117 | std::getline(is&: std::cin, str&: LineStr); |
118 | if (std::cin.eof()) |
119 | break; |
120 | |
121 | StringRef Line(LineStr); |
122 | Line = Line.trim(); |
123 | if (Line.empty() || Line.starts_with(Prefix: "#" ) || Line.starts_with(Prefix: ";" )) |
124 | continue; |
125 | |
126 | // If the user is manually typing in these decorated names, don't echo |
127 | // them to the terminal a second time. If they're coming from redirected |
128 | // input, however, then we should display the input line so that the |
129 | // mangled and demangled name can be easily correlated in the output. |
130 | if (!sys::Process::StandardInIsUserInput()) { |
131 | outs() << Line << "\n" ; |
132 | outs().flush(); |
133 | } |
134 | if (!msDemangle(S: std::string(Line))) |
135 | Success = false; |
136 | outs() << "\n" ; |
137 | } |
138 | } else { |
139 | for (StringRef S : Symbols) { |
140 | outs() << S << "\n" ; |
141 | outs().flush(); |
142 | if (!msDemangle(S: std::string(S))) |
143 | Success = false; |
144 | outs() << "\n" ; |
145 | } |
146 | } |
147 | |
148 | return Success ? 0 : 1; |
149 | } |
150 | |