xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-nm/llvm-nm.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===-- llvm-nm.cpp - Symbol table dumping utility for llvm ---------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric // This program is a utility that works like traditional Unix "nm", that is, it
10*0b57cec5SDimitry Andric // prints out the names of symbols in a bitcode or object file, along with some
11*0b57cec5SDimitry Andric // information about each symbol.
12*0b57cec5SDimitry Andric //
13*0b57cec5SDimitry Andric // This "nm" supports many of the features of GNU "nm", including its different
14*0b57cec5SDimitry Andric // output formats.
15*0b57cec5SDimitry Andric //
16*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
17*0b57cec5SDimitry Andric 
18*0b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h"
19*0b57cec5SDimitry Andric #include "llvm/BinaryFormat/COFF.h"
20*0b57cec5SDimitry Andric #include "llvm/Demangle/Demangle.h"
21*0b57cec5SDimitry Andric #include "llvm/IR/Function.h"
22*0b57cec5SDimitry Andric #include "llvm/IR/LLVMContext.h"
23*0b57cec5SDimitry Andric #include "llvm/Object/Archive.h"
24*0b57cec5SDimitry Andric #include "llvm/Object/COFF.h"
25*0b57cec5SDimitry Andric #include "llvm/Object/COFFImportFile.h"
26*0b57cec5SDimitry Andric #include "llvm/Object/ELFObjectFile.h"
27*0b57cec5SDimitry Andric #include "llvm/Object/IRObjectFile.h"
28*0b57cec5SDimitry Andric #include "llvm/Object/MachO.h"
29*0b57cec5SDimitry Andric #include "llvm/Object/MachOUniversal.h"
30*0b57cec5SDimitry Andric #include "llvm/Object/ObjectFile.h"
31*0b57cec5SDimitry Andric #include "llvm/Object/Wasm.h"
32*0b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
33*0b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
34*0b57cec5SDimitry Andric #include "llvm/Support/Format.h"
35*0b57cec5SDimitry Andric #include "llvm/Support/InitLLVM.h"
36*0b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
37*0b57cec5SDimitry Andric #include "llvm/Support/Program.h"
38*0b57cec5SDimitry Andric #include "llvm/Support/Signals.h"
39*0b57cec5SDimitry Andric #include "llvm/Support/TargetSelect.h"
40*0b57cec5SDimitry Andric #include "llvm/Support/WithColor.h"
41*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
42*0b57cec5SDimitry Andric #include <vector>
43*0b57cec5SDimitry Andric 
44*0b57cec5SDimitry Andric using namespace llvm;
45*0b57cec5SDimitry Andric using namespace object;
46*0b57cec5SDimitry Andric 
47*0b57cec5SDimitry Andric namespace {
48*0b57cec5SDimitry Andric enum OutputFormatTy { bsd, sysv, posix, darwin };
49*0b57cec5SDimitry Andric 
50*0b57cec5SDimitry Andric cl::OptionCategory NMCat("llvm-nm Options");
51*0b57cec5SDimitry Andric 
52*0b57cec5SDimitry Andric cl::opt<OutputFormatTy> OutputFormat(
53*0b57cec5SDimitry Andric     "format", cl::desc("Specify output format"),
54*0b57cec5SDimitry Andric     cl::values(clEnumVal(bsd, "BSD format"), clEnumVal(sysv, "System V format"),
55*0b57cec5SDimitry Andric                clEnumVal(posix, "POSIX.2 format"),
56*0b57cec5SDimitry Andric                clEnumVal(darwin, "Darwin -m format")),
57*0b57cec5SDimitry Andric     cl::init(bsd), cl::cat(NMCat));
58*0b57cec5SDimitry Andric cl::alias OutputFormat2("f", cl::desc("Alias for --format"),
59*0b57cec5SDimitry Andric                         cl::aliasopt(OutputFormat));
60*0b57cec5SDimitry Andric 
61*0b57cec5SDimitry Andric cl::list<std::string> InputFilenames(cl::Positional, cl::desc("<input files>"),
62*0b57cec5SDimitry Andric                                      cl::ZeroOrMore);
63*0b57cec5SDimitry Andric 
64*0b57cec5SDimitry Andric cl::opt<bool> UndefinedOnly("undefined-only",
65*0b57cec5SDimitry Andric                             cl::desc("Show only undefined symbols"),
66*0b57cec5SDimitry Andric                             cl::cat(NMCat));
67*0b57cec5SDimitry Andric cl::alias UndefinedOnly2("u", cl::desc("Alias for --undefined-only"),
68*0b57cec5SDimitry Andric                          cl::aliasopt(UndefinedOnly), cl::Grouping);
69*0b57cec5SDimitry Andric 
70*0b57cec5SDimitry Andric cl::opt<bool> DynamicSyms("dynamic",
71*0b57cec5SDimitry Andric                           cl::desc("Display the dynamic symbols instead "
72*0b57cec5SDimitry Andric                                    "of normal symbols."),
73*0b57cec5SDimitry Andric                           cl::cat(NMCat));
74*0b57cec5SDimitry Andric cl::alias DynamicSyms2("D", cl::desc("Alias for --dynamic"),
75*0b57cec5SDimitry Andric                        cl::aliasopt(DynamicSyms), cl::Grouping);
76*0b57cec5SDimitry Andric 
77*0b57cec5SDimitry Andric cl::opt<bool> DefinedOnly("defined-only", cl::desc("Show only defined symbols"),
78*0b57cec5SDimitry Andric                           cl::cat(NMCat));
79*0b57cec5SDimitry Andric cl::alias DefinedOnly2("U", cl::desc("Alias for --defined-only"),
80*0b57cec5SDimitry Andric                        cl::aliasopt(DefinedOnly), cl::Grouping);
81*0b57cec5SDimitry Andric 
82*0b57cec5SDimitry Andric cl::opt<bool> ExternalOnly("extern-only",
83*0b57cec5SDimitry Andric                            cl::desc("Show only external symbols"),
84*0b57cec5SDimitry Andric                            cl::ZeroOrMore, cl::cat(NMCat));
85*0b57cec5SDimitry Andric cl::alias ExternalOnly2("g", cl::desc("Alias for --extern-only"),
86*0b57cec5SDimitry Andric                         cl::aliasopt(ExternalOnly), cl::Grouping,
87*0b57cec5SDimitry Andric                         cl::ZeroOrMore);
88*0b57cec5SDimitry Andric 
89*0b57cec5SDimitry Andric cl::opt<bool> NoWeakSymbols("no-weak", cl::desc("Show only non-weak symbols"),
90*0b57cec5SDimitry Andric                             cl::cat(NMCat));
91*0b57cec5SDimitry Andric cl::alias NoWeakSymbols2("W", cl::desc("Alias for --no-weak"),
92*0b57cec5SDimitry Andric                          cl::aliasopt(NoWeakSymbols), cl::Grouping);
93*0b57cec5SDimitry Andric 
94*0b57cec5SDimitry Andric cl::opt<bool> BSDFormat("B", cl::desc("Alias for --format=bsd"), cl::Grouping,
95*0b57cec5SDimitry Andric                         cl::cat(NMCat));
96*0b57cec5SDimitry Andric cl::opt<bool> POSIXFormat("P", cl::desc("Alias for --format=posix"),
97*0b57cec5SDimitry Andric                           cl::Grouping, cl::cat(NMCat));
98*0b57cec5SDimitry Andric cl::alias Portability("portability", cl::desc("Alias for --format=posix"),
99*0b57cec5SDimitry Andric                       cl::aliasopt(POSIXFormat), cl::NotHidden);
100*0b57cec5SDimitry Andric cl::opt<bool> DarwinFormat("m", cl::desc("Alias for --format=darwin"),
101*0b57cec5SDimitry Andric                            cl::Grouping, cl::cat(NMCat));
102*0b57cec5SDimitry Andric 
103*0b57cec5SDimitry Andric static cl::list<std::string>
104*0b57cec5SDimitry Andric     ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"),
105*0b57cec5SDimitry Andric               cl::ZeroOrMore, cl::cat(NMCat));
106*0b57cec5SDimitry Andric bool ArchAll = false;
107*0b57cec5SDimitry Andric 
108*0b57cec5SDimitry Andric cl::opt<bool> PrintFileName(
109*0b57cec5SDimitry Andric     "print-file-name",
110*0b57cec5SDimitry Andric     cl::desc("Precede each symbol with the object file it came from"),
111*0b57cec5SDimitry Andric     cl::cat(NMCat));
112*0b57cec5SDimitry Andric 
113*0b57cec5SDimitry Andric cl::alias PrintFileNameA("A", cl::desc("Alias for --print-file-name"),
114*0b57cec5SDimitry Andric                          cl::aliasopt(PrintFileName), cl::Grouping);
115*0b57cec5SDimitry Andric cl::alias PrintFileNameo("o", cl::desc("Alias for --print-file-name"),
116*0b57cec5SDimitry Andric                          cl::aliasopt(PrintFileName), cl::Grouping);
117*0b57cec5SDimitry Andric 
118*0b57cec5SDimitry Andric cl::opt<bool> DebugSyms("debug-syms",
119*0b57cec5SDimitry Andric                         cl::desc("Show all symbols, even debugger only"),
120*0b57cec5SDimitry Andric                         cl::cat(NMCat));
121*0b57cec5SDimitry Andric cl::alias DebugSymsa("a", cl::desc("Alias for --debug-syms"),
122*0b57cec5SDimitry Andric                      cl::aliasopt(DebugSyms), cl::Grouping);
123*0b57cec5SDimitry Andric 
124*0b57cec5SDimitry Andric cl::opt<bool> NumericSort("numeric-sort", cl::desc("Sort symbols by address"),
125*0b57cec5SDimitry Andric                           cl::cat(NMCat));
126*0b57cec5SDimitry Andric cl::alias NumericSortn("n", cl::desc("Alias for --numeric-sort"),
127*0b57cec5SDimitry Andric                        cl::aliasopt(NumericSort), cl::Grouping);
128*0b57cec5SDimitry Andric cl::alias NumericSortv("v", cl::desc("Alias for --numeric-sort"),
129*0b57cec5SDimitry Andric                        cl::aliasopt(NumericSort), cl::Grouping);
130*0b57cec5SDimitry Andric 
131*0b57cec5SDimitry Andric cl::opt<bool> NoSort("no-sort", cl::desc("Show symbols in order encountered"),
132*0b57cec5SDimitry Andric                      cl::cat(NMCat));
133*0b57cec5SDimitry Andric cl::alias NoSortp("p", cl::desc("Alias for --no-sort"), cl::aliasopt(NoSort),
134*0b57cec5SDimitry Andric                   cl::Grouping);
135*0b57cec5SDimitry Andric 
136*0b57cec5SDimitry Andric cl::opt<bool> Demangle("demangle", cl::ZeroOrMore,
137*0b57cec5SDimitry Andric                        cl::desc("Demangle C++ symbol names"), cl::cat(NMCat));
138*0b57cec5SDimitry Andric cl::alias DemangleC("C", cl::desc("Alias for --demangle"),
139*0b57cec5SDimitry Andric                     cl::aliasopt(Demangle), cl::Grouping);
140*0b57cec5SDimitry Andric cl::opt<bool> NoDemangle("no-demangle", cl::init(false), cl::ZeroOrMore,
141*0b57cec5SDimitry Andric                          cl::desc("Don't demangle symbol names"),
142*0b57cec5SDimitry Andric                          cl::cat(NMCat));
143*0b57cec5SDimitry Andric 
144*0b57cec5SDimitry Andric cl::opt<bool> ReverseSort("reverse-sort", cl::desc("Sort in reverse order"),
145*0b57cec5SDimitry Andric                           cl::cat(NMCat));
146*0b57cec5SDimitry Andric cl::alias ReverseSortr("r", cl::desc("Alias for --reverse-sort"),
147*0b57cec5SDimitry Andric                        cl::aliasopt(ReverseSort), cl::Grouping);
148*0b57cec5SDimitry Andric 
149*0b57cec5SDimitry Andric cl::opt<bool> PrintSize("print-size",
150*0b57cec5SDimitry Andric                         cl::desc("Show symbol size as well as address"),
151*0b57cec5SDimitry Andric                         cl::cat(NMCat));
152*0b57cec5SDimitry Andric cl::alias PrintSizeS("S", cl::desc("Alias for --print-size"),
153*0b57cec5SDimitry Andric                      cl::aliasopt(PrintSize), cl::Grouping);
154*0b57cec5SDimitry Andric bool MachOPrintSizeWarning = false;
155*0b57cec5SDimitry Andric 
156*0b57cec5SDimitry Andric cl::opt<bool> SizeSort("size-sort", cl::desc("Sort symbols by size"),
157*0b57cec5SDimitry Andric                        cl::cat(NMCat));
158*0b57cec5SDimitry Andric 
159*0b57cec5SDimitry Andric cl::opt<bool> WithoutAliases("without-aliases", cl::Hidden,
160*0b57cec5SDimitry Andric                              cl::desc("Exclude aliases from output"),
161*0b57cec5SDimitry Andric                              cl::cat(NMCat));
162*0b57cec5SDimitry Andric 
163*0b57cec5SDimitry Andric cl::opt<bool> ArchiveMap("print-armap", cl::desc("Print the archive map"),
164*0b57cec5SDimitry Andric                          cl::cat(NMCat));
165*0b57cec5SDimitry Andric cl::alias ArchiveMaps("M", cl::desc("Alias for --print-armap"),
166*0b57cec5SDimitry Andric                       cl::aliasopt(ArchiveMap), cl::Grouping);
167*0b57cec5SDimitry Andric 
168*0b57cec5SDimitry Andric enum Radix { d, o, x };
169*0b57cec5SDimitry Andric cl::opt<Radix>
170*0b57cec5SDimitry Andric     AddressRadix("radix", cl::desc("Radix (o/d/x) for printing symbol Values"),
171*0b57cec5SDimitry Andric                  cl::values(clEnumVal(d, "decimal"), clEnumVal(o, "octal"),
172*0b57cec5SDimitry Andric                             clEnumVal(x, "hexadecimal")),
173*0b57cec5SDimitry Andric                  cl::init(x), cl::cat(NMCat));
174*0b57cec5SDimitry Andric cl::alias RadixAlias("t", cl::desc("Alias for --radix"),
175*0b57cec5SDimitry Andric                      cl::aliasopt(AddressRadix));
176*0b57cec5SDimitry Andric 
177*0b57cec5SDimitry Andric cl::opt<bool> JustSymbolName("just-symbol-name",
178*0b57cec5SDimitry Andric                              cl::desc("Print just the symbol's name"),
179*0b57cec5SDimitry Andric                              cl::cat(NMCat));
180*0b57cec5SDimitry Andric cl::alias JustSymbolNames("j", cl::desc("Alias for --just-symbol-name"),
181*0b57cec5SDimitry Andric                           cl::aliasopt(JustSymbolName), cl::Grouping);
182*0b57cec5SDimitry Andric 
183*0b57cec5SDimitry Andric cl::opt<bool> SpecialSyms("special-syms",
184*0b57cec5SDimitry Andric                           cl::desc("No-op. Used for GNU compatibility only"));
185*0b57cec5SDimitry Andric 
186*0b57cec5SDimitry Andric cl::list<std::string> SegSect("s", cl::multi_val(2), cl::ZeroOrMore,
187*0b57cec5SDimitry Andric                               cl::value_desc("segment section"), cl::Hidden,
188*0b57cec5SDimitry Andric                               cl::desc("Dump only symbols from this segment "
189*0b57cec5SDimitry Andric                                        "and section name, Mach-O only"),
190*0b57cec5SDimitry Andric                               cl::cat(NMCat));
191*0b57cec5SDimitry Andric 
192*0b57cec5SDimitry Andric cl::opt<bool> FormatMachOasHex("x",
193*0b57cec5SDimitry Andric                                cl::desc("Print symbol entry in hex, "
194*0b57cec5SDimitry Andric                                         "Mach-O only"),
195*0b57cec5SDimitry Andric                                cl::Grouping, cl::cat(NMCat));
196*0b57cec5SDimitry Andric cl::opt<bool> AddDyldInfo("add-dyldinfo",
197*0b57cec5SDimitry Andric                           cl::desc("Add symbols from the dyldinfo not already "
198*0b57cec5SDimitry Andric                                    "in the symbol table, Mach-O only"),
199*0b57cec5SDimitry Andric                           cl::cat(NMCat));
200*0b57cec5SDimitry Andric cl::opt<bool> NoDyldInfo("no-dyldinfo",
201*0b57cec5SDimitry Andric                          cl::desc("Don't add any symbols from the dyldinfo, "
202*0b57cec5SDimitry Andric                                   "Mach-O only"),
203*0b57cec5SDimitry Andric                          cl::cat(NMCat));
204*0b57cec5SDimitry Andric cl::opt<bool> DyldInfoOnly("dyldinfo-only",
205*0b57cec5SDimitry Andric                            cl::desc("Show only symbols from the dyldinfo, "
206*0b57cec5SDimitry Andric                                     "Mach-O only"),
207*0b57cec5SDimitry Andric                            cl::cat(NMCat));
208*0b57cec5SDimitry Andric 
209*0b57cec5SDimitry Andric cl::opt<bool> NoLLVMBitcode("no-llvm-bc",
210*0b57cec5SDimitry Andric                             cl::desc("Disable LLVM bitcode reader"),
211*0b57cec5SDimitry Andric                             cl::cat(NMCat));
212*0b57cec5SDimitry Andric 
213*0b57cec5SDimitry Andric cl::extrahelp HelpResponse("\nPass @FILE as argument to read options from FILE.\n");
214*0b57cec5SDimitry Andric 
215*0b57cec5SDimitry Andric bool PrintAddress = true;
216*0b57cec5SDimitry Andric 
217*0b57cec5SDimitry Andric bool MultipleFiles = false;
218*0b57cec5SDimitry Andric 
219*0b57cec5SDimitry Andric bool HadError = false;
220*0b57cec5SDimitry Andric 
221*0b57cec5SDimitry Andric std::string ToolName;
222*0b57cec5SDimitry Andric } // anonymous namespace
223*0b57cec5SDimitry Andric 
224*0b57cec5SDimitry Andric static void error(Twine Message, Twine Path = Twine()) {
225*0b57cec5SDimitry Andric   HadError = true;
226*0b57cec5SDimitry Andric   WithColor::error(errs(), ToolName) << Path << ": " << Message << ".\n";
227*0b57cec5SDimitry Andric }
228*0b57cec5SDimitry Andric 
229*0b57cec5SDimitry Andric static bool error(std::error_code EC, Twine Path = Twine()) {
230*0b57cec5SDimitry Andric   if (EC) {
231*0b57cec5SDimitry Andric     error(EC.message(), Path);
232*0b57cec5SDimitry Andric     return true;
233*0b57cec5SDimitry Andric   }
234*0b57cec5SDimitry Andric   return false;
235*0b57cec5SDimitry Andric }
236*0b57cec5SDimitry Andric 
237*0b57cec5SDimitry Andric // This version of error() prints the archive name and member name, for example:
238*0b57cec5SDimitry Andric // "libx.a(foo.o)" after the ToolName before the error message.  It sets
239*0b57cec5SDimitry Andric // HadError but returns allowing the code to move on to other archive members.
240*0b57cec5SDimitry Andric static void error(llvm::Error E, StringRef FileName, const Archive::Child &C,
241*0b57cec5SDimitry Andric                   StringRef ArchitectureName = StringRef()) {
242*0b57cec5SDimitry Andric   HadError = true;
243*0b57cec5SDimitry Andric   WithColor::error(errs(), ToolName) << FileName;
244*0b57cec5SDimitry Andric 
245*0b57cec5SDimitry Andric   Expected<StringRef> NameOrErr = C.getName();
246*0b57cec5SDimitry Andric   // TODO: if we have a error getting the name then it would be nice to print
247*0b57cec5SDimitry Andric   // the index of which archive member this is and or its offset in the
248*0b57cec5SDimitry Andric   // archive instead of "???" as the name.
249*0b57cec5SDimitry Andric   if (!NameOrErr) {
250*0b57cec5SDimitry Andric     consumeError(NameOrErr.takeError());
251*0b57cec5SDimitry Andric     errs() << "(" << "???" << ")";
252*0b57cec5SDimitry Andric   } else
253*0b57cec5SDimitry Andric     errs() << "(" << NameOrErr.get() << ")";
254*0b57cec5SDimitry Andric 
255*0b57cec5SDimitry Andric   if (!ArchitectureName.empty())
256*0b57cec5SDimitry Andric     errs() << " (for architecture " << ArchitectureName << ") ";
257*0b57cec5SDimitry Andric 
258*0b57cec5SDimitry Andric   std::string Buf;
259*0b57cec5SDimitry Andric   raw_string_ostream OS(Buf);
260*0b57cec5SDimitry Andric   logAllUnhandledErrors(std::move(E), OS);
261*0b57cec5SDimitry Andric   OS.flush();
262*0b57cec5SDimitry Andric   errs() << " " << Buf << "\n";
263*0b57cec5SDimitry Andric }
264*0b57cec5SDimitry Andric 
265*0b57cec5SDimitry Andric // This version of error() prints the file name and which architecture slice it
266*0b57cec5SDimitry Andric // is from, for example: "foo.o (for architecture i386)" after the ToolName
267*0b57cec5SDimitry Andric // before the error message.  It sets HadError but returns allowing the code to
268*0b57cec5SDimitry Andric // move on to other architecture slices.
269*0b57cec5SDimitry Andric static void error(llvm::Error E, StringRef FileName,
270*0b57cec5SDimitry Andric                   StringRef ArchitectureName = StringRef()) {
271*0b57cec5SDimitry Andric   HadError = true;
272*0b57cec5SDimitry Andric   WithColor::error(errs(), ToolName) << FileName;
273*0b57cec5SDimitry Andric 
274*0b57cec5SDimitry Andric   if (!ArchitectureName.empty())
275*0b57cec5SDimitry Andric     errs() << " (for architecture " << ArchitectureName << ") ";
276*0b57cec5SDimitry Andric 
277*0b57cec5SDimitry Andric   std::string Buf;
278*0b57cec5SDimitry Andric   raw_string_ostream OS(Buf);
279*0b57cec5SDimitry Andric   logAllUnhandledErrors(std::move(E), OS);
280*0b57cec5SDimitry Andric   OS.flush();
281*0b57cec5SDimitry Andric   errs() << " " << Buf << "\n";
282*0b57cec5SDimitry Andric }
283*0b57cec5SDimitry Andric 
284*0b57cec5SDimitry Andric namespace {
285*0b57cec5SDimitry Andric struct NMSymbol {
286*0b57cec5SDimitry Andric   uint64_t Address;
287*0b57cec5SDimitry Andric   uint64_t Size;
288*0b57cec5SDimitry Andric   char TypeChar;
289*0b57cec5SDimitry Andric   StringRef Name;
290*0b57cec5SDimitry Andric   StringRef SectionName;
291*0b57cec5SDimitry Andric   StringRef TypeName;
292*0b57cec5SDimitry Andric   BasicSymbolRef Sym;
293*0b57cec5SDimitry Andric   // The Sym field above points to the native symbol in the object file,
294*0b57cec5SDimitry Andric   // for Mach-O when we are creating symbols from the dyld info the above
295*0b57cec5SDimitry Andric   // pointer is null as there is no native symbol.  In these cases the fields
296*0b57cec5SDimitry Andric   // below are filled in to represent what would have been a Mach-O nlist
297*0b57cec5SDimitry Andric   // native symbol.
298*0b57cec5SDimitry Andric   uint32_t SymFlags;
299*0b57cec5SDimitry Andric   SectionRef Section;
300*0b57cec5SDimitry Andric   uint8_t NType;
301*0b57cec5SDimitry Andric   uint8_t NSect;
302*0b57cec5SDimitry Andric   uint16_t NDesc;
303*0b57cec5SDimitry Andric   StringRef IndirectName;
304*0b57cec5SDimitry Andric };
305*0b57cec5SDimitry Andric } // anonymous namespace
306*0b57cec5SDimitry Andric 
307*0b57cec5SDimitry Andric static bool compareSymbolAddress(const NMSymbol &A, const NMSymbol &B) {
308*0b57cec5SDimitry Andric   bool ADefined;
309*0b57cec5SDimitry Andric   if (A.Sym.getRawDataRefImpl().p)
310*0b57cec5SDimitry Andric     ADefined = !(A.Sym.getFlags() & SymbolRef::SF_Undefined);
311*0b57cec5SDimitry Andric   else
312*0b57cec5SDimitry Andric     ADefined = A.TypeChar != 'U';
313*0b57cec5SDimitry Andric   bool BDefined;
314*0b57cec5SDimitry Andric   if (B.Sym.getRawDataRefImpl().p)
315*0b57cec5SDimitry Andric     BDefined = !(B.Sym.getFlags() & SymbolRef::SF_Undefined);
316*0b57cec5SDimitry Andric   else
317*0b57cec5SDimitry Andric     BDefined = B.TypeChar != 'U';
318*0b57cec5SDimitry Andric   return std::make_tuple(ADefined, A.Address, A.Name, A.Size) <
319*0b57cec5SDimitry Andric          std::make_tuple(BDefined, B.Address, B.Name, B.Size);
320*0b57cec5SDimitry Andric }
321*0b57cec5SDimitry Andric 
322*0b57cec5SDimitry Andric static bool compareSymbolSize(const NMSymbol &A, const NMSymbol &B) {
323*0b57cec5SDimitry Andric   return std::make_tuple(A.Size, A.Name, A.Address) <
324*0b57cec5SDimitry Andric          std::make_tuple(B.Size, B.Name, B.Address);
325*0b57cec5SDimitry Andric }
326*0b57cec5SDimitry Andric 
327*0b57cec5SDimitry Andric static bool compareSymbolName(const NMSymbol &A, const NMSymbol &B) {
328*0b57cec5SDimitry Andric   return std::make_tuple(A.Name, A.Size, A.Address) <
329*0b57cec5SDimitry Andric          std::make_tuple(B.Name, B.Size, B.Address);
330*0b57cec5SDimitry Andric }
331*0b57cec5SDimitry Andric 
332*0b57cec5SDimitry Andric static char isSymbolList64Bit(SymbolicFile &Obj) {
333*0b57cec5SDimitry Andric   if (auto *IRObj = dyn_cast<IRObjectFile>(&Obj))
334*0b57cec5SDimitry Andric     return Triple(IRObj->getTargetTriple()).isArch64Bit();
335*0b57cec5SDimitry Andric   if (isa<COFFObjectFile>(Obj) || isa<COFFImportFile>(Obj))
336*0b57cec5SDimitry Andric     return false;
337*0b57cec5SDimitry Andric   if (isa<WasmObjectFile>(Obj))
338*0b57cec5SDimitry Andric     return false;
339*0b57cec5SDimitry Andric   if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj))
340*0b57cec5SDimitry Andric     return MachO->is64Bit();
341*0b57cec5SDimitry Andric   return cast<ELFObjectFileBase>(Obj).getBytesInAddress() == 8;
342*0b57cec5SDimitry Andric }
343*0b57cec5SDimitry Andric 
344*0b57cec5SDimitry Andric static StringRef CurrentFilename;
345*0b57cec5SDimitry Andric static std::vector<NMSymbol> SymbolList;
346*0b57cec5SDimitry Andric 
347*0b57cec5SDimitry Andric static char getSymbolNMTypeChar(IRObjectFile &Obj, basic_symbol_iterator I);
348*0b57cec5SDimitry Andric 
349*0b57cec5SDimitry Andric // darwinPrintSymbol() is used to print a symbol from a Mach-O file when the
350*0b57cec5SDimitry Andric // the OutputFormat is darwin or we are printing Mach-O symbols in hex.  For
351*0b57cec5SDimitry Andric // the darwin format it produces the same output as darwin's nm(1) -m output
352*0b57cec5SDimitry Andric // and when printing Mach-O symbols in hex it produces the same output as
353*0b57cec5SDimitry Andric // darwin's nm(1) -x format.
354*0b57cec5SDimitry Andric static void darwinPrintSymbol(SymbolicFile &Obj, const NMSymbol &S,
355*0b57cec5SDimitry Andric                               char *SymbolAddrStr, const char *printBlanks,
356*0b57cec5SDimitry Andric                               const char *printDashes,
357*0b57cec5SDimitry Andric                               const char *printFormat) {
358*0b57cec5SDimitry Andric   MachO::mach_header H;
359*0b57cec5SDimitry Andric   MachO::mach_header_64 H_64;
360*0b57cec5SDimitry Andric   uint32_t Filetype = MachO::MH_OBJECT;
361*0b57cec5SDimitry Andric   uint32_t Flags = 0;
362*0b57cec5SDimitry Andric   uint8_t NType = 0;
363*0b57cec5SDimitry Andric   uint8_t NSect = 0;
364*0b57cec5SDimitry Andric   uint16_t NDesc = 0;
365*0b57cec5SDimitry Andric   uint32_t NStrx = 0;
366*0b57cec5SDimitry Andric   uint64_t NValue = 0;
367*0b57cec5SDimitry Andric   MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj);
368*0b57cec5SDimitry Andric   if (Obj.isIR()) {
369*0b57cec5SDimitry Andric     uint32_t SymFlags = S.Sym.getFlags();
370*0b57cec5SDimitry Andric     if (SymFlags & SymbolRef::SF_Global)
371*0b57cec5SDimitry Andric       NType |= MachO::N_EXT;
372*0b57cec5SDimitry Andric     if (SymFlags & SymbolRef::SF_Hidden)
373*0b57cec5SDimitry Andric       NType |= MachO::N_PEXT;
374*0b57cec5SDimitry Andric     if (SymFlags & SymbolRef::SF_Undefined)
375*0b57cec5SDimitry Andric       NType |= MachO::N_EXT | MachO::N_UNDF;
376*0b57cec5SDimitry Andric     else {
377*0b57cec5SDimitry Andric       // Here we have a symbol definition.  So to fake out a section name we
378*0b57cec5SDimitry Andric       // use 1, 2 and 3 for section numbers.  See below where they are used to
379*0b57cec5SDimitry Andric       // print out fake section names.
380*0b57cec5SDimitry Andric       NType |= MachO::N_SECT;
381*0b57cec5SDimitry Andric       if (SymFlags & SymbolRef::SF_Const)
382*0b57cec5SDimitry Andric         NSect = 3;
383*0b57cec5SDimitry Andric       else if (SymFlags & SymbolRef::SF_Executable)
384*0b57cec5SDimitry Andric         NSect = 1;
385*0b57cec5SDimitry Andric       else
386*0b57cec5SDimitry Andric         NSect = 2;
387*0b57cec5SDimitry Andric     }
388*0b57cec5SDimitry Andric     if (SymFlags & SymbolRef::SF_Weak)
389*0b57cec5SDimitry Andric       NDesc |= MachO::N_WEAK_DEF;
390*0b57cec5SDimitry Andric   } else {
391*0b57cec5SDimitry Andric     DataRefImpl SymDRI = S.Sym.getRawDataRefImpl();
392*0b57cec5SDimitry Andric     if (MachO->is64Bit()) {
393*0b57cec5SDimitry Andric       H_64 = MachO->MachOObjectFile::getHeader64();
394*0b57cec5SDimitry Andric       Filetype = H_64.filetype;
395*0b57cec5SDimitry Andric       Flags = H_64.flags;
396*0b57cec5SDimitry Andric       if (SymDRI.p){
397*0b57cec5SDimitry Andric         MachO::nlist_64 STE_64 = MachO->getSymbol64TableEntry(SymDRI);
398*0b57cec5SDimitry Andric         NType = STE_64.n_type;
399*0b57cec5SDimitry Andric         NSect = STE_64.n_sect;
400*0b57cec5SDimitry Andric         NDesc = STE_64.n_desc;
401*0b57cec5SDimitry Andric         NStrx = STE_64.n_strx;
402*0b57cec5SDimitry Andric         NValue = STE_64.n_value;
403*0b57cec5SDimitry Andric       } else {
404*0b57cec5SDimitry Andric         NType = S.NType;
405*0b57cec5SDimitry Andric         NSect = S.NSect;
406*0b57cec5SDimitry Andric         NDesc = S.NDesc;
407*0b57cec5SDimitry Andric         NStrx = 0;
408*0b57cec5SDimitry Andric         NValue = S.Address;
409*0b57cec5SDimitry Andric       }
410*0b57cec5SDimitry Andric     } else {
411*0b57cec5SDimitry Andric       H = MachO->MachOObjectFile::getHeader();
412*0b57cec5SDimitry Andric       Filetype = H.filetype;
413*0b57cec5SDimitry Andric       Flags = H.flags;
414*0b57cec5SDimitry Andric       if (SymDRI.p){
415*0b57cec5SDimitry Andric         MachO::nlist STE = MachO->getSymbolTableEntry(SymDRI);
416*0b57cec5SDimitry Andric         NType = STE.n_type;
417*0b57cec5SDimitry Andric         NSect = STE.n_sect;
418*0b57cec5SDimitry Andric         NDesc = STE.n_desc;
419*0b57cec5SDimitry Andric         NStrx = STE.n_strx;
420*0b57cec5SDimitry Andric         NValue = STE.n_value;
421*0b57cec5SDimitry Andric       } else {
422*0b57cec5SDimitry Andric         NType = S.NType;
423*0b57cec5SDimitry Andric         NSect = S.NSect;
424*0b57cec5SDimitry Andric         NDesc = S.NDesc;
425*0b57cec5SDimitry Andric         NStrx = 0;
426*0b57cec5SDimitry Andric         NValue = S.Address;
427*0b57cec5SDimitry Andric       }
428*0b57cec5SDimitry Andric     }
429*0b57cec5SDimitry Andric   }
430*0b57cec5SDimitry Andric 
431*0b57cec5SDimitry Andric   // If we are printing Mach-O symbols in hex do that and return.
432*0b57cec5SDimitry Andric   if (FormatMachOasHex) {
433*0b57cec5SDimitry Andric     outs() << format(printFormat, NValue) << ' '
434*0b57cec5SDimitry Andric            << format("%02x %02x %04x %08x", NType, NSect, NDesc, NStrx) << ' '
435*0b57cec5SDimitry Andric            << S.Name;
436*0b57cec5SDimitry Andric     if ((NType & MachO::N_TYPE) == MachO::N_INDR) {
437*0b57cec5SDimitry Andric       outs() << " (indirect for ";
438*0b57cec5SDimitry Andric       outs() << format(printFormat, NValue) << ' ';
439*0b57cec5SDimitry Andric       StringRef IndirectName;
440*0b57cec5SDimitry Andric       if (S.Sym.getRawDataRefImpl().p) {
441*0b57cec5SDimitry Andric         if (MachO->getIndirectName(S.Sym.getRawDataRefImpl(), IndirectName))
442*0b57cec5SDimitry Andric           outs() << "?)";
443*0b57cec5SDimitry Andric         else
444*0b57cec5SDimitry Andric           outs() << IndirectName << ")";
445*0b57cec5SDimitry Andric       } else
446*0b57cec5SDimitry Andric         outs() << S.IndirectName << ")";
447*0b57cec5SDimitry Andric     }
448*0b57cec5SDimitry Andric     outs() << "\n";
449*0b57cec5SDimitry Andric     return;
450*0b57cec5SDimitry Andric   }
451*0b57cec5SDimitry Andric 
452*0b57cec5SDimitry Andric   if (PrintAddress) {
453*0b57cec5SDimitry Andric     if ((NType & MachO::N_TYPE) == MachO::N_INDR)
454*0b57cec5SDimitry Andric       strcpy(SymbolAddrStr, printBlanks);
455*0b57cec5SDimitry Andric     if (Obj.isIR() && (NType & MachO::N_TYPE) == MachO::N_TYPE)
456*0b57cec5SDimitry Andric       strcpy(SymbolAddrStr, printDashes);
457*0b57cec5SDimitry Andric     outs() << SymbolAddrStr << ' ';
458*0b57cec5SDimitry Andric   }
459*0b57cec5SDimitry Andric 
460*0b57cec5SDimitry Andric   switch (NType & MachO::N_TYPE) {
461*0b57cec5SDimitry Andric   case MachO::N_UNDF:
462*0b57cec5SDimitry Andric     if (NValue != 0) {
463*0b57cec5SDimitry Andric       outs() << "(common) ";
464*0b57cec5SDimitry Andric       if (MachO::GET_COMM_ALIGN(NDesc) != 0)
465*0b57cec5SDimitry Andric         outs() << "(alignment 2^" << (int)MachO::GET_COMM_ALIGN(NDesc) << ") ";
466*0b57cec5SDimitry Andric     } else {
467*0b57cec5SDimitry Andric       if ((NType & MachO::N_TYPE) == MachO::N_PBUD)
468*0b57cec5SDimitry Andric         outs() << "(prebound ";
469*0b57cec5SDimitry Andric       else
470*0b57cec5SDimitry Andric         outs() << "(";
471*0b57cec5SDimitry Andric       if ((NDesc & MachO::REFERENCE_TYPE) ==
472*0b57cec5SDimitry Andric           MachO::REFERENCE_FLAG_UNDEFINED_LAZY)
473*0b57cec5SDimitry Andric         outs() << "undefined [lazy bound]) ";
474*0b57cec5SDimitry Andric       else if ((NDesc & MachO::REFERENCE_TYPE) ==
475*0b57cec5SDimitry Andric                MachO::REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY)
476*0b57cec5SDimitry Andric         outs() << "undefined [private lazy bound]) ";
477*0b57cec5SDimitry Andric       else if ((NDesc & MachO::REFERENCE_TYPE) ==
478*0b57cec5SDimitry Andric                MachO::REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY)
479*0b57cec5SDimitry Andric         outs() << "undefined [private]) ";
480*0b57cec5SDimitry Andric       else
481*0b57cec5SDimitry Andric         outs() << "undefined) ";
482*0b57cec5SDimitry Andric     }
483*0b57cec5SDimitry Andric     break;
484*0b57cec5SDimitry Andric   case MachO::N_ABS:
485*0b57cec5SDimitry Andric     outs() << "(absolute) ";
486*0b57cec5SDimitry Andric     break;
487*0b57cec5SDimitry Andric   case MachO::N_INDR:
488*0b57cec5SDimitry Andric     outs() << "(indirect) ";
489*0b57cec5SDimitry Andric     break;
490*0b57cec5SDimitry Andric   case MachO::N_SECT: {
491*0b57cec5SDimitry Andric     if (Obj.isIR()) {
492*0b57cec5SDimitry Andric       // For llvm bitcode files print out a fake section name using the values
493*0b57cec5SDimitry Andric       // use 1, 2 and 3 for section numbers as set above.
494*0b57cec5SDimitry Andric       if (NSect == 1)
495*0b57cec5SDimitry Andric         outs() << "(LTO,CODE) ";
496*0b57cec5SDimitry Andric       else if (NSect == 2)
497*0b57cec5SDimitry Andric         outs() << "(LTO,DATA) ";
498*0b57cec5SDimitry Andric       else if (NSect == 3)
499*0b57cec5SDimitry Andric         outs() << "(LTO,RODATA) ";
500*0b57cec5SDimitry Andric       else
501*0b57cec5SDimitry Andric         outs() << "(?,?) ";
502*0b57cec5SDimitry Andric       break;
503*0b57cec5SDimitry Andric     }
504*0b57cec5SDimitry Andric     section_iterator Sec = SectionRef();
505*0b57cec5SDimitry Andric     if (S.Sym.getRawDataRefImpl().p) {
506*0b57cec5SDimitry Andric       Expected<section_iterator> SecOrErr =
507*0b57cec5SDimitry Andric           MachO->getSymbolSection(S.Sym.getRawDataRefImpl());
508*0b57cec5SDimitry Andric       if (!SecOrErr) {
509*0b57cec5SDimitry Andric         consumeError(SecOrErr.takeError());
510*0b57cec5SDimitry Andric         outs() << "(?,?) ";
511*0b57cec5SDimitry Andric         break;
512*0b57cec5SDimitry Andric       }
513*0b57cec5SDimitry Andric       Sec = *SecOrErr;
514*0b57cec5SDimitry Andric       if (Sec == MachO->section_end()) {
515*0b57cec5SDimitry Andric         outs() << "(?,?) ";
516*0b57cec5SDimitry Andric         break;
517*0b57cec5SDimitry Andric       }
518*0b57cec5SDimitry Andric     } else {
519*0b57cec5SDimitry Andric       Sec = S.Section;
520*0b57cec5SDimitry Andric     }
521*0b57cec5SDimitry Andric     DataRefImpl Ref = Sec->getRawDataRefImpl();
522*0b57cec5SDimitry Andric     StringRef SectionName;
523*0b57cec5SDimitry Andric     if (Expected<StringRef> NameOrErr = MachO->getSectionName(Ref))
524*0b57cec5SDimitry Andric       SectionName = *NameOrErr;
525*0b57cec5SDimitry Andric     StringRef SegmentName = MachO->getSectionFinalSegmentName(Ref);
526*0b57cec5SDimitry Andric     outs() << "(" << SegmentName << "," << SectionName << ") ";
527*0b57cec5SDimitry Andric     break;
528*0b57cec5SDimitry Andric   }
529*0b57cec5SDimitry Andric   default:
530*0b57cec5SDimitry Andric     outs() << "(?) ";
531*0b57cec5SDimitry Andric     break;
532*0b57cec5SDimitry Andric   }
533*0b57cec5SDimitry Andric 
534*0b57cec5SDimitry Andric   if (NType & MachO::N_EXT) {
535*0b57cec5SDimitry Andric     if (NDesc & MachO::REFERENCED_DYNAMICALLY)
536*0b57cec5SDimitry Andric       outs() << "[referenced dynamically] ";
537*0b57cec5SDimitry Andric     if (NType & MachO::N_PEXT) {
538*0b57cec5SDimitry Andric       if ((NDesc & MachO::N_WEAK_DEF) == MachO::N_WEAK_DEF)
539*0b57cec5SDimitry Andric         outs() << "weak private external ";
540*0b57cec5SDimitry Andric       else
541*0b57cec5SDimitry Andric         outs() << "private external ";
542*0b57cec5SDimitry Andric     } else {
543*0b57cec5SDimitry Andric       if ((NDesc & MachO::N_WEAK_REF) == MachO::N_WEAK_REF ||
544*0b57cec5SDimitry Andric           (NDesc & MachO::N_WEAK_DEF) == MachO::N_WEAK_DEF) {
545*0b57cec5SDimitry Andric         if ((NDesc & (MachO::N_WEAK_REF | MachO::N_WEAK_DEF)) ==
546*0b57cec5SDimitry Andric             (MachO::N_WEAK_REF | MachO::N_WEAK_DEF))
547*0b57cec5SDimitry Andric           outs() << "weak external automatically hidden ";
548*0b57cec5SDimitry Andric         else
549*0b57cec5SDimitry Andric           outs() << "weak external ";
550*0b57cec5SDimitry Andric       } else
551*0b57cec5SDimitry Andric         outs() << "external ";
552*0b57cec5SDimitry Andric     }
553*0b57cec5SDimitry Andric   } else {
554*0b57cec5SDimitry Andric     if (NType & MachO::N_PEXT)
555*0b57cec5SDimitry Andric       outs() << "non-external (was a private external) ";
556*0b57cec5SDimitry Andric     else
557*0b57cec5SDimitry Andric       outs() << "non-external ";
558*0b57cec5SDimitry Andric   }
559*0b57cec5SDimitry Andric 
560*0b57cec5SDimitry Andric   if (Filetype == MachO::MH_OBJECT) {
561*0b57cec5SDimitry Andric     if (NDesc & MachO::N_NO_DEAD_STRIP)
562*0b57cec5SDimitry Andric       outs() << "[no dead strip] ";
563*0b57cec5SDimitry Andric     if ((NType & MachO::N_TYPE) != MachO::N_UNDF &&
564*0b57cec5SDimitry Andric         NDesc & MachO::N_SYMBOL_RESOLVER)
565*0b57cec5SDimitry Andric       outs() << "[symbol resolver] ";
566*0b57cec5SDimitry Andric     if ((NType & MachO::N_TYPE) != MachO::N_UNDF && NDesc & MachO::N_ALT_ENTRY)
567*0b57cec5SDimitry Andric       outs() << "[alt entry] ";
568*0b57cec5SDimitry Andric     if ((NType & MachO::N_TYPE) != MachO::N_UNDF && NDesc & MachO::N_COLD_FUNC)
569*0b57cec5SDimitry Andric       outs() << "[cold func] ";
570*0b57cec5SDimitry Andric   }
571*0b57cec5SDimitry Andric 
572*0b57cec5SDimitry Andric   if ((NDesc & MachO::N_ARM_THUMB_DEF) == MachO::N_ARM_THUMB_DEF)
573*0b57cec5SDimitry Andric     outs() << "[Thumb] ";
574*0b57cec5SDimitry Andric 
575*0b57cec5SDimitry Andric   if ((NType & MachO::N_TYPE) == MachO::N_INDR) {
576*0b57cec5SDimitry Andric     outs() << S.Name << " (for ";
577*0b57cec5SDimitry Andric     StringRef IndirectName;
578*0b57cec5SDimitry Andric     if (MachO) {
579*0b57cec5SDimitry Andric       if (S.Sym.getRawDataRefImpl().p) {
580*0b57cec5SDimitry Andric         if (MachO->getIndirectName(S.Sym.getRawDataRefImpl(), IndirectName))
581*0b57cec5SDimitry Andric           outs() << "?)";
582*0b57cec5SDimitry Andric         else
583*0b57cec5SDimitry Andric           outs() << IndirectName << ")";
584*0b57cec5SDimitry Andric       } else
585*0b57cec5SDimitry Andric         outs() << S.IndirectName << ")";
586*0b57cec5SDimitry Andric     } else
587*0b57cec5SDimitry Andric       outs() << "?)";
588*0b57cec5SDimitry Andric   } else
589*0b57cec5SDimitry Andric     outs() << S.Name;
590*0b57cec5SDimitry Andric 
591*0b57cec5SDimitry Andric   if ((Flags & MachO::MH_TWOLEVEL) == MachO::MH_TWOLEVEL &&
592*0b57cec5SDimitry Andric       (((NType & MachO::N_TYPE) == MachO::N_UNDF && NValue == 0) ||
593*0b57cec5SDimitry Andric        (NType & MachO::N_TYPE) == MachO::N_PBUD)) {
594*0b57cec5SDimitry Andric     uint32_t LibraryOrdinal = MachO::GET_LIBRARY_ORDINAL(NDesc);
595*0b57cec5SDimitry Andric     if (LibraryOrdinal != 0) {
596*0b57cec5SDimitry Andric       if (LibraryOrdinal == MachO::EXECUTABLE_ORDINAL)
597*0b57cec5SDimitry Andric         outs() << " (from executable)";
598*0b57cec5SDimitry Andric       else if (LibraryOrdinal == MachO::DYNAMIC_LOOKUP_ORDINAL)
599*0b57cec5SDimitry Andric         outs() << " (dynamically looked up)";
600*0b57cec5SDimitry Andric       else {
601*0b57cec5SDimitry Andric         StringRef LibraryName;
602*0b57cec5SDimitry Andric         if (!MachO ||
603*0b57cec5SDimitry Andric             MachO->getLibraryShortNameByIndex(LibraryOrdinal - 1, LibraryName))
604*0b57cec5SDimitry Andric           outs() << " (from bad library ordinal " << LibraryOrdinal << ")";
605*0b57cec5SDimitry Andric         else
606*0b57cec5SDimitry Andric           outs() << " (from " << LibraryName << ")";
607*0b57cec5SDimitry Andric       }
608*0b57cec5SDimitry Andric     }
609*0b57cec5SDimitry Andric   }
610*0b57cec5SDimitry Andric 
611*0b57cec5SDimitry Andric   outs() << "\n";
612*0b57cec5SDimitry Andric }
613*0b57cec5SDimitry Andric 
614*0b57cec5SDimitry Andric // Table that maps Darwin's Mach-O stab constants to strings to allow printing.
615*0b57cec5SDimitry Andric struct DarwinStabName {
616*0b57cec5SDimitry Andric   uint8_t NType;
617*0b57cec5SDimitry Andric   const char *Name;
618*0b57cec5SDimitry Andric };
619*0b57cec5SDimitry Andric static const struct DarwinStabName DarwinStabNames[] = {
620*0b57cec5SDimitry Andric     {MachO::N_GSYM, "GSYM"},
621*0b57cec5SDimitry Andric     {MachO::N_FNAME, "FNAME"},
622*0b57cec5SDimitry Andric     {MachO::N_FUN, "FUN"},
623*0b57cec5SDimitry Andric     {MachO::N_STSYM, "STSYM"},
624*0b57cec5SDimitry Andric     {MachO::N_LCSYM, "LCSYM"},
625*0b57cec5SDimitry Andric     {MachO::N_BNSYM, "BNSYM"},
626*0b57cec5SDimitry Andric     {MachO::N_PC, "PC"},
627*0b57cec5SDimitry Andric     {MachO::N_AST, "AST"},
628*0b57cec5SDimitry Andric     {MachO::N_OPT, "OPT"},
629*0b57cec5SDimitry Andric     {MachO::N_RSYM, "RSYM"},
630*0b57cec5SDimitry Andric     {MachO::N_SLINE, "SLINE"},
631*0b57cec5SDimitry Andric     {MachO::N_ENSYM, "ENSYM"},
632*0b57cec5SDimitry Andric     {MachO::N_SSYM, "SSYM"},
633*0b57cec5SDimitry Andric     {MachO::N_SO, "SO"},
634*0b57cec5SDimitry Andric     {MachO::N_OSO, "OSO"},
635*0b57cec5SDimitry Andric     {MachO::N_LSYM, "LSYM"},
636*0b57cec5SDimitry Andric     {MachO::N_BINCL, "BINCL"},
637*0b57cec5SDimitry Andric     {MachO::N_SOL, "SOL"},
638*0b57cec5SDimitry Andric     {MachO::N_PARAMS, "PARAM"},
639*0b57cec5SDimitry Andric     {MachO::N_VERSION, "VERS"},
640*0b57cec5SDimitry Andric     {MachO::N_OLEVEL, "OLEV"},
641*0b57cec5SDimitry Andric     {MachO::N_PSYM, "PSYM"},
642*0b57cec5SDimitry Andric     {MachO::N_EINCL, "EINCL"},
643*0b57cec5SDimitry Andric     {MachO::N_ENTRY, "ENTRY"},
644*0b57cec5SDimitry Andric     {MachO::N_LBRAC, "LBRAC"},
645*0b57cec5SDimitry Andric     {MachO::N_EXCL, "EXCL"},
646*0b57cec5SDimitry Andric     {MachO::N_RBRAC, "RBRAC"},
647*0b57cec5SDimitry Andric     {MachO::N_BCOMM, "BCOMM"},
648*0b57cec5SDimitry Andric     {MachO::N_ECOMM, "ECOMM"},
649*0b57cec5SDimitry Andric     {MachO::N_ECOML, "ECOML"},
650*0b57cec5SDimitry Andric     {MachO::N_LENG, "LENG"},
651*0b57cec5SDimitry Andric };
652*0b57cec5SDimitry Andric 
653*0b57cec5SDimitry Andric static const char *getDarwinStabString(uint8_t NType) {
654*0b57cec5SDimitry Andric   for (auto I : makeArrayRef(DarwinStabNames))
655*0b57cec5SDimitry Andric     if (I.NType == NType)
656*0b57cec5SDimitry Andric       return I.Name;
657*0b57cec5SDimitry Andric   return nullptr;
658*0b57cec5SDimitry Andric }
659*0b57cec5SDimitry Andric 
660*0b57cec5SDimitry Andric // darwinPrintStab() prints the n_sect, n_desc along with a symbolic name of
661*0b57cec5SDimitry Andric // a stab n_type value in a Mach-O file.
662*0b57cec5SDimitry Andric static void darwinPrintStab(MachOObjectFile *MachO, const NMSymbol &S) {
663*0b57cec5SDimitry Andric   MachO::nlist_64 STE_64;
664*0b57cec5SDimitry Andric   MachO::nlist STE;
665*0b57cec5SDimitry Andric   uint8_t NType;
666*0b57cec5SDimitry Andric   uint8_t NSect;
667*0b57cec5SDimitry Andric   uint16_t NDesc;
668*0b57cec5SDimitry Andric   DataRefImpl SymDRI = S.Sym.getRawDataRefImpl();
669*0b57cec5SDimitry Andric   if (MachO->is64Bit()) {
670*0b57cec5SDimitry Andric     STE_64 = MachO->getSymbol64TableEntry(SymDRI);
671*0b57cec5SDimitry Andric     NType = STE_64.n_type;
672*0b57cec5SDimitry Andric     NSect = STE_64.n_sect;
673*0b57cec5SDimitry Andric     NDesc = STE_64.n_desc;
674*0b57cec5SDimitry Andric   } else {
675*0b57cec5SDimitry Andric     STE = MachO->getSymbolTableEntry(SymDRI);
676*0b57cec5SDimitry Andric     NType = STE.n_type;
677*0b57cec5SDimitry Andric     NSect = STE.n_sect;
678*0b57cec5SDimitry Andric     NDesc = STE.n_desc;
679*0b57cec5SDimitry Andric   }
680*0b57cec5SDimitry Andric 
681*0b57cec5SDimitry Andric   outs() << format(" %02x %04x ", NSect, NDesc);
682*0b57cec5SDimitry Andric   if (const char *stabString = getDarwinStabString(NType))
683*0b57cec5SDimitry Andric     outs() << format("%5.5s", stabString);
684*0b57cec5SDimitry Andric   else
685*0b57cec5SDimitry Andric     outs() << format("   %02x", NType);
686*0b57cec5SDimitry Andric }
687*0b57cec5SDimitry Andric 
688*0b57cec5SDimitry Andric static Optional<std::string> demangle(StringRef Name, bool StripUnderscore) {
689*0b57cec5SDimitry Andric   if (StripUnderscore && !Name.empty() && Name[0] == '_')
690*0b57cec5SDimitry Andric     Name = Name.substr(1);
691*0b57cec5SDimitry Andric 
692*0b57cec5SDimitry Andric   if (!Name.startswith("_Z"))
693*0b57cec5SDimitry Andric     return None;
694*0b57cec5SDimitry Andric 
695*0b57cec5SDimitry Andric   int Status;
696*0b57cec5SDimitry Andric   char *Undecorated =
697*0b57cec5SDimitry Andric       itaniumDemangle(Name.str().c_str(), nullptr, nullptr, &Status);
698*0b57cec5SDimitry Andric   if (Status != 0)
699*0b57cec5SDimitry Andric     return None;
700*0b57cec5SDimitry Andric 
701*0b57cec5SDimitry Andric   std::string S(Undecorated);
702*0b57cec5SDimitry Andric   free(Undecorated);
703*0b57cec5SDimitry Andric   return S;
704*0b57cec5SDimitry Andric }
705*0b57cec5SDimitry Andric 
706*0b57cec5SDimitry Andric static bool symbolIsDefined(const NMSymbol &Sym) {
707*0b57cec5SDimitry Andric   return Sym.TypeChar != 'U' && Sym.TypeChar != 'w' && Sym.TypeChar != 'v';
708*0b57cec5SDimitry Andric }
709*0b57cec5SDimitry Andric 
710*0b57cec5SDimitry Andric static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName,
711*0b57cec5SDimitry Andric                                    const std::string &ArchiveName,
712*0b57cec5SDimitry Andric                                    const std::string &ArchitectureName) {
713*0b57cec5SDimitry Andric   if (!NoSort) {
714*0b57cec5SDimitry Andric     std::function<bool(const NMSymbol &, const NMSymbol &)> Cmp;
715*0b57cec5SDimitry Andric     if (NumericSort)
716*0b57cec5SDimitry Andric       Cmp = compareSymbolAddress;
717*0b57cec5SDimitry Andric     else if (SizeSort)
718*0b57cec5SDimitry Andric       Cmp = compareSymbolSize;
719*0b57cec5SDimitry Andric     else
720*0b57cec5SDimitry Andric       Cmp = compareSymbolName;
721*0b57cec5SDimitry Andric 
722*0b57cec5SDimitry Andric     if (ReverseSort)
723*0b57cec5SDimitry Andric       Cmp = [=](const NMSymbol &A, const NMSymbol &B) { return Cmp(B, A); };
724*0b57cec5SDimitry Andric     llvm::sort(SymbolList, Cmp);
725*0b57cec5SDimitry Andric   }
726*0b57cec5SDimitry Andric 
727*0b57cec5SDimitry Andric   if (!PrintFileName) {
728*0b57cec5SDimitry Andric     if (OutputFormat == posix && MultipleFiles && printName) {
729*0b57cec5SDimitry Andric       outs() << '\n' << CurrentFilename << ":\n";
730*0b57cec5SDimitry Andric     } else if (OutputFormat == bsd && MultipleFiles && printName) {
731*0b57cec5SDimitry Andric       outs() << "\n" << CurrentFilename << ":\n";
732*0b57cec5SDimitry Andric     } else if (OutputFormat == sysv) {
733*0b57cec5SDimitry Andric       outs() << "\n\nSymbols from " << CurrentFilename << ":\n\n";
734*0b57cec5SDimitry Andric       if (isSymbolList64Bit(Obj))
735*0b57cec5SDimitry Andric         outs() << "Name                  Value           Class        Type"
736*0b57cec5SDimitry Andric                << "         Size             Line  Section\n";
737*0b57cec5SDimitry Andric       else
738*0b57cec5SDimitry Andric         outs() << "Name                  Value   Class        Type"
739*0b57cec5SDimitry Andric                << "         Size     Line  Section\n";
740*0b57cec5SDimitry Andric     }
741*0b57cec5SDimitry Andric   }
742*0b57cec5SDimitry Andric 
743*0b57cec5SDimitry Andric   const char *printBlanks, *printDashes, *printFormat;
744*0b57cec5SDimitry Andric   if (isSymbolList64Bit(Obj)) {
745*0b57cec5SDimitry Andric     printBlanks = "                ";
746*0b57cec5SDimitry Andric     printDashes = "----------------";
747*0b57cec5SDimitry Andric     switch (AddressRadix) {
748*0b57cec5SDimitry Andric     case Radix::o:
749*0b57cec5SDimitry Andric       printFormat = OutputFormat == posix ? "%" PRIo64 : "%016" PRIo64;
750*0b57cec5SDimitry Andric       break;
751*0b57cec5SDimitry Andric     case Radix::x:
752*0b57cec5SDimitry Andric       printFormat = OutputFormat == posix ? "%" PRIx64 : "%016" PRIx64;
753*0b57cec5SDimitry Andric       break;
754*0b57cec5SDimitry Andric     default:
755*0b57cec5SDimitry Andric       printFormat = OutputFormat == posix ? "%" PRId64 : "%016" PRId64;
756*0b57cec5SDimitry Andric     }
757*0b57cec5SDimitry Andric   } else {
758*0b57cec5SDimitry Andric     printBlanks = "        ";
759*0b57cec5SDimitry Andric     printDashes = "--------";
760*0b57cec5SDimitry Andric     switch (AddressRadix) {
761*0b57cec5SDimitry Andric     case Radix::o:
762*0b57cec5SDimitry Andric       printFormat = OutputFormat == posix ? "%" PRIo64 : "%08" PRIo64;
763*0b57cec5SDimitry Andric       break;
764*0b57cec5SDimitry Andric     case Radix::x:
765*0b57cec5SDimitry Andric       printFormat = OutputFormat == posix ? "%" PRIx64 : "%08" PRIx64;
766*0b57cec5SDimitry Andric       break;
767*0b57cec5SDimitry Andric     default:
768*0b57cec5SDimitry Andric       printFormat = OutputFormat == posix ? "%" PRId64 : "%08" PRId64;
769*0b57cec5SDimitry Andric     }
770*0b57cec5SDimitry Andric   }
771*0b57cec5SDimitry Andric 
772*0b57cec5SDimitry Andric   auto writeFileName = [&](raw_ostream &S) {
773*0b57cec5SDimitry Andric     if (!ArchitectureName.empty())
774*0b57cec5SDimitry Andric       S << "(for architecture " << ArchitectureName << "):";
775*0b57cec5SDimitry Andric     if (OutputFormat == posix && !ArchiveName.empty())
776*0b57cec5SDimitry Andric       S << ArchiveName << "[" << CurrentFilename << "]: ";
777*0b57cec5SDimitry Andric     else {
778*0b57cec5SDimitry Andric       if (!ArchiveName.empty())
779*0b57cec5SDimitry Andric         S << ArchiveName << ":";
780*0b57cec5SDimitry Andric       S << CurrentFilename << ": ";
781*0b57cec5SDimitry Andric     }
782*0b57cec5SDimitry Andric   };
783*0b57cec5SDimitry Andric 
784*0b57cec5SDimitry Andric   if (SymbolList.empty()) {
785*0b57cec5SDimitry Andric     if (PrintFileName)
786*0b57cec5SDimitry Andric       writeFileName(errs());
787*0b57cec5SDimitry Andric     errs() << "no symbols\n";
788*0b57cec5SDimitry Andric   }
789*0b57cec5SDimitry Andric 
790*0b57cec5SDimitry Andric   for (const NMSymbol &S : SymbolList) {
791*0b57cec5SDimitry Andric     uint32_t SymFlags;
792*0b57cec5SDimitry Andric     std::string Name = S.Name.str();
793*0b57cec5SDimitry Andric     MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj);
794*0b57cec5SDimitry Andric     if (Demangle) {
795*0b57cec5SDimitry Andric       if (Optional<std::string> Opt = demangle(S.Name, MachO))
796*0b57cec5SDimitry Andric         Name = *Opt;
797*0b57cec5SDimitry Andric     }
798*0b57cec5SDimitry Andric     if (S.Sym.getRawDataRefImpl().p)
799*0b57cec5SDimitry Andric       SymFlags = S.Sym.getFlags();
800*0b57cec5SDimitry Andric     else
801*0b57cec5SDimitry Andric       SymFlags = S.SymFlags;
802*0b57cec5SDimitry Andric 
803*0b57cec5SDimitry Andric     bool Undefined = SymFlags & SymbolRef::SF_Undefined;
804*0b57cec5SDimitry Andric     bool Global = SymFlags & SymbolRef::SF_Global;
805*0b57cec5SDimitry Andric     bool Weak = SymFlags & SymbolRef::SF_Weak;
806*0b57cec5SDimitry Andric     if ((!Undefined && UndefinedOnly) || (Undefined && DefinedOnly) ||
807*0b57cec5SDimitry Andric         (!Global && ExternalOnly) || (Weak && NoWeakSymbols))
808*0b57cec5SDimitry Andric       continue;
809*0b57cec5SDimitry Andric     if (PrintFileName)
810*0b57cec5SDimitry Andric       writeFileName(outs());
811*0b57cec5SDimitry Andric     if ((JustSymbolName ||
812*0b57cec5SDimitry Andric          (UndefinedOnly && MachO && OutputFormat != darwin)) &&
813*0b57cec5SDimitry Andric         OutputFormat != posix) {
814*0b57cec5SDimitry Andric       outs() << Name << "\n";
815*0b57cec5SDimitry Andric       continue;
816*0b57cec5SDimitry Andric     }
817*0b57cec5SDimitry Andric 
818*0b57cec5SDimitry Andric     char SymbolAddrStr[23], SymbolSizeStr[23];
819*0b57cec5SDimitry Andric 
820*0b57cec5SDimitry Andric     // If the format is SysV or the symbol isn't defined, then print spaces.
821*0b57cec5SDimitry Andric     if (OutputFormat == sysv || !symbolIsDefined(S)) {
822*0b57cec5SDimitry Andric       if (OutputFormat == posix) {
823*0b57cec5SDimitry Andric         format(printFormat, S.Address)
824*0b57cec5SDimitry Andric             .print(SymbolAddrStr, sizeof(SymbolAddrStr));
825*0b57cec5SDimitry Andric         format(printFormat, S.Size).print(SymbolSizeStr, sizeof(SymbolSizeStr));
826*0b57cec5SDimitry Andric       } else {
827*0b57cec5SDimitry Andric         strcpy(SymbolAddrStr, printBlanks);
828*0b57cec5SDimitry Andric         strcpy(SymbolSizeStr, printBlanks);
829*0b57cec5SDimitry Andric       }
830*0b57cec5SDimitry Andric     }
831*0b57cec5SDimitry Andric 
832*0b57cec5SDimitry Andric     if (symbolIsDefined(S)) {
833*0b57cec5SDimitry Andric       // Otherwise, print the symbol address and size.
834*0b57cec5SDimitry Andric       if (Obj.isIR())
835*0b57cec5SDimitry Andric         strcpy(SymbolAddrStr, printDashes);
836*0b57cec5SDimitry Andric       else if (MachO && S.TypeChar == 'I')
837*0b57cec5SDimitry Andric         strcpy(SymbolAddrStr, printBlanks);
838*0b57cec5SDimitry Andric       else
839*0b57cec5SDimitry Andric         format(printFormat, S.Address)
840*0b57cec5SDimitry Andric             .print(SymbolAddrStr, sizeof(SymbolAddrStr));
841*0b57cec5SDimitry Andric       format(printFormat, S.Size).print(SymbolSizeStr, sizeof(SymbolSizeStr));
842*0b57cec5SDimitry Andric     }
843*0b57cec5SDimitry Andric 
844*0b57cec5SDimitry Andric     // If OutputFormat is darwin or we are printing Mach-O symbols in hex and
845*0b57cec5SDimitry Andric     // we have a MachOObjectFile, call darwinPrintSymbol to print as darwin's
846*0b57cec5SDimitry Andric     // nm(1) -m output or hex, else if OutputFormat is darwin or we are
847*0b57cec5SDimitry Andric     // printing Mach-O symbols in hex and not a Mach-O object fall back to
848*0b57cec5SDimitry Andric     // OutputFormat bsd (see below).
849*0b57cec5SDimitry Andric     if ((OutputFormat == darwin || FormatMachOasHex) && (MachO || Obj.isIR())) {
850*0b57cec5SDimitry Andric       darwinPrintSymbol(Obj, S, SymbolAddrStr, printBlanks, printDashes,
851*0b57cec5SDimitry Andric                         printFormat);
852*0b57cec5SDimitry Andric     } else if (OutputFormat == posix) {
853*0b57cec5SDimitry Andric       outs() << Name << " " << S.TypeChar << " " << SymbolAddrStr << " "
854*0b57cec5SDimitry Andric              << (MachO ? "0" : SymbolSizeStr) << "\n";
855*0b57cec5SDimitry Andric     } else if (OutputFormat == bsd || (OutputFormat == darwin && !MachO)) {
856*0b57cec5SDimitry Andric       if (PrintAddress)
857*0b57cec5SDimitry Andric         outs() << SymbolAddrStr << ' ';
858*0b57cec5SDimitry Andric       if (PrintSize)
859*0b57cec5SDimitry Andric         outs() << SymbolSizeStr << ' ';
860*0b57cec5SDimitry Andric       outs() << S.TypeChar;
861*0b57cec5SDimitry Andric       if (S.TypeChar == '-' && MachO)
862*0b57cec5SDimitry Andric         darwinPrintStab(MachO, S);
863*0b57cec5SDimitry Andric       outs() << " " << Name;
864*0b57cec5SDimitry Andric       if (S.TypeChar == 'I' && MachO) {
865*0b57cec5SDimitry Andric         outs() << " (indirect for ";
866*0b57cec5SDimitry Andric         if (S.Sym.getRawDataRefImpl().p) {
867*0b57cec5SDimitry Andric           StringRef IndirectName;
868*0b57cec5SDimitry Andric           if (MachO->getIndirectName(S.Sym.getRawDataRefImpl(), IndirectName))
869*0b57cec5SDimitry Andric             outs() << "?)";
870*0b57cec5SDimitry Andric           else
871*0b57cec5SDimitry Andric             outs() << IndirectName << ")";
872*0b57cec5SDimitry Andric         } else
873*0b57cec5SDimitry Andric           outs() << S.IndirectName << ")";
874*0b57cec5SDimitry Andric       }
875*0b57cec5SDimitry Andric       outs() << "\n";
876*0b57cec5SDimitry Andric     } else if (OutputFormat == sysv) {
877*0b57cec5SDimitry Andric       outs() << left_justify(Name, 20) << "|" << SymbolAddrStr << "|   "
878*0b57cec5SDimitry Andric              << S.TypeChar << "  |" << right_justify(S.TypeName, 18) << "|"
879*0b57cec5SDimitry Andric              << SymbolSizeStr << "|     |" << S.SectionName << "\n";
880*0b57cec5SDimitry Andric     }
881*0b57cec5SDimitry Andric   }
882*0b57cec5SDimitry Andric 
883*0b57cec5SDimitry Andric   SymbolList.clear();
884*0b57cec5SDimitry Andric }
885*0b57cec5SDimitry Andric 
886*0b57cec5SDimitry Andric static char getSymbolNMTypeChar(ELFObjectFileBase &Obj,
887*0b57cec5SDimitry Andric                                 basic_symbol_iterator I) {
888*0b57cec5SDimitry Andric   // OK, this is ELF
889*0b57cec5SDimitry Andric   elf_symbol_iterator SymI(I);
890*0b57cec5SDimitry Andric 
891*0b57cec5SDimitry Andric   Expected<elf_section_iterator> SecIOrErr = SymI->getSection();
892*0b57cec5SDimitry Andric   if (!SecIOrErr) {
893*0b57cec5SDimitry Andric     consumeError(SecIOrErr.takeError());
894*0b57cec5SDimitry Andric     return '?';
895*0b57cec5SDimitry Andric   }
896*0b57cec5SDimitry Andric 
897*0b57cec5SDimitry Andric   uint8_t Binding = SymI->getBinding();
898*0b57cec5SDimitry Andric   if (Binding == ELF::STB_GNU_UNIQUE)
899*0b57cec5SDimitry Andric     return 'u';
900*0b57cec5SDimitry Andric 
901*0b57cec5SDimitry Andric   assert(Binding != ELF::STB_WEAK && "STB_WEAK not tested in calling function");
902*0b57cec5SDimitry Andric   if (Binding != ELF::STB_GLOBAL && Binding != ELF::STB_LOCAL)
903*0b57cec5SDimitry Andric     return '?';
904*0b57cec5SDimitry Andric 
905*0b57cec5SDimitry Andric   elf_section_iterator SecI = *SecIOrErr;
906*0b57cec5SDimitry Andric   if (SecI != Obj.section_end()) {
907*0b57cec5SDimitry Andric     uint32_t Type = SecI->getType();
908*0b57cec5SDimitry Andric     uint64_t Flags = SecI->getFlags();
909*0b57cec5SDimitry Andric     if (Flags & ELF::SHF_EXECINSTR)
910*0b57cec5SDimitry Andric       return 't';
911*0b57cec5SDimitry Andric     if (Type == ELF::SHT_NOBITS)
912*0b57cec5SDimitry Andric       return 'b';
913*0b57cec5SDimitry Andric     if (Flags & ELF::SHF_ALLOC)
914*0b57cec5SDimitry Andric       return Flags & ELF::SHF_WRITE ? 'd' : 'r';
915*0b57cec5SDimitry Andric 
916*0b57cec5SDimitry Andric     StringRef SecName;
917*0b57cec5SDimitry Andric     if (SecI->getName(SecName))
918*0b57cec5SDimitry Andric       return '?';
919*0b57cec5SDimitry Andric     if (SecName.startswith(".debug"))
920*0b57cec5SDimitry Andric       return 'N';
921*0b57cec5SDimitry Andric     if (!(Flags & ELF::SHF_WRITE))
922*0b57cec5SDimitry Andric       return 'n';
923*0b57cec5SDimitry Andric   }
924*0b57cec5SDimitry Andric 
925*0b57cec5SDimitry Andric   return '?';
926*0b57cec5SDimitry Andric }
927*0b57cec5SDimitry Andric 
928*0b57cec5SDimitry Andric static char getSymbolNMTypeChar(COFFObjectFile &Obj, symbol_iterator I) {
929*0b57cec5SDimitry Andric   COFFSymbolRef Symb = Obj.getCOFFSymbol(*I);
930*0b57cec5SDimitry Andric   // OK, this is COFF.
931*0b57cec5SDimitry Andric   symbol_iterator SymI(I);
932*0b57cec5SDimitry Andric 
933*0b57cec5SDimitry Andric   Expected<StringRef> Name = SymI->getName();
934*0b57cec5SDimitry Andric   if (!Name) {
935*0b57cec5SDimitry Andric     consumeError(Name.takeError());
936*0b57cec5SDimitry Andric     return '?';
937*0b57cec5SDimitry Andric   }
938*0b57cec5SDimitry Andric 
939*0b57cec5SDimitry Andric   char Ret = StringSwitch<char>(*Name)
940*0b57cec5SDimitry Andric                  .StartsWith(".debug", 'N')
941*0b57cec5SDimitry Andric                  .StartsWith(".sxdata", 'N')
942*0b57cec5SDimitry Andric                  .Default('?');
943*0b57cec5SDimitry Andric 
944*0b57cec5SDimitry Andric   if (Ret != '?')
945*0b57cec5SDimitry Andric     return Ret;
946*0b57cec5SDimitry Andric 
947*0b57cec5SDimitry Andric   uint32_t Characteristics = 0;
948*0b57cec5SDimitry Andric   if (!COFF::isReservedSectionNumber(Symb.getSectionNumber())) {
949*0b57cec5SDimitry Andric     Expected<section_iterator> SecIOrErr = SymI->getSection();
950*0b57cec5SDimitry Andric     if (!SecIOrErr) {
951*0b57cec5SDimitry Andric       consumeError(SecIOrErr.takeError());
952*0b57cec5SDimitry Andric       return '?';
953*0b57cec5SDimitry Andric     }
954*0b57cec5SDimitry Andric     section_iterator SecI = *SecIOrErr;
955*0b57cec5SDimitry Andric     const coff_section *Section = Obj.getCOFFSection(*SecI);
956*0b57cec5SDimitry Andric     Characteristics = Section->Characteristics;
957*0b57cec5SDimitry Andric     if (Expected<StringRef> NameOrErr = Obj.getSectionName(Section))
958*0b57cec5SDimitry Andric       if (NameOrErr->startswith(".idata"))
959*0b57cec5SDimitry Andric         return 'i';
960*0b57cec5SDimitry Andric   }
961*0b57cec5SDimitry Andric 
962*0b57cec5SDimitry Andric   switch (Symb.getSectionNumber()) {
963*0b57cec5SDimitry Andric   case COFF::IMAGE_SYM_DEBUG:
964*0b57cec5SDimitry Andric     return 'n';
965*0b57cec5SDimitry Andric   default:
966*0b57cec5SDimitry Andric     // Check section type.
967*0b57cec5SDimitry Andric     if (Characteristics & COFF::IMAGE_SCN_CNT_CODE)
968*0b57cec5SDimitry Andric       return 't';
969*0b57cec5SDimitry Andric     if (Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA)
970*0b57cec5SDimitry Andric       return Characteristics & COFF::IMAGE_SCN_MEM_WRITE ? 'd' : 'r';
971*0b57cec5SDimitry Andric     if (Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
972*0b57cec5SDimitry Andric       return 'b';
973*0b57cec5SDimitry Andric     if (Characteristics & COFF::IMAGE_SCN_LNK_INFO)
974*0b57cec5SDimitry Andric       return 'i';
975*0b57cec5SDimitry Andric     // Check for section symbol.
976*0b57cec5SDimitry Andric     if (Symb.isSectionDefinition())
977*0b57cec5SDimitry Andric       return 's';
978*0b57cec5SDimitry Andric   }
979*0b57cec5SDimitry Andric 
980*0b57cec5SDimitry Andric   return '?';
981*0b57cec5SDimitry Andric }
982*0b57cec5SDimitry Andric 
983*0b57cec5SDimitry Andric static char getSymbolNMTypeChar(COFFImportFile &Obj) {
984*0b57cec5SDimitry Andric   switch (Obj.getCOFFImportHeader()->getType()) {
985*0b57cec5SDimitry Andric   case COFF::IMPORT_CODE:
986*0b57cec5SDimitry Andric     return 't';
987*0b57cec5SDimitry Andric   case COFF::IMPORT_DATA:
988*0b57cec5SDimitry Andric     return 'd';
989*0b57cec5SDimitry Andric   case COFF::IMPORT_CONST:
990*0b57cec5SDimitry Andric     return 'r';
991*0b57cec5SDimitry Andric   }
992*0b57cec5SDimitry Andric   return '?';
993*0b57cec5SDimitry Andric }
994*0b57cec5SDimitry Andric 
995*0b57cec5SDimitry Andric static char getSymbolNMTypeChar(MachOObjectFile &Obj, basic_symbol_iterator I) {
996*0b57cec5SDimitry Andric   DataRefImpl Symb = I->getRawDataRefImpl();
997*0b57cec5SDimitry Andric   uint8_t NType = Obj.is64Bit() ? Obj.getSymbol64TableEntry(Symb).n_type
998*0b57cec5SDimitry Andric                                 : Obj.getSymbolTableEntry(Symb).n_type;
999*0b57cec5SDimitry Andric 
1000*0b57cec5SDimitry Andric   if (NType & MachO::N_STAB)
1001*0b57cec5SDimitry Andric     return '-';
1002*0b57cec5SDimitry Andric 
1003*0b57cec5SDimitry Andric   switch (NType & MachO::N_TYPE) {
1004*0b57cec5SDimitry Andric   case MachO::N_ABS:
1005*0b57cec5SDimitry Andric     return 's';
1006*0b57cec5SDimitry Andric   case MachO::N_INDR:
1007*0b57cec5SDimitry Andric     return 'i';
1008*0b57cec5SDimitry Andric   case MachO::N_SECT: {
1009*0b57cec5SDimitry Andric     Expected<section_iterator> SecOrErr = Obj.getSymbolSection(Symb);
1010*0b57cec5SDimitry Andric     if (!SecOrErr) {
1011*0b57cec5SDimitry Andric       consumeError(SecOrErr.takeError());
1012*0b57cec5SDimitry Andric       return 's';
1013*0b57cec5SDimitry Andric     }
1014*0b57cec5SDimitry Andric     section_iterator Sec = *SecOrErr;
1015*0b57cec5SDimitry Andric     if (Sec == Obj.section_end())
1016*0b57cec5SDimitry Andric       return 's';
1017*0b57cec5SDimitry Andric     DataRefImpl Ref = Sec->getRawDataRefImpl();
1018*0b57cec5SDimitry Andric     StringRef SectionName;
1019*0b57cec5SDimitry Andric     if (Expected<StringRef> NameOrErr = Obj.getSectionName(Ref))
1020*0b57cec5SDimitry Andric       SectionName = *NameOrErr;
1021*0b57cec5SDimitry Andric     StringRef SegmentName = Obj.getSectionFinalSegmentName(Ref);
1022*0b57cec5SDimitry Andric     if (Obj.is64Bit() && Obj.getHeader64().filetype == MachO::MH_KEXT_BUNDLE &&
1023*0b57cec5SDimitry Andric         SegmentName == "__TEXT_EXEC" && SectionName == "__text")
1024*0b57cec5SDimitry Andric       return 't';
1025*0b57cec5SDimitry Andric     if (SegmentName == "__TEXT" && SectionName == "__text")
1026*0b57cec5SDimitry Andric       return 't';
1027*0b57cec5SDimitry Andric     if (SegmentName == "__DATA" && SectionName == "__data")
1028*0b57cec5SDimitry Andric       return 'd';
1029*0b57cec5SDimitry Andric     if (SegmentName == "__DATA" && SectionName == "__bss")
1030*0b57cec5SDimitry Andric       return 'b';
1031*0b57cec5SDimitry Andric     return 's';
1032*0b57cec5SDimitry Andric   }
1033*0b57cec5SDimitry Andric   }
1034*0b57cec5SDimitry Andric 
1035*0b57cec5SDimitry Andric   return '?';
1036*0b57cec5SDimitry Andric }
1037*0b57cec5SDimitry Andric 
1038*0b57cec5SDimitry Andric static char getSymbolNMTypeChar(WasmObjectFile &Obj, basic_symbol_iterator I) {
1039*0b57cec5SDimitry Andric   uint32_t Flags = I->getFlags();
1040*0b57cec5SDimitry Andric   if (Flags & SymbolRef::SF_Executable)
1041*0b57cec5SDimitry Andric     return 't';
1042*0b57cec5SDimitry Andric   return 'd';
1043*0b57cec5SDimitry Andric }
1044*0b57cec5SDimitry Andric 
1045*0b57cec5SDimitry Andric static char getSymbolNMTypeChar(IRObjectFile &Obj, basic_symbol_iterator I) {
1046*0b57cec5SDimitry Andric   uint32_t Flags = I->getFlags();
1047*0b57cec5SDimitry Andric   // FIXME: should we print 'b'? At the IR level we cannot be sure if this
1048*0b57cec5SDimitry Andric   // will be in bss or not, but we could approximate.
1049*0b57cec5SDimitry Andric   if (Flags & SymbolRef::SF_Executable)
1050*0b57cec5SDimitry Andric     return 't';
1051*0b57cec5SDimitry Andric   else if (Triple(Obj.getTargetTriple()).isOSDarwin() &&
1052*0b57cec5SDimitry Andric            (Flags & SymbolRef::SF_Const))
1053*0b57cec5SDimitry Andric     return 's';
1054*0b57cec5SDimitry Andric   else
1055*0b57cec5SDimitry Andric     return 'd';
1056*0b57cec5SDimitry Andric }
1057*0b57cec5SDimitry Andric 
1058*0b57cec5SDimitry Andric static bool isObject(SymbolicFile &Obj, basic_symbol_iterator I) {
1059*0b57cec5SDimitry Andric   return !dyn_cast<ELFObjectFileBase>(&Obj)
1060*0b57cec5SDimitry Andric              ? false
1061*0b57cec5SDimitry Andric              : elf_symbol_iterator(I)->getELFType() == ELF::STT_OBJECT;
1062*0b57cec5SDimitry Andric }
1063*0b57cec5SDimitry Andric 
1064*0b57cec5SDimitry Andric // For ELF object files, Set TypeName to the symbol typename, to be printed
1065*0b57cec5SDimitry Andric // in the 'Type' column of the SYSV format output.
1066*0b57cec5SDimitry Andric static StringRef getNMTypeName(SymbolicFile &Obj, basic_symbol_iterator I) {
1067*0b57cec5SDimitry Andric   if (isa<ELFObjectFileBase>(&Obj)) {
1068*0b57cec5SDimitry Andric     elf_symbol_iterator SymI(I);
1069*0b57cec5SDimitry Andric     return SymI->getELFTypeName();
1070*0b57cec5SDimitry Andric   }
1071*0b57cec5SDimitry Andric   return "";
1072*0b57cec5SDimitry Andric }
1073*0b57cec5SDimitry Andric 
1074*0b57cec5SDimitry Andric // Return Posix nm class type tag (single letter), but also set SecName and
1075*0b57cec5SDimitry Andric // section and name, to be used in format=sysv output.
1076*0b57cec5SDimitry Andric static char getNMSectionTagAndName(SymbolicFile &Obj, basic_symbol_iterator I,
1077*0b57cec5SDimitry Andric                                    StringRef &SecName) {
1078*0b57cec5SDimitry Andric   uint32_t Symflags = I->getFlags();
1079*0b57cec5SDimitry Andric   if (isa<ELFObjectFileBase>(&Obj)) {
1080*0b57cec5SDimitry Andric     if (Symflags & object::SymbolRef::SF_Absolute)
1081*0b57cec5SDimitry Andric       SecName = "*ABS*";
1082*0b57cec5SDimitry Andric     else if (Symflags & object::SymbolRef::SF_Common)
1083*0b57cec5SDimitry Andric       SecName = "*COM*";
1084*0b57cec5SDimitry Andric     else if (Symflags & object::SymbolRef::SF_Undefined)
1085*0b57cec5SDimitry Andric       SecName = "*UND*";
1086*0b57cec5SDimitry Andric     else {
1087*0b57cec5SDimitry Andric       elf_symbol_iterator SymI(I);
1088*0b57cec5SDimitry Andric       Expected<elf_section_iterator> SecIOrErr = SymI->getSection();
1089*0b57cec5SDimitry Andric       if (!SecIOrErr) {
1090*0b57cec5SDimitry Andric         consumeError(SecIOrErr.takeError());
1091*0b57cec5SDimitry Andric         return '?';
1092*0b57cec5SDimitry Andric       }
1093*0b57cec5SDimitry Andric       elf_section_iterator secT = *SecIOrErr;
1094*0b57cec5SDimitry Andric       secT->getName(SecName);
1095*0b57cec5SDimitry Andric     }
1096*0b57cec5SDimitry Andric   }
1097*0b57cec5SDimitry Andric 
1098*0b57cec5SDimitry Andric   if ((Symflags & object::SymbolRef::SF_Weak) && !isa<MachOObjectFile>(Obj)) {
1099*0b57cec5SDimitry Andric     char Ret = isObject(Obj, I) ? 'v' : 'w';
1100*0b57cec5SDimitry Andric     return (!(Symflags & object::SymbolRef::SF_Undefined)) ? toupper(Ret) : Ret;
1101*0b57cec5SDimitry Andric   }
1102*0b57cec5SDimitry Andric 
1103*0b57cec5SDimitry Andric   if (Symflags & object::SymbolRef::SF_Undefined)
1104*0b57cec5SDimitry Andric     return 'U';
1105*0b57cec5SDimitry Andric 
1106*0b57cec5SDimitry Andric   if (Symflags & object::SymbolRef::SF_Common)
1107*0b57cec5SDimitry Andric     return 'C';
1108*0b57cec5SDimitry Andric 
1109*0b57cec5SDimitry Andric   char Ret = '?';
1110*0b57cec5SDimitry Andric   if (Symflags & object::SymbolRef::SF_Absolute)
1111*0b57cec5SDimitry Andric     Ret = 'a';
1112*0b57cec5SDimitry Andric   else if (IRObjectFile *IR = dyn_cast<IRObjectFile>(&Obj))
1113*0b57cec5SDimitry Andric     Ret = getSymbolNMTypeChar(*IR, I);
1114*0b57cec5SDimitry Andric   else if (COFFObjectFile *COFF = dyn_cast<COFFObjectFile>(&Obj))
1115*0b57cec5SDimitry Andric     Ret = getSymbolNMTypeChar(*COFF, I);
1116*0b57cec5SDimitry Andric   else if (COFFImportFile *COFFImport = dyn_cast<COFFImportFile>(&Obj))
1117*0b57cec5SDimitry Andric     Ret = getSymbolNMTypeChar(*COFFImport);
1118*0b57cec5SDimitry Andric   else if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj))
1119*0b57cec5SDimitry Andric     Ret = getSymbolNMTypeChar(*MachO, I);
1120*0b57cec5SDimitry Andric   else if (WasmObjectFile *Wasm = dyn_cast<WasmObjectFile>(&Obj))
1121*0b57cec5SDimitry Andric     Ret = getSymbolNMTypeChar(*Wasm, I);
1122*0b57cec5SDimitry Andric   else
1123*0b57cec5SDimitry Andric     Ret = getSymbolNMTypeChar(cast<ELFObjectFileBase>(Obj), I);
1124*0b57cec5SDimitry Andric 
1125*0b57cec5SDimitry Andric   if (!(Symflags & object::SymbolRef::SF_Global))
1126*0b57cec5SDimitry Andric     return Ret;
1127*0b57cec5SDimitry Andric 
1128*0b57cec5SDimitry Andric   if (Obj.isELF() && ELFSymbolRef(*I).getBinding() == ELF::STB_GNU_UNIQUE)
1129*0b57cec5SDimitry Andric     return Ret;
1130*0b57cec5SDimitry Andric 
1131*0b57cec5SDimitry Andric   return toupper(Ret);
1132*0b57cec5SDimitry Andric }
1133*0b57cec5SDimitry Andric 
1134*0b57cec5SDimitry Andric // getNsectForSegSect() is used to implement the Mach-O "-s segname sectname"
1135*0b57cec5SDimitry Andric // option to dump only those symbols from that section in a Mach-O file.
1136*0b57cec5SDimitry Andric // It is called once for each Mach-O file from dumpSymbolNamesFromObject()
1137*0b57cec5SDimitry Andric // to get the section number for that named section from the command line
1138*0b57cec5SDimitry Andric // arguments. It returns the section number for that section in the Mach-O
1139*0b57cec5SDimitry Andric // file or zero it is not present.
1140*0b57cec5SDimitry Andric static unsigned getNsectForSegSect(MachOObjectFile *Obj) {
1141*0b57cec5SDimitry Andric   unsigned Nsect = 1;
1142*0b57cec5SDimitry Andric   for (auto &S : Obj->sections()) {
1143*0b57cec5SDimitry Andric     DataRefImpl Ref = S.getRawDataRefImpl();
1144*0b57cec5SDimitry Andric     StringRef SectionName;
1145*0b57cec5SDimitry Andric     if (Expected<StringRef> NameOrErr = Obj->getSectionName(Ref))
1146*0b57cec5SDimitry Andric       SectionName = *NameOrErr;
1147*0b57cec5SDimitry Andric     StringRef SegmentName = Obj->getSectionFinalSegmentName(Ref);
1148*0b57cec5SDimitry Andric     if (SegmentName == SegSect[0] && SectionName == SegSect[1])
1149*0b57cec5SDimitry Andric       return Nsect;
1150*0b57cec5SDimitry Andric     Nsect++;
1151*0b57cec5SDimitry Andric   }
1152*0b57cec5SDimitry Andric   return 0;
1153*0b57cec5SDimitry Andric }
1154*0b57cec5SDimitry Andric 
1155*0b57cec5SDimitry Andric // getNsectInMachO() is used to implement the Mach-O "-s segname sectname"
1156*0b57cec5SDimitry Andric // option to dump only those symbols from that section in a Mach-O file.
1157*0b57cec5SDimitry Andric // It is called once for each symbol in a Mach-O file from
1158*0b57cec5SDimitry Andric // dumpSymbolNamesFromObject() and returns the section number for that symbol
1159*0b57cec5SDimitry Andric // if it is in a section, else it returns 0.
1160*0b57cec5SDimitry Andric static unsigned getNsectInMachO(MachOObjectFile &Obj, BasicSymbolRef Sym) {
1161*0b57cec5SDimitry Andric   DataRefImpl Symb = Sym.getRawDataRefImpl();
1162*0b57cec5SDimitry Andric   if (Obj.is64Bit()) {
1163*0b57cec5SDimitry Andric     MachO::nlist_64 STE = Obj.getSymbol64TableEntry(Symb);
1164*0b57cec5SDimitry Andric     return (STE.n_type & MachO::N_TYPE) == MachO::N_SECT ? STE.n_sect : 0;
1165*0b57cec5SDimitry Andric   }
1166*0b57cec5SDimitry Andric   MachO::nlist STE = Obj.getSymbolTableEntry(Symb);
1167*0b57cec5SDimitry Andric   return (STE.n_type & MachO::N_TYPE) == MachO::N_SECT ? STE.n_sect : 0;
1168*0b57cec5SDimitry Andric }
1169*0b57cec5SDimitry Andric 
1170*0b57cec5SDimitry Andric static void
1171*0b57cec5SDimitry Andric dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName,
1172*0b57cec5SDimitry Andric                           const std::string &ArchiveName = std::string(),
1173*0b57cec5SDimitry Andric                           const std::string &ArchitectureName = std::string()) {
1174*0b57cec5SDimitry Andric   auto Symbols = Obj.symbols();
1175*0b57cec5SDimitry Andric   if (DynamicSyms) {
1176*0b57cec5SDimitry Andric     const auto *E = dyn_cast<ELFObjectFileBase>(&Obj);
1177*0b57cec5SDimitry Andric     if (!E) {
1178*0b57cec5SDimitry Andric       error("File format has no dynamic symbol table", Obj.getFileName());
1179*0b57cec5SDimitry Andric       return;
1180*0b57cec5SDimitry Andric     }
1181*0b57cec5SDimitry Andric     Symbols = E->getDynamicSymbolIterators();
1182*0b57cec5SDimitry Andric   }
1183*0b57cec5SDimitry Andric   std::string NameBuffer;
1184*0b57cec5SDimitry Andric   raw_string_ostream OS(NameBuffer);
1185*0b57cec5SDimitry Andric   // If a "-s segname sectname" option was specified and this is a Mach-O
1186*0b57cec5SDimitry Andric   // file get the section number for that section in this object file.
1187*0b57cec5SDimitry Andric   unsigned int Nsect = 0;
1188*0b57cec5SDimitry Andric   MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj);
1189*0b57cec5SDimitry Andric   if (!SegSect.empty() && MachO) {
1190*0b57cec5SDimitry Andric     Nsect = getNsectForSegSect(MachO);
1191*0b57cec5SDimitry Andric     // If this section is not in the object file no symbols are printed.
1192*0b57cec5SDimitry Andric     if (Nsect == 0)
1193*0b57cec5SDimitry Andric       return;
1194*0b57cec5SDimitry Andric   }
1195*0b57cec5SDimitry Andric   if (!MachO || !DyldInfoOnly) {
1196*0b57cec5SDimitry Andric     for (BasicSymbolRef Sym : Symbols) {
1197*0b57cec5SDimitry Andric       uint32_t SymFlags = Sym.getFlags();
1198*0b57cec5SDimitry Andric       if (!DebugSyms && (SymFlags & SymbolRef::SF_FormatSpecific))
1199*0b57cec5SDimitry Andric         continue;
1200*0b57cec5SDimitry Andric       if (WithoutAliases && (SymFlags & SymbolRef::SF_Indirect))
1201*0b57cec5SDimitry Andric         continue;
1202*0b57cec5SDimitry Andric       // If a "-s segname sectname" option was specified and this is a Mach-O
1203*0b57cec5SDimitry Andric       // file and this section appears in this file, Nsect will be non-zero then
1204*0b57cec5SDimitry Andric       // see if this symbol is a symbol from that section and if not skip it.
1205*0b57cec5SDimitry Andric       if (Nsect && Nsect != getNsectInMachO(*MachO, Sym))
1206*0b57cec5SDimitry Andric         continue;
1207*0b57cec5SDimitry Andric       NMSymbol S = {};
1208*0b57cec5SDimitry Andric       S.Size = 0;
1209*0b57cec5SDimitry Andric       S.Address = 0;
1210*0b57cec5SDimitry Andric       if (isa<ELFObjectFileBase>(&Obj))
1211*0b57cec5SDimitry Andric         S.Size = ELFSymbolRef(Sym).getSize();
1212*0b57cec5SDimitry Andric       if (PrintAddress && isa<ObjectFile>(Obj)) {
1213*0b57cec5SDimitry Andric         SymbolRef SymRef(Sym);
1214*0b57cec5SDimitry Andric         Expected<uint64_t> AddressOrErr = SymRef.getAddress();
1215*0b57cec5SDimitry Andric         if (!AddressOrErr) {
1216*0b57cec5SDimitry Andric           consumeError(AddressOrErr.takeError());
1217*0b57cec5SDimitry Andric           break;
1218*0b57cec5SDimitry Andric         }
1219*0b57cec5SDimitry Andric         S.Address = *AddressOrErr;
1220*0b57cec5SDimitry Andric       }
1221*0b57cec5SDimitry Andric       S.TypeName = getNMTypeName(Obj, Sym);
1222*0b57cec5SDimitry Andric       S.TypeChar = getNMSectionTagAndName(Obj, Sym, S.SectionName);
1223*0b57cec5SDimitry Andric       if (Error E = Sym.printName(OS)) {
1224*0b57cec5SDimitry Andric         if (MachO) {
1225*0b57cec5SDimitry Andric           OS << "bad string index";
1226*0b57cec5SDimitry Andric           consumeError(std::move(E));
1227*0b57cec5SDimitry Andric         } else
1228*0b57cec5SDimitry Andric           error(std::move(E), Obj.getFileName());
1229*0b57cec5SDimitry Andric       }
1230*0b57cec5SDimitry Andric       OS << '\0';
1231*0b57cec5SDimitry Andric       S.Sym = Sym;
1232*0b57cec5SDimitry Andric       SymbolList.push_back(S);
1233*0b57cec5SDimitry Andric     }
1234*0b57cec5SDimitry Andric   }
1235*0b57cec5SDimitry Andric 
1236*0b57cec5SDimitry Andric   OS.flush();
1237*0b57cec5SDimitry Andric   const char *P = NameBuffer.c_str();
1238*0b57cec5SDimitry Andric   unsigned I;
1239*0b57cec5SDimitry Andric   for (I = 0; I < SymbolList.size(); ++I) {
1240*0b57cec5SDimitry Andric     SymbolList[I].Name = P;
1241*0b57cec5SDimitry Andric     P += strlen(P) + 1;
1242*0b57cec5SDimitry Andric   }
1243*0b57cec5SDimitry Andric 
1244*0b57cec5SDimitry Andric   // If this is a Mach-O file where the nlist symbol table is out of sync
1245*0b57cec5SDimitry Andric   // with the dyld export trie then look through exports and fake up symbols
1246*0b57cec5SDimitry Andric   // for the ones that are missing (also done with the -add-dyldinfo flag).
1247*0b57cec5SDimitry Andric   // This is needed if strip(1) -T is run on a binary containing swift
1248*0b57cec5SDimitry Andric   // language symbols for example.  The option -only-dyldinfo will fake up
1249*0b57cec5SDimitry Andric   // all symbols from the dyld export trie as well as the bind info.
1250*0b57cec5SDimitry Andric   std::string ExportsNameBuffer;
1251*0b57cec5SDimitry Andric   raw_string_ostream EOS(ExportsNameBuffer);
1252*0b57cec5SDimitry Andric   std::string BindsNameBuffer;
1253*0b57cec5SDimitry Andric   raw_string_ostream BOS(BindsNameBuffer);
1254*0b57cec5SDimitry Andric   std::string LazysNameBuffer;
1255*0b57cec5SDimitry Andric   raw_string_ostream LOS(LazysNameBuffer);
1256*0b57cec5SDimitry Andric   std::string WeaksNameBuffer;
1257*0b57cec5SDimitry Andric   raw_string_ostream WOS(WeaksNameBuffer);
1258*0b57cec5SDimitry Andric   std::string FunctionStartsNameBuffer;
1259*0b57cec5SDimitry Andric   raw_string_ostream FOS(FunctionStartsNameBuffer);
1260*0b57cec5SDimitry Andric   if (MachO && !NoDyldInfo) {
1261*0b57cec5SDimitry Andric     MachO::mach_header H;
1262*0b57cec5SDimitry Andric     MachO::mach_header_64 H_64;
1263*0b57cec5SDimitry Andric     uint32_t HFlags = 0;
1264*0b57cec5SDimitry Andric     if (MachO->is64Bit()) {
1265*0b57cec5SDimitry Andric       H_64 = MachO->MachOObjectFile::getHeader64();
1266*0b57cec5SDimitry Andric       HFlags = H_64.flags;
1267*0b57cec5SDimitry Andric     } else {
1268*0b57cec5SDimitry Andric       H = MachO->MachOObjectFile::getHeader();
1269*0b57cec5SDimitry Andric       HFlags = H.flags;
1270*0b57cec5SDimitry Andric     }
1271*0b57cec5SDimitry Andric     uint64_t BaseSegmentAddress = 0;
1272*0b57cec5SDimitry Andric     for (const auto &Command : MachO->load_commands()) {
1273*0b57cec5SDimitry Andric       if (Command.C.cmd == MachO::LC_SEGMENT) {
1274*0b57cec5SDimitry Andric         MachO::segment_command Seg = MachO->getSegmentLoadCommand(Command);
1275*0b57cec5SDimitry Andric         if (Seg.fileoff == 0 && Seg.filesize != 0) {
1276*0b57cec5SDimitry Andric           BaseSegmentAddress = Seg.vmaddr;
1277*0b57cec5SDimitry Andric           break;
1278*0b57cec5SDimitry Andric         }
1279*0b57cec5SDimitry Andric       } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
1280*0b57cec5SDimitry Andric         MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Command);
1281*0b57cec5SDimitry Andric         if (Seg.fileoff == 0 && Seg.filesize != 0) {
1282*0b57cec5SDimitry Andric           BaseSegmentAddress = Seg.vmaddr;
1283*0b57cec5SDimitry Andric           break;
1284*0b57cec5SDimitry Andric         }
1285*0b57cec5SDimitry Andric       }
1286*0b57cec5SDimitry Andric     }
1287*0b57cec5SDimitry Andric     if (DyldInfoOnly || AddDyldInfo ||
1288*0b57cec5SDimitry Andric         HFlags & MachO::MH_NLIST_OUTOFSYNC_WITH_DYLDINFO) {
1289*0b57cec5SDimitry Andric       unsigned ExportsAdded = 0;
1290*0b57cec5SDimitry Andric       Error Err = Error::success();
1291*0b57cec5SDimitry Andric       for (const llvm::object::ExportEntry &Entry : MachO->exports(Err)) {
1292*0b57cec5SDimitry Andric         bool found = false;
1293*0b57cec5SDimitry Andric         bool ReExport = false;
1294*0b57cec5SDimitry Andric         if (!DyldInfoOnly) {
1295*0b57cec5SDimitry Andric           for (const NMSymbol &S : SymbolList)
1296*0b57cec5SDimitry Andric             if (S.Address == Entry.address() + BaseSegmentAddress &&
1297*0b57cec5SDimitry Andric                 S.Name == Entry.name()) {
1298*0b57cec5SDimitry Andric               found = true;
1299*0b57cec5SDimitry Andric               break;
1300*0b57cec5SDimitry Andric             }
1301*0b57cec5SDimitry Andric         }
1302*0b57cec5SDimitry Andric         if (!found) {
1303*0b57cec5SDimitry Andric           NMSymbol S = {};
1304*0b57cec5SDimitry Andric           S.Address = Entry.address() + BaseSegmentAddress;
1305*0b57cec5SDimitry Andric           S.Size = 0;
1306*0b57cec5SDimitry Andric           S.TypeChar = '\0';
1307*0b57cec5SDimitry Andric           S.Name = Entry.name();
1308*0b57cec5SDimitry Andric           // There is no symbol in the nlist symbol table for this so we set
1309*0b57cec5SDimitry Andric           // Sym effectivly to null and the rest of code in here must test for
1310*0b57cec5SDimitry Andric           // it and not do things like Sym.getFlags() for it.
1311*0b57cec5SDimitry Andric           S.Sym = BasicSymbolRef();
1312*0b57cec5SDimitry Andric           S.SymFlags = SymbolRef::SF_Global;
1313*0b57cec5SDimitry Andric           S.Section = SectionRef();
1314*0b57cec5SDimitry Andric           S.NType = 0;
1315*0b57cec5SDimitry Andric           S.NSect = 0;
1316*0b57cec5SDimitry Andric           S.NDesc = 0;
1317*0b57cec5SDimitry Andric           S.IndirectName = StringRef();
1318*0b57cec5SDimitry Andric 
1319*0b57cec5SDimitry Andric           uint64_t EFlags = Entry.flags();
1320*0b57cec5SDimitry Andric           bool Abs = ((EFlags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) ==
1321*0b57cec5SDimitry Andric                       MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);
1322*0b57cec5SDimitry Andric           bool Resolver = (EFlags &
1323*0b57cec5SDimitry Andric                            MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);
1324*0b57cec5SDimitry Andric           ReExport = (EFlags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT);
1325*0b57cec5SDimitry Andric           bool WeakDef = (EFlags & MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
1326*0b57cec5SDimitry Andric           if (WeakDef)
1327*0b57cec5SDimitry Andric             S.NDesc |= MachO::N_WEAK_DEF;
1328*0b57cec5SDimitry Andric           if (Abs) {
1329*0b57cec5SDimitry Andric             S.NType = MachO::N_EXT | MachO::N_ABS;
1330*0b57cec5SDimitry Andric             S.TypeChar = 'A';
1331*0b57cec5SDimitry Andric           } else if (ReExport) {
1332*0b57cec5SDimitry Andric             S.NType = MachO::N_EXT | MachO::N_INDR;
1333*0b57cec5SDimitry Andric             S.TypeChar = 'I';
1334*0b57cec5SDimitry Andric           } else {
1335*0b57cec5SDimitry Andric             S.NType = MachO::N_EXT | MachO::N_SECT;
1336*0b57cec5SDimitry Andric             if (Resolver) {
1337*0b57cec5SDimitry Andric               S.Address = Entry.other() + BaseSegmentAddress;
1338*0b57cec5SDimitry Andric               if ((S.Address & 1) != 0 &&
1339*0b57cec5SDimitry Andric                   !MachO->is64Bit() && H.cputype == MachO::CPU_TYPE_ARM){
1340*0b57cec5SDimitry Andric                 S.Address &= ~1LL;
1341*0b57cec5SDimitry Andric                 S.NDesc |= MachO::N_ARM_THUMB_DEF;
1342*0b57cec5SDimitry Andric               }
1343*0b57cec5SDimitry Andric             } else {
1344*0b57cec5SDimitry Andric               S.Address = Entry.address() + BaseSegmentAddress;
1345*0b57cec5SDimitry Andric             }
1346*0b57cec5SDimitry Andric             StringRef SegmentName = StringRef();
1347*0b57cec5SDimitry Andric             StringRef SectionName = StringRef();
1348*0b57cec5SDimitry Andric             for (const SectionRef &Section : MachO->sections()) {
1349*0b57cec5SDimitry Andric               S.NSect++;
1350*0b57cec5SDimitry Andric               Section.getName(SectionName);
1351*0b57cec5SDimitry Andric               SegmentName = MachO->getSectionFinalSegmentName(
1352*0b57cec5SDimitry Andric                                                   Section.getRawDataRefImpl());
1353*0b57cec5SDimitry Andric               if (S.Address >= Section.getAddress() &&
1354*0b57cec5SDimitry Andric                   S.Address < Section.getAddress() + Section.getSize()) {
1355*0b57cec5SDimitry Andric                 S.Section = Section;
1356*0b57cec5SDimitry Andric                 break;
1357*0b57cec5SDimitry Andric               } else if (Entry.name() == "__mh_execute_header" &&
1358*0b57cec5SDimitry Andric                          SegmentName == "__TEXT" && SectionName == "__text") {
1359*0b57cec5SDimitry Andric                 S.Section = Section;
1360*0b57cec5SDimitry Andric                 S.NDesc |= MachO::REFERENCED_DYNAMICALLY;
1361*0b57cec5SDimitry Andric                 break;
1362*0b57cec5SDimitry Andric               }
1363*0b57cec5SDimitry Andric             }
1364*0b57cec5SDimitry Andric             if (SegmentName == "__TEXT" && SectionName == "__text")
1365*0b57cec5SDimitry Andric               S.TypeChar = 'T';
1366*0b57cec5SDimitry Andric             else if (SegmentName == "__DATA" && SectionName == "__data")
1367*0b57cec5SDimitry Andric               S.TypeChar = 'D';
1368*0b57cec5SDimitry Andric             else if (SegmentName == "__DATA" && SectionName == "__bss")
1369*0b57cec5SDimitry Andric               S.TypeChar = 'B';
1370*0b57cec5SDimitry Andric             else
1371*0b57cec5SDimitry Andric               S.TypeChar = 'S';
1372*0b57cec5SDimitry Andric           }
1373*0b57cec5SDimitry Andric           SymbolList.push_back(S);
1374*0b57cec5SDimitry Andric 
1375*0b57cec5SDimitry Andric           EOS << Entry.name();
1376*0b57cec5SDimitry Andric           EOS << '\0';
1377*0b57cec5SDimitry Andric           ExportsAdded++;
1378*0b57cec5SDimitry Andric 
1379*0b57cec5SDimitry Andric           // For ReExports there are a two more things to do, first add the
1380*0b57cec5SDimitry Andric           // indirect name and second create the undefined symbol using the
1381*0b57cec5SDimitry Andric           // referened dynamic library.
1382*0b57cec5SDimitry Andric           if (ReExport) {
1383*0b57cec5SDimitry Andric 
1384*0b57cec5SDimitry Andric             // Add the indirect name.
1385*0b57cec5SDimitry Andric             if (Entry.otherName().empty())
1386*0b57cec5SDimitry Andric               EOS << Entry.name();
1387*0b57cec5SDimitry Andric             else
1388*0b57cec5SDimitry Andric               EOS << Entry.otherName();
1389*0b57cec5SDimitry Andric             EOS << '\0';
1390*0b57cec5SDimitry Andric 
1391*0b57cec5SDimitry Andric             // Now create the undefined symbol using the referened dynamic
1392*0b57cec5SDimitry Andric             // library.
1393*0b57cec5SDimitry Andric             NMSymbol U = {};
1394*0b57cec5SDimitry Andric             U.Address = 0;
1395*0b57cec5SDimitry Andric             U.Size = 0;
1396*0b57cec5SDimitry Andric             U.TypeChar = 'U';
1397*0b57cec5SDimitry Andric             if (Entry.otherName().empty())
1398*0b57cec5SDimitry Andric               U.Name = Entry.name();
1399*0b57cec5SDimitry Andric             else
1400*0b57cec5SDimitry Andric               U.Name = Entry.otherName();
1401*0b57cec5SDimitry Andric             // Again there is no symbol in the nlist symbol table for this so
1402*0b57cec5SDimitry Andric             // we set Sym effectivly to null and the rest of code in here must
1403*0b57cec5SDimitry Andric             // test for it and not do things like Sym.getFlags() for it.
1404*0b57cec5SDimitry Andric             U.Sym = BasicSymbolRef();
1405*0b57cec5SDimitry Andric             U.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
1406*0b57cec5SDimitry Andric             U.Section = SectionRef();
1407*0b57cec5SDimitry Andric             U.NType = MachO::N_EXT | MachO::N_UNDF;
1408*0b57cec5SDimitry Andric             U.NSect = 0;
1409*0b57cec5SDimitry Andric             U.NDesc = 0;
1410*0b57cec5SDimitry Andric             // The library ordinal for this undefined symbol is in the export
1411*0b57cec5SDimitry Andric             // trie Entry.other().
1412*0b57cec5SDimitry Andric             MachO::SET_LIBRARY_ORDINAL(U.NDesc, Entry.other());
1413*0b57cec5SDimitry Andric             U.IndirectName = StringRef();
1414*0b57cec5SDimitry Andric             SymbolList.push_back(U);
1415*0b57cec5SDimitry Andric 
1416*0b57cec5SDimitry Andric             // Finally add the undefined symbol's name.
1417*0b57cec5SDimitry Andric             if (Entry.otherName().empty())
1418*0b57cec5SDimitry Andric               EOS << Entry.name();
1419*0b57cec5SDimitry Andric             else
1420*0b57cec5SDimitry Andric               EOS << Entry.otherName();
1421*0b57cec5SDimitry Andric             EOS << '\0';
1422*0b57cec5SDimitry Andric             ExportsAdded++;
1423*0b57cec5SDimitry Andric           }
1424*0b57cec5SDimitry Andric         }
1425*0b57cec5SDimitry Andric       }
1426*0b57cec5SDimitry Andric       if (Err)
1427*0b57cec5SDimitry Andric         error(std::move(Err), MachO->getFileName());
1428*0b57cec5SDimitry Andric       // Set the symbol names and indirect names for the added symbols.
1429*0b57cec5SDimitry Andric       if (ExportsAdded) {
1430*0b57cec5SDimitry Andric         EOS.flush();
1431*0b57cec5SDimitry Andric         const char *Q = ExportsNameBuffer.c_str();
1432*0b57cec5SDimitry Andric         for (unsigned K = 0; K < ExportsAdded; K++) {
1433*0b57cec5SDimitry Andric           SymbolList[I].Name = Q;
1434*0b57cec5SDimitry Andric           Q += strlen(Q) + 1;
1435*0b57cec5SDimitry Andric           if (SymbolList[I].TypeChar == 'I') {
1436*0b57cec5SDimitry Andric             SymbolList[I].IndirectName = Q;
1437*0b57cec5SDimitry Andric             Q += strlen(Q) + 1;
1438*0b57cec5SDimitry Andric           }
1439*0b57cec5SDimitry Andric           I++;
1440*0b57cec5SDimitry Andric         }
1441*0b57cec5SDimitry Andric       }
1442*0b57cec5SDimitry Andric 
1443*0b57cec5SDimitry Andric       // Add the undefined symbols from the bind entries.
1444*0b57cec5SDimitry Andric       unsigned BindsAdded = 0;
1445*0b57cec5SDimitry Andric       Error BErr = Error::success();
1446*0b57cec5SDimitry Andric       StringRef LastSymbolName = StringRef();
1447*0b57cec5SDimitry Andric       for (const llvm::object::MachOBindEntry &Entry : MachO->bindTable(BErr)) {
1448*0b57cec5SDimitry Andric         bool found = false;
1449*0b57cec5SDimitry Andric         if (LastSymbolName == Entry.symbolName())
1450*0b57cec5SDimitry Andric           found = true;
1451*0b57cec5SDimitry Andric         else if(!DyldInfoOnly) {
1452*0b57cec5SDimitry Andric           for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
1453*0b57cec5SDimitry Andric             if (SymbolList[J].Name == Entry.symbolName())
1454*0b57cec5SDimitry Andric               found = true;
1455*0b57cec5SDimitry Andric           }
1456*0b57cec5SDimitry Andric         }
1457*0b57cec5SDimitry Andric         if (!found) {
1458*0b57cec5SDimitry Andric           LastSymbolName = Entry.symbolName();
1459*0b57cec5SDimitry Andric           NMSymbol B = {};
1460*0b57cec5SDimitry Andric           B.Address = 0;
1461*0b57cec5SDimitry Andric           B.Size = 0;
1462*0b57cec5SDimitry Andric           B.TypeChar = 'U';
1463*0b57cec5SDimitry Andric           // There is no symbol in the nlist symbol table for this so we set
1464*0b57cec5SDimitry Andric           // Sym effectivly to null and the rest of code in here must test for
1465*0b57cec5SDimitry Andric           // it and not do things like Sym.getFlags() for it.
1466*0b57cec5SDimitry Andric           B.Sym = BasicSymbolRef();
1467*0b57cec5SDimitry Andric           B.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
1468*0b57cec5SDimitry Andric           B.NType = MachO::N_EXT | MachO::N_UNDF;
1469*0b57cec5SDimitry Andric           B.NSect = 0;
1470*0b57cec5SDimitry Andric           B.NDesc = 0;
1471*0b57cec5SDimitry Andric           MachO::SET_LIBRARY_ORDINAL(B.NDesc, Entry.ordinal());
1472*0b57cec5SDimitry Andric           B.IndirectName = StringRef();
1473*0b57cec5SDimitry Andric           B.Name = Entry.symbolName();
1474*0b57cec5SDimitry Andric           SymbolList.push_back(B);
1475*0b57cec5SDimitry Andric           BOS << Entry.symbolName();
1476*0b57cec5SDimitry Andric           BOS << '\0';
1477*0b57cec5SDimitry Andric           BindsAdded++;
1478*0b57cec5SDimitry Andric         }
1479*0b57cec5SDimitry Andric       }
1480*0b57cec5SDimitry Andric       if (BErr)
1481*0b57cec5SDimitry Andric         error(std::move(BErr), MachO->getFileName());
1482*0b57cec5SDimitry Andric       // Set the symbol names and indirect names for the added symbols.
1483*0b57cec5SDimitry Andric       if (BindsAdded) {
1484*0b57cec5SDimitry Andric         BOS.flush();
1485*0b57cec5SDimitry Andric         const char *Q = BindsNameBuffer.c_str();
1486*0b57cec5SDimitry Andric         for (unsigned K = 0; K < BindsAdded; K++) {
1487*0b57cec5SDimitry Andric           SymbolList[I].Name = Q;
1488*0b57cec5SDimitry Andric           Q += strlen(Q) + 1;
1489*0b57cec5SDimitry Andric           if (SymbolList[I].TypeChar == 'I') {
1490*0b57cec5SDimitry Andric             SymbolList[I].IndirectName = Q;
1491*0b57cec5SDimitry Andric             Q += strlen(Q) + 1;
1492*0b57cec5SDimitry Andric           }
1493*0b57cec5SDimitry Andric           I++;
1494*0b57cec5SDimitry Andric         }
1495*0b57cec5SDimitry Andric       }
1496*0b57cec5SDimitry Andric 
1497*0b57cec5SDimitry Andric       // Add the undefined symbols from the lazy bind entries.
1498*0b57cec5SDimitry Andric       unsigned LazysAdded = 0;
1499*0b57cec5SDimitry Andric       Error LErr = Error::success();
1500*0b57cec5SDimitry Andric       LastSymbolName = StringRef();
1501*0b57cec5SDimitry Andric       for (const llvm::object::MachOBindEntry &Entry :
1502*0b57cec5SDimitry Andric            MachO->lazyBindTable(LErr)) {
1503*0b57cec5SDimitry Andric         bool found = false;
1504*0b57cec5SDimitry Andric         if (LastSymbolName == Entry.symbolName())
1505*0b57cec5SDimitry Andric           found = true;
1506*0b57cec5SDimitry Andric         else {
1507*0b57cec5SDimitry Andric           // Here we must check to see it this symbol is already in the
1508*0b57cec5SDimitry Andric           // SymbolList as it might have already have been added above via a
1509*0b57cec5SDimitry Andric           // non-lazy (bind) entry.
1510*0b57cec5SDimitry Andric           for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
1511*0b57cec5SDimitry Andric             if (SymbolList[J].Name == Entry.symbolName())
1512*0b57cec5SDimitry Andric               found = true;
1513*0b57cec5SDimitry Andric           }
1514*0b57cec5SDimitry Andric         }
1515*0b57cec5SDimitry Andric         if (!found) {
1516*0b57cec5SDimitry Andric           LastSymbolName = Entry.symbolName();
1517*0b57cec5SDimitry Andric           NMSymbol L = {};
1518*0b57cec5SDimitry Andric           L.Name = Entry.symbolName();
1519*0b57cec5SDimitry Andric           L.Address = 0;
1520*0b57cec5SDimitry Andric           L.Size = 0;
1521*0b57cec5SDimitry Andric           L.TypeChar = 'U';
1522*0b57cec5SDimitry Andric           // There is no symbol in the nlist symbol table for this so we set
1523*0b57cec5SDimitry Andric           // Sym effectivly to null and the rest of code in here must test for
1524*0b57cec5SDimitry Andric           // it and not do things like Sym.getFlags() for it.
1525*0b57cec5SDimitry Andric           L.Sym = BasicSymbolRef();
1526*0b57cec5SDimitry Andric           L.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
1527*0b57cec5SDimitry Andric           L.NType = MachO::N_EXT | MachO::N_UNDF;
1528*0b57cec5SDimitry Andric           L.NSect = 0;
1529*0b57cec5SDimitry Andric           // The REFERENCE_FLAG_UNDEFINED_LAZY is no longer used but here it
1530*0b57cec5SDimitry Andric           // makes sence since we are creating this from a lazy bind entry.
1531*0b57cec5SDimitry Andric           L.NDesc = MachO::REFERENCE_FLAG_UNDEFINED_LAZY;
1532*0b57cec5SDimitry Andric           MachO::SET_LIBRARY_ORDINAL(L.NDesc, Entry.ordinal());
1533*0b57cec5SDimitry Andric           L.IndirectName = StringRef();
1534*0b57cec5SDimitry Andric           SymbolList.push_back(L);
1535*0b57cec5SDimitry Andric           LOS << Entry.symbolName();
1536*0b57cec5SDimitry Andric           LOS << '\0';
1537*0b57cec5SDimitry Andric           LazysAdded++;
1538*0b57cec5SDimitry Andric         }
1539*0b57cec5SDimitry Andric       }
1540*0b57cec5SDimitry Andric       if (LErr)
1541*0b57cec5SDimitry Andric         error(std::move(LErr), MachO->getFileName());
1542*0b57cec5SDimitry Andric       // Set the symbol names and indirect names for the added symbols.
1543*0b57cec5SDimitry Andric       if (LazysAdded) {
1544*0b57cec5SDimitry Andric         LOS.flush();
1545*0b57cec5SDimitry Andric         const char *Q = LazysNameBuffer.c_str();
1546*0b57cec5SDimitry Andric         for (unsigned K = 0; K < LazysAdded; K++) {
1547*0b57cec5SDimitry Andric           SymbolList[I].Name = Q;
1548*0b57cec5SDimitry Andric           Q += strlen(Q) + 1;
1549*0b57cec5SDimitry Andric           if (SymbolList[I].TypeChar == 'I') {
1550*0b57cec5SDimitry Andric             SymbolList[I].IndirectName = Q;
1551*0b57cec5SDimitry Andric             Q += strlen(Q) + 1;
1552*0b57cec5SDimitry Andric           }
1553*0b57cec5SDimitry Andric           I++;
1554*0b57cec5SDimitry Andric         }
1555*0b57cec5SDimitry Andric       }
1556*0b57cec5SDimitry Andric 
1557*0b57cec5SDimitry Andric       // Add the undefineds symbol from the weak bind entries which are not
1558*0b57cec5SDimitry Andric       // strong symbols.
1559*0b57cec5SDimitry Andric       unsigned WeaksAdded = 0;
1560*0b57cec5SDimitry Andric       Error WErr = Error::success();
1561*0b57cec5SDimitry Andric       LastSymbolName = StringRef();
1562*0b57cec5SDimitry Andric       for (const llvm::object::MachOBindEntry &Entry :
1563*0b57cec5SDimitry Andric            MachO->weakBindTable(WErr)) {
1564*0b57cec5SDimitry Andric         bool found = false;
1565*0b57cec5SDimitry Andric         unsigned J = 0;
1566*0b57cec5SDimitry Andric         if (LastSymbolName == Entry.symbolName() ||
1567*0b57cec5SDimitry Andric             Entry.flags() & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) {
1568*0b57cec5SDimitry Andric           found = true;
1569*0b57cec5SDimitry Andric         } else {
1570*0b57cec5SDimitry Andric           for (J = 0; J < SymbolList.size() && !found; ++J) {
1571*0b57cec5SDimitry Andric             if (SymbolList[J].Name == Entry.symbolName()) {
1572*0b57cec5SDimitry Andric                found = true;
1573*0b57cec5SDimitry Andric                break;
1574*0b57cec5SDimitry Andric             }
1575*0b57cec5SDimitry Andric           }
1576*0b57cec5SDimitry Andric         }
1577*0b57cec5SDimitry Andric         if (!found) {
1578*0b57cec5SDimitry Andric           LastSymbolName = Entry.symbolName();
1579*0b57cec5SDimitry Andric           NMSymbol W;
1580*0b57cec5SDimitry Andric           memset(&W, '\0', sizeof(NMSymbol));
1581*0b57cec5SDimitry Andric           W.Name = Entry.symbolName();
1582*0b57cec5SDimitry Andric           W.Address = 0;
1583*0b57cec5SDimitry Andric           W.Size = 0;
1584*0b57cec5SDimitry Andric           W.TypeChar = 'U';
1585*0b57cec5SDimitry Andric           // There is no symbol in the nlist symbol table for this so we set
1586*0b57cec5SDimitry Andric           // Sym effectivly to null and the rest of code in here must test for
1587*0b57cec5SDimitry Andric           // it and not do things like Sym.getFlags() for it.
1588*0b57cec5SDimitry Andric           W.Sym = BasicSymbolRef();
1589*0b57cec5SDimitry Andric           W.SymFlags = SymbolRef::SF_Global | SymbolRef::SF_Undefined;
1590*0b57cec5SDimitry Andric           W.NType = MachO::N_EXT | MachO::N_UNDF;
1591*0b57cec5SDimitry Andric           W.NSect = 0;
1592*0b57cec5SDimitry Andric           // Odd that we are using N_WEAK_DEF on an undefined symbol but that is
1593*0b57cec5SDimitry Andric           // what is created in this case by the linker when there are real
1594*0b57cec5SDimitry Andric           // symbols in the nlist structs.
1595*0b57cec5SDimitry Andric           W.NDesc = MachO::N_WEAK_DEF;
1596*0b57cec5SDimitry Andric           W.IndirectName = StringRef();
1597*0b57cec5SDimitry Andric           SymbolList.push_back(W);
1598*0b57cec5SDimitry Andric           WOS << Entry.symbolName();
1599*0b57cec5SDimitry Andric           WOS << '\0';
1600*0b57cec5SDimitry Andric           WeaksAdded++;
1601*0b57cec5SDimitry Andric         } else {
1602*0b57cec5SDimitry Andric           // This is the case the symbol was previously been found and it could
1603*0b57cec5SDimitry Andric           // have been added from a bind or lazy bind symbol.  If so and not
1604*0b57cec5SDimitry Andric           // a definition also mark it as weak.
1605*0b57cec5SDimitry Andric           if (SymbolList[J].TypeChar == 'U')
1606*0b57cec5SDimitry Andric             // See comment above about N_WEAK_DEF.
1607*0b57cec5SDimitry Andric             SymbolList[J].NDesc |= MachO::N_WEAK_DEF;
1608*0b57cec5SDimitry Andric         }
1609*0b57cec5SDimitry Andric       }
1610*0b57cec5SDimitry Andric       if (WErr)
1611*0b57cec5SDimitry Andric         error(std::move(WErr), MachO->getFileName());
1612*0b57cec5SDimitry Andric       // Set the symbol names and indirect names for the added symbols.
1613*0b57cec5SDimitry Andric       if (WeaksAdded) {
1614*0b57cec5SDimitry Andric         WOS.flush();
1615*0b57cec5SDimitry Andric         const char *Q = WeaksNameBuffer.c_str();
1616*0b57cec5SDimitry Andric         for (unsigned K = 0; K < WeaksAdded; K++) {
1617*0b57cec5SDimitry Andric           SymbolList[I].Name = Q;
1618*0b57cec5SDimitry Andric           Q += strlen(Q) + 1;
1619*0b57cec5SDimitry Andric           if (SymbolList[I].TypeChar == 'I') {
1620*0b57cec5SDimitry Andric             SymbolList[I].IndirectName = Q;
1621*0b57cec5SDimitry Andric             Q += strlen(Q) + 1;
1622*0b57cec5SDimitry Andric           }
1623*0b57cec5SDimitry Andric           I++;
1624*0b57cec5SDimitry Andric         }
1625*0b57cec5SDimitry Andric       }
1626*0b57cec5SDimitry Andric 
1627*0b57cec5SDimitry Andric       // Trying adding symbol from the function starts table and LC_MAIN entry
1628*0b57cec5SDimitry Andric       // point.
1629*0b57cec5SDimitry Andric       SmallVector<uint64_t, 8> FoundFns;
1630*0b57cec5SDimitry Andric       uint64_t lc_main_offset = UINT64_MAX;
1631*0b57cec5SDimitry Andric       for (const auto &Command : MachO->load_commands()) {
1632*0b57cec5SDimitry Andric         if (Command.C.cmd == MachO::LC_FUNCTION_STARTS) {
1633*0b57cec5SDimitry Andric           // We found a function starts segment, parse the addresses for
1634*0b57cec5SDimitry Andric           // consumption.
1635*0b57cec5SDimitry Andric           MachO::linkedit_data_command LLC =
1636*0b57cec5SDimitry Andric             MachO->getLinkeditDataLoadCommand(Command);
1637*0b57cec5SDimitry Andric 
1638*0b57cec5SDimitry Andric           MachO->ReadULEB128s(LLC.dataoff, FoundFns);
1639*0b57cec5SDimitry Andric         } else if (Command.C.cmd == MachO::LC_MAIN) {
1640*0b57cec5SDimitry Andric           MachO::entry_point_command LCmain =
1641*0b57cec5SDimitry Andric             MachO->getEntryPointCommand(Command);
1642*0b57cec5SDimitry Andric           lc_main_offset = LCmain.entryoff;
1643*0b57cec5SDimitry Andric         }
1644*0b57cec5SDimitry Andric       }
1645*0b57cec5SDimitry Andric       // See if these addresses are already in the symbol table.
1646*0b57cec5SDimitry Andric       unsigned FunctionStartsAdded = 0;
1647*0b57cec5SDimitry Andric       for (uint64_t f = 0; f < FoundFns.size(); f++) {
1648*0b57cec5SDimitry Andric         bool found = false;
1649*0b57cec5SDimitry Andric         for (unsigned J = 0; J < SymbolList.size() && !found; ++J) {
1650*0b57cec5SDimitry Andric           if (SymbolList[J].Address == FoundFns[f] + BaseSegmentAddress)
1651*0b57cec5SDimitry Andric             found = true;
1652*0b57cec5SDimitry Andric         }
1653*0b57cec5SDimitry Andric         // See this address is not already in the symbol table fake up an
1654*0b57cec5SDimitry Andric         // nlist for it.
1655*0b57cec5SDimitry Andric         if (!found) {
1656*0b57cec5SDimitry Andric           NMSymbol F = {};
1657*0b57cec5SDimitry Andric           F.Name = "<redacted function X>";
1658*0b57cec5SDimitry Andric           F.Address = FoundFns[f] + BaseSegmentAddress;
1659*0b57cec5SDimitry Andric           F.Size = 0;
1660*0b57cec5SDimitry Andric           // There is no symbol in the nlist symbol table for this so we set
1661*0b57cec5SDimitry Andric           // Sym effectivly to null and the rest of code in here must test for
1662*0b57cec5SDimitry Andric           // it and not do things like Sym.getFlags() for it.
1663*0b57cec5SDimitry Andric           F.Sym = BasicSymbolRef();
1664*0b57cec5SDimitry Andric           F.SymFlags = 0;
1665*0b57cec5SDimitry Andric           F.NType = MachO::N_SECT;
1666*0b57cec5SDimitry Andric           F.NSect = 0;
1667*0b57cec5SDimitry Andric           StringRef SegmentName = StringRef();
1668*0b57cec5SDimitry Andric           StringRef SectionName = StringRef();
1669*0b57cec5SDimitry Andric           for (const SectionRef &Section : MachO->sections()) {
1670*0b57cec5SDimitry Andric             Section.getName(SectionName);
1671*0b57cec5SDimitry Andric             SegmentName = MachO->getSectionFinalSegmentName(
1672*0b57cec5SDimitry Andric                                                 Section.getRawDataRefImpl());
1673*0b57cec5SDimitry Andric             F.NSect++;
1674*0b57cec5SDimitry Andric             if (F.Address >= Section.getAddress() &&
1675*0b57cec5SDimitry Andric                 F.Address < Section.getAddress() + Section.getSize()) {
1676*0b57cec5SDimitry Andric               F.Section = Section;
1677*0b57cec5SDimitry Andric               break;
1678*0b57cec5SDimitry Andric             }
1679*0b57cec5SDimitry Andric           }
1680*0b57cec5SDimitry Andric           if (SegmentName == "__TEXT" && SectionName == "__text")
1681*0b57cec5SDimitry Andric             F.TypeChar = 't';
1682*0b57cec5SDimitry Andric           else if (SegmentName == "__DATA" && SectionName == "__data")
1683*0b57cec5SDimitry Andric             F.TypeChar = 'd';
1684*0b57cec5SDimitry Andric           else if (SegmentName == "__DATA" && SectionName == "__bss")
1685*0b57cec5SDimitry Andric             F.TypeChar = 'b';
1686*0b57cec5SDimitry Andric           else
1687*0b57cec5SDimitry Andric             F.TypeChar = 's';
1688*0b57cec5SDimitry Andric           F.NDesc = 0;
1689*0b57cec5SDimitry Andric           F.IndirectName = StringRef();
1690*0b57cec5SDimitry Andric           SymbolList.push_back(F);
1691*0b57cec5SDimitry Andric           if (FoundFns[f] == lc_main_offset)
1692*0b57cec5SDimitry Andric             FOS << "<redacted LC_MAIN>";
1693*0b57cec5SDimitry Andric           else
1694*0b57cec5SDimitry Andric             FOS << "<redacted function " << f << ">";
1695*0b57cec5SDimitry Andric           FOS << '\0';
1696*0b57cec5SDimitry Andric           FunctionStartsAdded++;
1697*0b57cec5SDimitry Andric         }
1698*0b57cec5SDimitry Andric       }
1699*0b57cec5SDimitry Andric       if (FunctionStartsAdded) {
1700*0b57cec5SDimitry Andric         FOS.flush();
1701*0b57cec5SDimitry Andric         const char *Q = FunctionStartsNameBuffer.c_str();
1702*0b57cec5SDimitry Andric         for (unsigned K = 0; K < FunctionStartsAdded; K++) {
1703*0b57cec5SDimitry Andric           SymbolList[I].Name = Q;
1704*0b57cec5SDimitry Andric           Q += strlen(Q) + 1;
1705*0b57cec5SDimitry Andric           if (SymbolList[I].TypeChar == 'I') {
1706*0b57cec5SDimitry Andric             SymbolList[I].IndirectName = Q;
1707*0b57cec5SDimitry Andric             Q += strlen(Q) + 1;
1708*0b57cec5SDimitry Andric           }
1709*0b57cec5SDimitry Andric           I++;
1710*0b57cec5SDimitry Andric         }
1711*0b57cec5SDimitry Andric       }
1712*0b57cec5SDimitry Andric     }
1713*0b57cec5SDimitry Andric   }
1714*0b57cec5SDimitry Andric 
1715*0b57cec5SDimitry Andric   CurrentFilename = Obj.getFileName();
1716*0b57cec5SDimitry Andric   sortAndPrintSymbolList(Obj, printName, ArchiveName, ArchitectureName);
1717*0b57cec5SDimitry Andric }
1718*0b57cec5SDimitry Andric 
1719*0b57cec5SDimitry Andric // checkMachOAndArchFlags() checks to see if the SymbolicFile is a Mach-O file
1720*0b57cec5SDimitry Andric // and if it is and there is a list of architecture flags is specified then
1721*0b57cec5SDimitry Andric // check to make sure this Mach-O file is one of those architectures or all
1722*0b57cec5SDimitry Andric // architectures was specificed.  If not then an error is generated and this
1723*0b57cec5SDimitry Andric // routine returns false.  Else it returns true.
1724*0b57cec5SDimitry Andric static bool checkMachOAndArchFlags(SymbolicFile *O, std::string &Filename) {
1725*0b57cec5SDimitry Andric   auto *MachO = dyn_cast<MachOObjectFile>(O);
1726*0b57cec5SDimitry Andric 
1727*0b57cec5SDimitry Andric   if (!MachO || ArchAll || ArchFlags.empty())
1728*0b57cec5SDimitry Andric     return true;
1729*0b57cec5SDimitry Andric 
1730*0b57cec5SDimitry Andric   MachO::mach_header H;
1731*0b57cec5SDimitry Andric   MachO::mach_header_64 H_64;
1732*0b57cec5SDimitry Andric   Triple T;
1733*0b57cec5SDimitry Andric   const char *McpuDefault, *ArchFlag;
1734*0b57cec5SDimitry Andric   if (MachO->is64Bit()) {
1735*0b57cec5SDimitry Andric     H_64 = MachO->MachOObjectFile::getHeader64();
1736*0b57cec5SDimitry Andric     T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype,
1737*0b57cec5SDimitry Andric                                        &McpuDefault, &ArchFlag);
1738*0b57cec5SDimitry Andric   } else {
1739*0b57cec5SDimitry Andric     H = MachO->MachOObjectFile::getHeader();
1740*0b57cec5SDimitry Andric     T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype,
1741*0b57cec5SDimitry Andric                                        &McpuDefault, &ArchFlag);
1742*0b57cec5SDimitry Andric   }
1743*0b57cec5SDimitry Andric   const std::string ArchFlagName(ArchFlag);
1744*0b57cec5SDimitry Andric   if (none_of(ArchFlags, [&](const std::string &Name) {
1745*0b57cec5SDimitry Andric         return Name == ArchFlagName;
1746*0b57cec5SDimitry Andric       })) {
1747*0b57cec5SDimitry Andric     error("No architecture specified", Filename);
1748*0b57cec5SDimitry Andric     return false;
1749*0b57cec5SDimitry Andric   }
1750*0b57cec5SDimitry Andric   return true;
1751*0b57cec5SDimitry Andric }
1752*0b57cec5SDimitry Andric 
1753*0b57cec5SDimitry Andric static void dumpSymbolNamesFromFile(std::string &Filename) {
1754*0b57cec5SDimitry Andric   ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
1755*0b57cec5SDimitry Andric       MemoryBuffer::getFileOrSTDIN(Filename);
1756*0b57cec5SDimitry Andric   if (error(BufferOrErr.getError(), Filename))
1757*0b57cec5SDimitry Andric     return;
1758*0b57cec5SDimitry Andric 
1759*0b57cec5SDimitry Andric   LLVMContext Context;
1760*0b57cec5SDimitry Andric   LLVMContext *ContextPtr = NoLLVMBitcode ? nullptr : &Context;
1761*0b57cec5SDimitry Andric   Expected<std::unique_ptr<Binary>> BinaryOrErr =
1762*0b57cec5SDimitry Andric       createBinary(BufferOrErr.get()->getMemBufferRef(), ContextPtr);
1763*0b57cec5SDimitry Andric   if (!BinaryOrErr) {
1764*0b57cec5SDimitry Andric     error(BinaryOrErr.takeError(), Filename);
1765*0b57cec5SDimitry Andric     return;
1766*0b57cec5SDimitry Andric   }
1767*0b57cec5SDimitry Andric   Binary &Bin = *BinaryOrErr.get();
1768*0b57cec5SDimitry Andric 
1769*0b57cec5SDimitry Andric   if (Archive *A = dyn_cast<Archive>(&Bin)) {
1770*0b57cec5SDimitry Andric     if (ArchiveMap) {
1771*0b57cec5SDimitry Andric       Archive::symbol_iterator I = A->symbol_begin();
1772*0b57cec5SDimitry Andric       Archive::symbol_iterator E = A->symbol_end();
1773*0b57cec5SDimitry Andric       if (I != E) {
1774*0b57cec5SDimitry Andric         outs() << "Archive map\n";
1775*0b57cec5SDimitry Andric         for (; I != E; ++I) {
1776*0b57cec5SDimitry Andric           Expected<Archive::Child> C = I->getMember();
1777*0b57cec5SDimitry Andric           if (!C) {
1778*0b57cec5SDimitry Andric             error(C.takeError(), Filename);
1779*0b57cec5SDimitry Andric             break;
1780*0b57cec5SDimitry Andric           }
1781*0b57cec5SDimitry Andric           Expected<StringRef> FileNameOrErr = C->getName();
1782*0b57cec5SDimitry Andric           if (!FileNameOrErr) {
1783*0b57cec5SDimitry Andric             error(FileNameOrErr.takeError(), Filename);
1784*0b57cec5SDimitry Andric             break;
1785*0b57cec5SDimitry Andric           }
1786*0b57cec5SDimitry Andric           StringRef SymName = I->getName();
1787*0b57cec5SDimitry Andric           outs() << SymName << " in " << FileNameOrErr.get() << "\n";
1788*0b57cec5SDimitry Andric         }
1789*0b57cec5SDimitry Andric         outs() << "\n";
1790*0b57cec5SDimitry Andric       }
1791*0b57cec5SDimitry Andric     }
1792*0b57cec5SDimitry Andric 
1793*0b57cec5SDimitry Andric     {
1794*0b57cec5SDimitry Andric       Error Err = Error::success();
1795*0b57cec5SDimitry Andric       for (auto &C : A->children(Err)) {
1796*0b57cec5SDimitry Andric         Expected<std::unique_ptr<Binary>> ChildOrErr =
1797*0b57cec5SDimitry Andric             C.getAsBinary(ContextPtr);
1798*0b57cec5SDimitry Andric         if (!ChildOrErr) {
1799*0b57cec5SDimitry Andric           if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
1800*0b57cec5SDimitry Andric             error(std::move(E), Filename, C);
1801*0b57cec5SDimitry Andric           continue;
1802*0b57cec5SDimitry Andric         }
1803*0b57cec5SDimitry Andric         if (SymbolicFile *O = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
1804*0b57cec5SDimitry Andric           if (!MachOPrintSizeWarning && PrintSize &&  isa<MachOObjectFile>(O)) {
1805*0b57cec5SDimitry Andric             WithColor::warning(errs(), ToolName)
1806*0b57cec5SDimitry Andric                 << "sizes with -print-size for Mach-O files are always zero.\n";
1807*0b57cec5SDimitry Andric             MachOPrintSizeWarning = true;
1808*0b57cec5SDimitry Andric           }
1809*0b57cec5SDimitry Andric           if (!checkMachOAndArchFlags(O, Filename))
1810*0b57cec5SDimitry Andric             return;
1811*0b57cec5SDimitry Andric           if (!PrintFileName) {
1812*0b57cec5SDimitry Andric             outs() << "\n";
1813*0b57cec5SDimitry Andric             if (isa<MachOObjectFile>(O)) {
1814*0b57cec5SDimitry Andric               outs() << Filename << "(" << O->getFileName() << ")";
1815*0b57cec5SDimitry Andric             } else
1816*0b57cec5SDimitry Andric               outs() << O->getFileName();
1817*0b57cec5SDimitry Andric             outs() << ":\n";
1818*0b57cec5SDimitry Andric           }
1819*0b57cec5SDimitry Andric           dumpSymbolNamesFromObject(*O, false, Filename);
1820*0b57cec5SDimitry Andric         }
1821*0b57cec5SDimitry Andric       }
1822*0b57cec5SDimitry Andric       if (Err)
1823*0b57cec5SDimitry Andric         error(std::move(Err), A->getFileName());
1824*0b57cec5SDimitry Andric     }
1825*0b57cec5SDimitry Andric     return;
1826*0b57cec5SDimitry Andric   }
1827*0b57cec5SDimitry Andric   if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Bin)) {
1828*0b57cec5SDimitry Andric     // If we have a list of architecture flags specified dump only those.
1829*0b57cec5SDimitry Andric     if (!ArchAll && !ArchFlags.empty()) {
1830*0b57cec5SDimitry Andric       // Look for a slice in the universal binary that matches each ArchFlag.
1831*0b57cec5SDimitry Andric       bool ArchFound;
1832*0b57cec5SDimitry Andric       for (unsigned i = 0; i < ArchFlags.size(); ++i) {
1833*0b57cec5SDimitry Andric         ArchFound = false;
1834*0b57cec5SDimitry Andric         for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
1835*0b57cec5SDimitry Andric                                                    E = UB->end_objects();
1836*0b57cec5SDimitry Andric              I != E; ++I) {
1837*0b57cec5SDimitry Andric           if (ArchFlags[i] == I->getArchFlagName()) {
1838*0b57cec5SDimitry Andric             ArchFound = true;
1839*0b57cec5SDimitry Andric             Expected<std::unique_ptr<ObjectFile>> ObjOrErr =
1840*0b57cec5SDimitry Andric                 I->getAsObjectFile();
1841*0b57cec5SDimitry Andric             std::string ArchiveName;
1842*0b57cec5SDimitry Andric             std::string ArchitectureName;
1843*0b57cec5SDimitry Andric             ArchiveName.clear();
1844*0b57cec5SDimitry Andric             ArchitectureName.clear();
1845*0b57cec5SDimitry Andric             if (ObjOrErr) {
1846*0b57cec5SDimitry Andric               ObjectFile &Obj = *ObjOrErr.get();
1847*0b57cec5SDimitry Andric               if (ArchFlags.size() > 1) {
1848*0b57cec5SDimitry Andric                 if (PrintFileName)
1849*0b57cec5SDimitry Andric                   ArchitectureName = I->getArchFlagName();
1850*0b57cec5SDimitry Andric                 else
1851*0b57cec5SDimitry Andric                   outs() << "\n" << Obj.getFileName() << " (for architecture "
1852*0b57cec5SDimitry Andric                          << I->getArchFlagName() << ")"
1853*0b57cec5SDimitry Andric                          << ":\n";
1854*0b57cec5SDimitry Andric               }
1855*0b57cec5SDimitry Andric               dumpSymbolNamesFromObject(Obj, false, ArchiveName,
1856*0b57cec5SDimitry Andric                                         ArchitectureName);
1857*0b57cec5SDimitry Andric             } else if (auto E = isNotObjectErrorInvalidFileType(
1858*0b57cec5SDimitry Andric                        ObjOrErr.takeError())) {
1859*0b57cec5SDimitry Andric               error(std::move(E), Filename, ArchFlags.size() > 1 ?
1860*0b57cec5SDimitry Andric                     StringRef(I->getArchFlagName()) : StringRef());
1861*0b57cec5SDimitry Andric               continue;
1862*0b57cec5SDimitry Andric             } else if (Expected<std::unique_ptr<Archive>> AOrErr =
1863*0b57cec5SDimitry Andric                            I->getAsArchive()) {
1864*0b57cec5SDimitry Andric               std::unique_ptr<Archive> &A = *AOrErr;
1865*0b57cec5SDimitry Andric               Error Err = Error::success();
1866*0b57cec5SDimitry Andric               for (auto &C : A->children(Err)) {
1867*0b57cec5SDimitry Andric                 Expected<std::unique_ptr<Binary>> ChildOrErr =
1868*0b57cec5SDimitry Andric                     C.getAsBinary(ContextPtr);
1869*0b57cec5SDimitry Andric                 if (!ChildOrErr) {
1870*0b57cec5SDimitry Andric                   if (auto E = isNotObjectErrorInvalidFileType(
1871*0b57cec5SDimitry Andric                                        ChildOrErr.takeError())) {
1872*0b57cec5SDimitry Andric                     error(std::move(E), Filename, C, ArchFlags.size() > 1 ?
1873*0b57cec5SDimitry Andric                           StringRef(I->getArchFlagName()) : StringRef());
1874*0b57cec5SDimitry Andric                   }
1875*0b57cec5SDimitry Andric                   continue;
1876*0b57cec5SDimitry Andric                 }
1877*0b57cec5SDimitry Andric                 if (SymbolicFile *O =
1878*0b57cec5SDimitry Andric                         dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
1879*0b57cec5SDimitry Andric                   if (PrintFileName) {
1880*0b57cec5SDimitry Andric                     ArchiveName = A->getFileName();
1881*0b57cec5SDimitry Andric                     if (ArchFlags.size() > 1)
1882*0b57cec5SDimitry Andric                       ArchitectureName = I->getArchFlagName();
1883*0b57cec5SDimitry Andric                   } else {
1884*0b57cec5SDimitry Andric                     outs() << "\n" << A->getFileName();
1885*0b57cec5SDimitry Andric                     outs() << "(" << O->getFileName() << ")";
1886*0b57cec5SDimitry Andric                     if (ArchFlags.size() > 1) {
1887*0b57cec5SDimitry Andric                       outs() << " (for architecture " << I->getArchFlagName()
1888*0b57cec5SDimitry Andric                              << ")";
1889*0b57cec5SDimitry Andric                     }
1890*0b57cec5SDimitry Andric                     outs() << ":\n";
1891*0b57cec5SDimitry Andric                   }
1892*0b57cec5SDimitry Andric                   dumpSymbolNamesFromObject(*O, false, ArchiveName,
1893*0b57cec5SDimitry Andric                                             ArchitectureName);
1894*0b57cec5SDimitry Andric                 }
1895*0b57cec5SDimitry Andric               }
1896*0b57cec5SDimitry Andric               if (Err)
1897*0b57cec5SDimitry Andric                 error(std::move(Err), A->getFileName());
1898*0b57cec5SDimitry Andric             } else {
1899*0b57cec5SDimitry Andric               consumeError(AOrErr.takeError());
1900*0b57cec5SDimitry Andric               error(Filename + " for architecture " +
1901*0b57cec5SDimitry Andric                     StringRef(I->getArchFlagName()) +
1902*0b57cec5SDimitry Andric                     " is not a Mach-O file or an archive file",
1903*0b57cec5SDimitry Andric                     "Mach-O universal file");
1904*0b57cec5SDimitry Andric             }
1905*0b57cec5SDimitry Andric           }
1906*0b57cec5SDimitry Andric         }
1907*0b57cec5SDimitry Andric         if (!ArchFound) {
1908*0b57cec5SDimitry Andric           error(ArchFlags[i],
1909*0b57cec5SDimitry Andric                 "file: " + Filename + " does not contain architecture");
1910*0b57cec5SDimitry Andric           return;
1911*0b57cec5SDimitry Andric         }
1912*0b57cec5SDimitry Andric       }
1913*0b57cec5SDimitry Andric       return;
1914*0b57cec5SDimitry Andric     }
1915*0b57cec5SDimitry Andric     // No architecture flags were specified so if this contains a slice that
1916*0b57cec5SDimitry Andric     // matches the host architecture dump only that.
1917*0b57cec5SDimitry Andric     if (!ArchAll) {
1918*0b57cec5SDimitry Andric       Triple HostTriple = MachOObjectFile::getHostArch();
1919*0b57cec5SDimitry Andric       StringRef HostArchName = HostTriple.getArchName();
1920*0b57cec5SDimitry Andric       for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
1921*0b57cec5SDimitry Andric                                                  E = UB->end_objects();
1922*0b57cec5SDimitry Andric            I != E; ++I) {
1923*0b57cec5SDimitry Andric         if (HostArchName == I->getArchFlagName()) {
1924*0b57cec5SDimitry Andric           Expected<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();
1925*0b57cec5SDimitry Andric           std::string ArchiveName;
1926*0b57cec5SDimitry Andric           if (ObjOrErr) {
1927*0b57cec5SDimitry Andric             ObjectFile &Obj = *ObjOrErr.get();
1928*0b57cec5SDimitry Andric             dumpSymbolNamesFromObject(Obj, false);
1929*0b57cec5SDimitry Andric           } else if (auto E = isNotObjectErrorInvalidFileType(
1930*0b57cec5SDimitry Andric                      ObjOrErr.takeError())) {
1931*0b57cec5SDimitry Andric             error(std::move(E), Filename);
1932*0b57cec5SDimitry Andric             return;
1933*0b57cec5SDimitry Andric           } else if (Expected<std::unique_ptr<Archive>> AOrErr =
1934*0b57cec5SDimitry Andric                          I->getAsArchive()) {
1935*0b57cec5SDimitry Andric             std::unique_ptr<Archive> &A = *AOrErr;
1936*0b57cec5SDimitry Andric             Error Err = Error::success();
1937*0b57cec5SDimitry Andric             for (auto &C : A->children(Err)) {
1938*0b57cec5SDimitry Andric               Expected<std::unique_ptr<Binary>> ChildOrErr =
1939*0b57cec5SDimitry Andric                   C.getAsBinary(ContextPtr);
1940*0b57cec5SDimitry Andric               if (!ChildOrErr) {
1941*0b57cec5SDimitry Andric                 if (auto E = isNotObjectErrorInvalidFileType(
1942*0b57cec5SDimitry Andric                                      ChildOrErr.takeError()))
1943*0b57cec5SDimitry Andric                   error(std::move(E), Filename, C);
1944*0b57cec5SDimitry Andric                 continue;
1945*0b57cec5SDimitry Andric               }
1946*0b57cec5SDimitry Andric               if (SymbolicFile *O =
1947*0b57cec5SDimitry Andric                       dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
1948*0b57cec5SDimitry Andric                 if (PrintFileName)
1949*0b57cec5SDimitry Andric                   ArchiveName = A->getFileName();
1950*0b57cec5SDimitry Andric                 else
1951*0b57cec5SDimitry Andric                   outs() << "\n" << A->getFileName() << "(" << O->getFileName()
1952*0b57cec5SDimitry Andric                          << ")"
1953*0b57cec5SDimitry Andric                          << ":\n";
1954*0b57cec5SDimitry Andric                 dumpSymbolNamesFromObject(*O, false, ArchiveName);
1955*0b57cec5SDimitry Andric               }
1956*0b57cec5SDimitry Andric             }
1957*0b57cec5SDimitry Andric             if (Err)
1958*0b57cec5SDimitry Andric               error(std::move(Err), A->getFileName());
1959*0b57cec5SDimitry Andric           } else {
1960*0b57cec5SDimitry Andric             consumeError(AOrErr.takeError());
1961*0b57cec5SDimitry Andric             error(Filename + " for architecture " +
1962*0b57cec5SDimitry Andric                   StringRef(I->getArchFlagName()) +
1963*0b57cec5SDimitry Andric                   " is not a Mach-O file or an archive file",
1964*0b57cec5SDimitry Andric                   "Mach-O universal file");
1965*0b57cec5SDimitry Andric           }
1966*0b57cec5SDimitry Andric           return;
1967*0b57cec5SDimitry Andric         }
1968*0b57cec5SDimitry Andric       }
1969*0b57cec5SDimitry Andric     }
1970*0b57cec5SDimitry Andric     // Either all architectures have been specified or none have been specified
1971*0b57cec5SDimitry Andric     // and this does not contain the host architecture so dump all the slices.
1972*0b57cec5SDimitry Andric     bool moreThanOneArch = UB->getNumberOfObjects() > 1;
1973*0b57cec5SDimitry Andric     for (const MachOUniversalBinary::ObjectForArch &O : UB->objects()) {
1974*0b57cec5SDimitry Andric       Expected<std::unique_ptr<ObjectFile>> ObjOrErr = O.getAsObjectFile();
1975*0b57cec5SDimitry Andric       std::string ArchiveName;
1976*0b57cec5SDimitry Andric       std::string ArchitectureName;
1977*0b57cec5SDimitry Andric       ArchiveName.clear();
1978*0b57cec5SDimitry Andric       ArchitectureName.clear();
1979*0b57cec5SDimitry Andric       if (ObjOrErr) {
1980*0b57cec5SDimitry Andric         ObjectFile &Obj = *ObjOrErr.get();
1981*0b57cec5SDimitry Andric         if (PrintFileName) {
1982*0b57cec5SDimitry Andric           if (isa<MachOObjectFile>(Obj) && moreThanOneArch)
1983*0b57cec5SDimitry Andric             ArchitectureName = O.getArchFlagName();
1984*0b57cec5SDimitry Andric         } else {
1985*0b57cec5SDimitry Andric           if (moreThanOneArch)
1986*0b57cec5SDimitry Andric             outs() << "\n";
1987*0b57cec5SDimitry Andric           outs() << Obj.getFileName();
1988*0b57cec5SDimitry Andric           if (isa<MachOObjectFile>(Obj) && moreThanOneArch)
1989*0b57cec5SDimitry Andric             outs() << " (for architecture " << O.getArchFlagName() << ")";
1990*0b57cec5SDimitry Andric           outs() << ":\n";
1991*0b57cec5SDimitry Andric         }
1992*0b57cec5SDimitry Andric         dumpSymbolNamesFromObject(Obj, false, ArchiveName, ArchitectureName);
1993*0b57cec5SDimitry Andric       } else if (auto E = isNotObjectErrorInvalidFileType(
1994*0b57cec5SDimitry Andric                  ObjOrErr.takeError())) {
1995*0b57cec5SDimitry Andric         error(std::move(E), Filename, moreThanOneArch ?
1996*0b57cec5SDimitry Andric               StringRef(O.getArchFlagName()) : StringRef());
1997*0b57cec5SDimitry Andric         continue;
1998*0b57cec5SDimitry Andric       } else if (Expected<std::unique_ptr<Archive>> AOrErr =
1999*0b57cec5SDimitry Andric                   O.getAsArchive()) {
2000*0b57cec5SDimitry Andric         std::unique_ptr<Archive> &A = *AOrErr;
2001*0b57cec5SDimitry Andric         Error Err = Error::success();
2002*0b57cec5SDimitry Andric         for (auto &C : A->children(Err)) {
2003*0b57cec5SDimitry Andric           Expected<std::unique_ptr<Binary>> ChildOrErr =
2004*0b57cec5SDimitry Andric             C.getAsBinary(ContextPtr);
2005*0b57cec5SDimitry Andric           if (!ChildOrErr) {
2006*0b57cec5SDimitry Andric             if (auto E = isNotObjectErrorInvalidFileType(
2007*0b57cec5SDimitry Andric                                  ChildOrErr.takeError()))
2008*0b57cec5SDimitry Andric               error(std::move(E), Filename, C, moreThanOneArch ?
2009*0b57cec5SDimitry Andric                     StringRef(ArchitectureName) : StringRef());
2010*0b57cec5SDimitry Andric             continue;
2011*0b57cec5SDimitry Andric           }
2012*0b57cec5SDimitry Andric           if (SymbolicFile *F = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
2013*0b57cec5SDimitry Andric             if (PrintFileName) {
2014*0b57cec5SDimitry Andric               ArchiveName = A->getFileName();
2015*0b57cec5SDimitry Andric               if (isa<MachOObjectFile>(F) && moreThanOneArch)
2016*0b57cec5SDimitry Andric                 ArchitectureName = O.getArchFlagName();
2017*0b57cec5SDimitry Andric             } else {
2018*0b57cec5SDimitry Andric               outs() << "\n" << A->getFileName();
2019*0b57cec5SDimitry Andric               if (isa<MachOObjectFile>(F)) {
2020*0b57cec5SDimitry Andric                 outs() << "(" << F->getFileName() << ")";
2021*0b57cec5SDimitry Andric                 if (moreThanOneArch)
2022*0b57cec5SDimitry Andric                   outs() << " (for architecture " << O.getArchFlagName()
2023*0b57cec5SDimitry Andric                          << ")";
2024*0b57cec5SDimitry Andric               } else
2025*0b57cec5SDimitry Andric                 outs() << ":" << F->getFileName();
2026*0b57cec5SDimitry Andric               outs() << ":\n";
2027*0b57cec5SDimitry Andric             }
2028*0b57cec5SDimitry Andric             dumpSymbolNamesFromObject(*F, false, ArchiveName, ArchitectureName);
2029*0b57cec5SDimitry Andric           }
2030*0b57cec5SDimitry Andric         }
2031*0b57cec5SDimitry Andric         if (Err)
2032*0b57cec5SDimitry Andric           error(std::move(Err), A->getFileName());
2033*0b57cec5SDimitry Andric       } else {
2034*0b57cec5SDimitry Andric         consumeError(AOrErr.takeError());
2035*0b57cec5SDimitry Andric         error(Filename + " for architecture " +
2036*0b57cec5SDimitry Andric               StringRef(O.getArchFlagName()) +
2037*0b57cec5SDimitry Andric               " is not a Mach-O file or an archive file",
2038*0b57cec5SDimitry Andric               "Mach-O universal file");
2039*0b57cec5SDimitry Andric       }
2040*0b57cec5SDimitry Andric     }
2041*0b57cec5SDimitry Andric     return;
2042*0b57cec5SDimitry Andric   }
2043*0b57cec5SDimitry Andric   if (SymbolicFile *O = dyn_cast<SymbolicFile>(&Bin)) {
2044*0b57cec5SDimitry Andric     if (!MachOPrintSizeWarning && PrintSize &&  isa<MachOObjectFile>(O)) {
2045*0b57cec5SDimitry Andric       WithColor::warning(errs(), ToolName)
2046*0b57cec5SDimitry Andric           << "sizes with --print-size for Mach-O files are always zero.\n";
2047*0b57cec5SDimitry Andric       MachOPrintSizeWarning = true;
2048*0b57cec5SDimitry Andric     }
2049*0b57cec5SDimitry Andric     if (!checkMachOAndArchFlags(O, Filename))
2050*0b57cec5SDimitry Andric       return;
2051*0b57cec5SDimitry Andric     dumpSymbolNamesFromObject(*O, true);
2052*0b57cec5SDimitry Andric   }
2053*0b57cec5SDimitry Andric }
2054*0b57cec5SDimitry Andric 
2055*0b57cec5SDimitry Andric int main(int argc, char **argv) {
2056*0b57cec5SDimitry Andric   InitLLVM X(argc, argv);
2057*0b57cec5SDimitry Andric   cl::HideUnrelatedOptions(NMCat);
2058*0b57cec5SDimitry Andric   cl::ParseCommandLineOptions(argc, argv, "llvm symbol table dumper\n");
2059*0b57cec5SDimitry Andric 
2060*0b57cec5SDimitry Andric   // llvm-nm only reads binary files.
2061*0b57cec5SDimitry Andric   if (error(sys::ChangeStdinToBinary()))
2062*0b57cec5SDimitry Andric     return 1;
2063*0b57cec5SDimitry Andric 
2064*0b57cec5SDimitry Andric   // These calls are needed so that we can read bitcode correctly.
2065*0b57cec5SDimitry Andric   llvm::InitializeAllTargetInfos();
2066*0b57cec5SDimitry Andric   llvm::InitializeAllTargetMCs();
2067*0b57cec5SDimitry Andric   llvm::InitializeAllAsmParsers();
2068*0b57cec5SDimitry Andric 
2069*0b57cec5SDimitry Andric   ToolName = argv[0];
2070*0b57cec5SDimitry Andric   if (BSDFormat)
2071*0b57cec5SDimitry Andric     OutputFormat = bsd;
2072*0b57cec5SDimitry Andric   if (POSIXFormat)
2073*0b57cec5SDimitry Andric     OutputFormat = posix;
2074*0b57cec5SDimitry Andric   if (DarwinFormat)
2075*0b57cec5SDimitry Andric     OutputFormat = darwin;
2076*0b57cec5SDimitry Andric 
2077*0b57cec5SDimitry Andric   // The relative order of these is important. If you pass --size-sort it should
2078*0b57cec5SDimitry Andric   // only print out the size. However, if you pass -S --size-sort, it should
2079*0b57cec5SDimitry Andric   // print out both the size and address.
2080*0b57cec5SDimitry Andric   if (SizeSort && !PrintSize)
2081*0b57cec5SDimitry Andric     PrintAddress = false;
2082*0b57cec5SDimitry Andric   if (OutputFormat == sysv || SizeSort)
2083*0b57cec5SDimitry Andric     PrintSize = true;
2084*0b57cec5SDimitry Andric   if (InputFilenames.empty())
2085*0b57cec5SDimitry Andric     InputFilenames.push_back("a.out");
2086*0b57cec5SDimitry Andric   if (InputFilenames.size() > 1)
2087*0b57cec5SDimitry Andric     MultipleFiles = true;
2088*0b57cec5SDimitry Andric 
2089*0b57cec5SDimitry Andric   // If both --demangle and --no-demangle are specified then pick the last one.
2090*0b57cec5SDimitry Andric   if (NoDemangle.getPosition() > Demangle.getPosition())
2091*0b57cec5SDimitry Andric     Demangle = !NoDemangle;
2092*0b57cec5SDimitry Andric 
2093*0b57cec5SDimitry Andric   for (unsigned i = 0; i < ArchFlags.size(); ++i) {
2094*0b57cec5SDimitry Andric     if (ArchFlags[i] == "all") {
2095*0b57cec5SDimitry Andric       ArchAll = true;
2096*0b57cec5SDimitry Andric     } else {
2097*0b57cec5SDimitry Andric       if (!MachOObjectFile::isValidArch(ArchFlags[i]))
2098*0b57cec5SDimitry Andric         error("Unknown architecture named '" + ArchFlags[i] + "'",
2099*0b57cec5SDimitry Andric               "for the --arch option");
2100*0b57cec5SDimitry Andric     }
2101*0b57cec5SDimitry Andric   }
2102*0b57cec5SDimitry Andric 
2103*0b57cec5SDimitry Andric   if (!SegSect.empty() && SegSect.size() != 2)
2104*0b57cec5SDimitry Andric     error("bad number of arguments (must be two arguments)",
2105*0b57cec5SDimitry Andric           "for the -s option");
2106*0b57cec5SDimitry Andric 
2107*0b57cec5SDimitry Andric   if (NoDyldInfo && (AddDyldInfo || DyldInfoOnly))
2108*0b57cec5SDimitry Andric     error("--no-dyldinfo can't be used with --add-dyldinfo or --dyldinfo-only");
2109*0b57cec5SDimitry Andric 
2110*0b57cec5SDimitry Andric   llvm::for_each(InputFilenames, dumpSymbolNamesFromFile);
2111*0b57cec5SDimitry Andric 
2112*0b57cec5SDimitry Andric   if (HadError)
2113*0b57cec5SDimitry Andric     return 1;
2114*0b57cec5SDimitry Andric }
2115