Merge "Allow native bridge to work without a code cache"
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index a335eec..641b537 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -118,7 +118,7 @@
             return socket_loopback_server(port, SOCK_STREAM);
         }
     }
-#ifndef HAVE_WIN32_IPC  /* no Unix-domain sockets on Win32 */
+#if !defined(_WIN32)  // No Unix-domain sockets on Windows.
     // It's nonsensical to support the "reserved" space on the adb host side
     if (!strncmp(name, "local:", 6)) {
         return socket_local_server(name + 6, ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
diff --git a/adb/protocol.txt b/adb/protocol.txt
index c9d3c24..333e7e7 100644
--- a/adb/protocol.txt
+++ b/adb/protocol.txt
@@ -133,7 +133,7 @@
 
 
 
---- WRITE(0, remote-id, "data") ----------------------------------------
+--- WRITE(local-id, remote-id, "data") ---------------------------------
 
 The WRITE message sends data to the recipient's stream identified by
 remote-id.  The payload MUST be <= maxdata in length.
diff --git a/adb/remount_service.cpp b/adb/remount_service.cpp
index 3a4d2da..2893263 100644
--- a/adb/remount_service.cpp
+++ b/adb/remount_service.cpp
@@ -33,9 +33,12 @@
 #include "adb_io.h"
 #include "adb_utils.h"
 #include "cutils/properties.h"
+#include "fs_mgr.h"
+
+const std::string kFstab_Prefix = "/fstab.";
 
 // Returns the device used to mount a directory in /proc/mounts.
-static std::string find_mount(const char* dir) {
+static std::string find_proc_mount(const char* dir) {
     std::unique_ptr<FILE, int(*)(FILE*)> fp(setmntent("/proc/mounts", "r"), endmntent);
     if (!fp) {
         return "";
@@ -50,6 +53,29 @@
     return "";
 }
 
+// Returns the device used to mount a directory in the fstab.
+static std::string find_fstab_mount(const char* dir) {
+    char propbuf[PROPERTY_VALUE_MAX];
+
+    property_get("ro.hardware", propbuf, "");
+    std::string fstab_filename = kFstab_Prefix + propbuf;
+    struct fstab* fstab = fs_mgr_read_fstab(fstab_filename.c_str());
+    struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab, dir);
+    std::string dev = rec ? std::string(rec->blk_device) : "";
+    fs_mgr_free_fstab(fstab);
+    return dev;
+}
+
+// The proc entry for / is full of lies, so check fstab instead.
+// /proc/mounts lists rootfs and /dev/root, neither of which is what we want.
+static std::string find_mount(const char* dir) {
+    if (strcmp(dir, "/") == 0) {
+       return find_fstab_mount(dir);
+    } else {
+       return find_proc_mount(dir);
+    }
+}
+
 bool make_block_device_writable(const std::string& dev) {
     int fd = unix_open(dev.c_str(), O_RDONLY | O_CLOEXEC);
     if (fd == -1) {
@@ -112,7 +138,13 @@
     }
 
     bool success = true;
-    success &= remount_partition(fd, "/system");
+    property_get("ro.build.system_root_image", prop_buf, "");
+    bool system_root = !strcmp(prop_buf, "true");
+    if (system_root) {
+        success &= remount_partition(fd, "/");
+    } else {
+        success &= remount_partition(fd, "/system");
+    }
     success &= remount_partition(fd, "/vendor");
     success &= remount_partition(fd, "/oem");
 
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index 6cfb541..3fca709 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -77,12 +77,12 @@
 
 debuggerd_test_src_files := \
     utility.cpp \
-    test/dump_maps_test.cpp \
     test/dump_memory_test.cpp \
     test/elf_fake.cpp \
     test/log_fake.cpp \
     test/property_fake.cpp \
     test/ptrace_fake.cpp \
+    test/tombstone_test.cpp \
     test/selinux_fake.cpp \
 
 debuggerd_shared_libraries := \
diff --git a/debuggerd/arm/machine.cpp b/debuggerd/arm/machine.cpp
index b7d6997..78c2306 100644
--- a/debuggerd/arm/machine.cpp
+++ b/debuggerd/arm/machine.cpp
@@ -15,12 +15,15 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "DEBUG"
+
 #include <errno.h>
 #include <stdint.h>
 #include <string.h>
 #include <sys/ptrace.h>
 
 #include <backtrace/Backtrace.h>
+#include <log/log.h>
 
 #include "machine.h"
 #include "utility.h"
@@ -28,7 +31,7 @@
 void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
   pt_regs regs;
   if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &regs)) {
-    _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
+    ALOGE("cannot get registers: %s\n", strerror(errno));
     return;
   }
 
@@ -48,7 +51,7 @@
 void dump_registers(log_t* log, pid_t tid) {
   pt_regs r;
   if (ptrace(PTRACE_GETREGS, tid, 0, &r)) {
-    _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
+    ALOGE("cannot get registers: %s\n", strerror(errno));
     return;
   }
 
@@ -68,7 +71,7 @@
 
   user_vfp vfp_regs;
   if (ptrace(PTRACE_GETVFPREGS, tid, 0, &vfp_regs)) {
-    _LOG(log, logtype::ERROR, "cannot get FP registers: %s\n", strerror(errno));
+    ALOGE("cannot get FP registers: %s\n", strerror(errno));
     return;
   }
 
diff --git a/debuggerd/arm64/machine.cpp b/debuggerd/arm64/machine.cpp
index 2e097da..e7bf79a 100644
--- a/debuggerd/arm64/machine.cpp
+++ b/debuggerd/arm64/machine.cpp
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "DEBUG"
+
 #include <elf.h>
 #include <errno.h>
 #include <stdint.h>
@@ -23,6 +25,7 @@
 #include <sys/uio.h>
 
 #include <backtrace/Backtrace.h>
+#include <log/log.h>
 
 #include "machine.h"
 #include "utility.h"
@@ -34,8 +37,7 @@
   io.iov_len = sizeof(regs);
 
   if (ptrace(PTRACE_GETREGSET, backtrace->Tid(), reinterpret_cast<void*>(NT_PRSTATUS), &io) == -1) {
-    _LOG(log, logtype::ERROR, "%s: ptrace failed to get registers: %s",
-         __func__, strerror(errno));
+    ALOGE("ptrace failed to get registers: %s", strerror(errno));
     return;
   }
 
@@ -57,7 +59,7 @@
   io.iov_len = sizeof(r);
 
   if (ptrace(PTRACE_GETREGSET, tid, (void*) NT_PRSTATUS, (void*) &io) == -1) {
-    _LOG(log, logtype::ERROR, "ptrace error: %s\n", strerror(errno));
+    ALOGE("ptrace error: %s\n", strerror(errno));
     return;
   }
 
@@ -81,7 +83,7 @@
   io.iov_len = sizeof(f);
 
   if (ptrace(PTRACE_GETREGSET, tid, (void*) NT_PRFPREG, (void*) &io) == -1) {
-    _LOG(log, logtype::ERROR, "ptrace error: %s\n", strerror(errno));
+    ALOGE("ptrace error: %s\n", strerror(errno));
     return;
   }
 
diff --git a/debuggerd/backtrace.cpp b/debuggerd/backtrace.cpp
index b8084c5..b46f8f4 100644
--- a/debuggerd/backtrace.cpp
+++ b/debuggerd/backtrace.cpp
@@ -105,7 +105,7 @@
   }
 
   if (!attached && ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
-    _LOG(log, logtype::ERROR, "ptrace detach from %d failed: %s\n", tid, strerror(errno));
+    ALOGE("ptrace detach from %d failed: %s\n", tid, strerror(errno));
     *detach_failed = true;
   }
 }
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 26d6389..787b7aa 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -63,32 +63,18 @@
   int32_t original_si_code;
 };
 
