1 : // Copyright 2015 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/minidump/minidump.h"
16 :
17 : #include "base/logging.h"
18 : #include "base/files/file_util.h"
19 :
20 : namespace minidump {
21 :
22 : namespace internal {
23 :
24 E : size_t DefaultHeaderParser::Parse(const MINIDUMP_MEMORY_LIST& header) {
25 E : return header.NumberOfMemoryRanges;
26 E : }
27 :
28 E : size_t DefaultHeaderParser::Parse(const MINIDUMP_MODULE_LIST& header) {
29 E : return header.NumberOfModules;
30 E : }
31 :
32 E : size_t DefaultHeaderParser::Parse(const MINIDUMP_THREAD_LIST& header) {
33 E : return header.NumberOfThreads;
34 E : }
35 :
36 : size_t DefaultHeaderParser::Parse(const MINIDUMP_THREAD_EX_LIST& header) {
37 : return header.NumberOfThreads;
38 : }
39 :
40 : } // namespace internal
41 :
42 E : Minidump::Minidump() {
43 E : }
44 :
45 E : Minidump::~Minidump() {
46 E : }
47 :
48 E : Minidump::TypedMemoryList Minidump::GetMemoryList() const {
49 E : return TypedMemoryList(*this, MemoryListStream);
50 E : }
51 :
52 E : Minidump::TypedModuleList Minidump::GetModuleList() const {
53 E : return TypedModuleList(*this, ModuleListStream);
54 E : }
55 :
56 E : Minidump::TypedThreadList Minidump::GetThreadList() const {
57 E : return TypedThreadList(*this, ThreadListStream);
58 E : }
59 :
60 : Minidump::TypedThreadExList Minidump::GetThreadExList() const {
61 : return TypedThreadExList(*this, ThreadExListStream);
62 : }
63 :
64 E : bool Minidump::ReadDirectory() {
65 : // Read the header and validate the signature.
66 E : MINIDUMP_HEADER header = {};
67 E : if (!ReadBytes(0, sizeof(header), &header))
68 E : return false;
69 :
70 E : if (header.Signature != MINIDUMP_SIGNATURE || header.NumberOfStreams == 0) {
71 E : return false;
72 : }
73 :
74 E : directory_.resize(header.NumberOfStreams);
75 E : if (!ReadBytes(header.StreamDirectoryRva,
76 : header.NumberOfStreams * sizeof(directory_[0]),
77 : &directory_.at(0))) {
78 E : return false;
79 : }
80 :
81 E : return true;
82 E : }
83 :
84 E : bool FileMinidump::Open(const base::FilePath& path) {
85 E : file_.reset(base::OpenFile(path, "rb"));
86 E : if (!file_)
87 E : return false;
88 :
89 E : return ReadDirectory();
90 E : }
91 :
92 : Minidump::Stream Minidump::GetStreamFor(
93 E : const MINIDUMP_LOCATION_DESCRIPTOR& location) const {
94 E : return Stream(this, location.Rva, location.DataSize, kNoStreamId);
95 E : }
96 :
97 E : Minidump::Stream Minidump::GetStream(size_t stream_id) const {
98 E : DCHECK_GT(directory_.size(), stream_id);
99 E : const MINIDUMP_DIRECTORY& dir_entry = directory_[stream_id];
100 :
101 E : return Stream(this, dir_entry.Location.Rva, dir_entry.Location.DataSize,
102 : stream_id);
103 E : }
104 :
105 : Minidump::Stream Minidump::FindNextStream(const Stream* prev,
106 E : size_t stream_type) const {
107 E : size_t start = prev ? prev->stream_id() + 1 : 0;
108 :
109 E : for (size_t id = start; id < directory_.size(); ++id) {
110 E : if (directory_[id].StreamType == stream_type)
111 E : return GetStream(id);
112 E : }
113 :
114 : // Not found, return an invalid stream.
115 E : return Stream();
116 E : }
117 :
118 : bool FileMinidump::ReadBytes(size_t offset,
119 : size_t data_size,
120 E : void* data) const {
121 E : DCHECK_LE(offset, static_cast<size_t>(std::numeric_limits<long>::max()));
122 E : if (fseek(file_.get(), static_cast<long>(offset), SEEK_SET) != 0)
123 i : return false;
124 :
125 E : if (fread(data, 1, data_size, file_.get()) != data_size)
126 i : return false;
127 :
128 E : return true;
129 E : }
130 :
131 E : BufferMinidump::BufferMinidump() : buf_(nullptr), buf_len_(0) {
132 E : }
133 :
134 E : bool BufferMinidump::Initialize(const uint8_t* buf, size_t buf_len) {
135 E : DCHECK(buf);
136 :
137 E : buf_ = buf;
138 E : buf_len_ = buf_len;
139 :
140 E : return ReadDirectory();
141 E : }
142 :
143 : bool BufferMinidump::ReadBytes(size_t offset,
144 : size_t data_size,
145 E : void* data) const {
146 : // Bounds check the request.
147 E : if (offset >= buf_len_ || offset + data_size > buf_len_ ||
148 : offset + data_size < offset) { // Test for overflow.
149 E : return false;
150 : }
151 :
152 E : ::memcpy(data, buf_ + offset, data_size);
153 E : return true;
154 E : }
155 :
156 : Minidump::Stream::Stream()
157 E : : minidump_(nullptr),
158 E : current_offset_(0),
159 E : remaining_length_(0),
160 E : stream_id_(0) {
161 E : }
162 :
163 : Minidump::Stream::Stream(
164 : const Minidump* minidump, size_t offset, size_t length, size_t stream_id)
165 E : : minidump_(minidump),
166 E : current_offset_(offset),
167 E : remaining_length_(length),
168 E : stream_id_(stream_id) {
169 E : DCHECK_NE(static_cast<Minidump*>(nullptr), minidump);
170 E : }
171 :
172 E : bool Minidump::Stream::ReadAndAdvanceBytes(size_t data_len, void* data) {
173 E : return ReadBytes(data_len, data) && AdvanceBytes(data_len);
174 E : }
175 :
176 E : bool Minidump::Stream::ReadAndAdvanceBytes(size_t data_len, std::string* data) {
177 E : DCHECK(minidump_ != nullptr);
178 E : DCHECK(data != nullptr);
179 :
180 E : data->resize(data_len);
181 E : bool success = ReadAndAdvanceBytes(data_len, &data->at(0));
182 E : if (!success)
183 i : data->resize(0);
184 :
185 E : return success;
186 E : }
187 :
188 E : bool Minidump::Stream::ReadAndAdvanceString(std::wstring* data) {
189 E : DCHECK(minidump_ != nullptr);
190 E : DCHECK(data != nullptr);
191 :
192 E : ULONG32 size_bytes = 0U;
193 E : if (!ReadAndAdvanceElement(&size_bytes))
194 i : return false;
195 :
196 : // Increment to account for (consume) null-terminating character.
197 E : size_bytes += sizeof(wchar_t);
198 E : if (size_bytes % sizeof(wchar_t))
199 i : return false;
200 E : size_t num_characters = size_bytes / sizeof(wchar_t);
201 :
202 E : std::wstring buffer;
203 E : buffer.resize(num_characters);
204 E : if (!ReadAndAdvanceBytes(size_bytes, &buffer.at(0)))
205 i : return false;
206 :
207 : // Drop the extra null-terminating character.
208 E : buffer.resize(num_characters - 1);
209 E : buffer.swap(*data);
210 E : return true;
211 E : }
212 :
213 E : bool Minidump::Stream::ReadBytes(size_t data_len, void* data) {
214 E : DCHECK(minidump_ != nullptr);
215 :
216 E : if (data_len > remaining_length_)
217 E : return false;
218 :
219 E : if (!minidump_->ReadBytes(current_offset_, data_len, data))
220 i : return false;
221 :
222 E : return true;
223 E : }
224 :
225 E : bool Minidump::Stream::AdvanceBytes(size_t data_len) {
226 E : if (data_len > remaining_length_)
227 i : return false;
228 :
229 E : current_offset_ += data_len;
230 E : remaining_length_ -= data_len;
231 :
232 E : return true;
233 E : }
234 :
235 : } // namespace minidump
|