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