1 : // Copyright 2012 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/pdb/pdb_dbi_stream.h"
16 :
17 : #include "base/strings/stringprintf.h"
18 : #include "syzygy/common/align.h"
19 : #include "syzygy/pdb/pdb_constants.h"
20 : #include "syzygy/pdb/pdb_stream.h"
21 : #include "syzygy/pdb/pdb_util.h"
22 :
23 : namespace pdb {
24 :
25 E : bool DbiModuleInfo::Read(pdb::PdbStream* stream) {
26 E : DCHECK(stream != NULL);
27 :
28 : if (!stream->Read(&module_info_base_, 1) ||
29 : !ReadString(stream, &module_name_) ||
30 : !ReadString(stream, &object_name_) ||
31 E : !stream->Seek(common::AlignUp(stream->pos(), 4))) {
32 i : LOG(ERROR) << "Unable to read module information.";
33 i : return false;
34 : }
35 :
36 E : return true;
37 E : }
38 :
39 : // Reads the header from the Dbi stream of the PDB.
40 E : bool DbiStream::ReadDbiHeaders(pdb::PdbStream* stream) {
41 E : DCHECK(stream != NULL);
42 :
43 E : if (!stream->Seek(0) || !stream->Read(&header_, 1)) {
44 i : LOG(ERROR) << "Unable to read the header of the Dbi Stream.";
45 i : return false;
46 : }
47 :
48 : if (!stream->Seek(pdb::GetDbiDbgHeaderOffset(header_)) ||
49 E : !stream->Read(&dbg_header_, 1)) {
50 i : LOG(ERROR) << "Unable to read Dbg header of the Dbi Stream.";
51 i : return false;
52 : }
53 :
54 E : return true;
55 E : }
56 :
57 : // Reads the module info substream from the Dbi stream of the PDB.
58 E : bool DbiStream::ReadDbiModuleInfo(pdb::PdbStream* stream) {
59 E : DCHECK(stream != NULL);
60 :
61 : // This substream starts just after the Dbi header in the Dbi stream.
62 E : size_t module_start = sizeof(pdb::DbiHeader);
63 E : size_t module_end = module_start + header_.gp_modi_size;
64 :
65 E : if (!stream->Seek(module_start)) {
66 i : LOG(ERROR) << "Unable to read the module information substream of the Dbi "
67 : << "stream.";
68 i : return false;
69 : }
70 :
71 : // Read each module info block.
72 E : while (stream->pos() < module_end) {
73 E : DbiModuleInfo module_info;
74 E : if (!module_info.Read(stream))
75 i : return false;
76 E : modules_.push_back(module_info);
77 E : }
78 :
79 E : if (stream->pos() != module_end) {
80 i : LOG(ERROR) << "Module info substream of the Dbi stream is not valid.";
81 i : return false;
82 : }
83 :
84 E : return true;
85 E : }
86 :
87 : // Reads the section contribs substream from the Dbi stream of the PDB.
88 E : bool DbiStream::ReadDbiSectionContribs(pdb::PdbStream* stream) {
89 E : DCHECK(stream != NULL);
90 :
91 E : size_t section_contribs_start = sizeof(pdb::DbiHeader) + header_.gp_modi_size;
92 : size_t section_contribs_end =
93 E : section_contribs_start + header_.section_contribution_size;
94 E : uint32 signature = 0;
95 :
96 E : if (!stream->Seek(section_contribs_start) || !stream->Read(&signature, 1)) {
97 i : LOG(ERROR) << "Unable to seek to section contributions substream.";
98 i : return false;
99 : }
100 :
101 E : if (signature != kPdbDbiSectionContribsSignature) {
102 E : LOG(ERROR) << "Unexpected signature for the section contribs substream. "
103 : << "Expected "
104 : << base::StringPrintf("0x%08X", kPdbDbiSectionContribsSignature)
105 : << ", read "
106 : << base::StringPrintf("0x%08X", signature) << ".";
107 E : return false;
108 : }
109 :
110 : size_t section_contrib_count =
111 E : (section_contribs_end - stream->pos()) / sizeof(DbiSectionContrib);
112 :
113 E : if (!stream->Read(§ion_contribs_, section_contrib_count)) {
114 i : LOG(ERROR) << "Unable to read section contributions.";
115 i : return false;
116 : }
117 :
118 E : if (stream->pos() != section_contribs_end) {
119 i : LOG(ERROR) << "Section contribs substream of the Dbi stream is not valid.";
120 i : return false;
121 : }
122 :
123 E : return true;
124 E : }
125 :
126 : // Reads the section map substream from the Dbi stream of the PDB.
127 E : bool DbiStream::ReadDbiSectionMap(pdb::PdbStream* stream) {
128 E : DCHECK(stream != NULL);
129 :
130 : size_t section_map_start = sizeof(pdb::DbiHeader)
131 : + header_.gp_modi_size
132 E : + header_.section_contribution_size;
133 E : size_t section_map_end = section_map_start + header_.section_map_size;
134 E : uint16 number_of_sections = 0;
135 :
136 E : if (!stream->Seek(section_map_start)) {
137 i : LOG(ERROR) << "Unable to seek to section map substream.";
138 i : return false;
139 : }
140 :
141 E : if (!stream->Read(&number_of_sections, 1)) {
142 i : LOG(ERROR) << "Unable to read the length of the section map in the Dbi "
143 : << "stream.";
144 i : return false;
145 : }
146 :
147 : // The number of section appears to be present twice. This check ensure that
148 : // the value are always equals. If it's not it'll give us a sample to
149 : // understand what's this value.
150 :
151 E : uint16 number_of_sections_copy = 0;
152 E : if (!stream->Read(&number_of_sections_copy, 1)) {
153 i : LOG(ERROR) << "Unable to read the copy of the length of the section map in "
154 : << "the Dbi stream.";
155 i : return false;
156 : }
157 :
158 E : if (number_of_sections != number_of_sections_copy) {
159 i : LOG(ERROR) << "Mismatched values for the length of the section map ("
160 : << number_of_sections << " vs "<< number_of_sections_copy
161 : << ").";
162 i : return false;
163 : }
164 :
165 E : while (stream->pos() < section_map_end) {
166 : DbiSectionMapItem section_map_item;
167 E : stream->Read(§ion_map_item, 1);
168 E : section_map_[section_map_item.section_number] = section_map_item;
169 E : }
170 :
171 E : if (section_map_.size() != number_of_sections) {
172 i : LOG(ERROR) << "Unexpected number of sections in the section map (expected "
173 : << number_of_sections << ", read " << section_map_.size()
174 : << ").";
175 i : return false;
176 : }
177 :
178 E : if (stream->pos() != section_map_end) {
179 i : LOG(ERROR) << "Section map substream of the Dbi stream is not valid.";
180 i : return false;
181 : }
182 :
183 E : return true;
184 E : }
185 :
186 : // Reads the file info substream from the Dbi stream of the PDB.
187 : // The structure of this substream is:
188 : // Header | File-blocks table | Offset table | Name table.
189 : // - The header contains the number of entries in the File-blocks table (16
190 : // bits) followed by the number of entries in the offset table (16 bits). You
191 : // have to multiply each size by 4 to obtain the size in bytes.
192 : // - The file-blocks table is divided in 2 parts. The first part contains the
193 : // starting index of each block (16 bits) and the second one contains
194 : // the length of these blocks. These value refer to the offset table. It
195 : // seems that there's always a last block with a starting value equal to the
196 : // length of the offset table and a length of 0 at the end of this table.
197 : // - The offset table contains offsets to the beginning of file names in the
198 : // name table. These offsets are relative to the beginning of the name table.
199 : // - The name table contain all the filenames used in this substream.
200 E : bool DbiStream::ReadDbiFileInfo(pdb::PdbStream* stream) {
201 E : DCHECK(stream != NULL);
202 :
203 : size_t file_info_start = sizeof(pdb::DbiHeader)
204 : + header_.gp_modi_size
205 : + header_.section_contribution_size
206 E : + header_.section_map_size;
207 E : size_t file_info_end = file_info_start + header_.file_info_size;
208 E : uint16 file_blocks_table_size = 0;
209 E : uint16 offset_table_size = 0;
210 :
211 E : if (!stream->Seek(file_info_start)) {
212 i : LOG(ERROR) << "Unable to seek to file info substream.";
213 i : return false;
214 : }
215 :
216 : if (!stream->Read(&file_blocks_table_size, 1) ||
217 E : !stream->Read(&offset_table_size, 1)) {
218 i : LOG(ERROR) << "Unable to read the header of the file info substream.";
219 i : return false;
220 : }
221 :
222 : // Calculate the starting address of the different sections of this substream.
223 E : size_t file_blocks_table_start = stream->pos();
224 : size_t offset_table_start = stream->pos()
225 E : + file_blocks_table_size*sizeof(size_t);
226 : size_t name_table_start = offset_table_start
227 E : + offset_table_size*sizeof(size_t);
228 :
229 : if (!ReadDbiFileInfoBlocks(stream,
230 : file_blocks_table_size,
231 : file_blocks_table_start,
232 : offset_table_size,
233 E : offset_table_start)) {
234 i : return false;
235 : }
236 :
237 : // Read the name table in this substream.
238 : if (!ReadDbiFileNameTable(stream,
239 : name_table_start,
240 E : file_info_end)) {
241 i : return false;
242 : }
243 :
244 E : return true;
245 E : }
246 :
247 : bool DbiStream::ReadDbiFileInfoBlocks(pdb::PdbStream* stream,
248 : uint16 file_blocks_table_size,
249 : size_t file_blocks_table_start,
250 : uint16 offset_table_size,
251 E : size_t offset_table_start) {
252 E : file_info_.first.resize(file_blocks_table_size);
253 : // Read information about each block of the file info substream.
254 E : for (int i = 0; i < file_blocks_table_size; ++i) {
255 E : uint16 block_start = 0;
256 E : uint16 block_length = 0;
257 :
258 : if (!stream->Seek(file_blocks_table_start + i * sizeof(block_start)) ||
259 : !stream->Read(&block_start, 1) ||
260 : !stream->Seek(file_blocks_table_start
261 : + (file_blocks_table_size + i)*sizeof(block_start)) ||
262 E : !stream->Read(&block_length, 1)) {
263 i : LOG(ERROR) << "Unable to read the file info substream.";
264 i : return false;
265 : }
266 :
267 : // Fill the file list.
268 E : if (!stream->Seek(offset_table_start + block_start * sizeof(size_t))) {
269 i : LOG(ERROR) << "Unable to seek to the beginning of a block in the name "
270 : << " info substream (block index = " << block_start << ").";
271 i : return false;
272 : }
273 :
274 E : if (!stream->Read(&file_info_.first.at(i), block_length)) {
275 i : LOG(ERROR) << "Unable to read the file info substream.";
276 i : return false;
277 : }
278 E : }
279 :
280 E : return true;
281 E : }
282 :
283 : // It would be useful to move this code to a more generic function if we see
284 : // this structure somewhere else in the PDB.
285 : bool DbiStream::ReadDbiFileNameTable(pdb::PdbStream* stream,
286 : size_t name_table_start,
287 E : size_t name_table_end) {
288 E : if (!stream->Seek(name_table_start)) {
289 i : LOG(ERROR) << "Unable to seek to the name table of the file info "
290 : << "substream.";
291 i : return false;
292 : }
293 :
294 E : while (stream->pos() < name_table_end) {
295 E : std::string filename;
296 E : size_t pos = stream->pos() - name_table_start;
297 E : if (!ReadString(stream, &filename)) {
298 i : LOG(ERROR) << "Unable to read the name table of the file info substream.";
299 i : return false;
300 : }
301 E : file_info_.second.insert(std::make_pair(pos, filename));
302 E : }
303 :
304 E : if (stream->pos() != name_table_end) {
305 i : LOG(ERROR) << "File info substream of the Dbi stream is not valid.";
306 i : return false;
307 : }
308 :
309 E : return true;
310 E : }
311 :
312 E : bool DbiStream::ReadDbiECInfo(pdb::PdbStream* stream) {
313 : // It's important to note that the ec_info_size field appears after the
314 : // dbg_header_size field in the header of this stream but the EC info
315 : // substream is located before the DbgHeader substream.
316 : size_t ec_info_start = sizeof(pdb::DbiHeader)
317 : + header_.gp_modi_size
318 : + header_.section_contribution_size
319 : + header_.section_map_size
320 : + header_.file_info_size
321 E : + header_.ts_map_size;
322 E : size_t ec_info_end = ec_info_start + header_.ec_info_size;
323 :
324 : return ReadStringTable(stream,
325 : "EC info",
326 : ec_info_start,
327 : ec_info_end,
328 E : &ec_info_vector_);
329 E : }
330 :
331 E : bool DbiStream::Read(pdb::PdbStream* stream ) {
332 E : DCHECK(stream != NULL);
333 :
334 E : if (!ReadDbiHeaders(stream))
335 i : return false;
336 :
337 E : if (!ReadDbiModuleInfo(stream))
338 i : return false;
339 :
340 E : if (!ReadDbiSectionContribs(stream))
341 E : return false;
342 :
343 E : if (!ReadDbiSectionMap(stream))
344 i : return false;
345 :
346 E : if (!ReadDbiFileInfo(stream))
347 i : return false;
348 :
349 E : if (header_.ts_map_size != 0) {
350 i : LOG(ERROR) << "The length of the TS map is expected to be null but we've "
351 : << "read a length of " << header_.ts_map_size << ".";
352 i : return false;
353 : }
354 :
355 E : if (!ReadDbiECInfo(stream))
356 i : return false;
357 :
358 E : return true;
359 E : }
360 :
361 : } // namespace pdb
|