xref: /aosp_15_r20/external/llvm/tools/dsymutil/BinaryHolder.cpp (revision 9880d6810fe72a1726cb53787c6711e909410d58)
1*9880d681SAndroid Build Coastguard Worker //===-- BinaryHolder.cpp --------------------------------------------------===//
2*9880d681SAndroid Build Coastguard Worker //
3*9880d681SAndroid Build Coastguard Worker //                     The LLVM Compiler Infrastructure
4*9880d681SAndroid Build Coastguard Worker //
5*9880d681SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
6*9880d681SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
7*9880d681SAndroid Build Coastguard Worker //
8*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
9*9880d681SAndroid Build Coastguard Worker //
10*9880d681SAndroid Build Coastguard Worker // This program is a utility that aims to be a dropin replacement for
11*9880d681SAndroid Build Coastguard Worker // Darwin's dsymutil.
12*9880d681SAndroid Build Coastguard Worker //
13*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
14*9880d681SAndroid Build Coastguard Worker 
15*9880d681SAndroid Build Coastguard Worker #include "BinaryHolder.h"
16*9880d681SAndroid Build Coastguard Worker #include "llvm/Object/MachO.h"
17*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/raw_ostream.h"
18*9880d681SAndroid Build Coastguard Worker 
19*9880d681SAndroid Build Coastguard Worker namespace llvm {
20*9880d681SAndroid Build Coastguard Worker namespace dsymutil {
21*9880d681SAndroid Build Coastguard Worker 
22*9880d681SAndroid Build Coastguard Worker static std::vector<MemoryBufferRef>
getMachOFatMemoryBuffers(StringRef Filename,MemoryBuffer & Mem,object::MachOUniversalBinary & Fat)23*9880d681SAndroid Build Coastguard Worker getMachOFatMemoryBuffers(StringRef Filename, MemoryBuffer &Mem,
24*9880d681SAndroid Build Coastguard Worker                          object::MachOUniversalBinary &Fat) {
25*9880d681SAndroid Build Coastguard Worker   std::vector<MemoryBufferRef> Buffers;
26*9880d681SAndroid Build Coastguard Worker   StringRef FatData = Fat.getData();
27*9880d681SAndroid Build Coastguard Worker   for (auto It = Fat.begin_objects(), End = Fat.end_objects(); It != End;
28*9880d681SAndroid Build Coastguard Worker        ++It) {
29*9880d681SAndroid Build Coastguard Worker     StringRef ObjData = FatData.substr(It->getOffset(), It->getSize());
30*9880d681SAndroid Build Coastguard Worker     Buffers.emplace_back(ObjData, Filename);
31*9880d681SAndroid Build Coastguard Worker   }
32*9880d681SAndroid Build Coastguard Worker   return Buffers;
33*9880d681SAndroid Build Coastguard Worker }
34*9880d681SAndroid Build Coastguard Worker 
changeBackingMemoryBuffer(std::unique_ptr<MemoryBuffer> && Buf)35*9880d681SAndroid Build Coastguard Worker void BinaryHolder::changeBackingMemoryBuffer(
36*9880d681SAndroid Build Coastguard Worker     std::unique_ptr<MemoryBuffer> &&Buf) {
37*9880d681SAndroid Build Coastguard Worker   CurrentArchives.clear();
38*9880d681SAndroid Build Coastguard Worker   CurrentObjectFiles.clear();
39*9880d681SAndroid Build Coastguard Worker   CurrentFatBinary.reset();
40*9880d681SAndroid Build Coastguard Worker 
41*9880d681SAndroid Build Coastguard Worker   CurrentMemoryBuffer = std::move(Buf);
42*9880d681SAndroid Build Coastguard Worker }
43*9880d681SAndroid Build Coastguard Worker 
44*9880d681SAndroid Build Coastguard Worker ErrorOr<std::vector<MemoryBufferRef>>
GetMemoryBuffersForFile(StringRef Filename,sys::TimeValue Timestamp)45*9880d681SAndroid Build Coastguard Worker BinaryHolder::GetMemoryBuffersForFile(StringRef Filename,
46*9880d681SAndroid Build Coastguard Worker                                       sys::TimeValue Timestamp) {
47*9880d681SAndroid Build Coastguard Worker   if (Verbose)
48*9880d681SAndroid Build Coastguard Worker     outs() << "trying to open '" << Filename << "'\n";
49*9880d681SAndroid Build Coastguard Worker 
50*9880d681SAndroid Build Coastguard Worker   // Try that first as it doesn't involve any filesystem access.
51*9880d681SAndroid Build Coastguard Worker   if (auto ErrOrArchiveMembers = GetArchiveMemberBuffers(Filename, Timestamp))
52*9880d681SAndroid Build Coastguard Worker     return *ErrOrArchiveMembers;
53*9880d681SAndroid Build Coastguard Worker 
54*9880d681SAndroid Build Coastguard Worker   // If the name ends with a closing paren, there is a huge chance
55*9880d681SAndroid Build Coastguard Worker   // it is an archive member specification.
56*9880d681SAndroid Build Coastguard Worker   if (Filename.endswith(")"))
57*9880d681SAndroid Build Coastguard Worker     if (auto ErrOrArchiveMembers =
58*9880d681SAndroid Build Coastguard Worker             MapArchiveAndGetMemberBuffers(Filename, Timestamp))
59*9880d681SAndroid Build Coastguard Worker       return *ErrOrArchiveMembers;
60*9880d681SAndroid Build Coastguard Worker 
61*9880d681SAndroid Build Coastguard Worker   // Otherwise, just try opening a standard file. If this is an
62*9880d681SAndroid Build Coastguard Worker   // archive member specifiaction and any of the above didn't handle it
63*9880d681SAndroid Build Coastguard Worker   // (either because the archive is not there anymore, or because the
64*9880d681SAndroid Build Coastguard Worker   // archive doesn't contain the requested member), this will still
65*9880d681SAndroid Build Coastguard Worker   // provide a sensible error message.
66*9880d681SAndroid Build Coastguard Worker   auto ErrOrFile = MemoryBuffer::getFileOrSTDIN(Filename);
67*9880d681SAndroid Build Coastguard Worker   if (auto Err = ErrOrFile.getError())
68*9880d681SAndroid Build Coastguard Worker     return Err;
69*9880d681SAndroid Build Coastguard Worker 
70*9880d681SAndroid Build Coastguard Worker   changeBackingMemoryBuffer(std::move(*ErrOrFile));
71*9880d681SAndroid Build Coastguard Worker   if (Verbose)
72*9880d681SAndroid Build Coastguard Worker     outs() << "\tloaded file.\n";
73*9880d681SAndroid Build Coastguard Worker 
74*9880d681SAndroid Build Coastguard Worker   auto ErrOrFat = object::MachOUniversalBinary::create(
75*9880d681SAndroid Build Coastguard Worker       CurrentMemoryBuffer->getMemBufferRef());
76*9880d681SAndroid Build Coastguard Worker   if (!ErrOrFat) {
77*9880d681SAndroid Build Coastguard Worker     consumeError(ErrOrFat.takeError());
78*9880d681SAndroid Build Coastguard Worker     // Not a fat binary must be a standard one. Return a one element vector.
79*9880d681SAndroid Build Coastguard Worker     return std::vector<MemoryBufferRef>{CurrentMemoryBuffer->getMemBufferRef()};
80*9880d681SAndroid Build Coastguard Worker   }
81*9880d681SAndroid Build Coastguard Worker 
82*9880d681SAndroid Build Coastguard Worker   CurrentFatBinary = std::move(*ErrOrFat);
83*9880d681SAndroid Build Coastguard Worker   CurrentFatBinaryName = Filename;
84*9880d681SAndroid Build Coastguard Worker   return getMachOFatMemoryBuffers(CurrentFatBinaryName, *CurrentMemoryBuffer,
85*9880d681SAndroid Build Coastguard Worker                                   *CurrentFatBinary);
86*9880d681SAndroid Build Coastguard Worker }
87*9880d681SAndroid Build Coastguard Worker 
88*9880d681SAndroid Build Coastguard Worker ErrorOr<std::vector<MemoryBufferRef>>
GetArchiveMemberBuffers(StringRef Filename,sys::TimeValue Timestamp)89*9880d681SAndroid Build Coastguard Worker BinaryHolder::GetArchiveMemberBuffers(StringRef Filename,
90*9880d681SAndroid Build Coastguard Worker                                       sys::TimeValue Timestamp) {
91*9880d681SAndroid Build Coastguard Worker   if (CurrentArchives.empty())
92*9880d681SAndroid Build Coastguard Worker     return make_error_code(errc::no_such_file_or_directory);
93*9880d681SAndroid Build Coastguard Worker 
94*9880d681SAndroid Build Coastguard Worker   StringRef CurArchiveName = CurrentArchives.front()->getFileName();
95*9880d681SAndroid Build Coastguard Worker   if (!Filename.startswith(Twine(CurArchiveName, "(").str()))
96*9880d681SAndroid Build Coastguard Worker     return make_error_code(errc::no_such_file_or_directory);
97*9880d681SAndroid Build Coastguard Worker 
98*9880d681SAndroid Build Coastguard Worker   // Remove the archive name and the parens around the archive member name.
99*9880d681SAndroid Build Coastguard Worker   Filename = Filename.substr(CurArchiveName.size() + 1).drop_back();
100*9880d681SAndroid Build Coastguard Worker 
101*9880d681SAndroid Build Coastguard Worker   std::vector<MemoryBufferRef> Buffers;
102*9880d681SAndroid Build Coastguard Worker   Buffers.reserve(CurrentArchives.size());
103*9880d681SAndroid Build Coastguard Worker 
104*9880d681SAndroid Build Coastguard Worker   for (const auto &CurrentArchive : CurrentArchives) {
105*9880d681SAndroid Build Coastguard Worker     Error Err;
106*9880d681SAndroid Build Coastguard Worker     for (auto Child : CurrentArchive->children(Err)) {
107*9880d681SAndroid Build Coastguard Worker       if (auto NameOrErr = Child.getName()) {
108*9880d681SAndroid Build Coastguard Worker         if (*NameOrErr == Filename) {
109*9880d681SAndroid Build Coastguard Worker           if (Timestamp != sys::TimeValue::PosixZeroTime() &&
110*9880d681SAndroid Build Coastguard Worker               Timestamp != Child.getLastModified()) {
111*9880d681SAndroid Build Coastguard Worker             if (Verbose)
112*9880d681SAndroid Build Coastguard Worker               outs() << "\tmember had timestamp mismatch.\n";
113*9880d681SAndroid Build Coastguard Worker             continue;
114*9880d681SAndroid Build Coastguard Worker           }
115*9880d681SAndroid Build Coastguard Worker           if (Verbose)
116*9880d681SAndroid Build Coastguard Worker             outs() << "\tfound member in current archive.\n";
117*9880d681SAndroid Build Coastguard Worker           auto ErrOrMem = Child.getMemoryBufferRef();
118*9880d681SAndroid Build Coastguard Worker           if (auto Err = ErrOrMem.getError())
119*9880d681SAndroid Build Coastguard Worker             return Err;
120*9880d681SAndroid Build Coastguard Worker           Buffers.push_back(*ErrOrMem);
121*9880d681SAndroid Build Coastguard Worker         }
122*9880d681SAndroid Build Coastguard Worker       }
123*9880d681SAndroid Build Coastguard Worker     }
124*9880d681SAndroid Build Coastguard Worker     if (Err)
125*9880d681SAndroid Build Coastguard Worker       return errorToErrorCode(std::move(Err));
126*9880d681SAndroid Build Coastguard Worker   }
127*9880d681SAndroid Build Coastguard Worker 
128*9880d681SAndroid Build Coastguard Worker   if (Buffers.empty())
129*9880d681SAndroid Build Coastguard Worker     return make_error_code(errc::no_such_file_or_directory);
130*9880d681SAndroid Build Coastguard Worker   return Buffers;
131*9880d681SAndroid Build Coastguard Worker }
132*9880d681SAndroid Build Coastguard Worker 
133*9880d681SAndroid Build Coastguard Worker ErrorOr<std::vector<MemoryBufferRef>>
MapArchiveAndGetMemberBuffers(StringRef Filename,sys::TimeValue Timestamp)134*9880d681SAndroid Build Coastguard Worker BinaryHolder::MapArchiveAndGetMemberBuffers(StringRef Filename,
135*9880d681SAndroid Build Coastguard Worker                                             sys::TimeValue Timestamp) {
136*9880d681SAndroid Build Coastguard Worker   StringRef ArchiveFilename = Filename.substr(0, Filename.find('('));
137*9880d681SAndroid Build Coastguard Worker 
138*9880d681SAndroid Build Coastguard Worker   auto ErrOrBuff = MemoryBuffer::getFileOrSTDIN(ArchiveFilename);
139*9880d681SAndroid Build Coastguard Worker   if (auto Err = ErrOrBuff.getError())
140*9880d681SAndroid Build Coastguard Worker     return Err;
141*9880d681SAndroid Build Coastguard Worker 
142*9880d681SAndroid Build Coastguard Worker   if (Verbose)
143*9880d681SAndroid Build Coastguard Worker     outs() << "\topened new archive '" << ArchiveFilename << "'\n";
144*9880d681SAndroid Build Coastguard Worker 
145*9880d681SAndroid Build Coastguard Worker   changeBackingMemoryBuffer(std::move(*ErrOrBuff));
146*9880d681SAndroid Build Coastguard Worker   std::vector<MemoryBufferRef> ArchiveBuffers;
147*9880d681SAndroid Build Coastguard Worker   auto ErrOrFat = object::MachOUniversalBinary::create(
148*9880d681SAndroid Build Coastguard Worker       CurrentMemoryBuffer->getMemBufferRef());
149*9880d681SAndroid Build Coastguard Worker   if (!ErrOrFat) {
150*9880d681SAndroid Build Coastguard Worker     consumeError(ErrOrFat.takeError());
151*9880d681SAndroid Build Coastguard Worker     // Not a fat binary must be a standard one.
152*9880d681SAndroid Build Coastguard Worker     ArchiveBuffers.push_back(CurrentMemoryBuffer->getMemBufferRef());
153*9880d681SAndroid Build Coastguard Worker   } else {
154*9880d681SAndroid Build Coastguard Worker     CurrentFatBinary = std::move(*ErrOrFat);
155*9880d681SAndroid Build Coastguard Worker     CurrentFatBinaryName = ArchiveFilename;
156*9880d681SAndroid Build Coastguard Worker     ArchiveBuffers = getMachOFatMemoryBuffers(
157*9880d681SAndroid Build Coastguard Worker         CurrentFatBinaryName, *CurrentMemoryBuffer, *CurrentFatBinary);
158*9880d681SAndroid Build Coastguard Worker   }
159*9880d681SAndroid Build Coastguard Worker 
160*9880d681SAndroid Build Coastguard Worker   for (auto MemRef : ArchiveBuffers) {
161*9880d681SAndroid Build Coastguard Worker     auto ErrOrArchive = object::Archive::create(MemRef);
162*9880d681SAndroid Build Coastguard Worker     if (!ErrOrArchive)
163*9880d681SAndroid Build Coastguard Worker       return errorToErrorCode(ErrOrArchive.takeError());
164*9880d681SAndroid Build Coastguard Worker     CurrentArchives.push_back(std::move(*ErrOrArchive));
165*9880d681SAndroid Build Coastguard Worker   }
166*9880d681SAndroid Build Coastguard Worker   return GetArchiveMemberBuffers(Filename, Timestamp);
167*9880d681SAndroid Build Coastguard Worker }
168*9880d681SAndroid Build Coastguard Worker 
169*9880d681SAndroid Build Coastguard Worker ErrorOr<const object::ObjectFile &>
getObjfileForArch(const Triple & T)170*9880d681SAndroid Build Coastguard Worker BinaryHolder::getObjfileForArch(const Triple &T) {
171*9880d681SAndroid Build Coastguard Worker   for (const auto &Obj : CurrentObjectFiles) {
172*9880d681SAndroid Build Coastguard Worker     if (const auto *MachO = dyn_cast<object::MachOObjectFile>(Obj.get())) {
173*9880d681SAndroid Build Coastguard Worker       if (MachO->getArchTriple().str() == T.str())
174*9880d681SAndroid Build Coastguard Worker         return *MachO;
175*9880d681SAndroid Build Coastguard Worker     } else if (Obj->getArch() == T.getArch())
176*9880d681SAndroid Build Coastguard Worker       return *Obj;
177*9880d681SAndroid Build Coastguard Worker   }
178*9880d681SAndroid Build Coastguard Worker 
179*9880d681SAndroid Build Coastguard Worker   return make_error_code(object::object_error::arch_not_found);
180*9880d681SAndroid Build Coastguard Worker }
181*9880d681SAndroid Build Coastguard Worker 
182*9880d681SAndroid Build Coastguard Worker ErrorOr<std::vector<const object::ObjectFile *>>
GetObjectFiles(StringRef Filename,sys::TimeValue Timestamp)183*9880d681SAndroid Build Coastguard Worker BinaryHolder::GetObjectFiles(StringRef Filename, sys::TimeValue Timestamp) {
184*9880d681SAndroid Build Coastguard Worker   auto ErrOrMemBufferRefs = GetMemoryBuffersForFile(Filename, Timestamp);
185*9880d681SAndroid Build Coastguard Worker   if (auto Err = ErrOrMemBufferRefs.getError())
186*9880d681SAndroid Build Coastguard Worker     return Err;
187*9880d681SAndroid Build Coastguard Worker 
188*9880d681SAndroid Build Coastguard Worker   std::vector<const object::ObjectFile *> Objects;
189*9880d681SAndroid Build Coastguard Worker   Objects.reserve(ErrOrMemBufferRefs->size());
190*9880d681SAndroid Build Coastguard Worker 
191*9880d681SAndroid Build Coastguard Worker   CurrentObjectFiles.clear();
192*9880d681SAndroid Build Coastguard Worker   for (auto MemBuf : *ErrOrMemBufferRefs) {
193*9880d681SAndroid Build Coastguard Worker     auto ErrOrObjectFile = object::ObjectFile::createObjectFile(MemBuf);
194*9880d681SAndroid Build Coastguard Worker     if (!ErrOrObjectFile)
195*9880d681SAndroid Build Coastguard Worker       return errorToErrorCode(ErrOrObjectFile.takeError());
196*9880d681SAndroid Build Coastguard Worker 
197*9880d681SAndroid Build Coastguard Worker     Objects.push_back(ErrOrObjectFile->get());
198*9880d681SAndroid Build Coastguard Worker     CurrentObjectFiles.push_back(std::move(*ErrOrObjectFile));
199*9880d681SAndroid Build Coastguard Worker   }
200*9880d681SAndroid Build Coastguard Worker 
201*9880d681SAndroid Build Coastguard Worker   return std::move(Objects);
202*9880d681SAndroid Build Coastguard Worker }
203*9880d681SAndroid Build Coastguard Worker }
204*9880d681SAndroid Build Coastguard Worker }
205