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