1 : // Copyright 2013 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : // Template implementation of common definitions and helper routines
16 : // for reading both PE and COFF file formats.
17 :
18 : #ifndef SYZYGY_PE_PE_COFF_FILE_IMPL_H_
19 : #define SYZYGY_PE_PE_COFF_FILE_IMPL_H_
20 :
21 : namespace pe {
22 :
23 : template <typename AddressSpaceTraits>
24 E : void PECoffFile<AddressSpaceTraits>::Init(const base::FilePath& path) {
25 E : path_ = path;
26 E : }
27 :
28 : template <typename AddressSpaceTraits>
29 : bool PECoffFile<AddressSpaceTraits>::Contains(AddressType addr,
30 E : SizeType len) const {
31 E : const ImageAddressSpace::Range range(addr, len);
32 E : return image_data_.FindContaining(range) != image_data_.ranges().end();
33 E : }
34 :
35 : template <typename AddressSpaceTraits>
36 : size_t PECoffFile<AddressSpaceTraits>::GetSectionIndex(AddressType addr,
37 E : SizeType len) const {
38 E : const ImageAddressSpace::Range range(addr, len);
39 : ImageAddressSpace::RangeMap::const_iterator it =
40 E : image_data_.FindContaining(range);
41 E : if (it == image_data_.ranges().end())
42 E : return kInvalidSection;
43 E : return it->second.id;
44 E : }
45 :
46 : template <typename AddressSpaceTraits>
47 : const IMAGE_SECTION_HEADER* PECoffFile<AddressSpaceTraits>::GetSectionHeader(
48 E : AddressType addr, SizeType len) const {
49 E : size_t id = GetSectionIndex(addr, len);
50 E : if (id == kInvalidSection)
51 E : return NULL;
52 E : DCHECK_LT(id, file_header_->NumberOfSections);
53 E : return section_headers_ + id;
54 E : }
55 :
56 : template <typename AddressSpaceTraits>
57 : std::string PECoffFile<AddressSpaceTraits>::GetSectionName(
58 E : const IMAGE_SECTION_HEADER& section) {
59 E : const char* name = reinterpret_cast<const char*>(section.Name);
60 E : return std::string(name, strnlen(name, arraysize(section.Name)));
61 E : }
62 :
63 : template <typename AddressSpaceTraits>
64 : std::string PECoffFile<AddressSpaceTraits>::GetSectionName(
65 E : size_t section_index) const {
66 E : DCHECK_LT(section_index, file_header_->NumberOfSections);
67 :
68 E : const IMAGE_SECTION_HEADER* section = section_headers_ + section_index;
69 E : return GetSectionName(*section);
70 E : }
71 :
72 : template <typename AddressSpaceTraits>
73 : bool PECoffFile<AddressSpaceTraits>::ReadCommonHeaders(
74 E : FILE* file, FileOffsetAddress file_header_start) {
75 : // Test for unsupported object files.
76 : uint16 obj_sig[2];
77 E : if (!ReadAt(file, 0, obj_sig, sizeof(obj_sig))) {
78 i : LOG(ERROR) << "Unable to read first 4 bytes from object file.";
79 i : return false;
80 : }
81 E : if (obj_sig[0] == 0 && obj_sig[1] == 0xFFFF) {
82 E : LOG(ERROR) << "Unsupported anonymous object file.";
83 E : return false;
84 : }
85 :
86 : // Read the COFF file header.
87 E : IMAGE_FILE_HEADER file_header = {};
88 : if (!ReadAt(file, file_header_start.value(),
89 E : &file_header, sizeof(file_header))) {
90 i : LOG(ERROR) << "Unable to read COFF file header.";
91 i : return false;
92 : }
93 :
94 : // Compute size of all headers, from the beginning of the file to
95 : // the end of the section table.
96 : FileOffsetAddress opt_header_start(file_header_start.value() +
97 E : sizeof(file_header));
98 : FileOffsetAddress section_table_start(opt_header_start +
99 E : file_header.SizeOfOptionalHeader);
100 : SizeType section_table_size(
101 E : file_header.NumberOfSections * sizeof(IMAGE_SECTION_HEADER));
102 E : FileOffsetAddress header_end(section_table_start + section_table_size);
103 E : SizeType header_size = header_end.value();
104 E : if (file_header.SizeOfOptionalHeader != 0) {
105 E : IMAGE_OPTIONAL_HEADER opt_header = {};
106 : if (!ReadAt(file, opt_header_start.value(),
107 E : &opt_header, sizeof(opt_header))) {
108 i : LOG(ERROR) << "Unable to read optional header.";
109 i : return false;
110 : }
111 : // In a sane world the stated header size will match that manually
112 : // calculated by walking the headers and aligning up by the file alignment.
113 : // However, this is not necessary for the PE file to be valid, and there may
114 : // be a gap between the two.
115 E : header_size = opt_header.SizeOfHeaders;
116 : }
117 :
118 : // We now know how large the headers are, so create a range for them.
119 E : ImageAddressSpace::Range header_range(header_address(), header_size);
120 : if (!InsertRangeReadAt(file, FileOffsetAddress(0), header_size,
121 E : header_range)) {
122 i : return false;
123 : }
124 :
125 : bool success = GetImageData(header_address() + file_header_start.value(),
126 : SizeType(sizeof(*file_header_)),
127 E : &file_header_);
128 E : DCHECK(success);
129 : success = GetImageData(header_address() + section_table_start.value(),
130 : section_table_size,
131 E : §ion_headers_);
132 E : DCHECK(success);
133 :
134 E : return success;
135 E : }
136 :
137 : template <typename AddressSpaceTraits>
138 E : bool PECoffFile<AddressSpaceTraits>::ReadSections(FILE* file) {
139 E : DCHECK(file_header_ != NULL);
140 E : DCHECK(section_headers_ != NULL);
141 :
142 E : size_t num_sections = file_header_->NumberOfSections;
143 E : for (size_t i = 0; i < num_sections; ++i) {
144 E : const IMAGE_SECTION_HEADER* hdr = section_headers_ + i;
145 :
146 : // Construct address in the new address space; FromSectionHeader()
147 : // returns header_address() if unmapped.
148 E : AddressType addr = AddressSpaceTraits::GetSectionAddress(*hdr);
149 :
150 : // Ignore unmapped sections, as those, by definition, have no
151 : // address to map to within our address space. They need to be
152 : // handled separately during decomposition.
153 E : if (addr == AddressSpaceTraits::invalid_address())
154 E : continue;
155 :
156 : // Empty sections are ignored at this level of the parsing.
157 E : size_t section_size = AddressSpaceTraits::GetSectionSize(*hdr);
158 E : if (section_size == 0)
159 i : continue;
160 :
161 : // Insert the range for the new section.
162 E : ImageAddressSpace::Range section_range(addr, section_size);
163 E : ImageAddressSpace::RangeMap::iterator it;
164 E : if (!image_data_.Insert(section_range, SectionInfo(), &it)) {
165 i : LOG(ERROR) << "Unable to insert range for section " << hdr->Name << ".";
166 i : return false;
167 : }
168 :
169 E : it->second.id = i;
170 E : SectionBuffer& buf = it->second.buffer;
171 E : if (hdr->SizeOfRawData == 0)
172 i : continue;
173 :
174 E : buf.resize(hdr->SizeOfRawData);
175 E : if (!ReadAt(file, hdr->PointerToRawData, &buf.at(0), hdr->SizeOfRawData)) {
176 i : LOG(ERROR) << "Unable to read data for section " << hdr->Name << ".";
177 i : return false;
178 : }
179 E : }
180 :
181 E : return true;
182 E : }
183 :
184 : template <typename AddressSpaceTraits>
185 : bool PECoffFile<AddressSpaceTraits>::InsertRangeReadAt(
186 : FILE* file, FileOffsetAddress start, size_t size,
187 E : const typename ImageAddressSpace::Range& range) {
188 E : ImageAddressSpace::RangeMap::iterator it;
189 E : bool inserted = image_data_.Insert(range, SectionInfo(), &it);
190 E : if (!inserted) {
191 i : LOG(ERROR) << "Unable to create new range in address space.";
192 i : return false;
193 : }
194 :
195 E : SectionBuffer& buffer = it->second.buffer;
196 E : buffer.resize(size);
197 E : if (!ReadAt(file, start.value(), &buffer[0], size)) {
198 i : LOG(ERROR) << "Unable to file data.";
199 i : return false;
200 : }
201 :
202 E : return true;
203 E : }
204 :
205 : template <typename AddressSpaceTraits>
206 : bool PECoffFile<AddressSpaceTraits>::ReadAt(FILE* file, size_t pos,
207 E : void* buf, size_t len) {
208 E : if (fseek(file, pos, SEEK_SET) != 0)
209 i : return false;
210 :
211 E : size_t read = fread(buf, 1, len, file);
212 E : if (read != len)
213 i : return false;
214 :
215 E : return true;
216 E : }
217 :
218 : template <typename AddressSpaceTraits>
219 : const uint8* PECoffFile<AddressSpaceTraits>::GetImageData(AddressType addr,
220 E : SizeType len) const {
221 E : ImageAddressSpace::Range range(addr, len);
222 : ImageAddressSpace::RangeMap::const_iterator it(
223 E : image_data_.FindContaining(range));
224 :
225 E : if (it != image_data_.ranges().end()) {
226 E : ptrdiff_t offs = addr - it->first.start();
227 E : DCHECK_GE(offs, 0);
228 :
229 E : const SectionBuffer& buf = it->second.buffer;
230 E : if (offs + len <= buf.size())
231 E : return &buf.at(offs);
232 : }
233 :
234 E : return NULL;
235 E : }
236 :
237 : template <typename AddressSpaceTraits>
238 : uint8* PECoffFile<AddressSpaceTraits>::GetImageData(AddressType addr,
239 E : SizeType len) {
240 : return const_cast<uint8*>(
241 E : static_cast<const PECoffFile*>(this)->GetImageData(addr, len));
242 E : }
243 :
244 : template <typename AddressSpaceTraits>
245 : template <typename ItemType>
246 : bool PECoffFile<AddressSpaceTraits>::GetImageData(
247 E : AddressType addr, SizeType len, const ItemType** item_ptr) const {
248 E : const uint8* ptr = GetImageData(addr, len);
249 E : if (ptr == NULL)
250 i : return false;
251 E : *item_ptr = reinterpret_cast<const ItemType*>(ptr);
252 E : return true;
253 E : }
254 :
255 : template <typename AddressSpaceTraits>
256 : template <typename ItemType>
257 : bool PECoffFile<AddressSpaceTraits>::GetImageData(
258 E : AddressType addr, SizeType len, ItemType** item_ptr) {
259 E : uint8* ptr = GetImageData(addr, len);
260 E : if (ptr == NULL)
261 i : return false;
262 E : *item_ptr = reinterpret_cast<ItemType*>(ptr);
263 E : return true;
264 E : }
265 :
266 : template <typename AddressSpaceTraits>
267 : bool PECoffFile<AddressSpaceTraits>::ReadImage(AddressType addr,
268 E : void* data, SizeType len) const {
269 E : DCHECK(data != NULL);
270 E : const uint8* buf = GetImageData(addr, len);
271 E : if (buf == NULL)
272 i : return false;
273 :
274 E : memcpy(data, buf, len);
275 E : return true;
276 E : }
277 :
278 : template <typename AddressSpaceTraits>
279 : bool PECoffFile<AddressSpaceTraits>::ReadImageString(AddressType addr,
280 E : std::string* str) const {
281 E : DCHECK(file_header_ != NULL);
282 E : str->clear();
283 :
284 : // Locate the range that contains the first byte of the string.
285 E : ImageAddressSpace::Range range(addr, 1);
286 : ImageAddressSpace::RangeMap::const_iterator it(
287 E : image_data_.FindContaining(range));
288 :
289 E : if (it != image_data_.ranges().end()) {
290 E : ptrdiff_t offs = addr - it->first.start();
291 E : DCHECK_GE(offs, 0);
292 : // Stash the start position.
293 E : const SectionBuffer& buf = it->second.buffer;
294 E : const char* begin = reinterpret_cast<const char*>(&buf.at(offs));
295 : // And loop through until we find a zero-terminating byte,
296 : // or run off the end.
297 E : for (; static_cast<size_t>(offs) < buf.size() && buf.at(offs); ++offs) {
298 : // Intentionally empty.
299 E : }
300 :
301 E : if (static_cast<size_t>(offs) == buf.size())
302 i : return false;
303 :
304 E : str->assign(begin);
305 E : return true;
306 : }
307 :
308 i : return false;
309 E : }
310 :
311 : } // namespace pe
312 :
313 : #endif // SYZYGY_PE_PE_COFF_FILE_IMPL_H_
|