1//===-- sanitizer_win.cc --------------------------------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file is shared between AddressSanitizer and ThreadSanitizer 11// run-time libraries and implements windows-specific functions from 12// sanitizer_libc.h. 13//===----------------------------------------------------------------------===// 14 15#include "sanitizer_platform.h" 16#if SANITIZER_WINDOWS 17 18#define WIN32_LEAN_AND_MEAN 19#define NOGDI 20#include <windows.h> 21#include <dbghelp.h> 22#include <io.h> 23#include <psapi.h> 24#include <stdlib.h> 25 26#include "sanitizer_common.h" 27#include "sanitizer_libc.h" 28#include "sanitizer_mutex.h" 29#include "sanitizer_placement_new.h" 30#include "sanitizer_stacktrace.h" 31 32namespace __sanitizer { 33 34#include "sanitizer_syscall_generic.inc" 35 36// --------------------- sanitizer_common.h 37uptr GetPageSize() { 38 // FIXME: there is an API for getting the system page size (GetSystemInfo or 39 // GetNativeSystemInfo), but if we use it here we get test failures elsewhere. 40 return 1U << 14; 41} 42 43uptr GetMmapGranularity() { 44 return 1U << 16; // FIXME: is this configurable? 45} 46 47uptr GetMaxVirtualAddress() { 48 SYSTEM_INFO si; 49 GetSystemInfo(&si); 50 return (uptr)si.lpMaximumApplicationAddress; 51} 52 53bool FileExists(const char *filename) { 54 return ::GetFileAttributesA(filename) != INVALID_FILE_ATTRIBUTES; 55} 56 57uptr internal_getpid() { 58 return GetProcessId(GetCurrentProcess()); 59} 60 61// In contrast to POSIX, on Windows GetCurrentThreadId() 62// returns a system-unique identifier. 63uptr GetTid() { 64 return GetCurrentThreadId(); 65} 66 67uptr GetThreadSelf() { 68 return GetTid(); 69} 70 71#if !SANITIZER_GO 72void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, 73 uptr *stack_bottom) { 74 CHECK(stack_top); 75 CHECK(stack_bottom); 76 MEMORY_BASIC_INFORMATION mbi; 77 CHECK_NE(VirtualQuery(&mbi /* on stack */, &mbi, sizeof(mbi)), 0); 78 // FIXME: is it possible for the stack to not be a single allocation? 79 // Are these values what ASan expects to get (reserved, not committed; 80 // including stack guard page) ? 81 *stack_top = (uptr)mbi.BaseAddress + mbi.RegionSize; 82 *stack_bottom = (uptr)mbi.AllocationBase; 83} 84#endif // #if !SANITIZER_GO 85 86void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) { 87 void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 88 if (rv == 0) 89 ReportMmapFailureAndDie(size, mem_type, "allocate", 90 GetLastError(), raw_report); 91 return rv; 92} 93 94void UnmapOrDie(void *addr, uptr size) { 95 if (!size || !addr) 96 return; 97 98 if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) { 99 Report("ERROR: %s failed to " 100 "deallocate 0x%zx (%zd) bytes at address %p (error code: %d)\n", 101 SanitizerToolName, size, size, addr, GetLastError()); 102 CHECK("unable to unmap" && 0); 103 } 104} 105 106void *MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) { 107 // FIXME: is this really "NoReserve"? On Win32 this does not matter much, 108 // but on Win64 it does. 109 (void)name; // unsupported 110 void *p = VirtualAlloc((LPVOID)fixed_addr, size, 111 MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 112 if (p == 0) 113 Report("ERROR: %s failed to " 114 "allocate %p (%zd) bytes at %p (error code: %d)\n", 115 SanitizerToolName, size, size, fixed_addr, GetLastError()); 116 return p; 117} 118 119void *MmapFixedOrDie(uptr fixed_addr, uptr size) { 120 return MmapFixedNoReserve(fixed_addr, size); 121} 122 123void *MmapNoReserveOrDie(uptr size, const char *mem_type) { 124 // FIXME: make this really NoReserve? 125 return MmapOrDie(size, mem_type); 126} 127 128void *MmapNoAccess(uptr fixed_addr, uptr size, const char *name) { 129 (void)name; // unsupported 130 void *res = VirtualAlloc((LPVOID)fixed_addr, size, 131 MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS); 132 if (res == 0) 133 Report("WARNING: %s failed to " 134 "mprotect %p (%zd) bytes at %p (error code: %d)\n", 135 SanitizerToolName, size, size, fixed_addr, GetLastError()); 136 return res; 137} 138 139bool MprotectNoAccess(uptr addr, uptr size) { 140 DWORD old_protection; 141 return VirtualProtect((LPVOID)addr, size, PAGE_NOACCESS, &old_protection); 142} 143 144 145void FlushUnneededShadowMemory(uptr addr, uptr size) { 146 // This is almost useless on 32-bits. 147 // FIXME: add madvise-analog when we move to 64-bits. 148} 149 150void NoHugePagesInRegion(uptr addr, uptr size) { 151 // FIXME: probably similar to FlushUnneededShadowMemory. 152} 153 154void DontDumpShadowMemory(uptr addr, uptr length) { 155 // This is almost useless on 32-bits. 156 // FIXME: add madvise-analog when we move to 64-bits. 157} 158 159bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { 160 MEMORY_BASIC_INFORMATION mbi; 161 CHECK(VirtualQuery((void *)range_start, &mbi, sizeof(mbi))); 162 return mbi.Protect == PAGE_NOACCESS && 163 (uptr)mbi.BaseAddress + mbi.RegionSize >= range_end; 164} 165 166void *MapFileToMemory(const char *file_name, uptr *buff_size) { 167 UNIMPLEMENTED(); 168} 169 170void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset) { 171 UNIMPLEMENTED(); 172} 173 174static const int kMaxEnvNameLength = 128; 175static const DWORD kMaxEnvValueLength = 32767; 176 177namespace { 178 179struct EnvVariable { 180 char name[kMaxEnvNameLength]; 181 char value[kMaxEnvValueLength]; 182}; 183 184} // namespace 185 186static const int kEnvVariables = 5; 187static EnvVariable env_vars[kEnvVariables]; 188static int num_env_vars; 189 190const char *GetEnv(const char *name) { 191 // Note: this implementation caches the values of the environment variables 192 // and limits their quantity. 193 for (int i = 0; i < num_env_vars; i++) { 194 if (0 == internal_strcmp(name, env_vars[i].name)) 195 return env_vars[i].value; 196 } 197 CHECK_LT(num_env_vars, kEnvVariables); 198 DWORD rv = GetEnvironmentVariableA(name, env_vars[num_env_vars].value, 199 kMaxEnvValueLength); 200 if (rv > 0 && rv < kMaxEnvValueLength) { 201 CHECK_LT(internal_strlen(name), kMaxEnvNameLength); 202 internal_strncpy(env_vars[num_env_vars].name, name, kMaxEnvNameLength); 203 num_env_vars++; 204 return env_vars[num_env_vars - 1].value; 205 } 206 return 0; 207} 208 209const char *GetPwd() { 210 UNIMPLEMENTED(); 211} 212 213u32 GetUid() { 214 UNIMPLEMENTED(); 215} 216 217namespace { 218struct ModuleInfo { 219 const char *filepath; 220 uptr base_address; 221 uptr end_address; 222}; 223 224#ifndef SANITIZER_GO 225int CompareModulesBase(const void *pl, const void *pr) { 226 const ModuleInfo *l = (ModuleInfo *)pl, *r = (ModuleInfo *)pr; 227 if (l->base_address < r->base_address) 228 return -1; 229 return l->base_address > r->base_address; 230} 231#endif 232} // namespace 233 234#ifndef SANITIZER_GO 235void DumpProcessMap() { 236 Report("Dumping process modules:\n"); 237 InternalScopedBuffer<LoadedModule> modules(kMaxNumberOfModules); 238 uptr num_modules = 239 GetListOfModules(modules.data(), kMaxNumberOfModules, nullptr); 240 241 InternalScopedBuffer<ModuleInfo> module_infos(num_modules); 242 for (size_t i = 0; i < num_modules; ++i) { 243 module_infos[i].filepath = modules[i].full_name(); 244 module_infos[i].base_address = modules[i].base_address(); 245 module_infos[i].end_address = modules[i].ranges().next()->end; 246 } 247 qsort(module_infos.data(), num_modules, sizeof(ModuleInfo), 248 CompareModulesBase); 249 250 for (size_t i = 0; i < num_modules; ++i) { 251 const ModuleInfo &mi = module_infos[i]; 252 if (mi.end_address != 0) { 253 Printf("\t%p-%p %s\n", mi.base_address, mi.end_address, 254 mi.filepath[0] ? mi.filepath : "[no name]"); 255 } else if (mi.filepath[0]) { 256 Printf("\t??\?-??? %s\n", mi.filepath); 257 } else { 258 Printf("\t???\n"); 259 } 260 } 261} 262#endif 263 264void DisableCoreDumperIfNecessary() { 265 // Do nothing. 266} 267 268void ReExec() { 269 UNIMPLEMENTED(); 270} 271 272void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) { 273#if !SANITIZER_GO 274 CovPrepareForSandboxing(args); 275#endif 276} 277 278bool StackSizeIsUnlimited() { 279 UNIMPLEMENTED(); 280} 281 282void SetStackSizeLimitInBytes(uptr limit) { 283 UNIMPLEMENTED(); 284} 285 286bool AddressSpaceIsUnlimited() { 287 UNIMPLEMENTED(); 288} 289 290void SetAddressSpaceUnlimited() { 291 UNIMPLEMENTED(); 292} 293 294bool IsPathSeparator(const char c) { 295 return c == '\\' || c == '/'; 296} 297 298bool IsAbsolutePath(const char *path) { 299 UNIMPLEMENTED(); 300} 301 302void SleepForSeconds(int seconds) { 303 Sleep(seconds * 1000); 304} 305 306void SleepForMillis(int millis) { 307 Sleep(millis); 308} 309 310u64 NanoTime() { 311 return 0; 312} 313 314void Abort() { 315 if (::IsDebuggerPresent()) 316 __debugbreak(); 317 internal__exit(3); 318} 319 320// Read the file to extract the ImageBase field from the PE header. If ASLR is 321// disabled and this virtual address is available, the loader will typically 322// load the image at this address. Therefore, we call it the preferred base. Any 323// addresses in the DWARF typically assume that the object has been loaded at 324// this address. 325static uptr GetPreferredBase(const char *modname) { 326 fd_t fd = OpenFile(modname, RdOnly, nullptr); 327 if (fd == kInvalidFd) 328 return 0; 329 FileCloser closer(fd); 330 331 // Read just the DOS header. 332 IMAGE_DOS_HEADER dos_header; 333 uptr bytes_read; 334 if (!ReadFromFile(fd, &dos_header, sizeof(dos_header), &bytes_read) || 335 bytes_read != sizeof(dos_header)) 336 return 0; 337 338 // The file should start with the right signature. 339 if (dos_header.e_magic != IMAGE_DOS_SIGNATURE) 340 return 0; 341 342 // The layout at e_lfanew is: 343 // "PE\0\0" 344 // IMAGE_FILE_HEADER 345 // IMAGE_OPTIONAL_HEADER 346 // Seek to e_lfanew and read all that data. 347 char buf[4 + sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER)]; 348 if (::SetFilePointer(fd, dos_header.e_lfanew, nullptr, FILE_BEGIN) == 349 INVALID_SET_FILE_POINTER) 350 return 0; 351 if (!ReadFromFile(fd, &buf[0], sizeof(buf), &bytes_read) || 352 bytes_read != sizeof(buf)) 353 return 0; 354 355 // Check for "PE\0\0" before the PE header. 356 char *pe_sig = &buf[0]; 357 if (internal_memcmp(pe_sig, "PE\0\0", 4) != 0) 358 return 0; 359 360 // Skip over IMAGE_FILE_HEADER. We could do more validation here if we wanted. 361 IMAGE_OPTIONAL_HEADER *pe_header = 362 (IMAGE_OPTIONAL_HEADER *)(pe_sig + 4 + sizeof(IMAGE_FILE_HEADER)); 363 364 // Check for more magic in the PE header. 365 if (pe_header->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC) 366 return 0; 367 368 // Finally, return the ImageBase. 369 return (uptr)pe_header->ImageBase; 370} 371 372#ifndef SANITIZER_GO 373uptr GetListOfModules(LoadedModule *modules, uptr max_modules, 374 string_predicate_t filter) { 375 HANDLE cur_process = GetCurrentProcess(); 376 377 // Query the list of modules. Start by assuming there are no more than 256 378 // modules and retry if that's not sufficient. 379 HMODULE *hmodules = 0; 380 uptr modules_buffer_size = sizeof(HMODULE) * 256; 381 DWORD bytes_required; 382 while (!hmodules) { 383 hmodules = (HMODULE *)MmapOrDie(modules_buffer_size, __FUNCTION__); 384 CHECK(EnumProcessModules(cur_process, hmodules, modules_buffer_size, 385 &bytes_required)); 386 if (bytes_required > modules_buffer_size) { 387 // Either there turned out to be more than 256 hmodules, or new hmodules 388 // could have loaded since the last try. Retry. 389 UnmapOrDie(hmodules, modules_buffer_size); 390 hmodules = 0; 391 modules_buffer_size = bytes_required; 392 } 393 } 394 395 // |num_modules| is the number of modules actually present, 396 // |count| is the number of modules we return. 397 size_t nun_modules = bytes_required / sizeof(HMODULE), 398 count = 0; 399 for (size_t i = 0; i < nun_modules && count < max_modules; ++i) { 400 HMODULE handle = hmodules[i]; 401 MODULEINFO mi; 402 if (!GetModuleInformation(cur_process, handle, &mi, sizeof(mi))) 403 continue; 404 405 // Get the UTF-16 path and convert to UTF-8. 406 wchar_t modname_utf16[kMaxPathLength]; 407 int modname_utf16_len = 408 GetModuleFileNameW(handle, modname_utf16, kMaxPathLength); 409 if (modname_utf16_len == 0) 410 modname_utf16[0] = '\0'; 411 char module_name[kMaxPathLength]; 412 int module_name_len = 413 ::WideCharToMultiByte(CP_UTF8, 0, modname_utf16, modname_utf16_len + 1, 414 &module_name[0], kMaxPathLength, NULL, NULL); 415 module_name[module_name_len] = '\0'; 416 417 if (filter && !filter(module_name)) 418 continue; 419 420 uptr base_address = (uptr)mi.lpBaseOfDll; 421 uptr end_address = (uptr)mi.lpBaseOfDll + mi.SizeOfImage; 422 423 // Adjust the base address of the module so that we get a VA instead of an 424 // RVA when computing the module offset. This helps llvm-symbolizer find the 425 // right DWARF CU. In the common case that the image is loaded at it's 426 // preferred address, we will now print normal virtual addresses. 427 uptr preferred_base = GetPreferredBase(&module_name[0]); 428 uptr adjusted_base = base_address - preferred_base; 429 430 LoadedModule *cur_module = &modules[count]; 431 cur_module->set(module_name, adjusted_base); 432 // We add the whole module as one single address range. 433 cur_module->addAddressRange(base_address, end_address, /*executable*/ true); 434 count++; 435 } 436 UnmapOrDie(hmodules, modules_buffer_size); 437 438 return count; 439}; 440 441// We can't use atexit() directly at __asan_init time as the CRT is not fully 442// initialized at this point. Place the functions into a vector and use 443// atexit() as soon as it is ready for use (i.e. after .CRT$XIC initializers). 444InternalMmapVectorNoCtor<void (*)(void)> atexit_functions; 445 446int Atexit(void (*function)(void)) { 447 atexit_functions.push_back(function); 448 return 0; 449} 450 451static int RunAtexit() { 452 int ret = 0; 453 for (uptr i = 0; i < atexit_functions.size(); ++i) { 454 ret |= atexit(atexit_functions[i]); 455 } 456 return ret; 457} 458 459#pragma section(".CRT$XID", long, read) // NOLINT 460__declspec(allocate(".CRT$XID")) int (*__run_atexit)() = RunAtexit; 461#endif 462 463// ------------------ sanitizer_libc.h 464fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *last_error) { 465 fd_t res; 466 if (mode == RdOnly) { 467 res = CreateFile(filename, GENERIC_READ, 468 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 469 nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); 470 } else if (mode == WrOnly) { 471 res = CreateFile(filename, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 472 FILE_ATTRIBUTE_NORMAL, nullptr); 473 } else { 474 UNIMPLEMENTED(); 475 } 476 CHECK(res != kStdoutFd || kStdoutFd == kInvalidFd); 477 CHECK(res != kStderrFd || kStderrFd == kInvalidFd); 478 if (res == kInvalidFd && last_error) 479 *last_error = GetLastError(); 480 return res; 481} 482 483void CloseFile(fd_t fd) { 484 CloseHandle(fd); 485} 486 487bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read, 488 error_t *error_p) { 489 CHECK(fd != kInvalidFd); 490 491 // bytes_read can't be passed directly to ReadFile: 492 // uptr is unsigned long long on 64-bit Windows. 493 unsigned long num_read_long; 494 495 bool success = ::ReadFile(fd, buff, buff_size, &num_read_long, nullptr); 496 if (!success && error_p) 497 *error_p = GetLastError(); 498 if (bytes_read) 499 *bytes_read = num_read_long; 500 return success; 501} 502 503bool SupportsColoredOutput(fd_t fd) { 504 // FIXME: support colored output. 505 return false; 506} 507 508bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written, 509 error_t *error_p) { 510 CHECK(fd != kInvalidFd); 511 512 // Handle null optional parameters. 513 error_t dummy_error; 514 error_p = error_p ? error_p : &dummy_error; 515 uptr dummy_bytes_written; 516 bytes_written = bytes_written ? bytes_written : &dummy_bytes_written; 517 518 // Initialize output parameters in case we fail. 519 *error_p = 0; 520 *bytes_written = 0; 521 522 // Map the conventional Unix fds 1 and 2 to Windows handles. They might be 523 // closed, in which case this will fail. 524 if (fd == kStdoutFd || fd == kStderrFd) { 525 fd = GetStdHandle(fd == kStdoutFd ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE); 526 if (fd == 0) { 527 *error_p = ERROR_INVALID_HANDLE; 528 return false; 529 } 530 } 531 532 DWORD bytes_written_32; 533 if (!WriteFile(fd, buff, buff_size, &bytes_written_32, 0)) { 534 *error_p = GetLastError(); 535 return false; 536 } else { 537 *bytes_written = bytes_written_32; 538 return true; 539 } 540} 541 542bool RenameFile(const char *oldpath, const char *newpath, error_t *error_p) { 543 UNIMPLEMENTED(); 544} 545 546uptr internal_sched_yield() { 547 Sleep(0); 548 return 0; 549} 550 551void internal__exit(int exitcode) { 552 ExitProcess(exitcode); 553} 554 555uptr internal_ftruncate(fd_t fd, uptr size) { 556 UNIMPLEMENTED(); 557} 558 559uptr GetRSS() { 560 return 0; 561} 562 563void *internal_start_thread(void (*func)(void *arg), void *arg) { return 0; } 564void internal_join_thread(void *th) { } 565 566// ---------------------- BlockingMutex ---------------- {{{1 567const uptr LOCK_UNINITIALIZED = 0; 568const uptr LOCK_READY = (uptr)-1; 569 570BlockingMutex::BlockingMutex(LinkerInitialized li) { 571 // FIXME: see comments in BlockingMutex::Lock() for the details. 572 CHECK(li == LINKER_INITIALIZED || owner_ == LOCK_UNINITIALIZED); 573 574 CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_)); 575 InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 576 owner_ = LOCK_READY; 577} 578 579BlockingMutex::BlockingMutex() { 580 CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_)); 581 InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 582 owner_ = LOCK_READY; 583} 584 585void BlockingMutex::Lock() { 586 if (owner_ == LOCK_UNINITIALIZED) { 587 // FIXME: hm, global BlockingMutex objects are not initialized?!? 588 // This might be a side effect of the clang+cl+link Frankenbuild... 589 new(this) BlockingMutex((LinkerInitialized)(LINKER_INITIALIZED + 1)); 590 591 // FIXME: If it turns out the linker doesn't invoke our 592 // constructors, we should probably manually Lock/Unlock all the global 593 // locks while we're starting in one thread to avoid double-init races. 594 } 595 EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 596 CHECK_EQ(owner_, LOCK_READY); 597 owner_ = GetThreadSelf(); 598} 599 600void BlockingMutex::Unlock() { 601 CHECK_EQ(owner_, GetThreadSelf()); 602 owner_ = LOCK_READY; 603 LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 604} 605 606void BlockingMutex::CheckLocked() { 607 CHECK_EQ(owner_, GetThreadSelf()); 608} 609 610uptr GetTlsSize() { 611 return 0; 612} 613 614void InitTlsSize() { 615} 616 617void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, 618 uptr *tls_addr, uptr *tls_size) { 619#ifdef SANITIZER_GO 620 *stk_addr = 0; 621 *stk_size = 0; 622 *tls_addr = 0; 623 *tls_size = 0; 624#else 625 uptr stack_top, stack_bottom; 626 GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom); 627 *stk_addr = stack_bottom; 628 *stk_size = stack_top - stack_bottom; 629 *tls_addr = 0; 630 *tls_size = 0; 631#endif 632} 633 634#if !SANITIZER_GO 635void BufferedStackTrace::SlowUnwindStack(uptr pc, u32 max_depth) { 636 CHECK_GE(max_depth, 2); 637 // FIXME: CaptureStackBackTrace might be too slow for us. 638 // FIXME: Compare with StackWalk64. 639 // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc 640 size = CaptureStackBackTrace(2, Min(max_depth, kStackTraceMax), 641 (void**)trace, 0); 642 if (size == 0) 643 return; 644 645 // Skip the RTL frames by searching for the PC in the stacktrace. 646 uptr pc_location = LocatePcInTrace(pc); 647 PopStackFrames(pc_location); 648} 649 650void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context, 651 u32 max_depth) { 652 CONTEXT ctx = *(CONTEXT *)context; 653 STACKFRAME64 stack_frame; 654 memset(&stack_frame, 0, sizeof(stack_frame)); 655 size = 0; 656#if defined(_WIN64) 657 int machine_type = IMAGE_FILE_MACHINE_AMD64; 658 stack_frame.AddrPC.Offset = ctx.Rip; 659 stack_frame.AddrFrame.Offset = ctx.Rbp; 660 stack_frame.AddrStack.Offset = ctx.Rsp; 661#else 662 int machine_type = IMAGE_FILE_MACHINE_I386; 663 stack_frame.AddrPC.Offset = ctx.Eip; 664 stack_frame.AddrFrame.Offset = ctx.Ebp; 665 stack_frame.AddrStack.Offset = ctx.Esp; 666#endif 667 stack_frame.AddrPC.Mode = AddrModeFlat; 668 stack_frame.AddrFrame.Mode = AddrModeFlat; 669 stack_frame.AddrStack.Mode = AddrModeFlat; 670 while (StackWalk64(machine_type, GetCurrentProcess(), GetCurrentThread(), 671 &stack_frame, &ctx, NULL, &SymFunctionTableAccess64, 672 &SymGetModuleBase64, NULL) && 673 size < Min(max_depth, kStackTraceMax)) { 674 trace_buffer[size++] = (uptr)stack_frame.AddrPC.Offset; 675 } 676} 677#endif // #if !SANITIZER_GO 678 679void ReportFile::Write(const char *buffer, uptr length) { 680 SpinMutexLock l(mu); 681 ReopenIfNecessary(); 682 if (!WriteToFile(fd, buffer, length)) { 683 // stderr may be closed, but we may be able to print to the debugger 684 // instead. This is the case when launching a program from Visual Studio, 685 // and the following routine should write to its console. 686 OutputDebugStringA(buffer); 687 } 688} 689 690void SetAlternateSignalStack() { 691 // FIXME: Decide what to do on Windows. 692} 693 694void UnsetAlternateSignalStack() { 695 // FIXME: Decide what to do on Windows. 696} 697 698void InstallDeadlySignalHandlers(SignalHandlerType handler) { 699 (void)handler; 700 // FIXME: Decide what to do on Windows. 701} 702 703bool IsDeadlySignal(int signum) { 704 // FIXME: Decide what to do on Windows. 705 return false; 706} 707 708bool IsAccessibleMemoryRange(uptr beg, uptr size) { 709 SYSTEM_INFO si; 710 GetNativeSystemInfo(&si); 711 uptr page_size = si.dwPageSize; 712 uptr page_mask = ~(page_size - 1); 713 714 for (uptr page = beg & page_mask, end = (beg + size - 1) & page_mask; 715 page <= end;) { 716 MEMORY_BASIC_INFORMATION info; 717 if (VirtualQuery((LPCVOID)page, &info, sizeof(info)) != sizeof(info)) 718 return false; 719 720 if (info.Protect == 0 || info.Protect == PAGE_NOACCESS || 721 info.Protect == PAGE_EXECUTE) 722 return false; 723 724 if (info.RegionSize == 0) 725 return false; 726 727 page += info.RegionSize; 728 } 729 730 return true; 731} 732 733SignalContext SignalContext::Create(void *siginfo, void *context) { 734 EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD*)siginfo; 735 CONTEXT *context_record = (CONTEXT*)context; 736 737 uptr pc = (uptr)exception_record->ExceptionAddress; 738#ifdef _WIN64 739 uptr bp = (uptr)context_record->Rbp; 740 uptr sp = (uptr)context_record->Rsp; 741#else 742 uptr bp = (uptr)context_record->Ebp; 743 uptr sp = (uptr)context_record->Esp; 744#endif 745 uptr access_addr = exception_record->ExceptionInformation[1]; 746 747 return SignalContext(context, access_addr, pc, sp, bp); 748} 749 750uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { 751 // FIXME: Actually implement this function. 752 CHECK_GT(buf_len, 0); 753 buf[0] = 0; 754 return 0; 755} 756 757uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) { 758 return ReadBinaryName(buf, buf_len); 759} 760 761void CheckVMASize() { 762 // Do nothing. 763} 764 765void DisableReexec() { 766 // No need to re-exec on Windows. 767} 768 769void MaybeReexec() { 770 // No need to re-exec on Windows. 771} 772 773} // namespace __sanitizer 774 775#endif // _WIN32 776