-static void wait_for_user_action(const debugger_request_t &request) {
-  // Find out the name of the process that crashed.
-  char path[64];
-  snprintf(path, sizeof(path), "/proc/%d/exe", request.pid);
-
-  char exe[PATH_MAX];
-  int count;
-  if ((count = readlink(path, exe, sizeof(exe) - 1)) == -1) {
-    ALOGE("readlink('%s') failed: %s", path, strerror(errno));
-    strlcpy(exe, "unknown", sizeof(exe));
-  } else {
-    exe[count] = '\0';
-  }
-
+static void wait_for_user_action(const debugger_request_t& request) {
   // Explain how to attach the debugger.
-  ALOGI("********************************************************\n"
+  ALOGI("***********************************************************\n"
         "* Process %d has been suspended while crashing.\n"
-        "* To attach gdbserver for a gdb connection on port 5039\n"
-        "* and start gdbclient:\n"
+        "* To attach gdbserver and start gdb, run this on the host:\n"
         "*\n"
-        "*     gdbclient %s :5039 %d\n"
+        "*     gdbclient %d\n"
         "*\n"
         "* Wait for gdb to start, then press the VOLUME DOWN key\n"
         "* to let the process continue crashing.\n"
-        "********************************************************",
-        request.pid, exe, request.tid);
+        "***********************************************************",
+        request.pid, request.tid);
 
   // Wait for VOLUME DOWN.
   if (init_getevent() == 0) {
@@ -250,10 +236,7 @@
 
 static bool should_attach_gdb(debugger_request_t* request) {
   if (request->action == DEBUGGER_ACTION_CRASH) {
-    char value[PROPERTY_VALUE_MAX];
-    property_get("debug.db.uid", value, "-1");
-    int debug_uid = atoi(value);
-    return debug_uid >= 0 && request->uid <= (uid_t)debug_uid;
+    return property_get_bool("debug.debuggerd.wait_for_gdb", false);
   }
   return false;
 }
diff --git a/debuggerd/mips/machine.cpp b/debuggerd/mips/machine.cpp
index f7b8a86..cbf272a 100644
--- a/debuggerd/mips/machine.cpp
+++ b/debuggerd/mips/machine.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "DEBUG"
+
 #include <errno.h>
 #include <inttypes.h>
 #include <stdint.h>
@@ -21,6 +23,7 @@
 #include <sys/ptrace.h>
 
 #include <backtrace/Backtrace.h>
+#include <log/log.h>
 
 #include "machine.h"
 #include "utility.h"
@@ -32,7 +35,7 @@
 void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
   pt_regs r;
   if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &r)) {
-    _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
+    ALOGE("cannot get registers: %s\n", strerror(errno));
     return;
   }
 
@@ -61,7 +64,7 @@
 void dump_registers(log_t* log, pid_t tid) {
   pt_regs r;
   if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
-    _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
+    ALOGE("cannot get registers: %s\n", strerror(errno));
     return;
   }
 
diff --git a/debuggerd/mips64/machine.cpp b/debuggerd/mips64/machine.cpp
index 293dcf6..0a8d532 100644
--- a/debuggerd/mips64/machine.cpp
+++ b/debuggerd/mips64/machine.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "DEBUG"
+
 #include <errno.h>
 #include <inttypes.h>
 #include <stdint.h>
@@ -21,6 +23,7 @@
 #include <sys/ptrace.h>
 
 #include <backtrace/Backtrace.h>
+#include <log/log.h>
 
 #include "machine.h"
 #include "utility.h"
@@ -32,7 +35,7 @@
 void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
   pt_regs r;
   if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &r)) {
-    _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
+    ALOGE("cannot get registers: %s\n", strerror(errno));
     return;
   }
 
