Index: components/browser_watcher/postmortem_minidump_writer_win.cc |
diff --git a/components/browser_watcher/postmortem_minidump_writer_win.cc b/components/browser_watcher/postmortem_minidump_writer_win.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6994573bc3918e9e2bdf28e5a31c17e3a352f0c9 |
--- /dev/null |
+++ b/components/browser_watcher/postmortem_minidump_writer_win.cc |
@@ -0,0 +1,111 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+// |
+// Note: aside from using windows headers to obtain the definitions of minidump |
+// structures, nothing here is windows specific. This seems like the best |
+// approach given this code is for tempory experimentation on Windows. |
scottmg
2016/08/03 22:47:06
temporary
manzagop (departed)
2016/08/10 15:59:52
Done.
|
+// Longer term, CrashPad will take over the minidump writing in this case as |
+// well. |
+ |
+#include "components/browser_watcher/postmortem_minidump_writer.h" |
+ |
+#include <windows.h> // NOLINT |
+#include <dbghelp.h> |
+ |
+#include <string> |
+ |
+#include "base/files/file_util.h" |
+#include "base/numerics/safe_math.h" |
+ |
+namespace browser_watcher { |
+ |
+// The stream type assigned to the minidump stream that holds the serialized |
+// stability report. |
+// Note: the value was obtained by adding 1 to the stream type used for holding |
+// the SyzyAsan proto. |
+// TODO(manzagop): centralize the stream type definitions to avoid issues. |
+const uint32_t kStabilityReportStreamType = 0x4B6B0002; |
scottmg
2016/08/03 22:47:06
(Kk02... "K"as"k"o lives on, I guess?
manzagop (departed)
2016/08/10 15:59:52
Yeah, I really had no clue what value to use!
Is
|
+ |
+PostmortemMinidumpWriter::PostmortemMinidumpWriter() : cursor_(0U) {} |
+ |
+bool PostmortemMinidumpWriter::WriteDump(const base::FilePath& mindump_path, |
+ const StabilityReport& report) { |
+ // Open the minidump file. |
+ minidump_.reset(base::OpenFile(mindump_path, "wb")); |
+ if (minidump_.get() == nullptr) |
+ return false; |
scottmg
2016/08/03 22:47:06
Is it useful to log on any of these failures? Or i
manzagop (departed)
2016/08/10 15:59:52
Totally! It's a major TODO to sprinkle some UMA re
|
+ |
+ // Allocate space for the header. |
+ Position pos = 0U; |
+ if (!Allocate(sizeof(MINIDUMP_HEADER), &pos)) |
+ return false; |
+ DCHECK_EQ(kHeaderPos, pos); |
+ |
+ // Write the proto to the file. |
+ std::string serialized_report; |
+ report.SerializeToString(&serialized_report); |
+ Position report_pos = 0U; |
+ if (!AppendBytes(serialized_report, &report_pos)) |
+ return false; |
+ |
+ // Write the directory entry for the stability report's stream. |
scottmg
2016/08/03 22:47:06
As Mark described, you'll have to add keys for the
manzagop (departed)
2016/08/10 15:59:52
Done. I added product and version. Hopefully corre
|
+ MINIDUMP_DIRECTORY report_directory = {0}; |
+ report_directory.StreamType = kStabilityReportStreamType; |
+ report_directory.Location.Rva = report_pos; |
+ report_directory.Location.DataSize = serialized_report.length(); |
+ Position directory_pos = 0U; |
+ if (!Append(report_directory, &directory_pos)) |
+ return false; |
+ |
+ // Write the header. |
+ MINIDUMP_HEADER header; |
+ header.Signature = MINIDUMP_SIGNATURE; |
+ header.NumberOfStreams = 1; |
+ header.StreamDirectoryRva = directory_pos; |
+ return Write(kHeaderPos, header); |
+} |
+ |
+bool PostmortemMinidumpWriter::Allocate(size_t size_bytes, Position* pos) { |
+ DCHECK(pos); |
+ *pos = cursor_; |
+ return IncrementCursor(size_bytes); |
+} |
+ |
+bool PostmortemMinidumpWriter::WriteBytes(Position pos, |
+ size_t size_bytes, |
+ const void* data) { |
+ DCHECK(data); |
+ DCHECK(minidump_.get()); |
+ |
+ // Validate the write does not extend past the cursor. |
+ base::CheckedNumeric<Position> pos_end = pos; |
+ pos_end += size_bytes; |
+ if (!pos_end.IsValid() || pos_end.ValueOrDie() > cursor_) |
+ return false; |
+ |
+ // Seek and write. |
+ if (fseek(minidump_.get(), pos, SEEK_SET) != 0) |
+ return false; |
+ return fwrite(data, sizeof(char), size_bytes, minidump_.get()) == size_bytes; |
+} |
+ |
+bool PostmortemMinidumpWriter::AppendBytes(base::StringPiece data, |
+ Position* pos) { |
+ DCHECK(pos); |
+ if (!Allocate(data.length(), pos)) |
+ return false; |
+ return WriteBytes(*pos, data.length(), data.data()); |
+} |
+ |
+bool PostmortemMinidumpWriter::IncrementCursor(size_t size_bytes) { |
+ base::CheckedNumeric<Position> cur = cursor_; |
+ cur += size_bytes; |
+ if (!cur.IsValid()) |
+ return false; |
+ |
+ cursor_ += size_bytes; |
+ return true; |
+} |
+ |
+} // namespace browser_watcher |