Merge "Refactor dump_memory function."

This commit is contained in:
Christopher Ferris 2015-05-28 18:02:09 +00:00 committed by Gerrit Code Review
commit a684d9dad5
15 changed files with 992 additions and 240 deletions

View file

@ -1,4 +1,12 @@
LOCAL_PATH:= $(call my-dir)
LOCAL_PATH := $(call my-dir)
common_cppflags := \
-std=gnu++11 \
-W \
-Wall \
-Wextra \
-Wunused \
-Werror \
include $(CLEAR_VARS)
@ -17,11 +25,7 @@ LOCAL_SRC_FILES_mips64 := mips64/machine.cpp
LOCAL_SRC_FILES_x86 := x86/machine.cpp
LOCAL_SRC_FILES_x86_64 := x86_64/machine.cpp
LOCAL_CPPFLAGS := \
-std=gnu++11 \
-W -Wall -Wextra \
-Wunused \
-Werror \
LOCAL_CPPFLAGS := $(common_cppflags)
ifeq ($(TARGET_IS_64_BIT),true)
LOCAL_CPPFLAGS += -DTARGET_IS_64_BIT
@ -70,3 +74,47 @@ LOCAL_MODULE_STEM_64 := crasher64
LOCAL_MULTILIB := both
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
utility.cpp \
test/dump_memory_test.cpp \
test/log_fake.cpp \
LOCAL_MODULE := debuggerd_test
LOCAL_SHARED_LIBRARIES := \
libbacktrace \
libbase \
LOCAL_C_INCLUDES += $(LOCAL_PATH)/test
LOCAL_CPPFLAGS := $(common_cppflags)
LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
LOCAL_MULTILIB := both
include $(BUILD_HOST_NATIVE_TEST)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
utility.cpp \
test/dump_memory_test.cpp \
test/log_fake.cpp \
LOCAL_MODULE := debuggerd_test
LOCAL_SHARED_LIBRARIES := \
libbacktrace \
libbase \
LOCAL_C_INCLUDES += $(LOCAL_PATH)/test
LOCAL_CPPFLAGS := $(common_cppflags)
LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
LOCAL_MULTILIB := both
include $(BUILD_NATIVE_TEST)

View file

