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 | raw_ostream &object::operator<<(raw_ostream &OS, const SectionedAddress &Addr) { |
35 | OS << "SectionedAddress{" << format_hex(N: Addr.Address, Width: 10); |
36 | if (Addr.SectionIndex != SectionedAddress::UndefSection) |
37 | OS << ", " << Addr.SectionIndex; |
38 | return OS << "}" ; |
39 | } |
40 | |
41 | void ObjectFile::anchor() {} |
42 | |
43 | ObjectFile::ObjectFile(unsigned int Type, MemoryBufferRef Source) |
44 | : SymbolicFile(Type, Source) {} |
45 | |
46 | bool SectionRef::containsSymbol(SymbolRef S) const { |
47 | Expected<section_iterator> SymSec = S.getSection(); |
48 | if (!SymSec) { |
49 | // TODO: Actually report errors helpfully. |
50 | consumeError(Err: SymSec.takeError()); |
51 | return false; |
52 | } |
53 | return *this == **SymSec; |
54 | } |
55 | |
56 | Expected<uint64_t> ObjectFile::getSymbolValue(DataRefImpl Ref) const { |
57 | uint32_t Flags; |
58 | if (Error E = getSymbolFlags(Symb: Ref).moveInto(Value&: Flags)) |
59 | // TODO: Test this error. |
60 | return std::move(E); |
61 | |
62 | if (Flags & SymbolRef::SF_Undefined) |
63 | return 0; |
64 | if (Flags & SymbolRef::SF_Common) |
65 | return getCommonSymbolSize(Symb: Ref); |
66 | return getSymbolValueImpl(Symb: Ref); |
67 | } |
68 | |
69 | Error ObjectFile::printSymbolName(raw_ostream &OS, DataRefImpl Symb) const { |
70 | Expected<StringRef> Name = getSymbolName(Symb); |
71 | if (!Name) |
72 | return Name.takeError(); |
73 | OS << *Name; |
74 | return Error::success(); |
75 | } |
76 | |
77 | uint32_t ObjectFile::getSymbolAlignment(DataRefImpl DRI) const { return 0; } |
78 | |
79 | bool ObjectFile::isSectionBitcode(DataRefImpl Sec) const { |
80 | Expected<StringRef> NameOrErr = getSectionName(Sec); |
81 | if (NameOrErr) |
82 | return *NameOrErr == ".llvm.lto" ; |
83 | consumeError(Err: NameOrErr.takeError()); |
84 | return false; |
85 | } |
86 | |
87 | bool ObjectFile::isSectionStripped(DataRefImpl Sec) const { return false; } |
88 | |
89 | bool ObjectFile::isBerkeleyText(DataRefImpl Sec) const { |
90 | return isSectionText(Sec); |
91 | } |
92 | |
93 | bool ObjectFile::isBerkeleyData(DataRefImpl Sec) const { |
94 | return isSectionData(Sec); |
95 | } |
96 | |
97 | bool ObjectFile::isDebugSection(DataRefImpl Sec) const { return false; } |
98 | |
99 | bool ObjectFile::hasDebugInfo() const { |
100 | return any_of(Range: sections(), |
101 | P: [](SectionRef Sec) { return Sec.isDebugSection(); }); |
102 | } |
103 | |
104 | Expected<section_iterator> |
105 | ObjectFile::getRelocatedSection(DataRefImpl Sec) const { |
106 | return section_iterator(SectionRef(Sec, this)); |
107 | } |
108 | |
109 | Triple ObjectFile::makeTriple() const { |
110 | Triple TheTriple; |
111 | auto Arch = getArch(); |
112 | TheTriple.setArch(Kind: Triple::ArchType(Arch)); |
113 | |
114 | auto OS = getOS(); |
115 | if (OS != Triple::UnknownOS) |
116 | 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 | if (Arch == Triple::arm || Arch == Triple::armeb) |
122 | 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 | if (isMachO()) { |
127 | TheTriple.setObjectFormat(Triple::MachO); |
128 | } else if (isCOFF()) { |
129 | const auto COFFObj = cast<COFFObjectFile>(Val: this); |
130 | if (COFFObj->getArch() == Triple::thumb) |
131 | TheTriple.setTriple("thumbv7-windows" ); |
132 | } else if (isXCOFF()) { |
133 | // XCOFF implies AIX. |
134 | TheTriple.setOS(Triple::AIX); |
135 | TheTriple.setObjectFormat(Triple::XCOFF); |
136 | } else if (isGOFF()) { |
137 | TheTriple.setOS(Triple::ZOS); |
138 | TheTriple.setObjectFormat(Triple::GOFF); |
139 | } else if (TheTriple.isAMDGPU()) { |
140 | TheTriple.setVendor(Triple::AMD); |
141 | } else if (TheTriple.isNVPTX()) { |
142 | TheTriple.setVendor(Triple::NVIDIA); |
143 | } |
144 | |
145 | return TheTriple; |
146 | } |
147 | |
148 | Expected<std::unique_ptr<ObjectFile>> |
149 | ObjectFile::createObjectFile(MemoryBufferRef Object, file_magic Type, |
150 | bool InitContent) { |
151 | StringRef Data = Object.getBuffer(); |
152 | if (Type == file_magic::unknown) |
153 | Type = identify_magic(magic: Data); |
154 | |
155 | switch (Type) { |
156 | case file_magic::unknown: |
157 | case file_magic::bitcode: |
158 | case file_magic::clang_ast: |
159 | case file_magic::coff_cl_gl_object: |
160 | case file_magic::archive: |
161 | case file_magic::macho_universal_binary: |
162 | case file_magic::windows_resource: |
163 | case file_magic::pdb: |
164 | case file_magic::minidump: |
165 | case file_magic::goff_object: |
166 | case file_magic::cuda_fatbinary: |
167 | case file_magic::offload_binary: |
168 | case file_magic::dxcontainer_object: |
169 | case file_magic::offload_bundle: |
170 | case file_magic::offload_bundle_compressed: |
171 | case file_magic::spirv_object: |
172 | return errorCodeToError(EC: object_error::invalid_file_type); |
173 | case file_magic::tapi_file: |
174 | return errorCodeToError(EC: object_error::invalid_file_type); |
175 | case file_magic::elf: |
176 | case file_magic::elf_relocatable: |
177 | case file_magic::elf_executable: |
178 | case file_magic::elf_shared_object: |
179 | case file_magic::elf_core: |
180 | return createELFObjectFile(Object, InitContent); |
181 | case file_magic::macho_object: |
182 | case file_magic::macho_executable: |
183 | case file_magic::macho_fixed_virtual_memory_shared_lib: |
184 | case file_magic::macho_core: |
185 | case file_magic::macho_preload_executable: |
186 | case file_magic::macho_dynamically_linked_shared_lib: |
187 | case file_magic::macho_dynamic_linker: |
188 | case file_magic::macho_bundle: |
189 | case file_magic::macho_dynamically_linked_shared_lib_stub: |
190 | case file_magic::macho_dsym_companion: |
191 | case file_magic::macho_kext_bundle: |
192 | case file_magic::macho_file_set: |
193 | return createMachOObjectFile(Object); |
194 | case file_magic::coff_object: |
195 | case file_magic::coff_import_library: |
196 | case file_magic::pecoff_executable: |
197 | return createCOFFObjectFile(Object); |
198 | case file_magic::xcoff_object_32: |
199 | return createXCOFFObjectFile(Object, FileType: Binary::ID_XCOFF32); |
200 | case file_magic::xcoff_object_64: |
201 | return createXCOFFObjectFile(Object, FileType: Binary::ID_XCOFF64); |
202 | case file_magic::wasm_object: |
203 | return createWasmObjectFile(Object); |
204 | } |
205 | llvm_unreachable("Unexpected Object File Type" ); |
206 | } |
207 | |
208 | Expected<OwningBinary<ObjectFile>> |
209 | ObjectFile::createObjectFile(StringRef ObjectPath) { |
210 | ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr = |
211 | MemoryBuffer::getFile(Filename: ObjectPath); |
212 | if (std::error_code EC = FileOrErr.getError()) |
213 | return errorCodeToError(EC); |
214 | std::unique_ptr<MemoryBuffer> Buffer = std::move(FileOrErr.get()); |
215 | |
216 | Expected<std::unique_ptr<ObjectFile>> ObjOrErr = |
217 | createObjectFile(Object: Buffer->getMemBufferRef()); |
218 | if (Error Err = ObjOrErr.takeError()) |
219 | return std::move(Err); |
220 | std::unique_ptr<ObjectFile> Obj = std::move(ObjOrErr.get()); |
221 | |
222 | return OwningBinary<ObjectFile>(std::move(Obj), std::move(Buffer)); |
223 | } |
224 | |
225 | bool ObjectFile::isReflectionSectionStrippable( |
226 | llvm::binaryformat::Swift5ReflectionSectionKind ReflectionSectionKind) |
227 | const { |
228 | using llvm::binaryformat::Swift5ReflectionSectionKind; |
229 | return ReflectionSectionKind == Swift5ReflectionSectionKind::fieldmd || |
230 | ReflectionSectionKind == Swift5ReflectionSectionKind::reflstr || |
231 | ReflectionSectionKind == Swift5ReflectionSectionKind::assocty; |
232 | } |
233 | |