Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2014 The Crashpad Authors. 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 "minidump/minidump_file_writer.h" | |
| 16 | |
| 17 #include "base/logging.h" | |
| 18 #include "minidump/minidump_writer_util.h" | |
| 19 #include "util/numeric/safe_assignment.h" | |
| 20 | |
| 21 namespace crashpad { | |
| 22 | |
| 23 MinidumpFileWriter::MinidumpFileWriter() | |
| 24 : MinidumpWritable(), header_(), streams_(), stream_types_() { | |
| 25 // Don’t set the signature field right away. Leave it set to 0, so that a | |
| 26 // partially-written minidump file isn’t confused for a complete and valid | |
| 27 // one. The header will be rewritten in WriteToFile(). | |
| 28 header_.Signature = 0; | |
| 29 | |
| 30 header_.Version = MINIDUMP_VERSION; | |
| 31 header_.CheckSum = 0; | |
| 32 header_.Flags = MiniDumpNormal; | |
| 33 } | |
| 34 | |
| 35 MinidumpFileWriter::~MinidumpFileWriter() { | |
| 36 } | |
| 37 | |
| 38 void MinidumpFileWriter::SetTimestamp(time_t timestamp) { | |
| 39 DCHECK_EQ(state(), kStateMutable); | |
| 40 | |
| 41 internal::MinidumpWriterUtil::AssignTimeT(&header_.TimeDateStamp, timestamp); | |
| 42 } | |
| 43 | |
| 44 void MinidumpFileWriter::AddStream(internal::MinidumpStreamWriter* stream) { | |
| 45 DCHECK_EQ(state(), kStateMutable); | |
| 46 | |
| 47 MinidumpStreamType stream_type = stream->StreamType(); | |
| 48 | |
| 49 auto rv = stream_types_.insert(stream_type); | |
| 50 CHECK(rv.second) << "stream_type " << stream_type << " already present"; | |
| 51 | |
| 52 streams_.push_back(stream); | |
| 53 | |
| 54 DCHECK_EQ(streams_.size(), stream_types_.size()); | |
| 55 } | |
| 56 | |
| 57 bool MinidumpFileWriter::WriteEverything(FileWriterInterface* file_writer) { | |
| 58 DCHECK_EQ(state(), kStateMutable); | |
| 59 | |
| 60 off_t start_offset = file_writer->Seek(0, SEEK_CUR); | |
| 61 if (start_offset < 0) { | |
| 62 return false; | |
| 63 } | |
| 64 | |
| 65 if (!MinidumpWritable::WriteEverything(file_writer)) { | |
| 66 return false; | |
| 67 } | |
| 68 | |
| 69 off_t end_offset = file_writer->Seek(0, SEEK_CUR); | |
| 70 if (end_offset < 0) { | |
| 71 return false; | |
| 72 } | |
| 73 | |
| 74 // Now that the entire minidump file has been completely written, go back to | |
| 75 // the beginning and rewrite the header with the correct signature to identify | |
| 76 // it as a valid minidump file. | |
| 77 header_.Signature = MINIDUMP_SIGNATURE; | |
| 78 | |
| 79 if (file_writer->Seek(start_offset, SEEK_SET) != 0) { | |
| 80 return false; | |
| 81 } | |
| 82 | |
| 83 if (!file_writer->Write(&header_, sizeof(header_))) { | |
| 84 return false; | |
| 85 } | |
| 86 | |
| 87 // Seek back to the end of the file, in case some non-minidump content will be | |
| 88 // written to the file after the minidump content. | |
| 89 return file_writer->Seek(end_offset, SEEK_SET); | |
| 90 } | |
| 91 | |
| 92 bool MinidumpFileWriter::Freeze() { | |
| 93 DCHECK_EQ(state(), kStateMutable); | |
| 94 | |
| 95 if (!MinidumpWritable::Freeze()) { | |
| 96 return false; | |
| 97 } | |
| 98 | |
| 99 size_t stream_count = streams_.size(); | |
| 100 CHECK_EQ(stream_count, stream_types_.size()); | |
| 101 | |
| 102 if (!AssignIfInRange(&header_.NumberOfStreams, stream_count)) { | |
| 103 LOG(ERROR) << "stream_count " << stream_count << " out of range"; | |
| 104 return false; | |
| 105 } | |
| 106 | |
| 107 return true; | |
| 108 } | |
| 109 | |
| 110 size_t MinidumpFileWriter::SizeOfObject() { | |
| 111 DCHECK_GE(state(), kStateFrozen); | |
| 112 DCHECK_EQ(streams_.size(), stream_types_.size()); | |
| 113 | |
| 114 return sizeof(header_) + streams_.size() * sizeof(MINIDUMP_DIRECTORY); | |
| 115 } | |
| 116 | |
| 117 std::vector<internal::MinidumpWritable*> MinidumpFileWriter::Children() { | |
| 118 DCHECK_GE(state(), kStateFrozen); | |
| 119 DCHECK_EQ(streams_.size(), stream_types_.size()); | |
| 120 | |
| 121 std::vector<MinidumpWritable*> children; | |
|
Robert Sesek
2014/08/03 15:19:59
You're building a vector<MinidumpWritable*> yet th
Mark Mentovai
2014/08/03 20:14:10
rsesek wrote:
Robert Sesek
2014/08/03 21:20:55
Ack. I misread streams_ as MinidumpWritable* inste
| |
| 122 for (internal::MinidumpStreamWriter* stream : streams_) { | |
| 123 children.push_back(stream); | |
| 124 } | |
| 125 | |
| 126 return children; | |
| 127 } | |
| 128 | |
| 129 bool MinidumpFileWriter::WillWriteAtOffsetImpl(off_t offset) { | |
| 130 DCHECK_EQ(state(), kStateFrozen); | |
| 131 DCHECK_EQ(offset, 0); | |
| 132 DCHECK_EQ(streams_.size(), stream_types_.size()); | |
| 133 | |
| 134 auto directory_offset = streams_.empty() ? 0 : offset + sizeof(header_); | |
| 135 if (!AssignIfInRange(&header_.StreamDirectoryRva, directory_offset)) { | |
| 136 LOG(ERROR) << "offset " << directory_offset << " out of range"; | |
| 137 return false; | |
| 138 } | |
| 139 | |
| 140 return MinidumpWritable::WillWriteAtOffsetImpl(offset); | |
| 141 } | |
| 142 | |
| 143 bool MinidumpFileWriter::WriteObject(FileWriterInterface* file_writer) { | |
| 144 DCHECK_EQ(state(), kStateWritable); | |
| 145 DCHECK_EQ(streams_.size(), stream_types_.size()); | |
| 146 | |
| 147 WritableIoVec iov; | |
| 148 iov.iov_base = &header_; | |
| 149 iov.iov_len = sizeof(header_); | |
| 150 std::vector<WritableIoVec> iovecs(1, iov); | |
| 151 | |
| 152 if (!streams_.empty()) { | |
| 153 iov.iov_len = sizeof(MINIDUMP_DIRECTORY); | |
|
Robert Sesek
2014/08/03 15:19:59
If you moved this into the loop body, you could re
| |
| 154 for (internal::MinidumpStreamWriter* stream : streams_) { | |
| 155 iov.iov_base = stream->DirectoryListEntry(); | |
| 156 iovecs.push_back(iov); | |
| 157 } | |
| 158 } | |
| 159 | |
| 160 return file_writer->WriteIoVec(&iovecs); | |
| 161 } | |
| 162 | |
| 163 } // namespace crashpad | |
| OLD | NEW |