dart-sdk/runtime/vm/os_win.cc
Tess Strickland dfce3aa0ff [vm] Attempt to retrieve build ID or UUID from the loaded snapshot.
For direct-to-ELF snapshots, the story remains the same as before,
as we use the information from the Image header if available.

If it isn't, then we fall back to dladdr to get the dynamic shared
object containing the app snapshot and then walk the ELF or Mach-O
headers to find the build ID or UUID information.

TEST=vm/dart/use_dwarf_stack_traces_flag

Issue: https://github.com/dart-lang/sdk/issues/51941
Change-Id: I3705ed244d1b4a1255e75fffd238a29fc2a60800
Cq-Include-Trybots: luci.dart.try:vm-aot-dwarf-linux-product-x64-try,vm-aot-linux-debug-simarm_x64-try,vm-aot-linux-debug-x64-try,vm-aot-linux-release-x64-try,vm-aot-mac-product-arm64-try,vm-aot-mac-release-arm64-try,vm-aot-mac-release-x64-try,vm-aot-linux-product-x64-try,vm-aot-win-release-x64-try,vm-aot-win-product-x64-try,vm-aot-win-debug-x64c-try,vm-aot-android-release-arm_x64-try,vm-aot-android-release-arm64c-try,vm-fuchsia-release-x64-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/306640
Reviewed-by: Slava Egorov <vegorov@google.com>
Commit-Queue: Tess Strickland <sstrickl@google.com>
2023-06-12 15:26:29 +00:00

356 lines
10 KiB
C++

// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/globals.h"
#if defined(DART_HOST_OS_WINDOWS)
#include "vm/os.h"
#include <malloc.h> // NOLINT
#include <process.h> // NOLINT
#include <psapi.h> // NOLINT
#include <time.h> // NOLINT
#include "platform/assert.h"
#include "platform/utils.h"
#include "vm/image_snapshot.h"
#include "vm/os_thread.h"
#include "vm/zone.h"
namespace dart {
// Defined in vm/os_thread_win.cc
extern bool private_flag_windows_run_tls_destructors;
intptr_t OS::ProcessId() {
return static_cast<intptr_t>(GetCurrentProcessId());
}
// As a side-effect sets the globals _timezone, _daylight and _tzname.
static bool LocalTime(int64_t seconds_since_epoch, tm* tm_result) {
time_t seconds = static_cast<time_t>(seconds_since_epoch);
if (seconds != seconds_since_epoch) {
return false;
}
// localtime_s implicitly sets _timezone, _daylight and _tzname.
errno_t error_code = localtime_s(tm_result, &seconds);
return error_code == 0;
}
static int GetDaylightSavingBiasInSeconds() {
TIME_ZONE_INFORMATION zone_information;
memset(&zone_information, 0, sizeof(zone_information));
if (GetTimeZoneInformation(&zone_information) == TIME_ZONE_ID_INVALID) {
// By default the daylight saving offset is an hour.
return -60 * 60;
} else {
return static_cast<int>(zone_information.DaylightBias * 60);
}
}
const char* OS::GetTimeZoneName(int64_t seconds_since_epoch) {
TIME_ZONE_INFORMATION zone_information;
memset(&zone_information, 0, sizeof(zone_information));
// Initialize and grab the time zone data.
_tzset();
DWORD status = GetTimeZoneInformation(&zone_information);
if (GetTimeZoneInformation(&zone_information) == TIME_ZONE_ID_INVALID) {
// If we can't get the time zone data, the Windows docs indicate that we
// are probably out of memory. Return an empty string.
return "";
}
// Figure out whether we're in standard or daylight.
bool daylight_savings = (status == TIME_ZONE_ID_DAYLIGHT);
if (status == TIME_ZONE_ID_UNKNOWN) {
tm local_time;
if (LocalTime(seconds_since_epoch, &local_time)) {
daylight_savings = (local_time.tm_isdst == 1);
}
}
// Convert the wchar string to a null-terminated utf8 string.
wchar_t* wchar_name = daylight_savings ? zone_information.DaylightName
: zone_information.StandardName;
intptr_t utf8_len = WideCharToMultiByte(CP_UTF8, 0, wchar_name, -1, nullptr,
0, nullptr, nullptr);
char* name = ThreadState::Current()->zone()->Alloc<char>(utf8_len + 1);
WideCharToMultiByte(CP_UTF8, 0, wchar_name, -1, name, utf8_len, nullptr,
nullptr);
name[utf8_len] = '\0';
return name;
}
int OS::GetTimeZoneOffsetInSeconds(int64_t seconds_since_epoch) {
tm decomposed;
// LocalTime will set _timezone.
bool succeeded = LocalTime(seconds_since_epoch, &decomposed);
if (succeeded) {
int inDaylightSavingsTime = decomposed.tm_isdst;
ASSERT(inDaylightSavingsTime == 0 || inDaylightSavingsTime == 1);
// Dart and Windows disagree on the sign of the bias.
int offset = static_cast<int>(-_timezone);
if (inDaylightSavingsTime == 1) {
static int daylight_bias = GetDaylightSavingBiasInSeconds();
// Subtract because windows and Dart disagree on the sign.
offset = offset - daylight_bias;
}
return offset;
} else {
// Return zero like V8 does.
return 0;
}
}
int64_t OS::GetCurrentTimeMillis() {
return GetCurrentTimeMicros() / 1000;
}
int64_t OS::GetCurrentTimeMicros() {
const int64_t kTimeEpoc = 116444736000000000LL;
const int64_t kTimeScaler = 10; // 100 ns to us.
// Although win32 uses 64-bit integers for representing timestamps,
// these are packed into a FILETIME structure. The FILETIME
// structure is just a struct representing a 64-bit integer. The
// TimeStamp union allows access to both a FILETIME and an integer
// representation of the timestamp. The Windows timestamp is in
// 100-nanosecond intervals since January 1, 1601.
union TimeStamp {
FILETIME ft_;
int64_t t_;
};
TimeStamp time;
GetSystemTimeAsFileTime(&time.ft_);
return (time.t_ - kTimeEpoc) / kTimeScaler;
}
static int64_t qpc_ticks_per_second = 0;
int64_t OS::GetCurrentMonotonicTicks() {
if (qpc_ticks_per_second == 0) {
// QueryPerformanceCounter not supported, fallback.
return GetCurrentTimeMicros();
}
// Grab performance counter value.
LARGE_INTEGER now;
QueryPerformanceCounter(&now);
return static_cast<int64_t>(now.QuadPart);
}
int64_t OS::GetCurrentMonotonicFrequency() {
if (qpc_ticks_per_second == 0) {
// QueryPerformanceCounter not supported, fallback.
return kMicrosecondsPerSecond;
}
return qpc_ticks_per_second;
}
int64_t OS::GetCurrentMonotonicMicros() {
int64_t ticks = GetCurrentMonotonicTicks();
int64_t frequency = GetCurrentMonotonicFrequency();
// Convert to microseconds.
int64_t seconds = ticks / frequency;
int64_t leftover_ticks = ticks - (seconds * frequency);
int64_t result = seconds * kMicrosecondsPerSecond;
result += ((leftover_ticks * kMicrosecondsPerSecond) / frequency);
return result;
}
int64_t OS::GetCurrentThreadCPUMicros() {
// TODO(johnmccutchan): Implement. See base/time_win.cc for details.
return -1;
}
int64_t OS::GetCurrentMonotonicMicrosForTimeline() {
#if defined(SUPPORT_TIMELINE)
return OS::GetCurrentMonotonicMicros();
#else
return -1;
#endif
}
intptr_t OS::ActivationFrameAlignment() {
#if defined(TARGET_ARCH_ARM64)
return 16;
#elif defined(TARGET_ARCH_ARM)
return 8;
#elif defined(_WIN64)
// Windows 64-bit ABI requires the stack to be 16-byte aligned.
return 16;
#else
// No requirements on Win32.
return 1;
#endif
}
int OS::NumberOfAvailableProcessors() {
SYSTEM_INFO info;
GetSystemInfo(&info);
return info.dwNumberOfProcessors;
}
void OS::Sleep(int64_t millis) {
::Sleep(millis);
}
void OS::SleepMicros(int64_t micros) {
// Windows only supports millisecond sleeps.
if (micros < kMicrosecondsPerMillisecond) {
// Calling ::Sleep with 0 has no determined behaviour, round up.
micros = kMicrosecondsPerMillisecond;
}
OS::Sleep(micros / kMicrosecondsPerMillisecond);
}
void OS::DebugBreak() {
#if defined(_MSC_VER)
// Microsoft Visual C/C++ or drop-in replacement.
__debugbreak();
#elif defined(__GCC__)
__builtin_trap();
#else
// Microsoft style assembly.
__asm {
int 3
}
#endif
}
DART_NOINLINE uintptr_t OS::GetProgramCounter() {
return reinterpret_cast<uintptr_t>(_ReturnAddress());
}
void OS::Print(const char* format, ...) {
va_list args;
va_start(args, format);
VFPrint(stdout, format, args);
va_end(args);
}
void OS::VFPrint(FILE* stream, const char* format, va_list args) {
vfprintf(stream, format, args);
fflush(stream);
}
char* OS::SCreate(Zone* zone, const char* format, ...) {
va_list args;
va_start(args, format);
char* buffer = VSCreate(zone, format, args);
va_end(args);
return buffer;
}
char* OS::VSCreate(Zone* zone, const char* format, va_list args) {
// Measure.
va_list measure_args;
va_copy(measure_args, args);
intptr_t len = Utils::VSNPrint(nullptr, 0, format, measure_args);
va_end(measure_args);
char* buffer;
if (zone) {
buffer = zone->Alloc<char>(len + 1);
} else {
buffer = reinterpret_cast<char*>(malloc(len + 1));
}
ASSERT(buffer != nullptr);
// Print.
va_list print_args;
va_copy(print_args, args);
Utils::VSNPrint(buffer, len + 1, format, print_args);
va_end(print_args);
return buffer;
}
bool OS::StringToInt64(const char* str, int64_t* value) {
ASSERT(str != nullptr && strlen(str) > 0 && value != nullptr);
int32_t base = 10;
char* endptr;
int i = 0;
if (str[0] == '-') {
i = 1;
} else if (str[0] == '+') {
i = 1;
}
if ((str[i] == '0') && (str[i + 1] == 'x' || str[i + 1] == 'X') &&
(str[i + 2] != '\0')) {
base = 16;
}
errno = 0;
if (base == 16) {
// Unsigned 64-bit hexadecimal integer literals are allowed but
// immediately interpreted as signed 64-bit integers.
*value = static_cast<int64_t>(_strtoui64(str, &endptr, base));
} else {
*value = _strtoi64(str, &endptr, base);
}
return ((errno == 0) && (endptr != str) && (*endptr == 0));
}
void OS::RegisterCodeObservers() {}
void OS::PrintErr(const char* format, ...) {
va_list args;
va_start(args, format);
VFPrint(stderr, format, args);
va_end(args);
}
void OS::Init() {
static bool init_once_called = false;
if (init_once_called) {
return;
}
init_once_called = true;
// Do not pop up a message box when abort is called.
_set_abort_behavior(0, _WRITE_ABORT_MSG);
ThreadLocalData::Init();
LARGE_INTEGER ticks_per_sec;
if (!QueryPerformanceFrequency(&ticks_per_sec)) {
qpc_ticks_per_second = 0;
} else {
qpc_ticks_per_second = static_cast<int64_t>(ticks_per_sec.QuadPart);
}
}
void OS::Cleanup() {
// TODO(zra): Enable once VM can shutdown cleanly.
// ThreadLocalData::Cleanup();
}
void OS::PrepareToAbort() {
// TODO(zra): Remove once VM shuts down cleanly.
private_flag_windows_run_tls_destructors = false;
}
void OS::Abort() {
PrepareToAbort();
abort();
}
void OS::Exit(int code) {
// TODO(zra): Remove once VM shuts down cleanly.
private_flag_windows_run_tls_destructors = false;
// On Windows we use ExitProcess so that threads can't clobber the exit_code.
// See: https://code.google.com/p/nativeclient/issues/detail?id=2870
::ExitProcess(code);
}
OS::BuildId OS::GetAppBuildId(const uint8_t* snapshot_instructions) {
// Since we only use direct-to-ELF snapshots on Windows, the build ID
// information must be available from the instructions image.
const Image instructions_image(snapshot_instructions);
auto* const image_build_id = instructions_image.build_id();
ASSERT(image_build_id != nullptr);
return {instructions_image.build_id_length(), image_build_id};
}
} // namespace dart
#endif // defined(DART_HOST_OS_WINDOWS)