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_symbol_record.h"
16 :
17 : #include <string>
18 :
19 : #include "base/strings/stringprintf.h"
20 : #include "syzygy/common/align.h"
21 : #include "syzygy/pdb/pdb_reader.h"
22 : #include "syzygy/pdb/pdb_util.h"
23 : #include "third_party/cci/Files/CvInfo.h"
24 :
25 : namespace cci = Microsoft_Cci_Pdb;
26 :
27 : namespace pdb {
28 :
29 : bool ReadSymbolRecord(PdbStream* stream,
30 : size_t symbol_table_size,
31 E : SymbolRecordVector* symbol_vector) {
32 E : DCHECK(stream != NULL);
33 E : DCHECK(symbol_vector != NULL);
34 :
35 E : size_t stream_end = stream->pos() + symbol_table_size;
36 E : if (stream_end > stream->length()) {
37 i : LOG(ERROR) << "The specified symbol table size exceeds the size of the "
38 : << "stream.";
39 i : return false;
40 : }
41 :
42 : // Process each symbol present in the stream. For now we only save their
43 : // starting positions, their lengths and their types to be able to dump them.
44 E : while (stream->pos() < stream_end) {
45 E : uint16 len = 0;
46 E : uint16 symbol_type = 0;
47 E : if (!stream->Read(&len, 1)) {
48 i : LOG(ERROR) << "Unable to read a symbol record length.";
49 i : return false;
50 : }
51 E : size_t symbol_start = stream->pos();
52 E : if (!stream->Read(&symbol_type, 1)) {
53 i : LOG(ERROR) << "Unable to read a symbol record type.";
54 i : return false;
55 : }
56 : SymbolRecord sym_record;
57 E : sym_record.type = symbol_type;
58 E : sym_record.start_position = stream->pos();
59 E : sym_record.len = len - sizeof(symbol_type);
60 E : symbol_vector->push_back(sym_record);
61 E : if (stream->pos() != stream_end && !stream->Seek(symbol_start + len)) {
62 E : LOG(ERROR) << "Unable to seek to the end of the symbol record.";
63 E : return false;
64 : }
65 E : }
66 :
67 E : return true;
68 E : }
69 :
70 : // Reads symbols from the given symbol stream until the end of the stream.
71 : bool VisitSymbols(VisitSymbolsCallback callback,
72 : size_t symbol_table_size,
73 : bool has_header,
74 E : PdbStream* symbols) {
75 E : DCHECK(symbols != NULL);
76 :
77 E : size_t symbol_table_end = symbols->pos() + symbol_table_size;
78 E : if (symbol_table_end > symbols->length()) {
79 E : LOG(ERROR) << "Symbol table size provided exceeds stream length.";
80 E : return false;
81 : }
82 :
83 E : if (has_header) {
84 E : uint32 stream_type = 0;
85 E : if (!symbols->Read(&stream_type, 1)) {
86 E : LOG(ERROR) << "Unable to read symbol stream type.";
87 E : return false;
88 : }
89 E : if (stream_type != cci::C13) {
90 E : LOG(ERROR) << "Unexpected symbol stream type (" << stream_type
91 : << ").";
92 E : return false;
93 : }
94 : }
95 :
96 : // Read the symbols from the linker symbol stream. We try to read at least
97 : // one symbol without checking the stream position.
98 E : while (symbols->pos() < symbol_table_end) {
99 E : uint16 symbol_length = 0;
100 E : if (!symbols->Read(&symbol_length, 1)) {
101 E : LOG(ERROR) << "Unable to read symbol length from symbol stream.";
102 E : return false;
103 : }
104 : // We can see empty symbols in the symbol stream.
105 E : if (symbol_length == 0) {
106 : // TODO(chrisha): I've only seen these as terminators thus far. Validate
107 : // this fact for all symbol streams. If we find this to be true, we
108 : // can break here and double check that we've consumed the entire
109 : // stream content.
110 E : continue;
111 : }
112 :
113 E : if (symbol_length < 2) {
114 E : LOG(ERROR) << "Symbol length too short to hold symbol type.";
115 E : return false;
116 : }
117 :
118 : // Remember the position in the stream where the next symbol lies. This is
119 : // to be used for seeking later.
120 E : size_t symbol_end = symbols->pos() + symbol_length;
121 :
122 E : uint16 symbol_type = 0;
123 E : if (!symbols->Read(&symbol_type, 1)) {
124 E : LOG(ERROR) << "Failed to read symbol type from symbol stream.";
125 E : return false;
126 : }
127 :
128 E : if (symbol_end > symbol_table_end) {
129 E : LOG(ERROR) << "Encountered symbol length that exceeds table size.";
130 E : return false;
131 : }
132 :
133 : // We provide the length of the symbol data to the callback, exclusive of
134 : // the symbol type header.
135 E : if (!callback.Run(symbol_length - 2, symbol_type, symbols))
136 E : return false;
137 :
138 E : if (!symbols->Seek(symbol_end)) {
139 i : LOG(ERROR) << "Failed to seek past symbol in symbol stream.";
140 i : return false;
141 : }
142 E : }
143 :
144 E : return true;
145 E : }
146 :
147 : } // namespace pdb
|