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 E : Minidump::Minidump() {
23 E : }
24 :
25 E : Minidump::~Minidump() {
26 E : }
27 :
28 E : bool Minidump::Open(const base::FilePath& path) {
29 E : file_.reset(base::OpenFile(path, "rb"));
30 :
31 E : if (!file_)
32 E : return false;
33 :
34 : // Read the header and validate the signature.
35 E : MINIDUMP_HEADER header = {};
36 E : if (!ReadBytes(0, sizeof(header), &header))
37 E : return false;
38 :
39 E : if (header.Signature != MINIDUMP_SIGNATURE || header.NumberOfStreams == 0) {
40 E : return false;
41 : }
42 :
43 E : directory_.resize(header.NumberOfStreams);
44 : if (!ReadBytes(header.StreamDirectoryRva,
45 : header.NumberOfStreams * sizeof(directory_[0]),
46 E : &directory_.at(0))) {
47 E : return false;
48 : }
49 :
50 E : return true;
51 E : }
52 :
53 : Minidump::Stream Minidump::GetStreamFor(
54 E : const MINIDUMP_LOCATION_DESCRIPTOR& location) const {
55 E : return Stream(this, location.Rva, location.DataSize, kNoStreamId);
56 E : }
57 :
58 E : Minidump::Stream Minidump::GetStream(size_t stream_id) const {
59 E : DCHECK_GT(directory_.size(), stream_id);
60 E : const MINIDUMP_DIRECTORY& dir_entry = directory_[stream_id];
61 :
62 : return Stream(this, dir_entry.Location.Rva, dir_entry.Location.DataSize,
63 E : stream_id);
64 E : }
65 :
66 : Minidump::Stream Minidump::FindNextStream(const Stream* prev,
67 E : size_t stream_type) const {
68 E : size_t start = prev ? prev->stream_id() + 1 : 0;
69 :
70 E : for (size_t id = start; id < directory_.size(); ++id) {
71 E : if (directory_[id].StreamType == stream_type)
72 E : return GetStream(id);
73 E : }
74 :
75 : // Not found, return an invalid stream.
76 E : return Stream();
77 E : }
78 :
79 E : bool Minidump::ReadBytes(size_t offset, size_t data_size, void* data) const {
80 E : if (fseek(file_.get(), offset, SEEK_SET) != 0)
81 i : return false;
82 :
83 E : if (fread(data, 1, data_size, file_.get()) != data_size)
84 E : return false;
85 :
86 E : return true;
87 E : }
88 :
89 : Minidump::Stream::Stream()
90 : : minidump_(nullptr),
91 : current_offset_(0),
92 : remaining_length_(0),
93 E : stream_id_(0) {
94 E : }
95 :
96 : Minidump::Stream::Stream(
97 : const Minidump* minidump, size_t offset, size_t length, size_t stream_id)
98 : : minidump_(minidump),
99 : current_offset_(offset),
100 : remaining_length_(length),
101 E : stream_id_(stream_id) {
102 E : DCHECK_NE(static_cast<Minidump*>(nullptr), minidump);
103 E : }
104 :
105 E : bool Minidump::Stream::ReadBytes(size_t data_len, void* data) {
106 E : DCHECK(minidump_ != nullptr);
107 :
108 E : if (data_len > remaining_length_)
109 E : return false;
110 :
111 E : if (!minidump_->ReadBytes(current_offset_, data_len, data))
112 i : return false;
113 :
114 E : current_offset_ += data_len;
115 E : remaining_length_ -= data_len;
116 :
117 E : return true;
118 E : }
119 :
120 E : bool Minidump::Stream::ReadBytes(size_t data_len, std::string* data) {
121 E : DCHECK(minidump_ != nullptr);
122 E : DCHECK(data != nullptr);
123 :
124 E : data->resize(data_len);
125 E : bool success = ReadBytes(data_len, &data->at(0));
126 E : if (!success)
127 i : data->resize(0);
128 :
129 E : return success;
130 E : }
131 :
132 E : bool Minidump::Stream::ReadString(std::wstring* data) {
133 E : DCHECK(minidump_ != nullptr);
134 E : DCHECK(data != nullptr);
135 :
136 E : ULONG32 size_bytes = 0U;
137 E : if (!ReadElement(&size_bytes))
138 i : return false;
139 :
140 : // Increment to account for (consume) null-terminating character.
141 E : size_bytes += sizeof(wchar_t);
142 E : if (size_bytes % sizeof(wchar_t))
143 i : return false;
144 E : size_t num_characters = size_bytes / sizeof(wchar_t);
145 :
146 E : std::wstring buffer;
147 E : buffer.resize(num_characters);
148 E : if (!ReadBytes(size_bytes, &buffer.at(0)))
149 i : return false;
150 :
151 : // Drop the extra null-terminating character.
152 E : buffer.resize(num_characters - 1);
153 E : buffer.swap(*data);
154 E : return true;
155 E : }
156 :
157 : } // namespace minidump
|