/src/llvm-project/llvm/lib/Object/ObjectFile.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- ObjectFile.cpp - File format independent object file ---------------===// |
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 | | // This file defines a file format independent ObjectFile class. |
10 | | // |
11 | | //===----------------------------------------------------------------------===// |
12 | | |
13 | | #include "llvm/Object/ObjectFile.h" |
14 | | #include "llvm/ADT/StringRef.h" |
15 | | #include "llvm/BinaryFormat/Magic.h" |
16 | | #include "llvm/Object/Binary.h" |
17 | | #include "llvm/Object/COFF.h" |
18 | | #include "llvm/Object/Error.h" |
19 | | #include "llvm/Object/MachO.h" |
20 | | #include "llvm/Object/Wasm.h" |
21 | | #include "llvm/Support/Error.h" |
22 | | #include "llvm/Support/ErrorHandling.h" |
23 | | #include "llvm/Support/ErrorOr.h" |
24 | | #include "llvm/Support/Format.h" |
25 | | #include "llvm/Support/MemoryBuffer.h" |
26 | | #include "llvm/Support/raw_ostream.h" |
27 | | #include <cstdint> |
28 | | #include <memory> |
29 | | #include <system_error> |
30 | | |
31 | | using namespace llvm; |
32 | | using namespace object; |
33 | | |
34 | 0 | raw_ostream &object::operator<<(raw_ostream &OS, const SectionedAddress &Addr) { |
35 | 0 | OS << "SectionedAddress{" << format_hex(Addr.Address, 10); |
36 | 0 | if (Addr.SectionIndex != SectionedAddress::UndefSection) |
37 | 0 | OS << ", " << Addr.SectionIndex; |
38 | 0 | return OS << "}"; |
39 | 0 | } |
40 | | |
41 | 0 | void ObjectFile::anchor() {} |
42 | | |
43 | | ObjectFile::ObjectFile(unsigned int Type, MemoryBufferRef Source) |
44 | 101 | : SymbolicFile(Type, Source) {} |
45 | | |
46 | 0 | bool SectionRef::containsSymbol(SymbolRef S) const { |
47 | 0 | Expected<section_iterator> SymSec = S.getSection(); |
48 | 0 | if (!SymSec) { |
49 | | // TODO: Actually report errors helpfully. |
50 | 0 | consumeError(SymSec.takeError()); |
51 | 0 | return false; |
52 | 0 | } |
53 | 0 | return *this == **SymSec; |
54 | 0 | } |
55 | | |
56 | 1.76k | Expected<uint64_t> ObjectFile::getSymbolValue(DataRefImpl Ref) const { |
57 | 1.76k | uint32_t Flags; |
58 | 1.76k | if (Error E = getSymbolFlags(Ref).moveInto(Flags)) |
59 | | // TODO: Test this error. |
60 | 983 | return std::move(E); |
61 | | |
62 | 781 | if (Flags & SymbolRef::SF_Undefined) |
63 | 194 | return 0; |
64 | 587 | if (Flags & SymbolRef::SF_Common) |
65 | 10 | return getCommonSymbolSize(Ref); |
66 | 577 | return getSymbolValueImpl(Ref); |
67 | 587 | } |
68 | | |
69 | 0 | Error ObjectFile::printSymbolName(raw_ostream &OS, DataRefImpl Symb) const { |
70 | 0 | Expected<StringRef> Name = getSymbolName(Symb); |
71 | 0 | if (!Name) |
72 | 0 | return Name.takeError(); |
73 | 0 | OS << *Name; |
74 | 0 | return Error::success(); |
75 | 0 | } |
76 | | |
77 | 0 | uint32_t ObjectFile::getSymbolAlignment(DataRefImpl DRI) const { return 0; } |
78 | | |
79 | 0 | bool ObjectFile::isSectionBitcode(DataRefImpl Sec) const { |
80 | 0 | Expected<StringRef> NameOrErr = getSectionName(Sec); |
81 | 0 | if (NameOrErr) |
82 | 0 | return *NameOrErr == ".llvm.lto"; |
83 | 0 | consumeError(NameOrErr.takeError()); |
84 | 0 | return false; |
85 | 0 | } |
86 | | |
87 | 21.5k | bool ObjectFile::isSectionStripped(DataRefImpl Sec) const { return false; } |
88 | | |
89 | 0 | bool ObjectFile::isBerkeleyText(DataRefImpl Sec) const { |
90 | 0 | return isSectionText(Sec); |
91 | 0 | } |
92 | | |
93 | 0 | bool ObjectFile::isBerkeleyData(DataRefImpl Sec) const { |
94 | 0 | return isSectionData(Sec); |
95 | 0 | } |
96 | | |
97 | 0 | bool ObjectFile::isDebugSection(DataRefImpl Sec) const { return false; } |
98 | | |
99 | 0 | bool ObjectFile::hasDebugInfo() const { |
100 | 0 | return any_of(sections(), |
101 | 0 | [](SectionRef Sec) { return Sec.isDebugSection(); }); |
102 | 0 | } |
103 | | |
104 | | Expected<section_iterator> |
105 | 0 | ObjectFile::getRelocatedSection(DataRefImpl Sec) const { |
106 | 0 | return section_iterator(SectionRef(Sec, this)); |
107 | 0 | } |
108 | | |
109 | 0 | Triple ObjectFile::makeTriple() const { |
110 | 0 | Triple TheTriple; |
111 | 0 | auto Arch = getArch(); |
112 | 0 | TheTriple.setArch(Triple::ArchType(Arch)); |
113 | |
|
114 | 0 | auto OS = getOS(); |
115 | 0 | if (OS != Triple::UnknownOS) |
116 | 0 | TheTriple.setOS(OS); |
117 | | |
118 | | // For ARM targets, try to use the build attributes to build determine |
119 | | // the build target. Target features are also added, but later during |
120 | | // disassembly. |
121 | 0 | if (Arch == Triple::arm || Arch == Triple::armeb) |
122 | 0 | setARMSubArch(TheTriple); |
123 | | |
124 | | // TheTriple defaults to ELF, and COFF doesn't have an environment: |
125 | | // something we can do here is indicate that it is mach-o. |
126 | 0 | if (isMachO()) { |
127 | 0 | TheTriple.setObjectFormat(Triple::MachO); |
128 | 0 | } else if (isCOFF()) { |
129 | 0 | const auto COFFObj = cast<COFFObjectFile>(this); |
130 | 0 | if (COFFObj->getArch() == Triple::thumb) |
131 | 0 | TheTriple.setTriple("thumbv7-windows"); |
132 | 0 | } else if (isXCOFF()) { |
133 | | // XCOFF implies AIX. |
134 | 0 | TheTriple.setOS(Triple::AIX); |
135 | 0 | TheTriple.setObjectFormat(Triple::XCOFF); |
136 | 0 | } else if (isGOFF()) { |
137 | 0 | TheTriple.setOS(Triple::ZOS); |
138 | 0 | TheTriple.setObjectFormat(Triple::GOFF); |
139 | 0 | } else if (TheTriple.isAMDGPU()) { |
140 | 0 | TheTriple.setVendor(Triple::AMD); |
141 | 0 | } else if (TheTriple.isNVPTX()) { |
142 | 0 | TheTriple.setVendor(Triple::NVIDIA); |
143 | 0 | } |
144 | |
|
145 | 0 | return TheTriple; |
146 | 0 | } |
147 | | |
148 | | Expected<std::unique_ptr<ObjectFile>> |
149 | | ObjectFile::createObjectFile(MemoryBufferRef Object, file_magic Type, |
150 | 47 | bool InitContent) { |
151 | 47 | StringRef Data = Object.getBuffer(); |
152 | 47 | if (Type == file_magic::unknown) |
153 | 47 | Type = identify_magic(Data); |
154 | | |
155 | 47 | switch (Type) { |
156 | 0 | case file_magic::unknown: |
157 | 0 | case file_magic::bitcode: |
158 | 0 | case file_magic::clang_ast: |
159 | 0 | case file_magic::coff_cl_gl_object: |
160 | 0 | case file_magic::archive: |
161 | 0 | case file_magic::macho_universal_binary: |
162 | 0 | case file_magic::windows_resource: |
163 | 0 | case file_magic::pdb: |
164 | 0 | case file_magic::minidump: |
165 | 0 | case file_magic::goff_object: |
166 | 0 | case file_magic::cuda_fatbinary: |
167 | 0 | case file_magic::offload_binary: |
168 | 0 | case file_magic::dxcontainer_object: |
169 | 0 | case file_magic::offload_bundle: |
170 | 0 | case file_magic::offload_bundle_compressed: |
171 | 0 | case file_magic::spirv_object: |
172 | 0 | return errorCodeToError(object_error::invalid_file_type); |
173 | 0 | case file_magic::tapi_file: |
174 | 0 | return errorCodeToError(object_error::invalid_file_type); |
175 | 2 | case file_magic::elf: |
176 | 14 | case file_magic::elf_relocatable: |
177 | 19 | case file_magic::elf_executable: |
178 | 35 | case file_magic::elf_shared_object: |
179 | 35 | case file_magic::elf_core: |
180 | 35 | return createELFObjectFile(Object, InitContent); |
181 | 0 | case file_magic::macho_object: |
182 | 2 | case file_magic::macho_executable: |
183 | 2 | case file_magic::macho_fixed_virtual_memory_shared_lib: |
184 | 4 | case file_magic::macho_core: |
185 | 4 | case file_magic::macho_preload_executable: |
186 | 6 | case file_magic::macho_dynamically_linked_shared_lib: |
187 | 6 | case file_magic::macho_dynamic_linker: |
188 | 6 | case file_magic::macho_bundle: |
189 | 6 | case file_magic::macho_dynamically_linked_shared_lib_stub: |
190 | 6 | case file_magic::macho_dsym_companion: |
191 | 6 | case file_magic::macho_kext_bundle: |
192 | 6 | case file_magic::macho_file_set: |
193 | 6 | return createMachOObjectFile(Object); |
194 | 4 | case file_magic::coff_object: |
195 | 4 | case file_magic::coff_import_library: |
196 | 6 | case file_magic::pecoff_executable: |
197 | 6 | return createCOFFObjectFile(Object); |
198 | 0 | case file_magic::xcoff_object_32: |
199 | 0 | return createXCOFFObjectFile(Object, Binary::ID_XCOFF32); |
200 | 0 | case file_magic::xcoff_object_64: |
201 | 0 | return createXCOFFObjectFile(Object, Binary::ID_XCOFF64); |
202 | 0 | case file_magic::wasm_object: |
203 | 0 | return createWasmObjectFile(Object); |
204 | 47 | } |
205 | 0 | llvm_unreachable("Unexpected Object File Type"); |
206 | 0 | } |
207 | | |
208 | | Expected<OwningBinary<ObjectFile>> |
209 | 0 | ObjectFile::createObjectFile(StringRef ObjectPath) { |
210 | 0 | ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr = |
211 | 0 | MemoryBuffer::getFile(ObjectPath); |
212 | 0 | if (std::error_code EC = FileOrErr.getError()) |
213 | 0 | return errorCodeToError(EC); |
214 | 0 | std::unique_ptr<MemoryBuffer> Buffer = std::move(FileOrErr.get()); |
215 | |
|
216 | 0 | Expected<std::unique_ptr<ObjectFile>> ObjOrErr = |
217 | 0 | createObjectFile(Buffer->getMemBufferRef()); |
218 | 0 | if (Error Err = ObjOrErr.takeError()) |
219 | 0 | return std::move(Err); |
220 | 0 | std::unique_ptr<ObjectFile> Obj = std::move(ObjOrErr.get()); |
221 | |
|
222 | 0 | return OwningBinary<ObjectFile>(std::move(Obj), std::move(Buffer)); |
223 | 0 | } |
224 | | |
225 | | bool ObjectFile::isReflectionSectionStrippable( |
226 | | llvm::binaryformat::Swift5ReflectionSectionKind ReflectionSectionKind) |
227 | 0 | const { |
228 | 0 | using llvm::binaryformat::Swift5ReflectionSectionKind; |
229 | 0 | return ReflectionSectionKind == Swift5ReflectionSectionKind::fieldmd || |
230 | 0 | ReflectionSectionKind == Swift5ReflectionSectionKind::reflstr || |
231 | 0 | ReflectionSectionKind == Swift5ReflectionSectionKind::assocty; |
232 | 0 | } |