/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h
Line | Count | Source (jump to first uncovered line) |
1 | | //===- lib/ReaderWriter/MachO/MachONormalizedFileBinaryUtils.h ------------===// |
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 | | #ifndef LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H |
10 | | #define LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H |
11 | | |
12 | | #include "MachONormalizedFile.h" |
13 | | #include "lld/Common/LLVM.h" |
14 | | #include "lld/Core/Error.h" |
15 | | #include "llvm/ADT/StringRef.h" |
16 | | #include "llvm/BinaryFormat/MachO.h" |
17 | | #include "llvm/Support/Casting.h" |
18 | | #include "llvm/Support/Endian.h" |
19 | | #include "llvm/Support/ErrorHandling.h" |
20 | | #include "llvm/Support/Host.h" |
21 | | #include "llvm/Support/LEB128.h" |
22 | | #include <system_error> |
23 | | |
24 | | namespace lld { |
25 | | namespace mach_o { |
26 | | namespace normalized { |
27 | | |
28 | | class ByteBuffer { |
29 | | public: |
30 | 1.83k | ByteBuffer() : _ostream(_bytes) { } |
31 | | |
32 | 4.61k | void append_byte(uint8_t b) { |
33 | 4.61k | _ostream << b; |
34 | 4.61k | } |
35 | 932 | void append_uleb128(uint64_t value) { |
36 | 932 | llvm::encodeULEB128(value, _ostream); |
37 | 932 | } |
38 | 0 | void append_uleb128Fixed(uint64_t value, unsigned byteCount) { |
39 | 0 | unsigned min = llvm::getULEB128Size(value); |
40 | 0 | assert(min <= byteCount); |
41 | 0 | unsigned pad = byteCount - min; |
42 | 0 | llvm::encodeULEB128(value, _ostream, pad); |
43 | 0 | } |
44 | 0 | void append_sleb128(int64_t value) { |
45 | 0 | llvm::encodeSLEB128(value, _ostream); |
46 | 0 | } |
47 | 332 | void append_string(StringRef str) { |
48 | 332 | _ostream << str; |
49 | 332 | append_byte(0); |
50 | 332 | } |
51 | 669 | void align(unsigned alignment) { |
52 | 3.49k | while ( (_ostream.tell() % alignment) != 0 ) |
53 | 2.82k | append_byte(0); |
54 | 669 | } |
55 | 2.04k | size_t size() { |
56 | 2.04k | return _ostream.tell(); |
57 | 2.04k | } |
58 | 640 | const uint8_t *bytes() { |
59 | 640 | return reinterpret_cast<const uint8_t*>(_ostream.str().data()); |
60 | 640 | } |
61 | | |
62 | | private: |
63 | | SmallVector<char, 128> _bytes; |
64 | | // Stream ivar must be after SmallVector ivar to construct properly. |
65 | | llvm::raw_svector_ostream _ostream; |
66 | | }; |
67 | | |
68 | | using namespace llvm::support::endian; |
69 | | using llvm::sys::getSwappedBytes; |
70 | | |
71 | | template<typename T> |
72 | 20 | static inline uint16_t read16(const T *loc, bool isBig) { |
73 | 20 | assert((uint64_t)loc % alignof(T) == 0 && "invalid pointer alignment"); |
74 | 20 | return isBig ? read16be(loc)0 : read16le(loc); |
75 | 20 | } Unexecuted instantiation: ArchHandler.cpp:unsigned short lld::mach_o::normalized::read16<unsigned char>(unsigned char const*, bool) MachONormalizedFileBinaryReader.cpp:unsigned short lld::mach_o::normalized::read16<unsigned short>(unsigned short const*, bool) Line | Count | Source | 72 | 10 | static inline uint16_t read16(const T *loc, bool isBig) { | 73 | 10 | assert((uint64_t)loc % alignof(T) == 0 && "invalid pointer alignment"); | 74 | 10 | return isBig ? read16be(loc)0 : read16le(loc); | 75 | 10 | } |
MachONormalizedFileBinaryReader.cpp:unsigned short lld::mach_o::normalized::read16<unsigned char>(unsigned char const*, bool) Line | Count | Source | 72 | 10 | static inline uint16_t read16(const T *loc, bool isBig) { | 73 | 10 | assert((uint64_t)loc % alignof(T) == 0 && "invalid pointer alignment"); | 74 | 10 | return isBig ? read16be(loc)0 : read16le(loc); | 75 | 10 | } |
|
76 | | |
77 | | template<typename T> |
78 | 1.91k | static inline uint32_t read32(const T *loc, bool isBig) { |
79 | 1.91k | assert((uint64_t)loc % alignof(T) == 0 && "invalid pointer alignment"); |
80 | 1.91k | return isBig ? read32be(loc)95 : read32le(loc)1.81k ; |
81 | 1.91k | } ArchHandler.cpp:unsigned int lld::mach_o::normalized::read32<unsigned char>(unsigned char const*, bool) Line | Count | Source | 78 | 140 | static inline uint32_t read32(const T *loc, bool isBig) { | 79 | 140 | assert((uint64_t)loc % alignof(T) == 0 && "invalid pointer alignment"); | 80 | 140 | return isBig ? read32be(loc)0 : read32le(loc); | 81 | 140 | } |
Unexecuted instantiation: ArchHandler.cpp:unsigned int lld::mach_o::normalized::read32<unsigned int>(unsigned int const*, bool) Unexecuted instantiation: ArchHandler_arm.cpp:unsigned int lld::mach_o::normalized::read32<unsigned int>(unsigned int const*, bool) Unexecuted instantiation: ArchHandler_arm64.cpp:unsigned int lld::mach_o::normalized::read32<unsigned int>(unsigned int const*, bool) Unexecuted instantiation: ArchHandler_x86.cpp:unsigned int lld::mach_o::normalized::read32<unsigned int>(unsigned int const*, bool) Unexecuted instantiation: ArchHandler_x86_64.cpp:unsigned int lld::mach_o::normalized::read32<unsigned int>(unsigned int const*, bool) CompactUnwindPass.cpp:unsigned int lld::mach_o::normalized::read32<unsigned char>(unsigned char const*, bool) Line | Count | Source | 78 | 28 | static inline uint32_t read32(const T *loc, bool isBig) { | 79 | 28 | assert((uint64_t)loc % alignof(T) == 0 && "invalid pointer alignment"); | 80 | 28 | return isBig ? read32be(loc)0 : read32le(loc); | 81 | 28 | } |
Unexecuted instantiation: CompactUnwindPass.cpp:unsigned int lld::mach_o::normalized::read32<unsigned int>(unsigned int const*, bool) MachONormalizedFileBinaryReader.cpp:unsigned int lld::mach_o::normalized::read32<unsigned int>(unsigned int const*, bool) Line | Count | Source | 78 | 1.49k | static inline uint32_t read32(const T *loc, bool isBig) { | 79 | 1.49k | assert((uint64_t)loc % alignof(T) == 0 && "invalid pointer alignment"); | 80 | 1.49k | return isBig ? read32be(loc)87 : read32le(loc)1.40k ; | 81 | 1.49k | } |
MachONormalizedFileBinaryReader.cpp:unsigned int lld::mach_o::normalized::read32<unsigned char>(unsigned char const*, bool) Line | Count | Source | 78 | 101 | static inline uint32_t read32(const T *loc, bool isBig) { | 79 | 101 | assert((uint64_t)loc % alignof(T) == 0 && "invalid pointer alignment"); | 80 | 101 | return isBig ? read32be(loc)8 : read32le(loc)93 ; | 81 | 101 | } |
Unexecuted instantiation: MachONormalizedFileBinaryWriter.cpp:unsigned int lld::mach_o::normalized::read32<unsigned int>(unsigned int const*, bool) Unexecuted instantiation: MachONormalizedFileFromAtoms.cpp:unsigned int lld::mach_o::normalized::read32<unsigned int>(unsigned int const*, bool) MachONormalizedFileToAtoms.cpp:unsigned int lld::mach_o::normalized::read32<unsigned char>(unsigned char const*, bool) Line | Count | Source | 78 | 145 | static inline uint32_t read32(const T *loc, bool isBig) { | 79 | 145 | assert((uint64_t)loc % alignof(T) == 0 && "invalid pointer alignment"); | 80 | 145 | return isBig ? read32be(loc)0 : read32le(loc); | 81 | 145 | } |
Unexecuted instantiation: MachONormalizedFileToAtoms.cpp:unsigned int lld::mach_o::normalized::read32<unsigned int>(unsigned int const*, bool) Unexecuted instantiation: ObjCPass.cpp:unsigned int lld::mach_o::normalized::read32<unsigned int>(unsigned int const*, bool) |
82 | | |
83 | | template<typename T> |
84 | 156 | static inline uint64_t read64(const T *loc, bool isBig) { |
85 | 156 | assert((uint64_t)loc % alignof(T) == 0 && "invalid pointer alignment"); |
86 | 156 | return isBig ? read64be(loc)0 : read64le(loc); |
87 | 156 | } Unexecuted instantiation: ArchHandler.cpp:unsigned long long lld::mach_o::normalized::read64<unsigned char>(unsigned char const*, bool) MachONormalizedFileBinaryReader.cpp:unsigned long long lld::mach_o::normalized::read64<unsigned long long>(unsigned long long const*, bool) Line | Count | Source | 84 | 126 | static inline uint64_t read64(const T *loc, bool isBig) { | 85 | 126 | assert((uint64_t)loc % alignof(T) == 0 && "invalid pointer alignment"); | 86 | 126 | return isBig ? read64be(loc)0 : read64le(loc); | 87 | 126 | } |
MachONormalizedFileToAtoms.cpp:unsigned long long lld::mach_o::normalized::read64<unsigned char>(unsigned char const*, bool) Line | Count | Source | 84 | 30 | static inline uint64_t read64(const T *loc, bool isBig) { | 85 | 30 | assert((uint64_t)loc % alignof(T) == 0 && "invalid pointer alignment"); | 86 | 30 | return isBig ? read64be(loc)0 : read64le(loc); | 87 | 30 | } |
|
88 | | |
89 | 20 | inline void write16(uint8_t *loc, uint16_t value, bool isBig) { |
90 | 20 | if (isBig) |
91 | 0 | write16be(loc, value); |
92 | 20 | else |
93 | 20 | write16le(loc, value); |
94 | 20 | } |
95 | | |
96 | 137 | inline void write32(uint8_t *loc, uint32_t value, bool isBig) { |
97 | 137 | if (isBig) |
98 | 0 | write32be(loc, value); |
99 | 137 | else |
100 | 137 | write32le(loc, value); |
101 | 137 | } |
102 | | |
103 | 0 | inline void write64(uint8_t *loc, uint64_t value, bool isBig) { |
104 | 0 | if (isBig) |
105 | 0 | write64be(loc, value); |
106 | 0 | else |
107 | 0 | write64le(loc, value); |
108 | 0 | } |
109 | | |
110 | | inline uint32_t |
111 | | bitFieldExtract(uint32_t value, bool isBigEndianBigField, uint8_t firstBit, |
112 | 1.36k | uint8_t bitCount) { |
113 | 1.36k | const uint32_t mask = ((1<<bitCount)-1); |
114 | 1.36k | const uint8_t shift = isBigEndianBigField ? (32-firstBit-bitCount)403 : firstBit965 ; |
115 | 1.36k | return (value >> shift) & mask; |
116 | 1.36k | } |
117 | | |
118 | | inline void |
119 | | bitFieldSet(uint32_t &bits, bool isBigEndianBigField, uint32_t newBits, |
120 | 2.47k | uint8_t firstBit, uint8_t bitCount) { |
121 | 2.47k | const uint32_t mask = ((1<<bitCount)-1); |
122 | 2.47k | assert((newBits & mask) == newBits); |
123 | 2.47k | const uint8_t shift = isBigEndianBigField ? (32-firstBit-bitCount)740 : firstBit1.73k ; |
124 | 2.47k | bits &= ~(mask << shift); |
125 | 2.47k | bits |= (newBits << shift); |
126 | 2.47k | } |
127 | | |
128 | | inline Relocation unpackRelocation(const llvm::MachO::any_relocation_info &r, |
129 | 291 | bool isBigEndian) { |
130 | 291 | uint32_t r0 = read32(&r.r_word0, isBigEndian); |
131 | 291 | uint32_t r1 = read32(&r.r_word1, isBigEndian); |
132 | 291 | |
133 | 291 | Relocation result; |
134 | 291 | if (r0 & llvm::MachO::R_SCATTERED) { |
135 | 87 | // scattered relocation record always laid out like big endian bit field |
136 | 87 | result.offset = bitFieldExtract(r0, true, 8, 24); |
137 | 87 | result.scattered = true; |
138 | 87 | result.type = (RelocationInfoType) |
139 | 87 | bitFieldExtract(r0, true, 4, 4); |
140 | 87 | result.length = bitFieldExtract(r0, true, 2, 2); |
141 | 87 | result.pcRel = bitFieldExtract(r0, true, 1, 1); |
142 | 87 | result.isExtern = false; |
143 | 87 | result.value = r1; |
144 | 87 | result.symbol = 0; |
145 | 204 | } else { |
146 | 204 | result.offset = r0; |
147 | 204 | result.scattered = false; |
148 | 204 | result.type = (RelocationInfoType) |
149 | 204 | bitFieldExtract(r1, isBigEndian, 28, 4); |
150 | 204 | result.length = bitFieldExtract(r1, isBigEndian, 25, 2); |
151 | 204 | result.pcRel = bitFieldExtract(r1, isBigEndian, 24, 1); |
152 | 204 | result.isExtern = bitFieldExtract(r1, isBigEndian, 27, 1); |
153 | 204 | result.value = 0; |
154 | 204 | result.symbol = bitFieldExtract(r1, isBigEndian, 0, 24); |
155 | 204 | } |
156 | 291 | return result; |
157 | 291 | } |
158 | | |
159 | | |
160 | | inline llvm::MachO::any_relocation_info |
161 | 494 | packRelocation(const Relocation &r, bool swap, bool isBigEndian) { |
162 | 494 | uint32_t r0 = 0; |
163 | 494 | uint32_t r1 = 0; |
164 | 494 | |
165 | 494 | if (r.scattered) { |
166 | 137 | r1 = r.value; |
167 | 137 | bitFieldSet(r0, true, r.offset, 8, 24); |
168 | 137 | bitFieldSet(r0, true, r.type, 4, 4); |
169 | 137 | bitFieldSet(r0, true, r.length, 2, 2); |
170 | 137 | bitFieldSet(r0, true, r.pcRel, 1, 1); |
171 | 137 | bitFieldSet(r0, true, r.scattered, 0, 1); // R_SCATTERED |
172 | 357 | } else { |
173 | 357 | r0 = r.offset; |
174 | 357 | bitFieldSet(r1, isBigEndian, r.type, 28, 4); |
175 | 357 | bitFieldSet(r1, isBigEndian, r.isExtern, 27, 1); |
176 | 357 | bitFieldSet(r1, isBigEndian, r.length, 25, 2); |
177 | 357 | bitFieldSet(r1, isBigEndian, r.pcRel, 24, 1); |
178 | 357 | bitFieldSet(r1, isBigEndian, r.symbol, 0, 24); |
179 | 357 | } |
180 | 494 | |
181 | 494 | llvm::MachO::any_relocation_info result; |
182 | 494 | result.r_word0 = swap ? getSwappedBytes(r0)23 : r0471 ; |
183 | 494 | result.r_word1 = swap ? getSwappedBytes(r1)23 : r1471 ; |
184 | 494 | return result; |
185 | 494 | } |
186 | | |
187 | 172 | inline StringRef getString16(const char s[16]) { |
188 | 172 | // The StringRef(const char *) constructor passes the const char * to |
189 | 172 | // strlen(), so we can't use this constructor here, because if there is no |
190 | 172 | // null terminator in s, then strlen() will read past the end of the array. |
191 | 172 | return StringRef(s, strnlen(s, 16)); |
192 | 172 | } |
193 | | |
194 | 1.04k | inline void setString16(StringRef str, char s[16]) { |
195 | 1.04k | memset(s, 0, 16); |
196 | 1.04k | memcpy(s, str.begin(), (str.size() > 16) ? 160 : str.size()); |
197 | 1.04k | } |
198 | | |
199 | | // Implemented in normalizedToAtoms() and used by normalizedFromAtoms() so |
200 | | // that the same table can be used to map mach-o sections to and from |
201 | | // DefinedAtom::ContentType. |
202 | | void relocatableSectionInfoForContentType(DefinedAtom::ContentType atomType, |
203 | | StringRef &segmentName, |
204 | | StringRef §ionName, |
205 | | SectionType §ionType, |
206 | | SectionAttr §ionAttrs, |
207 | | bool &relocsToDefinedCanBeImplicit); |
208 | | |
209 | | } // namespace normalized |
210 | | } // namespace mach_o |
211 | | } // namespace lld |
212 | | |
213 | | #endif // LLD_READER_WRITER_MACHO_NORMALIZED_FILE_BINARY_UTILS_H |