Create an UnwindMapLocal object.

The way libunwind handles local unwinds is different from remote unwinds,
so create a new map object to handle the differences.

Add new test to verify the map data is being generated correctly.

Add new tests to check for leaks.

Refactor the BACK_LOGW code into a single header file.

Change-Id: I01f3cbfc4b927646174ea1b614fa25d23b9b3427
diff --git a/libbacktrace/GetPss.cpp b/libbacktrace/GetPss.cpp
new file mode 100644
index 0000000..442383b
--- /dev/null
+++ b/libbacktrace/GetPss.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+// This is an extremely simplified version of libpagemap.
+
+#define _BITS(x, offset, bits) (((x) >> offset) & ((1LL << (bits)) - 1))
+
+#define PAGEMAP_PRESENT(x)     (_BITS(x, 63, 1))
+#define PAGEMAP_SWAPPED(x)     (_BITS(x, 62, 1))
+#define PAGEMAP_SHIFT(x)       (_BITS(x, 55, 6))
+#define PAGEMAP_PFN(x)         (_BITS(x, 0, 55))
+#define PAGEMAP_SWAP_OFFSET(x) (_BITS(x, 5, 50))
+#define PAGEMAP_SWAP_TYPE(x)   (_BITS(x, 0,  5))
+
+static bool ReadData(int fd, unsigned long place, uint64_t *data) {
+  if (lseek(fd, place * sizeof(uint64_t), SEEK_SET) < 0) {
+    return false;
+  }
+  if (read(fd, (void*)data, sizeof(uint64_t)) != (ssize_t)sizeof(uint64_t)) {
+    return false;
+  }
+  return true;
+}
+
+size_t GetPssBytes() {
+  FILE* maps = fopen("/proc/self/maps", "r");
+  assert(maps != NULL);
+
+  int pagecount_fd = open("/proc/kpagecount", O_RDONLY);
+  assert(pagecount_fd >= 0);
+
+  int pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
+  assert(pagemap_fd >= 0);
+
+  char line[4096];
+  size_t total_pss = 0;
+  int pagesize = getpagesize();
+  while (fgets(line, sizeof(line), maps)) {
+    uintptr_t start, end;
+    if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR " ", &start, &end) != 2) {
+      total_pss = 0;
+      break;
+    }
+    for (size_t page = start/pagesize; page < end/pagesize; page++) {
+      uint64_t data;
+      if (ReadData(pagemap_fd, page, &data)) {
+        if (PAGEMAP_PRESENT(data) && !PAGEMAP_SWAPPED(data)) {
+          uint64_t count;
+          if (ReadData(pagecount_fd, PAGEMAP_PFN(data), &count)) {
+            total_pss += (count >= 1) ? pagesize / count : 0;
+          }
+        }
+      }
+    }
+  }
+
+  fclose(maps);
+
+  close(pagecount_fd);
+  close(pagemap_fd);
+
+  return total_pss;
+}