diff --git a/snapshot/win/process_reader_win.cc b/snapshot/win/process_reader_win.cc index c0a3c56b..84e176b8 100644 --- a/snapshot/win/process_reader_win.cc +++ b/snapshot/win/process_reader_win.cc @@ -15,6 +15,7 @@ #include "snapshot/win/process_reader_win.h" #include "base/numerics/safe_conversions.h" +#include "util/win/time.h" namespace crashpad { @@ -54,6 +55,28 @@ bool ProcessReaderWin::ReadMemory(WinVMAddress at, return true; } +bool ProcessReaderWin::StartTime(timeval* start_time) const { + FILETIME creation, exit, kernel, user; + if (!GetProcessTimes(process_, &creation, &exit, &kernel, &user)) { + PLOG(ERROR) << "GetProcessTimes"; + return false; + } + *start_time = FiletimeToTimevalEpoch(creation); + return true; +} + +bool ProcessReaderWin::CPUTimes(timeval* user_time, + timeval* system_time) const { + FILETIME creation, exit, kernel, user; + if (!GetProcessTimes(process_, &creation, &exit, &kernel, &user)) { + PLOG(ERROR) << "GetProcessTimes"; + return false; + } + *user_time = FiletimeToTimevalInterval(user); + *system_time = FiletimeToTimevalInterval(kernel); + return true; +} + const std::vector& ProcessReaderWin::Modules() { INITIALIZATION_STATE_DCHECK_VALID(initialized_); diff --git a/snapshot/win/process_reader_win.h b/snapshot/win/process_reader_win.h index b570a5e8..ff687885 100644 --- a/snapshot/win/process_reader_win.h +++ b/snapshot/win/process_reader_win.h @@ -15,6 +15,7 @@ #ifndef CRASHPAD_SNAPSHOT_WIN_PROCESS_READER_WIN_H_ #define CRASHPAD_SNAPSHOT_WIN_PROCESS_READER_WIN_H_ +#include #include #include "util/misc/initialization_state_dcheck.h" @@ -48,6 +49,23 @@ class ProcessReaderWin { bool ReadMemory(WinVMAddress at, WinVMSize num_bytes, void* into); + //! \brief Determines the target process' start time. + //! + //! \param[out] start_time The time that the process started. + //! + //! \return `true` on success, `false` on failure, with a warning logged. + bool StartTime(timeval* start_time) const; + + //! \brief Determines the target process' execution time. + //! + //! \param[out] user_time The amount of time the process has executed code in + //! user mode. + //! \param[out] system_time The amount of time the process has executed code + //! in kernel mode. + //! + //! \return `true` on success, `false` on failure, with a warning logged. + bool CPUTimes(timeval* user_time, timeval* system_time) const; + //! \return The modules loaded in the process. The first element (at index //! `0`) corresponds to the main executable. const std::vector& Modules(); diff --git a/snapshot/win/process_snapshot_win.cc b/snapshot/win/process_snapshot_win.cc index cf609610..16623069 100644 --- a/snapshot/win/process_snapshot_win.cc +++ b/snapshot/win/process_snapshot_win.cc @@ -99,12 +99,14 @@ void ProcessSnapshotWin::SnapshotTime(timeval* snapshot_time) const { } void ProcessSnapshotWin::ProcessStartTime(timeval* start_time) const { - CHECK(false) << "TODO(scottmg)"; + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + process_reader_.StartTime(start_time); } void ProcessSnapshotWin::ProcessCPUTimes(timeval* user_time, timeval* system_time) const { - CHECK(false) << "TODO(scottmg)"; + INITIALIZATION_STATE_DCHECK_VALID(initialized_); + process_reader_.CPUTimes(user_time, system_time); } void ProcessSnapshotWin::ReportID(UUID* report_id) const { diff --git a/util/win/time.cc b/util/win/time.cc index 1957b6c9..8e4760bb 100644 --- a/util/win/time.cc +++ b/util/win/time.cc @@ -15,15 +15,25 @@ #include "util/win/time.h" #include -#include #include "base/logging.h" namespace crashpad { -void GetTimeOfDay(timeval* tv) { - FILETIME filetime; - GetSystemTimeAsFileTime(&filetime); +namespace { + +const uint64_t kMicrosecondsPerSecond = static_cast(1E6); + +timeval MicrosecondsToTimeval(uint64_t t) { + timeval tv; + tv.tv_sec = static_cast(t / kMicrosecondsPerSecond); + tv.tv_usec = static_cast(t % kMicrosecondsPerSecond); + return tv; +} + +} // namespace + +timeval FiletimeToTimevalEpoch(const FILETIME& filetime) { uint64_t t = (static_cast(filetime.dwHighDateTime) << 32) | filetime.dwLowDateTime; t /= 10; // 100 nanosecond intervals to microseconds. @@ -32,11 +42,22 @@ void GetTimeOfDay(timeval* tv) { // day. It's not entirely clear, but it appears that these are solar seconds, // not SI seconds, so there are no leap seconds to be considered. const uint64_t kNumSecondsFrom1601To1970 = (369 * 365 + 89) * 86400ULL; - const uint64_t kMicrosecondsPerSecond = static_cast(1E6); DCHECK_GE(t, kNumSecondsFrom1601To1970 * kMicrosecondsPerSecond); t -= kNumSecondsFrom1601To1970 * kMicrosecondsPerSecond; - tv->tv_sec = static_cast(t / kMicrosecondsPerSecond); - tv->tv_usec = static_cast(t % kMicrosecondsPerSecond); + return MicrosecondsToTimeval(t); +} + +timeval FiletimeToTimevalInterval(const FILETIME& filetime) { + uint64_t t = (static_cast(filetime.dwHighDateTime) << 32) | + filetime.dwLowDateTime; + t /= 10; // 100 nanosecond intervals to microseconds. + return MicrosecondsToTimeval(t); +} + +void GetTimeOfDay(timeval* tv) { + FILETIME filetime; + GetSystemTimeAsFileTime(&filetime); + *tv = FiletimeToTimevalEpoch(filetime); } } // namespace crashpad diff --git a/util/win/time.h b/util/win/time.h index e61a8461..7cc0094f 100644 --- a/util/win/time.h +++ b/util/win/time.h @@ -16,9 +16,18 @@ #define CRASHPAD_UTIL_WIN_TIME_H_ #include +#include namespace crashpad { +//! \brief Convert Windows `FILETIME` to `timeval`, converting from Windows +//! epoch to POSIX epoch. +timeval FiletimeToTimevalEpoch(const FILETIME& filetime); + +//! \brief Convert Windows `FILETIME` to `timeval`, treating the values as +//! an interval of elapsed time. +timeval FiletimeToTimevalInterval(const FILETIME& filetime); + //! \brief Similar to POSIX gettimeofday(), gets the current system time in UTC. void GetTimeOfDay(timeval* tv);