@ -16,53 +16,39 @@
*/
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/user.h>
#include "../utility.h"
#include "../machine.h"
#include <backtrace/Backtrace.h>
void dump_memory_and_code(log_t* log, pid_t tid) {
#include "machine.h"
#include "utility.h"
void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
pt_regs regs;
if (ptrace(PTRACE_GETREGS, tid, 0, &regs)) {
if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &regs)) {
_LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
return;
}
static const char REG_NAMES[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp";
static const char reg_names[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp";
for (int reg = 0; reg < 14; reg++) {
// this may not be a valid way to access, but it'll do for now
uintptr_t addr = regs.uregs[reg];
// Don't bother if it looks like a small int or ~= null, or if
// it's in the kernel area.
if (addr < 4096 || addr >= 0xc0000000) {
continue;
}
_LOG(log, logtype::MEMORY, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
dump_memory(log, tid, addr);
dump_memory(log, backtrace, regs.uregs[reg], "memory near %.2s:", &reg_names[reg * 2]);
}
// explicitly allow upload of code dump logging
_LOG(log, logtype::MEMORY, "\ncode around pc:\n");
dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_pc));
dump_memory(log, backtrace, static_cast<uintptr_t>(regs.ARM_pc), "code around pc:");
if (regs.ARM_pc != regs.ARM_lr) {
_LOG(log, logtype::MEMORY, "\ncode around lr:\n");
dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_lr));
dump_memory(log, backtrace, static_cast<uintptr_t>(regs.ARM_lr), "code around lr:");
}
}
void dump_registers(log_t* log, pid_t tid) {
pt_regs r;
if (ptrace(PTRACE_GETREGS, tid, 0, &r)) {
_LOG(log, logtype::REGISTERS, "cannot get registers: %s\n", strerror(errno));
_LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
return;
}
@ -82,7 +68,7 @@ void dump_registers(log_t* log, pid_t tid) {
user_vfp vfp_regs;
if (ptrace(PTRACE_GETVFPREGS, tid, 0, &vfp_regs)) {
_LOG(log, logtype::FP_REGISTERS, "cannot get FP registers: %s\n", strerror(errno));
_LOG(log, logtype::ERROR, "cannot get FP registers: %s\n", strerror(errno));
return;
}

View file

@ -17,50 +17,37 @@
#include <elf.h>
#include <errno.h>
#include <inttypes.h>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <sys/uio.h>
#include "../utility.h"
#include "../machine.h"
#include <backtrace/Backtrace.h>
void dump_memory_and_code(log_t* log, pid_t tid) {
struct user_pt_regs regs;
struct iovec io;
io.iov_base = &regs;
io.iov_len = sizeof(regs);
#include "machine.h"
#include "utility.h"
if (ptrace(PTRACE_GETREGSET, tid, (void*)NT_PRSTATUS, &io) == -1) {
_LOG(log, logtype::ERROR, "%s: ptrace failed to get registers: %s\n",
__func__, strerror(errno));
return;
}
void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
struct user_pt_regs regs;
struct iovec io;
io.iov_base = &regs;
io.iov_len = sizeof(regs);
for (int reg = 0; reg < 31; reg++) {
uintptr_t addr = regs.regs[reg];
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));
return;
}
/*
* Don't bother if it looks like a small int or ~= null, or if
* it's in the kernel area.
*/
if (addr < 4096 || addr >= (1UL<<63)) {
continue;
}
for (int reg = 0; reg < 31; reg++) {
dump_memory(log, backtrace, regs.regs[reg], "memory near x%d:", reg);
}
_LOG(log, logtype::MEMORY, "\nmemory near x%d:\n", reg);
dump_memory(log, tid, addr);
}
dump_memory(log, backtrace, static_cast<uintptr_t>(regs.pc), "code around pc:");
_LOG(log, logtype::MEMORY, "\ncode around pc:\n");
dump_memory(log, tid, (uintptr_t)regs.pc);
if (regs.pc != regs.sp) {
_LOG(log, logtype::MEMORY, "\ncode around sp:\n");
dump_memory(log, tid, (uintptr_t)regs.sp);
}
if (regs.pc != regs.sp) {
dump_memory(log, backtrace, static_cast<uintptr_t>(regs.sp), "code around sp:");
}
}
void dump_registers(log_t* log, pid_t tid) {

View file

@ -19,9 +19,11 @@
#include <sys/types.h>
#include <backtrace/Backtrace.h>
#include "utility.h"
void dump_memory_and_code(log_t* log, pid_t tid);
void dump_memory_and_code(log_t* log, Backtrace* backtrace);
void dump_registers(log_t* log, pid_t tid);
#endif // _DEBUGGERD_MACHINE_H

View file

@ -14,30 +14,29 @@
* limitations under the License.
*/
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <inttypes.h>
#include <stdint.h>
#include <string.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <backtrace/Backtrace.h>
#include "../utility.h"
#include "../machine.h"
#include "machine.h"
#include "utility.h"
#define R(x) (static_cast<unsigned int>(x))
#define R(x) (static_cast<uintptr_t>(x))
// If configured to do so, dump memory around *all* registers
// for the crashing thread.
void dump_memory_and_code(log_t* log, pid_t tid) {
void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
pt_regs r;
if (ptrace(PTRACE_GETREGS, tid, 0, &r)) {
if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &r)) {
_LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
return;
}
static const char REG_NAMES[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
static const char reg_names[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
for (int reg = 0; reg < 32; reg++) {
// skip uninteresting registers
@ -48,27 +47,14 @@ void dump_memory_and_code(log_t* log, pid_t tid) {
)
continue;
uintptr_t addr = R(r.regs[reg]);
// Don't bother if it looks like a small int or ~= null, or if
// it's in the kernel area.
if (addr < 4096 || addr >= 0x80000000) {
continue;
}
_LOG(log, logtype::MEMORY, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
dump_memory(log, tid, addr);
dump_memory(log, backtrace, R(r.regs[reg]), "memory near %.2s:", &reg_names[reg * 2]);
}
unsigned int pc = R(r.cp0_epc);
unsigned int ra = R(r.regs[31]);
_LOG(log, logtype::MEMORY, "\ncode around pc:\n");
dump_memory(log, tid, (uintptr_t)pc);
uintptr_t pc = R(r.cp0_epc);
uintptr_t ra = R(r.regs[31]);
dump_memory(log, backtrace, pc, "code around pc:");
if (pc != ra) {
_LOG(log, logtype::MEMORY, "\ncode around ra:\n");
dump_memory(log, tid, (uintptr_t)ra);
dump_memory(log, backtrace, ra, "code around ra:");
}
}
@ -79,22 +65,31 @@ void dump_registers(log_t* log, pid_t tid) {
return;
}
_LOG(log, logtype::REGISTERS, " zr %08x at %08x v0 %08x v1 %08x\n",
_LOG(log, logtype::REGISTERS, " zr %08" PRIxPTR " at %08" PRIxPTR
" v0 %08" PRIxPTR " v1 %08" PRIxPTR "\n",
R(r.regs[0]), R(r.regs[1]), R(r.regs[2]), R(r.regs[3]));
_LOG(log, logtype::REGISTERS, " a0 %08x a1 %08x a2 %08x a3 %08x\n",
_LOG(log, logtype::REGISTERS, " a0 %08" PRIxPTR " a1 %08" PRIxPTR
" a2 %08" PRIxPTR " a3 %08" PRIxPTR "\n",
R(r.regs[4]), R(r.regs[5]), R(r.regs[6]), R(r.regs[7]));
_LOG(log, logtype::REGISTERS, " t0 %08x t1 %08x t2 %08x t3 %08x\n",
_LOG(log, logtype::REGISTERS, " t0 %08" PRIxPTR " t1 %08" PRIxPTR
" t2 %08" PRIxPTR " t3 %08" PRIxPTR "\n",
R(r.regs[8]), R(r.regs[9]), R(r.regs[10]), R(r.regs[11]));
_LOG(log, logtype::REGISTERS, " t4 %08x t5 %08x t6 %08x t7 %08x\n",
_LOG(log, logtype::REGISTERS, " t4 %08" PRIxPTR " t5 %08" PRIxPTR
" t6 %08" PRIxPTR " t7 %08" PRIxPTR "\n",
R(r.regs[12]), R(r.regs[13]), R(r.regs[14]), R(r.regs[15]));
_LOG(log, logtype::REGISTERS, " s0 %08x s1 %08x s2 %08x s3 %08x\n",
_LOG(log, logtype::REGISTERS, " s0 %08" PRIxPTR " s1 %08" PRIxPTR
" s2 %08" PRIxPTR " s3 %08" PRIxPTR "\n",
R(r.regs[16]), R(r.regs[17]), R(r.regs[18]), R(r.regs[19]));
_LOG(log, logtype::REGISTERS, " s4 %08x s5 %08x s6 %08x s7 %08x\n",
_LOG(log, logtype::REGISTERS, " s4 %08" PRIxPTR " s5 %08" PRIxPTR
" s6 %08" PRIxPTR " s7 %08" PRIxPTR "\n",
R(r.regs[20]), R(r.regs[21]), R(r.regs[22]), R(r.regs[23]));
_LOG(log, logtype::REGISTERS, " t8 %08x t9 %08x k0 %08x k1 %08x\n",
_LOG(log, logtype::REGISTERS, " t8 %08" PRIxPTR " t9 %08" PRIxPTR
" k0 %08" PRIxPTR " k1 %08" PRIxPTR "\n",
R(r.regs[24]), R(r.regs[25]), R(r.regs[26]), R(r.regs[27]));
_LOG(log, logtype::REGISTERS, " gp %08x sp %08x s8 %08x ra %08x\n",
_LOG(log, logtype::REGISTERS, " gp %08" PRIxPTR " sp %08" PRIxPTR
" s8 %08" PRIxPTR " ra %08" PRIxPTR "\n",
R(r.regs[28]), R(r.regs[29]), R(r.regs[30]), R(r.regs[31]));
_LOG(log, logtype::REGISTERS, " hi %08x lo %08x bva %08x epc %08x\n",
_LOG(log, logtype::REGISTERS, " hi %08" PRIxPTR " lo %08" PRIxPTR
" bva %08" PRIxPTR " epc %08" PRIxPTR "\n",
R(r.hi), R(r.lo), R(r.cp0_badvaddr), R(r.cp0_epc));
}

View file

@ -14,30 +14,29 @@
* limitations under the License.
*/
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <inttypes.h>
#include <stdint.h>
#include <string.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <backtrace/Backtrace.h>
#include "../utility.h"
#include "../machine.h"
#include "machine.h"
#include "utility.h"
#define R(x) (static_cast<unsigned long>(x))
#define R(x) (static_cast<uintptr_t>(x))
// If configured to do so, dump memory around *all* registers
// for the crashing thread.
void dump_memory_and_code(log_t* log, pid_t tid) {
void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
pt_regs r;
if (ptrace(PTRACE_GETREGS, tid, 0, &r)) {
if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &r)) {
_LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
return;
}
static const char REG_NAMES[] = "$0atv0v1a0a1a2a3a4a5a6a7t0t1t2t3s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
static const char reg_names[] = "$0atv0v1a0a1a2a3a4a5a6a7t0t1t2t3s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra";
for (int reg = 0; reg < 32; reg++) {
// skip uninteresting registers
@ -48,27 +47,14 @@ void dump_memory_and_code(log_t* log, pid_t tid) {
)
continue;
uintptr_t addr = R(r.regs[reg]);
// Don't bother if it looks like a small int or ~= null, or if
// it's in the kernel area.
if (addr < 4096 || addr >= 0x4000000000000000) {
continue;
}
_LOG(log, logtype::MEMORY, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
dump_memory(log, tid, addr);
dump_memory(log, backtrace, R(r.regs[reg]), "memory near %.2s:", &reg_names[reg * 2]);
}
unsigned long pc = R(r.cp0_epc);
unsigned long ra = R(r.regs[31]);
_LOG(log, logtype::MEMORY, "\ncode around pc:\n");
dump_memory(log, tid, (uintptr_t)pc);
uintptr_t pc = R(r.cp0_epc);
uintptr_t ra = R(r.regs[31]);
dump_memory(log, backtrace, pc, "code around pc:");
if (pc != ra) {
_LOG(log, logtype::MEMORY, "\ncode around ra:\n");
dump_memory(log, tid, (uintptr_t)ra);
dump_memory(log, backtrace, ra, "code around ra:");
}
}
@ -79,22 +65,31 @@ void dump_registers(log_t* log, pid_t tid) {
return;
}
_LOG(log, logtype::REGISTERS, " zr %016lx at %016lx v0 %016lx v1 %016lx\n",
_LOG(log, logtype::REGISTERS, " zr %016" PRIxPTR " at %016" PRIxPTR
" v0 %016" PRIxPTR " v1 %016" PRIxPTR "\n",
R(r.regs[0]), R(r.regs[1]), R(r.regs[2]), R(r.regs[3]));
_LOG(log, logtype::REGISTERS, " a0 %016lx a1 %016lx a2 %016lx a3 %016lx\n",
_LOG(log, logtype::REGISTERS, " a0 %016" PRIxPTR " a1 %016" PRIxPTR
" a2 %016" PRIxPTR " a3 %016" PRIxPTR "\n",
R(r.regs[4]), R(r.regs[5]), R(r.regs[6]), R(r.regs[7]));
_LOG(log, logtype::REGISTERS, " a4 %016lx a5 %016lx a6 %016lx a7 %016lx\n",
_LOG(log, logtype::REGISTERS, " a4 %016" PRIxPTR " a5 %016" PRIxPTR
" a6 %016" PRIxPTR " a7 %016" PRIxPTR "\n",
R(r.regs[8]), R(r.regs[9]), R(r.regs[10]), R(r.regs[11]));
_LOG(log, logtype::REGISTERS, " t0 %016lx t1 %016lx t2 %016lx t3 %016lx\n",
_LOG(log, logtype::REGISTERS, " t0 %016" PRIxPTR " t1 %016" PRIxPTR
" t2 %016" PRIxPTR " t3 %016" PRIxPTR "\n",
R(r.regs[12]), R(r.regs[13]), R(r.regs[14]), R(r.regs[15]));
_LOG(log, logtype::REGISTERS, " s0 %016lx s1 %016lx s2 %016lx s3 %016lx\n",
_LOG(log, logtype::REGISTERS, " s0 %016" PRIxPTR " s1 %016" PRIxPTR
" s2 %016" PRIxPTR " s3 %016" PRIxPTR "\n",
R(r.regs[16]), R(r.regs[17]), R(r.regs[18]), R(r.regs[19]));
_LOG(log, logtype::REGISTERS, " s4 %016lx s5 %016lx s6 %016lx s7 %016lx\n",
_LOG(log, logtype::REGISTERS, " s4 %016" PRIxPTR " s5 %016" PRIxPTR
" s6 %016" PRIxPTR " s7 %016" PRIxPTR "\n",
R(r.regs[20]), R(r.regs[21]), R(r.regs[22]), R(r.regs[23]));
_LOG(log, logtype::REGISTERS, " t8 %016lx t9 %016lx k0 %016lx k1 %016lx\n",
_LOG(log, logtype::REGISTERS, " t8 %016" PRIxPTR " t9 %016" PRIxPTR
" k0 %016" PRIxPTR " k1 %016" PRIxPTR "\n",
R(r.regs[24]), R(r.regs[25]), R(r.regs[26]), R(r.regs[27]));
_LOG(log, logtype::REGISTERS, " gp %016lx sp %016lx s8 %016lx ra %016lx\n",
_LOG(log, logtype::REGISTERS, " gp %016" PRIxPTR " sp %016" PRIxPTR
" s8 %016" PRIxPTR " ra %016" PRIxPTR "\n",
R(r.regs[28]), R(r.regs[29]), R(r.regs[30]), R(r.regs[31]));
_LOG(log, logtype::REGISTERS, " hi %016lx lo %016lx bva %016lx epc %016lx\n",
_LOG(log, logtype::REGISTERS, " hi %016" PRIxPTR " lo %016" PRIxPTR
" bva %016" PRIxPTR " epc %016" PRIxPTR "\n",
R(r.hi), R(r.lo), R(r.cp0_badvaddr), R(r.cp0_epc));
}

View file

@ -0,0 +1,97 @@
/*
* Copyright (C) 2015 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.
*/
#ifndef _DEBUGGERD_TEST_BACKTRACE_MOCK_H
#define _DEBUGGERD_TEST_BACKTRACE_MOCK_H
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ucontext.h>
#include <string>
#include <vector>
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
class BacktraceMapMock : public BacktraceMap {
public:
BacktraceMapMock() : BacktraceMap(0) {}
virtual ~BacktraceMapMock() {}
};
class BacktraceMock : public Backtrace {
public:
BacktraceMock(BacktraceMapMock* map) : Backtrace(0, 0, map) {
if (map_ == nullptr) {
abort();
}
}
virtual ~BacktraceMock() {}
virtual bool Unwind(size_t, ucontext_t*) { return false; }
virtual bool ReadWord(uintptr_t, word_t*) { return false;}
virtual std::string GetFunctionNameRaw(uintptr_t, uintptr_t*) { return ""; }
virtual size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) {
size_t offset = 0;
if (last_read_addr_ > 0) {
offset = addr - last_read_addr_;
}
size_t bytes_available = buffer_.size() - offset;
if (bytes_partial_read_ > 0) {
// Do a partial read.
if (bytes > bytes_partial_read_) {
bytes = bytes_partial_read_;
}
bytes_partial_read_ -= bytes;
} else if (bytes > bytes_available) {
bytes = bytes_available;
}
if (bytes > 0) {
memcpy(buffer, buffer_.data() + offset, bytes);
}
last_read_addr_ = addr;
return bytes;
}
void SetReadData(uint8_t* buffer, size_t bytes) {
buffer_.resize(bytes);
memcpy(buffer_.data(), buffer, bytes);
bytes_partial_read_ = 0;
last_read_addr_ = 0;
}
void SetPartialReadAmount(size_t bytes) {
if (bytes > buffer_.size()) {
abort();
}
bytes_partial_read_ = bytes;
}
private:
std::vector<uint8_t> buffer_;
size_t bytes_partial_read_ = 0;
uintptr_t last_read_addr_ = 0;
};
#endif // _DEBUGGERD_TEST_BACKTRACE_MOCK_H

View file

@ -0,0 +1,504 @@
/*
* Copyright (C) 2015 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 <stdlib.h>
#include <memory>
#include <string>
#include <gtest/gtest.h>
#include <base/file.h>
#include "BacktraceMock.h"
#include "log_fake.h"
#include "utility.h"
const char g_expected_full_dump[] =
"\nmemory near r1:\n"
#if defined(__LP64__)
" 0000000012345658 0706050403020100 0f0e0d0c0b0a0908 ................\n"
" 0000000012345668 1716151413121110 1f1e1d1c1b1a1918 ................\n"
" 0000000012345678 2726252423222120 2f2e2d2c2b2a2928 !\"#$%&'()*+,-./\n"
" 0000000012345688 3736353433323130 3f3e3d3c3b3a3938 0123456789:;<=>?\n"
" 0000000012345698 4746454443424140 4f4e4d4c4b4a4948 @ABCDEFGHIJKLMNO\n"
" 00000000123456a8 5756555453525150 5f5e5d5c5b5a5958 PQRSTUVWXYZ[\\]^_\n"
" 00000000123456b8 6766656463626160 6f6e6d6c6b6a6968 `abcdefghijklmno\n"
" 00000000123456c8 7776757473727170 7f7e7d7c7b7a7978 pqrstuvwxyz{|}~.\n"
" 00000000123456d8 8786858483828180 8f8e8d8c8b8a8988 ................\n"
" 00000000123456e8 9796959493929190 9f9e9d9c9b9a9998 ................\n"
" 00000000123456f8 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8 ................\n"
" 0000000012345708 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8 ................\n"
" 0000000012345718 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8 ................\n"
" 0000000012345728 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8 ................\n"
" 0000000012345738 e7e6e5e4e3e2e1e0 efeeedecebeae9e8 ................\n"
" 0000000012345748 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8 ................\n";
#else
" 12345658 03020100 07060504 0b0a0908 0f0e0d0c ................\n"
" 12345668 13121110 17161514 1b1a1918 1f1e1d1c ................\n"
" 12345678 23222120 27262524 2b2a2928 2f2e2d2c !\"#$%&'()*+,-./\n"
" 12345688 33323130 37363534 3b3a3938 3f3e3d3c 0123456789:;<=>?\n"
" 12345698 43424140 47464544 4b4a4948 4f4e4d4c @ABCDEFGHIJKLMNO\n"
" 123456a8 53525150 57565554 5b5a5958 5f5e5d5c PQRSTUVWXYZ[\\]^_\n"
" 123456b8 63626160 67666564 6b6a6968 6f6e6d6c `abcdefghijklmno\n"
" 123456c8 73727170 77767574 7b7a7978 7f7e7d7c pqrstuvwxyz{|}~.\n"
" 123456d8 83828180 87868584 8b8a8988 8f8e8d8c ................\n"
" 123456e8 93929190 97969594 9b9a9998 9f9e9d9c ................\n"
" 123456f8 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac ................\n"
" 12345708 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc ................\n"
" 12345718 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc ................\n"
" 12345728 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc ................\n"
" 12345738 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec ................\n"
" 12345748 f3f2f1f0 f7f6f5f4 fbfaf9f8 fffefdfc ................\n";
#endif
const char g_expected_partial_dump[] = \
"\nmemory near pc:\n"
#if defined(__LP64__)
" 00000000123455e0 0706050403020100 0f0e0d0c0b0a0908 ................\n"
" 00000000123455f0 1716151413121110 1f1e1d1c1b1a1918 ................\n"
" 0000000012345600 2726252423222120 2f2e2d2c2b2a2928 !\"#$%&'()*+,-./\n"
" 0000000012345610 3736353433323130 3f3e3d3c3b3a3938 0123456789:;<=>?\n"
" 0000000012345620 4746454443424140 4f4e4d4c4b4a4948 @ABCDEFGHIJKLMNO\n"
" 0000000012345630 5756555453525150 5f5e5d5c5b5a5958 PQRSTUVWXYZ[\\]^_\n"
" 0000000012345640 6766656463626160 ---------------- `abcdefg........\n"
" 0000000012345650 ---------------- ---------------- ................\n"
" 0000000012345660 ---------------- ---------------- ................\n"
" 0000000012345670 ---------------- ---------------- ................\n"
" 0000000012345680 ---------------- ---------------- ................\n"
" 0000000012345690 ---------------- ---------------- ................\n"
" 00000000123456a0 ---------------- ---------------- ................\n"
" 00000000123456b0 ---------------- ---------------- ................\n"
" 00000000123456c0 ---------------- ---------------- ................\n"
" 00000000123456d0 ---------------- ---------------- ................\n";
#else
" 123455e0 03020100 07060504 0b0a0908 0f0e0d0c ................\n"
" 123455f0 13121110 17161514 1b1a1918 1f1e1d1c ................\n"
" 12345600 23222120 27262524 2b2a2928 2f2e2d2c !\"#$%&'()*+,-./\n"
" 12345610 33323130 37363534 3b3a3938 3f3e3d3c 0123456789:;<=>?\n"
" 12345620 43424140 47464544 4b4a4948 4f4e4d4c @ABCDEFGHIJKLMNO\n"
" 12345630 53525150 57565554 5b5a5958 5f5e5d5c PQRSTUVWXYZ[\\]^_\n"
" 12345640 63626160 67666564 -------- -------- `abcdefg........\n"
" 12345650 -------- -------- -------- -------- ................\n"
" 12345660 -------- -------- -------- -------- ................\n"
" 12345670 -------- -------- -------- -------- ................\n"
" 12345680 -------- -------- -------- -------- ................\n"
" 12345690 -------- -------- -------- -------- ................\n"
" 123456a0 -------- -------- -------- -------- ................\n"
" 123456b0 -------- -------- -------- -------- ................\n"
" 123456c0 -------- -------- -------- -------- ................\n"
" 123456d0 -------- -------- -------- -------- ................\n";
#endif
class DumpMemoryTest : public ::testing::Test {
protected:
virtual void SetUp() {
map_mock_.reset(new BacktraceMapMock());
backtrace_mock_.reset(new BacktraceMock(map_mock_.get()));
char tmp_file[256];
const char data_template[] = "/data/local/tmp/debuggerd_memory_testXXXXXX";
memcpy(tmp_file, data_template, sizeof(data_template));
int tombstone_fd = mkstemp(tmp_file);
if (tombstone_fd == -1) {
const char tmp_template[] = "/tmp/debuggerd_memory_testXXXXXX";
memcpy(tmp_file, tmp_template, sizeof(tmp_template));
tombstone_fd = mkstemp(tmp_file);
if (tombstone_fd == -1) {
abort();
}
}
if (unlink(tmp_file) == -1) {
abort();
}
log_.tfd = tombstone_fd;
log_.amfd = -1;
log_.crashed_tid = 12;
log_.current_tid = 12;
log_.should_retrieve_logcat = false;
resetLogs();
}
virtual void TearDown() {
if (log_.tfd >= 0) {
close(log_.tfd);
}
}
std::unique_ptr<BacktraceMapMock> map_mock_;
std::unique_ptr<BacktraceMock> backtrace_mock_;
log_t log_;
};
TEST_F(DumpMemoryTest, aligned_addr) {
uint8_t buffer[256];
for (size_t i = 0; i < sizeof(buffer); i++) {
buffer[i] = i;
}
backtrace_mock_->SetReadData(buffer, sizeof(buffer));
dump_memory(&log_, backtrace_mock_.get(), 0x12345678, "memory near %.2s:", "r1");
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
ASSERT_STREQ(g_expected_full_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, partial_read) {
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(96);
dump_memory(&log_, backtrace_mock_.get(), 0x12345679, "memory near %.2s:", "r1");
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
ASSERT_STREQ(g_expected_full_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, unaligned_addr) {
uint8_t buffer[256];
for (size_t i = 0; i < sizeof(buffer); i++) {
buffer[i] = i;
}
backtrace_mock_->SetReadData(buffer, sizeof(buffer));
dump_memory(&log_, backtrace_mock_.get(), 0x12345679, "memory near %.2s:", "r1");
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
ASSERT_STREQ(g_expected_full_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, memory_unreadable) {
dump_memory(&log_, backtrace_mock_.get(), 0xa2345678, "memory near pc:");
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 pc:\n"
#if defined(__LP64__)
" 00000000a2345658 ---------------- ---------------- ................\n"
" 00000000a2345668 ---------------- ---------------- ................\n"
" 00000000a2345678 ---------------- ---------------- ................\n"
" 00000000a2345688 ---------------- ---------------- ................\n"
" 00000000a2345698 ---------------- ---------------- ................\n"
" 00000000a23456a8 ---------------- ---------------- ................\n"
" 00000000a23456b8 ---------------- ---------------- ................\n"
" 00000000a23456c8 ---------------- ---------------- ................\n"
" 00000000a23456d8 ---------------- ---------------- ................\n"
" 00000000a23456e8 ---------------- ---------------- ................\n"
" 00000000a23456f8 ---------------- ---------------- ................\n"
" 00000000a2345708 ---------------- ---------------- ................\n"
" 00000000a2345718 ---------------- ---------------- ................\n"
" 00000000a2345728 ---------------- ---------------- ................\n"
" 00000000a2345738 ---------------- ---------------- ................\n"
" 00000000a2345748 ---------------- ---------------- ................\n";
#else
" a2345658 -------- -------- -------- -------- ................\n"
" a2345668 -------- -------- -------- -------- ................\n"
" a2345678 -------- -------- -------- -------- ................\n"
" a2345688 -------- -------- -------- -------- ................\n"
" a2345698 -------- -------- -------- -------- ................\n"
" a23456a8 -------- -------- -------- -------- ................\n"
" a23456b8 -------- -------- -------- -------- ................\n"
" a23456c8 -------- -------- -------- -------- ................\n"
" a23456d8 -------- -------- -------- -------- ................\n"
" a23456e8 -------- -------- -------- -------- ................\n"
" a23456f8 -------- -------- -------- -------- ................\n"
" a2345708 -------- -------- -------- -------- ................\n"
" a2345718 -------- -------- -------- -------- ................\n"
" a2345728 -------- -------- -------- -------- ................\n"
" a2345738 -------- -------- -------- -------- ................\n"
" a2345748 -------- -------- -------- -------- ................\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, memory_partially_unreadable) {
uint8_t buffer[104];
for (size_t i = 0; i < sizeof(buffer); i++) {
buffer[i] = i;
}
backtrace_mock_->SetReadData(buffer, sizeof(buffer));
dump_memory(&log_, backtrace_mock_.get(), 0x12345600, "memory near pc:");
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
ASSERT_STREQ(g_expected_partial_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, memory_partially_unreadable_unaligned_return) {
uint8_t buffer[104];
for (size_t i = 0; i < sizeof(buffer); i++) {
buffer[i] = i;
}
backtrace_mock_->SetReadData(buffer, sizeof(buffer));
backtrace_mock_->SetPartialReadAmount(102);
dump_memory(&log_, backtrace_mock_.get(), 0x12345600, "memory near pc:");
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
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());
#else
ASSERT_STREQ("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.
ASSERT_STREQ("", getFakeLogBuf().c_str());
}
TEST_F(DumpMemoryTest, memory_partially_unreadable_two_unaligned_reads) {
uint8_t buffer[106];
for (size_t i = 0; i < sizeof(buffer); i++) {
buffer[i] = i;
}
backtrace_mock_->SetReadData(buffer, sizeof(buffer));
backtrace_mock_->SetPartialReadAmount(45);
dump_memory(&log_, backtrace_mock_.get(), 0x12345600, "memory near pc:");
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
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",
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",
getFakeLogPrint().c_str());
#endif
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
}
TEST_F(DumpMemoryTest, address_low_fence) {
uint8_t buffer[256];
memset(buffer, 0, sizeof(buffer));
backtrace_mock_->SetReadData(buffer, sizeof(buffer));
dump_memory(&log_, backtrace_mock_.get(), 0x1000, "memory near %.2s:", "r1");
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 r1:\n"
#if defined(__LP64__)
" 0000000000001000 0000000000000000 0000000000000000 ................\n"
" 0000000000001010 0000000000000000 0000000000000000 ................\n"
" 0000000000001020 0000000000000000 0000000000000000 ................\n"
" 0000000000001030 0000000000000000 0000000000000000 ................\n"
" 0000000000001040 0000000000000000 0000000000000000 ................\n"
" 0000000000001050 0000000000000000 0000000000000000 ................\n"
" 0000000000001060 0000000000000000 0000000000000000 ................\n"
" 0000000000001070 0000000000000000 0000000000000000 ................\n"
" 0000000000001080 0000000000000000 0000000000000000 ................\n"
" 0000000000001090 0000000000000000 0000000000000000 ................\n"
" 00000000000010a0 0000000000000000 0000000000000000 ................\n"
" 00000000000010b0 0000000000000000 0000000000000000 ................\n"
" 00000000000010c0 0000000000000000 0000000000000000 ................\n"
" 00000000000010d0 0000000000000000 0000000000000000 ................\n"
" 00000000000010e0 0000000000000000 0000000000000000 ................\n"
" 00000000000010f0 0000000000000000 0000000000000000 ................\n";
#else
" 00001000 00000000 00000000 00000000 00000000 ................\n"
" 00001010 00000000 00000000 00000000 00000000 ................\n"
" 00001020 00000000 00000000 00000000 00000000 ................\n"
" 00001030 00000000 00000000 00000000 00000000 ................\n"
" 00001040 00000000 00000000 00000000 00000000 ................\n"
" 00001050 00000000 00000000 00000000 00000000 ................\n"
" 00001060 00000000 00000000 00000000 00000000 ................\n"
" 00001070 00000000 00000000 00000000 00000000 ................\n"
" 00001080 00000000 00000000 00000000 00000000 ................\n"
" 00001090 00000000 00000000 00000000 00000000 ................\n"
" 000010a0 00000000 00000000 00000000 00000000 ................\n"
" 000010b0 00000000 00000000 00000000 00000000 ................\n"
" 000010c0 00000000 00000000 00000000 00000000 ................\n"
" 000010d0 00000000 00000000 00000000 00000000 ................\n"
" 000010e0 00000000 00000000 00000000 00000000 ................\n"
" 000010f0 00000000 00000000 00000000 00000000 ................\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, memory_address_too_low) {
uint8_t buffer[256];
memset(buffer, 0, sizeof(buffer));
backtrace_mock_->SetReadData(buffer, sizeof(buffer));
dump_memory(&log_, backtrace_mock_.get(), 0, "memory near %.2s:", "r1");
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());
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(DumpMemoryTest, memory_address_too_high) {
uint8_t buffer[256];
memset(buffer, 0, sizeof(buffer));
backtrace_mock_->SetReadData(buffer, sizeof(buffer));
#if defined(__LP64__)
dump_memory(&log_, backtrace_mock_.get(), 0x4000000000000000UL, "memory near %.2s:", "r1");
dump_memory(&log_, backtrace_mock_.get(), 0x4000000000000000UL - 32, "memory near %.2s:", "r1");
dump_memory(&log_, backtrace_mock_.get(), 0x4000000000000000UL - 216, "memory near %.2s:", "r1");
#else
dump_memory(&log_, backtrace_mock_.get(), 0xffff0000, "memory near %.2s:", "r1");
dump_memory(&log_, backtrace_mock_.get(), 0xffff0000 - 32, "memory near %.2s:", "r1");
dump_memory(&log_, backtrace_mock_.get(), 0xffff0000 - 220, "memory near %.2s:", "r1");
#endif
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());
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(DumpMemoryTest, memory_address_would_overflow) {
uint8_t buffer[256];
memset(buffer, 0, sizeof(buffer));
backtrace_mock_->SetReadData(buffer, sizeof(buffer));
#if defined(__LP64__)
dump_memory(&log_, backtrace_mock_.get(), 0xfffffffffffffff0, "memory near %.2s:", "r1");
#else
dump_memory(&log_, backtrace_mock_.get(), 0xfffffff0, "memory near %.2s:", "r1");
#endif
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());
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
TEST_F(DumpMemoryTest, memory_address_nearly_too_high) {
uint8_t buffer[256];
for (size_t i = 0; i < sizeof(buffer); i++) {
buffer[i] = i;
}
backtrace_mock_->SetReadData(buffer, sizeof(buffer));
#if defined(__LP64__)
dump_memory(&log_, backtrace_mock_.get(), 0x4000000000000000UL - 224, "memory near %.2s:", "r4");
#else
dump_memory(&log_, backtrace_mock_.get(), 0xffff0000 - 224, "memory near %.2s:", "r4");
#endif
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__)
" 3fffffffffffff00 0706050403020100 0f0e0d0c0b0a0908 ................\n"
" 3fffffffffffff10 1716151413121110 1f1e1d1c1b1a1918 ................\n"
" 3fffffffffffff20 2726252423222120 2f2e2d2c2b2a2928 !\"#$%&'()*+,-./\n"
" 3fffffffffffff30 3736353433323130 3f3e3d3c3b3a3938 0123456789:;<=>?\n"
" 3fffffffffffff40 4746454443424140 4f4e4d4c4b4a4948 @ABCDEFGHIJKLMNO\n"
" 3fffffffffffff50 5756555453525150 5f5e5d5c5b5a5958 PQRSTUVWXYZ[\\]^_\n"
" 3fffffffffffff60 6766656463626160 6f6e6d6c6b6a6968 `abcdefghijklmno\n"
" 3fffffffffffff70 7776757473727170 7f7e7d7c7b7a7978 pqrstuvwxyz{|}~.\n"
" 3fffffffffffff80 8786858483828180 8f8e8d8c8b8a8988 ................\n"
" 3fffffffffffff90 9796959493929190 9f9e9d9c9b9a9998 ................\n"
" 3fffffffffffffa0 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8 ................\n"
" 3fffffffffffffb0 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8 ................\n"
" 3fffffffffffffc0 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8 ................\n"
" 3fffffffffffffd0 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8 ................\n"
" 3fffffffffffffe0 e7e6e5e4e3e2e1e0 efeeedecebeae9e8 ................\n"
" 3ffffffffffffff0 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8 ................\n";
#else
" fffeff00 03020100 07060504 0b0a0908 0f0e0d0c ................\n"
" fffeff10 13121110 17161514 1b1a1918 1f1e1d1c ................\n"
" fffeff20 23222120 27262524 2b2a2928 2f2e2d2c !\"#$%&'()*+,-./\n"
" fffeff30 33323130 37363534 3b3a3938 3f3e3d3c 0123456789:;<=>?\n"
" fffeff40 43424140 47464544 4b4a4948 4f4e4d4c @ABCDEFGHIJKLMNO\n"
" fffeff50 53525150 57565554 5b5a5958 5f5e5d5c PQRSTUVWXYZ[\\]^_\n"
" fffeff60 63626160 67666564 6b6a6968 6f6e6d6c `abcdefghijklmno\n"
" fffeff70 73727170 77767574 7b7a7978 7f7e7d7c pqrstuvwxyz{|}~.\n"
" fffeff80 83828180 87868584 8b8a8988 8f8e8d8c ................\n"
" fffeff90 93929190 97969594 9b9a9998 9f9e9d9c ................\n"
" fffeffa0 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac ................\n"
" fffeffb0 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc ................\n"
" fffeffc0 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc ................\n"
" fffeffd0 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc ................\n"
" fffeffe0 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec ................\n"
" fffefff0 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());
}

View file

@ -0,0 +1,59 @@
/*
* Copyright (C) 2015 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 <stdarg.h>
#include <string>
#include <base/stringprintf.h>
std::string g_fake_log_buf;
std::string g_fake_log_print;
void resetLogs() {
g_fake_log_buf = "";
g_fake_log_print = "";
}
extern "C" int __android_log_buf_write(int, int, const char* tag, const char* msg) {
g_fake_log_buf += tag;
g_fake_log_buf += ' ';
g_fake_log_buf += msg;
return 1;
}
std::string getFakeLogBuf() {
return g_fake_log_buf;
}
extern "C" int __android_log_print(int, const char* tag, const char* fmt, ...) {
g_fake_log_print += tag;
g_fake_log_print += ' ';
va_list ap;
va_start(ap, fmt);
android::base::StringAppendV(&g_fake_log_print, fmt, ap);
va_end(ap);
g_fake_log_print += '\n';
return 1;
}
std::string getFakeLogPrint() {
return g_fake_log_print;
}

26
debuggerd/test/log_fake.h Normal file
View file

@ -0,0 +1,26 @@
/*
* Copyright (C) 2015 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.
*/
#ifndef _DEBUGGERD_TEST_LOG_FAKE_H
#define _DEBUGGERD_TEST_LOG_FAKE_H
#include <string>
void resetLogs();
std::string getFakeLogBuf();
std::string getFakeLogPrint();
#endif // _DEBUGGERD_TEST_LOG_FAKE_H

View file

@ -654,7 +654,7 @@ static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, int si_code
} else {
ALOGE("Unwind failed: pid = %d, tid = %d", pid, tid);
}
dump_memory_and_code(log, tid);
dump_memory_and_code(log, backtrace.get());
if (map.get() != nullptr) {
dump_all_maps(backtrace.get(), map.get(), log, tid);
}

View file

@ -27,6 +27,7 @@
#include <backtrace/Backtrace.h>
#include <base/file.h>
#include <base/stringprintf.h>
#include <log/log.h>
const int SLEEP_TIME_USEC = 50000; // 0.05 seconds
@ -118,68 +119,91 @@ int wait_for_sigstop(pid_t tid, int* total_sleep_time_usec, bool* detach_failed)
return -1;
}
void dump_memory(log_t* log, pid_t tid, uintptr_t addr) {
char code_buffer[64];
char ascii_buffer[32];
uintptr_t p, end;
#define MEMORY_BYTES_TO_DUMP 256
#define MEMORY_BYTES_PER_LINE 16
p = addr & ~(sizeof(long) - 1);
/* Dump 32 bytes before addr */
p -= 32;
if (p > addr) {
/* catch underflow */
p = 0;
}
/* Dump 256 bytes */
end = p + 256;
/* catch overflow; 'end - p' has to be multiples of 16 */
while (end < p) {
end -= 16;
}
void dump_memory(log_t* log, Backtrace* backtrace, uintptr_t addr, const char* fmt, ...) {
std::string log_msg;
va_list ap;
va_start(ap, fmt);
android::base::StringAppendV(&log_msg, fmt, ap);
va_end(ap);
/* Dump the code around PC as:
* addr contents ascii
* 0000000000008d34 ef000000e8bd0090 e1b00000512fff1e ............../Q
* 0000000000008d44 ea00b1f9e92d0090 e3a070fcef000000 ......-..p......
* On 32-bit machines, there are still 16 bytes per line but addresses and
* words are of course presented differently.
*/
while (p < end) {
char* asc_out = ascii_buffer;
// Align the address to sizeof(long) and start 32 bytes before the address.
addr &= ~(sizeof(long) - 1);
if (addr >= 4128) {
addr -= 32;
}
int len = snprintf(code_buffer, sizeof(code_buffer), "%" PRIPTR " ", p);
for (size_t i = 0; i < 16/sizeof(long); i++) {
long data = ptrace(PTRACE_PEEKTEXT, tid, (void*)p, NULL);
if (data == -1 && errno != 0) {
// ptrace failed, probably because we're dumping memory in an
// unmapped or inaccessible page.
#ifdef __LP64__
len += sprintf(code_buffer + len, "---------------- ");
// Don't bother if the address looks too low, or looks too high.
if (addr < 4096 ||
#if defined(__LP64__)
addr > 0x4000000000000000UL - MEMORY_BYTES_TO_DUMP) {
#else
len += sprintf(code_buffer + len, "-------- ");
addr > 0xffff0000 - MEMORY_BYTES_TO_DUMP) {
#endif
} else {
len += sprintf(code_buffer + len, "%" PRIPTR " ",
static_cast<uintptr_t>(data));
}
return;
}
for (size_t j = 0; j < sizeof(long); j++) {
/*
* Our isprint() allows high-ASCII characters that display
* differently (often badly) in different viewers, so we
* just use a simpler test.
*/
char val = (data >> (j*8)) & 0xff;
if (val >= 0x20 && val < 0x7f) {
*asc_out++ = val;
} else {
*asc_out++ = '.';
}
}
p += sizeof(long);
}
*asc_out = '\0';
_LOG(log, logtype::MEMORY, " %s %s\n", code_buffer, ascii_buffer);
_LOG(log, logtype::MEMORY, "\n%s\n", log_msg.c_str());
// Dump 256 bytes
uintptr_t data[MEMORY_BYTES_TO_DUMP/sizeof(uintptr_t)];
memset(data, 0, MEMORY_BYTES_TO_DUMP);
size_t bytes = backtrace->Read(addr, reinterpret_cast<uint8_t*>(data), sizeof(data));
if (bytes % sizeof(uintptr_t) != 0) {
// This should never happen, but just in case.
ALOGE("Bytes read %zu, is not a multiple of %zu", bytes, sizeof(uintptr_t));
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);
bytes += bytes2;
if (bytes2 > 0 && bytes % sizeof(uintptr_t) != 0) {
// This should never happen, but we'll try and continue any way.
ALOGE("Bytes after second read %zu, is not a multiple of %zu", bytes, sizeof(uintptr_t));
bytes &= ~(sizeof(uintptr_t) - 1);
}
}
// Dump the code around memory as:
// addr contents ascii
// 0000000000008d34 ef000000e8bd0090 e1b00000512fff1e ............../Q
// 0000000000008d44 ea00b1f9e92d0090 e3a070fcef000000 ......-..p......
// 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;
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);
android::base::StringAppendF(&logline, " %" PRIPTR, *data_ptr);
// Fill out the ascii string from the data.
uint8_t* ptr = reinterpret_cast<uint8_t*>(data_ptr);
for (size_t val = 0; val < sizeof(uintptr_t); val++, ptr++) {
if (*ptr >= 0x20 && *ptr < 0x7f) {
ascii += *ptr;
} else {
ascii += '.';
}
}
} else {
logline += ' ' + std::string(sizeof(uintptr_t) * 2, '-');
ascii += std::string(sizeof(uintptr_t), '.');
}
}
_LOG(log, logtype::MEMORY, "%s %s\n", logline.c_str(), ascii.c_str());
}
}

View file

@ -21,6 +21,8 @@
#include <stdbool.h>
#include <sys/types.h>
#include <backtrace/Backtrace.h>
// Figure out the abi based on defined macros.
#if defined(__arm__)
#define ABI_STRING "arm"
@ -75,6 +77,6 @@ void _LOG(log_t* log, logtype ltype, const char *fmt, ...)
int wait_for_sigstop(pid_t, int*, bool*);
void dump_memory(log_t* log, pid_t tid, uintptr_t addr);
void dump_memory(log_t* log, Backtrace* backtrace, uintptr_t addr, const char* fmt, ...);
#endif // _DEBUGGERD_UTILITY_H

View file

@ -14,18 +14,31 @@
* limitations under the License.
*/
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <stdint.h>
#include <string.h>
#include <sys/ptrace.h>
#include "../utility.h"
#include "../machine.h"
#include <backtrace/Backtrace.h>
void dump_memory_and_code(log_t*, pid_t) {
#include "machine.h"
#include "utility.h"
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));
return;
}
dump_memory(log, backtrace, static_cast<uintptr_t>(r.eax), "memory near eax:");
dump_memory(log, backtrace, static_cast<uintptr_t>(r.ebx), "memory near ebx:");
dump_memory(log, backtrace, static_cast<uintptr_t>(r.ecx), "memory near ecx:");
dump_memory(log, backtrace, static_cast<uintptr_t>(r.edx), "memory near edx:");
dump_memory(log, backtrace, static_cast<uintptr_t>(r.esi), "memory near esi:");
dump_memory(log, backtrace, static_cast<uintptr_t>(r.edi), "memory near edi:");
dump_memory(log, backtrace, static_cast<uintptr_t>(r.eip), "code around eip:");
}
void dump_registers(log_t* log, pid_t tid) {
@ -34,6 +47,7 @@ void dump_registers(log_t* log, pid_t tid) {
_LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
return;
}
_LOG(log, logtype::REGISTERS, " eax %08lx ebx %08lx ecx %08lx edx %08lx\n",
r.eax, r.ebx, r.ecx, r.edx);
_LOG(log, logtype::REGISTERS, " esi %08lx edi %08lx\n",

65
debuggerd/x86_64/machine.cpp Executable file → Normal file
View file

@ -14,38 +14,51 @@
** limitations under the License.
*/
#include <stddef.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <stdint.h>
#include <sys/ptrace.h>
#include <string.h>
#include <sys/user.h>
#include "../utility.h"
#include "../machine.h"
#include <backtrace/Backtrace.h>
void dump_memory_and_code(log_t*, pid_t) {
#include "machine.h"
#include "utility.h"
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));
return;
}
dump_memory(log, backtrace, static_cast<uintptr_t>(r.rax), "memory near rax:");
dump_memory(log, backtrace, static_cast<uintptr_t>(r.rbx), "memory near rbx:");
dump_memory(log, backtrace, static_cast<uintptr_t>(r.rcx), "memory near rcx:");
dump_memory(log, backtrace, static_cast<uintptr_t>(r.rdx), "memory near rdx:");
dump_memory(log, backtrace, static_cast<uintptr_t>(r.rsi), "memory near rsi:");
dump_memory(log, backtrace, static_cast<uintptr_t>(r.rdi), "memory near rdi:");
dump_memory(log, backtrace, static_cast<uintptr_t>(r.rip), "code around rip:");
}
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));
return;
}
_LOG(log, logtype::REGISTERS, " rax %016lx rbx %016lx rcx %016lx rdx %016lx\n",
r.rax, r.rbx, r.rcx, r.rdx);
_LOG(log, logtype::REGISTERS, " rsi %016lx rdi %016lx\n",
r.rsi, r.rdi);
_LOG(log, logtype::REGISTERS, " r8 %016lx r9 %016lx r10 %016lx r11 %016lx\n",
r.r8, r.r9, r.r10, r.r11);
_LOG(log, logtype::REGISTERS, " r12 %016lx r13 %016lx r14 %016lx r15 %016lx\n",
r.r12, r.r13, r.r14, r.r15);
_LOG(log, logtype::REGISTERS, " cs %016lx ss %016lx\n",
r.cs, r.ss);
_LOG(log, logtype::REGISTERS, " rip %016lx rbp %016lx rsp %016lx eflags %016lx\n",
r.rip, r.rbp, r.rsp, r.eflags);
struct user_regs_struct r;
if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
_LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
return;
}
_LOG(log, logtype::REGISTERS, " rax %016lx rbx %016lx rcx %016lx rdx %016lx\n",
r.rax, r.rbx, r.rcx, r.rdx);
_LOG(log, logtype::REGISTERS, " rsi %016lx rdi %016lx\n",
r.rsi, r.rdi);
_LOG(log, logtype::REGISTERS, " r8 %016lx r9 %016lx r10 %016lx r11 %016lx\n",
r.r8, r.r9, r.r10, r.r11);
_LOG(log, logtype::REGISTERS, " r12 %016lx r13 %016lx r14 %016lx r15 %016lx\n",
r.r12, r.r13, r.r14, r.r15);
_LOG(log, logtype::REGISTERS, " cs %016lx ss %016lx\n",
r.cs, r.ss);
_LOG(log, logtype::REGISTERS, " rip %016lx rbp %016lx rsp %016lx eflags %016lx\n",
r.rip, r.rbp, r.rsp, r.eflags);
}