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