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 : #include "syzygy/pe/coff_file.h"
16 :
17 : #include "base/file_util.h"
18 : #include "base/logging.h"
19 :
20 : namespace pe {
21 :
22 : using core::FileOffsetAddress;
23 :
24 : CoffFile::CoffFile()
25 : : symbols_(NULL),
26 : strings_(NULL),
27 : symbols_offset_(),
28 : symbols_size_(0),
29 : strings_offset_(),
30 : strings_size_(0),
31 E : reloc_infos_() {
32 E : }
33 :
34 E : CoffFile::~CoffFile() {
35 E : }
36 :
37 E : bool CoffFile::Init(const base::FilePath& path) {
38 E : PECoffFile::Init(path);
39 :
40 E : base::ScopedFILE file(base::OpenFile(path, "rb"));
41 E : if (file.get() == NULL) {
42 i : LOG(ERROR) << "Failed to open file " << path.value() << ".";
43 i : return false;
44 : }
45 :
46 E : bool success = ReadCommonHeaders(file.get(), FileOffsetAddress(0));
47 E : if (success)
48 E : success = ReadSections(file.get());
49 E : if (success)
50 E : success = ReadNonSections(file.get());
51 :
52 E : return success;
53 E : }
54 :
55 : bool CoffFile::FileOffsetToSectionOffset(FileOffsetAddress addr,
56 : size_t* section_index,
57 E : size_t* offset) const {
58 E : DCHECK(section_index != NULL);
59 E : DCHECK(offset != NULL);
60 :
61 : ImageAddressSpace::RangeMap::const_iterator it =
62 E : image_data_.FindContaining(ImageAddressSpace::Range(addr, 1));
63 E : if (it == image_data_.ranges().end())
64 i : return false;
65 E : if (it->second.id == kInvalidSection || addr >= it->first.end())
66 i : return false;
67 :
68 E : *section_index = it->second.id;
69 E : *offset = addr - it->first.start();
70 E : return true;
71 E : }
72 :
73 : bool CoffFile::SectionOffsetToFileOffset(size_t section_index,
74 : size_t offset,
75 E : FileOffsetAddress* addr) const {
76 E : DCHECK(addr != NULL);
77 :
78 E : if (section_index >= file_header_->NumberOfSections) {
79 i : LOG(ERROR) << "Unknown section index " << section_index << ".";
80 i : return false;
81 : }
82 :
83 E : const IMAGE_SECTION_HEADER* header = §ion_headers_[section_index];
84 E : if (offset > header->SizeOfRawData) {
85 i : LOG(ERROR) << "Section offset " << section_index << " out of bounds.";
86 i : return false;
87 : }
88 :
89 E : addr->set_value(header->PointerToRawData + offset);
90 E : return true;
91 E : }
92 :
93 E : bool CoffFile::ReadNonSections(FILE* file) {
94 E : DCHECK(file != NULL);
95 E : DCHECK(file_header_ != NULL);
96 :
97 : // Map the symbol table into our address space.
98 E : FileOffsetAddress symbols_start(file_header_->PointerToSymbolTable);
99 E : size_t symbols_size = file_header_->NumberOfSymbols * sizeof(*symbols_);
100 E : ImageAddressSpace::Range symbols_range(symbols_start, symbols_size);
101 E : if (!InsertRangeReadAt(file, symbols_start, symbols_size, symbols_range))
102 i : return false;
103 :
104 : // Get the pointer to our internal data range.
105 E : CHECK(GetImageData(symbols_start, symbols_size, &symbols_));
106 E : symbols_offset_ = symbols_start;
107 E : symbols_size_ = symbols_size;
108 :
109 : // Map the string table into our address space.
110 E : FileOffsetAddress strings_start(symbols_start + symbols_size);
111 E : uint32 strings_size = 0;
112 : if (!ReadAt(file, strings_start.value(),
113 E : &strings_size, sizeof(strings_size))) {
114 i : LOG(ERROR) << "Unable to read string table size.";
115 i : return false;
116 : }
117 E : if (strings_size > 0) {
118 E : ImageAddressSpace::Range strings_range(strings_start, strings_size);
119 E : if (!InsertRangeReadAt(file, strings_start, strings_size, strings_range))
120 i : return false;
121 :
122 E : CHECK(GetImageData(strings_start, strings_size, &strings_));
123 : }
124 E : strings_offset_ = strings_start;
125 E : strings_size_ = strings_size;
126 :
127 : // Map relocation data for every section.
128 E : size_t num_sections = file_header_->NumberOfSections;
129 E : reloc_infos_.resize(num_sections);
130 E : for (size_t i = 0; i < num_sections; ++i) {
131 E : const IMAGE_SECTION_HEADER* header = section_header(i);
132 E : FileOffsetAddress relocs_start(header->PointerToRelocations);
133 :
134 E : size_t num_relocs = header->NumberOfRelocations;
135 E : if ((header->Characteristics & IMAGE_SCN_LNK_NRELOC_OVFL) != 0) {
136 i : DCHECK_EQ(num_relocs, 0xffffu);
137 : IMAGE_RELOCATION reloc;
138 : if (!ReadAt(file, header->PointerToRelocations,
139 i : &reloc, sizeof(reloc))) {
140 i : LOG(ERROR) << "Unable to read extended relocation count.";
141 i : return false;
142 : }
143 i : num_relocs = reloc.VirtualAddress;
144 : }
145 :
146 E : if (num_relocs == 0)
147 E : continue;
148 E : size_t relocs_size = num_relocs * sizeof(IMAGE_RELOCATION);
149 :
150 E : ImageAddressSpace::Range relocs_range(relocs_start, relocs_size);
151 E : if (!InsertRangeReadAt(file, relocs_start, relocs_size, relocs_range))
152 i : return false;
153 :
154 : // Save section relocation info to avoid recomputing pointer and
155 : // size from headers.
156 E : CHECK(GetImageData(relocs_start, relocs_size, &reloc_infos_[i].relocs_));
157 E : reloc_infos_[i].num_relocs_ = num_relocs;
158 E : }
159 :
160 E : return true;
161 E : }
162 :
163 E : void CoffFile::DecodeRelocs(RelocMap* reloc_map) const {
164 E : DCHECK(file_header_ != NULL);
165 E : DCHECK(symbols_ != NULL);
166 :
167 E : size_t num_sections = file_header_->NumberOfSections;
168 E : for (size_t i = 0; i < num_sections; ++i) {
169 E : CHECK(DecodeSectionRelocs(i, reloc_map));
170 E : }
171 E : }
172 :
173 : bool CoffFile::DecodeSectionRelocs(size_t section_index,
174 E : RelocMap* reloc_map) const {
175 E : DCHECK(file_header_ != NULL);
176 E : DCHECK(symbols_ != NULL);
177 :
178 E : const IMAGE_SECTION_HEADER* header = section_header(section_index);
179 E : if (header == NULL)
180 i : return false;
181 :
182 E : IMAGE_RELOCATION* relocs = reloc_infos_[section_index].relocs_;
183 E : size_t num_relocs = reloc_infos_[section_index].num_relocs_;
184 :
185 E : for (size_t i = 0; i < num_relocs; ++i) {
186 E : size_t offset = relocs[i].VirtualAddress - header->VirtualAddress;
187 E : FileOffsetAddress addr(header->PointerToRawData + offset);
188 E : reloc_map->insert(std::make_pair(addr, &relocs[i]));
189 E : }
190 :
191 E : return true;
192 E : }
193 :
194 E : bool CoffFile::IsSectionMapped(size_t section_index) const {
195 E : DCHECK(section_headers_ != NULL);
196 :
197 E : const IMAGE_SECTION_HEADER* header = section_header(section_index);
198 : return header != NULL &&
199 : (CoffAddressSpaceTraits::GetSectionAddress(*header) !=
200 E : CoffAddressSpaceTraits::invalid_address());
201 E : }
202 :
203 E : const char* CoffFile::GetSymbolName(size_t symbol_index) const {
204 E : DCHECK(symbols_ != NULL);
205 :
206 E : IMAGE_SYMBOL* symbol = &symbols_[symbol_index];
207 E : if (symbol->N.Name.Short != 0)
208 E : return reinterpret_cast<const char*>(&symbol->N.ShortName);
209 i : else
210 E : return string(symbol->N.Name.Long);
211 E : }
212 :
213 : } // namespace pe
|