Changeset View
Changeset View
Standalone View
Standalone View
compiler-rt/lib/sanitizer_common/sanitizer_win.cpp
Show First 20 Lines • Show All 562 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
#if !SANITIZER_GO | #if !SANITIZER_GO | ||||
// Read the file to extract the ImageBase field from the PE header. If ASLR is | // Read the file to extract the ImageBase field from the PE header. If ASLR is | ||||
// disabled and this virtual address is available, the loader will typically | // disabled and this virtual address is available, the loader will typically | ||||
// load the image at this address. Therefore, we call it the preferred base. Any | // load the image at this address. Therefore, we call it the preferred base. Any | ||||
// addresses in the DWARF typically assume that the object has been loaded at | // addresses in the DWARF typically assume that the object has been loaded at | ||||
// this address. | // this address. | ||||
static uptr GetPreferredBase(const char *modname) { | static uptr GetPreferredBase(const char *modname, char *buf, size_t buf_size) { | ||||
fd_t fd = OpenFile(modname, RdOnly, nullptr); | fd_t fd = OpenFile(modname, RdOnly, nullptr); | ||||
if (fd == kInvalidFd) | if (fd == kInvalidFd) | ||||
return 0; | return 0; | ||||
FileCloser closer(fd); | FileCloser closer(fd); | ||||
// Read just the DOS header. | // Read just the DOS header. | ||||
IMAGE_DOS_HEADER dos_header; | IMAGE_DOS_HEADER dos_header; | ||||
uptr bytes_read; | uptr bytes_read; | ||||
if (!ReadFromFile(fd, &dos_header, sizeof(dos_header), &bytes_read) || | if (!ReadFromFile(fd, &dos_header, sizeof(dos_header), &bytes_read) || | ||||
bytes_read != sizeof(dos_header)) | bytes_read != sizeof(dos_header)) | ||||
return 0; | return 0; | ||||
// The file should start with the right signature. | // The file should start with the right signature. | ||||
if (dos_header.e_magic != IMAGE_DOS_SIGNATURE) | if (dos_header.e_magic != IMAGE_DOS_SIGNATURE) | ||||
return 0; | return 0; | ||||
// The layout at e_lfanew is: | // The layout at e_lfanew is: | ||||
// "PE\0\0" | // "PE\0\0" | ||||
// IMAGE_FILE_HEADER | // IMAGE_FILE_HEADER | ||||
// IMAGE_OPTIONAL_HEADER | // IMAGE_OPTIONAL_HEADER | ||||
// Seek to e_lfanew and read all that data. | // Seek to e_lfanew and read all that data. | ||||
char buf[4 + sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER)]; | |||||
if (::SetFilePointer(fd, dos_header.e_lfanew, nullptr, FILE_BEGIN) == | if (::SetFilePointer(fd, dos_header.e_lfanew, nullptr, FILE_BEGIN) == | ||||
INVALID_SET_FILE_POINTER) | INVALID_SET_FILE_POINTER) | ||||
return 0; | return 0; | ||||
if (!ReadFromFile(fd, &buf[0], sizeof(buf), &bytes_read) || | if (!ReadFromFile(fd, buf, buf_size, &bytes_read) || bytes_read != buf_size) | ||||
mstorsjo: Ah, this `sizeof(buf)` needs to be `buf.size()` or something like that. | |||||
I think that this line needs changing from sizeof(buf) to buf.size() as well. russell.gallop: I think that this line needs changing from sizeof(buf) to buf.size() as well. | |||||
Doh, thanks for catching it!, fixed now. mstorsjo: Doh, thanks for catching it!, fixed now. | |||||
bytes_read != sizeof(buf)) | |||||
return 0; | return 0; | ||||
// Check for "PE\0\0" before the PE header. | // Check for "PE\0\0" before the PE header. | ||||
char *pe_sig = &buf[0]; | char *pe_sig = &buf[0]; | ||||
if (internal_memcmp(pe_sig, "PE\0\0", 4) != 0) | if (internal_memcmp(pe_sig, "PE\0\0", 4) != 0) | ||||
return 0; | return 0; | ||||
// Skip over IMAGE_FILE_HEADER. We could do more validation here if we wanted. | // Skip over IMAGE_FILE_HEADER. We could do more validation here if we wanted. | ||||
IMAGE_OPTIONAL_HEADER *pe_header = | IMAGE_OPTIONAL_HEADER *pe_header = | ||||
(IMAGE_OPTIONAL_HEADER *)(pe_sig + 4 + sizeof(IMAGE_FILE_HEADER)); | (IMAGE_OPTIONAL_HEADER *)(pe_sig + 4 + sizeof(IMAGE_FILE_HEADER)); | ||||
// Check for more magic in the PE header. | // Check for more magic in the PE header. | ||||
if (pe_header->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC) | if (pe_header->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC) | ||||
return 0; | return 0; | ||||
// Finally, return the ImageBase. | // Finally, return the ImageBase. | ||||
return (uptr)pe_header->ImageBase; | return (uptr)pe_header->ImageBase; | ||||
} | } | ||||
#ifdef __clang__ | |||||
#pragma clang diagnostic push | |||||
#pragma clang diagnostic ignored "-Wframe-larger-than=" | |||||
#endif | |||||
void ListOfModules::init() { | void ListOfModules::init() { | ||||
clearOrInit(); | clearOrInit(); | ||||
HANDLE cur_process = GetCurrentProcess(); | HANDLE cur_process = GetCurrentProcess(); | ||||
// Query the list of modules. Start by assuming there are no more than 256 | // Query the list of modules. Start by assuming there are no more than 256 | ||||
// modules and retry if that's not sufficient. | // modules and retry if that's not sufficient. | ||||
HMODULE *hmodules = 0; | HMODULE *hmodules = 0; | ||||
uptr modules_buffer_size = sizeof(HMODULE) * 256; | uptr modules_buffer_size = sizeof(HMODULE) * 256; | ||||
DWORD bytes_required; | DWORD bytes_required; | ||||
while (!hmodules) { | while (!hmodules) { | ||||
hmodules = (HMODULE *)MmapOrDie(modules_buffer_size, __FUNCTION__); | hmodules = (HMODULE *)MmapOrDie(modules_buffer_size, __FUNCTION__); | ||||
CHECK(EnumProcessModules(cur_process, hmodules, modules_buffer_size, | CHECK(EnumProcessModules(cur_process, hmodules, modules_buffer_size, | ||||
&bytes_required)); | &bytes_required)); | ||||
if (bytes_required > modules_buffer_size) { | if (bytes_required > modules_buffer_size) { | ||||
// Either there turned out to be more than 256 hmodules, or new hmodules | // Either there turned out to be more than 256 hmodules, or new hmodules | ||||
// could have loaded since the last try. Retry. | // could have loaded since the last try. Retry. | ||||
UnmapOrDie(hmodules, modules_buffer_size); | UnmapOrDie(hmodules, modules_buffer_size); | ||||
hmodules = 0; | hmodules = 0; | ||||
modules_buffer_size = bytes_required; | modules_buffer_size = bytes_required; | ||||
} | } | ||||
} | } | ||||
InternalMmapVector<char> buf(4 + sizeof(IMAGE_FILE_HEADER) + | |||||
sizeof(IMAGE_OPTIONAL_HEADER)); | |||||
InternalMmapVector<wchar_t> modname_utf16(kMaxPathLength); | |||||
InternalMmapVector<char> module_name(kMaxPathLength); | |||||
// |num_modules| is the number of modules actually present, | // |num_modules| is the number of modules actually present, | ||||
size_t num_modules = bytes_required / sizeof(HMODULE); | size_t num_modules = bytes_required / sizeof(HMODULE); | ||||
for (size_t i = 0; i < num_modules; ++i) { | for (size_t i = 0; i < num_modules; ++i) { | ||||
Not Done ReplyInline ActionsThis might be a micro-optimization, but InternalMmapVector is built on VirtualAlloc, which is expensive, and now it's being done three times in a loop over the DLLs in a process. That might matter for startup time. Can you hoist the vectors out of the loop? You'll have to pass in memory to GetPreferredBase, which leaks implementation details, but I think it's worth doing. rnk: This might be a micro-optimization, but InternalMmapVector is built on VirtualAlloc, which is… | |||||
HMODULE handle = hmodules[i]; | HMODULE handle = hmodules[i]; | ||||
MODULEINFO mi; | MODULEINFO mi; | ||||
if (!GetModuleInformation(cur_process, handle, &mi, sizeof(mi))) | if (!GetModuleInformation(cur_process, handle, &mi, sizeof(mi))) | ||||
continue; | continue; | ||||
// Get the UTF-16 path and convert to UTF-8. | // Get the UTF-16 path and convert to UTF-8. | ||||
wchar_t modname_utf16[kMaxPathLength]; | |||||
int modname_utf16_len = | int modname_utf16_len = | ||||
GetModuleFileNameW(handle, modname_utf16, kMaxPathLength); | GetModuleFileNameW(handle, &modname_utf16[0], kMaxPathLength); | ||||
if (modname_utf16_len == 0) | if (modname_utf16_len == 0) | ||||
modname_utf16[0] = '\0'; | modname_utf16[0] = '\0'; | ||||
char module_name[kMaxPathLength]; | int module_name_len = ::WideCharToMultiByte( | ||||
int module_name_len = | CP_UTF8, 0, &modname_utf16[0], modname_utf16_len + 1, &module_name[0], | ||||
::WideCharToMultiByte(CP_UTF8, 0, modname_utf16, modname_utf16_len + 1, | kMaxPathLength, NULL, NULL); | ||||
&module_name[0], kMaxPathLength, NULL, NULL); | |||||
module_name[module_name_len] = '\0'; | module_name[module_name_len] = '\0'; | ||||
uptr base_address = (uptr)mi.lpBaseOfDll; | uptr base_address = (uptr)mi.lpBaseOfDll; | ||||
uptr end_address = (uptr)mi.lpBaseOfDll + mi.SizeOfImage; | uptr end_address = (uptr)mi.lpBaseOfDll + mi.SizeOfImage; | ||||
// Adjust the base address of the module so that we get a VA instead of an | // Adjust the base address of the module so that we get a VA instead of an | ||||
// RVA when computing the module offset. This helps llvm-symbolizer find the | // RVA when computing the module offset. This helps llvm-symbolizer find the | ||||
// right DWARF CU. In the common case that the image is loaded at it's | // right DWARF CU. In the common case that the image is loaded at it's | ||||
// preferred address, we will now print normal virtual addresses. | // preferred address, we will now print normal virtual addresses. | ||||
uptr preferred_base = GetPreferredBase(&module_name[0]); | uptr preferred_base = | ||||
GetPreferredBase(&module_name[0], &buf[0], buf.size()); | |||||
uptr adjusted_base = base_address - preferred_base; | uptr adjusted_base = base_address - preferred_base; | ||||
LoadedModule cur_module; | modules_.push_back(LoadedModule()); | ||||
cur_module.set(module_name, adjusted_base); | LoadedModule &cur_module = modules_.back(); | ||||
cur_module.set(&module_name[0], adjusted_base); | |||||
// We add the whole module as one single address range. | // We add the whole module as one single address range. | ||||
cur_module.addAddressRange(base_address, end_address, /*executable*/ true, | cur_module.addAddressRange(base_address, end_address, /*executable*/ true, | ||||
/*writable*/ true); | /*writable*/ true); | ||||
modules_.push_back(cur_module); | |||||
} | } | ||||
UnmapOrDie(hmodules, modules_buffer_size); | UnmapOrDie(hmodules, modules_buffer_size); | ||||
} | } | ||||
#ifdef __clang__ | |||||
#pragma clang diagnostic pop | |||||
#endif | |||||
void ListOfModules::fallbackInit() { clear(); } | void ListOfModules::fallbackInit() { clear(); } | ||||
// We can't use atexit() directly at __asan_init time as the CRT is not fully | // We can't use atexit() directly at __asan_init time as the CRT is not fully | ||||
// initialized at this point. Place the functions into a vector and use | // initialized at this point. Place the functions into a vector and use | ||||
// atexit() as soon as it is ready for use (i.e. after .CRT$XIC initializers). | // atexit() as soon as it is ready for use (i.e. after .CRT$XIC initializers). | ||||
InternalMmapVectorNoCtor<void (*)(void)> atexit_functions; | InternalMmapVectorNoCtor<void (*)(void)> atexit_functions; | ||||
▲ Show 20 Lines • Show All 358 Lines • ▼ Show 20 Lines | const char *SignalContext::Describe() const { | ||||
return "unknown exception"; | return "unknown exception"; | ||||
} | } | ||||
uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { | uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { | ||||
if (buf_len == 0) | if (buf_len == 0) | ||||
return 0; | return 0; | ||||
// Get the UTF-16 path and convert to UTF-8. | // Get the UTF-16 path and convert to UTF-8. | ||||
wchar_t binname_utf16[kMaxPathLength]; | InternalMmapVector<wchar_t> binname_utf16(kMaxPathLength); | ||||
int binname_utf16_len = | int binname_utf16_len = | ||||
GetModuleFileNameW(NULL, binname_utf16, ARRAY_SIZE(binname_utf16)); | GetModuleFileNameW(NULL, &binname_utf16[0], kMaxPathLength); | ||||
if (binname_utf16_len == 0) { | if (binname_utf16_len == 0) { | ||||
buf[0] = '\0'; | buf[0] = '\0'; | ||||
return 0; | return 0; | ||||
} | } | ||||
int binary_name_len = ::WideCharToMultiByte( | int binary_name_len = | ||||
CP_UTF8, 0, binname_utf16, binname_utf16_len, buf, buf_len, NULL, NULL); | ::WideCharToMultiByte(CP_UTF8, 0, &binname_utf16[0], binname_utf16_len, | ||||
buf, buf_len, NULL, NULL); | |||||
if ((unsigned)binary_name_len == buf_len) | if ((unsigned)binary_name_len == buf_len) | ||||
--binary_name_len; | --binary_name_len; | ||||
buf[binary_name_len] = '\0'; | buf[binary_name_len] = '\0'; | ||||
return binary_name_len; | return binary_name_len; | ||||
} | } | ||||
uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) { | uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) { | ||||
return ReadBinaryName(buf, buf_len); | return ReadBinaryName(buf, buf_len); | ||||
▲ Show 20 Lines • Show All 98 Lines • Show Last 20 Lines |
Ah, this sizeof(buf) needs to be buf.size() or something like that.