@@ -61,7 +64,7 @@
 void dump_registers(log_t* log, pid_t tid) {
   pt_regs r;
   if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
-    _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
+    ALOGE("cannot get registers: %s\n", strerror(errno));
     return;
   }
 
diff --git a/debuggerd/test/BacktraceMock.h b/debuggerd/test/BacktraceMock.h
index 5c252ab..f75534e 100644
--- a/debuggerd/test/BacktraceMock.h
+++ b/debuggerd/test/BacktraceMock.h
@@ -60,12 +60,14 @@
     }
     size_t bytes_available = buffer_.size() - offset;
 
-    if (bytes_partial_read_ > 0) {
+    if (do_partial_read_) {
       // Do a partial read.
       if (bytes > bytes_partial_read_) {
         bytes = bytes_partial_read_;
       }
       bytes_partial_read_ -= bytes;
+      // Only support a single partial read.
+      do_partial_read_ = false;
     } else if (bytes > bytes_available) {
       bytes = bytes_available;
     }
@@ -82,6 +84,7 @@
     buffer_.resize(bytes);
     memcpy(buffer_.data(), buffer, bytes);
     bytes_partial_read_ = 0;
+    do_partial_read_ = false;
     last_read_addr_ = 0;
   }
 
@@ -90,12 +93,14 @@
       abort();
     }
     bytes_partial_read_ = bytes;
+    do_partial_read_ = true;
   }
 
  private:
   std::vector<uint8_t> buffer_;
   size_t bytes_partial_read_ = 0;
   uintptr_t last_read_addr_ = 0;
+  bool do_partial_read_ = false;
 };
 
 #endif //  _DEBUGGERD_TEST_BACKTRACE_MOCK_H
diff --git a/debuggerd/test/dump_memory_test.cpp b/debuggerd/test/dump_memory_test.cpp
index fcb0108..75e7028 100644
--- a/debuggerd/test/dump_memory_test.cpp
+++ b/debuggerd/test/dump_memory_test.cpp
@@ -288,9 +288,9 @@
   ASSERT_STREQ(g_expected_partial_dump, tombstone_contents.c_str());
 
 #if defined(__LP64__)
-  ASSERT_STREQ("DEBUG Bytes read 102, is not a multiple of 8\n", getFakeLogPrint().c_str());
+  ASSERT_STREQ("6 DEBUG Bytes read 102, is not a multiple of 8\n", getFakeLogPrint().c_str());
 #else
-  ASSERT_STREQ("DEBUG Bytes read 102, is not a multiple of 4\n", getFakeLogPrint().c_str());
+  ASSERT_STREQ("6 DEBUG Bytes read 102, is not a multiple of 4\n", getFakeLogPrint().c_str());
 #endif
 
   // Verify that the log buf is empty, and no error messages.
@@ -313,12 +313,12 @@
   ASSERT_STREQ(g_expected_partial_dump, tombstone_contents.c_str());
 
 #if defined(__LP64__)
