diff options
author | Christopher Ferris <cferris@google.com> | 2015-03-26 19:18:36 -0700 |
---|---|---|
committer | Christopher Ferris <cferris@google.com> | 2015-03-31 10:51:44 -0700 |
commit | 2c43cff01d1271be451671567955158629b23670 (patch) | |
tree | b08d199b9cc4d0b665d7dc844cadedf883d0590c /libbacktrace/BacktracePtrace.cpp | |
parent | e29744d94df787fa83307572d90a954b1592f69b (diff) | |
download | system_core-2c43cff01d1271be451671567955158629b23670.zip system_core-2c43cff01d1271be451671567955158629b23670.tar.gz system_core-2c43cff01d1271be451671567955158629b23670.tar.bz2 |
Refactor the code.
The object hierarchy was confusing and convoluted. This removes
a lot of unnecessary code, and consolidates the BacktraceCurrent
and BacktraceThread code into BacktraceCurrent.
Change-Id: I01c8407d493712a48169df49dd3ff46db4a7c3ae
Diffstat (limited to 'libbacktrace/BacktracePtrace.cpp')
-rw-r--r-- | libbacktrace/BacktracePtrace.cpp | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/libbacktrace/BacktracePtrace.cpp b/libbacktrace/BacktracePtrace.cpp new file mode 100644 index 0000000..6134438 --- /dev/null +++ b/libbacktrace/BacktracePtrace.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2013 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 <errno.h> +#include <stdint.h> +#include <string.h> +#include <sys/param.h> +#include <sys/ptrace.h> +#include <sys/types.h> +#include <ucontext.h> +#include <unistd.h> + +#include <backtrace/Backtrace.h> +#include <backtrace/BacktraceMap.h> + +#include "BacktraceLog.h" +#include "BacktracePtrace.h" +#include "thread_utils.h" + +#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), nullptr); + 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 + if (!VerifyReadWordArgs(ptr, out_value)) { + return false; + } + + 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 +} |