16d1862363c88c183b0ed7740fca876342cf0474bStephen Hines//===-- sanitizer_procmaps_common.cc --------------------------------------===// 26d1862363c88c183b0ed7740fca876342cf0474bStephen Hines// 36d1862363c88c183b0ed7740fca876342cf0474bStephen Hines// The LLVM Compiler Infrastructure 46d1862363c88c183b0ed7740fca876342cf0474bStephen Hines// 56d1862363c88c183b0ed7740fca876342cf0474bStephen Hines// This file is distributed under the University of Illinois Open Source 66d1862363c88c183b0ed7740fca876342cf0474bStephen Hines// License. See LICENSE.TXT for details. 76d1862363c88c183b0ed7740fca876342cf0474bStephen Hines// 86d1862363c88c183b0ed7740fca876342cf0474bStephen Hines//===----------------------------------------------------------------------===// 96d1862363c88c183b0ed7740fca876342cf0474bStephen Hines// 106d1862363c88c183b0ed7740fca876342cf0474bStephen Hines// Information about the process mappings (common parts). 116d1862363c88c183b0ed7740fca876342cf0474bStephen Hines//===----------------------------------------------------------------------===// 126d1862363c88c183b0ed7740fca876342cf0474bStephen Hines 136d1862363c88c183b0ed7740fca876342cf0474bStephen Hines#include "sanitizer_platform.h" 143d763c0d3700e73b3aead8e65e04ec28efc56138Pirama Arumuga Nainar 156d1862363c88c183b0ed7740fca876342cf0474bStephen Hines#if SANITIZER_FREEBSD || SANITIZER_LINUX 163d763c0d3700e73b3aead8e65e04ec28efc56138Pirama Arumuga Nainar 176d1862363c88c183b0ed7740fca876342cf0474bStephen Hines#include "sanitizer_common.h" 186d1862363c88c183b0ed7740fca876342cf0474bStephen Hines#include "sanitizer_placement_new.h" 196d1862363c88c183b0ed7740fca876342cf0474bStephen Hines#include "sanitizer_procmaps.h" 206d1862363c88c183b0ed7740fca876342cf0474bStephen Hines 216d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesnamespace __sanitizer { 226d1862363c88c183b0ed7740fca876342cf0474bStephen Hines 236d1862363c88c183b0ed7740fca876342cf0474bStephen Hines// Linker initialized. 246d1862363c88c183b0ed7740fca876342cf0474bStephen HinesProcSelfMapsBuff MemoryMappingLayout::cached_proc_self_maps_; 256d1862363c88c183b0ed7740fca876342cf0474bStephen HinesStaticSpinMutex MemoryMappingLayout::cache_lock_; // Linker initialized. 266d1862363c88c183b0ed7740fca876342cf0474bStephen Hines 276d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesstatic int TranslateDigit(char c) { 286d1862363c88c183b0ed7740fca876342cf0474bStephen Hines if (c >= '0' && c <= '9') 296d1862363c88c183b0ed7740fca876342cf0474bStephen Hines return c - '0'; 306d1862363c88c183b0ed7740fca876342cf0474bStephen Hines if (c >= 'a' && c <= 'f') 316d1862363c88c183b0ed7740fca876342cf0474bStephen Hines return c - 'a' + 10; 326d1862363c88c183b0ed7740fca876342cf0474bStephen Hines if (c >= 'A' && c <= 'F') 336d1862363c88c183b0ed7740fca876342cf0474bStephen Hines return c - 'A' + 10; 346d1862363c88c183b0ed7740fca876342cf0474bStephen Hines return -1; 356d1862363c88c183b0ed7740fca876342cf0474bStephen Hines} 366d1862363c88c183b0ed7740fca876342cf0474bStephen Hines 376d1862363c88c183b0ed7740fca876342cf0474bStephen Hines// Parse a number and promote 'p' up to the first non-digit character. 386d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesstatic uptr ParseNumber(const char **p, int base) { 396d1862363c88c183b0ed7740fca876342cf0474bStephen Hines uptr n = 0; 406d1862363c88c183b0ed7740fca876342cf0474bStephen Hines int d; 416d1862363c88c183b0ed7740fca876342cf0474bStephen Hines CHECK(base >= 2 && base <= 16); 426d1862363c88c183b0ed7740fca876342cf0474bStephen Hines while ((d = TranslateDigit(**p)) >= 0 && d < base) { 436d1862363c88c183b0ed7740fca876342cf0474bStephen Hines n = n * base + d; 446d1862363c88c183b0ed7740fca876342cf0474bStephen Hines (*p)++; 456d1862363c88c183b0ed7740fca876342cf0474bStephen Hines } 466d1862363c88c183b0ed7740fca876342cf0474bStephen Hines return n; 476d1862363c88c183b0ed7740fca876342cf0474bStephen Hines} 486d1862363c88c183b0ed7740fca876342cf0474bStephen Hines 496d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesbool IsDecimal(char c) { 506d1862363c88c183b0ed7740fca876342cf0474bStephen Hines int d = TranslateDigit(c); 516d1862363c88c183b0ed7740fca876342cf0474bStephen Hines return d >= 0 && d < 10; 526d1862363c88c183b0ed7740fca876342cf0474bStephen Hines} 536d1862363c88c183b0ed7740fca876342cf0474bStephen Hines 546d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesuptr ParseDecimal(const char **p) { 556d1862363c88c183b0ed7740fca876342cf0474bStephen Hines return ParseNumber(p, 10); 566d1862363c88c183b0ed7740fca876342cf0474bStephen Hines} 576d1862363c88c183b0ed7740fca876342cf0474bStephen Hines 586d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesbool IsHex(char c) { 596d1862363c88c183b0ed7740fca876342cf0474bStephen Hines int d = TranslateDigit(c); 606d1862363c88c183b0ed7740fca876342cf0474bStephen Hines return d >= 0 && d < 16; 616d1862363c88c183b0ed7740fca876342cf0474bStephen Hines} 626d1862363c88c183b0ed7740fca876342cf0474bStephen Hines 636d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesuptr ParseHex(const char **p) { 646d1862363c88c183b0ed7740fca876342cf0474bStephen Hines return ParseNumber(p, 16); 656d1862363c88c183b0ed7740fca876342cf0474bStephen Hines} 666d1862363c88c183b0ed7740fca876342cf0474bStephen Hines 676d1862363c88c183b0ed7740fca876342cf0474bStephen HinesMemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) { 686d1862363c88c183b0ed7740fca876342cf0474bStephen Hines ReadProcMaps(&proc_self_maps_); 696d1862363c88c183b0ed7740fca876342cf0474bStephen Hines if (cache_enabled) { 706d1862363c88c183b0ed7740fca876342cf0474bStephen Hines if (proc_self_maps_.mmaped_size == 0) { 716d1862363c88c183b0ed7740fca876342cf0474bStephen Hines LoadFromCache(); 726d1862363c88c183b0ed7740fca876342cf0474bStephen Hines CHECK_GT(proc_self_maps_.len, 0); 736d1862363c88c183b0ed7740fca876342cf0474bStephen Hines } 746d1862363c88c183b0ed7740fca876342cf0474bStephen Hines } else { 756d1862363c88c183b0ed7740fca876342cf0474bStephen Hines CHECK_GT(proc_self_maps_.mmaped_size, 0); 766d1862363c88c183b0ed7740fca876342cf0474bStephen Hines } 776d1862363c88c183b0ed7740fca876342cf0474bStephen Hines Reset(); 786d1862363c88c183b0ed7740fca876342cf0474bStephen Hines // FIXME: in the future we may want to cache the mappings on demand only. 796d1862363c88c183b0ed7740fca876342cf0474bStephen Hines if (cache_enabled) 806d1862363c88c183b0ed7740fca876342cf0474bStephen Hines CacheMemoryMappings(); 816d1862363c88c183b0ed7740fca876342cf0474bStephen Hines} 826d1862363c88c183b0ed7740fca876342cf0474bStephen Hines 836d1862363c88c183b0ed7740fca876342cf0474bStephen HinesMemoryMappingLayout::~MemoryMappingLayout() { 846d1862363c88c183b0ed7740fca876342cf0474bStephen Hines // Only unmap the buffer if it is different from the cached one. Otherwise 856d1862363c88c183b0ed7740fca876342cf0474bStephen Hines // it will be unmapped when the cache is refreshed. 866d1862363c88c183b0ed7740fca876342cf0474bStephen Hines if (proc_self_maps_.data != cached_proc_self_maps_.data) { 876d1862363c88c183b0ed7740fca876342cf0474bStephen Hines UnmapOrDie(proc_self_maps_.data, proc_self_maps_.mmaped_size); 886d1862363c88c183b0ed7740fca876342cf0474bStephen Hines } 896d1862363c88c183b0ed7740fca876342cf0474bStephen Hines} 906d1862363c88c183b0ed7740fca876342cf0474bStephen Hines 916d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesvoid MemoryMappingLayout::Reset() { 926d1862363c88c183b0ed7740fca876342cf0474bStephen Hines current_ = proc_self_maps_.data; 936d1862363c88c183b0ed7740fca876342cf0474bStephen Hines} 946d1862363c88c183b0ed7740fca876342cf0474bStephen Hines 956d1862363c88c183b0ed7740fca876342cf0474bStephen Hines// static 966d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesvoid MemoryMappingLayout::CacheMemoryMappings() { 976d1862363c88c183b0ed7740fca876342cf0474bStephen Hines SpinMutexLock l(&cache_lock_); 986d1862363c88c183b0ed7740fca876342cf0474bStephen Hines // Don't invalidate the cache if the mappings are unavailable. 996d1862363c88c183b0ed7740fca876342cf0474bStephen Hines ProcSelfMapsBuff old_proc_self_maps; 1006d1862363c88c183b0ed7740fca876342cf0474bStephen Hines old_proc_self_maps = cached_proc_self_maps_; 1016d1862363c88c183b0ed7740fca876342cf0474bStephen Hines ReadProcMaps(&cached_proc_self_maps_); 1026d1862363c88c183b0ed7740fca876342cf0474bStephen Hines if (cached_proc_self_maps_.mmaped_size == 0) { 1036d1862363c88c183b0ed7740fca876342cf0474bStephen Hines cached_proc_self_maps_ = old_proc_self_maps; 1046d1862363c88c183b0ed7740fca876342cf0474bStephen Hines } else { 1056d1862363c88c183b0ed7740fca876342cf0474bStephen Hines if (old_proc_self_maps.mmaped_size) { 1066d1862363c88c183b0ed7740fca876342cf0474bStephen Hines UnmapOrDie(old_proc_self_maps.data, 1076d1862363c88c183b0ed7740fca876342cf0474bStephen Hines old_proc_self_maps.mmaped_size); 1086d1862363c88c183b0ed7740fca876342cf0474bStephen Hines } 1096d1862363c88c183b0ed7740fca876342cf0474bStephen Hines } 1106d1862363c88c183b0ed7740fca876342cf0474bStephen Hines} 1116d1862363c88c183b0ed7740fca876342cf0474bStephen Hines 1126d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesvoid MemoryMappingLayout::LoadFromCache() { 1136d1862363c88c183b0ed7740fca876342cf0474bStephen Hines SpinMutexLock l(&cache_lock_); 1146d1862363c88c183b0ed7740fca876342cf0474bStephen Hines if (cached_proc_self_maps_.data) { 1156d1862363c88c183b0ed7740fca876342cf0474bStephen Hines proc_self_maps_ = cached_proc_self_maps_; 1166d1862363c88c183b0ed7740fca876342cf0474bStephen Hines } 1176d1862363c88c183b0ed7740fca876342cf0474bStephen Hines} 1186d1862363c88c183b0ed7740fca876342cf0474bStephen Hines 1196d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesuptr MemoryMappingLayout::DumpListOfModules(LoadedModule *modules, 1206d1862363c88c183b0ed7740fca876342cf0474bStephen Hines uptr max_modules, 1216d1862363c88c183b0ed7740fca876342cf0474bStephen Hines string_predicate_t filter) { 1226d1862363c88c183b0ed7740fca876342cf0474bStephen Hines Reset(); 1236d1862363c88c183b0ed7740fca876342cf0474bStephen Hines uptr cur_beg, cur_end, cur_offset, prot; 12486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines InternalScopedString module_name(kMaxPathLength); 1256d1862363c88c183b0ed7740fca876342cf0474bStephen Hines uptr n_modules = 0; 1266d1862363c88c183b0ed7740fca876342cf0474bStephen Hines for (uptr i = 0; n_modules < max_modules && 1276d1862363c88c183b0ed7740fca876342cf0474bStephen Hines Next(&cur_beg, &cur_end, &cur_offset, module_name.data(), 1286d1862363c88c183b0ed7740fca876342cf0474bStephen Hines module_name.size(), &prot); 1296d1862363c88c183b0ed7740fca876342cf0474bStephen Hines i++) { 1306d1862363c88c183b0ed7740fca876342cf0474bStephen Hines const char *cur_name = module_name.data(); 1316d1862363c88c183b0ed7740fca876342cf0474bStephen Hines if (cur_name[0] == '\0') 1326d1862363c88c183b0ed7740fca876342cf0474bStephen Hines continue; 1336d1862363c88c183b0ed7740fca876342cf0474bStephen Hines if (filter && !filter(cur_name)) 1346d1862363c88c183b0ed7740fca876342cf0474bStephen Hines continue; 1356d1862363c88c183b0ed7740fca876342cf0474bStephen Hines // Don't subtract 'cur_beg' from the first entry: 1366d1862363c88c183b0ed7740fca876342cf0474bStephen Hines // * If a binary is compiled w/o -pie, then the first entry in 1376d1862363c88c183b0ed7740fca876342cf0474bStephen Hines // process maps is likely the binary itself (all dynamic libs 1386d1862363c88c183b0ed7740fca876342cf0474bStephen Hines // are mapped higher in address space). For such a binary, 1396d1862363c88c183b0ed7740fca876342cf0474bStephen Hines // instruction offset in binary coincides with the actual 1406d1862363c88c183b0ed7740fca876342cf0474bStephen Hines // instruction address in virtual memory (as code section 1416d1862363c88c183b0ed7740fca876342cf0474bStephen Hines // is mapped to a fixed memory range). 1426d1862363c88c183b0ed7740fca876342cf0474bStephen Hines // * If a binary is compiled with -pie, all the modules are 1436d1862363c88c183b0ed7740fca876342cf0474bStephen Hines // mapped high at address space (in particular, higher than 1446d1862363c88c183b0ed7740fca876342cf0474bStephen Hines // shadow memory of the tool), so the module can't be the 1456d1862363c88c183b0ed7740fca876342cf0474bStephen Hines // first entry. 1466d1862363c88c183b0ed7740fca876342cf0474bStephen Hines uptr base_address = (i ? cur_beg : 0) - cur_offset; 147259f7063e3e4c4b94dded1e90ab0a943d0fa737bPirama Arumuga Nainar LoadedModule *cur_module = &modules[n_modules]; 148259f7063e3e4c4b94dded1e90ab0a943d0fa737bPirama Arumuga Nainar cur_module->set(cur_name, base_address); 1496d1862363c88c183b0ed7740fca876342cf0474bStephen Hines cur_module->addAddressRange(cur_beg, cur_end, prot & kProtectionExecute); 1506d1862363c88c183b0ed7740fca876342cf0474bStephen Hines n_modules++; 1516d1862363c88c183b0ed7740fca876342cf0474bStephen Hines } 1526d1862363c88c183b0ed7740fca876342cf0474bStephen Hines return n_modules; 1536d1862363c88c183b0ed7740fca876342cf0474bStephen Hines} 1546d1862363c88c183b0ed7740fca876342cf0474bStephen Hines 1556d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesvoid GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) { 1563d763c0d3700e73b3aead8e65e04ec28efc56138Pirama Arumuga Nainar char *smaps = nullptr; 1576d1862363c88c183b0ed7740fca876342cf0474bStephen Hines uptr smaps_cap = 0; 1583d763c0d3700e73b3aead8e65e04ec28efc56138Pirama Arumuga Nainar uptr smaps_len = 0; 1593d763c0d3700e73b3aead8e65e04ec28efc56138Pirama Arumuga Nainar if (!ReadFileToBuffer("/proc/self/smaps", &smaps, &smaps_cap, &smaps_len)) 1603d763c0d3700e73b3aead8e65e04ec28efc56138Pirama Arumuga Nainar return; 1616d1862363c88c183b0ed7740fca876342cf0474bStephen Hines uptr start = 0; 1626d1862363c88c183b0ed7740fca876342cf0474bStephen Hines bool file = false; 1636d1862363c88c183b0ed7740fca876342cf0474bStephen Hines const char *pos = smaps; 1646d1862363c88c183b0ed7740fca876342cf0474bStephen Hines while (pos < smaps + smaps_len) { 1656d1862363c88c183b0ed7740fca876342cf0474bStephen Hines if (IsHex(pos[0])) { 1666d1862363c88c183b0ed7740fca876342cf0474bStephen Hines start = ParseHex(&pos); 1676d1862363c88c183b0ed7740fca876342cf0474bStephen Hines for (; *pos != '/' && *pos > '\n'; pos++) {} 1686d1862363c88c183b0ed7740fca876342cf0474bStephen Hines file = *pos == '/'; 1696d1862363c88c183b0ed7740fca876342cf0474bStephen Hines } else if (internal_strncmp(pos, "Rss:", 4) == 0) { 1706d1862363c88c183b0ed7740fca876342cf0474bStephen Hines while (!IsDecimal(*pos)) pos++; 1716d1862363c88c183b0ed7740fca876342cf0474bStephen Hines uptr rss = ParseDecimal(&pos) * 1024; 1726d1862363c88c183b0ed7740fca876342cf0474bStephen Hines cb(start, rss, file, stats, stats_size); 1736d1862363c88c183b0ed7740fca876342cf0474bStephen Hines } 1746d1862363c88c183b0ed7740fca876342cf0474bStephen Hines while (*pos++ != '\n') {} 1756d1862363c88c183b0ed7740fca876342cf0474bStephen Hines } 1766d1862363c88c183b0ed7740fca876342cf0474bStephen Hines UnmapOrDie(smaps, smaps_cap); 1776d1862363c88c183b0ed7740fca876342cf0474bStephen Hines} 1786d1862363c88c183b0ed7740fca876342cf0474bStephen Hines 1793d763c0d3700e73b3aead8e65e04ec28efc56138Pirama Arumuga Nainar} // namespace __sanitizer 1806d1862363c88c183b0ed7740fca876342cf0474bStephen Hines 1813d763c0d3700e73b3aead8e65e04ec28efc56138Pirama Arumuga Nainar#endif // SANITIZER_FREEBSD || SANITIZER_LINUX 182