Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2b4a63fc authored by Christopher Ferris's avatar Christopher Ferris
Browse files

Add variable length read to Backtrace.

Included tests for this new feature.

Changed the NULLs to nullptr in backtrace_test.

Changed UniquePtr to std::unique_ptr in backtrace_test.

Change-Id: I92375465b8f8ba84589834cc162db5915bf1be81
parent 928cbdd2
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -84,6 +84,12 @@ public:
  // Read the data at a specific address.
  virtual bool ReadWord(uintptr_t ptr, word_t* out_value) = 0;

  // Read arbitrary data from a specific address. If a read request would
  // span from one map to another, this call only reads up until the end
  // of the current map.
  // Returns the total number of bytes actually read.
  virtual size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) = 0;

  // Create a string representing the formatted line of backtrace information
  // for a single frame.
  virtual std::string FormatFrameData(size_t frame_num);
+85 −10
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <ucontext.h>
@@ -159,6 +160,17 @@ bool BacktraceCurrent::ReadWord(uintptr_t ptr, word_t* out_value) {
  }
}

size_t BacktraceCurrent::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) {
  backtrace_map_t map;
  FillInMap(addr, &map);
  if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) {
    return 0;
  }
  bytes = MIN(map.end - addr, bytes);
  memcpy(buffer, reinterpret_cast<uint8_t*>(addr), bytes);
  return bytes;
}

//-------------------------------------------------------------------------
// BacktracePtrace functions.
//-------------------------------------------------------------------------
@@ -171,25 +183,88 @@ BacktracePtrace::BacktracePtrace(
BacktracePtrace::~BacktracePtrace() {
}

bool BacktracePtrace::ReadWord(uintptr_t ptr, word_t* out_value) {
  if (!VerifyReadWordArgs(ptr, out_value)) {
#if !defined(__APPLE__)
static bool PtraceRead(pid_t tid, uintptr_t addr, word_t* out_value) {
  // ptrace() returns -1 and sets errno when the operation fails.
  // To disambiguate -1 from a valid result, we clear errno beforehand.
  errno = 0;
  *out_value = ptrace(PTRACE_PEEKTEXT, tid, reinterpret_cast<void*>(addr), NULL);
  if (*out_value == static_cast<word_t>(-1) && errno) {
    BACK_LOGW("invalid pointer %p reading from tid %d, ptrace() strerror(errno)=%s",
              reinterpret_cast<void*>(addr), tid, strerror(errno));
    return false;
  }
  return true;
}
#endif

bool BacktracePtrace::ReadWord(uintptr_t ptr, word_t* out_value) {
#if defined(__APPLE__)
  BACK_LOGW("MacOS does not support reading from another pid.");
  return false;
#else
  // ptrace() returns -1 and sets errno when the operation fails.
  // To disambiguate -1 from a valid result, we clear errno beforehand.
  errno = 0;
  *out_value = ptrace(PTRACE_PEEKTEXT, Tid(), reinterpret_cast<void*>(ptr), NULL);
  if (*out_value == static_cast<word_t>(-1) && errno) {
    BACK_LOGW("invalid pointer %p reading from tid %d, ptrace() strerror(errno)=%s",
              reinterpret_cast<void*>(ptr), Tid(), strerror(errno));
  if (!VerifyReadWordArgs(ptr, out_value)) {
    return false;
  }
  return true;

  backtrace_map_t map;
  FillInMap(ptr, &map);
  if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) {
    return false;
  }

  return PtraceRead(Tid(), ptr, out_value);
#endif
}

size_t BacktracePtrace::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) {
#if defined(__APPLE__)
  BACK_LOGW("MacOS does not support reading from another pid.");
  return 0;
#else
  backtrace_map_t map;
  FillInMap(addr, &map);
  if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) {
    return 0;
  }

  bytes = MIN(map.end - addr, bytes);
  size_t bytes_read = 0;
  word_t data_word;
  size_t align_bytes = addr & (sizeof(word_t) - 1);
  if (align_bytes != 0) {
    if (!PtraceRead(Tid(), addr & ~(sizeof(word_t) - 1), &data_word)) {
      return 0;
    }
    align_bytes = sizeof(word_t) - align_bytes;
    memcpy(buffer, reinterpret_cast<uint8_t*>(&data_word) + sizeof(word_t) - align_bytes,
           align_bytes);
    addr += align_bytes;
    buffer += align_bytes;
    bytes -= align_bytes;
    bytes_read += align_bytes;
  }

  size_t num_words = bytes / sizeof(word_t);
  for (size_t i = 0; i < num_words; i++) {
    if (!PtraceRead(Tid(), addr, &data_word)) {
      return bytes_read;
    }
    memcpy(buffer, &data_word, sizeof(word_t));
    buffer += sizeof(word_t);
    addr += sizeof(word_t);
    bytes_read += sizeof(word_t);
  }

  size_t left_over = bytes & (sizeof(word_t) - 1);
  if (left_over) {
    if (!PtraceRead(Tid(), addr, &data_word)) {
      return bytes_read;
    }
    memcpy(buffer, &data_word, left_over);
    bytes_read += left_over;
  }
  return bytes_read;
#endif
}

+4 −0
Original line number Diff line number Diff line
@@ -56,6 +56,8 @@ public:
  BacktraceCurrent(BacktraceImpl* impl, BacktraceMap* map);
  virtual ~BacktraceCurrent();

  size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes);

  bool ReadWord(uintptr_t ptr, word_t* out_value);
};

@@ -64,6 +66,8 @@ public:
  BacktracePtrace(BacktraceImpl* impl, pid_t pid, pid_t tid, BacktraceMap* map);
  virtual ~BacktracePtrace();

  size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes);

  bool ReadWord(uintptr_t ptr, word_t* out_value);
};

+238 −77

File changed.

Preview size limit exceeded, changes collapsed.