1 //===-- sanitizer_procmaps_common.cc --------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // Information about the process mappings (common parts).
9 //===----------------------------------------------------------------------===//
11 #include "sanitizer_platform.h"
13 #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
15 #include "sanitizer_common.h"
16 #include "sanitizer_placement_new.h"
17 #include "sanitizer_procmaps.h"
19 namespace __sanitizer
{
21 static ProcSelfMapsBuff cached_proc_self_maps
;
22 static StaticSpinMutex cache_lock
;
24 static int TranslateDigit(char c
) {
25 if (c
>= '0' && c
<= '9')
27 if (c
>= 'a' && c
<= 'f')
29 if (c
>= 'A' && c
<= 'F')
34 // Parse a number and promote 'p' up to the first non-digit character.
35 static uptr
ParseNumber(const char **p
, int base
) {
38 CHECK(base
>= 2 && base
<= 16);
39 while ((d
= TranslateDigit(**p
)) >= 0 && d
< base
) {
46 bool IsDecimal(char c
) {
47 int d
= TranslateDigit(c
);
48 return d
>= 0 && d
< 10;
51 uptr
ParseDecimal(const char **p
) {
52 return ParseNumber(p
, 10);
56 int d
= TranslateDigit(c
);
57 return d
>= 0 && d
< 16;
60 uptr
ParseHex(const char **p
) {
61 return ParseNumber(p
, 16);
64 void MemoryMappedSegment::AddAddressRanges(LoadedModule
*module
) {
65 // data_ should be unused on this platform
67 module
->addAddressRange(start
, end
, IsExecutable(), IsWritable());
70 MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled
) {
71 ReadProcMaps(&data_
.proc_self_maps
);
73 if (data_
.proc_self_maps
.mmaped_size
== 0) {
75 CHECK_GT(data_
.proc_self_maps
.len
, 0);
78 CHECK_GT(data_
.proc_self_maps
.mmaped_size
, 0);
81 // FIXME: in the future we may want to cache the mappings on demand only.
83 CacheMemoryMappings();
86 MemoryMappingLayout::~MemoryMappingLayout() {
87 // Only unmap the buffer if it is different from the cached one. Otherwise
88 // it will be unmapped when the cache is refreshed.
89 if (data_
.proc_self_maps
.data
!= cached_proc_self_maps
.data
) {
90 UnmapOrDie(data_
.proc_self_maps
.data
, data_
.proc_self_maps
.mmaped_size
);
94 void MemoryMappingLayout::Reset() { data_
.current
= data_
.proc_self_maps
.data
; }
97 void MemoryMappingLayout::CacheMemoryMappings() {
98 SpinMutexLock
l(&cache_lock
);
99 // Don't invalidate the cache if the mappings are unavailable.
100 ProcSelfMapsBuff old_proc_self_maps
;
101 old_proc_self_maps
= cached_proc_self_maps
;
102 ReadProcMaps(&cached_proc_self_maps
);
103 if (cached_proc_self_maps
.mmaped_size
== 0) {
104 cached_proc_self_maps
= old_proc_self_maps
;
106 if (old_proc_self_maps
.mmaped_size
) {
107 UnmapOrDie(old_proc_self_maps
.data
,
108 old_proc_self_maps
.mmaped_size
);
113 void MemoryMappingLayout::LoadFromCache() {
114 SpinMutexLock
l(&cache_lock
);
115 if (cached_proc_self_maps
.data
) {
116 data_
.proc_self_maps
= cached_proc_self_maps
;
120 void MemoryMappingLayout::DumpListOfModules(
121 InternalMmapVectorNoCtor
<LoadedModule
> *modules
) {
123 InternalScopedString
module_name(kMaxPathLength
);
124 MemoryMappedSegment
segment(module_name
.data(), module_name
.size());
125 for (uptr i
= 0; Next(&segment
); i
++) {
126 const char *cur_name
= segment
.filename
;
127 if (cur_name
[0] == '\0')
129 // Don't subtract 'cur_beg' from the first entry:
130 // * If a binary is compiled w/o -pie, then the first entry in
131 // process maps is likely the binary itself (all dynamic libs
132 // are mapped higher in address space). For such a binary,
133 // instruction offset in binary coincides with the actual
134 // instruction address in virtual memory (as code section
135 // is mapped to a fixed memory range).
136 // * If a binary is compiled with -pie, all the modules are
137 // mapped high at address space (in particular, higher than
138 // shadow memory of the tool), so the module can't be the
140 uptr base_address
= (i
? segment
.start
: 0) - segment
.offset
;
141 LoadedModule cur_module
;
142 cur_module
.set(cur_name
, base_address
);
143 segment
.AddAddressRanges(&cur_module
);
144 modules
->push_back(cur_module
);
148 void GetMemoryProfile(fill_profile_f cb
, uptr
*stats
, uptr stats_size
) {
149 char *smaps
= nullptr;
152 if (!ReadFileToBuffer("/proc/self/smaps", &smaps
, &smaps_cap
, &smaps_len
))
156 const char *pos
= smaps
;
157 while (pos
< smaps
+ smaps_len
) {
159 start
= ParseHex(&pos
);
160 for (; *pos
!= '/' && *pos
> '\n'; pos
++) {}
162 } else if (internal_strncmp(pos
, "Rss:", 4) == 0) {
163 while (!IsDecimal(*pos
)) pos
++;
164 uptr rss
= ParseDecimal(&pos
) * 1024;
165 cb(start
, rss
, file
, stats
, stats_size
);
167 while (*pos
++ != '\n') {}
169 UnmapOrDie(smaps
, smaps_cap
);
172 } // namespace __sanitizer
174 #endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD