OLD | NEW |
1 // Copyright 2014 The Crashpad Authors. All rights reserved. | 1 // Copyright 2014 The Crashpad Authors. All rights reserved. |
2 // | 2 // |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
4 // you may not use this file except in compliance with 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 | 5 // You may obtain a copy of the License at |
6 // | 6 // |
7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
8 // | 8 // |
9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
(...skipping 11 matching lines...) Expand all Loading... |
22 #include "minidump/minidump_exception_writer.h" | 22 #include "minidump/minidump_exception_writer.h" |
23 #include "minidump/minidump_handle_writer.h" | 23 #include "minidump/minidump_handle_writer.h" |
24 #include "minidump/minidump_memory_info_writer.h" | 24 #include "minidump/minidump_memory_info_writer.h" |
25 #include "minidump/minidump_memory_writer.h" | 25 #include "minidump/minidump_memory_writer.h" |
26 #include "minidump/minidump_misc_info_writer.h" | 26 #include "minidump/minidump_misc_info_writer.h" |
27 #include "minidump/minidump_module_writer.h" | 27 #include "minidump/minidump_module_writer.h" |
28 #include "minidump/minidump_system_info_writer.h" | 28 #include "minidump/minidump_system_info_writer.h" |
29 #include "minidump/minidump_thread_id_map.h" | 29 #include "minidump/minidump_thread_id_map.h" |
30 #include "minidump/minidump_thread_writer.h" | 30 #include "minidump/minidump_thread_writer.h" |
31 #include "minidump/minidump_unloaded_module_writer.h" | 31 #include "minidump/minidump_unloaded_module_writer.h" |
| 32 #include "minidump/minidump_user_extension_stream_data_source.h" |
32 #include "minidump/minidump_user_stream_writer.h" | 33 #include "minidump/minidump_user_stream_writer.h" |
33 #include "minidump/minidump_writer_util.h" | 34 #include "minidump/minidump_writer_util.h" |
34 #include "snapshot/exception_snapshot.h" | 35 #include "snapshot/exception_snapshot.h" |
35 #include "snapshot/module_snapshot.h" | 36 #include "snapshot/module_snapshot.h" |
36 #include "snapshot/process_snapshot.h" | 37 #include "snapshot/process_snapshot.h" |
37 #include "util/file/file_writer.h" | 38 #include "util/file/file_writer.h" |
38 #include "util/numeric/safe_assignment.h" | 39 #include "util/numeric/safe_assignment.h" |
39 | 40 |
40 namespace crashpad { | 41 namespace crashpad { |
41 | 42 |
(...skipping 25 matching lines...) Expand all Loading... |
67 // done by MinidumpMiscInfoWriter::InitializeFromSnapshot(). Handling both | 68 // done by MinidumpMiscInfoWriter::InitializeFromSnapshot(). Handling both |
68 // timestamps in the same way allows the highest-fidelity computation of | 69 // timestamps in the same way allows the highest-fidelity computation of |
69 // process uptime as the difference between the two values. | 70 // process uptime as the difference between the two values. |
70 timeval snapshot_time; | 71 timeval snapshot_time; |
71 process_snapshot->SnapshotTime(&snapshot_time); | 72 process_snapshot->SnapshotTime(&snapshot_time); |
72 SetTimestamp(snapshot_time.tv_sec); | 73 SetTimestamp(snapshot_time.tv_sec); |
73 | 74 |
74 const SystemSnapshot* system_snapshot = process_snapshot->System(); | 75 const SystemSnapshot* system_snapshot = process_snapshot->System(); |
75 auto system_info = base::WrapUnique(new MinidumpSystemInfoWriter()); | 76 auto system_info = base::WrapUnique(new MinidumpSystemInfoWriter()); |
76 system_info->InitializeFromSnapshot(system_snapshot); | 77 system_info->InitializeFromSnapshot(system_snapshot); |
77 AddStream(std::move(system_info)); | 78 bool add_stream_result = AddStream(std::move(system_info)); |
| 79 DCHECK(add_stream_result); |
78 | 80 |
79 auto misc_info = base::WrapUnique(new MinidumpMiscInfoWriter()); | 81 auto misc_info = base::WrapUnique(new MinidumpMiscInfoWriter()); |
80 misc_info->InitializeFromSnapshot(process_snapshot); | 82 misc_info->InitializeFromSnapshot(process_snapshot); |
81 AddStream(std::move(misc_info)); | 83 add_stream_result = AddStream(std::move(misc_info)); |
| 84 DCHECK(add_stream_result); |
82 | 85 |
83 auto memory_list = base::WrapUnique(new MinidumpMemoryListWriter()); | 86 auto memory_list = base::WrapUnique(new MinidumpMemoryListWriter()); |
84 auto thread_list = base::WrapUnique(new MinidumpThreadListWriter()); | 87 auto thread_list = base::WrapUnique(new MinidumpThreadListWriter()); |
85 thread_list->SetMemoryListWriter(memory_list.get()); | 88 thread_list->SetMemoryListWriter(memory_list.get()); |
86 MinidumpThreadIDMap thread_id_map; | 89 MinidumpThreadIDMap thread_id_map; |
87 thread_list->InitializeFromSnapshot(process_snapshot->Threads(), | 90 thread_list->InitializeFromSnapshot(process_snapshot->Threads(), |
88 &thread_id_map); | 91 &thread_id_map); |
89 AddStream(std::move(thread_list)); | 92 add_stream_result = AddStream(std::move(thread_list)); |
| 93 DCHECK(add_stream_result); |
90 | 94 |
91 const ExceptionSnapshot* exception_snapshot = process_snapshot->Exception(); | 95 const ExceptionSnapshot* exception_snapshot = process_snapshot->Exception(); |
92 if (exception_snapshot) { | 96 if (exception_snapshot) { |
93 auto exception = base::WrapUnique(new MinidumpExceptionWriter()); | 97 auto exception = base::WrapUnique(new MinidumpExceptionWriter()); |
94 exception->InitializeFromSnapshot(exception_snapshot, thread_id_map); | 98 exception->InitializeFromSnapshot(exception_snapshot, thread_id_map); |
95 AddStream(std::move(exception)); | 99 add_stream_result = AddStream(std::move(exception)); |
| 100 DCHECK(add_stream_result); |
96 } | 101 } |
97 | 102 |
98 auto module_list = base::WrapUnique(new MinidumpModuleListWriter()); | 103 auto module_list = base::WrapUnique(new MinidumpModuleListWriter()); |
99 module_list->InitializeFromSnapshot(process_snapshot->Modules()); | 104 module_list->InitializeFromSnapshot(process_snapshot->Modules()); |
100 AddStream(std::move(module_list)); | 105 add_stream_result = AddStream(std::move(module_list)); |
101 | 106 DCHECK(add_stream_result); |
102 for (const auto& module : process_snapshot->Modules()) { | |
103 for (const UserMinidumpStream* stream : module->CustomMinidumpStreams()) { | |
104 auto user_stream = base::WrapUnique(new MinidumpUserStreamWriter()); | |
105 user_stream->InitializeFromSnapshot(stream); | |
106 AddStream(std::move(user_stream)); | |
107 } | |
108 } | |
109 | 107 |
110 auto unloaded_modules = process_snapshot->UnloadedModules(); | 108 auto unloaded_modules = process_snapshot->UnloadedModules(); |
111 if (!unloaded_modules.empty()) { | 109 if (!unloaded_modules.empty()) { |
112 auto unloaded_module_list = | 110 auto unloaded_module_list = |
113 base::WrapUnique(new MinidumpUnloadedModuleListWriter()); | 111 base::WrapUnique(new MinidumpUnloadedModuleListWriter()); |
114 unloaded_module_list->InitializeFromSnapshot(unloaded_modules); | 112 unloaded_module_list->InitializeFromSnapshot(unloaded_modules); |
115 AddStream(std::move(unloaded_module_list)); | 113 add_stream_result = AddStream(std::move(unloaded_module_list)); |
| 114 DCHECK(add_stream_result); |
116 } | 115 } |
117 | 116 |
118 auto crashpad_info = base::WrapUnique(new MinidumpCrashpadInfoWriter()); | 117 auto crashpad_info = base::WrapUnique(new MinidumpCrashpadInfoWriter()); |
119 crashpad_info->InitializeFromSnapshot(process_snapshot); | 118 crashpad_info->InitializeFromSnapshot(process_snapshot); |
120 | 119 |
121 // Since the MinidumpCrashpadInfo stream is an extension, it’s safe to not add | 120 // Since the MinidumpCrashpadInfo stream is an extension, it’s safe to not add |
122 // it to the minidump file if it wouldn’t carry any useful information. | 121 // it to the minidump file if it wouldn’t carry any useful information. |
123 if (crashpad_info->IsUseful()) { | 122 if (crashpad_info->IsUseful()) { |
124 AddStream(std::move(crashpad_info)); | 123 add_stream_result = AddStream(std::move(crashpad_info)); |
| 124 DCHECK(add_stream_result); |
125 } | 125 } |
126 | 126 |
127 std::vector<const MemoryMapRegionSnapshot*> memory_map_snapshot = | 127 std::vector<const MemoryMapRegionSnapshot*> memory_map_snapshot = |
128 process_snapshot->MemoryMap(); | 128 process_snapshot->MemoryMap(); |
129 if (!memory_map_snapshot.empty()) { | 129 if (!memory_map_snapshot.empty()) { |
130 auto memory_info_list = | 130 auto memory_info_list = |
131 base::WrapUnique(new MinidumpMemoryInfoListWriter()); | 131 base::WrapUnique(new MinidumpMemoryInfoListWriter()); |
132 memory_info_list->InitializeFromSnapshot(memory_map_snapshot); | 132 memory_info_list->InitializeFromSnapshot(memory_map_snapshot); |
133 AddStream(std::move(memory_info_list)); | 133 add_stream_result = AddStream(std::move(memory_info_list)); |
| 134 DCHECK(add_stream_result); |
134 } | 135 } |
135 | 136 |
136 std::vector<HandleSnapshot> handles_snapshot = process_snapshot->Handles(); | 137 std::vector<HandleSnapshot> handles_snapshot = process_snapshot->Handles(); |
137 if (!handles_snapshot.empty()) { | 138 if (!handles_snapshot.empty()) { |
138 auto handle_data_writer = base::WrapUnique(new MinidumpHandleDataWriter()); | 139 auto handle_data_writer = base::WrapUnique(new MinidumpHandleDataWriter()); |
139 handle_data_writer->InitializeFromSnapshot(handles_snapshot); | 140 handle_data_writer->InitializeFromSnapshot(handles_snapshot); |
140 AddStream(std::move(handle_data_writer)); | 141 add_stream_result = AddStream(std::move(handle_data_writer)); |
| 142 DCHECK(add_stream_result); |
141 } | 143 } |
142 | 144 |
143 memory_list->AddFromSnapshot(process_snapshot->ExtraMemory()); | 145 memory_list->AddFromSnapshot(process_snapshot->ExtraMemory()); |
144 if (exception_snapshot) | 146 if (exception_snapshot) { |
145 memory_list->AddFromSnapshot(exception_snapshot->ExtraMemory()); | 147 memory_list->AddFromSnapshot(exception_snapshot->ExtraMemory()); |
| 148 } |
146 | 149 |
147 AddStream(std::move(memory_list)); | 150 // These user streams must be added last. Otherwise, a user stream with the |
| 151 // same type as a well-known stream could preempt the well-known stream. As it |
| 152 // stands now, earlier-discovered user streams can still preempt |
| 153 // later-discovered ones. The well-known memory list stream is added after |
| 154 // these user streams, but only with a check here to avoid adding a user |
| 155 // stream that would preempt the memory list stream. |
| 156 for (const auto& module : process_snapshot->Modules()) { |
| 157 for (const UserMinidumpStream* stream : module->CustomMinidumpStreams()) { |
| 158 if (stream->stream_type() == kMinidumpStreamTypeMemoryList) { |
| 159 LOG(WARNING) << "discarding duplicate stream of type " |
| 160 << stream->stream_type(); |
| 161 continue; |
| 162 } |
| 163 auto user_stream = base::WrapUnique(new MinidumpUserStreamWriter()); |
| 164 user_stream->InitializeFromSnapshot(stream); |
| 165 AddStream(std::move(user_stream)); |
| 166 } |
| 167 } |
| 168 |
| 169 // The memory list stream should be added last. This keeps the “extra memory” |
| 170 // at the end so that if the minidump file is truncated, other, more critical |
| 171 // data is more likely to be preserved. Note that non-“extra” memory regions |
| 172 // will not have to ride at the end of the file. Thread stack memory, for |
| 173 // example, exists as a children of threads, and appears alongside them in the |
| 174 // file, despite also being mentioned by the memory list stream. |
| 175 add_stream_result = AddStream(std::move(memory_list)); |
| 176 DCHECK(add_stream_result); |
148 } | 177 } |
149 | 178 |
150 void MinidumpFileWriter::SetTimestamp(time_t timestamp) { | 179 void MinidumpFileWriter::SetTimestamp(time_t timestamp) { |
151 DCHECK_EQ(state(), kStateMutable); | 180 DCHECK_EQ(state(), kStateMutable); |
152 | 181 |
153 internal::MinidumpWriterUtil::AssignTimeT(&header_.TimeDateStamp, timestamp); | 182 internal::MinidumpWriterUtil::AssignTimeT(&header_.TimeDateStamp, timestamp); |
154 } | 183 } |
155 | 184 |
156 void MinidumpFileWriter::AddStream( | 185 bool MinidumpFileWriter::AddStream( |
157 std::unique_ptr<internal::MinidumpStreamWriter> stream) { | 186 std::unique_ptr<internal::MinidumpStreamWriter> stream) { |
158 DCHECK_EQ(state(), kStateMutable); | 187 DCHECK_EQ(state(), kStateMutable); |
159 | 188 |
160 MinidumpStreamType stream_type = stream->StreamType(); | 189 MinidumpStreamType stream_type = stream->StreamType(); |
161 | 190 |
162 auto rv = stream_types_.insert(stream_type); | 191 auto rv = stream_types_.insert(stream_type); |
163 CHECK(rv.second) << "stream_type " << stream_type << " already present"; | 192 if (!rv.second) { |
| 193 LOG(WARNING) << "discarding duplicate stream of type " << stream_type; |
| 194 return false; |
| 195 } |
164 | 196 |
165 streams_.push_back(stream.release()); | 197 streams_.push_back(stream.release()); |
166 | 198 |
167 DCHECK_EQ(streams_.size(), stream_types_.size()); | 199 DCHECK_EQ(streams_.size(), stream_types_.size()); |
| 200 return true; |
| 201 } |
| 202 |
| 203 bool MinidumpFileWriter::AddUserExtensionStream( |
| 204 std::unique_ptr<MinidumpUserExtensionStreamDataSource> |
| 205 user_extension_stream_data) { |
| 206 DCHECK_EQ(state(), kStateMutable); |
| 207 |
| 208 auto user_stream = base::WrapUnique(new MinidumpUserStreamWriter()); |
| 209 user_stream->InitializeFromBuffer(user_extension_stream_data->stream_type(), |
| 210 user_extension_stream_data->buffer(), |
| 211 user_extension_stream_data->buffer_size()); |
| 212 |
| 213 return AddStream(std::move(user_stream)); |
168 } | 214 } |
169 | 215 |
170 bool MinidumpFileWriter::WriteEverything(FileWriterInterface* file_writer) { | 216 bool MinidumpFileWriter::WriteEverything(FileWriterInterface* file_writer) { |
171 DCHECK_EQ(state(), kStateMutable); | 217 DCHECK_EQ(state(), kStateMutable); |
172 | 218 |
173 FileOffset start_offset = file_writer->Seek(0, SEEK_CUR); | 219 FileOffset start_offset = file_writer->Seek(0, SEEK_CUR); |
174 if (start_offset < 0) { | 220 if (start_offset < 0) { |
175 return false; | 221 return false; |
176 } | 222 } |
177 | 223 |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
265 for (internal::MinidumpStreamWriter* stream : streams_) { | 311 for (internal::MinidumpStreamWriter* stream : streams_) { |
266 iov.iov_base = stream->DirectoryListEntry(); | 312 iov.iov_base = stream->DirectoryListEntry(); |
267 iov.iov_len = sizeof(MINIDUMP_DIRECTORY); | 313 iov.iov_len = sizeof(MINIDUMP_DIRECTORY); |
268 iovecs.push_back(iov); | 314 iovecs.push_back(iov); |
269 } | 315 } |
270 | 316 |
271 return file_writer->WriteIoVec(&iovecs); | 317 return file_writer->WriteIoVec(&iovecs); |
272 } | 318 } |
273 | 319 |
274 } // namespace crashpad | 320 } // namespace crashpad |
OLD | NEW |