sanitizer_procmaps_common.cc 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. //===-- sanitizer_procmaps_common.cc --------------------------------------===//
  2. //
  3. // This file is distributed under the University of Illinois Open Source
  4. // License. See LICENSE.TXT for details.
  5. //
  6. //===----------------------------------------------------------------------===//
  7. //
  8. // Information about the process mappings (common parts).
  9. //===----------------------------------------------------------------------===//
  10. #include "sanitizer_platform.h"
  11. #if SANITIZER_FREEBSD || SANITIZER_LINUX
  12. #include "sanitizer_common.h"
  13. #include "sanitizer_placement_new.h"
  14. #include "sanitizer_procmaps.h"
  15. namespace __sanitizer {
  16. // Linker initialized.
  17. ProcSelfMapsBuff MemoryMappingLayout::cached_proc_self_maps_;
  18. StaticSpinMutex MemoryMappingLayout::cache_lock_; // Linker initialized.
  19. static int TranslateDigit(char c) {
  20. if (c >= '0' && c <= '9')
  21. return c - '0';
  22. if (c >= 'a' && c <= 'f')
  23. return c - 'a' + 10;
  24. if (c >= 'A' && c <= 'F')
  25. return c - 'A' + 10;
  26. return -1;
  27. }
  28. // Parse a number and promote 'p' up to the first non-digit character.
  29. static uptr ParseNumber(const char **p, int base) {
  30. uptr n = 0;
  31. int d;
  32. CHECK(base >= 2 && base <= 16);
  33. while ((d = TranslateDigit(**p)) >= 0 && d < base) {
  34. n = n * base + d;
  35. (*p)++;
  36. }
  37. return n;
  38. }
  39. bool IsDecimal(char c) {
  40. int d = TranslateDigit(c);
  41. return d >= 0 && d < 10;
  42. }
  43. uptr ParseDecimal(const char **p) {
  44. return ParseNumber(p, 10);
  45. }
  46. bool IsHex(char c) {
  47. int d = TranslateDigit(c);
  48. return d >= 0 && d < 16;
  49. }
  50. uptr ParseHex(const char **p) {
  51. return ParseNumber(p, 16);
  52. }
  53. MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) {
  54. ReadProcMaps(&proc_self_maps_);
  55. if (cache_enabled) {
  56. if (proc_self_maps_.mmaped_size == 0) {
  57. LoadFromCache();
  58. CHECK_GT(proc_self_maps_.len, 0);
  59. }
  60. } else {
  61. CHECK_GT(proc_self_maps_.mmaped_size, 0);
  62. }
  63. Reset();
  64. // FIXME: in the future we may want to cache the mappings on demand only.
  65. if (cache_enabled)
  66. CacheMemoryMappings();
  67. }
  68. MemoryMappingLayout::~MemoryMappingLayout() {
  69. // Only unmap the buffer if it is different from the cached one. Otherwise
  70. // it will be unmapped when the cache is refreshed.
  71. if (proc_self_maps_.data != cached_proc_self_maps_.data) {
  72. UnmapOrDie(proc_self_maps_.data, proc_self_maps_.mmaped_size);
  73. }
  74. }
  75. void MemoryMappingLayout::Reset() {
  76. current_ = proc_self_maps_.data;
  77. }
  78. // static
  79. void MemoryMappingLayout::CacheMemoryMappings() {
  80. SpinMutexLock l(&cache_lock_);
  81. // Don't invalidate the cache if the mappings are unavailable.
  82. ProcSelfMapsBuff old_proc_self_maps;
  83. old_proc_self_maps = cached_proc_self_maps_;
  84. ReadProcMaps(&cached_proc_self_maps_);
  85. if (cached_proc_self_maps_.mmaped_size == 0) {
  86. cached_proc_self_maps_ = old_proc_self_maps;
  87. } else {
  88. if (old_proc_self_maps.mmaped_size) {
  89. UnmapOrDie(old_proc_self_maps.data,
  90. old_proc_self_maps.mmaped_size);
  91. }
  92. }
  93. }
  94. void MemoryMappingLayout::LoadFromCache() {
  95. SpinMutexLock l(&cache_lock_);
  96. if (cached_proc_self_maps_.data) {
  97. proc_self_maps_ = cached_proc_self_maps_;
  98. }
  99. }
  100. uptr MemoryMappingLayout::DumpListOfModules(LoadedModule *modules,
  101. uptr max_modules,
  102. string_predicate_t filter) {
  103. Reset();
  104. uptr cur_beg, cur_end, cur_offset, prot;
  105. InternalScopedBuffer<char> module_name(kMaxPathLength);
  106. uptr n_modules = 0;
  107. for (uptr i = 0; n_modules < max_modules &&
  108. Next(&cur_beg, &cur_end, &cur_offset, module_name.data(),
  109. module_name.size(), &prot);
  110. i++) {
  111. const char *cur_name = module_name.data();
  112. if (cur_name[0] == '\0')
  113. continue;
  114. if (filter && !filter(cur_name))
  115. continue;
  116. void *mem = &modules[n_modules];
  117. // Don't subtract 'cur_beg' from the first entry:
  118. // * If a binary is compiled w/o -pie, then the first entry in
  119. // process maps is likely the binary itself (all dynamic libs
  120. // are mapped higher in address space). For such a binary,
  121. // instruction offset in binary coincides with the actual
  122. // instruction address in virtual memory (as code section
  123. // is mapped to a fixed memory range).
  124. // * If a binary is compiled with -pie, all the modules are
  125. // mapped high at address space (in particular, higher than
  126. // shadow memory of the tool), so the module can't be the
  127. // first entry.
  128. uptr base_address = (i ? cur_beg : 0) - cur_offset;
  129. LoadedModule *cur_module = new(mem) LoadedModule(cur_name, base_address);
  130. cur_module->addAddressRange(cur_beg, cur_end, prot & kProtectionExecute);
  131. n_modules++;
  132. }
  133. return n_modules;
  134. }
  135. void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) {
  136. char *smaps = 0;
  137. uptr smaps_cap = 0;
  138. uptr smaps_len = ReadFileToBuffer("/proc/self/smaps",
  139. &smaps, &smaps_cap, 64<<20);
  140. uptr start = 0;
  141. bool file = false;
  142. const char *pos = smaps;
  143. while (pos < smaps + smaps_len) {
  144. if (IsHex(pos[0])) {
  145. start = ParseHex(&pos);
  146. for (; *pos != '/' && *pos > '\n'; pos++) {}
  147. file = *pos == '/';
  148. } else if (internal_strncmp(pos, "Rss:", 4) == 0) {
  149. while (!IsDecimal(*pos)) pos++;
  150. uptr rss = ParseDecimal(&pos) * 1024;
  151. cb(start, rss, file, stats, stats_size);
  152. }
  153. while (*pos++ != '\n') {}
  154. }
  155. UnmapOrDie(smaps, smaps_cap);
  156. }
  157. } // namespace __sanitizer
  158. #endif // SANITIZER_FREEBSD || SANITIZER_LINUX