-  ASSERT_STREQ("DEBUG Bytes read 45, is not a multiple of 8\n"
-               "DEBUG Bytes after second read 106, is not a multiple of 8\n",
+  ASSERT_STREQ("6 DEBUG Bytes read 45, is not a multiple of 8\n"
+               "6 DEBUG Bytes after second read 106, is not a multiple of 8\n",
                getFakeLogPrint().c_str());
 #else
-  ASSERT_STREQ("DEBUG Bytes read 45, is not a multiple of 4\n"
-               "DEBUG Bytes after second read 106, is not a multiple of 4\n",
+  ASSERT_STREQ("6 DEBUG Bytes read 45, is not a multiple of 4\n"
+               "6 DEBUG Bytes after second read 106, is not a multiple of 4\n",
                getFakeLogPrint().c_str());
 #endif
 
@@ -502,3 +502,239 @@
   ASSERT_STREQ("", getFakeLogBuf().c_str());
   ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
+
+TEST_F(DumpMemoryTest, first_read_empty) {
+  uint8_t buffer[256];
+  for (size_t i = 0; i < sizeof(buffer); i++) {
+    buffer[i] = i;
+  }
+  backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+  backtrace_mock_->SetPartialReadAmount(0);
+
+  size_t page_size = sysconf(_SC_PAGE_SIZE);
+  uintptr_t addr = 0x10000020 + page_size - 120;
+  dump_memory(&log_, backtrace_mock_.get(), addr, "memory near %.2s:", "r4");
+
+  std::string tombstone_contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  const char* expected_dump = \
+"\nmemory near r4:\n"
+#if defined(__LP64__)
+"    0000000010000f88 ---------------- ----------------  ................\n"
+"    0000000010000f98 ---------------- ----------------  ................\n"
+"    0000000010000fa8 ---------------- ----------------  ................\n"
+"    0000000010000fb8 ---------------- ----------------  ................\n"
+"    0000000010000fc8 ---------------- ----------------  ................\n"
+"    0000000010000fd8 ---------------- ----------------  ................\n"
+"    0000000010000fe8 ---------------- ----------------  ................\n"
+"    0000000010000ff8 ---------------- 7f7e7d7c7b7a7978  ........xyz{|}~.\n"
+"    0000000010001008 8786858483828180 8f8e8d8c8b8a8988  ................\n"
+"    0000000010001018 9796959493929190 9f9e9d9c9b9a9998  ................\n"
+"    0000000010001028 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8  ................\n"
+"    0000000010001038 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8  ................\n"
+"    0000000010001048 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8  ................\n"
+"    0000000010001058 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8  ................\n"
+"    0000000010001068 e7e6e5e4e3e2e1e0 efeeedecebeae9e8  ................\n"
+"    0000000010001078 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8  ................\n";
+#else
+"    10000f88 -------- -------- -------- --------  ................\n"
+"    10000f98 -------- -------- -------- --------  ................\n"
+"    10000fa8 -------- -------- -------- --------  ................\n"
+"    10000fb8 -------- -------- -------- --------  ................\n"
+"    10000fc8 -------- -------- -------- --------  ................\n"
+"    10000fd8 -------- -------- -------- --------  ................\n"
+"    10000fe8 -------- -------- -------- --------  ................\n"
+"    10000ff8 -------- -------- 7b7a7978 7f7e7d7c  ........xyz{|}~.\n"
+"    10001008 83828180 87868584 8b8a8988 8f8e8d8c  ................\n"
+"    10001018 93929190 97969594 9b9a9998 9f9e9d9c  ................\n"
+"    10001028 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac  ................\n"
+"    10001038 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc  ................\n"
+"    10001048 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc  ................\n"
+"    10001058 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc  ................\n"
+"    10001068 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec  ................\n"
+"    10001078 f3f2f1f0 f7f6f5f4 fbfaf9f8 fffefdfc  ................\n";
+#endif
+  ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+  // Verify that the log buf is empty, and no error messages.
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMemoryTest, first_read_empty_second_read_stops) {
+  uint8_t buffer[224];
+  for (size_t i = 0; i < sizeof(buffer); i++) {
+    buffer[i] = i;
+  }
+  backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+  backtrace_mock_->SetPartialReadAmount(0);
+
+  size_t page_size = sysconf(_SC_PAGE_SIZE);
+  uintptr_t addr = 0x10000020 + page_size - 192;
+  dump_memory(&log_, backtrace_mock_.get(), addr, "memory near %.2s:", "r4");
+
+  std::string tombstone_contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  const char* expected_dump = \
+"\nmemory near r4:\n"
+#if defined(__LP64__)
+"    0000000010000f40 ---------------- ----------------  ................\n"
+"    0000000010000f50 ---------------- ----------------  ................\n"
+"    0000000010000f60 ---------------- ----------------  ................\n"
+"    0000000010000f70 ---------------- ----------------  ................\n"
+"    0000000010000f80 ---------------- ----------------  ................\n"
+"    0000000010000f90 ---------------- ----------------  ................\n"
+"    0000000010000fa0 ---------------- ----------------  ................\n"
+"    0000000010000fb0 ---------------- ----------------  ................\n"
+"    0000000010000fc0 ---------------- ----------------  ................\n"
+"    0000000010000fd0 ---------------- ----------------  ................\n"
+"    0000000010000fe0 ---------------- ----------------  ................\n"
+"    0000000010000ff0 ---------------- ----------------  ................\n"
+"    0000000010001000 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8  ................\n"
+"    0000000010001010 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8  ................\n"
+"    0000000010001020 ---------------- ----------------  ................\n"
+"    0000000010001030 ---------------- ----------------  ................\n";
+#else
+"    10000f40 -------- -------- -------- --------  ................\n"
+"    10000f50 -------- -------- -------- --------  ................\n"
+"    10000f60 -------- -------- -------- --------  ................\n"
+"    10000f70 -------- -------- -------- --------  ................\n"
+"    10000f80 -------- -------- -------- --------  ................\n"
+"    10000f90 -------- -------- -------- --------  ................\n"
+"    10000fa0 -------- -------- -------- --------  ................\n"
+"    10000fb0 -------- -------- -------- --------  ................\n"
+"    10000fc0 -------- -------- -------- --------  ................\n"
+"    10000fd0 -------- -------- -------- --------  ................\n"
+"    10000fe0 -------- -------- -------- --------  ................\n"
+"    10000ff0 -------- -------- -------- --------  ................\n"
+"    10001000 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc  ................\n"
+"    10001010 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc  ................\n"
+"    10001020 -------- -------- -------- --------  ................\n"
+"    10001030 -------- -------- -------- --------  ................\n";
+#endif
+  ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+  // Verify that the log buf is empty, and no error messages.
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMemoryTest, first_read_empty_next_page_out_of_range) {
+  uint8_t buffer[256];
+  for (size_t i = 0; i < sizeof(buffer); i++) {
+    buffer[i] = i;
+  }
+  backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+  backtrace_mock_->SetPartialReadAmount(0);
+
+  uintptr_t addr = 0x10000020;
+  dump_memory(&log_, backtrace_mock_.get(), addr, "memory near %.2s:", "r4");
+
+  std::string tombstone_contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  const char* expected_dump = \
+"\nmemory near r4:\n"
+#if defined(__LP64__)
+"    0000000010000000 ---------------- ----------------  ................\n"
+"    0000000010000010 ---------------- ----------------  ................\n"
+"    0000000010000020 ---------------- ----------------  ................\n"
+"    0000000010000030 ---------------- ----------------  ................\n"
+"    0000000010000040 ---------------- ----------------  ................\n"
+"    0000000010000050 ---------------- ----------------  ................\n"
+"    0000000010000060 ---------------- ----------------  ................\n"
+"    0000000010000070 ---------------- ----------------  ................\n"
+"    0000000010000080 ---------------- ----------------  ................\n"
+"    0000000010000090 ---------------- ----------------  ................\n"
+"    00000000100000a0 ---------------- ----------------  ................\n"
+"    00000000100000b0 ---------------- ----------------  ................\n"
+"    00000000100000c0 ---------------- ----------------  ................\n"
+"    00000000100000d0 ---------------- ----------------  ................\n"
+"    00000000100000e0 ---------------- ----------------  ................\n"
+"    00000000100000f0 ---------------- ----------------  ................\n";
+#else
+"    10000000 -------- -------- -------- --------  ................\n"
+"    10000010 -------- -------- -------- --------  ................\n"
+"    10000020 -------- -------- -------- --------  ................\n"
+"    10000030 -------- -------- -------- --------  ................\n"
+"    10000040 -------- -------- -------- --------  ................\n"
+"    10000050 -------- -------- -------- --------  ................\n"
+"    10000060 -------- -------- -------- --------  ................\n"
+"    10000070 -------- -------- -------- --------  ................\n"
+"    10000080 -------- -------- -------- --------  ................\n"
+"    10000090 -------- -------- -------- --------  ................\n"
+"    100000a0 -------- -------- -------- --------  ................\n"
+"    100000b0 -------- -------- -------- --------  ................\n"
+"    100000c0 -------- -------- -------- --------  ................\n"
+"    100000d0 -------- -------- -------- --------  ................\n"
+"    100000e0 -------- -------- -------- --------  ................\n"
+"    100000f0 -------- -------- -------- --------  ................\n";
+#endif
+  ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+  // Verify that the log buf is empty, and no error messages.
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
+
+TEST_F(DumpMemoryTest, first_read_empty_next_page_out_of_range_fence_post) {
+  uint8_t buffer[256];
+  for (size_t i = 0; i < sizeof(buffer); i++) {
+    buffer[i] = i;
+  }
+  backtrace_mock_->SetReadData(buffer, sizeof(buffer));
+  backtrace_mock_->SetPartialReadAmount(0);
+
+  size_t page_size = sysconf(_SC_PAGE_SIZE);
+  uintptr_t addr = 0x10000020 + page_size - 256;
+
+  dump_memory(&log_, backtrace_mock_.get(), addr, "memory near %.2s:", "r4");
+
+  std::string tombstone_contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  const char* expected_dump = \
+"\nmemory near r4:\n"
+#if defined(__LP64__)
+"    0000000010000f00 ---------------- ----------------  ................\n"
+"    0000000010000f10 ---------------- ----------------  ................\n"
+"    0000000010000f20 ---------------- ----------------  ................\n"
+"    0000000010000f30 ---------------- ----------------  ................\n"
+"    0000000010000f40 ---------------- ----------------  ................\n"
+"    0000000010000f50 ---------------- ----------------  ................\n"
+"    0000000010000f60 ---------------- ----------------  ................\n"
+"    0000000010000f70 ---------------- ----------------  ................\n"
+"    0000000010000f80 ---------------- ----------------  ................\n"
+"    0000000010000f90 ---------------- ----------------  ................\n"
+"    0000000010000fa0 ---------------- ----------------  ................\n"
+"    0000000010000fb0 ---------------- ----------------  ................\n"
+"    0000000010000fc0 ---------------- ----------------  ................\n"
+"    0000000010000fd0 ---------------- ----------------  ................\n"
+"    0000000010000fe0 ---------------- ----------------  ................\n"
+"    0000000010000ff0 ---------------- ----------------  ................\n";
+#else
+"    10000f00 -------- -------- -------- --------  ................\n"
+"    10000f10 -------- -------- -------- --------  ................\n"
+"    10000f20 -------- -------- -------- --------  ................\n"
+"    10000f30 -------- -------- -------- --------  ................\n"
+"    10000f40 -------- -------- -------- --------  ................\n"
+"    10000f50 -------- -------- -------- --------  ................\n"
+"    10000f60 -------- -------- -------- --------  ................\n"
+"    10000f70 -------- -------- -------- --------  ................\n"
+"    10000f80 -------- -------- -------- --------  ................\n"
+"    10000f90 -------- -------- -------- --------  ................\n"
+"    10000fa0 -------- -------- -------- --------  ................\n"
+"    10000fb0 -------- -------- -------- --------  ................\n"
+"    10000fc0 -------- -------- -------- --------  ................\n"
+"    10000fd0 -------- -------- -------- --------  ................\n"
+"    10000fe0 -------- -------- -------- --------  ................\n"
+"    10000ff0 -------- -------- -------- --------  ................\n";
+#endif
+  ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+
+  // Verify that the log buf is empty, and no error messages.
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("", getFakeLogPrint().c_str());
+}
diff --git a/debuggerd/test/log_fake.cpp b/debuggerd/test/log_fake.cpp
index 26523ad..d584a5e 100644
--- a/debuggerd/test/log_fake.cpp
+++ b/debuggerd/test/log_fake.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <errno.h>
 #include <stdarg.h>
 
 #include <string>
@@ -44,14 +45,16 @@
   return g_fake_log_print;
 }
 
-extern "C" int __android_log_buf_write(int, int, const char* tag, const char* msg) {
+extern "C" int __android_log_buf_write(int bufId, int prio, const char* tag, const char* msg) {
+  g_fake_log_buf += std::to_string(bufId) + ' ' + std::to_string(prio) + ' ';
   g_fake_log_buf += tag;
   g_fake_log_buf += ' ';
   g_fake_log_buf += msg;
   return 1;
 }
 
-extern "C" int __android_log_print(int, const char* tag, const char* fmt, ...) {
+extern "C" int __android_log_print(int prio, const char* tag, const char* fmt, ...) {
+  g_fake_log_print += std::to_string(prio) + ' ';
   g_fake_log_print += tag;
   g_fake_log_print += ' ';
 
@@ -70,6 +73,7 @@
 }
 
 extern "C" struct logger_list* android_logger_list_open(log_id_t, int, unsigned int, pid_t) {
+  errno = EACCES;
   return nullptr;
 }
 
diff --git a/debuggerd/test/dump_maps_test.cpp b/debuggerd/test/tombstone_test.cpp
similarity index 90%
rename from debuggerd/test/dump_maps_test.cpp
rename to debuggerd/test/tombstone_test.cpp
index 230f4f5..a771a39 100644
--- a/debuggerd/test/dump_maps_test.cpp
+++ b/debuggerd/test/tombstone_test.cpp
@@ -45,7 +45,7 @@
 void dump_backtrace_to_log(Backtrace*, log_t*, char const*) {
 }
 
-class DumpMapsTest : public ::testing::Test {
+class TombstoneTest : public ::testing::Test {
  protected:
   virtual void SetUp() {
     map_mock_.reset(new BacktraceMapMock());
@@ -92,7 +92,7 @@
   log_t log_;
 };
 
-TEST_F(DumpMapsTest, single_map) {
+TEST_F(TombstoneTest, single_map) {
   backtrace_map_t map;
 #if defined(__LP64__)
   map.start = 0x123456789abcd000UL;
@@ -122,7 +122,7 @@
   ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
-TEST_F(DumpMapsTest, single_map_elf_build_id) {
+TEST_F(TombstoneTest, single_map_elf_build_id) {
   backtrace_map_t map;
 #if defined(__LP64__)
   map.start = 0x123456789abcd000UL;
@@ -157,7 +157,7 @@
 
 // Even though build id is present, it should not be printed in either of
 // these cases.
-TEST_F(DumpMapsTest, single_map_no_build_id) {
+TEST_F(TombstoneTest, single_map_no_build_id) {
   backtrace_map_t map;
 #if defined(__LP64__)
   map.start = 0x123456789abcd000UL;
@@ -194,7 +194,7 @@
   ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
-TEST_F(DumpMapsTest, multiple_maps) {
+TEST_F(TombstoneTest, multiple_maps) {
   backtrace_map_t map;
 
   map.start = 0xa234000;
@@ -256,7 +256,7 @@
   ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
-TEST_F(DumpMapsTest, multiple_maps_fault_address_before) {
+TEST_F(TombstoneTest, multiple_maps_fault_address_before) {
   backtrace_map_t map;
 
   map.start = 0xa434000;
@@ -310,7 +310,7 @@
   ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
-TEST_F(DumpMapsTest, multiple_maps_fault_address_between) {
+TEST_F(TombstoneTest, multiple_maps_fault_address_between) {
   backtrace_map_t map;
 
   map.start = 0xa434000;
@@ -364,7 +364,7 @@
   ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
-TEST_F(DumpMapsTest, multiple_maps_fault_address_in_map) {
+TEST_F(TombstoneTest, multiple_maps_fault_address_in_map) {
   backtrace_map_t map;
 
   map.start = 0xa434000;
@@ -416,7 +416,7 @@
   ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
-TEST_F(DumpMapsTest, multiple_maps_fault_address_after) {
+TEST_F(TombstoneTest, multiple_maps_fault_address_after) {
   backtrace_map_t map;
 
   map.start = 0xa434000;
@@ -474,7 +474,7 @@
   ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
-TEST_F(DumpMapsTest, multiple_maps_getsiginfo_fail) {
+TEST_F(TombstoneTest, multiple_maps_getsiginfo_fail) {
   backtrace_map_t map;
 
   map.start = 0xa434000;
@@ -493,7 +493,6 @@
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
   const char* expected_dump = \
-"Cannot get siginfo for 100: Bad address\n"
 "\nmemory map:\n"
 #if defined(__LP64__)
 "    00000000'0a434000-00000000'0a434fff -w-      1000      1000  (load base 0xd000)\n";
@@ -503,12 +502,11 @@
   ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
 
   // Verify that the log buf is empty, and no error messages.
-  ASSERT_STREQ("DEBUG Cannot get siginfo for 100: Bad address\n",
-               getFakeLogBuf().c_str());
-  ASSERT_STREQ("", getFakeLogPrint().c_str());
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("6 DEBUG Cannot get siginfo for 100: Bad address\n\n", getFakeLogPrint().c_str());
 }
 
-TEST_F(DumpMapsTest, multiple_maps_check_signal_has_si_addr) {
+TEST_F(TombstoneTest, multiple_maps_check_signal_has_si_addr) {
   backtrace_map_t map;
 
   map.start = 0xa434000;
@@ -569,3 +567,33 @@
     ASSERT_STREQ("", getFakeLogPrint().c_str());
   }
 }
+
+TEST_F(TombstoneTest, dump_signal_info_error) {
+  siginfo_t si;
+  si.si_signo = 0;
+  ptrace_set_fake_getsiginfo(si);
+
+  dump_signal_info(&log_, 123, SIGSEGV, 10);
+
+  std::string tombstone_contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  ASSERT_STREQ("", tombstone_contents.c_str());
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("6 DEBUG cannot get siginfo: Bad address\n\n", getFakeLogPrint().c_str());
+}
+
+TEST_F(TombstoneTest, dump_log_file_error) {
+  log_.should_retrieve_logcat = true;
+  dump_log_file(&log_, 123, "/fake/filename", 10);
+
+  std::string tombstone_contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
+  ASSERT_STREQ("", tombstone_contents.c_str());
+
+  ASSERT_STREQ("", getFakeLogBuf().c_str());
+  ASSERT_STREQ("6 DEBUG Unable to open /fake/filename: Permission denied\n\n",
+               getFakeLogPrint().c_str());
+}
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index b0ad274..114c7e4 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -180,7 +180,7 @@
   siginfo_t si;
   memset(&si, 0, sizeof(si));
   if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si) == -1) {
-    _LOG(log, logtype::HEADER, "cannot get siginfo: %s\n", strerror(errno));
+    ALOGE("cannot get siginfo: %s\n", strerror(errno));
     return;
   }
 
@@ -338,7 +338,7 @@
     print_fault_address_marker = signal_has_si_addr(si.si_signo);
     addr = reinterpret_cast<uintptr_t>(si.si_addr);
   } else {
-    _LOG(log, logtype::ERROR, "Cannot get siginfo for %d: %s\n", tid, strerror(errno));
+    ALOGE("Cannot get siginfo for %d: %s\n", tid, strerror(errno));
   }
 
   _LOG(log, logtype::MAPS, "\n");
@@ -448,7 +448,7 @@
 
     // Skip this thread if cannot ptrace it
     if (ptrace(PTRACE_ATTACH, new_tid, 0, 0) < 0) {
-      _LOG(log, logtype::ERROR, "ptrace attach to %d failed: %s\n", new_tid, strerror(errno));
+      ALOGE("ptrace attach to %d failed: %s\n", new_tid, strerror(errno));
       continue;
     }
 
@@ -471,7 +471,7 @@
     log->current_tid = log->crashed_tid;
 
     if (ptrace(PTRACE_DETACH, new_tid, 0, 0) != 0) {
-      _LOG(log, logtype::ERROR, "ptrace detach from %d failed: %s\n", new_tid, strerror(errno));
+      ALOGE("ptrace detach from %d failed: %s\n", new_tid, strerror(errno));
       detach_failed = true;
     }
   }
@@ -517,13 +517,11 @@
         // non-blocking EOF; we're done
         break;
       } else {
-        _LOG(log, logtype::ERROR, "Error while reading log: %s\n",
-          strerror(-actual));
+        ALOGE("Error while reading log: %s\n", strerror(-actual));
         break;
       }
     } else if (actual == 0) {
-      _LOG(log, logtype::ERROR, "Got zero bytes while reading log: %s\n",
-        strerror(errno));
+      ALOGE("Got zero bytes while reading log: %s\n", strerror(errno));
       break;
     }
 
@@ -789,11 +787,11 @@
   log.crashed_tid = tid;
 
   if ((mkdir(TOMBSTONE_DIR, 0755) == -1) && (errno != EEXIST)) {
-    _LOG(&log, logtype::ERROR, "failed to create %s: %s\n", TOMBSTONE_DIR, strerror(errno));
+    ALOGE("failed to create %s: %s\n", TOMBSTONE_DIR, strerror(errno));
   }
 
   if (chown(TOMBSTONE_DIR, AID_SYSTEM, AID_SYSTEM) == -1) {
-    _LOG(&log, logtype::ERROR, "failed to change ownership of %s: %s\n", TOMBSTONE_DIR, strerror(errno));
+    ALOGE("failed to change ownership of %s: %s\n", TOMBSTONE_DIR, strerror(errno));
   }
 
   int fd = -1;
@@ -801,11 +799,11 @@
   if (selinux_android_restorecon(TOMBSTONE_DIR, 0) == 0) {
     path = find_and_open_tombstone(&fd);
   } else {
-    _LOG(&log, logtype::ERROR, "Failed to restore security context, not writing tombstone.\n");
+    ALOGE("Failed to restore security context, not writing tombstone.\n");
   }
 
   if (fd < 0) {
-    _LOG(&log, logtype::ERROR, "Skipping tombstone write, nothing to do.\n");
+    ALOGE("Skipping tombstone write, nothing to do.\n");
     *detach_failed = false;
     return NULL;
   }
diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp
index 9f340a8..f5d6ec1 100644
--- a/debuggerd/utility.cpp
+++ b/debuggerd/utility.cpp
@@ -35,8 +35,7 @@
 
 // Whitelist output desired in the logcat output.
 bool is_allowed_in_logcat(enum logtype ltype) {
-  if ((ltype == ERROR)
-   || (ltype == HEADER)
+  if ((ltype == HEADER)
    || (ltype == REGISTERS)
    || (ltype == BACKTRACE)) {
     return true;
@@ -157,13 +156,28 @@
     bytes &= ~(sizeof(uintptr_t) - 1);
   }
 
-  if (bytes < MEMORY_BYTES_TO_DUMP && bytes > 0) {
-    // Try to do one more read. This could happen if a read crosses a map, but
-    // the maps do not have any break between them. Only requires one extra
-    // read because a map has to contain at least one page, and the total
-    // number of bytes to dump is smaller than a page.
-    size_t bytes2 = backtrace->Read(addr + bytes, reinterpret_cast<uint8_t*>(data) + bytes,
-                                    sizeof(data) - bytes);
+  uintptr_t start = 0;
+  bool skip_2nd_read = false;
+  if (bytes == 0) {
+    // In this case, we might want to try another read at the beginning of
+    // the next page only if it's within the amount of memory we would have
+    // read.
+    size_t page_size = sysconf(_SC_PAGE_SIZE);
+    start = ((addr + (page_size - 1)) & ~(page_size - 1)) - addr;
+    if (start == 0 || start >= MEMORY_BYTES_TO_DUMP) {
+      skip_2nd_read = true;
+    }
+  }
+
+  if (bytes < MEMORY_BYTES_TO_DUMP && !skip_2nd_read) {
+    // Try to do one more read. This could happen if a read crosses a map,
+    // but the maps do not have any break between them. Or it could happen
+    // if reading from an unreadable map, but the read would cross back
+    // into a readable map. Only requires one extra read because a map has
+    // to contain at least one page, and the total number of bytes to dump
+    // is smaller than a page.
+    size_t bytes2 = backtrace->Read(addr + start + bytes, reinterpret_cast<uint8_t*>(data) + bytes,
+                                    sizeof(data) - bytes - start);
     bytes += bytes2;
     if (bytes2 > 0 && bytes % sizeof(uintptr_t) != 0) {
       // This should never happen, but we'll try and continue any way.
@@ -179,15 +193,16 @@
   // On 32-bit machines, there are still 16 bytes per line but addresses and
   // words are of course presented differently.
   uintptr_t* data_ptr = data;
+  size_t current = 0;
+  size_t total_bytes = start + bytes;
   for (size_t line = 0; line < MEMORY_BYTES_TO_DUMP / MEMORY_BYTES_PER_LINE; line++) {
     std::string logline;
     android::base::StringAppendF(&logline, "    %" PRIPTR, addr);
 
     addr += MEMORY_BYTES_PER_LINE;
     std::string ascii;
-    for (size_t i = 0; i < MEMORY_BYTES_PER_LINE / sizeof(uintptr_t); i++, data_ptr++) {
-      if (bytes >= sizeof(uintptr_t)) {
-        bytes -= sizeof(uintptr_t);
+    for (size_t i = 0; i < MEMORY_BYTES_PER_LINE / sizeof(uintptr_t); i++) {
+      if (current >= start && current + sizeof(uintptr_t) <= total_bytes) {
         android::base::StringAppendF(&logline, " %" PRIPTR, *data_ptr);
 
         // Fill out the ascii string from the data.
@@ -199,10 +214,12 @@
             ascii += '.';
           }
         }
+        data_ptr++;
       } else {
         logline += ' ' + std::string(sizeof(uintptr_t) * 2, '-');
         ascii += std::string(sizeof(uintptr_t), '.');
       }
+      current += sizeof(uintptr_t);
     }
     _LOG(log, logtype::MEMORY, "%s  %s\n", logline.c_str(), ascii.c_str());
   }
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index 263374d..8bef192 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -59,7 +59,6 @@
 
 // List of types of logs to simplify the logging decision in _LOG
 enum logtype {
-  ERROR,
   HEADER,
   THREAD,
   REGISTERS,
diff --git a/debuggerd/x86/machine.cpp b/debuggerd/x86/machine.cpp
index c5f9259..af10817 100644
--- a/debuggerd/x86/machine.cpp
+++ b/debuggerd/x86/machine.cpp
@@ -14,12 +14,15 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "DEBUG"
+
 #include <errno.h>
 #include <stdint.h>
 #include <string.h>
 #include <sys/ptrace.h>
 
 #include <backtrace/Backtrace.h>
+#include <log/log.h>
 
 #include "machine.h"
 #include "utility.h"
@@ -27,7 +30,7 @@
 void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
   struct pt_regs r;
   if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &r) == -1) {
-    _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
+    ALOGE("cannot get registers: %s\n", strerror(errno));
     return;
   }
 
@@ -44,7 +47,7 @@
 void dump_registers(log_t* log, pid_t tid) {
   struct pt_regs r;
   if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
-    _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
+    ALOGE("cannot get registers: %s\n", strerror(errno));
     return;
   }
 
diff --git a/debuggerd/x86_64/machine.cpp b/debuggerd/x86_64/machine.cpp
index 4f09a5d..fc86bc2 100644
--- a/debuggerd/x86_64/machine.cpp
+++ b/debuggerd/x86_64/machine.cpp
@@ -14,6 +14,8 @@
 ** limitations under the License.
 */
 
+#define LOG_TAG "DEBUG"
+
 #include <errno.h>
 #include <stdint.h>
 #include <sys/ptrace.h>
@@ -21,6 +23,7 @@
 #include <sys/user.h>
 
 #include <backtrace/Backtrace.h>
+#include <log/log.h>
 
 #include "machine.h"
 #include "utility.h"
@@ -28,7 +31,7 @@
 void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
   struct user_regs_struct r;
   if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &r) == -1) {
-    _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
+    ALOGE("cannot get registers: %s\n", strerror(errno));
     return;
   }
 
@@ -45,7 +48,7 @@
 void dump_registers(log_t* log, pid_t tid) {
   struct user_regs_struct r;
   if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
-    _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
+    ALOGE("cannot get registers: %s\n", strerror(errno));
     return;
   }
 
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 760f5cc..6bd7529 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -974,8 +974,8 @@
           << "Offset at " << i << " length " << j << " wrote too much data";
     }
   }
-  delete data;
-  delete expected;
+  delete[] data;
+  delete[] expected;
 }
 
 TEST(libbacktrace, thread_read) {
diff --git a/libsparse/sparse_crc32.h b/libsparse/sparse_crc32.h
index cad8a86..50cd9e9 100644
--- a/libsparse/sparse_crc32.h
+++ b/libsparse/sparse_crc32.h
@@ -14,7 +14,19 @@
  * limitations under the License.
  */
 
+#ifndef _LIBSPARSE_SPARSE_CRC32_H_
+#define _LIBSPARSE_SPARSE_CRC32_H_
+
 #include <stdint.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 uint32_t sparse_crc32(uint32_t crc, const void *buf, size_t size);
 
+#ifdef __cplusplus
+}
+#endif
+
+#endif