1 | //===- IRObjectFile.cpp - IR object file implementation ---------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // Part of the IRObjectFile class implementation. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "llvm/Object/IRObjectFile.h" |
14 | #include "llvm/ADT/ArrayRef.h" |
15 | #include "llvm/BinaryFormat/Magic.h" |
16 | #include "llvm/Bitcode/BitcodeReader.h" |
17 | #include "llvm/IR/Module.h" |
18 | #include "llvm/Object/ObjectFile.h" |
19 | using namespace llvm; |
20 | using namespace object; |
21 | |
22 | namespace llvm { |
23 | class LLVMContext; |
24 | class raw_ostream; |
25 | } // namespace llvm |
26 | |
27 | IRObjectFile::IRObjectFile(MemoryBufferRef Object, |
28 | std::vector<std::unique_ptr<Module>> Mods) |
29 | : SymbolicFile(Binary::ID_IR, Object), Mods(std::move(Mods)) { |
30 | for (auto &M : this->Mods) |
31 | SymTab.addModule(M: M.get()); |
32 | } |
33 | |
34 | IRObjectFile::~IRObjectFile() = default; |
35 | |
36 | static ModuleSymbolTable::Symbol getSym(DataRefImpl &Symb) { |
37 | return *reinterpret_cast<ModuleSymbolTable::Symbol *>(Symb.p); |
38 | } |
39 | |
40 | void IRObjectFile::moveSymbolNext(DataRefImpl &Symb) const { |
41 | Symb.p += sizeof(ModuleSymbolTable::Symbol); |
42 | } |
43 | |
44 | Error IRObjectFile::printSymbolName(raw_ostream &OS, DataRefImpl Symb) const { |
45 | SymTab.printSymbolName(OS, S: getSym(Symb)); |
46 | return Error::success(); |
47 | } |
48 | |
49 | Expected<uint32_t> IRObjectFile::getSymbolFlags(DataRefImpl Symb) const { |
50 | return SymTab.getSymbolFlags(S: getSym(Symb)); |
51 | } |
52 | |
53 | basic_symbol_iterator IRObjectFile::symbol_begin() const { |
54 | DataRefImpl Ret; |
55 | Ret.p = reinterpret_cast<uintptr_t>(SymTab.symbols().data()); |
56 | return basic_symbol_iterator(BasicSymbolRef(Ret, this)); |
57 | } |
58 | |
59 | basic_symbol_iterator IRObjectFile::symbol_end() const { |
60 | DataRefImpl Ret; |
61 | Ret.p = reinterpret_cast<uintptr_t>(SymTab.symbols().data() + |
62 | SymTab.symbols().size()); |
63 | return basic_symbol_iterator(BasicSymbolRef(Ret, this)); |
64 | } |
65 | |
66 | StringRef IRObjectFile::getTargetTriple() const { |
67 | // Each module must have the same target triple, so we arbitrarily access the |
68 | // first one. |
69 | return Mods[0]->getTargetTriple(); |
70 | } |
71 | |
72 | Expected<MemoryBufferRef> |
73 | IRObjectFile::findBitcodeInObject(const ObjectFile &Obj) { |
74 | for (const SectionRef &Sec : Obj.sections()) { |
75 | if (Sec.isBitcode()) { |
76 | Expected<StringRef> Contents = Sec.getContents(); |
77 | if (!Contents) |
78 | return Contents.takeError(); |
79 | if (Contents->size() <= 1) |
80 | return errorCodeToError(EC: object_error::bitcode_section_not_found); |
81 | return MemoryBufferRef(*Contents, Obj.getFileName()); |
82 | } |
83 | } |
84 | |
85 | return errorCodeToError(EC: object_error::bitcode_section_not_found); |
86 | } |
87 | |
88 | Expected<MemoryBufferRef> |
89 | IRObjectFile::findBitcodeInMemBuffer(MemoryBufferRef Object) { |
90 | file_magic Type = identify_magic(magic: Object.getBuffer()); |
91 | switch (Type) { |
92 | case file_magic::bitcode: |
93 | return Object; |
94 | case file_magic::elf_relocatable: |
95 | case file_magic::macho_object: |
96 | case file_magic::wasm_object: |
97 | case file_magic::coff_object: { |
98 | Expected<std::unique_ptr<ObjectFile>> ObjFile = |
99 | ObjectFile::createObjectFile(Object, Type); |
100 | if (!ObjFile) |
101 | return ObjFile.takeError(); |
102 | return findBitcodeInObject(Obj: *ObjFile->get()); |
103 | } |
104 | default: |
105 | return errorCodeToError(EC: object_error::invalid_file_type); |
106 | } |
107 | } |
108 | |
109 | Expected<std::unique_ptr<IRObjectFile>> |
110 | IRObjectFile::create(MemoryBufferRef Object, LLVMContext &Context) { |
111 | Expected<MemoryBufferRef> BCOrErr = findBitcodeInMemBuffer(Object); |
112 | if (!BCOrErr) |
113 | return BCOrErr.takeError(); |
114 | |
115 | Expected<std::vector<BitcodeModule>> BMsOrErr = |
116 | getBitcodeModuleList(Buffer: *BCOrErr); |
117 | if (!BMsOrErr) |
118 | return BMsOrErr.takeError(); |
119 | |
120 | std::vector<std::unique_ptr<Module>> Mods; |
121 | for (auto BM : *BMsOrErr) { |
122 | Expected<std::unique_ptr<Module>> MOrErr = |
123 | BM.getLazyModule(Context, /*ShouldLazyLoadMetadata*/ true, |
124 | /*IsImporting*/ false); |
125 | if (!MOrErr) |
126 | return MOrErr.takeError(); |
127 | |
128 | Mods.push_back(x: std::move(*MOrErr)); |
129 | } |
130 | |
131 | return std::unique_ptr<IRObjectFile>( |
132 | new IRObjectFile(*BCOrErr, std::move(Mods))); |
133 | } |
134 | |
135 | Expected<IRSymtabFile> object::readIRSymtab(MemoryBufferRef MBRef) { |
136 | IRSymtabFile F; |
137 | Expected<MemoryBufferRef> BCOrErr = |
138 | IRObjectFile::findBitcodeInMemBuffer(Object: MBRef); |
139 | if (!BCOrErr) |
140 | return BCOrErr.takeError(); |
141 | |
142 | Expected<BitcodeFileContents> BFCOrErr = getBitcodeFileContents(Buffer: *BCOrErr); |
143 | if (!BFCOrErr) |
144 | return BFCOrErr.takeError(); |
145 | |
146 | Expected<irsymtab::FileContents> FCOrErr = irsymtab::readBitcode(BFC: *BFCOrErr); |
147 | if (!FCOrErr) |
148 | return FCOrErr.takeError(); |
149 | |
150 | F.Mods = std::move(BFCOrErr->Mods); |
151 | F.Symtab = std::move(FCOrErr->Symtab); |
152 | F.Strtab = std::move(FCOrErr->Strtab); |
153 | F.TheReader = std::move(FCOrErr->TheReader); |
154 | return std::move(F); |
155 | } |
156 | |