Jonas Devlieghere | 928fea2 | 2018-06-27 16:13:40 +0000 | [diff] [blame] | 1 | //===-- MachOUtils.cpp - Mach-o specific helpers for dsymutil ------------===// |
Frederic Riss | 7a42578 | 2015-08-05 18:27:44 +0000 | [diff] [blame] | 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | |
| 10 | #include "MachOUtils.h" |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 11 | #include "BinaryHolder.h" |
| 12 | #include "DebugMap.h" |
Jonas Devlieghere | 928fea2 | 2018-06-27 16:13:40 +0000 | [diff] [blame] | 13 | #include "LinkUtils.h" |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 14 | #include "NonRelocatableStringpool.h" |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 15 | #include "llvm/MC/MCAsmLayout.h" |
Reid Kleckner | e68240c | 2016-06-22 23:30:43 +0000 | [diff] [blame] | 16 | #include "llvm/MC/MCMachObjectWriter.h" |
Jonas Devlieghere | 3ad0c5a | 2018-02-22 11:32:51 +0000 | [diff] [blame] | 17 | #include "llvm/MC/MCObjectStreamer.h" |
| 18 | #include "llvm/MC/MCSectionMachO.h" |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 19 | #include "llvm/MC/MCStreamer.h" |
| 20 | #include "llvm/Object/MachO.h" |
Frederic Riss | 7a42578 | 2015-08-05 18:27:44 +0000 | [diff] [blame] | 21 | #include "llvm/Support/FileUtilities.h" |
| 22 | #include "llvm/Support/Program.h" |
Jonas Devlieghere | 5baab4c | 2018-04-14 21:36:42 +0000 | [diff] [blame] | 23 | #include "llvm/Support/WithColor.h" |
Frederic Riss | 7a42578 | 2015-08-05 18:27:44 +0000 | [diff] [blame] | 24 | #include "llvm/Support/raw_ostream.h" |
| 25 | |
| 26 | namespace llvm { |
| 27 | namespace dsymutil { |
| 28 | namespace MachOUtils { |
| 29 | |
Jonas Devlieghere | 58d4a39 | 2018-07-29 14:56:15 +0000 | [diff] [blame] | 30 | llvm::Error ArchAndFile::createTempFile() { |
| 31 | llvm::SmallString<128> TmpModel; |
| 32 | llvm::sys::path::system_temp_directory(true, TmpModel); |
| 33 | llvm::sys::path::append(TmpModel, "dsym.tmp%%%%%.dwarf"); |
| 34 | Expected<sys::fs::TempFile> T = sys::fs::TempFile::create(TmpModel); |
| 35 | |
| 36 | if (!T) |
| 37 | return T.takeError(); |
| 38 | |
| 39 | File = llvm::Optional<sys::fs::TempFile>(std::move(*T)); |
| 40 | return Error::success(); |
| 41 | } |
| 42 | |
| 43 | llvm::StringRef ArchAndFile::path() const { return File->TmpName; } |
| 44 | |
| 45 | ArchAndFile::~ArchAndFile() { |
| 46 | if (File) |
| 47 | if (auto E = File->discard()) |
| 48 | llvm::consumeError(std::move(E)); |
| 49 | } |
| 50 | |
Frederic Riss | 3abc9b6 | 2015-08-25 23:15:26 +0000 | [diff] [blame] | 51 | std::string getArchName(StringRef Arch) { |
| 52 | if (Arch.startswith("thumb")) |
| 53 | return (llvm::Twine("arm") + Arch.drop_front(5)).str(); |
| 54 | return Arch; |
| 55 | } |
| 56 | |
Zachary Turner | 0dcc115 | 2018-06-12 17:43:52 +0000 | [diff] [blame] | 57 | static bool runLipo(StringRef SDKPath, SmallVectorImpl<StringRef> &Args) { |
Frederic Riss | a642d2c | 2015-10-08 22:35:53 +0000 | [diff] [blame] | 58 | auto Path = sys::findProgramByName("lipo", makeArrayRef(SDKPath)); |
| 59 | if (!Path) |
| 60 | Path = sys::findProgramByName("lipo"); |
Frederic Riss | 7a42578 | 2015-08-05 18:27:44 +0000 | [diff] [blame] | 61 | |
| 62 | if (!Path) { |
Jonas Devlieghere | 5baab4c | 2018-04-14 21:36:42 +0000 | [diff] [blame] | 63 | WithColor::error() << "lipo: " << Path.getError().message() << "\n"; |
Frederic Riss | 7a42578 | 2015-08-05 18:27:44 +0000 | [diff] [blame] | 64 | return false; |
| 65 | } |
| 66 | |
| 67 | std::string ErrMsg; |
Zachary Turner | 0dcc115 | 2018-06-12 17:43:52 +0000 | [diff] [blame] | 68 | int result = sys::ExecuteAndWait(*Path, Args, None, {}, 0, 0, &ErrMsg); |
Frederic Riss | 7a42578 | 2015-08-05 18:27:44 +0000 | [diff] [blame] | 69 | if (result) { |
Jonas Devlieghere | 5baab4c | 2018-04-14 21:36:42 +0000 | [diff] [blame] | 70 | WithColor::error() << "lipo: " << ErrMsg << "\n"; |
Frederic Riss | 7a42578 | 2015-08-05 18:27:44 +0000 | [diff] [blame] | 71 | return false; |
| 72 | } |
| 73 | |
| 74 | return true; |
| 75 | } |
| 76 | |
Jonas Devlieghere | 58d4a39 | 2018-07-29 14:56:15 +0000 | [diff] [blame] | 77 | bool generateUniversalBinary(SmallVectorImpl<ArchAndFile> &ArchFiles, |
Frederic Riss | 7a42578 | 2015-08-05 18:27:44 +0000 | [diff] [blame] | 78 | StringRef OutputFileName, |
Frederic Riss | a642d2c | 2015-10-08 22:35:53 +0000 | [diff] [blame] | 79 | const LinkOptions &Options, StringRef SDKPath) { |
Jonas Devlieghere | 58d4a39 | 2018-07-29 14:56:15 +0000 | [diff] [blame] | 80 | // No need to merge one file into a universal fat binary. |
Frederic Riss | 7a42578 | 2015-08-05 18:27:44 +0000 | [diff] [blame] | 81 | if (ArchFiles.size() == 1) { |
Jonas Devlieghere | 58d4a39 | 2018-07-29 14:56:15 +0000 | [diff] [blame] | 82 | if (auto E = ArchFiles.front().File->keep(OutputFileName)) { |
| 83 | WithColor::error() << "while keeping " << ArchFiles.front().path() |
| 84 | << " as " << OutputFileName << ": " |
| 85 | << toString(std::move(E)) << "\n"; |
| 86 | return false; |
Frederic Riss | 7a42578 | 2015-08-05 18:27:44 +0000 | [diff] [blame] | 87 | } |
| 88 | return true; |
| 89 | } |
| 90 | |
Zachary Turner | 0dcc115 | 2018-06-12 17:43:52 +0000 | [diff] [blame] | 91 | SmallVector<StringRef, 8> Args; |
Frederic Riss | 7a42578 | 2015-08-05 18:27:44 +0000 | [diff] [blame] | 92 | Args.push_back("lipo"); |
| 93 | Args.push_back("-create"); |
| 94 | |
| 95 | for (auto &Thin : ArchFiles) |
Jonas Devlieghere | 58d4a39 | 2018-07-29 14:56:15 +0000 | [diff] [blame] | 96 | Args.push_back(Thin.path()); |
Frederic Riss | 7a42578 | 2015-08-05 18:27:44 +0000 | [diff] [blame] | 97 | |
| 98 | // Align segments to match dsymutil-classic alignment |
| 99 | for (auto &Thin : ArchFiles) { |
Frederic Riss | 3abc9b6 | 2015-08-25 23:15:26 +0000 | [diff] [blame] | 100 | Thin.Arch = getArchName(Thin.Arch); |
Frederic Riss | 7a42578 | 2015-08-05 18:27:44 +0000 | [diff] [blame] | 101 | Args.push_back("-segalign"); |
Zachary Turner | 0dcc115 | 2018-06-12 17:43:52 +0000 | [diff] [blame] | 102 | Args.push_back(Thin.Arch); |
Frederic Riss | 7a42578 | 2015-08-05 18:27:44 +0000 | [diff] [blame] | 103 | Args.push_back("20"); |
| 104 | } |
| 105 | |
| 106 | Args.push_back("-output"); |
| 107 | Args.push_back(OutputFileName.data()); |
Frederic Riss | 7a42578 | 2015-08-05 18:27:44 +0000 | [diff] [blame] | 108 | |
| 109 | if (Options.Verbose) { |
| 110 | outs() << "Running lipo\n"; |
| 111 | for (auto Arg : Args) |
Zachary Turner | 0dcc115 | 2018-06-12 17:43:52 +0000 | [diff] [blame] | 112 | outs() << ' ' << Arg; |
| 113 | outs() << "\n"; |
Frederic Riss | 7a42578 | 2015-08-05 18:27:44 +0000 | [diff] [blame] | 114 | } |
| 115 | |
Frederic Riss | a642d2c | 2015-10-08 22:35:53 +0000 | [diff] [blame] | 116 | return Options.NoOutput ? true : runLipo(SDKPath, Args); |
Frederic Riss | 7a42578 | 2015-08-05 18:27:44 +0000 | [diff] [blame] | 117 | } |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 118 | |
Jonas Devlieghere | 3ad0c5a | 2018-02-22 11:32:51 +0000 | [diff] [blame] | 119 | // Return a MachO::segment_command_64 that holds the same values as the passed |
| 120 | // MachO::segment_command. We do that to avoid having to duplicate the logic |
| 121 | // for 32bits and 64bits segments. |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 122 | struct MachO::segment_command_64 adaptFrom32bits(MachO::segment_command Seg) { |
| 123 | MachO::segment_command_64 Seg64; |
| 124 | Seg64.cmd = Seg.cmd; |
| 125 | Seg64.cmdsize = Seg.cmdsize; |
| 126 | memcpy(Seg64.segname, Seg.segname, sizeof(Seg.segname)); |
| 127 | Seg64.vmaddr = Seg.vmaddr; |
| 128 | Seg64.vmsize = Seg.vmsize; |
| 129 | Seg64.fileoff = Seg.fileoff; |
| 130 | Seg64.filesize = Seg.filesize; |
| 131 | Seg64.maxprot = Seg.maxprot; |
| 132 | Seg64.initprot = Seg.initprot; |
| 133 | Seg64.nsects = Seg.nsects; |
| 134 | Seg64.flags = Seg.flags; |
| 135 | return Seg64; |
| 136 | } |
| 137 | |
| 138 | // Iterate on all \a Obj segments, and apply \a Handler to them. |
| 139 | template <typename FunctionTy> |
| 140 | static void iterateOnSegments(const object::MachOObjectFile &Obj, |
| 141 | FunctionTy Handler) { |
| 142 | for (const auto &LCI : Obj.load_commands()) { |
| 143 | MachO::segment_command_64 Segment; |
| 144 | if (LCI.C.cmd == MachO::LC_SEGMENT) |
| 145 | Segment = adaptFrom32bits(Obj.getSegmentLoadCommand(LCI)); |
| 146 | else if (LCI.C.cmd == MachO::LC_SEGMENT_64) |
| 147 | Segment = Obj.getSegment64LoadCommand(LCI); |
| 148 | else |
| 149 | continue; |
| 150 | |
| 151 | Handler(Segment); |
| 152 | } |
| 153 | } |
| 154 | |
Jonas Devlieghere | 3ad0c5a | 2018-02-22 11:32:51 +0000 | [diff] [blame] | 155 | // Transfer the symbols described by \a NList to \a NewSymtab which is just the |
| 156 | // raw contents of the symbol table for the dSYM companion file. \returns |
| 157 | // whether the symbol was transferred or not. |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 158 | template <typename NListTy> |
| 159 | static bool transferSymbol(NListTy NList, bool IsLittleEndian, |
| 160 | StringRef Strings, SmallVectorImpl<char> &NewSymtab, |
| 161 | NonRelocatableStringpool &NewStrings, |
| 162 | bool &InDebugNote) { |
| 163 | // Do not transfer undefined symbols, we want real addresses. |
| 164 | if ((NList.n_type & MachO::N_TYPE) == MachO::N_UNDF) |
| 165 | return false; |
| 166 | |
| 167 | StringRef Name = StringRef(Strings.begin() + NList.n_strx); |
| 168 | if (InDebugNote) { |
| 169 | InDebugNote = |
| 170 | (NList.n_type != MachO::N_SO) || (!Name.empty() && Name[0] != '\0'); |
| 171 | return false; |
| 172 | } else if (NList.n_type == MachO::N_SO) { |
| 173 | InDebugNote = true; |
| 174 | return false; |
| 175 | } |
| 176 | |
| 177 | // FIXME: The + 1 is here to mimic dsymutil-classic that has 2 empty |
| 178 | // strings at the start of the generated string table (There is |
| 179 | // corresponding code in the string table emission). |
| 180 | NList.n_strx = NewStrings.getStringOffset(Name) + 1; |
| 181 | if (IsLittleEndian != sys::IsLittleEndianHost) |
| 182 | MachO::swapStruct(NList); |
| 183 | |
| 184 | NewSymtab.append(reinterpret_cast<char *>(&NList), |
| 185 | reinterpret_cast<char *>(&NList + 1)); |
| 186 | return true; |
| 187 | } |
| 188 | |
| 189 | // Wrapper around transferSymbol to transfer all of \a Obj symbols |
| 190 | // to \a NewSymtab. This function does not write in the output file. |
| 191 | // \returns the number of symbols in \a NewSymtab. |
| 192 | static unsigned transferSymbols(const object::MachOObjectFile &Obj, |
| 193 | SmallVectorImpl<char> &NewSymtab, |
| 194 | NonRelocatableStringpool &NewStrings) { |
| 195 | unsigned Syms = 0; |
| 196 | StringRef Strings = Obj.getStringTableData(); |
| 197 | bool IsLittleEndian = Obj.isLittleEndian(); |
| 198 | bool InDebugNote = false; |
| 199 | |
| 200 | if (Obj.is64Bit()) { |
| 201 | for (const object::SymbolRef &Symbol : Obj.symbols()) { |
| 202 | object::DataRefImpl DRI = Symbol.getRawDataRefImpl(); |
| 203 | if (transferSymbol(Obj.getSymbol64TableEntry(DRI), IsLittleEndian, |
| 204 | Strings, NewSymtab, NewStrings, InDebugNote)) |
| 205 | ++Syms; |
| 206 | } |
| 207 | } else { |
| 208 | for (const object::SymbolRef &Symbol : Obj.symbols()) { |
| 209 | object::DataRefImpl DRI = Symbol.getRawDataRefImpl(); |
| 210 | if (transferSymbol(Obj.getSymbolTableEntry(DRI), IsLittleEndian, Strings, |
| 211 | NewSymtab, NewStrings, InDebugNote)) |
| 212 | ++Syms; |
| 213 | } |
| 214 | } |
| 215 | return Syms; |
| 216 | } |
| 217 | |
| 218 | static MachO::section |
| 219 | getSection(const object::MachOObjectFile &Obj, |
| 220 | const MachO::segment_command &Seg, |
| 221 | const object::MachOObjectFile::LoadCommandInfo &LCI, unsigned Idx) { |
| 222 | return Obj.getSection(LCI, Idx); |
| 223 | } |
| 224 | |
| 225 | static MachO::section_64 |
| 226 | getSection(const object::MachOObjectFile &Obj, |
| 227 | const MachO::segment_command_64 &Seg, |
| 228 | const object::MachOObjectFile::LoadCommandInfo &LCI, unsigned Idx) { |
| 229 | return Obj.getSection64(LCI, Idx); |
| 230 | } |
| 231 | |
| 232 | // Transfer \a Segment from \a Obj to the output file. This calls into \a Writer |
| 233 | // to write these load commands directly in the output file at the current |
| 234 | // position. |
| 235 | // The function also tries to find a hole in the address map to fit the __DWARF |
| 236 | // segment of \a DwarfSegmentSize size. \a EndAddress is updated to point at the |
| 237 | // highest segment address. |
Simon Pilgrim | 428e693 | 2017-03-30 12:59:53 +0000 | [diff] [blame] | 238 | // When the __LINKEDIT segment is transferred, its offset and size are set resp. |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 239 | // to \a LinkeditOffset and \a LinkeditSize. |
| 240 | template <typename SegmentTy> |
| 241 | static void transferSegmentAndSections( |
| 242 | const object::MachOObjectFile::LoadCommandInfo &LCI, SegmentTy Segment, |
Peter Collingbourne | 8e93a95 | 2018-05-21 18:17:42 +0000 | [diff] [blame] | 243 | const object::MachOObjectFile &Obj, MachObjectWriter &Writer, |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 244 | uint64_t LinkeditOffset, uint64_t LinkeditSize, uint64_t DwarfSegmentSize, |
| 245 | uint64_t &GapForDwarf, uint64_t &EndAddress) { |
| 246 | if (StringRef("__DWARF") == Segment.segname) |
| 247 | return; |
| 248 | |
| 249 | Segment.fileoff = Segment.filesize = 0; |
| 250 | |
| 251 | if (StringRef("__LINKEDIT") == Segment.segname) { |
| 252 | Segment.fileoff = LinkeditOffset; |
| 253 | Segment.filesize = LinkeditSize; |
Steven Wu | 9a41e59 | 2017-02-02 00:00:13 +0000 | [diff] [blame] | 254 | // Resize vmsize by rounding to the page size. |
| 255 | Segment.vmsize = alignTo(LinkeditSize, 0x1000); |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 256 | } |
| 257 | |
| 258 | // Check if the end address of the last segment and our current |
| 259 | // start address leave a sufficient gap to store the __DWARF |
| 260 | // segment. |
| 261 | uint64_t PrevEndAddress = EndAddress; |
Rui Ueyama | 3edb0ec | 2016-01-14 21:06:47 +0000 | [diff] [blame] | 262 | EndAddress = alignTo(EndAddress, 0x1000); |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 263 | if (GapForDwarf == UINT64_MAX && Segment.vmaddr > EndAddress && |
| 264 | Segment.vmaddr - EndAddress >= DwarfSegmentSize) |
| 265 | GapForDwarf = EndAddress; |
| 266 | |
| 267 | // The segments are not necessarily sorted by their vmaddr. |
| 268 | EndAddress = |
| 269 | std::max<uint64_t>(PrevEndAddress, Segment.vmaddr + Segment.vmsize); |
| 270 | unsigned nsects = Segment.nsects; |
| 271 | if (Obj.isLittleEndian() != sys::IsLittleEndianHost) |
| 272 | MachO::swapStruct(Segment); |
Peter Collingbourne | 8e93a95 | 2018-05-21 18:17:42 +0000 | [diff] [blame] | 273 | Writer.W.OS.write(reinterpret_cast<char *>(&Segment), sizeof(Segment)); |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 274 | for (unsigned i = 0; i < nsects; ++i) { |
| 275 | auto Sect = getSection(Obj, Segment, LCI, i); |
| 276 | Sect.offset = Sect.reloff = Sect.nreloc = 0; |
| 277 | if (Obj.isLittleEndian() != sys::IsLittleEndianHost) |
| 278 | MachO::swapStruct(Sect); |
Peter Collingbourne | 8e93a95 | 2018-05-21 18:17:42 +0000 | [diff] [blame] | 279 | Writer.W.OS.write(reinterpret_cast<char *>(&Sect), sizeof(Sect)); |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 280 | } |
| 281 | } |
| 282 | |
| 283 | // Write the __DWARF segment load command to the output file. |
| 284 | static void createDwarfSegment(uint64_t VMAddr, uint64_t FileOffset, |
| 285 | uint64_t FileSize, unsigned NumSections, |
| 286 | MCAsmLayout &Layout, MachObjectWriter &Writer) { |
| 287 | Writer.writeSegmentLoadCommand("__DWARF", NumSections, VMAddr, |
Rui Ueyama | 3edb0ec | 2016-01-14 21:06:47 +0000 | [diff] [blame] | 288 | alignTo(FileSize, 0x1000), FileOffset, |
| 289 | FileSize, /* MaxProt */ 7, |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 290 | /* InitProt =*/3); |
| 291 | |
| 292 | for (unsigned int i = 0, n = Layout.getSectionOrder().size(); i != n; ++i) { |
| 293 | MCSection *Sec = Layout.getSectionOrder()[i]; |
| 294 | if (Sec->begin() == Sec->end() || !Layout.getSectionFileSize(Sec)) |
| 295 | continue; |
| 296 | |
| 297 | unsigned Align = Sec->getAlignment(); |
| 298 | if (Align > 1) { |
Rui Ueyama | 3edb0ec | 2016-01-14 21:06:47 +0000 | [diff] [blame] | 299 | VMAddr = alignTo(VMAddr, Align); |
| 300 | FileOffset = alignTo(FileOffset, Align); |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 301 | } |
| 302 | Writer.writeSection(Layout, *Sec, VMAddr, FileOffset, 0, 0, 0); |
| 303 | |
| 304 | FileOffset += Layout.getSectionAddressSize(Sec); |
| 305 | VMAddr += Layout.getSectionAddressSize(Sec); |
| 306 | } |
| 307 | } |
| 308 | |
| 309 | static bool isExecutable(const object::MachOObjectFile &Obj) { |
| 310 | if (Obj.is64Bit()) |
| 311 | return Obj.getHeader64().filetype != MachO::MH_OBJECT; |
| 312 | else |
| 313 | return Obj.getHeader().filetype != MachO::MH_OBJECT; |
| 314 | } |
| 315 | |
| 316 | static bool hasLinkEditSegment(const object::MachOObjectFile &Obj) { |
| 317 | bool HasLinkEditSegment = false; |
| 318 | iterateOnSegments(Obj, [&](const MachO::segment_command_64 &Segment) { |
| 319 | if (StringRef("__LINKEDIT") == Segment.segname) |
| 320 | HasLinkEditSegment = true; |
| 321 | }); |
| 322 | return HasLinkEditSegment; |
| 323 | } |
| 324 | |
| 325 | static unsigned segmentLoadCommandSize(bool Is64Bit, unsigned NumSections) { |
| 326 | if (Is64Bit) |
| 327 | return sizeof(MachO::segment_command_64) + |
| 328 | NumSections * sizeof(MachO::section_64); |
| 329 | |
| 330 | return sizeof(MachO::segment_command) + NumSections * sizeof(MachO::section); |
| 331 | } |
| 332 | |
| 333 | // Stream a dSYM companion binary file corresponding to the binary referenced |
| 334 | // by \a DM to \a OutFile. The passed \a MS MCStreamer is setup to write to |
| 335 | // \a OutFile and it must be using a MachObjectWriter object to do so. |
Jonas Devlieghere | 20767d1 | 2019-01-07 23:27:25 +0000 | [diff] [blame] | 336 | bool generateDsymCompanion(const DebugMap &DM, SymbolMapTranslator &Translator, |
| 337 | MCStreamer &MS, raw_fd_ostream &OutFile) { |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 338 | auto &ObjectStreamer = static_cast<MCObjectStreamer &>(MS); |
| 339 | MCAssembler &MCAsm = ObjectStreamer.getAssembler(); |
| 340 | auto &Writer = static_cast<MachObjectWriter &>(MCAsm.getWriter()); |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 341 | |
Jonas Devlieghere | 74dc404 | 2018-07-10 15:32:17 +0000 | [diff] [blame] | 342 | // Layout but don't emit. |
| 343 | ObjectStreamer.flushPendingLabels(); |
| 344 | MCAsmLayout Layout(MCAsm); |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 345 | MCAsm.layout(Layout); |
| 346 | |
| 347 | BinaryHolder InputBinaryHolder(false); |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 348 | |
Jonas Devlieghere | 9f33bbfe | 2018-06-29 16:51:52 +0000 | [diff] [blame] | 349 | auto ObjectEntry = InputBinaryHolder.getObjectEntry(DM.getBinaryPath()); |
| 350 | if (!ObjectEntry) { |
| 351 | auto Err = ObjectEntry.takeError(); |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 352 | return error(Twine("opening ") + DM.getBinaryPath() + ": " + |
Jonas Devlieghere | 9f33bbfe | 2018-06-29 16:51:52 +0000 | [diff] [blame] | 353 | toString(std::move(Err)), |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 354 | "output file streaming"); |
Jonas Devlieghere | 9f33bbfe | 2018-06-29 16:51:52 +0000 | [diff] [blame] | 355 | } |
| 356 | |
| 357 | auto Object = |
| 358 | ObjectEntry->getObjectAs<object::MachOObjectFile>(DM.getTriple()); |
| 359 | if (!Object) { |
| 360 | auto Err = Object.takeError(); |
| 361 | return error(Twine("opening ") + DM.getBinaryPath() + ": " + |
| 362 | toString(std::move(Err)), |
| 363 | "output file streaming"); |
| 364 | } |
| 365 | |
| 366 | auto &InputBinary = *Object; |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 367 | |
| 368 | bool Is64Bit = Writer.is64Bit(); |
| 369 | MachO::symtab_command SymtabCmd = InputBinary.getSymtabLoadCommand(); |
| 370 | |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 371 | // Compute the number of load commands we will need. |
| 372 | unsigned LoadCommandSize = 0; |
| 373 | unsigned NumLoadCommands = 0; |
Adrian Prantl | a3a30c0 | 2018-11-08 16:54:59 +0000 | [diff] [blame] | 374 | |
| 375 | // Get LC_UUID and LC_BUILD_VERSION. |
| 376 | MachO::uuid_command UUIDCmd; |
Adrian Prantl | 0ee0dff | 2018-11-13 23:31:25 +0000 | [diff] [blame] | 377 | SmallVector<MachO::build_version_command, 2> BuildVersionCmd; |
Adrian Prantl | a3a30c0 | 2018-11-08 16:54:59 +0000 | [diff] [blame] | 378 | memset(&UUIDCmd, 0, sizeof(UUIDCmd)); |
Adrian Prantl | a3a30c0 | 2018-11-08 16:54:59 +0000 | [diff] [blame] | 379 | for (auto &LCI : InputBinary.load_commands()) { |
| 380 | switch (LCI.C.cmd) { |
| 381 | case MachO::LC_UUID: |
Adrian Prantl | 0ee0dff | 2018-11-13 23:31:25 +0000 | [diff] [blame] | 382 | if (UUIDCmd.cmd) |
| 383 | return error("Binary contains more than one UUID"); |
Adrian Prantl | a3a30c0 | 2018-11-08 16:54:59 +0000 | [diff] [blame] | 384 | UUIDCmd = InputBinary.getUuidCommand(LCI); |
| 385 | ++NumLoadCommands; |
Adrian Prantl | 0ee0dff | 2018-11-13 23:31:25 +0000 | [diff] [blame] | 386 | LoadCommandSize += sizeof(UUIDCmd); |
Adrian Prantl | a3a30c0 | 2018-11-08 16:54:59 +0000 | [diff] [blame] | 387 | break; |
Adrian Prantl | 0ee0dff | 2018-11-13 23:31:25 +0000 | [diff] [blame] | 388 | case MachO::LC_BUILD_VERSION: { |
| 389 | MachO::build_version_command Cmd; |
| 390 | memset(&Cmd, 0, sizeof(Cmd)); |
| 391 | Cmd = InputBinary.getBuildVersionLoadCommand(LCI); |
Adrian Prantl | a3a30c0 | 2018-11-08 16:54:59 +0000 | [diff] [blame] | 392 | ++NumLoadCommands; |
Adrian Prantl | 0ee0dff | 2018-11-13 23:31:25 +0000 | [diff] [blame] | 393 | LoadCommandSize += sizeof(Cmd); |
Adrian Prantl | a3a30c0 | 2018-11-08 16:54:59 +0000 | [diff] [blame] | 394 | // LLDB doesn't care about the build tools for now. |
Adrian Prantl | 0ee0dff | 2018-11-13 23:31:25 +0000 | [diff] [blame] | 395 | Cmd.ntools = 0; |
| 396 | BuildVersionCmd.push_back(Cmd); |
Adrian Prantl | a3a30c0 | 2018-11-08 16:54:59 +0000 | [diff] [blame] | 397 | break; |
Adrian Prantl | 0ee0dff | 2018-11-13 23:31:25 +0000 | [diff] [blame] | 398 | } |
Adrian Prantl | a3a30c0 | 2018-11-08 16:54:59 +0000 | [diff] [blame] | 399 | default: |
| 400 | break; |
| 401 | } |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 402 | } |
| 403 | |
| 404 | // If we have a valid symtab to copy, do it. |
| 405 | bool ShouldEmitSymtab = |
| 406 | isExecutable(InputBinary) && hasLinkEditSegment(InputBinary); |
| 407 | if (ShouldEmitSymtab) { |
| 408 | LoadCommandSize += sizeof(MachO::symtab_command); |
| 409 | ++NumLoadCommands; |
| 410 | } |
| 411 | |
| 412 | unsigned HeaderSize = |
| 413 | Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header); |
| 414 | // We will copy every segment that isn't __DWARF. |
| 415 | iterateOnSegments(InputBinary, [&](const MachO::segment_command_64 &Segment) { |
| 416 | if (StringRef("__DWARF") == Segment.segname) |
| 417 | return; |
| 418 | |
| 419 | ++NumLoadCommands; |
| 420 | LoadCommandSize += segmentLoadCommandSize(Is64Bit, Segment.nsects); |
| 421 | }); |
| 422 | |
| 423 | // We will add our own brand new __DWARF segment if we have debug |
| 424 | // info. |
| 425 | unsigned NumDwarfSections = 0; |
| 426 | uint64_t DwarfSegmentSize = 0; |
| 427 | |
| 428 | for (unsigned int i = 0, n = Layout.getSectionOrder().size(); i != n; ++i) { |
| 429 | MCSection *Sec = Layout.getSectionOrder()[i]; |
| 430 | if (Sec->begin() == Sec->end()) |
| 431 | continue; |
| 432 | |
| 433 | if (uint64_t Size = Layout.getSectionFileSize(Sec)) { |
Rui Ueyama | 3edb0ec | 2016-01-14 21:06:47 +0000 | [diff] [blame] | 434 | DwarfSegmentSize = alignTo(DwarfSegmentSize, Sec->getAlignment()); |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 435 | DwarfSegmentSize += Size; |
| 436 | ++NumDwarfSections; |
| 437 | } |
| 438 | } |
| 439 | |
| 440 | if (NumDwarfSections) { |
| 441 | ++NumLoadCommands; |
| 442 | LoadCommandSize += segmentLoadCommandSize(Is64Bit, NumDwarfSections); |
| 443 | } |
| 444 | |
| 445 | SmallString<0> NewSymtab; |
Jonas Devlieghere | 20767d1 | 2019-01-07 23:27:25 +0000 | [diff] [blame] | 446 | NonRelocatableStringpool NewStrings(Translator); |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 447 | unsigned NListSize = Is64Bit ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist); |
| 448 | unsigned NumSyms = 0; |
| 449 | uint64_t NewStringsSize = 0; |
| 450 | if (ShouldEmitSymtab) { |
| 451 | NewSymtab.reserve(SymtabCmd.nsyms * NListSize / 2); |
| 452 | NumSyms = transferSymbols(InputBinary, NewSymtab, NewStrings); |
| 453 | NewStringsSize = NewStrings.getSize() + 1; |
| 454 | } |
| 455 | |
| 456 | uint64_t SymtabStart = LoadCommandSize; |
| 457 | SymtabStart += HeaderSize; |
Rui Ueyama | 3edb0ec | 2016-01-14 21:06:47 +0000 | [diff] [blame] | 458 | SymtabStart = alignTo(SymtabStart, 0x1000); |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 459 | |
| 460 | // We gathered all the information we need, start emitting the output file. |
| 461 | Writer.writeHeader(MachO::MH_DSYM, NumLoadCommands, LoadCommandSize, false); |
| 462 | |
| 463 | // Write the load commands. |
| 464 | assert(OutFile.tell() == HeaderSize); |
| 465 | if (UUIDCmd.cmd != 0) { |
Peter Collingbourne | 8e93a95 | 2018-05-21 18:17:42 +0000 | [diff] [blame] | 466 | Writer.W.write<uint32_t>(UUIDCmd.cmd); |
Adrian Prantl | a3a30c0 | 2018-11-08 16:54:59 +0000 | [diff] [blame] | 467 | Writer.W.write<uint32_t>(sizeof(UUIDCmd)); |
Peter Collingbourne | 8e93a95 | 2018-05-21 18:17:42 +0000 | [diff] [blame] | 468 | OutFile.write(reinterpret_cast<const char *>(UUIDCmd.uuid), 16); |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 469 | assert(OutFile.tell() == HeaderSize + sizeof(UUIDCmd)); |
| 470 | } |
Adrian Prantl | 0ee0dff | 2018-11-13 23:31:25 +0000 | [diff] [blame] | 471 | for (auto Cmd : BuildVersionCmd) { |
| 472 | Writer.W.write<uint32_t>(Cmd.cmd); |
| 473 | Writer.W.write<uint32_t>(sizeof(Cmd)); |
| 474 | Writer.W.write<uint32_t>(Cmd.platform); |
| 475 | Writer.W.write<uint32_t>(Cmd.minos); |
| 476 | Writer.W.write<uint32_t>(Cmd.sdk); |
| 477 | Writer.W.write<uint32_t>(Cmd.ntools); |
Adrian Prantl | a3a30c0 | 2018-11-08 16:54:59 +0000 | [diff] [blame] | 478 | } |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 479 | |
| 480 | assert(SymtabCmd.cmd && "No symbol table."); |
| 481 | uint64_t StringStart = SymtabStart + NumSyms * NListSize; |
| 482 | if (ShouldEmitSymtab) |
| 483 | Writer.writeSymtabLoadCommand(SymtabStart, NumSyms, StringStart, |
| 484 | NewStringsSize); |
| 485 | |
| 486 | uint64_t DwarfSegmentStart = StringStart + NewStringsSize; |
Rui Ueyama | 3edb0ec | 2016-01-14 21:06:47 +0000 | [diff] [blame] | 487 | DwarfSegmentStart = alignTo(DwarfSegmentStart, 0x1000); |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 488 | |
| 489 | // Write the load commands for the segments and sections we 'import' from |
| 490 | // the original binary. |
| 491 | uint64_t EndAddress = 0; |
| 492 | uint64_t GapForDwarf = UINT64_MAX; |
| 493 | for (auto &LCI : InputBinary.load_commands()) { |
| 494 | if (LCI.C.cmd == MachO::LC_SEGMENT) |
| 495 | transferSegmentAndSections(LCI, InputBinary.getSegmentLoadCommand(LCI), |
| 496 | InputBinary, Writer, SymtabStart, |
| 497 | StringStart + NewStringsSize - SymtabStart, |
| 498 | DwarfSegmentSize, GapForDwarf, EndAddress); |
| 499 | else if (LCI.C.cmd == MachO::LC_SEGMENT_64) |
| 500 | transferSegmentAndSections(LCI, InputBinary.getSegment64LoadCommand(LCI), |
| 501 | InputBinary, Writer, SymtabStart, |
| 502 | StringStart + NewStringsSize - SymtabStart, |
| 503 | DwarfSegmentSize, GapForDwarf, EndAddress); |
| 504 | } |
| 505 | |
Rui Ueyama | 3edb0ec | 2016-01-14 21:06:47 +0000 | [diff] [blame] | 506 | uint64_t DwarfVMAddr = alignTo(EndAddress, 0x1000); |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 507 | uint64_t DwarfVMMax = Is64Bit ? UINT64_MAX : UINT32_MAX; |
| 508 | if (DwarfVMAddr + DwarfSegmentSize > DwarfVMMax || |
| 509 | DwarfVMAddr + DwarfSegmentSize < DwarfVMAddr /* Overflow */) { |
| 510 | // There is no room for the __DWARF segment at the end of the |
Jonas Devlieghere | 3ad0c5a | 2018-02-22 11:32:51 +0000 | [diff] [blame] | 511 | // address space. Look through segments to find a gap. |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 512 | DwarfVMAddr = GapForDwarf; |
| 513 | if (DwarfVMAddr == UINT64_MAX) |
| 514 | warn("not enough VM space for the __DWARF segment.", |
| 515 | "output file streaming"); |
| 516 | } |
| 517 | |
| 518 | // Write the load command for the __DWARF segment. |
| 519 | createDwarfSegment(DwarfVMAddr, DwarfSegmentStart, DwarfSegmentSize, |
| 520 | NumDwarfSections, Layout, Writer); |
| 521 | |
| 522 | assert(OutFile.tell() == LoadCommandSize + HeaderSize); |
Peter Collingbourne | 8e93a95 | 2018-05-21 18:17:42 +0000 | [diff] [blame] | 523 | OutFile.write_zeros(SymtabStart - (LoadCommandSize + HeaderSize)); |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 524 | assert(OutFile.tell() == SymtabStart); |
| 525 | |
| 526 | // Transfer symbols. |
| 527 | if (ShouldEmitSymtab) { |
Peter Collingbourne | 8e93a95 | 2018-05-21 18:17:42 +0000 | [diff] [blame] | 528 | OutFile << NewSymtab.str(); |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 529 | assert(OutFile.tell() == StringStart); |
| 530 | |
| 531 | // Transfer string table. |
| 532 | // FIXME: The NonRelocatableStringpool starts with an empty string, but |
| 533 | // dsymutil-classic starts the reconstructed string table with 2 of these. |
| 534 | // Reproduce that behavior for now (there is corresponding code in |
| 535 | // transferSymbol). |
Peter Collingbourne | 8e93a95 | 2018-05-21 18:17:42 +0000 | [diff] [blame] | 536 | OutFile << '\0'; |
Pavel Labath | 23332c5 | 2018-08-07 09:54:52 +0000 | [diff] [blame] | 537 | std::vector<DwarfStringPoolEntryRef> Strings = |
| 538 | NewStrings.getEntriesForEmission(); |
Jonas Devlieghere | ef0ae3d | 2018-01-24 16:16:43 +0000 | [diff] [blame] | 539 | for (auto EntryRef : Strings) { |
Peter Collingbourne | 8e93a95 | 2018-05-21 18:17:42 +0000 | [diff] [blame] | 540 | OutFile.write(EntryRef.getString().data(), |
| 541 | EntryRef.getString().size() + 1); |
Jonas Devlieghere | ef0ae3d | 2018-01-24 16:16:43 +0000 | [diff] [blame] | 542 | } |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 543 | } |
| 544 | |
| 545 | assert(OutFile.tell() == StringStart + NewStringsSize); |
| 546 | |
| 547 | // Pad till the Dwarf segment start. |
Peter Collingbourne | 8e93a95 | 2018-05-21 18:17:42 +0000 | [diff] [blame] | 548 | OutFile.write_zeros(DwarfSegmentStart - (StringStart + NewStringsSize)); |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 549 | assert(OutFile.tell() == DwarfSegmentStart); |
| 550 | |
| 551 | // Emit the Dwarf sections contents. |
| 552 | for (const MCSection &Sec : MCAsm) { |
| 553 | if (Sec.begin() == Sec.end()) |
| 554 | continue; |
| 555 | |
| 556 | uint64_t Pos = OutFile.tell(); |
Peter Collingbourne | 8e93a95 | 2018-05-21 18:17:42 +0000 | [diff] [blame] | 557 | OutFile.write_zeros(alignTo(Pos, Sec.getAlignment()) - Pos); |
Peter Collingbourne | 74bda0b | 2018-05-21 18:11:35 +0000 | [diff] [blame] | 558 | MCAsm.writeSectionData(OutFile, &Sec, Layout); |
Frederic Riss | ef8ad01 | 2015-09-02 16:49:13 +0000 | [diff] [blame] | 559 | } |
| 560 | |
| 561 | return true; |
| 562 | } |
Jonas Devlieghere | 3ad0c5a | 2018-02-22 11:32:51 +0000 | [diff] [blame] | 563 | } // namespace MachOUtils |
| 564 | } // namespace dsymutil |
| 565 | } // namespace llvm |