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