Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/xpcom/base/MemoryMapping.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "mozilla/MemoryMapping.h"
8
9
#include "mozilla/BinarySearch.h"
10
#include "mozilla/FileUtils.h"
11
12
#include <fstream>
13
#include <string>
14
15
namespace mozilla {
16
17
namespace {
18
struct VMFlagString
19
{
20
  const char* mName;
21
  const char* mPrettyName;
22
  VMFlag mFlag;
23
};
24
25
static const VMFlagString sVMFlagStrings[] = {
26
  {"ac", "Accountable",   VMFlag::Accountable},
27
  {"ar", "ArchSpecific",  VMFlag::ArchSpecific},
28
  {"dc", "NoFork",        VMFlag::NoFork},
29
  {"dd", "NoCore",        VMFlag::NoCore},
30
  {"de", "NoExpand",      VMFlag::NoExpand},
31
  {"dw", "DisabledWrite", VMFlag::DisabledWrite},
32
  {"ex", "Executable",    VMFlag::Executable},
33
  {"gd", "GrowsDown",     VMFlag::GrowsDown},
34
  {"hg", "HugePage",      VMFlag::HugePage},
35
  {"ht", "HugeTLB",       VMFlag::HugeTLB},
36
  {"io", "IO",            VMFlag::IO},
37
  {"lo", "Locked",        VMFlag::Locked},
38
  {"me", "MayExecute",    VMFlag::MayExecute},
39
  {"mg", "Mergeable",     VMFlag::Mergeable},
40
  {"mm", "MixedMap",      VMFlag::MixedMap},
41
  {"mr", "MayRead",       VMFlag::MayRead},
42
  {"ms", "MayShare",      VMFlag::MayShare},
43
  {"mw", "MayWrite",      VMFlag::MayWrite},
44
  {"nh", "NoHugePage",    VMFlag::NoHugePage},
45
  {"nl", "NonLinear",     VMFlag::NonLinear},
46
  {"nr", "NotReserved",   VMFlag::NotReserved},
47
  {"pf", "PurePFN",       VMFlag::PurePFN},
48
  {"rd", "Readable",      VMFlag::Readable},
49
  {"rr", "Random",        VMFlag::Random},
50
  {"sd", "SoftDirty",     VMFlag::SoftDirty},
51
  {"sh", "Shared",        VMFlag::Shared},
52
  {"sr", "Sequential",    VMFlag::Sequential},
53
  {"wr", "Writable",      VMFlag::Writable},
54
};
55
} // anonymous namespace
56
57
constexpr size_t kVMFlags = size_t(-1);
58
59
// An array of known field names which may be present in an smaps file, and the
60
// offsets of the corresponding fields in a MemoryMapping class.
61
const MemoryMapping::Field MemoryMapping::sFields[] = {
62
  {"AnonHugePages",   offsetof(MemoryMapping, mAnonHugePages)},
63
  {"Anonymous",       offsetof(MemoryMapping, mAnonymous)},
64
  {"KernelPageSize",  offsetof(MemoryMapping, mKernelPageSize)},
65
  {"LazyFree",        offsetof(MemoryMapping, mLazyFree)},
66
  {"Locked",          offsetof(MemoryMapping, mLocked)},
67
  {"MMUPageSize",     offsetof(MemoryMapping, mMMUPageSize)},
68
  {"Private_Clean",   offsetof(MemoryMapping, mPrivate_Clean)},
69
  {"Private_Dirty",   offsetof(MemoryMapping, mPrivate_Dirty)},
70
  {"Private_Hugetlb", offsetof(MemoryMapping, mPrivate_Hugetlb)},
71
  {"Pss",             offsetof(MemoryMapping, mPss)},
72
  {"Referenced",      offsetof(MemoryMapping, mReferenced)},
73
  {"Rss",             offsetof(MemoryMapping, mRss)},
74
  {"Shared_Clean",    offsetof(MemoryMapping, mShared_Clean)},
75
  {"Shared_Dirty",    offsetof(MemoryMapping, mShared_Dirty)},
76
  {"Shared_Hugetlb",  offsetof(MemoryMapping, mShared_Hugetlb)},
77
  {"ShmemPmdMapped",  offsetof(MemoryMapping, mShmemPmdMapped)},
78
  {"Size",            offsetof(MemoryMapping, mSize)},
79
  {"Swap",            offsetof(MemoryMapping, mSwap)},
80
  {"SwapPss",         offsetof(MemoryMapping, mSwapPss)},
81
  // VmFlags is a special case. It contains an array of flag strings, which
82
  // describe attributes of the mapping, rather than a mapping size. We include
83
  // it in this array to aid in parsing, but give it a separate sentinel value,
84
  // and treat it specially.
85
  {"VmFlags",         kVMFlags},
86
};
87
88
template <typename T, int n>
89
const T*
90
FindEntry(const char* aName, const T (&aEntries)[n])
91
0
{
92
0
  size_t index;
93
0
  if (BinarySearchIf(aEntries, 0, n,
94
0
                     [&] (const T& aEntry) {
95
0
                       return strcmp(aName, aEntry.mName);
96
0
                     },
Unexecuted instantiation: mozilla::MemoryMapping::Field const* mozilla::FindEntry<mozilla::MemoryMapping::Field, 20>(char const*, mozilla::MemoryMapping::Field const (&) [20])::{lambda(mozilla::MemoryMapping::Field const&)#1}::operator()(mozilla::MemoryMapping::Field const&) const
Unexecuted instantiation: Unified_cpp_xpcom_base0.cpp:mozilla::(anonymous namespace)::VMFlagString const* mozilla::FindEntry<mozilla::(anonymous namespace)::VMFlagString, 28>(char const*, mozilla::(anonymous namespace)::VMFlagString const (&) [28])::{lambda(mozilla::(anonymous namespace)::VMFlagString const&)#1}::operator()(mozilla::(anonymous namespace)::VMFlagString const&) const
97
0
                     &index)) {
98
0
    return &aEntries[index];
99
0
  }
100
0
  return nullptr;
101
0
}
Unexecuted instantiation: mozilla::MemoryMapping::Field const* mozilla::FindEntry<mozilla::MemoryMapping::Field, 20>(char const*, mozilla::MemoryMapping::Field const (&) [20])
Unexecuted instantiation: Unified_cpp_xpcom_base0.cpp:mozilla::(anonymous namespace)::VMFlagString const* mozilla::FindEntry<mozilla::(anonymous namespace)::VMFlagString, 28>(char const*, mozilla::(anonymous namespace)::VMFlagString const (&) [28])
102
103
using Perm = MemoryMapping::Perm;
104
using PermSet = MemoryMapping::PermSet;
105
106
nsresult
107
GetMemoryMappings(nsTArray<MemoryMapping>& aMappings)
108
0
{
109
0
  std::ifstream stream("/proc/self/smaps");
110
0
  if (stream.fail()) {
111
0
    return NS_ERROR_FAILURE;
112
0
  }
113
0
114
0
  MemoryMapping* current = nullptr;
115
0
  std::string buffer;
116
0
  while (std::getline(stream, buffer)) {
117
0
    size_t start, end, offset;
118
0
    char flags[4] = "---";
119
0
    char name[512];
120
0
121
0
    name[0] = 0;
122
0
123
0
    // Match the start of an entry. A typical line looks something like:
124
0
    //
125
0
    // 1487118a7000-148711a5a000 r-xp 00000000 103:03 54004561                  /usr/lib/libc-2.27.so
126
0
    if (sscanf(buffer.c_str(), "%zx-%zx %4c %zx %*u:%*u %*u %511s\n",
127
0
               &start, &end, flags, &offset, name) >= 4) {
128
0
      PermSet perms;
129
0
      if (flags[0] == 'r') {
130
0
        perms += Perm::Read;
131
0
      }
132
0
      if (flags[1] == 'w') {
133
0
        perms += Perm::Write;
134
0
      }
135
0
      if (flags[2] == 'x') {
136
0
        perms += Perm::Execute;
137
0
      }
138
0
      if (flags[3] == 'p') {
139
0
        perms += Perm::Private;
140
0
      } else if (flags[3] == 's') {
141
0
        perms += Perm::Shared;
142
0
      }
143
0
144
0
      current = aMappings.AppendElement(MemoryMapping{start, end, perms, offset, name});
145
0
      continue;
146
0
    }
147
0
    if (!current) {
148
0
      continue;
149
0
    }
150
0
151
0
    nsAutoCStringN<128> line(buffer.c_str());
152
0
    char* savePtr;
153
0
    char* fieldName = strtok_r(line.BeginWriting(), ":", &savePtr);
154
0
    if (!fieldName) {
155
0
      continue;
156
0
    }
157
0
    auto* field = FindEntry(fieldName, MemoryMapping::sFields);
158
0
    if (!field) {
159
0
      continue;
160
0
    }
161
0
162
0
    if (field->mOffset == kVMFlags) {
163
0
      while (char* flagName = strtok_r(nullptr, " \n", &savePtr)) {
164
0
        if (auto* flag = FindEntry(flagName, sVMFlagStrings)) {
165
0
          current->mFlags += flag->mFlag;
166
0
        }
167
0
      }
168
0
      continue;
169
0
    }
170
0
171
0
    const char* rest = strtok_r(nullptr, "\n", &savePtr);
172
0
    size_t value;
173
0
    if (sscanf(rest, "%zd kB", &value) > 0) {
174
0
      current->ValueForField(*field) = value * 1024;
175
0
    }
176
0
  }
177
0
178
0
  return NS_OK;
179
0
}
180
181
void
182
MemoryMapping::Dump(nsACString& aOut) const
183
0
{
184
0
  aOut.AppendPrintf("%zx-%zx Size: %zu Offset: %zx %s\n",
185
0
                    mStart, mEnd,
186
0
                    mEnd - mStart,
187
0
                    mOffset, mName.get());
188
0
189
0
  for (auto& field : MemoryMapping::sFields) {
190
0
    if (field.mOffset < sizeof(*this)) {
191
0
      aOut.AppendPrintf("  %s: %zd\n", field.mName, ValueForField(field));
192
0
    }
193
0
  }
194
0
195
0
  aOut.AppendPrintf("  Flags: %x\n", mFlags.serialize());
196
0
  for (auto& flag : sVMFlagStrings) {
197
0
    if (mFlags.contains(flag.mFlag)) {
198
0
      aOut.AppendPrintf("       : %s %s\n", flag.mName, flag.mPrettyName);
199
0
    }
200
0
  }
201
0
}
202
203
} // namespace mozilla